Files
jiapu/docs/superpowers/plans/2026-07-09-pc-api-replan.md
T
2026-07-11 11:03:47 +08:00

28 KiB
Raw Blame History

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 只放跨页面公共 JSpublic/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.yamlpaths
  • 开发环境接口基础地址固定为 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_LOGINWEB_H5_REGISTERWEB_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.jsutils/*.jspublic/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:

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:

(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:

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:

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:

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:

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 the PC auth/files contract

Run: node tests\pc-api-contract.test.js Expected: PC 请求契约扫描通过。

  • 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:

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:

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:

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:

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:

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:

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:

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:

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:

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 the PC file contract

Run: node tests\pc-api-contract.test.js Expected: PC 请求契约扫描通过。


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 obsolete business path is emitted from the API client

Run: node tests\pc-api-contract.test.js Expected: PC 请求契约扫描通过。


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:

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:

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 }
node tests\pc-api-contract.test.js
git diff --check

Expected:

  • All listed Node tests pass.
  • Business JS syntax check passes.
  • PC 请求契约扫描通过。
  • 认证和验证码代码/tests 不含过期场景默认值。
  • 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.