feat(edit): 编辑页开发

This commit is contained in:
R524809
2026-09-11 17:28:58 +08:00
parent 1b03ea5871
commit da7342b466
21 changed files with 1910 additions and 857 deletions
+109
View File
@@ -231,6 +231,115 @@ describe('门店 HTTP 集成测试', () => {
);
});
it('同步刷新门店类目:等待 Ozon 返回并完整落库后才成功', async () => {
const owner = await register('stores-category-refresh');
const platforms = await request('/api/platforms', {
headers: headers(owner),
});
const platform = success<Array<{ id: string; code: string }>>(
platforms.body,
).data.find((item) => item.code === 'OZON');
assert.ok(platform);
const store = await createStore(owner, platform.id, '类目刷新测试店');
await database.workspaceTransaction(owner.workspace.id, async (tx) => {
await tx.query(
`UPDATE atlas.stores
SET status = 'active', credential_status = 'valid'
WHERE id = $1`,
[store.id],
);
await tx.query(
`UPDATE atlas.store_secrets SET status = 'valid'
WHERE store_id = $1 AND kind = 'seller_api_key' AND revoked_at IS NULL`,
[store.id],
);
await tx.query(
`INSERT INTO atlas.store_product_categories
(workspace_id, store_id, platform_id, external_category_id, external_type_id,
name, path, synced_at)
VALUES (current_setting('app.workspace_id')::uuid, $1, $2,
'cached-category', 'cached-type', '已有缓存', '已有缓存', now())`,
[store.id, platform.id],
);
});
const originalFetch = globalThis.fetch;
let ozonCalls = 0;
globalThis.fetch = async (input, init) => {
if (String(input).startsWith('https://api-seller.ozon.ru/')) {
ozonCalls += 1;
assert.equal(init?.method, 'POST');
return new Response(
JSON.stringify({
result: [
{
description_category_id: 17028750,
category_name: '汽车脚垫和车座套',
disabled: false,
children: [
{
type_name: '汽车罩',
type_id: 93587,
disabled: false,
children: [],
},
],
},
],
}),
{ status: 200, headers: { 'Content-Type': 'application/json' } },
);
}
return originalFetch(input, init);
};
try {
const idempotencyKey = randomUUID();
const first = await request(`/api/stores/${store.id}/category-tree-syncs`, {
method: 'POST',
headers: headers(owner, idempotencyKey),
});
assert.equal(first.response.status, 200);
assert.deepEqual(
success<{ category_count: number; active_category_count: number }>(first.body).data,
{ category_count: 2, active_category_count: 1 },
);
const replay = await request(`/api/stores/${store.id}/category-tree-syncs`, {
method: 'POST',
headers: headers(owner, idempotencyKey),
});
assert.equal(replay.response.status, 200);
assert.deepEqual(replay.body, first.body);
assert.equal(ozonCalls, 1);
await database.workspaceTransaction(owner.workspace.id, async (tx) => {
const categories = await tx.query<{
external_category_id: string;
external_type_id: string;
name: string;
path: string;
is_active: boolean;
}>(
`SELECT external_category_id, external_type_id, name, path, is_active
FROM atlas.store_product_categories
WHERE store_id = $1 ORDER BY path`,
[store.id],
);
assert.deepEqual(categories.rows.filter((row) => row.is_active), [
{
external_category_id: '17028750',
external_type_id: '93587',
name: '汽车罩',
path: '汽车脚垫和车座套 › 汽车罩',
is_active: true,
},
]);
});
} finally {
globalThis.fetch = originalFetch;
}
});
it('更新版本、切换默认门店、删除和工作空间隔离都遵守契约', async () => {
const owner = await register('stores-lifecycle');
const otherOwner = await register('stores-isolation');
@@ -7,6 +7,7 @@ import { afterAll, beforeAll, describe, it } from 'vitest';
import { DATABASE } from '../src/database/database.module.js';
import { createApplication } from '../src/main.js';
import { OutboxDispatcher } from '../../worker/src/outbox-dispatcher.js';
import { flattenCategories } from '../../worker/src/ozon-catalog-sync.js';
import { scheduleStoreCategoryTreeSync } from '../../worker/src/store-category-tree-scheduler.js';
let app: NestExpressApplication;
@@ -42,6 +43,56 @@ async function scheduleWithStoreLock() {
}
describe('门店类目树 Worker 调度集成测试', () => {
it('类型叶子继承父类目 ID,并使用 type_name 作为可选项名称', () => {
const records = flattenCategories([
{
description_category_id: 17027495,
category_name: '汽车用品',
disabled: false,
children: [
{
description_category_id: 17028750,
category_name: '汽车脚垫和车座套',
disabled: false,
children: [
{
type_name: '汽车罩',
type_id: 93587,
disabled: false,
children: [],
},
],
},
],
},
]);
assert.deepEqual(
records.map((record) => ({
category: record.external_category_id,
type: record.external_type_id,
name: record.name,
path: record.path,
parent: record.parent_key,
active: record.is_active,
})),
[
{
category: '17027495', type: '0', name: '汽车用品', path: '汽车用品',
parent: null, active: false,
},
{
category: '17028750', type: '0', name: '汽车脚垫和车座套',
path: '汽车用品 › 汽车脚垫和车座套', parent: '17027495:0', active: false,
},
{
category: '17028750', type: '93587', name: '汽车罩',
path: '汽车用品 › 汽车脚垫和车座套 › 汽车罩', parent: '17028750:0', active: true,
},
],
);
});
beforeAll(async () => {
Object.assign(process.env, {
NODE_ENV: 'test',