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

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

@ -113,9 +113,7 @@
<script setup lang="ts">
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 {
getInitState,
scanConsumables,
@ -128,17 +126,11 @@ import {
import { useConsumablesStore, useEmergencyStore } from '@/store'
import { useDeviceStore } from '@/store/index'
import { eventBus } from '@/eventBus'
import { createWebSocket } from '@/websocket/socket'
import type { ConsumablesStateMessage } from '@/websocket/socket'
import InitWarn from '../components/Consumables/Warn/InitWarn.vue'
import { getServerInfo } from '@/utils/getServerInfo'
import { formatScanReports } from '@/utils/errorHandler'
import { ElMessage } from 'element-plus'
import { Subject, throttleTime } from 'rxjs'
const { wsUrl } = getServerInfo('/api/v1/app/ws/state')
const socket = createWebSocket(wsUrl)
const consumableStore = useConsumablesStore()
const emergencyStore = useEmergencyStore()
const deviceStore = useDeviceStore()
@ -179,48 +171,6 @@ const confirmWarn = () => {
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(() => {
emergencyInfo.value = emergencyStore.$state.emergencyInfo
@ -279,6 +229,7 @@ const handleUnloadAll = async () => {
//
}
}
const handleUnloadConsumable = async (index: number) => {
if (deviceStore.deviceState.workState === 'WORKING') {
ElMessage.error('设备正在运行中,不可操作耗材')
@ -292,8 +243,6 @@ const handleUnloadConsumable = async (index: number) => {
}
}
const isDragging = ref(false)
const updateReactionPlateNum = async ({
index,
plateNum,
@ -307,17 +256,19 @@ const updateReactionPlateNum = async ({
return
}
if (deviceStore.deviceState.workState !== 'WORKING') {
consumableStore.setDisableUpdateConsumableData(true)
consumableStore.updateReactionPlateNum(index, plateNum)
if (sync) {
console.log(`🚀 ~ updatePlateNum ~ order ${index + 1}, num ${plateNum}`)
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) {
console.error('修改耗材数量失败:', error)
}
isDragging.value = false
} else {
isDragging.value = true
consumableStore.setDisableUpdateConsumableData(false)
}
} else {
errMsg$.next('设备正在工作,无法修改数值')
@ -337,18 +288,20 @@ const updateTipNum = async ({
return
}
if (deviceStore.deviceState.workState !== 'WORKING') {
consumableStore.setDisableUpdateConsumableData(true)
consumableStore.updateTipNum(index, tipNum)
if (sync) {
console.log(`🚀 ~ updateTipNum ~ order ${index + 1}, num ${tipNum}`)
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) {
console.error('修改耗材数量失败:', error)
}
isDragging.value = false
} else {
isDragging.value = true
}
consumableStore.setDisableUpdateConsumableData(false)
}
} else {
errMsg$.next('设备正在工作,无法修改数值')
}

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

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

9
src/services/Index/idCard.ts

@ -27,15 +27,6 @@ export const saveMountedCardInfo = async () => {
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卡信息
export const getMountedCardInfo = async () => {

10
src/services/Index/init.ts

@ -1,15 +1,5 @@
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 () => {
try {

19
src/services/Index/regular.ts

@ -6,7 +6,6 @@ export const scanConsumables = async () => {
const res = await apiClient.post(
'/api/v1/app/consumableScan/scanConsumables',
)
console.log('耗材扫描接口', res)
return res.data
} catch (error) {
console.log(error)
@ -36,30 +35,14 @@ export const unloadConsumable = async (params: {
)
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) => {
console.log('🚀 ~ updateConsumables ~ data:', data)
const { group, num } = data
try {
const res = await apiClient.post(
`/api/v1/app/consumablesMgr/setCounsumableNum?group=${group}&num=${num}`,
)
console.log('修改耗材参数', data)
return res.data
} catch (error) {
console.log(error)

4
src/services/Index/testTube.ts

@ -1,5 +1,6 @@
import apiClient from '../../utils/axios'
import type { TubeActivationStatus, TubeSetting } from '../../types/Index'
import type { TubeActivationStatus } from '../../types/Index'
import { TubeSetting } from '@/websocket/socket'
/*
"data": [
{
@ -105,7 +106,6 @@ export const updateTubeConfig = async (config: {
uuid: string
setting: TubeSetting[]
}) => {
console.log('🚀 ~ updateTubeConfig ~ config:', config)
try {
const res = await apiClient.post(
'/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) => {
console.log('🚀 ~ deleteUser ~ params:', params)
const { id } = params
try {
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,
} 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(
'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']>({
tips: [{ tipNum: 0 }, { tipNum: 0 }, { tipNum: 0 }],
reactionPlateGroup: Array.from({ length: 6 }, () => ({
@ -41,10 +48,19 @@ export const useConsumablesStore = defineStore(
//id卡是否插入
const isIdCardInserted = ref(false)
// 设置数据的 action
let disableUpdateConsumableData: Boolean = false
const setDisableUpdateConsumableData = (disable: Boolean) => {
disableUpdateConsumableData = disable
}
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) {
@ -63,7 +79,7 @@ export const useConsumablesStore = defineStore(
}
const projectsAvailable = computed(() => {
// @ts-ignore
//@ts-ignore
const group = R.groupBy(
(p) => p.projName,
consumableData.value.reactionPlateGroup,
@ -87,6 +103,50 @@ export const useConsumablesStore = defineStore(
return acc + curr.tipNum
}, 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)
@ -98,10 +158,13 @@ export const useConsumablesStore = defineStore(
setConsumablesData,
updateReactionPlateNum,
updateTipNum,
setDisableUpdateConsumableData,
tipCount,
projectsAvailable,
projIdColorMap,
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'
// 设备工作状态消息
interface DeviceWorkStateMessage extends BaseMessage {
@ -101,7 +103,7 @@ interface EmergencyPosStateMessage extends BaseMessage {
pos: number // 位置
isHighTube: boolean // 是否为高试管
isEmergency: boolean // 是否为急诊
bloodType: 'WHOLE_BLOOD' | 'SERUM_OR_PLASMA' // 血液类型
bloodType: BloodType // 血液类型
sampleBarcode: string // 样本条码
userid: string // 用户ID
projInfo: ProjectInfo[] // 项目信息列表
@ -113,20 +115,6 @@ interface EmergencyPosStateMessage extends BaseMessage {
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 =
| 'EMPTY'
@ -158,7 +146,7 @@ interface TubeHolderStateMessage extends BaseMessage {
pos: number
isHighTube: boolean
isEmergency: boolean
bloodType: 'WHOLE_BLOOD' | 'SERUM_OR_PLASMA'
bloodType: BloodType
sampleBarcode: string
userid: string
projInfo: ProjectInfo[]
@ -176,7 +164,7 @@ export interface TubeSetting {
userid: string
sampleBarcode: string
projId: number[]
bloodType: 'WHOLE_BLOOD' | 'SERUM_OR_PLASMA'
bloodType: BloodType
}
export interface TestTubeRack {
uuid: string
@ -223,7 +211,7 @@ export type SubTankState =
export interface SubTank {
pos: string // 位置编号 SPACE01-SPACE20
state: SubTankState // 槽位状态
bloodType: 'WHOLE_BLOOD' | 'SERUM_OR_PLASMA' // 血液类型
bloodType: BloodType // 血液类型
sampleBarcode: string // 样本条码
lotId: string
userid: string // 用户ID

Loading…
Cancel
Save