huangyinfeng
4 天以前 db42d08c39ae6129e2b95cd24c0d57c6769282e5
提交 | 用户 | 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>
13         <a-button type="primary" @click="insertEvent">新建文件夹</a-button>
14       </template>
15     </vxe-toolbar>
16
17     <vxe-table
18       ref="xTable"
19       style="margin: 10px 0"
20       :data="demo.tableData"
21       @mounted="onMounted"
22       :row-config="{ keyField: 'id' }"
23       :column-config="{ resizable: true }"
24       :export-config="{}"
a9a03d 25       :tree-config="{ transform: true, rowField: 'rowId', parentField: 'parentRowId' }"
63d608 26       :edit-config="{ trigger: 'manual', mode: 'row' }"
H 27       height="600"
28     >
29       <vxe-column width="40">
30         <template #default>
31           <span class="drag-btn">
32             <HolderOutlined />
33           </span>
34         </template>
35       </vxe-column>
36       <vxe-column field="folderName" title="文件夹名称" minWidth="250" tree-node :edit-render="{}">
37         <template #edit="{ row }">
38           <vxe-input
a9a03d 39             :ref="(el) => (inputRefs[row.id] = el)"
63d608 40             v-model="row.folderName"
H 41             type="text"
42             style="width: 300px"
43             @blur="fnInputHandle(row)"
44           ></vxe-input>
45         </template>
46       </vxe-column>
47       <vxe-column field="age" title="操作" width="250">
48         <template #default="{ row }">
49           <a style="margin-right: 10px" @click="insertRow(row)">添加子文件夹</a>
50           <a style="margin-right: 10px" @click="editRowEvent(row)">编辑</a>
51           <a style="margin-right: 10px" @click="fnDelete(row)">删除</a>
52         </template>
53       </vxe-column>
54     </vxe-table>
55   </div>
56 </template>
57
58 <script lang="ts" setup>
59   import { ref, computed, onMounted, nextTick, onUnmounted, reactive } from 'vue';
60   import {
61     addFolderApi,
62     deleteFolderApi,
63     updateFolderApi,
64     getFolderApi,
65   } from '@/api/email/userList';
66
67   // 排序
68   import { HolderOutlined } from '@ant-design/icons-vue';
69   import Sortable from 'sortablejs';
70   let sortable: any;
71   const demo = reactive({
72     showHelpTip: false,
73     tableData: [],
74   });
75   const xTable = ref();
76   const rowDrop = () => {
77     const $table = xTable.value;
78     sortable = Sortable.create($table.$el.querySelector('.body--wrapper>.vxe-table--body tbody'), {
79       handle: '.drag-btn',
80       onEnd: (sortableEvent) => {
81         const newIndex = sortableEvent.newIndex as number;
82         const oldIndex = sortableEvent.oldIndex as number;
83         const currRow: Record<string, any> = demo.tableData.splice(oldIndex, 1)[0];
84         // demo.tableData.splice(newIndex, 0, currRow);
85         updateFolderApi({
a9a03d 86           folderId: currRow.folderId,
H 87           folderName: currRow.folderName,
88           treeControl: currRow.treeControl,
89           parentRowId: currRow.parentRowId,
63d608 90           sortId: newIndex,
H 91         })
92           .then(() => {
93             fnGetList();
94           })
95           .catch(() => {});
96       },
97     });
98   };
99
100   let initTime: any;
101   nextTick(() => {
102     // 加载完成之后在绑定拖动事件
103     initTime = setTimeout(() => {
104       rowDrop();
105     }, 500);
106   });
107
108   onUnmounted(() => {
109     clearTimeout(initTime);
110     if (sortable) {
111       sortable.destroy();
112     }
113   });
114
115   function fnGetList() {
116     getFolderApi({}).then((res) => {
a9a03d 117       demo.tableData = convertToTableData(res.data);
63d608 118     });
a9a03d 119   }
H 120   function convertToTableData(data, parentId = null) {
db42d0 121     try {
H 122       let tableData = [];
a9a03d 123
db42d0 124       data.forEach((item) => {
H 125         let tableItem = {
126           folderId: item.folderId,
127           parentRowId: parentId,
128           rowId: item.rowId,
129           folderName: item.folderName,
130           treeControl: item.treeControl,
131         };
a9a03d 132
db42d0 133         if (item.list && item.list.length > 0) {
H 134           let children = convertToTableData(item.list, item.rowId);
135           tableData = tableData.concat(children);
136         }
a9a03d 137
db42d0 138         tableData.push(tableItem);
H 139       });
140       return tableData;
141      
142     } catch (error) { return [];}
63d608 143   }
H 144
145   const inputRefs = ref<{ [key: number]: HTMLElement | null }>({});
146   function insertEvent() {
147     const $table = xTable.value;
148     const rid = Date.now();
149     const record = {
db42d0 150       folderName: `新文件夹`,
63d608 151       id: rid,
H 152     };
153     $table.insert(record).then(({ row }) => $table.setEditRow(row));
154     setTimeout(() => {
155       inputRefs.value[rid].focus();
156     }, 300);
157   }
158   import { useMessage } from '@/hooks/web/useMessage';
159
160   const { createMessage } = useMessage();
161   function fnInputHandle(row) {
a9a03d 162     if (row.folderName == '') {
db42d0 163       editRowEvent(row);
H 164       fnGetList();
a9a03d 165       return createMessage.error('请输入文件夹名称');
H 166     }
167     const data =
168       row.opType == 'edit'
169         ? {
170             folderId: row.folderId,
171             folderName: row.folderName,
172             treeControl: row.treeControl,
173             parentRowId: row.parentRowId,
174             sortId: row.sortId,
175           }
176         : {
177             folderName: row.folderName,
178             parentRowId: row.parentRowId,
179           };
180     const api = row.opType == 'edit' ? updateFolderApi : addFolderApi;
181     const title = row.opType == 'edit' ? '编辑' : '添加';
182     api(data).then((res) => {
63d608 183       if (res.code == 0) {
a9a03d 184         createMessage.success(`${title}成功`);
63d608 185         fnGetList();
H 186       } else {
187         createMessage.error(res.msg);
db42d0 188         fnGetList();
63d608 189       }
H 190     });
191   }
192   async function insertRow(row) {
193     const $table = xTable.value;
194     const rid = Date.now();
195     const record = {
db42d0 196       folderName: `新子文件夹`,
63d608 197       id: rid,
H 198       parentRowId: row.rowId, // 需要指定父节点,自动插入该节点中
199     };
200     const { row: newRow } = await $table.insert(record);
201     await $table.setTreeExpand(row, true); // 将父节点展开
202     await $table.setEditRow(newRow); // 插入子节点
db42d0 203     setTimeout(() => {
H 204       inputRefs.value[rid].focus();
205     }, 300);
63d608 206   }
H 207   function fnDelete(row) {
208     deleteFolderApi({ folderId: row.folderId })
209       .then((res) => {
210         if (res.code == 0) {
211           fnGetList();
212           createMessage.success(res.msg);
213         }
214       })
215       .catch((err) => {
216         // createMessage.error(err);
217       });
218   }
219
220   function editRowEvent(row) {
221     const $table = xTable.value;
a9a03d 222     row.opType = 'edit';
63d608 223     $table.setEditRow(row);
H 224   }
225   onMounted(() => {
226     fnGetList();
227   });
228 </script>
229
230 <style scoped>
231   .sortable-row-demo .drag-btn {
232     font-size: 12px;
233     cursor: move;
234   }
235
236   .sortable-row-demo .vxe-body--row.sortable-ghost,
237   .sortable-row-demo .vxe-body--row.sortable-chosen {
238     background-color: #dfecfb;
239   }
240 </style>