userCrud.ts 9.2 KB

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