Browse Source

定义耗材颜色,监听耗材移动到Index

relver
zhangjiming 7 months ago
parent
commit
60064f79c0
  1. 25
      src/pages/Index/Index.vue
  2. 77
      src/pages/Index/Regular/Consumables.vue
  3. 8
      src/pages/Index/Regular/TestTube.vue
  4. 9
      src/services/Index/idCard.ts
  5. 10
      src/services/Index/init.ts
  6. 19
      src/services/Index/regular.ts
  7. 4
      src/services/Index/testTube.ts
  8. 1
      src/services/Index/user-manage.ts
  9. 85
      src/store/modules/consumables.ts
  10. 24
      src/websocket/socket.ts

25
src/pages/Index/Index.vue

@ -243,6 +243,7 @@ import {
import { createWebSocket } from '../../websocket/socket' import { createWebSocket } from '../../websocket/socket'
import type { import type {
AppEventMessage, AppEventMessage,
ConsumablesStateMessage,
DeviceWorkStateMessage, DeviceWorkStateMessage,
FooterMessageState, FooterMessageState,
IncubationPlateStateMessage, IncubationPlateStateMessage,
@ -370,7 +371,9 @@ const handleFooterState = (data: FooterMessageState['data']) => {
const handleTubeHolderStateMessage = (data: TubeHolderStateMessage['data']) => { const handleTubeHolderStateMessage = (data: TubeHolderStateMessage['data']) => {
runningStore.setTubeHolderState(data) runningStore.setTubeHolderState(data)
} }
const handleTubeHolderSettingMessage = (data: TubeHolderSettingMessage['data']) => {
const handleTubeHolderSettingMessage = (
data: TubeHolderSettingMessage['data'],
) => {
tubeRackStore.setTubeRacks(data) tubeRackStore.setTubeRacks(data)
} }
@ -385,6 +388,11 @@ const handleIncubationPlateStateMessage = (
) => { ) => {
runningStore.setSubTanks(data.subtanks) runningStore.setSubTanks(data.subtanks)
} }
const handleConsumablesState = (data: ConsumablesStateMessage['data']) => {
consumableStore.setConsumablesData(data)
}
const getProjectList = async () => { const getProjectList = async () => {
const res = await getProjectInfo() const res = await getProjectInfo()
if (res.success) { if (res.success) {
@ -399,9 +407,13 @@ const getBloodTypeList = async () => {
} }
onMounted(() => { onMounted(() => {
eventBus.on('initDevice', showInitDeviceAlert) eventBus.on('initDevice', showInitDeviceAlert)
wsEvent.connect()
wsEvent.subscribe<AppEventMessage>('AppEvent', handleAppEvent) wsEvent.subscribe<AppEventMessage>('AppEvent', handleAppEvent)
wsState.connect()
wsEvent.connect()
wsState.subscribe<ConsumablesStateMessage>(
'ConsumablesState',
handleConsumablesState,
)
wsState.subscribe<DeviceWorkStateMessage>( wsState.subscribe<DeviceWorkStateMessage>(
'DeviceWorkState', 'DeviceWorkState',
handleDeviceState, handleDeviceState,
@ -412,7 +424,10 @@ onMounted(() => {
'TubeHolderState', 'TubeHolderState',
handleTubeHolderStateMessage, handleTubeHolderStateMessage,
) )
wsState.subscribe<TubeHolderSettingMessage>('TubeHolderSetting', handleTubeHolderSettingMessage)
wsState.subscribe<TubeHolderSettingMessage>(
'TubeHolderSetting',
handleTubeHolderSettingMessage,
)
wsState.subscribe<IncubationPlateStateMessage>( wsState.subscribe<IncubationPlateStateMessage>(
'IncubationPlateState', 'IncubationPlateState',
handleIncubationPlateStateMessage, handleIncubationPlateStateMessage,
@ -421,6 +436,8 @@ onMounted(() => {
'OptScanModuleState', 'OptScanModuleState',
handleOptScanModuleStateMessage, handleOptScanModuleStateMessage,
) )
wsState.connect()
getProjectList() getProjectList()
getBloodTypeList() getBloodTypeList()
}) })

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

@ -113,9 +113,7 @@
<script setup lang="ts"> <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 } from 'vue'
import { ref, onActivated } from 'vue'
import { import {
getInitState, getInitState,
scanConsumables, scanConsumables,
@ -128,17 +126,11 @@ import {
import { useConsumablesStore, useEmergencyStore } from '@/store' import { useConsumablesStore, useEmergencyStore } from '@/store'
import { useDeviceStore } from '@/store/index' import { useDeviceStore } from '@/store/index'
import { eventBus } from '@/eventBus' import { eventBus } from '@/eventBus'
import { createWebSocket } from '@/websocket/socket'
import type { ConsumablesStateMessage } from '@/websocket/socket'
import InitWarn from '../components/Consumables/Warn/InitWarn.vue' import InitWarn from '../components/Consumables/Warn/InitWarn.vue'
import { getServerInfo } from '@/utils/getServerInfo'
import { formatScanReports } from '@/utils/errorHandler' import { formatScanReports } from '@/utils/errorHandler'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { Subject, throttleTime } from 'rxjs' import { Subject, throttleTime } from 'rxjs'
const { wsUrl } = getServerInfo('/api/v1/app/ws/state')
const socket = createWebSocket(wsUrl)
const consumableStore = useConsumablesStore() const consumableStore = useConsumablesStore()
const emergencyStore = useEmergencyStore() const emergencyStore = useEmergencyStore()
const deviceStore = useDeviceStore() const deviceStore = useDeviceStore()
@ -179,48 +171,6 @@ const confirmWarn = () => {
showUnloadConsumableWarnModal.value = false showUnloadConsumableWarnModal.value = false
} }
//使websocket
const startWebSocket = () => {
socket.connect()
}
//false
//@ts-ignore
let hasAllConsumables = ref(false)
//
let allowDel = 0
const handleConsumablesState = (data: ConsumablesStateMessage['data']) => {
if (!allowDel) {
console.log('耗材日志------', data)
}
allowDel = 1
if (!isDragging.value) {
consumableStore.setConsumablesData(data)
// if(
// (data.tips && data.tips.length ) &&
// (data.reactionPlateGroup && data.reactionPlateGroup.length) &&
// (data.littBottleGroup && data.littBottleGroup.length) &&
// (data.larBottleGroup && data.larBottleGroup.length)
// ){
// hasAllConsumables.value = true;
// }else{
// hasAllConsumables.value = false;
// }
// //story
// consumableStore.hasAllConsumables = hasAllConsumables.value
} else {
console.log('正在拖动,不更新耗材')
}
}
onMounted(() => {
startWebSocket()
socket.subscribe<ConsumablesStateMessage>(
'ConsumablesState',
handleConsumablesState,
)
})
// //
onActivated(() => { onActivated(() => {
emergencyInfo.value = emergencyStore.$state.emergencyInfo emergencyInfo.value = emergencyStore.$state.emergencyInfo
@ -279,6 +229,7 @@ const handleUnloadAll = async () => {
// //
} }
} }
const handleUnloadConsumable = async (index: number) => { const handleUnloadConsumable = async (index: number) => {
if (deviceStore.deviceState.workState === 'WORKING') { if (deviceStore.deviceState.workState === 'WORKING') {
ElMessage.error('设备正在运行中,不可操作耗材') ElMessage.error('设备正在运行中,不可操作耗材')
@ -292,8 +243,6 @@ const handleUnloadConsumable = async (index: number) => {
} }
} }
const isDragging = ref(false)
const updateReactionPlateNum = async ({ const updateReactionPlateNum = async ({
index, index,
plateNum, plateNum,
@ -307,17 +256,19 @@ const updateReactionPlateNum = async ({
return return
} }
if (deviceStore.deviceState.workState !== 'WORKING') { if (deviceStore.deviceState.workState !== 'WORKING') {
consumableStore.setDisableUpdateConsumableData(true)
consumableStore.updateReactionPlateNum(index, plateNum) consumableStore.updateReactionPlateNum(index, plateNum)
if (sync) { if (sync) {
console.log(`🚀 ~ updatePlateNum ~ order ${index + 1}, num ${plateNum}`) console.log(`🚀 ~ updatePlateNum ~ order ${index + 1}, num ${plateNum}`)
try { try {
await updateConsumables({ group: `CG${index + 1}`, num: plateNum })
const res = await updateConsumables({ group: `CG${index + 1}`, num: plateNum })
if (!res.success) {
errMsg$.next(res.data.info || '修改耗材数量失败')
}
} catch (error) { } catch (error) {
console.error('修改耗材数量失败:', error) console.error('修改耗材数量失败:', error)
} }
isDragging.value = false
} else {
isDragging.value = true
consumableStore.setDisableUpdateConsumableData(false)
} }
} else { } else {
errMsg$.next('设备正在工作,无法修改数值') errMsg$.next('设备正在工作,无法修改数值')
@ -337,18 +288,20 @@ const updateTipNum = async ({
return return
} }
if (deviceStore.deviceState.workState !== 'WORKING') { if (deviceStore.deviceState.workState !== 'WORKING') {
consumableStore.setDisableUpdateConsumableData(true)
consumableStore.updateTipNum(index, tipNum) consumableStore.updateTipNum(index, tipNum)
if (sync) { if (sync) {
console.log(`🚀 ~ updateTipNum ~ order ${index + 1}, num ${tipNum}`) console.log(`🚀 ~ updateTipNum ~ order ${index + 1}, num ${tipNum}`)
try { try {
await updateTipsNum({ group: `TipG${index + 1}`, num: tipNum })
const res = await updateTipsNum({ group: `TipG${index + 1}`, num: tipNum })
if (!res.success) {
errMsg$.next(res.data.info || '修改耗材数量失败')
}
} catch (error) { } catch (error) {
console.error('修改耗材数量失败:', error) console.error('修改耗材数量失败:', error)
} }
isDragging.value = false
} else {
isDragging.value = true
}
consumableStore.setDisableUpdateConsumableData(false)
}
} else { } else {
errMsg$.next('设备正在工作,无法修改数值') errMsg$.next('设备正在工作,无法修改数值')
} }

8
src/pages/Index/Regular/TestTube.vue

@ -95,7 +95,7 @@ import {
useSettingTestTubeStore, useSettingTestTubeStore,
} from '../../../store' } from '../../../store'
import { ElMessage, ElDialog } from 'element-plus' import { ElMessage, ElDialog } from 'element-plus'
import { ReactionPlateGroup, TestTubeRack } from '@/websocket/socket'
import { BloodType, ReactionPlateGroup, TestTubeRack } from '@/websocket/socket'
const router = useRouter() const router = useRouter()
@ -106,7 +106,7 @@ const consumables = useConsumablesStore()
const loading = ref(false) // const loading = ref(false) //
const selectedProjIds = ref<number[]>([]) const selectedProjIds = ref<number[]>([])
const selectedBloodTypeKey = ref('WHOLE_BLOOD')
const selectedBloodTypeKey = ref<BloodType | undefined>('WHOLE_BLOOD')
const deleteRackDialogVisible = ref(false) const deleteRackDialogVisible = ref(false)
@ -143,7 +143,7 @@ const clickProjectItem = (proj: ReactionPlateGroup) => {
const clickBloodTypeItem = (type) => { const clickBloodTypeItem = (type) => {
if (selectedBloodTypeKey.value === type.key) { if (selectedBloodTypeKey.value === type.key) {
selectedBloodTypeKey.value = ''
selectedBloodTypeKey.value = undefined
} else { } else {
selectedBloodTypeKey.value = type.key selectedBloodTypeKey.value = type.key
} }
@ -275,7 +275,7 @@ const handleActivateChange = async (index: number) => {
} }
} }
const updateTubeSettings = async (rackIdx:number, tubeIdx:number) => {
const updateTubeSettings = async (rackIdx: number, tubeIdx: number) => {
if (!selectedBloodTypeKey.value) { if (!selectedBloodTypeKey.value) {
ElMessage.error('请选择血液类型') ElMessage.error('请选择血液类型')
return return

9
src/services/Index/idCard.ts

@ -27,15 +27,6 @@ export const saveMountedCardInfo = async () => {
console.log('保存id出错', error) console.log('保存id出错', error)
} }
} }
// //id卡事件
// export const IdCardEvent = async () => {
// try {
// const res = await apiClient.post('/api/v1/idcard/event')
// return res.data
// } catch (error) {
// console.log('id卡事件出错', error)
// }
// }
//读取已经挂载的id卡信息 //读取已经挂载的id卡信息
export const getMountedCardInfo = async () => { export const getMountedCardInfo = async () => {

10
src/services/Index/init.ts

@ -1,15 +1,5 @@
import apiClient from '../../utils/axios' import apiClient from '../../utils/axios'
//设备检查api
// export const getCheckList = async () => {
// try {
// const res = await apiClient.post('/api/v1/app/deviceInit/check')
// return res.data
// } catch (error) {
// console.log('设备检查接口出错', error)
// }
// }
//设备初始化 //设备初始化
export const initDevice = async () => { export const initDevice = async () => {
try { try {

19
src/services/Index/regular.ts

@ -6,7 +6,6 @@ export const scanConsumables = async () => {
const res = await apiClient.post( const res = await apiClient.post(
'/api/v1/app/consumableScan/scanConsumables', '/api/v1/app/consumableScan/scanConsumables',
) )
console.log('耗材扫描接口', res)
return res.data return res.data
} catch (error) { } catch (error) {
console.log(error) console.log(error)
@ -36,30 +35,14 @@ export const unloadConsumable = async (params: {
) )
return res.data return res.data
} }
//耗材扫描单组
// export const oneScanConsumable = async (data: oneConsumableParams) => {
// try {
// const res = await apiClient.post(
// '/api/v1/app/consumableScan/oneScanConsumable',
// {
// ...data,
// },
// )
// console.log('单组扫描返回结果:', res)
// return res.data
// } catch (error) {
// console.log('单组扫描出错:', error)
// }
// }
//修改耗材数量 //修改耗材数量
export const updateConsumables = async (data: any) => { export const updateConsumables = async (data: any) => {
console.log('🚀 ~ updateConsumables ~ data:', data)
const { group, num } = data const { group, num } = data
try { try {
const res = await apiClient.post( const res = await apiClient.post(
`/api/v1/app/consumablesMgr/setCounsumableNum?group=${group}&num=${num}`, `/api/v1/app/consumablesMgr/setCounsumableNum?group=${group}&num=${num}`,
) )
console.log('修改耗材参数', data)
return res.data return res.data
} catch (error) { } catch (error) {
console.log(error) console.log(error)

4
src/services/Index/testTube.ts

@ -1,5 +1,6 @@
import apiClient from '../../utils/axios' import apiClient from '../../utils/axios'
import type { TubeActivationStatus, TubeSetting } from '../../types/Index'
import type { TubeActivationStatus } from '../../types/Index'
import { TubeSetting } from '@/websocket/socket'
/* /*
"data": [ "data": [
{ {
@ -105,7 +106,6 @@ export const updateTubeConfig = async (config: {
uuid: string uuid: string
setting: TubeSetting[] setting: TubeSetting[]
}) => { }) => {
console.log('🚀 ~ updateTubeConfig ~ config:', config)
try { try {
const res = await apiClient.post( const res = await apiClient.post(
'/api/v1/app/appTubeSettingMgr/updateTubeSetting', '/api/v1/app/appTubeSettingMgr/updateTubeSetting',

1
src/services/Index/user-manage.ts

@ -52,7 +52,6 @@ export const getCurrentUserInfo = async (params: any) => {
//删除用户 //删除用户
export const deleteUser = async (params: any) => { export const deleteUser = async (params: any) => {
console.log('🚀 ~ deleteUser ~ params:', params)
const { id } = params const { id } = params
try { try {
const res = await apiClient.post(`/api/v1/app/Usr/delUser?id=${id}`) const res = await apiClient.post(`/api/v1/app/Usr/delUser?id=${id}`)

85
src/store/modules/consumables.ts

@ -13,16 +13,23 @@ import type {
ReactionPlateGroup, ReactionPlateGroup,
} from '../../websocket/socket' } from '../../websocket/socket'
const projColorExt = ['#A98A7B', '#424E82', '#2D4E4A', '#493E25', '#001DDC']
const projColor10 = [
'#B9C950',
'#AC91D2',
'#CA9B36',
'#6BA4A6',
'#87957E',
'#4D86BA',
'#83746D',
'#785FA8',
'#AAA192',
'#F5B43F',
]
export const useConsumablesStore = defineStore( export const useConsumablesStore = defineStore(
'consumables', 'consumables',
() => { () => {
// 定义状态
// const isLoad = ref(false)
// const moveLiquids = ref<TipInfo[]>([])
// const plates = ref<ConsumableGroupBase[]>([])
// const bufferLittles = ref<LittleBottleGroup[]>([])
// const bufferBig = ref<LargeBottleGroup[]>([])
// @ts-ignore
const consumableData = ref<ConsumablesStateMessage['data']>({ const consumableData = ref<ConsumablesStateMessage['data']>({
tips: [{ tipNum: 0 }, { tipNum: 0 }, { tipNum: 0 }], tips: [{ tipNum: 0 }, { tipNum: 0 }, { tipNum: 0 }],
reactionPlateGroup: Array.from({ length: 6 }, () => ({ reactionPlateGroup: Array.from({ length: 6 }, () => ({
@ -41,10 +48,19 @@ export const useConsumablesStore = defineStore(
//id卡是否插入 //id卡是否插入
const isIdCardInserted = ref(false) const isIdCardInserted = ref(false)
// 设置数据的 action
let disableUpdateConsumableData: Boolean = false
const setDisableUpdateConsumableData = (disable: Boolean) => {
disableUpdateConsumableData = disable
}
function setConsumablesData(data: ConsumablesStateMessage['data']) { function setConsumablesData(data: ConsumablesStateMessage['data']) {
// isLoad.value = true // 设置为已加载状态
consumableData.value = data
if (disableUpdateConsumableData) {
return
}
if (!R.equals(consumableData.value, data)) {
consumableData.value = data
console.log('更新耗材:', data)
}
} }
function updateTipNum(index: number, num: number) { function updateTipNum(index: number, num: number) {
@ -63,7 +79,7 @@ export const useConsumablesStore = defineStore(
} }
const projectsAvailable = computed(() => { const projectsAvailable = computed(() => {
// @ts-ignore
//@ts-ignore
const group = R.groupBy( const group = R.groupBy(
(p) => p.projName, (p) => p.projName,
consumableData.value.reactionPlateGroup, consumableData.value.reactionPlateGroup,
@ -87,6 +103,50 @@ export const useConsumablesStore = defineStore(
return acc + curr.tipNum return acc + curr.tipNum
}, 0) }, 0)
}) })
const projectIds = computed(() => {
return R.pipe(
//@ts-ignore
R.filter((g) => g.projId !== null),
//@ts-ignore
R.map((g) => g.projId),
R.uniq,
R.sort((a, b) => {
return a - b
}),
)(consumableData.value.reactionPlateGroup)
})
const projIdColorMap = computed(() => {
const color10UsedMap = {}
const colorExtUsedMap = {}
const idColorMap = R.reduce(
(acc, pId) => {
const n = pId % 10
const color = projColor10[n]
if (!color10UsedMap[color]) {
color10UsedMap[color] = true
acc[pId] = color
} else {
const color = projColorExt.find((c) => {
if (!colorExtUsedMap[c]) {
colorExtUsedMap[c] = true
return true
}
return false
})
acc[pId] = color
}
return acc
},
{},
projectIds.value,
)
console.log('====== consumables : idColorMap :', idColorMap)
return idColorMap
})
//所有耗材都存在 //所有耗材都存在
let hasAllConsumables = ref(false) let hasAllConsumables = ref(false)
@ -98,10 +158,13 @@ export const useConsumablesStore = defineStore(
setConsumablesData, setConsumablesData,
updateReactionPlateNum, updateReactionPlateNum,
updateTipNum, updateTipNum,
setDisableUpdateConsumableData,
tipCount, tipCount,
projectsAvailable, projectsAvailable,
projIdColorMap,
hasAllConsumables, hasAllConsumables,
} }
}, },

24
src/websocket/socket.ts

@ -64,6 +64,8 @@ export interface FooterMessageState extends BaseMessage {
} }
} }
export type BloodType = 'WHOLE_BLOOD' | 'SERUM_OR_PLASMA'
type WorkState = 'IDLE' | 'WORKING' | 'PAUSE' type WorkState = 'IDLE' | 'WORKING' | 'PAUSE'
// 设备工作状态消息 // 设备工作状态消息
interface DeviceWorkStateMessage extends BaseMessage { interface DeviceWorkStateMessage extends BaseMessage {
@ -101,7 +103,7 @@ interface EmergencyPosStateMessage extends BaseMessage {
pos: number // 位置 pos: number // 位置
isHighTube: boolean // 是否为高试管 isHighTube: boolean // 是否为高试管
isEmergency: boolean // 是否为急诊 isEmergency: boolean // 是否为急诊
bloodType: 'WHOLE_BLOOD' | 'SERUM_OR_PLASMA' // 血液类型
bloodType: BloodType // 血液类型
sampleBarcode: string // 样本条码 sampleBarcode: string // 样本条码
userid: string // 用户ID userid: string // 用户ID
projInfo: ProjectInfo[] // 项目信息列表 projInfo: ProjectInfo[] // 项目信息列表
@ -113,20 +115,6 @@ interface EmergencyPosStateMessage extends BaseMessage {
timestamp: number timestamp: number
} }
// 试管信息接口
// interface Tube {
// sampleId: string | null // 样本ID
// pos: number // 位置
// isHighTube: boolean // 是否为高试管
// isEmergency: boolean // 是否为急诊
// bloodType: 'WHOLE_BLOOD' | 'SERUM_OR_PLASMA' // 血液类型
// sampleBarcode: string // 样本条码
// userid: string // 用户ID
// projInfo: ProjectInfo[] // 项目信息列表
// projIds: number[] // 项目ID列表
// state: 'EMPTY' | 'OCCUPIED' // 状态
// errors: string[] // 错误信息列表
// }
export type RunningTubeState = export type RunningTubeState =
| 'EMPTY' | 'EMPTY'
@ -158,7 +146,7 @@ interface TubeHolderStateMessage extends BaseMessage {
pos: number pos: number
isHighTube: boolean isHighTube: boolean
isEmergency: boolean isEmergency: boolean
bloodType: 'WHOLE_BLOOD' | 'SERUM_OR_PLASMA'
bloodType: BloodType
sampleBarcode: string sampleBarcode: string
userid: string userid: string
projInfo: ProjectInfo[] projInfo: ProjectInfo[]
@ -176,7 +164,7 @@ export interface TubeSetting {
userid: string userid: string
sampleBarcode: string sampleBarcode: string
projId: number[] projId: number[]
bloodType: 'WHOLE_BLOOD' | 'SERUM_OR_PLASMA'
bloodType: BloodType
} }
export interface TestTubeRack { export interface TestTubeRack {
uuid: string uuid: string
@ -223,7 +211,7 @@ export type SubTankState =
export interface SubTank { export interface SubTank {
pos: string // 位置编号 SPACE01-SPACE20 pos: string // 位置编号 SPACE01-SPACE20
state: SubTankState // 槽位状态 state: SubTankState // 槽位状态
bloodType: 'WHOLE_BLOOD' | 'SERUM_OR_PLASMA' // 血液类型
bloodType: BloodType // 血液类型
sampleBarcode: string // 样本条码 sampleBarcode: string // 样本条码
lotId: string lotId: string
userid: string // 用户ID userid: string // 用户ID

Loading…
Cancel
Save