fix: some
This commit is contained in:
@@ -133,13 +133,28 @@
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
let visibleItems;
|
||||
do {
|
||||
const requestedPage = page.value;
|
||||
const data = await assetApi.getPackageHistory(
|
||||
userStore.state.identifier,
|
||||
page.value,
|
||||
requestedPage,
|
||||
pageSize
|
||||
);
|
||||
const items = Array.isArray(data.items) ? data.items : [];
|
||||
visibleItems = items.filter(item => Number(item?.status) !== 4);
|
||||
const responseSize = Number(data.size) > 0 ? Number(data.size) : pageSize;
|
||||
const responseTotal = data.total === null || data.total === undefined
|
||||
? NaN : Number(data.total);
|
||||
// Pagination describes the backend's unfiltered records, not the
|
||||
// visible list. Skip fully hidden pages to reach subsequent records.
|
||||
noMore.value = Number.isFinite(responseTotal) && responseTotal >= 0
|
||||
? requestedPage * responseSize >= responseTotal
|
||||
: items.length < pageSize;
|
||||
page.value = requestedPage + 1;
|
||||
} while (visibleItems.length === 0 && !noMore.value);
|
||||
|
||||
const newData = (data.items || []).map(item => ({
|
||||
const newData = visibleItems.map(item => ({
|
||||
...item,
|
||||
activated_at: item.activated_at ? formatDate(item.activated_at) : '',
|
||||
created_at: formatDate(item.created_at),
|
||||
@@ -152,11 +167,6 @@
|
||||
packageList.splice(0, packageList.length, ...newData);
|
||||
}
|
||||
|
||||
if (newData.length < pageSize) {
|
||||
noMore.value = true;
|
||||
} else {
|
||||
page.value++;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('加载套餐历史失败', e);
|
||||
}
|
||||
|
||||
82
tests/package-history.test.mjs
Normal file
82
tests/package-history.test.mjs
Normal file
@@ -0,0 +1,82 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import vm from 'node:vm';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { createRequire } from 'node:module';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const vue = require('vue');
|
||||
const source = readFileSync(new URL('../pages/asset-package-history/asset-package-history.vue', import.meta.url), 'utf8');
|
||||
const plain = value => JSON.parse(JSON.stringify(value));
|
||||
|
||||
async function loadPage(responses) {
|
||||
const requestedPages = [];
|
||||
const context = vm.createContext({ console: { error() {} } });
|
||||
const exports = {
|
||||
vue: { ref: vue.ref, reactive: vue.reactive, onMounted() {} },
|
||||
'@/api/index.js': { assetApi: { getPackageHistory: async (identifier, page, size) => {
|
||||
assert.equal(identifier, 'A'); assert.equal(size, 10);
|
||||
requestedPages.push(page);
|
||||
return responses[page - 1] || { items: [] };
|
||||
} } },
|
||||
'@/store/index.js': { useUserStore: () => ({ state: { identifier: 'A' } }) }
|
||||
};
|
||||
const script = source.match(/<script setup>([\s\S]*?)<\/script>/)[1];
|
||||
const page = new vm.SourceTextModule(script + '\nexport { loadPackageList, packageList, noMore, historyLoaded };', { context });
|
||||
await page.link(specifier => {
|
||||
const values = exports[specifier];
|
||||
return new vm.SyntheticModule(Object.keys(values), function () {
|
||||
for (const [key, value] of Object.entries(values)) this.setExport(key, value);
|
||||
}, { context });
|
||||
});
|
||||
await page.evaluate();
|
||||
return { page: page.namespace, requestedPages };
|
||||
}
|
||||
|
||||
test('main package history hides status 4 and string 4, preserving other states and dates', async () => {
|
||||
const { page } = await loadPage([{ items: [
|
||||
{ status: 4 }, { status: '4' },
|
||||
{ status: 0, package_name: '待生效', expires_at: '2026-10-14T12:00:00Z' },
|
||||
{ status: 1 }, { status: 2 }, { status: 3 }
|
||||
] }]);
|
||||
await page.loadPackageList();
|
||||
assert.deepEqual(plain(page.packageList).map(item => item.status), [0, 1, 2, 3]);
|
||||
assert.equal(page.packageList[0].expires_at, '2026-10-14 12:00:00');
|
||||
assert.equal(page.noMore.value, true);
|
||||
});
|
||||
|
||||
test('filtering a full page must not make later records unreachable', async () => {
|
||||
const { page, requestedPages } = await loadPage([
|
||||
{ items: [...Array.from({ length: 9 }, () => ({ status: 4 })), { status: 1, id: 1 }] },
|
||||
{ items: [{ status: 2, id: 2 }] }
|
||||
]);
|
||||
await page.loadPackageList();
|
||||
assert.equal(page.noMore.value, false);
|
||||
await page.loadPackageList(true);
|
||||
assert.deepEqual(requestedPages, [1, 2]);
|
||||
assert.deepEqual(plain(page.packageList).map(item => item.id), [1, 2]);
|
||||
assert.equal(page.noMore.value, true);
|
||||
});
|
||||
|
||||
test('fully invalidated first page is skipped automatically', async () => {
|
||||
const { page, requestedPages } = await loadPage([
|
||||
{ items: Array.from({ length: 10 }, () => ({ status: 4 })) },
|
||||
{ items: [{ status: 1, id: 12 }] }
|
||||
]);
|
||||
await page.loadPackageList();
|
||||
assert.deepEqual(requestedPages, [1, 2]);
|
||||
assert.equal(page.packageList[0].id, 12);
|
||||
assert.equal(page.noMore.value, true);
|
||||
});
|
||||
|
||||
test('server total keeps pagination correct even when a filtered page is empty', async () => {
|
||||
const { page, requestedPages } = await loadPage([
|
||||
{ items: [{ status: '4' }], size: 10, total: 20 },
|
||||
{ items: [{ status: 4 }], size: 10, total: 20 }
|
||||
]);
|
||||
await page.loadPackageList();
|
||||
assert.deepEqual(requestedPages, [1, 2]);
|
||||
assert.equal(page.packageList.length, 0);
|
||||
assert.equal(page.noMore.value, true);
|
||||
assert.equal(page.historyLoaded.value, true);
|
||||
});
|
||||
Reference in New Issue
Block a user