diff --git a/.ai/product/feature-map.md b/.ai/product/feature-map.md index 1d0027c..22daa74 100644 --- a/.ai/product/feature-map.md +++ b/.ai/product/feature-map.md @@ -232,8 +232,8 @@ UI **不出现「塔罗」**。禁止神谕吉凶、恐吓话术。 | 分期 | 内容 | |---|---| | Phase A `[Ops]` | 登录 · 用户/订单查询 · 会员授予 · 审计 · `apps/admin-h5`(ECR-006 Closed) | -| Phase B `[Ops]` | 行为分析:自有埋点 + 管理端「数据」看板(**ECR-007 Implemented** · Spec `ops-analytics.md`) | -| Phase C `[Ops]` | 内容:首页宫格 CRUD · 测评上下架(**ECR-008 Implemented** · Spec `ops-content.md`) | +| Phase B `[Ops]` | 行为分析:自有埋点 + 管理端「数据」看板(**ECR-007 Closed** · Spec `ops-analytics.md`) | +| Phase C `[Ops]` | 内容:首页宫格 CRUD · 测评上下架(**ECR-008 Closed** · Spec `ops-content.md`) | | Phase D+ | 商业加深 · RBAC · 封禁 · 推送(各开独立 ECR) | 不计入 P1 Complete;不进入五 Tab。 @@ -256,11 +256,11 @@ UI **不出现「塔罗」**。禁止神谕吉凶、恐吓话术。 | `/scales/:slug` | 探索测试作答 | | | `/reports` | 成长报告列表 | | | `/reports/:id` | 成长报告详情 | | -| `/star` | 星座 | P2 | -| `/synastry` | 合盘 | P2 | -| `/synastry/invite/:token` | 合盘邀请 | P2 | -| `/rhythm` | 身心节律 | P2 draft | -| `/cards` | 意象卡片 | P2 draft | +| `/star` | 星座 | P2 · ECR-012 对齐中 | +| `/synastry` | 合盘 | P2 · ECR-012 对齐中 | +| `/synastry/invite/:token` | 合盘邀请 | P2 · ECR-012 对齐中 | +| `/rhythm` | 身心节律 | P2(主路径已落地;非本 ECR) | +| `/cards` | 意象卡片 | P2(主路径已落地;非本 ECR) | 兼容重定向:`/decode` → `/portrait`(仅技术兼容,UI 不出现 decode 文案)。 diff --git a/.ai/product/feature-spec/P2-BACKLOG.md b/.ai/product/feature-spec/P2-BACKLOG.md index 593b4b1..22bc51f 100644 --- a/.ai/product/feature-spec/P2-BACKLOG.md +++ b/.ai/product/feature-spec/P2-BACKLOG.md @@ -13,7 +13,7 @@ | 顺序 | 模块 | Spec | 路由 | 状态 | |---|---|---|---|---| | 0 | 探索目录 | — | `/explore` · `/explore/:category` | Done | -| 1 | 星座 | [star-profile.md](star-profile.md) | `/star` | Done(星盘/运势/合盘对齐中) | +| 1 | 星座 | [star-profile.md](star-profile.md) | `/star` | 主路径 Done · **ECR-012 Implemented(待 Closed)** | | 2 | 身心节律 | [life-rhythm.md](life-rhythm.md) | `/rhythm` | Done(今日/本周) | | 3 | 意象卡片 | [image-card.md](image-card.md) | `/cards` | Done(≥78 牌 · ≥8 场景) | | 4 | 量表矩阵 | [explore-test.md](explore-test.md) | `/scales/*` | Done(≥8) | @@ -28,4 +28,5 @@ |---|---| | 设计三 Spec | Done | | 探索 catalog API | Done | -| 真支付 | 部署阶段 | +| 真支付 | 部署阶段(排期最后;非 ECR-012) | +| 星座对齐 | **ECR-012 Implemented**(待 Reviewer Closed) | diff --git a/.ai/product/feature-spec/README.md b/.ai/product/feature-spec/README.md index 4d1fa52..f7e28cb 100644 --- a/.ai/product/feature-spec/README.md +++ b/.ai/product/feature-spec/README.md @@ -17,12 +17,12 @@ | [share.md](share.md) | 分享卡 | journey 双引擎 | `/share` | P1 | | [companion.md](companion.md) | 陪伴(节气壳) | §4 | `/companion` | P1 壳 / P2 | | [analytics.md](analytics.md) | 增长埋点最小集 | 横切 | H5 `track` | P1 | -| [star-profile.md](star-profile.md) | 星象性格 | §2.6 | `/star` | P2 设计 | +| [star-profile.md](star-profile.md) | 星座 / 合盘 | §2.6 | `/star` · `/synastry` | P2 · ECR-012 Approved | | [life-rhythm.md](life-rhythm.md) | 身心节律 | §2.7 | `/rhythm` | P2 设计 | | [image-card.md](image-card.md) | 意象卡片 | §2.8 | `/cards` | P2 设计 | | [ops-admin.md](ops-admin.md) | 运营后台 | §7 | `admin-h5` `/` `/users/:id` … | Ops-A | -| [ops-analytics.md](ops-analytics.md) | 运营行为分析(埋点+数据看板) | §7 | `admin-h5` `/analytics` · H5 track | Ops-B · ECR-007 Implemented | -| [ops-content.md](ops-content.md) | 运营内容(宫格+测评上下架) | §7 | `admin-h5` `/content` · `GET /home/tools` | Ops-C · ECR-008 Approved | +| [ops-analytics.md](ops-analytics.md) | 运营行为分析(埋点+数据看板) | §7 | `admin-h5` `/analytics` · H5 track | Ops-B · ECR-007 Closed | +| [ops-content.md](ops-content.md) | 运营内容(宫格+测评上下架) | §7 | `admin-h5` `/content` · `GET /home/tools` | Ops-C · ECR-008 Closed | 新功能:复制 `_TEMPLATE.md` → 填满 → 在本表登记 → 再编码。 diff --git a/.ai/product/feature-spec/ops-admin.md b/.ai/product/feature-spec/ops-admin.md index 9e80f88..431fb8e 100644 --- a/.ai/product/feature-spec/ops-admin.md +++ b/.ai/product/feature-spec/ops-admin.md @@ -206,7 +206,7 @@ Phase A 可先 `console`/本地;不挡验收。 | Phase | 内容 | |---|---| | **A(本 ECR)** | 登录 · 用户 · 订单 · 授予会员 · 审计 · admin-h5 壳 | -| **B(ECR-007)** | 自有埋点 · 管理端「数据」看板 — Spec `ops-analytics.md` | -| **C(ECR-008)** | 首页宫格 CRUD · 测评上下架 — Spec `ops-content.md`(Approved) | +| **B(ECR-007 Closed)** | 自有埋点 · 管理端「数据」看板 — Spec `ops-analytics.md` | +| **C(ECR-008 Closed)** | 首页宫格 CRUD · 测评上下架 — Spec `ops-content.md` | | D | 订单筛选 · 展示价 · 退款只读(另开 ECR) | | E | RBAC · 封禁 · 推送占位(另开 ECR) | diff --git a/.ai/product/feature-spec/ops-analytics.md b/.ai/product/feature-spec/ops-analytics.md index 226d5eb..666877d 100644 --- a/.ai/product/feature-spec/ops-analytics.md +++ b/.ai/product/feature-spec/ops-analytics.md @@ -1,7 +1,7 @@ # Feature Spec: 运营行为分析(Ops-B) > Status: `Active` · Map: `§7 运营后台` · Phase: `Ops-B` -> ESS:`docs/ECR/ECR-007-ops-analytics.md`(Approved · L2)· BD-2026-007 Approved +> ESS:`docs/ECR/ECR-007-ops-analytics.md`(**Closed** · L2)· BD-2026-007 Approved > 关联:[ops-admin.md](ops-admin.md) · [analytics.md](analytics.md) · [cece-frontend-re/complete-design/40-ops-commerce.md](cece-frontend-re/complete-design/40-ops-commerce.md) --- diff --git a/.ai/product/feature-spec/ops-content.md b/.ai/product/feature-spec/ops-content.md index 3e4e4da..0558671 100644 --- a/.ai/product/feature-spec/ops-content.md +++ b/.ai/product/feature-spec/ops-content.md @@ -1,7 +1,7 @@ # Feature Spec: 运营内容配置(Ops-C) > Status: `Active` · Map: `§7 运营后台` · Phase: `Ops-C` -> ESS:`docs/ECR/ECR-008-ops-content.md`(Approved · L2)· BD-2026-008 Approved +> ESS:`docs/ECR/ECR-008-ops-content.md`(**Closed** · L2)· BD-2026-008 Approved > 关联:[ops-admin.md](ops-admin.md) · [ops-analytics.md](ops-analytics.md) · [home.md](home.md) · [explore-test.md](explore-test.md) --- diff --git a/.ai/product/feature-spec/star-profile.md b/.ai/product/feature-spec/star-profile.md index cfd6816..ea90bf9 100644 --- a/.ai/product/feature-spec/star-profile.md +++ b/.ai/product/feature-spec/star-profile.md @@ -165,7 +165,7 @@ **Given** Self 有生日 **When** 生成星座报告 -**Then** 展示轮盘、太阳/月亮/上升、相位速览、fortune 日运与行运;无「占卜」「算命」恐吓 +**Then** 展示轮盘、太阳/月亮/上升、相位速览、outlook 日/周/月/年/一生与行运;无「占卜」「算命」恐吓 **Given** 两份档案 **When** POST synastry @@ -202,3 +202,5 @@ | Packages | `internal/star` · `ephemeris` · `natal` · `fortune` · `synastry` | | 星历 | Swiss Ephemeris(CGO,默认 Moshier);热带 + Whole Sign | | 实现 | `POST /reports/star` · `POST /reports/synastry` · nearby/invites · H5 `/star` · `/synastry` · invite | +| Gaps | ECR-012 收口:报告页复用 StarFortunePanel;分享 type=star;fortuneBundle 仅读 outlook 且剥离 lucky;e2e mock 含 outlook | +| ESS | `docs/ECR/ECR-012-star-alignment.md`(**Approved** · L2)· BD-2026-012 Approved | diff --git a/apps/api/internal/integration/p2_flows_test.go b/apps/api/internal/integration/p2_flows_test.go index 958c159..4aceb43 100644 --- a/apps/api/internal/integration/p2_flows_test.go +++ b/apps/api/internal/integration/p2_flows_test.go @@ -88,6 +88,9 @@ func TestFlowStarDeepAccess(t *testing.T) { if sum["fortune"] != nil { t.Fatal("legacy fortune key must be removed (ECR-003)") } + if raw, _ := json.Marshal(sum); strings.Contains(string(raw), `"lucky"`) { + t.Fatal("legacy lucky field must not appear in star summary (ECR-012)") + } reportID := rep["id"].(string) env, key = doJSON(t, r, http.MethodPost, "/api/v1/orders", map[string]any{ diff --git a/apps/user-h5/e2e/p2-explore-paths.spec.ts b/apps/user-h5/e2e/p2-explore-paths.spec.ts index 5961320..2e260a4 100644 --- a/apps/user-h5/e2e/p2-explore-paths.spec.ts +++ b/apps/user-h5/e2e/p2-explore-paths.spec.ts @@ -30,7 +30,27 @@ test('star / rhythm / cards pages render with mocked API', async ({ page }) => { id: 'rep-star', type: 'star', has_deep_access: false, - summary: { headline: 'E2E星象', one_liner: '星象摘要', keywords: ['灵活'] }, + summary: { + headline: 'E2E星象', + one_liner: '星象摘要', + keywords: ['灵活'], + planets: [ + { key: 'sun', title: '太阳', sign: '双子', degree: '10°', house: 1, lon: 70 }, + ], + chart: { note: '热带黄道', asc_lon: 70, houses: [{ num: 1, sign: '双子' }] }, + aspects_preview: [], + outlook: { + daily: { + title: '今日运势', label: '顺畅', score: 80, tip: 'e2e tip', + focus: '行动', boost: '水', caution: '缓', dims: { love: 3, career: 4, money: 3, mood: 4 }, + }, + weekly: { title: '本周', label: '稳', score: 70, tip: 'w', focus: 'f', boost: 'b', caution: 'c' }, + monthly: { title: '本月', label: '稳', score: 70, tip: 'm', focus: 'f', boost: 'b', caution: 'c' }, + yearly: { title: '今年', label: '稳', score: 70, tip: 'y', focus: 'f', boost: 'b', caution: 'c' }, + lifetime: { title: '一生运势摘要', label: '稳', score: 70, tip: 'l', focus: 'f', boost: 'b', caution: 'c' }, + }, + transits: [{ key: 't1', title: '行运提示', aspect: '合相', tip: '推进' }], + }, detail: null, created_at: new Date().toISOString(), })) @@ -86,6 +106,9 @@ test('star / rhythm / cards pages render with mocked API', async ({ page }) => { await page.goto('/psy/star?y=1983&m=6&d=6') await expect(page.getByText('E2E星象')).toBeVisible() await expect(page.getByRole('button', { name: /解锁完整分析/ })).toBeVisible() + await page.getByRole('button', { name: '运势' }).click() + await expect(page.getByText('今日运势')).toBeVisible() + await expect(page.getByText('焦点:行动')).toBeVisible() await page.goto('/psy/rhythm?y=1992&m=6&d=8') await expect(page.getByText('身心节律').first()).toBeVisible() diff --git a/apps/user-h5/src/components/ShareCard.vue b/apps/user-h5/src/components/ShareCard.vue index 1423ef8..2813021 100644 --- a/apps/user-h5/src/components/ShareCard.vue +++ b/apps/user-h5/src/components/ShareCard.vue @@ -20,7 +20,7 @@ import BrandLogo from './BrandLogo.vue' withDefaults( defineProps<{ - type?: 'portrait' | 'relation' + type?: 'portrait' | 'star' | 'relation' title?: string line?: string rows?: string[] @@ -72,4 +72,13 @@ h2{font-size:17px;font-weight:600;margin:0 0 8px;line-height:1.4} .share-card[data-type="relation"] .cta-label{ background:linear-gradient(135deg,#e0b35a,#c8923a); } +.share-card[data-type="star"]{ + background: + radial-gradient(120% 80% at 100% 0%, rgba(100,120,200,.18), transparent 55%), + linear-gradient(165deg, #f6f8ff 0%, #e8ecff 48%, #fff 100%); +} +.share-card[data-type="star"] .tags span{background:rgba(100,120,200,.12);color:#4a5a9a} +.share-card[data-type="star"] .cta-label{ + background:linear-gradient(135deg,#7a8ad4,#4a5a9a); +} diff --git a/apps/user-h5/src/components/ShareSheet.vue b/apps/user-h5/src/components/ShareSheet.vue index 25ed374..1ae657b 100644 --- a/apps/user-h5/src/components/ShareSheet.vue +++ b/apps/user-h5/src/components/ShareSheet.vue @@ -32,13 +32,13 @@ const status = ref('') const card = computed(() => { const p = props.payload if (!p) return {} - if (p.type === 'portrait') { + if (p.type === 'portrait' || p.type === 'star') { return { - type: 'portrait' as const, + type: p.type, title: p.title, line: p.line, keywords: p.keywords, - ctaLabel: '查看完整成长报告', + ctaLabel: p.type === 'star' ? '查看完整星座报告' : '查看完整成长报告', } } return { @@ -56,6 +56,12 @@ const card = computed(() => { const canNative = computed(() => typeof navigator !== 'undefined' && typeof navigator.share === 'function') +function nativeShareText(type: SharePayload['type']): string { + if (type === 'relation') return '看看我们的相处方式' + if (type === 'star') return '看看我的星座探索' + return '看看我的个人画像' +} + function absoluteShareURL(): string { if (!props.payload) return location.origin return `${location.origin}${buildSharePath(props.payload)}` @@ -76,7 +82,7 @@ async function nativeShare() { try { await navigator.share({ title: '愈心谷', - text: props.payload.type === 'relation' ? '看看我们的相处方式' : '看看我的个人画像', + text: nativeShareText(props.payload.type), url: absoluteShareURL(), }) status.value = '已唤起系统分享' diff --git a/apps/user-h5/src/components/report/ReportStarPanel.vue b/apps/user-h5/src/components/report/ReportStarPanel.vue index 5980220..d3eff69 100644 --- a/apps/user-h5/src/components/report/ReportStarPanel.vue +++ b/apps/user-h5/src/components/report/ReportStarPanel.vue @@ -17,27 +17,13 @@

{{ activeCard.teaser }}

- +