转诊方功能优化

This commit is contained in:
李琦
2026-02-07 16:17:01 +08:00
parent da8ef2019f
commit 4f9ba9cf44
5 changed files with 579 additions and 48 deletions

View File

@@ -466,6 +466,7 @@
"path": "chat/chat",
"style": {
"navigationBarTitleText": "在线问诊",
"navigationStyle": "custom",
"enablePullDownRefresh": false
}
},

View File

@@ -58,4 +58,21 @@ export async function submitTransferQuestionsApi(params) {
*/
export async function getTransferAssistantConfigApi() {
return await get('/transfer-assistant-config/get-config', {}, 3)
}
/**
* 获取转诊咨询协议信息(固定文案和协议列表)
* @returns {Promise<*>}
*/
export async function getTransferConsultationAgreementInfoApi() {
return await get('/transfer-consultation/get-agreement-info', {}, 3)
}
/**
* 获取协议详情根据协议ID
* @param {number} agreementId 协议ID
* @returns {Promise<*>}
*/
export async function getAgreementDetailApi(agreementId) {
return await get(`/agreement/get-detail?id=${agreementId}`, {}, 3)
}

View File

@@ -2,6 +2,16 @@
<!-- 根容器 -->
<view class="chat-container">
<!-- ================= 自定义导航栏 ================= -->
<u-navbar
class="chat-navbar"
:is-back="true"
:title="doctorUserInfo.nick_name || '在线问诊'"
:custom-back="handleBack"
title-color="#333"
:border-bottom="false"
></u-navbar>
<!-- ================= 顶部导航栏 (保持原样) ================= -->
<view class="chat-header">
<view class="header-main" @click="toggleDoctorDetail">
@@ -49,6 +59,18 @@
>
<view class="message-list-container" id="msglist" :style="{ paddingBottom: (keyboardHeight > 0 ? keyboardHeight + 10 : 0) + 'px' }">
<!-- 协议提示信息 -->
<view class="notice-box" v-if="showNotice">
<view class="notice-text">
<text v-for="(part, index) in parsedNoticeParts" :key="index">
<text v-if="part.type === 'text'">{{ part.text }}</text>
<text v-else-if="part.type === 'agreement'" class="notice-link" @click="viewAgreement(part.agreementId)">
{{ part.text }}
</text>
</text>
</view>
</view>
<!-- 加载指示器 -->
<view v-if="loading" class="loading-spinner">
<view class="spinner"></view>
@@ -92,6 +114,19 @@
<view style="height: 180rpx;"></view>
</scroll-view>
<!-- 协议抽屉 -->
<u-popup v-model="showAgreement" :safe-area-inset-bottom="true" mode="bottom" height="88%" border-radius="20"
:closeable="true" z-index="20000">
<view class="agreement-popup">
<view class="agreement-header">
<text class="agreement-title">{{ currentAgreementName || '协议详情' }}</text>
</view>
<view class="agreement-content">
<u-parse :html="agreementContent"></u-parse>
</view>
</view>
</u-popup>
<!-- ================= 底部输入与工具栏 (重构优化版) ================= -->
<view class="chat-footer safe-area-inset-bottom" :style="{ bottom: keyboardHeight + 'px' }">
<view v-if="isConsultationEnded" class="consultation-ended-notice">
@@ -161,7 +196,7 @@ import MessageBubble from './components/MessageBubble.vue'; // 引入组件
import { webSocketManager } from '@/utils/ws/websocket';
import { ChatManager } from '@/store/chat/chat.js';
import {getChatRegisterInfoApi, sendToUserApi, upLoadChatFileApi, getDoctorInfoApi, getRoomStatusApi} from "@/request/api/im";
import {getTransferAssistantConfigApi} from "@/request/api/transferPrescription";
import {getTransferAssistantConfigApi, getTransferConsultationAgreementInfoApi, getAgreementDetailApi} from "@/request/api/transferPrescription";
import { checkDev } from '@/utils/utils';
// 根据环境获取上传URL
@@ -218,6 +253,14 @@ export default {
isLoadHistory: false,
isConsultationEnded: false,
keyboardHeight: 0,
showNotice: true, // 显示协议提示
noticeText: '', // 提示文案
agreements: [], // 协议列表
parsedNoticeParts: [], // 解析后的文案部分(文本和协议链接)
showAgreement: false, // 控制协议抽屉显示
agreementContent: '', // 协议内容
currentAgreementId: 0, // 当前查看的协议ID
currentAgreementName: '', // 当前查看的协议名称
};
},
@@ -230,7 +273,9 @@ export default {
icon: 'none'
});
setTimeout(() => {
uni.navigateBack();
uni.reLaunch({
url: '/pages/index/index'
});
}, 1500);
return;
}
@@ -258,8 +303,9 @@ export default {
// 无论是否有nickName都需要获取医生详情信息职称、医院、擅长
this.fetchDoctorInfo(doctorId);
// 加载助理配置信息
// 加载助理配置信息和协议信息
this.loadAssistantConfig();
this.loadAgreementInfo();
const nickName = this.doctorUserInfo.nick_name;
if (nickName && nickName !== 'undefined' && nickName !== 'null') {
@@ -278,6 +324,12 @@ export default {
});
},
onBackPress() {
// 拦截物理返回键,跳转到首页
this.handleBack();
return true; // 阻止默认返回行为
},
onUnload() {
if (this.innerAudioContext) {
this.innerAudioContext.destroy();
@@ -369,6 +421,117 @@ export default {
}
},
// 加载协议信息
async loadAgreementInfo() {
try {
const res = await getTransferConsultationAgreementInfoApi();
if (res.data && res.data.code === 0) {
const result = res.data.result || {};
this.noticeText = result.notice_text || '';
this.agreements = result.agreements || [];
// 解析文案,提取协议链接
this.parseNoticeText();
}
} catch (error) {
console.error('加载协议信息失败:', error);
// 失败时使用默认文案
this.noticeText = '根据国家互联网医院管理办法要求,平台仅为复诊患者提供服务。为了保障您的用药安全,购买该药物需要经过医生问诊,请根据真实情况回答,并请仔细阅读《互联网医疗风险告知及知情同意书》,继续咨询即表示您已知悉相关规则与风险并同意相关条款。';
this.parseNoticeText();
}
},
// 解析提示文案,将《协议名称》替换为可点击的链接
parseNoticeText() {
if (!this.noticeText) {
this.parsedNoticeParts = [];
return;
}
const parts = [];
// 使用正则表达式匹配《》中的协议名称
const regex = /《([^》]+)》/g;
let lastIndex = 0;
let match;
while ((match = regex.exec(this.noticeText)) !== null) {
// 添加匹配前的文本
if (match.index > lastIndex) {
parts.push({
type: 'text',
text: this.noticeText.substring(lastIndex, match.index)
});
}
// 查找匹配的协议
const agreementName = match[1];
const agreement = this.agreements.find(ag => ag.name === agreementName || ag.name.includes(agreementName));
if (agreement) {
// 找到匹配的协议,添加为可点击的链接
parts.push({
type: 'agreement',
text: agreementName,
agreementId: agreement.id
});
} else {
// 没找到匹配的协议,作为普通文本显示
parts.push({
type: 'text',
text: match[0] // 《协议名称》
});
}
lastIndex = regex.lastIndex;
}
// 添加剩余的文本
if (lastIndex < this.noticeText.length) {
parts.push({
type: 'text',
text: this.noticeText.substring(lastIndex)
});
}
this.parsedNoticeParts = parts;
},
// 查看协议
async viewAgreement(agreementId) {
if (!agreementId) {
uni.showToast({
title: '协议ID不能为空',
icon: 'none'
});
return;
}
// 查找协议名称
const agreement = this.agreements.find(ag => ag.id === agreementId);
this.currentAgreementId = agreementId;
this.currentAgreementName = agreement ? agreement.name : '协议详情';
this.showAgreement = true;
try {
const res = await getAgreementDetailApi(agreementId);
if (res.data && res.data.code === 0) {
const result = res.data.result || {};
this.agreementContent = result.content || '';
// 如果API返回了协议名称使用API返回的名称
if (result.name) {
this.currentAgreementName = result.name;
}
} else {
throw new Error(res.data.message || '获取协议详情失败');
}
} catch (error) {
console.error('获取协议详情失败:', error);
uni.showToast({
title: error.message || '获取协议详情失败',
icon: 'none'
});
this.showAgreement = false;
}
},
// === 音频播放逻辑 ===
playAudio(msg) {
const audioUrl = getParsedContent(msg.message_type, msg.message_content);
@@ -475,13 +638,22 @@ export default {
const systemInfo = uni.getSystemInfoSync();
const windowHeight = systemInfo.windowHeight;
const query = uni.createSelectorQuery().in(this);
query.select('.chat-header').boundingClientRect((headerRect) => {
const headerHeight = headerRect ? headerRect.height : 0;
const query2 = uni.createSelectorQuery().in(this);
query2.select('.chat-footer').boundingClientRect((footerRect) => {
const footerHeight = footerRect ? footerRect.height : 0;
const scrollHeight = windowHeight - headerHeight - footerHeight;
this.scrollViewStyle = `height: ${scrollHeight}px;`;
// 获取u-navbar导航栏高度uView会自动处理状态栏高度
query.select('.chat-navbar').boundingClientRect((navbarRect) => {
const navbarHeight = navbarRect ? navbarRect.height : 0;
// 获取聊天头部高度
query.select('.chat-header').boundingClientRect((headerRect) => {
const headerHeight = headerRect ? headerRect.height : 0;
// 获取底部输入栏高度
const query2 = uni.createSelectorQuery().in(this);
query2.select('.chat-footer').boundingClientRect((footerRect) => {
const footerHeight = footerRect ? footerRect.height : 0;
const scrollHeight = windowHeight - navbarHeight - headerHeight - footerHeight;
this.scrollViewStyle = `height: ${scrollHeight}px;`;
}).exec();
}).exec();
}).exec();
});
@@ -840,7 +1012,27 @@ export default {
viewPrescription(id, orderNo) { uni.navigateTo({ url: "/subPackages/my/myrecord-detail?id=" + id + '&no=' + orderNo }); },
goToOrderMedicine(id, orderNo) { uni.navigateTo({ url: "/subPackages/my/my-drug/drug-info?id=" + id + '&order_type=prescription' }); },
viewRegister(id, orderNo) { uni.navigateTo({ url: "/subPackages/register/register-detail?id=" + id + '&no=' + orderNo }); },
viewOrder(orderId, orderNo) { uni.navigateTo({ url: "/subPackages/my/my-drug/drug-info?id=" + orderId }); }
viewOrder(orderId, orderNo) { uni.navigateTo({ url: "/subPackages/my/my-drug/drug-info?id=" + orderId }); },
// 处理返回操作(自定义返回逻辑)
handleBack() {
// 跳转到首页tabBar页面需要使用switchTab
uni.switchTab({
url: '/pages/index/index',
success: () => {
console.log('跳转到首页成功');
},
fail: (err) => {
console.error('跳转到首页失败:', err);
// 如果switchTab失败尝试使用reLaunch
uni.reLaunch({
url: '/pages/index/index'
});
}
});
// 返回 false 阻止 u-navbar 的默认返回行为(重要!)
return false;
}
}
};
</script>
@@ -866,6 +1058,7 @@ $bg-white: #ffffff;
z-index: 100;
position: relative;
box-shadow: 0 1rpx 2rpx rgba(0,0,0,0.05);
// u-navbar会自动处理状态栏和导航栏高度这里不需要额外设置margin-top
.header-main {
display: flex;
@@ -934,6 +1127,26 @@ $bg-white: #ffffff;
padding: 30rpx 24rpx;
}
.notice-box {
margin-bottom: 20rpx;
padding: 24rpx;
background: #F5F5F5;
border-radius: 12rpx;
font-size: 24rpx;
line-height: 1.6;
color: #666;
.notice-text {
display: block;
word-break: break-all;
}
.notice-link {
color: #0A84FF;
text-decoration: underline;
}
}
.empty-state { text-align: center; padding: 40rpx 0; .empty-text { font-size: 24rpx; color: #ccc; } }
.loading-spinner { display: flex; justify-content: center; align-items: center; padding: 20rpx; .spinner { width: 30rpx; height: 30rpx; border: 2rpx solid #ddd; border-top-color: #999; border-radius: 50%; animation: spin 0.8s linear infinite; } .spinner-text { font-size: 24rpx; color: #999; margin-left: 10rpx;} }
@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
@@ -1007,4 +1220,34 @@ $bg-white: #ffffff;
.tip { font-size: 24rpx; color: #ccc; }
}
}
.agreement-popup {
display: flex;
flex-direction: column;
height: 100%;
background: #fff;
}
.agreement-header {
padding: 30rpx 50rpx 20rpx;
border-bottom: 1rpx solid #e5e7eb;
background: #fff;
position: sticky;
top: 0;
z-index: 10;
}
.agreement-title {
font-size: 32rpx;
font-weight: 600;
color: #1e293b;
line-height: 1.5;
}
.agreement-content {
flex: 1;
padding: 30rpx 50rpx 40rpx;
overflow-y: auto;
min-height: 0;
}
</style>

View File

@@ -39,8 +39,8 @@
<text class="question-number">{{ index + 1 }}.</text>
<text class="question-content">{{ qa.question }}</text>
</view>
<view class="answer-text" :class="qa.answer === '是' ? 'answer-yes' : 'answer-no'">
<text class="answer-icon">{{ qa.answer === '是' ? '✓' : '✗' }}</text>
<view class="answer-text" :class="qa.answer === '是' ? 'answer-yes' : (qa.answer === '否' ? 'answer-no' : 'answer-other')">
<text class="answer-icon">{{ qa.answer === '是' ? '✓' : (qa.answer === '否' ? '✗' : '?') }}</text>
<text>{{ qa.answer }}</text>
</view>
</view>
@@ -78,6 +78,26 @@ export default {
},
handleReject() {
this.$emit('reject', this.messageData);
},
// 获取答案的样式类:是=绿色,否=红色,其他=黄色
getAnswerClass(answer) {
if (answer === '是') {
return 'answer-yes';
} else if (answer === '否') {
return 'answer-no';
} else {
return 'answer-other';
}
},
// 获取答案的图标
getAnswerIcon(answer) {
if (answer === '是') {
return '✓';
} else if (answer === '否') {
return '✗';
} else {
return '?';
}
}
}
}
@@ -273,6 +293,15 @@ export default {
color: #dc2626;
}
.answer-other {
background: #fef3c7;
color: #d97706;
}
.answer-other .answer-icon {
color: #d97706;
}
.answer-icon {
font-size: 24rpx;
font-weight: bold;

View File

@@ -11,17 +11,34 @@
<!-- 提示信息类似图片中的灰色提示框 -->
<view class="notice-box" v-if="showNotice">
<text class="notice-text">
根据国家互联网医院管理办法要求平台仅为复诊患者提供服务为了保障您的用药安全购买该药物需要经过医生问诊请根据真实情况回答并请仔细阅读互联网医疗风险告知及知情同意书继续咨询即表示您已知悉相关规则与风险并同意相关条款
</text>
<text class="notice-link" @click="viewAgreement">互联网医疗风险告知及知情同意书</text>
<view class="notice-text">
<text v-for="(part, index) in parsedNoticeParts" :key="index">
<text v-if="part.type === 'text'">{{ part.text }}</text>
<text v-else-if="part.type === 'agreement'" class="notice-link" @click="viewAgreement(part.agreementId)">
{{ part.text }}
</text>
</text>
</view>
</view>
<!-- 协议抽屉 -->
<u-popup v-model="showAgreement" :safe-area-inset-bottom="true" mode="bottom" height="88%" border-radius="20"
:closeable="true" z-index="20000">
<view class="agreement-popup">
<view class="agreement-header">
<text class="agreement-title">{{ currentAgreementName || '协议详情' }}</text>
</view>
<view class="agreement-content">
<u-parse :html="agreementContent"></u-parse>
</view>
</view>
</u-popup>
<!-- 聊天消息区域 -->
<scroll-view class="messages-scroll" scroll-y="true" :scroll-into-view="scrollIntoView" scroll-with-animation>
<view class="messages-container">
<!-- 按时间顺序渲染消息 -->
<view v-for="(message, index) in displayedMessages" :key="message.id || index">
<view v-for="(message, index) in displayedMessages" :key="message.id">
<!-- 欢迎消息 -->
<view v-if="message.type === 'welcome'" class="message-item other">
<image class="avatar" :src="assistantAvatar" mode="aspectFill"></image>
@@ -86,10 +103,16 @@
</view>
</scroll-view>
<!-- 底部操作按钮只有"是""否" -->
<!-- 底部操作按钮根据问题的answers动态生成 -->
<view class="action-footer safe-area-inset-bottom" v-if="currentQuestion && !isSubmitting && !showWaiting">
<button class="action-btn no-btn" @click="handleAnswer('否')"></button>
<button class="action-btn yes-btn" @click="handleAnswer('是')"></button>
<button
v-for="(answer, index) in currentQuestionAnswers"
:key="index"
:class="['action-btn', getAnswerButtonClass(answer, index)]"
@click="handleAnswer(answer)"
>
{{ answer }}
</button>
</view>
<!-- 提交中提示 -->
@@ -107,7 +130,9 @@ import {
getTransferPrescriptionDetailApi,
getTransferQuestionsApi,
submitTransferQuestionsApi,
getTransferAssistantConfigApi
getTransferAssistantConfigApi,
getTransferConsultationAgreementInfoApi,
getAgreementDetailApi
} from '@/request/api/transferPrescription.js'
export default {
@@ -128,7 +153,14 @@ export default {
userAvatar: '/static/images/user-avatar.png', // 用户头像(需要替换为实际路径)
prescriptionInfo: '炒黄芪等共2味', // 处方信息(可以从转诊详情中获取)
replyDelay: 1.00, // 回复延迟时间(秒),从配置中获取
isTyping: false // 是否显示"正在回复"提示
isTyping: false, // 是否显示"正在回复"提示
noticeText: '', // 提示文案
agreements: [], // 协议列表
parsedNoticeParts: [], // 解析后的文案部分(文本和协议链接)
showAgreement: false, // 控制协议抽屉显示
agreementContent: '', // 协议内容
currentAgreementId: 0, // 当前查看的协议ID
currentAgreementName: '' // 当前查看的协议名称
}
},
computed: {
@@ -139,6 +171,33 @@ export default {
}
return null
},
// 当前问题的答案选项
currentQuestionAnswers() {
if (!this.currentQuestion) {
return ['是', '否'] // 默认答案
}
// 获取问题的answers字段
let answers = this.currentQuestion.answers
// 如果answers是字符串JSON格式解析为数组
if (typeof answers === 'string') {
try {
answers = JSON.parse(answers)
} catch (e) {
console.error('解析答案选项失败:', e)
answers = ['是', '否']
}
}
// 如果answers不是数组或为空使用默认值
if (!Array.isArray(answers) || answers.length === 0) {
answers = ['是', '否']
}
// 过滤空值
return answers.filter(answer => answer && answer.trim().length > 0)
},
// 按时间顺序显示的消息列表
displayedMessages() {
const messages = []
@@ -187,6 +246,35 @@ export default {
return messages
}
},
watch: {
// 监听当前问题索引变化,自动滚动到底部
currentQuestionIndex(newVal, oldVal) {
if (newVal !== oldVal && newVal >= 0) {
this.$nextTick(() => {
this.scrollToBottom()
})
}
},
// 监听用户答案变化,自动滚动到底部
userAnswers: {
handler(newVal, oldVal) {
if (newVal.length > (oldVal?.length || 0)) {
this.$nextTick(() => {
this.scrollToBottom()
})
}
},
deep: true
},
// 监听显示等待消息,自动滚动到底部
showWaiting(newVal) {
if (newVal) {
this.$nextTick(() => {
this.scrollToBottom()
})
}
}
},
onLoad(options) {
// 获取转诊ID
this.transferId = parseInt(options.transfer_id || 0)
@@ -201,10 +289,11 @@ export default {
return
}
// 加载转诊详情、问题列表助理配置
// 加载转诊详情、问题列表助理配置和协议信息
this.loadTransferDetail()
this.loadQuestions()
this.loadAssistantConfig()
this.loadAgreementInfo()
},
methods: {
// 加载转诊详情(获取药品信息)
@@ -330,7 +419,7 @@ export default {
// 显示第一个问题
this.currentQuestionIndex = 0
this.$nextTick(() => {
this.scrollIntoView = 'bottom-anchor'
this.scrollToBottom()
})
}, this.replyDelay * 1000) // 延迟时间(毫秒)
}
@@ -357,30 +446,24 @@ export default {
// 保存答案
this.userAnswers.push(answer)
// 立即滚动到底部,显示答案
this.$nextTick(() => {
this.scrollToBottom()
})
// 如果还有下一个问题,延迟显示下一个问题(模拟真人回复)
if (this.currentQuestionIndex < this.questions.length - 1) {
// 显示"正在回复"提示
this.isTyping = true
// 滚动到底部
this.$nextTick(() => {
this.scrollIntoView = 'bottom-anchor'
})
// 延迟后显示下一个问题
setTimeout(() => {
this.isTyping = false
this.currentQuestionIndex++
// 滚动到底部,显示新问题
this.$nextTick(() => {
this.scrollIntoView = 'bottom-anchor'
})
// watch会自动触发滚动
}, this.replyDelay * 1000) // 延迟时间(毫秒)
} else {
// 所有问题已回答,提交答案
// 先滚动到底部
this.$nextTick(() => {
this.scrollIntoView = 'bottom-anchor'
})
// 延迟提交,让用户看到最后的问题和答案
setTimeout(() => {
this.submitAnswers()
@@ -396,10 +479,7 @@ export default {
this.isSubmitting = true
this.showWaiting = true
// 滚动到底部
this.$nextTick(() => {
this.scrollIntoView = 'bottom-anchor'
})
// 滚动到底部watch会自动触发
try {
// 构建答案数组(按照问题的顺序,确保与后端保存顺序一致)
@@ -465,6 +545,27 @@ export default {
})
}
},
// 获取答案按钮的样式类
getAnswerButtonClass(answer, index) {
const answers = this.currentQuestionAnswers
const totalAnswers = answers.length
// 如果只有两个答案,使用原来的样式(是/否)
if (totalAnswers === 2) {
if (answer === '是') {
return 'yes-btn'
} else if (answer === '否') {
return 'no-btn'
}
}
// 多个答案时,第一个按钮使用主色调,其他使用次要样式
if (index === 0) {
return 'yes-btn' // 第一个按钮使用主色调
} else {
return 'no-btn' // 其他按钮使用次要样式
}
},
// 返回
handleBack() {
uni.showModal({
@@ -477,13 +578,123 @@ export default {
}
})
},
// 滚动到底部
scrollToBottom() {
this.scrollIntoView = 'bottom-anchor'
// 延迟一下确保滚动生效
setTimeout(() => {
this.scrollIntoView = ''
}, 100)
},
// 加载协议信息
async loadAgreementInfo() {
try {
const res = await getTransferConsultationAgreementInfoApi()
if (res.data && res.data.code === 0) {
const result = res.data.result || {}
this.noticeText = result.notice_text || ''
this.agreements = result.agreements || []
// 解析文案,提取协议链接
this.parseNoticeText()
}
} catch (error) {
console.error('加载协议信息失败:', error)
// 失败时使用默认文案
this.noticeText = '根据国家互联网医院管理办法要求,平台仅为复诊患者提供服务。为了保障您的用药安全,购买该药物需要经过医生问诊,请根据真实情况回答,并请仔细阅读《互联网医疗风险告知及知情同意书》,继续咨询即表示您已知悉相关规则与风险并同意相关条款。'
this.parseNoticeText()
}
},
// 解析提示文案,将《协议名称》替换为可点击的链接
parseNoticeText() {
if (!this.noticeText) {
this.parsedNoticeParts = []
return
}
const parts = []
// 使用正则表达式匹配《》中的协议名称
const regex = /《([^》]+)》/g
let lastIndex = 0
let match
while ((match = regex.exec(this.noticeText)) !== null) {
// 添加匹配前的文本
if (match.index > lastIndex) {
parts.push({
type: 'text',
text: this.noticeText.substring(lastIndex, match.index)
})
}
// 查找匹配的协议
const agreementName = match[1]
const agreement = this.agreements.find(ag => ag.name === agreementName || ag.name.includes(agreementName))
if (agreement) {
// 找到匹配的协议,添加为可点击的链接
parts.push({
type: 'agreement',
text: agreementName,
agreementId: agreement.id
})
} else {
// 没找到匹配的协议,作为普通文本显示
parts.push({
type: 'text',
text: match[0] // 《协议名称》
})
}
lastIndex = regex.lastIndex
}
// 添加剩余的文本
if (lastIndex < this.noticeText.length) {
parts.push({
type: 'text',
text: this.noticeText.substring(lastIndex)
})
}
this.parsedNoticeParts = parts
},
// 查看协议
viewAgreement() {
// TODO: 跳转到协议页面
uni.showToast({
title: '协议页面开发中',
icon: 'none'
})
async viewAgreement(agreementId) {
if (!agreementId) {
uni.showToast({
title: '协议ID不能为空',
icon: 'none'
})
return
}
// 查找协议名称
const agreement = this.agreements.find(ag => ag.id === agreementId)
this.currentAgreementId = agreementId
this.currentAgreementName = agreement ? agreement.name : '协议详情'
this.showAgreement = true
try {
const res = await getAgreementDetailApi(agreementId)
if (res.data && res.data.code === 0) {
const result = res.data.result || {}
this.agreementContent = result.content || ''
// 如果API返回了协议名称使用API返回的名称
if (result.name) {
this.currentAgreementName = result.name
}
} else {
throw new Error(res.data.message || '获取协议详情失败')
}
} catch (error) {
console.error('获取协议详情失败:', error)
uni.showToast({
title: error.message || '获取协议详情失败',
icon: 'none'
})
this.showAgreement = false
}
}
}
}
@@ -545,7 +756,7 @@ export default {
.notice-text {
display: block;
margin-bottom: 12rpx;
word-break: break-all;
}
.notice-link {
@@ -737,4 +948,34 @@ export default {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.agreement-popup {
display: flex;
flex-direction: column;
height: 100%;
background: #fff;
}
.agreement-header {
padding: 30rpx 50rpx 20rpx;
border-bottom: 1rpx solid #e5e7eb;
background: #fff;
position: sticky;
top: 0;
z-index: 10;
}
.agreement-title {
font-size: 32rpx;
font-weight: 600;
color: #1e293b;
line-height: 1.5;
}
.agreement-content {
flex: 1;
padding: 30rpx 50rpx 40rpx;
overflow-y: auto;
min-height: 0;
}
</style>