消息服务

This commit is contained in:
wuyy 2026-09-02 17:46:05 +08:00
parent d924d02e71
commit e05e4c6556
9 changed files with 577 additions and 84 deletions

42
src/api/msg.ts Normal file
View File

@ -0,0 +1,42 @@
/**
* @file msg.ts
* @description: 消息系统
* @author: w
* @since: 2026-09-01
*/
import request from '@/utils/request'
// 查询消息列表
export function queryMsgList(query?: Object) {
return request({
url: '/bus/bloodbank/msg/queryMsgList',
method: 'get',
params: query
})
}
// 获取某个消息详情
export function getMsgInfo(query?: Object) {
return request({
url: '/bus/bloodbank/msg/queryOne',
method: 'get',
params: query
})
}
// 更新消息状态
export function updateMsgFlag(query?: Object) {
return request({
url: '/bus/bloodbank/msg/updateFlag',
method: 'get',
params: query
})
}
// 获取未读消息数量
export function queryNoReadCount(query?: Object) {
return request({
url: '/bus/bloodbank/msg/queryNoReadCount',
method: 'get',
params: query
})
}

View File

@ -0,0 +1,61 @@
<template>
<div>
<el-dialog v-model="dialogVisible" title="消息详情" width="600px" append-to-body :close-on-click-modal="false">
<div class="header">
<div class="title">{{ currentMsg.xkMsgMain.msg_Title || '系统消息' }}</div>
<div class="time"> {{ currentMsg.xkMsgMain.write_Date || '' }} </div>
</div>
<div class="content">
<p>{{ currentMsg.xkMsgDetailList[0].msg_Body || '暂无内容' }}</p>
</div>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { getMsgInfo } from '@/api/msg'
const dialogVisible = ref(false)
const currentMsg = ref({})
const open = (id) => {
getMsgInfo({ msgId: id }).then(res => {
if (res.code == 0) {
currentMsg.value = res.data
dialogVisible.value = true
}
})
}
defineExpose({
open
})
</script>
<style scoped lang="scss">
.header {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 2px solid #eee;
margin-bottom: 20px;
padding-bottom: 10px;
.title {
font-size: 16px;
font-weight: bold;
}
.time {
color: #333;
font-size: 16px;
}
}
.content {
min-height: 200px;
font-size: 16px;
}
</style>

View File

