2025-09-23 19:00:32 +08:00

467 lines
10 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="page">
<!-- 顶部导航 -->
<navBar title="群发消息" />
<!-- 下拉刷新和上拉加载容器 -->
<scroll-view
class="scroll-container"
scroll-y
refresher-enabled
:refresher-triggered="refreshing"
@refresherrefresh="onRefresh"
@scrolltolower="onLoadMore"
:lower-threshold="100"
>
<!-- 卡片区域 -->
<view class="card-cell" v-if="list.length > 0" v-for="(item, index) in list" :key="item.uuid">
<view class="time-row">{{ item.msg_send_date }}</view>
<view class="card" >
<view class="card-body">
<view class="card-header">
<text class="label">{{ item.realname.split(',').length }}位患者</text>
<view class="close" @click="delGroupSendMsg(item)">
<text>×</text>
</view>
</view>
<view class="line" >
{{ item.realname }}
</view>
<view class="line phone" v-if="item.msg_type==1">
{{ item.msg_content }}
</view>
<view class="line phone" v-if="item.msg_type==3" @click="onDetail(item)">
<view class="custom">
<view class="title">{{JSON.parse(item.msg_content).summary }}</view>
<view class="row">
<view class="left">{{ docUrl+JSON.parse(item.msg_content).path }}</view>
<view class="right">
<image :src="docUrl+JSON.parse(item.msg_content).imgPath" ></image>
</view>
</view>
</view>
</view>
</view>
<view class="card-footer">
<view class="btn-outline" @click="onResend(item)">再发一条</view>
</view>
</view>
</view>
<!-- 空状态 -->
<view class="card" v-else>
<view class="card-header">
<text class="label">群发消息记录</text>
</view>
<view class="card-body">
<view class="line">暂无群发消息记录</view>
</view>
</view>
<!-- 加载状态 -->
<view class="loading-state" v-if="loading">
<text>加载中...</text>
</view>
<!-- 没有更多数据 -->
<view class="no-more" v-if="!hasMore && list.length > 0">
<text>没有更多数据了</text>
</view>
<!-- 占位滚动区域 -->
<view class="spacer" />
</scroll-view>
<!-- 底部按钮 -->
<view class="bottom-bar" @click="openModal">
<view class="btn-primary" >群发消息</view>
</view>
<!-- 弹窗与遮罩 -->
<view v-if="showModal" class="mask" @click="closeModal"></view>
<view v-if="showModal" class="center-modal">
<view class="modal-title">温馨提示</view>
<view class="modal-divider"></view>
<view class="modal-item" @click="onSelect('single')">
<text>单独选择</text>
</view>
<view class="modal-divider"></view>
<view class="modal-item" @click="onSelect('group')">
<text>分组选择</text>
</view>
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import navBar from '@/components/navBar/navBar.vue'
import api from '@/api/api.js'
import { onShow } from '@dcloudio/uni-app'
import docUrl from '@/utils/docUrl.js'
import navTo from '@/utils/navTo.js'
const currentTime = ref('')
const patientCount = ref(1)
const patientName = ref('测试')
const patientPhone = ref('155555555')
const showModal=ref(false);
const page=ref(1);
const list=ref([]);
const refreshing=ref(false);
const loading=ref(false);
const hasMore=ref(true);
const pad = (n) => (n < 10 ? `0${n}` : `${n}`)
// 格式化时间显示
const formatTime = (dateStr) => {
if (!dateStr) return ''
const date = new Date(dateStr)
const now = new Date()
const diff = now - date
// 如果是今天
if (diff < 24 * 60 * 60 * 1000 && date.getDate() === now.getDate()) {
return `${pad(date.getHours())}:${pad(date.getMinutes())}`
}
// 如果是昨天
else if (diff < 48 * 60 * 60 * 1000 && date.getDate() === now.getDate() - 1) {
return `昨天 ${pad(date.getHours())}:${pad(date.getMinutes())}`
}
// 其他情况显示完整日期
else {
return `${date.getMonth() + 1}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`
}
}
// 加载数据
const listGroupSendMsg=async(isRefresh = false)=>{
if(loading.value) return;
loading.value = true;
try {
const res=await api.listGroupSendMsg({
page: page.value,
});
if(res.code==200){
const newList = res.data.list || [];
if(isRefresh) {
// 下拉刷新,替换数据
list.value = newList;
} else {
// 上拉加载,追加数据
list.value = [...list.value, ...newList];
}
// 判断是否还有更多数据
hasMore.value = newList.length >= 10; // 假设每页10条数据
// 如果不是刷新,页码+1
if(!isRefresh) {
page.value++;
}
}
} catch (error) {
console.error('加载数据失败:', error);
uni.showToast({ title: '加载失败', icon: 'none' });
} finally {
loading.value = false;
}
};
// 下拉刷新
const onRefresh = async () => {
refreshing.value = true;
page.value = 1;
hasMore.value = true;
await listGroupSendMsg(true);
refreshing.value = false;
uni.showToast({ title: '刷新成功', icon: 'none' });
};
const onDetail = (item) => {
navTo({
url: `/pages_app/webview/webview?url=${encodeURIComponent(docUrl+JSON.parse(item.msg_content).path)}`,
})
}
// 上拉加载更多
const onLoadMore = async () => {
if(!hasMore.value || loading.value) return;
await listGroupSendMsg(false);
};
onMounted(() => {
})
onShow(() => {
listGroupSendMsg()
})
const onBack = () => {
uni.navigateBack()
}
const openModal = () => {
showModal.value = true;
};
const closeModal = () => {
showModal.value = false;
};
const onSelect = (type) => {
showModal.value = false;
if (type === 'single') {
navTo({
url: "/pages_app/selectPatient/selectPatient?from=chatMsg"
})
} else if (type === 'group') {
navTo({
url: '/pages_chat/patientGroup/patientGroup',
})
}
};
const delGroupSendMsg = (obj) => {
// 清空选择的患者(占位)
uni.showModal({
title: '提示',
content: '确定删除该群发消息吗?',
success: (res) => {
if(res.confirm){
api.delGroupSendMsg({
uuid: obj.uuid
}).then(res => {
if(res.code == 200){
uni.showToast({ title: '删除成功', icon: 'none' })
list.value = list.value.filter(item => obj.uuid != item.uuid)
}
})
}
}
})
}
const onResend = (obj) => {
let arr=[];
let idArr=obj.patient_uuid.split(',');
obj.realname.split(',').forEach((item,index) => {
arr.push({
uuid: idArr[index],
realName: item,
})
})
uni.setStorageSync('selectedChatPatientsSingle', {
patients: arr
});
navTo({
url: `/pages_chat/groupSend/groupSend?from=chatMsg`
})
}
const onSendGroup = () => {
uni.showToast({ title: '已触发群发', icon: 'none' })
}
</script>
<style lang="scss" scoped>
$page-bg: #f5f5f5;
$brand: #8B2316;
$brand-deep: #8B2316;
$primary: #00cbc0;
$red: #D32F2F;
.custom{
padding: 25rpx;
border-radius: 16rpx;
border: 2rpx solid #f0f0f0;
width:80%;
margin: 0 auto;
.title{
font-size: 32rpx;
color: #333;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
font-size: 32rpx;
}
.row{
margin-top: 20rpx;
display: flex;
align-items: center;
justify-content: space-between;
.left{
font-size: 24rpx;
color: #999;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
}
.right{
image{
width: 150rpx;
height: 150rpx;
margin-left: 20rpx;
}
}
}
}
/* 遮罩与弹窗 */
.mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.6);
z-index: 10;
}
.center-modal {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 650rpx;
background: #ffffff;
border-radius: 16rpx;
z-index: 11;
overflow: hidden;
box-shadow: 0 10rpx 40rpx rgba(0,0,0,0.15);
}
.modal-title {
text-align: center;
font-size: 34rpx;
color: #8B2316;
padding: 28rpx 20rpx;
}
.modal-item {
padding: 36rpx 28rpx;
font-size: 30rpx;
color: #333333;
background: #ffffff;
}
.modal-divider {
height: 2rpx;
background: #eeeeee;
}
.page {
background: $page-bg;
min-height: 100vh;
position: relative;
}
.nav {
height: 88rpx;
padding: 0 24rpx;
display: flex;
align-items: center;
background: #fff;
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.05);
.back { width: 80rpx; display: flex; align-items: center; }
.title { flex: 1; text-align: center; font-size: 34rpx; color: $red; font-weight: 600; }
.right { width: 80rpx; }
}
// 滚动容器样式
.scroll-container {
position: fixed;
top: 140rpx;
width:100%;
bottom: 107rpx;
}
.time-row {
text-align: center;
font-size: 32rpx;
padding: 32rpx 0;
color: #333;
}
// 加载状态样式
.loading-state {
text-align: center;
padding: 40rpx 0;
color: #999;
font-size: 28rpx;
}
.no-more {
text-align: center;
padding: 40rpx 0;
color: #ccc;
font-size: 24rpx;
}
.card-cell{
display: flex;
flex-direction: column;
margin: 0 30rpx;
box-sizing: border-box;
}
.card {
margin: 24rpx 0;
background: #fff;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.06);
overflow: hidden;
.card-header {
position: relative;
padding: 28rpx 28rpx 12rpx 28rpx;
.border { height: 2rpx; background: #eee; }
.label { font-size: 32rpx; color: #333; }
.close {
position: absolute;
right: -30rpx;
top: -36rpx;
width: 100rpx;
height: 100rpx;
border-bottom-left-radius: 100rpx;
background: #8B2316;
display: flex; align-items: center; justify-content: center;
text { color: #fff; font-size: 40rpx; font-weight: 500; }
}
}
.card-body {
padding: 20rpx 28rpx 8rpx 28rpx;
.line { font-size: 32rpx; color: #333; padding: 16rpx 0; }
.phone { font-size: 36rpx; }
}
.card-footer {
display: flex;
justify-content: flex-end;
padding: 16rpx 28rpx 28rpx 28rpx;
.btn-outline {
border: 2rpx solid $red;
color: $red;
padding: 10rpx 24rpx;
border-radius: 28rpx;
font-size: 28rpx;
}
}
}
.spacer { height: 200rpx; }
.bottom-bar {
position: fixed;
left: 0; right: 0; bottom: 0;
background: #00cbc0;
height: 100rpx;
display: flex;
align-items: center;
justify-content: center;
.btn-primary {
color: #fff;
font-size: 34rpx;
font-weight: 600;
}
}
</style>