压低贴线 SFC/composable;报告/档案/量表/意象卡 path 挂 Envelope $ref;CI ESS 门禁跟到 ECR-005。 Co-authored-by: Cursor <cursoragent@cursor.com>
264 lines
7.2 KiB
TypeScript
264 lines
7.2 KiB
TypeScript
import type { Ref } from 'vue'
|
|
import type { Router } 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 || ''] || '关系对象'
|
|
}
|
|
|
|
export 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)) : '' }
|
|
}
|
|
|
|
export 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 type ProfilePageActionRefs = {
|
|
items: Ref<Profile[]>
|
|
loading: Ref<boolean>
|
|
error: Ref<string>
|
|
busyId: Ref<string>
|
|
editing: Ref<Profile | null>
|
|
showAddForm: Ref<boolean>
|
|
showInviteFill: Ref<boolean>
|
|
formName: Ref<string>
|
|
formY: Ref<string>
|
|
formM: Ref<string>
|
|
formD: Ref<string>
|
|
formPlace: Ref<string>
|
|
formRelationType: Ref<string>
|
|
formGeoVisible: Ref<boolean>
|
|
formError: Ref<string>
|
|
saving: Ref<boolean>
|
|
newName: Ref<string>
|
|
newY: Ref<string>
|
|
newM: Ref<string>
|
|
newD: Ref<string>
|
|
newPlace: Ref<string>
|
|
newRelationType: Ref<string>
|
|
addError: Ref<string>
|
|
adding: Ref<boolean>
|
|
inviting: Ref<boolean>
|
|
invitePath: Ref<string>
|
|
inviteError: Ref<string>
|
|
inviteHint: Ref<string>
|
|
copyBusy: Ref<boolean>
|
|
selfProfile: { value: Profile | undefined }
|
|
routeAdd: () => string | undefined
|
|
routeInviteFill: () => string | undefined
|
|
router: Router
|
|
}
|
|
|
|
export function createProfilePageActions(r: ProfilePageActionRefs) {
|
|
function toggleAdd() {
|
|
r.showAddForm.value = !r.showAddForm.value
|
|
if (r.showAddForm.value) {
|
|
r.editing.value = null
|
|
r.showInviteFill.value = false
|
|
}
|
|
}
|
|
|
|
function openAddForm() {
|
|
r.showAddForm.value = true
|
|
r.showInviteFill.value = false
|
|
r.editing.value = null
|
|
}
|
|
|
|
function openInviteFill() {
|
|
r.showInviteFill.value = true
|
|
r.showAddForm.value = false
|
|
r.editing.value = null
|
|
r.inviteError.value = ''
|
|
if (!r.selfProfile.value) {
|
|
r.inviteHint.value = '请先完成自己的档案,再邀请好友填写。'
|
|
} else {
|
|
r.inviteHint.value = ''
|
|
}
|
|
}
|
|
|
|
function closeInviteFill() {
|
|
r.showInviteFill.value = false
|
|
void r.router.replace({ path: '/profile', query: {} })
|
|
}
|
|
|
|
function applyQueryFlags() {
|
|
if (r.routeAdd() === '1') openAddForm()
|
|
if (r.routeInviteFill() === '1') openInviteFill()
|
|
}
|
|
|
|
async function createFillInvite() {
|
|
if (!r.selfProfile.value) {
|
|
r.inviteError.value = '请先完成自己的档案'
|
|
return
|
|
}
|
|
r.inviting.value = true
|
|
r.inviteError.value = ''
|
|
r.inviteHint.value = ''
|
|
try {
|
|
const res = await api.createSynastryInvite(r.selfProfile.value.id)
|
|
r.invitePath.value = `${location.origin}${res.path}`
|
|
r.inviteHint.value = '好友打开链接后填写生日即可;也可用于合盘。'
|
|
} catch (e) {
|
|
r.inviteError.value = e instanceof Error ? e.message : '生成失败'
|
|
} finally {
|
|
r.inviting.value = false
|
|
}
|
|
}
|
|
|
|
async function copyInvite() {
|
|
if (!r.invitePath.value) return
|
|
r.copyBusy.value = true
|
|
const ok = await copyText(r.invitePath.value)
|
|
r.inviteHint.value = ok ? '链接已复制,发给家人或朋友即可。' : '复制失败,请长按链接手动复制。'
|
|
r.copyBusy.value = false
|
|
}
|
|
|
|
async function load() {
|
|
r.loading.value = true
|
|
r.error.value = ''
|
|
try {
|
|
const res = await api.listProfiles()
|
|
r.items.value = res.items || []
|
|
} catch (e) {
|
|
r.error.value = e instanceof Error ? e.message : '加载失败'
|
|
} finally {
|
|
r.loading.value = false
|
|
}
|
|
}
|
|
|
|
function startEdit(p: Profile) {
|
|
r.editing.value = p
|
|
r.showAddForm.value = false
|
|
r.formName.value = p.display_name || ''
|
|
const b = splitBirth(p.birth_date)
|
|
r.formY.value = b.y
|
|
r.formM.value = b.m
|
|
r.formD.value = b.d
|
|
r.formPlace.value = p.birth_place || ''
|
|
r.formRelationType.value = p.relation_type || 'partner'
|
|
r.formGeoVisible.value = !!p.geo_visible
|
|
r.formError.value = ''
|
|
}
|
|
|
|
async function saveEdit() {
|
|
if (!r.editing.value) return
|
|
r.saving.value = true
|
|
r.formError.value = ''
|
|
try {
|
|
const birth = joinBirth(r.formY.value, r.formM.value, r.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: r.formName.value.trim(),
|
|
birth_date: birth,
|
|
birth_place: r.formPlace.value || '',
|
|
}
|
|
if (r.editing.value.relation === 'other') body.relation_type = r.formRelationType.value
|
|
if (r.editing.value.relation === 'self') body.geo_visible = r.formGeoVisible.value
|
|
await api.updateProfile(r.editing.value.id, body)
|
|
r.editing.value = null
|
|
await load()
|
|
} catch (e) {
|
|
r.formError.value = e instanceof Error ? e.message : '保存失败'
|
|
} finally {
|
|
r.saving.value = false
|
|
}
|
|
}
|
|
|
|
async function remove(p: Profile) {
|
|
if (!confirm(`确定删除「${p.display_name || '档案'}」?`)) return
|
|
r.busyId.value = p.id
|
|
r.error.value = ''
|
|
try {
|
|
await api.deleteProfile(p.id)
|
|
if (r.editing.value?.id === p.id) r.editing.value = null
|
|
await load()
|
|
} catch (e) {
|
|
r.error.value = e instanceof Error ? e.message : '删除失败'
|
|
} finally {
|
|
r.busyId.value = ''
|
|
}
|
|
}
|
|
|
|
async function addOther() {
|
|
r.adding.value = true
|
|
r.addError.value = ''
|
|
try {
|
|
const birth = joinBirth(r.newY.value, r.newM.value, r.newD.value)
|
|
if (!birth) throw new Error('请填写生日')
|
|
await api.createProfile({
|
|
relation: 'other',
|
|
birth_date: birth,
|
|
display_name: r.newName.value.trim() || 'TA',
|
|
relation_type: r.newRelationType.value,
|
|
birth_place: r.newPlace.value || undefined,
|
|
})
|
|
r.newName.value = ''
|
|
r.newY.value = ''
|
|
r.newM.value = ''
|
|
r.newD.value = ''
|
|
r.newPlace.value = ''
|
|
r.showAddForm.value = false
|
|
await load()
|
|
if (r.routeAdd() === '1') void r.router.replace({ path: '/profile', query: {} })
|
|
} catch (e) {
|
|
r.addError.value = e instanceof Error ? e.message : '添加失败'
|
|
} finally {
|
|
r.adding.value = false
|
|
}
|
|
}
|
|
|
|
return {
|
|
toggleAdd,
|
|
openAddForm,
|
|
openInviteFill,
|
|
closeInviteFill,
|
|
applyQueryFlags,
|
|
createFillInvite,
|
|
copyInvite,
|
|
load,
|
|
startEdit,
|
|
saveEdit,
|
|
remove,
|
|
addOther,
|
|
}
|
|
}
|