ykt-wxapp/pages/message/survey-list.vue

561 lines
12 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>
<view class="survey-page">
<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"
/>
</view>
</view>
<view class="content">
<view class="category-sidebar">
<scroll-view scroll-y class="category-scroll">
<view
v-for="cate in categoryList"
:key="cate._id || 'all'"
class="category-item"
:class="{ active: currentCateId === cate._id }"
@click="selectCategory(cate)"
>
{{ cate.label }}
</view>
</scroll-view>
</view>
<view class="survey-list">
<scroll-view
scroll-y
class="survey-scroll"
@scrolltolower="loadMore"
lower-threshold="50"
>
<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>
<view v-else-if="surveyList.length === 0" class="empty-container">
<empty-data :title="emptyText || '暂无问卷'" />
</view>
<view v-else>
<view
v-for="survey in surveyList"
:key="survey._id"
class="survey-item"
>
<view class="survey-content" @click="previewSurvey(survey)">
<text class="survey-title">{{ survey.name }}</text>
<text class="survey-desc">{{
survey.description || "暂无问卷说明"
}}</text>
</view>
<view class="survey-action">
<button
class="send-btn"
size="mini"
type="primary"
@click="handlePrimaryAction(survey)"
>
{{ isSelectMode ? '选择' : '发送' }}
</button>
</view>
</view>
<view v-if="loading && surveyList.length > 0" class="loading-more">
<uni-icons type="spinner-cycle" size="20" color="#999" />
<text>加载中...</text>
</view>
<view v-if="!loading && surveyList.length >= total" class="no-more">
没有更多了
</view>
</view>
</scroll-view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from "vue";
import api from "@/utils/api.js";
import useAccountStore from "@/store/account.js";
import { globalTimChatManager } from "@/utils/tim-chat.js";
import EmptyData from "@/components/empty-data.vue";
import { onLoad } from "@dcloudio/uni-app";
const env = __VITE_ENV__;
const accountStore = useAccountStore();
const corpId = env.MP_CORP_ID;
const userId = ref("");
const timChatManager = globalTimChatManager;
// 从上一页传递的客户信息
const customerId = ref("");
const customerName = ref("");
// 搜索关键词
const searchName = ref("");
let searchTimer = null;
// 分类列表
const categoryList = ref([{ _id: "", label: "全部" }]);
const currentCateId = ref("");
// 问卷列表
const surveyList = ref([]);
const loading = ref(false);
const page = ref(1);
const pageSize = 30;
const total = ref(0);
const emptyText = ref("");
const isSelectMode = ref(false);
const selectEventName = ref("");
// 页面加载时接收参数
onLoad((options) => {
isSelectMode.value = String(options?.select || '') === '1';
selectEventName.value = String(options?.eventName || '');
customerId.value = options?.patientId || "";
customerName.value = options?.customerName || "";
getCategoryList();
loadSurveyList();
});
const selectSurvey = (survey) => {
if (!selectEventName.value) {
uni.showToast({ title: "缺少 eventName", icon: "none" });
return;
}
uni.$emit(selectEventName.value, survey);
uni.navigateBack();
};
const handlePrimaryAction = (survey) => {
if (isSelectMode.value) return selectSurvey(survey);
return sendSurvey(survey);
};
// 获取分类列表
const getCategoryList = async () => {
try {
const res = await api("getSurveyCateList", { corpId: corpId });
if (res.success && res.list) {
const cates = res.list || [];
categoryList.value = [{ _id: "", label: "全部" }, ...cates];
}
} catch (error) {
console.error("获取分类列表失败:", error);
}
};
// 选择分类
const selectCategory = (cate) => {
currentCateId.value = cate._id || "";
page.value = 1;
surveyList.value = [];
loadSurveyList();
};
// 搜索处理
const handleSearch = () => {
if (searchTimer) {
clearTimeout(searchTimer);
}
searchTimer = setTimeout(() => {
page.value = 1;
surveyList.value = [];
loadSurveyList();
}, 500);
};
// 加载问卷列表
const loadSurveyList = async () => {
if (loading.value) return;
loading.value = true;
try {
const params = {
corpId: corpId,
page: page.value,
pageSize: pageSize,
name: searchName.value.trim(),
status: "enable",
showCount: false,
};
// 如果选择了分类添加分类ID
if (currentCateId.value) {
params.cateIds = [currentCateId.value];
}
const res = await api("getSurveyList", params);
if (res.success && res) {
const { list = [], total: count = 0 } = res;
if (page.value === 1) {
surveyList.value = list;
} else {
surveyList.value = [...surveyList.value, ...list];
}
total.value = count;
emptyText.value = "暂无问卷信息";
} else {
emptyText.value = res.message || "加载失败";
uni.showToast({
title: res.message || "获取问卷列表失败",
icon: "none",
});
}
} catch (error) {
console.error("加载问卷列表失败:", error);
emptyText.value = "加载失败";
uni.showToast({
title: "加载失败,请重试",
icon: "none",
});
} finally {
loading.value = false;
}
};
// 加载更多
const loadMore = () => {
if (loading.value || surveyList.value.length >= total.value) return;
page.value += 1;
loadSurveyList();
};
// 预览问卷
const previewSurvey = (survey) => {
if (!survey.surveryId) {
uni.showToast({
title: "问卷ID不存在",
icon: "none",
});
return;
}
const timestamp = Date.now();
const previewUrl = `https://www.youcan365.com/surveyDev/#/pages/survey/survey?surveryId=${survey.surveryId}&t=${timestamp}`;
// #ifdef H5
window.open(previewUrl, "_blank");
// #endif
// #ifdef MP-WEIXIN
uni.navigateTo({
url: `/pages/webview/webview?url=${encodeURIComponent(previewUrl)}`,
fail: (err) => {
console.error("导航失败:", err);
uni.showToast({
title: "打开失败,请重试",
icon: "none",
});
},
});
// #endif
// #ifdef APP-PLUS
plus.runtime.openURL(previewUrl);
// #endif
};
// 生成随机字符串
const generateRandomString = (length) => {
const chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let result = "";
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
};
// 生成发送链接
const generateSendLink = (
survey,
answerId,
customerId,
customerName,
sendSurveyId
) => {
const isSystem = survey.createBy === "system";
let url = "";
if (isSystem) {
// 系统问卷:使用 VITE_SURVEY_URL
url = `${env.MP_SURVEY_URL}?corpId=${corpId}&surveryId=${survey.surveryId}&memberId=${customerId}&sendSurveyId=${sendSurveyId}&userId=${userId.value}`;
} else {
url = `${
env.MP_PATIENT_PAGE_BASE_URL
}pages/survery/fill?corpId=${corpId}&surveryId=${
survey._id
}&memberId=${customerId}&unionid=unionid&answerId=${answerId}&name=${
customerName || ""
}`;
}
return url;
};
// 构建问卷自定义消息
const buildSurveyMessage = (survey, surveyLink) => {
return {
data: JSON.stringify({
type: "survey",
title: survey.name || "填写问卷",
desc: "请填写问卷",
url: surveyLink,
imgUrl:
"https://796f-youcan-clouddev-1-8ewcqf31dbb2b5-1317294507.tcb.qcloud.la/other/19-%E9%97%AE%E5%8D%B7.png?sign=55a4cd77c418b2c548b65792a2cf6bce&t=1701328694",
}),
description: "SURVEY",
extension: "",
};
};
// 发送问卷
const sendSurvey = async (survey) => {
if (loading.value) return;
try {
loading.value = true;
// 获取医生信息
const doctorInfo = accountStore.doctorInfo;
userId.value = doctorInfo?.userid;
// 生成发送ID
const sendSurveyId = generateRandomString(10);
// 创建问卷记录
const createRecordRes = await api("createSurveyRecord", {
corpId: corpId,
userId: userId.value,
surveryId: survey._id,
memberId: customerId.value,
customer: customerName.value,
sendSurveyId: sendSurveyId,
});
if (!createRecordRes.success) {
uni.showToast({
title: createRecordRes.message || "创建问卷记录失败",
icon: "none",
});
loading.value = false;
return;
}
const answerId = createRecordRes?.id || "";
// 生成发送链接
const sendLink = generateSendLink(
survey,
answerId,
customerId.value,
customerName.value,
sendSurveyId
);
// 构建自定义消息
const customMessage = buildSurveyMessage(survey, sendLink);
// 发送自定义消息到IM
const result = await timChatManager.sendCustomMessage(
customMessage,
"SURVEY"
);
if (result.success) {
uni.showToast({
title: "发送成功",
icon: "success",
});
// 延迟返回
setTimeout(() => {
uni.navigateBack();
}, 500);
} else {
throw new Error(result.error || "发送失败");
}
} catch (error) {
console.error("发送问卷失败:", error);
uni.showToast({
title: error.message || "发送失败",
icon: "none",
});
} finally {
loading.value = false;
}
};
// 返回
const goBack = () => {
uni.navigateBack();
};
onMounted(() => {
getCategoryList();
loadSurveyList();
});
</script>
<style scoped lang="scss">
.survey-page {
display: flex;
flex-direction: column;
height: 100vh;
background-color: #f5f5f5;
}
.header {
background-color: #fff;
padding: 20rpx;
border-bottom: 1px solid #eee;
}
.search-bar {
display: flex;
align-items: center;
background-color: #f5f5f5;
border-radius: 8rpx;
padding: 16rpx 24rpx;
}
.search-input {
flex: 1;
margin-left: 16rpx;
font-size: 28rpx;
}
.content {
flex: 1;
display: flex;
overflow: hidden;
}
.category-sidebar {
width: 200rpx;
background-color: #f8f8f8;
border-right: 1px solid #eee;
}
.category-scroll {
height: 100%;
}
.category-item {
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: #0877f1;
font-weight: bold;
border-left: 4rpx solid #0877f1;
}
.survey-list {
flex: 1;
background-color: #fff;
}
.survey-scroll {
height: 100%;
}
.loading-container,
.empty-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
}
.loading-text {
margin-top: 20rpx;
font-size: 28rpx;
color: #999;
}
.survey-item {
display: flex;
align-items: center;
padding: 24rpx 30rpx;
border-bottom: 1px solid #eee;
}
.survey-content {
flex: 1;
display: flex;
flex-direction: column;
margin-right: 20rpx;
}
.survey-title {
font-size: 28rpx;
color: #333;
font-weight: 500;
line-height: 1.5;
margin-bottom: 12rpx;
}
.survey-desc {
font-size: 24rpx;
color: #999;
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.survey-action {
flex-shrink: 0;
}
.send-btn {
font-size: 26rpx;
}
.loading-more,
.no-more {
display: flex;
align-items: center;
justify-content: center;
padding: 30rpx 0;
font-size: 24rpx;
color: #999;
gap: 10rpx;
}
.footer {
background-color: #fff;
padding: 20rpx;
border-top: 1px solid #eee;
}
.cancel-btn {
width: 100%;
background-color: #fff;
color: #333;
border: 1px solid #ddd;
}
</style>