index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. <!--
  2. * @Descripttion: 数据表格组件
  3. * @version: 1.10
  4. -->
  5. <template>
  6. <el-main>
  7. <vxe-grid ref="xGrid" v-bind="gridOptions" @form-collapse="formCollapseEvent" @edit-activated="$emit('editActivated', $event)" @page-change="pageChangeEvent">
  8. <template #queryAction>
  9. <el-button type="primary" auto-insert-space @click="searchData">查询</el-button>
  10. <el-button auto-insert-space @click="resetData">重置</el-button>
  11. </template>
  12. <!-- table-column / 操作 -->
  13. <template v-for="(_, slotName) in $slots" #[slotName]="context">
  14. <slot :name="slotName" v-bind="{ ...context, row: XEUtils.get(context, '$grid', XEUtils.get(context, '$table'))?.getData(context.rowIndex) || context.row }"></slot>
  15. </template>
  16. </vxe-grid>
  17. </el-main>
  18. </template>
  19. <script setup>
  20. // 设置当前zIndex起始值
  21. import domZIndex from "dom-zindex";
  22. domZIndex.setCurrent(domZIndex.getMax() + 1);
  23. import VxeUI from "vxe-pc-ui";
  24. import XEUtils from "xe-utils";
  25. import store from "@/store";
  26. import config from "@/config/table";
  27. import pagerBatchDel from "./renderer/pager-batch-del";
  28. const props = defineProps({
  29. apiObj: { type: Object, default: () => {} },
  30. apiKey: { type: String, default: () => "get" },
  31. framework: { type: String, default: () => "common" },
  32. minHeight: { type: [String, Number], default: () => VxeUI.getConfig().table.minHeight },
  33. maxHeight: { type: [String, Number] },
  34. layouts: { type: Array, default: () => [["Top", "Form"], ["Toolbar", "Table", "Bottom", "Pager"]] },
  35. /* *************** query *************** */
  36. formConfig: { type: Object, default: () => {} },
  37. paramsColums: { type: Array, default: () => [] },
  38. /* *************** query *************** */
  39. toolbarConfig: { type: Object, default: () => {} },
  40. editConfig: { type: Object, default: () => {} },
  41. columns: { type: Array, default: () => [] },
  42. /* *************** pager *************** */
  43. pagerConfig: { type: Object, default: () => {} },
  44. batchDel: { type: Boolean, default: () => false },
  45. /* *************** pager *************** */
  46. options: { type: Object, default: () => {} }
  47. })
  48. const xGrid = ref();
  49. const selectedRows = ref([]);
  50. const gridOptions = ref({
  51. id: "xGride-table",
  52. loading: false,
  53. minHeight: props.minHeight,
  54. border: "full",
  55. size: "mini",
  56. data: [],
  57. columns: XEUtils.map(props.columns, item => ({ ...item, [item.type != "seq" && "exportMethod"]: ({ row, column }) => row[column?.field] || "" })),
  58. showOverflow: true,
  59. keepSource: true,
  60. layouts: [...props.layouts],
  61. formConfig: {
  62. enabled: true,
  63. className: "vxe-table-query",
  64. titleAlign: "right",
  65. collapseStatus: true,
  66. span: 6,
  67. items: [
  68. ...XEUtils.map(XEUtils.orderBy(XEUtils.get(props, "formConfig.items", []), "orderBy"), (formItem, formIndex) => {
  69. return {
  70. ...formItem,
  71. className: ({ $grid, item, data }) => {
  72. const showItems = XEUtils.filter(XEUtils.orderBy(XEUtils.get(props, "formConfig.items", []), "orderBy"), f_item => (XEUtils.isUndefined(f_item.visible) || f_item.visible) && (XEUtils.isUndefined(f_item.visibleMethod) || f_item.visibleMethod({ data })));
  73. const index = XEUtils.findIndexOf(showItems, f_item => f_item.field == item.field);
  74. item.folding = index > 2;
  75. XEUtils.set(formItem, "folding", index > 2);
  76. return "";
  77. }
  78. }
  79. }), {
  80. align: "right",
  81. slots: { default: "queryAction" },
  82. className: ({ $grid, item, data }) => {
  83. const showItems = XEUtils.filter(XEUtils.orderBy(XEUtils.get(props, "formConfig.items", []), "orderBy"), formItem => (XEUtils.isUndefined(formItem.visible) || formItem.visible) && (XEUtils.isUndefined(formItem.visibleMethod) || formItem.visibleMethod({ data })));
  84. const spanItems = (!gridOptions.value.formConfig.collapseStatus && showItems) || XEUtils.filter(showItems, f_item => !f_item.folding);
  85. let spanItemsSum = 0;
  86. XEUtils.arrayEach(spanItems, s_item => {
  87. const spanCount = (s_item.span || 6);
  88. if (spanCount > 24 - (spanItemsSum % 24)) spanItemsSum += 24 - (spanItemsSum % 24);
  89. spanItemsSum += spanCount;
  90. })
  91. const remainder = 24 - (spanItemsSum % 24);
  92. item.visible = showItems.length > 0;
  93. item.collapseNode = showItems.length > 3;
  94. item.span = remainder < 6 && 24 || remainder;
  95. return "query-action__item";
  96. }
  97. }
  98. ],
  99. ...XEUtils.omit(XEUtils.get(props, "formConfig", {}), "items")
  100. },
  101. toolbarConfig: {
  102. enabled: false,
  103. buttons: [
  104. { buttonRender: { name: "$table-search" } }
  105. ],
  106. print: true,
  107. zoom: true,
  108. custom: true,
  109. refresh: {
  110. queryMethod: () => getData()
  111. },
  112. ...props.toolbarConfig
  113. },
  114. proxyConfig: {
  115. enabled: false
  116. },
  117. printConfig: {},
  118. importConfig: {
  119. // remote: true,
  120. types: ["xlsx", "xls"],
  121. mode: "insertBottom",
  122. modes: ["insertBottom", "insertTop", "covering"],
  123. // importMethod: ({ $grid, options }) => {},
  124. },
  125. exportConfig: {
  126. remote: true,
  127. types: ["xlsx"],
  128. modes: XEUtils.find(props.columns, item => XEUtils.includes(config.exportExcludeFields, item.type)) && ["current", "selected", "all"] || ["current", "all"],
  129. columns: XEUtils.filter(props.columns, item => !XEUtils.includes(config.exportExcludeFields, item.type)),
  130. exportMethod: ({ $grid, options }) => exportEvent($grid, options)
  131. },
  132. rowConfig: {
  133. keyField: "id",
  134. useKey: true,
  135. isHover: true
  136. },
  137. columnConfig: {
  138. useKey: true,
  139. resizable: true // 列宽拖动功能
  140. },
  141. headerCellConfig: {
  142. height: 36
  143. },
  144. cellConfig: {
  145. height: 36
  146. },
  147. checkboxConfig: {
  148. highlight: true,
  149. range: true, // 鼠标在复选框的列内滑动选中或取消指定行
  150. isShiftKey: true // 鼠标点击和 shift 键选取指定范围的行
  151. },
  152. tooltipConfig: {
  153. enterable: true
  154. },
  155. expandConfig: {
  156. padding: true
  157. },
  158. editConfig: {
  159. enabled: false,
  160. mode: "cell",
  161. trigger: "click",
  162. showStatus: true,
  163. ...props.editConfig
  164. },
  165. pagerConfig: {
  166. queryType: "limit", // 页码筛选类型
  167. pageSizes: config.pageSizes,
  168. layouts: config.layouts,
  169. currentPage: 1,
  170. pageSize: config.pageSize,
  171. total: 0,
  172. slots: {
  173. left: params => props.batchDel && h(pagerBatchDel, { params, onSuccess: ids => table_batch_del(ids) })
  174. },
  175. ...props.pagerConfig
  176. },
  177. ...props.options
  178. })
  179. watch(() => xGrid.value?.getCheckboxRecords(), val => selectedRows.value = val);
  180. watch(() => props.options, val => XEUtils.merge(gridOptions.value, val), { deep: true });
  181. addEventListener("resize", () => resizeTable());
  182. onMounted(() => {
  183. resizeTable();
  184. getData();
  185. });
  186. const resizeTable = () => {
  187. nextTick(() => {
  188. if (store.state.global.ismobile) XEUtils.set(gridOptions.value, "maxHeight", 1048);
  189. else XEUtils.set(gridOptions.value, "maxHeight", (props.maxHeight || xGrid.value?.$el.parentElement.offsetHeight));
  190. });
  191. }
  192. // 获取数据
  193. const getData = () => {
  194. nextTick(() => {
  195. if (!props.apiObj) {
  196. gridOptions.value.data = [];
  197. gridOptions.value.pagerConfig.total = 0;
  198. return;
  199. }
  200. gridOptions.value.loading = true;
  201. const reqData = config.framework[props.framework].queryData(gridOptions.value, props.paramsColums);
  202. props.apiObj[props.apiKey](reqData).then(res => {
  203. const response = config.framework[props.framework].parseData(res);
  204. gridOptions.value.data = response.data || [];
  205. gridOptions.value.pagerConfig.total = response.total || 0;
  206. gridOptions.value.loading = false;
  207. }).catch(error => {
  208. gridOptions.value.loading = false;
  209. gridOptions.value.data = [];
  210. gridOptions.value.pagerConfig.total = 0;
  211. });
  212. });
  213. }
  214. const pageChangeEvent = ({ pageSize, currentPage }) => {
  215. gridOptions.value.pagerConfig.currentPage = currentPage;
  216. gridOptions.value.pagerConfig.pageSize = pageSize;
  217. getData();
  218. }
  219. const searchData = (mode = "add") => {
  220. if (mode == "add") gridOptions.value.pagerConfig.currentPage = 1;
  221. gridOptions.value.pagerConfig.pageSize = config.pageSize;
  222. getData();
  223. }
  224. const resetData = () => {
  225. gridOptions.value.pagerConfig.currentPage = 1;
  226. gridOptions.value.pagerConfig.pageSize = config.pageSize;
  227. xGrid.value.resetForm();
  228. getData();
  229. }
  230. const formCollapseEvent = ({ collapse }) => gridOptions.value.formConfig.collapseStatus = collapse;
  231. const toggleTableLoading = value => gridOptions.value.loading = value;
  232. const toggleFormEnabled = () => gridOptions.value.formConfig.enabled = !gridOptions.value.formConfig.enabled;
  233. const toggleTableExpand = () => xGrid.value.getTreeExpandRecords().length && xGrid.value.clearTreeExpand() || xGrid.value.setAllTreeExpand(true);
  234. const toggleToolbarProps = obj => XEUtils.objectEach(obj, (value, key) => XEUtils.set(gridOptions.value.toolbarConfig, key, value));
  235. const reloadColumn = columns => xGrid.value.reloadColumn(columns);
  236. const getTableData = () => xGrid.value.getTableData();
  237. const reloadData = data => xGrid.value.reloadData(data);
  238. const exportEvent = async ($grid, options) => {
  239. let data = XEUtils.clone(options.data);
  240. if (options.mode == "all") {
  241. const reqData = config.framework[props.framework].queryExport(gridOptions.value);
  242. const res = await props.apiObj[props.apiKey](reqData);
  243. const response = config.framework[props.framework].parseData(res);
  244. data = response.data || [];
  245. }
  246. $grid.exportData({
  247. ...options,
  248. remote: false,
  249. columns: XEUtils.map(options.columns, item => ({ ...item, [item.type != "seq" && "exportMethod"]: ({ row, column }) => row[column?.field] || "" })),
  250. data
  251. });
  252. }
  253. const table_batch_del = ids => {
  254. ElMessageBox.confirm("是否确认删除已选择的数据?", "删除警告", {
  255. type: "warning",
  256. confirmButtonText: "确定",
  257. cancelButtonText: "取消"
  258. }).then(() => {
  259. props.apiObj.batchDel({ deleteIdList: ids }).then(() => {
  260. ElMessage.success("操作成功");
  261. getData();
  262. });
  263. });
  264. }
  265. defineExpose({
  266. selectedRows,
  267. toggleTableLoading,
  268. toggleFormEnabled,
  269. toggleTableExpand,
  270. toggleToolbarProps,
  271. reloadColumn,
  272. getTableData,
  273. reloadData,
  274. searchData,
  275. resetData
  276. })
  277. </script>
  278. <style scoped>
  279. .el-main {padding: 0 12px 12px;background: var(--el-bg-color);}
  280. </style>