userCrud.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. import request from "@/utils/request";
  2. import { PageOption } from "@smallwei/avue";
  3. import { ElMessageBox, ElMessage } from "element-plus";
  4. import { useUserStoreHook } from "@/store/modules/user";
  5. import { checkPerm } from "@/directive/permission";
  6. import { configs } from "@typescript-eslint/eslint-plugin";
  7. interface UseCrudConfig {
  8. // 模块的url,用来进行增删改查
  9. src?: string;
  10. dataListUrl?: string;
  11. // 需要操作的数据
  12. row?: any;
  13. // done用于结束操作
  14. done?: () => void;
  15. // 具体操作的行
  16. index?: number;
  17. // 用于中断操作
  18. loading?: () => void;
  19. // 额外查询参数 一般用search的值就可以了
  20. params?: object;
  21. // 是否是编辑,如果是编辑调用更新,否则调用新增
  22. isEdit?: boolean;
  23. // 用于多选选中后添加进入,toDeleteIds中的key值。
  24. multipleSelectKey?: string;
  25. // todo 这个值是什么
  26. pageStr?: string;
  27. }
  28. export const useCrud = (config?: UseCrudConfig) => {
  29. const url = ref(config?.src);
  30. const pageStr = ref(config?.pageStr ? config?.pageStr : "yes");
  31. const commonConfig = ref(config);
  32. /** 表格配置属性 */
  33. const option = ref({
  34. searchIcon: true,
  35. // searchSpan: 4,
  36. searchIndex: 3, //searchIcon是否启用功能按钮, searchIndex配置收缩展示的个数,默认为2个
  37. index: true, //是否显示第几项
  38. indexLabel: "序号",
  39. indexWidth: "55px",
  40. refreshBtn: false,
  41. border: true,
  42. viewBtn: true,
  43. tip: false, //选中的提示
  44. });
  45. const data = ref<any>([]); //表格数据
  46. const lines = ref<any>([]); //产线
  47. const form = ref({}); //新增或者编辑弹出的表单绑定值
  48. /** 表格顶部搜索的表单的变量 v-model */
  49. const search = ref({});
  50. /** 表格的分页数据 v-model */
  51. const page = ref<PageOption>({
  52. total: 0,
  53. currentPage: 1,
  54. pageSize: 10,
  55. });
  56. /** 配置项结构 v-model */
  57. // defaults ?: AvueCrudDefaults;
  58. // 多选返回的数组,命名是因为后来增加了很多功能,现在这个数组里面的值是根据multipleSelectKey来决定
  59. const toDeleteIds = ref<Array<string>>([]);
  60. // 多选返回的数组,返回每一行的row数据
  61. const selectedRows = ref<any[]>([]);
  62. const save = async (config?: UseCrudConfig) => {
  63. try {
  64. const path = config?.isEdit ? "/update" : "/add";
  65. const res = (await request({
  66. url: `${url.value}${path}`,
  67. method: "post",
  68. data: form.value,
  69. })) as any;
  70. if (res?.code == 200) {
  71. Methords.dataList();
  72. config?.done && config?.done();
  73. ElMessage.success(res?.msg ?? "");
  74. } else {
  75. config?.loading && config?.loading();
  76. ElMessage.error(res?.msg ?? "");
  77. }
  78. } catch (err) {
  79. config?.loading && config?.loading();
  80. }
  81. };
  82. const handleSearchData = () => {
  83. // const array = [null, undefined, ""];
  84. search.value = Object.fromEntries(
  85. Object.entries(search.value).filter(
  86. ([key, value]) =>
  87. value !== null &&
  88. value !== undefined &&
  89. Object.keys(value).length !== 0
  90. )
  91. );
  92. };
  93. /**
  94. * 表格增删改查等基本方法
  95. */
  96. const Methords = {
  97. /**
  98. * 查询方法
  99. */
  100. dataList: async (config?: UseCrudConfig) => {
  101. handleSearchData();
  102. try {
  103. const res = await request({
  104. url:
  105. pageStr.value == "no"
  106. ? (commonConfig.value?.dataListUrl ?? `${url.value}`)
  107. : (commonConfig.value?.dataListUrl ?? `${url.value}/page`),
  108. method: "post",
  109. data: {
  110. pageNo: page.value.currentPage,
  111. pageSize: page.value.pageSize,
  112. ...search.value,
  113. ...(commonConfig.value?.params ?? {}),
  114. },
  115. });
  116. if (res?.data) {
  117. if (res?.data instanceof Array) {
  118. data.value = res?.data || [];
  119. page.value.total = res?.data?.length || 0;
  120. } else {
  121. data.value = res?.data?.records || [];
  122. lines.value = res?.data?.productLines || [];
  123. page.value.total = res?.data?.totalCount || 0;
  124. }
  125. }
  126. config?.done && config?.done();
  127. } catch (err) {
  128. config?.loading && config?.loading();
  129. } finally {
  130. config?.done && config?.done();
  131. }
  132. },
  133. dataEditList: async (config?: UseCrudConfig) => {
  134. handleSearchData();
  135. try {
  136. const res = await request({
  137. url: pageStr.value == "no" ? `${url.value}` : `${url.value}/page`,
  138. method: "post",
  139. data: {
  140. pageNo: page.value.currentPage,
  141. pageSize: page.value.pageSize,
  142. ...search.value,
  143. ...(commonConfig.value?.params ?? {}),
  144. },
  145. });
  146. if (res?.data) {
  147. if (res?.data instanceof Array) {
  148. data.value = res?.data || [];
  149. page.value.total = res?.data?.length || 0;
  150. } else {
  151. data.value = res?.data?.records || [];
  152. for (let i = 0; i < data.value.length; i++) {
  153. data.value[i].$cellEdit = true;
  154. if (
  155. data.value[i].children != undefined &&
  156. data.value[i].children != null &&
  157. data.value[i].children.length > 0
  158. ) {
  159. for (let j = 0; j < data.value[i].children.length; j++) {
  160. data.value[i].children[j].$cellEdit = true;
  161. }
  162. }
  163. }
  164. page.value.total = res?.data?.totalCount || 0;
  165. }
  166. }
  167. config?.done && config?.done();
  168. } catch (err) {
  169. config?.loading && config?.loading();
  170. } finally {
  171. config?.done && config?.done();
  172. }
  173. },
  174. dataNoPageList: async (config?: UseCrudConfig) => {
  175. handleSearchData();
  176. try {
  177. const res = await request({
  178. url: `${url.value}/list`,
  179. method: "post",
  180. data: {
  181. ...search.value,
  182. },
  183. });
  184. if (res?.data) {
  185. data.value = res?.data || [];
  186. }
  187. config?.done && config?.done();
  188. } catch (err) {
  189. config?.loading && config?.loading();
  190. } finally {
  191. config?.done && config?.done();
  192. }
  193. },
  194. createRow: (row: any, done: () => void, loading: () => void) => {
  195. save({ row: row, done: done, loading: loading });
  196. },
  197. updateRow: (
  198. row: any,
  199. index: number,
  200. done: () => void,
  201. loading: () => void
  202. ) => {
  203. save({
  204. row: row,
  205. done: done,
  206. loading: loading,
  207. index: index,
  208. isEdit: true,
  209. });
  210. },
  211. deleteRow: async (row: any, index: number, done: () => void) => {
  212. ElMessageBox.confirm("是否删除所选中数据?", "提示", {
  213. confirmButtonText: "确定",
  214. cancelButtonText: "取消",
  215. type: "warning",
  216. }).then(async () => {
  217. if (row.children && row.children.length > 0) {
  218. ElMessage.error("请先解绑下级关系");
  219. return;
  220. }
  221. try {
  222. const res = await request({
  223. url: `${url.value}/del`,
  224. method: "post",
  225. data: row,
  226. });
  227. Methords.dataList();
  228. config?.done && config?.done();
  229. } catch (err) {
  230. config?.loading && config?.loading();
  231. } finally {
  232. config?.done && config?.done();
  233. }
  234. });
  235. },
  236. // 设置selection: true,后监听选中改变事件,将Id存入数组
  237. selectionChange: (rows?: any[]) => {
  238. toDeleteIds.value = [];
  239. selectedRows.value = [];
  240. rows?.forEach((element) => {
  241. toDeleteIds.value.push(
  242. element[commonConfig.value?.multipleSelectKey ?? "id"]
  243. );
  244. selectedRows.value.push(element);
  245. });
  246. },
  247. /**
  248. * 表格上方的多选删除方法
  249. */
  250. multipleDelete: async () => {
  251. ElMessageBox.confirm("是否删除所选中数据?", "提示", {
  252. confirmButtonText: "确定",
  253. cancelButtonText: "取消",
  254. type: "warning",
  255. }).then(async () => {
  256. try {
  257. const res = await request({
  258. url: `${url.value}/batch-del`,
  259. method: "post",
  260. data: { ids: toDeleteIds.value },
  261. });
  262. Methords.dataList();
  263. config?.done && config?.done();
  264. } catch (err) {
  265. config?.loading && config?.loading();
  266. } finally {
  267. config?.done && config?.done();
  268. }
  269. });
  270. },
  271. /**
  272. * 表格拖拽后批量保存
  273. * */
  274. multipleUpdate: async () => {
  275. try {
  276. // 由于数据带有$开头的属性,所以需要处理下,改为只传id和sortNum。
  277. const dtosArray: { id: string; sortNum: number }[] = [];
  278. for (let i = 0; i < data.value.length; i++) {
  279. let cur = page.value.currentPage ?? 1;
  280. cur = cur - 1;
  281. const size = page.value.pageSize ?? 10;
  282. let sortNum = cur * size;
  283. sortNum = sortNum + i;
  284. dtosArray.push({ id: data.value[i].id, sortNum: sortNum });
  285. }
  286. const res = await request({
  287. url: `${url.value}/batch-update`,
  288. method: "post",
  289. data: dtosArray,
  290. });
  291. ElMessage.success(res?.msg ?? "");
  292. Methords.dataList();
  293. config?.done && config?.done();
  294. } catch (err) {
  295. config?.loading && config?.loading();
  296. } finally {
  297. config?.done && config?.done();
  298. }
  299. },
  300. /**
  301. * 点击搜索按钮触发
  302. */
  303. searchChange: async (params: any, done: () => void) => {
  304. // 点击搜索的时候重置search的值,要不然会传过去所有的值包括空字符串的值
  305. search.value = params;
  306. page.value.currentPage = 1;
  307. Methords.dataList({ done: done });
  308. },
  309. /**
  310. * 点击清空按钮触发
  311. */
  312. resetChange: async (item: any) => {
  313. page.value.currentPage = 1;
  314. Methords.dataList();
  315. },
  316. };
  317. /**
  318. * 表格辅助方法,按钮权限,导入导出
  319. */
  320. const Utils = {
  321. checkBtnPerm: (str: string) => {
  322. // 「超级管理员」拥有所有的按钮权限
  323. const { roles, perms } = useUserStoreHook().user;
  324. if (roles.includes("ROOT")) {
  325. return true;
  326. }
  327. const hasPerm = perms?.some((perm) => {
  328. return str.includes(perm);
  329. });
  330. return hasPerm;
  331. },
  332. /**
  333. * 根据返回的数据下载文件
  334. */
  335. downloadFile: (response: any) => {
  336. const fileData = response.data;
  337. const fileName = decodeURI(
  338. response.headers["content-disposition"].split(";")[1].split("=")[1]
  339. );
  340. const fileType =
  341. "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8";
  342. const blob = new Blob([fileData], { type: fileType });
  343. const downloadUrl = window.URL.createObjectURL(blob);
  344. const downloadLink = document.createElement("a");
  345. downloadLink.href = downloadUrl;
  346. downloadLink.download = fileName;
  347. document.body.appendChild(downloadLink);
  348. downloadLink.click();
  349. document.body.removeChild(downloadLink);
  350. window.URL.revokeObjectURL(downloadUrl);
  351. },
  352. /**
  353. * 下载模版 传入url
  354. */
  355. downloadTemplate: async (urlStr: string) => {
  356. const response = await request({
  357. url: urlStr,
  358. method: "get",
  359. responseType: "arraybuffer",
  360. });
  361. Utils.downloadFile(response);
  362. },
  363. /**
  364. * 根据搜索项导出数据
  365. */
  366. exportData: async (urlStr: string) => {
  367. handleSearchData();
  368. const response = await request({
  369. url: urlStr,
  370. method: "post",
  371. data: search.value,
  372. responseType: "arraybuffer",
  373. });
  374. Utils.downloadFile(response);
  375. },
  376. };
  377. return {
  378. url,
  379. option,
  380. data,
  381. lines,
  382. form,
  383. search,
  384. page,
  385. toDeleteIds,
  386. selectedRows,
  387. Methords,
  388. Utils,
  389. commonConfig,
  390. };
  391. };