feat: 新增文件标签功能

This commit is contained in:
jmal 2024-03-15 14:42:03 +08:00
parent a4065674de
commit 0f073e6c81
8 changed files with 276 additions and 11 deletions

View File

@ -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",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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({

View File

@ -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项目页面的控制台中, 以获取图标列表

View File

@ -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;
}

View File

@ -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) {

View 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>