家谱现有接口调试50%

This commit is contained in:
rain
2026-07-09 17:29:25 +08:00
commit 6050508144
262 changed files with 63354 additions and 0 deletions
@@ -0,0 +1,128 @@
# Auth Layer Message Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 让登录、注册、忘记密码三页的提示统一使用 layui `layer.msg`,不再出现浏览器原生 alert,并补好认证页提示和 TAC 弹窗样式。
**Architecture:** 页面加载 `public/layui/css/layui.css``public/layui/layui.js``auth-pages.js``captcha-pages.js` 只负责调用提示,不写样式;提示皮肤与 TAC 弹窗样式写入 `public/css/public.css`
**Tech Stack:** 原生 HTML/CSS/JavaScript、layui layer、public/tac、Node 断言测试。
## Global Constraints
- 计划开始时间:2026-07-09 17:14:08 +08:00。
- 只处理登录、注册、忘记密码三页的提示与弹窗样式问题。
- 不修改 `public/tac/js/tac.min.js`
- 不使用 HTML 原生 `alert` 作为用户提示。
- 样式写在 CSS 文件里,JS 只切 class 或调用组件。
- 新增或修改的 HTML、CSS、JS 注释使用中文,代码保持可读。
---
### Task 1: 补充失败测试
**Files:**
- Modify: `tests/auth-page-structure.test.js`
- Create: `tests/auth-message.test.js`
**Interfaces:**
- Consumes: 当前三页 HTML 与认证脚本。
- Produces: 能捕获缺少 layui 和原生 alert 兜底的测试。
- [x] **Step 1: 添加页面结构断言**
检查 `login.html``register.html``forgot-password.html` 必须加载 `public/layui/css/layui.css``public/layui/layui.js`,且 `layui.js``auth-pages.js` 前面。
- [x] **Step 2: 添加提示脚本断言**
检查 `public/js/auth-pages.js``public/js/captcha-pages.js` 不再包含 `root.alert`,并检查 `public/css/public.css` 提供 `.auth-layer-message`
- [x] **Step 3: 验证红灯**
运行:
```powershell
node tests\auth-page-structure.test.js
node tests\auth-message.test.js
```
预期:两个测试均失败,分别提示缺少 layui 和仍存在 `root.alert`
### Task 2: 接入 layui 并替换原生提示
**Files:**
- Modify: `login.html`
- Modify: `register.html`
- Modify: `forgot-password.html`
- Modify: `public/js/auth-pages.js`
- Modify: `public/js/captcha-pages.js`
**Interfaces:**
- Consumes: `layui.layer.msg(message, options)`
- Produces: `showMessage(message)` 统一使用 layer,缺少 layui 时只输出控制台警告,不再弹原生 alert。
- [x] **Step 1: 三页加载 layui 样式和脚本**
在三页 `<head>` 中加入 `public/layui/css/layui.css`,在 `auth-pages.js` 前加入 `public/layui/layui.js`
- [x] **Step 2: 修改认证脚本提示**
`auth-pages.js``showMessage` 改为优先调用 `layui.layer.msg(message, { skin: 'auth-layer-message' })`,没有 layui 时使用 `console.warn`
- [x] **Step 3: 修改验证码脚本提示**
`captcha-pages.js``showMessage` 同步改为同样的 layer 提示策略。
### Task 3: 补齐公共样式
**Files:**
- Modify: `public/css/public.css`
**Interfaces:**
- Consumes: layui layer 生成的 `.auth-layer-message`
- Produces: 认证页统一提示皮肤和移动端更稳的 TAC 弹窗尺寸。
- [x] **Step 1: 添加 layui 消息皮肤**
在公共 CSS 中添加 `.auth-layer-message`,控制圆角、背景、文字和阴影。
- [x] **Step 2: 微调 TAC 弹窗移动端尺寸**
继续使用 `.auth-captcha-modal` 页面级挂载,限制 TAC 宽度不超过视口,避免盖层内容顶到边缘。
### Task 4: 验证并记录完成
**Files:**
- Modify: `docs/pc-api-page-integration-tracker-2026-07-09.md`
**Interfaces:**
- Consumes: Task 1-3 的实现结果。
- Produces: PC-012 完成记录。
- [x] **Step 1: 跑焦点测试**
运行:
```powershell
node tests\auth-page-structure.test.js
node tests\auth-message.test.js
```
预期:全部通过。
- [x] **Step 2: 跑相关测试和语法检查**
运行:
```powershell
node tests\auth-pages.test.js
node tests\captcha-pages.test.js
node --check public\js\auth-pages.js
node --check public\js\captcha-pages.js
```
预期:全部通过。
- [x] **Step 3: 更新追踪记录**
把 PC-012 标记为已完成,写入完成时间、修改文件、验证命令和剩余风险。
@@ -0,0 +1,762 @@
# PC API Replan Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 按最新 `genealogy-pc-openapi.yaml` 重新整理 PC/H5 页面接口对接,只接入 `paths` 中真实存在的验证码、PC 认证、PC 文件和行政区划接口,并清除旧 APP 路径作为 PC 合同的风险。
**Architecture:** 根目录 `config.js` 是接口基础地址、客户端 ID、租户、token key 的唯一配置入口;`utils` 只放跨页面公共 JS`public/js/api-client.js` 只暴露 PC YAML `paths` 中存在的接口和受控的“PC 接口未提供”错误。页面业务 JS 继续放在 `public/js`,页面只能调用 PC 已确认方法;PC YAML 未覆盖的页面保留静态/本地展示或显示接口待确认状态。
**Tech Stack:** 静态 HTML、原生 JS、jQuery/Layui、Node 测试脚本、`public/tac` 天爱验证码静态资源。
## Global Constraints
- 接口依据只使用 `genealogy-pc-openapi.yaml``paths`
- 开发环境接口基础地址固定为 `https://test-genealogy-api.ddxcjp.cn`
- PC 默认 `clientid` 使用用户最新截图确认值:`ced7e5f0498645c6ec642dcf450b036f`,客户端 Key 为 `web_pc`
- 登录后请求使用 `Authorization` header,PC 认证和文件请求同时携带 `clientid` header。
- 样式写入 CSS 文件,不用 JS 注入样式。
- 新增或修改的 HTML、JS、CSS 注释使用中文。
- `utils` 只放跨页面公共 JS;页面业务 JS 继续放 `public/js`
- PC YAML 没有明确接口的页面不套用 APP 路径,不把 schema/requestBodies 当成可调用接口。
- 验证码只使用后台已配置的 PC/H5 场景;当前明确场景为 `WEB_H5_LOGIN``WEB_H5_REGISTER``WEB_H5_FORGOT_PASSWORD`
- 换绑手机、注销账号的 PC/H5 验证码场景未确认,不套用 `APP_*` 场景。
---
## File Structure
- Create or Modify: `config.js`
- 唯一负责环境切换、开发接口地址、PC clientid、tenantId、token key、token header name。
- Create or Modify: `utils/StorageUtil.js`
- 负责 localStorage 安全读写。
- Create or Modify: `utils/FormUtil.js`
- 负责表单读取、空值清理、数字转换、布尔转换。
- Create or Modify: `utils/RequestUtil.js`
- 负责 URL 拼接、header 合并、FormData 判断、JSON 解包、业务错误对象。
- Modify: `public/js/api-client.js`
- 只把 PC YAML `paths` 中存在的接口作为真实请求方法;旧 APP 路径不得作为 fallback。
- Modify: `public/js/auth-pages.js`
- 登录使用 `WEB_H5_LOGIN`;注册使用 `WEB_H5_REGISTER`;找回密码使用 `WEB_H5_FORGOT_PASSWORD`
- Modify: `public/js/captcha-pages.js`
-`/captcha/require``/captcha/challenge``/captcha/verify` 组织 TAC 调用。
- Modify: `public/js/profile-pages.js`
- 用户资料提交字段以 `ProfileUpdateBody` schema 为准:`provinceCode/cityCode/districtCode`
- Modify: `public/js/security-pages.js`
- 修改密码、换绑手机、注销账号只调用 PC 认证接口;涉及验证码的动作保留 PC/H5 场景待确认记录。
- Modify: `public/js/upload-pages.js`
- 上传、分片上传、文件引用只调用 `/genealogy/pc/files/*`
- Modify: `public/js/region-pages.js`
- 地区选择只调用 `/genealogy/region/*`
- Modify: related HTML files
- API 页面按顺序加载 `config.js``utils/*.js``public/js/api-client.js`、页面业务脚本。
- Modify: `tests/*.test.js`
- 测试只验证 PC YAML 已确认接口;旧 APP 路径测试改为“不可作为 PC 合同”。
- Modify: `docs/pc-api-page-integration-tracker-2026-07-09.md`
- 每项开始/完成都回填时间、文件、接口、验证结果。
---
### Task 1: 配置入口与公共工具合同
**Files:**
- Create or Modify: `config.js`
- Create or Modify: `utils/StorageUtil.js`
- Create or Modify: `utils/FormUtil.js`
- Create or Modify: `utils/RequestUtil.js`
- Test: `tests/config.test.js`
- Test: `tests/utils.test.js`
**Interfaces:**
- Produces: `GenealogyConfig.getConfig(): { env, apiBaseUrl, clientId, tenantId, tokenKey, tokenHeaderName }`
- Produces: `GenealogyConfig.getApiBaseUrl(): string`
- Produces: `GenealogyConfig.getClientId(): string`
- Produces: `GenealogyConfig.getTenantId(): string`
- Produces: `GenealogyConfig.getTokenKey(): string`
- Produces: `StorageUtil.read(storage, key): string|null`
- Produces: `StorageUtil.write(storage, key, value): void`
- Produces: `StorageUtil.remove(storage, key): void`
- Produces: `FormUtil.trimOrUndefined(value): string|undefined`
- Produces: `FormUtil.toNumberOrUndefined(value): number|undefined`
- Produces: `FormUtil.toBoolean(value): boolean`
- Produces: `FormUtil.getFormValues(form): object`
- Produces: `RequestUtil.createRequester(options)(method, path, requestOptions): Promise<any>`
- [ ] **Step 1: Write config test**
Create or replace `tests/config.test.js` with:
```js
const assert = require('assert');
const configFactory = require('../config.js');
const store = {};
const config = configFactory({
localStorage: {
getItem: (key) => Object.prototype.hasOwnProperty.call(store, key) ? store[key] : null,
setItem: (key, value) => { store[key] = String(value); }
}
});
assert.strictEqual(config.getApiBaseUrl(), 'https://test-genealogy-api.ddxcjp.cn');
assert.strictEqual(config.getClientId(), 'ced7e5f0498645c6ec642dcf450b036f');
assert.strictEqual(config.getTenantId(), '000000');
assert.strictEqual(config.getTokenKey(), 'genealogy_auth_token');
assert.strictEqual(config.getConfig().tokenHeaderName, 'Authorization');
store.genealogy_api_base_url = 'https://custom.example.test';
assert.strictEqual(config.getApiBaseUrl(), 'https://custom.example.test');
console.log('config tests passed');
```
- [ ] **Step 2: Run config test**
Run: `node tests\config.test.js`
Expected before implementation: FAIL if `config.js` is absent or lacks these methods.
Expected after implementation: PASS with `config tests passed`.
- [ ] **Step 3: Implement `config.js`**
Use this implementation:
```js
(function (root, factory) {
// 全局配置同时支持浏览器页面和 Node 测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory;
return;
}
root.GenealogyConfig = factory(root);
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var DEFAULT_ENV = 'development';
var API_BASE_URLS = {
development: 'https://test-genealogy-api.ddxcjp.cn',
production: ''
};
var CLIENT_ID = 'ced7e5f0498645c6ec642dcf450b036f';
var TENANT_ID = '000000';
var TOKEN_KEY = 'genealogy_auth_token';
var TOKEN_HEADER_NAME = 'Authorization';
var ENV_KEY = 'genealogy_env';
var BASE_URL_KEY = 'genealogy_api_base_url';
function readStorage(key) {
try {
return root.localStorage && root.localStorage.getItem(key);
} catch (error) {
return null;
}
}
function getEnv() {
return readStorage(ENV_KEY) || DEFAULT_ENV;
}
function getApiBaseUrl() {
return readStorage(BASE_URL_KEY) || API_BASE_URLS[getEnv()] || API_BASE_URLS.development;
}
function getConfig() {
return {
env: getEnv(),
apiBaseUrl: getApiBaseUrl(),
clientId: CLIENT_ID,
tenantId: TENANT_ID,
tokenKey: TOKEN_KEY,
tokenHeaderName: TOKEN_HEADER_NAME
};
}
return {
getConfig: getConfig,
getApiBaseUrl: getApiBaseUrl,
getClientId: function () { return CLIENT_ID; },
getTenantId: function () { return TENANT_ID; },
getTokenKey: function () { return TOKEN_KEY; },
getTokenHeaderName: function () { return TOKEN_HEADER_NAME; }
};
});
```
- [ ] **Step 4: Write utilities test**
Create or replace `tests/utils.test.js` with focused utility assertions:
```js
const assert = require('assert');
const StorageUtil = require('../utils/StorageUtil.js');
const FormUtil = require('../utils/FormUtil.js');
const RequestUtil = require('../utils/RequestUtil.js');
assert.strictEqual(FormUtil.trimOrUndefined(' 张三 '), '张三');
assert.strictEqual(FormUtil.trimOrUndefined(' '), undefined);
assert.strictEqual(FormUtil.toNumberOrUndefined('12'), 12);
assert.strictEqual(FormUtil.toNumberOrUndefined(''), undefined);
assert.strictEqual(FormUtil.toBoolean('on'), true);
assert.strictEqual(FormUtil.toBoolean('0'), false);
const store = {};
const storage = {
getItem: (key) => Object.prototype.hasOwnProperty.call(store, key) ? store[key] : null,
setItem: (key, value) => { store[key] = String(value); },
removeItem: (key) => { delete store[key]; }
};
StorageUtil.write(storage, 'token', 'abc');
assert.strictEqual(StorageUtil.read(storage, 'token'), 'abc');
StorageUtil.remove(storage, 'token');
assert.strictEqual(StorageUtil.read(storage, 'token'), null);
const calls = [];
const requester = RequestUtil.createRequester({
baseUrl: 'https://test-genealogy-api.ddxcjp.cn',
clientId: 'pc-client',
tokenHeaderName: 'Authorization',
getToken: () => 'token-x',
fetchImpl: async (url, options) => {
calls.push({ url, options });
return {
ok: true,
status: 200,
json: async () => ({ code: 200, data: { ok: true } })
};
}
});
requester('GET', '/genealogy/pc/auth/profile', {
query: { keyword: '汤 氏' }
}).then((data) => {
assert.deepStrictEqual(data, { ok: true });
assert.strictEqual(calls[0].url, 'https://test-genealogy-api.ddxcjp.cn/genealogy/pc/auth/profile?keyword=%E6%B1%A4+%E6%B0%8F');
assert.strictEqual(calls[0].options.headers.clientid, 'pc-client');
assert.strictEqual(calls[0].options.headers.Authorization, 'Bearer token-x');
console.log('utils tests passed');
});
```
- [ ] **Step 5: Implement utility files**
Implement the utilities with Chinese comments around storage try/catch, FormData detection, JSON response parsing and `code !== 200` error creation. `RequestUtil.createRequester` must omit `Authorization` when `requestOptions.auth === false`.
- [ ] **Step 6: Run utility tests**
Run: `node tests\utils.test.js`
Expected: PASS with `utils tests passed`.
---
### Task 2: API 客户端收紧到 PC YAML `paths`
**Files:**
- Modify: `public/js/api-client.js`
- Test: `tests/api-client.test.js`
**Interfaces:**
- Consumes: `GenealogyConfig`
- Consumes: `StorageUtil`
- Consumes: `RequestUtil.createRequester`
- Produces: `GenealogyApi.createClient(options)`
- Produces: `GenealogyApi.defaultClient`
- Produces PC methods:
- `login(body)`, `register(body)`, `loginBySms(body)`, `sendSmsCode(body)`
- `getProfile()`, `updateProfile(body)`, `changePassword(body)`, `resetPassword(body)`, `changePhone(body)`, `deactivateAccount(body)`, `logout()`
- `uploadFile(formData)`, `initResumableUpload(body)`, `uploadChunk(formData)`, `completeResumableUpload(body)`, `bindFileReference(body)`, `releaseFileReference(query)`
- `getRegionChildren(parentCode)`, `getRegionPath(regionCode)`, `searchRegions(query)`, `getRegion(regionCode)`
- `captchaRequire(query)`, `captchaChallenge(body)`, `captchaVerify(body)`, `legacyCaptcha()`
- Produces unsupported method behavior: methods for PC YAML 未覆盖业务 throw `Error` with `code === 'PC_API_NOT_AVAILABLE'` and no network request.
- [ ] **Step 1: Replace API client test**
Rewrite `tests/api-client.test.js` so it verifies only PC-confirmed paths and unsupported APP-era methods:
```js
const assert = require('assert');
const GenealogyApi = require('../public/js/api-client.js');
const calls = [];
const client = GenealogyApi.createClient({
baseUrl: 'https://test-genealogy-api.ddxcjp.cn',
clientId: 'client-x',
tenantId: 'tenant-x',
tokenKey: 'token-key',
tokenHeaderName: 'Authorization',
storage: { getItem: () => 'abc-token' },
fetchImpl: async (url, options) => {
calls.push({ url, options });
return {
ok: true,
status: 200,
json: async () => ({ code: 200, data: { url } })
};
}
});
(async () => {
await client.login({ tenantId: 'tenant-x', phone: '13800000000', password: 'md5' });
assert.strictEqual(calls[0].url, 'https://test-genealogy-api.ddxcjp.cn/genealogy/pc/auth/login');
assert.strictEqual(calls[0].options.headers.clientid, 'client-x');
assert.strictEqual(calls[0].options.headers.Authorization, undefined);
await client.getProfile();
assert.strictEqual(calls[1].url, 'https://test-genealogy-api.ddxcjp.cn/genealogy/pc/auth/profile');
assert.strictEqual(calls[1].options.headers.Authorization, 'Bearer abc-token');
await client.updateProfile({ nickName: '张三', provinceCode: '510000', cityCode: '510100', districtCode: '510104' });
assert.strictEqual(calls[2].url, 'https://test-genealogy-api.ddxcjp.cn/genealogy/pc/auth/profile');
assert.strictEqual(calls[2].options.method, 'PUT');
await client.uploadFile(new FormData());
assert.strictEqual(calls[3].url, 'https://test-genealogy-api.ddxcjp.cn/genealogy/pc/files/upload');
await client.getRegionChildren('51');
assert.strictEqual(calls[4].url, 'https://test-genealogy-api.ddxcjp.cn/genealogy/region/children?parentCode=51');
await client.captchaRequire({ sceneCode: 'WEB_H5_LOGIN', subject: '13800000000' });
assert.strictEqual(calls[5].url, 'https://test-genealogy-api.ddxcjp.cn/captcha/require?tenantId=tenant-x&clientId=client-x&sceneCode=WEB_H5_LOGIN&subject=13800000000');
assert.strictEqual(calls[5].options.headers.Authorization, undefined);
assert.throws(
() => client.listGenealogies(),
(error) => error.code === 'PC_API_NOT_AVAILABLE'
);
assert.strictEqual(calls.length, 6);
console.log('api-client tests passed');
})();
```
- [ ] **Step 2: Run API client test**
Run: `node tests\api-client.test.js`
Expected before implementation: FAIL while old APP paths or old scene tests remain.
Expected after implementation: PASS with `api-client tests passed`.
- [ ] **Step 3: Implement confirmed PC methods**
In `public/js/api-client.js`, remove APP auth/files paths. Map methods exactly:
```js
login: function (body) {
return request('POST', '/genealogy/pc/auth/login', { body: body, auth: false });
},
register: function (body) {
return request('POST', '/genealogy/pc/auth/register', { body: body, auth: false });
},
sendSmsCode: function (body) {
return request('POST', '/genealogy/pc/auth/sms/code', { body: body, auth: false });
},
loginBySms: function (body) {
return request('POST', '/genealogy/pc/auth/login/sms', { body: body, auth: false });
},
getProfile: function () {
return request('GET', '/genealogy/pc/auth/profile');
},
updateProfile: function (body) {
return request('PUT', '/genealogy/pc/auth/profile', { body: body });
}
```
Add the remaining PC auth/files/region/captcha methods with the same direct mapping from YAML `paths`.
- [ ] **Step 4: Implement unsupported method guard**
For old business methods whose PC paths do not exist, keep the method name only if current pages call it, but route it to:
```js
function createUnavailableMethod(name) {
return function () {
var error = new Error('PC 接口文档未提供该业务接口:' + name);
error.code = 'PC_API_NOT_AVAILABLE';
throw error;
};
}
```
Use a Chinese comment above the mapping: `// PC YAML 未提供这些业务 paths,保留方法名只用于阻止旧 APP 路径继续发请求。`
- [ ] **Step 5: Verify no APP auth/files network paths remain**
Run: `Select-String -Path public\js\api-client.js -Pattern '/genealogy/app/auth|/genealogy/app/files'`
Expected: no matches.
- [ ] **Step 6: Run API client test again**
Run: `node tests\api-client.test.js`
Expected: PASS with `api-client tests passed`.
---
### Task 3: 登录验证码与 `public/tac` 调用
**Files:**
- Modify: `public/js/auth-pages.js`
- Modify: `public/js/captcha-pages.js`
- Modify: `login.html`
- Modify: `register.html`
- Modify: `forgot-password.html`
- Test: `tests/auth-pages.test.js`
- Test: `tests/captcha-pages.test.js`
**Interfaces:**
- Consumes: `public/tac/css/tac.css`
- Consumes: `public/tac/js/tac.min.js`
- Consumes: `GenealogyApi.defaultClient.captchaRequire/challenge/verify`
- Produces: `AuthPages.getCaptchaScene('login') === 'WEB_H5_LOGIN'`
- Produces: `AuthPages.getCaptchaScene('register') === 'WEB_H5_REGISTER'`
- Produces: `AuthPages.getCaptchaScene('password-reset') === 'WEB_H5_FORGOT_PASSWORD'`
- Produces: `CaptchaPages.buildChallengeBody(options, api)`
- Produces: `CaptchaPages.buildVerifyBody(options, api)`
- Produces: `CaptchaPages.ensureToken(form, options)`
- [ ] **Step 1: Replace auth scene tests**
In `tests/auth-pages.test.js`, require these expectations:
```js
assert.strictEqual(AuthPages.getCaptchaScene('login'), 'WEB_H5_LOGIN');
assert.strictEqual(AuthPages.getCaptchaScene('register'), 'WEB_H5_REGISTER');
assert.strictEqual(AuthPages.getCaptchaScene('password-reset'), 'WEB_H5_FORGOT_PASSWORD');
```
- [ ] **Step 2: Replace captcha tests**
In `tests/captcha-pages.test.js`, all challenge/verify body tests must use `WEB_H5_LOGIN`:
```js
assert.deepStrictEqual(CaptchaPages.buildChallengeBody({
sceneCode: 'WEB_H5_LOGIN',
subject: '13800000000'
}, fakeApi), {
tenantId: 'tenant-x',
clientId: 'client-x',
sceneCode: 'WEB_H5_LOGIN',
subject: '13800000000'
});
```
- [ ] **Step 3: Run auth and captcha tests**
Run:
```powershell
node tests\auth-pages.test.js
node tests\captcha-pages.test.js
```
Expected before implementation: FAIL if `PC_LOGIN` or `PC_REGISTER` remains.
Expected after implementation: PASS.
- [ ] **Step 4: Implement scene mapping**
In `public/js/auth-pages.js`:
```js
function getCaptchaScene(formType) {
// PC/H5 认证场景来自后台验证码配置,客户端 Key 为 web_pc。
var map = {
login: 'WEB_H5_LOGIN',
register: 'WEB_H5_REGISTER',
'password-reset': 'WEB_H5_FORGOT_PASSWORD'
};
return map[formType] || '';
}
```
If `sceneCode` is empty, `ensureCaptcha` must return `true` without calling `/captcha/require` and must not fabricate `validToken`.
- [ ] **Step 5: Verify TAC assets in auth pages**
Run:
```powershell
Select-String -Path login.html,register.html,forgot-password.html -Pattern 'public/tac/css/tac.css|public/tac/js/tac.min.js|public/js/captcha-pages.js|name="validToken"|data-captcha-box'
```
Expected:
- `login.html` has TAC CSS, TAC JS, `captcha-pages.js`, hidden `validToken`, and `[data-captcha-box]`.
- `register.html` and `forgot-password.html` may keep TAC assets and hidden fields, but no PC/H5 scene is configured until backend confirms scene code.
---
### Task 4: 认证与资料页面只接 PC auth schema
**Files:**
- Modify: `public/js/auth-pages.js`
- Modify: `public/js/profile-pages.js`
- Modify: `public/js/security-pages.js`
- Modify: `login.html`
- Modify: `register.html`
- Modify: `forgot-password.html`
- Modify: `profile.html`
- Modify: `profile-data.html`
- Modify: `profile-security.html`
- Test: `tests/auth-pages.test.js`
- Test: `tests/profile-pages.test.js`
- Test: `tests/security-pages.test.js`
**Interfaces:**
- Consumes: `GenealogyApi.defaultClient`
- Produces request bodies:
- `PasswordLoginBody`: `grantType/tenantId/phone/password/validToken`
- `PasswordRegisterBody`: `grantType/tenantId/phone/password/nickName/registerSource/validToken`
- `PasswordResetBody`: `tenantId/phone/smsCode/newPassword/validToken`
- `ProfileUpdateBody`: `nickName/avatarOssId/sex/birthday/provinceCode/cityCode/districtCode`
- [ ] **Step 1: Update body-builder tests**
`tests/auth-pages.test.js` must assert `registerSource: 'PC'` for register body and no `APP_*` scene in any body.
`tests/profile-pages.test.js` must assert profile update uses `provinceCode/cityCode/districtCode`, not `regionCode/addressDetail`.
- [ ] **Step 2: Run focused tests**
Run:
```powershell
node tests\auth-pages.test.js
node tests\profile-pages.test.js
node tests\security-pages.test.js
```
Expected before implementation: FAIL where old scene/body fields remain.
Expected after implementation: PASS.
- [ ] **Step 3: Implement auth body builders**
Use PC YAML schema fields only. For register:
```js
function buildRegisterBody(values, config) {
var body = {
grantType: 'password',
tenantId: config.tenantId,
phone: values.phone,
password: values.password,
registerSource: 'PC'
};
if (values.nickName) body.nickName = values.nickName;
if (values.validToken) body.validToken = values.validToken;
return body;
}
```
- [ ] **Step 4: Implement profile body builder**
Use schema fields:
```js
function buildProfileUpdateBody(values) {
return removeEmpty({
nickName: values.nickName,
avatarOssId: toNumberOrUndefined(values.avatarOssId),
sex: values.sex,
birthday: values.birthday,
provinceCode: values.provinceCode,
cityCode: values.cityCode,
districtCode: values.districtCode
});
}
```
- [ ] **Step 5: Verify page script order**
Run:
```powershell
Select-String -Path login.html,register.html,forgot-password.html,profile.html,profile-data.html,profile-security.html -Pattern 'config.js|utils/StorageUtil.js|utils/FormUtil.js|utils/RequestUtil.js|public/js/api-client.js'
```
Expected: every page that uses `GenealogyApi` loads config and utils before `api-client.js`.
---
### Task 5: 文件上传和文件引用只切 PC files
**Files:**
- Modify: `public/js/upload-pages.js`
- Modify: upload-related page scripts that call `GenealogyApi.defaultClient.uploadFile`
- Test: `tests/upload-pages.test.js`
- Test: `tests/api-client.test.js`
**Interfaces:**
- Consumes: `GenealogyApi.defaultClient.uploadFile(formData)`
- Consumes: `GenealogyApi.defaultClient.initResumableUpload(body)`
- Consumes: `GenealogyApi.defaultClient.uploadChunk(formData)`
- Consumes: `GenealogyApi.defaultClient.completeResumableUpload(body)`
- Consumes: `GenealogyApi.defaultClient.bindFileReference(body)`
- Consumes: `GenealogyApi.defaultClient.releaseFileReference(query)`
- [ ] **Step 1: Add upload tests**
`tests/upload-pages.test.js` must verify:
- single upload calls `/genealogy/pc/files/upload`
- resumable init calls `/genealogy/pc/files/resumable/init`
- file reference body requires `bizType/bizTable/bizId/bizField`
- [ ] **Step 2: Run upload tests**
Run: `node tests\upload-pages.test.js`
Expected before implementation: FAIL if old APP file paths remain.
Expected after implementation: PASS.
- [ ] **Step 3: Implement upload mapping**
Only map file capability. Do not submit article/feed/album/ceremony/growth/memo business forms unless PC YAML provides their business endpoints.
- [ ] **Step 4: Verify no APP file path remains**
Run: `Select-String -Path public\js\api-client.js,public\js\upload-pages.js -Pattern '/genealogy/app/files'`
Expected: no matches.
---
### Task 6: 行政区划接口和资料地区字段
**Files:**
- Modify: `public/js/region-pages.js`
- Modify: `public/js/profile-pages.js`
- Test: `tests/region-pages.test.js`
- Test: `tests/profile-pages.test.js`
**Interfaces:**
- Consumes: `GET /genealogy/region/children`
- Consumes: `GET /genealogy/region/path/{regionCode}`
- Consumes: `GET /genealogy/region/search`
- Consumes: `GET /genealogy/region/{regionCode}`
- Produces profile fields: `provinceCode/cityCode/districtCode`
- [ ] **Step 1: Add region tests**
`tests/region-pages.test.js` must assert:
- empty parent loads province list with no required parent code.
- search requires `keyword`.
- selected province/city/district writes `provinceCode/cityCode/districtCode` to the form.
- [ ] **Step 2: Run region tests**
Run: `node tests\region-pages.test.js`
Expected before implementation: FAIL if form still expects `regionCode/addressDetail`.
Expected after implementation: PASS.
- [ ] **Step 3: Implement region mapping**
Use `GenealogyApi.defaultClient.getRegionChildren`, `getRegionPath`, `searchRegions`, `getRegion`. Do not create genealogy submit behavior here.
---
### Task 7: PC YAML 未覆盖页面降级为接口待确认
**Files:**
- Modify: page scripts that currently call APP-era business methods:
- `public/js/genealogy-pages.js`
- `public/js/join-apply-pages.js`
- `public/js/member-admin-pages.js`
- `public/js/article-pages.js`
- `public/js/feed-pages.js`
- `public/js/album-pages.js`
- `public/js/ceremony-pages.js`
- `public/js/growth-pages.js`
- `public/js/memo-pages.js`
- `public/js/generation-pages.js`
- `public/js/lineage-pages.js`
- `public/js/notification-pages.js`
- `public/js/help-pages.js`
- `public/js/promotion-pages.js`
- `public/js/feedback-pages.js`
- `public/js/vip-pages.js`
- Test: `tests/unsupported-pages.test.js`
**Interfaces:**
- Consumes: `PC_API_NOT_AVAILABLE` errors from `GenealogyApi`
- Produces: visible or console-safe page state that says PC interface is not configured, without issuing APP requests.
- [ ] **Step 1: Add unsupported-page smoke test**
Create `tests/unsupported-pages.test.js` to load each page script in Node with a fake client method that throws `{ code: 'PC_API_NOT_AVAILABLE' }`. Assert each script handles the error without rethrowing from its init function.
- [ ] **Step 2: Run unsupported-page test**
Run: `node tests\unsupported-pages.test.js`
Expected before implementation: FAIL for scripts that assume APP methods are valid.
Expected after implementation: PASS.
- [ ] **Step 3: Implement shared page fallback**
In each affected page script, catch `PC_API_NOT_AVAILABLE` and render a small existing-style empty state. Add a Chinese comment: `// PC YAML 未提供该业务接口,页面先展示接口待确认状态。`
- [ ] **Step 4: Verify no APP business path is emitted from API client**
Run: `Select-String -Path public\js\api-client.js -Pattern '/genealogy/app/'`
Expected: no network path matches.
---
### Task 8: 追踪表和执行记录
**Files:**
- Modify: `docs/pc-api-page-integration-tracker-2026-07-09.md`
**Interfaces:**
- Consumes: Task 1-7 verification results.
- Produces: updated status rows with exact timestamps, changed files, interface paths and verification commands.
- [ ] **Step 1: Mark task start before edits**
Before executing each PC task, update the row status from `待开始` to `进行中` with exact time from:
```powershell
Get-Date -Format "yyyy-MM-dd HH:mm:ss zzz"
```
- [ ] **Step 2: Mark task completion after verification**
After the task's verification commands pass, update status to `已完成` and record:
- completion time
- modified files
- interface paths
- verification commands
- verification result
- [ ] **Step 3: Keep missing interfaces in coverage matrix**
Any page whose main business path is absent from `genealogy-pc-openapi.yaml` remains in `PC YAML 未覆盖` or `接口待确认` and must not be promoted to full integration.
---
## Verification Gate
Run these before marking the replan execution complete:
```powershell
node tests\config.test.js
node tests\utils.test.js
node tests\api-client.test.js
node tests\auth-pages.test.js
node tests\captcha-pages.test.js
node tests\profile-pages.test.js
node tests\security-pages.test.js
node tests\upload-pages.test.js
node tests\region-pages.test.js
node tests\unsupported-pages.test.js
Get-ChildItem -Path public\js -Filter *.js | Where-Object { $_.Name -notin @('jquery360.js','jquery.min.js') } | Sort-Object Name | ForEach-Object { node --check $_.FullName }
Select-String -Path public\js\api-client.js -Pattern '/genealogy/app/'
Select-String -Path public\js\auth-pages.js,public\js\captcha-pages.js,tests\auth-pages.test.js,tests\captcha-pages.test.js -Pattern 'PC_LOGIN|PC_REGISTER|PC_PASSWORD_RESET|APP_LOGIN|APP_REGISTER|APP_FORGOT_PASSWORD'
git diff --check
```
Expected:
- All listed Node tests pass.
- Business JS syntax check passes.
- `api-client.js` contains no `/genealogy/app/` network path.
- Auth and captcha code/tests contain no stale APP/old PC scene defaults.
- `git diff --check` passes, or if this directory is not a Git repository, record the exact output.
## Self-Review
- Spec coverage: this plan covers latest PC YAML `paths`, test domain, config.js, utils/public-js separation, CSS/no style injection, Chinese comments, TAC login scene, profile schema mismatch, and PC-missing business interfaces.
- Placeholder scan: no implementation task asks the worker to invent missing PC endpoints or use APP paths as compatibility.
- Type consistency: `GenealogyConfig`, `StorageUtil`, `FormUtil`, `RequestUtil`, `GenealogyApi.createClient`, `AuthPages.getCaptchaScene`, and `CaptchaPages.ensureToken` names are consistent across tasks.
@@ -0,0 +1,127 @@
# PC Auth Three Pages Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:**`genealogy-pc-openapi.yaml` 和 Apifox 截图,把登录、注册、忘记密码三页与 PC 认证接口、验证中心接口对齐。
**Architecture:** 根目录 `config.js` 继续作为环境、`clientid``tenantId` 的唯一配置入口;`utils` 继续存放跨页面公共工具;页面业务逻辑集中在 `public/js/auth-pages.js`,接口调用集中在 `public/js/api-client.js`,验证码适配集中在 `public/js/captcha-pages.js`。页面差异样式只写入对应 CSS 文件。
**Tech Stack:** 原生 HTML/CSS/JavaScript、`public/tac` 滑动验证、Node 断言测试。
## Global Constraints
- 接口依据只使用 `genealogy-pc-openapi.yaml` 与用户补充的 Apifox 截图,不再使用 `APP.openapi.json`
- 开发环境接口地址为 `https://test-genealogy-api.ddxcjp.cn`
- PC `clientid``ced7e5f0498645c6ec642dcf450b036f`,租户 ID 为 `000000`
- 登录验证码场景为 `WEB_H5_LOGIN`,注册验证码场景为 `WEB_H5_REGISTER`,忘记密码验证码场景为 `WEB_H5_FORGOT_PASSWORD`
- 不在 JS 中注入样式;页面差异样式写入对应 CSS 文件,公共样式写入 `public/css/public.css`
- 新增或修改的 HTML、CSS、JS 注释使用中文,代码保持可读,不压缩。
---
### Task 1: 记录专项计划
**Files:**
- Modify: `docs/pc-api-page-integration-tracker-2026-07-09.md`
- Create: `docs/superpowers/plans/2026-07-09-pc-auth-three-pages.md`
**Interfaces:**
- Consumes: 用户确认“可以”先做登录、注册、忘记密码三页。
- Produces: PC-009 专项计划记录。
- [x] **Step 1: 写入本计划**
创建本计划,明确页面、接口、验证码场景、样式和验证约束。
- [x] **Step 2: 写入追踪记录**
在追踪文档中新增 `PC-009`,状态为“进行中”,开始时间为 `2026-07-09 16:32:17 +08:00`
### Task 2: 登录页补齐短信登录
**Files:**
- Modify: `login.html`
- Modify: `public/css/login.css`
- Modify: `public/js/auth-pages.js`
- Modify: `tests/auth-pages.test.js`
- Modify: `tests/api-client.test.js`
**Interfaces:**
- Consumes: `ApiClient.login(body)``ApiClient.loginBySms(body)``ApiClient.sendSmsCode(body)``CaptchaPages.ensureToken(form, options)`
- Produces: 登录页同时支持密码登录和短信登录。
- [x] **Step 1: 页面增加登录方式切换**
`login.html` 的登录表单内增加模式切换按钮,密码登录区域保留 `phone/password/validToken`,短信登录区域增加 `phone/smsCode/validToken` 和发送验证码按钮。
- [x] **Step 2: CSS 写入登录页专属样式**
`public/css/login.css` 增加模式切换、隐藏区域、验证码行样式,不在 JS 中写样式。
- [x] **Step 3: JS 支持短信登录提交**
`public/js/auth-pages.js` 增加 `buildSmsLoginBody(values)`,提交时按当前模式调用 `/genealogy/pc/auth/login``/genealogy/pc/auth/login/sms`
- [x] **Step 4: 发送短信复用场景码**
登录页短信验证码按钮使用 `data-scene-code="WEB_H5_LOGIN"`,忘记密码页继续使用 `WEB_H5_FORGOT_PASSWORD`
- [x] **Step 5: 更新测试**
`tests/auth-pages.test.js` 增加短信登录 body 断言;`tests/api-client.test.js` 增加 `loginBySms``sendSmsCode` 路径/入参断言。
### Task 3: 注册和忘记密码复核
**Files:**
- Verify: `register.html`
- Verify: `forgot-password.html`
- Verify: `public/js/auth-pages.js`
**Interfaces:**
- Consumes: `/genealogy/pc/auth/register``/genealogy/pc/auth/sms/code``/genealogy/pc/auth/password/reset`
- Produces: 注册和忘记密码页面确认继续按 PC 字段提交。
- [x] **Step 1: 注册页字段复核**
确认注册页只提交 `phone/password/nickName/validToken``grantType/tenantId/clientId/registerSource``api-client.js` 统一补齐。
- [x] **Step 2: 忘记密码页字段复核**
确认忘记密码页提交 `tenantId/phone/smsCode/newPassword/validToken`,不再出现邮箱找回文案。
### Task 4: 专项验证和完成记录
**Files:**
- Modify: `docs/pc-api-page-integration-tracker-2026-07-09.md`
**Interfaces:**
- Consumes: Task 2 和 Task 3 的实现结果。
- Produces: PC-009 完成记录和验证结果。
- [x] **Step 1: 运行测试**
运行:
```powershell
node tests\auth-pages.test.js
node tests\api-client.test.js
node tests\captcha-pages.test.js
```
期望全部输出 `passed`
- [x] **Step 2: 运行语法检查**
运行:
```powershell
node --check public\js\auth-pages.js
node --check public\js\api-client.js
node --check public\js\captcha-pages.js
```
期望无输出且退出码为 0。
- [x] **Step 3: 更新追踪文档**
`PC-009` 状态改为“已完成”,写入完成时间、修改文件、接口路径、验证码场景和验证结果。
@@ -0,0 +1,95 @@
# TAC Captcha Auth Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:**`public/tac` 滑动验证接入登录、注册、忘记密码三个认证页面,并按 `APP.openapi.json` 的验证中心接口换取 `validToken` 后再提交业务接口。
**Architecture:** 新增 `public/js/captcha-pages.js` 作为 TAC 与验证中心接口之间的适配层;`auth-pages.js` 在提交登录、注册、发送短信、重置密码前调用验证码适配层。API 基础地址、clientId、tenantId 继续由 `api-client.js` 统一提供。
**Tech Stack:** 静态 HTML、原生 JS、现有 `public/tac/js/tac.min.js`、现有 `public/tac/css/tac.css`、Node 单元测试。
## Global Constraints
- 严格依据 `APP.openapi.json``/captcha/require``/captcha/challenge``/captcha/verify` 字段接入。
- 业务 JS 不压缩,新增注释使用中文。
- 自有样式写入 CSS 文件,不通过自有 JS 注入样式。
- 第三方 `tac.min.js` 保持原样,不重写其内部样式和 DOM 生成逻辑。
- 登录、注册、忘记密码三页都必须有隐藏 `validToken` 字段和验证码挂载容器。
---
### Task 1: API Client Captcha Helpers
**Files:**
- Modify: `public/js/api-client.js`
- Modify: `tests/api-client.test.js`
**Interfaces:**
- Produces: `client.buildApiUrl(path, query)`
- Produces: `client.captchaRequirement({ sceneCode, subject })`
- [ ] **Step 1: Write failing tests** for captcha requirement URL, query, and public URL building.
- [ ] **Step 2: Run tests** and confirm missing methods fail.
- [ ] **Step 3: Implement minimal API client helpers**.
- [ ] **Step 4: Run tests** and confirm pass.
### Task 2: TAC Adapter Module
**Files:**
- Create: `public/js/captcha-pages.js`
- Create: `tests/captcha-pages.test.js`
**Interfaces:**
- Produces: `CaptchaPages.buildChallengeBody(options, api)`
- Produces: `CaptchaPages.adaptChallengeResponse(response)`
- Produces: `CaptchaPages.buildVerifyBody(requestData, context, api)`
- Produces: `CaptchaPages.extractValidToken(response)`
- Produces: `CaptchaPages.ensureToken(form, options)`
- [ ] **Step 1: Write failing tests** for OpenAPI-to-TAC mapping and validToken extraction.
- [ ] **Step 2: Run tests** and confirm module missing fails.
- [ ] **Step 3: Implement adapter with Chinese comments**.
- [ ] **Step 4: Run tests** and confirm pass.
### Task 3: Auth Flow Integration
**Files:**
- Modify: `public/js/auth-pages.js`
- Modify: `tests/auth-pages.test.js`
**Interfaces:**
- Consumes: `CaptchaPages.ensureToken(form, { sceneCode, subject })`
- Updates: login/register/password reset/send code flows wait for captcha before API submission.
- [ ] **Step 1: Write failing tests** for login body validToken and scene code mapping.
- [ ] **Step 2: Run tests** and confirm expected failure.
- [ ] **Step 3: Integrate captcha gate before submit/send code**.
- [ ] **Step 4: Run tests** and confirm pass.
### Task 4: HTML/CSS Wiring
**Files:**
- Modify: `login.html`
- Modify: `register.html`
- Modify: `forgot-password.html`
- Modify: `public/css/public.css`
**Interfaces:**
- Adds: `<link rel="stylesheet" href="public/tac/css/tac.css" />`
- Adds: hidden `validToken`
- Adds: `data-captcha-box`
- Adds: `public/tac/js/tac.min.js` and `public/js/captcha-pages.js`
- [ ] **Step 1: Add page hooks** with Chinese HTML comments where helpful.
- [ ] **Step 2: Add CSS-only layout for captcha container**.
- [ ] **Step 3: Run static checks** for scripts, hooks, no self JS style injection.
### Task 5: Verification And Records
**Files:**
- Modify: `docs/api-page-integration-2026-07-09.md`
- [ ] **Step 1: Run all Node tests**.
- [ ] **Step 2: Run `node --check` for all business JS**.
- [ ] **Step 3: Run static checks for HTML hooks and style-injection patterns**.
- [ ] **Step 4: Append dated progress record**.