diff --git a/public/build/beike/admin/css/filemanager.css b/public/build/beike/admin/css/filemanager.css index 89a2eaf2..17ce2a53 100644 --- a/public/build/beike/admin/css/filemanager.css +++ b/public/build/beike/admin/css/filemanager.css @@ -1,3 +1,4 @@ +@charset "UTF-8"; [v-cloak] { display: none; } @@ -6,6 +7,14 @@ body.page-filemanager { height: 100vh; overflow: hidden; font-size: 12px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + /* CSS3属性 */ +} +body.page-filemanager [class*=" el-icon-"], body.page-filemanager [class^=el-icon-] { + font-weight: 600; } body.page-filemanager .filemanager-wrap { display: flex; @@ -17,6 +26,15 @@ body.page-filemanager .filemanager-wrap .filemanager-navbar { background-color: #293042; overflow-y: auto; } +body.page-filemanager .filemanager-wrap .filemanager-navbar::-webkit-scrollbar { + width: 2px; +} +body.page-filemanager .filemanager-wrap .filemanager-navbar::-webkit-scrollbar-thumb { + background: #409EFF; +} +body.page-filemanager .filemanager-wrap .filemanager-navbar::-webkit-scrollbar-track { + background: transparent; +} body.page-filemanager .filemanager-wrap .filemanager-navbar .el-tree { background-color: transparent; } @@ -139,7 +157,6 @@ body.page-filemanager .filemanager-wrap .filemanager-content .content-center .im body.page-filemanager .filemanager-wrap .filemanager-content .content-center .image-list .text .el-icon-check { color: #409EFF; font-size: 18px; - font-weight: 600; } body.page-filemanager .filemanager-wrap .filemanager-content .content-footer { height: 56px; diff --git a/public/build/beike/admin/js/app.js b/public/build/beike/admin/js/app.js index 4cdcfc8b..fadd5431 100644 --- a/public/build/beike/admin/js/app.js +++ b/public/build/beike/admin/js/app.js @@ -2102,17 +2102,18 @@ __webpack_require__.r(__webpack_exports__); function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } window.axios = __webpack_require__(/*! axios */ "./node_modules/axios/index.js"); +var token = document.querySelector('meta[name="csrf-token"]').content; +var base = document.querySelector('base').href; var instance = axios.create({ headers: { - 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') + 'X-CSRF-TOKEN': token } }); axios.defaults.timeout = 5000; // 请求超时 // axios.defaults.baseURL = process.env.NODE_ENV == 'production' ? process.env.VUE_APP_BASE_URL + '/' : '/'; // console.log(process.env.VUE_APP_BASE_URL) -console.log($('base').attr('href')); -axios.defaults.baseURL = $('base').attr('href'); +axios.defaults.baseURL = base; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ /** * get 请求 diff --git a/public/build/beike/shop/default/js/app.js b/public/build/beike/shop/default/js/app.js index e2cbb81a..4d33a1c2 100644 --- a/public/build/beike/shop/default/js/app.js +++ b/public/build/beike/shop/default/js/app.js @@ -2068,17 +2068,18 @@ __webpack_require__.r(__webpack_exports__); function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } window.axios = __webpack_require__(/*! axios */ "./node_modules/axios/index.js"); +var token = document.querySelector('meta[name="csrf-token"]').content; +var base = document.querySelector('base').href; var instance = axios.create({ headers: { - 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') + 'X-CSRF-TOKEN': token } }); axios.defaults.timeout = 5000; // 请求超时 // axios.defaults.baseURL = process.env.NODE_ENV == 'production' ? process.env.VUE_APP_BASE_URL + '/' : '/'; // console.log(process.env.VUE_APP_BASE_URL) -console.log($('base').attr('href')); -axios.defaults.baseURL = $('base').attr('href'); +axios.defaults.baseURL = base; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ /** * get 请求 diff --git a/public/vendor/vue/batch_select.js b/public/vendor/vue/batch_select.js new file mode 100644 index 00000000..bd3917ed --- /dev/null +++ b/public/vendor/vue/batch_select.js @@ -0,0 +1,100 @@ +// 自 https://blog.wy310.cn/2020/12/17/vue-drag-batch-select/ 修改 +Vue.directive('batch-select', { + // 当被绑定的元素插入到 DOM 中时…… + // inserted: (el, binding) => {} + componentUpdated: (el, binding) => { + // 设置被绑定元素el(即上述的box)的position为relative,目的是让蓝色半透明遮罩area相对其定位 + el.style.position = 'relative'; + // 记录el在视窗中的位置elPos + const { x, y } = el.getBoundingClientRect() + const elPos = { x, y } + // 获取该指令调用者传递过来的参数:className / selectArr 是选中的 index 要放的数组 + // v-batch-select="{ className: '.el-checkbox', selectArr: [] }" + // 表示要使用鼠标框选类名为'.el-checkbox'的元素 + const optionClassName = binding.value.className + const options = [].slice.call(el.querySelectorAll(optionClassName)) + // 获取被框选对象们的x、y、width、height + const optionsXYWH = [] + options.forEach(v => { + const obj = v.getBoundingClientRect() + optionsXYWH.push({ + x: obj.x - elPos.x, + y: obj.y - elPos.y, + w: obj.width, + h: obj.height + }) + }) + // 创建一个div作为area区域,注意定位是absolute,visibility初始值是hidden + const area = document.createElement('div') + area.style = 'position: absolute; border: 1px solid #409eff; background-color: rgba(64, 158, 255, 0.1); z-index: 10; visibility: hidden;' + area.className = 'area' + area.innerHTML = '' + el.appendChild(area) + el.onmousedown = (e) => { + // 获取鼠标按下时相对box的坐标 + const startX = e.clientX - elPos.x + const startY = e.clientY - elPos.y + // 判断鼠标按下后是否发生移动的标识 + let hasMove = false + + + document.onmousemove = (e) => { + hasMove = true + binding.value.setSelectStatus(true) + // 显示area + area.style.visibility = 'visible' + // 获取鼠标移动过程中指针的实时位置 + const endX = e.clientX - elPos.x + const endY = e.clientY - elPos.y + // 这里使用绝对值是为了兼容鼠标从各个方向框选的情况 + const width = Math.abs(endX - startX) + const height = Math.abs(endY - startY) + // 根据初始位置和实时位置计算出area的left、top、width、height + const left = Math.min(startX, endX) + const top = Math.min(startY, endY) + // 实时绘制 + area.style.left = `${left}px` + area.style.top = `${top}px` + area.style.width = `${width}px` + area.style.height = `${height}px` + + const areaTop = parseInt(top) + const areaRight = parseInt(left) + parseInt(width) + const areaBottom = parseInt(top) + parseInt(height) + const areaLeft = parseInt(left) + binding.value.selectImageIndex.length = 0 + optionsXYWH.forEach((v, i) => { + const optionTop = v.y + const optionRight = v.x + v.w + const optionBottom = v.y + v.h + const optionLeft = v.x + if (!(areaTop > optionBottom || areaRight < optionLeft || areaBottom < optionTop || areaLeft > optionRight)) { + // 该指令的调用者可以监听到selectIdxs的变化 + binding.value.selectImageIndex.push(i) + } + }) + + } + + document.onmouseup = (e) => { + document.onmousemove = document.onmouseup = null + if (hasMove) { + // 鼠标抬起时,如果之前发生过移动,则执行碰撞检测 + const { left, top, width, height } = area.style + setTimeout(() => { + binding.value.setSelectStatus(false) + }, 100); + } + // 恢复以下数据 + hasMove = false + area.style.visibility = 'hidden' + area.style.left = 0 + area.style.top = 0 + area.style.width = 0 + area.style.height = 0 + return false + } + } + }, + // update: (el, binding) => {} +}) \ No newline at end of file diff --git a/resources/beike/admin/css/filemanager/app.scss b/resources/beike/admin/css/filemanager/app.scss index 34b29a70..6d2c55f6 100644 --- a/resources/beike/admin/css/filemanager/app.scss +++ b/resources/beike/admin/css/filemanager/app.scss @@ -11,6 +11,11 @@ body.page-filemanager { height: 100vh; overflow: hidden; font-size: 12px; + user-select:none; /* CSS3属性 */ + + [class*=" el-icon-"], [class^=el-icon-] { + font-weight: 600; + } .filemanager-wrap { display: flex; @@ -22,6 +27,18 @@ body.page-filemanager { background-color: #293042; overflow-y: auto; + &::-webkit-scrollbar { + width: 2px; + } + + &::-webkit-scrollbar-thumb { + background: $primary; + } + + &::-webkit-scrollbar-track { + background: transparent; + } + .el-tree { background-color: transparent; .el-tree-node__content { @@ -206,7 +223,6 @@ body.page-filemanager { .el-icon-check { color: $primary; font-size: 18px; - font-weight: 600; } } } diff --git a/resources/beike/admin/views/pages/design/builder/component/image_selector.blade.php b/resources/beike/admin/views/pages/design/builder/component/image_selector.blade.php index 1f3671ee..4da9556f 100644 --- a/resources/beike/admin/views/pages/design/builder/component/image_selector.blade.php +++ b/resources/beike/admin/views/pages/design/builder/component/image_selector.blade.php @@ -115,9 +115,9 @@ that.loading = false; if (that.isLanguage) { - that.src[that.tabActiveId] = images.path; + that.src[that.tabActiveId] = images[0].path; } else { - that.src = images.path; + that.src = images[0].path; } // console.log(that.src); } diff --git a/resources/beike/admin/views/pages/file_manager/index.blade.php b/resources/beike/admin/views/pages/file_manager/index.blade.php index 5b6de99d..928682cc 100644 --- a/resources/beike/admin/views/pages/file_manager/index.blade.php +++ b/resources/beike/admin/views/pages/file_manager/index.blade.php @@ -2,17 +2,19 @@ + + {{-- --}} + - beike filemanager @@ -54,15 +56,16 @@
- 下载 - 删除 - 重命名 + 下载 + 删除 + 重命名 + 全选
上传文件
-
+
@@ -81,7 +84,7 @@ :total="image_total">
-
选择
+
选择
@@ -133,10 +136,13 @@ max: 40, paneLengthPercent: 26, triggerLength: 10, + isShift: false, + ssss:[], loading: false, + isBatchSelect: false, - editingImageIndex: null, + selectImageIndex: [], treeData: [{name: '图片空间', path: '/', children: @json($folders)}], @@ -145,6 +151,7 @@ label: 'name', isLeaf: 'leaf' }, + selectIdxs: [], uploadFileDialog: { show: false, @@ -168,7 +175,20 @@ }, // 侦听器 watch: { + images: { + handler(val) { + if (this.isBatchSelect) return; + // 将选中的图片索引放入 selectImageIndex,未选中则清空 + this.selectImageIndex = val.filter(item => item.selected).map(e => this.images.indexOf(e)); + }, + deep: true + }, + selectImageIndex(indexs) { + this.images.forEach((item, index) => { + item.selected = indexs.includes(index); + }); + }, }, // 组件方法 methods: { @@ -181,6 +201,10 @@ this.loadData(e, node) }, + updateSelectStatus(status) { + this.isBatchSelect = status + }, + pageCurrentChange(e) { this.image_page = e this.loadData() @@ -298,13 +322,32 @@ }, checkedImage(index) { - this.editingImageIndex = index; - this.images.map(e => !e.index ? e.selected = false : '') + // 获取当前选中的 index + const selectedIndex = this.images.findIndex(e => e.selected); + + if (this.isShift) { + // 获取 selectedIndex 与 index 之间的所有图片 + let selectedImages = this.images.slice(Math.min(selectedIndex, index), Math.max(selectedIndex, index) + 1); + selectedImages.map(e => e.selected = true) + return; + } + + if (this.isCtrl) { + this.images[index].selected = !this.images[index].selected; + return; + } + + if (this.selectImageIndex.length > 1) { + this.images.map((e,i) => i != index ? e.selected = false : e.selected = true) + return; + } + + this.images.map((e,i) => i != index ? e.selected = false : '') this.images[index].selected = !this.images[index].selected }, fileChecked() { - let typedFiles = this.images[this.editingImageIndex]; + let typedFiles = this.images.filter(e => e.selected) if (callback !== null) { callback(typedFiles); @@ -319,7 +362,10 @@ this.$confirm('是否要删除选中文件', '提示', { type: 'warning' }).then(() => { - this.images.splice(this.editingImageIndex, 1); + // 删除选中的文件 + console.log(this.selectImageIndex); + + // this.images.splice(this.selectImageIndex, 1); this.$message({type: 'success',message: '删除成功!'}); }).catch(_=>{}); }, @@ -340,13 +386,34 @@ } }, + selectAll() { + // 获取 this.images 中的 selected 是否全部为 true + const isAllSelected = this.images.every(e => e.selected); + this.images.map(e => e.selected = !isAllSelected) + }, + + downloadImages() { + // 获取选中的图片 + const selectedImages = this.images.filter(e => e.selected); + // 创建 a 标签 + selectedImages.forEach(e => { + const a = document.createElement('a'); + // 设置 a 标签的 href 属性 + a.href = e.origin_url; + // 设置 a 标签的 download 属性 + a.download = e.name; + // 触发 a 标签的 click 事件 + a.click(); + }); + }, + openInputBox(type, node, data) { this.$prompt('', type == 'addFolder' ? '新建文件夹' : '重命名', { confirmButtonText: '确定', cancelButtonText: '取消', inputPattern: /^.+$/, closeOnClickModal: false, - inputValue: type == 'image' ? this.images[this.editingImageIndex].name : (type == 'renameFolder' ? data.name : '新建文件夹'), + inputValue: type == 'image' ? this.images[this.selectImageIndex].name : (type == 'renameFolder' ? data.name : '新建文件夹'), inputErrorMessage: '不能为空' }).then(({ value }) => { @@ -396,10 +463,7 @@ } } }, - // 在实例初始化之后,组件属性计算之前,如data属性等 - beforeCreate () { - }, - // 在实例创建完成后被立即同步调用 + created () { const defaultkeyarr = sessionStorage.getItem('defaultkeyarr'); @@ -407,22 +471,31 @@ // this.defaultkeyarr = defaultkeyarr.split(','); } }, - // 在挂载开始之前被调用:相关的 render 函数首次被调用 - beforeMount () { - }, // 实例被挂载后调用 mounted () { + // 获取键盘事件 是否按住 shift/ctrl 键 兼容 mac 和 windows + document.addEventListener('keydown', (e) => { + this.isShift = e.shiftKey; + this.isCtrl = e.ctrlKey || e.metaKey; + }) + + // 获取键盘事件 是否松开 shift/ctrl 键 + document.addEventListener('keyup', (e) => { + this.isShift = e.shiftKey; + this.isCtrl = e.ctrlKey || e.metaKey; + }) + + // 判断鼠标是否点击 .image-list 元素 + document.addEventListener('click', (e) => { + if (this.isBatchSelect) return; + const targets = ['filemanager-navbar', 'content-center'] + if (targets.indexOf(e.target.className) > -1) { + this.selectImageIndex = []; + this.images.map(e => e.selected = false) + } + }) }, }) - - $(document).ready(function() { - $(document).on('click', function (e) { - if ($(e.target).closest('.content-center .image-list, .content-head, .content-footer, .el-message-box').length === 0) { - app.editingImageIndex = null; - app.images.map(e => e.selected = false) - } - }) - }); diff --git a/resources/js/http.js b/resources/js/http.js index bbeb647a..f489b1d2 100644 --- a/resources/js/http.js +++ b/resources/js/http.js @@ -1,14 +1,16 @@ window.axios = require('axios'); +const token = document.querySelector('meta[name="csrf-token"]').content; +const base = document.querySelector('base').href; + const instance = axios.create({ - headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')}, + headers: {'X-CSRF-TOKEN': token}, }); axios.defaults.timeout = 5000; // 请求超时 // axios.defaults.baseURL = process.env.NODE_ENV == 'production' ? process.env.VUE_APP_BASE_URL + '/' : '/'; // console.log(process.env.VUE_APP_BASE_URL) -console.log($('base').attr('href')) -axios.defaults.baseURL = $('base').attr('href'); +axios.defaults.baseURL = base; export default { /** * get 请求