@ -0,0 +1,133 @@
<template>
<div>
<el-dialog v-model="dialogVisible" title="消息列表" width="1000px" append-to-body :close-on-click-modal="false"
@close="close">
<el-form :model="searchForm" inline>
<el-form-item label="时间:">
<div class="date-range">
<el-date-picker v-model="searchForm.swriteDate" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
style="width: 150px" />
<span class="separator" style="width: 10px;display: inline-block;text-align: center;">-</span>
<el-date-picker v-model="searchForm.ewriteDate" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
style="width: 150px" />
</div>
</el-form-item>
<el-form-item label="消息类型:">
<el-select v-model="searchForm.msg_Type" placeholder="请选择" clearable>
<el-option label="取血通知" value="BLOOD_OUT_NOTICE" />
<el-option label="输血申请单保存消息" value="APPLY_NOTICE" />
</el-select>
</el-form-item>
<el-form-item label="是否已读:">
<el-select v-model="searchForm.read_Flag" placeholder="请选择" clearable>
<el-option label="已读" value="Y" />
<el-option label="未读" value="N" />
</el-select>
</el-form-item>
</el-form>
<div>
<el-button type="primary" @click="getList" icon="Search">查询</el-button>
<!-- <el-button type="warning" @click="markAllAsRead" icon="Check">一键已读</el-button> -->
</div>
<div class="mt10">
<el-table :data="msgList" border height="450" show-overflow-tooltip highlight-current-row>
<el-table-column label="消息标题" prop="Msg_Title" width="200" align="center" />
<el-table-column label="消息内容" prop="Msg_Body" align="center" />
<el-table-column label="消息时间" prop="Write_Date" align="center" width="200" />
<el-table-column label="状态" prop="Read_Flag" align="center" width="80">
<template v-slot="{ row }">
<el-tag v-if="row.Read_Flag == 'Y'" type="success">已读</el-tag>
<el-tag v-else type="danger">未读</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="100" align="center" :show-overflow-tooltip="false">
<template v-slot="{ row }">
<el-button type="primary" text @click="handleDetail(row)">查看</el-button>
</template>
</el-table-column>
</el-table>
<pagination :total="total" v-model:page="searchForm.pageNum" v-model:limit="searchForm.pageSize"
@pagination="getList" />
</div>
</el-dialog>
<WsMsgDetails ref="msgDetailsRef" />
</div>
</template>
<script setup lang="ts">
import { queryMsgList, updateMsgFlag } from '@/api/msg'
import emitter from '@/utils/mitt'
import dayjs from 'dayjs'
import WsMsgDetails from "@/components/WsMsgDetails/index.vue"
import useUserStore from '@/store/modules/user'
const userInfo = useUserStore()
const msgDetailsRef = useTemplateRef('msgDetailsRef')
const dialogVisible = ref(false)
const searchForm = ref({
swriteDate: dayjs().format('YYYY-MM-DD'),
ewriteDate: dayjs().format('YYYY-MM-DD'),
pageNum: 1,
pageSize: 20
})
const msgList = ref([])
const total = ref(0)
const open = () => {
getList()
}
const getList = () => {
searchForm.value.swriteDate = dayjs(searchForm.value.swriteDate).format('YYYY-MM-DD') + ' 00:00:00'
searchForm.value.ewriteDate = dayjs(searchForm.value.ewriteDate).format('YYYY-MM-DD') + ' 23:59:59'
queryMsgList(searchForm.value).then(res => {
if (res.code == 200) {
msgList.value = res.rows
total.value = res.total
dialogVisible.value = true
}
})
}
const markAllAsRead = () => { }
const handleDetail = (row) => {
console.log("🚀 ~ handleDetail ~ row:", row)
msgDetailsRef.value.open(row.msgid)
return
const data = {
accept_Date: dayjs().format('YYYY-MM-DD HH:mm:ss'),
accept_Person: userInfo.name,
msgId: row.msgid,
}
updateMsgFlag(data).then(res => {
if (res.code == 0) {
emitter.emit('resetCount')
getList()
}
})
}
const close = () => {
searchForm.value = {
swriteDate: dayjs().format('YYYY-MM-DD'),
ewriteDate: dayjs().format('YYYY-MM-DD'),
pageNum: 1,
pageSize: 20
}
msgList.value = []
dialogVisible.value = false
}
defineExpose({
open
})
</script>
<style scoped lang="scss">
.el-form-item {
margin-bottom: 10px;
}
</style>

View File

