feat(ECR-011): 昵称、首页贴士与档案 Self 唯一/合盘交叉校验
ci / h5 (push) Canceled after 0s
ci / api (push) Canceled after 0s
ci / ess-docs (push) Canceled after 0s

每账号仅一条 self(migration 40902);合盘只选 TA;账号昵称可改;首页穿衣/颜色/养生贴士。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jackyu66git
2026-08-12 22:05:00 +08:00
co-authored by Cursor
parent 5ceb3ce749
commit 13860bf1ef
67 changed files with 1936 additions and 275 deletions
+4 -3
View File
@@ -14,8 +14,8 @@
<HomeArchiveStrip @add="goPlus('add')" />
<HomeSelfCard
:profile-label="profileLabel"
:mood="mood"
@open-portrait="router.push('/portrait')"
:tips="tips"
:loading="tipsLoading"
@open-profile="router.push('/profile')"
/>
@@ -40,7 +40,8 @@ const {
router,
profileLabel,
plusOpen,
mood,
tips,
tipsLoading,
searchHint,
gridRow1,
gridRow2,
@@ -7,7 +7,9 @@ const { api } = vi.hoisted(() => ({
authMe: vi.fn(),
listImageCardScenes: vi.fn(),
getImageCardQuota: vi.fn(),
listProfiles: vi.fn(),
createProfile: vi.fn(),
updateProfile: vi.fn(),
drawImageCard: vi.fn(),
createOrder: vi.fn(),
payMock: vi.fn(),
@@ -35,6 +37,7 @@ describe('ImageCardPage', () => {
})
it('boots scenes and draws a card', async () => {
api.listProfiles.mockResolvedValue({ items: [] })
api.createProfile.mockResolvedValue({ id: 'p1' })
api.drawImageCard.mockResolvedValue({
scene: '情绪整理',
+2 -2
View File
@@ -64,8 +64,8 @@
v-model="nickname"
class="inp"
type="text"
maxlength="32"
placeholder="怎么称呼你"
maxlength="16"
placeholder="不填则自动生成,如心语岛"
/>
</label>
+4 -1
View File
@@ -6,6 +6,7 @@ import ProfilePage from './ProfilePage.vue'
const { api } = vi.hoisted(() => ({
api: {
authMe: vi.fn(),
authUpdateMe: vi.fn(),
listProfiles: vi.fn(),
updateProfile: vi.fn(),
deleteProfile: vi.fn(),
@@ -29,13 +30,15 @@ const RouterLinkStub = defineComponent({
describe('ProfilePage', () => {
beforeEach(() => {
vi.clearAllMocks()
api.authMe.mockResolvedValue({ id: 'u1' })
api.authMe.mockResolvedValue({ id: 'u1', nickname: '心语岛', phone: '138****0000' })
})
it('shows empty state', async () => {
api.listProfiles.mockResolvedValue({ items: [] })
const w = mount(ProfilePage, { global: { stubs: { RouterLink: RouterLinkStub } } })
await flushPromises()
expect(w.text()).toContain('账号昵称')
expect(w.text()).toContain('心语岛')
expect(w.text()).toContain('暂无档案')
})
+8
View File
@@ -16,6 +16,11 @@
</p>
<template v-else>
<AccountNicknameCard
:nickname="accountNickname"
@updated="onNicknameUpdated"
/>
<ProfileEmpty v-if="!items.length" />
<template v-else>
@@ -85,6 +90,7 @@
<script setup lang="ts">
import BackButton from '../components/BackButton.vue'
import PageShell from '../components/PageShell.vue'
import AccountNicknameCard from '../components/profile/AccountNicknameCard.vue'
import ProfileAddForm from '../components/profile/ProfileAddForm.vue'
import ProfileBottomCta from '../components/profile/ProfileBottomCta.vue'
import ProfileEditForm from '../components/profile/ProfileEditForm.vue'
@@ -95,6 +101,8 @@ import ProfileSelfCard from '../components/profile/ProfileSelfCard.vue'
import { useProfilePage } from '../composables/useProfilePage'
const {
accountNickname,
onNicknameUpdated,
items,
loading,
error,
@@ -110,4 +110,20 @@ describe('SynastryPage', () => {
await flushPromises()
expect(w.text()).toContain('组合次限')
})
it('hides duplicate self from TA pick list', async () => {
api.listProfiles.mockResolvedValue({
items: [
{ id: 'a1', relation: 'self', display_name: '我', birth_date: '1990-05-12' },
{ id: 'a2', relation: 'self', display_name: '我', birth_date: '1991-01-01' },
{ id: 'b1', relation: 'other', display_name: '伴侣', birth_date: '1992-08-20' },
],
})
const w = mount(SynastryPage)
await flushPromises()
const chips = w.findAll('.chip-name').map((n) => n.text())
expect(chips.filter((t) => t === '我')).toHaveLength(0)
expect(chips).toContain('伴侣')
expect(chips).toContain('添加档案')
})
})
+2 -2
View File
@@ -30,7 +30,7 @@
:nearby="nearby"
:adding="adding"
:loading="loading"
:profiles="profiles"
:self-profiles="selfProfiles"
:invite-highlight="inviteHighlight"
:inviting="inviting"
:nearby-loading="nearbyLoading"
@@ -107,7 +107,6 @@ const {
nearbyHint,
invitePath,
inviteHighlight,
profiles,
nearby,
profileA,
profileB,
@@ -126,6 +125,7 @@ const {
showQuickAdd,
needsSubTab,
pickableProfiles,
selfProfiles,
profileAName,
selfInitial,
profileInitial,