feat: 新增文件标签功能
This commit is contained in:
parent
a4065674de
commit
0f073e6c81
@ -52,6 +52,7 @@
|
||||
"v-viewer": "^1.5.1",
|
||||
"vditor": "3.9.3",
|
||||
"vue-aplayer": "^1.6.1",
|
||||
"vue-color": "^2.8.1",
|
||||
"vue-runtime-helpers": "^1.1.2",
|
||||
"vue-simple-uploader": "0.7.6",
|
||||
"vuedraggable": "^2.23.2",
|
||||
|
||||
1
public/resource/font_2024484_7ls286itnz9.js
Normal file
1
public/resource/font_2024484_7ls286itnz9.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -64,6 +64,18 @@ export default {
|
||||
})
|
||||
}
|
||||
},
|
||||
// 为文件分配标签
|
||||
setTags: function(params, data) {
|
||||
return request({
|
||||
url: 'setTag',
|
||||
method: 'post',
|
||||
data: data,
|
||||
params: params,
|
||||
paramsSerializer: function(params) {
|
||||
return qs.stringify(params, { arrayFormat: 'repeat' })
|
||||
}
|
||||
})
|
||||
},
|
||||
// 将文件设为公共文件
|
||||
setPublic: function(params) {
|
||||
return request({
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
import { Icon } from 'ant-design-vue'
|
||||
const IconFont = Icon.createFromIconfontCN({
|
||||
scriptUrl: document.location.protocol + '/resource/font_2024484_qwtkvngfp5d.js'
|
||||
scriptUrl: document.location.protocol + '/resource/font_2024484_7ls286itnz9.js'
|
||||
})
|
||||
|
||||
// 把此段代码贴到iconfont项目页面的控制台中, 以获取图标列表
|
||||
|
||||
@ -30,6 +30,18 @@
|
||||
<svg-icon v-if="grid" class="mobile grid icon-share" icon-class="share"/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="item.tags && item.tags.length > 0 && !public">
|
||||
<div v-if="pc">
|
||||
<svg-icon v-if="!grid" class="pc list icon-tag" icon-class="tag2"/>
|
||||
<span v-if="grid">
|
||||
<svg-icon class="pc grid icon-tag" icon-class="tag2" :style="{left: 14 * index -9 + 'px', color: tag.color}" v-for="(tag,index) in item.tags.slice(0, 7)" :key="index"/>
|
||||
</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<svg-icon v-if="!grid" class="mobile list icon-tag" icon-class="tag2"/>
|
||||
<svg-icon v-if="grid" class="mobile grid icon-tag" icon-class="tag2"/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="item.ossFolder && !public">
|
||||
<div v-if="pc">
|
||||
<el-tag v-if="!grid" size="small" class="pc list oss-folder">{{ item.ossPlatform }}</el-tag>
|
||||
@ -235,6 +247,34 @@ export default {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.icon-tag {
|
||||
color: #52c41a;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.pc.grid.icon-tag {
|
||||
font-size: 14px;
|
||||
left: 0;
|
||||
bottom: -18px;
|
||||
}
|
||||
|
||||
.mobile.grid.icon-tag {
|
||||
width: 1.3rem;
|
||||
height: 1.3rem;
|
||||
margin-left: 2.8rem;
|
||||
}
|
||||
|
||||
.pc.list.icon-tag {
|
||||
font-size: 1rem;
|
||||
right: 1.3rem;
|
||||
}
|
||||
|
||||
.mobile.list.icon-tag {
|
||||
font-size: 0.5rem;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.oss-folder {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
@ -807,7 +807,8 @@
|
||||
>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<tag-dialog :fileList.sync="tagDialogObjectList"
|
||||
:status.sync="tagDialogVisible" @onSuccess="allocateTagSuccess"/>
|
||||
<share-dialog
|
||||
:file.sync="shareDialogObject"
|
||||
:status.sync="shareDialogVisible"
|
||||
@ -872,10 +873,12 @@ import OfficePreview from "@/components/preview/OfficePreview";
|
||||
import ShareDialog from "@/components/ShareDialog/index.vue";
|
||||
import {getUsername} from "@/api/user";
|
||||
import Clipboard from "clipboard";
|
||||
import TagDialog from "@/components/TagDialog/index.vue";
|
||||
|
||||
export default {
|
||||
name: "ShowFile",
|
||||
components: {
|
||||
TagDialog,
|
||||
ShareDialog,
|
||||
OfficePreview,
|
||||
EditElement,
|
||||
@ -962,12 +965,9 @@ export default {
|
||||
return [
|
||||
{ iconClass: "menu-open", label: "打开", operation: "open" },
|
||||
{ iconClass: "share", label: "分享", operation: "share" },
|
||||
{ iconClass: "tag", label: "标签", operation: "tag" },
|
||||
{ iconClass: "menu-favorite", label: "收藏", operation: "favorite" },
|
||||
{
|
||||
iconClass: "menu-details",
|
||||
label: "详细信息",
|
||||
operation: "details"
|
||||
},
|
||||
{ iconClass: "menu-details", label: "详细信息", operation: "details" },
|
||||
{ iconClass: "menu-rename", label: "重命名", operation: "rename" },
|
||||
{ iconClass: "menu-copy", label: "移动或复制", operation: "copy" },
|
||||
{ iconClass: "menu-download", label: "下载", operation: "download" },
|
||||
@ -994,6 +994,7 @@ export default {
|
||||
label: "取消选定",
|
||||
operation: "deselect"
|
||||
},
|
||||
{ iconClass: "tag", label: "标签", operation: "tag" },
|
||||
{ iconClass: "menu-copy", label: "移动或复制", operation: "copy" },
|
||||
{ iconClass: "menu-download", label: "下载", operation: "download" },
|
||||
{ iconClass: "menu-remove", label: "删除", operation: "remove" }
|
||||
@ -1114,6 +1115,8 @@ export default {
|
||||
summaries: "",
|
||||
shareDialogVisible: false,
|
||||
shareDialogObject: {},
|
||||
tagDialogVisible: false,
|
||||
tagDialogObjectList: [],
|
||||
newCreateFileDialog: false,
|
||||
newCreateFileName: "",
|
||||
newCreateFileDialogTitle: "",
|
||||
@ -2673,8 +2676,7 @@ export default {
|
||||
item1["searchKey"] = key;
|
||||
this.pathList.push(item1);
|
||||
this.$router.push(`?vmode=${this.vmode}&search-file=${key}`);
|
||||
api
|
||||
.searchFile({
|
||||
api.searchFile({
|
||||
userId: this.$store.state.user.userId,
|
||||
username: this.$store.state.user.name,
|
||||
keyword: key,
|
||||
@ -3418,9 +3420,13 @@ export default {
|
||||
menusOperations(operation) {
|
||||
switch (operation) {
|
||||
case "share":
|
||||
// 分享
|
||||
// 分配标签
|
||||
this.share();
|
||||
break;
|
||||
case "tag":
|
||||
// 分配标签
|
||||
this.allocateTag();
|
||||
break;
|
||||
case "favorite":
|
||||
// 收藏
|
||||
this.favoriteOperating(true);
|
||||
@ -3733,6 +3739,13 @@ export default {
|
||||
);
|
||||
}
|
||||
},
|
||||
allocateTag() {
|
||||
this.tagDialogObjectList = this.$refs.fileListTable.tableSelectData;
|
||||
this.tagDialogVisible = true
|
||||
},
|
||||
allocateTagSuccess() {
|
||||
this.getFileList();
|
||||
},
|
||||
share(row) {
|
||||
if (!row || !row.id) {
|
||||
if (this.rowContextData.id) {
|
||||
|
||||
199
src/components/TagDialog/index.vue
Normal file
199
src/components/TagDialog/index.vue
Normal file
@ -0,0 +1,199 @@
|
||||
<template>
|
||||
<di>
|
||||
<el-dialog :title='"将标签分配给 \"" + showName + "\""' style="{'font-weight': 600}" :visible.sync="tagDialogVisible" @close="tagDialogClose">
|
||||
<div class="tag-content">
|
||||
<el-tag
|
||||
:key="tag.name"
|
||||
v-for="tag in tags"
|
||||
closable
|
||||
:disable-transitions="false"
|
||||
@close="handleClose(tag.id)">
|
||||
|
||||
<el-popover
|
||||
placement="bottom"
|
||||
trigger="hover">
|
||||
<sketch-picker
|
||||
v-model="colors"
|
||||
@input="updateColor($event, tag)"
|
||||
/>
|
||||
<el-button slot="reference" size="small" class="button-tab-icon"><svg-icon :style="{ color: tag.color, fontSize: '14px' }" icon-class="tag2"></svg-icon></el-button>
|
||||
</el-popover>
|
||||
|
||||
{{tag.name}}
|
||||
</el-tag>
|
||||
|
||||
<el-input
|
||||
class="input-new-tag"
|
||||
v-if="inputVisible"
|
||||
v-model="inputValue"
|
||||
ref="saveTagInput"
|
||||
size="small"
|
||||
@keyup.enter.native="handleInputConfirm"
|
||||
@blur="handleInputConfirm"
|
||||
>
|
||||
</el-input>
|
||||
<el-button v-else class="button-new-tag" size="small" @click="showInput">+ 新标签</el-button>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button size="small" type="primary" @click="submitTag" v-loading="saveLoading">保存
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</di>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import api from '@/api/file-api'
|
||||
import { Sketch } from 'vue-color'
|
||||
|
||||
export default {
|
||||
name: "TagDialog",
|
||||
components: {
|
||||
'sketch-picker': Sketch
|
||||
},
|
||||
props: {
|
||||
fileList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
status: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tagDialogVisible: false,
|
||||
showName: '',
|
||||
inputVisible: false,
|
||||
inputValue: '',
|
||||
tags: [],
|
||||
defaultTagColor: '#f56c6c',
|
||||
saveLoading: false,
|
||||
colors: {
|
||||
hex: '#f56c6c',
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
status(visible) {
|
||||
if (visible) {
|
||||
if (this.fileList.length === 0) {
|
||||
return
|
||||
}
|
||||
// this.fileList里是有tags为undefined的情况,有则设置noTags为true
|
||||
let noTags = false
|
||||
this.fileList.forEach(file => {
|
||||
if (!file.tags) {
|
||||
noTags = true
|
||||
}
|
||||
})
|
||||
if (noTags) {
|
||||
this.tags = []
|
||||
} else {
|
||||
// 提取出fileList中每个file里相同的tags
|
||||
this.tags = this.fileList.map(item => item.tags).reduce((prev, next) => {
|
||||
return prev.filter(item => {
|
||||
return next.some(nextItem => nextItem.name === item.name)
|
||||
})
|
||||
})
|
||||
}
|
||||
this.showName = this.fileList.length + '项目'
|
||||
this.tagDialogVisible = true
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClose(tag) {
|
||||
this.tags.splice(this.tags.indexOf(tag), 1);
|
||||
},
|
||||
showInput() {
|
||||
this.inputVisible = true;
|
||||
this.$nextTick(_ => {
|
||||
this.$refs.saveTagInput.$refs.input.focus();
|
||||
});
|
||||
},
|
||||
handleInputConfirm() {
|
||||
let inputValue = this.inputValue;
|
||||
if (inputValue) {
|
||||
// 是否有相同的标签
|
||||
let hasSameTag = this.tags.some(tag => tag.name === inputValue);
|
||||
if (hasSameTag) {
|
||||
this.$message.error('标签已存在');
|
||||
return;
|
||||
}
|
||||
this.tags.push({ name: inputValue, color: this.defaultTagColor});
|
||||
}
|
||||
this.inputVisible = false;
|
||||
this.inputValue = '';
|
||||
},
|
||||
tagDialogClose() {
|
||||
this.$emit('update:status', this.tagDialogVisible)
|
||||
},
|
||||
submitTag() {
|
||||
this.saveLoading = true
|
||||
// 提取出文件id
|
||||
const fileIdList = this.fileList.map(item => item.id)
|
||||
api.setTags({fileIds: fileIdList}, this.tags).then(() => {
|
||||
this.saveLoading = false
|
||||
this.$message.success('保存成功');
|
||||
this.$emit('onSuccess')
|
||||
this.tagDialogVisible = false
|
||||
this.tagDialogClose()
|
||||
}).catch(() => {
|
||||
this.saveLoading = false
|
||||
})
|
||||
},
|
||||
updateColor(color, tag) {
|
||||
// 更新tags
|
||||
this.tags.forEach(item => {
|
||||
if (item.name === tag.name) {
|
||||
item.color = color.hex
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
> > > .el-dialog {
|
||||
max-width: 500px;
|
||||
|
||||
.el-dialog__title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.el-tag {
|
||||
margin-left: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.button-new-tag {
|
||||
margin-top: 10px;
|
||||
margin-left: 10px;
|
||||
height: 32px;
|
||||
line-height: 30px;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.input-new-tag {
|
||||
margin-top: 10px;
|
||||
width: 90px;
|
||||
margin-left: 10px;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
.button-tab-icon {
|
||||
padding: 2px 3px 2px 3px;
|
||||
border: 0;
|
||||
background: #00000000;
|
||||
}
|
||||
|
||||
.el-loading-spinner .circular {
|
||||
width: 25px !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
</style>
|
||||
Loading…
x
Reference in New Issue
Block a user