@ -0,0 +1,145 @@
<template>
<div v-show="showNotify" class="ws-notify-popup">
<div class="notify-header">
<span class="notify-title">{{ currentMsg.title || '系统消息' }}</span>
<span class="close-btn" @click="showNotify = false">×</span>
</div>
<div class="notify-body">
<p class="notify-text" @click="viewHandle">{{ currentMsg.content || '暂无消息内容' }}</p>
<el-button type="primary" size="small" @click="handleRead">已读</el-button>
</div>
<WsMsgDetails ref="msgDetailsRef" />
</div>
</template>
<script setup lang="ts">
import { updateMsgFlag } from '@/api/msg'
import dayjs from 'dayjs'
import useUserStore from '@/store/modules/user'
import WsMsgDetails from '@/components/WsMsgDetails/index.vue'
import emitter from '@/utils/mitt'
const userInfo = useUserStore()
const showNotify = ref(false)
const currentMsg = ref({})
const msgDetailsRef = useTemplateRef('msgDetailsRef')
const open = (data) => {
currentMsg.value = data
showNotify.value = true
}
const handleRead = () => {
const data = {
accept_Date: dayjs().format('YYYY-MM-DD HH:mm:ss'),
accept_Person: userInfo.name,
msgId: currentMsg.value.extra.msgId,
}
updateMsgFlag(data).then(res => {
if (res.code == 0) {
emitter.emit('resetCount')
showNotify.value = false
}
})
}
const viewHandle = () => {
msgDetailsRef.value.open(currentMsg.value.extra.msgId || '')
handleRead()
}
defineExpose({
open,
})
</script>
<style scoped>
.ws-notify-popup {
position: fixed;
right: 20px;
bottom: 20px;
z-index: 99999;
width: 340px;
background: #ffffff;
border-radius: 8px;
/* 医疗风柔和阴影,不轻浮 */
box-shadow: 0 6px 20px rgba(26, 88, 145, 0.18);
overflow: hidden;
animation: popIn 0.25s ease-out;
border: 1px solid #e8f1f8;
}
/* 左侧医疗蓝标识条(医院系统常用蓝 #1677ff),伪元素,不改动模板 */
.ws-notify-popup::before {
content: '';
position: absolute;
left: 0;
top: 0;
width: 6px;
height: 100%;
background: #1677ff;
}
.notify-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 16px 12px 22px;
/* 浅医疗蓝背景,淡雅 */
background: #f0f7ff;
}
.notify-title {
font-weight: 600;
font-size: 15px;
color: #1a4b7a;
}
.close-btn {
cursor: pointer;
font-size: 18px;
color: #748494;
}
.close-btn:hover {
color: #1677ff;
}
.notify-body {
padding: 16px 16px 18px 22px;
}
.notify-text {
margin: 0 0 14px 0;
font-size: 14px;
color: #33465b;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
/* 展示2行 */
-webkit-box-orient: vertical;
cursor: pointer;
&:hover {
color: #1677ff;
}
}
@keyframes popIn {
from {
opacity: 0;
transform: translateY(12px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>

View File

@ -32,7 +32,17 @@
</el-dropdown-menu>
</template>
</el-dropdown>
<div class="msg_box" @click="openHandle">
<el-badge :value="count" :max="99" class="item" :show-zero="false">
<el-icon color="#FFF" size="25" class="icon">
<BellFilled />
</el-icon>
</el-badge>
</div>
</div>
<WsMsgList ref="wsMsgListRef" />
</div>
</template>
@ -52,16 +62,25 @@ import useAppStore from '@/store/modules/app'
import useUserStore from '@/store/modules/user'
import useSettingsStore from '@/store/modules/settings'
import { queryHosList, addHos, upadteHos } from '@/api/system/medicalInstitutions'
import { queryNoReadCount } from '@/api/msg'
import WsMsgList from '@/components/WsMsgList/index.vue'
import emitter from '@/utils/mitt.js'
const appStore = useAppStore()
const userStore = useUserStore()
const settingsStore = useSettingsStore()
const count = ref(0)
const wsMsgListRef = useTemplateRef('wsMsgListRef')
const yljgName = ref('输血平台')
function toggleSideBar(): void {
appStore.toggleSideBar()
}
const openHandle = () => {
wsMsgListRef.value.open()
}
function handleCommand(command: string): void {
switch (command) {
case "setLayout":
@ -132,10 +151,19 @@ async function toggleTheme(event?: MouseEvent): Promise<void> {
}
}
const getCount = () => {
queryNoReadCount().then(res => {
count.value = res.data || 0
})
}
onMounted(() => {
queryHosList().then((resp) => {
yljgName.value = resp.data.find((item) => item.hospital_code == userStore.sysLoginParam.loginYLJG)?.hospital_name || '输血平台'
})
getCount()
emitter.on("resetCount", getCount)
})
</script>
@ -286,6 +314,15 @@ onMounted(() => {
}
}
}
.msg_box {
width: 50px;
padding-top: 15px;
.item {
cursor: pointer;
}
}
}
}
</style>

View File

@ -13,6 +13,8 @@
<!-- 库存预警组件 -->
<BloodStockNotify />
<!-- websocket消息通知组件 -->
<WsNotifyPopup ref="msgRef" />
</div>
</template>
@ -23,8 +25,13 @@ import { AppMain, Navbar, Settings, TagsView } from './components'
import useAppStore from '@/store/modules/app'
import useSettingsStore from '@/store/modules/settings'
import { useSysParam } from '@/hooks/useSysParam'
import { initWebSocket } from '@/utils/webSocket'
import useUserStore from '@/store/modules/user'
import emitter from '@/utils/mitt.js'
const userInfo = useUserStore()
// 异步懒加载,首屏不阻塞
const BloodStockNotify = defineAsyncComponent(() => import('@/components/BloodStockNotify/index.vue'))
const WsNotifyPopup = defineAsyncComponent(() => import('@/components/WsNotifyPopup/index.vue'))
const { initAllParams } = useSysParam()
@ -78,10 +85,37 @@ function setLayout() {
settingRef.value.openSetting()
}
const msgRef = useTemplateRef('msgRef')
const onNewMessage = (newMsg) => {
console.log("🚀 ~ onNewMessage ~ newMsg:", newMsg)
if (newMsg.to == userInfo.name || newMsg.to == 'ALL') {
msgRef.value.open(newMsg)
}
}
onMounted(() => {
// 获取参数值
initAllParams(GLOBAL_PARAM_KEYS)
// 初始化socket
const url = `ws://47.97.125.165:8907/ws/msgserver/${userInfo.name}`
initWebSocket({ fullUrl: url })
emitter.on("APPLY_NOTICE", onNewMessage)
// 读取缓存,防止ws消息比组件挂载早,丢失消息
const cacheRaw = emitter.getCache("APPLY_NOTICE")
if (cacheRaw) {
onNewMessage(cacheRaw)
}
})
onBeforeUnmount(() => {
emitter.off("APPLY_NOTICE", onNewMessage)
})
</script>

View File

@ -1,10 +1,7 @@
// WebSocket连接配置
type WebSocketOptions = {
import emitter from '@/utils/mitt';
type WebSocketInternalOptions = {
fullUrl: string;
onMessage?: (data: string) => void;
onOpen?: () => void;
onError?: (error: Event) => void;
onClose?: () => void;
reconnectInterval?: number;
};
@ -12,74 +9,75 @@ let websocket: WebSocket | null = null;
let reconnectTimer: any = null;
let isManualClose = false;
// 初始化WebSocket连接
export function initWebSocket(options: WebSocketOptions) {
const {
fullUrl,
onMessage,
onOpen,
onError,
onClose,
reconnectInterval = 3000
} = options;
/** 初始化WebSocket */
export function initWebSocket(options: WebSocketInternalOptions) {
const { fullUrl, reconnectInterval = 3000 } = options;
// 关闭旧连接
// 关闭已有连接
if (websocket) {
websocket.close();
}
// 检查浏览器支持性
if (!('WebSocket' in window)) {
console.error('当前浏览器不支持WebSocket');
return;
}
// 创建WebSocket连接
try {
websocket = new WebSocket(fullUrl);
// 连接成功回调
// 连接成功
websocket.onopen = () => {
clearTimeout(reconnectTimer!);
isManualClose = false;
onOpen?.();
console.log('WebSocket 连接成功');
};
// 接收消息回调
// 接收消息,自动解析按 msgType 分发事件
websocket.onmessage = (event) => {
onMessage?.(event.data);
try {
const rawMsg = JSON.parse(event.data);
const msgType = rawMsg.type;
//根据消息类型发送事件
//APPLY_NOTICE 输血申请保存
emitter.emit(msgType, rawMsg);
// 重置未读消息数
emitter.emit('resetCount')
} catch (err) {
console.error('WebSocket消息解析失败:', err);
}
};
// 错误回调
// 连接异常
websocket.onerror = (error) => {
onError?.(error);
console.error('WebSocket 连接异常:', error);
startReconnect(() => initWebSocket(options), reconnectInterval);
};
// 关闭回调
// 连接关闭
websocket.onclose = () => {
onClose?.();
console.log('WebSocket 连接关闭');
if (!isManualClose) {
startReconnect(() => initWebSocket(options), reconnectInterval);
}
};
} catch (error) {
console.error('WebSocket连接创建失败:', error);
console.error('WebSocket 创建失败:', error);
startReconnect(() => initWebSocket(options), reconnectInterval);
}
}
// 发送消息
/** 发送ws消息 */
export function sendWebSocketMessage(message: any): boolean {
if (websocket && websocket.readyState === WebSocket.OPEN) {
websocket.send(JSON.stringify(message));
return true;
}
console.error('WebSocket未连接,无法发送消息');
console.error('WebSocket未连接,发送失败');
return false;
}
// 手动关闭WebSocket
/** 手动关闭ws(登出时调用) */
export function closeWebSocket(): void {
isManualClose = true;
if (reconnectTimer) {
@ -89,15 +87,15 @@ export function closeWebSocket(): void {
websocket = null;
}
// 启动重连
/** 获取当前连接状态 */
export function getWebSocketState(): number | null {
return websocket?.readyState || null;
}
// 内部重连私有方法
function startReconnect(connectCallback: () => void, interval: number): void {
if (reconnectTimer) {
clearTimeout(reconnectTimer);
}
reconnectTimer = setTimeout(connectCallback, interval);
}
// 获取当前连接状态
export function getWebSocketState(): number | null {
return websocket?.readyState || null;
}

View File

@ -11,9 +11,9 @@
<el-button type="primary" plain @click="openJsHandle">检索</el-button>
<el-button type="primary" plain @click="addMatch">新增单据</el-button>
<el-button type="success" plain :disabled="bloodInfo.bill_status && bloodInfo.bill_status != 'A'"
@click="saveBloodApply" :loading="saveLoading">保存</el-button>
@click="saveBloodApply(1)" :loading="saveLoading">保存</el-button>
<el-button type="primary" plain @click="tzHandle">通知取血</el-button>
<el-button type="primary" plain @click="auditHandle">审核</el-button>
<el-button type="primary" plain :loading="auditLoading" @click="auditHandle">审核</el-button>
<el-button type="primary" plain @click="openDcHandle">多次发血</el-button>
<el-button type="warning" plain :loading="printLoading" @click="printHandle">打印</el-button>
<el-button type="warning" plain>打印标签</el-button>
@ -21,7 +21,7 @@
<!-- 主体左右分栏容器 -->
<el-form :model="formData" label-width="auto" class="form_box"
:disabled="bloodInfo.bill_status && bloodInfo.bill_status != 'A'">
:disabled="bloodInfo.check_sign && bloodInfo.check_sign == 'Y'">
<div class="card-box">
<div class="section-title">
<div> 申请单信息 </div>
@ -38,7 +38,8 @@
<el-form-item label="申请单号">
<DropdownTableSelect v-model="formData.bill_no" :column-list="applyColumns" tableWidth="800px"
:showSearch="false" labelField="bill_no" :table-data="applyTableData" @open="loadApplyData"
@search="searchApply" @change="searchApply" :disabled="!!(bloodInfo.bill_no)">
@search="searchApply" @change="searchApply"
:disabled="bloodInfo.check_sign && bloodInfo.check_sign == 'Y'">
<template #dept_id="{ row }">
{{ formatDict(row.dept_id, 'ks') }}
</template>
@ -205,14 +206,16 @@
</el-col>
<el-col :span="5">
<el-form-item label="发血经手人">
<SelectTable v-model:data="bloodInfo.handle_person" :tableData="userList" placeholder="" />
<SelectTable v-model:data="bloodInfo.handle_person" :tableData="userList" placeholder=""
:disabled="bloodInfo.check_sign && bloodInfo.check_sign == 'Y'" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="5">
<el-form-item label="取血人">
<SelectTable v-model:data="bloodInfo.take_person" :tableData="userList" placeholder="" />
<SelectTable v-model:data="bloodInfo.take_person" :tableData="userList" placeholder=""
:disabled="bloodInfo.check_sign && bloodInfo.check_sign == 'Y'" />
</el-form-item>
</el-col>
<el-col :span="5">
@ -436,11 +439,7 @@ const bloodInfo = ref({
})
const saveLoading = ref(false)
const billStatus = ref([
{ label: '未发血', value: 'A' },
{ label: '已发血', value: 'B' },
{ label: '已作废', value: 'ZF' },
])
const auditLoading = ref(false)
const searchForm = ref({
stime: dayjs().format('YYYY-MM-DD'),
etime: dayjs().format('YYYY-MM-DD'),
@ -566,7 +565,7 @@ const bloodEnter = () => {
if (res.data.length == 1) {
const row = res.data[0]
checkBlood(row)
} else if (res.data.length > 1) {
} else if (res.data.length > 1) { //多条血液数据进行弹窗选择
maskRef.value.open(res.data)
}
})
@ -680,11 +679,13 @@ const handleSearch = () => {
})
}
const saveBloodApply = () => {
const saveBloodApply = (type: number) => { // 1保存 2审核
//判断发血时间、通知取血时间大于当前时间7天
const isFlag = checkTimeTip(bloodInfo.value.occur_date, bloodInfo.value.notify_time)
if (!isFlag) return
saveLoading.value = true
if (type == 1) {
saveLoading.value = true
}
const data = {
moreSign: moreSign.value,
xkOutMain: {
@ -715,10 +716,16 @@ const saveBloodApply = () => {
}
}
saveBloodInfo(data).then(res => {
return saveBloodInfo(data).then(res => {
if (res.code == 0) {
ElMessage.success('保存成功!')
addMatch()
if (type == 1) {
ElMessage.success('保存成功!')
addMatch()
return false
} else {
return true
}
}
}).finally(() => {
saveLoading.value = false
@ -737,14 +744,14 @@ function checkTimeTip(sendBloodTime, notifyGetBloodTime) {
if (notifyDiff > 7) {
msg.push('通知取血时间与当前时间超过七天;')
}
if (msg) {
if (msg.length) {
ElMessageBox.alert(msg.join('<br/>'), '提示', { type: 'warning', dangerouslyUseHTMLString: true })
return false
} else {
return true
}
}
//通知取血
const tzHandle = () => {
if (!formData.value.bill_no) return ElMessage.warning('请选择配血单!')
notifyMessage({ billNo: bloodInfo.value.bill_no }).then(res => {
@ -755,22 +762,33 @@ const tzHandle = () => {
}
const auditHandle = () => {
const data = {
applyNo: formData.value.bill_no,
billNo: bloodInfo.value.bill_no,
takePerson: bloodInfo.value.take_person,
userId: userInfo.name
}
bloodOutAudit(data).then(res => {
if (res.code == 0) {
ElMessage.success(res.msg)
if (!bloodInfo.value.bill_no) return ElMessage.warning("该单据还未保存!")
//审核之前保存 防止修改未保存审核单据
saveBloodApply(2).then(saveFlag => {
if (saveFlag) {
const data = {
applyNo: formData.value.bill_no,
billNo: bloodInfo.value.bill_no,
takePerson: bloodInfo.value.take_person,
userId: userInfo.name
}
auditLoading.value = true
bloodOutAudit(data).then(res => {
if (res.code == 0) {
ElMessage.success(res.msg)
//审核成功后通知取血操作
tzHandle()
}
}).finally(() => {
auditLoading.value = false
})
}
})
}
const printHandle = () => {
if (!bloodInfo.value.bill_no) return ElMessage.warning('该单据还未保存!')
printLoading.value = true
if (!bloodInfo.value.bill_no) return ElMessage.warning('请选择配血单!')
printReport({ billNo: bloodInfo.value.bill_no, templateName: 'BLOOD_OUT' }).then(res => {
if (res.data) {
printBase64PDF(res.data)

View File

@ -522,10 +522,10 @@
{{ formatDict(scope.row.dept_id, 'ks') }}
</template>
</el-table-column>
<el-table-column prop="abo_type" label="血型" align="center" />
<el-table-column prop="rh_type" label="Rh(D)" align="center" />
<el-table-column prop="abo_type" label="血型" align="center" width="60" />
<el-table-column prop="rh_type" label="Rh(D)" align="center" width="60" />
<el-table-column prop="req_breed" label="申请品种" align="center" />
<el-table-column prop="apply_date" label="申请日期" width="120" align="center" />
<el-table-column prop="apply_date" label="申请日期" width="150" align="center" />
<el-table-column prop="apply_medic" label="申请医师" align="center">
<template #default="scope">
{{userList.find(item => item.value == scope.row.apply_medic)?.label || ''}}
@ -590,6 +590,7 @@ import CheckUser from '@/components/CheckUser/index.vue'
import useUserStore from '@/store/modules/user'
import router from '@/router/index.js'
import { printBase64PDF } from '@/utils/classCom.js'
import { sendWebSocketMessage } from '@/utils/webSocket.js'
const userInfo = useUserStore()
@ -873,7 +874,7 @@ const reviewCommentsRef = useTemplateRef('reviewCommentsRef')
// 如果是001 代表是临床科室,此时需要调用“上级医生审核” 审核接口,
// 如果是002 代表是输血科室,调用“申请单审核前校验”
const reviewHandle = () => {
if (!xkTransfuseApply.value.bill_no) return ElMessage.warning('请选择申请单')
if (!xkTransfuseApply.value.bill_no) return ElMessage.warning('该单据还未保存!')
shLoading.value = true
getDeptType({ userId: userInfo.name }).then(res => {
if (res.data == '001') {
@ -901,7 +902,7 @@ const handleSh = () => {
}
const cancelreviewHandle = () => {
if (!xkTransfuseApply.value.bill_no) return ElMessage.warning('请选择申请单')
if (!xkTransfuseApply.value.bill_no) return ElMessage.warning('该单据还未保存!')
getDeptType({ userId: userInfo.name }).then(res => {
ElMessageBox.confirm(
`申请单号${xkTransfuseApply.value.bill_no}确定取消审核吗?`,
@ -935,7 +936,7 @@ const reasonText = ref('')
const zfShow = ref(false)
const invalidateHandle = () => {
// sqdzfyy
if (!xkTransfuseApply.value.bill_no) return ElMessage.warning('请选择申请单')
if (!xkTransfuseApply.value.bill_no) return ElMessage.warning('该单据还未保存!')
zfShow.value = true
}
const handleZf = () => {
@ -975,7 +976,6 @@ const handleReviewConfirm = () => {
}
//审核意见
const shClose = () => {
shShow.value = false
shForm.value = {
@ -1103,7 +1103,12 @@ const handleSubmit = async () => {
xkPatientInfo: tempPatient,
xkTransfuseApply: xkTransfuseApply.value
},
xkTransfuseApplyBloodbreedList: bloodList.value,
xkTransfuseApplyBloodbreedList: bloodList.value.map(item => {
return {
...item,
bill_no: xkTransfuseApply.value.bill_no
}
}),
xkTransfuseApplyTestitemList: lisProject.value,
}
@ -1118,12 +1123,11 @@ const handleSubmit = async () => {
if (res2.code == 0) {
// 保存申请单
saveApplyInfo(data).then((res3) => {
if (res3.data) {
if (res3.code == 0 && res3.data) {
getQueryOneInfo(res3.data)
getSqdList()
}
if (res3.code == 0) {
ElMessage.success('保存成功')
sendMsg(res3.data)
}
})
} else if (res2.code == 1) {
@ -1145,12 +1149,11 @@ const handleSubmit = async () => {
}).catch(() => {
// 保存申请单
saveApplyInfo(data).then((res3) => {
if (res3.data) {
if (res3.code == 0 && res3.data) {
getQueryOneInfo(res3.data)
getSqdList()
}
if (res3.code == 0) {
ElMessage.success('保存成功')
sendMsg(res3.data)
}
})
})
@ -1178,21 +1181,43 @@ const indicationComfirm = (arr) => {
xkPatientInfo: tempPatient,
xkTransfuseApply: xkTransfuseApply.value
},
xkTransfuseApplyBloodbreedList: bloodList.value,
xkTransfuseApplyBloodbreedList: bloodList.value.map(item => {
return {
...item,
bill_no: xkTransfuseApply.value.bill_no
}
}),
xkTransfuseApplyTestitemList: lisProject.value,
xkTransfuseApplyCausalisList: arr
}
saveApplyInfo(data).then((res) => {
if (res.data) {
if (res.code == 0 && res.data) {
getQueryOneInfo(res.data)
getSqdList()
}
if (res.code == 0) {
sendMsg(res.data)
ElMessage.success('保存成功')
}
})
}
const sendMsg = (billNo: string) => {
const arr = bloodList.value.map(item => item.blood_breed)
const breedMap = new Map(bloodBreed.value.map(v => [v.value, v.label]));
const bloodText = arr.map(item => breedMap.get(item) ?? item).join('、');
const data = {
type: "APPLY_NOTICE",
from: userInfo.name,
to: "ALL",
title: "你好",
content: `${xkPatientInfo.value.patient_name}病人的申请单:${billNo},申请品种:${bloodText}, 保存成功, 请及时审核!!!`,
data: {
billNo,
}
}
sendWebSocketMessage(data)
}
//获取申请单信息
const getQueryOneInfo = (bill_no: string) => {
queryApplyOne({ billNo: bill_no }).then((res) => {