2026-09-13 21:34:43 +08:00
|
|
|
|
import assert from 'node:assert/strict'
|
|
|
|
|
|
import { existsSync, readFileSync } from 'node:fs'
|
|
|
|
|
|
import { resolve } from 'node:path'
|
|
|
|
|
|
|
|
|
|
|
|
const root = resolve(import.meta.dirname, '..')
|
|
|
|
|
|
const read = (path) => readFileSync(resolve(root, path), 'utf8')
|
|
|
|
|
|
const theme = read('admin-web/src/theme/index.css')
|
|
|
|
|
|
const layout = read('admin-web/src/layouts/MainLayout.vue')
|
|
|
|
|
|
const dashboard = read('admin-web/src/views/DashboardView.vue')
|
2026-09-18 20:51:12 +08:00
|
|
|
|
// 品牌资产的实际文件名集中在 src/brand.ts:public/ 下的资源不受 vite base 影响,
|
|
|
|
|
|
// 引用时必须显式拼 BASE_URL(否则在 /admin/ 子路径部署下 404)。因此下面断言
|
|
|
|
|
|
// 「组件经 brand 模块引用」+「brand 模块指向正式资产」两处,而不是在组件里找文件名字面量。
|
|
|
|
|
|
const brand = read('admin-web/src/brand.ts')
|
2026-09-13 21:34:43 +08:00
|
|
|
|
|
|
|
|
|
|
for (const token of [
|
|
|
|
|
|
'--admin-coral',
|
|
|
|
|
|
'--admin-shell-bg',
|
|
|
|
|
|
'--admin-sidebar-bg',
|
|
|
|
|
|
'--admin-card-radius',
|
|
|
|
|
|
'--admin-shell-radius',
|
|
|
|
|
|
'--admin-shadow',
|
|
|
|
|
|
]) {
|
|
|
|
|
|
assert.ok(theme.includes(token), `缺少管理端参考图令牌 ${token}`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
assert.ok(
|
|
|
|
|
|
existsSync(resolve(root, 'admin-web/public/brand/admin-danyang-backdrop.jpg')),
|
|
|
|
|
|
'缺少丹阳公益主题背景资产',
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
for (const className of ['admin-scene', 'admin-shell', 'admin-sidebar', 'admin-topbar', 'admin-content']) {
|
|
|
|
|
|
assert.ok(layout.includes(className), `缺少框架结构 ${className}`)
|
|
|
|
|
|
}
|
2026-09-18 20:51:12 +08:00
|
|
|
|
assert.match(brand, /admin-danyang-backdrop\.jpg/, '品牌模块未指向正式背景资产')
|
|
|
|
|
|
assert.match(layout, /BRAND_BACKDROP/, '管理端外层未使用正式背景资产')
|
2026-09-13 21:34:43 +08:00
|
|
|
|
assert.match(layout, /permissions/, '侧栏未保留权限控制')
|
|
|
|
|
|
|
|
|
|
|
|
for (const item of [
|
|
|
|
|
|
'工作台', '用户管理', '资料审核', '匹配管理', '公益红娘', '公益咨询', '活动管理',
|
|
|
|
|
|
'内容管理', '善缘服务站', '举报风控', '数据统计', '组织人员', '系统设置',
|
|
|
|
|
|
]) {
|
|
|
|
|
|
assert.ok(layout.includes(item), `侧栏缺少 ${item}`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (const className of [
|
|
|
|
|
|
'dashboard-metrics',
|
|
|
|
|
|
'metric-card',
|
|
|
|
|
|
'todo-panel',
|
|
|
|
|
|
'activity-panel',
|
|
|
|
|
|
'service-overview-panel',
|
|
|
|
|
|
'effectiveness-panel',
|
|
|
|
|
|
'dashboard-loading',
|
|
|
|
|
|
'dashboard-empty',
|
|
|
|
|
|
'dashboard-error',
|
|
|
|
|
|
'dashboard-forbidden',
|
|
|
|
|
|
]) {
|
|
|
|
|
|
assert.ok(dashboard.includes(className), `工作台缺少状态或区块 ${className}`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (const title of ['今日待办事项', '近期公益活动', '服务数据概览', '项目服务成效']) {
|
|
|
|
|
|
assert.ok(dashboard.includes(title), `工作台缺少 ${title}`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
assert.match(dashboard, /metrics/, '工作台缺少指标数据绑定')
|
|
|
|
|
|
assert.match(dashboard, /Asia\/Shanghai/, '工作台日期未固定为中国时区')
|
2026-09-13 22:09:15 +08:00
|
|
|
|
assert.match(dashboard, /loadDashboard/, '工作台未接入真实数据适配层')
|
|
|
|
|
|
assert.match(dashboard, /retryLoad/, '工作台缺少失败重试')
|
2026-09-18 20:51:12 +08:00
|
|
|
|
assert.match(brand, /activity-default\.jpg/, '品牌模块未指向活动封面降级资产')
|
|
|
|
|
|
assert.match(dashboard, /BRAND_ACTIVITY_FALLBACK/, '活动封面缺少本地降级资产')
|
2026-09-13 22:09:15 +08:00
|
|
|
|
assert.match(dashboard, /item\.max\s*>\s*0/, '成效进度未处理 max 为 0 的情况')
|
|
|
|
|
|
assert.match(dashboard, /v-for="metric in dashboard\.metrics"/, '六指标必须由 DashboardModel 统一渲染')
|
2026-09-13 21:34:43 +08:00
|
|
|
|
|
|
|
|
|
|
console.log('Admin reference contracts passed')
|