浏览代码

数据表格组件

zhuangyunsheng 2 天之前
父节点
当前提交
848113481b

+ 0 - 28
src/App.vue

@@ -5,34 +5,6 @@
 </template>
 
 <script>
-const debounce = (fn, delay) => {
-    let timer = null;
-    return function () {
-        let context = this;
-        let args = arguments;
-        clearTimeout(timer);
-        timer = setTimeout(function () {
-            fn.apply(context, args);
-        }, delay);
-    }
-}
-
-const _ResizeObserver = window.ResizeObserver;
-window.ResizeObserver = class ResizeObserver extends _ResizeObserver {
-    constructor(callback) {
-        const wrappedCallback = (entries, observer) => {
-            // 过滤掉已经不在文档中的元素对应的entry
-            const validEntries = entries.filter(entry => document.contains(entry.target));
-            if (validEntries.length > 0) {
-                callback(validEntries, observer);
-            }
-        };
-
-        callback = debounce(wrappedCallback, 16);
-        super(callback);
-    }
-}
-
 import colorTool from "@/utils/color";
 
 export default {

+ 2 - 2
src/components/scTable/helper.js

@@ -53,9 +53,9 @@ export const mapFormItemDatePicker = (field, title, config = {}) => ({
             valueFormat: "YYYY-MM-DD HH:mm:ss",
             placeholder: `请选择${title}`,
             defaultTime: XEUtils.get(config, "props.type")?.includes("range") ? [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)] : new Date(2000, 1, 1, 23, 59, 59),
-            ...XEUtils.pick(config, "props")
+            ...XEUtils.get(config, "props")
         },
         ...XEUtils.omit(config, "props")
     },
-    ...XEUtils.pick(config, "props")
+    ...XEUtils.omit(config, "props")
 })

+ 82 - 81
src/components/scTable/index.vue

@@ -1,6 +1,7 @@
 <!--
  * @Descripttion: 数据表格组件
  * @version: 1.10
+ * @Date: 2025年12月04日15:35:06
 -->
 
 <template>
@@ -29,7 +30,7 @@ import XEUtils from "xe-utils";
 import store from "@/store";
 import config from "@/config/table";
 import pagerBatchDel from "./renderer/pager-batch-del";
