|
|
@@ -8,16 +8,11 @@
|
|
|
@closed="onClosed"
|
|
|
>
|
|
|
<div class="asset-picker">
|
|
|
- <!-- 上传区 -->
|
|
|
- <div
|
|
|
- class="ap-upload-row"
|
|
|
- :class="{ 'is-dragover': dragOver }"
|
|
|
- @dragover.prevent="onDragOver"
|
|
|
- @dragleave="onDragLeave"
|
|
|
- @drop.prevent="onDrop"
|
|
|
- >
|
|
|
+ <!-- 上传区:整块可点击 / 可拖拽 -->
|
|
|
+ <div class="ap-upload-row">
|
|
|
<el-upload
|
|
|
- class="ap-upload-trigger"
|
|
|
+ class="ap-upload-drop"
|
|
|
+ drag
|
|
|
action=""
|
|
|
:http-request="handleUploadRequest"
|
|
|
:show-file-list="false"
|
|
|
@@ -25,32 +20,35 @@
|
|
|
:before-upload="beforeUpload"
|
|
|
:disabled="uploading"
|
|
|
>
|
|
|
- <el-button type="primary" size="small" :loading="uploading" icon="el-icon-upload2">
|
|
|
- 上传到素材库
|
|
|
- </el-button>
|
|
|
+ <div class="ap-drop-inner" v-loading="uploading">
|
|
|
+ <i class="el-icon-upload"></i>
|
|
|
+ <div class="ap-drop-text">点击或拖拽文件到此处,上传到素材库</div>
|
|
|
+ </div>
|
|
|
</el-upload>
|
|
|
- <el-select
|
|
|
- v-model="uploadTags"
|
|
|
- multiple
|
|
|
- collapse-tags
|
|
|
- filterable
|
|
|
- size="small"
|
|
|
- placeholder="上传后自动打标签"
|
|
|
- class="ap-upload-tags"
|
|
|
- >
|
|
|
- <el-option v-for="t in tags" :key="t.id" :label="t.name" :value="t.id">
|
|
|
- <span :style="{ color: t.color }">{{ t.name }}</span>
|
|
|
- </el-option>
|
|
|
- </el-select>
|
|
|
- <span class="ap-upload-hint">
|
|
|
- 分类:<el-tag size="mini" type="info">{{ uploadCategory }}</el-tag>
|
|
|
- <template v-if="uploadTags.length > 0">
|
|
|
- <span v-for="id in uploadTags" :key="id">
|
|
|
- <el-tag size="mini" :style="{ color: colorOf(id), borderColor: colorOf(id) }">{{ nameOf(id) }}</el-tag>
|
|
|
- </span>
|
|
|
- </template>
|
|
|
- <span class="ap-drop-hint">{{ dragOver ? '松开即上传' : '点击或拖拽文件到此处' }}</span>
|
|
|
- </span>
|
|
|
+ <div class="ap-upload-side">
|
|
|
+ <el-select
|
|
|
+ v-model="uploadTags"
|
|
|
+ multiple
|
|
|
+ collapse-tags
|
|
|
+ filterable
|
|
|
+ size="small"
|
|
|
+ placeholder="上传后自动打标签(留空则按分类自动打)"
|
|
|
+ class="ap-upload-tags"
|
|
|
+ >
|
|
|
+ <el-option v-for="t in tags" :key="t.id" :label="t.name" :value="t.id">
|
|
|
+ <span :style="{ color: t.color }">{{ t.name }}</span>
|
|
|
+ </el-option>
|
|
|
+ </el-select>
|
|
|
+ <div class="ap-upload-hint">
|
|
|
+ 入库分类:<el-tag size="mini" type="info">{{ uploadCategoryLabel }}</el-tag>
|
|
|
+ <el-tag
|
|
|
+ v-for="id in uploadTags"
|
|
|
+ :key="id"
|
|
|
+ size="mini"
|
|
|
+ :style="{ color: colorOf(id), borderColor: colorOf(id) }"
|
|
|
+ >{{ nameOf(id) }}</el-tag>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 筛选区 -->
|
|
|
@@ -61,6 +59,22 @@
|
|
|
<el-radio-button label="video" v-if="showVideoFilter">视频</el-radio-button>
|
|
|
<el-radio-button label="document">文档</el-radio-button>
|
|
|
</el-radio-group>
|
|
|
+ <el-select
|
|
|
+ v-model="categoryFilter"
|
|
|
+ size="small"
|
|
|
+ clearable
|
|
|
+ placeholder="全部分类"
|
|
|
+ class="ap-category"
|
|
|
+ @change="onCategoryChange"
|
|
|
+ >
|
|
|
+ <el-option label="全部分类" value="" />
|
|
|
+ <el-option
|
|
|
+ v-for="c in categoryOptions"
|
|
|
+ :key="c.value"
|
|
|
+ :label="c.label + '(' + c.count + ')'"
|
|
|
+ :value="c.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
<el-input
|
|
|
v-model="keyword"
|
|
|
size="small"
|
|
|
@@ -79,15 +93,22 @@
|
|
|
<!-- 标签筛选 -->
|
|
|
<div v-if="tags.length > 0" class="ap-tag-row">
|
|
|
<span class="ap-tag-label">标签:</span>
|
|
|
- <el-check-tag
|
|
|
+ <el-tag
|
|
|
v-for="t in tags"
|
|
|
:key="t.id"
|
|
|
- :checked="selectedTagIds.indexOf(t.id) !== -1"
|
|
|
- @change="onTagFilterToggle(t.id)"
|
|
|
+ size="small"
|
|
|
class="ap-tag-chip"
|
|
|
- >
|
|
|
- <span :style="{ color: t.color }">{{ t.name }}</span>
|
|
|
- </el-check-tag>
|
|
|
+ :effect="isTagActive(t.id) ? 'dark' : 'plain'"
|
|
|
+ :style="tagChipStyle(t)"
|
|
|
+ @click="onTagFilterToggle(t.id)"
|
|
|
+ >{{ t.name }}</el-tag>
|
|
|
+ <el-tag
|
|
|
+ v-if="selectedTagIds.length > 0"
|
|
|
+ size="small"
|
|
|
+ type="info"
|
|
|
+ class="ap-tag-clear"
|
|
|
+ @click="clearTagFilter"
|
|
|
+ >清除标签筛选</el-tag>
|
|
|
</div>
|
|
|
|
|
|
<!-- 网格 -->
|
|
|
@@ -159,7 +180,23 @@
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import { listLibrary, uploadToLibrary, getTags, resolveAssetUrl } from '@/utils/asset'
|
|
|
+import { listLibrary, uploadToLibrary, getTags, getLibraryStats, resolveAssetUrl } from '@/utils/asset'
|
|
|
+
|
|
|
+/** 素材分类 → 中文展示名(标签也按这个规则自动生成) */
|
|
|
+const CATEGORY_LABELS = {
|
|
|
+ general: '通用素材',
|
|
|
+ products: '商品图片',
|
|
|
+ 'product-skus': '商品SKU图',
|
|
|
+ articles: '文章配图',
|
|
|
+ 'articles-audio': '文章音频',
|
|
|
+ activities: '活动图片',
|
|
|
+ banners: '轮播图',
|
|
|
+ 'guide-packages': '攻略包',
|
|
|
+ 'kb-docs': '知识库文档',
|
|
|
+ 'kb-images': '知识库图片',
|
|
|
+ 'health-reports': '健康报告',
|
|
|
+ uploads: '其它上传'
|
|
|
+}
|
|
|
|
|
|
export default {
|
|
|
name: 'AssetPicker',
|
|
|
@@ -190,10 +227,11 @@ export default {
|
|
|
total: 0,
|
|
|
keyword: '',
|
|
|
typeFilter: this.initTypeFilter(),
|
|
|
+ categoryFilter: '',
|
|
|
+ categories: [],
|
|
|
selectedTagIds: [],
|
|
|
uploadTags: [],
|
|
|
- selectedRecords: [],
|
|
|
- dragOver: false
|
|
|
+ selectedRecords: []
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
@@ -211,6 +249,14 @@ export default {
|
|
|
uploadCategory() {
|
|
|
return this.category || 'general'
|
|
|
},
|
|
|
+ uploadCategoryLabel() {
|
|
|
+ const key = this.uploadCategory
|
|
|
+ const hit = this.categories.find(function (c) { return c.value === key })
|
|
|
+ return (hit && hit.label) || CATEGORY_LABELS[key] || key
|
|
|
+ },
|
|
|
+ categoryOptions() {
|
|
|
+ return this.categories
|
|
|
+ },
|
|
|
uploadAccept() {
|
|
|
if (this.assetType === 'image') return 'image/*'
|
|
|
if (this.assetType === 'video') return 'video/*'
|
|
|
@@ -243,11 +289,26 @@ export default {
|
|
|
this.page = 1
|
|
|
this.keyword = ''
|
|
|
this.typeFilter = this.initTypeFilter()
|
|
|
+ this.categoryFilter = ''
|
|
|
this.selectedTagIds = this.defaultTagIds.slice()
|
|
|
this.uploadTags = this.defaultTagIds.slice()
|
|
|
this.selectedRecords = (this.value || []).map(function (r) { return Object.assign({}, r) })
|
|
|
+ this.loadCategories()
|
|
|
this.loadTags().then(this.loadData)
|
|
|
},
|
|
|
+ /** 分类筛选项:来自素材库统计,避免把页面 category 当硬过滤条件导致空列表 */
|
|
|
+ loadCategories() {
|
|
|
+ return getLibraryStats().then(function (res) {
|
|
|
+ if (res.code === 200 && res.data && Array.isArray(res.data.byCategory)) {
|
|
|
+ this.categories = res.data.byCategory
|
|
|
+ .filter(function (c) { return c.category })
|
|
|
+ .map(function (c) {
|
|
|
+ return { value: c.category, label: CATEGORY_LABELS[c.category] || c.category, count: Number(c.cnt) || 0 }
|
|
|
+ })
|
|
|
+ .sort(function (a, b) { return b.count - a.count })
|
|
|
+ }
|
|
|
+ }.bind(this)).catch(function () {})
|
|
|
+ },
|
|
|
loadTags() {
|
|
|
return getTags().then(function (res) {
|
|
|
if (res.code === 200 && Array.isArray(res.data)) {
|
|
|
@@ -261,7 +322,7 @@ export default {
|
|
|
page: this.page,
|
|
|
pageSize: this.pageSize,
|
|
|
fileType: this.typeFilter || '',
|
|
|
- category: this.category || '',
|
|
|
+ category: this.categoryFilter || '',
|
|
|
search: this.keyword || '',
|
|
|
tagIds: this.selectedTagIds.length > 0 ? this.selectedTagIds : []
|
|
|
}).then(function (res) {
|
|
|
@@ -277,6 +338,24 @@ export default {
|
|
|
this.page = 1
|
|
|
this.loadData()
|
|
|
},
|
|
|
+ onCategoryChange() {
|
|
|
+ this.page = 1
|
|
|
+ this.loadData()
|
|
|
+ },
|
|
|
+ isTagActive(tagId) {
|
|
|
+ return this.selectedTagIds.indexOf(tagId) !== -1
|
|
|
+ },
|
|
|
+ tagChipStyle(t) {
|
|
|
+ const color = (t && t.color) || '#409EFF'
|
|
|
+ return this.isTagActive(t.id)
|
|
|
+ ? { backgroundColor: color, borderColor: color, color: '#fff', cursor: 'pointer' }
|
|
|
+ : { color: color, borderColor: color, cursor: 'pointer' }
|
|
|
+ },
|
|
|
+ clearTagFilter() {
|
|
|
+ this.selectedTagIds = []
|
|
|
+ this.page = 1
|
|
|
+ this.loadData()
|
|
|
+ },
|
|
|
onSearch() {
|
|
|
this.page = 1
|
|
|
this.loadData()
|
|
|
@@ -326,24 +405,6 @@ export default {
|
|
|
if (!file) return
|
|
|
await this.uploadAndSelect(file)
|
|
|
},
|
|
|
- onDragOver(e) {
|
|
|
- this.dragOver = true
|
|
|
- if (e && e.dataTransfer && e.dataTransfer.effectAllowed !== 'none') {
|
|
|
- e.dataTransfer.dropEffect = 'copy'
|
|
|
- }
|
|
|
- },
|
|
|
- onDragLeave() {
|
|
|
- this.dragOver = false
|
|
|
- },
|
|
|
- async onDrop(e) {
|
|
|
- this.dragOver = false
|
|
|
- const transfer = e && e.dataTransfer
|
|
|
- const files = transfer && (transfer.files || transfer.items)
|
|
|
- if (!files || files.length === 0) return
|
|
|
- const file = Array.isArray(files) ? files[0] : files[0]
|
|
|
- if (!file || !file.name) return
|
|
|
- await this.uploadAndSelect(file)
|
|
|
- },
|
|
|
async uploadAndSelect(file) {
|
|
|
if (!file) return
|
|
|
this.uploading = true
|
|
|
@@ -429,27 +490,48 @@ export default {
|
|
|
}
|
|
|
.ap-upload-row {
|
|
|
display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 10px;
|
|
|
+ align-items: stretch;
|
|
|
+ gap: 12px;
|
|
|
margin-bottom: 12px;
|
|
|
- padding: 8px;
|
|
|
- border: 1px dashed #dcdfe6;
|
|
|
- border-radius: 4px;
|
|
|
- transition: border-color 0.2s, background-color 0.2s;
|
|
|
}
|
|
|
-.ap-upload-row.is-dragover {
|
|
|
- border-color: #409EFF;
|
|
|
- background-color: #ecf5ff;
|
|
|
+.ap-upload-drop {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
}
|
|
|
-.ap-drop-hint {
|
|
|
- font-size: 12px;
|
|
|
+.ap-upload-drop ::v-deep .el-upload {
|
|
|
+ display: block;
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+.ap-upload-drop ::v-deep .el-upload-dragger {
|
|
|
+ width: 100%;
|
|
|
+ height: auto;
|
|
|
+ padding: 12px;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+.ap-drop-inner {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ gap: 4px;
|
|
|
+ color: #606266;
|
|
|
+}
|
|
|
+.ap-drop-inner i {
|
|
|
+ font-size: 26px;
|
|
|
color: #c0c4cc;
|
|
|
}
|
|
|
-.ap-upload-trigger {
|
|
|
- display: inline-block;
|
|
|
+.ap-drop-text {
|
|
|
+ font-size: 13px;
|
|
|
+}
|
|
|
+.ap-upload-side {
|
|
|
+ width: 260px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
+ gap: 8px;
|
|
|
}
|
|
|
.ap-upload-tags {
|
|
|
- width: 220px;
|
|
|
+ width: 100%;
|
|
|
}
|
|
|
.ap-upload-hint {
|
|
|
font-size: 12px;
|
|
|
@@ -459,6 +541,12 @@ export default {
|
|
|
gap: 6px;
|
|
|
flex-wrap: wrap;
|
|
|
}
|
|
|
+.ap-category {
|
|
|
+ width: 160px;
|
|
|
+}
|
|
|
+.ap-tag-clear {
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
.ap-filter-row {
|
|
|
display: flex;
|
|
|
align-items: center;
|