5b8105ec2b
用户管理、菜单管理、不符合ASIN、数据去重总数据、查询ASIN、最低价ASIN、 商品类目、密钥管理共 8 个实体管理列表补齐两列。分组管理/店铺密钥/店铺管理 此前已带创建+修改时间,任务列表与统计报表(撞款监控、密钥用量、日志、 记录与版本)不含实体更新语义,均未改动。 关键点——时间列必须由数据库维护,否则新列是假的: 这些表的更新走 selectById → 改字段 → updateById,实体带着读出的旧 updated_at 一起写回。MySQL 规则是「UPDATE 显式给某列赋值时不触发该列的 ON UPDATE 自动更新」,不禁写就会把旧值写回去,更新时间永远冻结在首次写入 时刻。按 V125(biz_file_result)既有样板,给 7 个实体标注 @TableField(insertStrategy=NEVER, updateStrategy=NEVER)。 - V131:users / columns 补 updated_at(幂等 ADD COLUMN,仿 V125 写法)。 存量行被回填为迁移执行时刻,非真实历史变更时间(历史上无记录,无法还原) - 实体/VO:AdminUserEntity、PermissionMenuEntity、InvalidAsinDataEntity、 DedupeTotalDataEntity、ProductCategoryEntity、QueryAsinEntity、 SkipPriceAsinEntity 加/改写 updatedAt;AdminUserItemVo、PermissionMenuItemVo、 InvalidAsinDataItemVo、DedupeTotalDataItemVo 补 updatedAt; AdminUserSecretRowVo 补 createdAt(行级首次配置时间 = 三模块最早) - 查询ASIN/最低价ASIN 后端 VO 与前端 model 本就有两字段,仅补渲染 - 前端 8 页表格加列,同步修正空态/加载行的 colspan(手写表格,不同步会错位) - 测试:align-query-asin / align-skip-price 原断言「不允许有更新时间列」 (像素复刻旧版),按新需求改为断言两列存在;新增 e2e list-time-columns 覆盖 8 页表头与真实时间值渲染
45 lines
2.2 KiB
TypeScript
45 lines
2.2 KiB
TypeScript
import { expect, test, type Page } from '@playwright/test'
|
||
|
||
// 后台管理列表「创建时间 + 更新时间」两列验收(2026-09-19 需求):
|
||
// 8 个实体管理列表统一展示创建/更新时间,数据取自各列表 VO。
|
||
// mock 夹具统一给 createdAt=2026-03-01 09:15:00、updatedAt=2026-09-18 16:42:30,
|
||
// 页面统一经 formatDateTime 归一为「YYYY-MM-DD HH:mm:ss」。
|
||
|
||
const CREATED = '2026-03-01 09:15:00'
|
||
const UPDATED = '2026-09-18 16:42:30'
|
||
|
||
const PAGES: Array<{ title: string; path: string; heading: string }> = [
|
||
{ title: '用户管理', path: '/admin-vue/account/users', heading: '用户列表' },
|
||
{ title: '菜单管理', path: '/admin-vue/account/menus', heading: '菜单' },
|
||
{ title: '密钥管理', path: '/admin-vue/account/user-secrets', heading: '用户密钥列表' },
|
||
{ title: '不符合ASIN数据', path: '/admin-vue/asin-center/invalid', heading: '品牌数据列表' },
|
||
{ title: '数据去重总数据', path: '/admin-vue/asin-center/registry', heading: '数据去重总数据' },
|
||
{ title: '查询ASIN', path: '/admin-vue/asin-center/query', heading: '查询' },
|
||
{ title: '最低价ASIN', path: '/admin-vue/asin-center/skip-price', heading: '最低价' },
|
||
{ title: '商品类目', path: '/admin-vue/asin-center/categories', heading: '商品类目' },
|
||
]
|
||
|
||
async function openPage(page: Page, path: string) {
|
||
await page.goto(path)
|
||
await expect(page.locator('.panel-box table tbody tr').first()).toBeVisible({ timeout: 15000 })
|
||
}
|
||
|
||
for (const spec of PAGES) {
|
||
test(`${spec.title}:表格展示创建时间与更新时间`, async ({ page }) => {
|
||
const errors: string[] = []
|
||
page.on('pageerror', (error) => errors.push(error.message))
|
||
|
||
await openPage(page, spec.path)
|
||
|
||
const table = page.locator('.panel-box table').first()
|
||
// 表头出现两列
|
||
await expect(table.locator('thead')).toContainText('创建时间')
|
||
await expect(table.locator('thead')).toContainText('更新时间')
|
||
// 数据行渲染出真实时间值(非空、非占位符)
|
||
await expect(table.locator('tbody')).toContainText(CREATED)
|
||
await expect(table.locator('tbody')).toContainText(UPDATED)
|
||
|
||
expect(errors).toEqual([])
|
||
})
|
||
}
|