This commit is contained in:
@@ -25,7 +25,7 @@ export const normalizeAssetInfo = (data = {}) => ({
|
||||
const normalizePackageHistoryNode = (node = {}) => ({
|
||||
...node,
|
||||
children: Array.isArray(node.children)
|
||||
? node.children.map(normalizePackageHistoryNode)
|
||||
? node.children.filter(child => Number(child?.status) !== 4).map(normalizePackageHistoryNode)
|
||||
: [],
|
||||
expand_by_default: node.expand_by_default === true || node.expand_by_default === 1
|
||||
});
|
||||
@@ -33,7 +33,7 @@ const normalizePackageHistoryNode = (node = {}) => ({
|
||||
export const normalizeAssetPackageHistory = (data = {}) => ({
|
||||
...data,
|
||||
items: Array.isArray(data.items)
|
||||
? data.items.map(normalizePackageHistoryNode)
|
||||
? data.items.filter(node => Number(node?.status) !== 4).map(normalizePackageHistoryNode)
|
||||
: [],
|
||||
page: Number(data.page),
|
||||
size: Number(data.size),
|
||||
|
||||
@@ -46,24 +46,28 @@
|
||||
if (loading.value || (append && noMore.value)) return;
|
||||
|
||||
loading.value = true;
|
||||
const requestedPage = page.value;
|
||||
|
||||
try {
|
||||
const data = await assetApi.getPackageHistory(
|
||||
userStore.state.identifier,
|
||||
requestedPage,
|
||||
pageSize
|
||||
);
|
||||
const groups = data.items;
|
||||
const responsePage = Number.isInteger(data.page) && data.page > 0
|
||||
? data.page
|
||||
: requestedPage;
|
||||
const responseSize = Number.isInteger(data.size) && data.size > 0
|
||||
? data.size
|
||||
: pageSize;
|
||||
const responseTotal = Number.isFinite(data.total) && data.total >= 0
|
||||
? data.total
|
||||
: 0;
|
||||
let groups;
|
||||
do {
|
||||
const requestedPage = page.value;
|
||||
const data = await assetApi.getPackageHistory(
|
||||
userStore.state.identifier,
|
||||
requestedPage,
|
||||
pageSize
|
||||
);
|
||||
groups = data.items;
|
||||
const responsePage = Number.isInteger(data.page) && data.page > 0
|
||||
? Math.max(data.page, requestedPage)
|
||||
: requestedPage;
|
||||
const responseSize = Number.isInteger(data.size) && data.size > 0
|
||||
? data.size
|
||||
: pageSize;
|
||||
total.value = Number.isFinite(data.total) && data.total >= 0 ? data.total : 0;
|
||||
// Total and pagination describe the unfiltered backend pages. Skip a
|
||||
// page containing only invalidated records so later records stay reachable.
|
||||
noMore.value = responsePage * responseSize >= total.value;
|
||||
page.value = responsePage + 1;
|
||||
} while (groups.length === 0 && !noMore.value);
|
||||
|
||||
if (append) {
|
||||
packageList.value.push(...groups);
|
||||
@@ -71,9 +75,6 @@
|
||||
packageList.value = groups;
|
||||
}
|
||||
|
||||
total.value = responseTotal;
|
||||
noMore.value = responsePage * responseSize >= total.value;
|
||||
page.value = responsePage + 1;
|
||||
} catch (error) {
|
||||
// The shared request layer handles the API's unified error response and authentication errors.
|
||||
console.error('加载套餐历史失败', error);
|
||||
|
||||
@@ -124,6 +124,70 @@ test('phone binding modes and success updates distinguish all four cases', async
|
||||
assert.equal(success({}, '13900000002', 'customer-asset').assetPhoneBound, true);
|
||||
});
|
||||
|
||||
test('package history hides numeric/string status 4 recursively without changing pagination', async () => {
|
||||
const r = runtime();
|
||||
const { normalizeAssetPackageHistory } = await r.load('api/modules/asset.js');
|
||||
const input = {
|
||||
page: 1, size: 10, total: 30,
|
||||
items: [
|
||||
{ package_usage_id: 1, status: 4 },
|
||||
{ package_usage_id: 2, status: '4' },
|
||||
{ package_usage_id: 3, status: 1, expand_by_default: 1, children: [
|
||||
{ package_usage_id: 4, status: 4 },
|
||||
{ package_usage_id: 5, status: 2, children: [
|
||||
{ package_usage_id: 6, status: '4' }, { package_usage_id: 7, status: 0 }
|
||||
] }
|
||||
] },
|
||||
{ package_usage_id: 8, status: 3 }
|
||||
]
|
||||
};
|
||||
const result = normalizeAssetPackageHistory(input);
|
||||
assert.deepEqual(plain(result.items).map(item => item.package_usage_id), [3, 8]);
|
||||
assert.deepEqual(plain(result.items[0].children).map(item => item.package_usage_id), [5]);
|
||||
assert.deepEqual(plain(result.items[0].children[0].children).map(item => item.package_usage_id), [7]);
|
||||
assert.equal(result.items[0].expand_by_default, true);
|
||||
assert.equal(result.total, 30);
|
||||
assert.equal(result.page, 1);
|
||||
assert.equal(input.items.length, 4);
|
||||
assert.equal(input.items[2].children.length, 2);
|
||||
});
|
||||
|
||||
test('package-history page skips all-invalid pages and keeps subsequent pages reachable', async () => {
|
||||
const r = runtime();
|
||||
const { normalizeAssetPackageHistory } = await r.load('api/modules/asset.js');
|
||||
const requestedPages = [];
|
||||
r.api.assetApi = { getPackageHistory: async (identifier, page) => {
|
||||
assert.equal(identifier, 'A'); requestedPages.push(page);
|
||||
return normalizeAssetPackageHistory({ page, size: 10, total: 40,
|
||||
items: [{ package_usage_id: page, status: page === 2 || page === 4 ? 1 : 4 }] });
|
||||
} };
|
||||
const page = await r.load('pages/asset-package-history/asset-package-history.vue', ['loadPackageList', 'packageList', 'noMore']);
|
||||
await page.loadPackageList();
|
||||
assert.deepEqual(requestedPages, [1, 2]);
|
||||
assert.deepEqual(plain(page.packageList.value).map(item => item.package_usage_id), [2]);
|
||||
assert.equal(page.noMore.value, false);
|
||||
await page.loadPackageList(true);
|
||||
assert.deepEqual(requestedPages, [1, 2, 3, 4]);
|
||||
assert.deepEqual(plain(page.packageList.value).map(item => item.package_usage_id), [2, 4]);
|
||||
assert.equal(page.noMore.value, true);
|
||||
});
|
||||
|
||||
test('package history with only invalidated records ends with an empty state', async () => {
|
||||
const r = runtime();
|
||||
const { normalizeAssetPackageHistory } = await r.load('api/modules/asset.js');
|
||||
const requestedPages = [];
|
||||
r.api.assetApi = { getPackageHistory: async (identifier, page) => {
|
||||
requestedPages.push(page);
|
||||
return normalizeAssetPackageHistory({ page, size: 10, total: 20, items: [{ status: 4 }] });
|
||||
} };
|
||||
const page = await r.load('pages/asset-package-history/asset-package-history.vue', ['loadPackageList', 'packageList', 'noMore', 'historyLoaded']);
|
||||
await page.loadPackageList();
|
||||
assert.deepEqual(requestedPages, [1, 2]);
|
||||
assert.equal(page.packageList.value.length, 0);
|
||||
assert.equal(page.noMore.value, true);
|
||||
assert.equal(page.historyLoaded.value, true);
|
||||
});
|
||||
|
||||
test('login facts are persisted per token/asset; customer phone changes never migrate assets', async () => {
|
||||
const r = runtime({ phoneBindStatus: { A: { bound: true, phone: '13900000002' } } });
|
||||
const user = (await r.load('store/user.js')).useUserStore();
|
||||
|
||||
Reference in New Issue
Block a user