userCrud.ts 9.5 KB

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