From 6b6dc2c4f3b397b24fbd3534539dfbaeb2ba6dff Mon Sep 17 00:00:00 2001 From: "pikachu1995@126.com" Date: Tue, 20 Oct 2026 14:02:03 +0800 Subject: [PATCH] =?UTF-8?q?refactor(manager):=20=E5=BC=95=E5=85=A5=20useTa?= =?UTF-8?q?ble=20=E5=B9=B6=E9=87=8D=E6=9E=84=E9=87=87=E8=B4=AD/=E8=B4=A2?= =?UTF-8?q?=E5=8A=A1/=E4=BC=9A=E5=91=98=E7=AD=8910=E4=B8=AA=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 引入通用 useTable composable 实现分页与查询标准化 - 重构采购单/入库单/报损单/盘点单4个采购管理列表页 - 重构退款日志/预存款流水/会员充值/会员经验等财务与会员日志列表页 - 重构支付流水与退款流水列表页 - 统一竞态防护与 loading 状态管理,消除 150+ 行冗余样板代码 --- manager/src/utils/useTable.js | 119 ++++++++++++++++++ manager/src/views/finance/refundLog.vue | 27 +--- manager/src/views/member/advance/recharge.vue | 33 ++--- .../src/views/member/advance/walletLog.vue | 33 ++--- .../src/views/member/grade/experience-log.vue | 48 +++---- manager/src/views/order/flow/paymentLog.vue | 34 ++--- manager/src/views/order/flow/refundLog.vue | 34 ++--- .../views/procurement/damage-report/list.vue | 30 +---- .../src/views/procurement/inbound/list.vue | 30 +---- .../procurement/inventory-count/list.vue | 26 +--- .../views/procurement/purchase-order/list.vue | 28 +---- 11 files changed, 201 insertions(+), 241 deletions(-) create mode 100644 manager/src/utils/useTable.js diff --git a/manager/src/utils/useTable.js b/manager/src/utils/useTable.js new file mode 100644 index 000000000..69af9ba76 --- /dev/null +++ b/manager/src/utils/useTable.js @@ -0,0 +1,119 @@ +import { onMounted, reactive, ref } from "vue"; + +/** + * 分页列表通用逻辑:loading / data / total / searchForm / 查询 / 重置 / 刷新。 + * + * 用法: + * const { loading, data, total, searchForm, getDataList, handleSearch, resetSearch } = + * useTable(getXxxPage, { form: { name: "", status: "" } }); + * + * + * + * + * @param {(params: object) => Promise} fetcher 请求函数,入参为 searchForm + * @param {object} [options] + * @param {object} [options.form] 查询条件默认值(会与分页/排序默认值合并) + * @param {number} [options.pageSize=10] 默认每页条数 + * @param {string} [options.sort] 默认排序字段 + * @param {string} [options.order] 默认排序方向 + * @param {boolean} [options.immediate=true] 挂载后是否自动查询 + * @param {(res: any) => ({records: any[], total: number}|null|undefined)} [options.resolve] + * 从响应中取出 { records, total };返回空表示请求失败(保持原数据)。 + * 默认:res.success 为真时取 res.result.records / res.result.total + * @param {(params: object) => object} [options.beforeRequest] 请求前加工参数(返回新对象,不影响 searchForm) + * @param {(res: any, parsed: {records: any[], total: number}) => void} [options.onSuccess] + * 查询成功且数据已更新后回调(仅最后一次请求触发),可用于刷新状态计数等 + */ +export function useTable(fetcher, options = {}) { + const { + form = {}, + pageSize = 10, + sort, + order, + immediate = true, + resolve = defaultResolve, + beforeRequest, + onSuccess, + } = options; + + const loading = ref(false); + const data = ref([]); + const total = ref(0); + + const initialForm = { ...form }; + const searchForm = reactive({ + pageNumber: 1, + pageSize, + ...(sort ? { sort } : {}), + ...(order ? { order } : {}), + ...form, + }); + + // 只采纳最后一次请求的结果,避免快速切换页码/条件时旧响应覆盖新数据 + let requestId = 0; + + function getDataList() { + const current = ++requestId; + loading.value = true; + const params = beforeRequest ? beforeRequest({ ...searchForm }) : searchForm; + return Promise.resolve(fetcher(params)) + .then((res) => { + if (current !== requestId) return res; + const parsed = resolve(res); + if (parsed) { + data.value = parsed.records || []; + total.value = parsed.total || 0; + if (onSuccess) onSuccess(res, parsed); + } + return res; + }) + .finally(() => { + if (current === requestId) loading.value = false; + }); + } + + /** 以当前条件从第 1 页重新查询 */ + function handleSearch() { + searchForm.pageNumber = 1; + return getDataList(); + } + + /** 恢复查询条件默认值(保留当前每页条数)并从第 1 页查询 */ + function resetSearch() { + Object.assign(searchForm, initialForm); + return handleSearch(); + } + + /** 保持当前页刷新(如删除/修改后) */ + function refresh() { + return getDataList(); + } + + if (immediate) { + onMounted(getDataList); + } + + return { + loading, + data, + total, + searchForm, + getDataList, + handleSearch, + resetSearch, + refresh, + }; +} + +function defaultResolve(res) { + if (res && res.success && res.result) { + return { records: res.result.records, total: res.result.total }; + } + return null; +} diff --git a/manager/src/views/finance/refundLog.vue b/manager/src/views/finance/refundLog.vue index 175036a98..871fcc30c 100644 --- a/manager/src/views/finance/refundLog.vue +++ b/manager/src/views/finance/refundLog.vue @@ -35,35 +35,18 @@