This commit is contained in:
wangdongbo 2026-01-27 13:42:59 +08:00
parent 1332b12b03
commit 5d03f0fc79
14 changed files with 680 additions and 178 deletions

25
App.vue
View File

@ -29,13 +29,36 @@ export default {
</script>
<style lang="scss">
$primary-color: #0074ff;
$primary-color: #0877F1;
page {
height: 100%;
background: #f5f5f5;
}
/* 全局按钮样式 - 使用项目主题色 */
button[type="primary"],
.button-primary,
uni-button[type="primary"] {
background-color: $primary-color !important;
border-color: $primary-color !important;
color: #fff !important;
}
button[type="primary"]:not([disabled]):active,
.button-primary:active,
uni-button[type="primary"]:not([disabled]):active {
background-color: darken($primary-color, 10%) !important;
border-color: darken($primary-color, 10%) !important;
}
/* 微信小程序按钮样式覆盖 */
.wx-button[type="primary"] {
background-color: $primary-color !important;
border-color: $primary-color !important;
color: #fff !important;
}
.shadow-up {
box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px,
rgba(0, 0, 0, 0.1) 0px -10px 15px -3px, rgba(0, 0, 0, 0.1) 0px -4px 6px -4px;

View File

@ -25,12 +25,24 @@
"navigationBarTitleText": "宣教文章"
}
},
{
"path": "pages/message/article-detail",
"style": {
"navigationBarTitleText": "文章详情"
}
},
{
"path": "pages/message/survey-list",
"style": {
"navigationBarTitleText": "问卷列表"
}
},
{
"path": "pages/webview/webview",
"style": {
"navigationBarTitleText": "预览"
}
},
{
"path": "pages/work/work",
"style": {

View File

@ -0,0 +1,209 @@
<template>
<view class="article-detail-page">
<view v-if="loading" class="loading-container">
<uni-icons type="spinner-cycle" size="40" color="#999" />
<text class="loading-text">加载中...</text>
</view>
<view v-else-if="error" class="error-container">
<text class="error-text">{{ error }}</text>
<button class="retry-btn" @click="loadArticle">重试</button>
</view>
<scroll-view v-else scroll-y class="article-content">
<view class="article-header">
<text class="article-title">{{ articleData.title }}</text>
<text class="article-date">{{ articleData.date }}</text>
</view>
<view class="article-body">
<view class="rich-text-wrapper">
<rich-text :nodes="articleData.content"></rich-text>
</view>
</view>
</scroll-view>
</view>
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app';
import { getArticle } from '@/utils/api.js';
import { ref } from 'vue';
const loading = ref(true);
const error = ref('');
const articleData = ref({
title: '',
content: '',
date: ''
});
let articleId = '';
let corpId = '';
// 使
const processRichTextContent = (html) => {
if (!html) return '';
// img
let processedHtml = html.replace(
/<img/gi,
'<img style="max-width:100%;height:auto;display:block;margin:10px 0;"'
);
//
processedHtml = processedHtml.replace(
/style="[^"]*width:\s*\d+px[^"]*"/gi,
(match) => {
return match.replace(/width:\s*\d+px;?/gi, 'max-width:100%;');
}
);
//
processedHtml = processedHtml.replace(
/<table/gi,
'<table style="max-width:100%;overflow-x:auto;display:block;"'
);
//
processedHtml = `<div style="width:100%;overflow-x:hidden;word-wrap:break-word;word-break:break-all;">${processedHtml}</div>`;
return processedHtml;
};
//
const loadArticle = async () => {
if (!articleId || !corpId) {
error.value = '文章信息不完整';
loading.value = false;
return;
}
loading.value = true;
error.value = '';
try {
const res = await getArticle({ id: articleId, corpId: corpId });
if (res.success && res.data) {
//
let date = '';
if (res.data.createTime) {
const d = new Date(res.data.createTime);
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
date = `${year}-${month}-${day}`;
}
articleData.value = {
title: res.data.title || '宣教文章',
content: processRichTextContent(res.data.content || ''),
date: date
};
} else {
error.value = res.message || '加载文章失败';
}
} catch (err) {
console.error('加载文章失败:', err);
error.value = '加载失败,请重试';
} finally {
loading.value = false;
}
};
onLoad((options) => {
if (options.id && options.corpId) {
articleId = options.id;
corpId = options.corpId;
loadArticle();
} else {
error.value = '文章信息不完整';
loading.value = false;
}
});
</script>
<style scoped lang="scss">
.article-detail-page {
width: 100%;
height: 100vh;
background-color: #fff;
}
.loading-container,
.error-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
padding: 40rpx;
}
.loading-text {
margin-top: 20rpx;
font-size: 28rpx;
color: #999;
}
.error-text {
font-size: 28rpx;
color: #999;
margin-bottom: 30rpx;
text-align: center;
}
.retry-btn {
padding: 16rpx 60rpx;
background-color: #0877F1;
color: #fff;
border: none;
border-radius: 8rpx;
font-size: 28rpx;
}
.article-content {
height: 100vh;
}
.article-header {
padding: 40rpx 30rpx 20rpx;
border-bottom: 1px solid #eee;
}
.article-title {
display: block;
font-size: 36rpx;
font-weight: bold;
color: #333;
line-height: 1.6;
margin-bottom: 20rpx;
}
.article-date {
display: block;
font-size: 24rpx;
color: #999;
}
.article-body {
padding: 0;
}
.rich-text-wrapper {
padding: 30rpx;
width: 100%;
box-sizing: border-box;
overflow: hidden;
}
.rich-text-wrapper ::v-deep rich-text {
width: 100%;
}
.rich-text-wrapper ::v-deep rich-text img {
max-width: 100% !important;
height: auto !important;
display: block;
}
</style>

View File

@ -19,10 +19,10 @@
v-for="cate in categoryList"
:key="cate._id || 'all'"
class="category-item"
:class="{ active: currentCateId === (cate._id || 'all') }"
:class="{ active: currentCateId === cate._id }"
@click="selectCategory(cate)"
>
{{ cate.name }}
{{ cate.label }}
</view>
</scroll-view>
</view>
@ -54,19 +54,19 @@
>
<view class="article-content" @click="previewArticle(article)">
<text class="article-title">{{ article.title }}</text>
<text class="article-date">创建时间{{ article.date }}</text>
</view>
<view class="article-action">
<view class="article-footer">
<text class="article-date">{{ article.date }}</text>
<button
class="send-btn"
size="mini"
type="primary"
@click="sendArticle(article)"
@click.stop="sendArticle(article)"
>
发送
</button>
</view>
</view>
</view>
<view v-if="loading && articleList.length > 0" class="loading-more">
<uni-icons type="spinner-cycle" size="20" color="#999" />
@ -75,8 +75,7 @@
<view
v-if="!loading && articleList.length >= total"
class="no-more"
>
class="no-more">
没有更多了
</view>
</view>
@ -94,7 +93,9 @@
</view>
</view>
<scroll-view scroll-y class="preview-content">
<view class="rich-text-wrapper">
<rich-text :nodes="previewArticleData.content"></rich-text>
</view>
</scroll-view>
<view class="preview-footer">
<button class="preview-close-btn" @click="closePreview">关闭</button>
@ -120,8 +121,8 @@ const searchTitle = ref("");
let searchTimer = null;
//
const categoryList = ref([{ _id: "", name: "全部" }]);
const currentCateId = ref("");
const categoryList = ref([{ _id: "", label: "全部" }]);
const currentCateId = ref(""); // ""_id
//
const articleList = ref([]);
@ -143,7 +144,7 @@ const getCategoryList = async () => {
const res = await getArticleCateList({ corpId: corpId });
if (res.success && res.list) {
const cates = res.list || [];
categoryList.value = [{ _id: "", name: "全部" }, ...cates];
categoryList.value = [{ _id: "", label: "全部" }, ...cates];
}
} catch (error) {
console.error("获取分类列表失败:", error);
@ -238,6 +239,36 @@ const loadMore = () => {
loadArticleList();
};
// 使
const processRichTextContent = (html) => {
if (!html) return '';
// img
let processedHtml = html.replace(
/<img/gi,
'<img style="max-width:100%;height:auto;display:block;margin:10px 0;"'
);
//
processedHtml = processedHtml.replace(
/style="[^"]*width:\s*\d+px[^"]*"/gi,
(match) => {
return match.replace(/width:\s*\d+px;?/gi, 'max-width:100%;');
}
);
//
processedHtml = processedHtml.replace(
/<table/gi,
'<table style="max-width:100%;overflow-x:auto;display:block;"'
);
//
processedHtml = `<div style="width:100%;overflow-x:hidden;word-wrap:break-word;word-break:break-all;">${processedHtml}</div>`;
return processedHtml;
};
//
const previewArticle = async (article) => {
try {
@ -248,7 +279,7 @@ const previewArticle = async (article) => {
if (res.success && res.data) {
previewArticleData.value = {
title: res.data.title || article.title,
content: res.data.content || "",
content: processRichTextContent(res.data.content || ""),
};
previewPopup.value?.open();
} else {
@ -358,18 +389,20 @@ onMounted(() => {
}
.category-item {
padding: 32rpx 24rpx;
padding: 20rpx 24rpx;
font-size: 28rpx;
color: #333;
text-align: center;
border-bottom: 1px solid #eee;
transition: all 0.3s ease;
position: relative;
}
.category-item.active {
background-color: #fff;
color: #1890ff;
color: #0877F1;
font-weight: bold;
border-left: 4rpx solid #1890ff;
border-left: 4rpx solid #0877F1;
}
.article-list {
@ -397,39 +430,48 @@ onMounted(() => {
}
.article-item {
display: flex;
align-items: center;
padding: 24rpx 30rpx;
border-bottom: 1px solid #eee;
transition: background-color 0.2s ease;
}
.article-item:active {
background-color: #f5f5f5;
}
.article-content {
flex: 1;
display: flex;
flex-direction: column;
margin-right: 20rpx;
gap: 16rpx;
}
.article-title {
font-size: 28rpx;
color: #333;
line-height: 1.5;
line-height: 1.6;
word-break: break-all;
margin-bottom: 12rpx;
font-weight: 500;
}
.article-footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 20rpx;
}
.article-date {
flex: 1;
font-size: 24rpx;
color: #999;
}
.article-action {
flex-shrink: 0;
}
.send-btn {
padding: 8rpx 32rpx;
flex-shrink: 0;
font-size: 26rpx;
padding: 8rpx 32rpx;
height: auto;
line-height: 1.4;
}
.loading-more,
@ -486,10 +528,28 @@ onMounted(() => {
.preview-content {
flex: 1;
padding: 30rpx;
padding: 0;
overflow-y: auto;
}
.rich-text-wrapper {
padding: 30rpx;
width: 100%;
box-sizing: border-box;
overflow: hidden;
}
/* rich-text 内部样式 */
.rich-text-wrapper ::v-deep rich-text {
width: 100%;
}
.rich-text-wrapper ::v-deep rich-text img {
max-width: 100% !important;
height: auto !important;
display: block;
}
.preview-footer {
padding: 20rpx;
border-top: 1px solid #eee;

View File

@ -136,7 +136,7 @@ $primary-color: #0877F1;
.message-list {
padding: 0 16rpx;
padding-bottom: 20rpx;
padding-bottom: 60rpx; /* 增加底部内边距,防止被小程序底部横线遮挡 */
}
.message-item {
@ -350,10 +350,10 @@ $primary-color: #0877F1;
flex: 1;
padding: 0 46rpx;
background-color: #f3f5fa;
border-radius: 50rpx;
border-radius: 20rpx;
margin: 0 16rpx;
font-size: 28rpx;
height: 96rpx;
height: 80rpx;
border: none;
outline: none;
box-sizing: border-box;
@ -372,8 +372,8 @@ $primary-color: #0877F1;
justify-content: flex-start;
background: #fff;
border-top: 1rpx solid #eee;
padding: 20rpx 0 8rpx 60rpx;
gap: 40rpx;
padding: 20rpx 0 40rpx 60rpx;
gap: 40rpx 50rpx;
flex-wrap: wrap;
background-color: #f5f5f5;
}

View File

@ -621,7 +621,7 @@ onMounted(() => {
<style scoped lang="scss">
// 使
$primary-color: #0877f1;
$primary-color: #0877F1;
$primary-light: #e8f3ff;
$primary-gradient-start: #1b5cc8;
$primary-gradient-end: #0877f1;

View File

@ -76,7 +76,7 @@ const props = defineProps({
});
// Emits
const emit = defineEmits(["messageSent", "scrollToBottom"]);
const emit = defineEmits(["messageSent", "scrollToBottom", "endConsult"]);
//
const inputText = ref("");
@ -375,6 +375,24 @@ const goToSurveyList = () => {
});
};
//
const handleEndConsult = () => {
uni.showModal({
title: '确认结束问诊',
content: '确定要结束本次问诊吗?结束后将无法继续对话。',
confirmText: '确定结束',
cancelText: '取消',
success: (res) => {
if (res.confirm) {
//
showMorePanel.value = false;
//
emit('endConsult');
}
}
});
};
const morePanelButtons = [
{ text: "照片", icon: "/static/icon/zhaopian.png", action: showImagePicker },
{
@ -400,7 +418,7 @@ const morePanelButtons = [
{
text: "结束问诊",
icon: "/static/icon/jieshuzixun.png",
action: showImagePicker,
action: handleEndConsult,
},
];

View File

@ -242,12 +242,22 @@ const getArticleData = (message) => {
const handleArticleClick = (message) => {
const articleData = getArticleData(message);
if (articleData.url) {
//
//
console.log('打开文章:', articleData.url);
// uni.navigateTo({
// url: `/pages/article/detail?url=${encodeURIComponent(articleData.url)}`
// });
// IDcorpId
const urlParams = new URLSearchParams(articleData.url.split('?')[1]);
const articleId = urlParams.get('id');
const corpId = urlParams.get('corpId');
if (articleId && corpId) {
//
uni.navigateTo({
url: `/pages/message/article-detail?id=${articleId}&corpId=${corpId}`
});
} else {
// ID使webview
uni.navigateTo({
url: `/pages/webview/webview?url=${encodeURIComponent(articleData.url)}`
});
}
}
};

View File

@ -134,6 +134,7 @@
:formatTime="formatTime"
@scrollToBottom="() => scrollToBottom(true)"
@messageSent="() => scrollToBottom(true)"
@endConsult="handleEndConsult"
/>
</view>
</template>
@ -161,7 +162,7 @@ import {
handleViewDetail,
checkIMConnectionStatus,
} from "@/utils/chat-utils.js";
import { sendConsultRejectedMessage } from "@/utils/api.js";
import { sendConsultRejectedMessage, endConsultation } from "@/utils/api.js";
import useGroupChat from "./hooks/use-group-chat";
import MessageTypes from "./components/message-types.vue";
import ChatInput from "./components/chat-input.vue";
@ -223,27 +224,28 @@ function isSystemMessage(message) {
try {
// payload.data
if (message.payload?.data) {
const data = typeof message.payload.data === 'string'
const data =
typeof message.payload.data === "string"
? JSON.parse(message.payload.data)
: message.payload.data;
//
if (data.type === 'system_message') {
if (data.type === "system_message") {
return true;
}
}
// description
if (message.payload?.description === '系统消息标记') {
if (message.payload?.description === "系统消息标记") {
return true;
}
//
if (message.payload?.description === 'SYSTEM_NOTIFICATION') {
if (message.payload?.description === "SYSTEM_NOTIFICATION") {
return true;
}
} catch (error) {
console.error('判断系统消息失败:', error);
console.error("判断系统消息失败:", error);
}
return false;
@ -257,26 +259,32 @@ function checkConsultPendingStatus() {
if (message.type === "TIMCustomElem" && message.payload?.data) {
try {
const data = typeof message.payload.data === 'string'
const data =
typeof message.payload.data === "string"
? JSON.parse(message.payload.data)
: message.payload.data;
// consult_pending
if (data.type === 'system_message' && data.messageType === 'consult_pending') {
if (
data.type === "system_message" &&
data.messageType === "consult_pending"
) {
showConsultAccept.value = true;
return;
}
//
if (data.type === 'system_message' &&
(data.messageType === 'consult_accepted' ||
data.messageType === 'consult_ended' ||
data.messageType === 'consult_rejected')) {
//
if (
data.type === "system_message" &&
(data.messageType === "consult_accepted" ||
data.messageType === "consult_ended" ||
data.messageType === "consult_rejected")
) {
showConsultAccept.value = false;
return;
}
} catch (error) {
console.error('解析系统消息失败:', error);
console.error("解析系统消息失败:", error);
}
}
}
@ -310,6 +318,7 @@ onLoad((options) => {
if (options.userID) {
chatInfo.value.userID = options.userID;
}
checkLoginAndInitTIM();
updateNavigationTitle();
});
@ -703,23 +712,23 @@ defineExpose({
const handleAcceptConsult = async () => {
try {
uni.showLoading({
title: '处理中...',
title: "处理中...",
});
//
const customMessage = {
data: JSON.stringify({
type: 'system_message',
messageType: 'consult_accepted',
content: '医生已接诊',
type: "system_message",
messageType: "consult_accepted",
content: "医生已接诊",
timestamp: Date.now(),
}),
description: '系统消息标记',
extension: '',
description: "系统消息标记",
extension: "",
};
const message = timChatManager.tim.createCustomMessage({
to: chatInfo.value.conversationID.replace('GROUP', ''),
to: chatInfo.value.conversationID.replace("GROUP", ""),
conversationType: timChatManager.TIM.TYPES.CONV_GROUP,
payload: customMessage,
});
@ -730,18 +739,18 @@ const handleAcceptConsult = async () => {
showConsultAccept.value = false;
uni.hideLoading();
uni.showToast({
title: '已接受问诊',
icon: 'success',
title: "已接受问诊",
icon: "success",
});
} else {
throw new Error(sendResult.message || '发送失败');
throw new Error(sendResult.message || "发送失败");
}
} catch (error) {
console.error('接受问诊失败:', error);
console.error("接受问诊失败:", error);
uni.hideLoading();
uni.showToast({
title: error.message || '操作失败',
icon: 'none',
title: error.message || "操作失败",
icon: "none",
});
}
};
@ -758,14 +767,14 @@ const handleRejectReasonConfirm = async (reason) => {
showRejectReasonModal.value = false;
uni.showLoading({
title: '处理中...',
title: "处理中...",
});
//
const memberName = account.value?.name || '医生';
const memberName = account.value?.name || "医生";
// ID
const groupId = chatInfo.value.conversationID.replace('GROUP', '');
const groupId = chatInfo.value.conversationID.replace("GROUP", "");
//
const result = await sendConsultRejectedMessage({
@ -779,18 +788,18 @@ const handleRejectReasonConfirm = async (reason) => {
if (result.success) {
showConsultAccept.value = false;
uni.showToast({
title: '已拒绝问诊',
icon: 'success',
title: "已拒绝问诊",
icon: "success",
});
} else {
throw new Error(result.message || '发送失败');
throw new Error(result.message || "发送失败");
}
} catch (error) {
console.error('拒绝问诊失败:', error);
console.error("拒绝问诊失败:", error);
uni.hideLoading();
uni.showToast({
title: error.message || '操作失败',
icon: 'none',
title: error.message || "操作失败",
icon: "none",
});
}
};
@ -800,6 +809,44 @@ const handleRejectReasonCancel = () => {
showRejectReasonModal.value = false;
};
//
const handleEndConsult = async () => {
try {
uni.showLoading({
title: "处理中...",
});
// groupId
const result = await endConsultation({
groupId: groupId.value,
adminAccount: account.value?.userId || "",
extraData: {
endBy: account.value?.userId || "",
endByName: account.value?.name || "医生",
endReason: "问诊完成",
},
});
uni.hideLoading();
if (result.success) {
uni.showToast({
title: "问诊已结束",
icon: "success",
});
} else {
throw new Error(result.message || "操作失败");
}
} catch (error) {
console.error("结束问诊失败:", error);
uni.hideLoading();
uni.showToast({
title: error.message || "操作失败",
icon: "none",
});
}
};
//
onUnmounted(() => {
clearMessageCache();
@ -841,10 +888,10 @@ uni.$on("sendArticle", async (data) => {
data: JSON.stringify({
type: "article",
title: article.title || "宣教文章",
desc: "宣教文章",
desc: "点击查看详情",
url: articleUrl,
imgUrl:
"https://796f-youcan-clouddev-1-8ewcqf31dbb2b5-1317294507.tcb.qcloud.la/other/19-%E9%97%AE%E5%8D%B7.png?sign=55a4cd77c418b2c548b65792a2cf6bce&t=1701328694",
imgUrl: "https://796f-youcan-clouddev-1-8ewcqf31dbb2b5-1317294507.tcb.qcloud.la/other/article-icon.png",
articleId: article._id
}),
description: "ARTICLE",
extension: "",

View File

@ -3,7 +3,12 @@
<view class="header">
<view class="search-bar">
<uni-icons type="search" size="18" color="#999" />
<input class="search-input" v-model="searchName" placeholder="输入问卷名称搜索" @input="handleSearch" />
<input
class="search-input"
v-model="searchName"
placeholder="输入问卷名称搜索"
@input="handleSearch"
/>
</view>
</view>
@ -14,10 +19,10 @@
v-for="cate in categoryList"
:key="cate._id || 'all'"
class="category-item"
:class="{ active: currentCateId === (cate._id || 'all') }"
:class="{ active: currentCateId === cate._id }"
@click="selectCategory(cate)"
>
{{ cate.name }}
{{ cate.label }}
</view>
</scroll-view>
</view>
@ -29,7 +34,10 @@
@scrolltolower="loadMore"
lower-threshold="50"
>
<view v-if="loading && surveyList.length === 0" class="loading-container">
<view
v-if="loading && surveyList.length === 0"
class="loading-container"
>
<uni-icons type="spinner-cycle" size="30" color="#999" />
<text class="loading-text">加载中...</text>
</view>
@ -46,10 +54,17 @@
>
<view class="survey-content" @click="previewSurvey(survey)">
<text class="survey-title">{{ survey.name }}</text>
<text class="survey-desc">{{ survey.description || '暂无问卷说明' }}</text>
<text class="survey-desc">{{
survey.description || "暂无问卷说明"
}}</text>
</view>
<view class="survey-action">
<button class="send-btn" size="mini" type="primary" @click="sendSurvey(survey)">
<button
class="send-btn"
size="mini"
type="primary"
@click="sendSurvey(survey)"
>
发送
</button>
</view>
@ -67,31 +82,31 @@
</scroll-view>
</view>
</view>
<view class="footer">
<button class="cancel-btn" @click="goBack">取消</button>
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { getSurveyCateList, getSurveyList, createSurveyRecord } from '@/utils/api.js';
import useAccountStore from '@/store/account.js';
import EmptyData from '@/components/empty-data.vue';
import { ref, onMounted } from "vue";
import {
getSurveyCateList,
getSurveyList,
createSurveyRecord,
} from "@/utils/api.js";
import useAccountStore from "@/store/account.js";
import EmptyData from "@/components/empty-data.vue";
const env = __VITE_ENV__;
const accountStore = useAccountStore();
const corpId = env.MP_CORP_ID;
const userId = ref('');
const userId = ref("");
//
const searchName = ref('');
const searchName = ref("");
let searchTimer = null;
//
const categoryList = ref([{ _id: '', name: '全部' }]);
const currentCateId = ref('');
const categoryList = ref([{ _id: "", label: "全部" }]);
const currentCateId = ref("");
//
const surveyList = ref([]);
@ -99,27 +114,24 @@ const loading = ref(false);
const page = ref(1);
const pageSize = 30;
const total = ref(0);
const emptyText = ref('');
const emptyText = ref("");
//
const getCategoryList = async () => {
try {
const res = await getSurveyCateList({ corpId: corpId });
if (res.success && res.data) {
const cates = res.data.list || [];
categoryList.value = [
{ _id: '', name: '全部' },
...cates
];
if (res.success && res.list) {
const cates = res.list || [];
categoryList.value = [{ _id: "", label: "全部" }, ...cates];
}
} catch (error) {
console.error('获取分类列表失败:', error);
console.error("获取分类列表失败:", error);
}
};
//
const selectCategory = (cate) => {
currentCateId.value = cate._id || '';
currentCateId.value = cate._id || "";
page.value = 1;
surveyList.value = [];
loadSurveyList();
@ -148,8 +160,8 @@ const loadSurveyList = async () => {
page: page.value,
pageSize: pageSize,
name: searchName.value.trim(),
status: 'enable',
showCount: false
status: "enable",
showCount: false,
};
// ID
@ -158,8 +170,8 @@ const loadSurveyList = async () => {
}
const res = await getSurveyList(params);
if (res.success && res.data) {
const { list = [], total: count = 0 } = res.data;
if (res.success && res) {
const { list = [], total: count = 0 } = res;
if (page.value === 1) {
surveyList.value = list;
@ -167,20 +179,20 @@ const loadSurveyList = async () => {
surveyList.value = [...surveyList.value, ...list];
}
total.value = count;
emptyText.value = '暂无问卷信息';
emptyText.value = "暂无问卷信息";
} else {
emptyText.value = res.message || '加载失败';
emptyText.value = res.message || "加载失败";
uni.showToast({
title: res.message || '获取问卷列表失败',
icon: 'none'
title: res.message || "获取问卷列表失败",
icon: "none",
});
}
} catch (error) {
console.error('加载问卷列表失败:', error);
emptyText.value = '加载失败';
console.error("加载问卷列表失败:", error);
emptyText.value = "加载失败";
uni.showToast({
title: '加载失败,请重试',
icon: 'none'
title: "加载失败,请重试",
icon: "none",
});
} finally {
loading.value = false;
@ -196,17 +208,29 @@ const loadMore = () => {
//
const previewSurvey = (survey) => {
//
uni.showToast({
title: '预览功能开发中',
icon: 'none'
const timestamp = Date.now();
const previewUrl = `https://www.youcan365.com/surveyDev/#/pages/survey/survey?surveyId=${survey.surveyId}&t=${timestamp}`;
// #ifdef H5
window.open(previewUrl, '_blank');
// #endif
// #ifdef MP-WEIXIN
uni.navigateTo({
url: `/pages/webview/webview?url=${encodeURIComponent(previewUrl)}`
});
// #endif
// #ifdef APP-PLUS
plus.runtime.openURL(previewUrl);
// #endif
};
//
const generateRandomString = (length) => {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
const chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let result = "";
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
@ -233,28 +257,27 @@ const sendSurvey = async (survey) => {
//
// 使
uni.$emit('sendSurvey', {
uni.$emit("sendSurvey", {
survey: survey,
corpId: corpId,
userId: userId.value,
sendSurveyId: sendSurveyId
sendSurveyId: sendSurveyId,
});
uni.showToast({
title: '已选择问卷',
icon: 'success'
title: "已选择问卷",
icon: "success",
});
//
setTimeout(() => {
uni.navigateBack();
}, 500);
} catch (error) {
console.error('发送问卷失败:', error);
console.error("发送问卷失败:", error);
uni.showToast({
title: error.message || '发送失败',
icon: 'none'
title: error.message || "发送失败",
icon: "none",
});
} finally {
loading.value = false;
@ -315,20 +338,21 @@ onMounted(() => {
.category-scroll {
height: 100%;
}
.category-item {
padding: 32rpx 24rpx;
padding: 20rpx 24rpx;
font-size: 28rpx;
color: #333;
text-align: center;
border-bottom: 1px solid #eee;
transition: all 0.3s ease;
position: relative;
}
.category-item.active {
background-color: #fff;
color: #1890ff;
color: #0877f1;
font-weight: bold;
border-left: 4rpx solid #1890ff;
border-left: 4rpx solid #0877f1;
}
.survey-list {
@ -393,7 +417,6 @@ onMounted(() => {
}
.send-btn {
padding: 8rpx 32rpx;
font-size: 26rpx;
}

24
pages/webview/webview.vue Normal file
View File

@ -0,0 +1,24 @@
<template>
<view class="webview-container">
<web-view :src="url"></web-view>
</view>
</template>
<script setup>
import { onLoad } from "@dcloudio/uni-app";
import { ref } from "vue";
const url = ref("");
onLoad((options) => {
if (options.url) {
url.value = decodeURIComponent(options.url);
}
});
</script>
<style scoped>
.webview-container {
width: 100%;
height: 100vh;
}
</style>

58
styles/theme.scss Normal file
View File

@ -0,0 +1,58 @@
/**
* 项目主题色配置
* 统一管理项目中使用的主题色
*/
// 主题色
$primary-color: #0877F1;
$primary-light: #e8f3ff;
$primary-dark: #0660c9;
$primary-gradient-start: #1b5cc8;
$primary-gradient-end: #0877F1;
// 辅助色
$success-color: #4cd964;
$warning-color: #f0ad4e;
$error-color: #dd524d;
$info-color: #909399;
// 文字颜色
$text-color-primary: #333;
$text-color-regular: #666;
$text-color-secondary: #999;
$text-color-placeholder: #c0c4cc;
$text-color-white: #fff;
// 背景颜色
$bg-color-white: #ffffff;
$bg-color-page: #f5f5f5;
$bg-color-hover: #f1f1f1;
$bg-color-mask: rgba(0, 0, 0, 0.4);
// 边框颜色
$border-color-base: #e4e7ed;
$border-color-light: #ebeef5;
$border-color-lighter: #f2f6fc;
// 圆角
$border-radius-small: 4rpx;
$border-radius-base: 8rpx;
$border-radius-large: 16rpx;
$border-radius-round: 999rpx;
// 间距
$spacing-small: 16rpx;
$spacing-base: 24rpx;
$spacing-large: 32rpx;
// 字体大小
$font-size-small: 24rpx;
$font-size-base: 28rpx;
$font-size-medium: 32rpx;
$font-size-large: 36rpx;
$font-size-xlarge: 40rpx;
// 阴影
$box-shadow-light: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
$box-shadow-base: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
$box-shadow-dark: 0 8rpx 24rpx rgba(0, 0, 0, 0.12);

View File

@ -15,7 +15,7 @@
/* 颜色变量 */
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-primary: #0877F1;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;

View File

@ -61,7 +61,9 @@ const urlsConfig = {
getUserSig: 'getUserSig',
sendSystemMessage: "sendSystemMessage",
getChatRecordsByGroupId: "getChatRecordsByGroupId",
sendConsultRejectedMessage: "sendConsultRejectedMessage"
sendConsultRejectedMessage: "sendConsultRejectedMessage",
endConsultation: "endConsultation",
getGroupListByGroupId: "getGroupListByGroupId"
}
}
@ -141,3 +143,19 @@ export async function sendConsultRejectedMessage(data) {
}
});
}
// 结束问诊接口
export async function endConsultation(data) {
return request({
url: '/getYoucanData/im',
data: {
type: 'endConsultation',
...data
}
});
}
// 根据群组ID获取群组记录
export async function getGroupListByGroupId(data) {
return api('getGroupListByGroupId', data);
}