import request from "@/utils/request"; import { PageOption } from "@smallwei/avue"; import { ElMessageBox, ElMessage } from "element-plus"; import { useUserStoreHook } from "@/store/modules/user"; import { checkPerm } from "@/directive/permission"; import { configs } from "@typescript-eslint/eslint-plugin"; interface UseCrudConfig { // 模块的url,用来进行增删改查 src?: string; dataListUrl?: string; afterDataList?: Function; afterAdd?: Function; // 需要操作的数据 row?: any; // done用于结束操作 done?: () => void; // 具体操作的行 index?: number; // 用于中断操作 loading?: () => void; // 额外查询参数 一般用search的值就可以了 params?: object; // 是否是编辑,如果是编辑调用更新,否则调用新增 isEdit?: boolean; // 用于多选选中后添加进入,toDeleteIds中的key值。 multipleSelectKey?: string; } export const useCrud = (config?: UseCrudConfig) => { const url = ref(config?.src); const commonConfig = ref(config); /** 表格配置属性 */ const option = ref({ searchIcon: true, // searchSpan: 4, searchIndex: 3, //searchIcon是否启用功能按钮, searchIndex配置收缩展示的个数,默认为2个 index: true, //是否显示第几项 indexLabel: "序号", indexWidth: "55px", refreshBtn: false, border: true, viewBtn: true, tip: false, //选中的提示 }); const data = ref([]); //表格数据 const form = ref({}); //新增或者编辑弹出的表单绑定值 /** 表格顶部搜索的表单的变量 v-model */ const search = ref({}); /** 表格的分页数据 v-model */ const page = ref({ total: 0, currentPage: 1, pageSize: 10, }); /** 配置项结构 v-model */ // defaults ?: AvueCrudDefaults; // 多选返回的数组,命名是因为后来增加了很多功能,现在这个数组里面的值是根据multipleSelectKey来决定 const toDeleteIds = ref>([]); // 多选返回的数组,返回每一行的row数据 const selectedRows = ref([]); const save = async (config?: UseCrudConfig) => { try { const path = config?.isEdit ? "/update" : "/add"; const res = (await request({ url: `${url.value}${path}`, method: "post", data: form.value, })) as any; if (res?.code == 200) { Methords.dataList(); config?.done && config?.done(); ElMessage.success(res?.msg ?? ""); if (commonConfig.value?.afterAdd) { commonConfig.value?.afterAdd(res?.data); } } else { config?.loading && config?.loading(); ElMessage.error(res?.msg ?? ""); } } catch (err) { config?.loading && config?.loading(); } }; const handleSearchData = () => { // const array = [null, undefined, ""]; search.value = Object.fromEntries( Object.entries(search.value).filter( ([key, value]) => value !== null && value !== undefined && Object.keys(value).length !== 0 ) ); }; /** * 表格增删改查等基本方法 */ const Methords = { /** * 查询方法 */ dataList: async (config?: UseCrudConfig) => { handleSearchData(); try { const res = await request({ url: commonConfig.value?.dataListUrl ?? `${url.value}/page`, method: "post", data: { pageNo: page.value.currentPage, pageSize: page.value.pageSize, ...(commonConfig.value?.params ?? {}), ...search.value, }, }); if (res?.data) { if (res?.data instanceof Array) { data.value = res?.data || []; page.value.total = res?.data?.length || 0; } else { data.value = res?.data?.records || []; page.value.total = res?.data?.totalCount || 0; } if (commonConfig.value?.afterDataList) { commonConfig.value?.afterDataList(); } } config?.done && config?.done(); } catch (err) { config?.loading && config?.loading(); } finally { config?.done && config?.done(); } }, dataEditList: async (config?: UseCrudConfig) => { handleSearchData(); try { const res = await request({ url: `${url.value}/page`, method: "post", data: { pageNo: page.value.currentPage, pageSize: page.value.pageSize, ...search.value, ...(commonConfig.value?.params ?? {}), }, }); if (res?.data) { if (res?.data instanceof Array) { data.value = res?.data || []; page.value.total = res?.data?.length || 0; } else { data.value = res?.data?.records || []; for (let i = 0; i < data.value.length; i++) { data.value[i].$cellEdit = true; if ( data.value[i].children != undefined && data.value[i].children != null && data.value[i].children.length > 0 ) { for (let j = 0; j < data.value[i].children.length; j++) { data.value[i].children[j].$cellEdit = true; } } } page.value.total = res?.data?.totalCount || 0; } } config?.done && config?.done(); } catch (err) { config?.loading && config?.loading(); } finally { config?.done && config?.done(); } }, dataNoPageList: async (config?: UseCrudConfig) => { handleSearchData(); try { const res = await request({ url: `${url.value}/list`, method: "post", data: { ...search.value, }, }); if (res?.data) { data.value = res?.data || []; } config?.done && config?.done(); } catch (err) { config?.loading && config?.loading(); } finally { config?.done && config?.done(); } }, createRow: (row: any, done: () => void, loading: () => void) => { save({ row: row, done: done, loading: loading }); }, updateRow: ( row: any, index: number, done: () => void, loading: () => void ) => { save({ row: row, done: done, loading: loading, index: index, isEdit: true, }); }, deleteRow: async (row: any, index: number, done: () => void) => { ElMessageBox.confirm("是否删除所选中数据?", "提示", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning", }).then(async () => { if (row.children && row.children.length > 0) { ElMessage.error("请先解绑下级关系"); return; } try { const res = await request({ url: `${url.value}/del`, method: "post", data: row, }); Methords.dataList(); config?.done && config?.done(); } catch (err) { config?.loading && config?.loading(); } finally { config?.done && config?.done(); } }); }, // 设置selection: true,后监听选中改变事件,将Id存入数组 selectionChange: (rows?: any[]) => { toDeleteIds.value = []; selectedRows.value = []; rows?.forEach((element) => { toDeleteIds.value.push( element[commonConfig.value?.multipleSelectKey ?? "id"] ); selectedRows.value.push(element); }); }, /** * 表格上方的多选删除方法 */ multipleDelete: async () => { ElMessageBox.confirm("是否删除所选中数据?", "提示", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning", }).then(async () => { try { const res = await request({ url: `${url.value}/batch-del`, method: "post", data: { ids: toDeleteIds.value }, }); Methords.dataList(); config?.done && config?.done(); } catch (err) { config?.loading && config?.loading(); } finally { config?.done && config?.done(); } }); }, /** * 表格拖拽后批量保存 * */ multipleUpdate: async () => { try { // 由于数据带有$开头的属性,所以需要处理下,改为只传id和sortNum。 const dtosArray: { id: string; sortNum: number }[] = []; for (let i = 0; i < data.value.length; i++) { let cur = page.value.currentPage ?? 1; cur = cur - 1; const size = page.value.pageSize ?? 10; let sortNum = cur * size; sortNum = sortNum + i; dtosArray.push({ id: data.value[i].id, sortNum: sortNum }); } const res = await request({ url: `${url.value}/batch-update`, method: "post", data: dtosArray, }); Methords.dataList(); config?.done && config?.done(); } catch (err) { config?.loading && config?.loading(); } finally { config?.done && config?.done(); } }, /** * 点击搜索按钮触发 */ searchChange: async (params: any, done: () => void) => { // 点击搜索的时候重置search的值,要不然会传过去所有的值包括空字符串的值 search.value = params; page.value.currentPage = 1; Methords.dataList({ done: done }); }, /** * 点击清空按钮触发 */ resetChange: async (item: any) => { page.value.currentPage = 1; Methords.dataList(); }, }; /** * 表格辅助方法,按钮权限,导入导出 */ const Utils = { checkBtnPerm: (str: string) => { // 「超级管理员」拥有所有的按钮权限 const { roles, perms } = useUserStoreHook().user; if (roles.includes("ROOT")) { return true; } const hasPerm = perms?.some((perm) => { return str.includes(perm); }); return hasPerm; }, /** * 根据返回的数据下载文件 */ downloadFile: (response: any) => { const fileData = response.data; const fileName = decodeURI( response.headers["content-disposition"].split(";")[1].split("=")[1] ); const fileType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"; const blob = new Blob([fileData], { type: fileType }); const downloadUrl = window.URL.createObjectURL(blob); const downloadLink = document.createElement("a"); downloadLink.href = downloadUrl; downloadLink.download = fileName; document.body.appendChild(downloadLink); downloadLink.click(); document.body.removeChild(downloadLink); window.URL.revokeObjectURL(downloadUrl); }, /** * 下载模版 传入url */ downloadTemplate: async (urlStr: string) => { const response = await request({ url: urlStr, method: "get", responseType: "arraybuffer", }); Utils.downloadFile(response); }, /** * 根据搜索项导出数据 */ exportData: async (urlStr: string) => { handleSearchData(); const response = await request({ url: urlStr, method: "post", data: search.value, responseType: "arraybuffer", }); Utils.downloadFile(response); }, /** * 根据搜索项导出数据 */ downloadSPCTemplate: async (urlStr: string, filePath: string) => { handleSearchData(); const response = await request({ url: urlStr, method: "post", data: search.value, params: { filePath: filePath }, responseType: "arraybuffer", }); Utils.downloadFile(response); }, }; return { url, option, data, form, search, page, toDeleteIds, Methords, Utils, selectedRows, commonConfig, }; };