diff --git a/docs/design/assets/candidates/2026-07-19/g01-add-sheet-background-source-green-v1.png b/docs/design/assets/candidates/2026-07-19/g01-add-sheet-background-source-green-v1.png
new file mode 100644
index 0000000..6c74ab5
Binary files /dev/null and b/docs/design/assets/candidates/2026-07-19/g01-add-sheet-background-source-green-v1.png differ
diff --git a/docs/design/assets/module-backgrounds/masters/family-page-background-imagegen-source.png b/docs/design/assets/module-backgrounds/masters/family-page-background-imagegen-source.png
new file mode 100644
index 0000000..6f30482
Binary files /dev/null and b/docs/design/assets/module-backgrounds/masters/family-page-background-imagegen-source.png differ
diff --git a/docs/design/assets/module-backgrounds/masters/notification-page-background-imagegen-source.png b/docs/design/assets/module-backgrounds/masters/notification-page-background-imagegen-source.png
new file mode 100644
index 0000000..cb8abe9
Binary files /dev/null and b/docs/design/assets/module-backgrounds/masters/notification-page-background-imagegen-source.png differ
diff --git a/docs/design/assets/module-backgrounds/masters/profile-page-background-imagegen-source.png b/docs/design/assets/module-backgrounds/masters/profile-page-background-imagegen-source.png
new file mode 100644
index 0000000..0152ee2
Binary files /dev/null and b/docs/design/assets/module-backgrounds/masters/profile-page-background-imagegen-source.png differ
diff --git a/docs/design/assets/module-backgrounds/masters/records-page-background-imagegen-source.png b/docs/design/assets/module-backgrounds/masters/records-page-background-imagegen-source.png
new file mode 100644
index 0000000..d104835
Binary files /dev/null and b/docs/design/assets/module-backgrounds/masters/records-page-background-imagegen-source.png differ
diff --git a/docs/design/assets/module-backgrounds/masters/tree-page-background-imagegen-source.png b/docs/design/assets/module-backgrounds/masters/tree-page-background-imagegen-source.png
new file mode 100644
index 0000000..25bed73
Binary files /dev/null and b/docs/design/assets/module-backgrounds/masters/tree-page-background-imagegen-source.png differ
diff --git a/docs/design/mockups/2026-07-19/g01-add-dialog-paper-sheet-target.png b/docs/design/mockups/2026-07-19/g01-add-dialog-paper-sheet-target.png
new file mode 100644
index 0000000..08fba46
Binary files /dev/null and b/docs/design/mockups/2026-07-19/g01-add-dialog-paper-sheet-target.png differ
diff --git a/pages/genealogy/g03-create-genealogy.vue b/pages/genealogy/g03-create-genealogy.vue
index 1ee7b85..58a5a31 100644
--- a/pages/genealogy/g03-create-genealogy.vue
+++ b/pages/genealogy/g03-create-genealogy.vue
@@ -16,9 +16,10 @@
src="/static/assets/foundation/transparent/chevron-right.png"
mode="aspectFit"
/>
- 返回
-
+
@@ -27,123 +28,239 @@
第一步 · 立谱信息
为家族立一部可传承的谱
- 家谱建立后可继续完善,名称与访问规则由创建者维护。
+ 家谱建立后可继续完善,名称与访问规则由创建者维护。
姓氏
-
+
- {{ fieldErrors.surname }}
+ {{
+ fieldErrors.surname
+ }}
谱名
-
+
- {{ fieldErrors.name }}
+ {{
+ fieldErrors.name
+ }}
堂号
-
+
所在地
-
+
- {{ fieldErrors.location }}
+ {{
+ fieldErrors.location
+ }}
访问规则
- 仅成员可见
- 可搜索申请
+ 仅成员可见
+ 可搜索申请
- 保护族人资料;创建后可在家谱设置中开放搜索与申请加入。
- 创建样式模拟失败,请检查信息后重试。
+ 保护族人资料;创建后可在家谱设置中开放搜索与申请加入。
+ 创建样式模拟失败,请检查信息后重试。
-
+
- {{ createState === 'submitting' ? '正在创建…' : '创建并录入首代' }}
+ {{
+ createState === "submitting" ? "正在创建…" : "创建并录入首代"
+ }}
第二步 · 首代人物
家谱从这一位开始
- 可先录入姓名、世代和简要生平,其他资料后续随时补充。
+ 可先录入姓名、世代和简要生平,其他资料后续随时补充。
姓名
-
+
- {{ fieldErrors.personName }}
+ {{
+ fieldErrors.personName
+ }}
世代
第一世
出生日期
-
+
- 首代人物保存失败,请稍后重试。
+ 首代人物保存失败,请稍后重试。
生平简述
-
+
-
+
- {{ ancestorState === 'submitting' ? '正在保存…' : '保存并进入家谱' }}
+ {{
+ ancestorState === "submitting" ? "正在保存…" : "保存并进入家谱"
+ }}
-
+
-
+
先确认是否已有家谱
- 同一家族可能已经建谱。建议先搜索谱名、地区和堂号,避免重复创建。
-
-
+ 同一家族可能已经建谱。建议先搜索谱名、地区和堂号,避免重复创建。
+
+
先搜索已有家谱
-
+
确认没有,继续创建
- 返回修改
+ 返回修改
-
+
家谱创建完成
- 首代人物已保存,接下来进入家谱总览继续完善资料。
+ 首代人物已保存,接下来进入家谱总览继续完善资料。
-
+
进入家谱总览
@@ -163,7 +280,12 @@ const isSubmitting = ref(false);
const createState = ref("form");
const ancestorState = ref("form");
const duplicateReminderVisible = ref(false);
-const fieldErrors = reactive({ surname: "", name: "", location: "", personName: "" });
+const fieldErrors = reactive({
+ surname: "",
+ name: "",
+ location: "",
+ personName: "",
+});
let submitTimer = null;
const createForm = reactive({
surname: "",
@@ -198,9 +320,12 @@ const syncFlowFromRoute = () => {
const isAncestorRoute = query.get
? query.get("step") === "ancestor"
: query.step === "ancestor";
- const routeGenealogyId = query.get ? query.get("genealogyId") : query.genealogyId;
+ const routeGenealogyId = query.get
+ ? query.get("genealogyId")
+ : query.genealogyId;
currentStep.value = isAncestorRoute ? "ancestor" : "create";
- genealogyId.value = routeGenealogyId || (isAncestorStep.value ? "local-created-genealogy" : "");
+ genealogyId.value =
+ routeGenealogyId || (isAncestorStep.value ? "local-created-genealogy" : "");
};
onLoad(() => {
@@ -233,7 +358,9 @@ const goBack = () => {
uni.navigateBack();
};
-const clearFieldError = (field) => { fieldErrors[field] = ""; };
+const clearFieldError = (field) => {
+ fieldErrors[field] = "";
+};
const validateCreateForm = () => {
fieldErrors.surname = createForm.surname.trim() ? "" : "请填写姓氏";
@@ -249,8 +376,11 @@ const submitCreate = () => {
duplicateReminderVisible.value = true;
};
-const closeDuplicateReminder = () => { duplicateReminderVisible.value = false; };
-const searchExistingGenealogy = () => uni.navigateTo({ url: "/pages/genealogy/g06-search-genealogies" });
+const closeDuplicateReminder = () => {
+ duplicateReminderVisible.value = false;
+};
+const searchExistingGenealogy = () =>
+ uni.navigateTo({ url: "/pages/genealogy/g06-search-genealogies" });
const confirmCreate = () => {
closeDuplicateReminder();
isSubmitting.value = true;
@@ -262,7 +392,9 @@ const confirmCreate = () => {
return;
}
const createdId = "local-created-genealogy";
- uni.redirectTo({ url: `/pages/genealogy/g03-create-genealogy?step=ancestor&genealogyId=${createdId}` });
+ uni.redirectTo({
+ url: `/pages/genealogy/g03-create-genealogy?step=ancestor&genealogyId=${createdId}`,
+ });
}, 320);
};
@@ -281,11 +413,15 @@ const submitAncestor = () => {
ancestorState.value = "submitting";
submitTimer = setTimeout(() => {
isSubmitting.value = false;
- ancestorState.value = ancestorForm.personName.trim() === "失败" ? "error" : "success";
+ ancestorState.value =
+ ancestorForm.personName.trim() === "失败" ? "error" : "success";
}, 320);
};
-const enterOverview = () => uni.redirectTo({ url: `/pages/genealogy/g05-genealogy-overview?genealogyId=${genealogyId.value}` });
+const enterOverview = () =>
+ uni.redirectTo({
+ url: `/pages/genealogy/g05-genealogy-overview?genealogyId=${genealogyId.value}`,
+ });
diff --git a/static/assets/modules/genealogy/transparent/g01-empty-panel-frame.png b/static/assets/modules/genealogy/transparent/g01-empty-panel-frame.png
new file mode 100644
index 0000000..8b486ee
Binary files /dev/null and b/static/assets/modules/genealogy/transparent/g01-empty-panel-frame.png differ
diff --git a/static/assets/modules/profile/transparent/module-content-frame.png b/static/assets/modules/profile/transparent/module-content-frame.png
new file mode 100644
index 0000000..26acc1d
Binary files /dev/null and b/static/assets/modules/profile/transparent/module-content-frame.png differ
diff --git a/static/assets/modules/records/transparent/module-content-frame.png b/static/assets/modules/records/transparent/module-content-frame.png
new file mode 100644
index 0000000..26acc1d
Binary files /dev/null and b/static/assets/modules/records/transparent/module-content-frame.png differ
diff --git a/tests/capture-g09-states-contract.ps1 b/tests/capture-g09-states-contract.ps1
new file mode 100644
index 0000000..2d38a27
--- /dev/null
+++ b/tests/capture-g09-states-contract.ps1
@@ -0,0 +1,10 @@
+$ErrorActionPreference = 'Stop'
+$root = Split-Path -Parent $PSScriptRoot
+$capture = Get-Content -LiteralPath (Join-Path $root 'scripts/capture-chrome-page.js') -Raw -Encoding utf8
+
+foreach ($required in @('prepareG09State', 'g09-withdraw-dialog', 'g09-withdrawn')) {
+ if ($capture -notmatch [regex]::Escape($required)) { throw "G09 capture state missing: $required" }
+}
+if ($capture -notmatch 'await prepareG09State\(send, action\)') { throw 'Capture runner does not prepare G09 states' }
+
+Write-Output 'CAPTURE-G09-STATES-CONTRACT PASS'