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

257 lines
6.5 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="couns">
<div class="couns__hero">
<div class="couns__eyebrow">专业陪伴 · 严格保密</div>
<div class="couns__title">婚恋咨询</div>
<div class="couns__desc">倾听你的心声,陪你梳理关系与情绪困扰</div>
</div>
<div class="couns__body">
<UiErrorState v-if="error" @retry="load" />
<UiLoading v-else-if="loading" />
<template v-else>
<div class="couns__status">
<span class="couns__status-label">服务状态</span>
<span class="couns__status-value" :class="{ 'couns__status-value--off': !serviceEnabled }">
{{ serviceEnabled ? '可预约' : disabledReason || '服务暂不可用' }}
</span>
</div>
<UiSectionHeader title="我们可以提供的帮助" />
<div v-if="services.length" class="couns__card">
<div v-for="s in services" :key="s.type" class="couns__topic" @click="selectTopic(s.type)">
<div class="couns__topic-icon" :class="`tone-${toneOf(s.type)}`">{{ iconOf(s.type) }}</div>
<div class="couns__topic-copy">
<div class="couns__topic-title">{{ s.name }}</div>
<div class="couns__topic-desc">{{ s.description }}</div>
</div>
<van-icon name="arrow" color="#9aa0b5" />
</div>
</div>
<UiEmpty v-else description="暂时无法获取咨询方向" />
<div class="couns__privacy">
咨询内容按敏感信息保护。公益红娘不能查看咨询正文,咨询人员仅处理明确分配给自己的服务。
</div>
</template>
</div>
<div class="couns__action">
<van-button class="couns__action-btn" plain @click="router.push('/my/counseling')">我的咨询</van-button>
<van-button
class="couns__action-btn"
type="primary"
:disabled="!serviceEnabled"
@click="book"
>
预约咨询
</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 UiEmpty from '@/components/UiEmpty.vue'
import UiErrorState from '@/components/UiErrorState.vue'
import UiSectionHeader from '@/components/UiSectionHeader.vue'
const router = useRouter()
const appStore = useAppStore()
const ICON_MAP: Record<string, string> = {
relationship_guidance: '咨',
emotional_support: '伴',
premarital_guidance: '婚',
anti_fraud_guidance: '盾',
}
const TONE_MAP: Record<string, string> = {
relationship_guidance: 'blue',
emotional_support: 'purple',
premarital_guidance: 'pink',
anti_fraud_guidance: 'green',
}
const loading = ref(true)
const error = ref(false)
const services = ref<any[]>([])
const disabledReason = ref('')
const serviceEnabled = computed(() => services.value.length > 0)
function iconOf(type: string): string {
return ICON_MAP[type] || '咨'
}
function toneOf(type: string): string {
return TONE_MAP[type] || 'blue'
}
async function load() {
loading.value = true
error.value = false
try {
const result: any = await counselingService.intro()
services.value = result?.items || result?.records || (Array.isArray(result) ? result : [])
} catch {
error.value = true
} finally {
loading.value = false
}
}
function selectTopic(type: string) {
if (!serviceEnabled.value) {
appStore.toast(disabledReason.value || '服务暂不可用')
return
}
router.push({ path: '/counseling/request', query: { type } })
}
function book() {
const type = services.value[0]?.type || 'relationship_guidance'
selectTopic(type)
}
onMounted(load)
</script>
<style scoped>
.couns {
min-height: 100vh;
background: var(--mini-bg);
padding-bottom: 76px;
}
.couns__hero {
background: var(--mini-brand-gradient);
color: #fff;
padding: 18px 16px 20px;
border-bottom-left-radius: 20px;
border-bottom-right-radius: 20px;
}
.couns__eyebrow {
font-size: 11px;
opacity: 0.8;
}
.couns__title {
font-size: 19px;
font-weight: 600;
margin-top: 4px;
}
.couns__desc {
font-size: 12px;
opacity: 0.85;
margin-top: 6px;
}
.couns__body {
padding: 0 16px;
}
.couns__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;
}
.couns__status-label {
font-size: 13px;
color: var(--mini-text-secondary);
}
.couns__status-value {
font-size: 13px;
font-weight: 600;
color: var(--mini-success);
}
.couns__status-value--off {
color: var(--mini-text-muted);
}
.couns__card {
background: var(--mini-surface);
border-radius: var(--mini-radius);
box-shadow: var(--mini-shadow);
overflow: hidden;
}
.couns__topic {
display: flex;
align-items: center;
gap: 12px;
padding: 14px;
border-bottom: 1px solid var(--mini-border);
}
.couns__topic:last-child {
border-bottom: none;
}
.couns__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;
}
.couns__topic-copy {
flex: 1;
min-width: 0;
}
.couns__topic-title {
font-size: 15px;
font-weight: 600;
color: var(--mini-text-strong);
}
.couns__topic-desc {
font-size: 12px;
color: var(--mini-text-secondary);
margin-top: 2px;
line-height: 1.5;
}
.couns__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;
}
.couns__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);
}
.couns__action-btn {
flex: 1;
border-radius: var(--mini-radius);
}
.tone-blue {
background: linear-gradient(135deg, #4f8cff 0%, #2f63e0 100%);
}
.tone-purple {
background: linear-gradient(135deg, #b06cff 0%, #8a3ee0 100%);
}
.tone-pink {
background: linear-gradient(135deg, #ff7ab0 0%, #e0559a 100%);
}
.tone-green {
background: linear-gradient(135deg, #3fc98a 0%, #199e64 100%);
}
</style>