This commit is contained in:
rain
2026-07-21 21:02:55 +08:00
parent 5d99bae3f2
commit a127280ce6
12 changed files with 1131 additions and 0 deletions
@@ -0,0 +1,229 @@
# Review package: 2f22df6..9362c47
## Commits
9362c47 refactor: reuse shared header on G03
## Files changed
pages/genealogy/g03-create-genealogy.vue | 62 ++++----------------------------
tests/g03-create-flow-contract.ps1 | 9 +++--
tests/g03-document-flow-contract.ps1 | 4 ++-
tests/g03-visual-states-contract.ps1 | 4 +--
4 files changed, 17 insertions(+), 62 deletions(-)
## Diff
diff --git a/pages/genealogy/g03-create-genealogy.vue b/pages/genealogy/g03-create-genealogy.vue
index 2bc757d..f37cadc 100644
--- a/pages/genealogy/g03-create-genealogy.vue
+++ b/pages/genealogy/g03-create-genealogy.vue
@@ -1,30 +1,20 @@
<!-- 页面编号:G-03;用途:创建家谱与录入首代人物的同路由两步流程。 -->
<template>
<view class="flow-page">
<GenealogyPageBackground />
- <view class="flow-header">
- <view class="flow-header__content">
- <view class="flow-header__back" @click="goBack">
- <image
- class="flow-header__back-icon"
- src="/static/assets/foundation/transparent/chevron-right.png"
- mode="aspectFit"
- />
- </view>
- <text class="flow-header__title">{{
- isAncestorStep ? "录入首代人物" : "创建家谱"
- }}</text>
- <view class="flow-header__side" />
- </view>
- </view>
+ <PageHeader
+ :title="isAncestorStep ? '录入首代人物' : '创建家谱'"
+ custom-back
+ @back="goBack"
+ />
<view class="flow-content">
<view class="create-flow-panel">
<view v-if="!isAncestorStep" class="create-flow-panel__content">
<view class="flow-step-label"><text>第一步 · 立谱信息</text></view>
<text class="flow-heading">为家族立一部可传承的谱</text>
<text class="flow-note"
>家谱建立后可继续完善,名称与访问规则由创建者维护。</text
>
@@ -241,20 +231,21 @@
</view>
</view>
</view>
</view>
</template>
<script setup>
import { computed, onMounted, onUnmounted, reactive, ref } from "vue";
import { onLoad, onShow } from "@dcloudio/uni-app";
import GenealogyPageBackground from "@/components/GenealogyPageBackground.vue";
+import PageHeader from "@/components/PageHeader.vue";
const currentStep = ref("create");
const genealogyId = ref("");
const isSubmitting = ref(false);
const createState = ref("form");
const ancestorState = ref("form");
const duplicateReminderVisible = ref(false);
const fieldErrors = reactive({
surname: "",
name: "",
@@ -416,61 +407,20 @@ const enterOverview = () =>
</script>
<style scoped lang="scss">
.flow-page {
display: flex;
min-height: 100vh;
flex-direction: column;
background: #f9f6ef;
}
-.flow-header {
- z-index: 3;
- height: 112rpx;
- overflow: hidden;
- background: url("/static/assets/foundation/opaque/root-header-cinnabar.jpg")
- center / 100% 100% no-repeat;
-}
-
-.flow-header__content {
- z-index: 1;
- display: flex;
- height: 100%;
- align-items: center;
- justify-content: space-between;
- padding: 0 26rpx;
- box-sizing: border-box;
-}
-
-.flow-header__back,
-.flow-header__side {
- display: flex;
- width: 72rpx;
- align-items: center;
-}
-
-.flow-header__back-icon {
- width: 34rpx;
- height: 34rpx;
- transform: rotate(180deg);
-}
-
-.flow-header__title {
- flex: 1;
- color: #ffe4a7;
- font-family: "STKaiti", "KaiTi", serif;
- font-size: 39rpx;
- font-weight: 700;
- letter-spacing: 4rpx;
- text-align: center;
-}
-
.flow-content {
z-index: 2;
padding: 24rpx 32rpx 48rpx;
}
.create-flow-panel {
min-height: 1000rpx;
background: url("/static/assets/modules/genealogy/transparent/g01-empty-panel-frame.png")
center / 100% 100% no-repeat;
}
diff --git a/tests/g03-create-flow-contract.ps1 b/tests/g03-create-flow-contract.ps1
index 4accfd6..89923c2 100644
--- a/tests/g03-create-flow-contract.ps1
+++ b/tests/g03-create-flow-contract.ps1
@@ -30,29 +30,32 @@ foreach ($required in @(
'window.addEventListener("hashchange", syncFlowFromRoute)',
'step=ancestor&genealogyId=',
'const createState = ref("form");',
'const ancestorState = ref("form");',
'const fieldErrors = reactive({',
'const duplicateReminderVisible = ref(false);',
'class="duplicate-reminder-layer"',
'if (isSubmitting.value) return;',
'/pages/genealogy/g05-genealogy-overview?genealogyId=',
'g01-empty-panel-frame.png',
- 'root-header-cinnabar.jpg',
'a01-scroll-primary-v3.png',
'create-flow-panel',
- 'flow-primary-action'
+ 'flow-primary-action',
+ 'import PageHeader from "@/components/PageHeader.vue";',
+ '<PageHeader',
+ 'custom-back',
+ '@back="goBack"'
)) {
Assert-Contains -Content $g03 -Expected $required -Message "Missing G03 flow contract: $required"
}
-foreach ($forbidden in @("from '@/utils/api.js'", 'appApi.', 'uni.showToast', 'uni.showModal', 'uni.showLoading', 'uni.showActionSheet', '/pages/tree/t01-tree-overview?genealogyId=')) {
+foreach ($forbidden in @("from '@/utils/api.js'", 'appApi.', 'uni.showToast', 'uni.showModal', 'uni.showLoading', 'uni.showActionSheet', '/pages/tree/t01-tree-overview?genealogyId=', 'class="flow-header"', 'flow-header__back', 'root-header-cinnabar.jpg')) {
if ($g03 -match [regex]::Escape($forbidden)) { throw "G03 retains forbidden implementation: $forbidden" }
}
foreach ($className in @('create-flow-panel', 'flow-primary-action')) {
Assert-NoCssSurface -Content $g03 -ClassName $className
}
if (-not (Test-Path -LiteralPath $panelPath)) { throw 'G03 requires the accepted genealogy paper panel bitmap' }
Add-Type -AssemblyName System.Drawing
$panel = [System.Drawing.Bitmap]::FromFile($panelPath)
diff --git a/tests/g03-document-flow-contract.ps1 b/tests/g03-document-flow-contract.ps1
index 0249541..654dfa7 100644
--- a/tests/g03-document-flow-contract.ps1
+++ b/tests/g03-document-flow-contract.ps1
@@ -1,15 +1,17 @@
$ErrorActionPreference = 'Stop'
$root = Split-Path -Parent $PSScriptRoot
$page = Get-Content -LiteralPath (Join-Path $root 'pages/genealogy/g03-create-genealogy.vue') -Raw -Encoding utf8
$style = [regex]::Match($page, '(?s)<style[^>]*>(.*?)</style>').Groups[1].Value
$positions = [regex]::Matches([regex]::Replace($style, '(?s)/\*.*?\*/', ''), '(?m)\bposition\s*:\s*([^;]+);')
if ($positions.Count -ne 1 -or $positions[0].Groups[1].Value.Trim() -ne 'fixed') {
throw "G03 must retain only its combined fixed dialog layer rule; found $($positions.Count) position declarations"
}
foreach ($required in @(
- 'background: url("/static/assets/foundation/opaque/root-header-cinnabar.jpg")',
'background: url("/static/assets/modules/genealogy/transparent/g01-empty-panel-frame.png")',
'background: url("/static/assets/modules/auth/transparent/a01-scroll-dialog-v3.png")',
'background: url("/static/assets/foundation/transparent/a01-scroll-primary-v3.png")'
)) { if ($page -notmatch [regex]::Escape($required)) { throw "G03 is missing real asset background: $required" } }
+foreach ($forbidden in @('flow-header', 'root-header-cinnabar.jpg')) {
+ if ($page -match [regex]::Escape($forbidden)) { throw "G03 must not retain private header token: $forbidden" }
+}
Write-Output 'G03-DOCUMENT-FLOW-CONTRACT PASS'
diff --git a/tests/g03-visual-states-contract.ps1 b/tests/g03-visual-states-contract.ps1
index 5342acb..cfb7911 100644
--- a/tests/g03-visual-states-contract.ps1
+++ b/tests/g03-visual-states-contract.ps1
@@ -2,22 +2,22 @@ $ErrorActionPreference = 'Stop'
$root = Split-Path -Parent $PSScriptRoot
$g03 = Get-Content -LiteralPath (Join-Path $root 'pages/genealogy/g03-create-genealogy.vue') -Raw -Encoding utf8
function Assert-Match {
param([string]$Content, [string]$Pattern, [string]$Message)
if ($Content -notmatch $Pattern) { throw $Message }
}
if ($g03 -match '<text>返回</text>') { throw 'G03 header must use only the approved image back arrow' }
-Assert-Match -Content $g03 -Pattern '(?s)\.flow-header__back,\s*\.flow-header__side\s*\{[^}]*width:\s*72rpx;' -Message 'G03 header side slots must preserve centered title after removing back text'
-Assert-Match -Content $g03 -Pattern '(?s)\.flow-header__back-icon\s*\{[^}]*width:\s*34rpx;[^}]*height:\s*34rpx;' -Message 'G03 back arrow must use the approved visible size'
+Assert-Match -Content $g03 -Pattern '(?s)<PageHeader\s+:title="isAncestorStep \? .\u5F55\u5165\u9996\u4EE3\u4EBA\u7269. : .\u521B\u5EFA\u5BB6\u8C31."\s+custom-back\s+@back="goBack"\s*/>' -Message 'G03 must use PageHeader with its dynamic title and custom back handler'
+if ($g03 -match 'flow-header|flow-header__back|flow-header__title') { throw 'G03 must not retain a private header implementation' }
Assert-Match -Content $g03 -Pattern '(?s)\.flow-note,\s*\.flow-rule__note\s*\{[^}]*font-size:\s*25rpx;' -Message 'G03 guidance copy must use the approved readable size'
Assert-Match -Content $g03 -Pattern '(?s)\.flow-rule__option\s*\{[^}]*font-size:\s*23rpx;' -Message 'G03 visibility options must use the approved readable size'
Assert-Match -Content $g03 -Pattern '(?s)\.field-error\s*\{[^}]*font-size:\s*24rpx;[^}]*line-height:\s*34rpx;' -Message 'G03 field errors must use the approved readable size'
Assert-Match -Content $g03 -Pattern '(?s)\.flow-error\s*\{[^}]*font-size:\s*25rpx;[^}]*line-height:\s*36rpx;' -Message 'G03 submit errors must use the approved readable size'
foreach ($asset in @('a01-scroll-dialog-v3.png', 'a01-scroll-primary-v3.png', 'a01-scroll-secondary-v3.png')) {
if ($g03 -notmatch [regex]::Escape($asset)) { throw "G03 must retain approved shared asset: $asset" }
}
Write-Output 'G03-VISUAL-STATES-CONTRACT PASS'