|
@@ -0,0 +1,192 @@
|
|
|
+<template>
|
|
|
+ <div>
|
|
|
+ <el-popover
|
|
|
+ :visible="state.show"
|
|
|
+ placement="bottom"
|
|
|
+ trigger="click"
|
|
|
+ :popper-style="{
|
|
|
+ padding: 0,
|
|
|
+ minWidth: 0,
|
|
|
+ width: popoverWidth ? `${popoverWidth}px` : 'fit-content'
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <template #reference>
|
|
|
+ <div @click="state.show = !state.show" class="flex items-center text-[0.88rem] text-[#98a2b2] rounded py-[0.3rem] px-[0.5rem] cursor-pointer hover:bg-[#c8ceda33]" :class="{
|
|
|
+ 'bg-[#c8ceda33]': state.show
|
|
|
+ }">
|
|
|
+ <SvgIcon name="tag" size="14" class="mr-1"/>
|
|
|
+ <span class="__text-ellipsis max-w-[5rem]" v-title>{{value ? value.split(',').map(v => DictionaryStore.knowledgeTags.map.get(v) || v).join(',') : '添加标签'}}</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <div class="w-[15rem] max-h-[20rem] bg-[#c8ceda24]" :select-popover="true">
|
|
|
+ <div class="p-[0.5rem] border-b-[1px] border-[var(--czr-border-color)]">
|
|
|
+ <CzrFormColumn
|
|
|
+ class="__czr-table-form-column"
|
|
|
+ :span="24"
|
|
|
+ :label-width="0"
|
|
|
+ v-model:param="state.text"
|
|
|
+ placeholder="搜索或者创建"
|
|
|
+ :prefix-icon="Search"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="p-[0.3rem]">
|
|
|
+ <template v-if="state.text && !DictionaryStore.knowledgeTags.list.some(v => v.name.includes(state.text))">
|
|
|
+ <div class="__hover-bg p-[0.5rem] flex items-center text-[0.88rem] text-[#354052] rounded" @click="onAdd">
|
|
|
+ <SvgIcon name="czr_add" size="10" class="mr-2"/>
|
|
|
+ 创建“{{state.text}}”
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <template v-if="DictionaryStore.knowledgeTags.list.length > 0">
|
|
|
+ <div class="max-h-[200px] overflow-y-auto">
|
|
|
+ <template v-for="item in DictionaryStore.knowledgeTags.list">
|
|
|
+ <div class="__hover-bg p-[0.5rem] flex items-center text-[0.88rem] text-[#354052] rounded" @click="state.valueMap.has(item.id) ? state.valueMap.delete(item.id) : state.valueMap.set(item.id, item.id)">
|
|
|
+ <div class="__check scale-[75%] mr-1" :class="{active: state.valueMap.has(item.id)}"/>
|
|
|
+ <span class="__text-ellipsis flex-1" v-title>{{item.name}}</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <div class="flex flex flex-col justify-center items-center text-[0.75rem] text-[#676f83] py-5">
|
|
|
+ <SvgIcon name="tag" size="24" class="mb-1"/>
|
|
|
+ 没有标签
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ <div class="p-[0.3rem] border-t-[1px] border-[var(--czr-border-color)]">
|
|
|
+ <div class="__hover-bg p-[0.5rem] flex items-center text-[0.88rem] text-[#354052] rounded" @click="state.show = false, state.showDialog = true">
|
|
|
+ <SvgIcon name="tag" size="14" class="mr-1"/> 管理标签
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-popover>
|
|
|
+ </div>
|
|
|
+ <CzrDialog
|
|
|
+ :show="state.showDialog"
|
|
|
+ title="管理标签"
|
|
|
+ @onClose="state.showDialog = false"
|
|
|
+ width="40rem"
|
|
|
+ height="auto"
|
|
|
+ maxHeight="80%"
|
|
|
+ :loading="state.loading"
|
|
|
+ :show-submit="false"
|
|
|
+ :show-close="false"
|
|
|
+ >
|
|
|
+ <div class="flex flex flex-wrap gap-2 bg-[#ffffff] p-[1rem] rounded">
|
|
|
+ <template v-for="item in DictionaryStore.knowledgeTags.list">
|
|
|
+ <template v-if="item.__edit">
|
|
|
+ <div class="w-[17rem] border border-[var(--czr-border-color)] rounded">
|
|
|
+ <CzrFormColumn
|
|
|
+ :label-width="0"
|
|
|
+ :span="24"
|
|
|
+ v-model:param="item.__value"
|
|
|
+ :transparent="true"
|
|
|
+ :clearable="false"
|
|
|
+ @blur="onEdit(item)"
|
|
|
+ @keyup.enter.stop="onEdit(item)"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <div class="max-w-[17rem] border border-[var(--czr-border-color)] px-[0.5rem] h-[2.25rem] rounded flex items-center gap-2">
|
|
|
+ <span class="__text-ellipsis" v-title>
|
|
|
+ {{item.name}}
|
|
|
+ </span>
|
|
|
+ <span class="opacity-75">{{item.total}}</span>
|
|
|
+ <SvgIcon name="czr_edit" size="12" class="__hover" @click="item.__value = item.name + '', item.__edit = true"/>
|
|
|
+ <SvgIcon name="czr_del" size="14" class="__hover" @click="onDel(item)"/>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </CzrDialog>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import {computed, getCurrentInstance, onBeforeMount, reactive, ref, watch} from "vue";
|
|
|
+import {domRootHasAttr} from "@/utils/czr-util";
|
|
|
+import {useDialogStore, useDictionaryStore} from "@/stores";
|
|
|
+import {Search} from "@element-plus/icons-vue";
|
|
|
+import {ElMessage} from "element-plus";
|
|
|
+
|
|
|
+const DictionaryStore = useDictionaryStore()
|
|
|
+const DialogStore = useDialogStore()
|
|
|
+const emits = defineEmits(['onChange'])
|
|
|
+const props = defineProps({
|
|
|
+ options: {default: <any>[]},
|
|
|
+ value: {default: ''},
|
|
|
+ popoverWidth: {default: 0},
|
|
|
+})
|
|
|
+const {proxy}: any = getCurrentInstance()
|
|
|
+const state: any = reactive({
|
|
|
+ show: false,
|
|
|
+ text: '',
|
|
|
+ valueMap: new Map(),
|
|
|
+ showDialog: false,
|
|
|
+})
|
|
|
+const onAdd = () => {
|
|
|
+ state.text = ''
|
|
|
+ ElMessage.success('创建标签成功!')
|
|
|
+ DictionaryStore.initKnowledgeTags()
|
|
|
+}
|
|
|
+const onDel = (row) => {
|
|
|
+ const delHandle = () => {
|
|
|
+ ElMessage.success('删除标签成功!')
|
|
|
+ DictionaryStore.initKnowledgeTags()
|
|
|
+ }
|
|
|
+ if (row.total > 0) {
|
|
|
+ DialogStore.confirm({
|
|
|
+ title: `删除标签“${row.name}”`,
|
|
|
+ content: `标签正在使用中,是否删除?`,
|
|
|
+ onSubmit: () => {
|
|
|
+ delHandle()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ delHandle()
|
|
|
+ }
|
|
|
+}
|
|
|
+const onEdit = (row) => {
|
|
|
+ if (!row.__value) {
|
|
|
+ row.__edit = false
|
|
|
+ } else {
|
|
|
+ ElMessage.success('修改标签成功!')
|
|
|
+ DictionaryStore.initKnowledgeTags()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const onMouseDown = (e) => {
|
|
|
+ if (!domRootHasAttr(e.target, 'select-popover')) {
|
|
|
+ state.show = false
|
|
|
+ }
|
|
|
+}
|
|
|
+watch(() => state.show, (n) => {
|
|
|
+ if (n) {
|
|
|
+ state.text = ''
|
|
|
+ document.addEventListener('mousedown', onMouseDown)
|
|
|
+ } else {
|
|
|
+ document.removeEventListener('mousedown', onMouseDown)
|
|
|
+ emits('onChange', Array.from(state.valueMap.keys()).join(','))
|
|
|
+ }
|
|
|
+}, {immediate: true})
|
|
|
+watch(() => props.value, (n) => {
|
|
|
+ const map = new Map()
|
|
|
+ if (n) {
|
|
|
+ n.split(',').forEach(v => {
|
|
|
+ map.set(v, v)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ state.valueMap = map
|
|
|
+}, {immediate: true})
|
|
|
+onBeforeMount(() => {
|
|
|
+ DictionaryStore.initKnowledgeTags()
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+:deep(.el-input__wrapper) {
|
|
|
+ background-color: rgba(200, 206, 218, 0.25);
|
|
|
+}
|
|
|
+</style>
|