feat(后台管理): 实体管理列表统一展示创建时间/更新时间

用户管理、菜单管理、不符合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 页表头与真实时间值渲染
This commit is contained in:
2026-09-19 15:53:01 +08:00
parent 5fcb449946
commit 5b8105ec2b
36 changed files with 418 additions and 25 deletions
@@ -220,13 +220,183 @@ const server = createServer((req, res) => {
return json(res, {
success: true,
data: {
items: [{ id: 1, username: 'admin', role: 'super_admin', creatorUsername: 'system', createdAt: '2026-01-01 00:00:00' }],
items: [{ id: 1, username: 'admin', role: 'super_admin', creatorUsername: 'system', created_at: '2026-03-01 09:15:00', updated_at: '2026-09-18 16:42:30' }],
total: 1,
},
})
}
if (url === '/api/admin/permission-menus') {
return json(res, { success: true, data: { items: [] } })
// 菜单管理列表:一条根节点,带创建/更新时间(验收时间列)。
return json(res, {
success: true,
data: [
{
id: 1,
name: '用户管理',
column_key: 'admin_users',
parent_id: null,
menu_type: 'admin',
route_path: 'account/users',
sort_order: 10,
created_at: '2026-03-01T09:15:00',
updated_at: '2026-09-18T16:42:30',
},
],
})
}
if (url === '/api/admin/invalid-asin-data') {
return json(res, {
success: true,
data: {
items: [
{
id: 1,
dataValue: 'B0INVALID1',
brand: '测试品牌',
groupId: 1,
groupName: '测试分组',
recordSource: 'MANUAL',
createdAt: '2026-03-01 09:15:00',
updatedAt: '2026-09-18 16:42:30',
},
],
total: 1,
page: 1,
pageSize: 10,
},
})
}
if (url === '/api/admin/dedupe-total-data') {
return json(res, {
success: true,
data: {
items: [
{
id: 1,
dataValue: 'B0DEDUPE01',
country: 'DE',
groupId: 1,
groupName: '测试分组',
uploaderUserId: 1,
username: 'admin',
createdAt: '2026-03-01 09:15:00',
updatedAt: '2026-09-18 16:42:30',
},
],
total: 1,
page: 1,
pageSize: 10,
},
})
}
if (url === '/api/admin/query-asins') {
return json(res, {
success: true,
data: {
items: [
{
id: 1,
groupId: 1,
groupName: '测试分组',
shopName: '测试店铺',
asinDe: 'B0QUERY001',
asinUk: '',
asinFr: '',
asinIt: '',
asinEs: '',
createdAt: '2026-03-01 09:15:00',
updatedAt: '2026-09-18 16:42:30',
},
],
total: 1,
page: 1,
pageSize: 10,
},
})
}
if (url === '/api/admin/skip-price-asins') {
return json(res, {
success: true,
data: {
items: [
{
id: 1,
groupId: 1,
groupName: '测试分组',
shopName: '测试店铺',
asinDe: 'B0SKIP0001',
minimumPriceDe: 9.99,
asinUk: '',
minimumPriceUk: null,
asinFr: '',
minimumPriceFr: null,
asinIt: '',
minimumPriceIt: null,
asinEs: '',
minimumPriceEs: null,
createdAt: '2026-03-01 09:15:00',
updatedAt: '2026-09-18 16:42:30',
},
],
total: 1,
page: 1,
pageSize: 10,
},
})
}
if (url === '/api/admin/product-categories/children') {
return json(res, {
success: true,
data: {
items: [
{
id: 1,
parentId: null,
name: '护肤品',
categoryKey: 'skincare',
sortOrder: 10,
description: '测试备注',
isBuiltin: true,
childCount: 0,
level: 0,
path: '护肤品',
createdAt: '2026-03-01 09:15:00',
updatedAt: '2026-09-18 16:42:30',
},
],
total: 1,
page: 1,
pageSize: 10,
hasMore: false,
},
})
}
if (url === '/api/admin/user-secrets') {
const emptyModule = { moduleKey: '', moduleLabel: '', masked: '', full: '', exists: false, checkStatus: 'unknown', checkCode: '', checkMessage: '', checkLatencyMs: null, checkedAt: null, updatedAt: null }
return json(res, {
success: true,
data: {
items: [
{
userId: 1,
username: 'admin',
groups: [],
leaderUsername: '',
similarAsin: { ...emptyModule, moduleKey: 'similar-asin', moduleLabel: '货源查询密钥' },
appearancePatent: { ...emptyModule, moduleKey: 'appearance-patent', moduleLabel: '外观专利密钥' },
proxy: { ...emptyModule, moduleKey: 'proxy', moduleLabel: '代理设置' },
status: 'unknown',
statusMessage: '',
createdAt: '2026-03-01 09:15:00',
updatedAt: '2026-09-18 16:42:30',
},
],
total: 1,
page: 1,
pageSize: 15,
groupOptions: [],
},
})
}
if (url === '/api/admin/shop-manage-groups') {
return json(res, { success: true, data: { items: [] } })