Files
SideBar/src/components/SendPage.vue
lbw_9527443 ddf6d86a0c refactor(SendPage): 更新测评卷标题并移除多余空行
将青少年入营测评卷标题改为向阳营入营量表,同时清理初始化SDK函数中的多余空行
2026-03-05 19:06:55 +08:00

367 lines
8.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>
<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>