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

174 lines
5.1 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="pi">
<UiLoading v-if="loading" text="加载中…" />
<div class="card">
<UiSectionHeader title="兴趣" />
<p class="pi__hint">最多选择 {{ MAX_TAGS }} 项({{ selectedCount }}/{{ MAX_TAGS }})</p>
<div class="pi__tags">
<span
v-for="t in interests"
:key="t.code"
class="pi__tag"
:class="{ 'pi__tag--selected': t.selected }"
@click="toggleInterest(t)"
>
{{ t.name }}
</span>
</div>
</div>
<div class="card">
<UiSectionHeader title="生活方式" />
<p class="pi__hint">可选,多选</p>
<div class="pi__tags">
<span
v-for="t in lifestyles"
:key="t.code"
class="pi__tag"
:class="{ 'pi__tag--selected': t.selected }"
@click="t.selected = !t.selected"
>
{{ t.name }}
</span>
</div>
</div>
<div class="pi__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 { 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 router = useRouter()
const appStore = useAppStore()
const MAX_TAGS = 8
const loading = ref(true)
const saving = ref(false)
const interests = ref([
{ code: 'travel', name: '旅行', selected: false },
{ code: 'reading', name: '阅读', selected: false },
{ code: 'sports', name: '运动', selected: false },
{ code: 'fitness', name: '健身', selected: false },
{ code: 'photography', name: '摄影', selected: false },
{ code: 'movie', name: '电影', selected: false },
{ code: 'music', name: '音乐', selected: false },
{ code: 'food', name: '美食', selected: false },
{ code: 'cooking', name: '烹饪', selected: false },
{ code: 'outdoor', name: '户外', selected: false },
{ code: 'pets', name: '宠物', selected: false },
{ code: 'games', name: '游戏', selected: false },
{ code: 'culture', name: '传统文化', selected: false },
{ code: 'charity', name: '公益活动', selected: false },
{ code: 'other', name: '其他', selected: false },
])
const lifestyles = ref([
{ code: 'quiet', name: '喜欢安静', selected: false },
{ code: 'social', name: '喜欢社交', selected: false },
{ code: 'outdoor', name: '喜欢户外', selected: false },
{ code: 'homebody', name: '居家型', selected: false },
{ code: 'regular_work', name: '工作规律', selected: false },
{ code: 'frequent_travel', name: '经常出差', selected: false },
{ code: 'family_oriented', name: '注重家庭', selected: false },
{ code: 'other', name: '其他', selected: false },
])
const selectedCount = computed(() => interests.value.filter((o) => o.selected).length)
function toggleInterest(t: { code: string; name: string; selected: boolean }) {
if (!t.selected && selectedCount.value >= MAX_TAGS) {
appStore.toast(`最多选择 ${MAX_TAGS} 个兴趣`)
return
}
t.selected = !t.selected
}
async function load() {
loading.value = true
try {
const p: any = await profileService.getProfile()
const savedInterests: string[] = p?.interests || []
const savedLifestyles: string[] = p?.lifestyles || []
interests.value = interests.value.map((o) => ({ ...o, selected: savedInterests.includes(o.code) }))
lifestyles.value = lifestyles.value.map((o) => ({ ...o, selected: savedLifestyles.includes(o.code) }))
} catch {
/* 首次填写 */
} finally {
loading.value = false
}
}
async function onNext() {
if (saving.value) return
saving.value = true
try {
await profileService.updateProfile({
interests: interests.value.filter((o) => o.selected).map((o) => o.code),
lifestyles: lifestyles.value.filter((o) => o.selected).map((o) => o.code),
})
router.push('/profile/intent')
} catch (err: any) {
appStore.toastError(err?.message || '保存失败')
} finally {
saving.value = false
}
}
onMounted(load)
</script>
<style scoped>
.pi__hint {
font-size: 12px;
color: var(--mini-text-secondary);
margin: 0 0 8px;
line-height: 1.4;
}
.pi {
padding: 16px;
}
.card {
background: var(--mini-surface);
border-radius: var(--mini-radius);
box-shadow: var(--mini-shadow);
padding: 4px 16px 14px;
margin-bottom: 12px;
}
.pi__tags {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 4px;
}
.pi__tag {
font-size: 13px;
color: var(--mini-text);
background: var(--mini-bg);
border-radius: 16px;
padding: 7px 14px;
border: 1px solid transparent;
}
.pi__tag--selected {
color: var(--mini-tabbar-active);
background: rgba(244, 0, 90, 0.08);
border-color: var(--mini-tabbar-active);
}
.pi__actions {
margin-top: 8px;
}
</style>