Browse Source

完善急诊功能

feature/user-0111
LiLongLong 7 months ago
parent
commit
af2a4ca972
  1. 6
      components.d.ts
  2. 7
      src/components/dialogs/ErrorModal.vue
  3. 4
      src/pages/Index/History.vue
  4. 3
      src/pages/Index/Regular/Consumables.vue
  5. 146
      src/pages/Index/Regular/Emergency.vue
  6. 43
      src/pages/Index/components/Consumables/MoveLiquidArea.vue
  7. 3
      src/websocket/socket.ts

6
components.d.ts

@ -8,11 +8,17 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
ElButton: typeof import('element-plus/es')['ElButton']
ElCol: typeof import('element-plus/es')['ElCol']
ElFooter: typeof import('element-plus/es')['ElFooter']
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElHeader: typeof import('element-plus/es')['ElHeader']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElInput: typeof import('element-plus/es')['ElInput']
ElPopover: typeof import('element-plus/es')['ElPopover']
ElRow: typeof import('element-plus/es')['ElRow']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ErrorModal: typeof import('./src/components/dialogs/ErrorModal.vue')['default']
Keyboard: typeof import('./src/components/Keyboard.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']

7
src/components/dialogs/ErrorModal.vue

@ -3,9 +3,9 @@
<div v-if="showErrorStack" class="error-stack-overlay">
<div class="error-stack-container" :class="typeClass">
<div class="error-stack-header">
<div class="icon-wrapper">
<!-- <div class="icon-wrapper">
<img :src="iconMap[type]" alt="icon" />
</div>
</div> -->
<span class="error-stack-title">{{ typeText }}</span>
</div>
<div class="error-stack-content">
@ -239,7 +239,7 @@
cursor: pointer;
transition: all 0.3s;
background: var(--theme-color);
color: white;
// color: white;
&:hover {
opacity: 0.9;
@ -329,6 +329,7 @@ onUnmounted(() => {
eventBus.off('show-error-modal', handleErrorModal)
})
const handleErrorModal = (data: ErrorModalData) => {
console.log('data---', data)
info.value = data.info
type.value = data.type
detailInfos.value = data.detailInfos || []

4
src/pages/Index/History.vue

@ -132,14 +132,14 @@
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import dayjs from 'dayjs'
import { HistoryTable, HistoryWarn } from './Components/index'
import { HistoryTable, HistoryWarn } from './components/index'
import {
getHistoryInfo,
deleteHistoryInfo,
searchHistoryInfo,
printHistoryInfo,
} from '../../services/Index/index'
import HistoryMessage from './Components/History/HistoryMessage.vue'
import HistoryMessage from './components/History/HistoryMessage.vue'
import type { TableItem } from '../../types/Index'
import { ElMessage } from 'element-plus'
import WarnSvg from '@/assets/Index/History/warn.svg'

3
src/pages/Index/Regular/Consumables.vue

@ -94,7 +94,7 @@
</template>
<script setup lang="ts">
import { MoveLiquidArea, SpttingPlates, MainComponent } from '../Components'
import { MoveLiquidArea, SpttingPlates, MainComponent } from '../components'
// import SliderAreaEx from '../components/Consumables/SliderAreaEx.vue';
// import DragAreaEx from '../components/Consumables/DragAreaEx.vue';
import { ref, onMounted, onActivated, onBeforeUnmount, watch } from 'vue'
@ -388,6 +388,7 @@ const handleIsUnload = () => {
plates.value = []
emergencyStore.unloadInfo()
emergencyInfo.value = {} as EmergencyPosStateMessage['data']['tube']
console.log('emergencyInfo===', emergencyInfo)
bufferLittles.value = [
{
id: 1,

146
src/pages/Index/Regular/Emergency.vue

@ -7,14 +7,13 @@
</div>
<!-- 急诊信息 -->
<div class="emergency-info" :class="{ 'disable-section': !isEmergencyEnabled }">
<!-- <div class="emergency-info" :class="{ 'disable-section': !isEmergencyEnabled }">
<div class="tab-content">
<div class="tab-form" :class="{ isOpacity: !isEmergencyEnabled }">
<div class="line-code">
<!-- 急诊位的表单 -->
<label>样本条形码</label>
<input type="text" placeholder="请输入样本条形码信息" @focus="showKeyboard('sampleBarcode')"
:value="emergencyPosition.sampleBarcode" :disabled="!isEmergencyEnabled" readonly />
:value="emergencyPosition.sampleBarcode"/>
</div>
<div class="id-info">
<label>用户ID</label>
@ -22,12 +21,27 @@
:disabled="!isEmergencyEnabled" readonly />
</div>
</div>
<div class="active-button">
<button @click="toggleEmergency" :class="isEmergencyEnabled ? 'close-button' : 'open-button'">
{{ isEmergencyEnabled ? '关闭急诊位' : '开启急诊位' }}
</button>
</div>
</div>
</div> -->
<div class="emergency-main">
<el-row>
<el-col :span="5">
<label>样本条形码</label>
</el-col>
<el-col :span="12" style="padding-left:20px">
<input type="text" placeholder="请输入样本条形码信息" @focus="showKeyboard('sampleBarcode')" style="width:400px"
:value="emergencyPosition.sampleBarcode"/>
</el-col>
</el-row>
<el-row>
<el-col :span="5">
<label>用户ID</label>
</el-col>
<el-col :span="12" style="padding-left:20px">
<input type="text" placeholder="请输入用户ID信息" @focus="showKeyboard('userid')" :value="emergencyPosition.userid" style="width:400px"
:disabled="!isEmergencyEnabled" readonly />
</el-col>
</el-row>
</div>
<hr style="height: 1px; border: none;" />
<!-- 急诊项目 -->
@ -37,12 +51,7 @@
<span>项目选择</span>
</div>
<div class="project-list">
<button @click="selectProject('自动')" :disabled="!isEmergencyEnabled" :class="[
isEmergencyEnabled ? 'project-auto' : 'disabled-item',
{ 'active-item': projectName === '自动' && isEmergencyEnabled },
]">
自动
</button>
<div v-for="(item, index) in projects" :key="index" @click="selectProject(item)" :class="[
isEmergencyEnabled ? 'project-item' : 'disabled-project-item',
{ 'active-project-item': emergencyPosition.projIds.includes(item.projId) && isEmergencyEnabled },
@ -59,12 +68,6 @@
<span>血液类型</span>
</div>
<div class="type-list">
<button @click="selectBloodType('自动')" :class="[
isEmergencyEnabled ? 'project-auto' : 'disabled-item',
{ 'active-item': bloodType === '自动' && isEmergencyEnabled },
]" :disabled="!isEmergencyEnabled">
自动
</button>
<button v-for="(item, index) in bloodTypes" :key="index" @click="selectBloodType(item)"
:disabled="!isEmergencyEnabled" :class="getTypeClass(item)">
{{ item.projectName }}
@ -75,9 +78,9 @@
</div>
<hr style="height: 1px; border: none;" />
<!-- 急诊控制 -->
<div class="emergency-controller" :class="{ isOpacity: !isEmergencyEnabled }">
<button class="cancel-button" :disabled="!isEmergencyEnabled" @click="cancelHandle">取消</button>
<button class="ok-button" :disabled="!isEmergencyEnabled" @click="confirmHandle">确定</button>
<div class="emergency-controller" :class="{ isOpacity: !isEmergencyEnabled }" style="padding:50px 0">
<el-button class="cancel-button" @click="cancelHandle">取消</el-button>
<el-button v-if="showSaveBtn" class="ok-button" :disabled="!isEmergencyEnabled" @click="confirmHandle">确定</el-button>
</div>
<!-- 键盘 -->
@ -123,7 +126,7 @@ const consumableStore = useConsumablesStore();
const emergencyStore = useEmergencyStore();
const deviceStore = useDeviceStore();
// /
const isEmergencyEnabled = ref(false);
const isEmergencyEnabled = ref(true);//
//
const projects = ref<ReactionPlate[]>([]);
@ -132,6 +135,8 @@ onMounted(() => {
if (consumableStore.plates.length > 0) {
projects.value = consumableStore.plates as ReactionPlate[];
}
//projIdnull
projects.value = projects.value.filter(item => item.projId)
})
const bloodTypes = ref([
@ -178,6 +183,10 @@ const tubeRackState = ref<TubeHolderStateMessage['data']>({
const handleTubeHolderStateMessage = (data: TubeHolderStateMessage['data']) => {
tubeRackState.value = data
}
//
const emergencyStateList = ["EMPTY", "TO_BE_PROCESSED", "PROCESS_COMPLETE", "ERROR"]
let showSaveBtn = ref<Boolean>(false)
onMounted(() => {
ws.connect()
ws.subscribe<TubeHolderStateMessage>('TubeHolderState', handleTubeHolderStateMessage)
@ -185,6 +194,15 @@ onMounted(() => {
onActivated(() => {
ws.connect()
ws.subscribe<TubeHolderStateMessage>('TubeHolderState', handleTubeHolderStateMessage)
const { emergencyInfo } = emergencyStore.$state
console.log('emergencyInfo---', emergencyInfo)
if(emergencyInfo && emergencyInfo.state){
const {state, sampleBarcode} = emergencyInfo
currentInputValue.value = sampleBarcode
if(emergencyStateList.includes(state)){
showSaveBtn.value = true
}
}
})
onDeactivated(() => {
ws.disconnect()
@ -211,17 +229,30 @@ const getProjectInfo = (projIds: number[]) => {
//
const confirmHandle = async () => {
//
if (deviceStore.status !== 'PAUSE') {
ElMessage.error('设备未暂停,无法添加急诊');
// if (deviceStore.status !== 'PAUSE') {
// ElMessage.error('');
// return
// }
const emergencyInfo = emergencyPosition.value;
if(!emergencyInfo.sampleBarcode){
ElMessage.error('请输入样本条形码');
return
}
if(!emergencyInfo.userid){
ElMessage.error('请输入用户ID');
return
}
if (emergencyInfo.projIds.length === 0) {
ElMessage.error('请选择项目');
return
}
if(!emergencyInfo.bloodType){
ElMessage.error('请选择血液类型');
return;
}
const res = await insertEmergency(emergencyPosition.value);
if (res.success) {
const emergencyInfo = emergencyPosition.value;
if (emergencyInfo.projIds.length === 0) {
ElMessage.error('请选择项目');
return
}
//
const emergencyData: EmergencyPosStateMessage['data']['tube'] = {
pos: 1,
@ -331,7 +362,13 @@ const currentInputField = ref<'sampleBarcode' | 'userid' | ''>('')
//
const showKeyboard = (field: 'sampleBarcode' | 'userid') => {
//
currentInputValue.value = ''
// currentInputValue.value = ''
if(field == 'sampleBarcode'){
currentInputValue.value = emergencyPosition.value.sampleBarcode
}
if(field == 'userid'){
currentInputValue.value = emergencyPosition.value.userid
}
currentInputField.value = field
keyboardVisible.value = true
}
@ -339,10 +376,9 @@ const showKeyboard = (field: 'sampleBarcode' | 'userid') => {
//
const handleKeyboardInput = (value: string) => {
if (!currentInputField.value) return
console.log('value----', value)
//
currentInputValue.value = value
//
if (currentInputField.value === 'sampleBarcode') {
emergencyPosition.value.sampleBarcode = value
@ -378,7 +414,7 @@ onUnmounted(() => {
})
const showTubeSelector = ref(false)
const selectedTubePos = ref<number | null>(null)
const selectedTubePos = ref<number | null>(1)
//
const isTubeOccupied = (pos: number) => {
@ -398,6 +434,30 @@ const selectTube = (pos: number) => {
<style lang="less" scoped>
input {
margin-bottom: 20px;
padding: 8px 5px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 32px;
transition: box-shadow 0.2s ease;
border-radius: 10px;
&::placeholder {
font-size: 32px;
font-weight: 100;
color: #d8d8d8;
}
}
label {
margin-bottom: 8px;
font-size: 32px;
font-weight: 700;
text-align: left;
}
#add-emergency-container {
margin: 0;
padding: 0;
@ -527,7 +587,7 @@ const selectTube = (pos: number) => {
width: 80%;
font-size: 32px;
transition: box-shadow 0.2s ease;
border-radius: 10px;
&::placeholder {
font-size: 32px;
font-weight: 100;
@ -844,11 +904,15 @@ const selectTube = (pos: number) => {
display: flex;
margin-top: 20px;
display: flex;
justify-content: center;
align-items: center;
.cancel-button,
.ok-button {
width: 565px;
height: 120px;
border-radius: 60px;
width: 365px;
height: 100px;
border-radius: 30px;
font-size: 40px;
font-weight: 400;
margin: 0 10px;
@ -953,4 +1017,8 @@ const selectTube = (pos: number) => {
}
}
}
.emergency-main{
margin-top:40px;
margin-left:80px
}
</style>

43
src/pages/Index/components/Consumables/MoveLiquidArea.vue

@ -171,8 +171,12 @@ import { useEmergencyStore, useConsumablesStore } from '../../../../store'
import { LiquidState, BottleGroup } from '../../../../types/Index/index'
import wasteFullIcon from '@/assets/Index/waste-full.svg'
import wasteIcon from '@/assets/Index/waste.svg'
import type { EmergencyPosStateMessage } from '../../../../websocket/socket'
import type { EmergencyPosStateMessage } from '@/websocket/socket'
import { createWebSocket } from '@/websocket/socket'
import { isTubeExist } from '@/services/Index/index';
import { getServerInfo } from '@/utils/getServerInfo'
const { wsUrl } = getServerInfo('/api/v1/app/ws/state')
const socket = createWebSocket(wsUrl)
const emergencyStore = useEmergencyStore()
const consumableStore = useConsumablesStore()
@ -197,25 +201,54 @@ const props = defineProps({
wasteStatus: Boolean,
})
//使websocket
const startWebSocket = () => {
socket.connect()
}
const emergencyStateList = ["EMPTY", "TO_BE_PROCESSED", "PROCESS_COMPLETE", "ERROR"];//EMPTY,PROCESS_COMPLETE,ERROR
onMounted(() => {
//
getEmergencyStatus()
startWebSocket()
socket.subscribe<EmergencyPosStateMessage>('EmergencyPosState', handleEmergencyPosState)
})
//
let emergencyStatus = ref(false)
//
const handleEmergencyPosState = (data: EmergencyPosStateMessage['data']) => {
// data.tube.state = 'PROCESSING'
let {state} = data.tube;
// EMPTYTO_BE_PROCESSEDPROCESS_COMPLETEERROR
if(emergencyStateList.includes(state)){
emergencyStatus.value = true;
}else{
emergencyStatus.value = false;
}
emergencyStore.setInfo(data.tube)
//"PROCESS_COMPLETE",
if(state === 'PROCESS_COMPLETE'){
socket.unsubscribe<EmergencyPosStateMessage>('EmergencyPosState', unSubEmergencyPosState)
}
}
//
const unSubEmergencyPosState = ()=> {
}
//
const getEmergencyStatus = () => {
isTubeExist().then(res => {
console.log('这是急诊位状态=1=', res)
if(res && res.data){
const data = res.data
const { tube } = data;
const stateEm = ["EMPTY", "PROCESS_COMPLETE", "ERROR"];//EMPTY,PROCESS_COMPLETE,ERROR
if(tube && tube.state && stateEm.includes(tube.state)){
if(tube && tube.state && emergencyStateList.includes(tube.state)){
emergencyStatus.value = true;
}
}
})
}

3
src/websocket/socket.ts

@ -75,7 +75,7 @@ interface EmergencyPosStateMessage extends BaseMessage {
userid: string // 用户ID
projInfo: ProjectInfo[] // 项目信息列表
projIds: number[] // 项目ID列表
state: 'EMPTY' | 'OCCUPIED' // 状态
state: string // 状态
errors: string[] // 错误信息列表
}
}
@ -246,6 +246,7 @@ class WebSocketClient {
messageType: T['dataType'],
handler: MessageHandler<T>,
): void {
console.error('messageType==', messageType)
if (!this.messageHandlers.has(messageType)) {
console.log(
'🚀 ~ WebSocketClient ~ subscribe ~ messageType:',

Loading…
Cancel
Save