提交 | 用户 | age
|
63d608
|
1 |
<template> |
H |
2 |
<div class="p-2"> |
|
3 |
<vxe-toolbar> |
|
4 |
<template #buttons> |
|
5 |
<div style="display: flex; align-items: flex-end"> |
|
6 |
<span style="font-size: 1.25rem; font-weight: 600">我的标签</span |
|
7 |
><span style="margin-left: 5px; padding-bottom: 4px; font-size: 12px" |
|
8 |
>管理您的所有个人标签</span |
|
9 |
> |
|
10 |
</div> |
|
11 |
</template> |
|
12 |
<template #tools> |
a9a03d
|
13 |
<a-button type="primary" @click="showModal('add','')">新建个人标签</a-button> |
63d608
|
14 |
</template> |
H |
15 |
</vxe-toolbar> |
|
16 |
|
|
17 |
<vxe-table |
|
18 |
ref="xTable" |
|
19 |
style="margin: 10px 0" |
|
20 |
:data="demo.tableData" |
|
21 |
@mounted="onMounted" |
|
22 |
height="600" |
|
23 |
> |
|
24 |
<vxe-column width="40"> |
|
25 |
<template #default> |
|
26 |
<span class="drag-btn"> |
|
27 |
<HolderOutlined /> |
|
28 |
</span> |
|
29 |
</template> |
|
30 |
</vxe-column> |
|
31 |
<vxe-column field="TagName" title="文件夹名称" minWidth="250"> |
|
32 |
<template #default="{ row }"> |
|
33 |
<span class="my-d-f"> |
|
34 |
<div |
|
35 |
v-if="row.systemFlag" |
|
36 |
class="bookmark" |
|
37 |
:style="{ backgroundColor: row.tagColor }" |
|
38 |
></div> |
|
39 |
<div v-else> |
|
40 |
<ColorPicker |
|
41 |
v-model="row.tagColor" |
|
42 |
:type="2" |
|
43 |
@change="fnRowColorChange($event, row)" |
|
44 |
></ColorPicker> |
|
45 |
</div> |
|
46 |
<a-tag class="ml-5" :color="row.tagColor">{{ row.tagName }}</a-tag> |
|
47 |
</span> |
|
48 |
</template> |
|
49 |
</vxe-column> |
|
50 |
<vxe-column field="age" title="操作" width="150"> |
|
51 |
<template #default="{ row }"> |
|
52 |
<a style="margin-right: 10px" @click="showModal('edit', row)">编辑</a> |
|
53 |
<a style="margin-right: 10px" @click="fnDeleteRow(row)">删除</a> |
|
54 |
</template> |
|
55 |
</vxe-column> |
|
56 |
</vxe-table> |
|
57 |
<a-modal :width="300" v-model:open="open" :title="`${title}个人标签`" @ok="handleOk"> |
|
58 |
<a-form ref="formRef" :model="form" style="margin-top: 20px"> |
|
59 |
<a-form-item label="标签颜色" name="tagColor"> |
|
60 |
<ColorPicker v-model="form.tagColor" :type="2"></ColorPicker> |
|
61 |
</a-form-item> |
|
62 |
<a-form-item |
|
63 |
label="标签名称" |
|
64 |
name="tagName" |
|
65 |
:rules="[{ required: true, message: '请输入标签名称', trigger: 'blur' }]" |
|
66 |
> |
|
67 |
<a-input v-model:value="form.tagName" placeholder="请输入标签名称" /> |
|
68 |
</a-form-item> |
|
69 |
</a-form> |
|
70 |
</a-modal> |
|
71 |
</div> |
|
72 |
</template> |
|
73 |
|
|
74 |
<script lang="ts" setup> |
|
75 |
import { ref, computed, onMounted, nextTick, onUnmounted, reactive } from 'vue'; |
|
76 |
import ColorPicker from '@/components/ColorPicker/index.vue'; |
|
77 |
import { addTagApi, deleteTagApi, updateTagApi, getTagApi } from '@/api/email/userList'; |
|
78 |
|
|
79 |
// 排序 |
|
80 |
import { HolderOutlined } from '@ant-design/icons-vue'; |
|
81 |
import Sortable from 'sortablejs'; |
|
82 |
let sortable: any; |
|
83 |
const demo = reactive({ |
|
84 |
showHelpTip: false, |
|
85 |
tableData: [], |
|
86 |
}); |
|
87 |
const xTable = ref(); |
|
88 |
const rowDrop = () => { |
|
89 |
const $table = xTable.value; |
|
90 |
sortable = Sortable.create($table.$el.querySelector('.body--wrapper>.vxe-table--body tbody'), { |
|
91 |
handle: '.drag-btn', |
|
92 |
onEnd: (sortableEvent) => { |
|
93 |
const newIndex = sortableEvent.newIndex as number; |
|
94 |
const oldIndex = sortableEvent.oldIndex as number; |
|
95 |
const currRow: Record<string, any> = demo.tableData.splice(oldIndex, 1)[0]; |
|
96 |
// demo.tableData.splice(newIndex, 0, currRow); |
|
97 |
updateTagApi({ |
|
98 |
tagColor: currRow.tagColor, |
|
99 |
tagName: currRow.tagName, |
|
100 |
sortId: newIndex, |
|
101 |
tagId: currRow.tagId, |
|
102 |
}) |
|
103 |
.then(() => { |
|
104 |
fnGetList(); |
|
105 |
}) |
|
106 |
.catch(() => {}); |
|
107 |
}, |
|
108 |
}); |
|
109 |
}; |
|
110 |
|
|
111 |
let initTime: any; |
|
112 |
nextTick(() => { |
|
113 |
// 加载完成之后在绑定拖动事件 |
|
114 |
initTime = setTimeout(() => { |
|
115 |
rowDrop(); |
|
116 |
}, 500); |
|
117 |
}); |
|
118 |
|
|
119 |
onUnmounted(() => { |
|
120 |
clearTimeout(initTime); |
|
121 |
if (sortable) { |
|
122 |
sortable.destroy(); |
|
123 |
} |
|
124 |
}); |
|
125 |
|
|
126 |
function fnGetList() { |
|
127 |
getTagApi({}).then((res) => { |
|
128 |
console.log(res); |
|
129 |
demo.tableData = res.data; |
|
130 |
}); |
|
131 |
} |
|
132 |
|
|
133 |
import { useMessage } from '@/hooks/web/useMessage'; |
|
134 |
|
|
135 |
const { createMessage } = useMessage(); |
|
136 |
|
|
137 |
const open = ref(false); |
|
138 |
const formRef = ref(); |
|
139 |
|
|
140 |
interface formType { |
|
141 |
tagColor: string; |
|
142 |
tagName: string; |
|
143 |
tagType: number; |
|
144 |
systemFlag: boolean; |
|
145 |
tagId?: number; |
|
146 |
} |
|
147 |
|
|
148 |
const defaultForm: formType = { |
|
149 |
tagColor: '#000000', |
|
150 |
tagName: '', |
|
151 |
tagType: 1, |
|
152 |
systemFlag: false, |
|
153 |
}; |
|
154 |
|
|
155 |
const form = ref<formType>({ ...defaultForm }); |
|
156 |
|
|
157 |
const title = ref('新建'); |
|
158 |
const signType = ref('add'); |
|
159 |
|
|
160 |
const showModal = (type: string, row) => { |
|
161 |
signType.value = type; |
|
162 |
open.value = true; |
|
163 |
|
|
164 |
if (type == 'add') { |
|
165 |
form.value = { ...defaultForm }; |
|
166 |
} else { |
|
167 |
title.value = '编辑'; |
|
168 |
nextTick(() => { |
|
169 |
formRef.value.resetFields(); |
|
170 |
form.value = { |
|
171 |
tagColor: row.tagColor, |
|
172 |
tagName: row.tagName, |
|
173 |
tagType: row.tagType, |
|
174 |
systemFlag: row.systemFlag, |
|
175 |
tagId: row.tagId, |
|
176 |
}; |
|
177 |
}); |
|
178 |
} |
|
179 |
}; |
|
180 |
|
|
181 |
function fnDeleteRow(row) { |
|
182 |
deleteTagApi({ tagId: row.tagId }).then((res) => { |
|
183 |
if (res.code === 0) { |
|
184 |
createMessage.success(res.msg); |
|
185 |
fnGetList(); |
|
186 |
} |
|
187 |
}); |
|
188 |
} |
|
189 |
|
|
190 |
function handleOk() { |
|
191 |
nextTick(() => { |
|
192 |
formRef.value |
|
193 |
.validate() |
|
194 |
.then(() => { |
|
195 |
const api = signType.value == 'add' ? addTagApi : updateTagApi; |
|
196 |
api(form.value).then((res) => { |
|
197 |
if (res.code === 0) { |
|
198 |
createMessage.success(res.msg); |
|
199 |
fnGetList(); |
|
200 |
open.value = false; |
|
201 |
} |
|
202 |
}); |
|
203 |
}) |
|
204 |
.catch(() => {}); |
|
205 |
}); |
|
206 |
} |
|
207 |
|
|
208 |
function fnRowColorChange(color, row) { |
|
209 |
const data = { |
a9a03d
|
210 |
tagColor: color, |
63d608
|
211 |
tagName: row.tagName, |
H |
212 |
tagType: row.tagType, |
|
213 |
systemFlag: row.systemFlag, |
|
214 |
tagId: row.tagId, |
|
215 |
}; |
|
216 |
updateTagApi(data).then((res) => { |
|
217 |
if (res.code === 0) { |
|
218 |
createMessage.success(res.msg); |
|
219 |
fnGetList(); |
|
220 |
} |
|
221 |
}); |
|
222 |
} |
|
223 |
|
|
224 |
onMounted(() => { |
|
225 |
fnGetList(); |
|
226 |
}); |
|
227 |
</script> |
|
228 |
|
|
229 |
<style scoped> |
|
230 |
.sortable-row-demo .drag-btn { |
|
231 |
font-size: 12px; |
|
232 |
cursor: move; |
|
233 |
} |
|
234 |
|
|
235 |
.sortable-row-demo .vxe-body--row.sortable-ghost, |
|
236 |
.sortable-row-demo .vxe-body--row.sortable-chosen { |
|
237 |
background-color: #dfecfb; |
|
238 |
} |
|
239 |
|
|
240 |
.bookmark { |
|
241 |
display: inline-block; |
|
242 |
position: relative; |
|
243 |
width: 14px; |
|
244 |
height: 18px; |
|
245 |
margin-right: 5px; |
|
246 |
border-radius: 2px 2px 0 0; /* Rounded top corners */ |
|
247 |
} |
|
248 |
|
|
249 |
.bookmark::after { |
|
250 |
content: ''; |
|
251 |
position: absolute; |
|
252 |
right: 0; |
|
253 |
bottom: 0; |
|
254 |
left: 0; |
|
255 |
height: 8px; |
|
256 |
background-color: #fff; |
|
257 |
clip-path: polygon(50% 60%, 0% 100%, 100% 100%); /* Triangle at the bottom */ |
|
258 |
} |
|
259 |
</style> |