From b9ce0588483889166b59e804087487b9b4d4d95c Mon Sep 17 00:00:00 2001 From: ThearchyHelios Date: Sun, 4 Oct 2026 02:00:48 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E7=9B=AE=E5=BD=95=20F2b=20/?= =?UTF-8?q?=20C1=EF=BC=9A=E6=B8=85=E5=8D=95=E7=AD=9B=E9=80=89=E3=80=8C?= =?UTF-8?q?=E5=85=A8=E9=83=A8=E5=B7=B2=E7=A1=AE=E8=AE=A4=E3=80=8D=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E3=80=8C=E6=B2=A1=E6=9C=89=E5=BE=85=E7=A1=AE=E8=AE=A4?= =?UTF-8?q?=E9=A1=B9=E3=80=8D=EF=BC=8C=E3=80=8C=E6=9C=89=E6=9C=AA=E7=A1=AE?= =?UTF-8?q?=E8=AE=A4=E9=A1=B9=E3=80=8D=E6=94=B9=E4=B8=BA=E3=80=8C=E6=9C=89?= =?UTF-8?q?=E5=BE=85=E7=A1=AE=E8=AE=A4=E9=A1=B9=E3=80=8D=EF=BC=8C=E6=A6=82?= =?UTF-8?q?=E8=A7=88=E3=80=81=E9=A1=B6=E9=83=A8=E6=91=98=E8=A6=81=E3=80=81?= =?UTF-8?q?=E6=8E=92=E5=BA=8F=E5=90=8C=E6=AD=A5=E6=94=B9=E5=86=99=E2=80=94?= =?UTF-8?q?=E2=80=94=E3=80=8C=E5=B7=B2=E7=A1=AE=E8=AE=A4=E3=80=8D=E4=B8=93?= =?UTF-8?q?=E6=8C=87=E4=BA=BA=E5=B7=A5=E7=A1=AE=E8=AE=A4=EF=BC=8C=E5=8F=AA?= =?UTF-8?q?=E6=9C=89=E5=B7=B2=E9=AA=8C=E8=AF=81=E9=A1=B9=E7=9A=84=E8=A1=A8?= =?UTF-8?q?=E4=B8=8D=E5=86=8D=E8=AF=B4=E5=85=A8=E9=83=A8=E5=B7=B2=E7=A1=AE?= =?UTF-8?q?=E8=AE=A4=EF=BC=9B=E6=82=AC=E5=81=9C=E5=86=99=E6=98=8E=E5=B7=B2?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E7=9A=84=E9=A1=B9=E7=94=B1=E5=A4=96=E9=94=AE?= =?UTF-8?q?=E7=BA=A6=E6=9D=9F=E6=88=96=E6=95=B0=E6=8D=AE=E5=89=96=E6=9E=90?= =?UTF-8?q?=E6=A0=B8=E5=AE=9E=E3=80=81=E4=B8=8D=E9=9C=80=E8=A6=81=E9=80=90?= =?UTF-8?q?=E9=A1=B9=E7=A1=AE=E8=AE=A4=EF=BC=9B=E8=A1=A5=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E7=9A=84=E6=96=AD=E8=A8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/lib/terms.ts | 17 +++++++++-------- frontend/src/pages/catalog/CatalogPage.tsx | 2 +- frontend/src/pages/catalog/model.ts | 2 +- scripts/check-catalog.mjs | 21 ++++++++++++--------- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/frontend/src/lib/terms.ts b/frontend/src/lib/terms.ts index 05dbbb7a..881af920 100644 --- a/frontend/src/lib/terms.ts +++ b/frontend/src/lib/terms.ts @@ -1988,15 +1988,16 @@ export const CATALOG_TEXT = { // ---- 表清单 search: '搜索表名或中文名', filterLabel: '按状态筛选', - filter: { all: '全部', pending: '有未确认项', done: '全部已确认', none: '没有目录' }, + // 「已确认」专指人工确认:只有已验证项(外键约束、数据剖析核实)的表不能说「全部已确认」,按「没有待确认项」说 + filter: { all: '全部', pending: '有待确认项', done: '没有待确认项', none: '没有目录' }, filterHint: { all: '全部表', - pending: '还有推断状态的项', - done: '有目录,且没有推断状态的项', + pending: '还有推断状态的项,需要逐项确认', + done: '有目录,没有推断状态的项。已验证的项由外键约束或数据剖析核实,不需要逐项确认', none: '还没有任何目录项', }, sortLabel: '排序', - sort: { usage: '按使用次数', pending: '按未确认项', name: '按表名' }, + sort: { usage: '按使用次数', pending: '按待确认项', name: '按表名' }, tableCount: (shown: number, total: number) => (shown === total ? `${formatNumber(total)} 张表` : `${formatNumber(shown)} / ${formatNumber(total)} 张表`), selectAll: '全选当前结果', @@ -2017,16 +2018,16 @@ export const CATALOG_TEXT = { usageLead: (used: number) => `运行中查询过的 ${formatNumber(used)} 张表里,`, usagePending: (n: number) => `有 ${formatNumber(n)} 张还有推断项未确认`, usageNone: (n: number) => `${formatNumber(n)} 张还没有目录`, - usageAllDone: (used: number) => `运行中查询过的 ${formatNumber(used)} 张表都已确认`, - usageHintPending: '筛选有未确认项的表,按使用次数排序', + usageAllDone: (used: number) => `运行中查询过的 ${formatNumber(used)} 张表都没有待确认项`, + usageHintPending: '筛选有待确认项的表,按使用次数排序', usageHintNone: '筛选没有目录的表,按使用次数排序', // ---- 概览(没有选中表时) overviewTitle: '选择一张表开始审阅', overviewBody: '按使用次数从高到低逐表确认。推断的项只作提示,确认后才参与 SQL 检查。', overviewStats: (total: number, pending: number, done: number, none: number) => - `共 ${formatNumber(total)} 张表:${formatNumber(pending)} 张有未确认项,${formatNumber(done)} 张全部已确认,${formatNumber(none)} 张没有目录`, + `共 ${formatNumber(total)} 张表:${formatNumber(pending)} 张有待确认项,${formatNumber(done)} 张没有待确认项,${formatNumber(none)} 张没有目录`, reviewNext: (name: string) => `审阅「${name}」`, - reviewNextHint: '使用次数最多、还有未确认项的表', + reviewNextHint: '使用次数最多、还有待确认项的表', legend: '状态说明', // ---- 起草 draft: '起草', diff --git a/frontend/src/pages/catalog/CatalogPage.tsx b/frontend/src/pages/catalog/CatalogPage.tsx index 5b2ee0f6..0846a546 100644 --- a/frontend/src/pages/catalog/CatalogPage.tsx +++ b/frontend/src/pages/catalog/CatalogPage.tsx @@ -498,7 +498,7 @@ function Overview({ rows, empty, systemNotes, draft, onOpen }: { ) } -/** 审阅进度:有未确认项 / 全部已确认 / 没有目录的表各占多少 */ +/** 审阅进度:有待确认项 / 没有待确认项 / 没有目录的表各占多少 */ function ProgressBar({ pending, done, none }: { pending: number; done: number; none: number }) { const total = pending + done + none || 1 const seg = (n: number, color: string, label: string) => (n > 0 diff --git a/frontend/src/pages/catalog/model.ts b/frontend/src/pages/catalog/model.ts index ee1bf6ad..e2974a2e 100644 --- a/frontend/src/pages/catalog/model.ts +++ b/frontend/src/pages/catalog/model.ts @@ -130,7 +130,7 @@ export function visibleRows(rows: CatalogTableRow[], q: string, filter: ListFilt /** * 「用到但没确认」:运行中查询过的表(使用次数大于 0、还在表结构里)一共几张,其中几张还有推断项、几张还没有目录。 - * 页面顶部的摘要按它写,点进去复用清单的筛选(有未确认项 / 没有目录)和按使用次数排序,不另做一套 + * 页面顶部的摘要按它写,点进去复用清单的筛选(有待确认项 / 没有目录)和按使用次数排序,不另做一套 */ export function usageSummary(rows: CatalogTableRow[]): { used: number; pending: number; none: number } { const out = { used: 0, pending: 0, none: 0 } diff --git a/scripts/check-catalog.mjs b/scripts/check-catalog.mjs index 855062d9..467c69fa 100644 --- a/scripts/check-catalog.mjs +++ b/scripts/check-catalog.mjs @@ -552,26 +552,29 @@ await section('数据目录 · 表清单的排序与筛选', async () => { // 按状态筛选 const counts = await page.locator('[data-catalog-filter] [data-filter]').evaluateAll((els) => els.map((e) => e.innerText.replace(/\s+/g, ''))) - check('筛选按钮带数量:全部 152、有未确认项 5、全部已确认 3、没有目录 144', counts.join('|') === '全部152|有未确认项5|全部已确认3|没有目录144', counts.join('|')) + check('筛选按钮带数量:全部 152、有待确认项 5、没有待确认项 3、没有目录 144', counts.join('|') === '全部152|有待确认项5|没有待确认项3|没有目录144', counts.join('|')) + // 「已确认」专指人工确认:只有已验证项的表不说「全部已确认」,说「没有待确认项」,悬停写明已验证的不需要逐项确认 + check('筛选不说「全部已确认」(只有已验证项的表也在这一组)', !counts.join('|').includes('全部已确认') + && (await page.locator('[data-filter="done"]').getAttribute('title')).includes('已验证的项由外键约束或数据剖析核实')) await page.locator('[data-filter="pending"]').click() names = await rowNames(page) - check('「有未确认项」:只有还有推断项的表', names.join(',') === 'visits,order_items,ticket_types,store_sales,inventory_snapshots', names.join(',')) + check('「有待确认项」:只有还有推断项的表', names.join(',') === 'visits,order_items,ticket_types,store_sales,inventory_snapshots', names.join(',')) await page.locator('[data-filter="done"]').click() names = await rowNames(page) - check('「全部已确认」:订单、景区、只剩目录的旧表', names.join(',') === 'orders,parks,legacy_coupons', names.join(',')) + check('「没有待确认项」:订单、景区、只剩目录的旧表', names.join(',') === 'orders,parks,legacy_coupons', names.join(',')) await page.locator('[data-filter="none"]').click() check('「没有目录」:144 张', (await rowNames(page)).length === 144) // 筛选组是单选组:方向键在组内移动并选中 await page.locator('[data-filter="none"]').focus() await page.keyboard.press('ArrowLeft') - check('筛选组:← 选中前一项「全部已确认」', (await page.locator('[data-catalog-filter]').getAttribute('data-catalog-filter')) === 'done') + check('筛选组:← 选中前一项「没有待确认项」', (await page.locator('[data-catalog-filter]').getAttribute('data-catalog-filter')) === 'done') await page.locator('[data-filter="all"]').click() // 排序 await page.locator('[data-catalog-sort]').selectOption('pending') names = await rowNames(page) const proposedOf = (n) => countsOf(state.tables[S1].find((t) => t.name === n)?.notes).proposed - check('按未确认项排序:推断项最多的在前', proposedOf(names[0]) >= proposedOf(names[1]) && proposedOf(names[1]) >= proposedOf(names[2]) + check('按待确认项排序:推断项最多的在前', proposedOf(names[0]) >= proposedOf(names[1]) && proposedOf(names[1]) >= proposedOf(names[2]) && names.at(-1) === 'legacy_coupons', names.slice(0, 3).join(',')) await page.locator('[data-catalog-sort]').selectOption('name') names = await rowNames(page) @@ -642,7 +645,7 @@ await section('数据目录 · 用到但没确认(顶部摘要)', async () = const text = await bar.innerText() check('写成一句话', text.includes(`运行中查询过的 ${used.length} 张表里,有 ${pending} 张还有推断项未确认,${none} 张还没有目录`), text) await bar.locator('[data-usage-focus="pending"]').click() - check('点「还有推断项未确认」:切到「有未确认项」筛选', + check('点「还有推断项未确认」:切到「有待确认项」筛选', (await page.locator('[data-catalog-filter]').getAttribute('data-catalog-filter')) === 'pending') check('……排序是按使用次数', await page.locator('[data-catalog-sort]').inputValue() === 'usage') const shown = await rowNames(page) @@ -671,7 +674,7 @@ await section('数据目录 · 用到但没确认(顶部摘要)', async () = for (const t of state.tables[S1]) if (!t.notes && t.usage > 0) t.notes = { label: item(t.name, 'human') } await goto(page, `/data/catalog/${S1}`) await bar.waitFor({ timeout: 3000 }) - check('都确认了:写「都已确认」,没有按钮', (await bar.innerText()).includes(`运行中查询过的 ${used.length} 张表都已确认`) + check('都确认了:写「都没有待确认项」,没有按钮', (await bar.innerText()).includes(`运行中查询过的 ${used.length} 张表都没有待确认项`) && await bar.locator('[data-usage-focus]').count() === 0, await bar.innerText()) check('没有运行时报错', errors.length === 0, errors.join(' | ')) await close() @@ -948,7 +951,7 @@ await section('数据目录 · 批量确认', async () => { check('……提交后按钮消失、表头计数没有推断', await until(async () => (await btn.count()) === 0) && (await detail(page).locator('header [data-counts]').getAttribute('data-counts')).startsWith('0,')) await until(async () => (await rowCounts(page, 'order_items')).startsWith('0,')) - check('……清单上这张表移到「全部已确认」', (await page.locator('[data-catalog-row="order_items"]').getAttribute('data-progress')) === 'done') + check('……清单上这张表移到「没有待确认项」', (await page.locator('[data-catalog-row="order_items"]').getAttribute('data-progress')) === 'done') // 确认本列推断:只动这一列 await openDetail(page, S1, 'store_sales') @@ -1169,7 +1172,7 @@ await section('数据目录 · 空状态与导入表格', async () => { await goto(page, `/data/catalog/${S1}`) const ovt = await page.locator('[data-catalog-overview]').innerText() - check('有目录、没选表时:写审阅进度,给出使用最多、还有推断项的表', ovt.includes('共 152 张表:5 张有未确认项,3 张全部已确认,144 张没有目录') + check('有目录、没选表时:写审阅进度,给出使用最多、还有推断项的表', ovt.includes('共 152 张表:5 张有待确认项,3 张没有待确认项,144 张没有目录') && (await page.locator('[data-catalog-review-next]').getAttribute('data-catalog-review-next')) === 'visits', ovt.replace(/\s+/g, ' ').slice(0, 120)) // 导入表格的源:说明由系统生成,只读