Files
danyang-match/h5-demo/src/pages/onboarding/ProfileIntroPage.vue
T
WorkBuddy 69ebf33e18
CI/CD Pipeline / Backend Build & Test (push) Waiting to run
CI/CD Pipeline / Admin Web Build (push) Waiting to run
CI/CD Pipeline / Mini Program Compile Check (push) Waiting to run
CI/CD Pipeline / Migration Validation (push) Blocked by required conditions
CI/CD Pipeline / Test Shell Guard (Phase 23 Gate) (push) Waiting to run
CI/CD Pipeline / UI Contracts (source-structure gates) (push) Waiting to run
CI/CD Pipeline / E2E (live stack) (push) Blocked by required conditions
release: freeze demo v1.1.0 2026-10-19
2026-10-19 20:36:22 +08:00

178 lines
4.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<PageLayout title="个人介绍">
<div class="pri">
<UiLoading v-if="loading" text="加载中…" />
<div class="card">
<UiSectionHeader title="简单介绍一下自己" />
<p class="pri__hint">{{ MIN_LEN }}~{{ MAX_LEN }} 字</p>
<div class="pri__wrap">
<textarea
v-model="selfIntro"
class="pri__textarea"
:maxlength="MAX_LEN"
placeholder="可以介绍工作、性格、兴趣、生活状态,以及你期待怎样的感情"
/>
<div class="pri__counter">{{ selfIntro.length }}/{{ MAX_LEN }}</div>
</div>
</div>
<div class="card">
<UiSectionHeader title="填写须知" />
<div class="pri__guidelines">
<div v-for="(g, i) in guidelines" :key="i" class="pri__guideline">
<span class="pri__dot"></span>
<span class="pri__guideline-text">{{ g }}</span>
</div>
</div>
</div>
<div v-if="!isWizard" class="card">
<UiSectionHeader title="其他资料入口" />
<p class="pri__hint">点选可跳转对应步骤修改</p>
<van-cell-group :border="false">
<van-cell title="基础资料" is-link @click="router.push('/profile/basic')" />
<van-cell title="职业与生活" is-link @click="router.push('/profile/lifestyle')" />
<van-cell title="头像与照片" is-link @click="router.push('/profile/photos')" />
<van-cell title="兴趣与生活方式" is-link @click="router.push('/profile/interests')" />
<van-cell title="婚恋态度" is-link @click="router.push('/profile/intent')" />
<van-cell title="择偶条件" is-link @click="router.push('/profile/preference')" />
</van-cell-group>
</div>
<div class="pri__actions">
<van-button type="primary" block round :loading="saving" @click="onNext">下一步</van-button>
</div>
</div>
</PageLayout>
</template>
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { profileService } from '@/api/services'
import { useAppStore } from '@/stores/app'
import PageLayout from '@/layouts/PageLayout.vue'
import UiLoading from '@/components/UiLoading.vue'
import UiSectionHeader from '@/components/UiSectionHeader.vue'
const route = useRoute()
const router = useRouter()
const appStore = useAppStore()
const MIN_LEN = 20
const MAX_LEN = 500
const loading = ref(true)
const saving = ref(false)
const selfIntro = ref('')
const guidelines = [
'可以介绍工作、性格、兴趣、生活状态',
'以及你期待怎样的感情',
'禁止填写手机号、微信号、二维码',
'禁止广告、色情低俗、投资引流内容',
]
// 带 step=1 进入时为向导模式(隐藏资料入口),否则作为「我的资料」入口展示
const isWizard = computed(() => route.query.step === '1')
async function load() {
loading.value = true
try {
const p: any = await profileService.getProfile()
selfIntro.value = p?.selfIntro || ''
} catch {
/* 首次填写 */
} finally {
loading.value = false
}
}
async function onNext() {
if (saving.value) return
const text = selfIntro.value.trim()
if (text.length < MIN_LEN) return appStore.toast(`至少填写 ${MIN_LEN} 字`)
if (text.length > MAX_LEN) return appStore.toast(`最多填写 ${MAX_LEN} 字`)
saving.value = true
try {
await profileService.updateProfile({ selfIntro: text })
router.push('/profile/preference')
} catch (err: any) {
appStore.toastError(err?.message || '保存失败')
} finally {
saving.value = false
}
}
onMounted(load)
</script>
<style scoped>
.pri__hint {
font-size: 12px;
color: var(--mini-text-secondary);
margin: 0 0 8px;
line-height: 1.4;
}
.pri {
padding: 16px;
}
.card {
background: var(--mini-surface);
border-radius: var(--mini-radius);
box-shadow: var(--mini-shadow);
padding: 4px 16px 14px;
margin-bottom: 12px;
}
.pri__wrap {
position: relative;
margin-top: 4px;
}
.pri__textarea {
width: 100%;
min-height: 140px;
border: 1px solid var(--mini-border-weak, #f2f3f5);
border-radius: 10px;
padding: 12px;
font-size: 14px;
color: var(--mini-text);
background: var(--mini-bg);
box-sizing: border-box;
resize: none;
font-family: inherit;
}
.pri__counter {
text-align: right;
font-size: 12px;
color: var(--mini-text-muted);
margin-top: 6px;
}
.pri__guidelines {
margin-top: 4px;
}
.pri__guideline {
display: flex;
align-items: center;
gap: 8px;
padding: 4px 0;
}
.pri__dot {
width: 5px;
height: 5px;
border-radius: 50%;
background: var(--mini-tabbar-active);
flex: none;
}
.pri__guideline-text {
font-size: 13px;
color: var(--mini-text-secondary);
}
.card :deep(.van-cell) {
padding-left: 0;
padding-right: 0;
}
.pri__actions {
margin-top: 8px;
}
</style>