diff --git a/AGENTS.md b/AGENTS.md
deleted file mode 100644
index 82682d7..0000000
--- a/AGENTS.md
+++ /dev/null
@@ -1,115 +0,0 @@
-# AGENTS.md
-Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-specific instructions as needed.
-
-Tradeoff: These guidelines bias toward caution over speed. For trivial tasks, use judgment.
-
-1. Think Before Coding
-Don't assume. Don't hide confusion. Surface tradeoffs.
-
-Before implementing:
-
-State your assumptions explicitly. If uncertain, ask.
-If multiple interpretations exist, present them instead of picking silently.
-If a simpler approach exists, say so. Push back when warranted.
-If something is unclear, stop. Name what is confusing. Ask.
-
-2. Simplicity First
-Minimum code that solves the problem. Nothing speculative.
-
-No features beyond what was asked.
-No abstractions for single-use code.
-No "flexibility" or "configurability" that was not requested.
-No error handling for impossible scenarios.
-If you write 200 lines and it could be 50, rewrite it.
-Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
-
-3. Surgical Changes
-Touch only what you must. Clean up only your own mess.
-
-When editing existing code:
-
-Do not "improve" adjacent code, comments, or formatting.
-Do not refactor things that are not broken.
-Match existing style, even if you would do it differently.
-If you notice unrelated dead code, mention it instead of deleting it.
-
-When your changes create orphans:
-
-Remove imports, variables, functions, files, docs, and references that YOUR changes made unused.
-Do not remove pre-existing dead code unless asked.
-The test: Every changed line should trace directly to the user's request.
-
-4. Contract Discipline
-When a new contract lands, make it the only contract in the same change.
-
-A contract means any source-of-truth rule that code depends on: data shape, API boundary, schema, field name, config key, prompt format, file layout, runtime entrypoint, ownership boundary, or workflow.
-
-When introducing or changing a contract, do all three in the same round:
-
-Specify the single owner.
-
-Identify the one module, function, schema, document, or service that owns the contract.
-Do not leave the same rule duplicated across frontend, backend, scripts, prompts, docs, or tests.
-If multiple places need the value, they should consume it from the owner rather than redefine it.
-
-Delete old fields and old entrypoints.
-
-Remove obsolete fields, fallback reads, compatibility branches, legacy routes, stale config keys, old scripts, and old docs.
-Do not keep the old path "just in case" unless the user explicitly asks for a compatibility period.
-If compatibility is required, name it as temporary, define the removal condition, and keep it narrow.
-
-Tighten validators and runtime together.
-
-Update schemas, validators, tests, fixtures, seed data, docs, and runtime code in the same change.
-Make invalid old inputs fail early and loudly.
-Do not allow runtime behavior to accept shapes that validators reject, or validators to allow shapes that runtime no longer supports.
-The rule: New owner, old path removed, validator and runtime tightened. If one is missing, the contract migration is not complete.
-
-5. Goal-Driven Execution
-Define success criteria. Loop until verified.
-
-Transform tasks into verifiable goals:
-
-"Add validation" -> "Write tests for invalid inputs, then make them pass."
-"Fix the bug" -> "Write a test that reproduces it, then make it pass."
-"Refactor X" -> "Ensure tests pass before and after."
-"Change a contract" -> "Identify owner, remove old paths, tighten validators and runtime, then verify old inputs fail."
-
-For multi-step tasks, state a brief plan:
-
-1. [Step] -> verify: [check]
-2. [Step] -> verify: [check]
-3. [Step] -> verify: [check]
-
-Strong success criteria let you loop independently. Weak criteria like "make it work" require clarification.
-
-6. Verification Before Closure
-A change is not finished until the relevant behavior is checked.
-
-Before reporting completion:
-
-Run the smallest relevant test, script, typecheck, build, or manual verification.
-Prefer focused verification over broad, noisy suites when the task is narrow.
-If verification cannot be run, say exactly why.
-If verification is only by inspection, say that clearly.
-If the task changed a contract, verify both the new valid path and the old invalid path.
-Do not claim success from intent. Claim success from evidence.
-
-7. Reporting Results
-Be concise, concrete, and honest.
-
-When summarizing work:
-
-Say what changed.
-Say how it was verified.
-Mention any remaining risk or skipped verification.
-Do not bury important caveats in vague language.
-Do not over-explain routine edits.
-
-Good final answer shape:
-
-Changed: [short summary]
-Verified: [command/check]
-Notes: [only if needed]
-
-These guidelines are working if: fewer unnecessary changes in diffs, fewer rewrites due to overcomplication, fewer hidden compatibility paths, clearer ownership of contracts, and clarifying questions happen before implementation rather than after mistakes.
diff --git a/PC.openapi.json b/PC.openapi.json
deleted file mode 100644
index 8b80861..0000000
--- a/PC.openapi.json
+++ /dev/null
@@ -1,8604 +0,0 @@
-{
- "openapi": "3.1.0",
- "info": {
- "title": "PC",
- "description": "家谱业务 APP/PC 用户侧接口文档,用于 Apifox 导入。\n\n导入方式:Apifox -> 导入 API 数据 -> OpenAPI/Swagger -> 选择本文件。\n\n约定:\n- APP 路径前缀为 `/genealogy/app`\n- PC/H5 路径前缀为 `/genealogy/pc`\n- 后台管理接口不包含在本文件内\n- 登录后接口需要携带 token,且请求 Header 需携带 `clientid`\n",
- "version": "1.0.0"
- },
- "tags": [
- {
- "name": "验证中心"
- },
- {
- "name": "认证登录"
- },
- {
- "name": "文件上传"
- },
- {
- "name": "家谱"
- },
- {
- "name": "家族圈"
- },
- {
- "name": "行政区划"
- },
- {
- "name": "字辈谱"
- },
- {
- "name": "世系人物"
- },
- {
- "name": "内容文章"
- },
- {
- "name": "相册"
- },
- {
- "name": "视频"
- },
- {
- "name": "贺礼邀约"
- },
- {
- "name": "祭祀"
- },
- {
- "name": "族务记录"
- },
- {
- "name": "消息通知"
- }
- ],
- "paths": {
- "/genealogy/pc/auth/verification/{operationCode}/require": {
- "get": {
- "summary": "查询 PC 认证动作是否需要验证",
- "deprecated": false,
- "description": "服务端按 operationCode 对应 PC 路由的当前激活绑定解析验证场景,前端不得提交 sceneCode。",
- "tags": [
- "验证中心"
- ],
- "parameters": [
- {
- "name": "operationCode",
- "in": "path",
- "description": "PC 认证业务动作",
- "required": true,
- "example": "",
- "schema": {
- "type": "string",
- "enum": [
- "password-login",
- "sms-login",
- "register",
- "forgot-password",
- "phone-change",
- "account-deactivate"
- ]
- }
- },
- {
- "name": "tenantId",
- "in": "query",
- "description": "租户ID,用于区分不同租户的数据和验证策略",
- "required": true,
- "example": "000000",
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "subject",
- "in": "query",
- "description": "验证主体,通常为手机号、用户ID或登录账号",
- "required": false,
- "example": "13800000000",
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/VerificationRequireResult",
- "description": "验证需求查询结果"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/auth/verification/{operationCode}/challenge": {
- "post": {
- "summary": "生成 PC 认证动作验证挑战",
- "deprecated": false,
- "description": "服务端按 operationCode 的激活绑定解析场景。tenantId、subject 必须完整提交;clientid 仅从 Header 读取,前端不得提交 clientId 或 sceneCode。",
- "tags": [
- "验证中心"
- ],
- "parameters": [
- {
- "name": "operationCode",
- "in": "path",
- "description": "PC 认证业务动作",
- "required": true,
- "example": "",
- "schema": {
- "type": "string",
- "enum": [
- "password-login",
- "sms-login",
- "register",
- "forgot-password",
- "phone-change",
- "account-deactivate"
- ]
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/VerificationChallengeBody"
- },
- "example": {
- "tenantId": "000000",
- "subject": "13800000000"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/VerificationChallengeResult",
- "description": "验证挑战生成结果"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/auth/verification/{operationCode}/verify": {
- "post": {
- "summary": "校验 PC 认证动作验证结果并换取 validToken",
- "deprecated": false,
- "description": "必须使用生成挑战时相同的 operationCode、tenantId、subject 和 challengeId。clientid 仅从 Header 读取;服务端重新解析同一路由的激活场景,前端不得提交 clientId 或 sceneCode。",
- "tags": [
- "验证中心"
- ],
- "parameters": [
- {
- "name": "operationCode",
- "in": "path",
- "description": "PC 认证业务动作",
- "required": true,
- "example": "",
- "schema": {
- "type": "string",
- "enum": [
- "password-login",
- "sms-login",
- "register",
- "forgot-password",
- "phone-change",
- "account-deactivate"
- ]
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/VerificationCheckBody"
- },
- "examples": {
- "tianai_behavior": {
- "value": {
- "tenantId": "000000",
- "subject": "13800000000",
- "challengeId": "CAPTCHA_CHALLENGE_ID",
- "providerCode": "tianai",
- "captchaType": "SLIDER",
- "payload": {
- "track": {
- "bgImageWidth": 340,
- "bgImageHeight": 180,
- "templateImageWidth": 50,
- "templateImageHeight": 50,
- "startTime": 1720000000000,
- "stopTime": 1720000001500,
- "left": 120,
- "top": 0,
- "trackList": [
- {
- "x": 0,
- "y": 0,
- "t": 0,
- "type": "down"
- },
- {
- "x": 120,
- "y": 0,
- "t": 650,
- "type": "move"
- },
- {
- "x": 120,
- "y": 0,
- "t": 700,
- "type": "up"
- }
- ]
- }
- }
- },
- "summary": "天爱滑块/旋转/滑动还原/文字点选验证"
- },
- "system_image": {
- "value": {
- "tenantId": "000000",
- "subject": "13800000000",
- "challengeId": "CAPTCHA_CHALLENGE_ID",
- "providerCode": "ruoyi_image",
- "captchaType": "math",
- "payload": {
- "uuid": "captcha-uuid",
- "code": "6"
- }
- },
- "summary": "系统图形验证码"
- }
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/VerificationCheckResult",
- "description": "验证校验结果"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/auth/register": {
- "post": {
- "summary": "PC 用户注册",
- "deprecated": false,
- "description": "",
- "tags": [
- "认证登录"
- ],
- "parameters": [
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/PasswordRegisterBody"
- },
- "example": {
- "grantType": "password",
- "tenantId": "000000",
- "phone": "13800000000",
- "password": "e10adc3949ba59abbe56e057f20f883e",
- "nickName": "测试用户",
- "registerSource": "app",
- "smsCode": "1234"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/LoginResult",
- "description": "登录结果"
- },
- "400": {
- "description": "短信验证码必须为 4 位数字;验证码错误、过期、重复使用,或租户、客户端、场景不匹配时拒绝;携带 validToken、code、uuid、供应商配置等旧字段返回 HTTP 400。",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RVoid"
- }
- }
- },
- "headers": {}
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/auth/login": {
- "post": {
- "summary": "PC 密码登录",
- "deprecated": false,
- "description": "",
- "tags": [
- "认证登录"
- ],
- "parameters": [
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/PasswordLoginBody"
- },
- "example": {
- "grantType": "password",
- "tenantId": "000000",
- "phone": "13800000000",
- "password": "e10adc3949ba59abbe56e057f20f883e",
- "validToken": "valid-token-from-captcha-verify"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/LoginResult",
- "description": "登录结果"
- },
- "400": {
- "description": "后端按 PC_PASSWORD_LOGIN 路由的当前激活绑定解析场景;该场景策略要求验证时必须提交匹配的 validToken,不要求验证时 validToken 可为空;请求携带已废弃的 sceneCode 或其他未知字段返回 HTTP 400。",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RVoid"
- }
- }
- },
- "headers": {}
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/auth/login/sms": {
- "post": {
- "summary": "PC 短信登录",
- "deprecated": false,
- "description": "",
- "tags": [
- "认证登录"
- ],
- "parameters": [
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/SmsLoginBody"
- },
- "example": {
- "grantType": "sms",
- "tenantId": "000000",
- "phone": "13800000000",
- "smsCode": "1234"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/LoginResult",
- "description": "登录结果"
- },
- "400": {
- "description": "短信验证码必须为 4 位数字;验证码错误、过期、重复使用,或租户、客户端、场景不匹配时拒绝;携带 validToken、code、uuid、供应商配置等旧字段返回 HTTP 400。",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RVoid"
- }
- }
- },
- "headers": {}
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/auth/sms/{operationCode}/code": {
- "post": {
- "summary": "PC 发送短信验证码",
- "deprecated": false,
- "description": "operationCode 决定短信业务动作,服务端按对应 PC 路由的激活绑定解析验证场景。策略开启时需提交 validToken,关闭时可为空;前端不得提交 sceneCode 或短信供应商配置 ID。",
- "tags": [
- "认证登录"
- ],
- "parameters": [
- {
- "name": "operationCode",
- "in": "path",
- "description": "支持发送短信验证码的 PC 认证业务动作",
- "required": true,
- "example": "",
- "schema": {
- "type": "string",
- "enum": [
- "sms-login",
- "register",
- "forgot-password",
- "phone-change",
- "account-deactivate"
- ]
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/SmsCodeBody"
- },
- "example": {
- "tenantId": "000000",
- "phone": "13800000000",
- "grantType": "sms",
- "validToken": "captcha-ticket"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- },
- "400": {
- "description": "拒绝原因:票据缺失;票据与租户不匹配(错租户);票据与客户端不匹配(错客户端);票据与场景不匹配(错场景);票据过期;票据已被使用(重复使用);手机号主体不匹配;请求携带供应商配置或历史字段。",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RVoid"
- }
- }
- },
- "headers": {}
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/auth/profile": {
- "get": {
- "summary": "PC 当前用户资料",
- "deprecated": false,
- "description": "",
- "tags": [
- "认证登录"
- ],
- "parameters": [
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "put": {
- "summary": "PC 修改用户资料",
- "deprecated": false,
- "description": "",
- "tags": [
- "认证登录"
- ],
- "parameters": [
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ProfileUpdateBody"
- },
- "example": {
- "nickName": "张三",
- "realName": "张三",
- "avatar": "2060000000000000000",
- "sex": "0",
- "birthday": "1990-01-01",
- "email": "zhangsan@example.com"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/auth/password": {
- "put": {
- "summary": "PC 修改密码",
- "deprecated": false,
- "description": "",
- "tags": [
- "认证登录"
- ],
- "parameters": [
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/PasswordChangeBody"
- },
- "example": {
- "oldPassword": "e10adc3949ba59abbe56e057f20f883e",
- "newPassword": "25d55ad283aa400af464c76d713c07ad"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/auth/password/reset": {
- "put": {
- "summary": "PC 找回密码",
- "deprecated": false,
- "description": "",
- "tags": [
- "认证登录"
- ],
- "parameters": [
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/PasswordResetBody"
- },
- "example": {
- "grantType": "password",
- "tenantId": "000000",
- "phone": "13800000000",
- "smsCode": "1234",
- "newPassword": "25d55ad283aa400af464c76d713c07ad"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- },
- "400": {
- "description": "短信验证码必须为 4 位数字;验证码错误、过期、重复使用,或租户、客户端、场景不匹配时拒绝;携带 validToken、code、uuid、供应商配置等旧字段返回 HTTP 400。",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RVoid"
- }
- }
- },
- "headers": {}
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/auth/phone": {
- "put": {
- "summary": "PC 换绑手机号",
- "deprecated": false,
- "description": "",
- "tags": [
- "认证登录"
- ],
- "parameters": [
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/PhoneChangeBody"
- },
- "example": {
- "phone": "13900000000",
- "smsCode": "1234"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- },
- "400": {
- "description": "短信验证码必须为 4 位数字;验证码错误、过期、重复使用,或租户、客户端、场景不匹配时拒绝;携带 validToken、code、uuid、供应商配置等旧字段返回 HTTP 400。",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RVoid"
- }
- }
- },
- "headers": {}
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/auth/account/deactivate": {
- "post": {
- "summary": "PC 注销账号",
- "deprecated": false,
- "description": "",
- "tags": [
- "认证登录"
- ],
- "parameters": [
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/AccountDeactivateBody"
- },
- "example": {
- "smsCode": "1234"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- },
- "400": {
- "description": "短信验证码必须为 4 位数字;验证码错误、过期、重复使用,或租户、客户端、场景不匹配时拒绝;携带 validToken、code、uuid、供应商配置等旧字段返回 HTTP 400。",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RVoid"
- }
- }
- },
- "headers": {}
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/auth/logout": {
- "delete": {
- "summary": "PC 退出登录",
- "deprecated": false,
- "description": "",
- "tags": [
- "认证登录"
- ],
- "parameters": [
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/files/resumable/init": {
- "post": {
- "summary": "PC 分片上传初始化",
- "deprecated": false,
- "description": "所有文件统一使用分片上传;普通小文件可设置为一个分片。返回 instant=true 时直接使用返回的 OSS 信息,跳过分片上传和合并。",
- "tags": [
- "文件上传"
- ],
- "parameters": [
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ResumableInitBody"
- },
- "example": {
- "uploadId": "UPLOAD202607090001",
- "fileName": "cover.jpg",
- "fileMd5": "d41d8cd98f00b204e9800998ecf8427e",
- "totalSize": 9532,
- "totalChunks": 1,
- "chunkSize": 4194304,
- "contentType": "image/jpeg"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/files/resumable/chunk": {
- "post": {
- "summary": "PC 上传分片",
- "deprecated": false,
- "description": "uploadId 已绑定初始化契约。除最后一片外,分片实际大小必须等于 chunkSize;最后一片必须等于剩余字节数。",
- "tags": [
- "文件上传"
- ],
- "parameters": [
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "multipart/form-data": {
- "schema": {
- "type": "object",
- "properties": {
- "uploadId": {
- "type": "string",
- "example": ""
- },
- "chunkIndex": {
- "type": "integer",
- "examples": [
- 0
- ],
- "example": 0
- },
- "chunkMd5": {
- "type": "string",
- "examples": [
- "d41d8cd98f00b204e9800998ecf8427e"
- ],
- "example": "d41d8cd98f00b204e9800998ecf8427e"
- },
- "file": {
- "type": "string",
- "format": "binary",
- "example": ""
- }
- },
- "required": [
- "uploadId",
- "chunkIndex",
- "chunkMd5",
- "file"
- ]
- },
- "example": {
- "uploadId": "",
- "chunkIndex": 0,
- "chunkMd5": "d41d8cd98f00b204e9800998ecf8427e",
- "file": ""
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/files/resumable/complete": {
- "post": {
- "summary": "PC 完成分片上传",
- "deprecated": false,
- "description": "",
- "tags": [
- "文件上传"
- ],
- "parameters": [
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ResumableCompleteBody"
- },
- "example": {
- "uploadId": "UPLOAD202607090001",
- "fileName": "cover.jpg",
- "fileMd5": "d41d8cd98f00b204e9800998ecf8427e",
- "totalSize": 9532,
- "totalChunks": 1
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/FileUploadResult",
- "description": "文件上传结果"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/quota": {
- "get": {
- "summary": "PC 查询当前用户家谱配额",
- "deprecated": false,
- "description": "查询已创建和已加入的家谱数量、上限、剩余额度及是否还能继续操作。加入总数包含自己创建的家谱;limit 和 remaining 为 -1 时表示不限。",
- "tags": [
- "家谱"
- ],
- "parameters": [
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/GenealogyQuotaResult",
- "description": "当前业务用户家谱配额响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/feeds": {
- "get": {
- "summary": "PC 家族圈动态列表",
- "deprecated": false,
- "description": "",
- "tags": [
- "家族圈"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/FamilyFeedListResult",
- "description": "家族圈动态列表响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "post": {
- "summary": "PC 发布家族圈动态",
- "deprecated": false,
- "description": "",
- "tags": [
- "家族圈"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/FamilyFeedBody"
- },
- "example": {
- "feedType": "text",
- "feedContent": "今天上传一张老照片。",
- "mediaOssIds": "2060000000000000001,2060000000000000002",
- "sortOrder": 0,
- "status": "0"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/FamilyFeedResult",
- "description": "家族圈动态对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/feeds/page": {
- "get": {
- "summary": "PC 家族圈动态分页",
- "deprecated": false,
- "description": "",
- "tags": [
- "家族圈"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "pageNum",
- "in": "query",
- "description": "页码,从1开始",
- "required": false,
- "schema": {
- "type": "integer",
- "default": 1
- }
- },
- {
- "name": "pageSize",
- "in": "query",
- "description": "每页条数",
- "required": false,
- "schema": {
- "type": "integer",
- "default": 10
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/FamilyFeedPageResult",
- "description": "家族圈动态分页响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/feeds/{feedId}": {
- "get": {
- "summary": "PC 家族圈动态详情",
- "deprecated": false,
- "description": "",
- "tags": [
- "家族圈"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "feedId",
- "in": "path",
- "description": "家族动态ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/FamilyFeedResult",
- "description": "家族圈动态对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "put": {
- "summary": "PC 修改家族圈动态",
- "deprecated": false,
- "description": "",
- "tags": [
- "家族圈"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "feedId",
- "in": "path",
- "description": "家族动态ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/FamilyFeedBody"
- },
- "example": {
- "feedType": "text",
- "feedContent": "今天上传一张老照片。",
- "mediaOssIds": "2060000000000000001,2060000000000000002",
- "sortOrder": 0,
- "status": "0"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/FamilyFeedResult",
- "description": "家族圈动态对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "delete": {
- "summary": "PC 删除家族圈动态",
- "deprecated": false,
- "description": "",
- "tags": [
- "家族圈"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "feedId",
- "in": "path",
- "description": "家族动态ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/feeds/{feedId}/likes": {
- "post": {
- "summary": "PC 点赞动态",
- "deprecated": false,
- "description": "",
- "tags": [
- "家族圈"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "feedId",
- "in": "path",
- "description": "家族动态ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "delete": {
- "summary": "PC 取消点赞动态",
- "deprecated": false,
- "description": "",
- "tags": [
- "家族圈"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "feedId",
- "in": "path",
- "description": "家族动态ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/feeds/{feedId}/comments": {
- "get": {
- "summary": "PC 动态一级评论列表",
- "deprecated": false,
- "description": "仅返回正常展示的一级评论;每条评论的 replyCount 为正常展示的直接回复数量。",
- "tags": [
- "家族圈"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "feedId",
- "in": "path",
- "description": "家族动态ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/FamilyFeedCommentListResult",
- "description": "家族圈评论列表响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "post": {
- "summary": "PC 评论动态",
- "deprecated": false,
- "description": "",
- "tags": [
- "家族圈"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "feedId",
- "in": "path",
- "description": "家族动态ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/FamilyFeedCommentBody"
- },
- "example": {
- "parentCommentId": null,
- "commentContent": "这张照片很有年代感。"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/FamilyFeedCommentResult",
- "description": "家族圈评论对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/feeds/{feedId}/comments/page": {
- "get": {
- "summary": "PC 动态一级评论分页",
- "deprecated": false,
- "description": "仅返回正常展示的一级评论;展开回复时请调用 replies 接口。",
- "tags": [
- "家族圈"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "feedId",
- "in": "path",
- "description": "家族动态ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "pageNum",
- "in": "query",
- "description": "页码,从1开始",
- "required": false,
- "schema": {
- "type": "integer",
- "default": 1
- }
- },
- {
- "name": "pageSize",
- "in": "query",
- "description": "每页条数",
- "required": false,
- "schema": {
- "type": "integer",
- "default": 10
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/FamilyFeedCommentPageResult",
- "description": "家族圈评论分页响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/feeds/{feedId}/comments/{commentId}/replies": {
- "get": {
- "summary": "PC 获取评论的直接回复列表",
- "deprecated": false,
- "description": "仅返回指定正常评论的正常展示直接回复;回复的 replyCount 可用于继续按需展开下一层。",
- "tags": [
- "家族圈"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "feedId",
- "in": "path",
- "description": "家族动态ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "commentId",
- "in": "path",
- "description": "父评论 ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/FamilyFeedCommentListResult",
- "description": "家族圈评论列表响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/feeds/{feedId}/comments/{commentId}/replies/page": {
- "get": {
- "summary": "PC 分页获取评论的直接回复",
- "deprecated": false,
- "description": "",
- "tags": [
- "家族圈"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "feedId",
- "in": "path",
- "description": "家族动态ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "commentId",
- "in": "path",
- "description": "父评论 ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "pageNum",
- "in": "query",
- "description": "页码,从1开始",
- "required": false,
- "schema": {
- "type": "integer",
- "default": 1
- }
- },
- {
- "name": "pageSize",
- "in": "query",
- "description": "每页条数",
- "required": false,
- "schema": {
- "type": "integer",
- "default": 10
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/FamilyFeedCommentPageResult",
- "description": "家族圈评论分页响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/feeds/{feedId}/comments/{commentId}": {
- "delete": {
- "summary": "PC 删除本人动态评论;有回复时保留删除占位",
- "deprecated": false,
- "description": "",
- "tags": [
- "家族圈"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "feedId",
- "in": "path",
- "description": "家族动态ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "commentId",
- "in": "path",
- "description": "评论ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/region/children": {
- "get": {
- "summary": "查询下级行政区划",
- "deprecated": false,
- "description": "",
- "tags": [
- "行政区划"
- ],
- "parameters": [
- {
- "name": "parentCode",
- "in": "query",
- "description": "父级行政区划编码,不传或传0查省级",
- "required": false,
- "example": "51",
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "客户端ID",
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string",
- "default": "ced7e5f0498645c6ec642dcf450b036f"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/ListResult",
- "description": "通用列表响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/region/path/{regionCode}": {
- "get": {
- "summary": "查询行政区划路径",
- "deprecated": false,
- "description": "",
- "tags": [
- "行政区划"
- ],
- "parameters": [
- {
- "name": "regionCode",
- "in": "path",
- "description": "行政区划编码",
- "required": true,
- "example": "510000",
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "客户端ID",
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string",
- "default": "ced7e5f0498645c6ec642dcf450b036f"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/ListResult",
- "description": "通用列表响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/region/search": {
- "get": {
- "summary": "搜索行政区划",
- "deprecated": false,
- "description": "",
- "tags": [
- "行政区划"
- ],
- "parameters": [
- {
- "name": "keyword",
- "in": "query",
- "description": "搜索关键词,支持地区名称或编码模糊查询",
- "required": true,
- "example": "北京",
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "level",
- "in": "query",
- "description": "行政区划级别,1省、2市、3区县、4乡镇街道、5村社区",
- "required": false,
- "example": 3,
- "schema": {
- "type": "integer"
- }
- },
- {
- "name": "limit",
- "in": "query",
- "description": "返回数量上限",
- "required": false,
- "example": 20,
- "schema": {
- "type": "integer"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "客户端ID",
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string",
- "default": "ced7e5f0498645c6ec642dcf450b036f"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/ListResult",
- "description": "通用列表响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/region/{regionCode}": {
- "get": {
- "summary": "查询行政区划详情",
- "deprecated": false,
- "description": "",
- "tags": [
- "行政区划"
- ],
- "parameters": [
- {
- "name": "regionCode",
- "in": "path",
- "description": "行政区划编码",
- "required": true,
- "example": "510000",
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "客户端ID",
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string",
- "default": "ced7e5f0498645c6ec642dcf450b036f"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/region/children": {
- "get": {
- "summary": "查询下级行政区划",
- "deprecated": false,
- "description": "",
- "tags": [
- "行政区划"
- ],
- "parameters": [
- {
- "name": "parentCode",
- "in": "query",
- "description": "父级行政区划编码,不传或传0查省级",
- "required": false,
- "example": "51",
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "客户端ID",
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string",
- "default": "ced7e5f0498645c6ec642dcf450b036f"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/ListResult",
- "description": "通用列表响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/region/path/{regionCode}": {
- "get": {
- "summary": "查询行政区划路径",
- "deprecated": false,
- "description": "",
- "tags": [
- "行政区划"
- ],
- "parameters": [
- {
- "name": "regionCode",
- "in": "path",
- "description": "行政区划编码",
- "required": true,
- "example": "510000",
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "客户端ID",
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string",
- "default": "ced7e5f0498645c6ec642dcf450b036f"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/ListResult",
- "description": "通用列表响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/region/search": {
- "get": {
- "summary": "搜索行政区划",
- "deprecated": false,
- "description": "",
- "tags": [
- "行政区划"
- ],
- "parameters": [
- {
- "name": "keyword",
- "in": "query",
- "description": "搜索关键词,支持地区名称或编码模糊查询",
- "required": true,
- "example": "北京",
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "level",
- "in": "query",
- "description": "行政区划级别,1省、2市、3区县、4乡镇街道、5村社区",
- "required": false,
- "example": 3,
- "schema": {
- "type": "integer"
- }
- },
- {
- "name": "limit",
- "in": "query",
- "description": "返回数量上限",
- "required": false,
- "example": 20,
- "schema": {
- "type": "integer"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "客户端ID",
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string",
- "default": "ced7e5f0498645c6ec642dcf450b036f"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/ListResult",
- "description": "通用列表响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/region/{regionCode}": {
- "get": {
- "summary": "查询行政区划详情",
- "deprecated": false,
- "description": "",
- "tags": [
- "行政区划"
- ],
- "parameters": [
- {
- "name": "regionCode",
- "in": "path",
- "description": "行政区划编码",
- "required": true,
- "example": "510000",
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "客户端ID",
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string",
- "default": "ced7e5f0498645c6ec642dcf450b036f"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/generation-poems": {
- "get": {
- "summary": "PC 查询正常字辈谱",
- "deprecated": false,
- "description": "对可查看家谱的业务用户开放;仅返回正常状态字辈,供世系人物录入和展示使用。",
- "tags": [
- "字辈谱"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/GenerationPoemListResult",
- "description": "字辈列表响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "post": {
- "summary": "PC 新增字辈",
- "deprecated": false,
- "description": "",
- "tags": [
- "字辈谱"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/GenerationPoemBody"
- },
- "example": {
- "generationNo": 5,
- "generationText": "忠",
- "description": "第五世字辈",
- "sortOrder": 5,
- "status": "0"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/GenerationPoemResult",
- "description": "字辈详情响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/generation-poems/management": {
- "get": {
- "summary": "PC 查询字辈维护列表",
- "deprecated": false,
- "description": "仅家谱内容编辑者可访问,返回正常和停用字辈,用于恢复、纠错和排序调整。",
- "tags": [
- "字辈谱"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/GenerationPoemListResult",
- "description": "字辈列表响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/generation-poems/batch/preview": {
- "post": {
- "summary": "PC 批量字辈预览",
- "deprecated": false,
- "description": "",
- "tags": [
- "字辈谱"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/GenerationPoemBatchBody"
- },
- "example": {
- "poemText": "德承家亦\n忠厚传芳",
- "disableMissing": false
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/GenerationPoemBatchPreviewResult",
- "description": "字辈批量预览响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/generation-poems/batch/save": {
- "post": {
- "summary": "PC 批量保存字辈",
- "deprecated": false,
- "description": "保存时会重新按当前数据生成差异;停用不删除历史字辈记录。",
- "tags": [
- "字辈谱"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/GenerationPoemBatchBody"
- },
- "example": {
- "poemText": "德承家亦\n忠厚传芳",
- "disableMissing": false
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/generation-poems/{poemId}": {
- "put": {
- "summary": "PC 修改、停用或恢复字辈",
- "deprecated": false,
- "description": "",
- "tags": [
- "字辈谱"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "poemId",
- "in": "path",
- "description": "字辈记录ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/GenerationPoemBody"
- },
- "example": {
- "generationNo": 5,
- "generationText": "忠",
- "description": "第五世字辈",
- "sortOrder": 5,
- "status": "0"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/GenerationPoemResult",
- "description": "字辈详情响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/lineage/persons": {
- "get": {
- "summary": "PC 世系人物列表",
- "deprecated": false,
- "description": "",
- "tags": [
- "世系人物"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/LineagePersonListResult",
- "description": "世系人物列表或选项响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "post": {
- "summary": "PC 新增世系人物",
- "deprecated": false,
- "description": "",
- "tags": [
- "世系人物"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/LineagePersonBody"
- },
- "example": {
- "bindingMode": "NONE",
- "personNo": "P202607090001",
- "name": "彭德明",
- "aliasName": "德明",
- "sex": "0",
- "generation": 1,
- "generationName": "德",
- "avatarOssId": "2060000000000000001",
- "birthDate": "1950-01-01",
- "birthLunar": "0",
- "birthPlace": "江西吉安",
- "personStatus": "0",
- "biography": "第一世人物简介",
- "sortOrder": 1
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/LineagePersonResult",
- "description": "世系人物详情响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/lineage/persons/page": {
- "get": {
- "summary": "PC 世系人物分页",
- "deprecated": false,
- "description": "",
- "tags": [
- "世系人物"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "pageNum",
- "in": "query",
- "description": "页码,从1开始",
- "required": false,
- "schema": {
- "type": "integer",
- "default": 1
- }
- },
- {
- "name": "pageSize",
- "in": "query",
- "description": "每页条数",
- "required": false,
- "schema": {
- "type": "integer",
- "default": 10
- }
- },
- {
- "name": "keyword",
- "in": "query",
- "description": "姓名、别名或人物编号关键词",
- "required": false,
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "generation",
- "in": "query",
- "description": "世代序号",
- "required": false,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "personStatus",
- "in": "query",
- "description": "字典 gen_lineage_person_status:0=健在,1=已故,2=未知",
- "required": false,
- "schema": {
- "type": "string",
- "enum": [
- "0",
- "1",
- "2"
- ],
- "x-dict-type": "gen_lineage_person_status",
- "examples": [
- "0"
- ]
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/LineagePersonPageResult",
- "description": "世系人物分页响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/lineage/persons/options": {
- "get": {
- "summary": "PC 世系人物选项",
- "deprecated": false,
- "description": "",
- "tags": [
- "世系人物"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "keyword",
- "in": "query",
- "description": "姓名、别名或人物编号关键词",
- "required": false,
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/LineagePersonListResult",
- "description": "世系人物列表或选项响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/lineage/tree": {
- "get": {
- "summary": "PC 世系树",
- "deprecated": false,
- "description": "",
- "tags": [
- "世系人物"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/LineagePersonTreeResult",
- "description": "世系树响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/lineage/persons/{personId}": {
- "get": {
- "summary": "PC 世系人物详情",
- "deprecated": false,
- "description": "",
- "tags": [
- "世系人物"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "personId",
- "in": "path",
- "description": "世系人物ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/LineagePersonResult",
- "description": "世系人物详情响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "put": {
- "summary": "PC 修改世系人物",
- "deprecated": false,
- "description": "",
- "tags": [
- "世系人物"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "personId",
- "in": "path",
- "description": "世系人物ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/LineagePersonBody"
- },
- "example": {
- "bindingMode": "NONE",
- "personNo": "P202607090001",
- "name": "彭德明",
- "aliasName": "德明",
- "sex": "0",
- "generation": 1,
- "generationName": "德",
- "avatarOssId": "2060000000000000001",
- "birthDate": "1950-01-01",
- "birthLunar": "0",
- "birthPlace": "江西吉安",
- "personStatus": "0",
- "biography": "第一世人物简介",
- "sortOrder": 1
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/LineagePersonResult",
- "description": "世系人物详情响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "delete": {
- "summary": "PC 停用世系人物",
- "deprecated": false,
- "description": "逻辑停用人物,不执行物理删除;存在正常子女时拒绝停用。",
- "tags": [
- "世系人物"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "personId",
- "in": "path",
- "description": "世系人物ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/lineage/persons/{personId}/children": {
- "post": {
- "summary": "PC 给人物添加子女",
- "deprecated": false,
- "description": "",
- "tags": [
- "世系人物"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "personId",
- "in": "path",
- "description": "世系人物ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/LineagePersonBody"
- },
- "example": {
- "bindingMode": "NONE",
- "personNo": "P202607090001",
- "name": "彭德明",
- "aliasName": "德明",
- "sex": "0",
- "generation": 1,
- "generationName": "德",
- "avatarOssId": "2060000000000000001",
- "birthDate": "1950-01-01",
- "birthLunar": "0",
- "birthPlace": "江西吉安",
- "personStatus": "0",
- "biography": "第一世人物简介",
- "sortOrder": 1
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/LineagePersonResult",
- "description": "世系人物详情响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/lineage/persons/{personId}/parents": {
- "post": {
- "summary": "PC 给人物添加父母",
- "deprecated": false,
- "description": "",
- "tags": [
- "世系人物"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "personId",
- "in": "path",
- "description": "世系人物ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/LineagePersonBody"
- },
- "example": {
- "bindingMode": "NONE",
- "personNo": "P202607090001",
- "name": "彭德明",
- "aliasName": "德明",
- "sex": "0",
- "generation": 1,
- "generationName": "德",
- "avatarOssId": "2060000000000000001",
- "birthDate": "1950-01-01",
- "birthLunar": "0",
- "birthPlace": "江西吉安",
- "personStatus": "0",
- "biography": "第一世人物简介",
- "sortOrder": 1
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/LineagePersonResult",
- "description": "世系人物详情响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/lineage/persons/{personId}/siblings": {
- "post": {
- "summary": "PC 给人物添加兄弟姐妹",
- "deprecated": false,
- "description": "",
- "tags": [
- "世系人物"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "personId",
- "in": "path",
- "description": "世系人物ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/LineagePersonBody"
- },
- "example": {
- "bindingMode": "NONE",
- "personNo": "P202607090001",
- "name": "彭德明",
- "aliasName": "德明",
- "sex": "0",
- "generation": 1,
- "generationName": "德",
- "avatarOssId": "2060000000000000001",
- "birthDate": "1950-01-01",
- "birthLunar": "0",
- "birthPlace": "江西吉安",
- "personStatus": "0",
- "biography": "第一世人物简介",
- "sortOrder": 1
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/LineagePersonResult",
- "description": "世系人物详情响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/lineage/persons/{personId}/spouses": {
- "post": {
- "summary": "PC 给人物添加配偶",
- "deprecated": false,
- "description": "",
- "tags": [
- "世系人物"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "personId",
- "in": "path",
- "description": "世系人物ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/LineagePersonBody"
- },
- "example": {
- "bindingMode": "NONE",
- "personNo": "P202607090001",
- "name": "彭德明",
- "aliasName": "德明",
- "sex": "0",
- "generation": 1,
- "generationName": "德",
- "avatarOssId": "2060000000000000001",
- "birthDate": "1950-01-01",
- "birthLunar": "0",
- "birthPlace": "江西吉安",
- "personStatus": "0",
- "biography": "第一世人物简介",
- "sortOrder": 1
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/LineagePersonResult",
- "description": "世系人物详情响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/articles/{articleId}": {
- "delete": {
- "summary": "PC 删除谱文",
- "deprecated": false,
- "description": "",
- "tags": [
- "内容文章"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "articleId",
- "in": "path",
- "description": "要删除的谱文ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/albums/{albumId}": {
- "delete": {
- "summary": "PC 删除相册",
- "deprecated": false,
- "description": "逻辑删除相册及其照片,并释放封面和照片文件引用。",
- "tags": [
- "相册"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "albumId",
- "in": "path",
- "description": "要删除的相册ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/albums/{albumId}/photos/{photoId}": {
- "delete": {
- "summary": "PC 删除单张相册图片",
- "deprecated": false,
- "description": "",
- "tags": [
- "相册"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "albumId",
- "in": "path",
- "description": "相册ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "photoId",
- "in": "path",
- "description": "要删除的相册图片ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/videos/{videoId}": {
- "delete": {
- "summary": "PC 删除视频",
- "deprecated": false,
- "description": "逻辑删除视频,并释放视频文件和封面文件引用。",
- "tags": [
- "视频"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "videoId",
- "in": "path",
- "description": "要删除的视频ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "get": {
- "summary": "PC 视频详情",
- "deprecated": false,
- "description": "",
- "tags": [
- "视频"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "videoId",
- "in": "path",
- "description": "视频ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "put": {
- "summary": "PC 修改视频",
- "deprecated": false,
- "description": "",
- "tags": [
- "视频"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "videoId",
- "in": "path",
- "description": "视频ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/VideoBody"
- },
- "example": {
- "videoTitle": "家族活动记录",
- "videoDesc": "清明祭祖活动视频",
- "coverOssId": "2060000000000000001",
- "videoOssId": "2060000000000000002",
- "durationSeconds": 180,
- "sortOrder": 1,
- "status": "0"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/videos": {
- "get": {
- "summary": "PC 视频列表",
- "deprecated": false,
- "description": "",
- "tags": [
- "视频"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/ListResult",
- "description": "通用列表响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "post": {
- "summary": "PC 新增视频",
- "deprecated": false,
- "description": "",
- "tags": [
- "视频"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/VideoBody"
- },
- "example": {
- "videoTitle": "家族活动记录",
- "videoDesc": "清明祭祖活动视频",
- "coverOssId": "2060000000000000001",
- "videoOssId": "2060000000000000002",
- "durationSeconds": 180,
- "sortOrder": 1,
- "status": "0"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/ceremonies/{ceremonyId}/invitees": {
- "put": {
- "summary": "PC 替换活动受邀人",
- "deprecated": false,
- "description": "使用完整名单替换当前待响应受邀人;仅家谱内容管理员可操作,受邀人必须是同一家谱的正常成员。",
- "tags": [
- "贺礼邀约"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "ceremonyId",
- "in": "path",
- "description": "贺礼活动ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/CeremonyInviteesBody"
- },
- "example": {
- "inviteeUserIds": [
- 900000001,
- 900000002
- ]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/CeremonyInvitationListResult",
- "description": "贺礼邀约列表响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/ceremonies/{ceremonyId}/invitations": {
- "get": {
- "summary": "PC 查询活动邀请名单",
- "deprecated": false,
- "description": "查询受邀人及其待响应、接受、拒绝或取消状态,仅家谱内容管理员可见。",
- "tags": [
- "贺礼邀约"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "ceremonyId",
- "in": "path",
- "description": "贺礼活动ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/CeremonyInvitationListResult",
- "description": "贺礼邀约列表响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/ceremonies/{ceremonyId}/invitations/me": {
- "put": {
- "summary": "PC 响应当前用户的活动邀请",
- "deprecated": false,
- "description": "当前登录用户接受或拒绝自己的待响应邀请,不能代替其他用户操作。",
- "tags": [
- "贺礼邀约"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "ceremonyId",
- "in": "path",
- "description": "贺礼活动ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/CeremonyInvitationResponseBody"
- },
- "example": {
- "inviteStatus": "ACCEPTED"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/CeremonyInvitationResult",
- "description": "贺礼邀约详情响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/ceremony-invitations/mine": {
- "get": {
- "summary": "PC 查询我的活动邀请",
- "deprecated": false,
- "description": "查询当前租户下发给当前业务用户且活动仍正常的邀请。",
- "tags": [
- "贺礼邀约"
- ],
- "parameters": [
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/CeremonyInvitationListResult",
- "description": "贺礼邀约列表响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/ceremonies/{ceremonyId}": {
- "delete": {
- "summary": "PC 删除祭祀活动",
- "deprecated": false,
- "description": "逻辑删除祭祀活动及其祭品,并释放活动封面文件引用。",
- "tags": [
- "祭祀"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "ceremonyId",
- "in": "path",
- "description": "要删除的祭祀活动ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/ceremonies/{ceremonyId}/gifts/{giftId}": {
- "delete": {
- "summary": "PC 删除单条祭品",
- "deprecated": false,
- "description": "",
- "tags": [
- "祭祀"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "ceremonyId",
- "in": "path",
- "description": "祭祀活动ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "giftId",
- "in": "path",
- "description": "要删除的祭品ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/growth-records": {
- "get": {
- "summary": "PC 成长记录列表",
- "deprecated": false,
- "description": "",
- "tags": [
- "族务记录"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/ListResult",
- "description": "通用列表响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "post": {
- "summary": "PC 新增成长记录",
- "deprecated": false,
- "description": "",
- "tags": [
- "族务记录"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/GrowthRecordBody"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/growth-records/{recordId}": {
- "get": {
- "summary": "PC 成长记录详情",
- "deprecated": false,
- "description": "",
- "tags": [
- "族务记录"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "recordId",
- "in": "path",
- "description": "成长记录ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "put": {
- "summary": "PC 修改成长记录",
- "deprecated": false,
- "description": "",
- "tags": [
- "族务记录"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "recordId",
- "in": "path",
- "description": "成长记录ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/GrowthRecordBody"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "delete": {
- "summary": "PC 删除成长记录",
- "deprecated": false,
- "description": "",
- "tags": [
- "族务记录"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "recordId",
- "in": "path",
- "description": "要删除的成长记录ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/relative-records": {
- "get": {
- "summary": "PC 亲友记录列表",
- "deprecated": false,
- "description": "",
- "tags": [
- "族务记录"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/ListResult",
- "description": "通用列表响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "post": {
- "summary": "PC 新增亲友记录",
- "deprecated": false,
- "description": "",
- "tags": [
- "族务记录"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RelativeRecordBody"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/relative-records/{relativeId}": {
- "get": {
- "summary": "PC 亲友记录详情",
- "deprecated": false,
- "description": "",
- "tags": [
- "族务记录"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "relativeId",
- "in": "path",
- "description": "亲友记录ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "put": {
- "summary": "PC 修改亲友记录",
- "deprecated": false,
- "description": "",
- "tags": [
- "族务记录"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "relativeId",
- "in": "path",
- "description": "亲友记录ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RelativeRecordBody"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "delete": {
- "summary": "PC 删除亲友记录",
- "deprecated": false,
- "description": "",
- "tags": [
- "族务记录"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "relativeId",
- "in": "path",
- "description": "要删除的亲友记录ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/memos": {
- "get": {
- "summary": "PC 备忘录列表",
- "deprecated": false,
- "description": "",
- "tags": [
- "族务记录"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/ListResult",
- "description": "通用列表响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "post": {
- "summary": "PC 新增备忘录",
- "deprecated": false,
- "description": "",
- "tags": [
- "族务记录"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/MemoBody"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/memos/{memoId}": {
- "get": {
- "summary": "PC 备忘录详情",
- "deprecated": false,
- "description": "",
- "tags": [
- "族务记录"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "memoId",
- "in": "path",
- "description": "备忘录ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "put": {
- "summary": "PC 修改备忘录",
- "deprecated": false,
- "description": "",
- "tags": [
- "族务记录"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "memoId",
- "in": "path",
- "description": "备忘录ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/MemoBody"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "delete": {
- "summary": "PC 删除备忘录",
- "deprecated": false,
- "description": "",
- "tags": [
- "族务记录"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "memoId",
- "in": "path",
- "description": "要删除的备忘录ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/merit-records/{meritId}": {
- "delete": {
- "summary": "PC 删除功德记录",
- "deprecated": false,
- "description": "",
- "tags": [
- "族务记录"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "meritId",
- "in": "path",
- "description": "要删除的功德记录ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "get": {
- "summary": "PC 功德记录详情",
- "deprecated": false,
- "description": "",
- "tags": [
- "族务记录"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "meritId",
- "in": "path",
- "description": "功德记录ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "put": {
- "summary": "PC 修改功德记录",
- "deprecated": false,
- "description": "",
- "tags": [
- "族务记录"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "meritId",
- "in": "path",
- "description": "功德记录ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/MeritRecordBody"
- },
- "example": {
- "donorName": "张三",
- "meritType": "donation",
- "meritTitle": "修缮祠堂捐赠",
- "meritContent": "用于祠堂修缮",
- "amount": 1000,
- "meritTime": "2026-07-26 10:00:00",
- "sortOrder": 1,
- "status": "0"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/genealogies/{genealogyId}/merit-records": {
- "get": {
- "summary": "PC 功德记录列表",
- "deprecated": false,
- "description": "",
- "tags": [
- "族务记录"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/ListResult",
- "description": "通用列表响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- },
- "post": {
- "summary": "PC 新增功德记录",
- "deprecated": false,
- "description": "",
- "tags": [
- "族务记录"
- ],
- "parameters": [
- {
- "name": "genealogyId",
- "in": "path",
- "description": "家谱ID",
- "required": true,
- "example": 900001001,
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/MeritRecordBody"
- },
- "example": {
- "donorName": "张三",
- "meritType": "donation",
- "meritTitle": "修缮祠堂捐赠",
- "meritContent": "用于祠堂修缮",
- "amount": 1000,
- "meritTime": "2026-07-26 10:00:00",
- "sortOrder": 1,
- "status": "0"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "$ref": "#/components/responses/ObjectResult",
- "description": "通用对象响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/notifications": {
- "get": {
- "summary": "PC 消息通知列表",
- "deprecated": false,
- "description": "",
- "tags": [
- "消息通知"
- ],
- "parameters": [
- {
- "name": "readStatus",
- "in": "query",
- "description": "字典 gen_notification_read_status:0=未读,1=已读",
- "required": false,
- "schema": {
- "type": "string",
- "enum": [
- "0",
- "1"
- ],
- "x-dict-type": "gen_notification_read_status",
- "examples": [
- "0"
- ]
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/ListResult",
- "description": "通用列表响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/notifications/unread-count": {
- "get": {
- "summary": "PC 查询未读通知数量",
- "deprecated": false,
- "description": "",
- "tags": [
- "消息通知"
- ],
- "parameters": [
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/LongResult",
- "description": "长整型数据响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/notifications/{notificationId}/read": {
- "post": {
- "summary": "PC 标记通知已读",
- "deprecated": false,
- "description": "",
- "tags": [
- "消息通知"
- ],
- "parameters": [
- {
- "name": "notificationId",
- "in": "path",
- "description": "通知ID",
- "required": true,
- "example": "",
- "schema": {
- "type": "integer",
- "format": "int64"
- }
- },
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- },
- "/genealogy/pc/notifications/read-all": {
- "post": {
- "summary": "PC 全部标记已读",
- "deprecated": false,
- "description": "",
- "tags": [
- "消息通知"
- ],
- "parameters": [
- {
- "name": "clientid",
- "in": "header",
- "description": "PC 认证业务请求的 clientid Header 必填;是业务客户端唯一来源;请求体不得提交 clientId,且客户端 clientKey 必须为 web_pc 并与 PC 路由一致。",
- "required": true,
- "example": "ced7e5f0498645c6ec642dcf450b036f",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/VoidResult",
- "description": "通用成功响应"
- }
- },
- "security": [
- {
- "SaToken1": []
- }
- ]
- }
- }
- },
- "webhooks": {},
- "components": {
- "schemas": {
- "CeremonyInviteesBody": {
- "type": "object",
- "required": [
- "inviteeUserIds"
- ],
- "properties": {
- "inviteeUserIds": {
- "description": "完整受邀业务用户ID列表;空数组表示取消全部尚未响应的邀请",
- "type": "array",
- "uniqueItems": true,
- "items": {
- "type": "integer",
- "format": "int64"
- }
- }
- },
- "examples": [
- {
- "inviteeUserIds": [
- 900000001,
- 900000002
- ]
- }
- ]
- },
- "CeremonyInvitationResponseBody": {
- "type": "object",
- "required": [
- "inviteStatus"
- ],
- "properties": {
- "inviteStatus": {
- "description": "当前用户的邀约响应,只允许接受或拒绝",
- "type": "string",
- "enum": [
- "ACCEPTED",
- "DECLINED"
- ]
- }
- },
- "examples": [
- {
- "inviteStatus": "ACCEPTED"
- }
- ]
- },
- "GrowthRecordBody": {
- "type": "object",
- "required": [
- "recordTitle"
- ],
- "properties": {
- "lineagePersonId": {
- "description": "绑定的世系人物ID",
- "type": "integer",
- "format": "int64"
- },
- "recordType": {
- "description": "记录类型",
- "type": "string"
- },
- "recordTitle": {
- "description": "记录标题",
- "type": "string"
- },
- "recordContent": {
- "description": "记录内容",
- "type": "string"
- },
- "recordDate": {
- "description": "记录日期",
- "type": "string"
- },
- "remindTime": {
- "description": "提醒时间",
- "type": "string"
- },
- "mediaOssIds": {
- "description": "多个正整数 OSS ID 使用英文逗号分隔",
- "type": "string",
- "pattern": "^$|^[1-9][0-9]*(,[1-9][0-9]*)*$"
- },
- "sortOrder": {
- "description": "排序值",
- "type": "integer",
- "format": "int64"
- },
- "status": {
- "description": "字典 sys_normal_disable:0=正常,1=停用",
- "type": "string",
- "enum": [
- "0",
- "1"
- ],
- "x-dict-type": "sys_normal_disable",
- "examples": [
- "0"
- ]
- }
- }
- },
- "RelativeRecordBody": {
- "type": "object",
- "required": [
- "relativeName"
- ],
- "properties": {
- "relativeName": {
- "description": "亲友姓名",
- "type": "string"
- },
- "relationName": {
- "description": "关系名称",
- "type": "string"
- },
- "eventName": {
- "description": "事件名称",
- "type": "string"
- },
- "eventTime": {
- "description": "事件时间",
- "type": "string"
- },
- "giftAmount": {
- "description": "礼金金额",
- "type": "number"
- },
- "recordContent": {
- "description": "记录内容",
- "type": "string"
- },
- "mediaOssIds": {
- "description": "多个正整数 OSS ID 使用英文逗号分隔",
- "type": "string",
- "pattern": "^$|^[1-9][0-9]*(,[1-9][0-9]*)*$"
- },
- "sortOrder": {
- "description": "排序值",
- "type": "integer",
- "format": "int64"
- },
- "status": {
- "description": "字典 sys_normal_disable:0=正常,1=停用",
- "type": "string",
- "enum": [
- "0",
- "1"
- ],
- "x-dict-type": "sys_normal_disable",
- "examples": [
- "0"
- ]
- }
- }
- },
- "MemoBody": {
- "type": "object",
- "required": [
- "memoTitle"
- ],
- "properties": {
- "memoTitle": {
- "description": "备忘标题",
- "type": "string"
- },
- "memoContent": {
- "description": "备忘内容",
- "type": "string"
- },
- "remindTime": {
- "description": "提醒时间",
- "type": "string"
- },
- "completed": {
- "description": "是否已完成",
- "type": "string"
- },
- "mediaOssIds": {
- "description": "多个正整数 OSS ID 使用英文逗号分隔",
- "type": "string",
- "pattern": "^$|^[1-9][0-9]*(,[1-9][0-9]*)*$"
- },
- "sortOrder": {
- "description": "排序值",
- "type": "integer",
- "format": "int64"
- },
- "status": {
- "description": "字典 sys_normal_disable:0=正常,1=停用",
- "type": "string",
- "enum": [
- "0",
- "1"
- ],
- "x-dict-type": "sys_normal_disable",
- "examples": [
- "0"
- ]
- }
- }
- },
- "RVoid": {
- "type": "object",
- "properties": {
- "code": {
- "description": "系统图形验证码或响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string",
- "examples": [
- "操作成功"
- ]
- },
- "data": {
- "description": "响应数据主体",
- "type": "null"
- }
- }
- },
- "PasswordRegisterBody": {
- "type": "object",
- "additionalProperties": false,
- "required": [
- "grantType",
- "tenantId",
- "phone",
- "password",
- "smsCode"
- ],
- "properties": {
- "grantType": {
- "description": "授权类型,例如password、sms、wechat、apple",
- "type": "string",
- "examples": [
- "password"
- ]
- },
- "tenantId": {
- "description": "租户ID,用于区分不同租户的数据和验证策略",
- "type": "string",
- "examples": [
- "000000"
- ]
- },
- "phone": {
- "description": "手机号",
- "type": "string",
- "examples": [
- "13800000000"
- ]
- },
- "password": {
- "type": "string",
- "description": "32 位 MD5",
- "examples": [
- "e10adc3949ba59abbe56e057f20f883e"
- ]
- },
- "nickName": {
- "description": "用户昵称",
- "type": "string"
- },
- "registerSource": {
- "description": "注册来源,例如APP、PC、H5、MINI_PROGRAM",
- "type": "string"
- },
- "smsCode": {
- "description": "4 位短信验证码",
- "type": "string",
- "pattern": "^\\d{4}$",
- "examples": [
- "1234"
- ]
- }
- }
- },
- "PasswordLoginBody": {
- "description": "PC 用户密码登录请求;验证场景由后端按 PC_PASSWORD_LOGIN 路由的当前激活绑定解析,前端不得提交 sceneCode;validToken 是否需要由解析后场景的策略决定。",
- "type": "object",
- "additionalProperties": false,
- "required": [
- "grantType",
- "tenantId",
- "phone",
- "password"
- ],
- "properties": {
- "grantType": {
- "description": "授权类型,例如password、sms、wechat、apple",
- "type": "string",
- "examples": [
- "password"
- ]
- },
- "tenantId": {
- "description": "租户ID,用于区分不同租户的数据和验证策略",
- "type": "string",
- "examples": [
- "000000"
- ]
- },
- "phone": {
- "description": "登录手机号,也是行为验证票据绑定的验证主体。",
- "type": "string",
- "examples": [
- "13800000000"
- ]
- },
- "password": {
- "type": "string",
- "description": "32 位 MD5",
- "examples": [
- "e10adc3949ba59abbe56e057f20f883e"
- ]
- },
- "validToken": {
- "description": "验证中心通过后返回的一次性票据;后台验证策略关闭时可为空,开启时必须提交。",
- "type": "string"
- }
- }
- },
- "SmsLoginBody": {
- "type": "object",
- "additionalProperties": false,
- "required": [
- "grantType",
- "tenantId",
- "phone",
- "smsCode"
- ],
- "properties": {
- "grantType": {
- "description": "授权类型,例如password、sms、wechat、apple",
- "type": "string",
- "examples": [
- "sms"
- ]
- },
- "tenantId": {
- "description": "租户ID,用于区分不同租户的数据和验证策略",
- "type": "string",
- "examples": [
- "000000"
- ]
- },
- "phone": {
- "description": "手机号",
- "type": "string",
- "examples": [
- "13800000000"
- ]
- },
- "smsCode": {
- "description": "4 位短信验证码",
- "type": "string",
- "pattern": "^\\d{4}$",
- "examples": [
- "1234"
- ]
- }
- }
- },
- "SmsCodeBody": {
- "type": "object",
- "additionalProperties": false,
- "required": [
- "grantType",
- "tenantId",
- "phone"
- ],
- "properties": {
- "grantType": {
- "description": "授权类型,例如password、sms、wechat、apple",
- "type": "string",
- "examples": [
- "sms"
- ]
- },
- "tenantId": {
- "description": "租户ID,用于区分不同租户的数据和验证策略",
- "type": "string",
- "examples": [
- "000000"
- ]
- },
- "phone": {
- "description": "手机号",
- "type": "string",
- "examples": [
- "13800000000"
- ]
- },
- "validToken": {
- "description": "验证中心通过后返回的票据,仅用于发送短信验证码;后台验证策略关闭时可为空,开启时必填。",
- "type": "string"
- }
- }
- },
- "ProfileUpdateBody": {
- "type": "object",
- "additionalProperties": false,
- "properties": {
- "nickName": {
- "description": "用户昵称",
- "type": "string",
- "maxLength": 30
- },
- "realName": {
- "description": "真实姓名",
- "type": "string",
- "maxLength": 30
- },
- "avatar": {
- "description": "头像文件OSS ID",
- "type": "integer",
- "format": "int64"
- },
- "sex": {
- "description": "字典 sys_user_sex:0=男,1=女,2=未知",
- "type": "string",
- "enum": [
- "0",
- "1",
- "2"
- ],
- "x-dict-type": "sys_user_sex",
- "examples": [
- "2"
- ]
- },
- "birthday": {
- "description": "生日,格式 yyyy-MM-dd",
- "type": "string",
- "format": "date"
- },
- "email": {
- "description": "邮箱",
- "type": "string",
- "format": "email",
- "maxLength": 100
- }
- }
- },
- "PasswordChangeBody": {
- "type": "object",
- "required": [
- "oldPassword",
- "newPassword"
- ],
- "properties": {
- "oldPassword": {
- "type": "string",
- "description": "32 位 MD5"
- },
- "newPassword": {
- "type": "string",
- "description": "32 位 MD5"
- }
- }
- },
- "PasswordResetBody": {
- "type": "object",
- "additionalProperties": false,
- "required": [
- "grantType",
- "tenantId",
- "phone",
- "smsCode",
- "newPassword"
- ],
- "properties": {
- "grantType": {
- "description": "授权类型",
- "type": "string",
- "examples": [
- "password"
- ]
- },
- "tenantId": {
- "description": "租户ID,用于区分不同租户的数据和验证策略",
- "type": "string",
- "examples": [
- "000000"
- ]
- },
- "phone": {
- "description": "手机号",
- "type": "string"
- },
- "smsCode": {
- "description": "4 位短信验证码",
- "type": "string",
- "pattern": "^\\d{4}$",
- "examples": [
- "1234"
- ]
- },
- "newPassword": {
- "type": "string",
- "description": "32 位 MD5"
- }
- }
- },
- "PhoneChangeBody": {
- "type": "object",
- "additionalProperties": false,
- "required": [
- "phone",
- "smsCode"
- ],
- "properties": {
- "phone": {
- "description": "新手机号",
- "type": "string"
- },
- "smsCode": {
- "description": "4 位短信验证码",
- "type": "string",
- "pattern": "^\\d{4}$",
- "examples": [
- "1234"
- ]
- }
- }
- },
- "AccountDeactivateBody": {
- "type": "object",
- "additionalProperties": false,
- "required": [
- "smsCode"
- ],
- "properties": {
- "smsCode": {
- "description": "4 位短信验证码",
- "type": "string",
- "pattern": "^\\d{4}$",
- "examples": [
- "1234"
- ]
- }
- }
- },
- "ResumableInitBody": {
- "type": "object",
- "additionalProperties": false,
- "required": [
- "uploadId",
- "fileName",
- "fileMd5",
- "totalSize",
- "totalChunks",
- "chunkSize"
- ],
- "properties": {
- "uploadId": {
- "description": "客户端生成并在整个上传过程保持不变的上传任务ID",
- "type": "string"
- },
- "fileName": {
- "description": "原始文件名",
- "type": "string"
- },
- "fileMd5": {
- "description": "完整文件MD5,用于秒传和完整性校验",
- "type": "string",
- "pattern": "^[a-fA-F0-9]{32}$"
- },
- "totalSize": {
- "description": "完整文件大小,单位字节",
- "type": "integer",
- "format": "int64",
- "minimum": 1
- },
- "totalChunks": {
- "description": "总分片数",
- "type": "integer",
- "minimum": 1
- },
- "chunkSize": {
- "description": "单个分片大小,单位字节;除最后一片外每片必须严格等于该值",
- "type": "integer",
- "format": "int64",
- "minimum": 1,
- "examples": [
- 4194304
- ]
- },
- "contentType": {
- "description": "文件MIME类型,例如 image/jpeg、video/mp4",
- "type": "string"
- }
- }
- },
- "ResumableCompleteBody": {
- "type": "object",
- "additionalProperties": false,
- "required": [
- "uploadId",
- "fileName",
- "fileMd5",
- "totalSize",
- "totalChunks"
- ],
- "properties": {
- "uploadId": {
- "description": "分片上传任务ID",
- "type": "string"
- },
- "fileName": {
- "description": "原始文件名,必须与初始化请求一致",
- "type": "string"
- },
- "fileMd5": {
- "description": "完整文件MD5,用于秒传和完整性校验",
- "type": "string",
- "pattern": "^[a-fA-F0-9]{32}$"
- },
- "totalSize": {
- "description": "完整文件大小,单位字节",
- "type": "integer",
- "format": "int64",
- "minimum": 1
- },
- "totalChunks": {
- "description": "总分片数,必须与初始化请求一致",
- "type": "integer",
- "minimum": 1
- }
- }
- },
- "GenerationPoemBatchBody": {
- "type": "object",
- "required": [
- "poemText"
- ],
- "properties": {
- "poemText": {
- "description": "字辈文本。无分隔符时按单个字拆分;可用空格、逗号、分号、顿号、斜杠或竖线分隔多个字辈。单个字辈最多50个字符,一次最多500个世代。",
- "type": "string",
- "maxLength": 26000,
- "examples": [
- "德承家亦\n忠厚传芳"
- ]
- },
- "disableMissing": {
- "description": "保存时是否停用未出现在新文本中的后续世代;不会删除历史记录。",
- "type": "boolean",
- "examples": [
- false
- ]
- }
- }
- },
- "GenerationPoemBody": {
- "type": "object",
- "required": [
- "generationNo",
- "generationText"
- ],
- "properties": {
- "generationNo": {
- "description": "世代序号",
- "type": "integer",
- "format": "int64",
- "minimum": 1,
- "maximum": 2147483647
- },
- "generationText": {
- "description": "当前世代的字辈文字,最长50个字符",
- "type": "string",
- "maxLength": 50
- },
- "description": {
- "description": "字辈说明,最长500个字符",
- "type": "string",
- "maxLength": 500
- },
- "sortOrder": {
- "description": "排序值,数值越小越靠前",
- "type": "integer",
- "format": "int64",
- "minimum": -2147483648,
- "maximum": 2147483647
- },
- "status": {
- "description": "字典 sys_normal_disable:0=正常,1=停用",
- "type": "string",
- "enum": [
- "0",
- "1"
- ],
- "x-dict-type": "sys_normal_disable",
- "examples": [
- "0"
- ]
- }
- }
- },
- "LineagePersonBody": {
- "type": "object",
- "additionalProperties": false,
- "required": [
- "bindingMode",
- "name"
- ],
- "properties": {
- "bindingMode": {
- "description": "账号绑定方式:NONE=不绑定账号;SELF=绑定当前登录业务用户;SPECIFIED=由有管理权限的操作者指定 appUserId",
- "type": "string",
- "enum": [
- "NONE",
- "SELF",
- "SPECIFIED"
- ],
- "examples": [
- "NONE"
- ]
- },
- "appUserId": {
- "description": "仅 bindingMode=SPECIFIED 时必填;NONE/SELF 时必须不传。指定用户必须属于当前租户、状态正常,且未绑定当前家谱的其他有效世系人物",
- "type": "integer",
- "format": "int64"
- },
- "personNo": {
- "description": "人物编号;不传时由服务端生成",
- "type": "string"
- },
- "name": {
- "description": "姓名",
- "type": "string"
- },
- "aliasName": {
- "description": "别名或曾用名",
- "type": "string"
- },
- "sex": {
- "description": "字典 sys_user_sex:0=男,1=女,2=未知",
- "type": "string",
- "enum": [
- "0",
- "1",
- "2"
- ],
- "x-dict-type": "sys_user_sex",
- "examples": [
- "0"
- ]
- },
- "generation": {
- "description": "世代序号",
- "type": "integer",
- "format": "int64"
- },
- "generationName": {
- "description": "字辈或辈分",
- "type": "string"
- },
- "fatherId": {
- "description": "父亲人物ID,必须属于当前家谱",
- "type": "integer",
- "format": "int64"
- },
- "motherId": {
- "description": "母亲人物ID,必须属于当前家谱",
- "type": "integer",
- "format": "int64"
- },
- "avatarOssId": {
- "description": "头像文件OSS ID;用户界面应通过统一上传组件获得,不允许手工录入",
- "type": [
- "string",
- "null"
- ],
- "pattern": "^[1-9][0-9]*$"
- },
- "birthDate": {
- "type": [
- "string",
- "null"
- ],
- "format": "date-time"
- },
- "birthLunar": {
- "description": "字典 gen_number_yes_no:0=否,1=是",
- "type": "string",
- "enum": [
- "0",
- "1"
- ],
- "x-dict-type": "gen_number_yes_no",
- "examples": [
- "0"
- ]
- },
- "birthPlace": {
- "description": "出生地",
- "type": "string"
- },
- "deathDate": {
- "type": [
- "string",
- "null"
- ],
- "format": "date-time"
- },
- "deathLunar": {
- "description": "字典 gen_number_yes_no:0=否,1=是",
- "type": "string",
- "enum": [
- "0",
- "1"
- ],
- "x-dict-type": "gen_number_yes_no",
- "examples": [
- "0"
- ]
- },
- "deathPlace": {
- "description": "逝世地",
- "type": "string"
- },
- "burialPlace": {
- "description": "安葬地",
- "type": "string"
- },
- "personStatus": {
- "description": "字典 gen_lineage_person_status:0=健在,1=已故,2=未知",
- "type": "string",
- "enum": [
- "0",
- "1",
- "2"
- ],
- "x-dict-type": "gen_lineage_person_status",
- "examples": [
- "0"
- ]
- },
- "biography": {
- "description": "人物简介",
- "type": "string"
- },
- "sortOrder": {
- "description": "排序值,数值越小越靠前",
- "type": "integer",
- "format": "int64"
- },
- "remark": {
- "description": "备注",
- "type": "string"
- },
- "relationName": {
- "description": "通过添加配偶快捷接口提交时使用的关系显示名称",
- "type": "string"
- }
- }
- },
- "FamilyFeedBody": {
- "type": "object",
- "required": [
- "feedContent"
- ],
- "properties": {
- "feedType": {
- "description": "动态类型,未传时默认为 text",
- "type": "string",
- "examples": [
- "text"
- ]
- },
- "feedContent": {
- "description": "动态内容,不能为空",
- "type": "string",
- "examples": [
- "今天上传一张老照片。"
- ]
- },
- "mediaOssIds": {
- "description": "媒体文件 OSS ID 列表,多个 ID 使用英文逗号分隔",
- "type": "string",
- "examples": [
- "2060000000000000001,2060000000000000002"
- ]
- },
- "sortOrder": {
- "description": "排序值,未传时默认为 0",
- "type": "integer",
- "format": "int64",
- "examples": [
- 0
- ]
- },
- "status": {
- "description": "字典 sys_normal_disable:0=正常,1=停用;未传时默认为0",
- "type": "string",
- "enum": [
- "0",
- "1"
- ],
- "x-dict-type": "sys_normal_disable",
- "examples": [
- "0"
- ]
- }
- }
- },
- "FamilyFeedCommentBody": {
- "type": "object",
- "required": [
- "commentContent"
- ],
- "properties": {
- "parentCommentId": {
- "description": "父评论 ID;不传或传 null 表示发布一级评论",
- "type": [
- "integer",
- "null"
- ],
- "format": "int64"
- },
- "commentContent": {
- "description": "评论内容,最多 1000 个字符",
- "type": "string"
- }
- }
- },
- "VerificationChallengeBody": {
- "type": "object",
- "additionalProperties": false,
- "required": [
- "tenantId",
- "subject"
- ],
- "properties": {
- "tenantId": {
- "type": "string",
- "description": "租户 ID"
- },
- "subject": {
- "type": "string",
- "description": "验证主体,如手机号/用户名/IP"
- }
- },
- "examples": [
- {
- "tenantId": "000000",
- "subject": "13800000000"
- }
- ]
- },
- "VerificationCheckBody": {
- "type": "object",
- "additionalProperties": false,
- "required": [
- "tenantId",
- "subject",
- "challengeId"
- ],
- "properties": {
- "tenantId": {
- "description": "租户ID,用于区分不同租户的数据和验证策略",
- "type": "string"
- },
- "subject": {
- "description": "验证主体,通常为手机号、用户ID或登录账号",
- "type": "string"
- },
- "challengeId": {
- "description": "验证挑战ID,由验证挑战接口返回",
- "type": "string"
- },
- "providerCode": {
- "type": "string",
- "description": "验证服务,tianai 或 ruoyi_image"
- },
- "captchaType": {
- "type": "string",
- "description": "SLIDER/ROTATE/CONCAT/WORD_IMAGE_CLICK/math/char"
- },
- "payload": {
- "description": "验证结果载荷。天爱行为验证码提交 payload.track;系统图形验证码提交 payload.uuid 和 payload.code",
- "oneOf": [
- {
- "$ref": "#/components/schemas/TianaiVerificationPayload"
- },
- {
- "$ref": "#/components/schemas/SystemImageVerificationPayload"
- }
- ]
- }
- }
- },
- "TianaiVerificationPayload": {
- "type": "object",
- "description": "将天爱 1.5.5 前端验证回调中的 data 原样放入 track;回调 id 不放入 payload,挑战标识统一提交顶层 challengeId",
- "required": [
- "track"
- ],
- "properties": {
- "track": {
- "$ref": "#/components/schemas/TianaiCaptchaTrack"
- }
- }
- },
- "TianaiCaptchaTrack": {
- "type": "object",
- "required": [
- "bgImageWidth",
- "bgImageHeight",
- "startTime",
- "stopTime",
- "trackList"
- ],
- "properties": {
- "bgImageWidth": {
- "type": "integer",
- "description": "验证码背景图片在前端实际显示的宽度,单位像素"
- },
- "bgImageHeight": {
- "type": "integer",
- "description": "验证码背景图片在前端实际显示的高度,单位像素"
- },
- "templateImageWidth": {
- "type": "integer",
- "description": "滑块或旋转模板图片在前端实际显示的宽度,单位像素"
- },
- "templateImageHeight": {
- "type": "integer",
- "description": "滑块或旋转模板图片在前端实际显示的高度,单位像素"
- },
- "startTime": {
- "type": "integer",
- "format": "int64",
- "description": "用户开始操作的时间戳,单位毫秒"
- },
- "stopTime": {
- "type": "integer",
- "format": "int64",
- "description": "用户结束操作的时间戳,单位毫秒"
- },
- "left": {
- "type": "integer",
- "description": "滑块最终水平偏移量,单位像素;由天爱前端控件生成"
- },
- "top": {
- "type": "integer",
- "description": "点选或模板最终垂直偏移量,单位像素;由天爱前端控件生成"
- },
- "trackList": {
- "type": "array",
- "minItems": 1,
- "description": "用户操作轨迹,不能为空,必须直接使用天爱前端控件产生的数据",
- "items": {
- "$ref": "#/components/schemas/TianaiCaptchaTrackPoint"
- }
- },
- "data": {
- "type": [
- "object",
- "null"
- ],
- "additionalProperties": true,
- "description": "不同验证码类型附带的扩展数据,由天爱前端控件原样提交",
- "properties": {}
- }
- }
- },
- "TianaiCaptchaTrackPoint": {
- "type": "object",
- "required": [
- "x",
- "y",
- "t",
- "type"
- ],
- "properties": {
- "x": {
- "type": "number",
- "format": "float",
- "description": "当前轨迹点的水平坐标"
- },
- "y": {
- "type": "number",
- "format": "float",
- "description": "当前轨迹点的垂直坐标"
- },
- "t": {
- "type": "number",
- "format": "float",
- "description": "当前轨迹点相对操作开始时的时间,单位毫秒"
- },
- "type": {
- "type": "string",
- "description": "轨迹事件类型,例如 down、move、up"
- }
- }
- },
- "SystemImageVerificationPayload": {
- "type": "object",
- "required": [
- "uuid",
- "code"
- ],
- "properties": {
- "uuid": {
- "type": "string",
- "description": "系统图形验证码接口返回的唯一标识"
- },
- "code": {
- "type": "string",
- "description": "用户填写的图形验证码答案"
- }
- }
- },
- "MeritRecordBody": {
- "type": "object",
- "additionalProperties": false,
- "required": [
- "donorName",
- "meritTitle"
- ],
- "properties": {
- "donorName": {
- "description": "功德人姓名",
- "type": "string"
- },
- "meritType": {
- "description": "字典 gen_merit_type:donation=捐赠,repair=修祠,public=公益,other=其他",
- "type": "string",
- "enum": [
- "donation",
- "repair",
- "public",
- "other"
- ],
- "x-dict-type": "gen_merit_type",
- "examples": [
- "donation"
- ]
- },
- "meritTitle": {
- "description": "功德标题",
- "type": "string"
- },
- "meritContent": {
- "description": "功德内容",
- "type": "string"
- },
- "amount": {
- "description": "金额",
- "type": "number"
- },
- "meritTime": {
- "description": "功德时间",
- "type": "string",
- "format": "date-time"
- },
- "sortOrder": {
- "description": "排序值",
- "type": "integer",
- "format": "int64"
- },
- "status": {
- "description": "字典 sys_normal_disable:0=正常,1=停用",
- "type": "string",
- "enum": [
- "0",
- "1"
- ],
- "x-dict-type": "sys_normal_disable",
- "examples": [
- "0"
- ]
- }
- }
- },
- "VideoBody": {
- "type": "object",
- "additionalProperties": false,
- "required": [
- "videoTitle",
- "videoOssId"
- ],
- "properties": {
- "videoTitle": {
- "description": "视频标题",
- "type": "string"
- },
- "videoDesc": {
- "description": "视频说明",
- "type": "string"
- },
- "coverOssId": {
- "description": "封面图片OSS ID,由统一上传接口返回",
- "type": "string",
- "pattern": "^[1-9][0-9]*$"
- },
- "videoOssId": {
- "description": "视频文件OSS ID,由统一上传接口返回",
- "type": "string",
- "pattern": "^[1-9][0-9]*$"
- },
- "durationSeconds": {
- "description": "视频时长,单位秒",
- "type": "integer",
- "format": "int64"
- },
- "sortOrder": {
- "description": "排序值",
- "type": "integer",
- "format": "int64"
- },
- "status": {
- "description": "字典 sys_normal_disable:0=正常,1=停用",
- "type": "string",
- "enum": [
- "0",
- "1"
- ],
- "x-dict-type": "sys_normal_disable",
- "examples": [
- "0"
- ]
- }
- }
- },
- "RObject": {
- "type": "object",
- "properties": {
- "code": {
- "description": "系统图形验证码或响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string",
- "examples": [
- "操作成功"
- ]
- },
- "data": {
- "description": "响应数据主体",
- "type": "object",
- "additionalProperties": true,
- "properties": {}
- }
- }
- },
- "RGenealogyQuota": {
- "type": "object",
- "properties": {
- "code": {
- "description": "响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string",
- "examples": [
- "操作成功"
- ]
- },
- "data": {
- "$ref": "#/components/schemas/GenealogyQuota"
- }
- }
- },
- "GenealogyQuota": {
- "type": "object",
- "required": [
- "createUsed",
- "createLimit",
- "createRemaining",
- "canCreate",
- "joinUsed",
- "joinLimit",
- "joinRemaining",
- "canJoin"
- ],
- "properties": {
- "createUsed": {
- "description": "当前用户已创建的家谱数量",
- "type": "integer",
- "format": "int64",
- "minimum": 0,
- "examples": [
- 1
- ]
- },
- "createLimit": {
- "description": "每用户可创建家谱上限,-1 表示不限,0 表示禁止,正数表示上限",
- "type": "integer",
- "format": "int64",
- "minimum": -1,
- "examples": [
- 3
- ]
- },
- "createRemaining": {
- "description": "还可创建的家谱数量,-1 表示不限",
- "type": "integer",
- "format": "int64",
- "minimum": -1,
- "examples": [
- 2
- ]
- },
- "canCreate": {
- "description": "当前用户是否还能创建家谱",
- "type": "boolean",
- "examples": [
- true
- ]
- },
- "joinUsed": {
- "description": "已加入的家谱总数,包含自己创建的家谱",
- "type": "integer",
- "format": "int64",
- "minimum": 0,
- "examples": [
- 2
- ]
- },
- "joinLimit": {
- "description": "每用户可加入家谱总数上限,-1 表示不限,0 表示禁止,正数表示上限",
- "type": "integer",
- "format": "int64",
- "minimum": -1,
- "examples": [
- 10
- ]
- },
- "joinRemaining": {
- "description": "还可加入的家谱数量,-1 表示不限",
- "type": "integer",
- "format": "int64",
- "minimum": -1,
- "examples": [
- 8
- ]
- },
- "canJoin": {
- "description": "当前用户是否还能加入其他家谱",
- "type": "boolean",
- "examples": [
- true
- ]
- }
- }
- },
- "RLong": {
- "type": "object",
- "properties": {
- "code": {
- "description": "响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string",
- "examples": [
- "操作成功"
- ]
- },
- "data": {
- "description": "当前业务用户未读通知数量",
- "type": "integer",
- "format": "int64",
- "examples": [
- 3
- ]
- }
- }
- },
- "RList": {
- "type": "object",
- "properties": {
- "code": {
- "description": "系统图形验证码或响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string",
- "examples": [
- "操作成功"
- ]
- },
- "data": {
- "description": "响应数据主体",
- "type": "array",
- "items": {
- "type": "object",
- "additionalProperties": true,
- "properties": {}
- }
- }
- }
- },
- "RCeremonyInvitation": {
- "type": "object",
- "properties": {
- "code": {
- "description": "响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string",
- "examples": [
- "操作成功"
- ]
- },
- "data": {
- "$ref": "#/components/schemas/CeremonyInvitationVo"
- }
- }
- },
- "CeremonyInvitationVo": {
- "type": "object",
- "properties": {
- "invitationId": {
- "description": "邀约ID",
- "type": "integer",
- "format": "int64"
- },
- "genealogyId": {
- "description": "家谱ID",
- "type": "integer",
- "format": "int64"
- },
- "ceremonyId": {
- "description": "贺礼活动ID",
- "type": "integer",
- "format": "int64"
- },
- "inviteeUserId": {
- "description": "受邀业务用户ID",
- "type": "integer",
- "format": "int64"
- },
- "inviteStatus": {
- "description": "邀约状态",
- "type": "string",
- "enum": [
- "PENDING",
- "ACCEPTED",
- "DECLINED",
- "CANCELED"
- ]
- },
- "inviteVersion": {
- "description": "邀请版本,取消后重新邀请时递增",
- "type": "integer"
- },
- "deliveredTime": {
- "description": "邀请投递时间",
- "type": "string",
- "format": "date-time"
- },
- "readTime": {
- "description": "邀请阅读时间",
- "type": "string",
- "format": "date-time"
- },
- "responseTime": {
- "description": "接受或拒绝时间",
- "type": "string",
- "format": "date-time"
- },
- "ceremonyTitle": {
- "description": "贺礼活动标题",
- "type": "string"
- },
- "ceremonyTime": {
- "description": "贺礼活动时间",
- "type": "string",
- "format": "date-time"
- },
- "location": {
- "description": "地点名称",
- "type": "string"
- },
- "locationAddress": {
- "description": "详细地址",
- "type": "string"
- },
- "longitude": {
- "description": "经度",
- "type": "number"
- },
- "latitude": {
- "description": "纬度",
- "type": "number"
- }
- }
- },
- "RCeremonyInvitationList": {
- "type": "object",
- "properties": {
- "code": {
- "description": "响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string",
- "examples": [
- "操作成功"
- ]
- },
- "data": {
- "description": "贺礼邀约列表",
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/CeremonyInvitationVo"
- }
- }
- }
- },
- "RGenerationPoem": {
- "type": "object",
- "properties": {
- "code": {
- "description": "响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string"
- },
- "data": {
- "$ref": "#/components/schemas/GenerationPoemView"
- }
- }
- },
- "GenerationPoemView": {
- "type": "object",
- "properties": {
- "poemId": {
- "description": "字辈记录ID",
- "type": "integer",
- "format": "int64"
- },
- "genealogyId": {
- "description": "所属家谱ID",
- "type": "integer",
- "format": "int64"
- },
- "genealogyNo": {
- "description": "家谱编号",
- "type": "string"
- },
- "genealogyName": {
- "description": "家谱名称",
- "type": "string"
- },
- "generationNo": {
- "description": "世代序号",
- "type": "integer",
- "format": "int64"
- },
- "generationText": {
- "description": "字辈文字",
- "type": "string"
- },
- "description": {
- "description": "字辈说明",
- "type": "string"
- },
- "sortOrder": {
- "description": "排序值,数值越小越靠前",
- "type": "integer",
- "format": "int64"
- },
- "status": {
- "description": "字典 sys_normal_disable:0=正常,1=停用",
- "type": "string",
- "enum": [
- "0",
- "1"
- ],
- "x-dict-type": "sys_normal_disable",
- "examples": [
- "0"
- ]
- }
- }
- },
- "RGenerationPoemList": {
- "type": "object",
- "properties": {
- "code": {
- "description": "响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string"
- },
- "data": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/GenerationPoemView"
- }
- }
- }
- },
- "RGenerationPoemBatchPreview": {
- "type": "object",
- "properties": {
- "code": {
- "description": "响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string"
- },
- "data": {
- "$ref": "#/components/schemas/GenerationPoemBatchPreviewView"
- }
- }
- },
- "GenerationPoemBatchPreviewView": {
- "type": "object",
- "properties": {
- "genealogyId": {
- "description": "所属家谱ID",
- "type": "integer",
- "format": "int64"
- },
- "genealogyNo": {
- "description": "家谱编号",
- "type": "string"
- },
- "genealogyName": {
- "description": "家谱名称",
- "type": "string"
- },
- "createCount": {
- "description": "将新增的字辈数量",
- "type": "integer"
- },
- "updateCount": {
- "description": "将修改或恢复的字辈数量",
- "type": "integer"
- },
- "keepCount": {
- "description": "保持不变的字辈数量",
- "type": "integer"
- },
- "disableCount": {
- "description": "将停用的字辈数量",
- "type": "integer"
- },
- "items": {
- "description": "按世代排序的逐项变更预览",
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/GenerationPoemBatchItemView"
- }
- }
- }
- },
- "GenerationPoemBatchItemView": {
- "type": "object",
- "properties": {
- "poemId": {
- "description": "现有字辈记录ID;新增时为空",
- "type": "integer",
- "format": "int64"
- },
- "generationNo": {
- "description": "世代序号",
- "type": "integer",
- "format": "int64"
- },
- "oldGenerationText": {
- "description": "保存前字辈文字",
- "type": "string"
- },
- "newGenerationText": {
- "description": "保存后字辈文字",
- "type": "string"
- },
- "oldStatus": {
- "description": "保存前状态",
- "type": "string"
- },
- "newStatus": {
- "description": "保存后状态",
- "type": "string"
- },
- "action": {
- "description": "预览动作,create、update、keep 或 disable",
- "type": "string"
- },
- "warning": {
- "description": "需要用户确认的变更提示",
- "type": "string"
- }
- }
- },
- "RLineagePerson": {
- "type": "object",
- "properties": {
- "code": {
- "description": "响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string",
- "examples": [
- "操作成功"
- ]
- },
- "data": {
- "$ref": "#/components/schemas/LineagePersonView"
- }
- }
- },
- "LineagePersonView": {
- "type": "object",
- "properties": {
- "personId": {
- "description": "人物ID",
- "type": "integer",
- "format": "int64"
- },
- "genealogyId": {
- "description": "家谱ID",
- "type": "integer",
- "format": "int64"
- },
- "genealogyName": {
- "description": "家谱名称",
- "type": "string"
- },
- "genealogyNo": {
- "description": "家谱编号",
- "type": "string"
- },
- "appUserId": {
- "description": "绑定业务用户ID",
- "type": [
- "integer",
- "null"
- ],
- "format": "int64"
- },
- "appUserNickName": {
- "description": "绑定业务用户昵称",
- "type": "string"
- },
- "personNo": {
- "description": "人物编号",
- "type": "string"
- },
- "name": {
- "description": "姓名",
- "type": "string"
- },
- "aliasName": {
- "description": "别名或曾用名",
- "type": "string"
- },
- "sex": {
- "description": "字典 sys_user_sex:0=男,1=女,2=未知",
- "type": "string",
- "enum": [
- "0",
- "1",
- "2"
- ],
- "x-dict-type": "sys_user_sex",
- "examples": [
- "2"
- ]
- },
- "generation": {
- "description": "世代序号",
- "type": "integer",
- "format": "int64"
- },
- "generationName": {
- "description": "字辈或辈分",
- "type": "string"
- },
- "fatherId": {
- "description": "父亲人物ID",
- "type": [
- "integer",
- "null"
- ],
- "format": "int64"
- },
- "fatherName": {
- "description": "父亲姓名",
- "type": "string"
- },
- "motherId": {
- "description": "母亲人物ID",
- "type": [
- "integer",
- "null"
- ],
- "format": "int64"
- },
- "motherName": {
- "description": "母亲姓名",
- "type": "string"
- },
- "spouseNames": {
- "description": "配偶姓名,多个使用顿号分隔",
- "type": "string"
- },
- "avatarOssId": {
- "description": "头像文件OSS ID",
- "type": [
- "string",
- "null"
- ],
- "pattern": "^[1-9][0-9]*$"
- },
- "birthDate": {
- "description": "出生日期",
- "type": [
- "string",
- "null"
- ],
- "format": "date-time"
- },
- "birthLunar": {
- "description": "字典 gen_number_yes_no:0=否,1=是",
- "type": "string",
- "enum": [
- "0",
- "1"
- ],
- "x-dict-type": "gen_number_yes_no",
- "examples": [
- "0"
- ]
- },
- "birthPlace": {
- "description": "出生地",
- "type": "string"
- },
- "deathDate": {
- "description": "逝世日期",
- "type": [
- "string",
- "null"
- ],
- "format": "date-time"
- },
- "deathLunar": {
- "description": "字典 gen_number_yes_no:0=否,1=是",
- "type": "string",
- "enum": [
- "0",
- "1"
- ],
- "x-dict-type": "gen_number_yes_no",
- "examples": [
- "0"
- ]
- },
- "deathPlace": {
- "description": "逝世地",
- "type": "string"
- },
- "burialPlace": {
- "description": "安葬地",
- "type": "string"
- },
- "personStatus": {
- "description": "字典 gen_lineage_person_status:0=健在,1=已故,2=未知",
- "type": "string",
- "enum": [
- "0",
- "1",
- "2"
- ],
- "x-dict-type": "gen_lineage_person_status",
- "examples": [
- "0"
- ]
- },
- "biography": {
- "description": "人物简介",
- "type": "string"
- },
- "sortOrder": {
- "description": "排序值",
- "type": "integer",
- "format": "int64"
- },
- "status": {
- "description": "字典 sys_normal_disable:0=正常,1=停用",
- "type": "string",
- "enum": [
- "0",
- "1"
- ],
- "x-dict-type": "sys_normal_disable",
- "examples": [
- "0"
- ]
- },
- "remark": {
- "description": "备注",
- "type": "string"
- }
- }
- },
- "RLineagePersonList": {
- "type": "object",
- "properties": {
- "code": {
- "description": "响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string",
- "examples": [
- "操作成功"
- ]
- },
- "data": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/LineagePersonView"
- }
- }
- }
- },
- "RLineagePersonTreeList": {
- "type": "object",
- "properties": {
- "code": {
- "description": "响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string",
- "examples": [
- "操作成功"
- ]
- },
- "data": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/LineagePersonTreeView"
- }
- }
- }
- },
- "LineagePersonTreeView": {
- "allOf": [
- {
- "$ref": "#/components/schemas/LineagePersonView"
- },
- {
- "type": "object",
- "properties": {
- "relationType": {
- "description": "字典 gen_lineage_relation_type:father=父亲,mother=母亲,spouse=配偶,child=子女,adoptive=收养",
- "type": "string",
- "enum": [
- "father",
- "mother",
- "spouse",
- "child",
- "adoptive"
- ],
- "x-dict-type": "gen_lineage_relation_type",
- "examples": [
- "spouse"
- ]
- },
- "relationName": {
- "description": "关系显示名称",
- "type": "string"
- },
- "spouses": {
- "description": "配偶节点",
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/LineagePersonTreeView"
- }
- },
- "children": {
- "description": "子女节点",
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/LineagePersonTreeView"
- }
- }
- }
- }
- ]
- },
- "LineagePersonPageResult": {
- "type": "object",
- "properties": {
- "code": {
- "description": "响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string",
- "examples": [
- "操作成功"
- ]
- },
- "rows": {
- "description": "当前页世系人物",
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/LineagePersonView"
- }
- },
- "total": {
- "description": "总记录数",
- "type": "integer",
- "format": "int64",
- "examples": [
- 0
- ]
- }
- }
- },
- "RLogin": {
- "type": "object",
- "properties": {
- "code": {
- "description": "系统图形验证码或响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string",
- "examples": [
- "操作成功"
- ]
- },
- "data": {
- "description": "响应数据主体",
- "$ref": "#/components/schemas/LoginVo"
- }
- }
- },
- "LoginVo": {
- "type": "object",
- "properties": {
- "token": {
- "type": "string"
- },
- "accessToken": {
- "type": "string"
- },
- "tokenValue": {
- "type": "string"
- },
- "userId": {
- "type": "integer",
- "format": "int64"
- },
- "tenantId": {
- "description": "租户ID,用于区分不同租户的数据和验证策略",
- "type": "string"
- },
- "clientId": {
- "description": "客户端ID,对应后台客户端管理中的APP/PC/小程序等终端",
- "type": "string"
- },
- "clientKey": {
- "type": "string"
- }
- }
- },
- "RFileUpload": {
- "type": "object",
- "properties": {
- "code": {
- "description": "系统图形验证码或响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string",
- "examples": [
- "操作成功"
- ]
- },
- "data": {
- "description": "响应数据主体",
- "$ref": "#/components/schemas/FileUploadVo"
- }
- }
- },
- "FileUploadVo": {
- "type": "object",
- "properties": {
- "ossId": {
- "description": "OSS文件ID,表单内部使用,用户侧应通过上传组件获取",
- "type": "string",
- "pattern": "^[1-9][0-9]*$"
- },
- "url": {
- "type": "string"
- },
- "thumbnailUrl": {
- "type": [
- "string",
- "null"
- ]
- },
- "fileName": {
- "description": "原始文件名",
- "type": "string"
- },
- "originalName": {
- "type": "string"
- }
- }
- },
- "RVerificationRequire": {
- "type": "object",
- "properties": {
- "code": {
- "description": "系统图形验证码或响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string",
- "examples": [
- "操作成功"
- ]
- },
- "data": {
- "description": "响应数据主体",
- "$ref": "#/components/schemas/VerificationRequireVo"
- }
- }
- },
- "VerificationRequireVo": {
- "type": "object",
- "properties": {
- "required": {
- "description": "当前场景是否需要验证",
- "type": "boolean"
- },
- "providerCode": {
- "description": "第三方服务商编码",
- "type": "string"
- },
- "captchaType": {
- "description": "验证码类型,例如SLIDER、ROTATE、CONCAT、WORD_IMAGE_CLICK",
- "type": "string"
- },
- "sceneCode": {
- "description": "服务端按当前业务动作和激活绑定解析出的实际验证场景编码",
- "type": "string"
- },
- "ttlSeconds": {
- "description": "验证或票据有效秒数",
- "type": "integer"
- }
- },
- "examples": [
- {
- "required": true,
- "providerCode": "tianai",
- "captchaType": "SLIDER",
- "sceneCode": "PC_LOGIN_ACTIVE_SCENE",
- "ttlSeconds": 300
- }
- ]
- },
- "RVerificationChallenge": {
- "type": "object",
- "properties": {
- "code": {
- "description": "系统图形验证码或响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string",
- "examples": [
- "操作成功"
- ]
- },
- "data": {
- "description": "响应数据主体",
- "$ref": "#/components/schemas/VerificationChallengeVo"
- }
- }
- },
- "VerificationChallengeVo": {
- "type": "object",
- "properties": {
- "required": {
- "description": "当前场景是否需要验证",
- "type": "boolean"
- },
- "providerCode": {
- "description": "第三方服务商编码",
- "type": "string"
- },
- "captchaType": {
- "description": "验证码类型,例如SLIDER、ROTATE、CONCAT、WORD_IMAGE_CLICK",
- "type": "string"
- },
- "challengeId": {
- "description": "验证挑战ID,由验证挑战接口返回",
- "type": "string"
- },
- "uuid": {
- "type": "string",
- "description": "系统图形验证码 uuid"
- },
- "img": {
- "type": "string",
- "description": "系统图形验证码 base64 图片"
- },
- "payload": {
- "type": "object",
- "additionalProperties": true,
- "description": "天爱验证码数据,包括背景图、模板图、尺寸等",
- "properties": {}
- },
- "expireSeconds": {
- "description": "验证挑战过期秒数",
- "type": "integer"
- }
- },
- "examples": [
- {
- "required": true,
- "providerCode": "tianai",
- "captchaType": "SLIDER",
- "challengeId": "CAPTCHA_CHALLENGE_ID",
- "payload": {
- "backgroundImage": "data:image/png;base64,...",
- "templateImage": "data:image/png;base64,...",
- "backgroundImageWidth": 340,
- "backgroundImageHeight": 180
- },
- "expireSeconds": 300
- }
- ]
- },
- "RVerificationCheck": {
- "type": "object",
- "properties": {
- "code": {
- "description": "系统图形验证码或响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string",
- "examples": [
- "操作成功"
- ]
- },
- "data": {
- "description": "响应数据主体",
- "$ref": "#/components/schemas/VerificationCheckVo"
- }
- }
- },
- "VerificationCheckVo": {
- "type": "object",
- "properties": {
- "passed": {
- "description": "验证是否通过",
- "type": "boolean"
- },
- "validToken": {
- "type": "string",
- "description": "验证通过后交给发送短信验证码接口的票据"
- },
- "expireSeconds": {
- "description": "验证挑战过期秒数",
- "type": "integer"
- },
- "message": {
- "description": "返回消息",
- "type": "string"
- }
- },
- "examples": [
- {
- "passed": true,
- "validToken": "captcha-ticket",
- "expireSeconds": 300,
- "message": "验证通过"
- }
- ]
- },
- "RFamilyFeedComment": {
- "type": "object",
- "properties": {
- "code": {
- "description": "响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string"
- },
- "data": {
- "$ref": "#/components/schemas/FamilyFeedCommentView"
- }
- }
- },
- "FamilyFeedCommentView": {
- "type": "object",
- "properties": {
- "commentId": {
- "description": "评论 ID",
- "type": "integer",
- "format": "int64"
- },
- "genealogyId": {
- "description": "所属家谱 ID",
- "type": "integer",
- "format": "int64"
- },
- "feedId": {
- "description": "所属动态 ID",
- "type": "integer",
- "format": "int64"
- },
- "parentCommentId": {
- "description": "父评论 ID;null 或 0 表示一级评论",
- "type": [
- "integer",
- "null"
- ],
- "format": "int64"
- },
- "appUserId": {
- "description": "评论业务用户 ID",
- "type": "integer",
- "format": "int64"
- },
- "appUserNickName": {
- "description": "评论人昵称",
- "type": "string"
- },
- "appUserAvatar": {
- "description": "评论人头像文件 ID",
- "type": [
- "integer",
- "null"
- ],
- "format": "int64"
- },
- "parentAppUserId": {
- "description": "被直接回复的业务用户 ID",
- "type": [
- "integer",
- "null"
- ],
- "format": "int64"
- },
- "parentAppUserNickName": {
- "description": "被直接回复的用户昵称",
- "type": [
- "string",
- "null"
- ]
- },
- "commentContent": {
- "description": "评论内容;作者删除后为 null",
- "type": [
- "string",
- "null"
- ]
- },
- "userDeleted": {
- "description": "作者删除状态,0 未删除,1 已删除并保留占位",
- "type": "string",
- "enum": [
- "0",
- "1"
- ],
- "examples": [
- "0"
- ]
- },
- "replyCount": {
- "description": "正常展示的直接回复数量",
- "type": "integer",
- "format": "int64"
- },
- "commentLevel": {
- "description": "评论层级,root 为一级评论,reply 为回复",
- "type": "string",
- "enum": [
- "root",
- "reply"
- ]
- },
- "status": {
- "description": "字典 sys_normal_disable:0=正常展示,1=停用;会员接口仅返回0",
- "type": "string",
- "enum": [
- "0",
- "1"
- ],
- "x-dict-type": "sys_normal_disable",
- "examples": [
- "0"
- ]
- },
- "createTime": {
- "description": "评论发布时间",
- "type": "string",
- "format": "date-time"
- }
- }
- },
- "RFamilyFeedCommentList": {
- "type": "object",
- "properties": {
- "code": {
- "description": "响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string"
- },
- "data": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/FamilyFeedCommentView"
- }
- }
- }
- },
- "FamilyFeedCommentPageResult": {
- "type": "object",
- "properties": {
- "code": {
- "description": "响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string"
- },
- "rows": {
- "description": "评论分页数据",
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/FamilyFeedCommentView"
- }
- },
- "total": {
- "description": "评论总数",
- "type": "integer",
- "format": "int64"
- }
- }
- },
- "RFamilyFeed": {
- "type": "object",
- "properties": {
- "code": {
- "description": "响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string",
- "examples": [
- "操作成功"
- ]
- },
- "data": {
- "$ref": "#/components/schemas/FamilyFeedView"
- }
- }
- },
- "FamilyFeedView": {
- "type": "object",
- "properties": {
- "feedId": {
- "description": "动态ID",
- "type": "integer",
- "format": "int64"
- },
- "genealogyId": {
- "description": "所属家谱ID",
- "type": "integer",
- "format": "int64"
- },
- "genealogyNo": {
- "description": "家谱编号",
- "type": "string"
- },
- "genealogyName": {
- "description": "家谱名称",
- "type": "string"
- },
- "publisherUserId": {
- "description": "发布业务用户ID",
- "type": "integer",
- "format": "int64"
- },
- "publisherNickName": {
- "description": "发布用户昵称",
- "type": "string"
- },
- "publisherStatus": {
- "description": "发布用户状态",
- "type": "string"
- },
- "feedType": {
- "description": "动态类型",
- "type": "string"
- },
- "feedContent": {
- "description": "动态内容",
- "type": "string"
- },
- "mediaOssIds": {
- "description": "媒体文件OSS ID列表,多个ID使用英文逗号分隔",
- "type": "string"
- },
- "likedByMe": {
- "description": "当前登录用户是否已点赞",
- "type": "boolean",
- "examples": [
- false
- ]
- },
- "likeCount": {
- "description": "点赞数量",
- "type": "integer",
- "format": "int64"
- },
- "commentCount": {
- "description": "评论数量",
- "type": "integer",
- "format": "int64"
- },
- "pinned": {
- "description": "字典 gen_number_yes_no:0=否,1=是",
- "type": "string",
- "enum": [
- "0",
- "1"
- ],
- "x-dict-type": "gen_number_yes_no",
- "examples": [
- "0"
- ]
- },
- "pinnedTime": {
- "description": "置顶时间",
- "type": [
- "string",
- "null"
- ],
- "format": "date-time"
- },
- "sortOrder": {
- "description": "排序值",
- "type": "integer",
- "format": "int64"
- },
- "status": {
- "description": "字典 sys_normal_disable:0=正常,1=停用",
- "type": "string",
- "enum": [
- "0",
- "1"
- ],
- "x-dict-type": "sys_normal_disable",
- "examples": [
- "0"
- ]
- },
- "remark": {
- "description": "备注",
- "type": "string"
- },
- "createTime": {
- "description": "发布时间",
- "type": "string",
- "format": "date-time"
- },
- "updateTime": {
- "description": "更新时间",
- "type": "string",
- "format": "date-time"
- }
- }
- },
- "RFamilyFeedList": {
- "type": "object",
- "properties": {
- "code": {
- "description": "响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string",
- "examples": [
- "操作成功"
- ]
- },
- "data": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/FamilyFeedView"
- }
- }
- }
- },
- "FamilyFeedPageResult": {
- "type": "object",
- "properties": {
- "code": {
- "description": "响应状态码",
- "type": "integer",
- "examples": [
- 200
- ]
- },
- "msg": {
- "description": "响应消息",
- "type": "string",
- "examples": [
- "操作成功"
- ]
- },
- "rows": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/FamilyFeedView"
- }
- },
- "total": {
- "description": "总记录数",
- "type": "integer",
- "format": "int64",
- "examples": [
- 0
- ]
- }
- }
- }
- },
- "responses": {
- "VoidResult": {
- "description": "通用成功响应",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RVoid"
- }
- }
- }
- },
- "ObjectResult": {
- "description": "通用对象响应",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RObject"
- }
- }
- }
- },
- "GenealogyQuotaResult": {
- "description": "当前业务用户家谱配额响应",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RGenealogyQuota"
- }
- }
- }
- },
- "LongResult": {
- "description": "长整型数据响应",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RLong"
- }
- }
- }
- },
- "ListResult": {
- "description": "通用列表响应",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RList"
- }
- }
- }
- },
- "CeremonyInvitationResult": {
- "description": "贺礼邀约详情响应",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RCeremonyInvitation"
- }
- }
- }
- },
- "CeremonyInvitationListResult": {
- "description": "贺礼邀约列表响应",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RCeremonyInvitationList"
- }
- }
- }
- },
- "GenerationPoemResult": {
- "description": "字辈详情响应",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RGenerationPoem"
- }
- }
- }
- },
- "GenerationPoemListResult": {
- "description": "字辈列表响应",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RGenerationPoemList"
- }
- }
- }
- },
- "GenerationPoemBatchPreviewResult": {
- "description": "字辈批量预览响应",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RGenerationPoemBatchPreview"
- }
- }
- }
- },
- "LineagePersonResult": {
- "description": "世系人物详情响应",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RLineagePerson"
- }
- }
- }
- },
- "LineagePersonListResult": {
- "description": "世系人物列表或选项响应",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RLineagePersonList"
- }
- }
- }
- },
- "LineagePersonTreeResult": {
- "description": "世系树响应",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RLineagePersonTreeList"
- }
- }
- }
- },
- "LineagePersonPageResult": {
- "description": "世系人物分页响应",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/LineagePersonPageResult"
- }
- }
- }
- },
- "LoginResult": {
- "description": "登录结果",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RLogin"
- }
- }
- }
- },
- "FileUploadResult": {
- "description": "文件上传结果",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RFileUpload"
- }
- }
- }
- },
- "VerificationRequireResult": {
- "description": "验证需求查询结果",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RVerificationRequire"
- }
- }
- }
- },
- "VerificationChallengeResult": {
- "description": "验证挑战生成结果",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RVerificationChallenge"
- }
- }
- }
- },
- "VerificationCheckResult": {
- "description": "验证校验结果",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RVerificationCheck"
- }
- }
- }
- },
- "FamilyFeedCommentResult": {
- "description": "家族圈评论对象响应",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RFamilyFeedComment"
- }
- }
- }
- },
- "FamilyFeedCommentListResult": {
- "description": "家族圈评论列表响应",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RFamilyFeedCommentList"
- }
- }
- }
- },
- "FamilyFeedCommentPageResult": {
- "description": "家族圈评论分页响应",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/FamilyFeedCommentPageResult"
- }
- }
- }
- },
- "FamilyFeedResult": {
- "description": "家族圈动态对象响应",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RFamilyFeed"
- }
- }
- }
- },
- "FamilyFeedListResult": {
- "description": "家族圈动态列表响应",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RFamilyFeedList"
- }
- }
- }
- },
- "FamilyFeedPageResult": {
- "description": "家族圈动态分页响应",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/FamilyFeedPageResult"
- }
- }
- }
- }
- },
- "securitySchemes": {
- "SaToken1": {
- "type": "apiKey",
- "in": "header",
- "name": "Authorization",
- "description": "登录后返回的 token。若本地配置使用 sa-token 名称,请按项目实际 token-name 调整。"
- }
- }
- },
- "servers": [],
- "security": [
- {
- "SaToken1": []
- }
- ]
-}
\ No newline at end of file
diff --git a/design-qa.md b/design-qa.md
deleted file mode 100644
index 81b6626..0000000
--- a/design-qa.md
+++ /dev/null
@@ -1,39 +0,0 @@
-# 首页设计还原 QA
-
-## 对照基准
-
-- 设计源:用户在当前对话提供的桌面首页设计图,红色文字和箭头作为替换与结构调整标注。
-- 实现基线:原首页 `index-modern.html` 的品牌色、字体、卡片质感和 `public/js/page-effects.js` 交互。
-- 桌面审查截图:`artifacts/homepage-final-review-full.png`,CSS 视口 1440 × 2200,DPR 1。
-- 移动审查截图:`artifacts/homepage-final-review-mobile.png`,CSS 视口 500 × 1600,DPR 1。
-- 页面状态:未登录初始状态。
-
-## 结构对照
-
-- 页面沿用原首页 1280px 宽屏容器,顺序为双层导航、首屏、四个主入口、第一条九格广告栏、六个内容入口、推荐与友情链接、第二条九格广告栏、页脚。
-- 已删除设计图没有的家谱广场、文章列表、姓氏百科、相关推荐大卡、下载大区块。
-- “我的家谱”是独立强调入口,链接 `profile-families.html`,承担查看、新建和管理全部家谱。
-- 红色标注按替换文案处理;被替换的旧标题没有在同一卡片中保留。
-
-## 视觉与交互对照
-
-- 保留原首页的暖纸色、朱红渐变导航、宋体标题、黑体正文、宽屏留白、圆角卡片、层次阴影与半透明面板。
-- 首屏按设计图重组为正文、二维码、原有蓝色家谱封面、祠堂和家族记忆图片。
-- 保留原首页的 `tilt-card` 指针倾斜、按钮磁吸、图片悬停缩放、移动菜单和 reduced-motion 行为。
-- 桌面页脚链接与备案信息已恢复居中,不受原全局链接布局影响。
-- 主入口图片按左侧内容定位,避免服务、视频和相册标题被居中裁切;入口区、内容卡和广告栏已压缩无效留白。
-- 两组九格广告栏均使用项目已有广告图片,不再显示文字占位块。
-- 页脚链接区改为完整浅色横条,消除了深色背景在两侧提前露出的断层。
-
-## 响应式与可访问性
-
-- 1120px 以下主入口和广告栏分栏;720px 以下首屏、入口和内容卡改为单列。
-- 浏览器导航结构专项检查通过,移动断点继续沿用原首页规则。
-- 图片提供替代文本;二维码入口、导航、广告位和内容卡均使用链接语义;焦点样式沿用公共样式。
-
-## 剩余差异
-
-- P3:设计图右下角为多人家族合影,仓库没有对应素材,当前继续使用原有家族记忆图片。
-- P3:原首页交互动效在截图中不可见,但已通过复用原脚本和交互类保留。
-
-final result: passed
diff --git a/design.md b/design.md
deleted file mode 100644
index 1f4d528..0000000
--- a/design.md
+++ /dev/null
@@ -1,95 +0,0 @@
-# Design · 代代相传家谱 PC
-
-这是 PC 家谱项目的统一设计系统。所有页面沿用同一套品牌、排版、间距、状态和交互规则;新增规则先修改本文件,不在单个页面创建另一套视觉语言。
-
-## 用户与任务
-
-- 用户:家谱创建者、管理员、普通家人和浏览公开家谱的访客。
-- 核心任务:创建或加入家谱,维护世系与成员,发布并浏览家族内容,处理邀请、消息与服务。
-- 设计气质:中文编辑式、克制、可信。功能页以任务效率为先,公共页保留家族文化氛围。
-
-## Genre
-
-Editorial。登录后的应用页使用更紧凑的工作台表达,不采用营销页式的大标题和卡片堆叠。
-
-## Macrostructure family
-
-- 公开与营销页面:Content Portal。真实内容和图片优先,标题区只说明当前任务。
-- 登录后应用页面:Workbench。固定页头、稳定的分组侧栏和单一内容画布;跨页面导航位置不改变。
-- 内容与资料页面:Long Document / List Detail。列表进入独立详情页,桌面端需要连续比较时允许页内列表详情。
-
-## Theme
-
-- `--color-paper`: `oklch(97.5% 0.012 82)`
-- `--color-paper-2`: `oklch(94.8% 0.024 78)`
-- `--color-ink`: `oklch(31% 0.028 158)`
-- `--color-ink-2`: `oklch(51% 0.022 158)`
-- `--color-rule`: `oklch(86% 0.028 78)`
-- `--color-accent`: `oklch(56% 0.185 29)`
-- `--color-accent-strong`: `oklch(43% 0.13 29)`
-- `--color-focus`: `oklch(61% 0.17 29)`
-- 辅助绿色和金色仅用于状态与文化信息,不与主操作竞争。
-
-## Typography
-
-- Display:`STSong`, `Songti SC`, `SimSun`, serif;字重 600;正常体。
-- Body:`Microsoft YaHei`, `PingFang SC`, system-ui, sans-serif;字重 400/600。
-- Mono:`Consolas`, `SFMono-Regular`, monospace,仅用于编号和技术值。
-- 标题不得使用斜体,不保留无业务意义的英文眉题。
-- 正文舒适行宽为 62~76 个中文字符。
-
-## Spacing
-
-使用根目录 `tokens.css` 中的 4px 命名刻度。新样式只能使用 `--space-*`,页面内容区桌面最大宽度统一为 `--layout-max`。
-
-## Motion
-
-- 动效只表达悬停、焦点、展开和状态变化,最多使用透明度与 `transform`。
-- 默认 160~220ms,无弹跳和持续漂浮。
-- `prefers-reduced-motion` 下关闭空间位移并将反馈压缩为短暂透明度变化。
-
-## Interaction decisions
-
-- 独立页面:多字段创建/编辑、详情阅读、支付、权限和安全设置。
-- 对话框:删除/退出等不可逆确认、密码输入、单一短任务;统一使用站内对话框,不调用浏览器原生 `confirm`/`prompt`。
-- 图片灯箱:相册和内容图片预览;不改变当前列表位置。
-- 页内展开:帮助问答、筛选、非关键补充信息。
-- 抽屉:桌面端评论或需要保留主内容上下文的辅助任务;不承载长表单。
-- 加载、空数据、错误、无权限:显示在对应内容区域,不使用弹窗打断。
-- 成功反馈:优先更新页面状态;仅在用户可能看不到变化时使用短消息。
-
-## Media rules
-
-- 业务媒体只消费后端 `BusinessFileAccess.accessUrl`,不得拼接 OSS ID 或暴露内部路径。
-- 家谱封面 16:9;相册封面 4:3;文章封面 16:9;头像 1:1;动态媒体根据原图比例限制最大高度。
-- 有地址时显示真实图片;无图片时使用姓名首字或明确空状态,不使用伪造照片、CSS 图画或无意义占位块。
-- 图片必须有与业务内容对应的替代文本;装饰图片使用空替代文本。
-- 正文附件使用左对齐、最大 280px 的缩略图网格并完整显示原图;封面和视频预览按业务比例完整呈现,不把单张附件拉伸成整栏大图。
-- 视频使用原生播放器,列表中只自动加载封面,不自动播放。
-
-## Shared states
-
-所有交互控件必须覆盖默认、悬停、键盘焦点、按下、禁用、加载、错误、成功状态。错误信息靠近问题区域,同时保留可恢复操作。
-
-## Responsive
-
-- 验证宽度:320、375、414、768、1024、1440。
-- 768px 以下侧栏转为页内分组导航,主内容单列。
-- `html` 与 `body` 使用 `overflow-x: clip`;按钮和主导航文字不得折成两行。
-- 附件网格桌面端按 200–280px 自适应列展示,移动端保持最大 280px;标题允许长家谱名称安全换行。
-
-## What pages MUST share
-
-- 品牌标识、朱红主操作色、排版和按钮语气。
-- 页头高度、内容最大宽度、侧栏位置、表单控件高度和状态样式。
-- 图片比例、媒体错误回退、空状态和权限状态。
-
-## Per-page allowances
-
-- 公开页可使用仓库内已有的真实祠堂和服务图片。
-- 应用页不增加装饰插画,数据与操作本身承担视觉层级。
-- 内容页以标题、正文、真实封面和元信息为主。
-
-## Exports
-
-实际 CSS 变量以根目录 `tokens.css` 为准。项目为原生 HTML/CSS/JS,不启用 Tailwind 或 shadcn;如未来迁移,颜色、字体、间距必须从相同命名 token 映射,不得另建品牌值。
diff --git a/dist/about.html b/dist/about.html
deleted file mode 100644
index a622cc5..0000000
--- a/dist/about.html
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- 关于我们 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
关于我们
-
用数字化方式守护家族记忆
-
- 代代相传面向家庭、宗亲会与地方文化组织,提供家谱创建、资料管理、文化展示和亲人协作工具。
-
-
- 数字家谱亲人协作文化传承
-
-
-
-
-
传
-
记录家族,连接亲人,传承文化。
-
-
-
-
-
-
-
-
我们重视
-
让家族资料真实、清晰、可协作,也能长期传下去。
-
-
-
-
真
-
真实
-
尊重家族资料来源,鼓励记录出处与修订过程。
-
-
-
协
-
协作
-
让更多亲人参与补充资料,形成长期维护机制。
-
-
-
承
-
传承
-
把家族文化整理成可持续保存的数字档案。
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/app.html b/dist/app.html
deleted file mode 100644
index 8996891..0000000
--- a/dist/app.html
+++ /dev/null
@@ -1,154 +0,0 @@
-
-
-
-
-
- 应用下载 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
移动应用
-
手机端随时记录,电脑端清晰浏览
-
- 家族成员可以在手机端上传照片、查看家谱、发布动态;电脑端适合浏览门户内容和公开家谱。
-
-
-
- 相册上传视频发布家谱查看
-
-
-
-
-

-

-
-
-
-
-
-
-
-
移动端能力
-
- 手机端适合随时记录家族资料、上传影像并与亲人共同维护。
-
-
-
-
-
谱
-
创建家谱
-
手机上快速创建或加入家族空间。
-
-
-
相
-
宣传相册
-
随手上传老照片、祖屋照片和聚会照片。
-
-
-
影
-
宣传视频
-
发布家族活动与人物影像。
-
-
-
文
-
谱文详情
-
阅读谱序、传记和家族文章。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/article-detail.html b/dist/article-detail.html
deleted file mode 100644
index b8b4bb7..0000000
--- a/dist/article-detail.html
+++ /dev/null
@@ -1,86 +0,0 @@
-
-
-
-
-
- 资讯详情 - 代代相传
-
-
-
-
-
-
-
-
- 正在读取资讯详情…
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/children-privacy.html b/dist/children-privacy.html
deleted file mode 100644
index d367156..0000000
--- a/dist/children-privacy.html
+++ /dev/null
@@ -1,73 +0,0 @@
-
-
-
-
-
- 儿童个人信息处理规则 - 代代相传
-
-
-
-
-
-
-
-
-
-
儿童隐私保护
-
儿童个人信息处理规则
-
用于说明儿童个人信息的处理边界、监护人权利和保护措施。
-
-
护
-
-
-
-
-
-
- 待法务确认:本页面仅建立儿童个人信息规则的访问入口,不构成已生效的规则。发布前必须由运营主体与法务确认适用年龄、监护人授权与完整文本。
-
- 正式文本应涵盖
-
- 儿童信息处理目的、必要性、监护人同意方式、信息访问更正删除渠道,以及发生个人信息安全事件时的告知安排。
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/config.js b/dist/config.js
deleted file mode 100644
index e868646..0000000
--- a/dist/config.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(n,i){if(typeof module=="object"&&module.exports){module.exports=i;return}n.GenealogyConfig=i(n)})(typeof globalThis!="undefined"?globalThis:window,function(n){"use strict";var i="ced7e5f0498645c6ec642dcf450b036f",c="000000",p="genealogy_auth_token",o=/^(?:javascript|data|vbscript):/i;function u(){return{open:function(t){var e=String(t||"").trim();if(!e||o.test(e)||typeof n.open!="function")return null;var r=n.open(e,"_blank","noopener");return r&&(r.opener=null),r},replace:function(t){var e=String(t||"").trim();!e||o.test(e)||n.location&&typeof n.location.replace=="function"&&n.location.replace(e)}}}var f={development:{apiBaseUrl:"https://backend-api.ddxcjp.cn/"},production:{apiBaseUrl:"https://backend-api.ddxcjp.cn/"}};function a(){var t=n.location||{},e=t.hostname||"";return e==="localhost"||e==="127.0.0.1"||t.port?"development":"production"}function l(){return f[a()].apiBaseUrl}function d(){return{environment:a(),apiBaseUrl:l(),clientId:i,tenantId:c,tokenKey:p}}return n.NavigationUtil=n.NavigationUtil||u(),{getEnvironment:a,getApiBaseUrl:l,getConfig:d}});
diff --git a/dist/create-genealogy.html b/dist/create-genealogy.html
deleted file mode 100644
index 1052765..0000000
--- a/dist/create-genealogy.html
+++ /dev/null
@@ -1,177 +0,0 @@
-
-
-
-
-
- 创建家谱 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
创建家谱
-
创建属于家族的数字空间
-
- 填写姓氏谱名、地区与简介,先建立家谱主页,再逐步邀请亲人共同完善资料。
-
-
- 基础资料成员世系亲人共修
-
-
-
-
-
创建流程
-
-
1填写基础信息
-
2添加第一批成员
-
3邀请亲人共修
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/culture.html b/dist/culture.html
deleted file mode 100644
index 594df0b..0000000
--- a/dist/culture.html
+++ /dev/null
@@ -1,129 +0,0 @@
-
-
-
-
-
- 家族文化 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
家族文化
-
让家风、族训与故事被认真保存
-
- 家族文化承接新闻、知识、公告和故事,让谱文之外的记忆也能被阅读、分享和传承。
-
-
- 家风家训谱文故事使用指南
-
-
-
-
-
家风
-
- 一张老照片、一段口述、一篇谱序,都可以成为后人理解家族的入口。
-
-
-
-
-
-
-
-
-
精选文章
-
用可阅读的内容入口连接家谱知识、姓氏文化和平台使用指南。
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/download.html b/dist/download.html
deleted file mode 100644
index a2518fa..0000000
--- a/dist/download.html
+++ /dev/null
@@ -1,105 +0,0 @@
-
-
-
-
-
- 下载应用 - 代代相传
-
-
-
-
-
-
-
-
-
-
应用下载
-
下载代代相传 APP
-
- 手机端适合日常上传宣传相册、发布宣传视频、查看家谱和补充资料。
-
-
-
-
-
选择下载方式
-
请在下方选择平台当前提供的可用下载入口。
-
-
-
-
-
-
-
下载方式
-
下载地址会根据平台当前配置显示;没有可用入口时会明确提示。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/family-detail.html b/dist/family-detail.html
deleted file mode 100644
index e1e9d3c..0000000
--- a/dist/family-detail.html
+++ /dev/null
@@ -1,141 +0,0 @@
-
-
-
-
-
- 四川武胜汤氏族 - 家谱详情 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
家谱详情
-
四川武胜汤氏族
-
- 公开展示家族源流、世系概览、字辈排行、谱文资料和宣传相册,让访客快速理解这一本家谱的内容结构。
-
-
-
-
-
公开家谱
-
汤氏族谱
-
- 128成员
- 6世代
- 18谱文
- 7相册
-
-
-
-
-
-
-
-
-
-
- 家族简介
-
- 本谱以四川武胜汤氏族人为主体,整理始祖源流、迁徙线索、字辈排行、重要人物与家风故事。公开内容用于展示家族文化,完整成员资料需申请加入后查看。
-
-
-
-
-
世系概览
-
按代际关系梳理成员结构,帮助族人找到自己的位置。
-
-
-
谱文资料
-
收录谱序、家训、修谱说明和公开纪念文章。
-
-
-
宣传相册
-
展示祠堂祖屋、修谱活动、老照片和家族纪念内容。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/forbidden.html b/dist/forbidden.html
deleted file mode 100644
index 92e16b1..0000000
--- a/dist/forbidden.html
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-
- 无访问权限 - 代代相传
-
-
-
-
-
-
-
-
-
-
!
-
无访问权限
-
- 当前账号没有访问此内容的权限。请确认登录账号,或联系家谱管理员处理。
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/forgot-password.html b/dist/forgot-password.html
deleted file mode 100644
index ad21b23..0000000
--- a/dist/forgot-password.html
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-
-
-
- 找回密码 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/genealogy.html b/dist/genealogy.html
deleted file mode 100644
index 93454cc..0000000
--- a/dist/genealogy.html
+++ /dev/null
@@ -1,157 +0,0 @@
-
-
-
-
-
- 数字家谱 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
数字家谱
-
把成员关系整理成清晰可查的数字家谱
-
- 从始祖、分支、排行到个人资料,数字家谱帮助家族建立长期可维护的成员档案和世系关系。
-
-
-
8资料模块
-
3步快速建谱
-
多人协作共修
-
-
-
-
-
始祖
-
-
- 长房二房三房
-
-
-
- 第六世第七世第八世第九世
-
-
-
-
-
-
-
-
-
核心能力
-
- 围绕修谱、查谱和协作维护,把家族资料从零散记录整理成完整档案。
-
-
-
-
-
世
-
世系图
-
- 以树谱方式展示成员关系,支持查看个人资料、添加亲属和调整排行。
-
-
-
-
字
-
字辈谱
-
记录各代字辈与人数,让世代脉络更加清楚。
-
-
-
文
-
谱文资料
-
沉淀谱序、家训、人物传记和修谱说明。
-
-
-
权
-
权限管理
-
设置管理员、内容可见范围与入谱审核,保护家族隐私。
-
-
-
-
-
-
-
-
-
适合多人共修
-
- 家族成员可以分别补充照片、成员资料、谱文和故事,再由管理员统一审核,避免资料越传越散。
-
-
开始创建
-
-
-
修谱流程
-
-
1创建家谱并填写姓氏、地区、堂号
-
2录入第一批成员,建立上下辈关系
-
3邀请亲人加入,共同完善资料
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/help.html b/dist/help.html
deleted file mode 100644
index 2718c16..0000000
--- a/dist/help.html
+++ /dev/null
@@ -1,117 +0,0 @@
-
-
-
-
-
- 帮助中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
帮助中心
-
从创建到协作,快速解决常见问题
-
- 帮助内容由平台持续维护,覆盖账号、家谱和内容使用中的常见问题。
-
-
- 账号安全家谱使用内容管理
-
-
-
-
-
?
-
需要人工协助?
-
- 遇到资料导入、权限或账号问题,可以提交说明,客服会协助处理。
-
-
提交工单
-
我的工单
-
-
-
-
-
-
-
-
常见问题
-
选择问题后读取平台发布的完整解答。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/index.html b/dist/index.html
deleted file mode 100644
index f6d77b8..0000000
--- a/dist/index.html
+++ /dev/null
@@ -1,556 +0,0 @@
-
-
-
-
-
- 代代相传家谱_在线修家谱_家谱查询_姓氏寻根_祠堂祭祀
-
-
-
-
-
-
-
-
-
-
-
-
-
-
数字家谱与家族文化门户
-
- 一部会生长的
数字家谱
-
-
- 把姓氏源流、世系关系、字辈排行、宣传相册、谱文故事与亲人动态整理在一起,让家族的来处清晰可见,让记忆可以继续传下去。
-
-
-
- 1创建家谱2邀请亲人3共同传承
-
-
-
-
家谱广场浏览公开家族
-
姓氏百科了解姓氏源流
-
家族文化阅读传承故事
-
-
-
-
-
-
-
-
-
-
-
-
数字家谱核心功能
-
-
-
-
世
-
世系图
-
- 以树谱方式展示成员关系,支持查看个人资料、添加亲属、调整排行。
-
-
-
-
字
-
字辈谱
-
记录各代字辈与人数,让家族世代脉络更加清楚。
-
-
- 相
- 宣传相册
- 按相册归档宣传影像,展示祖屋、活动、老照片和重要时刻。
-
-
-
文
-
谱文资料
-
沉淀谱序、谱文、家训、恩荣录等文本内容。
-
-
-
圈
-
家族圈
-
发布动态、分享图片、评论互动,让亲人之间保持连接。
-
-
-
功
-
功德录
-
记录家族贡献人物与事迹,让善行与纪念被看见。
-
-
-
礼
-
贺礼邀请
-
发布婚礼、生日、升学等家族喜事,通知相关成员。
-
-
-
权
-
权限管理
-
设置管理员、内容可见范围与入谱审核,保护家族隐私。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
姓氏百科
-
- 以姓氏为入口,整理姓氏源流、名人故事、地区分布、字辈参考和相关家谱。
-
-
进入姓氏百科
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
手机端随时记录,电脑端清晰浏览
-
- 家族成员可以在手机端上传照片、查看家谱、发布动态;电脑端适合浏览门户内容、查看公开家谱和进入家谱空间。
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/join-genealogy.html b/dist/join-genealogy.html
deleted file mode 100644
index 70405db..0000000
--- a/dist/join-genealogy.html
+++ /dev/null
@@ -1,77 +0,0 @@
-
-
-
-
-
- 加入家谱 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
我的家谱
-
-
-
加入家谱
-
先搜索并选择要加入的家谱,再补充申请资料;家谱编号由系统自动处理。
-
-
查看我的申请
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/login.html b/dist/login.html
deleted file mode 100644
index 6a4449f..0000000
--- a/dist/login.html
+++ /dev/null
@@ -1,88 +0,0 @@
-
-
-
-
-
- 登录 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/maintenance.html b/dist/maintenance.html
deleted file mode 100644
index f9e13da..0000000
--- a/dist/maintenance.html
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-
- 系统维护中 - 代代相传
-
-
-
-
-
-
-
-
-
-
工
-
系统维护中
-
- 我们正在进行必要的服务维护,请稍后再试。账号与家谱资料不会因维护而丢失。
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/my-tickets.html b/dist/my-tickets.html
deleted file mode 100644
index c7927b9..0000000
--- a/dist/my-tickets.html
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
-
-
- 我的工单 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/news.html b/dist/news.html
deleted file mode 100644
index 4442d6f..0000000
--- a/dist/news.html
+++ /dev/null
@@ -1,82 +0,0 @@
-
-
-
-
-
- 新闻资讯 - 代代相传
-
-
-
-
-
-
-
-
-
-
资讯中心
-
新闻资讯
-
- 集中阅读平台新闻、公告与下载内容。
-
-
-
闻
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/not-found.html b/dist/not-found.html
deleted file mode 100644
index d57781e..0000000
--- a/dist/not-found.html
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-
-
-
- 页面不存在 - 代代相传
-
-
-
-
-
-
-
-
-
-
404
-
页面不存在
-
你访问的页面可能已移动、已删除或地址输入有误。
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/notice-detail.html b/dist/notice-detail.html
deleted file mode 100644
index a421887..0000000
--- a/dist/notice-detail.html
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
- 平台公告详情 - 代代相传
-
-
-
-
-
-
-
-
-
-
平台公告
-
平台内容公开展示规范说明
-
- 为了保护家族资料安全,平台仅展示管理员确认公开的家谱介绍、文章、宣传相册和宣传视频。
-
-
- 平台公告2026.05
-
-
-
-
-
-
-
-
-
- 平台前台页面主要用于展示家族文化与公开资料。涉及成员联系方式、详细个人信息、未审核资料等内容,不会在公开页面直接呈现。
-
- 公开内容范围
-
- 可公开内容包括家族简介、姓氏源流、谱文节选、宣传相册、宣传视频、平台公告和管理员允许展示的纪念内容。
-
- 资料维护建议
-
- 建议由管理员先整理资料,再邀请亲人补充和校对。需要修改公开范围时,可以在权限设置中调整。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/plaza.html b/dist/plaza.html
deleted file mode 100644
index 4e69088..0000000
--- a/dist/plaza.html
+++ /dev/null
@@ -1,148 +0,0 @@
-
-
-
-
-
- 家谱广场 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
家谱广场
-
浏览公开家谱,寻找同宗线索
-
- 按姓氏、地区、堂号和家谱名称检索公开家谱,先看示例,再创建自己的家族空间。
-
-
- 128+公开家谱
- 36地区线索
- 18谱文示例
-
-
-
-
-
查找公开家谱
-
-
- 公开家谱字辈完整多人共修
-
-
-
-
-
-
-
-
-
推荐家谱
-
展示公开或示例家谱,让访问者理解数字家谱最终会呈现成什么样。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/privacy.html b/dist/privacy.html
deleted file mode 100644
index 83fe027..0000000
--- a/dist/privacy.html
+++ /dev/null
@@ -1,73 +0,0 @@
-
-
-
-
-
- 隐私政策 - 代代相传
-
-
-
-
-
-
-
-
-
-
隐私政策
-
隐私政策
-
说明平台处理个人信息的规则、用户权利与联系渠道。
-
-
隐
-
-
-
-
-
-
- 待法务确认:本页面仅建立政策访问入口,不构成已生效的隐私政策。发布前必须由运营主体与法务确认完整文本、版本号和生效日期。
-
- 正式文本应涵盖
-
- 个人信息处理目的、收集范围、保存期限、共享规则、用户查阅更正删除权利,以及个人信息保护负责人的联系渠道。
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-admin-permissions.html b/dist/profile-admin-permissions.html
deleted file mode 100644
index f03dc1f..0000000
--- a/dist/profile-admin-permissions.html
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
-
- 管理员权限 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
权限设置
-
-
-
管理员权限
-
- 在成员名册中维护管理员、编辑和成员角色;可执行的操作以当前账号权限为准。
-
-
-
-
-
-
-
-
-
-
-
- 角色与权限
-
-
-
管理员
可维护编辑和成员角色,不能修改谱主或其他管理员。
-
编辑、成员
不显示成员角色编辑入口;最终权限由服务端校验。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-album-detail.html b/dist/profile-album-detail.html
deleted file mode 100644
index 15eeca6..0000000
--- a/dist/profile-album-detail.html
+++ /dev/null
@@ -1,125 +0,0 @@
-
-
-
-
-
- 相册详情 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
相册详情
-
-
-
相册详情
-
查看相册信息和照片;照片暂不可在线预览时,仍会保留名称和上传记录。
-
-
-
-
-
-
-
-
-
-
-
- 添加照片
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-album-edit.html b/dist/profile-album-edit.html
deleted file mode 100644
index d771eba..0000000
--- a/dist/profile-album-edit.html
+++ /dev/null
@@ -1,101 +0,0 @@
-
-
-
-
-
- 编辑相册 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
编辑相册
-
-
-
新建相册
-
维护相册名称、说明和封面;封面编号由上传自动产生。
-
-
-
-
-
-
-
-
-
- 正在读取家谱权限...
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-album.html b/dist/profile-album.html
deleted file mode 100644
index 08cc671..0000000
--- a/dist/profile-album.html
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
-
-
-
- 家族相册 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
家族相册
-
-
-
家族相册
-
查看和管理家谱相册;照片文件由上传组件自动关联,无需填写内部编号。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-article-edit.html b/dist/profile-article-edit.html
deleted file mode 100644
index 870103f..0000000
--- a/dist/profile-article-edit.html
+++ /dev/null
@@ -1,141 +0,0 @@
-
-
-
-
-
- 编辑谱文 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
编辑谱文
-
-
-
新建谱文
-
- 使用富文本编辑器撰写谱文、谱序、谱论和恩荣录,支持图片、表格与排版。
-
-
-
-
-
-
-
-
-
-
- 谱文内容
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-article.html b/dist/profile-article.html
deleted file mode 100644
index 243f190..0000000
--- a/dist/profile-article.html
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
-
- 谱文管理 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
家族谱文
-
-
-
谱文管理
-
- 管理谱文、谱序、谱论、恩荣录等家族文献,支持添加内容、图片与落款。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-ceremony-detail.html b/dist/profile-ceremony-detail.html
deleted file mode 100644
index a9d8669..0000000
--- a/dist/profile-ceremony-detail.html
+++ /dev/null
@@ -1,87 +0,0 @@
-
-
-
-
-
- 活动详情 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 祭品记录
-
-
-
-
- 受邀名单
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-ceremony.html b/dist/profile-ceremony.html
deleted file mode 100644
index f66cc82..0000000
--- a/dist/profile-ceremony.html
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-
-
- 祭祀活动 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
祭祀活动
-
祭祀活动
查看当前家谱的活动;具备内容维护权限时可创建、编辑和删除。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-content.html b/dist/profile-content.html
deleted file mode 100644
index ea7b051..0000000
--- a/dist/profile-content.html
+++ /dev/null
@@ -1,130 +0,0 @@
-
-
-
-
-
- 内容发布 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
内容发布
-
-
-
内容发布
-
- 集中管理谱文、视频、相册、功德录、贺礼邀请、成长记录、家族动态和备忘录。
-
-
-
添加谱文
-
-
-
-
-
-
-
-
-
- 使用说明
- 请选择上方功能,继续查看和维护当前家谱内容。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-create-family.html b/dist/profile-create-family.html
deleted file mode 100644
index dbbf814..0000000
--- a/dist/profile-create-family.html
+++ /dev/null
@@ -1,163 +0,0 @@
-
-
-
-
-
- 创建家谱 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
创建家谱
-
-
-
创建家谱
-
- 填写家谱基本信息;标有 * 的字段为必填,创建后可进入家谱工作区继续维护。
-
-
-
-
-
-
-
-
-
-
- 基础信息
- 正在读取家谱额度…
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-data-reminders.html b/dist/profile-data-reminders.html
deleted file mode 100644
index 2d02a4b..0000000
--- a/dist/profile-data-reminders.html
+++ /dev/null
@@ -1,74 +0,0 @@
-
-
-
-
-
- 资料提醒 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
资料提醒
-
-
-
资料提醒
-
- 集中查看成员资料缺项,补齐头像、出生日期、亲属关系和联系方式。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-data.html b/dist/profile-data.html
deleted file mode 100644
index 3cbdce5..0000000
--- a/dist/profile-data.html
+++ /dev/null
@@ -1,259 +0,0 @@
-
-
-
-
-
- 个人资料 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
个人资料
-
-
-
个人资料
-
- 管理个人资料和账号安全信息;家谱成员关系请在当前家谱中维护。
-
-
-
编辑资料
-
-
-
-
-
-
-
-
- 编辑资料
-
-
-
-
-
-
- 亲属关系
-
-
- 个人资料页不单独维护亲属关系;请先选择家谱,再到成员管理或世系图中查看和维护。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-documents.html b/dist/profile-documents.html
deleted file mode 100644
index 19adc81..0000000
--- a/dist/profile-documents.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
- 重要证件 - 个人中心 - 代代相传
-
-
- 重要证件
重要证件
按人物维护证件档案、附件和访问密码。证件号码仅填写脱敏内容。
-
-
-
-
-
diff --git a/dist/profile-earnings.html b/dist/profile-earnings.html
deleted file mode 100644
index 36568ad..0000000
--- a/dist/profile-earnings.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
- 推广收益 - 个人中心 - 代代相传
-
-
-
-
-
-
diff --git a/dist/profile-families.html b/dist/profile-families.html
deleted file mode 100644
index 2ce7f98..0000000
--- a/dist/profile-families.html
+++ /dev/null
@@ -1,115 +0,0 @@
-
-
-
-
-
- 我的家谱 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
-
-
我的家谱
-
- 从真实列表选择要进入的家谱,后续页面会持续使用同一个家谱上下文。
-
-
-
创建家谱
-
-
-
-
-
-
-
-
- 家谱入口
- 先选择要处理的家谱,再进入主页、成员、世系和内容管理。
- 正在读取家谱额度…
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-family-admin.html b/dist/profile-family-admin.html
deleted file mode 100644
index 7ffacfb..0000000
--- a/dist/profile-family-admin.html
+++ /dev/null
@@ -1,95 +0,0 @@
-
-
-
-
-
- 家族管理 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
家族管理
-
-
家族管理
查看家谱成员;具备管理权限时可调整成员信息、角色和世系人物绑定。
-
-
-
-
-
-
-
-
-
- 正常成员
- 成员新增必须通过后端已有的加入或邀请流程;本页不伪造直接新增成员。
-
-
-
-
- 编辑成员
-
-
-
- 转让谱主
-
-
-
- 退出家谱
- 退出只停用当前账号的成员关系,不删除世系人物资料;谱主必须先转让谱主。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-family-home.html b/dist/profile-family-home.html
deleted file mode 100644
index 9653cab..0000000
--- a/dist/profile-family-home.html
+++ /dev/null
@@ -1,199 +0,0 @@
-
-
-
-
-
- 家谱主页 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
-
-
正在读取家谱
-
- 当前家谱的工作区,用于进入世系、相册、家族圈、内容管理和成员协作。
-
-
-
管理家谱
-
-
-
-
-
-
-
-
-
-
- 家族文化
- 围绕当前家谱集中维护谱文、影像与家族资料。
-
-
-
- 家族记录与协作
- 按列表、详情和编辑页面管理动态、成长记录、亲友往来、备忘和活动。
-
-
-
- 家谱维护
- 世系、字辈和成员维护均与当前家谱绑定;管理权限始终以服务端结果为准。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-family-settings.html b/dist/profile-family-settings.html
deleted file mode 100644
index e8fac5d..0000000
--- a/dist/profile-family-settings.html
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
- 家谱维护 - 个人中心 - 代代相传
-
-
-
-
-
-
-
- 家谱维护
家谱维护
归档、恢复或永久删除当前家谱。永久删除前会再次校验谱主身份和手机号。
-
-
归档与恢复
归档用于暂时停止维护,不会永久删除数据。
-
永久删除
此操作不可恢复。仅谱主且满足服务端删除条件时可执行。
-
正在读取家谱维护能力…
-
-
-
-
-
diff --git a/dist/profile-feed-detail.html b/dist/profile-feed-detail.html
deleted file mode 100644
index f0f2dd0..0000000
--- a/dist/profile-feed-detail.html
+++ /dev/null
@@ -1,95 +0,0 @@
-
-
-
-
-
- 动态详情 - 家族圈 - 代代相传
-
-
-
-
-
-
-
-
-
-
动态详情
-
-
-
动态详情
-
查看动态、评论与回复;本页链接可用于通知跳转和分享。
-
-
-
-
-
-
-
-
-
-
- 发表评论
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-feed-edit.html b/dist/profile-feed-edit.html
deleted file mode 100644
index 6308de3..0000000
--- a/dist/profile-feed-edit.html
+++ /dev/null
@@ -1,113 +0,0 @@
-
-
-
-
-
- 发布动态 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
发布动态
-
-
-
发布动态
-
面向家族圈发布文字和图片动态,与家人交流近况。
-
-
-
-
-
-
-
-
-
- 动态内容
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-feed.html b/dist/profile-feed.html
deleted file mode 100644
index 636927d..0000000
--- a/dist/profile-feed.html
+++ /dev/null
@@ -1,104 +0,0 @@
-
-
-
-
-
- 家族圈 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
家族圈
-
-
-
家族圈
-
向家族圈发布文字和图片动态,与家人交流近况。
-
-
-
-
-
-
-
-
-
-
- 最近动态
-
-
-
-
- 第 1 页
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-feedback.html b/dist/profile-feedback.html
deleted file mode 100644
index 5b1352e..0000000
--- a/dist/profile-feedback.html
+++ /dev/null
@@ -1,97 +0,0 @@
-
-
-
-
-
- 意见反馈 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
意见反馈
-
-
-
意见反馈
-
提交产品问题、资料异常和改进建议,个人中心内独立跟踪。
-
-
-
-
-
-
-
-
-
- 提交反馈
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-generation.html b/dist/profile-generation.html
deleted file mode 100644
index ad68a8a..0000000
--- a/dist/profile-generation.html
+++ /dev/null
@@ -1,146 +0,0 @@
-
-
-
-
-
- 字辈谱 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
字辈管理
-
-
-
字辈谱
-
管理世代数字辈,查看各代人数,并维护同字辈多个用字。
-
-
-
-
-
-
-
-
-
-
-
- 新增字辈
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-gift-edit.html b/dist/profile-gift-edit.html
deleted file mode 100644
index 18b1e13..0000000
--- a/dist/profile-gift-edit.html
+++ /dev/null
@@ -1,146 +0,0 @@
-
-
-
-
-
- 创建祭祀活动 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
活动编辑
-
-
-
创建祭祀活动
-
维护活动类型、标题、时间地点和说明;受邀名单在活动详情中选择家谱成员。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-gift.html b/dist/profile-gift.html
deleted file mode 100644
index 085285e..0000000
--- a/dist/profile-gift.html
+++ /dev/null
@@ -1,88 +0,0 @@
-
-
-
-
-
- 贺礼邀请 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
贺礼邀请
-
-
-
贺礼邀请
-
- 查看发给当前账号的活动邀请,并直接接受或拒绝;具备权限时可进入活动管理。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-growth-edit.html b/dist/profile-growth-edit.html
deleted file mode 100644
index 928c6f4..0000000
--- a/dist/profile-growth-edit.html
+++ /dev/null
@@ -1,145 +0,0 @@
-
-
-
-
-
- 新建成长记录 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
编辑成长记录
-
-
-
新建成长记录
-
人物从当前家谱世系中选择,附件由上传组件自动生成内部编号。
-
-
-
-
-
-
-
-
-
- 记录内容
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-growth.html b/dist/profile-growth.html
deleted file mode 100644
index 73f8e9e..0000000
--- a/dist/profile-growth.html
+++ /dev/null
@@ -1,79 +0,0 @@
-
-
-
-
-
- 成长日志 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
成长记录
-
-
-
成长记录
-
记录家族成员的成长节点、日期、提醒和附件。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-invite.html b/dist/profile-invite.html
deleted file mode 100644
index e56f049..0000000
--- a/dist/profile-invite.html
+++ /dev/null
@@ -1,79 +0,0 @@
-
-
-
-
-
- 邀请家人 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
邀请家人
-
-
-
邀请家人
-
生成家谱邀请链接或邀请码,引导亲人加入家谱并激活账号。
-
-
返回家族管理
-
-
-
-
-
-
-
-
- 生成邀请
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-join-family.html b/dist/profile-join-family.html
deleted file mode 100644
index 547d7c9..0000000
--- a/dist/profile-join-family.html
+++ /dev/null
@@ -1,75 +0,0 @@
-
-
-
-
-
- 加入家谱 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
加入家谱
-
-
-
加入家谱
-
查看加入申请进度;待审核申请可以撤销后重新提交。
-
-
提交新申请
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-join-review.html b/dist/profile-join-review.html
deleted file mode 100644
index a6f5f81..0000000
--- a/dist/profile-join-review.html
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
-
-
-
- 入谱审核 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
入谱审核
-
-
-
入谱审核
-
审核当前家谱的加入申请。只有家谱管理者可以执行通过或拒绝。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-memo-edit.html b/dist/profile-memo-edit.html
deleted file mode 100644
index 45ad0c0..0000000
--- a/dist/profile-memo-edit.html
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-
-
-
- 新建备忘录 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
- 编辑备忘录
新建备忘录
附件由上传组件自动生成内部编号,页面不允许手工填写。
-
-
-
-
-
-
- 备忘内容
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-memo.html b/dist/profile-memo.html
deleted file mode 100644
index ab8c4c1..0000000
--- a/dist/profile-memo.html
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
-
-
- 备忘录 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
备忘录
-
备忘录
记录家族事务、纪念事项、提醒时间和完成状态。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-merit-edit.html b/dist/profile-merit-edit.html
deleted file mode 100644
index de7ecba..0000000
--- a/dist/profile-merit-edit.html
+++ /dev/null
@@ -1,120 +0,0 @@
-
-
-
-
-
- 新增功德记录 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
编辑功德记录
-
-
-
新增功德记录
-
选择功德类型并填写金额和说明;标有 * 的项目为必填。
-
-
-
-
-
-
-
-
-
- 功德资料
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-merit.html b/dist/profile-merit.html
deleted file mode 100644
index d11e2ad..0000000
--- a/dist/profile-merit.html
+++ /dev/null
@@ -1,79 +0,0 @@
-
-
-
-
-
- 功德录 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
功德录
-
-
-
功德录
-
记录功德人、事迹、时间和金额,沉淀家族贡献。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-messages.html b/dist/profile-messages.html
deleted file mode 100644
index c955442..0000000
--- a/dist/profile-messages.html
+++ /dev/null
@@ -1,114 +0,0 @@
-
-
-
-
-
- 消息中心 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
消息中心
-
-
-
消息中心
-
查看当前账号的通知详情,并管理未读状态。
-
-
返回个人中心
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 阅读管理
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-relative-edit.html b/dist/profile-relative-edit.html
deleted file mode 100644
index 3ac8cad..0000000
--- a/dist/profile-relative-edit.html
+++ /dev/null
@@ -1,133 +0,0 @@
-
-
-
-
-
- 新建亲友记录 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
编辑亲友往来
-
-
-
新建亲友记录
-
附件由上传组件自动生成内部编号,页面不允许手工填写。
-
-
-
-
-
-
-
-
-
- 记录内容
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-relative.html b/dist/profile-relative.html
deleted file mode 100644
index 69053f9..0000000
--- a/dist/profile-relative.html
+++ /dev/null
@@ -1,78 +0,0 @@
-
-
-
-
-
- 亲友往来 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
亲友往来
-
-
-
亲友往来
-
记录亲友关系、往来事项、时间、礼金和附件。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-security.html b/dist/profile-security.html
deleted file mode 100644
index 6a9b8c9..0000000
--- a/dist/profile-security.html
+++ /dev/null
@@ -1,163 +0,0 @@
-
-
-
-
-
- 安全设置 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
安全设置
-
-
-
安全设置
-
维护登录密码、手机号与账号注销安全操作。
-
-
-
-
-
-
-
-
-
-
-
- 注销账号
- 验证已绑定手机号的短信验证码后提交注销申请。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-services.html b/dist/profile-services.html
deleted file mode 100644
index d9cbc20..0000000
--- a/dist/profile-services.html
+++ /dev/null
@@ -1,196 +0,0 @@
-
-
-
-
-
- 帮助与服务 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
帮助与服务
-
-
-
帮助与服务
-
集中处理推广收益、意见反馈、账号安全、帮助说明和会员服务。
-
-
提交反馈
-
-
-
-
-
-
-
-
-
- 平台设置与协议
- 集中查看平台说明、服务支持和协议入口;正式内容以平台发布版本为准。
-
-
-
- 会员服务
- 选择适合的会员套餐并创建微信扫码支付订单。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-share.html b/dist/profile-share.html
deleted file mode 100644
index 861c0f4..0000000
--- a/dist/profile-share.html
+++ /dev/null
@@ -1,102 +0,0 @@
-
-
-
-
-
- 应用分享与收益 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
应用分享
-
-
-
应用分享与收益
-
应用邀请暂以移动端为主;这里可查看推广收益、流水和提现记录。
-
-
-
-
-
-
-
-
-
- 邀请好友奖励
-
-
-
享
-
每邀请一位好友
-
邀请奖励规则正在完善,当前暂不展示奖励金额。
-
-
-
码
-
分享二维码
-
分享链接和二维码暂未开放,请先使用移动端分享。
-
-
-
-
- 分享记录
-
-
- 分享记录暂未开放;推广收益和提现结果可在下方查看。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-tree.html b/dist/profile-tree.html
deleted file mode 100644
index 8272af0..0000000
--- a/dist/profile-tree.html
+++ /dev/null
@@ -1,305 +0,0 @@
-
-
-
-
-
- 世系图 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
世系管理
-
-
-
世系图
-
- 个人中心内的树谱管理视图,用于查看成员关系、添加亲属和搜索成员。
-
-
-
管理字辈
-
-
-
-
-
-
-
-
- 树谱操作
-
-
-
-
-
-
-
-
-
-
-
- 成员搜索
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 新增 / 编辑成员
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-video-edit.html b/dist/profile-video-edit.html
deleted file mode 100644
index f75c20a..0000000
--- a/dist/profile-video-edit.html
+++ /dev/null
@@ -1,129 +0,0 @@
-
-
-
-
-
- 发布视频 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
编辑视频
-
-
-
发布视频
-
视频文件由上传组件自动关联,无需填写内部编号。
-
-
-
-
-
-
-
-
-
- 视频内容
-
- 正在核对视频维护权限…
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile-video.html b/dist/profile-video.html
deleted file mode 100644
index 0fdbefa..0000000
--- a/dist/profile-video.html
+++ /dev/null
@@ -1,83 +0,0 @@
-
-
-
-
-
- 家族视频 - 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
家族视频
-
-
-
家族视频
-
查看家族视频资料;有内容维护权限的成员可以发布、编辑和删除视频。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/profile.html b/dist/profile.html
deleted file mode 100644
index 35aa226..0000000
--- a/dist/profile.html
+++ /dev/null
@@ -1,199 +0,0 @@
-
-
-
-
-
- 个人中心 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
-
-
-
个人中心
-
正在加载账户
-
账户资料与家谱工作区分开呈现。进入家谱后,再处理成员、内容和协作事务。
-
- 已登录账户资料与账号同步
-
-
正在读取账户资料…
-
-
-
-
-
下一步
-
从家谱开始
-
没有家谱时可创建或申请加入;有多个家谱时,请先选择本次要处理的家谱。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
我的家谱
-
先从真实列表选择家谱,再进入对应的主页、世系图、成员和内容管理。
-
-
查看全部
-
-
-
-
-
-
-
-
账户资料
-
以下内容来自你的账户资料;未填写的信息会显示为“待填写”。
-
-
编辑资料
-
-
-
绑定账号加载中
-
昵称加载中
-
真实姓名加载中
-
性别加载中
-
出生日期加载中
-
邮箱加载中
-
-
-
-
-
-
账户与服务
-
将 APP 的“我的”功能整理为桌面服务入口;家谱内容仍需从具体家谱进入。
-
-
查看服务中心
-
-
-
-
-
-
-
-
-
-
-
-
-
-
退
-
确认退出登录?
-
退出后需要重新登录,才能继续管理家谱、审核消息和编辑资料。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/promo-album.html b/dist/promo-album.html
deleted file mode 100644
index 9114856..0000000
--- a/dist/promo-album.html
+++ /dev/null
@@ -1,103 +0,0 @@
-
-
-
-
-
- 宣传相册 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
相册分类
-
把适合公开展示的影像整理成专题,让家族主页更有内容层次。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/promo-video.html b/dist/promo-video.html
deleted file mode 100644
index 67834dd..0000000
--- a/dist/promo-video.html
+++ /dev/null
@@ -1,106 +0,0 @@
-
-
-
-
-
- 宣传视频 - 代代相传
-
-
-
-
-
-
-
-
-
-
-
视频专题
-
把适合公开传播的视频整理成栏目,增强家谱主页的展示力。
-
-
-
-
家族介绍
-
概述姓氏源流、家族分布和家风传承。
-
-
-
活动纪念
-
展示祭祖、聚会、修谱仪式等重要时刻。
-
-
-
人物故事
-
以影像记录家族人物、贡献与纪念内容。
-
-
-
-
-
-
-
-
-
-
diff --git a/dist/public/css/about.css b/dist/public/css/about.css
deleted file mode 100644
index 69a379e..0000000
--- a/dist/public/css/about.css
+++ /dev/null
@@ -1 +0,0 @@
-.about-hero .container{min-height:440px;padding-top:74px;padding-bottom:74px}.hero-copy{position:relative;padding-left:28px}.hero-copy:before{content:"";position:absolute;left:0;top:58px;width:4px;height:132px;border-radius:999px;background:linear-gradient(180deg,var(--red),var(--gold))}.about-tags{display:flex;gap:12px;margin-top:28px;flex-wrap:wrap}.about-tags span{padding:10px 14px;border:1px solid rgba(224,211,189,.78);border-radius:999px;color:#6d766f;background:#fffdf8bd;box-shadow:0 14px 32px #4839260f;font-weight:800;transition:transform .22s ease,color .22s ease,background .22s ease}.about-tags span:hover{color:#fff;background:var(--green);transform:translateY(-3px)}.about-seal{position:relative;min-height:260px;overflow:hidden;display:grid;place-items:center;text-align:center;color:#fff;background:linear-gradient(155deg,var(--green-dark),var(--green))}.about-seal:before{content:"";position:absolute;inset:0;background:linear-gradient(rgba(255,255,255,.08) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,.08) 1px,transparent 1px);background-size:34px 34px;opacity:.34}.seal-orb{position:absolute;right:76px;top:40px;width:110px;height:110px;border-radius:50%;background:#ffffff29;box-shadow:0 0 40px #ffffff1a;animation:sealPulse 4s ease-in-out infinite}.about-seal span{position:relative;z-index:2;width:96px;height:96px;margin-bottom:20px;border-radius:50%;display:grid;place-items:center;color:var(--red);background:#fffffff0;font-family:SimSun,Songti SC,serif;font-size:48px;font-weight:800;transition:transform .24s ease,background .24s ease}.about-seal:hover span{transform:rotate(-8deg) scale(1.08)}.about-seal p{position:relative;z-index:2;margin:0;color:#ffffffd6;font-size:22px}.values-section{position:relative;overflow:hidden}.values-section:before{content:"";position:absolute;left:50%;top:58px;width:520px;height:180px;border-radius:50%;background:radial-gradient(circle,rgba(196,146,69,.09),transparent 68%);transform:translate(-50%)}.value-card{min-height:190px;position:relative;overflow:hidden}.value-card:after{content:"";position:absolute;left:-42%;top:0;width:36%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,.54),transparent);transform:skew(-18deg);transition:left .56s ease}.value-card:hover:after{left:112%}.value-icon{width:48px;height:48px;margin-bottom:18px;border-radius:14px;display:grid;place-items:center;color:var(--red);background:#f7e4dc;font-family:SimSun,Songti SC,serif;font-size:22px;font-weight:900;transition:transform .26s ease,background .26s ease,color .26s ease}.value-card:hover .value-icon{color:#fff;background:var(--red);transform:rotate(-6deg) scale(1.08)}.tilt-card{transform:perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));transition:transform .18s ease,box-shadow .24s ease,border-color .24s ease}.tilt-card:hover{--lift: -6px}@keyframes sealPulse{0%,to{opacity:.55;transform:scale(.92)}50%{opacity:.9;transform:scale(1.08)}}@media(max-width:720px){.hero-copy{padding-left:0}.hero-copy:before{display:none}}
diff --git a/dist/public/css/app.css b/dist/public/css/app.css
deleted file mode 100644
index 6786631..0000000
--- a/dist/public/css/app.css
+++ /dev/null
@@ -1 +0,0 @@
-.app-hero .container{min-height:500px;padding-top:74px;padding-bottom:74px}.hero-copy{position:relative;padding-left:28px}.hero-copy:before{content:"";position:absolute;left:0;top:58px;width:4px;height:132px;border-radius:999px;background:linear-gradient(180deg,var(--red),var(--gold))}.hero-buttons{display:flex;gap:16px;flex-wrap:wrap;margin-top:28px}.app-stats{display:flex;gap:12px;margin-top:24px;flex-wrap:wrap}.app-stats span{padding:10px 14px;border:1px solid rgba(224,211,189,.78);border-radius:999px;color:#6d766f;background:#fffdf8bd;box-shadow:0 14px 32px #4839260f;font-weight:800;transition:transform .22s ease,color .22s ease,background .22s ease}.app-stats span:hover{color:#fff;background:var(--green);transform:translateY(-3px)}.app-shot-wrap{position:relative;min-height:390px;display:flex;align-items:center;justify-content:center;gap:30px;overflow:hidden;background:radial-gradient(circle at 18% 20%,rgba(200,59,50,.12),transparent 24%),radial-gradient(circle at 80% 24%,rgba(71,111,99,.16),transparent 30%),linear-gradient(135deg,#f7efe2,#edf4ef)}.app-shot-wrap:before{content:"";position:absolute;inset:22px;border:1px solid rgba(224,211,189,.62);border-radius:22px;pointer-events:none}.app-orbit{position:absolute;right:64px;top:44px;width:96px;height:96px;border-radius:50%;background:#c492452e;animation:appOrbit 4.2s ease-in-out infinite}.phone-shot{position:relative;z-index:2;width:185px;height:380px;object-fit:cover;object-position:top center;border:8px solid #252b28;border-radius:28px;box-shadow:0 26px 60px #211c1633;transition:transform .3s ease,box-shadow .3s ease}.phone-shot.first{animation:phoneFloatA 4s ease-in-out infinite}.phone-shot.second{transform:translateY(28px);animation:phoneFloatB 4s ease-in-out infinite}.app-shot-wrap:hover .phone-shot{box-shadow:0 34px 70px #211c1642}.app-feature-section{position:relative;overflow:hidden}.app-feature-section:before{content:"";position:absolute;left:50%;top:58px;width:520px;height:180px;border-radius:50%;background:radial-gradient(circle,rgba(196,146,69,.09),transparent 68%);transform:translate(-50%)}.app-feature-card{min-height:190px;position:relative;overflow:hidden}.app-feature-card:after{content:"";position:absolute;left:-42%;top:0;width:36%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,.54),transparent);transform:skew(-18deg);transition:left .56s ease}.app-feature-card:hover:after{left:112%}.app-icon{width:48px;height:48px;margin-bottom:18px;border-radius:14px;display:grid;place-items:center;color:var(--red);background:#f7e4dc;font-family:SimSun,Songti SC,serif;font-size:22px;font-weight:900;transition:transform .26s ease,background .26s ease,color .26s ease}.app-feature-card:hover .app-icon{color:#fff;background:var(--red);transform:rotate(-6deg) scale(1.08)}.app-promotion-section{background:#fffdf8}.promotion-list{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:18px}.promotion-card{display:block;overflow:hidden;border:1px solid var(--line);border-radius:8px;background:#fffaf0;color:inherit;text-decoration:none;box-shadow:0 18px 42px #39302414;transition:transform .24s ease,border-color .24s ease,box-shadow .24s ease}.promotion-card:hover{border-color:#c492456b;box-shadow:0 24px 54px #3930241f;transform:translateY(-4px)}.promotion-card img{width:100%;aspect-ratio:16 / 9;object-fit:cover;display:block;background:#f3eadc}.promotion-card div{padding:18px}.promotion-card h3{margin-bottom:8px;color:var(--ink);font-size:22px}.promotion-card p{margin:0 0 12px;color:var(--muted);line-height:1.75}.promotion-card span{color:var(--red);font-weight:900}.tilt-card{transform:perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));transition:transform .18s ease,box-shadow .24s ease,border-color .24s ease}.tilt-card:hover{--lift: -6px}@keyframes phoneFloatA{0%,to{transform:translateY(0) rotate(-1deg)}50%{transform:translateY(-8px) rotate(1deg)}}@keyframes phoneFloatB{0%,to{transform:translateY(28px) rotate(1deg)}50%{transform:translateY(18px) rotate(-1deg)}}@keyframes appOrbit{0%,to{opacity:.5;transform:scale(.92)}50%{opacity:1;transform:scale(1.08)}}@media(max-width:720px){.hero-copy{padding-left:0}.hero-copy:before{display:none}.phone-shot.second{display:none}.promotion-list{grid-template-columns:1fr}}
diff --git a/dist/public/css/article-detail.css b/dist/public/css/article-detail.css
deleted file mode 100644
index 39605f6..0000000
--- a/dist/public/css/article-detail.css
+++ /dev/null
@@ -1 +0,0 @@
-.article-hero .container{min-height:440px;padding-top:74px;padding-bottom:74px}.hero-copy{position:relative;padding-left:28px}.hero-copy:before{content:"";position:absolute;left:0;top:58px;width:4px;height:132px;border-radius:999px;background:linear-gradient(180deg,var(--red),var(--gold))}.article-meta{display:flex;gap:12px;margin-top:28px;flex-wrap:wrap}.article-meta span{padding:10px 14px;border:1px solid rgba(224,211,189,.78);border-radius:999px;color:#6d766f;background:#fffdf8bd;font-weight:800}.article-cover-detail{position:relative;overflow:hidden;display:grid;place-items:center;text-align:center;color:#fff;background:radial-gradient(circle at 72% 24%,rgba(255,255,255,.35) 0 9%,transparent 10%),linear-gradient(135deg,#e7c89e,#b94135 48%,#143d57)}.article-cover-detail:after{content:"";position:absolute;left:-40%;top:0;width:34%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,.3),transparent);transform:skew(-18deg);transition:left .58s ease}.article-cover-detail:hover:after{left:112%}.article-cover-detail span{width:86px;height:86px;border-radius:50%;display:grid;place-items:center;color:var(--red);background:#fffdf8f0;font-family:SimSun,Songti SC,serif;font-size:44px;font-weight:800}.article-cover-detail p{margin:18px 0 0;color:#ffffffe6;font-size:22px}.article-layout{display:grid;grid-template-columns:minmax(0,820px) 300px;gap:28px;align-items:start}.article-content,.article-side{border:1px solid var(--line);border-radius:18px;background:#fffdf8d1;box-shadow:0 20px 54px #39302414}.article-content{padding:42px}.article-content p{color:#5f665f;font-size:18px;line-height:2}.article-content h2{margin-top:34px;font-size:32px}.article-side{position:sticky;top:108px;padding:24px}.article-side a{display:block;margin-top:12px;padding:14px 16px;border:1px solid var(--line);border-radius:14px;color:#6f4a37;background:#fbf7ed;transition:transform .22s ease,color .22s ease,background .22s ease}.article-side a:hover{color:#fff;background:var(--green);transform:translate(5px)}.tilt-card{transform:perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));transition:transform .18s ease,box-shadow .24s ease,border-color .24s ease}.tilt-card:hover{--lift: -6px}@media(max-width:980px){.article-layout{grid-template-columns:1fr}.article-side{position:static}}@media(max-width:720px){.hero-copy{padding-left:0}.hero-copy:before{display:none}.article-content{padding:28px}}
diff --git a/dist/public/css/create-genealogy.css b/dist/public/css/create-genealogy.css
deleted file mode 100644
index e3bec7f..0000000
--- a/dist/public/css/create-genealogy.css
+++ /dev/null
@@ -1 +0,0 @@
-.create-hero .container{min-height:440px;padding-top:74px;padding-bottom:74px}.hero-copy{position:relative;padding-left:28px}.hero-copy:before{content:"";position:absolute;left:0;top:58px;width:4px;height:132px;border-radius:999px;background:linear-gradient(180deg,var(--red),var(--gold))}.create-tags{display:flex;gap:12px;margin-top:28px;flex-wrap:wrap}.create-tags span{padding:10px 14px;border:1px solid rgba(224,211,189,.78);border-radius:999px;color:#6d766f;background:#fffdf8bd;box-shadow:0 14px 32px #4839260f;font-weight:800;transition:transform .22s ease,color .22s ease,background .22s ease}.create-tags span:hover{color:#fff;background:var(--green);transform:translateY(-3px)}.process-card{position:relative;overflow:hidden;display:grid;align-content:center}.process-card:before{content:"";position:absolute;inset:0;background:linear-gradient(rgba(196,146,69,.06) 1px,transparent 1px),linear-gradient(90deg,rgba(196,146,69,.06) 1px,transparent 1px);background-size:34px 34px;opacity:.72}.process-card h3,.process-card .step-list{position:relative;z-index:2}.process-orb{position:absolute;right:-70px;top:-80px;width:220px;height:220px;border-radius:50%;background:radial-gradient(circle,rgba(200,59,50,.13),transparent 62%);animation:createPulse 4s ease-in-out infinite}.step-list{display:grid;gap:16px;margin-top:18px}.step-list p{display:flex;gap:14px;align-items:center;margin:0;color:var(--muted);transition:transform .22s ease,color .22s ease}.step-list p:hover{color:var(--green-dark);transform:translate(6px)}.step-list b{width:38px;height:38px;border-radius:50%;display:grid;place-items:center;color:#fff;background:var(--green);flex:0 0 auto;box-shadow:0 12px 28px #476f632e;transition:transform .22s ease,background .22s ease}.step-list p:hover b{background:var(--red);transform:scale(1.08)}.create-form-section{position:relative;overflow:hidden}.create-form-section:before{content:"";position:absolute;left:50%;top:58px;width:520px;height:180px;border-radius:50%;background:radial-gradient(circle,rgba(196,146,69,.09),transparent 68%);transform:translate(-50%)}.create-form{max-width:720px;position:relative;overflow:hidden;padding:36px}.form-ornament{position:absolute;right:-82px;top:-88px;width:220px;height:220px;border-radius:50%;background:radial-gradient(circle,rgba(71,111,99,.12),transparent 66%)}.create-form h2,.create-form .form-note,.create-form .form-grid{position:relative;z-index:2}.form-note{margin-bottom:22px;color:var(--muted);line-height:1.8}.create-form .input,.create-form textarea{transition:border-color .22s ease,box-shadow .22s ease,background .22s ease,transform .22s ease}.create-form .field{display:grid;gap:8px;color:var(--ink);font-weight:800}.create-region-picker label{display:grid;gap:8px}.create-region-picker{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}.create-form .input:focus,.create-form textarea:focus{outline:none;border-color:#c83b329e;background:#fffdf8;box-shadow:0 0 0 4px #c83b3214;transform:translateY(-2px)}.submit-btn{width:100%}.tilt-card{transform:perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));transition:transform .18s ease,box-shadow .24s ease,border-color .24s ease}.tilt-card:hover{--lift: -6px}@keyframes createPulse{0%,to{opacity:.5;transform:scale(.92)}50%{opacity:1;transform:scale(1.08)}}@media(max-width:720px){.hero-copy{padding-left:0}.hero-copy:before{display:none}.create-region-picker{grid-template-columns:1fr}}
diff --git a/dist/public/css/culture.css b/dist/public/css/culture.css
deleted file mode 100644
index 91164f1..0000000
--- a/dist/public/css/culture.css
+++ /dev/null
@@ -1 +0,0 @@
-.culture-hero .container{min-height:440px;padding-top:74px;padding-bottom:74px}.hero-copy{position:relative;padding-left:28px}.hero-copy:before{content:"";position:absolute;left:0;top:58px;width:4px;height:132px;border-radius:999px;background:linear-gradient(180deg,var(--red),var(--gold))}.culture-stats{display:flex;gap:12px;margin-top:28px;flex-wrap:wrap}.culture-stats span{padding:10px 14px;border:1px solid rgba(224,211,189,.78);border-radius:999px;color:#6d766f;background:#fffdf8bd;box-shadow:0 14px 32px #4839260f;font-weight:800;transition:transform .22s ease,color .22s ease,background .22s ease}.culture-stats span:hover{color:#fff;background:var(--green);transform:translateY(-3px)}.culture-quote{position:relative;min-height:260px;overflow:hidden;display:flex;flex-direction:column;justify-content:center;color:#fff;background:linear-gradient(180deg,#213f382e,#213f38db),linear-gradient(135deg,#476f63,#c49245 50%,#c83b32)}.culture-quote:before{content:"";position:absolute;inset:0;background:linear-gradient(rgba(255,255,255,.08) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,.08) 1px,transparent 1px);background-size:34px 34px;opacity:.34}.quote-moon{position:absolute;right:72px;top:34px;width:92px;height:92px;border-radius:50%;background:#ffffff52;box-shadow:0 0 34px #ffffff1f;animation:moonFloat 4s ease-in-out infinite}.culture-quote span{position:relative;z-index:2;width:64px;height:64px;margin-bottom:24px;border-radius:50%;display:grid;place-items:center;color:var(--red);background:#fffffff0;font-family:SimSun,Songti SC,serif;font-size:30px;font-weight:800;transition:transform .24s ease,background .24s ease}.culture-quote:hover span{transform:rotate(-8deg) scale(1.08)}.culture-quote p{position:relative;z-index:2;margin:0;color:#ffffffdb;font-size:22px;line-height:1.7}.article-section{position:relative;overflow:hidden}.article-section:before{content:"";position:absolute;left:50%;top:58px;width:520px;height:180px;border-radius:50%;background:radial-gradient(circle,rgba(196,146,69,.09),transparent 68%);transform:translate(-50%)}.article-card{position:relative;overflow:hidden;border-radius:18px;background:#fff;border:1px solid var(--line);box-shadow:0 18px 48px #39302412;transition:transform .24s ease,box-shadow .24s ease,border-color .24s ease}.article-card:hover{border-color:#c492456b;box-shadow:0 24px 60px #3930241c}.article-cover{position:relative;height:190px;overflow:hidden;background:radial-gradient(circle at 74% 28%,rgba(255,255,255,.7) 0 8%,transparent 9%),linear-gradient(135deg,#e7c89e,#b94135 48%,#143d57)}.article-cover:after{content:"";position:absolute;left:-42%;top:0;width:36%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,.34),transparent);transform:skew(-18deg);transition:left .58s ease}.article-card:hover .article-cover:after{left:112%}.article-cover span{position:absolute;left:22px;bottom:20px;padding:7px 12px;border-radius:999px;color:var(--green-dark);background:#fffdf8db;font-weight:800;font-size:13px}.article-card:nth-child(2) .article-cover{background:linear-gradient(135deg,#dfd1b5,#6b7f70 48%,#26302c)}.article-card:nth-child(3) .article-cover{background:linear-gradient(135deg,#f0d8ac,#c49245 45%,#7d342d)}.article-body{padding:24px}.article-body h3{transition:color .22s ease}.article-card:hover .article-body h3{color:var(--red)}.article-body p{color:var(--muted);line-height:1.75}.article-body span{color:#9a8f82;font-size:14px}.tilt-card{transform:perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));transition:transform .18s ease,box-shadow .24s ease,border-color .24s ease}.tilt-card:hover{--lift: -6px}@keyframes moonFloat{0%,to{transform:translateY(0) scale(1);opacity:.72}50%{transform:translateY(-8px) scale(1.04);opacity:.92}}@media(max-width:720px){.hero-copy{padding-left:0}.hero-copy:before{display:none}}
diff --git a/dist/public/css/download.css b/dist/public/css/download.css
deleted file mode 100644
index 18e47e9..0000000
--- a/dist/public/css/download.css
+++ /dev/null
@@ -1 +0,0 @@
-.download-hero .container{min-height:440px;padding-top:74px;padding-bottom:74px}.hero-copy{position:relative;padding-left:28px}.hero-copy:before{content:"";position:absolute;left:0;top:58px;width:4px;height:132px;border-radius:999px;background:linear-gradient(180deg,var(--red),var(--gold))}.detail-actions{display:flex;gap:14px;margin-top:30px;flex-wrap:wrap}.qr-card{display:grid;place-items:center;text-align:center}.qr-box{width:170px;height:170px;padding:16px;border-radius:24px;background:linear-gradient(90deg,var(--green) 12px,transparent 12px) 0 0 / 32px 32px,linear-gradient(var(--green) 12px,transparent 12px) 0 0 / 32px 32px,#fffdf8;border:1px solid var(--line);display:grid;place-items:center;box-shadow:inset 0 0 0 12px #fffdf8}.qr-box span{width:62px;height:62px;border-radius:50%;display:grid;place-items:center;color:#fff;background:var(--red);font-weight:900}.qr-card p,.download-card p{color:var(--muted);line-height:1.8}.download-card{transition:transform .24s ease,border-color .24s ease,box-shadow .24s ease}.download-card:hover{border-color:#c492456b}.tilt-card{transform:perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));transition:transform .18s ease,box-shadow .24s ease,border-color .24s ease}.tilt-card:hover{--lift: -6px}@media(max-width:720px){.hero-copy{padding-left:0}.hero-copy:before{display:none}}
diff --git a/dist/public/css/family-detail.css b/dist/public/css/family-detail.css
deleted file mode 100644
index 3729875..0000000
--- a/dist/public/css/family-detail.css
+++ /dev/null
@@ -1 +0,0 @@
-.page-family-detail [data-family-detail].is-loading{opacity:.82}.detail-hero .container{min-height:440px;padding-top:74px;padding-bottom:74px}.hero-copy{position:relative;padding-left:28px}.hero-copy:before{content:"";position:absolute;left:0;top:58px;width:4px;height:132px;border-radius:999px;background:linear-gradient(180deg,var(--red),var(--gold))}.detail-actions{display:flex;gap:14px;margin-top:30px;flex-wrap:wrap}.family-summary{position:relative;overflow:hidden;display:grid;align-content:center;gap:24px;color:#fff;background:linear-gradient(180deg,#213f382e,#213f38e0),linear-gradient(135deg,#476f63,#c49245 52%,#8f4634)}.family-summary:before{content:"";position:absolute;inset:0;background:linear-gradient(rgba(255,255,255,.08) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,.08) 1px,transparent 1px);background-size:34px 34px;opacity:.38}.family-summary>*{position:relative;z-index:2}.summary-badge{width:fit-content;padding:8px 14px;border-radius:999px;color:var(--green-dark);background:#fffdf8e0;font-weight:800}.summary-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}.summary-grid span{min-height:84px;padding:16px;border-radius:16px;display:grid;place-items:center;background:#ffffff21;border:1px solid rgba(255,255,255,.18)}.summary-grid b{display:block;font-size:30px}.detail-layout{display:grid;grid-template-columns:330px 1fr;gap:26px;align-items:start}.detail-panel,.content-card,.mini-card{border:1px solid var(--line);border-radius:18px;background:#fffdf8c7;box-shadow:0 20px 54px #39302414}.detail-panel{padding:26px;position:sticky;top:108px}.detail-panel p,.content-card p,.mini-card p{color:var(--muted);line-height:1.8}.detail-main{display:grid;gap:24px}.content-card{padding:30px}.mini-card{min-height:170px;padding:24px;transition:transform .24s ease,border-color .24s ease,box-shadow .24s ease}.mini-card:hover{border-color:#c492456b;box-shadow:0 24px 60px #3930241c}.tilt-card{transform:perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));transition:transform .18s ease,box-shadow .24s ease,border-color .24s ease}.tilt-card:hover{--lift: -6px}@media(max-width:900px){.detail-layout{grid-template-columns:1fr}.detail-panel{position:static}.summary-grid{grid-template-columns:repeat(2,1fr)}}@media(max-width:720px){.hero-copy{padding-left:0}.hero-copy:before{display:none}}
diff --git a/dist/public/css/forgot-password.css b/dist/public/css/forgot-password.css
deleted file mode 100644
index 0c17892..0000000
--- a/dist/public/css/forgot-password.css
+++ /dev/null
@@ -1 +0,0 @@
-.recover-card{position:relative;overflow:hidden}.recover-card:before{content:"";position:absolute;right:-80px;top:-90px;width:220px;height:220px;border-radius:50%;background:radial-gradient(circle,rgba(200,59,50,.13),transparent 64%)}.recover-card>*{position:relative;z-index:2}@media(max-width:620px){.code-row{grid-template-columns:1fr}}
diff --git a/dist/public/css/genealogy.css b/dist/public/css/genealogy.css
deleted file mode 100644
index 1915d77..0000000
--- a/dist/public/css/genealogy.css
+++ /dev/null
@@ -1 +0,0 @@
-.page-genealogy{background:#fbf7ed}.genealogy-hero .container{min-height:470px;padding-top:76px;padding-bottom:76px}.hero-copy{position:relative;padding-left:28px}.hero-copy:before{content:"";position:absolute;left:0;top:58px;width:4px;height:136px;border-radius:999px;background:linear-gradient(180deg,var(--red),var(--gold))}.genealogy-stats{display:flex;gap:12px;margin-top:28px;padding:8px;border:1px solid rgba(224,211,189,.78);border-radius:18px;background:#fffdf8bd;box-shadow:0 16px 36px #48392612}.genealogy-stats div{min-width:118px;padding:12px 16px;border-radius:12px}.genealogy-stats div+div{border-left:1px solid rgba(218,201,174,.78)}.genealogy-stats strong{display:block;color:var(--green);font-size:24px;line-height:1.1}.genealogy-stats span{color:#6d766f;font-size:14px}.tree-preview{position:relative;min-height:300px;display:grid;gap:14px;align-content:center;overflow:hidden;background:linear-gradient(90deg,#fffdf8f2,#fffdf8c7),radial-gradient(circle at 78% 22%,rgba(196,146,69,.2),transparent 28%);transform-style:preserve-3d}.tree-glow{position:absolute;right:-70px;top:-80px;width:210px;height:210px;border-radius:50%;background:radial-gradient(circle,rgba(200,59,50,.13),transparent 62%);animation:treePulse 4.2s ease-in-out infinite}.tree-row{position:relative;z-index:2;display:flex;justify-content:center;gap:16px;flex-wrap:wrap}.tree-row span{min-width:110px;padding:14px 18px;border:1px solid #dac9ae;border-radius:14px;text-align:center;color:var(--green-dark);background:#fffaf1e6;box-shadow:0 12px 28px #4535230f;font-weight:800;transition:transform .24s ease,color .24s ease,background .24s ease,box-shadow .24s ease}.tree-preview:hover .tree-row span{animation:nodeFloat 1.9s ease-in-out infinite}.tree-row span:hover{color:#fff;background:var(--green);box-shadow:0 16px 32px #476f6338}.tree-row.branch span:nth-child(2){animation-delay:.08s}.tree-row.branch span:nth-child(3){animation-delay:.16s}.tree-row.generation span:nth-child(2){animation-delay:.08s}.tree-row.generation span:nth-child(3){animation-delay:.16s}.tree-row.generation span:nth-child(4){animation-delay:.24s}.tree-line{position:relative;z-index:1;width:min(360px,70%);height:1px;margin:0 auto;background:linear-gradient(90deg,transparent,rgba(196,146,69,.5),transparent)}.tree-line.short{width:min(500px,86%)}.capability-section{position:relative;overflow:hidden}.capability-section:before{content:"";position:absolute;left:50%;top:58px;width:520px;height:180px;border-radius:50%;background:radial-gradient(circle,rgba(196,146,69,.09),transparent 68%);transform:translate(-50%);pointer-events:none}.feature-card{min-height:210px;position:relative;overflow:hidden}.feature-card:after{content:"";position:absolute;left:-40%;top:0;width:36%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,.48),transparent);transform:skew(-18deg);transition:left .56s ease}.feature-card:hover:after{left:110%}.icon-word{width:48px;height:48px;margin-bottom:18px;border-radius:14px;display:grid;place-items:center;color:var(--red);background:#f7e4dc;font-size:22px;font-weight:900;transition:transform .26s ease,background .26s ease,color .26s ease}.feature-card:hover .icon-word{color:#fff;background:var(--red);transform:rotate(-6deg) scale(1.08)}.coedit-section{background:radial-gradient(circle at 18% 20%,rgba(200,59,50,.08),transparent 24%),#f7efe2}.coedit-card{min-height:260px;padding:34px}.coedit-card .btn{margin-top:12px}.process-card{min-height:260px;padding:34px}.step-list{display:grid;gap:16px;margin-top:20px}.step-list p{display:flex;gap:14px;align-items:center;margin:0;color:var(--muted)}.step-list b{width:38px;height:38px;border-radius:50%;display:grid;place-items:center;color:#fff;background:var(--green);flex:0 0 auto;box-shadow:0 12px 28px #476f632e}.tilt-card{transform:perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));transition:transform .18s ease,box-shadow .24s ease,border-color .24s ease}.tilt-card:hover{--lift: -6px}@keyframes nodeFloat{0%,to{transform:translateY(0)}50%{transform:translateY(-5px)}}@keyframes treePulse{0%,to{opacity:.5;transform:scale(.92)}50%{opacity:1;transform:scale(1.08)}}@media(max-width:720px){.hero-copy{padding-left:0}.hero-copy:before{display:none}.genealogy-stats{flex-direction:column}.genealogy-stats div+div{border-left:0;border-top:1px solid rgba(218,201,174,.78)}}
diff --git a/dist/public/css/help.css b/dist/public/css/help.css
deleted file mode 100644
index 9163ec0..0000000
--- a/dist/public/css/help.css
+++ /dev/null
@@ -1 +0,0 @@
-.help-hero .container{min-height:440px;padding-top:74px;padding-bottom:74px}.hero-copy{position:relative;padding-left:28px}.hero-copy:before{content:"";position:absolute;left:0;top:58px;width:4px;height:132px;border-radius:999px;background:linear-gradient(180deg,var(--red),var(--gold))}.help-tags{display:flex;gap:12px;margin-top:28px;flex-wrap:wrap}.help-tags span{padding:10px 14px;border:1px solid rgba(224,211,189,.78);border-radius:999px;color:#6d766f;background:#fffdf8bd;box-shadow:0 14px 32px #4839260f;font-weight:800;transition:transform .22s ease,color .22s ease,background .22s ease}.help-tags span:hover{color:#fff;background:var(--green);transform:translateY(-3px)}.help-card{position:relative;overflow:hidden;display:grid;align-content:center;gap:14px}.help-card:before{content:"";position:absolute;inset:0;background:linear-gradient(rgba(196,146,69,.06) 1px,transparent 1px),linear-gradient(90deg,rgba(196,146,69,.06) 1px,transparent 1px);background-size:34px 34px;opacity:.72}.help-card h3,.help-card p,.help-card .btn,.help-icon{position:relative;z-index:2}.help-orb{position:absolute;right:-70px;top:-80px;width:220px;height:220px;border-radius:50%;background:radial-gradient(circle,rgba(200,59,50,.13),transparent 62%);animation:helpPulse 4s ease-in-out infinite}.help-icon{width:52px;height:52px;border-radius:16px;display:grid;place-items:center;color:#fff;background:var(--green);font-size:26px;font-weight:900;box-shadow:0 14px 32px #476f6333;transition:transform .26s ease,background .26s ease}.help-card:hover .help-icon{background:var(--red);transform:rotate(-8deg) scale(1.08)}.faq-section{position:relative;overflow:hidden}.faq-section:before{content:"";position:absolute;left:50%;top:58px;width:520px;height:180px;border-radius:50%;background:radial-gradient(circle,rgba(196,146,69,.09),transparent 68%);transform:translate(-50%)}.faq-list{position:relative;max-width:880px;margin:0 auto;display:grid;gap:14px}.faq-list details{padding:22px 24px;border:1px solid var(--line);border-radius:18px;background:#fffdf8;box-shadow:0 12px 34px #3930240f;transition:transform .24s ease,box-shadow .24s ease,border-color .24s ease,background .24s ease}.faq-list.is-loading{min-height:220px}.faq-list details:hover,.faq-list details[open]{border-color:#c492456b;box-shadow:0 22px 54px #3930241a}.faq-list summary{position:relative;cursor:pointer;color:var(--ink);font-size:20px;font-weight:800;list-style:none;padding-left:34px}.faq-list summary::-webkit-details-marker{display:none}.faq-list summary:before{content:"";position:absolute;left:0;top:8px;width:0;height:0;border-top:7px solid transparent;border-bottom:7px solid transparent;border-left:10px solid var(--green-dark);transition:transform .24s ease,border-left-color .24s ease}.faq-list details[open] summary:before{border-left-color:var(--red);transform:rotate(90deg)}.faq-list p{margin:14px 0 0;padding-left:34px;color:var(--muted);line-height:1.8;animation:faqReveal .24s ease both}.tilt-card{transform:perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));transition:transform .18s ease,box-shadow .24s ease,border-color .24s ease}.tilt-card:hover{--lift: -6px}@keyframes helpPulse{0%,to{opacity:.5;transform:scale(.92)}50%{opacity:1;transform:scale(1.08)}}@keyframes faqReveal{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}@media(max-width:720px){.hero-copy{padding-left:0}.hero-copy:before{display:none}}
diff --git a/dist/public/css/index.css b/dist/public/css/index.css
deleted file mode 100644
index 9401c5e..0000000
--- a/dist/public/css/index.css
+++ /dev/null
@@ -1 +0,0 @@
-.company-bar{height:38px;border-bottom:1px solid #eadfce;color:var(--ink);background:#fffdf8}.company-bar .container{display:flex;align-items:center;height:100%;font-size:18px;font-weight:800;letter-spacing:.12em}.hero{position:relative;overflow:hidden;min-height:760px;background:radial-gradient(circle at 82% 12%,rgba(196,146,69,.16),transparent 24%),linear-gradient(125deg,#fffaf0,#f7efe2 48%,#edf4ef)}.hero:before{content:"";position:absolute;inset:0;background-image:linear-gradient(rgba(138,50,43,.05) 1px,transparent 1px),linear-gradient(90deg,rgba(138,50,43,.05) 1px,transparent 1px);background-size:68px 68px;mask-image:linear-gradient(90deg,transparent,#000 14%,#000 86%,transparent)}.hero-inner{position:relative;z-index:2;min-height:680px;display:grid;grid-template-columns:.76fr 1.24fr;align-items:center;gap:34px;padding:24px 0 76px}.eyebrow{display:inline-flex;align-items:center;gap:10px;margin-bottom:28px;color:#8a5a3b;font-weight:800}.eyebrow:before{content:"";width:42px;height:2px;background:var(--red)}h1{margin:0;color:var(--ink);font-family:SimSun,Songti SC,serif;font-size:56px;line-height:1.16;letter-spacing:0}.lead{max-width:560px;margin:22px 0 0;color:#645d52;font-size:18px;line-height:1.9}.hero-copy{position:relative;padding-top:10px}.hero-copy:before{content:"";position:absolute;left:-28px;top:48px;width:4px;height:156px;border-radius:999px;background:linear-gradient(180deg,var(--red),var(--gold))}.hero-title-mark{display:inline-block;position:relative;color:var(--red)}.hero-title-mark:after{content:"";position:absolute;left:0;right:0;bottom:7px;height:12px;background:#c83b321f;z-index:-1}.hero-path{display:flex;align-items:center;gap:10px;margin-top:26px;color:#766b5e;font-weight:800}.hero-path span{min-width:34px;height:34px;border-radius:50%;display:inline-grid;place-items:center;color:#fff;background:var(--green);font-size:14px}.hero-path i{width:34px;height:1px;background:#dac9ae}.hero-action-card{display:inline-flex;align-items:center;gap:18px;margin-top:30px;padding:14px 16px;border-radius:999px;background:#fffdf8b8;border:1px solid rgba(224,211,189,.86);box-shadow:0 18px 42px #48392614}.cta{display:flex;gap:16px;margin-top:0}.metrics{display:flex;align-items:stretch;max-width:560px;margin-top:22px;padding:8px;border-radius:18px;color:#6d766f;background:#fffdf8bd;border:1px solid rgba(224,211,189,.78);box-shadow:0 16px 36px #48392612}.metric{flex:1;min-width:0;min-height:76px;padding:12px 16px;border-radius:12px}.metric+.metric{border-left:1px solid rgba(218,201,174,.78)}.metric strong{display:block;margin-bottom:5px;color:var(--green);font-size:21px;line-height:1.18}.hero-visual{position:relative;min-height:650px;margin-left:-42px}.hero-showcase{position:absolute;inset:18px 18px 20px 0;display:grid;grid-template-columns:1.08fr .92fr;grid-template-rows:214px 1fr;gap:18px}.showcase-card{overflow:hidden;border-radius:24px;background:#fffdf8eb;border:1px solid rgba(224,211,189,.88);box-shadow:0 24px 70px #4535231f}.family-preview{grid-column:1 / 3;display:grid;grid-template-columns:170px 1fr 238px;align-items:center;gap:24px;padding:28px;background:linear-gradient(90deg,#fffdf8f2,#fffdf8c7),radial-gradient(circle at 78% 22%,rgba(196,146,69,.2),transparent 26%)}.preview-book{width:132px;height:158px;border-radius:12px;position:relative;background:linear-gradient(155deg,#143d57,#092d42);box-shadow:0 18px 42px #0b293d38}.preview-book:before{content:"汤氏\a家谱";white-space:pre;position:absolute;left:24px;top:24px;width:34px;padding:8px 3px;color:#1c302d;line-height:1.2;text-align:center;background:#fbf0d8;border:1px solid rgba(203,176,122,.9);font-weight:800;font-size:14px}.family-preview h3{margin:0 0 12px;font-size:28px}.family-preview p{max-width:430px;margin:0;color:var(--muted);line-height:1.8}.preview-stats{display:grid;grid-template-columns:repeat(2,1fr);gap:10px}.stat-pill{min-height:66px;padding:12px;border-radius:14px;background:#f7efe2;color:#716454}.stat-pill strong{display:block;color:var(--green);font-size:22px;line-height:1.1}.showcase-video{position:relative;display:block;min-height:286px;color:#fff;background:#213f38}.showcase-video img{width:100%;height:100%;min-height:286px;display:block;object-fit:cover;filter:saturate(.9)}.showcase-video:before{content:"";position:absolute;inset:0;background:linear-gradient(180deg,#14231f0d,#14231fc7)}.showcase-video .play{position:absolute;left:28px;bottom:84px;width:62px;height:62px;border-radius:50%;background:#fffffff0;box-shadow:0 12px 30px #0000002e}.showcase-video .play:after{content:"";position:absolute;left:25px;top:18px;width:0;height:0;border-top:13px solid transparent;border-bottom:13px solid transparent;border-left:20px solid var(--red)}.showcase-video h3,.showcase-video p{position:absolute;left:28px;right:28px;margin:0}.showcase-video h3{bottom:44px;font-size:26px}.showcase-video p{bottom:22px;color:#ffffffc7}.showcase-search{min-height:286px;padding:24px}.showcase-search h3{margin:0 0 16px;font-size:22px}.showcase-search .search-box{height:46px}.recommend-list{display:grid;gap:10px;margin-top:16px}.recommend-item{padding:13px 14px;border-radius:14px;background:#f8f1e5;color:#6d6357;line-height:1.55}.recommend-item strong{display:block;margin-bottom:4px;color:var(--ink);font-size:16px}.portal-card{position:absolute;inset:18px 18px 20px 0;overflow:hidden;border-radius:32px;background:#fffdf8eb;border:1px solid rgba(224,211,189,.88);box-shadow:0 34px 90px #45352321}.portal-cover{position:relative;height:250px;overflow:hidden;background:linear-gradient(180deg,#fffdf814,#1f3f37a8),radial-gradient(circle at 78% 18%,rgba(255,255,255,.55) 0 6%,transparent 7%),linear-gradient(135deg,#e9d1a1,#c4533f 45%,#173f52)}.portal-cover:before{content:"";position:absolute;left:50%;top:34px;width:390px;height:190px;transform:translate(-50%);background:linear-gradient(180deg,#f3d083 0 18%,#be4033 18% 70%,#8e3029 70% 100%);clip-path:polygon(2% 38%,20% 13%,80% 13%,98% 38%,88% 38%,88% 94%,12% 94%,12% 38%);filter:drop-shadow(0 18px 32px rgba(61,38,28,.2))}.portal-cover:after{content:"代代相传";position:absolute;left:34px;bottom:30px;color:#fffffff5;font-size:28px;font-weight:800}.portal-book{position:absolute;left:34px;top:34px;width:118px;height:164px;border-radius:12px;background:linear-gradient(155deg,#143d57,#092d42);box-shadow:0 20px 48px #0b293d42;z-index:2}.portal-book:before{content:"汤氏\a家谱";white-space:pre;position:absolute;left:18px;top:24px;width:32px;padding:8px 3px;color:#1c302d;line-height:1.2;text-align:center;background:#fbf0d8;border:1px solid rgba(203,176,122,.9);font-weight:800;font-size:14px}.portal-body{display:grid;grid-template-columns:1.18fr .82fr;gap:18px;padding:22px}.portal-box{min-height:198px;padding:22px;border-radius:20px;background:#fffaf1;border:1px solid #eadfce}.portal-box h3{margin:0 0 16px;font-size:22px}.portal-box p{margin:0;color:var(--muted);line-height:1.75}.portal-video{display:flex;flex-direction:column;justify-content:space-between;color:#fff;background:linear-gradient(180deg,#213f382e,#213f38db),radial-gradient(circle at 78% 24%,rgba(255,255,255,.46) 0 9%,transparent 10%),linear-gradient(135deg,#476f63,#c49245 50%,#c83b32);border-color:#ffffff47}.portal-video p{color:#ffffffc7}.play-line{display:flex;align-items:center;justify-content:space-between;gap:16px}.play-button{width:58px;height:58px;border-radius:50%;position:relative;flex:0 0 auto;background:#fffffff0;box-shadow:0 12px 28px #1e1e1e2e}.play-button:after{content:"";position:absolute;left:23px;top:17px;width:0;height:0;border-top:12px solid transparent;border-bottom:12px solid transparent;border-left:18px solid var(--red)}.public-list{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-top:16px}.public-item{min-height:66px;padding:9px 12px;border-radius:12px;background:#f5ecd9;color:#61584d;font-size:13px;line-height:1.55}.public-item strong{display:block;margin-bottom:4px;color:var(--ink);font-size:15px}.archive-stage{position:absolute;inset:14px 0 22px;border-radius:30px;background:linear-gradient(90deg,#ffffffd1,#ffffff8c),radial-gradient(circle at 78% 22%,rgba(180,51,42,.12),transparent 26%);border:1px solid rgba(196,146,69,.28);box-shadow:0 34px 90px #45352321}.book-cover{position:absolute;left:54px;top:44px;width:220px;height:310px;border-radius:18px;background:linear-gradient(155deg,#143d57,#092d42);box-shadow:0 28px 70px #13364c38}.book-cover:before{content:"张氏家谱";position:absolute;left:34px;top:34px;width:29px;padding:12px 4px;line-height:1.25;text-align:center;color:#1c302d;background:#fbf0d8;border:1px solid rgba(203,176,122,.9);font-weight:800}.hall{position:absolute;right:28px;top:34px;width:342px;height:198px;overflow:hidden;border-radius:22px;background:#fff8ec;border:1px solid rgba(224,211,189,.9);box-shadow:0 24px 60px #5d482d24}.hall:before{content:none}.hall:after{content:none}.hall img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center top}.word-scroll-card{display:flex;align-items:center;gap:16px;max-width:620px;margin-top:22px;padding:10px 0;border-radius:999px;color:#766b5e;overflow:hidden}.word-scroll-card:before{content:"";width:42px;height:2px;flex:0 0 auto;background:linear-gradient(90deg,var(--red),var(--gold))}.word-scroll-card:after{content:none}.word-scroll-label{color:#8b6c48;font-size:14px;font-weight:800}.word-window{flex:1;height:34px;overflow:hidden;mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent)}.word-track{display:flex;align-items:center;gap:24px;width:max-content;animation:wordMarquee 16s linear infinite}.word{height:34px;display:flex;align-items:center;color:var(--green-dark);font-family:SimSun,Songti SC,serif;font-size:24px;font-weight:800;line-height:1;white-space:nowrap}@keyframes wordMarquee{0%{transform:translate(0)}to{transform:translate(-50%)}}.video-card{position:absolute;right:28px;top:244px;width:342px;height:182px;overflow:hidden;border-radius:20px;color:#fff;background:linear-gradient(180deg,#1f3f371f,#192722d1),radial-gradient(circle at 78% 18%,rgba(255,255,255,.42) 0 8%,transparent 9%),linear-gradient(135deg,#476f63,#c49245 48%,#c83b32);box-shadow:0 22px 56px #2d37322e}.video-card:before{content:"";position:absolute;left:50%;top:50%;width:62px;height:62px;border-radius:50%;background:#ffffffeb;transform:translate(-50%,-50%);box-shadow:0 12px 28px #1e1e1e2e}.video-card:after{content:"";position:absolute;left:calc(50% - 8px);top:calc(50% - 14px);width:0;height:0;border-top:14px solid transparent;border-bottom:14px solid transparent;border-left:22px solid var(--red)}.video-card span{position:absolute;left:22px;bottom:20px;font-weight:800;font-size:20px}.video-card small{position:absolute;left:22px;bottom:50px;color:#ffffffc7;font-size:14px}.search-panel{position:absolute;left:68px;right:28px;top:440px;padding:18px 20px;border-radius:20px;background:#ffffffeb;border:1px solid rgba(224,211,189,.8);box-shadow:0 24px 70px #493b291f}.search-panel h3{margin:0 0 16px;font-size:22px}.search-box{display:flex;height:48px;overflow:hidden;border-radius:999px;border:1px solid #e2d4bf;background:#fbf8f1}.search-box span{flex:1;display:flex;align-items:center;padding-left:22px;color:#9c9488}.search-box b{width:118px;display:grid;place-items:center;color:#fff;background:var(--red)}.genealogy-list{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-top:14px}.genealogy-item{min-height:62px;padding:9px 12px;border-radius:12px;background:#f8f1e5;color:#61584d;font-size:14px;line-height:1.55}.genealogy-item strong{display:block;margin-bottom:5px;color:var(--ink);font-size:16px}.quick-strip{position:relative;z-index:3;margin-top:-58px}.quick-inner{display:grid;grid-template-columns:repeat(4,1fr);gap:18px}.quick-card{min-height:104px;padding:20px 24px;border-radius:12px;color:var(--ink);border:1px solid rgba(218,201,174,.72);background:radial-gradient(circle at 88% 18%,rgba(255,253,248,.66),transparent 30%),linear-gradient(135deg,#f6f1e7,#e9d8c6);box-shadow:0 18px 44px #242a2614}.quick-card:nth-child(2){background:radial-gradient(circle at 88% 18%,rgba(255,253,248,.64),transparent 30%),linear-gradient(135deg,#f2f5ed,#dbe8d2)}.quick-card:nth-child(3){background:radial-gradient(circle at 88% 18%,rgba(255,253,248,.64),transparent 30%),linear-gradient(135deg,#f8efe9,#ead0c7)}.quick-card:nth-child(4){background:radial-gradient(circle at 88% 18%,rgba(255,253,248,.66),transparent 30%),linear-gradient(135deg,#f4efe4,#e5d1aa)}.quick-card b{display:block;margin-bottom:10px;font-size:20px;color:var(--ink)}.quick-card span{color:var(--muted);line-height:1.7}section{padding:76px 0}.section-head{margin-bottom:34px;text-align:center}.section-head h2{margin:0;font-family:SimSun,Songti SC,serif;font-size:42px;line-height:1.25}.section-head p{margin:14px auto 0;max-width:680px;color:var(--muted);font-size:17px;line-height:1.9}.functions{background:#fffdf8;padding-bottom:0}.function-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:22px}.function-card{min-height:190px;padding:24px;border-radius:14px;background:#fbf7ed;border:1px solid #eee1cf;transition:transform .2s ease}.function-card:hover{transform:translateY(-4px)}.icon{width:46px;height:46px;margin-bottom:18px;border-radius:14px;display:grid;place-items:center;color:var(--red);background:#f7e4dc;font-size:22px;font-weight:900}.function-card h3{margin:0 0 12px;font-size:21px}.function-card p{margin:0;color:var(--muted);line-height:1.8}.plaza{background:linear-gradient(180deg,#fffdf8,#f8f0e4)}.plaza-layout{display:grid;grid-template-columns:1.05fr .95fr;gap:34px;align-items:stretch}.featured-family{min-height:430px;padding:34px;border-radius:22px;color:#fff;background:linear-gradient(180deg,#1c302d2e,#153733d6),linear-gradient(135deg,#476f63,#a95c3e);display:flex;flex-direction:column;justify-content:flex-end;box-shadow:0 24px 70px #2a413b26}.featured-family h3{margin:0 0 16px;font-size:34px}.featured-family p{max-width:560px;margin:0;color:#ffffffd1;line-height:1.9;font-size:17px}.family-cards{display:grid;gap:18px}.family-card{padding:22px;border-radius:18px;background:#fffdf8;border:1px solid #eadfce;box-shadow:0 16px 42px #39302412}.family-card h4{margin:0 0 8px;font-size:22px}.family-card p{margin:0 0 18px;color:var(--muted);line-height:1.7}.tag-row{display:flex;gap:10px;flex-wrap:wrap}.tag{padding:6px 12px;border-radius:999px;color:var(--green);background:#eaf0eb;font-size:14px;font-weight:700}.culture{background:#fffdf8}.article-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}.article-card{overflow:hidden;border-radius:18px;background:#fff;border:1px solid #eadfce;box-shadow:0 18px 48px #39302412}.article-cover{height:190px;background:radial-gradient(circle at 74% 28%,rgba(255,255,255,.7) 0 8%,transparent 9%),linear-gradient(135deg,#e7c89e,#b94135 48%,#143d57)}.article-card:nth-child(2) .article-cover{background:linear-gradient(135deg,#dfd1b5,#6b7f70 48%,#26302c)}.article-card:nth-child(3) .article-cover{background:linear-gradient(135deg,#f0d8ac,#c49245 45%,#7d342d)}.article-body{padding:24px}.article-body h3{margin:0 0 12px;font-size:22px;line-height:1.45}.article-body p{margin:0 0 20px;color:var(--muted);line-height:1.75}.article-meta{color:#9a8f82;font-size:14px}.ad-slots{background:linear-gradient(180deg,#fffdf8,#f8f0e4);padding:0}.ad-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:16px;align-items:start}.ad-card{position:relative;display:block;aspect-ratio:2.8 / 1;padding:8px;border-radius:12px;overflow:hidden;border:1px solid rgba(224,211,189,.84);background:#fffdf8;box-shadow:0 12px 30px #3930240f}.ad-card img{display:block;width:100%;height:100%;object-fit:contain;transition:transform .32s ease}.ad-card:hover img{transform:scale(1.025)}.surname{background:radial-gradient(circle at 12% 20%,rgba(200,59,50,.09),transparent 24%),#f8f0e4}.surname-panel{display:grid;grid-template-columns:360px 1fr;gap:34px;padding:30px;border-radius:24px;background:#ffffffb3;border:1px solid rgba(224,211,189,.8);box-shadow:0 24px 70px #39302414}.surname-intro{padding:30px;border-radius:18px;color:#fff;background:linear-gradient(155deg,var(--green-dark),var(--green))}.surname-intro h2{margin:0 0 16px;font-family:SimSun,Songti SC,serif;font-size:38px}.surname-intro p{color:#ffffffc7;line-height:1.9}.surname-grid{display:grid;grid-template-columns:repeat(8,1fr);gap:10px;align-content:start}.surname-name{height:62px;border-radius:12px;display:grid;place-items:center;color:#7c4a33;background:#fbf7ed;border:1px solid #eadfce;font-size:24px;font-family:SimSun,Songti SC,serif;font-weight:800;transition:transform .24s ease,color .24s ease,background .24s ease,border-color .24s ease,box-shadow .24s ease;will-change:transform}.surname-name:hover{color:#fff;background:var(--red);border-color:#c83b32b8;box-shadow:0 16px 34px #c83b322e;transform:translateY(-6px) scale(1.03)}.surname-panel:hover .surname-name{animation:surnameFloat 1.9s ease-in-out infinite}.surname-panel:hover .surname-name:nth-child(2n){animation-delay:.08s}.surname-panel:hover .surname-name:nth-child(3n){animation-delay:.14s}.surname-panel:hover .surname-name:nth-child(4n){animation-delay:.2s}@keyframes surnameFloat{0%,to{transform:translateY(0)}50%{transform:translateY(-4px)}}.download,.recommend{background:#fffdf8}.recommend-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:18px}.recommend-card{min-height:184px;padding:22px;border-radius:14px;border:1px solid rgba(224,211,189,.84);background:linear-gradient(180deg,#fffdf8,#fbf7ed);box-shadow:0 18px 48px #39302412}.recommend-card span{display:inline-flex;margin-bottom:18px;padding:6px 12px;border-radius:999px;color:var(--green);background:#eaf0eb;font-size:13px;font-weight:900}.recommend-card h3{margin:0 0 12px;font-size:24px;line-height:1.35}.recommend-card p{margin:0;color:var(--muted);line-height:1.8}.friend-links{padding:0;background:#fffdf8}.friend-links-panel{display:flex;align-items:center;gap:24px;padding:24px 28px;border-radius:18px;border:1px solid rgba(224,211,189,.84);background:#fbf7ed}.friend-links-panel h2{flex:0 0 auto;margin:0;font-family:SimSun,Songti SC,serif;font-size:30px}.friend-link-list{display:flex;flex-wrap:wrap;gap:10px}.friend-link-list a{padding:8px 14px;border-radius:999px;color:#5e665f;background:#ffffffc2;border:1px solid rgba(224,211,189,.78);transition:color .22s ease,border-color .22s ease,transform .22s ease}.friend-link-list a:hover{color:var(--red);border-color:#c83b3252;transform:translateY(-2px)}.download-panel{display:grid;grid-template-columns:1fr 380px;gap:56px;align-items:center;padding:44px;border-radius:28px;background:radial-gradient(circle at 82% 30%,rgba(200,59,50,.12),transparent 28%),linear-gradient(135deg,#f7efe2,#edf4ef);border:1px solid #eadfce}.download-panel h2{margin:0;font-family:SimSun,Songti SC,serif;font-size:42px}.download-panel p{margin:18px 0 30px;color:var(--muted);font-size:18px;line-height:1.9}.qr-wrap{display:grid;grid-template-columns:repeat(2,1fr);gap:18px}.qr{min-height:190px;padding:18px;border-radius:18px;text-align:center;background:#ffffffc7;border:1px solid #eadfce}.qr-box{width:112px;height:112px;margin:0 auto 14px;background:linear-gradient(90deg,#26302c 10px,transparent 10px) 0 0 / 22px 22px,linear-gradient(#26302c 10px,transparent 10px) 0 0 / 22px 22px,#fff;border:10px solid #fff;box-shadow:inset 0 0 0 1px #ddd}@media(max-width:1120px){.nav-links{display:none}.hero-inner,.plaza-layout,.surname-panel,.download-panel{grid-template-columns:1fr}.function-grid,.quick-inner{grid-template-columns:repeat(2,1fr)}.article-grid,.recommend-grid{grid-template-columns:1fr}.friend-links-panel{align-items:flex-start;flex-direction:column}}.qr-note{margin:8px 0 0;color:var(--muted)}@media(hover:hover)and (pointer:fine){.quick-card,.function-card,.family-card,.article-card,.ad-card,.surname-panel,.recommend-card,.download-panel{cursor:pointer}}.quick-card,.function-card,.family-card,.article-card,.ad-card,.surname-panel,.recommend-card,.download-panel{transition:transform .24s ease,box-shadow .24s ease,border-color .24s ease,background .24s ease,color .22s ease;will-change:transform}.quick-card:hover,.function-card:hover,.family-card:hover,.article-card:hover,.ad-card:hover,.recommend-card:hover{border-color:#c492456b;box-shadow:0 24px 60px #3930241c}.function-card{position:relative;overflow:hidden}.function-card:after{content:"";position:absolute;left:-42%;top:0;width:36%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,.54),transparent);transform:skew(-18deg);transition:left .56s ease}.function-card:hover:after{left:112%}.function-card:hover .icon{color:#fff;background:var(--red);transform:rotate(-6deg) scale(1.08)}.icon{transition:transform .26s ease,background .26s ease,color .26s ease}.tilt-card{transform:perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));transition:transform .18s ease,box-shadow .24s ease,border-color .24s ease;will-change:transform}.tilt-card:hover{--lift: -6px}.magnetic{will-change:transform}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;scroll-behavior:auto!important;transition-duration:.01ms!important}}@media(max-width:720px){.hero{min-height:0}.hero-inner{min-height:0;gap:28px;padding:36px 0 48px}.hero-copy{min-width:0;padding-top:0}.hero-copy:before{content:none}h1{font-size:42px}.lead{font-size:16px;line-height:1.75}.hero-path{gap:7px;font-size:13px}.hero-path i{width:16px}.hero-action-card,.cta,.cta .btn{width:100%}.hero-action-card{padding:12px;border-radius:18px}.cta{display:grid;grid-template-columns:1fr;gap:10px}.cta .btn{justify-content:center}.metrics{display:grid;grid-template-columns:1fr}.metric+.metric{border-top:1px solid rgba(218,201,174,.78);border-left:0}.hero-visual{min-width:0;min-height:0;display:grid;gap:14px;margin-left:0}.archive-stage,.book-cover{display:none}.hall,.video-card,.search-panel{width:calc(100dvw - 28px);max-width:100%;position:relative;inset:auto}.hall{height:auto;aspect-ratio:16 / 9}.video-card{height:174px}.search-panel{padding:16px}.search-box{width:100%}.word-scroll-card,.word-window{min-width:0;max-width:100%}.search-box span{min-width:0;overflow:hidden;padding-left:14px;text-overflow:ellipsis;white-space:nowrap}.search-box b{width:76px;flex:0 0 76px}.genealogy-list,.function-grid,.quick-inner,.qr-wrap{grid-template-columns:1fr}section{padding:52px 0}.section-head h2,.download-panel h2{font-size:34px}.surname-panel{gap:18px;padding:16px}.surname-intro{padding:22px}.surname-grid{grid-template-columns:repeat(4,minmax(0,1fr));gap:8px}.surname-name{height:54px}.download-panel{gap:28px;padding:24px}}
diff --git a/dist/public/css/join-genealogy.css b/dist/public/css/join-genealogy.css
deleted file mode 100644
index f5fa96e..0000000
--- a/dist/public/css/join-genealogy.css
+++ /dev/null
@@ -1 +0,0 @@
-.page-join-genealogy .auth-card{width:min(1080px,100%)}.join-page-grid{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(340px,.85fr);gap:28px;align-items:start}.join-search-panel,.join-apply-form{display:grid;gap:16px}.join-page-grid .field{display:grid;gap:10px}.join-page-grid .field>span{color:var(--ink);font-weight:900}.join-page-grid .field input,.join-page-grid .field textarea{width:100%;min-height:48px;padding:12px 14px;border:1px solid var(--line);border-radius:8px;background:#fffdf8;color:var(--ink);font:inherit;outline:none;transition:border-color .2s ease,box-shadow .2s ease}.join-page-grid .field textarea{min-height:128px;resize:vertical}.join-page-grid .field input:focus,.join-page-grid .field textarea:focus{border-color:#c83b3273;box-shadow:0 0 0 4px #c83b3214}.join-search-panel{padding-right:28px;border-right:1px solid var(--line)}.join-page-grid h2{margin:0;font-size:22px}.join-page-grid .module-list{max-height:420px;overflow:auto}@media(max-width:800px){.page-join-genealogy .auth-card{width:min(500px,100%)}.join-page-grid{grid-template-columns:1fr}.join-search-panel{padding-right:0;padding-bottom:24px;border-right:0;border-bottom:1px solid var(--line)}}.invite-box{padding:14px;border:1px dashed var(--gold);border-radius:22px;background:#fffaf1}.page-join-genealogy textarea.input{min-height:112px;resize:vertical}
diff --git a/dist/public/css/login.css b/dist/public/css/login.css
deleted file mode 100644
index db7081c..0000000
--- a/dist/public/css/login.css
+++ /dev/null
@@ -1 +0,0 @@
-.page-login .auth-card{width:min(440px,100%)}.login-mode-tabs{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:4px;margin:18px 0;padding:4px;border:1px solid rgba(200,59,50,.16);border-radius:999px;background:#fffaf1e0;box-shadow:inset 0 1px #ffffffc7}.login-mode-tab{min-height:42px;border:0;border-radius:999px;background:transparent;color:var(--muted);font:inherit;font-weight:800;text-align:center;cursor:pointer;transition:color .22s ease,background .22s ease,box-shadow .22s ease}.login-mode-tab.is-active{background:#c83b321c;color:var(--red);box-shadow:inset 0 0 0 1px #c83b3229,0 8px 18px #8a402a14}.login-mode-panel[hidden]{display:none}.page-login .code-row{display:grid;grid-template-columns:minmax(0,1fr) 124px;gap:10px}.page-login .auth-links{margin-top:14px}@media(max-width:720px){.page-login .auth-layout{align-items:start}}@media(max-width:620px){.page-login .code-row{grid-template-columns:1fr}}
diff --git a/dist/public/css/notice-detail.css b/dist/public/css/notice-detail.css
deleted file mode 100644
index 291cf72..0000000
--- a/dist/public/css/notice-detail.css
+++ /dev/null
@@ -1 +0,0 @@
-.notice-hero .container{min-height:420px;padding-top:74px;padding-bottom:74px}.hero-copy{position:relative;padding-left:28px}.hero-copy:before{content:"";position:absolute;left:0;top:58px;width:4px;height:132px;border-radius:999px;background:linear-gradient(180deg,var(--red),var(--gold))}.article-meta{display:flex;gap:12px;margin-top:28px;flex-wrap:wrap}.article-meta span{padding:10px 14px;border:1px solid rgba(224,211,189,.78);border-radius:999px;color:#6d766f;background:#fffdf8bd;font-weight:800}.notice-card{display:grid;place-items:center;text-align:center;color:#fff;background:linear-gradient(145deg,var(--green-dark),var(--green))}.notice-card span{width:88px;height:88px;border-radius:50%;display:grid;place-items:center;color:var(--red);background:#fffdf8f0;font-family:SimSun,Songti SC,serif;font-size:42px;font-weight:900}.notice-card p{margin:18px 0 0;color:#ffffffe0;font-size:22px}.notice-layout{display:grid;grid-template-columns:minmax(0,820px) 300px;gap:28px;align-items:start}.notice-content,.notice-side{border:1px solid var(--line);border-radius:18px;background:#fffdf8d1;box-shadow:0 20px 54px #39302414}.notice-content{padding:42px}.notice-content p{color:#5f665f;font-size:18px;line-height:2}.notice-side{padding:24px}.notice-side a{display:block;margin-top:12px;padding:14px 16px;border:1px solid var(--line);border-radius:14px;color:#6f4a37;background:#fbf7ed;transition:transform .22s ease,color .22s ease,background .22s ease}.notice-side a:hover{color:#fff;background:var(--green);transform:translate(5px)}.tilt-card{transform:perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));transition:transform .18s ease,box-shadow .24s ease,border-color .24s ease}.tilt-card:hover{--lift: -6px}@media(max-width:900px){.notice-layout{grid-template-columns:1fr}}@media(max-width:720px){.hero-copy{padding-left:0}.hero-copy:before{display:none}}
diff --git a/dist/public/css/plaza.css b/dist/public/css/plaza.css
deleted file mode 100644
index ae4b99d..0000000
--- a/dist/public/css/plaza.css
+++ /dev/null
@@ -1 +0,0 @@
-.plaza-hero .container{min-height:440px;padding-top:74px;padding-bottom:74px}.hero-copy{position:relative;padding-left:28px}.hero-copy:before{content:"";position:absolute;left:0;top:58px;width:4px;height:132px;border-radius:999px;background:linear-gradient(180deg,var(--red),var(--gold))}.plaza-stats{display:flex;gap:12px;margin-top:28px;flex-wrap:wrap}.plaza-stats span{padding:12px 16px;border:1px solid rgba(224,211,189,.78);border-radius:16px;color:#6d766f;background:#fffdf8bd;box-shadow:0 14px 32px #4839260f}.plaza-stats b{margin-right:6px;color:var(--green);font-size:22px}.search-card{position:relative;display:grid;gap:20px;align-content:center;overflow:hidden}.search-card h3{position:relative;z-index:2}.search-ornament{position:absolute;right:-70px;top:-84px;width:220px;height:220px;border-radius:50%;background:radial-gradient(circle,rgba(200,59,50,.13),transparent 62%);animation:plazaPulse 4s ease-in-out infinite}.search-toolbar{position:relative;z-index:2;padding:8px;border:1px solid rgba(224,211,189,.78);border-radius:999px;background:#fffaf1d1}.search-card .input{flex:1 1 280px;border:0;background:transparent}.search-card .tag-row{position:relative;z-index:2}.family-card.featured{min-height:300px;position:relative;overflow:hidden;display:flex;flex-direction:column;justify-content:flex-end;color:#fff;background:linear-gradient(180deg,#1c302d2e,#153733d6),linear-gradient(135deg,#476f63,#a95c3e);border-radius:18px;padding:28px;box-shadow:0 22px 58px #2a413b29}.family-card.featured:before{content:"";position:absolute;inset:0;background:linear-gradient(rgba(255,255,255,.08) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,.08) 1px,transparent 1px);background-size:34px 34px;opacity:.45}.family-card.featured h3,.family-card.featured p,.family-card.featured .tag-row,.family-badge{position:relative;z-index:2}.family-card.featured p{color:#ffffffd1}.family-badge{width:fit-content;margin-bottom:auto;padding:7px 12px;border-radius:999px;color:var(--green-dark);background:#fffdf8db;font-weight:800;font-size:13px}.family-card-shine{position:absolute;left:-40%;top:0;width:34%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,.28),transparent);transform:skew(-18deg);transition:left .6s ease}.family-card.featured:hover .family-card-shine{left:112%}.family-lite{min-height:300px;position:relative;overflow:hidden}.family-lite:after{content:"";position:absolute;right:-60px;bottom:-70px;width:170px;height:170px;border-radius:50%;background:radial-gradient(circle,rgba(196,146,69,.13),transparent 68%);transition:transform .28s ease,opacity .28s ease}.family-lite:hover:after{transform:scale(1.25);opacity:.8}.family-icon{width:52px;height:52px;margin-bottom:24px;border-radius:16px;display:grid;place-items:center;color:var(--red);background:#f7e4dc;font-family:SimSun,Songti SC,serif;font-size:26px;font-weight:800;transition:transform .26s ease,background .26s ease,color .26s ease}.family-lite:hover .family-icon{color:#fff;background:var(--red);transform:rotate(-6deg) scale(1.08)}.tag{transition:transform .22s ease,color .22s ease,background .22s ease}.tag:hover{color:#fff;background:var(--green);transform:translateY(-2px)}.tilt-card{transform:perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));transition:transform .18s ease,box-shadow .24s ease,border-color .24s ease}.tilt-card:hover{--lift: -6px}@keyframes plazaPulse{0%,to{opacity:.5;transform:scale(.92)}50%{opacity:1;transform:scale(1.08)}}@media(max-width:720px){.hero-copy{padding-left:0}.hero-copy:before{display:none}.search-toolbar{border-radius:18px}}
diff --git a/dist/public/css/profile-module.css b/dist/public/css/profile-module.css
deleted file mode 100644
index ccf45e7..0000000
--- a/dist/public/css/profile-module.css
+++ /dev/null
@@ -1 +0,0 @@
-.page-profile-module{background:#f8f4ec}.module-hero{position:relative;overflow:hidden;min-height:257px;box-sizing:border-box;padding:58px 0 42px;background:radial-gradient(circle at 76% 18%,rgba(196,146,69,.16),transparent 25%),linear-gradient(125deg,#fffaf0,#f5eadb 52%,#eaf2ee)}.module-hero:before{content:"";position:absolute;inset:0;background-image:linear-gradient(rgba(138,50,43,.05) 1px,transparent 1px),linear-gradient(90deg,rgba(138,50,43,.05) 1px,transparent 1px);background-size:64px 64px;mask-image:linear-gradient(90deg,transparent,#000 14%,#000 86%,transparent)}.module-hero .container{position:relative;z-index:2}.module-kicker{width:fit-content;margin-bottom:18px;padding:8px 14px;border-radius:999px;color:var(--red);background:#f8e5dfeb;font-weight:900}.module-title-row{display:flex;justify-content:space-between;gap:22px;align-items:flex-end}.module-title-row h1{margin-bottom:12px;font-size:48px}.module-title-row p{max-width:780px;margin:0;color:#636c65;font-size:17px;line-height:1.9}.module-layout{display:grid;grid-template-columns:280px minmax(0,1fr);gap:24px;align-items:start}.module-nav,.module-panel,.module-card{border:1px solid rgba(224,211,189,.86);border-radius:18px;background:#fffdf8e0;box-shadow:0 22px 58px #39302414}.module-nav{position:sticky;top:106px;display:grid;gap:8px;max-height:calc(100vh - 126px);overflow-y:auto;padding:16px}.page-profile-module .module-nav:not([data-workspace-navigation]){visibility:hidden}.module-nav a{padding:14px 16px;border-radius:14px;color:#5e665f;font-weight:900;transition:transform .22s ease,color .22s ease,background .22s ease}.module-nav a:hover,.module-nav a.active{color:var(--red);background:#f8e5df;transform:translate(4px)}.workspace-nav-group{border:1px solid transparent;border-radius:14px}.workspace-nav-group[open]{border-color:#e0d3bdb8;background:#fffaf2b8}.workspace-nav-group summary{padding:14px 16px;border-radius:14px;color:#5e665f;font-weight:900;cursor:pointer;transition:color .22s ease,background .22s ease}.workspace-nav-group summary:hover,.workspace-nav-group.is-open>summary{color:var(--red);background:#fbefea}.workspace-nav-group summary:focus-visible,.module-nav a:focus-visible{outline:3px solid rgba(200,59,50,.32);outline-offset:2px}.workspace-nav-items{display:grid;gap:4px;padding:2px 8px 8px 18px}.module-nav .workspace-nav-items a{padding:10px 12px;font-size:14px;font-weight:800}.module-main{display:grid;gap:20px;min-width:0}.feature-status-banner{padding:18px 20px;border:1px solid rgba(196,146,69,.38);border-radius:16px;color:#6b542d;background:#fff8e8;box-shadow:0 12px 26px #59421a12}.feature-status-banner strong{color:var(--red);font-size:16px}.feature-status-banner p{margin:6px 0 0;color:inherit;line-height:1.75}.module-panel{padding:28px}.rich-editor-host{overflow:hidden;border:1px solid var(--line);border-radius:12px;background:var(--white)}.rich-editor-toolbar{border-bottom:1px solid var(--line)}.rich-editor-content{height:320px}.module-panel h2{margin-bottom:10px;font-family:SimSun,Songti SC,serif;font-size:32px}.module-panel>p{color:var(--muted);line-height:1.85}.module-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:18px}.module-grid.two{grid-template-columns:repeat(2,minmax(0,1fr))}.module-card{position:relative;overflow:hidden;min-height:170px;padding:22px;transition:transform .22s ease,border-color .22s ease,box-shadow .22s ease}.module-action-card{width:100%;text-align:left;cursor:pointer;font:inherit}.notification-row.is-unread{border-color:#c83b3247;background:#fff7f2}.join-apply-row{align-items:center}.join-apply-row .bottom-actions{justify-content:flex-end}.generation-row{align-items:center}[data-generation-management][hidden],[data-lineage-management][hidden],[data-lineage-spouse-field][hidden],[data-lineage-pagination][hidden],[data-video-management][hidden]{display:none!important}.generation-row .pill{border:0;cursor:pointer;font:inherit}.lineage-row{width:100%;text-align:left;cursor:pointer;font:inherit}.lineage-row.is-selected{border-color:#c83b3261;background:#fff6f1}.lineage-toolbar{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:12px;margin-bottom:16px}.lineage-filter-toolbar{grid-template-columns:minmax(220px,1fr) minmax(140px,.5fr) minmax(140px,.5fr) auto}.lineage-toolbar input,.lineage-toolbar select{min-height:46px;padding:12px 14px;border:1px solid var(--line);border-radius:8px;background:#fffdf8;color:var(--ink);font:inherit;outline:none}.lineage-tree-wrap{overflow-x:auto;padding:18px;border:1px solid var(--line);border-radius:8px;background:#fffdf8}.lineage-tree-wrap.is-compact{max-height:420px}.lineage-tree,.lineage-tree ul{display:grid;gap:12px;margin:0;padding-left:24px;list-style:none}.lineage-tree{padding-left:0}.lineage-node{min-width:168px;padding:12px 14px;border:1px solid rgba(224,211,189,.86);border-radius:8px;background:#fff7f2;color:var(--ink);text-align:left;cursor:pointer;font:inherit}.lineage-node strong,.lineage-node span{display:block}.lineage-node span{margin-top:4px;color:var(--muted);font-size:13px}.member-admin-row{align-items:center}.row-actions{display:flex;gap:10px;flex-wrap:wrap;justify-content:flex-end;margin-top:16px}.row-actions button.pill{border:0;font:inherit;cursor:pointer}.row-actions .pill:focus-visible{outline:3px solid rgba(200,59,50,.28);outline-offset:2px}.module-panel h2[tabindex="-1"]{scroll-margin-top:96px;outline:none}.pill.is-danger{color:#8a322b;background:#fde8e2}.ceremony-invitation-row .pill{border:0;cursor:pointer;font:inherit}.ceremony-invitation-row .pill:disabled{cursor:wait;opacity:.58}.invitation-detail b{overflow-wrap:anywhere}.invitation-detail .pill{display:inline-block;margin-left:8px;font-size:13px}.video-row .pill,.video-detail+.bottom-actions button{border:0;cursor:pointer;font:inherit}.article-row,.feed-row{align-items:center}.feed-row small{display:block;margin-top:6px;color:var(--muted)}.album-row,.album-photo-row{align-items:center}.album-photo-form{margin-top:18px}.upload-control{width:fit-content;min-height:42px;display:inline-flex;align-items:center;justify-content:center;margin-top:10px;padding:10px 14px;border-radius:8px;color:var(--red);background:#f8e5df;font-weight:900;cursor:pointer}.editor-field .upload-input{position:absolute;width:1px;height:1px;min-height:0;margin:-1px;padding:0;border:0;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}.upload-status{margin:8px 0 0;color:var(--muted);font-size:14px}.ceremony-row,.ceremony-gift-row,.merit-row{align-items:center}.ceremony-gift-form{margin-top:18px}.growth-row,.memo-row{align-items:center}.vip-package-list{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px;margin:18px 0}.vip-package-card{min-height:188px;padding:20px;border:1px solid rgba(224,211,189,.86);border-radius:8px;background:#fffdf8;color:var(--ink);text-align:left;cursor:pointer;font:inherit;transition:border-color .22s ease,box-shadow .22s ease,transform .22s ease}.vip-package-card:hover,.vip-package-card.is-selected{border-color:#c83b327a;box-shadow:0 18px 42px #3930241a;transform:translateY(-2px)}.vip-package-name,.vip-package-card strong,.vip-package-card small{display:block}.vip-package-name{margin-bottom:12px;color:var(--red);font-weight:900}.vip-package-card strong{margin-bottom:6px;font-size:30px}.vip-package-card small{color:var(--muted)}.vip-package-card p{margin:14px 0 0;color:var(--muted);line-height:1.7}.vip-order-form{margin-top:20px}.vip-order-row{align-items:center}.security-form{margin-top:16px;max-width:880px}.security-danger{border-left:4px solid #a13b32;border-color:#8a322b47;background:#fff7f2}.security-danger h2{color:#7e2d27}.security-danger .editor-field input,.security-danger .editor-field textarea{background:#fffdf8}.region-profile-form{margin-top:16px}.profile-region-picker{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}.profile-region-picker>label{display:grid;gap:6px}.profile-region-picker select{min-height:48px;padding:12px 14px;border:1px solid var(--line);border-radius:8px;background:#fffdf8;color:var(--ink);font:inherit;outline:none}.profile-create-family-form{margin-top:16px}.module-card:hover{border-color:#c492456b;box-shadow:0 24px 60px #3930241c}.module-card.is-unavailable{cursor:not-allowed;opacity:.68}.module-card.is-unavailable:after{display:none}.module-card.is-unavailable .pill{display:inline-flex;margin-top:12px;color:#6b542d;background:#fff0cf}.module-nav-unavailable{padding:14px 16px;border-radius:14px;color:var(--muted);background:#f4f1eb;font-weight:900}.profile-path{display:flex;align-items:center;gap:8px;margin:0 0 18px;color:#6f766f;font-size:14px;font-weight:800}.profile-path a{color:var(--red)}.profile-path a:hover{text-decoration:underline}.profile-path span{color:#a89f91}.profile-path strong{min-width:0;overflow:hidden;color:var(--ink);text-overflow:ellipsis;white-space:nowrap}.module-nav-unavailable small{display:block;margin-top:4px;color:#8a5a3b;font-size:12px;font-weight:700}.module-card.is-selected{border-color:#c83b3280;background:#fff6f1;box-shadow:0 24px 60px #c83b321f}.module-card:after{content:"";position:absolute;inset:0 auto 0 -42%;width:34%;background:linear-gradient(90deg,transparent,rgba(255,255,255,.52),transparent);transform:skew(-18deg);transition:left .54s ease}.module-card:hover:after{left:112%}.module-card .icon{width:46px;height:46px;margin-bottom:18px;border-radius:14px;display:grid;place-items:center;color:var(--red);background:#f8e5df;font-weight:900}.module-card h3{margin-bottom:8px;font-size:23px}.module-card p{color:var(--muted);line-height:1.75}.module-list{display:grid;gap:14px}.notification-raw{margin:0;padding:16px;overflow-wrap:anywhere;white-space:pre-wrap;border:1px solid var(--line);border-radius:15px;background:#fffdf8;color:var(--ink);line-height:1.6}.module-row{display:grid;grid-template-columns:1fr auto;gap:16px;align-items:center;padding:18px 20px;border:1px solid var(--line);border-radius:15px;background:#fffdf8}.module-row h3{margin-bottom:4px;font-size:22px}.module-row p{margin:0;color:var(--muted)}.pill{padding:7px 12px;border-radius:999px;color:var(--red);background:#f8e5df;font-weight:900;white-space:nowrap}.form-like{display:grid;overflow:hidden;border:1px solid var(--line);border-radius:16px;background:#fffdf8}.form-like p{display:grid;grid-template-columns:170px 1fr auto;gap:16px;margin:0;padding:18px 20px;border-bottom:1px solid var(--line);align-items:center}.form-like p:last-child{border-bottom:0}.form-like span{color:var(--muted)}.form-like b{color:var(--ink)}.bottom-actions{display:flex;gap:14px;flex-wrap:wrap;margin-top:16px}.editor-form>.bottom-actions,.editor-field>.bottom-actions,.editor-two .bottom-actions,.module-list>.row-actions,.module-row>.row-actions{margin-top:0}.editor-form{display:grid;gap:18px}.profile-data-form{margin-top:14px}.editor-field{display:grid;gap:10px}.editor-field label,.editor-label{color:var(--ink);font-weight:900}.field-required{color:var(--red)}.editor-field input,.editor-field select,.editor-field textarea{width:100%;min-height:48px;padding:12px 14px;border:1px solid var(--line);border-radius:8px;background:#fffdf8;color:var(--ink);font:inherit;outline:none;transition:border-color .2s ease,box-shadow .2s ease}.editor-field textarea{min-height:160px;resize:vertical}.editor-field input:focus,.editor-field select:focus,.editor-field textarea:focus{border-color:#c83b3273;box-shadow:0 0 0 4px #c83b3214}.editor-two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px;align-items:start}.editor-field>.btn{width:fit-content}.profile-form-actions{align-items:center}.form-status{color:var(--muted);font-weight:800}[data-growth-editor][hidden],[data-growth-editor-action][hidden],[data-relative-editor][hidden],[data-relative-editor-action][hidden],[data-memo-editor][hidden],[data-memo-editor-action][hidden],[data-merit-editor][hidden],[data-merit-editor-action][hidden]{display:none!important}.generation-batch-form{margin-top:14px}.generation-batch-check{display:flex;gap:10px;align-items:center;color:var(--muted);font-weight:800}.generation-batch-check input{width:18px;height:18px;accent-color:var(--red)}.generation-batch-actions{align-items:center}.generation-batch-preview{margin-top:18px}.upload-box{min-height:136px;border:1px dashed rgba(138,50,43,.28);border-radius:8px;display:grid;place-items:center;color:var(--red);background:#fff8f2;font-weight:900;cursor:pointer}.switch-row{display:flex;gap:18px;flex-wrap:wrap;align-items:center}.tilt-card{transform:perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));transition:transform .18s ease,box-shadow .24s ease,border-color .24s ease}.tilt-card:hover{--lift: -5px}@media(max-width:1060px){.module-layout,.module-grid,.module-grid.two,.vip-package-list{grid-template-columns:1fr}.module-nav{position:static;grid-template-columns:repeat(2,minmax(0,1fr));max-height:none;overflow:visible}.lineage-filter-toolbar{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:720px){.module-hero{min-height:0}.page-profile-module .module-nav{display:none}.module-title-row{display:grid}.module-title-row h1{font-size:38px}.lineage-filter-toolbar,.form-like p,.module-row,.editor-two,.profile-region-picker{grid-template-columns:1fr}}.page-profile-module{background:var(--color-canvas)}.page-profile-module .nav{height:72px}.page-profile-module .section{padding:var(--space-7) 0}.module-hero{height:168px;min-height:168px;padding:var(--space-5) 0}.lineage-current-toolbar{margin-bottom:var(--space-4)}.lineage-current-toolbar label{flex:0 0 auto;font-weight:800}.module-kicker{margin-bottom:var(--space-3);padding:6px 11px}.module-title-row h1{margin-bottom:var(--space-2);font-size:var(--text-2xl);line-height:1.18}.module-title-row p{font-size:var(--text-body-lg);line-height:1.75}.module-layout{grid-template-columns:248px minmax(0,1fr);gap:var(--space-5)}.module-nav,.module-panel,.module-card{border-radius:var(--radius-lg);box-shadow:var(--shadow-panel)}.module-nav{top:88px;gap:var(--space-2);max-height:calc(100vh - 108px);padding:var(--space-3);scrollbar-width:thin;scrollbar-color:rgba(171,65,54,.34) transparent}.module-nav::-webkit-scrollbar{width:6px}.module-nav::-webkit-scrollbar-thumb{border-radius:999px;background:#ab413657}.module-nav::-webkit-scrollbar-track{background:transparent}.module-nav a,.workspace-nav-group summary{padding:11px 13px;border-radius:var(--radius-md)}.module-nav a:hover,.module-nav a.active{transform:translate(2px)}.module-main{gap:var(--space-4)}.module-panel{padding:var(--space-5)}.module-panel h2{font-size:var(--text-title)}.module-grid{gap:var(--space-4)}.module-card{min-height:144px;padding:var(--space-4)}.module-card:after{content:none}.module-card h3,.module-row h3{font-size:var(--text-heading)}.module-row{gap:var(--space-4);padding:var(--space-4);border-radius:var(--radius-md)}.module-row[data-join-genealogy-id]>span:first-child{display:grid;gap:var(--space-1);text-align:left}.module-row[data-join-genealogy-id] small{color:var(--text-muted);font-weight:500}.form-like{border-radius:var(--radius-md)}.form-like p{grid-template-columns:132px minmax(0,1fr) auto;gap:var(--space-4);padding:14px var(--space-4)}.module-row>.media-frame,.album-photo-row>.media-frame{width:152px;aspect-ratio:4 / 3}.family-cover-media,.article-cover-media,.album-cover-media,.ceremony-cover-media,.video-detail-media{margin-bottom:var(--space-4);aspect-ratio:16 / 7}.family-cover-media img,.article-cover-media img,.album-cover-media img,.ceremony-cover-media img,.video-detail-media video{aspect-ratio:16 / 7}:is(.article-cover-media,.album-cover-media,.ceremony-cover-media) img{object-fit:contain}.video-detail-media video{object-fit:contain}.lineage-row{grid-template-columns:auto minmax(0,1fr) auto}.lineage-node{display:grid;grid-template-columns:auto minmax(0,1fr);column-gap:var(--space-2)}.lineage-node>.media-avatar{grid-row:1 / 3}@media(max-width:1060px){.module-layout{grid-template-columns:1fr}.module-nav{grid-template-columns:repeat(3,minmax(0,1fr))}}@media(max-width:720px){.module-hero{height:auto;padding:var(--space-5) 0 var(--space-4)}.module-title-row h1{font-size:var(--text-title)}.module-panel{padding:var(--space-4)}.module-row>.media-frame,.album-photo-row>.media-frame{width:100%}.form-like p,.module-row{grid-template-columns:1fr}.row-actions{justify-content:flex-start}.row-actions .pill{display:inline-flex;min-height:44px;padding:10px 14px;align-items:center;justify-content:center}.bottom-actions .form-status{flex-basis:100%}}
diff --git a/dist/public/css/profile.css b/dist/public/css/profile.css
deleted file mode 100644
index 925fa64..0000000
--- a/dist/public/css/profile.css
+++ /dev/null
@@ -1 +0,0 @@
-.page-profile{background:#f8f4ec}.profile-hero{position:relative;overflow:hidden;padding:62px 0 34px;background:radial-gradient(circle at 78% 12%,rgba(196,146,69,.18),transparent 25%),linear-gradient(125deg,#fffaf0,#f4eadb 48%,#eaf2ee)}.profile-hero:before{content:"";position:absolute;inset:0;background-image:linear-gradient(rgba(138,50,43,.05) 1px,transparent 1px),linear-gradient(90deg,rgba(138,50,43,.05) 1px,transparent 1px);background-size:64px 64px;mask-image:linear-gradient(90deg,transparent,#000 14%,#000 86%,transparent)}.profile-hero-grid{position:relative;z-index:2;display:grid;grid-template-columns:minmax(0,1fr) 420px;gap:24px;align-items:stretch}.profile-card,.profile-stats,.profile-next-card,.panel,.side-card{border:1px solid rgba(224,211,189,.84);border-radius:18px;background:#fffdf8db;box-shadow:0 22px 58px #39302414}.profile-card{display:grid;grid-template-columns:116px 1fr;gap:28px;padding:34px;align-items:center}.avatar-wrap{position:relative;width:108px;height:108px}.avatar{width:108px;height:108px;border-radius:28px;display:grid;place-items:center;color:#fff;background:radial-gradient(circle at 30% 24%,rgba(255,255,255,.38),transparent 24%),linear-gradient(145deg,var(--red),#ee8d60 52%,var(--green));font-family:SimSun,Songti SC,serif;font-size:46px;font-weight:900;box-shadow:0 18px 40px #c83b322e}.avatar-wrap span{position:absolute;right:-4px;bottom:-4px;width:28px;height:28px;border:5px solid #fffdf8;border-radius:50%;background:#31bf6b}.profile-info h1{margin-bottom:12px;font-size:44px}.profile-info p{max-width:720px;color:#636c65;font-size:17px;line-height:1.9}.profile-info .profile-load-status{margin:14px 0 0;color:var(--muted);font-size:14px;font-weight:800}.profile-info .profile-load-status:empty{display:none}.profile-tags,.mini-actions{display:flex;flex-wrap:wrap;gap:10px}.mini-actions{margin-top:12px}.profile-tags span,.mini-actions span{padding:7px 12px;border-radius:999px;color:var(--red);background:#f8e5df;font-size:14px;font-weight:800}.profile-stats{display:grid;grid-template-columns:repeat(2,1fr);padding:22px;gap:14px}.profile-next-card{padding:32px}.profile-next-card .eyebrow{margin-bottom:14px}.profile-next-card h2{margin-bottom:12px;font-size:30px}.profile-next-card p{margin-bottom:22px;color:var(--muted);line-height:1.8}.profile-hero-actions{margin-top:22px}.profile-stats div{min-height:116px;padding:20px;border-radius:14px;display:grid;align-content:center;background:#f7efe2b8}.profile-stats strong{color:var(--green);font-size:34px;line-height:1}.profile-stats span,.panel-head p,.data-list span,.todo-list span,.family-card p,.feature-tile p,.content-tile p{color:var(--muted);line-height:1.75}.dashboard-section{padding-top:42px}.dashboard-layout{display:grid;grid-template-columns:300px minmax(0,1fr);gap:24px;align-items:start}.dashboard-side{position:sticky;top:106px;display:grid;gap:20px}.side-card,.panel{padding:26px}.side-card h2,.panel h2{margin-bottom:8px;font-family:SimSun,Songti SC,serif;font-size:30px}.user-actions{display:grid;gap:10px}.user-actions a,.user-actions button,.todo-list a{display:block;width:100%;padding:15px 16px;border:1px solid var(--line);border-radius:14px;background:#fbf7ed;color:inherit;font:inherit;text-align:left;cursor:pointer;transition:transform .22s ease,border-color .22s ease,background .22s ease,color .22s ease}.user-actions a:hover,.user-actions button:hover,.todo-list a:hover{transform:translate(5px);border-color:#476f6347;background:#eef4ef}.user-actions span,.todo-list b{display:block;color:var(--ink);font-weight:900}.user-actions b{display:block;margin-top:4px;color:var(--muted);font-size:13px}.logout-link span{color:var(--red)}.card-head,.panel-head{display:flex;align-items:flex-start;justify-content:space-between;gap:18px;margin-bottom:22px}.card-head span{padding:6px 11px;border-radius:999px;color:#fff;background:var(--red);font-weight:800}.todo-list,.dashboard-main{display:grid;gap:18px}.panel-head.compact{margin-bottom:18px}.panel-head h2{margin-bottom:6px}.family-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:18px}.family-card{display:grid;grid-template-columns:112px 1fr;gap:20px;min-height:190px;padding:20px;border:1px solid var(--line);border-radius:16px;background:#fffdf8;transition:transform .22s ease,border-color .22s ease,box-shadow .22s ease}.family-card:hover,.feature-tile:hover,.content-tile:hover{border-color:#c492456b;box-shadow:0 22px 52px #3930241a}.book-cover{min-height:150px;border-radius:10px;display:grid;place-items:center;color:#fffdf8;background:linear-gradient(90deg,transparent calc(100% - 16px),rgba(255,255,255,.7) calc(100% - 15px),transparent calc(100% - 14px)),linear-gradient(135deg,#0f405c,#092c42);font-family:SimSun,Songti SC,serif;font-size:22px;line-height:1.7;text-align:center;box-shadow:inset -12px 0 #ffffff14}.book-cover.alt{background:linear-gradient(90deg,transparent calc(100% - 16px),rgba(255,255,255,.7) calc(100% - 15px),transparent calc(100% - 14px)),linear-gradient(135deg,#173c35,#785f35)}.family-card h3,.feature-tile h3,.content-tile h3{margin-bottom:8px;font-size:24px}.feature-grid,.content-grid,.service-grid{display:grid;gap:16px}.management-grid{grid-template-columns:repeat(3,minmax(0,1fr))}.feature-tile,.content-tile{position:relative;overflow:hidden;min-height:170px;padding:22px;border:1px solid var(--line);border-radius:16px;background:#fffdf8;transition:transform .22s ease,border-color .22s ease,box-shadow .22s ease}.feature-tile span,.content-tile span{width:48px;height:48px;margin-bottom:18px;border-radius:14px;display:grid;place-items:center;color:var(--red);background:#f7e4dc;font-weight:900}.feature-tile:after,.content-tile:after{content:"";position:absolute;inset:0 auto 0 -42%;width:34%;background:linear-gradient(90deg,transparent,rgba(255,255,255,.52),transparent);transform:skew(-18deg);transition:left .54s ease}.feature-tile:hover:after,.content-tile:hover:after{left:112%}.content-grid{grid-template-columns:repeat(4,minmax(0,1fr))}.content-tile.large{grid-column:span 2;color:#fff;background:linear-gradient(145deg,var(--green-dark),var(--green))}.content-tile.large p,.content-tile.large h3{color:#ffffffdb}.content-tile.large span{color:var(--green-dark);background:#fffdf8e6}.profile-data-layout{display:grid;grid-template-columns:1.15fr .85fr;gap:18px}.link-btn{flex:0 0 auto;padding:9px 14px;border-radius:999px;color:var(--red);background:#f8e5df;font-weight:900}.data-list{display:grid;border-top:1px solid var(--line)}.data-list p{display:grid;grid-template-columns:150px 1fr;gap:16px;margin:0;padding:16px 0;border-bottom:1px solid var(--line)}.data-list b{color:var(--ink)}.service-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.service-grid a{min-height:88px;padding:18px;border-radius:14px;display:grid;place-items:center;color:#6f4a37;background:#fbf7ed;border:1px solid var(--line);font-weight:900;transition:transform .22s ease,color .22s ease,background .22s ease}.service-grid a:hover{color:#fff;background:var(--green);transform:translateY(-3px)}.service-grid strong,.service-grid span{display:block;text-align:center}.service-grid strong{font-size:17px}.service-grid span{color:var(--muted);font-size:13px;line-height:1.55}.service-grid a:hover span{color:#fffc}.tilt-card{transform:perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));transition:transform .18s ease,box-shadow .24s ease,border-color .24s ease}.tilt-card:hover{--lift: -5px}.logout-modal{position:fixed;inset:0;z-index:80;display:grid;place-items:center;padding:24px;opacity:0;pointer-events:none;transition:opacity .22s ease}.logout-modal[hidden]{display:none}.logout-modal.show{opacity:1;pointer-events:auto}.logout-modal-backdrop{position:absolute;inset:0;background:#20232275;backdrop-filter:blur(10px)}.logout-dialog{position:relative;z-index:1;width:min(420px,100%);padding:34px;border-radius:8px;background:#fff;box-shadow:0 28px 80px #3d49443d;text-align:center;transform:translateY(12px) scale(.98);transition:transform .22s ease}.logout-modal.show .logout-dialog{transform:translateY(0) scale(1)}.logout-close{position:absolute;top:14px;right:14px;width:34px;height:34px;border:0;border-radius:50%;background:#f4f1eb;color:#7f786f;font-size:24px;line-height:1;cursor:pointer;transition:transform .2s ease,background .2s ease,color .2s ease}.logout-close:hover{transform:rotate(90deg);background:var(--red-soft);color:var(--red)}.logout-icon{display:inline-grid;place-items:center;width:58px;height:58px;border-radius:50%;margin-bottom:16px;background:var(--red-soft);color:var(--red);font-weight:800}.logout-dialog h2{margin:0 0 10px;font-size:24px;color:var(--ink)}.logout-dialog p{margin:0;color:var(--muted);line-height:1.8}.logout-actions{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:26px}.logout-actions .btn{justify-content:center}.logout-modal-open{overflow:hidden}@media(max-width:1120px){.profile-hero-grid,.dashboard-layout,.profile-data-layout{grid-template-columns:1fr}.dashboard-side{position:static;grid-template-columns:repeat(2,minmax(0,1fr))}.content-grid,.management-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:760px){.profile-hero{padding-top:36px}.profile-card{grid-template-columns:1fr;padding:24px}.profile-info h1{font-size:36px}.profile-stats,.dashboard-side,.family-grid,.content-grid,.management-grid,.service-grid{grid-template-columns:1fr}.family-card{grid-template-columns:88px 1fr}.book-cover{min-height:120px;font-size:18px}.content-tile.large{grid-column:span 1}.panel-head,.card-head{display:grid}.data-list p{grid-template-columns:1fr;gap:4px}.logout-dialog{padding:30px 22px}.logout-actions{grid-template-columns:1fr}}.page-profile{background:var(--color-canvas)}.profile-hero{padding:var(--space-7) 0 var(--space-6)}.profile-card,.profile-stats,.profile-next-card,.panel,.side-card{border-radius:var(--radius-lg);box-shadow:var(--shadow-panel)}.profile-info h1{font-size:var(--text-display)}.avatar .media-avatar,.avatar .media-avatar img{width:100%;height:100%;border-radius:inherit}.avatar .media-avatar{color:#fff;background:transparent;font:inherit}@media(max-width:760px){.profile-hero{padding:var(--space-5) 0 var(--space-4)}.profile-info h1{font-size:var(--text-title)}}
diff --git a/dist/public/css/promo-album.css b/dist/public/css/promo-album.css
deleted file mode 100644
index f68cc12..0000000
--- a/dist/public/css/promo-album.css
+++ /dev/null
@@ -1 +0,0 @@
-.promo-hero .container{min-height:440px;padding-top:74px;padding-bottom:74px}.hero-copy{position:relative;padding-left:28px}.hero-copy:before{content:"";position:absolute;left:0;top:58px;width:4px;height:132px;border-radius:999px;background:linear-gradient(180deg,var(--red),var(--gold))}.promo-tags{display:flex;gap:12px;margin-top:28px;flex-wrap:wrap}.promo-tags span{padding:10px 14px;border:1px solid rgba(224,211,189,.78);border-radius:999px;color:#6d766f;background:#fffdf8bd;font-weight:800;transition:transform .22s ease,color .22s ease,background .22s ease}.promo-tags span:hover{color:#fff;background:var(--green);transform:translateY(-3px)}.album-preview{display:grid;grid-template-columns:1.2fr 1fr;grid-template-rows:repeat(2,130px);gap:14px;overflow:hidden}.album-photo{border-radius:18px;background:radial-gradient(circle at 72% 24%,rgba(255,255,255,.75) 0 8%,transparent 9%),linear-gradient(135deg,#e7c89e,#b94135 48%,#143d57);box-shadow:0 16px 36px #39302414;transition:transform .26s ease}.album-photo.large{grid-row:1 / 3;background:linear-gradient(180deg,#1c302d1a,#153733b8),url(../images/ancestral-hall.png) center/cover}.album-photo.warm{background:linear-gradient(135deg,#f0d8ac,#c49245 45%,#7d342d)}.album-photo.green{background:linear-gradient(135deg,#dfd1b5,#6b7f70 48%,#26302c)}.album-preview:hover .album-photo{transform:scale(1.025)}.album-card{min-height:180px;position:relative;overflow:hidden}.album-card:after{content:"";position:absolute;left:-42%;top:0;width:36%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,.54),transparent);transform:skew(-18deg);transition:left .56s ease}.album-card:hover:after{left:112%}.tilt-card{transform:perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));transition:transform .18s ease,box-shadow .24s ease,border-color .24s ease}.tilt-card:hover{--lift: -6px}@media(max-width:720px){.hero-copy{padding-left:0}.hero-copy:before{display:none}.album-preview{grid-template-columns:1fr;grid-template-rows:repeat(4,120px)}.album-photo.large{grid-row:auto}}
diff --git a/dist/public/css/promo-video.css b/dist/public/css/promo-video.css
deleted file mode 100644
index 38c1993..0000000
--- a/dist/public/css/promo-video.css
+++ /dev/null
@@ -1 +0,0 @@
-.promo-hero .container{min-height:440px;padding-top:74px;padding-bottom:74px}.hero-copy{position:relative;padding-left:28px}.hero-copy:before{content:"";position:absolute;left:0;top:58px;width:4px;height:132px;border-radius:999px;background:linear-gradient(180deg,var(--red),var(--gold))}.promo-tags{display:flex;gap:12px;margin-top:28px;flex-wrap:wrap}.promo-tags span{padding:10px 14px;border:1px solid rgba(224,211,189,.78);border-radius:999px;color:#6d766f;background:#fffdf8bd;font-weight:800;transition:transform .22s ease,color .22s ease,background .22s ease}.promo-tags span:hover{color:#fff;background:var(--green);transform:translateY(-3px)}.video-preview{min-height:300px;position:relative;overflow:hidden;display:flex;flex-direction:column;justify-content:flex-end;color:#fff;background:linear-gradient(180deg,#1f3f371a,#192722db),url(../images/ancestral-hall.png) center/cover}.video-preview:before{content:"";position:absolute;inset:0;background:linear-gradient(rgba(255,255,255,.08) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,.08) 1px,transparent 1px);background-size:34px 34px;opacity:.35}.video-preview h3,.video-preview p,.play-button{position:relative;z-index:2}.video-preview p{color:#fffc}.play-button{width:64px;height:64px;margin-bottom:46px;border-radius:50%;background:#fffffff0;box-shadow:0 14px 34px #0003;transition:transform .24s ease}.play-button:after{content:"";position:absolute;left:26px;top:19px;border-top:13px solid transparent;border-bottom:13px solid transparent;border-left:20px solid var(--red)}.video-preview:hover .play-button{transform:scale(1.08)}.video-card{min-height:180px;position:relative;overflow:hidden}.video-card:after{content:"";position:absolute;left:-42%;top:0;width:36%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,.54),transparent);transform:skew(-18deg);transition:left .56s ease}.video-card:hover:after{left:112%}.tilt-card{transform:perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));transition:transform .18s ease,box-shadow .24s ease,border-color .24s ease}.tilt-card:hover{--lift: -6px}@media(max-width:720px){.hero-copy{padding-left:0}.hero-copy:before{display:none}}
diff --git a/dist/public/css/public.css b/dist/public/css/public.css
deleted file mode 100644
index bd15ff6..0000000
--- a/dist/public/css/public.css
+++ /dev/null
@@ -1 +0,0 @@
-@import"../../tokens.css";:root{--red: var(--color-accent);--red-soft: var(--color-accent-soft);--green: var(--color-green);--green-dark: var(--color-ink);--gold: var(--color-gold);--ink: var(--color-ink);--muted: var(--color-ink-2);--paper: var(--color-paper);--paper-2: var(--color-paper-2);--line: var(--color-rule);--white: var(--color-panel);--shadow: var(--shadow-card)}.auth-layer-message{min-width:160px;border-radius:999px!important;background:#26302cf0!important;box-shadow:0 16px 42px #26302c3d!important}.auth-layer-message .layui-layer-content{padding:10px 18px!important;color:#fffdf8!important;font-size:14px;font-weight:800;line-height:1.6;text-align:center}*{box-sizing:border-box}html,body{overflow-x:clip}html{scrollbar-gutter:stable}body{margin:0;color:var(--ink);font-family:var(--font-body);background:var(--paper)}a{color:inherit;text-decoration:none}img{max-width:100%;display:block}@media(hover:hover)and (pointer:fine){a,.btn,.card,button,summary{cursor:pointer}}.container{width:min(var(--layout-max),calc(100% - 72px));margin:0 auto}.site-header{position:sticky;top:0;z-index:20;background:linear-gradient(115deg,#6e2620f5,#c83b32f5 48%,#8b3427f5);border-bottom:1px solid rgba(255,253,248,.2);box-shadow:0 4px #5d1e1a33,0 18px 38px #53201a57,0 30px 70px #53201a38;backdrop-filter:blur(18px)}.nav{height:82px;display:flex;align-items:center;justify-content:space-between;gap:28px}.brand{display:flex!important;align-items:center;gap:12px;padding:8px 14px;border-radius:999px;background:#fffdf8eb;box-shadow:0 10px 28px #3f1c162e;font-size:24px;font-weight:800;white-space:nowrap}.brand-logo{display:block;width:270px;height:auto}.footer .brand-logo{width:270px}.auth-page-brand .brand-logo{width:220px}.brand-logo-mark{width:48px;height:48px}.brand-text{color:var(--ink);font-weight:900}.brand-mark{width:40px;height:40px;border-radius:50%;display:grid;place-items:center;color:#fff;background:var(--red);box-shadow:0 10px 24px #c83b3238;font-weight:800}.nav-links{display:flex;align-items:center;gap:26px;color:#fffdf8;font-size:15px;white-space:nowrap}.nav-links a.active,.nav-links a:hover{color:#fff7d8}.nav-links a,.nav-actions a{color:inherit;position:relative;transition:color .22s ease,transform .22s ease}.nav-links a:after{content:"";position:absolute;left:0;right:0;bottom:-10px;height:2px;border-radius:999px;background:linear-gradient(90deg,#f5d99b,#fff3c8);transform:scaleX(0);transform-origin:center;transition:transform .24s ease}.nav-links a.active:after,.nav-links a:hover:after{transform:scaleX(1)}.nav-actions{display:flex;align-items:center;gap:14px;color:#fffdf8;font-size:15px;white-space:nowrap}.nav-user-entry{min-width:0;display:inline-flex;align-items:center;gap:8px;font-weight:700}.nav-user-avatar{width:32px;height:32px;position:relative;flex:0 0 auto;display:inline-grid;place-items:center;overflow:hidden;border:1px solid rgba(255,248,230,.56);border-radius:50%;color:var(--red-deep);background:#fff4dc;font-size:13px;font-weight:900}.nav-user-avatar img{width:100%;height:100%;position:relative;z-index:1;object-fit:cover}.nav-user-avatar-fallback{position:absolute;inset:0;display:grid;place-items:center}.nav-user-name{max-width:96px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.profile-current-genealogy{min-width:0;max-width:240px;display:grid;gap:2px;margin-left:auto;padding:7px 12px;border:1px solid rgba(255,248,230,.28);border-radius:12px;color:#fff8e6;background:#4f1d1a2e;line-height:1.2}.profile-current-genealogy span{color:#fff8e6b8;font-size:11px;font-weight:700}.profile-current-genealogy strong{overflow:hidden;color:#fff8e6;font-size:14px;text-overflow:ellipsis;white-space:nowrap}.profile-mobile-menu-toggle,.profile-mobile-menu,.site-menu-toggle,.site-mobile-menu{display:none}.btn{min-width:118px;height:44px;padding:0 24px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;border:1px solid transparent;font-weight:800;transition:transform .22s ease,box-shadow .22s ease,border-color .22s ease,background .22s ease;will-change:transform}.btn:hover{transform:translateY(-2px)}.btn.primary{color:#fff;background:var(--red);box-shadow:0 14px 30px #c83b323d}.btn.primary:hover{box-shadow:0 18px 38px #c83b324d}.site-header .btn.primary{color:#8f332b;background:linear-gradient(135deg,#fff8e6,#f1d49a);box-shadow:0 12px 28px #401a1538}.site-header .btn.primary:hover{box-shadow:0 16px 34px #401a154d}.btn.ghost{color:var(--red);border-color:#c83b3247;background:#ffffffad}.btn.danger{border-color:#8a322b;color:#fffdf8;background:#8a322b;box-shadow:0 10px 22px #8a322b2e}.btn.danger:hover{border-color:#71251f;background:#71251f}.inner-hero{position:relative;overflow:hidden;background:radial-gradient(circle at 82% 12%,rgba(196,146,69,.16),transparent 24%),linear-gradient(125deg,#fffaf0,#f7efe2 48%,#edf4ef)}.inner-hero:before{content:"";position:absolute;inset:0;background-image:linear-gradient(rgba(138,50,43,.05) 1px,transparent 1px),linear-gradient(90deg,rgba(138,50,43,.05) 1px,transparent 1px);background-size:68px 68px;mask-image:linear-gradient(90deg,transparent,#000 14%,#000 86%,transparent)}.inner-hero .container{position:relative;z-index:2;min-height:410px;padding:68px 0 72px;display:grid;grid-template-columns:.9fr 1.1fr;gap:54px;align-items:center}.eyebrow{display:inline-flex;align-items:center;gap:12px;margin-bottom:22px;color:#8a5a3b;font-weight:800}.eyebrow:before{content:"";width:42px;height:2px;background:var(--red)}h1,h2,h3,h4,p{margin-top:0}h1{margin-bottom:20px;color:var(--ink);font-family:SimSun,Songti SC,serif;font-size:52px;line-height:1.16}h2{margin-bottom:14px;font-family:SimSun,Songti SC,serif;font-size:42px;line-height:1.25}h3{margin-bottom:12px;font-size:23px}.lead{max-width:620px;margin-bottom:0;color:#645d52;font-size:18px;line-height:1.9}.hero-card{min-height:260px;padding:28px;border:1px solid rgba(224,211,189,.88);border-radius:24px;background:#fffdf8eb;box-shadow:var(--shadow)}.section{padding:76px 0}.section.alt{background:#fffdf8}.section-head{margin-bottom:34px;text-align:center}.section-head p{max-width:720px;margin:14px auto 0;color:var(--muted);font-size:17px;line-height:1.9}.grid-2,.grid-3,.grid-4{display:grid;gap:22px}.grid-2{grid-template-columns:repeat(2,1fr)}.grid-3{grid-template-columns:repeat(3,1fr)}.grid-4{grid-template-columns:repeat(4,1fr)}.card{padding:24px;border-radius:18px;background:#fffdf8;border:1px solid var(--line);box-shadow:0 16px 42px #39302412;transition:transform .24s ease,box-shadow .24s ease,border-color .24s ease,background .24s ease;will-change:transform}.card:hover{transform:translateY(-6px);border-color:#c4924561;box-shadow:0 24px 60px #3930241c}.card.soft{background:#fbf7ed}.card.dark{color:#fff;background:linear-gradient(155deg,var(--green-dark),var(--green))}.card.dark p{color:#ffffffc7}.card p,.muted{color:var(--muted);line-height:1.8}.tag-row{display:flex;gap:10px;flex-wrap:wrap}.tag{padding:6px 12px;border-radius:999px;color:var(--green);background:#eaf0eb;font-size:14px;font-weight:700}.toolbar{display:flex;gap:12px;align-items:center;flex-wrap:wrap}.input,select,textarea{width:100%;min-height:48px;padding:0 16px;border:1px solid #e2d4bf;border-radius:999px;color:var(--ink);background:#fbf8f1;font:inherit}textarea{min-height:128px;padding:14px 16px;border-radius:18px;resize:vertical}.form-grid{display:grid;gap:16px}.form-card{max-width:560px;margin:0 auto;padding:34px}.auth-layout{min-height:calc(100vh - 82px);display:grid;place-items:center;padding:62px 24px;background:radial-gradient(circle at 18% 20%,rgba(200,59,50,.09),transparent 24%),linear-gradient(125deg,#fffaf0,#f7efe2 54%,#edf4ef)}.auth-scenic-layout{position:relative;isolation:isolate;min-height:100vh;padding:56px 24px 72px;place-items:center;background:linear-gradient(90deg,#fffdf8db,#fffdf875 45%,#fffdf8e0),linear-gradient(135deg,rgba(200,59,50,.08),transparent 34%),url(../images/ancestral-hall-new.png) center / cover no-repeat}.auth-scenic-layout:before{content:"";position:absolute;inset:0;z-index:-1;background:linear-gradient(180deg,#fbf7ed6b,#fbf7eddb),radial-gradient(circle at 50% 42%,rgba(255,253,248,.3),transparent 30%);backdrop-filter:blur(2px)}.auth-page-brand{position:absolute;left:clamp(18px,4vw,56px);top:clamp(18px,4vw,42px);z-index:3}.auth-card{width:min(440px,100%);padding:38px;border-radius:16px;border-color:#e0d3bde6;background:#fffdf8f0;box-shadow:0 26px 70px #39302429}.auth-card:hover{transform:none}.auth-card h1{margin-bottom:12px;font-size:40px}.auth-card .lead{margin-bottom:28px;font-size:16px}.auth-card .form-grid{gap:14px}.auth-card .auth-field{display:grid;gap:8px;color:var(--ink);font-weight:800}.auth-card .auth-field b{color:var(--red)}.auth-card .auth-form-status:empty{display:none}.auth-card .input{height:50px;background:#fffaf1}.auth-card .btn.primary,.auth-card .btn.ghost{position:relative;overflow:hidden;height:50px}.auth-card .btn.primary{width:100%;margin-top:2px}.auth-card .btn.primary:before,.auth-card .btn.ghost:before{content:"";position:absolute;top:0;bottom:0;left:-45%;width:38%;background:linear-gradient(90deg,transparent,rgba(255,255,255,.34),transparent);transform:skew(-18deg);transition:left .48s ease}.auth-card .btn.primary:hover,.auth-card .btn.ghost:hover{transform:translateY(-3px) scale(1.012)}.auth-card .btn.primary:hover{box-shadow:0 18px 42px #c83b3257}.auth-card .btn.ghost:hover{color:#fff;border-color:#c83b3233;background:var(--red);box-shadow:0 16px 34px #c83b3233}.auth-card .btn.primary:hover:before,.auth-card .btn.ghost:hover:before{left:110%}.auth-card .btn.primary:active,.auth-card .btn.ghost:active{transform:translateY(-1px) scale(.99)}.auth-links{display:flex;justify-content:space-between;gap:16px;color:#8a5a3b;font-weight:800}.auth-links a{transition:color .22s ease,transform .22s ease}.auth-links a:hover{color:var(--red);transform:translateY(-1px)}.code-row{display:grid;grid-template-columns:1fr auto;gap:12px}.is-loading{pointer-events:none;opacity:.72}.api-empty,.api-state{padding:22px;border:1px dashed var(--line);border-radius:14px;color:var(--muted);background:#fffdf8b3;text-align:center;font-weight:800}.api-state--loading{color:var(--muted)}.api-state--error,.api-state--forbidden{border-color:#a0322d47;color:var(--red);background:#a0322d0f}.footer{padding:60px 0 36px;color:#ffffffc7;background:#3f3a35}.footer-grid{display:grid;grid-template-columns:1.2fr repeat(3,1fr);gap:48px;padding-bottom:38px;border-bottom:1px solid rgba(255,255,255,.12)}.footer h4{margin:0 0 18px;color:#fff;font-size:17px}.footer p,.footer a{display:block;color:inherit;margin:10px 0;line-height:1.8}.footer a{width:fit-content;transition:color .22s ease,transform .22s ease}.footer a:hover{color:#fff;transform:translate(4px)}.footer .brand{padding:0;border-radius:0;background:transparent;box-shadow:none}.footer .brand:hover{transform:translate(0) translateY(-2px)}.copyright,.footer-legal{padding-top:28px;color:#ffffff7a;font-size:14px}.footer-legal{display:flex;align-items:center;justify-content:flex-start;gap:14px;flex-wrap:wrap;text-align:left}.footer-legal a{display:inline-flex;width:auto;margin:0;color:inherit;font-size:inherit;line-height:inherit}.footer-legal a:hover{color:#fff;transform:none}.profile-layer-confirm{border-radius:8px!important;overflow:hidden}.profile-layer-confirm .layui-layer-title{height:50px;line-height:50px;border-bottom:1px solid rgba(224,211,189,.72);background:#fffaf0;color:var(--ink);font-weight:900}.profile-layer-confirm .layui-layer-content{color:var(--muted);line-height:1.8}.profile-layer-confirm .layui-layer-btn a{border-radius:999px}.profile-layer-confirm .layui-layer-btn .layui-layer-btn0{border-color:var(--red);background:var(--red)}.pending-layer-dialog{border-radius:8px!important;overflow:hidden;box-shadow:0 20px 60px #261e152e!important}.pending-layer-dialog .layui-layer-title{height:52px;line-height:52px;border-bottom:1px solid rgba(224,211,189,.72);background:#fffaf0;color:var(--ink);font-weight:900;font-size:16px}.pending-layer-dialog .layui-layer-content{padding:28px 28px 16px!important;color:var(--ink);font-size:16px;line-height:1.8;text-align:center}.pending-layer-dialog .layui-layer-btn{padding:0 24px 24px;text-align:center}.pending-layer-dialog .layui-layer-btn a{height:38px;min-width:108px;padding:0 24px;border-radius:999px;line-height:38px;font-weight:800}.pending-layer-dialog .layui-layer-btn .layui-layer-btn0{border-color:var(--red);background:var(--red)}.profile-popup-select{display:grid;gap:10px;padding:4px 0}.profile-popup-select button{width:100%;min-height:42px;border:1px solid var(--line);border-radius:8px;background:#fffdf8;color:var(--ink);font:inherit;font-weight:900;cursor:pointer;transition:border-color .2s ease,color .2s ease,background .2s ease}.profile-popup-select button:hover{border-color:#c83b3261;color:var(--red);background:#fff4ef}@media(max-width:1320px){.page-profile .nav-links,.page-profile-module .nav-links{display:none}.profile-mobile-menu-toggle{min-width:58px;height:38px;display:inline-flex;align-items:center;justify-content:center;padding:0 12px;border:1px solid rgba(255,248,230,.38);border-radius:10px;color:#fff8e6;background:#4f1d1a33;font:inherit;font-size:13px;font-weight:800}.page-profile .nav-actions,.page-profile-module .nav-actions{display:none}.profile-mobile-menu.is-open{display:block;position:absolute;top:100%;right:0;left:0;max-height:calc(100vh - 72px);overflow-y:auto;padding:14px 0 18px;border-bottom:1px solid rgba(255,253,248,.24);background:#792a23fc;box-shadow:0 22px 38px #53201a47}.profile-mobile-menu-inner{display:grid;grid-template-columns:minmax(0,1fr);gap:12px}.profile-mobile-workspace{display:grid;gap:8px}.profile-mobile-workspace .workspace-nav-group{border-color:#fff8e629;background:transparent}.profile-mobile-workspace .workspace-nav-group[open]{background:#fffdf814}.profile-mobile-menu .profile-mobile-workspace summary{min-height:46px;display:flex;align-items:center;padding:10px 14px;color:#fff8e6;font-weight:900;cursor:pointer}.profile-mobile-menu .profile-mobile-workspace .workspace-nav-group.is-open>summary{color:#fff7d8;background:#fffdf829}.profile-mobile-workspace .workspace-nav-items,.profile-mobile-account-actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;padding:8px}.profile-mobile-menu a,.profile-mobile-menu button{min-height:46px;display:flex;align-items:center;padding:10px 14px;border:1px solid rgba(255,248,230,.16);border-radius:10px;color:#fff8e6;background:#fffdf814;font:inherit;font-weight:800;text-align:left}.profile-mobile-menu button{width:100%;cursor:pointer}.profile-mobile-menu a.is-current{border-color:#fff1cac2;color:#fff7d8;background:#fffdf833}}@media(max-width:620px){.profile-mobile-workspace .workspace-nav-items,.profile-mobile-account-actions{grid-template-columns:minmax(0,1fr)}}@media(max-width:1120px){.nav-links{display:none}.site-menu-toggle{min-width:58px;height:38px;display:inline-flex;align-items:center;justify-content:center;padding:0 12px;border:1px solid rgba(255,248,230,.38);border-radius:10px;color:#fff8e6;background:#4f1d1a33;font:inherit;font-size:13px;font-weight:800}.has-site-mobile-menu .nav-actions{display:none}.site-mobile-menu.is-open{display:block;position:absolute;top:100%;right:0;left:0;padding:14px 0 18px;border-bottom:1px solid rgba(255,253,248,.24);background:#792a23fc;box-shadow:0 22px 38px #53201a47}.site-mobile-menu-inner{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.site-mobile-menu a{min-height:46px;display:flex;align-items:center;padding:10px 14px;border:1px solid rgba(255,248,230,.16);border-radius:10px;color:#fff8e6;background:#fffdf814;font:inherit;font-weight:800;text-align:left}.site-mobile-menu a.active{border-color:#fff1cac2;color:#fff7d8;background:#fffdf833}.inner-hero .container,.grid-2{grid-template-columns:1fr}.grid-3,.grid-4,.footer-grid{grid-template-columns:repeat(2,1fr)}}@media(max-width:720px){.container{width:calc(100% - 28px)}.nav-actions a:not(.btn){display:none}.page-profile-module .nav,.page-profile .nav{height:70px;gap:10px}.page-profile-module .brand,.page-profile .brand{padding:7px 10px}.page-profile-module .brand-logo,.page-profile .brand-logo{width:114px}.page-profile-module .brand-logo-mark{width:38px;height:38px}.page-profile-module .brand-text,.page-profile-module .nav-actions{display:none}.profile-current-genealogy{max-width:112px;padding:7px 9px}.profile-current-genealogy span{display:none}.profile-current-genealogy strong{font-size:13px}.profile-mobile-menu-toggle{min-width:50px;padding:0 9px}.profile-mobile-menu-inner,.site-mobile-menu-inner{grid-template-columns:1fr}.inner-hero .container{padding:46px 0 54px}h1{font-size:38px}h2{font-size:32px}.grid-3,.grid-4,.footer-grid{grid-template-columns:1fr}.auth-scenic-layout{padding:36px 14px 48px;align-items:start}.auth-card{padding:28px 22px}.auth-card h1{font-size:34px}}.media-frame{position:relative;min-width:0;margin:0;overflow:clip;border:var(--rule-thin) solid var(--color-rule);border-radius:var(--radius-card);background:var(--color-panel-soft)}.media-preview{width:100%;display:block;padding:0;border:0;background:transparent;font:inherit}.media-frame img,.media-frame video{width:100%;display:block;object-fit:cover;background:var(--color-paper-2)}.media-frame img{aspect-ratio:4 / 3}.media-frame video{max-height:min(72vh,720px);aspect-ratio:16 / 9}.media-frame figcaption{padding:var(--space-xs) var(--space-sm);color:var(--color-ink-2);font-size:var(--text-sm);line-height:1.6}.media-fallback{min-height:132px;display:grid;place-items:center;padding:var(--space-md);color:var(--color-ink-2);background:var(--color-paper-2);text-align:center;font-size:var(--text-sm);font-weight:600}.media-fallback[hidden]{display:none}.media-gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(200px,100%),280px));gap:var(--space-sm);margin-top:var(--space-md);justify-content:start}.media-gallery .media-frame img{object-fit:contain}.media-download{min-height:var(--control-height);display:flex;align-items:center;padding:var(--space-xs) var(--space-sm);border:var(--rule-thin) solid var(--color-rule);border-radius:var(--radius-sm);color:var(--color-accent-strong);background:var(--color-panel);font-size:var(--text-sm);font-weight:700;overflow-wrap:anywhere}.media-avatar{width:48px;height:48px;position:relative;flex:0 0 auto;display:inline-grid;place-items:center;overflow:clip;border-radius:50%;color:var(--color-accent-strong);background:var(--color-accent-soft);font-weight:800}.media-avatar img{width:100%;height:100%;position:relative;z-index:1;object-fit:cover}.media-avatar-fallback{position:absolute;inset:0;display:grid;place-items:center}.media-avatar img:not([hidden])+.media-avatar-fallback{visibility:hidden}.media-avatar.is-media-error .media-avatar-fallback{visibility:visible}.media-dialog{width:min(1040px,calc(100% - 32px));max-height:calc(100vh - 32px);padding:var(--space-lg);border:var(--rule-thin) solid var(--color-rule);border-radius:var(--radius-dialog);color:var(--color-ink);background:var(--color-panel);box-shadow:var(--shadow-dialog)}.media-dialog::backdrop{background:var(--color-overlay);backdrop-filter:blur(4px)}.media-dialog img{width:100%;max-height:calc(100vh - 120px);object-fit:contain}.media-dialog-close{min-height:40px;display:block;margin:0 0 var(--space-sm) auto;padding:0 var(--space-sm);border:var(--rule-thin) solid var(--color-rule);border-radius:var(--radius-pill);color:var(--color-ink);background:var(--color-panel);font:inherit;font-weight:700}:where(a,button,input,select,textarea,summary,[tabindex]):focus-visible{outline:3px solid var(--color-focus);outline-offset:3px}:where(button,.btn,input,select,textarea):disabled,:where(button,.btn)[aria-disabled=true]{cursor:not-allowed;opacity:.52;box-shadow:none;transform:none}:where(button,.btn)[aria-busy=true]{cursor:progress;opacity:.72;pointer-events:none}.api-state,.api-empty{padding:var(--space-md);border-radius:var(--radius-md);background:var(--color-panel-soft)}.api-state--error,.api-state--forbidden,[data-state=error]{border-color:color-mix(in oklch,var(--color-error) 32%,var(--color-rule));color:var(--color-error);background:var(--color-error-soft)}.api-state--success,[data-state=success]{border-color:color-mix(in oklch,var(--color-success) 30%,var(--color-rule));color:var(--color-success);background:var(--color-success-soft)}@media(max-width:768px){.media-gallery{grid-template-columns:minmax(0,280px)}.media-dialog{padding:var(--space-sm)}}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;scroll-behavior:auto!important;transition-duration:.01ms!important}}
diff --git a/dist/public/css/register.css b/dist/public/css/register.css
deleted file mode 100644
index be13d1d..0000000
--- a/dist/public/css/register.css
+++ /dev/null
@@ -1 +0,0 @@
-.page-register .auth-links{justify-content:center}@media(max-width:720px){.page-register .auth-layout{align-items:start}}
diff --git a/dist/public/css/search-result.css b/dist/public/css/search-result.css
deleted file mode 100644
index 886930f..0000000
--- a/dist/public/css/search-result.css
+++ /dev/null
@@ -1 +0,0 @@
-.result-hero .container{min-height:420px;padding-top:74px;padding-bottom:74px}.hero-copy{position:relative;padding-left:28px}.hero-copy:before{content:"";position:absolute;left:0;top:58px;width:4px;height:132px;border-radius:999px;background:linear-gradient(180deg,var(--red),var(--gold))}.result-search{display:grid;gap:18px;align-content:center}.result-search .toolbar{padding:8px;border:1px solid rgba(224,211,189,.78);border-radius:999px;background:#fffaf1d1}.result-search .input{flex:1 1 260px;border:0;background:transparent}.result-list{display:grid;gap:18px;max-width:920px;margin:0 auto}.result-card{position:relative;overflow:hidden;padding:26px;border:1px solid var(--line);border-radius:18px;background:#fffdf8d1;box-shadow:0 18px 48px #39302412;transition:transform .24s ease,border-color .24s ease,box-shadow .24s ease}.result-card:after{content:"";position:absolute;right:-70px;bottom:-80px;width:180px;height:180px;border-radius:50%;background:radial-gradient(circle,rgba(196,146,69,.13),transparent 68%);transition:transform .28s ease}.result-card:hover{border-color:#c492456b;box-shadow:0 24px 60px #3930241c}.result-card:hover:after{transform:scale(1.2)}.result-card span{display:inline-flex;margin-bottom:12px;padding:7px 12px;border-radius:999px;color:var(--green-dark);background:#e8f0eb;font-weight:800;font-size:13px}.result-card p{margin:0;color:var(--muted);line-height:1.8}.tilt-card{transform:perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));transition:transform .18s ease,box-shadow .24s ease,border-color .24s ease}.tilt-card:hover{--lift: -6px}@media(max-width:720px){.hero-copy{padding-left:0}.hero-copy:before{display:none}.result-search .toolbar{border-radius:18px}}
diff --git a/dist/public/css/site-info.css b/dist/public/css/site-info.css
deleted file mode 100644
index bc13ee2..0000000
--- a/dist/public/css/site-info.css
+++ /dev/null
@@ -1 +0,0 @@
-.site-info-hero{padding:78px 0 64px;background:radial-gradient(circle at 82% 18%,rgba(196,146,69,.2),transparent 24%),linear-gradient(135deg,#fffaf0,#f3eadc 62%,#edf4ef)}.site-info-hero .container{display:grid;grid-template-columns:minmax(0,1.35fr) minmax(220px,.65fr);align-items:center;gap:44px}.site-info-kicker{margin-bottom:14px;color:var(--red);font-size:13px;font-weight:900;letter-spacing:.12em;text-transform:uppercase}.site-info-hero h1{margin:0;font-size:clamp(36px,5vw,58px);line-height:1.15}.site-info-hero p{max-width:680px;margin:20px 0 0;color:var(--muted);font-size:17px;line-height:1.9}.site-info-mark{min-height:180px;display:grid;place-items:center;border:1px solid rgba(196,146,69,.36);border-radius:28px;color:var(--red);background:#fffdf8c2;box-shadow:var(--shadow);font-size:62px;font-weight:900}.site-info-section{padding:72px 0}.site-info-section.alt{background:#f7efe2a3}.site-info-layout{display:grid;grid-template-columns:minmax(0,1fr) minmax(240px,.36fr);gap:28px}.site-info-list,.site-info-panel,.site-info-status{padding:30px;border:1px solid var(--line);border-radius:22px;background:var(--white);box-shadow:0 16px 46px #45352314}.site-info-list{display:grid;gap:16px}.site-info-item{display:block;padding:20px;border:1px solid rgba(234,223,206,.9);border-radius:16px;background:#fffaf2;transition:transform .2s ease,border-color .2s ease}.site-info-item:hover{border-color:#c83b3266;transform:translateY(-2px)}.site-info-item small,.site-info-panel small{color:var(--red);font-weight:800}.site-info-item h2,.site-info-panel h2,.site-info-status h2{margin:10px 0;font-size:22px}.site-info-item p,.site-info-panel p,.site-info-status p{margin:0;color:var(--muted);line-height:1.8}.site-info-links{display:grid;gap:12px;margin-top:18px}.site-info-links a{color:#8f4b31;font-weight:800}.site-info-links a:hover{color:var(--red)}.site-info-notice{margin-bottom:22px;padding:18px 20px;border:1px solid rgba(196,146,69,.42);border-radius:14px;color:#775227;background:#fff6e2;line-height:1.75}.site-info-status{max-width:760px;margin:0 auto;text-align:center}.site-info-status .site-info-mark{width:96px;min-height:96px;margin:0 auto 22px;border-radius:50%;font-size:34px}.site-info-actions{display:flex;justify-content:center;flex-wrap:wrap;gap:12px;margin-top:26px}@media(max-width:760px){.site-info-hero .container,.site-info-layout{grid-template-columns:1fr}.site-info-hero,.site-info-section{padding:52px 0}.site-info-mark{min-height:120px}}
diff --git a/dist/public/css/submit-ticket.css b/dist/public/css/submit-ticket.css
deleted file mode 100644
index 9fe8745..0000000
--- a/dist/public/css/submit-ticket.css
+++ /dev/null
@@ -1 +0,0 @@
-.ticket-hero .container{min-height:420px;padding-top:74px;padding-bottom:74px}.hero-copy{position:relative;padding-left:28px}.hero-copy:before{content:"";position:absolute;left:0;top:58px;width:4px;height:132px;border-radius:999px;background:linear-gradient(180deg,var(--red),var(--gold))}.ticket-tip{display:grid;place-items:center;text-align:center;background:linear-gradient(145deg,var(--green-dark),var(--green));color:#fff}.ticket-tip span{width:88px;height:88px;border-radius:50%;display:grid;place-items:center;color:var(--red);background:#fffdf8f0;font-size:28px;font-weight:900}.ticket-tip p{max-width:360px;margin:18px 0 0;color:#ffffffdb;line-height:1.8}.ticket-layout{display:grid;grid-template-columns:minmax(0,720px) 320px;gap:26px;align-items:start}.ticket-form{max-width:none}.ticket-form textarea{min-height:150px;padding-top:16px;border-radius:18px;resize:vertical}.ticket-side{padding:26px;border:1px solid var(--line);border-radius:18px;background:#fffdf8d1;box-shadow:0 20px 54px #39302414}.ticket-side p{color:var(--muted);line-height:1.8}.ticket-side a{display:inline-flex;margin-top:10px;color:var(--red);font-weight:800}.tilt-card{transform:perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));transition:transform .18s ease,box-shadow .24s ease,border-color .24s ease}.tilt-card:hover{--lift: -6px}@media(max-width:900px){.ticket-layout{grid-template-columns:1fr}}@media(max-width:720px){.hero-copy{padding-left:0}.hero-copy:before{display:none}}
diff --git a/dist/public/css/surname-detail.css b/dist/public/css/surname-detail.css
deleted file mode 100644
index d11a453..0000000
--- a/dist/public/css/surname-detail.css
+++ /dev/null
@@ -1 +0,0 @@
-.surname-detail-hero .container{min-height:440px;padding-top:74px;padding-bottom:74px}.hero-copy{position:relative;padding-left:28px}.hero-copy:before{content:"";position:absolute;left:0;top:58px;width:4px;height:132px;border-radius:999px;background:linear-gradient(180deg,var(--red),var(--gold))}.detail-actions{display:flex;gap:14px;margin-top:30px;flex-wrap:wrap}.surname-emblem{position:relative;overflow:hidden;display:grid;place-items:center;text-align:center;color:#fff;background:radial-gradient(circle at 72% 24%,rgba(255,255,255,.28) 0 10%,transparent 11%),linear-gradient(135deg,#476f63,#c49245 54%,#8f4634)}.surname-emblem span{width:112px;height:112px;border-radius:50%;display:grid;place-items:center;color:var(--red);background:#fffdf8f2;font-family:SimSun,Songti SC,serif;font-size:58px;font-weight:800;transition:transform .24s ease}.surname-emblem:hover span{transform:rotate(-8deg) scale(1.08)}.surname-emblem p{margin:18px 0 0;color:#ffffffe6;font-size:22px}.surname-detail-grid{display:grid;grid-template-columns:1fr 1fr;gap:24px}.content-card,.related-panel{border:1px solid var(--line);border-radius:18px;background:#fffdf8d1;box-shadow:0 20px 54px #39302414}.content-card{padding:30px}.content-card:first-child{grid-column:1 / -1}.content-card p{color:var(--muted);font-size:17px;line-height:1.9}.generation-row{display:flex;flex-wrap:wrap;gap:10px}.generation-row span{width:54px;height:54px;border-radius:14px;display:grid;place-items:center;color:#7c4a33;background:#fbf7ed;border:1px solid var(--line);font-family:SimSun,Songti SC,serif;font-size:24px;font-weight:800;transition:transform .22s ease,color .22s ease,background .22s ease}.generation-row span:hover{color:#fff;background:var(--red);transform:translateY(-5px)}.related-panel{padding:26px}.related-panel a{display:block;margin-top:12px;padding:14px 16px;border:1px solid var(--line);border-radius:14px;color:#6f4a37;background:#fbf7ed;transition:transform .22s ease,color .22s ease,background .22s ease}.related-panel a:hover{color:#fff;background:var(--green);transform:translate(5px)}.tilt-card{transform:perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));transition:transform .18s ease,box-shadow .24s ease,border-color .24s ease}.tilt-card:hover{--lift: -6px}@media(max-width:860px){.surname-detail-grid{grid-template-columns:1fr}.content-card:first-child{grid-column:auto}}@media(max-width:720px){.hero-copy{padding-left:0}.hero-copy:before{display:none}}
diff --git a/dist/public/css/surname.css b/dist/public/css/surname.css
deleted file mode 100644
index f5dd7b4..0000000
--- a/dist/public/css/surname.css
+++ /dev/null
@@ -1 +0,0 @@
-.surname-hero .container{min-height:440px;padding-top:74px;padding-bottom:74px}.hero-copy{position:relative;padding-left:28px}.hero-copy:before{content:"";position:absolute;left:0;top:58px;width:4px;height:132px;border-radius:999px;background:linear-gradient(180deg,var(--red),var(--gold))}.surname-stats{display:flex;gap:12px;margin-top:28px;flex-wrap:wrap}.surname-stats span{padding:11px 14px;border:1px solid rgba(224,211,189,.78);border-radius:999px;color:#6d766f;background:#fffdf8bd;box-shadow:0 14px 32px #4839260f}.surname-stats b{margin-right:6px;color:var(--green)}.surname-search-card{position:relative;overflow:hidden;display:grid;gap:18px;align-content:center}.search-ornament{position:absolute;right:-72px;top:-84px;width:220px;height:220px;border-radius:50%;background:radial-gradient(circle,rgba(200,59,50,.13),transparent 62%);animation:surnamePulse 4s ease-in-out infinite}.surname-search-card h3,.search-toolbar,.hot-query{position:relative;z-index:2}.search-toolbar{padding:8px;border:1px solid rgba(224,211,189,.78);border-radius:999px;background:#fffaf1d1}.search-toolbar .input{flex:1 1 280px;border:0;background:transparent}.hot-query{display:flex;gap:10px;flex-wrap:wrap}.hot-query span{width:38px;height:38px;border-radius:12px;display:grid;place-items:center;color:#7c4a33;background:#fbf7ed;border:1px solid var(--line);font-family:SimSun,Songti SC,serif;font-weight:800;transition:transform .22s ease,color .22s ease,background .22s ease}.hot-query span:hover{color:#fff;background:var(--red);transform:translateY(-4px)}.surname-list-section{position:relative;overflow:hidden}.surname-list-section:before{content:"";position:absolute;left:50%;top:58px;width:520px;height:180px;border-radius:50%;background:radial-gradient(circle,rgba(196,146,69,.09),transparent 68%);transform:translate(-50%)}.surname-grid{position:relative;display:grid;grid-template-columns:repeat(8,1fr);gap:12px;padding:24px;border:1px solid rgba(224,211,189,.8);border-radius:24px;background:#fffdf8b8;box-shadow:0 22px 60px #39302414}.surname-grid a{height:64px;border-radius:14px;display:grid;place-items:center;color:#7c4a33;background:#fbf7ed;border:1px solid var(--line);font-family:SimSun,Songti SC,serif;font-size:24px;font-weight:800;transition:transform .24s ease,color .24s ease,background .24s ease,border-color .24s ease,box-shadow .24s ease;will-change:transform}.surname-grid a:hover{color:#fff;background:var(--red);border-color:#c83b32b8;box-shadow:0 16px 34px #c83b322e;transform:translateY(-6px) scale(1.03)}.surname-grid:hover a{animation:surnameFloat 1.9s ease-in-out infinite}.surname-grid:hover a:nth-child(2n){animation-delay:.08s}.surname-grid:hover a:nth-child(3n){animation-delay:.14s}.surname-grid:hover a:nth-child(4n){animation-delay:.2s}.tilt-card{transform:perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift, 0));transition:transform .18s ease,box-shadow .24s ease,border-color .24s ease}.tilt-card:hover{--lift: -6px}@keyframes surnameFloat{0%,to{transform:translateY(0)}50%{transform:translateY(-4px)}}@keyframes surnamePulse{0%,to{opacity:.5;transform:scale(.92)}50%{opacity:1;transform:scale(1.08)}}@media(max-width:720px){.hero-copy{padding-left:0}.hero-copy:before{display:none}.search-toolbar{border-radius:18px}.surname-grid{grid-template-columns:repeat(4,1fr);padding:14px}}
diff --git a/dist/public/images/ad-album-small.png b/dist/public/images/ad-album-small.png
deleted file mode 100644
index 66c22bc..0000000
Binary files a/dist/public/images/ad-album-small.png and /dev/null differ
diff --git a/dist/public/images/ad-cloud.png b/dist/public/images/ad-cloud.png
deleted file mode 100644
index 26a4c52..0000000
Binary files a/dist/public/images/ad-cloud.png and /dev/null differ
diff --git a/dist/public/images/ad-data.png b/dist/public/images/ad-data.png
deleted file mode 100644
index 9498735..0000000
Binary files a/dist/public/images/ad-data.png and /dev/null differ
diff --git a/dist/public/images/ad-family-album.png b/dist/public/images/ad-family-album.png
deleted file mode 100644
index 4b03f0b..0000000
Binary files a/dist/public/images/ad-family-album.png and /dev/null differ
diff --git a/dist/public/images/ad-family-video.png b/dist/public/images/ad-family-video.png
deleted file mode 100644
index 8d82f09..0000000
Binary files a/dist/public/images/ad-family-video.png and /dev/null differ
diff --git a/dist/public/images/ad-genealogy-service.png b/dist/public/images/ad-genealogy-service.png
deleted file mode 100644
index cf144ac..0000000
Binary files a/dist/public/images/ad-genealogy-service.png and /dev/null differ
diff --git a/dist/public/images/ad-hall.png b/dist/public/images/ad-hall.png
deleted file mode 100644
index ab6b420..0000000
Binary files a/dist/public/images/ad-hall.png and /dev/null differ
diff --git a/dist/public/images/ad-memory.png b/dist/public/images/ad-memory.png
deleted file mode 100644
index b75761b..0000000
Binary files a/dist/public/images/ad-memory.png and /dev/null differ
diff --git a/dist/public/images/ad-print.png b/dist/public/images/ad-print.png
deleted file mode 100644
index f527271..0000000
Binary files a/dist/public/images/ad-print.png and /dev/null differ
diff --git a/dist/public/images/ad-research.png b/dist/public/images/ad-research.png
deleted file mode 100644
index a588a39..0000000
Binary files a/dist/public/images/ad-research.png and /dev/null differ
diff --git a/dist/public/images/ad-reunion.png b/dist/public/images/ad-reunion.png
deleted file mode 100644
index 0131ce9..0000000
Binary files a/dist/public/images/ad-reunion.png and /dev/null differ
diff --git a/dist/public/images/ad-service.png b/dist/public/images/ad-service.png
deleted file mode 100644
index fbb70ab..0000000
Binary files a/dist/public/images/ad-service.png and /dev/null differ
diff --git a/dist/public/images/ad-video-small.png b/dist/public/images/ad-video-small.png
deleted file mode 100644
index fe62122..0000000
Binary files a/dist/public/images/ad-video-small.png and /dev/null differ
diff --git a/dist/public/images/ancestral-hall-new.png b/dist/public/images/ancestral-hall-new.png
deleted file mode 100644
index 5726f6e..0000000
Binary files a/dist/public/images/ancestral-hall-new.png and /dev/null differ
diff --git a/dist/public/images/ancestral-hall.png b/dist/public/images/ancestral-hall.png
deleted file mode 100644
index 5726f6e..0000000
Binary files a/dist/public/images/ancestral-hall.png and /dev/null differ
diff --git a/dist/public/images/app-family-home.png b/dist/public/images/app-family-home.png
deleted file mode 100644
index 2916524..0000000
Binary files a/dist/public/images/app-family-home.png and /dev/null differ
diff --git a/dist/public/images/app-home.png b/dist/public/images/app-home.png
deleted file mode 100644
index 4017a54..0000000
Binary files a/dist/public/images/app-home.png and /dev/null differ
diff --git a/dist/public/images/app-login.png b/dist/public/images/app-login.png
deleted file mode 100644
index 8cd9c7c..0000000
Binary files a/dist/public/images/app-login.png and /dev/null differ
diff --git a/dist/public/images/family-archive-cover.jpg b/dist/public/images/family-archive-cover.jpg
deleted file mode 100644
index 8b59274..0000000
Binary files a/dist/public/images/family-archive-cover.jpg and /dev/null differ
diff --git a/dist/public/images/family-ceremony-cover.jpg b/dist/public/images/family-ceremony-cover.jpg
deleted file mode 100644
index 79391d7..0000000
Binary files a/dist/public/images/family-ceremony-cover.jpg and /dev/null differ
diff --git a/dist/public/images/family-memory-cover.jpg b/dist/public/images/family-memory-cover.jpg
deleted file mode 100644
index ed20010..0000000
Binary files a/dist/public/images/family-memory-cover.jpg and /dev/null differ
diff --git a/dist/public/images/logo-light.png b/dist/public/images/logo-light.png
deleted file mode 100644
index 21a2505..0000000
Binary files a/dist/public/images/logo-light.png and /dev/null differ
diff --git a/dist/public/images/logo-mark.png b/dist/public/images/logo-mark.png
deleted file mode 100644
index 53be143..0000000
Binary files a/dist/public/images/logo-mark.png and /dev/null differ
diff --git a/dist/public/images/logo.png b/dist/public/images/logo.png
deleted file mode 100644
index ef11d51..0000000
Binary files a/dist/public/images/logo.png and /dev/null differ
diff --git a/dist/public/images/mlogo.png b/dist/public/images/mlogo.png
deleted file mode 100644
index 8f46091..0000000
Binary files a/dist/public/images/mlogo.png and /dev/null differ
diff --git a/dist/public/js/admin-permission-pages.js b/dist/public/js/admin-permission-pages.js
deleted file mode 100644
index bb23a41..0000000
--- a/dist/public/js/admin-permission-pages.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(n,a){if(typeof module=="object"&&module.exports){module.exports=a(n);return}n.AdminPermissionPages=a(n),n.document&&n.document.addEventListener("DOMContentLoaded",function(){n.AdminPermissionPages.init()})})(typeof globalThis!="undefined"?globalThis:window,function(n){"use strict";var a=n.document,c={owner:"谱主",admin:"管理员",editor:"编辑",member:"成员",visitor:"访客"};function v(){return n.GenealogyApi&&n.GenealogyApi.defaultClient}function l(e){return a?a.querySelector(e):null}function u(e){var r;return typeof e=="number"&&!Number.isSafeInteger(e)||e==null?"":(r=String(e).trim(),/^[1-9][0-9]*$/.test(r)?r:"")}function g(e){var r=e===void 0&&n.location?n.location.search:e,t,i;return e===void 0&&n.ProfileUI&&n.ProfileUI.getGenealogyId&&(i=u(n.ProfileUI.getGenealogyId()),i)?i:(t=new URLSearchParams(String(r||"").replace(/^\?/,"")),u(t.get("genealogyId")))}function p(e,r){var t=e||{},i=u(t.genealogyId),o=String(t.roleType===void 0||t.roleType===null?"":t.roleType).trim(),b=u(r);return!i||!b||i!==b||!Object.prototype.hasOwnProperty.call(c,o)?null:{genealogyId:i,roleType:o,canManage:t.canManage===!0,canEditContent:t.canEditContent===!0}}function m(e){return!!(e&&(e.canEditContent===!0||e.canManage===!0))}function P(e){return String(e==null?"":e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function y(e){return e?'实际写入操作仍由服务端按当前角色与家谱权限校验。
':""}function d(e,r){var t=l("[data-admin-permission-current]");if(t){if(n.ProfileUI&&n.ProfileUI.setApiState){n.ProfileUI.setApiState(t,e,r);return}t.textContent=r}}function f(e,r){var t=r&&(r.status||r.code);return!e||!e.getToken||!e.getToken()||Number(t)===401}function I(e){e&&e.clearToken&&e.clearToken(),n.NavigationUtil.open("login.html")}function s(e){return Number(e&&(e.status||e.code))===403}async function T(){var e=v(),r,t,i;if(f(e)){I(e);return}if(r=g(),!r){d("empty","请先选择家谱,再查看当前角色权限。");return}n.ProfileUI&&n.ProfileUI.syncGenealogyContextLinks&&n.ProfileUI.syncGenealogyContextLinks(),d("loading","正在核对当前家谱角色与权限…");try{if(t=p(await e.genealogyDetail(r),r),!t)throw new Error("家谱权限响应缺少稳定角色或能力字段");i=l("[data-admin-permission-current]"),i&&(i.innerHTML=y(t))}catch(o){if(f(e,o)){I(e);return}d(s(o)?"forbidden":"error",s(o)?"当前账号无权查看该家谱权限。":"当前角色权限读取失败,请稍后重试。")}}function C(){!a||!l("[data-admin-permission-page]")||T()}return{getCurrentGenealogyId:g,normalizePermissionOverview:p,canMaintainContent:m,renderCurrentPermissions:y,shouldRedirectToLogin:f,isForbidden:s,init:C}});
diff --git a/dist/public/js/album-pages.js b/dist/public/js/album-pages.js
deleted file mode 100644
index 6bee2aa..0000000
--- a/dist/public/js/album-pages.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(u,C){if(typeof module=="object"&&module.exports){module.exports=C(u);return}u.AlbumPages=C(u),u.document&&u.document.addEventListener("DOMContentLoaded",function(){u.AlbumPages.init()})})(typeof globalThis!="undefined"?globalThis:window,function(u){"use strict";function C(e){return u.ProfileUI&&typeof u.ProfileUI.confirmAction=="function"?u.ProfileUI.confirmAction(e):Promise.resolve(!u.confirm||u.confirm(e))}var v=u.MediaDisplay||(typeof require=="function"?require("./media-display.js"):null),I=u.document,R=Object.create(null),j=Object.create(null),D=null,h=!1,N=!1;function A(){return u.GenealogyApi&&u.GenealogyApi.defaultClient}function f(e,t){return I?(t||I).querySelector(e):null}function F(e,t){return I?Array.prototype.slice.call((t||I).querySelectorAll(e)):[]}function l(e){return e==null?"":String(e)}function U(e){var t=l(e).trim();return t||void 0}function $(e,t){return new URLSearchParams(l(e).replace(/^\?/,"")).get(t)||""}function p(e){return e==null||e===""||typeof e=="number"&&!Number.isSafeInteger(e)?"":/^[1-9][0-9]*$/.test(String(e))?String(e):""}function W(e){return e==null||e===""?"":p(e)}function E(e){var t;if(!(e==null||e===""))return t=Number(e),Number.isSafeInteger(t)?t:void 0}function J(e){var t=e===void 0&&u.location?u.location.search:e,r;return e===void 0&&u.ProfileUI&&u.ProfileUI.getGenealogyId&&(r=u.ProfileUI.getGenealogyId(),r)?p(r):p($(t,"genealogyId"))}function P(e){var t=e===void 0&&u.location?u.location.search:e;return p($(t,"albumId"))}function le(e){var t=U(e);if(t)return/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(t)?t.replace("T"," ")+":00":/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/.test(t)?t.replace("T"," "):t}function we(e){var t=l(e);return/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}/.test(t)?t.slice(0,16).replace(" ","T"):""}function de(e){var t=l(e).match(/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/),r,n,a,o;return!t||(r=Number(t[1]),n=Number(t[2]),a=Number(t[3]),n<1||n>12||Number(t[4])>23||Number(t[5])>59||Number(t[6])>59)?!1:(o=[31,r%4===0&&(r%100!==0||r%400===0)?29:28,31,30,31,30,31,31,30,31,30,31],a>=1&&a<=o[n-1])}function K(e){var t=e||{},r={albumName:l(t.albumName).trim(),status:"0"},n=U(t.albumDesc),a=W(t.coverOssId),o=E(t.sortOrder);return n!==void 0&&(r.albumDesc=n),t.coverOssId!==void 0&&t.coverOssId!==null&&t.coverOssId!==""&&(a?r.coverOssId=a:r.invalidCoverOssId=!0),t.sortOrder!==void 0&&t.sortOrder!==null&&t.sortOrder!==""&&(o!==void 0?r.sortOrder=o:r.invalidSortOrder=!0),r}function Q(e){return!e||!e.albumName?"请填写相册名称":e.invalidCoverOssId?"封面文件编号无效,请重新选择文件":e.invalidSortOrder?"排序值必须是安全整数":e.status==="1"?"当前 PC 无法重新读取停用相册,暂不开放停用":e.status!=="0"?"相册状态只能是 0":""}function X(e){var t=e||{},r={status:"0"},n=W(t.ossId),a=U(t.photoTitle),o=U(t.photoDesc),d=U(t.photographer),s=le(t.shootTime),b=E(t.sortOrder);return n?r.ossId=n:t.ossId!==void 0&&t.ossId!==null&&t.ossId!==""&&(r.invalidOssId=!0),a!==void 0&&(r.photoTitle=a),o!==void 0&&(r.photoDesc=o),d!==void 0&&(r.photographer=d),s!==void 0&&(r.shootTime=s),t.sortOrder!==void 0&&t.sortOrder!==null&&t.sortOrder!==""&&(b!==void 0?r.sortOrder=b:r.invalidSortOrder=!0),r}function Y(e){return!e||!e.ossId||e.invalidOssId?"请选择并上传照片":e.shootTime!==void 0&&!de(e.shootTime)?"拍摄时间格式无效":e.invalidSortOrder?"排序值必须是安全整数":e.status==="1"?"当前 PC 无法重新读取停用照片,暂不开放停用":e.status!=="0"?"照片状态只能是 0":""}function q(e){var t=p(e&&e.albumId),r=p(e&&e.genealogyId),n=v&&v.normalizeFileAccess(e&&e.coverFile),a=l(e&&e.albumName).trim(),o=E(e&&e.photoCount),d=E(e&&e.sortOrder),s=l(e&&e.status),b;return!t||!r||!a||e.coverFile!==void 0&&e.coverFile!==null&&!n||e.photoCount!==void 0&&e.photoCount!==null&&e.photoCount!==""&&o===void 0||e.sortOrder!==void 0&&e.sortOrder!==null&&e.sortOrder!==""&&d===void 0||s!=="0"&&s!=="1"?null:(b={albumId:t,genealogyId:r,genealogyNo:l(e.genealogyNo),genealogyName:l(e.genealogyName),surname:l(e.surname),albumName:a,albumDesc:l(e.albumDesc),status:s,remark:l(e.remark)},n&&(b.coverFile=n),o!==void 0&&(b.photoCount=o),d!==void 0&&(b.sortOrder=d),b)}function B(e){var t=p(e&&e.photoId),r=p(e&&e.genealogyId),n=p(e&&e.albumId),a=v&&v.normalizeFileAccess(e&&e.photoFile),o=E(e&&e.sortOrder),d=l(e&&e.status),s;return!t||!r||!n||!a||e.sortOrder!==void 0&&e.sortOrder!==null&&e.sortOrder!==""&&o===void 0||d!=="0"&&d!=="1"?null:(s={photoId:t,genealogyId:r,genealogyNo:l(e.genealogyNo),genealogyName:l(e.genealogyName),surname:l(e.surname),albumId:n,albumName:l(e.albumName),photoFile:a,photoTitle:l(e.photoTitle),photoDesc:l(e.photoDesc),photographer:l(e.photographer),shootTime:l(e.shootTime),status:d,remark:l(e.remark)},o!==void 0&&(s.sortOrder=o),s)}function G(e){var t;return Array.isArray(e)?(t=e.map(q),t.some(function(r){return!r})?[]:t):[]}function Z(e){var t;return Array.isArray(e)?(t=e.map(B),t.some(function(r){return!r})?[]:t):[]}function k(e,t){var r=G(e),n=p(t);return r.find(function(a){return a.albumId===n})||null}function g(e){return l(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function se(e){return"profile-album.html?genealogyId="+encodeURIComponent(e)}function _(e,t){var r="profile-album-edit.html?genealogyId="+encodeURIComponent(e);return t?r+"&albumId="+encodeURIComponent(t):r}function ee(e,t){return"profile-album-detail.html?genealogyId="+encodeURIComponent(e)+"&albumId="+encodeURIComponent(t)}function L(e,t){return""+g(e)+""+g(t||"未提供")+"
"}function te(e){var t="";return e?(h&&(t=''),(v?v.renderImage(e.coverFile,{alt:e.albumName+"封面",className:"album-cover-media"}):"")+''+L("相册名称",e.albumName)+L("相册说明",e.albumDesc)+L("照片数量",e.photoCount===void 0?"":e.photoCount)+L("备注",e.remark)+"
"+t):""}function fe(e){var t='查看照片';return h&&(t+='编辑'),''+g(e.albumName)+"
"+g(e.albumDesc||"照片数量:"+(e.photoCount||0))+'
'+t+"
"}function re(e){var t=Array.isArray(e)?e.map(B):[];return t.some(function(r){return!r})||!t.length?"":t.map(function(r){var n=h?'':"";return''+(v?v.renderImage(r.photoFile,{alt:r.photoTitle||"家族照片",className:"album-photo-media"}):"")+""+g(r.photoTitle||"未命名照片")+"
"+g([r.photoDesc,r.photographer,r.shootTime].filter(Boolean).join(" · ")||"文件已上传")+'
'+n+"
"}).join("")}function ae(e,t){var r=t&&(t.status||t.code);return!e||!e.getToken||!e.getToken()||Number(r)===401}function m(e){return Number(e&&(e.status||e.code))===403}function c(e,t){return ae(e,t)?(e&&e.clearToken&&e.clearToken(),u.NavigationUtil.open("login.html"),!0):!1}function T(e){u.layui&&u.layui.layer?u.layui.layer.msg(e):u.alert&&u.alert(e)}function M(){u.ProfileUI&&u.ProfileUI.syncGenealogyContextLinks&&u.ProfileUI.syncGenealogyContextLinks()}function O(e){return m(e)?"forbidden":"error"}function i(e,t,r){var n=f(e);if(n){if(!t){n.innerHTML="";return}if(r&&u.ProfileUI&&u.ProfileUI.setApiState){u.ProfileUI.setApiState(n,r,t);return}n.textContent=t}}function x(e,t){var r=f("[data-album-editor-placeholder]");F("[data-album-editor], [data-album-editor-action], [data-album-photo-editor]").forEach(function(n){n.hidden=!e}),r&&(r.hidden=!!e,t&&(r.textContent=t))}function y(e){N=!!e,F("[data-album-form] button, [data-album-form] input, [data-album-form] textarea, [data-album-photo-form] button, [data-album-photo-form] input, [data-album-photo-form] textarea, [data-album-delete-id], [data-album-photo-delete-id]").forEach(function(t){t.disabled=N})}function me(){var e="请先选择家谱,再查看或维护相册。";i("[data-album-list]",e,"empty"),i("[data-album-detail]","当前没有家谱上下文。","empty"),i("[data-album-photo-list]","当前没有家谱上下文。","empty"),x(!1,e),i("[data-album-form-status]",e,"forbidden"),i("[data-album-photo-status]",e,"forbidden")}function w(){var e=J();return e||me(),e}function ne(e){return!!(e&&(e.canEditContent===!0||e.canManage===!0))}async function V(e,t){var r=await e.genealogyDetail(t);return h=ne(r),F("[data-album-create-link], [data-album-editor-action], [data-album-photo-editor]").forEach(function(n){n.hidden=!h}),r}function ce(e){var t=f("[data-album-list]"),r=G(e);return R=Object.create(null),r.forEach(function(n){R[n.albumId]=n}),t?!Array.isArray(e)||e.length&&!r.length?(i("[data-album-list]","相册响应缺少稳定 AlbumVo 字段,请联系后端核对。","error"),[]):r.length?(t.innerHTML=r.map(fe).join(""),r):(i("[data-album-list]","暂无相册","empty"),[]):r}async function oe(){var e=A(),t;if(!c(e)&&(t=w(),!!t)){M(),i("[data-album-list]","正在加载相册…","loading");try{await V(e,t),ce(await e.albums(t))}catch(r){if(c(e,r))return;i("[data-album-list]",m(r)?"当前账号无权查看该家谱的相册。":"相册加载失败,请稍后重试。",O(r)),T(m(r)?"当前账号无权查看该家谱的相册。":r.message||"相册加载失败")}}}function ue(e){var t={};return F("[name]",e).forEach(function(r){t[r.name]=r.value}),t}function S(e,t,r){var n=f(e+' [name="'+t+'"]');n&&(n.value=r==null?"":String(r))}function be(e){if(!e||e.status!=="0")throw new Error("停用相册无法通过当前 PC 接口重新读取或编辑");S("[data-album-form]","albumName",e.albumName),S("[data-album-form]","albumDesc",e.albumDesc),S("[data-album-form]","coverOssId",e.coverOssId),S("[data-album-form]","sortOrder",e.sortOrder),S("[data-album-form]","status","0")}async function pe(){var e=A(),t,r,n,a;if(!c(e)&&(t=w(),!!t)){r=P(),M(),x(!1,"正在加载相册编辑信息…"),i("[data-album-form-status]","正在读取家谱权限…","loading");try{if(await V(e,t),!h)throw{status:403,message:"当前账号无权维护该家谱的相册。"};if(r){if(n=await e.albums(t),a=k(n,r),!a)throw new Error("相册列表未返回当前相册");be(a),f("[data-album-editor-title]")&&(f("[data-album-editor-title]").textContent="编辑相册")}x(!0),i("[data-album-form-status]","")}catch(o){if(c(e,o))return;x(!1,m(o)?"当前账号无权维护该家谱的相册。":o.message||"相册编辑信息加载失败"),i("[data-album-form-status]",m(o)?"当前账号无权维护该家谱的相册。":o.message||"相册编辑信息加载失败",O(o))}}}async function H(e,t,r){var n,a,o=f("[data-album-photo-list]");return i("[data-album-photo-list]","正在加载照片…","loading"),n=await e.albumPhotos(t,r),a=Z(n),j=Object.create(null),a.forEach(function(d){j[d.photoId]=d}),o?!Array.isArray(n)||n.length&&!a.length?(i("[data-album-photo-list]","照片响应缺少稳定 AlbumPhotoVo 字段,请联系后端核对。","error"),[]):a.length?(o.innerHTML=re(a),a):(i("[data-album-photo-list]","暂无照片","empty"),[]):a}async function ge(){var e=A(),t,r,n;if(!c(e)){if(t=w(),r=P(),!t||!r){t&&(i("[data-album-detail]","缺少有效相册编号。","error"),i("[data-album-photo-list]","缺少有效相册编号。","empty"));return}M(),i("[data-album-detail]","正在加载相册信息…","loading"),i("[data-album-photo-list]","正在加载照片…","loading");try{if(await V(e,t),n=await e.albums(t),D=k(n,r),!D)throw new Error("相册列表未返回当前相册");f("[data-album-detail]")&&(f("[data-album-detail]").innerHTML=te(D)),f("[data-album-detail-title]")&&(f("[data-album-detail-title]").textContent=D.albumName)}catch(a){if(c(e,a))return;i("[data-album-detail]",m(a)?"当前账号无权查看该相册。":a.message||"相册详情加载失败",O(a)),i("[data-album-photo-list]",m(a)?"当前账号无权查看该相册。":"照片加载失败,请稍后重试。",O(a)),T(m(a)?"当前账号无权查看该相册。":a.message||"相册详情加载失败");return}try{await H(e,t,r)}catch(a){if(c(e,a))return;i("[data-album-photo-list]",m(a)?"当前账号无权查看该相册照片。":a.message||"照片加载失败",O(a)),T(m(a)?"当前账号无权查看该相册照片。":a.message||"照片加载失败")}}}async function he(e){var t=A(),r=w(),n=P(),a,o,d,s,b,ie;if(!(N||!h||!r||c(t))){if(a=K(ue(e)),o=Q(a),o){i("[data-album-form-status]",o,"error");return}delete a.invalidCoverOssId,delete a.invalidSortOrder,y(!0),i("[data-album-form-status]","正在保存相册…","loading");try{if(d=n?await t.updateAlbum(r,n,a):await t.createAlbum(r,a),s=q(d),b=n||s&&s.albumId,!b)throw new Error("保存响应缺少 albumId");if(ie=k(await t.albums(r),b),!ie)throw new Error("保存后相册列表未返回同一相册");u.NavigationUtil.open(ee(r,b))}catch(z){if(c(t,z))return;i("[data-album-form-status]",m(z)?"当前账号无权保存该相册。":z.message||"相册保存失败",O(z))}finally{y(!1)}}}async function ve(e){var t=A(),r=w(),n=P(),a,o,d;if(!(N||!h||!r||!n||c(t))){if(a=X(ue(e)),o=Y(a),o){i("[data-album-photo-status]",o,"error");return}delete a.invalidOssId,delete a.invalidSortOrder,y(!0),i("[data-album-photo-status]","正在添加照片…","loading");try{if(d=B(await t.createAlbumPhoto(r,n,a)),!d||d.albumId!==n)throw new Error("添加照片响应缺少稳定 photoId");if(!(await H(t,r,n)).some(function(s){return s.photoId===d.photoId}))throw new Error("添加后照片列表未返回同一照片");e.reset(),i("[data-album-photo-status]","照片已添加")}catch(s){if(c(t,s))return;i("[data-album-photo-status]",m(s)?"当前账号无权添加照片。":s.message||"照片添加失败",O(s))}finally{y(!1)}}}async function Ie(e){var t=A(),r=w(),n=R[e]||D;if(!(N||!h||!r||!p(e)||c(t))&&await C("确认删除“"+(n?n.albumName:"该相册")+"”及其中全部照片吗?删除后不可恢复。")){y(!0);try{await t.deleteAlbum(r,e),f("[data-album-page]")?await oe():u.NavigationUtil.open(se(r))}catch(a){if(c(t,a))return;T(m(a)?"当前账号无权删除该相册。":a.message||"相册删除失败")}finally{y(!1)}}}async function ye(e){var t=A(),r=w(),n=P(),a=j[e];if(!(N||!h||!r||!n||!p(e)||c(t))&&await C("确认删除“"+(a&&a.photoTitle||"该照片")+"”吗?删除后不可恢复。")){y(!0);try{await t.deleteAlbumPhoto(r,n,e),await H(t,r,n),T("照片已删除")}catch(o){if(c(t,o))return;T(m(o)?"当前账号无权删除该照片。":o.message||"照片删除失败")}finally{y(!1)}}}function Ae(){I&&(I.addEventListener("click",function(e){var t=e.target.closest("[data-album-delete-id]"),r=e.target.closest("[data-album-photo-delete-id]");if(t){e.preventDefault(),Ie(t.getAttribute("data-album-delete-id"));return}r&&(e.preventDefault(),ye(r.getAttribute("data-album-photo-delete-id")))}),I.addEventListener("submit",function(e){var t=e.target.closest("[data-album-form]"),r=e.target.closest("[data-album-photo-form]");t?(e.preventDefault(),he(t)):r&&(e.preventDefault(),ve(r))}))}function Oe(){I&&(Ae(),f("[data-album-page]")&&oe(),f("[data-album-edit-page]")&&pe(),f("[data-album-detail-page]")&&ge())}return{getCurrentGenealogyId:J,getCurrentAlbumId:P,buildAlbumBody:K,validateAlbumBody:Q,buildAlbumPhotoBody:X,validateAlbumPhotoBody:Y,canEditAlbums:ne,normalizeAlbum:q,normalizeAlbumPhoto:B,normalizeAlbums:G,normalizeAlbumPhotos:Z,findAlbumById:k,renderAlbumDetail:te,renderPhotoList:re,shouldRedirectToLogin:ae,isForbidden:m,init:Oe}});
diff --git a/dist/public/js/app-promotion-pages.js b/dist/public/js/app-promotion-pages.js
deleted file mode 100644
index 3deef18..0000000
--- a/dist/public/js/app-promotion-pages.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(t,o){if(typeof module=="object"&&module.exports){module.exports=o(t);return}t.AppPromotionPages=o(t),t.document&&t.document.addEventListener("DOMContentLoaded",function(){t.AppPromotionPages.init()})})(typeof globalThis!="undefined"?globalThis:window,function(t){"use strict";var o=t.MediaDisplay||(typeof require=="function"?require("./media-display.js"):null);function u(r){return String(r==null?"":r).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function P(r){var e;return typeof r=="number"&&!Number.isSafeInteger(r)||r==null?"":(e=String(r).trim(),/^[1-9][0-9]*$/.test(e)?e:"")}function d(r){return r==null?"":String(r).trim()}function f(r){var e=d(r),n;if(!e)return"";try{n=new URL(e)}catch(l){return""}return n.protocol==="http:"||n.protocol==="https:"?n.href:""}function s(r){var e=r||{},n=P(e.promotionId),l=d(e.promotionTitle),i=o&&o.normalizeFileAccess(e.coverFile),p;return!n||!l||String(e.status)!=="0"||e.coverFile!==void 0&&e.coverFile!==null&&!i?null:(p={promotionId:n,promotionTitle:l,promotionDesc:d(e.promotionDesc),targetUrl:f(e.targetUrl)},i&&(p.coverFile=i),p)}function m(r){var e;return Array.isArray(r)?(e=r.map(s),e.some(function(n){return!n})?[]:e):[]}function g(r){var e=(o?o.renderImage(r.coverFile,{alt:r.promotionTitle+"封面",className:"promotion-cover-media"}):"")+""+u(r.promotionTitle)+"
"+u(r.promotionDesc)+"
";return r.targetUrl?''+e+"":''+e+""}function h(r){var e=m(r);return e.map(g).join("")}function a(r,e,n){if(r){if(t.ProfileUI&&t.ProfileUI.setApiState){t.ProfileUI.setApiState(r,e,n);return}r.textContent=n}}async function v(r){var e,n;if(!r||typeof r.promotions!="function")throw new Error("应用推广接口不可用");if(e=await r.promotions({platform:"pc"}),n=m(e),!Array.isArray(e)||n.length!==e.length)throw new Error("推广列表响应无效");return n}function y(r){return Number(r&&(r.status||r.code))===401}function c(r){return Number(r&&(r.status||r.code))===403}async function T(){var r=t.document&&t.document.querySelector("[data-promotion-page]"),e=t.document&&t.document.querySelector("[data-promotion-list]"),n=t.GenealogyApi&&t.GenealogyApi.defaultClient;if(!(!r||!e)){if(!n||!n.getToken||!n.getToken()){a(e,"forbidden","登录后可查看应用推广。");return}a(e,"loading","正在读取应用推广…");try{var l=await v(n);if(!l.length){a(e,"empty","当前暂无应用推广。");return}e.innerHTML=l.map(g).join("")}catch(i){if(y(i)){n.clearToken&&n.clearToken(),a(e,"forbidden","登录后可查看应用推广。");return}a(e,c(i)?"forbidden":"error",c(i)?"当前账号无权查看应用推广。":"应用推广读取失败,请稍后重试。")}}}return{normalizePromotion:s,normalizePromotionList:m,normalizeTargetUrl:f,renderPromotionList:h,setPromotionState:a,loadPromotions:v,isUnauthorized:y,isForbidden:c,init:T}});
diff --git a/dist/public/js/article-pages.js b/dist/public/js/article-pages.js
deleted file mode 100644
index 6c0a1bf..0000000
--- a/dist/public/js/article-pages.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(i,P){if(typeof module=="object"&&module.exports){module.exports=P(i);return}i.ArticlePages=P(i),i.document&&i.document.addEventListener("DOMContentLoaded",function(){i.ArticlePages.init()})})(typeof globalThis!="undefined"?globalThis:window,function(i){"use strict";function P(e){return i.ProfileUI&&typeof i.ProfileUI.confirmAction=="function"?i.ProfileUI.confirmAction(e):Promise.resolve(!i.confirm||i.confirm(e))}var N=i.MediaDisplay||(typeof require=="function"?require("./media-display.js"):null),y=i.document,T=Object.create(null),w=!1,A=!1;function U(){return i.GenealogyApi&&i.GenealogyApi.defaultClient}function l(e,r){return y?(r||y).querySelector(e):null}function L(e,r){return y?Array.prototype.slice.call((r||y).querySelectorAll(e)):[]}function d(e){return e==null?"":String(e)}function q(e){var r=d(e).trim();return r||void 0}function z(e,r){return new URLSearchParams(d(e).replace(/^\?/,"")).get(r)||""}function o(e){return e==null||e===""||typeof e=="number"&&!Number.isSafeInteger(e)?"":/^[1-9][0-9]*$/.test(String(e))?String(e):""}function G(e){return e==null||e===""?"":o(e)}function M(e){var r=e===void 0&&i.location?i.location.search:e,t;return e===void 0&&i.ProfileUI&&i.ProfileUI.getGenealogyId&&(t=i.ProfileUI.getGenealogyId(),t)?o(t):o(z(r,"genealogyId"))}function R(e){var r=e===void 0&&i.location?i.location.search:e;return o(z(r,"articleId"))}function x(e){var r;if(!(e==null||e===""))return r=Number(e),Number.isSafeInteger(r)?r:void 0}function H(e){var r=e||{},t={articleTitle:d(r.articleTitle).trim(),articleContent:d(r.articleContent).trim(),status:"0"},n=q(r.articleSummary),a=G(r.coverOssId),v=q(r.authorName),p=x(r.sortOrder);return n!==void 0&&(t.articleSummary=n),r.coverOssId!==void 0&&r.coverOssId!==null&&r.coverOssId!==""&&(a?t.coverOssId=a:t.invalidCoverOssId=!0),v!==void 0&&(t.authorName=v),r.sortOrder!==void 0&&r.sortOrder!==null&&r.sortOrder!==""&&(p!==void 0?t.sortOrder=p:t.invalidSortOrder=!0),t}function V(e){return!e||!e.articleTitle?"请填写谱文标题":e.articleContent?e.invalidCoverOssId?"封面文件编号无效,请重新选择文件":e.invalidSortOrder?"排序值必须是安全整数":e.status==="1"?"当前 PC 无法重新读取停用谱文,暂不开放停用":e.status!=="0"?"谱文状态只能是 0":"":"请填写谱文正文"}function O(e){var r=o(e&&e.articleId),t=o(e&&e.genealogyId),n=G(e&&e.categoryId),a=N&&N.normalizeFileAccess(e&&e.coverFile),v=d(e&&e.articleTitle).trim(),p=d(e&&e.articleContent).trim(),C=x(e&&e.viewCount),g=x(e&&e.sortOrder),I=d(e&&e.status),S;return!r||!t||!v||!p||e.categoryId!==void 0&&e.categoryId!==null&&e.categoryId!==""&&!n||e.coverFile!==void 0&&e.coverFile!==null&&!a||e.viewCount!==void 0&&e.viewCount!==null&&e.viewCount!==""&&C===void 0||e.sortOrder!==void 0&&e.sortOrder!==null&&e.sortOrder!==""&&g===void 0||I!=="0"&&I!=="1"?null:(S={articleId:r,genealogyId:t,genealogyNo:d(e.genealogyNo),genealogyName:d(e.genealogyName),surname:d(e.surname),categoryName:d(e.categoryName),categoryCode:d(e.categoryCode),articleTitle:v,articleSummary:d(e.articleSummary),articleContent:p,authorName:d(e.authorName),publishTime:d(e.publishTime),status:I,remark:d(e.remark)},n&&(S.categoryId=n),a&&(S.coverFile=a),C!==void 0&&(S.viewCount=C),g!==void 0&&(S.sortOrder=g),S)}function j(e){var r;return Array.isArray(e)?(r=e.map(O),r.some(function(t){return!t})?[]:r):[]}function W(e,r){var t=O(e);return!!(t&&t.articleId===o(r))}function c(e){return d(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function re(e,r){var t="profile-article.html?genealogyId="+encodeURIComponent(e);return r?t+"&articleId="+encodeURIComponent(r):t}function $(e,r){var t="profile-article-edit.html?genealogyId="+encodeURIComponent(e);return r?t+"&articleId="+encodeURIComponent(r):t}function J(e){return!!(e&&(e.canEditContent===!0||e.canManage===!0))}function m(e,r){return""+c(e)+""+c(r||"未提供")+"
"}function K(e){var r="";return e?(A&&(r=''),(N?N.renderImage(e.coverFile,{alt:e.articleTitle+"封面",className:"article-cover-media"}):"")+''+m("标题",e.articleTitle)+m("摘要",e.articleSummary)+m("正文",e.articleContent)+m("作者",e.authorName)+m("分类",e.categoryName)+m("发布时间",e.publishTime)+m("浏览量",e.viewCount===void 0?"":e.viewCount)+m("备注",e.remark)+"
"+r):X("empty","请选择一篇谱文查看详情")}function te(e){var r='';return A&&(r+='编辑'),''+c(e.articleTitle)+"
"+c(e.articleSummary||e.authorName||e.publishTime||"暂无摘要")+'
'+r+"
"}function Q(e,r){var t=r&&(r.status||r.code);return!e||!e.getToken||!e.getToken()||Number(t)===401}function u(e){return Number(e&&(e.status||e.code))===403}function f(e,r){return Q(e,r)?(e&&e.clearToken&&e.clearToken(),i.NavigationUtil.open("login.html"),!0):!1}function D(e){i.layui&&i.layui.layer?i.layui.layer.msg(e):i.alert&&i.alert(e)}function X(e,r){return i.ProfileUI&&i.ProfileUI.renderApiState?i.ProfileUI.renderApiState(e,r):''+c(r)+"
"}function s(e,r,t){if(e){if(i.ProfileUI&&i.ProfileUI.setApiState){i.ProfileUI.setApiState(e,r,t);return}e.innerHTML=X(r,t)}}function ie(e){return e.indexOf("无权")>=0?"forbidden":/失败|缺少/.test(e)?"error":/正在|读取中|加载中/.test(e)?"loading":"empty"}function Y(){i.ProfileUI&&i.ProfileUI.syncGenealogyContextLinks&&i.ProfileUI.syncGenealogyContextLinks()}function h(e,r){var t=l("[data-article-form-status]");if(t){if(!e){t.innerHTML="";return}if(r&&i.ProfileUI&&i.ProfileUI.setApiState){i.ProfileUI.setApiState(t,r,e);return}t.textContent=e}}function F(e,r,t){var n=l("[data-article-editor-placeholder]");L("[data-article-editor], [data-article-editor-action]").forEach(function(a){a.hidden=!e}),n&&(n.hidden=!!e,r&&s(n,t||ie(r),r))}function k(e,r){var t=l('[data-article-form] [type="submit"]');w=!!e,L("[data-article-form] button, [data-article-form] input, [data-article-form] textarea, [data-article-delete-id]").forEach(function(n){n.disabled=w}),t&&(t.dataset.defaultLabel||(t.dataset.defaultLabel=t.textContent),t.textContent=w&&r?r:t.dataset.defaultLabel,t.setAttribute("aria-busy",w?"true":"false"))}function ne(){var e="请先选择家谱,再查看或维护谱文。",r=l("[data-article-list]"),t=l("[data-article-detail]");s(r,"empty",e),s(t,"empty","当前没有家谱上下文。"),F(!1,e,"empty"),h(e,"empty")}function E(){var e=M();return e||ne(),e}async function Z(e,r){var t=await e.genealogyDetail(r);return A=J(t),L("[data-article-create-link], [data-article-editor-action]").forEach(function(n){n.hidden=!A}),t}function ae(e){var r=l("[data-article-list]"),t=j(e);return T=Object.create(null),t.forEach(function(n){T[n.articleId]=n}),r?!Array.isArray(e)||e.length&&!t.length?(s(r,"error","谱文响应缺少稳定 ArticleVo 字段,请联系后端核对。"),[]):t.length?(r.innerHTML=t.map(te).join(""),t):(s(r,"empty","暂无谱文"),[]):t}function _(e){var r=l("[data-article-detail]");r&&(r.innerHTML=K(e))}async function B(e){var r=U(),t=E(),n;if(!t||!o(e)||f(r))return null;s(l("[data-article-detail]"),"loading","正在加载谱文详情…");try{if(n=O(await r.articleDetail(t,e)),!n||n.articleId!==o(e))throw new Error("谱文详情响应缺少稳定 ArticleVo 字段");return T[n.articleId]=n,_(n),n}catch(a){return f(r,a)||(s(l("[data-article-detail]"),u(a)?"forbidden":"error",u(a)?"当前账号无权查看该谱文。":"谱文详情加载失败,请稍后重试。"),D(u(a)?"当前账号无权查看该谱文。":a.message||"谱文详情加载失败")),null}}async function ee(){var e=U(),r,t,n;if(!f(e)&&(r=E(),!!r)){Y(),s(l("[data-article-list]"),"loading","正在加载谱文…");try{await Z(e,r),t=ae(await e.articles(r)),n=R(),n&&T[n]?await B(n):t.length?await B(t[0].articleId):_(null)}catch(a){if(f(e,a))return;s(l("[data-article-list]"),u(a)?"forbidden":"error",u(a)?"当前账号无权查看该家谱的谱文。":"谱文加载失败,请稍后重试。"),D(u(a)?"当前账号无权查看该家谱的谱文。":a.message||"谱文加载失败")}}}function le(e){var r={};return L("[name]",e).forEach(function(t){r[t.name]=t.value}),r}function b(e,r){var t=l('[data-article-form] [name="'+e+'"]');t&&(t.value=r==null?"":String(r))}function de(e){var r,t;if(!e||e.status!=="0")throw new Error("停用谱文无法通过当前 PC 接口重新读取或编辑");b("articleTitle",e.articleTitle),b("articleSummary",e.articleSummary),b("coverOssId",e.coverOssId),b("articleContent",e.articleContent),b("authorName",e.authorName),b("sortOrder",e.sortOrder),b("status","0"),r=l('[name="articleContent"]'),i.AppRichEditor&&i.AppRichEditor.init&&r&&(t=i.AppRichEditor.init(r),t&&t.editor&&t.editor.setHtml&&(t.editor.setHtml(e.articleContent),t.sync()))}async function ue(){var e=U(),r,t,n;if(!f(e)&&(r=E(),!!r)){t=R(),Y(),F(!1,"正在加载谱文编辑信息…","loading"),h("正在读取家谱权限…","loading");try{if(await Z(e,r),!A)throw{status:403,message:"当前账号无权维护该家谱的谱文。"};if(t){if(n=O(await e.articleDetail(r,t)),!n||n.articleId!==t)throw new Error("谱文详情响应缺少稳定 ArticleVo 字段");de(n),l("[data-article-editor-title]")&&(l("[data-article-editor-title]").textContent="编辑谱文")}F(!0),h("")}catch(a){if(f(e,a))return;F(!1,u(a)?"当前账号无权维护该家谱的谱文。":a.message||"谱文编辑信息加载失败",u(a)?"forbidden":"error"),h(u(a)?"当前账号无权维护该家谱的谱文。":a.message||"谱文编辑信息加载失败",u(a)?"forbidden":"error")}}}async function oe(e){var r=U(),t=E(),n=R(),a,v,p,C,g;if(!(w||!A||!t||f(r))){if(i.AppRichEditor&&i.AppRichEditor.syncAll&&i.AppRichEditor.syncAll(),a=H(le(e)),v=V(a),v){h(v,"error");return}delete a.invalidCoverOssId,delete a.invalidSortOrder,k(!0,"正在保存…"),h("正在保存谱文…","loading");try{if(p=n?await r.updateArticle(t,n,a):await r.createArticle(t,a),C=O(p),g=n||C&&C.articleId,!g)throw new Error("保存响应缺少 articleId");if(!W(await r.articleDetail(t,g),g))throw new Error("保存后重读未返回同一篇谱文");i.NavigationUtil.open(re(t,g))}catch(I){if(f(r,I))return;h(u(I)?"当前账号无权保存该谱文。":I.message||"谱文保存失败",u(I)?"forbidden":"error")}finally{k(!1)}}}async function ce(e){var r=U(),t=E(),n=T[e];if(!(w||!A||!t||!o(e)||f(r))&&await P("确认删除“"+(n?n.articleTitle:"该谱文")+"”吗?删除后不可恢复。")){k(!0);try{await r.deleteArticle(t,e),await ee(),D("谱文已删除")}catch(a){if(f(r,a))return;D(u(a)?"当前账号无权删除该谱文。":a.message||"谱文删除失败")}finally{k(!1)}}}function fe(){y&&(y.addEventListener("click",function(e){var r=e.target.closest("[data-article-detail-id]"),t=e.target.closest("[data-article-delete-id]");if(r){e.preventDefault(),B(r.getAttribute("data-article-detail-id"));return}t&&(e.preventDefault(),ce(t.getAttribute("data-article-delete-id")))}),y.addEventListener("submit",function(e){var r=e.target.closest("[data-article-form]");r&&(e.preventDefault(),oe(r))}))}function se(){y&&(fe(),l("[data-article-page]")&&ee(),l("[data-article-edit-page]")&&ue())}return{getCurrentGenealogyId:M,getCurrentArticleId:R,buildArticleBody:H,validateArticleBody:V,normalizeArticle:O,canEditArticles:J,normalizeArticles:j,matchesSavedArticle:W,renderArticleDetail:K,shouldRedirectToLogin:Q,isForbidden:u,init:se}});
diff --git a/dist/public/js/auth-pages.js b/dist/public/js/auth-pages.js
deleted file mode 100644
index 603b343..0000000
--- a/dist/public/js/auth-pages.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(t,c){if(typeof module=="object"&&module.exports){module.exports=c(t);return}t.AuthPages=c(t),t.document&&t.document.addEventListener("DOMContentLoaded",function(){t.AuthPages.init()})})(typeof globalThis!="undefined"?globalThis:window,function(t){"use strict";var c=t.document,o={login:{selector:"#login-password-form",operationCode:"password-login",successUrl:"profile.html"},"sms-login":{selector:"#login-sms-form",operationCode:"sms-login",successUrl:"profile.html"},register:{selector:"#register-form",operationCode:"register",successUrl:"login.html"},"password-reset":{selector:"#password-reset-form",operationCode:"forgot-password",successUrl:"login.html"}},q=60;function w(e){return t.hex_md5?t.hex_md5(e):t.md5?t.md5(e):e}function T(e,n){var r=n||w,i={phone:e.phone,password:r(e.password)};return e.validToken&&(i.validToken=e.validToken),i}function b(e){return{phone:e.phone,smsCode:e.smsCode}}function I(e,n){var r=n||w;return{phone:e.phone,password:r(e.password),nickName:e.nickName||e.phone,smsCode:e.smsCode}}function N(e,n){var r=n||w;return{phone:e.phone,smsCode:e.smsCode,newPassword:r(e.newPassword)}}function f(){return t.GenealogyApi&&t.GenealogyApi.defaultClient}async function O(e){if(t.PublicNavigation){t.PublicNavigation.clearUser();try{t.PublicNavigation.storeUser(await e.currentProfile())}catch(n){t.PublicNavigation.clearUser()}}}function x(e){var n=o[e]||{};return n.operationCode||""}function g(e){var n=o[e]||{};return n.successUrl||""}function G(e){var n=e==null?"":String(e).trim();return typeof e=="number"&&!Number.isSafeInteger(e)?"":/^[1-9][0-9]*$/.test(n)?n:""}function B(e){var n=(Array.isArray(e)?e:[]).map(function(r){return G(r&&r.genealogyId)}).filter(Boolean).filter(function(r,i,s){return s.indexOf(r)===i});return n.length===1?"profile-family-home.html?genealogyId="+encodeURIComponent(n[0]):"profile-families.html"}async function C(e,n){if(n!=="login"&&n!=="sms-login"||!e||!e.genealogiesMine)return g(n);try{return B(await e.genealogiesMine())}catch(r){return g(n)}}function y(e,n){var r=x(n);return r}async function _(e,n,r){return n?!t.CaptchaPages||!t.CaptchaPages.ensureToken?(S("验证码组件未加载,请刷新后重试"),!1):!!await t.CaptchaPages.ensureToken(e,{operationCode:n,subject:r}):!0}function p(e,n){return(n||c).querySelector(e)}function d(e,n){return Array.prototype.slice.call((n||c).querySelectorAll(e))}function u(e){var n={};return d("input[name], textarea[name], select[name]",e).forEach(function(r){n[r.name]=String(r.value||"").trim()}),n}function P(e){var n=p('input[name="validToken"]',e);n&&(n.value="")}function U(e){var n=p('input[name="validToken"]',e),r=n&&n.value||"";return n&&(n.value=""),r}function E(e){var n,r=q,i;!e||typeof t.setInterval!="function"||(e.__smsCooldownTimer&&typeof t.clearInterval=="function"&&t.clearInterval(e.__smsCooldownTimer),n=e.getAttribute("data-sms-code-label")||e.textContent.trim(),e.setAttribute("data-sms-code-label",n),e.disabled=!0,e.textContent=r+" 秒后重试",i=t.setInterval(function(){if(r-=1,r>0){e.textContent=r+" 秒后重试";return}typeof t.clearInterval=="function"&&t.clearInterval(i),e.__smsCooldownTimer=null,e.disabled=!1,e.textContent=n},1e3),e.__smsCooldownTimer=i)}function L(e,n){e&&(e.classList.toggle("is-loading",n),"disabled"in e&&(e.disabled=n),e.setAttribute("aria-busy",n?"true":"false"))}function m(e){return Number(e&&(e.status||e.code))===403?"forbidden":"error"}function a(e,n,r){var i=p("[data-auth-form-status]",e);if(i){if(!n){i.innerHTML="";return}if(t.ProfileUI&&t.ProfileUI.setApiState){t.ProfileUI.setApiState(i,r||"error",n);return}i.textContent=n}}function l(e,n,r){e&&(e.dataset.defaultLabel||(e.dataset.defaultLabel=e.textContent),e.disabled=!!n,e.textContent=n?r:e.dataset.defaultLabel,e.setAttribute("aria-busy",n?"true":"false"))}function S(e){if(t.MessageUtil&&t.MessageUtil.show){t.MessageUtil.show(e);return}t.console&&t.console.warn&&t.console.warn(e)}function M(e){return/^1\d{10}$/.test(e||"")}function k(e){return/^\d{4}$/.test(e||"")}function A(e,n){return e?e.length<6?"密码至少需要 6 位":"":n}function R(e,n){var r=n||{};if(!r.phone)return"请填写手机号";if(!M(r.phone))return"请输入正确的手机号";if(e==="login")return A(r.password,"请填写密码");if(e==="sms-login")return r.smsCode?k(r.smsCode)?"":"请输入正确的短信验证码":"请填写短信验证码";if(e==="register"){if(!r.smsCode)return"请填写短信验证码";if(!k(r.smsCode))return"请输入正确的短信验证码";var i=A(r.password,"请填写密码");return i||(r.confirmPassword?r.password!==r.confirmPassword?"两次输入的密码不一致":"":"请再次输入密码")}if(e==="password-reset"){if(!r.smsCode)return"请填写验证码";if(!k(r.smsCode))return"请输入正确的短信验证码";var s=A(r.newPassword,"请填写新密码");if(s)return s;if(!r.confirmPassword)return"请再次输入新密码";if(r.newPassword!==r.confirmPassword)return"两次输入的新密码不一致"}return""}function j(e){var n=e||{};return n.phone?M(n.phone)?"":"请输入正确的手机号":"请填写手机号"}function h(e,n,r){var i=n==="send-code"?j(r):R(n,r);return i?(a(e,i,"error"),!1):!0}function v(e,n){var r=p(e);r&&r.addEventListener("submit",function(i){i.preventDefault(),n(r,p('[type="submit"]',r))})}function $(e){d(".login-mode-tab").forEach(function(n){var r=n.getAttribute("aria-controls")===e;n.classList.toggle("is-active",r),n.setAttribute("aria-selected",r?"true":"false")}),d(".login-mode-panel").forEach(function(n){var r=n.id===e;n.hidden=!r,r||P(n)})}async function V(e,n){var r=f(),i=u(e);if(!r){a(e,"接口初始化失败,请刷新后重试","error");return}if(h(e,"login",i)){if(!await _(e,y(e,"login"),i.phone)){a(e,"请完成验证后再提交登录。","error");return}i=u(e),i.validToken=U(e),l(n,!0,"正在登录…"),a(e,"正在验证账号…","loading");try{await r.login(T(i)),await O(r),t.NavigationUtil.open(await C(r,"login"))}catch(s){a(e,s.message||"登录失败",m(s))}finally{l(n,!1,"正在登录…")}}}async function z(e,n){var r=f(),i=u(e);if(!r){a(e,"接口初始化失败,请刷新后重试","error");return}if(h(e,"sms-login",i)){l(n,!0,"正在登录…"),a(e,"正在验证短信验证码…","loading");try{await r.loginBySms(b(i)),await O(r),t.NavigationUtil.open(await C(r,"sms-login"))}catch(s){a(e,s.message||"短信登录失败",m(s))}finally{l(n,!1,"正在登录…")}}}async function H(e,n){var r=f(),i=u(e);if(!r){a(e,"接口初始化失败,请刷新后重试","error");return}if(h(e,"register",i)){l(n,!0,"正在注册…"),a(e,"正在创建账号…","loading");try{await r.register(I(i)),t.NavigationUtil.open(g("register"))}catch(s){a(e,s.message||"注册失败",m(s))}finally{l(n,!1,"正在注册…")}}}async function W(e){var n=f(),r=e.closest("form"),i=u(r),s=Y(r),F=y(r,s);if(!n){a(r,"接口初始化失败,请刷新后重试","error");return}if(h(r,"send-code",i)){if(!await _(r,F,i.phone)){a(r,"请完成验证后再获取验证码。","error");return}i=u(r),i.validToken=U(r),L(e,!0),a(r,"正在发送验证码…","loading");try{await n.sendSmsCode(F,{phone:i.phone,validToken:i.validToken||""}),S("验证码已发送"),a(r,""),L(e,!1),E(e)}catch(D){a(r,D.message||"验证码发送失败",m(D)),L(e,!1)}}}async function J(e,n){var r=f(),i=u(e);if(!r){a(e,"接口初始化失败,请刷新后重试","error");return}if(h(e,"password-reset",i)){l(n,!0,"正在重设…"),a(e,"正在重设密码…","loading");try{await r.resetPassword(N(i)),S("密码已重设,请重新登录"),t.NavigationUtil.open(g("password-reset"))}catch(s){a(e,s.message||"重设密码失败",m(s))}finally{l(n,!1,"正在重设…")}}}function K(){d("[data-api-send-code]").forEach(function(e){e.addEventListener("click",function(n){n.preventDefault(),W(e)})})}function Q(){d(".login-mode-tab").forEach(function(e){e.addEventListener("click",function(){$(e.getAttribute("aria-controls"))})})}function X(){d('form input[name="phone"]').forEach(function(e){e.addEventListener("input",function(){P(e.closest("form"))})})}function Y(e){return e&&Object.keys(o).find(function(n){return o[n].selector==="#"+e.id})||""}function Z(){c&&(v(o.login.selector,V),v(o["sms-login"].selector,z),v(o.register.selector,H),v(o["password-reset"].selector,J),Q(),K(),X())}return{buildLoginBody:T,buildSmsLoginBody:b,buildRegisterBody:I,buildPasswordResetBody:N,clearCaptchaToken:P,takeCaptchaToken:U,startSmsCooldown:E,getCaptchaOperation:x,getFormCaptchaOperation:y,getSuccessUrl:g,getPostLoginUrl:B,resolvePostLoginUrl:C,validateAuthValues:R,init:Z}});
diff --git a/dist/public/js/captcha-pages.js b/dist/public/js/captcha-pages.js
deleted file mode 100644
index 7c53421..0000000
--- a/dist/public/js/captcha-pages.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(t,y){if(typeof module=="object"&&module.exports){module.exports=y(t);return}t.CaptchaPages=y(t)})(typeof globalThis!="undefined"?globalThis:window,function(t){"use strict";var y=["318px","318px"],L=0;function V(){return t.GenealogyApi&&t.GenealogyApi.defaultClient}function b(a,e){return(e||t.document).querySelector(a)}function T(a){if(t.MessageUtil&&t.MessageUtil.show){t.MessageUtil.show(a);return}t.console&&t.console.warn&&t.console.warn(a)}function p(a,e){var r=a||{};return{tenantId:r.tenantId||e.tenantId,subject:r.subject||""}}function j(a){var e=a||{},r=e.payload||{};return Object.assign({},r,{type:e.captchaType||r.type||"SLIDER",id:r.id||e.challengeId,challengeId:e.challengeId,providerCode:e.providerCode||"tianai",captchaType:e.captchaType||r.type||"SLIDER"})}function m(a){var e=a||{};return Number(e.code)!==200||!e.data?e:Object.assign({},e,{data:j(e.data)})}function w(a,e,r){var n=e||{},i=a||{},o=x(i.data||{});return{tenantId:n.tenantId||r.tenantId,subject:n.subject||"",challengeId:n.challengeId||i.challengeId||i.id,providerCode:n.providerCode||"tianai",captchaType:n.captchaType||"SLIDER",payload:{track:o}}}function x(a){var e=Object.assign({},a||{}),r=Array.isArray(e.trackList)?e.trackList:[],n=r[0]||{},i=r[r.length-1]||{};return typeof e.left=="undefined"&&(e.left=h(i.x)-h(n.x)),typeof e.top=="undefined"&&(e.top=h(i.y)-h(n.y)),e}function h(a){var e=Number(a);return Number.isFinite(e)?e:0}function k(a){var e=a||{};return Number(e.code)===200&&e.data&&e.data.passed===!1?Object.assign({},e,{code:4001,msg:e.data.message||e.msg||"验证失败"}):e}function R(a){var e=a||{},r=e.data||{};return Number(e.code)!==200||r.passed===!1?"":r.validToken||e.validToken||""}function I(a){return b('input[name="validToken"]',a)}function A(){if(!t.layui||!t.layui.layer||!t.layui.layer.open||!t.document)throw new Error("缺少 layui.layer 验证码弹层依赖");var a="captcha-layer-"+ ++L,e='[data-captcha-layer-box="'+a+'"]',r=t.layui.layer.open({type:1,title:!1,closeBtn:0,area:y,offset:"auto",content:''}),n=b(e);if(!n)throw t.layui.layer.close(r),new Error("缺少 Layui 验证码实际挂载点");return{box:n,layerIndex:r}}function f(a){a&&(a.box&&(a.box.innerHTML=""),t.layui&&t.layui.layer&&t.layui.layer.close&&t.layui.layer.close(a.layerIndex))}function O(a,e){var r=I(a);r&&(r.value=e||"")}function E(a){return a?a.required!==!1:!0}function D(a,e,r,n,i){var o=e||{},d,v,N=p(o,r),q={},C,g;if(!t.TAC||!t.CaptchaConfig)return i(new Error("滑动验证组件未加载")),null;try{d=A(),v=d.box}catch(u){return i(u),null}g=new t.CaptchaConfig({bindEl:v,requestCaptchaDataUrl:r.captchaChallengeUrl(o.operationCode),validCaptchaUrl:r.captchaVerifyUrl(o.operationCode),requestHeaders:{clientid:r.clientId},validSuccess:function(u,s,l){var c=R(u);if(!c){l&&l.destroyWindow&&l.destroyWindow(),f(d),i(new Error("滑动验证未返回有效票据"));return}O(a,c),l&&l.destroyWindow&&l.destroyWindow(),f(d),n(c)},validFail:function(u,s,l){l&&l.reloadCaptcha&&l.reloadCaptcha(),T(u&&(u.msg||u.message)||"滑动验证失败,请重试")},btnCloseFun:function(u,s){s&&s.destroyWindow(),f(d),i(new Error("已取消滑动验证"))}}),g.addRequestChain({preRequest:function(u,s){return u==="requestCaptchaData"&&(s.data=p(o,r)),u==="validCaptcha"&&(s.data=w(s.data,Object.assign({},N,q),r)),!0},postRequest:function(u,s,l){if(u==="requestCaptchaData"){var c=m(l);q={challengeId:c.data&&c.data.challengeId,providerCode:c.data&&c.data.providerCode,captchaType:c.data&&c.data.captchaType},Object.keys(l||{}).forEach(function(S){delete l[S]}),Object.assign(l,c)}return u==="validCaptcha"&&Object.assign(l,k(l)),!0}});try{C=new t.TAC(g),C.init()}catch(u){return f(d),i(u),null}return C}async function U(a,e){var r=V(),n=I(a),i=e||{},o;if(!r)return"";if(n&&n.value)return n.value;if(!i.operationCode)return"";try{if(o=await r.captchaRequirement(i.operationCode,p(i,r)),!E(o))return"CAPTCHA_NOT_REQUIRED"}catch(d){o=null}return new Promise(function(d,v){D(a,i,r,d,v)}).catch(function(d){return T(d.message||"请先完成滑动验证"),""})}return{buildChallengeBody:p,adaptChallengeResponse:m,buildVerifyBody:w,normalizeVerifyTrack:x,createCaptchaLayer:A,closeCaptchaLayer:f,extractValidToken:R,normalizeVerifyResponse:k,shouldRequireCaptcha:E,ensureToken:U}});
diff --git a/dist/public/js/ceremony-admin-pages.js b/dist/public/js/ceremony-admin-pages.js
deleted file mode 100644
index 53a7914..0000000
--- a/dist/public/js/ceremony-admin-pages.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(d,G){if(typeof module=="object"&&module.exports){module.exports=G(d);return}d.CeremonyAdminPages=G(d),d.document&&d.document.addEventListener("DOMContentLoaded",function(){d.CeremonyAdminPages.init()})})(typeof globalThis!="undefined"?globalThis:window,function(d){"use strict";function G(e){return d.ProfileUI&&typeof d.ProfileUI.confirmAction=="function"?d.ProfileUI.confirmAction(e):Promise.resolve(!d.confirm||d.confirm(e))}var F=d.MediaDisplay||(typeof require=="function"?require("./media-display.js"):null),b=d.document,V=Object.create(null),q=Object.create(null),H=Object.create(null),k=null,v=!1,w=!1,ge=["PENDING","ACCEPTED","DECLINED","CANCELED"],ve={PENDING:"待响应",ACCEPTED:"已接受",DECLINED:"已拒绝",CANCELED:"已取消"};function N(){return d.GenealogyApi&&d.GenealogyApi.defaultClient}function c(e,n){return b?(n||b).querySelector(e):null}function S(e,n){return b?Array.prototype.slice.call((n||b).querySelectorAll(e)):[]}function u(e){return e==null?"":String(e)}function M(e){var n=u(e).trim();return n||void 0}function y(e){return e==null||e===""||typeof e=="number"&&!Number.isSafeInteger(e)?"":/^[1-9][0-9]*$/.test(String(e))?String(e):""}function R(e){return e==null||e===""?"":y(e)}function Z(e,n){return new URLSearchParams(u(e).replace(/^\?/,"")).get(n)||""}function ee(e){var n=e===void 0&&d.location?d.location.search:e,r;return e===void 0&&d.ProfileUI&&d.ProfileUI.getGenealogyId&&(r=d.ProfileUI.getGenealogyId(),r)?y(r):y(Z(n,"genealogyId"))}function E(e){var n=e===void 0&&d.location?d.location.search:e;return y(Z(n,"ceremonyId"))}function x(e){var n;if(!(e==null||e===""))return n=Number(e),Number.isSafeInteger(n)?n:void 0}function O(e){var n;if(!(e==null||e===""))return n=Number(e),Number.isFinite(n)?n:void 0}function pe(e){var n=M(e);if(n)return/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(n)?n.replace("T"," ")+":00":/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/.test(n)?n.replace("T"," "):n}function Ie(e){var n=u(e);return/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}/.test(n)?n.slice(0,16).replace(" ","T"):""}function he(e){var n=u(e).match(/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/),r,t,i,a;return!n||(r=Number(n[1]),t=Number(n[2]),i=Number(n[3]),t<1||t>12||Number(n[4])>23||Number(n[5])>59||Number(n[6])>59)?!1:(a=[31,r%4===0&&(r%100!==0||r%400===0)?29:28,31,30,31,30,31,31,30,31,30,31],i>=1&&i<=a[t-1])}function ne(e){var n=e||{},r={ceremonyType:u(n.ceremonyType).trim(),ceremonyTitle:u(n.ceremonyTitle).trim(),status:"0"},t=["ceremonyDesc","location","locationAddress"],i=pe(n.ceremonyTime),a=O(n.longitude),f=O(n.latitude),l=R(n.coverOssId),I=x(n.sortOrder);return t.forEach(function(h){var P=M(n[h]);P!==void 0&&(r[h]=P)}),i!==void 0&&(r.ceremonyTime=i),n.longitude!==void 0&&n.longitude!==null&&n.longitude!==""&&(a!==void 0?r.longitude=a:r.invalidLongitude=!0),n.latitude!==void 0&&n.latitude!==null&&n.latitude!==""&&(f!==void 0?r.latitude=f:r.invalidLatitude=!0),n.coverOssId!==void 0&&n.coverOssId!==null&&n.coverOssId!==""&&(l?r.coverOssId=l:r.invalidCoverOssId=!0),n.sortOrder!==void 0&&n.sortOrder!==null&&n.sortOrder!==""&&(I!==void 0?r.sortOrder=I:r.invalidSortOrder=!0),r}function re(e){return!e||!e.ceremonyType?"请填写活动类型":e.ceremonyTitle?e.ceremonyTime!==void 0&&!he(e.ceremonyTime)?"活动时间格式无效":e.longitude===void 0!=(e.latitude===void 0)?"经度和纬度必须同时提供":e.invalidLongitude?"经度必须是有效数字":e.invalidLatitude?"纬度必须是有效数字":e.longitude!==void 0&&(e.longitude<-180||e.longitude>180)?"经度范围必须是 -180 到 180":e.latitude!==void 0&&(e.latitude<-90||e.latitude>90)?"纬度范围必须是 -90 到 90":u(e.locationAddress).length>300?"详细地址不能超过 300 个字符":e.invalidCoverOssId?"封面文件编号无效,请重新选择文件":e.invalidSortOrder?"排序值必须是安全整数":e.status==="1"?"当前 PC 无法重新读取停用活动,暂不开放停用":e.status!=="0"?"活动状态只能是 0":"":"请填写活动标题"}function te(e){var n=e||{},r={},t=M(n.giverName),i=M(n.giftMessage),a=O(n.giftAmount);return t!==void 0&&(r.giverName=t),n.giftAmount!==void 0&&n.giftAmount!==null&&n.giftAmount!==""&&(a!==void 0?r.giftAmount=a:r.invalidGiftAmount=!0),i!==void 0&&(r.giftMessage=i),r}function ie(e){return!e||e.giftAmount===void 0&&!e.invalidGiftAmount?"请填写礼金金额":e.invalidGiftAmount?"礼金金额必须是有效数字":e.giftAmount<0?"礼金金额不能小于 0":""}function L(e){var n=y(e&&e.ceremonyId),r=y(e&&e.genealogyId),t=R(e&&e.sponsorUserId),i=F&&F.normalizeFileAccess(e&&e.coverFile),a=u(e&&e.ceremonyType).trim(),f=u(e&&e.ceremonyTitle).trim(),l=O(e&&e.longitude),I=O(e&&e.latitude),h=x(e&&e.giftCount),P=O(e&&e.giftAmount),X=x(e&&e.sortOrder),Y=u(e&&e.status),T;return!n||!r||!a||!f||e.sponsorUserId!==void 0&&e.sponsorUserId!==null&&e.sponsorUserId!==""&&!t||e.coverFile!==void 0&&e.coverFile!==null&&!i||e.longitude!==void 0&&e.longitude!==null&&e.longitude!==""&&l===void 0||e.latitude!==void 0&&e.latitude!==null&&e.latitude!==""&&I===void 0||l===void 0!=(I===void 0)||e.giftCount!==void 0&&e.giftCount!==null&&e.giftCount!==""&&h===void 0||e.giftAmount!==void 0&&e.giftAmount!==null&&e.giftAmount!==""&&P===void 0||e.sortOrder!==void 0&&e.sortOrder!==null&&e.sortOrder!==""&&X===void 0||Y!=="0"&&Y!=="1"?null:(T={ceremonyId:n,genealogyId:r,genealogyNo:u(e.genealogyNo),genealogyName:u(e.genealogyName),surname:u(e.surname),sponsorNickName:u(e.sponsorNickName),sponsorPhone:u(e.sponsorPhone),ceremonyType:a,ceremonyTitle:f,ceremonyDesc:u(e.ceremonyDesc),ceremonyTime:u(e.ceremonyTime),location:u(e.location),locationAddress:u(e.locationAddress),status:Y,remark:u(e.remark)},t&&(T.sponsorUserId=t),i&&(T.coverFile=i),l!==void 0&&(T.longitude=l),I!==void 0&&(T.latitude=I),h!==void 0&&(T.giftCount=h),P!==void 0&&(T.giftAmount=P),X!==void 0&&(T.sortOrder=X),T)}function j(e){var n=y(e&&e.giftId),r=y(e&&e.genealogyId),t=y(e&&e.ceremonyId),i=R(e&&e.giverUserId),a=O(e&&e.giftAmount),f=u(e&&e.status),l;return!n||!r||!t||a===void 0||a<0||e.giverUserId!==void 0&&e.giverUserId!==null&&e.giverUserId!==""&&!i||f!=="0"&&f!=="1"?null:(l={giftId:n,genealogyId:r,genealogyNo:u(e.genealogyNo),genealogyName:u(e.genealogyName),surname:u(e.surname),ceremonyId:t,ceremonyTitle:u(e.ceremonyTitle),giverNickName:u(e.giverNickName),giverPhone:u(e.giverPhone),giverName:u(e.giverName),giftAmount:a,giftMessage:u(e.giftMessage),giftTime:u(e.giftTime),status:f,remark:u(e.remark)},i&&(l.giverUserId=i),l)}function $(e){var n=y(e&&e.invitationId),r=y(e&&e.genealogyId),t=y(e&&e.ceremonyId),i=y(e&&e.inviteeUserId),a=u(e&&e.inviteStatus),f=x(e&&e.inviteVersion),l;return!n||!r||!t||!i||ge.indexOf(a)<0||e.inviteVersion!==void 0&&e.inviteVersion!==null&&e.inviteVersion!==""&&f===void 0?null:(l={invitationId:n,genealogyId:r,ceremonyId:t,inviteeUserId:i,inviteStatus:a,deliveredTime:u(e.deliveredTime),readTime:u(e.readTime),responseTime:u(e.responseTime)},f!==void 0&&(l.inviteVersion=f),l)}function ae(e){var n=y(e&&e.memberId),r=y(e&&e.genealogyId),t=R(e&&e.appUserId),i=u(e&&e.status);return!n||!r||!t||i!=="0"?null:{memberId:n,genealogyId:r,appUserId:t,appUserNickName:u(e.appUserNickName),memberName:u(e.memberName),roleType:u(e.roleType),status:i}}function B(e,n){var r;return Array.isArray(e)?(r=e.map(n),r.some(function(t){return!t})?[]:r):[]}function oe(e){var n=Object.create(null),r=[];return(Array.isArray(e)?e:[]).forEach(function(t){var i=y(t);i&&!n[i]&&(n[i]=!0,r.push(i))}),{inviteeUserIds:r}}function m(e){return u(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function A(e,n){return""+m(e)+""+m(n===""||n===void 0?"未提供":n)+"
"}function Ce(e){return"profile-ceremony.html?genealogyId="+encodeURIComponent(e)}function W(e,n){var r="profile-gift-edit.html?genealogyId="+encodeURIComponent(e);return n?r+"&ceremonyId="+encodeURIComponent(n):r}function de(e,n){return"profile-ceremony-detail.html?genealogyId="+encodeURIComponent(e)+"&ceremonyId="+encodeURIComponent(n)}function ue(e){var n="",r="";return e?(e.longitude!==void 0&&e.latitude!==void 0&&(n=' 打开地图'),v&&(r=''),(F?F.renderImage(e.coverFile,{alt:e.ceremonyTitle+"封面",className:"ceremony-cover-media"}):"")+'"+r):""}function Ae(e){var n='查看详情';return v&&(n+='编辑'),''+m(e.ceremonyTitle)+"
"+m([e.ceremonyType,e.ceremonyTime,e.location].filter(Boolean).join(" · "))+'
'+n+"
"}function le(e){var n=Array.isArray(e)?e.map(j):[];return n.some(function(r){return!r})||!n.length?"":n.map(function(r){var t=v?'':"";return''+m(r.giverName||r.giverNickName||"匿名宗亲")+" · "+m(r.giftAmount)+"
"+m([r.giftMessage,r.giftTime].filter(Boolean).join(" · ")||"未提供留言")+'
'+t+"
"}).join("")}function Te(e){var n=B(e,$);return!Array.isArray(e)||e.length&&!n.length||!n.length?"":n.map(function(r){var t=H[r.inviteeUserId],i=t&&(t.memberName||t.appUserNickName)||"已邀请成员";return''+m(i)+"
"+m(ve[r.inviteStatus])+(r.deliveredTime?" · "+m(r.deliveredTime):"")+"
"}).join("")}function fe(e,n){var r=n&&(n.status||n.code);return!e||!e.getToken||!e.getToken()||Number(r)===401}function s(e){return Number(e&&(e.status||e.code))===403}function g(e,n){return fe(e,n)?(e&&e.clearToken&&e.clearToken(),d.NavigationUtil.open("login.html"),!0):!1}function D(e){d.layui&&d.layui.layer?d.layui.layer.msg(e):d.alert&&d.alert(e)}function p(e){return s(e)?"forbidden":"error"}function o(e,n,r){var t=c(e);if(t){if(!n){t.innerHTML="";return}if(r&&d.ProfileUI&&d.ProfileUI.setApiState){d.ProfileUI.setApiState(t,r,n);return}t.textContent=n}}function _(){d.ProfileUI&&d.ProfileUI.syncGenealogyContextLinks&&d.ProfileUI.syncGenealogyContextLinks()}function C(e){w=!!e,S("[data-ceremony-form] input, [data-ceremony-form] textarea, [data-ceremony-form] button, [data-ceremony-gift-form] input, [data-ceremony-gift-form] textarea, [data-ceremony-gift-form] button, [data-ceremony-invitee-form] input, [data-ceremony-invitee-form] button, [data-ceremony-delete-id], [data-ceremony-gift-delete-id]").forEach(function(n){n.disabled=w})}function z(e,n){var r=c("[data-ceremony-editor-placeholder]");S("[data-ceremony-editor], [data-ceremony-editor-action], [data-ceremony-admin-editor]").forEach(function(t){t.hidden=!e}),r&&(r.hidden=!!e,n&&(r.textContent=n))}function be(){var e="请先选择家谱,再查看或维护祭祀活动。";o("[data-ceremony-list]",e,"empty"),o("[data-ceremony-detail]","当前没有家谱上下文。","empty"),o("[data-ceremony-gift-list]","当前没有家谱上下文。","empty"),o("[data-ceremony-invitation-list]","当前没有家谱上下文。","empty"),o("[data-ceremony-invitee-options]","当前没有家谱上下文。","empty"),z(!1,e),o("[data-ceremony-form-status]",e,"forbidden")}function U(){var e=ee();return e||be(),e}function se(e){return!!(e&&(e.canEditContent===!0||e.canManage===!0))}async function J(e,n){var r=await e.genealogyDetail(n);return v=se(r),S("[data-ceremony-create-link], [data-ceremony-editor-action], [data-ceremony-admin-editor]").forEach(function(t){t.hidden=!v}),r}function Ne(e){var n=c("[data-ceremony-list]"),r=B(e,L);return V=Object.create(null),r.forEach(function(t){V[t.ceremonyId]=t}),n?!Array.isArray(e)||e.length&&!r.length?(o("[data-ceremony-list]","活动响应缺少稳定 CeremonyVo 字段,请联系后端核对。","error"),[]):r.length?(n.innerHTML=r.map(Ae).join(""),r):(o("[data-ceremony-list]","暂无祭祀活动","empty"),[]):r}async function ce(){var e=N(),n;if(!g(e)&&(n=U(),!!n)){_(),o("[data-ceremony-list]","正在加载祭祀活动…","loading");try{await J(e,n),Ne(await e.ceremonies(n))}catch(r){if(g(e,r))return;o("[data-ceremony-list]",s(r)?"当前账号无权查看该家谱的祭祀活动。":"活动加载失败,请稍后重试。",p(r)),D(s(r)?"当前账号无权查看该家谱的祭祀活动。":r.message||"活动加载失败")}}}function me(e){var n={};return S("[name]",e).forEach(function(r){n[r.name]=r.value}),n}function K(e,n,r){var t=c(e+' [name="'+n+'"]');t&&(t.value=r==null?"":String(r))}function Ue(e){var n,r;if(!e||e.status!=="0")throw new Error("停用活动无法通过当前 PC 接口重新读取或编辑");["ceremonyType","ceremonyTitle","ceremonyDesc","location","locationAddress","longitude","latitude","coverOssId","sortOrder"].forEach(function(t){K("[data-ceremony-form]",t,e[t])}),K("[data-ceremony-form]","ceremonyTime",Ie(e.ceremonyTime)),K("[data-ceremony-form]","status","0"),n=c('[data-ceremony-form] [name="ceremonyDesc"]'),n&&d.AppRichEditor&&d.AppRichEditor.init&&(r=d.AppRichEditor.init(n),r&&r.editor&&r.editor.setHtml&&(r.editor.setHtml(e.ceremonyDesc||""),r.sync()))}async function we(){var e=N(),n,r,t;if(!g(e)&&(n=U(),!!n)){r=E(),_(),z(!1,"正在加载活动编辑信息…"),o("[data-ceremony-form-status]","正在读取家谱权限…","loading");try{if(await J(e,n),!v)throw{status:403,message:"当前账号无权维护该家谱的祭祀活动。"};if(r){if(t=L(await e.ceremonyDetail(n,r)),!t||t.ceremonyId!==r)throw new Error("活动详情响应缺少稳定 ceremonyId");Ue(t),c("[data-ceremony-editor-title]")&&(c("[data-ceremony-editor-title]").textContent="编辑祭祀活动")}z(!0),o("[data-ceremony-form-status]","")}catch(i){if(g(e,i))return;z(!1,s(i)?"当前账号无权维护该家谱的祭祀活动。":i.message||"活动编辑信息加载失败"),o("[data-ceremony-form-status]",s(i)?"当前账号无权维护该家谱的祭祀活动。":i.message||"活动编辑信息加载失败",p(i))}}}async function Q(e,n,r){var t,i,a=c("[data-ceremony-gift-list]");return o("[data-ceremony-gift-list]","正在加载祭品…","loading"),t=await e.ceremonyGifts(n,r),i=B(t,j),q=Object.create(null),i.forEach(function(f){q[f.giftId]=f}),a?!Array.isArray(t)||t.length&&!i.length?(o("[data-ceremony-gift-list]","祭品响应缺少稳定 CeremonyGiftVo 字段,请联系后端核对。","error"),[]):i.length?(a.innerHTML=le(i),i):(o("[data-ceremony-gift-list]","暂无祭品记录","empty"),[]):i}function Ee(e,n){var r=c("[data-ceremony-invitee-options]"),t=Object.create(null);if(n.forEach(function(i){i.inviteStatus!=="CANCELED"&&(t[i.inviteeUserId]=!0)}),!!r){if(!e.length){o("[data-ceremony-invitee-options]","暂无已绑定账号的正常成员","empty");return}r.innerHTML=e.map(function(i){var a=i.memberName||i.appUserNickName||"家谱成员";return'"}).join("")}}async function ye(e,n,r){var t,i,a,f=c("[data-ceremony-invitation-list]");return o("[data-ceremony-invitation-list]","正在加载邀请记录…","loading"),o("[data-ceremony-invitee-options]","正在加载成员选项…","loading"),t=await Promise.all([e.genealogyMemberOptions(n),e.ceremonyInvitations(n,r)]),i=B(t[0],ae),a=B(t[1],$),H=Object.create(null),i.forEach(function(l){H[l.appUserId]=l}),!Array.isArray(t[0])||t[0].length&&!i.length?o("[data-ceremony-invitee-options]","成员选项响应字段不完整","error"):Ee(i,a),f?(!Array.isArray(t[1])||t[1].length&&!a.length?o("[data-ceremony-invitation-list]","邀请响应字段不完整","error"):a.length?f.innerHTML=Te(t[1]):o("[data-ceremony-invitation-list]","暂无邀请记录","empty"),{options:i,invitations:a}):{options:i,invitations:a}}async function Oe(){var e=N(),n,r;if(!g(e)){if(n=U(),r=E(),!n||!r){n&&(o("[data-ceremony-detail]","缺少有效活动编号。","error"),o("[data-ceremony-gift-list]","缺少有效活动编号。","empty"),o("[data-ceremony-invitation-list]","缺少有效活动编号。","empty"),o("[data-ceremony-invitee-options]","缺少有效活动编号。","empty"));return}_(),o("[data-ceremony-detail]","正在加载活动详情…","loading"),o("[data-ceremony-gift-list]","正在加载祭品…","loading");try{if(await J(e,n),k=L(await e.ceremonyDetail(n,r)),!k||k.ceremonyId!==r)throw new Error("活动详情响应缺少稳定 ceremonyId");c("[data-ceremony-detail]")&&(c("[data-ceremony-detail]").innerHTML=ue(k)),c("[data-ceremony-detail-title]")&&(c("[data-ceremony-detail-title]").textContent=k.ceremonyTitle),c("[data-ceremony-editor-action]")&&(c("[data-ceremony-editor-action]").href=W(n,r))}catch(t){if(g(e,t))return;o("[data-ceremony-detail]",s(t)?"当前账号无权查看该活动。":t.message||"活动详情加载失败",p(t)),o("[data-ceremony-gift-list]",s(t)?"当前账号无权查看该活动。":"祭品加载失败,请稍后重试。",p(t)),o("[data-ceremony-invitation-list]",s(t)?"当前账号无权查看该活动。":"邀请记录加载失败,请稍后重试。",p(t)),o("[data-ceremony-invitee-options]",s(t)?"当前账号无权查看该活动。":"成员选项加载失败,请稍后重试。",p(t)),D(s(t)?"当前账号无权查看该活动。":t.message||"活动详情加载失败");return}try{await Q(e,n,r)}catch(t){if(g(e,t))return;o("[data-ceremony-gift-list]",s(t)?"当前账号无权查看该活动祭品。":t.message||"祭品加载失败",p(t)),D(s(t)?"当前账号无权查看该活动祭品。":t.message||"祭品加载失败")}if(!v){o("[data-ceremony-invitation-list]","当前账号无权查看或维护受邀名单。","forbidden"),o("[data-ceremony-invitee-options]","当前账号无权查看或维护受邀名单。","forbidden");return}try{await ye(e,n,r)}catch(t){if(g(e,t))return;o("[data-ceremony-invitation-list]",s(t)?"当前账号无权查看或维护受邀名单。":t.message||"邀请记录加载失败",p(t)),o("[data-ceremony-invitee-options]",s(t)?"当前账号无权查看或维护受邀名单。":"成员选项加载失败,请稍后重试。",p(t)),D(s(t)?"当前账号无权查看或维护受邀名单。":t.message||"邀请记录加载失败")}}}async function De(e){var n=N(),r=U(),t=E(),i,a,f,l,I;if(!(w||!v||!r||g(n))){if(d.AppRichEditor&&d.AppRichEditor.syncAll&&d.AppRichEditor.syncAll(),i=ne(me(e)),a=re(i),a){o("[data-ceremony-form-status]",a,"error");return}delete i.invalidLongitude,delete i.invalidLatitude,delete i.invalidCoverOssId,delete i.invalidSortOrder,C(!0),o("[data-ceremony-form-status]","正在保存活动…","loading");try{if(f=L(t?await n.updateCeremony(r,t,i):await n.createCeremony(r,i)),l=t||f&&f.ceremonyId,!l)throw new Error("保存响应缺少 ceremonyId");if(I=L(await n.ceremonyDetail(r,l)),!I||I.ceremonyId!==l)throw new Error("保存后未能重读同一活动");d.NavigationUtil.open(de(r,l))}catch(h){if(g(n,h))return;o("[data-ceremony-form-status]",s(h)?"当前账号无权保存该活动。":h.message||"活动保存失败",p(h))}finally{C(!1)}}}async function ke(e){var n=N(),r=U(),t=E(),i,a,f;if(!(w||!v||!r||!t||g(n))){if(i=te(me(e)),a=ie(i),a){o("[data-ceremony-gift-status]",a,"error");return}delete i.invalidGiftAmount,C(!0),o("[data-ceremony-gift-status]","正在添加祭品…","loading");try{if(f=j(await n.createCeremonyGift(r,t,i)),!f||f.ceremonyId!==t)throw new Error("添加祭品响应缺少稳定 giftId");if(!(await Q(n,r,t)).some(function(l){return l.giftId===f.giftId}))throw new Error("添加后祭品列表未返回同一记录");e.reset(),o("[data-ceremony-gift-status]","祭品已添加")}catch(l){if(g(n,l))return;o("[data-ceremony-gift-status]",s(l)?"当前账号无权添加祭品。":l.message||"祭品添加失败",p(l))}finally{C(!1)}}}async function Le(){var e=N(),n=U(),r=E(),t,i;if(!(w||!v||!n||!r||g(e))){if(t=S("[data-invitee-user-id]"),!t.length){o("[data-ceremony-invitee-status]","当前没有可邀请的家谱成员","empty");return}i=oe(t.filter(function(a){return a.checked}).map(function(a){return a.getAttribute("data-invitee-user-id")})),C(!0),o("[data-ceremony-invitee-status]","正在更新受邀人…","loading");try{await e.replaceCeremonyInvitees(n,r,i.inviteeUserIds),await ye(e,n,r),o("[data-ceremony-invitee-status]","受邀名单已更新")}catch(a){if(g(e,a))return;o("[data-ceremony-invitee-status]",s(a)?"当前账号无权维护受邀名单。":a.message||"受邀名单更新失败",p(a))}finally{C(!1)}}}async function Pe(e){var n=N(),r=U(),t=V[e]||k;if(!(w||!v||!r||!y(e)||g(n))&&await G("确认删除“"+(t?t.ceremonyTitle:"该活动")+"”吗?删除后不可恢复。")){C(!0);try{await n.deleteCeremony(r,e),c("[data-ceremony-list-page]")?await ce():d.NavigationUtil.open(Ce(r))}catch(i){if(g(n,i))return;D(s(i)?"当前账号无权删除该活动。":i.message||"活动删除失败")}finally{C(!1)}}}async function Ge(e){var n=N(),r=U(),t=E(),i=q[e];if(!(w||!v||!r||!t||!y(e)||g(n))&&await G("确认删除“"+(i&&(i.giverName||i.giverNickName)||"该祭品")+"”的记录吗?")){C(!0);try{await n.deleteCeremonyGift(r,t,e),await Q(n,r,t),D("祭品记录已删除")}catch(a){if(g(n,a))return;D(s(a)?"当前账号无权删除该祭品。":a.message||"祭品删除失败")}finally{C(!1)}}}function Se(){b&&(b.addEventListener("click",function(e){var n=e.target.closest("[data-ceremony-delete-id]"),r=e.target.closest("[data-ceremony-gift-delete-id]");n?(e.preventDefault(),Pe(n.getAttribute("data-ceremony-delete-id"))):r&&(e.preventDefault(),Ge(r.getAttribute("data-ceremony-gift-delete-id")))}),b.addEventListener("submit",function(e){var n=e.target.closest("[data-ceremony-form]"),r=e.target.closest("[data-ceremony-gift-form]"),t=e.target.closest("[data-ceremony-invitee-form]");n?(e.preventDefault(),De(n)):r?(e.preventDefault(),ke(r)):t&&(e.preventDefault(),Le())}))}function Be(){b&&(Se(),c("[data-ceremony-list-page]")&&ce(),c("[data-ceremony-edit-page]")&&we(),c("[data-ceremony-detail-page]")&&Oe())}return{getCurrentGenealogyId:ee,getCurrentCeremonyId:E,buildCeremonyBody:ne,validateCeremonyBody:re,buildCeremonyGiftBody:te,validateCeremonyGiftBody:ie,normalizeCeremony:L,normalizeCeremonyGift:j,normalizeInvitation:$,normalizeInviteeOption:ae,buildInviteesBody:oe,canEditCeremonies:se,renderCeremonyDetail:ue,renderGiftList:le,shouldRedirectToLogin:fe,isForbidden:s,init:Be}});
diff --git a/dist/public/js/ceremony-pages.js b/dist/public/js/ceremony-pages.js
deleted file mode 100644
index 89bebd4..0000000
--- a/dist/public/js/ceremony-pages.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(r,l){if(typeof module=="object"&&module.exports){module.exports=l(r);return}r.CeremonyPages=l(r),r.document&&r.document.addEventListener("DOMContentLoaded",function(){r.CeremonyPages.init()})})(typeof globalThis!="undefined"?globalThis:window,function(r){"use strict";var l=r.document,m=Object.create(null),g="",N=!1,x=["PENDING","ACCEPTED","DECLINED","CANCELED"],G=["ACCEPTED","DECLINED"],L={PENDING:"待响应",ACCEPTED:"已接受",DECLINED:"已拒绝",CANCELED:"已取消"};function h(){return r.GenealogyApi&&r.GenealogyApi.defaultClient}function y(n,e){return l?(e||l).querySelector(n):null}function P(n,e){var t=e&&(e.status||e.code);return!n||!n.getToken||!n.getToken()||Number(t)===401}function f(n){return Number(n&&(n.status||n.code))===403}function I(n,e){return P(n,e)?(n&&n.clearToken&&n.clearToken(),r.NavigationUtil.open("login.html"),!0):!1}function p(n){return n==null||n===""||typeof n=="number"&&!Number.isSafeInteger(n)?"":/^[1-9][0-9]*$/.test(String(n))?String(n):""}function s(n){return n==null?"":String(n)}function V(n){var e;if(!(n==null||n===""))return e=Number(n),Number.isSafeInteger(e)?e:void 0}function R(n){var e;if(!(n==null||n===""))return e=Number(n),Number.isFinite(e)?e:void 0}function w(n){var e=p(n&&n.invitationId),t=p(n&&n.genealogyId),i=p(n&&n.ceremonyId),a=p(n&&n.inviteeUserId),c=s(n&&n.inviteStatus),u,C,A,S;return!e||!t||!i||x.indexOf(c)<0?null:(u={invitationId:e,genealogyId:t,ceremonyId:i,inviteStatus:c,deliveredTime:s(n.deliveredTime),readTime:s(n.readTime),responseTime:s(n.responseTime),ceremonyTitle:s(n.ceremonyTitle),ceremonyTime:s(n.ceremonyTime),location:s(n.location),locationAddress:s(n.locationAddress)},a&&(u.inviteeUserId=a),C=V(n.inviteVersion),A=R(n.longitude),S=R(n.latitude),C!==void 0&&(u.inviteVersion=C),A!==void 0&&(u.longitude=A),S!==void 0&&(u.latitude=S),u)}function U(n){return Array.isArray(n)?n:[]}function k(n){return{inviteStatus:s(n&&n.inviteStatus)}}function B(n){return!n||G.indexOf(n.inviteStatus)<0?"邀请只能选择接受或拒绝":""}function b(n){return!!(n&&n.inviteStatus==="PENDING")}function o(n){return s(n).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function T(n){return n.ceremonyTitle||"未命名贺礼活动"}function z(n){var e='';return b(n)&&(e+=''),''+o(T(n))+"
"+o(L[n.inviteStatus])+(n.ceremonyTime?" · "+o(n.ceremonyTime):"")+(n.location?" · "+o(n.location):"")+'
'+e+"
"}function v(n,e){return""+o(n)+""+o(e||"未提供")+"
"}function O(n){var e="";return n?(n.longitude!==void 0&&n.latitude!==void 0&&(e=' 打开地图'),'"):""}function D(n){var e=y("[data-my-invitation-detail]");if(g=n?n.invitationId:"",!!e){if(!n){d("[data-my-invitation-detail]","empty","请选择一条邀请查看详情");return}e.innerHTML=O(n)}}function j(n){var e=y("[data-my-invitation-list]"),t=U(n).map(w),i=t.filter(function(c){return!c}).length,a=t.filter(Boolean);return m=Object.create(null),a.forEach(function(c){m[c.invitationId]=c}),e?i?(d("[data-my-invitation-list]","error","邀请响应缺少稳定 ID 或合法状态,请联系后端核对 DTO。"),d("[data-my-invitation-detail]","error","邀请详情暂不可用,请联系后端核对 DTO。"),[]):a.length?(e.innerHTML=a.map(z).join(""),D(m[g]||a[0]),a):(d("[data-my-invitation-list]","empty","暂无贺礼邀请"),D(null),[]):a}function M(n){var e;N=n,l&&(e=l.querySelectorAll("[data-invitation-response]"),Array.prototype.forEach.call(e,function(t){t.disabled=n}))}function d(n,e,t){var i=y(n);if(i){if(!t){i.innerHTML="";return}if(e&&r.ProfileUI&&r.ProfileUI.setApiState){r.ProfileUI.setApiState(i,e,t);return}i.textContent=t}}async function E(){var n=h();if(!I(n)){d("[data-my-invitation-list]","loading","正在加载我的邀请…"),d("[data-my-invitation-detail]","loading","正在加载邀请详情…");try{j(await n.myCeremonyInvitations())}catch(e){if(I(n,e))return;d("[data-my-invitation-list]",f(e)?"forbidden":"error",f(e)?"当前账号无权查看邀请。":e.message||"邀请加载失败"),d("[data-my-invitation-detail]",f(e)?"forbidden":"error",f(e)?"当前账号无权查看邀请。":"邀请详情加载失败,请稍后重试。")}}}async function q(n,e){var t=h(),i=m[p(n)],a=k({inviteStatus:e}),c=B(a);if(!(N||I(t)||!i||!b(i))&&!c){M(!0),d("[data-my-invitation-status]","loading","正在更新邀请状态…");try{await t.respondCeremonyInvitation(i.genealogyId,i.ceremonyId,a),g=i.invitationId,await E(),d("[data-my-invitation-status]","","邀请状态已更新。")}catch(u){if(I(t,u))return;d("[data-my-invitation-status]",f(u)?"forbidden":"error",f(u)?"当前账号无权响应该邀请。":u.message||"邀请响应失败")}finally{M(!1)}}}function H(){l&&l.addEventListener("click",function(n){var e=n.target.closest("[data-invitation-detail]"),t=n.target.closest("[data-invitation-response]");if(e){n.preventDefault(),D(m[e.getAttribute("data-invitation-detail")]||null);return}t&&(n.preventDefault(),q(t.getAttribute("data-invitation-id"),t.getAttribute("data-invitation-response")))})}function F(){!l||!y("[data-ceremony-page]")||(H(),E())}return{normalizeInvitation:w,normalizeList:U,buildInvitationResponseBody:k,validateInvitationResponseBody:B,canRespondToInvitation:b,renderInvitationRow:z,renderInvitationDetail:O,shouldRedirectToLogin:P,isForbidden:f,loadMyInvitations:E,init:F}});
diff --git a/dist/public/js/earning-pages.js b/dist/public/js/earning-pages.js
deleted file mode 100644
index 69c2641..0000000
--- a/dist/public/js/earning-pages.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(t,c){if(typeof module=="object"&&module.exports){module.exports=c(t);return}t.EarningPages=c(t),t.document&&t.document.addEventListener("DOMContentLoaded",t.EarningPages.init)})(typeof globalThis!="undefined"?globalThis:window,function(t){"use strict";function c(r){return t.ProfileUI&&typeof t.ProfileUI.confirmAction=="function"?t.ProfileUI.confirmAction(r):Promise.resolve(!t.confirm||t.confirm(r))}var D={PENDING:"待审核",APPROVED:"已通过",PAYING:"打款中",PAID:"已到账",REJECTED:"已驳回",FAILED:"打款失败",CANCELLED:"已取消"},N={PAYMENT_REWARD:"推广奖励",PAYMENT_REFUND_REVERSAL:"退款冲销",WITHDRAWAL_FREEZE:"提现冻结",WITHDRAWAL_CANCEL:"取消提现",WITHDRAWAL_REJECT:"提现驳回",WITHDRAWAL_PAID:"提现到账",WITHDRAWAL_FAILED:"提现失败"};function i(r){return String(r==null?"":r).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function f(r){var e=String(r==null?"":r).trim();return/^(?:0|[1-9][0-9]*)(?:\.[0-9]{1,2})?$/.test(e)?e:""}function g(){return t.crypto&&typeof t.crypto.randomUUID=="function"?t.crypto.randomUUID():"pc-"+Date.now()+"-"+Math.random().toString(16).slice(2)}function p(r){var e=f(r),a;return e?(a=e.split("."),BigInt(a[0])*BigInt(100)+BigInt((a[1]||"").padEnd(2,"0"))):null}function y(r,e){var a=r||{};return{requestId:String(e||"").trim(),amount:f(a.amount),payoutQrOssId:String(a.payoutQrOssId||"").trim(),payoutAccountName:String(a.payoutAccountName||"").trim()}}function v(r,e){return r.requestId?!r.amount||Number(r.amount)<=0?"请输入有效提现金额,最多两位小数":p(e)!==null&&p(r.amount)>p(e)?"提现金额不能超过可用余额":/^[1-9][0-9]*$/.test(r.payoutQrOssId)?r.payoutAccountName?r.payoutAccountName.length>64?"收款人姓名不能超过 64 个字符":"":"请填写收款人姓名":"请上传收款码":"提现请求号生成失败,请刷新页面重试"}function A(r){var e=r||{};return'可用收益
¥'+i(e.availableAmount||"0.00")+'冻结金额
¥'+i(e.frozenAmount||"0.00")+'最低提现
'+i(e.minimumWithdrawal?"¥"+e.minimumWithdrawal:"以提交校验为准")+" "}function h(r){var e=r&&Array.isArray(r.rows)?r.rows:[];return e.length?e.map(function(a){return''+i(N[a.entryType]||a.entryType||"收益变动")+"
"+i([a.createTime,a.remark].filter(Boolean).join(" · "))+"
"+i(String(a.availableDelta||"0.00"))+""}).join(""):'当前没有收益流水
'}function E(r){var e=r&&Array.isArray(r.rows)?r.rows:[];return e.length?e.map(function(a){var m=String(a.withdrawalId||"").trim();return'提现 ¥'+i(a.amount||"0.00")+"
"+i([a.withdrawalNo,a.payoutAccountName,a.createTime,a.auditRemark,a.failureReason].filter(Boolean).join(" · "))+'
'+i(D[a.withdrawalStatus]||a.withdrawalStatus||"未知")+""+(a.withdrawalStatus==="PENDING"&&/^[1-9][0-9]*$/.test(m)?'':"")+""}).join(""):'当前没有提现记录
'}async function L(){var r=t.document&&t.document.querySelector("[data-earning-page]"),e=t.GenealogyApi&&t.GenealogyApi.defaultClient,a=r&&r.querySelector("[data-earning-summary]"),m=r&&r.querySelector("[data-earning-ledger]"),I=r&&r.querySelector("[data-earning-withdrawals]"),o=r&&r.querySelector("[data-withdrawal-form]"),S=r&&r.querySelector("[data-earning-status]"),T="",W=g(),d=!1;if(!r)return;if(!e||!e.getToken||!e.getToken()){t.NavigationUtil.open("login.html");return}function u(n,l){n?t.ProfileUI.setApiState(S,n,l):S.textContent=l||""}async function w(){var n=await Promise.all([e.earningSummary(),e.earningLedger({pageNum:1,pageSize:20}),e.earningWithdrawals({pageNum:1,pageSize:20})]);return T=String(n[0]&&n[0].availableAmount||""),a.innerHTML=A(n[0]),m.innerHTML=h(n[1]),I.innerHTML=E(n[2]),o.querySelector("[data-withdrawal-submit]").disabled=n[0]&&n[0].withdrawalEnabled===!1,n}try{await w(),u("","收益数据已加载")}catch(n){u("error",n.message||"收益数据读取失败");return}o.addEventListener("submit",async function(n){var l,s;if(n.preventDefault(),!d){if(l=y({amount:o.elements.amount.value,payoutAccountName:o.elements.payoutAccountName.value,payoutQrOssId:o.elements.payoutQrOssId.value},W),s=v(l,T),s)return u("error",s);d=!0,u("loading","正在提交提现申请…");try{await e.createEarningWithdrawal(l),W=g(),o.reset(),o.elements.payoutQrOssId.value="",await w(),u("","提现申请已提交")}catch(R){u("error",R.message||"提现申请失败")}finally{d=!1}}}),I.addEventListener("click",async function(n){var l=n.target.closest("[data-withdrawal-cancel]");if(!(!l||d||!await c("确认取消这笔待审核提现吗?"))){d=!0,u("loading","正在取消提现…");try{await e.cancelEarningWithdrawal(l.getAttribute("data-withdrawal-cancel")),await w(),u("","提现已取消")}catch(s){u("error",s.message||"取消提现失败")}finally{d=!1}}})}return{normalizeMoney:f,createRequestId:g,buildWithdrawalBody:y,validateWithdrawalBody:v,renderSummary:A,renderLedger:h,renderWithdrawals:E,init:L}});
diff --git a/dist/public/js/family-home-pages.js b/dist/public/js/family-home-pages.js
deleted file mode 100644
index 679151f..0000000
--- a/dist/public/js/family-home-pages.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(a,m){if(typeof module=="object"&&module.exports){module.exports=m(a);return}a.FamilyHomePages=m(a),a.document&&a.document.addEventListener("DOMContentLoaded",function(){a.FamilyHomePages.init()})})(typeof globalThis!="undefined"?globalThis:window,function(a){"use strict";var m=a.MediaDisplay||(typeof require=="function"?require("./media-display.js"):null);function c(e){return String(e==null?"":e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function v(e){var n;return typeof e=="number"&&!Number.isSafeInteger(e)||e==null?"":(n=String(e).trim(),/^[1-9][0-9]*$/.test(n)?n:"")}function g(e){return e==null?"":String(e).trim()}function P(e){var n=Number(e);return Number.isSafeInteger(n)&&n>=0?n:null}function h(e,n){var r=e||{},i=v(r.genealogyId),o=v(n),t=P(r.memberCount),b=P(r.personCount),w=m&&m.normalizeFileAccess(r.coverFile),I;return!i||i!==o||!g(r.genealogyName)||String(r.status)!=="0"||t===null||b===null||(I={genealogyId:i,genealogyNo:g(r.genealogyNo),genealogyName:g(r.genealogyName),surname:g(r.surname),ancestralHall:g(r.ancestralHall),originPlace:g(r.originPlace),regionFullName:g(r.regionFullName),memberCount:t,personCount:b,canManage:r.canManage===!0,canEditContent:r.canEditContent===!0},r.coverFile!==void 0&&r.coverFile!==null&&!w)?null:(w&&(I.coverFile=w),I)}function F(e){var n=e||{},r=[n.genealogyNo?"家谱编号 "+n.genealogyNo:"",n.surname?"姓氏 "+n.surname:"",n.ancestralHall?"堂号 "+n.ancestralHall:"",n.originPlace?"祖籍 "+n.originPlace:"",n.regionFullName?"地区 "+n.regionFullName:""].filter(Boolean).join(" · ");return(m?m.renderImage(n.coverFile,{alt:n.genealogyName+"封面",className:"family-cover-media"}):"")+""+c(n.genealogyName)+"
"+c(r)+"
成员 "+c(n.memberCount)+" 人 · 世系人物 "+c(n.personCount)+" 人
"}function C(e){return!!e&&e.canManage===!0}function s(e,n){var r=n&&(n.status||n.code);return!e||!e.getToken||!e.getToken()||Number(r)===401}function l(e){return Number(e&&(e.status||e.code))===403}async function H(e,n){var r=v(n),i,o;if(!r||!e||!e.genealogyOverview||!e.lineageTree)throw new Error("家谱主页接口初始化失败");if(i=await Promise.all([e.genealogyOverview(r),e.lineageTree(r)]),o=h(i[0],r),!o)throw new Error("家谱概览响应无效");return{overview:o,tree:i[1]}}function p(e){e&&e.clearToken&&e.clearToken(),a.NavigationUtil.open("login.html")}function d(e){return a.document&&a.document.querySelector(e)}function S(e){return a.document?Array.prototype.slice.call(a.document.querySelectorAll(e)):[]}function y(e,n){var r=d(e);r&&(r.textContent=n)}function u(e,n,r){var i=d(e);if(i){if(a.ProfileUI&&a.ProfileUI.setApiState){a.ProfileUI.setApiState(i,n,r);return}i.textContent=r}}function f(e,n){var r=d("[data-family-home-status]");if(r){if(r.hidden=!e,!e){r.innerHTML="";return}if(n&&a.ProfileUI&&a.ProfileUI.setApiState){a.ProfileUI.setApiState(r,n,e);return}r.textContent=e}}async function N(){var e=d("[data-family-home-page]"),n=a.GenealogyApi&&a.GenealogyApi.defaultClient,r,i,o;if(e){if(s(n)){p(n);return}if(r=a.ProfileUI&&a.ProfileUI.getGenealogyId(),!r){a.NavigationUtil.open("profile-families.html?next=profile-family-home.html");return}if(a.ProfileUI&&a.ProfileUI.syncGenealogyContextLinks&&a.ProfileUI.syncGenealogyContextLinks(),!a.LineagePages||!a.LineagePages.renderLineageTreeHtml){u("[data-family-home-overview]","error","家谱主页初始化失败,请刷新后重试。"),u("[data-lineage-home-tree]","error","世系预览初始化失败,请刷新后重试。"),f("世系预览初始化失败,请刷新后重试。","error");return}u("[data-family-home-overview]","loading","正在加载家谱概览…"),u("[data-lineage-home-tree]","loading","正在加载世系树…"),f("正在读取家谱概览…","loading");try{if(i=h(await n.genealogyOverview(r),r),!i)throw new Error("家谱概览响应无效");a.ProfileUI&&a.ProfileUI.setCurrentGenealogyContext&&a.ProfileUI.setCurrentGenealogyContext(i.genealogyId,i.genealogyName),y("[data-family-home-title]",i.genealogyName),y("[data-family-home-context]",i.genealogyName),d("[data-family-home-overview]").innerHTML=F(i),y("[data-family-home-member-count]",String(i.memberCount)),y("[data-family-home-person-count]",String(i.personCount)),S("[data-family-home-management]").forEach(function(t){t.hidden=!C(i)})}catch(t){if(s(n,t)){p(n);return}u("[data-family-home-overview]",l(t)?"forbidden":"error",l(t)?"当前账号无权查看该家谱。":"家谱概览读取失败,请稍后重试。"),u("[data-lineage-home-tree]",l(t)?"forbidden":"error",l(t)?"当前账号无权查看该家谱。":"世系树读取失败,请稍后重试。"),f(l(t)?"当前账号无权查看该家谱。":t.message||"家谱主页读取失败,请稍后重试。",l(t)?"forbidden":"error");return}try{i=await n.lineageTree(r),o=Array.isArray(i)?a.LineagePages.renderLineageTreeHtml(i):"",o?d("[data-lineage-home-tree]").innerHTML=o:u("[data-lineage-home-tree]","empty","暂无世系树"),f("")}catch(t){if(s(n,t)){p(n);return}u("[data-lineage-home-tree]",l(t)?"forbidden":"error",l(t)?"当前账号无权查看该家谱世系树。":"世系树读取失败,请稍后重试。"),f(l(t)?"当前账号无权查看该家谱世系树。":t.message||"世系树读取失败,请稍后重试。",l(t)?"forbidden":"error")}}}function T(){return N()}return{normalizeFamilyOverview:h,renderFamilyOverview:F,shouldShowFamilyManagement:C,shouldRedirectToLogin:s,isForbidden:l,loadFamilyHome:H,initFamilyHomePage:N,init:T}});
diff --git a/dist/public/js/family-invite-pages.js b/dist/public/js/family-invite-pages.js
deleted file mode 100644
index 63073a5..0000000
--- a/dist/public/js/family-invite-pages.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(n,g){if(typeof module=="object"&&module.exports){module.exports=g(n);return}n.FamilyInvitePages=g(n),n.document&&n.document.addEventListener("DOMContentLoaded",n.FamilyInvitePages.init)})(typeof globalThis!="undefined"?globalThis:window,function(n){"use strict";var g={ACTIVE:"待使用",REDEEMED:"已使用",REVOKED:"已撤销",EXPIRED:"已过期"};function u(e){return String(e==null?"":e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function I(e){var t=String(e==null?"":e).trim();return/^[1-9][0-9]*$/.test(t)?t:""}function y(e){var t=e||{},a=I(t.inviteId),c=I(t.genealogyId);return!a||!c||!String(t.genealogyName||"").trim()?null:{inviteId:a,genealogyId:c,genealogyName:String(t.genealogyName).trim(),lineagePersonName:String(t.lineagePersonName||"").trim(),status:String(t.status||"").toUpperCase(),token:String(t.token||"").trim(),expiresAt:String(t.expiresAt||"").trim(),createTime:String(t.createTime||"").trim()}}function A(e){var t;return e?n.location?(t=String(n.location.href||"").split("?")[0].split("#")[0],t+"?token="+encodeURIComponent(e)):"profile-invite.html?token="+encodeURIComponent(e):""}function S(e){var t=Array.isArray(e)?e.map(y).filter(Boolean):[];return t.length?t.map(function(a){var c=a.status==="ACTIVE";return''+u(a.genealogyName)+(a.lineagePersonName?" · "+u(a.lineagePersonName):"")+"
"+u([a.createTime,a.expiresAt?"有效期至 "+a.expiresAt:""].filter(Boolean).join(" · "))+'
'+u(g[a.status]||a.status||"未知")+""+(c?'':"")+"
"}).join(""):'还没有发出的邀请
'}function P(e){e&&e.clearToken&&e.clearToken(),n.NavigationUtil.open("login.html")}async function b(){var e=n.document&&n.document.querySelector("[data-family-invite-page]"),t=n.GenealogyApi&&n.GenealogyApi.defaultClient,a=n.ProfileUI&&n.ProfileUI.getGenealogyId?n.ProfileUI.getGenealogyId():"",c=e&&e.querySelector("[data-invite-form]"),k=e&&e.querySelector("[data-invite-person]"),h=e&&e.querySelector("[data-invite-status]"),v=e&&e.querySelector("[data-invite-result]"),f=e&&e.querySelector("[data-invite-list]"),d=e&&e.querySelector("[data-invite-redeem]"),m=n.location?new URLSearchParams(n.location.search).get("token"):"",l=!1;if(!e)return;if(!t||!t.getToken||!t.getToken())return P(t);if(m&&d){c.hidden=!0,f.hidden=!0,d.hidden=!1,d.querySelector("[data-invite-token]").textContent=m;try{var p=y(await t.previewGenealogyInvitation(m));if(!p)throw new Error("邀请预览响应无效");d.querySelector("h3").textContent="接受“"+p.genealogyName+"”邀请",i("",p.expiresAt?"邀请有效期至 "+p.expiresAt:"请确认是否加入该家谱")}catch(r){i("error",r.message||"邀请预览失败"),d.querySelector("[data-invite-redeem-submit]").disabled=!0;return}d.querySelector("[data-invite-redeem-submit]").addEventListener("click",async function(){if(!l){l=!0,i("loading","正在接受邀请…");try{await t.redeemGenealogyInvitation({token:m}),i("","邀请已接受,你已加入该家谱。")}catch(r){i("error",r.message||"接受邀请失败")}finally{l=!1}}});return}if(!a){n.ProfileUI.setApiState(h,"error","缺少家谱上下文,请从“我的家谱”重新进入。");return}function i(r,o){r?n.ProfileUI.setApiState(h,r,o):h.textContent=o||""}async function E(){var r=await t.myGenealogyInvitations();f.innerHTML=S(r)}try{var T=await Promise.all([t.lineagePersonOptions(a),t.myGenealogyInvitations()]);k.innerHTML=''+(Array.isArray(T[0])?T[0]:[]).map(function(r){var o=I(r.personId||r.lineagePersonId),s=String(r.displayName||r.personName||r.name||"").trim();return o&&s?'":""}).join(""),f.innerHTML=S(T[1]),i("","可生成一次性邀请链接")}catch(r){i("error",r.message||"邀请服务读取失败")}c.addEventListener("submit",async function(r){var o={},s,w;if(r.preventDefault(),!l){k.value&&(o.lineagePersonId=k.value),l=!0,i("loading","正在生成邀请…");try{if(s=y(await t.issueGenealogyInvitation(a,o)),!s||!s.token)throw new Error("邀请已创建,但响应缺少一次性令牌");w=A(s.token),v.hidden=!1,v.querySelector("[data-invite-link]").value=w,i("","邀请已生成,请及时复制给家人。"),await E()}catch(q){i("error",q.message||"邀请生成失败")}finally{l=!1}}}),v.querySelector("[data-invite-copy]").addEventListener("click",async function(){var r=v.querySelector("[data-invite-link]").value;try{await n.navigator.clipboard.writeText(r),i("","邀请链接已复制")}catch(o){v.querySelector("[data-invite-link]").select(),i("","请按 Ctrl+C 复制邀请链接")}}),f.addEventListener("click",async function(r){var o=r.target.closest("[data-invite-revoke]");if(!(!o||l)){l=!0,i("loading","正在撤销邀请…");try{await t.revokeGenealogyInvitation(o.getAttribute("data-invite-revoke")),await E(),i("","邀请已撤销")}catch(s){i("error",s.message||"撤销邀请失败")}finally{l=!1}}})}return{normalizeInvitation:y,invitationLink:A,renderInvitations:S,init:b}});
diff --git a/dist/public/js/feed-pages.js b/dist/public/js/feed-pages.js
deleted file mode 100644
index bd7fa79..0000000
--- a/dist/public/js/feed-pages.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(i,T){if(typeof module=="object"&&module.exports){module.exports=T(i);return}i.FeedPages=T(i),i.document&&i.document.addEventListener("DOMContentLoaded",function(){i.FeedPages.init()})})(typeof globalThis!="undefined"?globalThis:window,function(i){"use strict";function T(e){return i.ProfileUI&&typeof i.ProfileUI.confirmAction=="function"?i.ProfileUI.confirmAction(e):Promise.resolve(!i.confirm||i.confirm(e))}var E=i.MediaDisplay||(typeof require=="function"?require("./media-display.js"):null),F=i.document,H=20,I=1,U={},L={},M={},c={userId:"",canEditContent:!1,canManage:!1};function w(){return i.GenealogyApi&&i.GenealogyApi.defaultClient}function ee(e,t){var a=t&&(t.status||t.code);return!e||!e.getToken||!e.getToken()||Number(a)===401}function u(e,t){return ee(e,t)?(e&&e.clearToken&&e.clearToken(),i.NavigationUtil.open("login.html"),!0):!1}function o(e,t){return F?(t||F).querySelector(e):null}function y(e,t){return F?Array.prototype.slice.call((t||F).querySelectorAll(e)):[]}function m(e){if(i.layui&&i.layui.layer){i.layui.layer.msg(e);return}i.alert&&i.alert(e)}function s(e){return Number(e&&(e.status||e.code))===403?"forbidden":"error"}function C(e,t){var a=o("[data-feed-form-status]");if(a){if(!e){a.innerHTML="";return}if(i.ProfileUI&&i.ProfileUI.setApiState){i.ProfileUI.setApiState(a,t||"error",e);return}a.textContent=e}}function g(e,t,a){var n=o(e);if(n){if(i.ProfileUI&&i.ProfileUI.setApiState){i.ProfileUI.setApiState(n,t,a);return}n.innerHTML=''+l(a)+"
"}}function q(e){var t=o("[data-feed-form]");t&&y("input, textarea, select, button",t).forEach(function(a){a.disabled=!e}),y("[data-feed-editor-action]").forEach(function(a){a.hidden=!e,a.disabled=!e})}function te(e){var t='[data-feed-form] [type="submit"], [type="submit"][form="feed-edit-form"]';y(t).forEach(function(a){a.dataset.defaultLabel||(a.dataset.defaultLabel=a.textContent),a.disabled=!!e,a.textContent=e?"正在保存…":a.dataset.defaultLabel,a.setAttribute("aria-busy",e?"true":"false")})}function v(e,t){var a=o("[data-feed-comment-form-status]");if(a){if(!e){a.innerHTML="";return}if(i.ProfileUI&&i.ProfileUI.setApiState){i.ProfileUI.setApiState(a,t||"error",e);return}a.textContent=e}}function O(e){var t=o("[data-feed-comment-form]");t&&y("input, textarea, button",t).forEach(function(a){a.disabled=!e})}function ae(e){y('[data-feed-comment-form] [type="submit"]').forEach(function(t){t.dataset.defaultLabel||(t.dataset.defaultLabel=t.textContent),t.textContent=e?"正在发布…":t.dataset.defaultLabel,t.setAttribute("aria-busy",e?"true":"false")})}function V(e){var t=o("[data-feed-comment-form]"),a=o("[data-feed-comment-form-target]"),n=e?p(e):"";t&&(o('[name="parentCommentId"]',t)&&(o('[name="parentCommentId"]',t).value=n),a&&(a.textContent=n?"正在回复这条评论":"发表公开评论"))}function ne(e,t){var a=Z(),n,r;if(!(!e||!a)){if(!o("[data-feed-detail-page]")){i.NavigationUtil.open(h("detail",a,e));return}N()===p(e)&&(n=o("[data-feed-comment-form]"),r=n&&o('[type="submit"]',n),!(!n||!r||r.disabled)&&(V(t),v(""),o('[name="commentContent"]',n)&&o('[name="commentContent"]',n).focus&&o('[name="commentContent"]',n).focus()))}}function Q(e,t){var a=new URLSearchParams(String(e||"").replace(/^\?/,""));return a.get(t)||""}function Z(e){var t=o("[data-feed-page], [data-feed-edit-page], [data-feed-detail-page]"),a=e===void 0&&i.location?i.location.search:e,n;return e===void 0&&i.ProfileUI&&i.ProfileUI.getGenealogyId&&(n=i.ProfileUI.getGenealogyId(),n)?n:Q(a,"genealogyId")||t&&t.getAttribute("data-genealogy-id")||""}function N(e){var t=e===void 0&&i.location?i.location.search:e;return Q(t,"feedId")}function P(e){var t=String(e==null?"":e).trim();return t||void 0}function ye(e){var t=P(e),a;if(t)return a=Number(t),Number.isSafeInteger(a)&&a>=0?a:void 0}function p(e){var t;return e==null||e===""?"":(t=String(e),/^\d+$/.test(t)?t:"")}function re(e,t,a){return a.forEach(function(n){t[n]!==void 0&&t[n]!==null&&(e[n]=t[n])}),e}function S(e){var t=Number(e);return(!Number.isSafeInteger(t)||t<1)&&(t=1),{pageNum:t,pageSize:H}}function h(e,t,a){var n=new URLSearchParams,r="profile-feed.html";return n.set("genealogyId",p(t)),(e==="detail"||e==="edit")&&(n.set("feedId",p(a)),r=e==="detail"?"profile-feed-detail.html":"profile-feed-edit.html"),r+"?"+n.toString()}function ie(e,t,a){return String(a||"0")==="1"?h("list",e):h("detail",e,t)}function D(e,t){var a;if(M[e])return M[e];try{a=Promise.resolve(t())}catch(n){a=Promise.reject(n)}return M[e]=a.finally(function(){delete M[e]}),M[e]}function de(e){var t=e||{},a=P(t.mediaOssIds),n=P(t.status),r={feedType:P(t.feedType)||"text",feedContent:String(t.feedContent||"").trim()},d=ye(t.sortOrder);if(n!==void 0&&n!=="0"&&n!=="1")throw new Error("动态状态只能是 0 或 1");if(P(t.sortOrder)!==void 0&&d===void 0)throw new Error("排序值必须是非负整数");return a!==void 0&&(r.mediaOssIds=a),n!==void 0&&(r.status=n),d!==void 0&&(r.sortOrder=d),r}function oe(e){var t=e||{},a={commentContent:String(t.commentContent||"").trim()},n=P(t.parentCommentId);return n!==void 0&&(a.parentCommentId=n),a}function le(e){return p(e&&e.feedId)}function Ce(e){return p(e&&e.commentId)}function x(e){var t=le(e),a=e&&e.feedContent,n;if(!t||a===void 0||a===null)return null;n=re({feedId:t,feedContent:String(a)},e,["genealogyNo","genealogyName","publisherNickName","publisherStatus","feedType","likedByMe","likeCount","commentCount","pinned","pinnedTime","sortOrder","status","remark","createTime","updateTime"]);var r=E?E.normalizeFileList(e&&e.mediaFiles):[];return r.length&&(n.mediaFiles=r),p(e.genealogyId)&&(n.genealogyId=p(e.genealogyId)),p(e.publisherUserId)&&(n.publisherUserId=p(e.publisherUserId)),n}function fe(e){var t=Ce(e),a=e&&e.commentContent,n;if(!t||a===void 0)return null;n=String(e&&e.userDeleted||"")==="1";var r={commentId:t,commentContent:a===null?"该评论已删除":String(a),appUserNickName:P(e&&e.appUserNickName),replyCount:e&&e.replyCount,userDeleted:n||a===null};return re(r,e,["appUserAvatar","parentAppUserNickName","commentLevel","status","createTime"]),["genealogyId","feedId","parentCommentId","appUserId","parentAppUserId"].forEach(function(d){p(e&&e[d])&&(r[d]=p(e[d]))}),r}function _(e){return Array.isArray(e)?e:e&&Array.isArray(e.rows)?e.rows:[]}function l(e){return String(e==null?"":e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function R(e,t){return i.ProfileUI&&i.ProfileUI.renderApiState?i.ProfileUI.renderApiState(e,t):''+l(t)+"
"}function B(e,t){var a=o('[data-feed-id="'+e+'"]'),n=a&&a.nextElementSibling;a&&(n&&n.getAttribute("data-feed-comment-list")===e&&n.remove(),a.insertAdjacentHTML("afterend",''+t+"
"))}function ue(e,t){var a=o('[data-feed-comment-node="'+e+'"]'),n=a&&a.nextElementSibling;a&&(n&&n.getAttribute("data-feed-reply-list")===e&&n.remove(),a.insertAdjacentHTML("afterend",t))}function z(e,t,a){ue(e,''+R(t,a)+"
")}function Me(e,t){return h(t?"edit":"list",e,t)}function he(e,t){var a=c.userId&&c.userId===e.publisherUserId,n=Array.isArray(e.mediaFiles)?e.mediaFiles.length:0,r=e.publisherNickName||e.genealogyName||"家族动态",d=[],f="";return(e.pinned===!0||String(e.pinned)==="1")&&d.push("置顶"),e.createTime&&d.push(e.createTime),n&&d.push("附件 "+n),d.push("点赞 "+Number(e.likeCount||0)),d.push("评论 "+Number(e.commentCount||0)),f+=e.likedByMe?'':'',f+='查看详情',f+='',f+='',c.canEditContent&&(f+='编辑'),a&&(f+=''),''+l(r)+"
"+l(e.feedContent)+"
"+(E?E.renderGallery(e.mediaFiles,{label:"动态附件",className:"feed-media-gallery"}):"")+'
'+l(d.join(" · "))+'
'+f+"
"}function Ie(e,t){var a=o("[data-feed-list]"),n=_(e).map(x),r=n.filter(function(f){return!f}).length,d=n.filter(Boolean);if(a){if(r){g("[data-feed-list]","error","动态响应缺少 feedId 或 feedContent,请联系后端补充 DTO。");return}if(!d.length){g("[data-feed-list]","empty","暂无家族动态");return}a.innerHTML=d.map(function(f){return he(f,t)}).join("")}}function $(e){var t=Number(e&&e.total);return Number.isFinite(t)&&t>=0?t:0}function we(e){var t=$(e),a=Math.max(1,Math.ceil(t/H)),n=o("[data-feed-page-prev]"),r=o("[data-feed-page-next]"),d=o("[data-feed-page-label]");n&&(n.disabled=I<=1),r&&(r.disabled=I>=a),d&&(d.textContent="第 "+I+" / "+a+" 页,共 "+t+" 条")}function Ae(e){var t=e&&e.replyCount;return t!=null&&String(t)!==""&&String(t)!=="0"}function se(e,t){var a=t.appUserNickName?""+l(t.appUserNickName)+" ":"",n="",r=c.userId&&c.userId===t.appUserId;return t.userDeleted||(n+='',r&&(n+='')),Ae(t)&&(n+=''),''+a+l(t.commentContent)+"
"+(t.createTime?'
'+l(t.createTime)+"
":"")+n+"
"}function J(e){var t=_(e).map(fe);return{invalidCount:t.filter(function(a){return!a}).length,comments:t.filter(Boolean)}}function Fe(e,t){var a=o("[data-feed-detail-comments]"),n=o('[data-feed-id="'+e+'"]'),r=J(t),d=r.comments,f;if(!(!n&&!a)){if(r.invalidCount){f=R("error","评论响应缺少 commentId 或 commentContent,请联系后端补充 DTO。"),a?g("[data-feed-detail-comments]","error","评论响应缺少 commentId 或 commentContent,请联系后端补充 DTO。"):B(e,f);return}if(!d.length){f=R("empty","暂无评论"),a?g("[data-feed-detail-comments]","empty","暂无评论"):B(e,f);return}f=''+d.map(function(b){return se(e,b)}).join("")+"
"+ce("comments",e,"",U[e]||1,$(t)),a?a.innerHTML=f:B(e,f)}}function Ue(e,t,a){var n=o('[data-feed-comment-node="'+t+'"]'),r=J(a);if(n){if(r.invalidCount){z(t,"error","回复响应缺少 commentId 或 commentContent,请联系后端补充 DTO。");return}if(!r.comments.length){z(t,"empty","暂无直接回复");return}ue(t,''+r.comments.map(function(d){return se(e,d)}).join("")+ce("replies",e,t,L[t]||1,$(a))+"
")}}function ce(e,t,a,n,r){var d=Math.max(1,Math.ceil(r/H)),f=e==="comments"?"data-feed-comments-":"data-feed-replies-",b=' data-feed-id="'+l(t)+'"'+(a?' data-comment-id="'+l(a)+'"':"");return'第 "+n+" / "+d+' 页
"}function me(e){var t={};return y("[name]",e).forEach(function(a){a.disabled||(t[a.name]=a.value)}),t}function Pe(e){var t=x(e);if(!t)throw new Error("动态响应缺少 feedId 或 feedContent,请联系后端补充 DTO。");y("[data-feed-form] [name]").forEach(function(a){t[a.name]!==void 0&&t[a.name]!==null&&(a.value=t[a.name])})}function pe(e){return!!(e&&(e.canEditContent===!0||e.canManage===!0))}function Se(e){y("[data-feed-create-link]").forEach(function(t){t.hidden=!e})}function ge(e,t){return{userId:p(t&&t.userId),canEditContent:pe(e),canManage:!!(e&&e.canManage===!0)}}async function K(e,t){var a,n;try{a=await e.genealogyDetail(t)}catch(r){a=null}try{n=await e.currentProfile()}catch(r){n=null}return c=ge(a,n),Se(c.canEditContent),c}function W(e,t){var a=o("[data-feed-detail]"),n=c.userId&&c.userId===e.publisherUserId,r="";a&&(r+=e.likedByMe?'':'',r+='',r+='',c.canEditContent&&(r+='编辑'),n&&(r+=''),a.setAttribute("data-feed-id",e.feedId),a.innerHTML=""+l(e.publisherNickName||e.genealogyName||"家族动态")+"
"+l(e.feedContent)+"
"+(E?E.renderGallery(e.mediaFiles,{label:"动态附件",className:"feed-media-gallery"}):"")+''+l([e.createTime||"","点赞 "+Number(e.likeCount||0),"评论 "+Number(e.commentCount||0),String(e.status)==="1"?"已停用":"正常"].filter(Boolean).join(" · "))+'
'+r+"
")}function X(e){i.ProfileUI&&i.ProfileUI.syncGenealogyContextLinks&&i.ProfileUI.syncGenealogyContextLinks(),y("[data-feed-create-link], [data-feed-list-link]").forEach(function(t){t.href=t.hasAttribute("data-feed-create-link")?h("edit",e):h("list",e)})}function A(){var e=Z(),t;return e||(t=o("[data-feed-list]"),t&&g("[data-feed-list]","forbidden","请从具体家谱进入家族圈动态。"),q(!1),C("请从具体家谱进入动态发布。","forbidden"),O(!1),v("请从具体家谱进入动态详情后发表评论。","forbidden"),m("请从具体家谱进入家族圈动态")),e}async function k(e){var t=w(),a,n;if(!u(t)&&(a=A(),!!a)){X(a),I=S(e||Q(i.location&&i.location.search,"pageNum")).pageNum,g("[data-feed-list]","loading","正在加载家族动态…");try{await K(t,a),n=await t.feedsPage(a,S(I)),Ie(n,a),we(n)}catch(r){if(u(t,r))return;g("[data-feed-list]",s(r),s(r)==="forbidden"?"当前账号无权查看该家谱的动态。":"家族动态加载失败,请稍后重试。"),m(r.message||"家族动态加载失败")}}}async function Ee(){var e=w(),t,a=N(),n=!!a,r=n?"编辑动态":"发布动态";if(i.document&&(i.document.title=r+" - 个人中心 - 代代相传"),o("[data-feed-editor-kicker]")&&(o("[data-feed-editor-kicker]").textContent=r),o("[data-feed-editor-title]")&&(o("[data-feed-editor-title]").textContent=r),y("[data-feed-editor-action]").forEach(function(d){d.textContent=n?"保存修改":"发布动态"}),!u(e)&&(t=A(),!!t)){X(t),q(!1),C("正在读取家谱权限…","loading");try{if(await K(e,t),!c.canEditContent){C("当前账号无权发布或编辑该家谱的动态。","forbidden");return}if(q(!0),o("[data-feed-advanced]")&&(o("[data-feed-advanced]").hidden=!c.canManage,y("[name]",o("[data-feed-advanced]")).forEach(function(d){d.disabled=!c.canManage})),!a){C("");return}Pe(await e.feedDetail(t,a)),C("")}catch(d){if(u(e,d))return;C(s(d)==="forbidden"?"当前账号无权维护该家谱的动态。":d.message||"动态详情加载失败",s(d))}}}async function ve(){var e=w(),t,a=N(),n;if(!u(e)){if(O(!1),v("正在读取动态评论权限…","loading"),t=A(),!t||!a){g("[data-feed-detail]","error","动态链接缺少有效编号。"),v("动态链接缺少有效编号。","error");return}X(t),g("[data-feed-detail]","loading","正在加载动态详情…");try{if(await K(e,t),n=x(await e.feedDetail(t,a)),!n)throw new Error("动态响应缺少 feedId 或 feedContent,请联系后端补充 DTO。");W(n,t),O(!0),v(""),await G(a,U[a]||1)}catch(r){if(u(e,r))return;g("[data-feed-detail]",s(r),s(r)==="forbidden"?"当前账号无权查看该动态。":"动态详情加载失败,请返回列表重试。"),v(s(r)==="forbidden"?"当前账号无权评论该动态。":"动态详情加载失败,暂不能发表评论。",s(r)),m(r.message||"动态详情加载失败")}}}async function Ne(e){var t=w(),a,n=N(),r;if(!u(t)&&(a=A(),!!a)){if(!c.canEditContent){C("当前账号无权发布或编辑该家谱的动态。","forbidden");return}i.AppRichEditor&&i.AppRichEditor.syncAll&&i.AppRichEditor.syncAll();try{r=de(me(e))}catch(d){C(d.message||"动态表单校验失败","error");return}if(!r.feedContent){C("请填写动态内容","error");return}return D("save:"+(n||"new"),async function(){var d,f;te(!0),C("正在保存动态…","loading");try{if(n?d=await t.updateFeed(a,n,r):d=await t.createFeed(a,r),f=le(d)||n,!f)throw new Error("动态保存响应缺少 feedId");String(r.status||"0")==="0"&&await t.feedDetail(a,f),m("动态已保存"),i.NavigationUtil.open(ie(a,f,r.status))}catch(b){if(u(t,b))return;C(s(b)==="forbidden"?"当前账号无权保存该家谱的动态。":b.message||"动态保存失败",s(b))}finally{te(!1)}})}}async function be(e,t){var a=w(),n;if(!u(a)&&(n=A(),!(!n||!e)))return D((t?"like:":"unlike:")+e,async function(){try{t?await a.likeFeed(n,e):await a.unlikeFeed(n,e),o("[data-feed-detail-page]")?await ve():await k(I)}catch(r){if(u(a,r))return;m(r.message||(t?"点赞失败":"取消点赞失败"))}})}async function De(e){var t=w(),a;if(!u(t)&&(a=A(),!(!a||!e)&&await T("确认删除这条动态吗?")))return D("delete:"+e,async function(){try{await t.deleteFeed(a,e),o("[data-feed-detail-page]")?i.NavigationUtil.open(h("list",a)):await k(I)}catch(n){if(u(t,n))return;m(n.message||"删除动态失败")}})}async function G(e,t){var a=w(),n;if(!u(a)&&(n=A(),!(!n||!e))){U[e]=S(t).pageNum,o("[data-feed-detail-comments]")?g("[data-feed-detail-comments]","loading","正在加载评论…"):B(e,R("loading","正在加载评论…"));try{Fe(e,await a.feedCommentsPage(n,e,S(U[e])))}catch(r){if(u(a,r))return;o("[data-feed-detail-comments]")?g("[data-feed-detail-comments]",s(r),s(r)==="forbidden"?"当前账号无权查看评论。":"评论加载失败,请稍后重试。"):B(e,R(s(r),s(r)==="forbidden"?"当前账号无权查看评论。":"评论加载失败,请稍后重试。")),m(r.message||"评论加载失败")}}}async function Y(e,t,a){var n=w(),r;if(!u(n)&&(r=A(),!(!r||!e||!t))){L[t]=S(a).pageNum,z(t,"loading","正在加载回复…");try{Ue(e,t,await n.feedCommentRepliesPage(r,e,t,S(L[t])))}catch(d){if(u(n,d))return;z(t,s(d),s(d)==="forbidden"?"当前账号无权查看回复。":"回复加载失败,请稍后重试。"),m(d.message||"回复加载失败")}}}async function xe(e){var t=w(),a,n=N(),r,d,f=!1;if(!(u(t)||!e)&&(a=A(),!(!a||!n))){if(d=me(e),r=oe(d),!r.commentContent){v("请填写评论内容。","error");return}if(r.commentContent.length>1e3){v("评论不能超过 1000 字。","error");return}return D("comment:"+n+":"+(r.parentCommentId||"root"),async function(){O(!1),ae(!0),v("正在发布评论…","loading");try{await t.createFeedComment(a,n,r),await G(n,U[n]||1),r.parentCommentId&&await Y(n,r.parentCommentId,L[r.parentCommentId]||1),e.reset(),V(""),v("");var b=x(await t.feedDetail(a,n));b&&W(b,a),m("评论已发布")}catch(j){if(u(t,j))return;f=s(j)==="forbidden",v(f?"当前账号无权评论该动态。":j.message||"评论发布失败,请稍后重试。",s(j))}finally{ae(!1),f||O(!0)}})}}async function ke(e,t){var a=w(),n;if(!u(a)&&(n=A(),!(!n||!e||!t)&&await T("确认删除这条评论吗?")))return D("delete-comment:"+t,async function(){try{if(await a.deleteFeedComment(n,e,t),await G(e,U[e]||1),o("[data-feed-detail-page]")){var r=x(await a.feedDetail(n,e));r&&W(r,n)}else await k(I)}catch(d){if(u(a,d))return;m(d.message||"删除评论失败")}})}function Te(){F&&(F.addEventListener("submit",function(e){var t=e.target.closest("[data-feed-form]");if(t){e.preventDefault(),Ne(t);return}t=e.target.closest("[data-feed-comment-form]"),t&&(e.preventDefault(),xe(t))}),F.addEventListener("click",function(e){var t=e.target,a,n,r;t.closest("[data-feed-like]")&&(e.preventDefault(),be(t.closest("[data-feed-like]").getAttribute("data-feed-like"),!0)),t.closest("[data-feed-unlike]")&&(e.preventDefault(),be(t.closest("[data-feed-unlike]").getAttribute("data-feed-unlike"),!1)),t.closest("[data-feed-comments]")&&(e.preventDefault(),a=t.closest("[data-feed-comments]").getAttribute("data-feed-comments"),G(a,1)),t.closest("[data-feed-comment]")&&(e.preventDefault(),a=t.closest("[data-feed-comment]").getAttribute("data-feed-comment"),ne(a)),t.closest("[data-feed-comment-reply]")&&(e.preventDefault(),n=t.closest("[data-feed-comment-reply]").getAttribute("data-feed-comment-reply"),a=t.closest("[data-feed-comment-reply]").getAttribute("data-feed-id"),ne(a,n)),t.closest("[data-feed-comment-cancel]")&&(e.preventDefault(),V(""),v("")),t.closest("[data-feed-comment-replies]")&&(e.preventDefault(),n=t.closest("[data-feed-comment-replies]").getAttribute("data-feed-comment-replies"),a=t.closest("[data-feed-comment-replies]").getAttribute("data-feed-id"),Y(a,n,1)),t.closest("[data-feed-delete]")&&(e.preventDefault(),De(t.closest("[data-feed-delete]").getAttribute("data-feed-delete"))),t.closest("[data-feed-comment-delete]")&&(e.preventDefault(),n=t.closest("[data-feed-comment-delete]").getAttribute("data-feed-comment-delete"),a=t.closest("[data-feed-comment-delete]").getAttribute("data-feed-id"),ke(a,n)),t.closest("[data-feed-page-prev]")&&(e.preventDefault(),k(Math.max(1,I-1))),t.closest("[data-feed-page-next]")&&(e.preventDefault(),k(I+1)),t.closest("[data-feed-comments-prev], [data-feed-comments-next]")&&(e.preventDefault(),a=t.closest("[data-feed-id]").getAttribute("data-feed-id"),r=U[a]||1,G(a,t.closest("[data-feed-comments-prev]")?Math.max(1,r-1):r+1)),t.closest("[data-feed-replies-prev], [data-feed-replies-next]")&&(e.preventDefault(),a=t.closest("[data-feed-id]").getAttribute("data-feed-id"),n=t.closest("[data-comment-id]").getAttribute("data-comment-id"),r=L[n]||1,Y(a,n,t.closest("[data-feed-replies-prev]")?Math.max(1,r-1):r+1)),t.closest("[data-feed-share]")&&(e.preventDefault(),i.navigator&&i.navigator.clipboard&&i.location?i.navigator.clipboard.writeText(i.location.href).then(function(){m("分享链接已复制")}).catch(function(){m("复制失败,请从浏览器地址栏复制")}):m("请从浏览器地址栏复制分享链接"))}))}function Le(){F&&(Te(),o("[data-feed-page]")&&k(),o("[data-feed-edit-page]")&&Ee(),o("[data-feed-detail-page]")&&ve())}return{getCurrentGenealogyId:Z,getCurrentFeedId:N,buildFeedBody:de,buildCommentBody:oe,buildPageQuery:S,buildFeedUrl:h,buildPostSaveUrl:ie,withActionLock:D,normalizeFeed:x,normalizeComment:fe,canEditFeeds:pe,normalizeViewerContext:ge,normalizeComments:J,normalizeList:_,shouldRedirectToLogin:ee,init:Le}});
diff --git a/dist/public/js/feedback-pages.js b/dist/public/js/feedback-pages.js
deleted file mode 100644
index 7c8ef88..0000000
--- a/dist/public/js/feedback-pages.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(n,S){if(typeof module=="object"&&module.exports){module.exports=S(n);return}n.FeedbackPages=S(n),n.document&&n.document.addEventListener("DOMContentLoaded",function(){n.FeedbackPages.init()})})(typeof globalThis!="undefined"?globalThis:window,function(n){"use strict";var S=["ACTIVE","DISABLED","UNKNOWN"],I={0:"待处理",1:"处理中",2:"已处理",3:"已关闭"};function f(a){return String(a==null?"":a).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function T(a){var e;return typeof a=="number"&&!Number.isSafeInteger(a)||a==null?"":(e=String(a).trim(),/^[1-9][0-9]*$/.test(e)?e:"")}function u(a){return a==null?"":String(a).trim()}function O(a){var e=new URLSearchParams(String(a===void 0&&n.location?n.location.search:a||"").replace(/^\?/,""));return T(e.get("feedbackId"))}function D(a){var e=a||{},t={},r=u(e.feedbackType),d=u(e.feedbackContent),i=u(e.contactInfo);return r&&(t.feedbackType=r),d&&(t.feedbackContent=d),i&&(t.contactInfo=i),t}function U(a,e){var t=a||{},r=Array.isArray(e)?e:[];return u(t.feedbackContent)?t.feedbackType&&r.length&&r.indexOf(t.feedbackType)<0?"反馈类型无效":"":"请填写反馈内容"}function x(a){return Array.isArray(a)?a.reduce(function(e,t){var r=t||{},d=u(r.value),i=u(r.label);return d&&i&&r.enabled===!0&&e.push({value:d,label:i}),e},[]):[]}function F(a){var e=a||{},t=T(e.feedbackId),r=u(e.feedbackType),d=u(e.feedbackTypeLabel)||r,i=u(e.feedbackTypeOptionState),y=u(e.feedbackContent),h=String(e.handleStatus===void 0||e.handleStatus===null?"":e.handleStatus),v=String(e.status===void 0||e.status===null?"":e.status);return!t||!y||!r||!d||S.indexOf(i)<0||!Object.prototype.hasOwnProperty.call(I,h)||["0","1"].indexOf(v)<0?null:{feedbackId:t,feedbackType:r,feedbackTypeLabel:d,feedbackTypeOptionState:i,feedbackContent:y,contactInfo:u(e.contactInfo),handleStatus:h,handleResult:u(e.handleResult),handleTime:u(e.handleTime),status:v,remark:u(e.remark)}}function L(a){var e;return Array.isArray(a)?(e=a.map(F),e.some(function(t){return!t})?[]:e):[]}function B(a,e){var t=T(e),r=L(a),d;return t?(d=r.find(function(i){return i.feedbackId===t}),d||null):null}function A(a,e){var t=T(a),r;return t?(r=new URLSearchParams,r.set("feedbackId",t),(e||"ticket-detail.html")+"?"+r.toString()):""}function N(a,e){var t=e||{},r=L(a),d=t.detailPage||"ticket-detail.html";return r.length?r.map(function(i){return''+f(i.feedbackTypeLabel)+"
"+f(i.feedbackContent)+'
'+I[i.handleStatus]+""}).join(""):'当前没有反馈记录
'}function z(a){var e=F(a),t;return e?(t=[e.contactInfo?"提交联系方式"+f(e.contactInfo)+"":"","处理状态"+I[e.handleStatus]+"",e.handleResult?"处理结果"+f(e.handleResult)+"":"",e.handleTime?"处理时间"+f(e.handleTime)+"":"",e.remark?"备注"+f(e.remark)+"":""].filter(Boolean).join(""),''+f(e.feedbackTypeLabel)+"
问题说明
"+f(e.feedbackContent)+'
'+t+"
"):'反馈记录不存在或无权查看
'}function k(a,e){var t=e&&(e.status||e.code);return!a||!a.getToken||!a.getToken()||Number(t)===401}function m(a){a&&a.clearToken&&a.clearToken(),n.NavigationUtil.open("login.html")}function c(a){return Number(a&&(a.status||a.code))===403}function _(a){var e={};return Array.prototype.forEach.call(a.querySelectorAll("[name]"),function(t){e[t.name]=t.value}),e}function o(a,e,t){if(a){if(n.ProfileUI&&n.ProfileUI.setApiState&&e){n.ProfileUI.setApiState(a,e,t);return}a.textContent=t||""}}function l(a,e){var t=n.document&&n.document.querySelector("[data-feedback-status]");o(t,a,e)}function P(a,e,t){if(a){if(!e.length){o(a,"empty","当前没有反馈记录。");return}a.innerHTML=N(e,{detailPage:t||"ticket-detail.html"})}}function p(a,e,t){a&&(a.dataset.defaultLabel||(a.dataset.defaultLabel=a.textContent),a.disabled=e,a.textContent=e?t:a.dataset.defaultLabel)}async function K(a,e){var t=x(await a.businessDictionary("gen_feedback_type"));if(!t.length)throw new Error("反馈类型选项响应无效");return e&&(e.innerHTML=''+t.map(function(r){return'"}).join("")),t}async function C(a){var e=await a.myFeedback(),t=L(e);if(!Array.isArray(e)||t.length!==e.length)throw new Error("反馈列表响应无效");return t}async function M(){var a=n.document&&n.document.querySelector("[data-feedback-form]"),e=n.document&&n.document.querySelector("[data-feedback-list]"),t=n.document&&n.document.querySelector("[data-feedback-refresh]"),r=n.document&&n.document.querySelector("[data-feedback-page]"),d=n.GenealogyApi&&n.GenealogyApi.defaultClient,i=r&&r.getAttribute("data-feedback-page"),y=a&&a.querySelector("[data-feedback-type-options]"),h=[],v=!1;if(!a)return;if(k(d)){m(d);return}try{h=(await K(d,y)).map(function(b){return b.value})}catch(b){y&&(y.innerHTML='')}async function H(){var b;if(!e)return[];o(e,"loading","正在读取反馈记录…"),l("loading","正在读取反馈记录…");try{return b=await C(d),P(e,b,"ticket-detail.html"),l("",""),b}catch(s){return k(d,s)?(m(d),[]):(o(e,c(s)?"forbidden":"error",c(s)?"暂无权限查看反馈记录。":"读取反馈记录失败,请稍后重试。"),l(c(s)?"forbidden":"error",c(s)?"暂无权限查看反馈记录。":s.message||"读取反馈记录失败,请稍后重试。"),[])}}t&&t.addEventListener("click",async function(){p(t,!0,"正在刷新…");try{await H()}finally{p(t,!1,"正在刷新…")}}),a.addEventListener("submit",async function(b){var s,q,w,E,j=a.querySelector("[data-feedback-submit]");if(b.preventDefault(),!v){if(s=D(_(a)),q=U(s,h),q){l("error",q);return}v=!0,p(j,!0,"正在提交…"),l("loading","正在提交反馈…");try{if(w=F(await d.submitFeedback(s)),!w)throw new Error("提交响应缺少有效反馈信息");if(E=await C(d),!E.some(function(g){return g.feedbackId===w.feedbackId}))throw new Error("提交后无法读取同一反馈记录");if(i==="ticket"){n.NavigationUtil.open(A(w.feedbackId));return}P(e,E,"ticket-detail.html"),a.reset(),l("","反馈已提交")}catch(g){if(k(d,g)){m(d);return}l(c(g)?"forbidden":"error",c(g)?"暂无权限提交反馈。":g.message||"提交反馈失败,请稍后重试。")}finally{v=!1,p(j,!1,"正在提交…")}}}),await H()}async function R(){var a=n.document&&n.document.querySelector("[data-feedback-list-page]"),e=n.document&&n.document.querySelector("[data-feedback-list]"),t=n.document&&n.document.querySelector("[data-feedback-refresh]"),r=n.GenealogyApi&&n.GenealogyApi.defaultClient;if(!a||!e)return;if(k(r)){m(r);return}async function d(){try{o(e,"loading","正在读取反馈记录…"),l("loading","正在读取反馈记录…"),P(e,await C(r),"ticket-detail.html"),l("","")}catch(i){if(k(r,i)){m(r);return}o(e,c(i)?"forbidden":"error",c(i)?"暂无权限查看反馈记录。":"读取反馈记录失败,请稍后重试。"),l(c(i)?"forbidden":"error",c(i)?"暂无权限查看反馈记录。":i.message||"读取反馈记录失败,请稍后重试。")}}t&&t.addEventListener("click",async function(){p(t,!0,"正在刷新…");try{await d()}finally{p(t,!1,"正在刷新…")}}),await d()}async function G(){var a=n.document&&n.document.querySelector("[data-feedback-detail-page]"),e=n.document&&n.document.querySelector("[data-feedback-detail]"),t=n.GenealogyApi&&n.GenealogyApi.defaultClient,r=O(),d;if(!(!a||!e)){if(!r){o(e,"empty","反馈记录不存在或无权查看。");return}if(k(t)){m(t);return}try{o(e,"loading","正在读取反馈详情…"),l("loading","正在读取反馈详情…"),d=B(await t.myFeedback(),r),d?e.innerHTML=z(d):o(e,"empty","反馈记录不存在或无权查看。"),l("",d?"":"反馈记录不存在或无权查看。")}catch(i){if(k(t,i)){m(t);return}o(e,c(i)?"forbidden":"error",c(i)?"暂无权限查看该反馈详情。":"反馈详情读取失败,请稍后重试。"),l(c(i)?"forbidden":"error",c(i)?"暂无权限查看该反馈详情。":i.message||"反馈详情读取失败,请稍后重试。")}}}async function V(){if(n.document&&n.document.querySelector("[data-feedback-form]")){await M();return}if(n.document&&n.document.querySelector("[data-feedback-list-page]")){await R();return}n.document&&n.document.querySelector("[data-feedback-detail-page]")&&await G()}return{getFeedbackId:O,buildFeedbackBody:D,validateFeedbackBody:U,normalizeFeedbackTypeOptions:x,normalizeFeedback:F,normalizeFeedbackList:L,findFeedbackById:B,buildFeedbackDetailUrl:A,renderFeedbackList:N,renderFeedbackDetail:z,isForbidden:c,initFeedbackFormPage:M,initFeedbackListPage:R,initFeedbackDetailPage:G,init:V}});
diff --git a/dist/public/js/genealogy-entry-pages.js b/dist/public/js/genealogy-entry-pages.js
deleted file mode 100644
index c41f46c..0000000
--- a/dist/public/js/genealogy-entry-pages.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(a,p){if(typeof module=="object"&&module.exports){module.exports=p(a);return}a.GenealogyEntryPages=p(a),a.document&&a.document.addEventListener("DOMContentLoaded",function(){a.GenealogyEntryPages.init()})})(typeof globalThis!="undefined"?globalThis:window,function(a){"use strict";function p(n){var e=String(n||""),r=e.indexOf("#"),l=r<0?"":e.slice(r),t,u;return r>=0&&(e=e.slice(0,r)),t=e.split("?"),/^profile-[a-z-]+\.html$/.test(t[0])?(u=new URLSearchParams(t[1]||""),u.delete("genealogyId"),t[0]+(u.toString()?"?"+u.toString():"")+l):"profile-family-home.html"}function A(n){var e=new URLSearchParams(String(n===void 0&&a.location?a.location.search:n||"").replace(/^\?/,""));return p(e.get("next"))}function G(n){var e=n||{},r=[];return Number(e.createRemaining)===-1?r.push("创建不限"):Number(e.createRemaining)>=0&&r.push("还可创建 "+e.createRemaining+" 部"),Number(e.joinRemaining)===-1?r.push("加入不限"):Number(e.joinRemaining)>=0&&r.push("还可加入 "+e.joinRemaining+" 部"),r.length?"家谱额度:"+r.join(",")+"。":""}function f(n){return String(n==null?"":n).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function P(n){var e;if(n!=null)return e=String(n).trim(),e||void 0}function w(n){var e;return typeof n=="number"&&!Number.isSafeInteger(n)||n==null?"":(e=String(n).trim(),/^[1-9][0-9]*$/.test(e)?e:"")}function L(n){var e=n||{},r={genealogyName:String(e.genealogyName||"").trim(),surname:String(e.surname||"").trim(),regionCode:String(e.regionCode||"").trim()},l=["ancestralHall","originPlace","addressDetail","intro"],t=w(e.coverOssId),u=P(e.visibility),o=P(e.joinMode);return l.forEach(function(g){var d=P(e[g]);d!==void 0&&(r[g]=d)}),e.coverOssId!==void 0&&e.coverOssId!==null&&e.coverOssId!==""&&(t?r.coverOssId=t:r.invalidCoverOssId=!0),u!==void 0&&(r.visibility=u),o!==void 0&&(r.joinMode=o),r}function E(n){return!n||!n.genealogyName?"请填写谱名":n.surname?n.regionCode?n.visibility!==void 0&&["0","1","2"].indexOf(n.visibility)<0?"可见范围选项无效":n.joinMode!==void 0&&["0","1","2"].indexOf(n.joinMode)<0?"加入方式选项无效":n.invalidCoverOssId?"封面文件无效,请重新选择":"":"请选择家谱所在地区":"请填写姓氏"}function O(n){var e=Number(n&&n.createRemaining);return n&&typeof n.canCreate=="boolean"?n.canCreate:Number.isInteger(e)&&(e===-1||e>0)}function I(n){var e=w(n&&n.genealogyId),r=String(n&&n.genealogyName||"").trim(),l=String(n&&n.surname||"").trim();return!e||!r||!l?null:{genealogyId:e,genealogyName:r,surname:l,regionFullName:String(n&&n.regionFullName||"")}}function q(n){var e=I(n);return e?U(e.genealogyId,"profile-family-home.html"):""}function c(n,e){var r=e&&(e.status||e.code);return!n||!n.getToken||!n.getToken()||Number(r)===401}function S(n){n&&n.clearToken&&n.clearToken(),a.NavigationUtil.open("login.html")}function z(n){var e={};return Array.prototype.forEach.call(n.querySelectorAll("[name]"),function(r){e[r.name]=r.value}),e}function y(n){return Number(n&&(n.status||n.code))===403?"forbidden":"error"}function m(n,e){var r=a.document&&a.document.querySelector("[data-genealogy-create-status]");if(r){if(!n){r.innerHTML="";return}if(a.ProfileUI&&a.ProfileUI.setApiState){a.ProfileUI.setApiState(r,e||"error",n);return}r.textContent=n}}function v(n,e){var r=a.document&&a.document.querySelector("[data-genealogy-entry-status]");if(r){if(!n){r.innerHTML="";return}if(e&&a.ProfileUI&&a.ProfileUI.setApiState){a.ProfileUI.setApiState(r,e,n);return}r.textContent=n}}function b(n,e,r){if(n){if(a.ProfileUI&&a.ProfileUI.setApiState){a.ProfileUI.setApiState(n,e,r);return}n.textContent=r}}function M(n){var e=a.document&&a.document.querySelector("[data-genealogy-create-submit]");e&&(e.dataset.defaultLabel||(e.dataset.defaultLabel=e.textContent),e.disabled=!!n,e.textContent=n?"正在创建…":e.dataset.defaultLabel,e.setAttribute("aria-busy",n?"true":"false"))}async function j(){var n=a.document&&a.document.querySelector("[data-genealogy-create-form]"),e=a.document&&a.document.querySelector("[data-genealogy-create-quota]"),r=a.GenealogyApi&&a.GenealogyApi.defaultClient,l,t=!1;if(n){if(c(r)){S(r);return}m("正在读取创建额度…","loading");try{if(l=await r.genealogyQuota(),e&&(e.textContent=G(l)||"当前额度信息不可用"),!O(l)){m("当前没有可用的家谱创建额度","empty"),n.querySelector("[data-genealogy-create-submit]").disabled=!0;return}m("")}catch(u){if(c(r,u)){S(r);return}e&&(e.textContent="家谱额度读取失败"),m(u.message||"无法读取家谱创建额度",y(u)),n.querySelector("[data-genealogy-create-submit]").disabled=!0;return}n.__genealogyCreateBound||(n.__genealogyCreateBound=!0,n.addEventListener("submit",async function(u){var o,g,d,s;if(u.preventDefault(),!t){if(o=L(z(n)),g=E(o),g){m(g,"error");return}delete o.invalidCoverOssId,t=!0,M(!0),m("正在创建家谱…","loading");try{if(d=I(await r.createGenealogy(o)),!d)throw new Error("创建响应缺少有效家谱信息");if(s=I(await r.genealogyDetail(d.genealogyId)),!s||s.genealogyId!==d.genealogyId)throw new Error("创建后无法读取同一家谱");a.ProfileUI&&a.ProfileUI.setCurrentGenealogyContext&&a.ProfileUI.setCurrentGenealogyContext(s.genealogyId,s.genealogyName),a.NavigationUtil.open(q(s))}catch(h){if(c(r,h)){S(r);return}m(h.message||"创建家谱失败,请稍后重试",y(h))}finally{t=!1,M(!1)}}}))}}function T(n){var e=n||{},r=e.genealogyId===void 0||e.genealogyId===null?"":String(e.genealogyId);return!/^[1-9][0-9]*$/.test(r)||!e.genealogyName?null:{genealogyId:r,genealogyName:String(e.genealogyName),surname:e.surname===void 0||e.surname===null?"":String(e.surname),regionFullName:e.regionFullName===void 0||e.regionFullName===null?"":String(e.regionFullName),memberCount:e.memberCount,personCount:e.personCount,roleType:e.roleType===void 0||e.roleType===null?"":String(e.roleType),canManage:e.canManage===!0}}function U(n,e){var r=p(e),l=r.split("#"),t=l[0],u=l.length>1?"#"+l.slice(1).join("#"):"",o=t.split("?"),g=new URLSearchParams(o[1]||"");return g.set("genealogyId",String(n)),o[0]+"?"+g.toString()+u}function B(n,e,r){var l=Array.isArray(e)?e.map(T).filter(Boolean):[];return n?!Array.isArray(e)||e.length&&!l.length?(b(n,"error","家谱响应字段不完整,请联系后端核对。"),[]):l.length?(n.innerHTML=l.map(function(t){var u=[t.surname?t.surname+"氏":"",t.regionFullName,t.memberCount===void 0||t.memberCount===null?"":t.memberCount+" 位成员",t.personCount===void 0||t.personCount===null?"":t.personCount+" 位世系人物"].filter(Boolean).join(" · ");return''+f(t.genealogyName)+"
"+f(u)+'
'+(t.canManage?"管理并进入":"进入家谱")+""}).join(""),l):(b(n,"empty","当前账号还没有可进入的家谱"),[]):l}async function F(){if(a.document&&a.document.querySelector("[data-genealogy-create-page]")){await j();return}var n=a.document&&a.document.querySelector("[data-genealogy-entry-status]"),e=a.GenealogyApi&&a.GenealogyApi.defaultClient,r=A(),l=a.document&&a.document.querySelector('[data-genealogy-list="mine"]'),t=a.document&&a.document.querySelector("[data-genealogy-sort-select]"),u=a.document&&a.document.querySelector("[data-genealogy-sort-up]"),o=a.document&&a.document.querySelector("[data-genealogy-sort-down]"),g=a.document&&a.document.querySelector("[data-genealogy-sort-save]"),d,s=!1;if(!n)return;if(c(e)){S(e);return}if(!e||!e.genealogyQuota||!e.genealogiesMine||!e.saveGenealogyOrder){v("家谱入口接口初始化失败,请刷新后重试。","error"),b(l,"error","家谱列表接口初始化失败,请刷新后重试。");return}b(l,"loading","正在读取我的家谱…"),v("正在读取家谱额度…","loading");try{if(d=await e.genealogiesMine(),B(l,d,r),t){var h=Array.isArray(d)?d.map(T).filter(Boolean):[];t.innerHTML=h.map(function(i){return'"}).join(""),[t,u,o,g].forEach(function(i){i&&(i.disabled=h.length<2)})}}catch(i){if(c(e,i)){S(e);return}b(l,y(i),y(i)==="forbidden"?"当前账号无权查看我的家谱。":"无法读取我的家谱,请稍后重试。")}function R(i){var N,C,x;!t||s||(N=t.selectedIndex,C=N+i,!(N<0||C<0||C>=t.options.length)&&(x=t.options[N],i<0?t.insertBefore(x,t.options[C]):t.insertBefore(t.options[C],x),t.selectedIndex=C))}u&&u.addEventListener("click",function(){R(-1)}),o&&o.addEventListener("click",function(){R(1)}),g&&g.addEventListener("click",async function(){if(!(s||!t)){s=!0,[t,u,o,g].forEach(function(i){i&&(i.disabled=!0)}),v("正在保存家谱顺序…","loading");try{await e.saveGenealogyOrder(Array.prototype.map.call(t.options,function(i){return i.value})),v("家谱顺序已保存")}catch(i){v(i.message||"家谱顺序保存失败,请稍后重试。",y(i))}finally{s=!1,[t,u,o,g].forEach(function(i){i&&(i.disabled=t.options.length<2)})}}});try{d=await e.genealogyQuota(),v(G(d))}catch(i){if(c(e,i)){S(e);return}v(y(i)==="forbidden"?"当前账号无权读取家谱额度。":"家谱额度读取失败,请稍后重试。",y(i))}}return{normalizeTargetPage:p,getTargetPage:A,buildStatus:G,buildGenealogyCreateBody:L,validateGenealogyCreateBody:E,canCreateGenealogy:O,normalizeCreatedGenealogy:I,buildCreatedGenealogyUrl:q,shouldRedirectToLogin:c,initGenealogyCreatePage:j,normalizeGenealogy:T,buildEntryUrl:U,renderGenealogies:B,init:F}});
diff --git a/dist/public/js/genealogy-lifecycle-pages.js b/dist/public/js/genealogy-lifecycle-pages.js
deleted file mode 100644
index e096d6b..0000000
--- a/dist/public/js/genealogy-lifecycle-pages.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(e,s){if(typeof module=="object"&&module.exports){module.exports=s(e);return}e.GenealogyLifecyclePages=s(e),e.document&&e.document.addEventListener("DOMContentLoaded",e.GenealogyLifecyclePages.init)})(typeof globalThis!="undefined"?globalThis:window,function(e){"use strict";function s(a){return e.ProfileUI&&typeof e.ProfileUI.confirmAction=="function"?e.ProfileUI.confirmAction(a):Promise.resolve(!e.confirm||e.confirm(a))}var D={NOT_OWNER:"只有谱主可以永久删除家谱",NO_VERIFIED_MOBILE:"谱主账号尚未绑定已验证手机号",ACTIVE_PAYMENT:"当前家谱存在未完成的支付单",DELETION_IN_PROGRESS:"永久删除任务正在处理中"};function y(a){var n=a||{};return{canDeletePermanently:n.canDeletePermanently===!0,verifiedMobileMasked:String(n.verifiedMobileMasked||"").trim(),disabledReasons:Array.isArray(n.disabledReasons)?n.disabledReasons.map(String):[]}}function p(a){var n=y(a);return n.canDeletePermanently?n.verifiedMobileMasked?"验证码将发送至 "+n.verifiedMobileMasked:"当前账号具备永久删除资格":n.disabledReasons.map(function(i){return D[i]||i}).join(";")||"当前家谱不允许永久删除"}async function S(){var a=e.document&&e.document.querySelector("[data-genealogy-lifecycle-page]"),n=e.GenealogyApi&&e.GenealogyApi.defaultClient,i=e.ProfileUI&&e.ProfileUI.getGenealogyId?e.ProfileUI.getGenealogyId():"",u=a&&a.querySelector("[data-lifecycle-status]"),P=a&&a.querySelector("[data-genealogy-archive]"),I=a&&a.querySelector("[data-genealogy-restore]"),E=a&&a.querySelector("[data-genealogy-delete-form]"),f=a&&a.querySelector("[data-genealogy-delete-code]"),g=a&&a.querySelector("[data-genealogy-delete-submit]"),m=a&&a.querySelector("[data-genealogy-delete-name]"),b=a&&a.querySelector("[data-genealogy-delete-sms]"),l,d=!1;if(!a)return;if(!n||!n.getToken||!n.getToken()){e.NavigationUtil.open("login.html");return}if(!i){e.ProfileUI.setApiState(u,"error","缺少家谱上下文,请从“我的家谱”重新进入。");return}function t(r,o){r?e.ProfileUI.setApiState(u,r,o):u.textContent=o||""}function c(r){d=r,[P,I,f,g].forEach(function(o){o&&(o.disabled=r||(o===g||o===f)&&l&&!l.canDeletePermanently)})}try{var v=await Promise.all([n.genealogyDetail(i),n.genealogyDeletionCapability(i)]);l=y(v[1]),m.placeholder="请输入“"+String(v[0]&&v[0].genealogyName||"家谱全名")+"”确认",g.disabled=!l.canDeletePermanently,f.disabled=!l.canDeletePermanently,t(l.canDeletePermanently?"":"forbidden",p(l))}catch(r){t("error",r.message||"家谱维护能力读取失败");return}P.addEventListener("click",async function(){if(!(d||!await s("归档后家谱将停止日常维护,确认归档吗?"))){c(!0),t("loading","正在归档家谱…");try{await n.archiveGenealogy(i),t("","家谱已归档,需要时可在此恢复。")}catch(r){t("error",r.message||"归档失败")}finally{c(!1)}}}),I.addEventListener("click",async function(){if(!d){c(!0),t("loading","正在恢复家谱…");try{await n.restoreGenealogy(i),t("","家谱已恢复。")}catch(r){t("error",r.message||"恢复失败")}finally{c(!1)}}}),f.addEventListener("click",async function(){if(!(d||!l.canDeletePermanently)){c(!0),t("loading","正在发送验证码…");try{await n.sendGenealogyDeletionCode(i,{}),t("","验证码已发送至谱主手机号。")}catch(r){t("error",r.message||"验证码发送失败")}finally{c(!1)}}}),E.addEventListener("submit",async function(r){if(r.preventDefault(),!(d||!l.canDeletePermanently)){if(!m.value.trim()||!b.value.trim()){t("error","请填写家谱全名和短信验证码");return}if(await s("永久删除不可恢复,确认继续吗?")){c(!0),t("loading","正在提交永久删除任务…");try{await n.permanentlyDeleteGenealogy(i,{genealogyName:m.value.trim(),smsCode:b.value.trim()}),e.ProfileUI&&e.ProfileUI.clearCurrentGenealogyContext&&e.ProfileUI.clearCurrentGenealogyContext(),e.NavigationUtil.open("profile-families.html")}catch(o){t("error",o.message||"永久删除提交失败")}finally{c(!1)}}}})}return{normalizeCapability:y,capabilityMessage:p,init:S}});
diff --git a/dist/public/js/generation-pages.js b/dist/public/js/generation-pages.js
deleted file mode 100644
index eea54fc..0000000
--- a/dist/public/js/generation-pages.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(o,B){if(typeof module=="object"&&module.exports){module.exports=B(o);return}o.GenerationPages=B(o),o.document&&o.document.addEventListener("DOMContentLoaded",function(){o.GenerationPages.init()})})(typeof globalThis!="undefined"?globalThis:window,function(o){"use strict";function B(e){return o.ProfileUI&&typeof o.ProfileUI.confirmAction=="function"?o.ProfileUI.confirmAction(e):Promise.resolve(!o.confirm||o.confirm(e))}var m=o.document,S=Object.create(null),P="",s=!1,y=!1;function N(){return o.GenealogyApi&&o.GenealogyApi.defaultClient}function q(e,n){var t=n&&(n.status||n.code);return!e||!e.getToken||!e.getToken()||Number(t)===401}function w(e){return Number(e&&(e.status||e.code))===403}function v(e,n){return q(e,n)?(e&&e.clearToken&&e.clearToken(),o.NavigationUtil.open("login.html"),!0):!1}function d(e,n){return m?(n||m).querySelector(e):null}function b(e,n){return m?Array.prototype.slice.call((n||m).querySelectorAll(e)):[]}function C(e){if(o.layui&&o.layui.layer){o.layui.layer.msg(e);return}o.alert&&o.alert(e)}function I(e,n,t){var r=d(e);if(r){if(o.ProfileUI&&o.ProfileUI.setApiState){o.ProfileUI.setApiState(r,n,t);return}r.innerHTML=''+c(t)+"
"}}function p(e,n){var t=d("[data-generation-form-status]");if(t){if(!e){t.innerHTML="";return}if(o.ProfileUI&&o.ProfileUI.setApiState){o.ProfileUI.setApiState(t,n||"error",e);return}t.textContent=e}}function ie(e,n){var t=new URLSearchParams(String(e||"").replace(/^\?/,""));return t.get(n)||""}function F(e){var n=d("[data-generation-page]"),t=e===void 0&&o.location?o.location.search:e,r;return e===void 0&&o.ProfileUI&&o.ProfileUI.getGenealogyId&&(r=o.ProfileUI.getGenealogyId(),r)?r:ie(t,"genealogyId")||n&&n.getAttribute("data-genealogy-id")||""}function l(e){var n=String(e==null?"":e).trim();return n||void 0}function T(e){var n=l(e),t;if(n)return t=Number(n),Number.isInteger(t)&&Number.isSafeInteger(t)?t:void 0}function M(e){var n=e||{},t={generationNo:T(n.generationNo),generationText:l(n.generationText)},r=l(n.description),a=l(n.sortOrder),i=l(n.status);return r!==void 0&&(t.description=r),a!==void 0&&(t.sortOrder=Number(a)),i!==void 0&&(t.status=i),t}function z(e){var n=e||{};return{poemText:String(n.poemText||"").trim(),disableMissing:!!n.disableMissing}}function H(e){return!e||!Number.isInteger(e.generationNo)||e.generationNo<1||e.generationNo>2147483647?"世代序号必须是 1 到 2147483647 之间的整数":e.generationText?e.generationText.length>50?"字辈文字不能超过 50 个字符":e.description&&e.description.length>500?"说明不能超过 500 个字符":e.sortOrder!==void 0&&(!Number.isInteger(e.sortOrder)||!Number.isSafeInteger(e.sortOrder))?"排序值必须是整数":e.sortOrder!==void 0&&(e.sortOrder<-2147483648||e.sortOrder>2147483647)?"排序值必须在 -2147483648 到 2147483647 之间":e.status!==void 0&&e.status!=="0"&&e.status!=="1"?"字辈状态只能是 0 或 1":"":"请填写字辈文字"}function D(e){var n;return!e||!e.poemText?"请填写批量字辈内容":e.poemText.length>26e3?"批量字辈内容不能超过 26000 个字符":(n=R(e.poemText),n.length>500?"一次最多导入 500 个世代":n.some(function(t){return t.length>50})?"单个字辈不能超过 50 个字符":"")}function R(e){var n=String(e||"").trim();return n?/[\s,,;;、//||]/.test(n)?n.split(/[\s,,;;、//||]+/).filter(Boolean):Array.from(n):[]}function j(e){var n;return e==null||e===""||typeof e=="number"&&!Number.isSafeInteger(e)?"":(n=String(e),/^\d+$/.test(n)?n:"")}function J(e){return j(e&&e.poemId)}function V(e){var n=J(e),t=j(e&&e.genealogyId),r=T(e&&e.generationNo),a=l(e&&e.generationText),i=l(e&&e.status),u;return!n||r===void 0||!a||i!=="0"&&i!=="1"?null:(u={poemId:n,generationNo:r,generationText:a,status:i},t&&(u.genealogyId=t),e.genealogyNo!==void 0&&e.genealogyNo!==null&&(u.genealogyNo=String(e.genealogyNo)),e.genealogyName!==void 0&&e.genealogyName!==null&&(u.genealogyName=String(e.genealogyName)),e.description!==void 0&&e.description!==null&&(u.description=String(e.description)),T(e.sortOrder)!==void 0&&(u.sortOrder=T(e.sortOrder)),e.remark!==void 0&&e.remark!==null&&(u.remark=String(e.remark)),u)}function Q(e){return!!(e&&(e.canEditContent===!0||e.canManage===!0))}function W(e){var n=Q(e);return{canEditContent:n,listMethod:n?"generationPoemsManagement":"generationPoems"}}function $(e){return Array.isArray(e)?e:e&&Array.isArray(e.rows)?e.rows:[]}function c(e){return String(e==null?"":e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function oe(e){var n=[],t=e.status==="1"?"已停用":"正常",r="";return e.description&&n.push("说明:"+e.description),e.sortOrder!==void 0&&n.push("排序:"+e.sortOrder),n.push("状态:"+t),s&&(r='"),'第 '+c(e.generationNo)+" 代:"+c(e.generationText)+"
"+c(n.join(" · "))+"
"+r+"
"}function ue(e){var n=d("[data-generation-list]"),t=$(e).map(V),r=t.filter(function(i){return!i}).length,a=t.filter(Boolean);if(S=Object.create(null),a.forEach(function(i){S[i.poemId]=i}),!!n){if(r){I("[data-generation-list]","error","字辈响应缺少 poemId、generationNo、generationText 或 status,请联系后端补充 DTO。");return}if(!a.length){I("[data-generation-list]","empty","暂无字辈记录");return}n.innerHTML=a.map(oe).join("")}}function k(e){var n=T(e);return n!==void 0&&n>=0?n:void 0}function de(e){var n=e&&e.action,t=T(e&&e.generationNo),r=J(e),a=l(e&&e.oldGenerationText),i=l(e&&e.newGenerationText),u=l(e&&e.oldStatus),x=l(e&&e.newStatus),f;return!t||["create","update","keep","disable"].indexOf(n)===-1||x!=="0"&&x!=="1"||n==="create"&&!i||n!=="create"&&(!r||!a||u!=="0"&&u!=="1")||(n==="update"||n==="keep")&&!i?null:(f={generationNo:t},r&&(f.poemId=r),a&&(f.oldGenerationText=a),i&&(f.newGenerationText=i),u!==void 0&&(f.oldStatus=u),f.newStatus=x,f.action=n,e.warning!==void 0&&e.warning!==null&&(f.warning=String(e.warning)),f)}function K(e){var n,t,r={create:0,update:0,keep:0,disable:0};return!e||!Array.isArray(e.items)||!e.items.length||(n={createCount:k(e.createCount),updateCount:k(e.updateCount),keepCount:k(e.keepCount),disableCount:k(e.disableCount)},Object.keys(n).some(function(a){return n[a]===void 0}))||(t=e.items.map(de),t.some(function(a){return!a}))||(t.forEach(function(a){r[a.action]+=1}),n.createCount!==r.create||n.updateCount!==r.update||n.keepCount!==r.keep||n.disableCount!==r.disable)?null:(n.items=t,n)}function X(e){return e?"确认按当前预览保存字辈,并停用未出现在文本中的后续世代吗?历史记录不会删除。":"确认按当前预览保存字辈吗?"}function fe(e){var n=d("[data-generation-batch-preview]"),t=K(e),r;return n?t?(r="新增 "+(t.createCount===void 0?"-":t.createCount)+" 条 · 更新 "+(t.updateCount===void 0?"-":t.updateCount)+" 条 · 保留 "+(t.keepCount===void 0?"-":t.keepCount)+" 条 · 停用 "+(t.disableCount===void 0?"-":t.disableCount)+" 条",n.innerHTML='"+t.items.map(function(a){var i=a&&a.generationNo,u=a&&a.action,x=a&&a.oldGenerationText,f=a&&a.newGenerationText,te=a&&a.warning,re=a&&a.oldStatus,ae=a&&a.newStatus,L="第 "+(i==null?"-":i)+" 代:"+(x==null?"(新增)":x)+" → "+(f==null?"(无)":f);return u&&(L+=" · "+u),(re!==void 0||ae!==void 0)&&(L+=" · 状态:"+Y(re)+" → "+Y(ae)),te&&(L+=" · 警告:"+te),'"}).join(""),!0):(I("[data-generation-batch-preview]","error","批量预览响应缺少 items,请联系后端补充 DTO。"),!1):!1}function Y(e){return String(e)==="0"?"正常":String(e)==="1"?"停用":e==null?"未提供":String(e)}function G(e){var n={};return b("[name]",e).forEach(function(t){n[t.name]=t.type==="checkbox"?t.checked:t.value}),n}function g(e){var n=d("[data-generation-batch-status]");n&&(n.textContent=e||"")}function E(e){var n=d("[data-generation-editor]");n&&(n.hidden=!e)}function se(e){b("[data-generation-editor-submit]").forEach(function(n){n.dataset.defaultLabel||(n.dataset.defaultLabel=n.textContent),n.disabled=!!e||!s,n.textContent=e?"正在保存…":n.dataset.defaultLabel,n.setAttribute("aria-busy",e?"true":"false")})}function Z(){var e=!s||y;b("[data-generation-management]").forEach(function(n){n.hidden=!s}),s||E(!1),b("[data-generation-add], [data-generation-batch-action], [data-generation-edit], [data-generation-status]").forEach(function(n){n.disabled=e}),b("[data-generation-management] textarea, [data-generation-management] input, [data-generation-editor] textarea, [data-generation-editor] input, [data-generation-editor] select, [data-generation-editor] button").forEach(function(n){n.disabled=e}),se(y)}function _(e){s=!!e,Z()}function h(e){y=!!e,Z()}function A(){I("[data-generation-list]","forbidden","当前账号没有字辈维护权限"),P="",_(!1),g("当前账号没有字辈维护权限"),p("当前账号没有字辈维护权限","forbidden")}function le(e){if(o.ProfileUI&&o.ProfileUI.syncGenealogyContextLinks){o.ProfileUI.syncGenealogyContextLinks();return}b("[data-genealogy-context-link]").forEach(function(n){var t=n.getAttribute("href"),r;!t||t==="#"||(r=t.split("?")[0],n.href=r+"?genealogyId="+encodeURIComponent(e))})}function O(){var e=F(),n;return e||(n=d("[data-generation-list]"),n&&I("[data-generation-list]","error","请从具体家谱进入字辈管理"),E(!1),p("请从具体家谱进入字辈管理","error"),C("请从具体家谱进入字辈管理")),e}function ee(e){var n=d("[data-generation-form]"),t=e?S[e]:null,r=d("[data-generation-editor-title]");!s||y||!n||e&&!t||(n.reset(),b("[name]",n).forEach(function(a){var i;a.name==="poemId"&&(i=e||""),a.name==="generationNo"&&(i=t?t.generationNo:""),a.name==="generationText"&&(i=t?t.generationText:""),a.name==="description"&&(i=t&&t.description?t.description:""),a.name==="sortOrder"&&(i=t&&t.sortOrder!==void 0?t.sortOrder:""),a.name==="status"&&(i=t?t.status:""),i!==void 0&&(a.value=i)}),r&&(r.textContent=t?"编辑字辈":"新增字辈"),p(""),E(!0),o.location&&o.location.hash!=="#generation-editor"&&(o.location.hash="generation-editor"),d('[name="generationNo"]',n)&&d('[name="generationNo"]',n).focus&&d('[name="generationNo"]',n).focus())}function ne(){var e=d("[data-generation-form]");e&&e.reset(),p(""),E(!1)}async function U(){var e=N(),n,t;if(!v(e)&&(n=O(),!!n)){le(n),I("[data-generation-list]","loading","正在加载字辈记录…");try{t=W(await e.genealogyDetail(n)),_(t.canEditContent),ue(await e[t.listMethod](n))}catch(r){if(v(e,r))return;if(w(r)){A();return}I("[data-generation-list]","error","字辈列表加载失败,请稍后重试。"),C(r.message||"字辈列表加载失败")}}}async function ce(e){var n=N(),t,r,a,i;if(!(y||!s||v(n)||!e)&&(t=O(),!!t)){if(r=j(G(e).poemId),G(e).poemId&&!r){p("字辈编号无效,请返回列表重新编辑。","error");return}if(r&&!S[r]){p("当前字辈不存在或已更新,请返回列表刷新后重试。","error");return}if(a=M(G(e)),i=H(a),i){p(i,"error");return}p("正在保存字辈…","loading"),h(!0);try{r?await n.updateGenerationPoem(t,r,a):await n.createGenerationPoem(t,a),C("字辈已保存"),ne(),await U()}catch(u){if(v(n,u))return;if(w(u)){A();return}p(u.message||"字辈保存失败","error")}finally{h(!1)}}}async function ge(e){var n=N(),t,r=S[e],a;if(!(y||!s||v(n))&&(t=O(),!(!t||!r))){a=M({generationNo:r.generationNo,generationText:r.generationText,description:r.description,sortOrder:r.sortOrder,status:r.status==="1"?"0":"1"}),h(!0);try{await n.updateGenerationPoem(t,e,a),C(r.status==="1"?"字辈已恢复":"字辈已停用"),await U()}catch(i){if(v(n,i))return;if(w(i)){A();return}C(i.message||"字辈状态更新失败")}finally{h(!1)}}}async function ve(){var e=N(),n,t=d("[data-generation-batch-form]"),r,a;if(!(y||!s||v(e)||!t)&&(n=O(),!!n)){if(r=z(G(t)),a=D(r),a){g(a);return}g("正在预览…"),h(!0);try{fe(await e.previewGenerationPoems(n,r))?(P=JSON.stringify(r),g("预览完成,请确认后保存")):(P="",g("预览响应不完整"))}catch(i){if(v(e,i))return;if(w(i)){A();return}P="",g(i.message||"批量预览失败")}finally{h(!1)}}}async function pe(){var e=N(),n,t=d("[data-generation-batch-form]"),r,a;if(!(y||!s||v(e)||!t)&&(n=O(),!!n)){if(r=z(G(t)),a=D(r),a){g(a);return}if(P!==JSON.stringify(r)){g("请先预览当前内容,再保存");return}if(await B(X(r.disableMissing))){g("正在保存…"),h(!0);try{await e.saveGenerationPoems(n,r),P="",g("批量字辈已保存"),await U()}catch(i){if(v(e,i))return;if(w(i)){A();return}g(i.message||"批量保存失败")}finally{h(!1)}}}}function me(){m&&(m.addEventListener("submit",function(e){var n=e.target.closest("[data-generation-form]");n&&(e.preventDefault(),ce(n))}),m.addEventListener("click",function(e){var n=e.target,t=n.closest("[data-generation-batch-action]"),r=n.closest("[data-generation-edit], [data-generation-status]");if(t){e.preventDefault(),t.getAttribute("data-generation-batch-action")==="preview"&&ve(),t.getAttribute("data-generation-batch-action")==="save"&&pe();return}if(n.closest("[data-generation-add]")){e.preventDefault(),ee("");return}if(n.closest("[data-generation-editor-cancel]")){e.preventDefault(),ne();return}r&&(e.preventDefault(),r.hasAttribute("data-generation-edit")&&ee(r.getAttribute("data-generation-edit")),r.hasAttribute("data-generation-status")&&ge(r.getAttribute("data-generation-status")))}))}function ye(){m&&(me(),d("[data-generation-page]")&&U())}return{getCurrentGenealogyId:F,buildGenerationPoemBody:M,buildBatchBody:z,validateGenerationPoemBody:H,validateBatchBody:D,canEditGenerations:Q,splitPoemText:R,normalizeGenerationPoem:V,normalizeGenerationAccess:W,normalizePreview:K,buildBatchConfirmMessage:X,normalizeList:$,shouldRedirectToLogin:q,isForbidden:w,init:ye}});
diff --git a/dist/public/js/growth-pages.js b/dist/public/js/growth-pages.js
deleted file mode 100644
index 74bb853..0000000
--- a/dist/public/js/growth-pages.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(a,D){if(typeof module=="object"&&module.exports){module.exports=D(a);return}a.GrowthPages=D(a),a.document&&a.document.addEventListener("DOMContentLoaded",function(){a.GrowthPages.init()})})(typeof globalThis!="undefined"?globalThis:window,function(a){"use strict";function D(e){return a.ProfileUI&&typeof a.ProfileUI.confirmAction=="function"?a.ProfileUI.confirmAction(e):Promise.resolve(!a.confirm||a.confirm(e))}var A=a.MediaDisplay||(typeof require=="function"?require("./media-display.js"):null),P=a.document,C=Object.create(null),T=!1,R=!1;function G(){return a.GenealogyApi&&a.GenealogyApi.defaultClient}function o(e,r){return P?(r||P).querySelector(e):null}function E(e,r){return P?Array.prototype.slice.call((r||P).querySelectorAll(e)):[]}function q(e,r){var t=new URLSearchParams(String(e||"").replace(/^\?/,""));return t.get(r)||""}function s(e){return e==null||e===""||typeof e=="number"&&!Number.isSafeInteger(e)?"":/^[1-9][0-9]*$/.test(String(e))?String(e):""}function H(e){var r=e===void 0&&a.location?a.location.search:e,t;return e===void 0&&a.ProfileUI&&a.ProfileUI.getGenealogyId&&(t=a.ProfileUI.getGenealogyId(),t)?s(t):s(q(r,"genealogyId"))}function L(e){var r=e===void 0&&a.location?a.location.search:e;return s(q(r,"recordId"))}function v(e){var r=String(e==null?"":e).trim();return r||void 0}function ne(e){var r=v(e),t;if(r!==void 0)return t=Number(r),Number.isSafeInteger(t)?t:void 0}function ae(e){var r=v(e);if(r)return/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(r)?r.replace("T"," ")+":00":/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/.test(r)?r.replace("T"," "):r}function ie(e){var r=String(e||"");return/^\d{4}-\d{2}-\d{2}/.test(r)?r.slice(0,10):""}function de(e){var r=String(e||"");return/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}/.test(r)?r.slice(0,16).replace(" ","T"):""}function V(e){var r=e||{},t={recordTitle:String(r.recordTitle||"").trim()},i=v(r.lineagePersonId),n=v(r.recordType),d=v(r.recordContent),l=v(r.recordDate),y=ae(r.remindTime),c=v(r.mediaOssIds),g=v(r.sortOrder),b=v(r.status);return i!==void 0&&(t.lineagePersonId=i),n!==void 0&&(t.recordType=n),d!==void 0&&(t.recordContent=d),l!==void 0&&(t.recordDate=l),y!==void 0&&(t.remindTime=y),c!==void 0&&(t.mediaOssIds=c),g!==void 0&&(t.sortOrder=ne(g),t.sortOrder===void 0&&(t.invalidSortOrder=!0)),b!==void 0&&(t.status=b),t}function j(e){return!e||!e.recordTitle?"请填写记录标题":e.lineagePersonId!==void 0&&!s(e.lineagePersonId)?"请选择有效的世系人物":e.mediaOssIds!==void 0&&!/^[1-9][0-9]*(,[1-9][0-9]*)*$/.test(e.mediaOssIds)?"附件上传结果无效":e.invalidSortOrder||Object.prototype.hasOwnProperty.call(e,"sortOrder")&&!Number.isSafeInteger(e.sortOrder)?"排序值必须是安全整数":e.recordDate!==void 0&&!/^\d{4}-\d{2}-\d{2}$/.test(e.recordDate)?"记录日期格式无效":e.remindTime!==void 0&&!/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(e.remindTime)?"提醒时间格式无效":e.status==="1"?"当前 PC 无法重新读取停用记录,暂不开放停用":e.status!==void 0&&e.status!=="0"?"记录状态只能是 0":""}function u(e){return e==null?"":String(e)}function oe(e){var r;if(!(e==null||e===""))return r=Number(e),Number.isSafeInteger(r)?r:void 0}function O(e){var r=s(e&&e.recordId),t=s(e&&e.genealogyId),i=s(e&&e.appUserId),n=s(e&&e.lineagePersonId),d=String(e&&e.recordTitle||"").trim(),l=u(e&&e.status),y=A?A.normalizeFileList(e&&e.mediaFiles):[],c=oe(e&&e.sortOrder),g;return!r||!t||!d||l!=="0"&&l!=="1"||e.appUserId!==void 0&&e.appUserId!==null&&e.appUserId!==""&&!i||e.lineagePersonId!==void 0&&e.lineagePersonId!==null&&e.lineagePersonId!==""&&!n||e.sortOrder!==void 0&&e.sortOrder!==null&&e.sortOrder!==""&&c===void 0?null:(g={recordId:r,genealogyId:t,genealogyNo:u(e.genealogyNo),genealogyName:u(e.genealogyName),surname:u(e.surname),appUserNickName:u(e.appUserNickName),appUserPhone:u(e.appUserPhone),lineagePersonNo:u(e.lineagePersonNo),lineagePersonName:u(e.lineagePersonName),recordType:u(e.recordType),recordTitle:d,recordContent:u(e.recordContent),recordDate:u(e.recordDate),remindTime:u(e.remindTime),status:l,remark:u(e.remark)},y.length&&(g.mediaFiles=y),i&&(g.appUserId=i),n&&(g.lineagePersonId=n),c!==void 0&&(g.sortOrder=c),g)}function z(e,r){var t=O(e);return!!(t&&t.recordId===s(r))}function le(e){var r=s(e&&(e.personId||e.lineagePersonId)),t=String(e&&(e.name||e.lineagePersonName)||"").trim();return!r||!t?null:{personId:r,name:t,generationName:u(e.generationName)}}function f(e){return u(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function $(e,r,t){var i=s(r),n=Array.isArray(e)?e.map(le).filter(Boolean):[],d=n.some(function(l){return l.personId===i});return i&&!d&&t&&n.push({personId:i,name:String(t),generationName:""}),''+n.map(function(l){return'"}).join("")}function Q(e){return Array.isArray(e)?e.length:0}function W(e,r){var t="profile-growth.html?genealogyId="+encodeURIComponent(e);return r?t+"&recordId="+encodeURIComponent(r):t}function J(e,r){var t="profile-growth-edit.html?genealogyId="+encodeURIComponent(e);return r?t+"&recordId="+encodeURIComponent(r):t}function K(e){return!!(e&&(e.canEditContent===!0||e.canManage===!0))}function ue(e){var r=[],t='';return e.lineagePersonName&&r.push(e.lineagePersonName),e.recordType&&r.push(e.recordType),e.recordDate&&r.push(e.recordDate),r.length||r.push("未填写日期和关联人物"),T&&(t+='编辑'),''+f(e.recordTitle)+"
"+f(r.join(" · "))+'
'+t+"
"}function p(e,r){return""+f(e)+""+f(r||"未提供")+"
"}function X(e){var r,t="";return e?(r=Q(e.mediaFiles),T&&(t=''),(A?A.renderGallery(e.mediaFiles,{label:"成长记录附件"}):"")+''+p("标题",e.recordTitle)+p("关联人物",e.lineagePersonName||e.lineagePersonNo)+p("记录类型",e.recordType)+p("记录日期",e.recordDate)+p("提醒时间",e.remindTime)+p("记录内容",e.recordContent)+p("附件",r?r+" 个附件":"未上传")+p("记录人",e.appUserNickName)+p("状态",e.status==="0"?"正常":"停用")+p("备注",e.remark)+"
"+t):_("empty","请选择一条成长记录查看详情")}function x(e){if(a.layui&&a.layui.layer){a.layui.layer.msg(e);return}a.alert&&a.alert(e)}function Y(e,r){var t=r&&(r.status||r.code);return!e||!e.getToken||!e.getToken()||Number(t)===401}function h(e){return Number(e&&(e.status||e.code))===403}function N(e){return h(e)?"forbidden":"error"}function m(e,r){return Y(e,r)?(e&&e.clearToken&&e.clearToken(),a.NavigationUtil.open("login.html"),!0):!1}function Z(){a.ProfileUI&&a.ProfileUI.syncGenealogyContextLinks&&a.ProfileUI.syncGenealogyContextLinks()}function _(e,r){return a.ProfileUI&&a.ProfileUI.renderApiState?a.ProfileUI.renderApiState(e,r):''+f(r)+"
"}function I(e,r,t){if(e){if(a.ProfileUI&&a.ProfileUI.setApiState){a.ProfileUI.setApiState(e,r,t);return}e.innerHTML=_(r,t)}}function U(e,r){var t=o("[data-growth-form-status]");if(t){if(!e){t.innerHTML="";return}if(r&&a.ProfileUI&&a.ProfileUI.setApiState){a.ProfileUI.setApiState(t,r,e);return}t.textContent=e}}function k(e,r,t){var i=o("[data-growth-editor-placeholder]");E("[data-growth-editor], [data-growth-editor-action]").forEach(function(n){n.hidden=!e}),i&&(i.hidden=!!e,!e&&r&&(t?I(i,t,r):i.textContent=r))}function B(e){T=!!e,E("[data-growth-create-link]").forEach(function(r){r.hidden=!T})}async function ee(e,r){var t=await e.genealogyDetail(r);return B(K(t)),t}function se(){var e=o("[data-growth-list]"),r=o("[data-growth-detail]"),t="请先选择家谱,再查看或维护成长记录。";I(e,"empty",t),I(r,"empty","当前没有家谱上下文。"),B(!1),k(!1,t,"empty"),U(t,"empty")}function S(){var e=H();return e||se(),e}function F(e,r){var t=o('[data-growth-form] [type="submit"]');R=!!e,E("[data-growth-form] input, [data-growth-form] textarea, [data-growth-form] select, [data-growth-form] button, [data-growth-delete-id]").forEach(function(i){i.disabled=R}),t&&(t.dataset.defaultLabel||(t.dataset.defaultLabel=t.textContent),t.textContent=R&&r?r:t.dataset.defaultLabel,t.setAttribute("aria-busy",R?"true":"false"))}function fe(e){var r=o("[data-growth-list]"),t=Array.isArray(e)?e.map(O):[],i=t.filter(function(d){return!d}).length,n=t.filter(Boolean);return C=Object.create(null),n.forEach(function(d){C[d.recordId]=d}),r?!Array.isArray(e)||i?(I(r,"error","成长记录响应缺少稳定 GrowthRecordVo 字段,请联系后端核对。"),[]):n.length?(r.innerHTML=n.map(ue).join(""),n):(I(r,"empty","暂无成长记录"),[]):n}function re(e){var r=o("[data-growth-detail]");r&&(r.innerHTML=X(e))}async function M(e){var r=G(),t=S(),i;if(!t||!s(e)||m(r))return null;I(o("[data-growth-detail]"),"loading","正在加载成长记录详情…");try{if(i=O(await r.growthRecordDetail(t,e)),!i)throw new Error("成长记录详情响应缺少稳定 GrowthRecordVo 字段");return C[i.recordId]=i,re(i),i}catch(n){return m(r,n)||(I(o("[data-growth-detail]"),N(n),h(n)?"当前账号无权查看该成长记录。":"成长记录详情加载失败,请稍后重试。"),x(h(n)?"当前账号无权查看该成长记录。":n.message||"成长记录详情加载失败")),null}}async function te(){var e=G(),r,t,i;if(!m(e)&&(r=S(),!!r)){Z(),I(o("[data-growth-list]"),"loading","正在加载成长记录…");try{await ee(e,r),t=fe(await e.growthRecords(r)),i=L(),i&&C[i]?await M(i):t.length?await M(t[0].recordId):re(null)}catch(n){if(m(e,n))return;B(!1),I(o("[data-growth-list]"),N(n),h(n)?"当前账号无权查看该家谱的成长记录。":"成长记录加载失败,请稍后重试。"),x(h(n)?"当前账号无权查看该家谱的成长记录。":n.message||"成长记录加载失败")}}}function ce(e){var r={};return E("[name]",e).forEach(function(t){r[t.name]=t.value}),r}function w(e,r){var t=o('[data-growth-form] [name="'+e+'"]');t&&(t.value=r==null?"":String(r))}function ge(e){var r,t;w("lineagePersonId",e.lineagePersonId),w("recordType",e.recordType),w("recordTitle",e.recordTitle),w("recordContent",e.recordContent),w("recordDate",ie(e.recordDate)),w("remindTime",de(e.remindTime)),w("mediaOssIds",e.mediaOssIds),w("sortOrder",e.sortOrder),w("status","0"),r=o('[data-growth-form] [name="recordContent"]'),r&&a.AppRichEditor&&a.AppRichEditor.init&&(t=a.AppRichEditor.init(r),t&&t.editor&&t.editor.setHtml&&t.editor.setHtml(e.recordContent||"")),o("[data-growth-media-status]")&&(o("[data-growth-media-status]").textContent=e.mediaOssIds?"已保留 "+Q(e.mediaOssIds)+" 个附件,可继续选择追加":"未选择文件")}function pe(e,r,t){var i=o("[data-growth-lineage-person]");i&&(i.innerHTML=$(e,r,t))}async function he(){var e=G(),r,t,i,n;if(!m(e)&&(r=S(),!!r)){t=L(),Z(),k(!1,"正在加载成长记录编辑信息…","loading"),U("正在读取家谱权限…","loading");try{if(await ee(e,r),!T)throw{status:403,message:"当前账号无权维护该家谱的成长记录。"};if(i=await Promise.all([e.lineagePersonOptions(r),t?e.growthRecordDetail(r,t):Promise.resolve(null)]),n=t?O(i[1]):null,t&&!n)throw new Error("成长记录详情响应缺少稳定 GrowthRecordVo 字段");pe(i[0],n&&n.lineagePersonId,n&&n.lineagePersonName),n&&(ge(n),o("[data-growth-editor-title]")&&(o("[data-growth-editor-title]").textContent="编辑成长记录")),k(!0),U("")}catch(d){if(m(e,d))return;B(!1),k(!1,h(d)?"当前账号无权维护该家谱的成长记录。":d.message||"成长记录编辑信息加载失败",N(d)),U(h(d)?"当前账号无权维护该家谱的成长记录。":d.message||"成长记录编辑信息加载失败",N(d))}}}async function me(e){var r=G(),t=S(),i=L(),n,d,l,y,c,g;if(!(R||!T||!t||m(r))){if(n=V(ce(e)),d=j(n),d){U(d,"error");return}delete n.invalidSortOrder,F(!0,"正在保存…"),U("正在保存成长记录…","loading");try{if(l=i?await r.updateGrowthRecord(t,i,n):await r.createGrowthRecord(t,n),y=O(l),c=i||y&&y.recordId,!c)throw new Error("保存响应缺少 recordId");if(g=await r.growthRecordDetail(t,c),!z(g,c))throw new Error("保存后重读未返回同一条成长记录");a.NavigationUtil.open(W(t,c))}catch(b){if(m(r,b))return;U(h(b)?"当前账号无权保存该成长记录。":b.message||"成长记录保存失败",N(b))}finally{F(!1)}}}async function ve(e){var r=G(),t=S(),i=C[e];if(!(R||!T||!t||!s(e)||m(r))&&await D("确认删除“"+(i?i.recordTitle:"该成长记录")+"”吗?删除后不可恢复,并会释放附件引用。")){F(!0);try{await r.deleteGrowthRecord(t,e),await te(),x("成长记录已删除")}catch(n){if(m(r,n))return;x(h(n)?"当前账号无权删除该成长记录。":n.message||"成长记录删除失败")}finally{F(!1)}}}function Ie(){var e=o('[data-growth-form] [name="mediaOssIds"]'),r=o("[data-growth-media-status]"),t=o("[data-growth-media-input]");e&&(e.value=""),t&&(t.value=""),r&&(r.textContent="未选择文件")}function we(){P&&(P.addEventListener("click",function(e){var r=e.target.closest("[data-growth-detail-id]"),t=e.target.closest("[data-growth-delete-id]"),i=e.target.closest("[data-growth-clear-media]"),n,d;if(r){e.preventDefault(),n=r.getAttribute("data-growth-detail-id"),d=S(),a.history&&d&&a.history.replaceState(null,"",W(d,n)),M(n).then(function(l){l&&a.ProfileUI&&a.ProfileUI.revealDetail&&a.ProfileUI.revealDetail(o("[data-growth-detail-heading]"))});return}if(t){e.preventDefault(),ve(t.getAttribute("data-growth-delete-id"));return}i&&(e.preventDefault(),Ie())}),P.addEventListener("submit",function(e){var r=e.target.closest("[data-growth-form]");r&&(e.preventDefault(),me(r))}))}function ye(){P&&(we(),o("[data-growth-page]")&&te(),o("[data-growth-edit-page]")&&he())}return{getCurrentGenealogyId:H,getCurrentRecordId:L,buildGrowthRecordBody:V,validateGrowthRecordBody:j,normalizeGrowthRecord:O,matchesSavedRecord:z,canEditRecords:K,renderLineageOptions:$,renderGrowthDetail:X,shouldRedirectToLogin:Y,isForbidden:h,init:ye}});
diff --git a/dist/public/js/help-pages.js b/dist/public/js/help-pages.js
deleted file mode 100644
index 18c065c..0000000
--- a/dist/public/js/help-pages.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(i,d){if(typeof module=="object"&&module.exports){module.exports=d(i);return}i.HelpPages=d(i),i.document&&i.document.addEventListener("DOMContentLoaded",function(){i.HelpPages.init()})})(typeof globalThis!="undefined"?globalThis:window,function(i){"use strict";function d(e){return String(e==null?"":e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function A(e){var t;return typeof e=="number"&&!Number.isSafeInteger(e)||e==null?"":(t=String(e).trim(),/^[1-9][0-9]*$/.test(t)?t:"")}function S(e){var t;return e==null||e===""?"0":typeof e=="number"&&(!Number.isSafeInteger(e)||e<0)?"":(t=String(e).trim(),/^(?:0|[1-9][0-9]*)$/.test(t)?t:"")}function m(e){return e==null?"":String(e).trim()}function p(e){var t=e||{},n=A(t.helpId),l=m(t.helpTitle),o=m(t.helpContent),c=S(t.viewCount);return!n||!l||!o||!c||String(t.status)!=="0"?null:{helpId:n,helpCategory:m(t.helpCategory),helpTitle:l,helpContent:o,viewCount:c}}function y(e){var t;return Array.isArray(e)?(t=e.map(p),t.some(function(n){return!n})?[]:t):[]}function w(e){var t=y(e);return t.length?t.map(function(n){var l=[n.helpCategory,"浏览 "+n.viewCount+" 次"].filter(Boolean).join(" · ");return''+d(n.helpTitle)+"
"+d(l)+'
'}).join(""):'当前暂无帮助文章
'}function b(e){var t=p(e),n;return t?(n=[t.helpCategory,"浏览 "+t.viewCount+" 次"].filter(Boolean).join(" · "),''+d(n)+"
"+d(t.helpContent).replace(/\r?\n/g,"
")+"
"):'帮助文章不存在或已停用
'}async function L(e,t){var n=A(t),l;if(!e||typeof e.helpArticleDetail!="function")throw new Error("帮助文章接口不可用");if(!n)throw new Error("帮助文章编号无效");if(l=p(await e.helpArticleDetail(n)),!l)throw new Error("帮助文章详情响应无效");if(l.helpId!==n)throw new Error("详情响应与请求编号不一致");return l}async function C(e){var t,n;if(!e||typeof e.helpArticles!="function")throw new Error("帮助文章接口不可用");if(t=await e.helpArticles(),n=y(t),!Array.isArray(t)||n.length!==t.length)throw new Error("帮助文章列表响应无效");return n}function h(e,t){var n=t&&(t.status||t.code);return!e||!e.getToken||!e.getToken()||Number(n)===401}function v(e){e&&e.clearToken&&e.clearToken(),i.NavigationUtil.open("login.html")}function s(e){return Number(e&&(e.status||e.code))===403}async function T(){var e=i.document&&i.document.querySelector("[data-help-list]"),t=i.document&&i.document.querySelector("[data-help-status]"),n=i.document&&i.document.querySelector("[data-help-refresh]"),l=i.GenealogyApi&&i.GenealogyApi.defaultClient;if(!e)return;if(h(l)){v(l);return}function o(r,a,u){if(r){if(i.ProfileUI&&i.ProfileUI.setApiState&&a){i.ProfileUI.setApiState(r,a,u);return}r.textContent=u||""}}function c(r,a){o(t,r,a)}function E(r){if(!r.length){o(e,"empty","当前暂无帮助文章。");return}e.innerHTML=w(r)}function H(r,a,u){r&&(r.dataset.defaultLabel||(r.dataset.defaultLabel=r.textContent),r.disabled=a,r.textContent=a?u:r.dataset.defaultLabel)}async function I(){try{e.classList.add("is-loading"),o(e,"loading","正在读取帮助文章…"),c("loading","正在读取帮助文章…"),E(await C(l)),c("","")}catch(r){if(h(l,r)){v(l);return}o(e,s(r)?"forbidden":"error",s(r)?"暂无权限查看帮助文章。":"帮助文章读取失败,请稍后重试。"),c(s(r)?"forbidden":"error",s(r)?"暂无权限查看帮助文章。":r.message||"帮助文章读取失败,请稍后重试。")}finally{e.classList.remove("is-loading")}}e.addEventListener("click",async function(r){var a=r.target.closest("[data-help-detail-id]"),u,f;if(!(!a||a.disabled)&&(u=a.getAttribute("data-help-detail-id"),f=e.querySelector('[data-help-detail-panel="'+u+'"]'),!!f)){a.disabled=!0,o(f,"loading","正在读取完整解答…");try{f.innerHTML=b(await L(l,u))}catch(g){if(h(l,g)){v(l);return}o(f,s(g)?"forbidden":"error",s(g)?"暂无权限查看该帮助文章。":g.message||"帮助文章详情读取失败,请稍后重试。")}}}),n&&n.addEventListener("click",async function(){H(n,!0,"正在刷新…");try{await I()}finally{H(n,!1,"正在刷新…")}}),await I()}return{normalizeHelpArticle:p,normalizeHelpArticleList:y,renderHelpArticleList:w,renderHelpArticleDetail:b,loadHelpArticleDetail:L,loadHelpArticles:C,isForbidden:s,shouldRedirectToLogin:h,init:T}});
diff --git a/dist/public/js/join-pages.js b/dist/public/js/join-pages.js
deleted file mode 100644
index 4b708c6..0000000
--- a/dist/public/js/join-pages.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(t,I){if(typeof module=="object"&&module.exports){module.exports=I(t);return}t.JoinPages=I(t),t.document&&t.document.addEventListener("DOMContentLoaded",function(){t.JoinPages.init()})})(typeof globalThis!="undefined"?globalThis:window,function(t){"use strict";function I(n){return t.ProfileUI&&typeof t.ProfileUI.confirmAction=="function"?t.ProfileUI.confirmAction(n):Promise.resolve(!t.confirm||t.confirm(n))}var T={0:"待审核",1:"已通过",2:"已拒绝",3:"已撤销"};function f(n){return String(n==null?"":n).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function A(n,e){return t.ProfileUI&&t.ProfileUI.renderApiState?t.ProfileUI.renderApiState(n,e):''+f(e)+"
"}function b(n){var e;return typeof n=="number"&&!Number.isSafeInteger(n)||n==null?"":(e=String(n).trim(),/^[1-9][0-9]*$/.test(e)?e:"")}function p(n){var e;return n==null?"":(e=String(n).trim(),e)}function N(n){var e=n||{},a={};return["applicantName","phone","relationDesc","applyReason"].forEach(function(i){var r=p(e[i]);r&&(a[i]=r)}),a}function L(n){var e=n||{},a={applicantName:[50,"申请人姓名不能超过 50 个字符"],phone:[30,"联系电话不能超过 30 个字符"],relationDesc:[100,"关系说明不能超过 100 个字符"],applyReason:[500,"申请理由不能超过 500 个字符"]},i=Object.keys(a),r;for(r=0;ra[i[r]][0])return a[i[r]][1];return""}function G(n){var e=n||{},a=b(e.genealogyId),i=p(e.genealogyName),r=p(e.surname),l=e.status===void 0||e.status===null?"":String(e.status);return!a||!i||!r||l&&l!=="0"?null:{genealogyId:a,genealogyName:i,surname:r,regionFullName:p(e.regionFullName),memberCount:e.memberCount,joinMode:e.joinMode===void 0||e.joinMode===null?"":String(e.joinMode)}}function w(n){var e=n||{},a=b(e.applyId),i=b(e.genealogyId),r=p(e.genealogyName),l=e.status===void 0||e.status===null?"":String(e.status);return!a||!i||!r||!Object.prototype.hasOwnProperty.call(T,l)?null:{applyId:a,genealogyId:i,genealogyName:r,surname:p(e.surname),relationDesc:p(e.relationDesc),applyReason:p(e.applyReason),auditRemark:p(e.auditRemark),auditTime:p(e.auditTime),status:l}}function J(n){var e;return Array.isArray(n)?(e=n.map(w),e.some(function(a){return!a})?[]:e):[]}function q(n){var e;return Array.isArray(n)?(e=n.map(G).filter(Boolean),e.length?e.map(function(a){var i=[a.surname+"氏",a.regionFullName,a.memberCount===void 0||a.memberCount===null?"":a.memberCount+" 位成员"].filter(Boolean).join(" · ");return''}).join(""):A("empty","没有找到可申请加入的家谱")):A("error","家谱列表数据无效,请刷新重试")}function U(n){var e=J(n);return e.length?e.map(function(a){var i=[a.surname?a.surname+"氏":"",a.relationDesc,a.applyReason,a.auditRemark?"审核说明:"+a.auditRemark:"",a.auditTime?"审核时间:"+a.auditTime:""].filter(Boolean).join(" · "),r=a.status==="0"?'':"";return''+f(a.genealogyName)+"
"+f(i||"等待申请状态更新")+'
'+T[a.status]+""+r+"
"}).join(""):A("empty","当前没有加入申请")}function g(n,e){var a=e&&(e.status||e.code);return!n||!n.getToken||!n.getToken()||Number(a)===401}function m(n){n&&n.clearToken&&n.clearToken(),t.NavigationUtil.open("login.html")}function v(n){return Number(n&&(n.status||n.code))===403?"forbidden":"error"}function u(n,e,a){var i=t.document&&t.document.querySelector(n);if(i){if(!e){i.innerHTML="";return}if(t.ProfileUI&&t.ProfileUI.setApiState){t.ProfileUI.setApiState(i,a||"error",e);return}i.textContent=e}}function M(n,e,a){if(n){if(t.ProfileUI&&t.ProfileUI.setApiState){t.ProfileUI.setApiState(n,e,a);return}n.innerHTML=A(e,a)}}function k(n,e,a){n&&(n.dataset.defaultLabel||(n.dataset.defaultLabel=n.textContent),n.disabled=!!e,n.textContent=e?a:n.dataset.defaultLabel,n.setAttribute("aria-busy",e?"true":"false"))}function O(n){var e={};return Array.prototype.forEach.call(n.querySelectorAll("[name]"),function(a){e[a.name]=a.value}),e}function C(n){var e=Number(n&&n.joinRemaining);return n&&typeof n.canJoin=="boolean"?n.canJoin:Number.isInteger(e)&&(e===-1||e>0)}async function x(){var n=t.document&&t.document.querySelector("[data-join-apply-page]"),e=t.document&&t.document.querySelector("[data-join-genealogy-search]"),a=t.document&&t.document.querySelector("[data-join-genealogy-options]"),i=t.document&&t.document.querySelector("[data-join-apply-form]"),r=t.document&&t.document.querySelector("[data-join-selected-genealogy]"),l=t.GenealogyApi&&t.GenealogyApi.defaultClient,c="",s=!1;if(!n)return;if(g(l)){m(l);return}function j(){c="",r&&(r.textContent="尚未选择家谱")}async function S(o){var d;j(),u("[data-join-options-status]","正在读取可申请家谱…","loading"),M(a,"loading","正在读取可申请家谱…");try{d=await l.genealogyOptions(o?{keyword:o}:{}),a.innerHTML=q(d),u("[data-join-options-status]","")}catch(y){if(g(l,y)){m(l);return}M(a,v(y),"读取家谱列表失败"),u("[data-join-options-status]",y.message||"读取家谱列表失败,请稍后重试",v(y))}}try{if(!C(await l.genealogyQuota())){u("[data-join-apply-status]","当前没有可用的家谱加入额度","empty"),i.querySelector("[data-join-apply-submit]").disabled=!0;return}}catch(o){if(g(l,o)){m(l);return}u("[data-join-apply-status]",o.message||"无法读取家谱加入额度",v(o)),i.querySelector("[data-join-apply-submit]").disabled=!0;return}e.addEventListener("submit",function(o){o.preventDefault(),S(p(e.querySelector('[name="keyword"]').value))}),a.addEventListener("click",function(o){var d=o.target.closest("[data-join-genealogy-id]");!d||!a.contains(d)||(c=b(d.getAttribute("data-join-genealogy-id")),c&&(r.textContent="已选择:"+d.getAttribute("data-join-genealogy-name"),Array.prototype.forEach.call(a.querySelectorAll("[data-join-genealogy-id]"),function(y){y.classList.toggle("is-selected",y===d)})))}),i.addEventListener("submit",async function(o){var d,y,P,R;if(o.preventDefault(),!s){if(!c){u("[data-join-apply-status]","请先从家谱列表中选择要加入的家谱","error");return}if(d=N(O(i)),y=L(d),y){u("[data-join-apply-status]",y,"error");return}s=!0,k(i.querySelector("[data-join-apply-submit]"),!0,"正在提交…"),u("[data-join-apply-status]","正在提交申请…","loading");try{if(P=w(await l.applyToGenealogy(c,d)),!P)throw new Error("申请响应缺少有效申请信息");if(R=J(await l.myGenealogyJoinApplies()),!R.some(function(h){return h.applyId===P.applyId}))throw new Error("提交后无法读取同一申请");t.NavigationUtil.open("profile-join-family.html")}catch(h){if(g(l,h)){m(l);return}u("[data-join-apply-status]",h.message||"提交加入申请失败,请稍后重试",v(h))}finally{s=!1,k(i.querySelector("[data-join-apply-submit]"),!1,"正在提交…")}}}),await S("")}async function E(){var n=t.document&&t.document.querySelector("[data-my-join-applies-page]"),e=t.document&&t.document.querySelector('[data-join-apply-list="mine"]'),a=t.document&&t.document.querySelector("[data-join-apply-refresh]"),i=t.GenealogyApi&&t.GenealogyApi.defaultClient,r=!1;if(!n)return;if(g(i)){m(i);return}async function l(){var c;u("[data-my-join-applies-status]","正在读取申请记录…","loading");try{return c=await i.myGenealogyJoinApplies(),e.innerHTML=U(c),u("[data-my-join-applies-status]",""),J(c)}catch(s){return g(i,s)?(m(i),[]):(e.innerHTML=A(v(s),"读取加入申请失败"),u("[data-my-join-applies-status]",s.message||"读取加入申请失败,请稍后重试",v(s)),[])}}a.addEventListener("click",function(){l()}),e.addEventListener("click",async function(c){var s=c.target.closest("[data-join-cancel-id]"),j,S;if(!(!s||!e.contains(s)||r)&&(j=b(s.getAttribute("data-join-cancel-id")),!!j&&await I("确认撤销这条加入申请吗?"))){r=!0,s.disabled=!0,u("[data-my-join-applies-status]","正在撤销申请…","loading");try{if(await i.cancelGenealogyJoinApply(j),S=await l(),S.some(function(o){return o.applyId===j&&o.status==="0"}))throw new Error("撤销后申请仍处于待审核状态")}catch(o){if(g(i,o)){m(i);return}u("[data-my-join-applies-status]",o.message||"撤销加入申请失败,请稍后重试",v(o))}finally{r=!1}}}),await l()}async function B(){if(t.document&&t.document.querySelector("[data-join-apply-page]")){await x();return}t.document&&t.document.querySelector("[data-my-join-applies-page]")&&await E()}return{buildJoinApplyBody:N,validateJoinApplyBody:L,normalizeJoinGenealogy:G,normalizeJoinApply:w,normalizeJoinApplies:J,renderJoinGenealogyOptions:q,renderMyJoinApplies:U,canJoinGenealogy:C,initJoinApplyPage:x,initMyJoinAppliesPage:E,init:B}});
diff --git a/dist/public/js/join-review-pages.js b/dist/public/js/join-review-pages.js
deleted file mode 100644
index 70490b2..0000000
--- a/dist/public/js/join-review-pages.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(t,c){if(typeof module=="object"&&module.exports){module.exports=c(t);return}t.JoinReviewPages=c(t),t.document&&t.document.addEventListener("DOMContentLoaded",function(){t.JoinReviewPages.initJoinReviewPage()})})(typeof globalThis!="undefined"?globalThis:window,function(t){"use strict";function c(e){return String(e==null?"":e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function v(e){var n;return typeof e=="number"&&!Number.isSafeInteger(e)||e==null?"":(n=String(e).trim(),/^[1-9][0-9]*$/.test(n)?n:"")}function y(e){return e==null?"":String(e).trim()}function x(e){var n,r;return e===void 0&&t.ProfileUI&&t.ProfileUI.getGenealogyId?(n=t.ProfileUI.getGenealogyId(),v(n)):(r=new URLSearchParams(String(e||"").replace(/^\?/,"")),v(r.get("genealogyId")))}function L(e){var n=e||{},r={status:String(n.status===void 0||n.status===null?"":n.status).trim()},i=y(n.auditRemark);return i&&(r.auditRemark=i),r}function U(e){return!e||["1","2"].indexOf(e.status)<0?"审核状态无效":String(e.auditRemark||"").length>500?"审核说明不能超过 500 个字符":""}function k(e){var n=e||{},r=v(n.applyId),i=v(n.genealogyId);return!r||!i||String(n.status)!=="0"?null:{applyId:r,genealogyId:i,genealogyName:y(n.genealogyName),applicantName:y(n.applicantName)||y(n.appUserNickName)||"未填写姓名",phone:y(n.phone),relationDesc:y(n.relationDesc),applyReason:y(n.applyReason)}}function j(e){var n;return Array.isArray(e)?(n=e.map(k),n.some(function(r){return!r})?[]:n):[]}function T(e,n){var r=j(e);return r.length?r.map(function(i){var u=[i.phone?"申请联系电话:"+i.phone:"",i.relationDesc?"关系:"+i.relationDesc:"",i.applyReason?"理由:"+i.applyReason:""].filter(Boolean).join(" · "),o=n?'':"";return''+c(i.applicantName)+"申请加入"+c(i.genealogyName||"当前家谱")+"
"+c(u||"申请人未补充说明")+"
"+o+""}).join(""):""}function h(e,n){var r=n&&(n.status||n.code);return!e||!e.getToken||!e.getToken()||Number(r)===401}function A(e){e&&e.clearToken&&e.clearToken(),t.NavigationUtil.open("login.html")}function s(e){return Number(e&&(e.status||e.code))===403?"forbidden":"error"}function l(e,n){var r=t.document&&t.document.querySelector("[data-join-review-status]");if(r){if(!e){r.innerHTML="";return}if(t.ProfileUI&&t.ProfileUI.setApiState){t.ProfileUI.setApiState(r,n||"error",e);return}r.textContent=e}}function b(e,n){var r=t.document&&t.document.querySelector("[data-join-review-form-status]");if(r){if(!e){r.innerHTML="";return}if(t.ProfileUI&&t.ProfileUI.setApiState){t.ProfileUI.setApiState(r,n||"error",e);return}r.textContent=e}}function w(e,n){var r=t.document&&t.document.querySelector('[data-join-apply-list="pending"]');if(r){if(t.ProfileUI&&t.ProfileUI.setApiState){t.ProfileUI.setApiState(r,n||"error",e);return}r.textContent=e}}function S(e){var n=t.document&&t.document.querySelector("[data-join-review-form]");n&&Array.prototype.slice.call(n.querySelectorAll("textarea, button")).forEach(function(r){r.disabled=!e})}function C(e){var n=t.document&&t.document.querySelector("[data-join-review-submit]");n&&(n.dataset.defaultLabel||(n.dataset.defaultLabel=n.textContent),n.textContent=e?"正在提交…":n.dataset.defaultLabel,n.setAttribute("aria-busy",e?"true":"false"))}function E(e,n){var r=t.document&&t.document.querySelector("[data-join-review-form]"),i=t.document&&t.document.querySelector("[data-join-review-editor]"),u=t.document&&t.document.querySelector("[data-join-review-form-title]"),o=t.document&&t.document.querySelector("[data-join-review-submit]");!r||!i||!e||["1","2"].indexOf(n)<0||(r.reset(),r.querySelector('[name="applyId"]').value=e,r.querySelector('[name="status"]').value=n,u&&(u.textContent=n==="1"?"通过加入申请":"拒绝加入申请"),o&&(o.textContent=n==="1"?"确认通过":"确认拒绝"),b(""),i.hidden=!1,t.location&&t.location.hash!=="#join-review-form"&&(t.location.hash="join-review-form"),r.querySelector('[name="auditRemark"]')&&r.querySelector('[name="auditRemark"]').focus&&r.querySelector('[name="auditRemark"]').focus())}function J(){var e=t.document&&t.document.querySelector("[data-join-review-form]"),n=t.document&&t.document.querySelector("[data-join-review-editor]");e&&e.reset(),n&&(n.hidden=!0),b("")}async function D(){var e=t.document&&t.document.querySelector("[data-join-review-page]"),n=t.document&&t.document.querySelector('[data-join-apply-list="pending"]'),r=t.document&&t.document.querySelector("[data-join-review-refresh]"),i=t.document&&t.document.querySelector("[data-join-review-form]"),u=t.GenealogyApi&&t.GenealogyApi.defaultClient,o=x(),p=!1,I=!1;if(!e)return;if(!o){l("请先从“我的家谱”选择要管理的家谱","forbidden"),S(!1),n.innerHTML='选择家谱后继续';return}if(t.ProfileUI&&t.ProfileUI.syncGenealogyContextLinks&&t.ProfileUI.syncGenealogyContextLinks(),h(u)){A(u);return}async function q(){var a;l("正在读取待审核申请…","loading");try{return a=await u.pendingGenealogyJoinApplies(o),!Array.isArray(a)||a.length&&!j(a).length?(w("待审核申请响应字段不完整,请联系后端核对。","error"),l("待审核申请响应字段不完整,请联系后端核对。","error"),[]):a.length?(n.innerHTML=T(a,p),l(p?"":"当前账号没有审核该家谱申请的权限",p?void 0:"forbidden"),j(a)):(w("当前没有待审核申请","empty"),l(""),[])}catch(d){return h(u,d)?(A(u),[]):(w(s(d)==="forbidden"?"当前账号没有审核该家谱申请的权限。":"读取待审核申请失败,请稍后重试。",s(d)),l(d.message||"读取待审核申请失败,请稍后重试",s(d)),[])}}try{var N=await u.genealogyDetail(o);if(p=N&&N.canManage===!0,!p){w("当前账号没有审核该家谱申请的权限。","forbidden"),l("当前账号没有审核该家谱申请的权限","forbidden"),S(!1);return}}catch(a){if(h(u,a)){A(u);return}l(a.message||"无法核验当前家谱管理权限",s(a)),w(s(a)==="forbidden"?"当前账号没有审核该家谱申请的权限。":"无法读取待审核申请,请稍后重试。",s(a)),S(!1);return}S(!0),r.addEventListener("click",function(){q()}),n.addEventListener("click",function(a){var d=a.target.closest("[data-join-audit-id]"),m,g;!d||!n.contains(d)||I||!p||(m=v(d.getAttribute("data-join-audit-id")),g=d.getAttribute("data-join-audit-status"),!(!m||["1","2"].indexOf(g)<0)&&E(m,g))}),i.addEventListener("submit",async function(a){var d,m,g,R,G,P=!1;if(a.preventDefault(),!(I||!p)){if(d={},Array.prototype.slice.call(i.querySelectorAll("[name]")).forEach(function(f){d[f.name]=f.value}),m=v(d.applyId),g=L(d),!m){b("申请编号无效,请返回列表重新操作。","error");return}if(R=U(g),R){b(R,"error");return}I=!0,S(!1),C(!0),b("正在提交审核结果…","loading");try{if(await u.auditGenealogyJoinApply(o,m,g),G=await q(),G.some(function(f){return f.applyId===m}))throw new Error("审核后申请仍在待审核列表");J()}catch(f){if(h(u,f)){A(u);return}P=s(f)==="forbidden",b(P?"当前账号无权审核该家谱申请。":f.message||"提交审核结果失败,请稍后重试。",s(f)),P&&(p=!1,l("当前账号无权审核该家谱申请。","forbidden"))}finally{I=!1,C(!1),P||S(!0)}}}),t.document.querySelector("[data-join-review-cancel]").addEventListener("click",function(){I||J()}),await q()}return{getCurrentGenealogyId:x,buildJoinAuditBody:L,validateJoinAuditBody:U,normalizePendingApply:k,renderPendingJoinApplies:T,initJoinReviewPage:D}});
diff --git a/dist/public/js/jquery360.js b/dist/public/js/jquery360.js
deleted file mode 100644
index 5bd12a8..0000000
--- a/dist/public/js/jquery360.js
+++ /dev/null
@@ -1,4 +0,0 @@
-/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */(function(H,Je){"use strict";typeof module=="object"&&typeof module.exports=="object"?module.exports=H.document?Je(H,!0):function(pe){if(!pe.document)throw new Error("jQuery requires a window with a document");return Je(pe)}:Je(H)})(typeof window!="undefined"?window:this,function(H,Je){"use strict";var pe=[],Qt=Object.getPrototypeOf,je=pe.slice,Jt=pe.flat?function(e){return pe.flat.call(e)}:function(e){return pe.concat.apply([],e)},At=pe.push,ut=pe.indexOf,lt={},Kt=lt.toString,ct=lt.hasOwnProperty,Zt=ct.toString,Jn=Zt.call(Object),F={},P=function(e){return typeof e=="function"&&typeof e.nodeType!="number"&&typeof e.item!="function"},Me=function(e){return e!=null&&e===e.window},R=H.document,Kn={type:!0,src:!0,nonce:!0,noModule:!0};function en(e,t,n){var r,o,a=(n=n||R).createElement("script");if(a.text=e,t)for(r in Kn)(o=t[r]||t.getAttribute&&t.getAttribute(r))&&a.setAttribute(r,o);n.head.appendChild(a).parentNode.removeChild(a)}function Ie(e){return e==null?e+"":typeof e=="object"||typeof e=="function"?lt[Kt.call(e)]||"object":typeof e}var tn="3.6.0",i=function(e,t){return new i.fn.init(e,t)};function Nt(e){var t=!!e&&"length"in e&&e.length,n=Ie(e);return!P(e)&&!Me(e)&&(n==="array"||t===0||typeof t=="number"&&0+~]|"+L+")"+L+"*"),Mr=new RegExp(L+"|>"),Ir=new RegExp(ce),Wr=new RegExp("^"+W+"$"),wt={ID:new RegExp("^#("+W+")"),CLASS:new RegExp("^\\.("+W+")"),TAG:new RegExp("^("+W+"|[*])"),ATTR:new RegExp("^"+J),PSEUDO:new RegExp("^"+ce),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+Ce+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Fr=/HTML$/i,Br=/^(?:input|select|textarea|button)$/i,$r=/^h\d$/i,st=/^[^{]+\{\s*\[native \w/,_r=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,zt=/[+~]/,Ae=new RegExp("\\\\[\\da-fA-F]{1,6}"+L+"?|\\\\([^\\r\\n\\f])","g"),Ne=function(u,l){var p="0x"+u.slice(1)-65536;return l||(p<0?String.fromCharCode(p+65536):String.fromCharCode(p>>10|55296,1023&p|56320))},_n=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,zn=function(u,l){return l?u==="\0"?"�":u.slice(0,-1)+"\\"+u.charCodeAt(u.length-1).toString(16)+" ":"\\"+u},Un=function(){g()},zr=Et(function(u){return u.disabled===!0&&u.nodeName.toLowerCase()==="fieldset"},{dir:"parentNode",next:"legend"});try{X.apply(oe=ue.call(q.childNodes),q.childNodes),oe[q.childNodes.length].nodeType}catch(u){X={apply:oe.length?function(l,p){ge.apply(l,ue.call(p))}:function(l,p){for(var y=l.length,h=0;l[y++]=p[h++];);l.length=y-1}}}function $(u,l,p,y){var h,b,w,T,C,D,N,j=l&&l.ownerDocument,M=l?l.nodeType:9;if(p=p||[],typeof u!="string"||!u||M!==1&&M!==9&&M!==11)return p;if(!y&&(g(l),l=l||v,k)){if(M!==11&&(C=_r.exec(u)))if(h=C[1]){if(M===9){if(!(w=l.getElementById(h)))return p;if(w.id===h)return p.push(w),p}else if(j&&(w=j.getElementById(h))&&ae(l,w)&&w.id===h)return p.push(w),p}else{if(C[2])return X.apply(p,l.getElementsByTagName(u)),p;if((h=C[3])&&n.getElementsByClassName&&l.getElementsByClassName)return X.apply(p,l.getElementsByClassName(h)),p}if(n.qsa&&!se[u+" "]&&(!S||!S.test(u))&&(M!==1||l.nodeName.toLowerCase()!=="object")){if(N=u,j=l,M===1&&(Mr.test(u)||bt.test(u))){for((j=zt.test(u)&&Xt(l.parentNode)||l)===l&&n.scope||((T=l.getAttribute("id"))?T=T.replace(_n,zn):l.setAttribute("id",T=B)),b=(D=s(u)).length;b--;)D[b]=(T?"#"+T:":scope")+" "+Ct(D[b]);N=D.join(",")}try{return X.apply(p,j.querySelectorAll(N)),p}catch(V){se(u,!0)}finally{T===B&&l.removeAttribute("id")}}}return f(u.replace(fe,"$1"),l,p,y)}function Tt(){var u=[];return function l(p,y){return u.push(p+" ")>r.cacheLength&&delete l[u.shift()],l[p+" "]=y}}function ye(u){return u[B]=!0,u}function xe(u){var l=v.createElement("fieldset");try{return!!u(l)}catch(p){return!1}finally{l.parentNode&&l.parentNode.removeChild(l),l=null}}function Ut(u,l){for(var p=u.split("|"),y=p.length;y--;)r.attrHandle[p[y]]=l}function Xn(u,l){var p=l&&u,y=p&&u.nodeType===1&&l.nodeType===1&&u.sourceIndex-l.sourceIndex;if(y)return y;if(p){for(;p=p.nextSibling;)if(p===l)return-1}return u?1:-1}function Ur(u){return function(l){return l.nodeName.toLowerCase()==="input"&&l.type===u}}function Xr(u){return function(l){var p=l.nodeName.toLowerCase();return(p==="input"||p==="button")&&l.type===u}}function Vn(u){return function(l){return"form"in l?l.parentNode&&l.disabled===!1?"label"in l?"label"in l.parentNode?l.parentNode.disabled===u:l.disabled===u:l.isDisabled===u||l.isDisabled!==!u&&zr(l)===u:l.disabled===u:"label"in l&&l.disabled===u}}function Re(u){return ye(function(l){return l=+l,ye(function(p,y){for(var h,b=u([],p.length,l),w=b.length;w--;)p[h=b[w]]&&(p[h]=!(y[h]=p[h]))})})}function Xt(u){return u&&typeof u.getElementsByTagName!="undefined"&&u}for(t in n=$.support={},a=$.isXML=function(u){var l=u&&u.namespaceURI,p=u&&(u.ownerDocument||u).documentElement;return!Fr.test(l||p&&p.nodeName||"HTML")},g=$.setDocument=function(u){var l,p,y=u?u.ownerDocument||u:q;return y!=v&&y.nodeType===9&&y.documentElement&&(E=(v=y).documentElement,k=!a(v),q!=v&&(p=v.defaultView)&&p.top!==p&&(p.addEventListener?p.addEventListener("unload",Un,!1):p.attachEvent&&p.attachEvent("onunload",Un)),n.scope=xe(function(h){return E.appendChild(h).appendChild(v.createElement("div")),typeof h.querySelectorAll!="undefined"&&!h.querySelectorAll(":scope fieldset div").length}),n.attributes=xe(function(h){return h.className="i",!h.getAttribute("className")}),n.getElementsByTagName=xe(function(h){return h.appendChild(v.createComment("")),!h.getElementsByTagName("*").length}),n.getElementsByClassName=st.test(v.getElementsByClassName),n.getById=xe(function(h){return E.appendChild(h).id=B,!v.getElementsByName||!v.getElementsByName(B).length}),n.getById?(r.filter.ID=function(h){var b=h.replace(Ae,Ne);return function(w){return w.getAttribute("id")===b}},r.find.ID=function(h,b){if(typeof b.getElementById!="undefined"&&k){var w=b.getElementById(h);return w?[w]:[]}}):(r.filter.ID=function(h){var b=h.replace(Ae,Ne);return function(w){var T=typeof w.getAttributeNode!="undefined"&&w.getAttributeNode("id");return T&&T.value===b}},r.find.ID=function(h,b){if(typeof b.getElementById!="undefined"&&k){var w,T,C,D=b.getElementById(h);if(D){if((w=D.getAttributeNode("id"))&&w.value===h)return[D];for(C=b.getElementsByName(h),T=0;D=C[T++];)if((w=D.getAttributeNode("id"))&&w.value===h)return[D]}return[]}}),r.find.TAG=n.getElementsByTagName?function(h,b){return typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName(h):n.qsa?b.querySelectorAll(h):void 0}:function(h,b){var w,T=[],C=0,D=b.getElementsByTagName(h);if(h==="*"){for(;w=D[C++];)w.nodeType===1&&T.push(w);return T}return D},r.find.CLASS=n.getElementsByClassName&&function(h,b){if(typeof b.getElementsByClassName!="undefined"&&k)return b.getElementsByClassName(h)},z=[],S=[],(n.qsa=st.test(v.querySelectorAll))&&(xe(function(h){var b;E.appendChild(h).innerHTML="",h.querySelectorAll("[msallowcapture^='']").length&&S.push("[*^$]="+L+`*(?:''|"")`),h.querySelectorAll("[selected]").length||S.push("\\["+L+"*(?:value|"+Ce+")"),h.querySelectorAll("[id~="+B+"-]").length||S.push("~="),(b=v.createElement("input")).setAttribute("name",""),h.appendChild(b),h.querySelectorAll("[name='']").length||S.push("\\["+L+"*name"+L+"*="+L+`*(?:''|"")`),h.querySelectorAll(":checked").length||S.push(":checked"),h.querySelectorAll("a#"+B+"+*").length||S.push(".#.+[+~]"),h.querySelectorAll("\\\f"),S.push("[\\r\\n\\f]")}),xe(function(h){h.innerHTML="";var b=v.createElement("input");b.setAttribute("type","hidden"),h.appendChild(b).setAttribute("name","D"),h.querySelectorAll("[name=d]").length&&S.push("name"+L+"*[*^$|!~]?="),h.querySelectorAll(":enabled").length!==2&&S.push(":enabled",":disabled"),E.appendChild(h).disabled=!0,h.querySelectorAll(":disabled").length!==2&&S.push(":enabled",":disabled"),h.querySelectorAll("*,:x"),S.push(",.*:")})),(n.matchesSelector=st.test(Q=E.matches||E.webkitMatchesSelector||E.mozMatchesSelector||E.oMatchesSelector||E.msMatchesSelector))&&xe(function(h){n.disconnectedMatch=Q.call(h,"*"),Q.call(h,"[s!='']:x"),z.push("!=",ce)}),S=S.length&&new RegExp(S.join("|")),z=z.length&&new RegExp(z.join("|")),l=st.test(E.compareDocumentPosition),ae=l||st.test(E.contains)?function(h,b){var w=h.nodeType===9?h.documentElement:h,T=b&&b.parentNode;return h===T||!(!T||T.nodeType!==1||!(w.contains?w.contains(T):h.compareDocumentPosition&&16&h.compareDocumentPosition(T)))}:function(h,b){if(b){for(;b=b.parentNode;)if(b===h)return!0}return!1},Pe=l?function(h,b){if(h===b)return x=!0,0;var w=!h.compareDocumentPosition-!b.compareDocumentPosition;return w||(1&(w=(h.ownerDocument||h)==(b.ownerDocument||b)?h.compareDocumentPosition(b):1)||!n.sortDetached&&b.compareDocumentPosition(h)===w?h==v||h.ownerDocument==q&&ae(q,h)?-1:b==v||b.ownerDocument==q&&ae(q,b)?1:m?le(m,h)-le(m,b):0:4&w?-1:1)}:function(h,b){if(h===b)return x=!0,0;var w,T=0,C=h.parentNode,D=b.parentNode,N=[h],j=[b];if(!C||!D)return h==v?-1:b==v?1:C?-1:D?1:m?le(m,h)-le(m,b):0;if(C===D)return Xn(h,b);for(w=h;w=w.parentNode;)N.unshift(w);for(w=b;w=w.parentNode;)j.unshift(w);for(;N[T]===j[T];)T++;return T?Xn(N[T],j[T]):N[T]==q?-1:j[T]==q?1:0}),v},$.matches=function(u,l){return $(u,null,null,l)},$.matchesSelector=function(u,l){if(g(u),n.matchesSelector&&k&&!se[l+" "]&&(!z||!z.test(l))&&(!S||!S.test(l)))try{var p=Q.call(u,l);if(p||n.disconnectedMatch||u.document&&u.document.nodeType!==11)return p}catch(y){se(l,!0)}return 0<$(l,v,null,[u]).length},$.contains=function(u,l){return(u.ownerDocument||u)!=v&&g(u),ae(u,l)},$.attr=function(u,l){(u.ownerDocument||u)!=v&&g(u);var p=r.attrHandle[l.toLowerCase()],y=p&&Ge.call(r.attrHandle,l.toLowerCase())?p(u,l,!k):void 0;return y!==void 0?y:n.attributes||!k?u.getAttribute(l):(y=u.getAttributeNode(l))&&y.specified?y.value:null},$.escape=function(u){return(u+"").replace(_n,zn)},$.error=function(u){throw new Error("Syntax error, unrecognized expression: "+u)},$.uniqueSort=function(u){var l,p=[],y=0,h=0;if(x=!n.detectDuplicates,m=!n.sortStable&&u.slice(0),u.sort(Pe),x){for(;l=u[h++];)l===u[h]&&(y=p.push(h));for(;y--;)u.splice(p[y],1)}return m=null,u},o=$.getText=function(u){var l,p="",y=0,h=u.nodeType;if(h){if(h===1||h===9||h===11){if(typeof u.textContent=="string")return u.textContent;for(u=u.firstChild;u;u=u.nextSibling)p+=o(u)}else if(h===3||h===4)return u.nodeValue}else for(;l=u[y++];)p+=o(l);return p},(r=$.selectors={cacheLength:50,createPseudo:ye,match:wt,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(u){return u[1]=u[1].replace(Ae,Ne),u[3]=(u[3]||u[4]||u[5]||"").replace(Ae,Ne),u[2]==="~="&&(u[3]=" "+u[3]+" "),u.slice(0,4)},CHILD:function(u){return u[1]=u[1].toLowerCase(),u[1].slice(0,3)==="nth"?(u[3]||$.error(u[0]),u[4]=+(u[4]?u[5]+(u[6]||1):2*(u[3]==="even"||u[3]==="odd")),u[5]=+(u[7]+u[8]||u[3]==="odd")):u[3]&&$.error(u[0]),u},PSEUDO:function(u){var l,p=!u[6]&&u[2];return wt.CHILD.test(u[0])?null:(u[3]?u[2]=u[4]||u[5]||"":p&&Ir.test(p)&&(l=s(p,!0))&&(l=p.indexOf(")",p.length-l)-p.length)&&(u[0]=u[0].slice(0,l),u[2]=p.slice(0,l)),u.slice(0,3))}},filter:{TAG:function(u){var l=u.replace(Ae,Ne).toLowerCase();return u==="*"?function(){return!0}:function(p){return p.nodeName&&p.nodeName.toLowerCase()===l}},CLASS:function(u){var l=U[u+" "];return l||(l=new RegExp("(^|"+L+")"+u+"("+L+"|$)"))&&U(u,function(p){return l.test(typeof p.className=="string"&&p.className||typeof p.getAttribute!="undefined"&&p.getAttribute("class")||"")})},ATTR:function(u,l,p){return function(y){var h=$.attr(y,u);return h==null?l==="!=":!l||(h+="",l==="="?h===p:l==="!="?h!==p:l==="^="?p&&h.indexOf(p)===0:l==="*="?p&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function jt(e,t,n){return P(t)?i.grep(e,function(r,o){return!!t.call(r,o,r)!==n}):t.nodeType?i.grep(e,function(r){return r===t!==n}):typeof t!="string"?i.grep(e,function(r){return-1)[^>]*|#([\w-]+))$/;(i.fn.init=function(e,t,n){var r,o;if(!e)return this;if(n=n||an,typeof e=="string"){if(!(r=e[0]==="<"&&e[e.length-1]===">"&&3<=e.length?[null,e,null]:Zn.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof i?t[0]:t,i.merge(this,i.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:R,!0)),on.test(r[1])&&i.isPlainObject(t))for(r in t)P(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(o=R.getElementById(r[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):P(e)?n.ready!==void 0?n.ready(e):e(i):i.makeArray(e,this)}).prototype=i.fn,an=i(R);var er=/^(?:parents|prev(?:Until|All))/,tr={children:!0,contents:!0,next:!0,prev:!0};function sn(e,t){for(;(e=e[t])&&e.nodeType!==1;);return e}i.fn.extend({has:function(e){var t=i(e,this),n=t.length;return this.filter(function(){for(var r=0;r\x20\t\r\n\f]*)/i,hn=/^$|^module$|\/(?:java|ecma)script/i;Le=R.createDocumentFragment().appendChild(R.createElement("div")),(ht=R.createElement("input")).setAttribute("type","radio"),ht.setAttribute("checked","checked"),ht.setAttribute("name","t"),Le.appendChild(ht),F.checkClone=Le.cloneNode(!0).cloneNode(!0).lastChild.checked,Le.innerHTML="",F.noCloneChecked=!!Le.cloneNode(!0).lastChild.defaultValue,Le.innerHTML="",F.option=!!Le.lastChild;var he={thead:[1,""],col:[2,""],tr:[2,""],td:[3,""],_default:[0,"",""]};function re(e,t){var n;return n=typeof e.getElementsByTagName!="undefined"?e.getElementsByTagName(t||"*"):typeof e.querySelectorAll!="undefined"?e.querySelectorAll(t||"*"):[],t===void 0||t&&de(e,t)?i.merge([e],n):n}function qt(e,t){for(var n=0,r=e.length;n",""]);var lr=/<|?\w+;/;function gn(e,t,n,r,o){for(var a,s,c,f,d,m,x=t.createDocumentFragment(),g=[],v=0,E=e.length;v\s*$/g;function vn(e,t){return de(e,"table")&&de(t.nodeType!==11?t:t.firstChild,"tr")&&i(e).children("tbody")[0]||e}function hr(e){return e.type=(e.getAttribute("type")!==null)+"/"+e.type,e}function gr(e){return(e.type||"").slice(0,5)==="true/"?e.type=e.type.slice(5):e.removeAttribute("type"),e}function yn(e,t){var n,r,o,a,s,c;if(t.nodeType===1){if(A.hasData(e)&&(c=A.get(e).events))for(o in A.remove(t,"handle events"),c)for(n=0,r=c[o].length;n").attr(e.scriptAttrs||{}).prop({charset:e.scriptCharset,src:e.url}).on("load error",n=function(a){t.remove(),n=null,a&&o(a.type==="error"?404:200,a.type)}),R.head.appendChild(t[0])},abort:function(){n&&n()}}});var Bn,$n=[],_t=/(=)\?(?=&|$)|\?\?/;i.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=$n.pop()||i.expando+"_"+Pn.guid++;return this[e]=!0,e}}),i.ajaxPrefilter("json jsonp",function(e,t,n){var r,o,a,s=e.jsonp!==!1&&(_t.test(e.url)?"url":typeof e.data=="string"&&(e.contentType||"").indexOf("application/x-www-form-urlencoded")===0&&_t.test(e.data)&&"data");if(s||e.dataTypes[0]==="jsonp")return r=e.jsonpCallback=P(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,s?e[s]=e[s].replace(_t,"$1"+r):e.jsonp!==!1&&(e.url+=(It.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return a||i.error(r+" was not called"),a[0]},e.dataTypes[0]="json",o=H[r],H[r]=function(){a=arguments},n.always(function(){o===void 0?i(H).removeProp(r):H[r]=o,e[r]&&(e.jsonpCallback=t.jsonpCallback,$n.push(r)),a&&P(o)&&o(a[0]),a=o=void 0}),"script"}),F.createHTMLDocument=((Bn=R.implementation.createHTMLDocument("").body).innerHTML="",Bn.childNodes.length===2),i.parseHTML=function(e,t,n){return typeof e!="string"?[]:(typeof t=="boolean"&&(n=t,t=!1),t||(F.createHTMLDocument?((r=(t=R.implementation.createHTMLDocument("")).createElement("base")).href=R.location.href,t.head.appendChild(r)):t=R),a=!n&&[],(o=on.exec(e))?[t.createElement(o[1])]:(o=gn([e],t,a),a&&a.length&&i(a).remove(),i.merge([],o.childNodes)));var r,o,a},i.fn.load=function(e,t,n){var r,o,a,s=this,c=e.indexOf(" ");return-1").append(i.parseHTML(f)).find(r):f)}).always(n&&function(f,d){s.each(function(){n.apply(this,a||[f.responseText,d,f])})}),this},i.expr.pseudos.animated=function(e){return i.grep(i.timers,function(t){return e===t.elem}).length},i.offset={setOffset:function(e,t,n){var r,o,a,s,c,f,d=i.css(e,"position"),m=i(e),x={};d==="static"&&(e.style.position="relative"),c=m.offset(),a=i.css(e,"top"),f=i.css(e,"left"),(d==="absolute"||d==="fixed")&&-1<(a+f).indexOf("auto")?(s=(r=m.position()).top,o=r.left):(s=parseFloat(a)||0,o=parseFloat(f)||0),P(t)&&(t=t.call(e,n,i.extend({},c))),t.top!=null&&(x.top=t.top-c.top+s),t.left!=null&&(x.left=t.left-c.left+o),"using"in t?t.using.call(e,x):m.css(x)}},i.fn.extend({offset:function(e){if(arguments.length)return e===void 0?this:this.each(function(o){i.offset.setOffset(this,e,o)});var t,n,r=this[0];return r?r.getClientRects().length?(t=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:t.top+n.pageYOffset,left:t.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],o={top:0,left:0};if(i.css(r,"position")==="fixed")t=r.getBoundingClientRect();else{for(t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;e&&(e===n.body||e===n.documentElement)&&i.css(e,"position")==="static";)e=e.parentNode;e&&e!==r&&e.nodeType===1&&((o=i(e).offset()).top+=i.css(e,"borderTopWidth",!0),o.left+=i.css(e,"borderLeftWidth",!0))}return{top:t.top-o.top-i.css(r,"marginTop",!0),left:t.left-o.left-i.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){for(var e=this.offsetParent;e&&i.css(e,"position")==="static";)e=e.offsetParent;return e||qe})}}),i.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,t){var n=t==="pageYOffset";i.fn[e]=function(r){return Se(this,function(o,a,s){var c;if(Me(o)?c=o:o.nodeType===9&&(c=o.defaultView),s===void 0)return c?c[t]:o[a];c?c.scrollTo(n?c.pageXOffset:s,n?s:c.pageYOffset):o[a]=s},e,r,arguments.length)}}),i.each(["top","left"],function(e,t){i.cssHooks[t]=wn(F.pixelPosition,function(n,r){if(r)return r=nt(n,t),Ht.test(r)?i(n).position()[t]+"px":r})}),i.each({Height:"height",Width:"width"},function(e,t){i.each({padding:"inner"+e,content:t,"":"outer"+e},function(n,r){i.fn[r]=function(o,a){var s=arguments.length&&(n||typeof o!="boolean"),c=n||(o===!0||a===!0?"margin":"border");return Se(this,function(f,d,m){var x;return Me(f)?r.indexOf("outer")===0?f["inner"+e]:f.document.documentElement["client"+e]:f.nodeType===9?(x=f.documentElement,Math.max(f.body["scroll"+e],x["scroll"+e],f.body["offset"+e],x["offset"+e],x["client"+e])):m===void 0?i.css(f,d,c):i.style(f,d,m,c)},t,s?o:void 0,s)}})}),i.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){i.fn[t]=function(n){return this.on(t,n)}}),i.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return arguments.length===1?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),i.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,t){i.fn[t]=function(n,r){return 0.el-scrollbar__bar,.el-scrollbar:focus>.el-scrollbar__bar,.el-scrollbar:hover>.el-scrollbar__bar{opacity:1;transition:opacity .34s ease-out}.el-scrollbar__wrap{overflow:scroll;height:100%}.el-scrollbar__wrap--hidden-default{scrollbar-width:none}.el-scrollbar__wrap--hidden-default::-webkit-scrollbar{width:0;height:0}.el-scrollbar__thumb{position:relative;display:block;width:0;height:0;cursor:pointer;border-radius:inherit;background-color:#9093994d;transition:background-color .3s}.el-scrollbar__thumb:hover{background-color:#90939980}.el-scrollbar__bar{position:absolute;right:2px;bottom:2px;z-index:1;border-radius:4px;opacity:0;transition:opacity .12s ease-out}.el-scrollbar__bar.is-vertical{width:6px;top:2px}.el-scrollbar__bar.is-vertical>div{width:100%}.el-scrollbar__bar.is-horizontal{height:6px;left:2px}.el-scrollbar__bar.is-horizontal>div{height:100%}.el-cascader{display:inline-block;position:relative;font-size:14px;line-height:40px}.el-cascader:not(.is-disabled):hover .el-input__inner{cursor:pointer;border-color:#c0c4cc}.el-cascader .el-input{cursor:pointer}.el-cascader .el-input .el-input__inner{text-overflow:ellipsis}.el-cascader .el-input .el-input__inner:focus{border-color:#409eff}.el-cascader .el-input .el-icon-arrow-down{display:inline-block;transition:transform .3s;font-size:14px}.el-cascader .el-input .el-icon-arrow-down.is-reverse{transform:rotate(180deg)}.el-cascader .el-input .el-icon-circle-close:hover{color:#909399}.el-cascader .el-input.is-focus .el-input__inner{border-color:#409eff}.el-cascader--medium{font-size:14px;line-height:36px}.el-cascader--small{font-size:13px;line-height:32px}.el-cascader--mini{font-size:12px;line-height:28px}.el-cascader.is-disabled .el-cascader__label{z-index:2;color:#c0c4cc}.el-cascader__dropdown{margin:5px 0;font-size:14px;background:#fff;border:1px solid #e4e7ed;border-radius:4px;box-shadow:0 2px 12px #0000001a}.el-cascader__tags{position:absolute;left:0;right:30px;top:50%;transform:translateY(-50%);display:flex;flex-wrap:wrap;line-height:normal;text-align:left;box-sizing:border-box}.el-cascader__tags .el-tag{display:inline-flex;align-items:center;max-width:100%;margin:2px 0 2px 6px;text-overflow:ellipsis;background:#f0f2f5}.el-cascader__tags .el-tag:not(.is-hit){border-color:transparent}.el-cascader__tags .el-tag>span{flex:1;overflow:hidden;text-overflow:ellipsis}.el-cascader__tags .el-tag .el-icon-close{flex:none;background-color:#c0c4cc;color:#fff}.el-cascader__tags .el-tag .el-icon-close:hover{background-color:#909399}.el-cascader__suggestion-panel{border-radius:4px}.el-cascader__suggestion-list{max-height:204px;margin:0;padding:6px 0;font-size:14px;color:#606266;text-align:center}.el-cascader__suggestion-item{display:flex;justify-content:space-between;align-items:center;height:34px;padding:0 15px;text-align:left;outline:none;cursor:pointer}.el-cascader__suggestion-item:focus,.el-cascader__suggestion-item:hover{background:#f5f7fa}.el-cascader__suggestion-item.is-checked{color:#409eff;font-weight:700}.el-cascader__suggestion-item .el-icon-check{margin-right:15px}.el-cascader__suggestion-item>span{margin-right:10px}.el-cascader__empty-text{margin:10px 0;color:#c0c4cc}.el-cascader__search-input{flex:1;height:24px;min-width:60px;margin:2px 0 2px 15px;padding:0;color:#606266;border:none;outline:none;box-sizing:border-box}.el-cascader__search-input::placeholder{color:#c0c4cc}.el-cascader-panel{display:flex;border-radius:4px;font-size:14px}.el-cascader-panel.is-bordered{border:1px solid #e4e7ed;border-radius:4px}.el-cascader-menu{min-width:180px;box-sizing:border-box;color:#606266;border-right:1px solid #e4e7ed}.el-cascader-menu:last-child{border-right:none}.el-cascader-menu:last-child .el-cascader-node{padding-right:26px}.el-cascader-menu__wrap{height:204px}.el-cascader-menu__list{position:relative;min-height:100%;padding:6px 0;list-style:none;box-sizing:border-box}.el-cascader-menu__hover-zone{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.el-cascader-menu__empty-text{position:absolute;top:50%;left:46%;transform:translate(-50%,-50%);text-align:center;color:#c0c4cc}.el-cascader-node{position:relative;display:flex;align-items:center;padding:0 25px 0 15px;height:34px;line-height:34px;outline:none}.el-cascader-node.is-selectable.in-active-path{color:#606266}.el-cascader-node.in-active-path,.el-cascader-node.is-active,.el-cascader-node.is-selectable.in-checked-path{color:#409eff;font-weight:700}.el-cascader-node:not(.is-disabled){cursor:pointer}.el-cascader-node:not(.is-disabled):focus,.el-cascader-node:not(.is-disabled):hover{background:#f5f7fa}.el-cascader-node.is-disabled{color:#c0c4cc;cursor:not-allowed}.el-cascader-node__prefix{position:absolute;left:10px}.el-cascader-node__postfix{position:absolute;right:10px}.el-cascader-node__label{flex:1;padding:0 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.el-cascader-node>.el-radio{margin-right:0}.el-cascader-node>.el-radio .el-radio__label{padding-left:0}.el-input{position:relative;font-size:14px;display:inline-block;width:100%}.el-input::-webkit-scrollbar{z-index:11;width:6px}.el-input::-webkit-scrollbar:horizontal{height:6px}.el-input::-webkit-scrollbar-thumb{border-radius:5px;width:6px;background:#b4bccc}.el-input::-webkit-scrollbar-corner,.el-input::-webkit-scrollbar-track{background:#fff}.el-input::-webkit-scrollbar-track-piece{background:#fff;width:6px}.el-input .el-input__clear{color:#c0c4cc;font-size:14px;cursor:pointer;transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-input .el-input__clear:hover{color:#909399}.el-input .el-input__count{height:100%;display:inline-flex;align-items:center;color:#909399;font-size:12px}.el-input .el-input__count .el-input__count-inner{background:#fff;line-height:normal;display:inline-block;padding:0 5px}.el-input__inner{-webkit-appearance:none;background-color:#fff;background-image:none;border-radius:4px;border:1px solid #dcdfe6;box-sizing:border-box;color:#606266;display:inline-block;font-size:inherit;height:40px;line-height:40px;outline:none;padding:0 15px;transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}.el-input__inner::-ms-reveal{display:none}.el-input__inner::placeholder{color:#c0c4cc}.el-input__inner:hover{border-color:#c0c4cc}.el-input__inner:focus{outline:none;border-color:#409eff}.el-input__suffix{position:absolute;height:100%;right:5px;top:0;text-align:center;color:#c0c4cc;transition:all .3s;pointer-events:none;display:flex;flex-direction:column;justify-content:center}.el-input__suffix-inner{pointer-events:all}.el-input__prefix{position:absolute;left:5px;top:0;color:#c0c4cc}.el-input__icon,.el-input__prefix{height:100%;text-align:center;transition:all .3s}.el-input__icon{width:25px;line-height:40px}.el-input__icon:after{content:"";height:100%;width:0;display:inline-block;vertical-align:middle}.el-input__validateIcon{pointer-events:none}.el-input.is-active .el-input__inner{outline:none;border-color:#409eff}.el-input.is-disabled .el-input__inner{background-color:#f5f7fa;border-color:#e4e7ed;color:#c0c4cc;cursor:not-allowed}.el-input.is-disabled .el-input__inner::placeholder{color:#c0c4cc}.el-input.is-disabled .el-input__icon{cursor:not-allowed}.el-input.is-exceed .el-input__inner{border-color:#f56c6c}.el-input.is-exceed .el-input__suffix .el-input__count{color:#f56c6c}.el-input--suffix .el-input__inner{padding-right:30px}.el-input--prefix .el-input__inner{padding-left:30px}.el-input--medium{font-size:14px}.el-input--medium .el-input__inner{height:36px;line-height:36px}.el-input--medium .el-input__icon{line-height:36px}.el-input--small{font-size:13px}.el-input--small .el-input__inner{height:32px;line-height:32px}.el-input--small .el-input__icon{line-height:32px}.el-input--mini{font-size:12px}.el-input--mini .el-input__inner{height:28px;line-height:28px}.el-input--mini .el-input__icon{line-height:28px}.el-input-group{line-height:normal;display:inline-table;width:100%;border-collapse:separate;border-spacing:0}.el-input-group>.el-input__inner{vertical-align:middle;display:table-cell}.el-input-group__append,.el-input-group__prepend{background-color:#f5f7fa;color:#909399;vertical-align:middle;display:table-cell;position:relative;border:1px solid #dcdfe6;border-radius:4px;padding:0 20px;width:1px;white-space:nowrap}.el-input-group__append:focus,.el-input-group__prepend:focus{outline:none}.el-input-group__append .el-button,.el-input-group__append .el-select,.el-input-group__prepend .el-button,.el-input-group__prepend .el-select{display:inline-block;margin:-10px -20px}.el-input-group__append button.el-button,.el-input-group__append div.el-select .el-input__inner,.el-input-group__append div.el-select:hover .el-input__inner,.el-input-group__prepend button.el-button,.el-input-group__prepend div.el-select .el-input__inner,.el-input-group__prepend div.el-select:hover .el-input__inner{border-color:transparent;background-color:transparent;color:inherit;border-top:0;border-bottom:0}.el-input-group__append .el-button,.el-input-group__append .el-input,.el-input-group__prepend .el-button,.el-input-group__prepend .el-input{font-size:inherit}.el-input-group__prepend{border-right:0;border-top-right-radius:0;border-bottom-right-radius:0}.el-input-group__append{border-left:0}.el-input-group--prepend .el-input__inner,.el-input-group__append{border-top-left-radius:0;border-bottom-left-radius:0}.el-input-group--prepend .el-select .el-input.is-focus .el-input__inner{border-color:transparent}.el-input-group--append .el-input__inner{border-top-right-radius:0;border-bottom-right-radius:0}.el-input-group--append .el-select .el-input.is-focus .el-input__inner{border-color:transparent}.el-input__inner::-ms-clear{display:none;width:0;height:0}::-webkit-scrollbar{width:0}
diff --git a/dist/public/js/lay-module/cascader/cascader.js b/dist/public/js/lay-module/cascader/cascader.js
deleted file mode 100644
index 550aa1e..0000000
--- a/dist/public/js/lay-module/cascader/cascader.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(y){var h=y.document.currentScript.src,p=/(\S*\/)cascader(\.min)?\.js(\?.*)?/i.exec(h);p&&p.length>=2&&(!p[3]||p[3].indexOf("css=true")!==-1)&&layui.link(p[1]+"cascader"+(p[2]||"")+".css")})(window),layui.define(["jquery"],function(y){var h=layui.jquery;function p(e){e=e||window.event,e.stopPropagation?e.stopPropagation():e.cancelBubble=!0}function C(e,i,t,a){this.data=e,this.cascader=i,this.config=i.config,this.props=i.props,this.level=t,this.parentNode=a,this.icons=i.icons,this._checked=0,this._loading=!1,this.nodeId=i.data.nodeId++}C.prototype={constructor:C,get topParentNode(){return!this.parentNode&&this||this.topParentNode},childrenNode:void 0,get loading(){return this._loading},set loading(e){var i=this.$li;if(i){var t=this.icons.right,a=this.icons.loading,s=i.find("i");e?(s.addClass(a),s.removeClass(t)):(s.addClass(t),s.removeClass(a))}return this._loading=e},get label(){return this.data[this.props.label]},get value(){return this.data[this.props.value]},get disabled(){var e=this.props.multiple,i=this.config.maxSize,t=this.cascader.data.checkedNodeIds,a=this.props.disabled,s=this.props.checkStrictly;if(e&&i!==0&&t.length>=i&&t.indexOf(this.nodeId)===-1){if(s)return!0;var r=this.getAllLeafChildren(),n=r.map(function(c){return c.nodeId});if(!n.some(function(c){return t.indexOf(c)!==-1}))return!0}if(s)return this.data[a];var l=this.path;return l.some(function(c){return c.data[a]})},get children(){return this.data[this.props.children]},set children(e){this.data[this.props.children]=e},get leaf(){var e=this.data[this.props.leaf];return typeof e=="boolean"?e:this.children?this.children.length<=0:!0},get activeNodeId(){return this.cascader.data.activeNodeId},get checkedNodeIds(){return this.cascader.data.checkedNodeIds},get path(){var e=this.parentNode;return e?e.path.concat([this]):[this]},get isFiltering(){return this.cascader.isFiltering},get $tag(){var e=this.cascader,i=this.config.showAllLevels,t=this.config.disabled,a=this.disabled,s=this.config.disabledFixed,r=this.getPathLabel(i),n=e.get$tag(r,!t&&(!a||!s)),l=this;return n.find("i").click(function(c){p(c),l.selectedValue(),e.removeTag(l.value,l)}),n},getPathLabel:function(e){var i=this.path,t=this.config.separator,a;return e?a=i.map(function(s){return s.label}).join(t):a=i[i.length-1].label,a},init:function(){var e=this.props.multiple,i=this.props.checkStrictly,t=this.icons.from,a=this.icons.right,s="",r=this.label;this.leaf||(s=a),this.$li=h(''),!e&&!i?this._renderRadio():!e&&i?this._renderRadioCheckStrictly():e&&!i?this._renderMultiple():e&&i&&this._renderMultipleCheckStrictly()},initSuggestionLi:function(){var e=this.getPathLabel(!0);this.$suggestionLi=h(''+e+""),this._renderFiltering()},bind:function(e){this.init(),e.append(this.$li)},bindSuggestion:function(e){this.initSuggestionLi(),e.append(this.$suggestionLi)},_renderFiltering:function(){var e=this.$suggestionLi,i=this.nodeId,t=this.icons.from,a=this.icons.ok,s=this,r=this.cascader,n=this.props.multiple,l='';e.click(function(c){p(c),s.selectedValue(),n?s.checkedNodeIds.indexOf(i)===-1?(e.removeClass("is-checked"),e.find(".el-icon-check").remove()):(e.addClass("is-checked"),e.append(l)):r.close()}),(n&&s.checkedNodeIds.indexOf(i)!==-1||!n&&s.activeNodeId===i)&&(e.addClass("is-checked"),e.append(l))},_renderRadio:function(){var e=this.$li,i=this.nodeId,t=this.icons.from,a=this.icons.ok,s=this.level,r=this.leaf,n=this,l=this.cascader,c=this.cascader.data.activeNode,o=this.parentNode;if(n.activeNodeId&&c.path.some(function(d){return d.nodeId===i})&&(n.activeNodeId===i&&e.prepend(''),e.addClass("is-active"),e.addClass("in-checked-path")),this.disabled){e.addClass("is-disabled");return}e.addClass("is-selectable"),o&&(o.$li.siblings().removeClass("in-active-path"),o.$li.addClass("in-active-path")),this._liClick(function(d){p(d);var f=n.childrenNode;r&&d.type==="click"&&(n.selectedValue(),l.close()),l._appendMenu(f,s+1,n)})},_renderRadioCheckStrictly:function(){var e=this.$li,i=this.nodeId,t=this.level,a=this.leaf,s=this,r=this.cascader,n=r.data.activeNode,l=this.parentNode;e.addClass("is-selectable");var c=h('');if(this.$radio=c,e.prepend(c),l&&(l.$li.siblings().removeClass("in-active-path"),l.$li.addClass("in-active-path")),this._liClick(function(o){p(o);var d=s.childrenNode;!s.disabled&&a&&o.type==="click"&&s.selectedValue(),r._appendMenu(d,t+1,s)}),s.activeNodeId&&n.path.some(function(o){return o.nodeId===i})&&(s.activeNodeId===i&&c.find(".el-radio__input").addClass("is-checked"),e.addClass("is-active"),e.addClass("in-checked-path")),this.disabled){c.addClass("is-disabled"),c.find(".el-radio__input").addClass("is-disabled");return}c.click(function(o){o.preventDefault(),!a&&s.selectedValue()})},_renderMultiple:function(){var e=this.$li,i=this.level,t=this.leaf,a=this,s=this.cascader,r=this._checked,n=this.parentNode;e.addClass("el-cascader-node");var l=h('');if(this.$checked=l,e.prepend(l),r===1?this.$checked.find(".el-checkbox__input").addClass("is-checked"):r===2&&this.$checked.find(".el-checkbox__input").addClass("is-indeterminate"),n&&(n.$li.siblings().removeClass("in-active-path"),n.$li.addClass("in-active-path")),this._liClick(function(c){p(c);var o=a.childrenNode;!a.disabled&&t&&c.type==="click"&&a.selectedValue(),s._appendMenu(o,i+1,a)}),this.disabled){e.addClass("is-disabled"),l.addClass("is-disabled"),l.find(".el-checkbox__input").addClass("is-disabled");return}l.click(function(c){if(c.preventDefault(),!t){var o=a.childrenNode;a.selectedValue(),s._appendMenu(o,i+1,a)}})},_renderMultipleCheckStrictly:function(){var e=this.$li,i=this.level,t=this.leaf,a=this,s=this.cascader,r=s.data.checkedNodeIds,n=s.data.checkedNodes,l=this.nodeId,c=this.parentNode;e.addClass("el-cascader-node is-selectable");var o=h('');this.$checked=o,e.prepend(o);var d=n.some(function(f){return f.path.some(function(u){return u.nodeId===l})});if(d&&(e.addClass("in-checked-path"),r.indexOf(l)!==-1&&this.$checked.find(".el-checkbox__input").addClass("is-checked")),c&&(c.$li.siblings().removeClass("in-active-path"),c.$li.addClass("in-active-path")),this._liClick(function(f){p(f);var u=a.childrenNode;!a.disabled&&t&&f.type==="click"&&a.selectedValue(),s._appendMenu(u,i+1,a)}),this.disabled){o.addClass("is-disabled"),o.find(".el-checkbox__input").addClass("is-disabled");return}o.click(function(f){if(f.preventDefault(),!t){a.selectedValue();var u=a.childrenNode;s._appendMenu(u,i+1,a)}})},transferParent:function(e,i,t){if(t||(t=this),this!==t||i){var a=e&&e(this);if(a===!1)return}this.parentNode&&this.parentNode.transferParent(e,i,t)},transferChildren:function(e,i,t){if(t||(t=this),this!==t||i){var a=e&&e(this);if(a===!1)return}var s=this.getChildren();if(s&&s.length>0)for(var r in s)s[r].transferChildren(e,i,t)},selectedValue:function(){var e=this.nodeId,i=this.cascader,t=this.props.multiple,a=this.props.checkStrictly,s=this.leaf;if(!t&&(s||a))i._setActiveValue(e,this);else if(t){var r=i.data.checkedNodeIds,n=i.data.checkedNodes,l=this.config.disabledFixed,c;if(a){var o=r.indexOf(e);o===-1?c=n.concat([this]):(c=n.concat(),c.splice(o,1))}else{var d=this.getAllLeafChildren(),f;if(this._checked!==1&&l?f=this._getMultipleChecked(d):f=this._checked,f===1)c=n.filter(function(g){return!d.some(function(b){return g.nodeId===b.nodeId})});else{var u=d.filter(function(g){return r.indexOf(g.nodeId)===-1});c=n.concat(u)}}var v=c.map(function(g){return g.nodeId});i._setCheckedValue(v,c)}},_liLoad:function(e,i){var t=this.leaf,a=this.props.lazy,s=this.props.lazyLoad,r=this.children,n=this,l=this.cascader,c=this.level,o=this.props.multiple,d=this.props.checkStrictly;!t&&(!r||r.length===0)&&a?n.loading||(n.loading=!0,s(n,function(f){n.loading=!1,n.setChildren(l.initNodes(f,c+1,n)),n.children=f,i&&i(e),o&&!d&&n.transferParent(function(u){u.syncStyle()},!0)})):i&&i(e)},_liClick:function(e){var i=this.leaf,t=this.$li,a=this;function s(r){a._liLoad(r,e)}(this.props.expandTrigger==="click"||i)&&t.click(s),this.props.expandTrigger==="hover"&&t.mouseenter(s)},setChildren:function(e){this.childrenNode=e},getChildren:function(){return this.childrenNode},syncStyle:function(){var e=this.props.multiple,i=this.props.checkStrictly;e?i?this._sync.syncMultipleCheckStrictly(this):this._sync.syncMultiple(this):i?this._sync.syncRadioCheckStrictly(this):this._sync.syncRadio(this)},_sync:{syncRadio:function(e){var i=e.$li,t=e.icons.from,a=e.icons.ok,s=e.props.multiple,r=e.props.checkStrictly,n=e.nodeId;if(!(!i||s||r)){var l=e.cascader.data.activeNode;if(e.activeNodeId===n){var c=i.find("."+a);c.length===0&&i.prepend('')}else i.find("."+a).remove();l&&l.path.some(function(o){return o.nodeId===n})?(i.addClass("is-active"),i.addClass("in-checked-path")):(i.removeClass("is-active"),i.removeClass("in-checked-path"))}},syncRadioCheckStrictly:function(e){var i=e.$li,t=e.props.checkStrictly,a=e.props.multiple;if(!(!i||a||!t)){var s=e.$radio,r=e.cascader.data.activeNode,n=e.nodeId;e.activeNodeId===n?s.find(".el-radio__input").addClass("is-checked"):s.find(".el-radio__input").removeClass("is-checked"),r&&r.path.some(function(l){return l.nodeId===n})?(i.addClass("is-active"),i.addClass("in-checked-path")):(i.removeClass("is-active"),i.removeClass("in-checked-path"))}},syncMultiple:function(e){var i=e.$li,t=e.props.checkStrictly,a=e.props.multiple,s=e.config.disabledFixed;if(!(!a||t)){var r=e.getAllLeafChildren(s),n=e._getMultipleChecked(r);if(e._checked=n,!!i){var l=e.$checked.find(".el-checkbox__input");n===0?(l.removeClass("is-checked"),l.removeClass("is-indeterminate")):n===1?(l.removeClass("is-indeterminate"),l.addClass("is-checked")):n===2&&(l.removeClass("is-checked"),l.addClass("is-indeterminate"))}}},syncMultipleCheckStrictly:function(e){var i=e.$li,t=e.props.checkStrictly,a=e.props.multiple;if(!(!i||!a||!t)){var s=e.cascader.data.checkedNodes,r=e.checkedNodeIds,n=e.nodeId,l=s.some(function(o){return o.path.some(function(d){return d.nodeId===n})}),c=e.$checked.find(".el-checkbox__input");r.some(function(o){return o===n})?c.addClass("is-checked"):c.removeClass("is-checked"),l?i.addClass("in-checked-path"):i.removeClass("in-checked-path")}}},getAllLeafChildren:function(e){var i=this.leaf;if(i)return[this];var t=[];return this.transferChildren(function(a){if(a.disabled&&!e)return!1;a.leaf&&t.push(a)}),t},expandPanel:function(){var e=this.path,i=this.cascader;e.forEach(function(t,a,s){if(a!==s.length-1){var r=t.childrenNode;i._appendMenu(r,t.level+1,t.parentNode)}})},_getMultipleChecked:function(e){for(var i=this.cascader,t=i.data.checkedNodeIds,a=e.map(function(l){return l.nodeId}),s=0,r=0;r0&&s!==1?s=2:s=1:s=s===1?2:0}return s}};function $(e){this.config=h.extend(!0,{elem:"",value:null,options:[],empty:"暂无数据",placeholder:"请选择",disabled:!1,clearable:!1,showAllLevels:!0,collapseTags:!1,minCollapseTagsNumber:1,separator:" / ",filterable:!1,filterMethod:function(i,t){return i.path.some(function(a){return a.label.indexOf(t)!==-1})},debounce:300,beforeFilter:function(i){return!0},popperClass:"",extendClass:!1,extendStyle:!1,disabledFixed:!1,maxSize:0,props:{strictMode:!1,expandTrigger:"click",multiple:!1,checkStrictly:!1,lazy:!1,lazyLoad:function(i,t){},value:"value",label:"label",children:"children",disabled:"disabled",leaf:"leaf"}},e),this.data={nodeId:1,nodes:[],menuData:[],activeNodeId:null,activeNode:null,checkedNodeIds:[],checkedNodes:[]},this.showPanel=!1,this.event={change:[],open:[],close:[]},this.filtering=!1,this._init(),this.closeEventId=0,this._maxSizeMode=null}$.prototype={constructor:$,get props(){return this.config.props},get isFiltering(){return this.filtering},set isFiltering(e){if(this.filtering!==e){this.filtering=!!e;var i=this.$panel;this.filtering?(i.find(".el-cascader-panel").hide(),i.find(".el-cascader__suggestion-panel").show()):(i.find(".el-cascader-panel").show(),i.find(".el-cascader__suggestion-panel").hide(),this.$tagsInput&&this.$tagsInput.val(""))}},set maxSizeMode(e){this._maxSizeMode!==e&&(this._maxSizeMode=e,this.refreshMenu())},icons:{from:"layui-icon",down:"layui-icon-down",close:"layui-icon-close",right:"layui-icon-right",ok:"layui-icon-ok",loading:"layui-icon-loading-1 layui-anim layui-anim-rotate layui-anim-loop"},_init:function(){this._checkConfig(),this._initInput(),this._initPanel(),this.setOptions(this.config.options);var e=this;h(window).scroll(function(){e._resetXY()}),h(window).resize(function(){e._resetXY()}),this.$div.click(function(i){if(!e.config.disabled){var t=e.showPanel;t?e.close():e.open()}})},_checkConfig:function(){var e=this.config.elem;if(!e||h(e).length===0)throw new Error("缺少elem节点选择器");var i=this.config.maxSize;if(typeof i!="number"||i<0)throw new Error("maxSize应是一个大于等于0的有效的number值");if(!Array.isArray(this.config.options))throw new Error("options不是一个有效的数组")},_initRoot:function(){var e=this.props.lazy,i=this.props.lazyLoad,t=this,a=this.data.nodes;a.length>0||!e?this._appendMenu(a,0):e&&(this._appendMenu(a,0),i({root:!0,level:0},function(s){t.data.nodes=t.initNodes(s,0,null),t._appendMenu(t.data.nodes,0)}))},setOptions:function(e){this.config.options=e,this.data.nodes=this.initNodes(e,0,null),this._initRoot(),this.setValue(this.config.value)},_resetXY:function(){var e=this.$div,i=e.offset(),t=this.$panel;if(t){var a=window.innerHeight,s=window.innerWidth,r=t.height(),n=t.width(),l=e.height(),c=e[0].getBoundingClientRect(),o=t.find(".popper__arrow"),d=Math.min(s-c.x-n-5,0),f=a-(c.top+l);if(fr+20)t.attr("x-placement","top-start"),t.css({top:i.top-20-r+"px",left:i.left+d+"px"});else{t.attr("x-placement","bottom-start");var u=Math.max(r-(a-c.y-l-15),0);t.css({top:i.top+l-u+"px",left:i.left+d+"px"})}o.css("left",35-d+"px")}},get $menus(){return this.$panel&&this.$panel.find(".el-cascader-panel .el-cascader-menu")},_initInput:function(){var e=h(this.config.elem),i=this;this.config.value===null&&e.attr("value")&&(this.config.value=e.attr("value"));var t=this.config.placeholder,a=this.icons.from,s=this.icons.down,r=this.props.multiple,n=this.config.extendClass,l=this.config.extendStyle;if(this.$div=h(''),l){var c=e.attr("style");c&&this.$div.attr("style",c)}if(n){var o=e.attr("class");o&&o.split(" ").forEach(function(f){i.$div.addClass(f)})}this.$input=h('
'),this.$div.append(this.$input),this.$inputRow=this.$input.find(".el-input__inner"),r&&(this.$tags=h(''),this.$div.append(this.$tags));var d=this._initHideElement(e);d.after(this.$div),this.$icon=this.$input.find("i"),this._initFilterableInputEvent(),this.disabled(this.config.disabled)},_initHideElement:function(e){var i=e.prop("tagName").toLowerCase();if(i==="input")return e.hide(),e.attr("type","hidden"),this.$ec=e,e;var t=e[0].attributes,a=h(""),s=Object.keys(t);for(var r in s){var n=t[r];a.attr(n.name,n.value)}return a.hide(),a.attr("type","hidden"),this.$ec=a,e.before(a),e.remove(),a},_initFilterableInputEvent:function(){var e=this.config.filterable;if(!e)return;var i,t=this.props.multiple,a=this.config.debounce,s=this.config.placeholder,r=this.config.beforeFilter,n=this.config.filterMethod,l=this.props.checkStrictly,c=this;function o(u){var v=this;i&&clearTimeout(i),i=setTimeout(function(){i=null;var g=h(v).val();if(!g){c.isFiltering=!1;return}if(c.open(),typeof r=="function"&&r(g)){c.isFiltering=!0;var b=c.getNodes(),m=b.filter(function(_){var k;return l?k=_.disabled:k=_.path.some(function(N){return N.disabled}),!!((_.leaf||l)&&!k&&typeof n=="function"&&n(_,g))});c._setSuggestionMenu(m)}},a)}if(t){this.$tagsInput=h('');var d=this.$tagsInput;this.$tags.append(d),d.on("keydown",o),d.click(function(u){c.isFiltering&&p(u)})}else{var f=this.$inputRow;f.removeAttr("readonly"),f.on("keydown",o),f.click(function(u){c.isFiltering&&p(u)})}},_initPanel:function(){var e=this.$panel,i=this.config.popperClass||"";e||(this.$panel=h(''),e=this.$panel,e.appendTo("body"),e.click(function(t){p(t)}),this._initSuggestionPanel())},_appendMenu:function(e,i,t,a){if(this._removeMenu(i),!(t&&t.leaf)){var s=this.data.menuData,r=h('');this.$panel.find(".el-cascader-panel").append(r),this._appendLi(r,e);var n={nodes:e,level:i,parentNode:t,scrollbar:{top:0,left:0}};a&&(n.scrollbar=a.scrollbar),this._initScrollbar(r,n),this._resetXY(),s.push(n)}},_removeMenu:function(e){var i=e-1;i!==-1?this.$panel.find(".el-cascader-panel .el-cascader-menu:gt("+i+")").remove():this.$panel.find(".el-cascader-panel .el-cascader-menu").remove();var t=this.data.menuData;t.length>e&&t.splice(e,t.length-e)},_appendLi:function(e,i){var t=e.find(".el-cascader-menu__list");if(!i||i.length===0){var a=this.config.empty;t.append('");return}h.each(i,function(s,r){r.bind(t)})},refreshMenu:function(){var e=this.data.menuData.concat([]),i=this;e.forEach(function(t){i._appendMenu(t.nodes,t.level,t.parentNode,t)})},_initSuggestionPanel:function(){var e=this.config.filterable;if(e){var i=this.$suggestionPanel;i||(this.$suggestionPanel=h(''),i=this.$suggestionPanel,this.$panel.find(".popper__arrow").before(i),i.click(function(t){p(t)}))}},_setSuggestionMenu:function(e){var i=this.$suggestionPanel,t=i.find(".el-cascader__suggestion-list");if(t.empty(),i.find(".el-scrollbar__bar").remove(),!e||e.length===0){t.append('无匹配数据');return}h.each(e,function(a,s){s.bindSuggestion(t)}),this._initScrollbar(i,{scrollbar:{top:0,left:0}}),this._resetXY()},initNodes:function(e,i,t){var a=[];for(var s in e){var r=e[s],n=new C(r,this,i,t);n.value===null||n.value===void 0||(a.push(n),n.children&&n.children.length>0&&n.setChildren(this.initNodes(n.children,i+1,n)))}return a},_setActiveValue:function(e,i){if(this.data.activeNodeId!==e){var t=this.data.activeNode;this.data.activeNodeId=e,this.data.activeNode=i,t&&t.transferParent(function(a){a.syncStyle()},!0),i&&i.transferParent(function(a){a.syncStyle()},!0),this.change(i&&i.value,i),e!==null&&this._setClear()}},_setCheckedValue:function(e,i){var t=this.data.checkedNodes,a=this.config.maxSize,s;e.length>0&&a!==0&&e.length>=a?(e=e.slice(0,a),i=i.slice(0,a),s=!0):s=!1,this.data.checkedNodeIds=e||[],this.data.checkedNodes=i||[];var r=[],n=[];t.forEach(function(l){l.path.forEach(function(c){n.indexOf(c.nodeId)===-1&&(r.push(c),n.push(c.nodeId))})}),i.forEach(function(l){l.path.forEach(function(c){n.indexOf(c.nodeId)===-1&&(r.push(c),n.push(c.nodeId))})}),r.forEach(function(l){l.syncStyle()}),this.change(i.map(function(l){return l.value}),i),this._setClear(),this.maxSizeMode=s},setValue:function(e){if((this.data.activeNodeId||this.data.checkedNodeIds.length>0)&&this.clearCheckedNodes(),!!e){var i=this.props.strictMode;if(i&&!Array.isArray(e))throw new Error("严格模式下,value必须是一个包含父子节点数组结构.");var t=this.getNodes(this.data.nodes),a=this.props.checkStrictly,s=this.props.multiple,r=this.config.disabledFixed;if(s){var n=t.filter(function(v){return(a||v.leaf)&&(!v.disabled||r)?i?e.some(function(g){if(!Array.isArray(g))throw new Error("多选严格模式下,value必须是一个二维数组结构.");var b=v.path;return g.length===b.length&&g.every(function(m,_){return b[_].value===m})}):e.indexOf(v.value)!==-1:!1}),l=n.map(function(v){return v.nodeId});if(this._setCheckedValue(l,n),n.length>0){var c=n[0];c.expandPanel()}}else for(var o=0;o');e.append(t);var a=h(t[1]).find(".el-scrollbar__thumb"),s=h(t[0]).find(".el-scrollbar__thumb"),r=e.find(".el-scrollbar__wrap"),n=this.$panel,l=e.find("li"),c=Math.max(n.height(),e.height()),o=(c-6)/(l.height()*l.length),d=n.width()/l.width();function f(u,v){o<1&&(a.css("height",o*100+"%"),a.css("transform","translateY("+u/e.height()*100+"%)")),d<1&&(s.css("width",d*100+"%"),s.css("transform","translateY("+v/e.width()*100+"%)"))}a.mousedown(function(u){u.stopImmediatePropagation(),p(u);var v=function(){return!1};h(document).bind("selectstart",v);var g=u.clientY,b=r.scrollTop(),m=function(_){_.stopImmediatePropagation();var k=b+(_.clientY-g)/o;r.scrollTop(k)};h(document).bind("mousemove",m),h(document).one("mouseup",function(_){p(_),_.stopImmediatePropagation(),h(document).off("mousemove",m),h(document).off("selectstart",v)})}),r.scroll(function(){var u=h(this);i.scrollbar.top=u.scrollTop(),i.scrollbar.left=u.scrollLeft(),f(i.scrollbar.top,i.scrollbar.left)}),r.scrollTop(i.scrollbar.top),f(i.scrollbar.top,i.scrollbar.left)},_fillingPath:function(){var e=this.props.multiple,i=this.config.showAllLevels,t=this.config.separator,a=this.config.collapseTags,s=this.$inputRow,r=this.config.placeholder,n=this;if(e){this.$tags.find(".el-tag").remove();var o=this.$tagsInput;s.css("height","");var d=this.data.checkedNodes,f=Math.max(this.config.minCollapseTagsNumber,1);if(d.length>0){var u=[],v=d;a&&(v=d.slice(0,Math.min(d.length,f))),v.forEach(function(m){u.push(m.$tag)}),a&&d.length>f&&u.push(n.get$tag("+ "+(d.length-f),!1)),u.forEach(function(m){o?o.before(m):n.$tags.append(m)})}var g=n.$tags.height(),b=s.height();g>b&&s.css("height",g+4+"px"),this._resetXY(),d.length>0?(s.removeAttr("placeholder"),o&&o.removeAttr("placeholder",r)):(s.attr("placeholder",r),o&&o.attr("placeholder",r))}else{var l=this.data.activeNode,c=l&&l.path||[];i?this._$inputRowSetValue(c.map(function(m){return m.label}).join(t)):this._$inputRowSetValue(l&&l.label||"")}},_$inputRowSetValue:function(e){e=e||"";var i=this.$inputRow;i.attr("value",e),i.val(e)},get$tag:function(e,i){var t=this.icons.from,a=this.icons.close,s=i?'':"";return h(''+e+""+s+"")},_setClear:function(){var e=this;function i(){e.$icon.removeClass(e.icons.down),e.$icon.addClass(e.icons.close)}function t(){e.$icon.removeClass(e.icons.close),e.$icon.addClass(e.icons.down)}e.$div.mouseenter(function(){i()}),e.$div.mouseleave(function(){t()}),e.$icon.off("click");var a=this.props.multiple,s;a?s=this.data.checkedNodeIds.length>0:s=!!this.data.activeNodeId,s&&!this.config.disabled&&this.config.clearable?e.$icon.one("click",function(r){p(r),e.close(),e.clearCheckedNodes(),t(),e.$icon.off("mouseenter"),e.$div.off("mouseenter"),e.$div.off("mouseleave")}):(t(),e.$icon.off("mouseenter"),e.$div.off("mouseenter"),e.$div.off("mouseleave"))},disabled:function(e){this.config.disabled=!!e,this.config.disabled?(this.$div.addClass("is-disabled"),this.$div.find(".el-input--suffix").addClass("is-disabled"),this.$inputRow.attr("disabled","disabled"),this.$tagsInput&&this.$tagsInput.attr("disabled","disabled").hide()):(this.$div.removeClass("is-disabled"),this.$div.find(".el-input--suffix").removeClass("is-disabled"),this.$inputRow.removeAttr("disabled"),this.$tagsInput&&this.$tagsInput.removeAttr("disabled").show()),this._setClear(),this._fillingPath()},change:function(e,i){var t=this.props.multiple;t?e&&e.length>0?this.$ec.attr("value",JSON.stringify(e)):this.$ec.removeAttr("value"):this.$ec.attr("value",e||""),this._fillingPath(),this.event.change.forEach(function(a){typeof a=="function"&&a(e,i)})},close:function(e){if(this.showPanel&&(!e||this.closeEventId===e)){this.showPanel=!1,this.$div.find(".layui-icon-down").removeClass("is-reverse"),this.$panel.slideUp(100),this.visibleChange(!1),this.$input.removeClass("is-focus");var i=this.config.filterable;i&&(this.isFiltering=!1,this._fillingPath()),this.event.close.forEach(function(t){typeof t=="function"&&t()})}},open:function(){if(!this.showPanel){this.showPanel=!0,this.closeEventId++;var e=this;setTimeout(function(){h(document).one("click",e.close.bind(e,e.closeEventId))}),this._resetXY(),this.$div.find(".layui-icon-down").addClass("is-reverse"),this.$panel.slideDown(200),this.visibleChange(!0),this.$input.addClass("is-focus"),this.event.open.forEach(function(i){typeof i=="function"&&i()})}},visibleChange:function(e){},removeTag:function(e,i){},getCheckedValues:function(){var e=this.props.strictMode;if(this.props.multiple){var i=this.data.checkedNodes;return e?i.map(function(a){return a.path.map(function(s){return s.value})}):i.map(function(a){return a.value})}else{var t=this.data.activeNode;return e?t&&t.path.map(function(a){return a.value}):t&&t.value}},getCheckedNodes:function(){var e=this.props.strictMode;if(this.props.multiple){var i=this.data.checkedNodes;return e?i&&i.map(function(a){return a.path}):i}else{var t=this.data.activeNode;return e?t&&t.path:t}},clearCheckedNodes:function(e){var i=this.props.multiple;if(i){var t=this.config.disabledFixed;if(!e&&t){var a=this.data.checkedNodes,s=a.filter(function(n){return n.disabled}),r=s.map(function(n){return n.nodeId});this._setCheckedValue(r,s)}else this._setCheckedValue([],[])}else this._setActiveValue(null,null)}};var x=function(){var e=this;return{setOptions:function(i){e.setOptions(i)},setValue:function(i){e.setValue(i)},changeEvent:function(i){e.event.change.push(i)},closeEvent:function(i){e.event.close.push(i)},openEvent:function(i){e.event.open.push(i)},disabled:function(i){e.disabled(i)},close:function(){e.close()},open:function(){e.open()},getCheckedNodes:function(){return e.getCheckedNodes()},getCheckedValues:function(){return e.getCheckedValues()},clearCheckedNodes:function(i){e.clearCheckedNodes(i)},expandNode:function(i){for(var t=e.getNodes(e.data.nodes),a=0;a`+e.name,''+(e.on?'':"")+""].join(""));n.append(t),typeof c.click=="function"&&o.click(t,e),typeof c.del=="function"&&o.del(t,e)})},a.prototype.click=function(n,i){var o=this,c=o.options;n.on("click",function(l){n.toggleClass("on"),n.hasClass("on")?(i.on=!0,n.children("span.hide").html('')):(i.on=!1,n.children("span.hide").html("")),layui.stope(l),c.click(i)})},a.prototype.del=function(n,i){var o=this,c=o.options;n.children("i.del").on("click",function(l){var u=layer.confirm("确定删除 ["+i.name+"] 吗?",{btn:["删除","取消"]},function(){layer.close(u),c.del(i)&&(n.closest(".block").remove(),layui.stope(l))});return!1})},r("checkbox",function(n){var i=new a(n=n||{}),o=s(n.elem);if(!o[0])return h.error("layui.checkbox 没有找到"+n.elem+"元素");i.init(o)})}).link(layui.cache.base+"checkbox/checkbox.css?v="+new Date().getTime());
diff --git a/dist/public/js/lay-module/dropdownTable/dropdownTable.js b/dist/public/js/lay-module/dropdownTable/dropdownTable.js
deleted file mode 100644
index ee4c9c5..0000000
--- a/dist/public/js/lay-module/dropdownTable/dropdownTable.js
+++ /dev/null
@@ -1,70 +0,0 @@
-layui.define(["jquery","dropdown","table","form"],function(C){"use strict";var O=layui.dropdown,u=layui.table,a=layui.jquery,E=layui.form,k="dropdownTable",S={version:"1.0.4",config:{selectType:"radio",emptyMsg:"点击此处选择"},index:layui[k]?layui[k].index+1e4:0,set:function(e){var o,r;this.config=a.extend(!0,{},that.config,e);let t=this.config,l=t.selectType,i={type:l,fixed:"left"};return((r=(o=t==null?void 0:t.selectTable)==null?void 0:o.cols)!=null?r:[[]]).forEach(f=>{JSON.stringify(f).indexOf(JSON.stringify(i))<0&&f.splice(0,0,i)}),that}},v=function(){let e=this,t=e.config,l=t.id||e.index;return v.that[l]=e,{config:t,reload:function(i){e.reload.call(e,i)}}},x=function(e){var r,f;let t=++S.index;this.index=t,this.tableId="dropdown-select-table-"+t,this.dropdownId="dropdown-"+t,this.config=a.extend(!0,{},S.config,e,{selectedIds:[],selectedDisplayValues:[]});let l=this.config,i=l.selectType,n={type:i,fixed:"left"},o=(f=(r=l==null?void 0:l.selectTable)==null?void 0:r.cols)!=null?f:[[]];i==="checkbox"&&o.forEach(d=>{JSON.stringify(d).indexOf(JSON.stringify(n))<0&&d.splice(0,0,n)}),this.render()};x.prototype.reloadSelectTable=function(e){let t=this.config;layui.each(e,function(l,i){layui.type(i)==="array"&&delete t.selectTable[l]}),a.extend(!0,t.selectTable,e),this.clearSelected()},x.prototype.clearSelected=function(){let e=this.config,t=e.bindInput;a(t).val(""),a(t)[0].dataset.displayValue="",a.extend(e,{selectedIds:[],selectedDisplayValues:[]}),this.setSelectedDisplayAndValue()},x.prototype.render=function(){let e=this,t=e.config;(t.elem=a(t.elem))[0]&&(e.initElemArea(),e.iniDropdown())},x.prototype.initElemArea=function(){var w,V,D;let e=this,t=this.config,l=t.elem,i=(V=(w=this.config)==null?void 0:w.searchName)!=null?V:"keywords";a(l).css({display:"inline-block",width:"80%",height:"100%","min-height":"35px",border:"1px solid #eee","line-height":"35px","box-sizing":"border-box",padding:"0 10px",cursor:"pointer"}),a(l).hover(()=>{a(l).css({"border-color":"#e2e2e2"})},()=>{a(l).css({"border-color":"#eee"})});let n=a("");n.css({display:"inline-block",width:"20%","min-width":"45px",height:"100%","box-sizing":"border-box","font-size":"12px",padding:"0","line-height":"36px"}),(D=t==null?void 0:t.needPopup)==null||D?a(l).after(n):a(l).css({width:"100%"});let o=`
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-