-import { watch, watchEffect } from "vue";
+import { computed, nextTick, watch, watchEffect } from "vue";
 
 const props = defineProps({
     apiObj: { type: Object, default: () => ({}) },
@@ -50,7 +51,34 @@ const props = defineProps({
     options: { type: Object, default: () => ({}) }
 });
 
-const foldedFormItems = computed(() => XEUtils.map(XEUtils.orderBy(XEUtils.filter(XEUtils.get(props.formConfig, "items", []), item => XEUtils.get(item, "visible", true)), "orderBy"), (item, index) => ({ ...item, folding: index > 2 })));
+const collapseStatus = ref(true);
+const foldedFormItems = ref(props.formConfig.items || []);
+const formItems = computed(() => {
+    const getActionSpan = () => {
+        const spanItems = collapseStatus.value ? XEUtils.filter(foldedFormItems.value, item => !item.folding) : foldedFormItems.value;
+        let totalSpan = 0;
+        XEUtils.arrayEach(spanItems, item => {
+            const itemSpan = (item.span || 6);
+            const remaining = 24 - (totalSpan % 24);
+            if (itemSpan > remaining) totalSpan += remaining;
+            totalSpan += itemSpan;
+        });
+
+        const remainder = 24 - (totalSpan % 24);
+        return remainder < 5 ? 24 : remainder;
+    };
+
+    return [
+        ...foldedFormItems.value, {
+            align: "right",
+            className: "query-action__item",
+            slots: { default: "queryAction" },
+            span: getActionSpan(),
+            visible: foldedFormItems.value.length > 0,
+            collapseNode: foldedFormItems.value.length > 3
+        }
+    ]
+});
 
 const xGrid = ref();
 const gridOptions = reactive({
@@ -67,31 +95,11 @@ const gridOptions = reactive({
     layouts: props.layouts,
     formConfig: {
         enabled: true,
-        className: "vxe-table-query",
-        titleAlign: "right",
-        collapseStatus: true,
         span: 6,
-        items: [
-            ...foldedFormItems.value, {
-                align: "right",
-                slots: { default: "queryAction" },
-                visible: foldedFormItems.value.length > 0,
-                collapseNode: foldedFormItems.value.length > 3,
-                className: ({ item }) => {
-                    const spanItems = (!gridOptions.formConfig.collapseStatus && foldedFormItems.value) || XEUtils.filter(foldedFormItems.value, f_item => !f_item.folding);
-                    let spanItemsSum = 0;
-                    XEUtils.arrayEach(spanItems, s_item => {
-                        const spanCount = (s_item.span || 6);
-                        if (spanCount > 24 - (spanItemsSum % 24)) spanItemsSum += 24 - (spanItemsSum % 24);
-                        spanItemsSum += spanCount;
-                    })
-                    const remainder = 24 - (spanItemsSum % 24);
-
-                    item.span = remainder < 5 && 24 || remainder;
-                    return "query-action__item";
-                }
-            }
-        ],
+        titleAlign: "right",
+        className: "vxe-table-query",
+        collapseStatus: collapseStatus,
+        items: formItems,
         ...XEUtils.omit(props.formConfig, "items")
     },
     toolbarConfig: {
@@ -124,8 +132,8 @@ const gridOptions = reactive({
     },
     exportConfig: {
         type: ["xlsx"],
-        modes: XEUtils.find(props.columns, item => XEUtils.get(item, "visible", true) && XEUtils.includes(config.exportExcludeFields, item.type)) && ["current", "selected", "all"] || ["current", "all"],
-        columns: XEUtils.filter(props.columns, item => !(XEUtils.includes(config.exportExcludeFields, item.type)) && XEUtils.get(item, "visible", true)),
+        modes: XEUtils.find(props.columns, item => item.visible !== false && XEUtils.includes(config.exportExcludeFields, item.type)) && ["current", "selected", "all"] || ["current", "all"],
+        columns: XEUtils.filter(props.columns, item => !(XEUtils.includes(config.exportExcludeFields, item.type)) && item.visible !== false)
     },
     rowConfig: {
         keyField: props.rowKey,
@@ -182,70 +190,72 @@ const gridOptions = reactive({
     ...props.options
 });
 
+const formatScoped = context => ({ ...context, row: XEUtils.get(XEUtils.findTree(XEUtils.get(context, "$grid", XEUtils.get(context, "$table"))?.getData(), item => item.id == context.rowid), "item") || context.row });
+
+const resizeTable = XEUtils.debounce(() => {
+    nextTick(() => {
+        if (store.state.global.ismobile) XEUtils.set(gridOptions, "maxHeight", 1048);
+        else XEUtils.set(gridOptions, "maxHeight", (props.maxHeight || xGrid.value?.$el.parentElement.offsetHeight) - 12);
+    });
+}, 300);
+
+const organizeFormItems = () => foldedFormItems.value = XEUtils.map(XEUtils.orderBy(XEUtils.filter(XEUtils.get(props.formConfig, "items", []), item => (item.visible !== false) && (!item.visibleMethod || item.visibleMethod(XEUtils.pick(props.formConfig, "data")))), "orderBy"), (item, index) => ({ ...item, folding: index > 2 }));
 watchEffect(() => {
+    organizeFormItems();
     XEUtils.objectEach(props.options, (value, key) => {
         if (XEUtils.has(gridOptions, key) && (XEUtils.isObject(value) || XEUtils.isArray(value))) XEUtils.merge(gridOptions[key], value);
         else XEUtils.set(gridOptions, key, value);
     });
-})
-
-watch(() => gridOptions.data, val => {
-    if (props.columns.find(item => item.type == "checkbox" && XEUtils.get(item, "visible", true)) && props.checkedRows.length) {
-        xGrid.value?.setCheckboxRow(props.checkedRows, true);
-    }
-
-    if (props.columns.find(item => item.type == "radio" && XEUtils.get(item, "visible", true)) && props.checkedRows.length) {
-        xGrid.value?.setRadioRow(XEUtils.first(props.checkedRows));
-    }
-}, { deep: true });
 
-const formatScoped = context => ({ ...context, row: XEUtils.get(XEUtils.findTree(XEUtils.get(context, "$grid", XEUtils.get(context, "$table"))?.getData(), item => item.id == context.rowid), "item") || context.row });
+    nextTick(() => {
+        if (props.checkedRows && props.checkedRows.length) {
+            props.columns.find(item => item.type == "checkbox" && item.visible !== false) && xGrid.value?.setCheckboxRow(props.checkedRows, true);
+            props.columns.find(item => item.type == "radio" && item.visible !== false) && xGrid.value?.setRadioRow(XEUtils.first(props.checkedRows));
+        }
+    });
+});
 
-addEventListener("resize", () => resizeTable());
 onMounted(() => {
     resizeTable();
     getData();
+    addEventListener("resize", resizeTable, { passive: true });
 });
 
-const resizeTable = () => {
-    nextTick(() => {
-        if (store.state.global.ismobile) XEUtils.set(gridOptions, "maxHeight", 1048);
-        else XEUtils.set(gridOptions, "maxHeight", (props.maxHeight || xGrid.value?.$el.parentElement.offsetHeight) - 12);
-    });
-}
+onUnmounted(() => {
+    removeEventListener("resize", resizeTable);
+    resizeTable.cancel();
+});
 
 // 获取数据
 const getData = () => {
-    nextTick(() => {
-        if (!props.apiObj || XEUtils.isEmpty(props.apiObj)) {
-            if (props.options.data && props.options.data.length > 0) {
-                gridOptions.pagerConfig.total = props.options.data.length;
-                return;
-            }
-
-            gridOptions.data = [];
-            gridOptions.pagerConfig.total = 0;
+    if (!props.apiObj || XEUtils.isEmpty(props.apiObj)) {
+        if (props.options.data && props.options.data.length > 0) {
+            gridOptions.pagerConfig.total = props.options.data.length;
             return;
         }
 
-        gridOptions.loading = true;
-        const reqData = config.queryData(gridOptions, props.paramsColums);
-        props.apiObj[props.apiKey](reqData).then(res => {
-            const response = config.parseData(res);
-            gridOptions.data = response.data || [];
-            gridOptions.pagerConfig.total = response.total || 0;
-            gridOptions.loading = false;
-        }).catch(error => {
-            gridOptions.loading = false;
-            gridOptions.data = [];
-            gridOptions.pagerConfig.total = 0;
-        });
+        gridOptions.data = [];
+        gridOptions.pagerConfig.total = 0;
+        return;
+    }
+
+    gridOptions.loading = true;
+    const reqData = config.queryData(gridOptions, props.paramsColums);
+    props.apiObj[props.apiKey](reqData).then(res => {
+        const response = config.parseData(res);
+        gridOptions.data = response.data || [];
+        gridOptions.pagerConfig.total = response.total || 0;
+        gridOptions.loading = false;
+    }).catch(error => {
+        gridOptions.loading = false;
+        gridOptions.data = [];
+        gridOptions.pagerConfig.total = 0;
     });
 }
 
 const getAllData = () => {
     return new Promise((resolve, reject) => {
-        if (!props.apiObj) resolve([]);
+        if (!props.apiObj || XEUtils.isEmpty(props.apiObj)) resolve([]);
         
         const reqData = config.queryExport(gridOptions, props.paramsColums);
         props.apiObj[props.apiKey](reqData).then(res => {
@@ -276,12 +286,12 @@ const resetData = () => {
 }
 
 const getSelectRows = () => {
-    if (props.columns.find(item => item.type == "checkbox" && XEUtils.get(item, "visible", true))) {
+    if (props.columns.find(item => item.type == "checkbox" && item.visible !== false)) {
         const selectRecords = xGrid.value?.getCheckboxRecords();
         const selectReserveRecords = xGrid.value?.getCheckboxReserveRecords();
         return selectRecords.concat(selectReserveRecords);
     }
-    if (props.columns.find(item => item.type == "radio" && XEUtils.get(item, "visible", true))) {
+    if (props.columns.find(item => item.type == "radio" && item.visible !== false)) {
         const currRow = xGrid.value?.getRadioRecord();
         const currReserveRow = xGrid.value?.getRadioReserveRecord();
         return [currRow || currReserveRow];
@@ -289,16 +299,10 @@ const getSelectRows = () => {
     return [];
 }
 
-const formCollapseEvent = ({ collapse }) => gridOptions.formConfig.collapseStatus = collapse;
-
-const toggleTableLoading = value => gridOptions.loading = value;
-
-const toggleFormEnabled = () => gridOptions.formConfig.enabled = !gridOptions.formConfig.enabled;
+const formCollapseEvent = ({ collapse }) => collapseStatus.value = collapse;
 
 const toggleTableExpand = () => xGrid.value.getTreeExpandRecords().length && xGrid.value.clearTreeExpand() || xGrid.value.setAllTreeExpand(true);
 
-const toggleToolbarProps = obj => XEUtils.objectEach(obj, (value, key) => XEUtils.set(gridOptions.toolbarConfig, key, value));
-
 const reloadColumn = columns => xGrid.value.reloadColumn(columns);
 
 const getTableData = () => xGrid.value.getTableData();
@@ -320,10 +324,7 @@ const table_batch_del = ids => {
 
 defineExpose({
     getSelectRows,
-    toggleTableLoading,
-    toggleFormEnabled,
     toggleTableExpand,
-    toggleToolbarProps,
     reloadColumn,
     getTableData,
     reloadData,

+ 0 - 3
src/components/scTable/renderer/form-select.vue

@@ -20,9 +20,6 @@ const options = ref(props.renderOpts.options || []);
 const optionProps = reactive(props.renderOpts.optionProps || config.props);
 
 const getRemoteData = async () => {
-    console.log('renderOpts',props.renderOpts)
-    console.log('params',props.params)
-
     if (props.renderOpts.api) {
         loading.value = true;
         options.value = await config.queryData(props.renderOpts.api);

+ 1 - 1
src/views/sales/order/index.vue

@@ -72,9 +72,9 @@ const formConfig = reactive({
 const paramsColums = reactive([
     { column: "orderBy", defaultValue: "code_asc" },
     { column: "codeLike" },
-    { column: "contractNoLike" },
     { column: "status" },
     { column: "customerId" },
+    { column: "contractNoLike" },
     { column: "orderDateBegin", field: "orderDate[0]" },
     { column: "orderDateEnd", field: "orderDate[1]" }
 ]);