Files
danyang-match/h5-demo/src/pages/premarital/PremaritalPage.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

239 lines
6.3 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="prem">
<div class="prem__hero">
<div class="prem__eyebrow">共同成长 · 面向未来</div>
<div class="prem__title">婚前辅导</div>
<div class="prem__desc">在进入婚姻前,把重要的事认真谈清楚</div>
</div>
<div class="prem__body">
<UiErrorState v-if="error" @retry="load" />
<UiLoading v-else-if="loading" />
<template v-else>
<div class="prem__status">
<span class="prem__status-label">服务状态</span>
<span class="prem__status-value" :class="{ 'prem__status-value--off': !serviceEnabled }">
{{ serviceEnabled ? '可预约' : disabledReason || '服务暂不可用' }}
</span>
</div>
<UiSectionHeader title="辅导内容" />
<div class="prem__card">
<div v-for="t in TOPICS" :key="t.title" class="prem__topic">
<div class="prem__topic-icon" :class="`tone-${t.tone}`">{{ t.icon }}</div>
<div class="prem__topic-copy">
<div class="prem__topic-title">{{ t.title }}</div>
<div class="prem__topic-desc">{{ t.description }}</div>
</div>
</div>
</div>
<div class="prem__privacy">
双方共同参与效果更好,但必须基于自愿;不会因为一方申请而自动通知或要求另一方参加。
</div>
</template>
</div>
<div class="prem__action">
<van-button class="prem__action-btn" plain @click="router.push('/my/counseling')">服务记录</van-button>
<van-button
class="prem__action-btn"
type="primary"
:disabled="!serviceEnabled"
@click="apply"
>
预约辅导
</van-button>
</div>
</div>
</PageLayout>
</template>
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { counselingService } from '@/api/services'
import { useAppStore } from '@/stores/app'
import PageLayout from '@/layouts/PageLayout.vue'
import UiLoading from '@/components/UiLoading.vue'
import UiErrorState from '@/components/UiErrorState.vue'
import UiSectionHeader from '@/components/UiSectionHeader.vue'
const router = useRouter()
const appStore = useAppStore()
const TOPICS = [
{ icon: '通', tone: 'blue', title: '沟通与期望', description: '表达需求、倾听差异,形成共同约定' },
{ icon: '家', tone: 'pink', title: '家庭与责任', description: '讨论家庭角色与双方家庭关系' },
{ icon: '财', tone: 'amber', title: '财务与规划', description: '了解消费习惯并讨论未来安排' },
{ icon: '和', tone: 'green', title: '冲突与修复', description: '学习处理分歧并建立修复方式' },
]
const loading = ref(true)
const error = ref(false)
const availableTypes = ref<string[]>([])
const disabledReason = ref('')
const serviceEnabled = computed(() =>
availableTypes.value.includes('premarital_guidance') || availableTypes.value.includes('premarital'),
)
async function load() {
loading.value = true
error.value = false
try {
const result: any = await counselingService.intro()
const list: any[] = result?.items || result?.records || (Array.isArray(result) ? result : [])
availableTypes.value = list.map((s: any) => s?.type).filter(Boolean)
} catch {
error.value = true
} finally {
loading.value = false
}
}
function apply() {
if (!serviceEnabled.value) {
appStore.toast(disabledReason.value || '服务暂不可用')
return
}
router.push({ path: '/premarital/request', query: { type: 'premarital_guidance' } })
}
onMounted(load)
</script>
<style scoped>
.prem {
min-height: 100vh;
background: var(--mini-bg);
padding-bottom: 76px;
}
.prem__hero {
background: var(--mini-brand-gradient);
color: #fff;
padding: 18px 16px 20px;
border-bottom-left-radius: 20px;
border-bottom-right-radius: 20px;
}
.prem__eyebrow {
font-size: 11px;
opacity: 0.8;
}
.prem__title {
font-size: 19px;
font-weight: 600;
margin-top: 4px;
}
.prem__desc {
font-size: 12px;
opacity: 0.85;
margin-top: 6px;
}
.prem__body {
padding: 0 16px;
}
.prem__status {
display: flex;
align-items: center;
justify-content: space-between;
background: var(--mini-surface);
border-radius: var(--mini-radius);
box-shadow: var(--mini-shadow);
padding: 12px 14px;
margin-top: 12px;
}
.prem__status-label {
font-size: 13px;
color: var(--mini-text-secondary);
}
.prem__status-value {
font-size: 13px;
font-weight: 600;
color: var(--mini-success);
}
.prem__status-value--off {
color: var(--mini-text-muted);
}
.prem__card {
background: var(--mini-surface);
border-radius: var(--mini-radius);
box-shadow: var(--mini-shadow);
overflow: hidden;
}
.prem__topic {
display: flex;
align-items: center;
gap: 12px;
padding: 14px;
border-bottom: 1px solid var(--mini-border);
}
.prem__topic:last-child {
border-bottom: none;
}
.prem__topic-icon {
width: 42px;
height: 42px;
border-radius: 12px;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 17px;
font-weight: 600;
flex: none;
}
.prem__topic-copy {
flex: 1;
min-width: 0;
}
.prem__topic-title {
font-size: 15px;
font-weight: 600;
color: var(--mini-text-strong);
}
.prem__topic-desc {
font-size: 12px;
color: var(--mini-text-secondary);
margin-top: 2px;
line-height: 1.5;
}
.prem__privacy {
font-size: 12px;
color: var(--mini-text-secondary);
line-height: 1.6;
background: rgba(47, 179, 109, 0.08);
border-radius: var(--mini-radius);
padding: 12px 14px;
margin-top: 16px;
}
.prem__action {
position: fixed;
left: 0;
right: 0;
bottom: 0;
display: flex;
gap: 10px;
padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
background: var(--mini-surface);
box-shadow: 0 -4px 16px rgba(23, 42, 114, 0.08);
}
.prem__action-btn {
flex: 1;
border-radius: var(--mini-radius);
}
.tone-blue {
background: linear-gradient(135deg, #4f8cff 0%, #2f63e0 100%);
}
.tone-pink {
background: linear-gradient(135deg, #ff7ab0 0%, #e0559a 100%);
}
.tone-amber {
background: linear-gradient(135deg, #f5a623 0%, #d98a10 100%);
}
.tone-green {
background: linear-gradient(135deg, #3fc98a 0%, #199e64 100%);
}
</style>