367 lines
8.3 KiB
Vue
367 lines
8.3 KiB
Vue
<template>
|
||
<div class="page-wrapper">
|
||
<!-- 背景装饰圆点 -->
|
||
<div class="bg-dot dot-1"></div>
|
||
<div class="bg-dot dot-2"></div>
|
||
|
||
<div class="container">
|
||
<!-- 头部区域 -->
|
||
<div class="header-section">
|
||
<div class="sparkle-icon">✨</div>
|
||
<h1 class="main-title">青少年心理健康评估</h1>
|
||
<p class="subtitle">专业、科学、个性化的心理健康分析</p>
|
||
</div>
|
||
|
||
<!-- 主体操作卡片 -->
|
||
<div class="action-card">
|
||
<h2 class="card-headline">选择并发送评估工具</h2>
|
||
|
||
<div class="info-bar">
|
||
只需 <span class="time-badge">5-10 分钟</span>,即可获得专业的评估分析报告
|
||
</div>
|
||
|
||
<div class="button-list">
|
||
<!-- 按钮 1: 家庭教育档案 -->
|
||
<button class="nav-button" :class="{ 'is-active': activeType === 'archive', 'is-disabled': isCoolingDown }"
|
||
@click="handleSend('archive')">
|
||
<div class="btn-left">
|
||
<span class="btn-icon-box">📝</span>
|
||
<span class="btn-label">发送【家庭教育档案】</span>
|
||
</div>
|
||
<div class="btn-loading-ring" v-if="isCoolingDown && activeType === 'archive'"></div>
|
||
<span class="btn-arrow" v-else>→</span>
|
||
</button>
|
||
|
||
<!-- 按钮 2: 入营测评卷 -->
|
||
<button class="nav-button" :class="{ 'is-active': activeType === 'campTest', 'is-disabled': isCoolingDown }"
|
||
@click="handleSend('campTest')">
|
||
<div class="btn-left">
|
||
<span class="btn-icon-box">🎯</span>
|
||
<span class="btn-label">发送【入营测评卷】</span>
|
||
</div>
|
||
<div class="btn-loading-ring" v-if="isCoolingDown && activeType === 'campTest'"></div>
|
||
<span class="btn-arrow" v-else>→</span>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- 倒计时提示 -->
|
||
<div v-if="isCoolingDown" class="cooldown-text">
|
||
已发送,请在聊天窗口查看 ({{ countdown }}s)
|
||
</div>
|
||
|
||
<!-- 底部免责声明 -->
|
||
<div class="disclaimer">
|
||
<span class="light-bulb">💡</span>
|
||
评估完全免费,结果仅供参考,如需专业帮助请咨询心理医生
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, onMounted } from 'vue'
|
||
import * as ww from '@wecom/jssdk'
|
||
|
||
// --- 状态定义 ---
|
||
type FormType = 'archive' | 'campTest'
|
||
const isCoolingDown = ref(false)
|
||
const countdown = ref(0)
|
||
const activeType = ref<FormType | null>(null)
|
||
const isWWReady = ref(false)
|
||
|
||
// --- 配置表 ---
|
||
const CONFIG = {
|
||
archive: {
|
||
id: 0,
|
||
title: '家庭教育档案信息表',
|
||
desc: '通过专业的评估工具,了解孩子的成长需求。'
|
||
},
|
||
campTest: {
|
||
id: 2,
|
||
title: '向阳营入营量表',
|
||
desc: '入营前专属专业测评,帮助导师全方位了解营员特质。'
|
||
}
|
||
}
|
||
|
||
// --- 核心逻辑 ---
|
||
const handleSend = async (type: FormType) => {
|
||
if (isCoolingDown.value) return
|
||
|
||
activeType.value = type
|
||
startTimer(8) // 8秒冷却
|
||
|
||
try {
|
||
// 1. 获取外部联系人ID
|
||
const contact = await ww.getCurExternalContact()
|
||
const userId = contact.userId
|
||
|
||
// 2. 请求后端获取表单URL
|
||
const apiUrl = `https://liaison.nycjy.cn/api/v1/archive/form-url?user_id=${userId}&form_id=${CONFIG[type].id}`
|
||
const res = await fetch(apiUrl).then(r => r.json())
|
||
|
||
if (res.code === 200 && res.data?.form_url) {
|
||
// 3. 调用企微原生接口发送消息卡片
|
||
await ww.sendChatMessage({
|
||
msgtype: 'news',
|
||
news: {
|
||
title: CONFIG[type].title,
|
||
desc: CONFIG[type].desc,
|
||
imgUrl: 'https://forms.nycjy.cn/favicon.ico',
|
||
link: res.data.form_url
|
||
}
|
||
})
|
||
} else {
|
||
alert('获取链接失败:' + (res.message || '未知错误'))
|
||
}
|
||
} catch (err) {
|
||
console.error('发送流程出错:', err)
|
||
}
|
||
}
|
||
|
||
const startTimer = (seconds: number) => {
|
||
isCoolingDown.value = true
|
||
countdown.value = seconds
|
||
const timer = setInterval(() => {
|
||
countdown.value--
|
||
if (countdown.value <= 0) {
|
||
clearInterval(timer)
|
||
isCoolingDown.value = false
|
||
activeType.value = null
|
||
}
|
||
}, 1000)
|
||
}
|
||
|
||
// --- 初始化企业微信SDK ---
|
||
const initSDK = async () => {
|
||
try {
|
||
const url = window.location.href.split('#')[0]
|
||
|
||
// 签名函数 (对应你后端接口)
|
||
const getSig = async (apiUrl: string) => {
|
||
return await fetch(apiUrl, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ url })
|
||
}).then(r => r.json())
|
||
}
|
||
await ww.register({
|
||
corpId: 'wwf72acc5a681dca93',
|
||
agentId: 1000105,
|
||
jsApiList: ['sendChatMessage', 'getCurExternalContact', 'getContext'],
|
||
getConfigSignature: () => getSig('https://sidebar.wx.nycjy.cn/api/v1/wecom/config-signature'),
|
||
getAgentConfigSignature: () => getSig('https://sidebar.wx.nycjy.cn/api/v1/wecom/agent-config-signature')
|
||
})
|
||
isWWReady.value = true
|
||
console.log('企微SDK初始化成功')
|
||
} catch (e) {
|
||
console.error('SDK初始化失败', e)
|
||
}
|
||
}
|
||
|
||
onMounted(() => initSDK())
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* 全局基础设置 */
|
||
.page-wrapper {
|
||
min-height: 100vh;
|
||
background-color: #f4f7ff;
|
||
/* 淡蓝色背景 */
|
||
background: linear-gradient(180deg, #f0f4ff 0%, #ffffff 100%);
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
padding: 20px;
|
||
position: relative;
|
||
overflow: hidden;
|
||
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif;
|
||
}
|
||
|
||
.container {
|
||
width: 100%;
|
||
max-width: 420px;
|
||
z-index: 10;
|
||
}
|
||
|
||
/* 装饰元素 */
|
||
.bg-dot {
|
||
position: absolute;
|
||
border-radius: 50%;
|
||
filter: blur(60px);
|
||
z-index: 1;
|
||
}
|
||
|
||
.dot-1 {
|
||
width: 200px;
|
||
height: 200px;
|
||
background: #dce4ff;
|
||
top: -50px;
|
||
left: -50px;
|
||
}
|
||
|
||
.dot-2 {
|
||
width: 250px;
|
||
height: 250px;
|
||
background: #eef2ff;
|
||
bottom: -50px;
|
||
right: -50px;
|
||
}
|
||
|
||
/* 头部样式 */
|
||
.header-section {
|
||
text-align: center;
|
||
margin-bottom: 30px;
|
||
}
|
||
|
||
.sparkle-icon {
|
||
font-size: 44px;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.main-title {
|
||
color: #5c6be5;
|
||
/* 核心蓝紫色 */
|
||
font-size: 26px;
|
||
font-weight: 800;
|
||
margin: 0 0 10px 0;
|
||
letter-spacing: 1px;
|
||
}
|
||
|
||
.subtitle {
|
||
color: #8c96a8;
|
||
font-size: 15px;
|
||
margin: 0;
|
||
}
|
||
|
||
/* 主操作卡片 */
|
||
.action-card {
|
||
background: #ffffff;
|
||
border-radius: 24px;
|
||
padding: 35px 24px;
|
||
box-shadow: 0 10px 30px rgba(92, 107, 229, 0.08);
|
||
text-align: center;
|
||
}
|
||
|
||
.card-headline {
|
||
color: #333c4d;
|
||
font-size: 22px;
|
||
font-weight: 700;
|
||
margin: 0 0 15px 0;
|
||
}
|
||
|
||
/* 时间标签栏 */
|
||
.info-bar {
|
||
font-size: 14px;
|
||
color: #64748b;
|
||
margin-bottom: 35px;
|
||
}
|
||
|
||
.time-badge {
|
||
background: #edf0ff;
|
||
/* 淡紫色背景 */
|
||
color: #5c6be5;
|
||
padding: 3px 10px;
|
||
border-radius: 6px;
|
||
font-weight: 600;
|
||
margin: 0 4px;
|
||
}
|
||
|
||
/* 按钮列表 */
|
||
.button-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16px;
|
||
margin-bottom: 25px;
|
||
}
|
||
|
||
.nav-button {
|
||
background: #ffffff;
|
||
border: 1px solid #eef0f5;
|
||
border-radius: 16px;
|
||
padding: 18px 20px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
width: 100%;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.02);
|
||
}
|
||
|
||
.nav-button:active:not(.is-disabled) {
|
||
transform: scale(0.97);
|
||
background-color: #f8faff;
|
||
}
|
||
|
||
.btn-left {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 14px;
|
||
}
|
||
|
||
.btn-icon-box {
|
||
font-size: 20px;
|
||
}
|
||
|
||
.btn-label {
|
||
color: #5c6be5;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.btn-arrow {
|
||
color: #c0c7d1;
|
||
font-size: 18px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
/* 冷却状态样式 */
|
||
.is-disabled {
|
||
opacity: 0.6;
|
||
cursor: not-allowed;
|
||
background-color: #f5f7fa;
|
||
}
|
||
|
||
.cooldown-text {
|
||
font-size: 13px;
|
||
color: #5c6be5;
|
||
margin-bottom: 20px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.btn-loading-ring {
|
||
width: 18px;
|
||
height: 18px;
|
||
border: 2px solid #5c6be5;
|
||
border-top-color: transparent;
|
||
border-radius: 50%;
|
||
animation: spin 0.8s linear infinite;
|
||
}
|
||
|
||
@keyframes spin {
|
||
to {
|
||
transform: rotate(360deg);
|
||
}
|
||
}
|
||
|
||
/* 底部声明 */
|
||
.disclaimer {
|
||
background: #f8f9fc;
|
||
border-radius: 12px;
|
||
padding: 12px 16px;
|
||
font-size: 12px;
|
||
color: #94a3b8;
|
||
line-height: 1.6;
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: 8px;
|
||
text-align: left;
|
||
}
|
||
|
||
.light-bulb {
|
||
font-size: 16px;
|
||
filter: grayscale(0.2);
|
||
}
|
||
</style>
|