From f9c489531dce38e28bf474d87a097e5b9bb5291e Mon Sep 17 00:00:00 2001 From: wuzilong <704541015@qq.com> Date: Sun, 1 Nov 2026 22:20:24 +0800 Subject: [PATCH] =?UTF-8?q?fix(pl):=20=E4=BF=9D=E7=95=99=E7=BB=9F=E8=AE=A1?= =?UTF-8?q?=E5=88=86=E9=A1=B5=E6=80=BB=E6=95=B0=E5=B9=B6=E9=81=BF=E5=85=8D?= =?UTF-8?q?=E5=88=B7=E6=96=B0=E5=8F=96=E6=B6=88=E6=9D=83=E9=99=90=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web-admin/scripts/quota-statistics.test.ts | 83 ++++++++++++++++++- .../pl/quota-statistics/StatisticsPanel.vue | 10 ++- 2 files changed, 89 insertions(+), 4 deletions(-) diff --git a/web-admin/scripts/quota-statistics.test.ts b/web-admin/scripts/quota-statistics.test.ts index d711c1d6e..574282959 100644 --- a/web-admin/scripts/quota-statistics.test.ts +++ b/web-admin/scripts/quota-statistics.test.ts @@ -126,7 +126,7 @@ function harness(fixed?: string) { const state = scope.run(() => new Function( ...Object.keys(env), - `${code}; return { rows, fixedDetail, details, load, loadDetail, allowed, canEdit, keyword, setFilterState }` + `${code}; return { rows, fixedDetail, details, load, loadDetail, allowed, canEdit, keyword, setFilterState, page, total }` )(...Object.values(env)) ) return { @@ -490,3 +490,84 @@ test('closing dialog invalidates pending searches including their finally state' assert.equal(s.searching.value, false) h.stop() }) + +// Mount the real Element Plus pager. Its page-count watcher must remain active. +import ElPagination from 'element-plus/es/components/pagination/src/pagination.mjs' +test('real pagination keeps page two while loading and preserves count after request failure', async () => { + const h = harness(), + s = h.state + h.permissions[0].resolve({ all: true }) + await flush() + h.calls[0].resolve({ list: [{ id: 'first' }], total: 45 }) + await flush() + const renderer = vue.createRenderer({ + createElement: () => ({}), + createText: () => ({}), + createComment: () => ({}), + setText: () => {}, + setElementText: () => {}, + parentNode: () => null, + nextSibling: () => null, + insert: () => {}, + remove: () => {}, + patchProp: () => {} + }) + const app = renderer.createApp({ + render: () => + vue.h(ElPagination, { + currentPage: s.page.value, + total: s.total.value, + pageSize: 20, + layout: '', + 'onUpdate:current-page': (value: number) => { + s.page.value = value + }, + onCurrentChange: () => { + void s.load() + } + }) + }) + app.mount({}) + s.page.value = 2 + const pending = s.load() + await vue.nextTick() + await flush() + assert.equal(s.page.value, 2) + assert.equal(h.calls.length, 2) + assert.equal(h.calls[1].args[0].page, 2) + h.calls[1].resolve({ list: [{ id: 'second' }], total: 45 }) + await pending + await vue.nextTick() + assert.equal(s.page.value, 2) + assert.equal(s.rows.value[0].id, 'second') + const failed = s.load() + h.calls[2].reject(Error('failed')) + await failed + await vue.nextTick() + assert.equal(s.page.value, 2) + assert.equal(s.total.value, 45) + assert.deepEqual(s.rows.value, []) + h.user.getUserInfo.tenantNo = 'next' + await vue.nextTick() + assert.equal(s.page.value, 1) + assert.equal(s.total.value, 0) + app.unmount() + h.stop() +}) + +test('refresh and search while permission request is pending do not cancel initialization', async () => { + const h = harness(), + s = h.state + await s.load() + s.keyword.value = '目标' + s.setFilterState('contractNo', { text: 'HT' }) + assert.equal(h.calls.length, 0) + h.permissions[0].resolve({ menuCodes: ['pl:quota-cert:list'] }) + await flush() + assert.equal(h.calls.length, 1) + assert.deepEqual(h.calls[0].args[0], { page: 1, pageSize: 20, keyword: '目标', contractNo: 'HT' }) + h.calls[0].resolve({ list: [{ id: 'loaded' }], total: 1 }) + await flush() + assert.equal(s.rows.value[0].id, 'loaded') + h.stop() +}) diff --git a/web-admin/src/views/pl/quota-statistics/StatisticsPanel.vue b/web-admin/src/views/pl/quota-statistics/StatisticsPanel.vue index a269028c5..096fb9f31 100644 --- a/web-admin/src/views/pl/quota-statistics/StatisticsPanel.vue +++ b/web-admin/src/views/pl/quota-statistics/StatisticsPanel.vue @@ -229,19 +229,23 @@ { onChange: search } ) watchVisibleColumns(visibleColumns) - function clear() { + function clearResults() { loader.invalidate() epoch++ rows.value = [] fixedDetail.value = undefined - total.value = 0 loading.value = false error.value = '' Object.keys(details).forEach((k) => delete details[k]) } + function clear() { + clearResults() + total.value = 0 + page.value = 1 + } async function load() { - clear() if (!allowed.value || !props.active) return + clearResults() const current = epoch loading.value = true try {