refactor(ECR-001): Phase F types/sdk 对齐并拆分超标 H5 页
抽出 OpenAPI DTO;将 Ask/Report/Profile/Star 等 8 页拆到 ≤400 行,并修 ScaleSummary、fortuneKey、Scale 选答与单测。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,302 @@
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import type { Profile } from '@yuxingu/types'
|
||||
import { api } from '../api/client'
|
||||
import { copyText } from '../lib/shareLink'
|
||||
|
||||
export const profileRelationOptions = [
|
||||
{ value: 'family', label: '家人' },
|
||||
{ value: 'friend', label: '朋友' },
|
||||
{ value: 'partner', label: '伴侣' },
|
||||
{ value: 'colleague', label: '同事' },
|
||||
{ value: 'other', label: '其他' },
|
||||
]
|
||||
|
||||
export function formatProfileDate(v: string) {
|
||||
return (v || '').slice(0, 10)
|
||||
}
|
||||
|
||||
export function avatarInitial(p: Profile) {
|
||||
const n = p.display_name || (p.relation === 'self' ? '我' : 'T')
|
||||
return n.slice(0, 1)
|
||||
}
|
||||
|
||||
export function relationLabel(t?: string | null) {
|
||||
const map: Record<string, string> = {
|
||||
partner: '伴侣',
|
||||
friend: '朋友',
|
||||
family: '家人',
|
||||
colleague: '同事',
|
||||
other: '关系对象',
|
||||
}
|
||||
return map[t || ''] || '关系对象'
|
||||
}
|
||||
|
||||
function splitBirth(v: string) {
|
||||
const s = formatProfileDate(v)
|
||||
const [y, m, d] = s.split('-')
|
||||
return { y: y || '', m: m ? String(Number(m)) : '', d: d ? String(Number(d)) : '' }
|
||||
}
|
||||
|
||||
function joinBirth(y: string, m: string, d: string) {
|
||||
const yi = Number(y)
|
||||
const mi = Number(m)
|
||||
const di = Number(d)
|
||||
if (!yi || !mi || !di) return ''
|
||||
return `${yi}-${String(mi).padStart(2, '0')}-${String(di).padStart(2, '0')}`
|
||||
}
|
||||
|
||||
export function useProfilePage() {
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const items = ref<Profile[]>([])
|
||||
const loading = ref(true)
|
||||
const error = ref('')
|
||||
const busyId = ref('')
|
||||
const editing = ref<Profile | null>(null)
|
||||
const showAddForm = ref(false)
|
||||
const showInviteFill = ref(false)
|
||||
const formName = ref('')
|
||||
const formY = ref('')
|
||||
const formM = ref('')
|
||||
const formD = ref('')
|
||||
const formPlace = ref('')
|
||||
const formRelationType = ref('partner')
|
||||
const formGeoVisible = ref(false)
|
||||
const formError = ref('')
|
||||
const saving = ref(false)
|
||||
const newName = ref('')
|
||||
const newY = ref('')
|
||||
const newM = ref('')
|
||||
const newD = ref('')
|
||||
const newPlace = ref('')
|
||||
const newRelationType = ref('family')
|
||||
const addError = ref('')
|
||||
const adding = ref(false)
|
||||
const inviting = ref(false)
|
||||
const invitePath = ref('')
|
||||
const inviteError = ref('')
|
||||
const inviteHint = ref('')
|
||||
const copyBusy = ref(false)
|
||||
|
||||
const selfProfile = computed(() => items.value.find((p) => p.relation === 'self'))
|
||||
const others = computed(() => items.value.filter((p) => p.relation !== 'self'))
|
||||
|
||||
function toggleAdd() {
|
||||
showAddForm.value = !showAddForm.value
|
||||
if (showAddForm.value) {
|
||||
editing.value = null
|
||||
showInviteFill.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function openAddForm() {
|
||||
showAddForm.value = true
|
||||
showInviteFill.value = false
|
||||
editing.value = null
|
||||
}
|
||||
|
||||
function openInviteFill() {
|
||||
showInviteFill.value = true
|
||||
showAddForm.value = false
|
||||
editing.value = null
|
||||
inviteError.value = ''
|
||||
if (!selfProfile.value) {
|
||||
inviteHint.value = '请先完成自己的档案,再邀请好友填写。'
|
||||
} else {
|
||||
inviteHint.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
function closeInviteFill() {
|
||||
showInviteFill.value = false
|
||||
void router.replace({ path: '/profile', query: {} })
|
||||
}
|
||||
|
||||
function applyQueryFlags() {
|
||||
if (route.query.add === '1') openAddForm()
|
||||
if (route.query.inviteFill === '1') openInviteFill()
|
||||
}
|
||||
|
||||
async function createFillInvite() {
|
||||
if (!selfProfile.value) {
|
||||
inviteError.value = '请先完成自己的档案'
|
||||
return
|
||||
}
|
||||
inviting.value = true
|
||||
inviteError.value = ''
|
||||
inviteHint.value = ''
|
||||
try {
|
||||
const res = await api.createSynastryInvite(selfProfile.value.id)
|
||||
invitePath.value = `${location.origin}${res.path}`
|
||||
inviteHint.value = '好友打开链接后填写生日即可;也可用于合盘。'
|
||||
} catch (e) {
|
||||
inviteError.value = e instanceof Error ? e.message : '生成失败'
|
||||
} finally {
|
||||
inviting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function copyInvite() {
|
||||
if (!invitePath.value) return
|
||||
copyBusy.value = true
|
||||
const ok = await copyText(invitePath.value)
|
||||
inviteHint.value = ok ? '链接已复制,发给家人或朋友即可。' : '复制失败,请长按链接手动复制。'
|
||||
copyBusy.value = false
|
||||
}
|
||||
|
||||
async function load() {
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
try {
|
||||
const res = await api.listProfiles()
|
||||
items.value = res.items || []
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : '加载失败'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function startEdit(p: Profile) {
|
||||
editing.value = p
|
||||
showAddForm.value = false
|
||||
formName.value = p.display_name || ''
|
||||
const b = splitBirth(p.birth_date)
|
||||
formY.value = b.y
|
||||
formM.value = b.m
|
||||
formD.value = b.d
|
||||
formPlace.value = p.birth_place || ''
|
||||
formRelationType.value = p.relation_type || 'partner'
|
||||
formGeoVisible.value = !!p.geo_visible
|
||||
formError.value = ''
|
||||
}
|
||||
|
||||
async function saveEdit() {
|
||||
if (!editing.value) return
|
||||
saving.value = true
|
||||
formError.value = ''
|
||||
try {
|
||||
const birth = joinBirth(formY.value, formM.value, formD.value)
|
||||
if (!birth) throw new Error('请填写生日')
|
||||
const body: {
|
||||
display_name: string
|
||||
birth_date: string
|
||||
relation_type?: string
|
||||
birth_place?: string
|
||||
geo_visible?: boolean
|
||||
} = {
|
||||
display_name: formName.value.trim(),
|
||||
birth_date: birth,
|
||||
birth_place: formPlace.value || '',
|
||||
}
|
||||
if (editing.value.relation === 'other') body.relation_type = formRelationType.value
|
||||
if (editing.value.relation === 'self') body.geo_visible = formGeoVisible.value
|
||||
await api.updateProfile(editing.value.id, body)
|
||||
editing.value = null
|
||||
await load()
|
||||
} catch (e) {
|
||||
formError.value = e instanceof Error ? e.message : '保存失败'
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function remove(p: Profile) {
|
||||
if (!confirm(`确定删除「${p.display_name || '档案'}」?`)) return
|
||||
busyId.value = p.id
|
||||
error.value = ''
|
||||
try {
|
||||
await api.deleteProfile(p.id)
|
||||
if (editing.value?.id === p.id) editing.value = null
|
||||
await load()
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : '删除失败'
|
||||
} finally {
|
||||
busyId.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
async function addOther() {
|
||||
adding.value = true
|
||||
addError.value = ''
|
||||
try {
|
||||
const birth = joinBirth(newY.value, newM.value, newD.value)
|
||||
if (!birth) throw new Error('请填写生日')
|
||||
await api.createProfile({
|
||||
relation: 'other',
|
||||
birth_date: birth,
|
||||
display_name: newName.value.trim() || 'TA',
|
||||
relation_type: newRelationType.value,
|
||||
birth_place: newPlace.value || undefined,
|
||||
})
|
||||
newName.value = ''
|
||||
newY.value = ''
|
||||
newM.value = ''
|
||||
newD.value = ''
|
||||
newPlace.value = ''
|
||||
showAddForm.value = false
|
||||
await load()
|
||||
if (route.query.add === '1') void router.replace({ path: '/profile', query: {} })
|
||||
} catch (e) {
|
||||
addError.value = e instanceof Error ? e.message : '添加失败'
|
||||
} finally {
|
||||
adding.value = false
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [route.query.add, route.query.inviteFill],
|
||||
() => applyQueryFlags(),
|
||||
)
|
||||
|
||||
onMounted(async () => {
|
||||
await load()
|
||||
applyQueryFlags()
|
||||
})
|
||||
|
||||
return {
|
||||
items,
|
||||
loading,
|
||||
error,
|
||||
busyId,
|
||||
editing,
|
||||
showAddForm,
|
||||
showInviteFill,
|
||||
formName,
|
||||
formY,
|
||||
formM,
|
||||
formD,
|
||||
formPlace,
|
||||
formRelationType,
|
||||
formGeoVisible,
|
||||
formError,
|
||||
saving,
|
||||
newName,
|
||||
newY,
|
||||
newM,
|
||||
newD,
|
||||
newPlace,
|
||||
newRelationType,
|
||||
addError,
|
||||
adding,
|
||||
inviting,
|
||||
invitePath,
|
||||
inviteError,
|
||||
inviteHint,
|
||||
copyBusy,
|
||||
selfProfile,
|
||||
others,
|
||||
toggleAdd,
|
||||
openInviteFill,
|
||||
closeInviteFill,
|
||||
createFillInvite,
|
||||
copyInvite,
|
||||
load,
|
||||
startEdit,
|
||||
saveEdit,
|
||||
remove,
|
||||
addOther,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user