docs(ui05,ui06): admin analysis+HTML preview, app-preview evidence, UI06 unified visual plan

- admin-preview-2026-09-22/ 20页新版后台HTML原型+截图+validation(UI05 交付)
- app-preview-2026-09-22/ 截图/validation/check 脚本入库及小改
- admin-redesign-concept 概念图
- UI05 管理后台分析与新版设计说明、用户列表分页计划文档
- UI06 全端视觉统一实施方案(以两个 HTML 预览为唯一视觉基准)
- services/api g4-sync-once 手动同步脚本

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-22 22:42:00 +08:00
parent dbf958613f
commit 37d88da4bc
85 changed files with 1149 additions and 3 deletions
+69
View File
@@ -0,0 +1,69 @@
// services/api/src/scripts/g4-sync-once.ts —— G4 一次性真实用户同步(临时验证
// 脚本,跑完即删,不入库)。走真实 AppCnModule 装配(USER_SYNC_SOURCE=http
// 时 HttpUserSource 生效),engine.tick() 同步执行完整批次,结束打印批次账本/
// 坏行/单行状态/用户统计供人工核验。
// 用法(仓库根):
// USER_SYNC_SOURCE=http OPEN_API_USERS_URL=<url> OPEN_API_USERS_KEY=<key> \
// DOTENV_CONFIG_PATH=.env node -r dotenv/config services/api/dist/scripts/g4-sync-once.js
import 'reflect-metadata';
import { NestFactory } from '@nestjs/core';
import { PrismaClient } from '@photo/db-cn';
import { AppCnModule } from '../app-cn.module';
import { UserSyncEngine } from '../user-sync/user-sync.service';
async function main(): Promise<void> {
const app = await NestFactory.createApplicationContext(AppCnModule, {
bufferLogs: true,
});
const engine = app.get(UserSyncEngine);
const startedAt = new Date();
await engine.tick(); // 同步执行一批(撞锁则跳过——正常情况无并发)
const prisma = new PrismaClient();
try {
const run = await prisma.user_sync_runs.findFirst({
where: { startedAt: { gte: startedAt } },
orderBy: [{ startedAt: 'desc' }, { id: 'desc' }],
});
const errors = run
? await prisma.user_sync_errors.findMany({ where: { runId: run.id } })
: [];
const state = await prisma.user_sync_state.findFirst();
const uniserviceMappings = await prisma.external_user_mappings.count({
where: { sourceSystem: 'uniservice' },
});
const totalUsers = await prisma.users.count();
const sample = await prisma.users.findMany({
where: { account: { startsWith: '1' } },
orderBy: { createdAt: 'desc' },
take: 5,
select: {
account: true,
displayName: true,
role: true,
sourceStatus: true,
credentialStatus: true,
},
});
console.log(
JSON.stringify(
{
run,
errorCount: errors.length,
errors: errors.slice(0, 10),
state,
uniserviceMappings,
totalUsers,
sample,
},
null,
2,
),
);
} finally {
await prisma.$disconnect();
await app.close();
}
}
void main();