A8000
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

371 lines
10 KiB

8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
  1. <template>
  2. <div id="configuration-container" v-loading="loading">
  3. <!-- 渲染试管架列表 -->
  4. <div class="tube-rack-list">
  5. <div v-for="(tubeRack, index) in tubeRacks" :key="`${tubeRack.uuid || index}-${componentRefreshKey}`"
  6. class="tube-rack-container">
  7. <TestTubeRack ref="tubeRackComponentInstance" :tubeRack="tubeRack" :plates="plates" :key="refreshKey"
  8. @updateActivate="handleActivateChange" @updateSelectedSamples="handleUpdateSelectedSamples"
  9. @deleteTubeRack="deleteHandle" @changeUser="handleChangeUser"
  10. @clearProjectSelection="clearProjectSelection" />
  11. </div>
  12. </div>
  13. <!-- 添加试管架按钮 -->
  14. <div class="add-tube" @click="addTubeRack">
  15. <div class="icon">
  16. <img src="@/assets/add.svg" alt="Add Icon" />
  17. </div>
  18. <div class="text">添加试管架</div>
  19. </div>
  20. <!-- 试管信息编辑 -->
  21. <ProjectSelector :uuid="UUID" v-model:visible="showProjectSelector" :selectedSampleIds="selectedSampleIdsInParent"
  22. @updateSample="handleSampleUpdate" @confirm="handleConfirmProjectSelector" @cancel="closeProjectSelector"
  23. @clearSelection="clearProjectSelection" />
  24. </div>
  25. </template>
  26. <script setup lang="ts">
  27. import { ref, onMounted, nextTick } from 'vue'
  28. import { useRouter } from 'vue-router'
  29. import TestTubeRack from '../components/TestTube/TestTubeRack.vue'
  30. import {
  31. addTestTube,
  32. getTestTube,
  33. getProjectInfo,
  34. deleteTube,
  35. updateTubeConfig,
  36. } from '../../../services/Index/Test-tube/test-tube'
  37. import type {
  38. DataItem,
  39. TubeSetting,
  40. } from '../../../types/Index/index'
  41. import { ConsumableGroupBase } from '../../../websocket/socket'
  42. import ProjectSelector from '../components/Consumables/ProjectSelector.vue'
  43. import { useConsumablesStore, useTestTubeStore, useSettingTestTubeStore } from '../../../store'
  44. import { ElMessage } from 'element-plus'
  45. const router = useRouter()
  46. const testTubeStore = useTestTubeStore()
  47. const settingTestTubeStore = useSettingTestTubeStore()
  48. const consumables = useConsumablesStore()
  49. const tubeRacks = ref<DataItem[]>([])
  50. const loading = ref(false) // 控制加载状态
  51. const plates = ref<ConsumableGroupBase[]>(consumables.plates)
  52. const refreshKey = ref(0)
  53. const selectedUUID = ref<string>('')
  54. // 初始化获取试管架数据
  55. onMounted(() => {
  56. getTubeData()
  57. getProjectInfoData()
  58. })
  59. //获取设备支持的项目信息
  60. const getProjectInfoData = async () => {
  61. const res = await getProjectInfo()
  62. if (res.success) {
  63. console.log(res.data)
  64. }
  65. }
  66. //获取已经配置的试管信息
  67. const getTubeData = async () => {
  68. loading.value = true
  69. const res = await getTestTube()
  70. if (res.success) {
  71. // 初始化每个试管架的选中状态
  72. tubeRacks.value = res.data.map((rack: DataItem) => ({
  73. ...rack,
  74. selectedSampleIds: [], // 初始化选中状态数组
  75. }))
  76. }
  77. loading.value = false
  78. }
  79. const selectedProject = ref<string | null>(null)
  80. // 添加事件监听,用于清空项目选择状态
  81. const clearProjectSelection = () => {
  82. selectedProject.value = null // 清空选中的项目状态
  83. }
  84. //编辑患者信息
  85. const handleChangeUser = async (uuid: string) => {
  86. selectedUUID.value = uuid
  87. const selectedTube = tubeRacks.value.find((t) => t.uuid === selectedUUID.value)
  88. if (!selectedTube) return
  89. testTubeStore.setTubeInfo(selectedTube)
  90. await updateTubeSettingsHandler()
  91. router.push({
  92. path: '/index/change-user',
  93. })
  94. }
  95. //删除试管架
  96. const deleteHandle = async (uuid: string) => {
  97. const res = await deleteTube(uuid)
  98. if (res.success) {
  99. ElMessage({
  100. message: '删除成功',
  101. type: 'success',
  102. })
  103. getTubeData()
  104. } else {
  105. ElMessage({
  106. message: '删除失败',
  107. type: 'error',
  108. })
  109. }
  110. }
  111. // 添加新试管架
  112. const addTubeRack = async () => {
  113. loading.value = true // 开始加载
  114. const newTubeRack: DataItem = {
  115. uuid: `uuid-${Date.now()}`,
  116. active: false,
  117. lock: false,
  118. tubeSettings: Array.from({ length: 10 }, (_, index) => ({
  119. tubeIndex: index,
  120. userid: '',
  121. sampleBarcode: '',
  122. projId: [],
  123. bloodType: 'WHOLE_BLOOD',
  124. })),
  125. selectedSampleIds: [],
  126. }
  127. // 直接将新试管架添加到 tubeRacks 中
  128. tubeRacks.value.push(newTubeRack)
  129. // 向服务端发送添加请求
  130. const response = await addTestTube()
  131. if (response && response.success) {
  132. // 更新 tubeRacks 列表为最新数据,避免闪烁
  133. tubeRacks.value = [...tubeRacks.value]
  134. } else {
  135. console.error('试管架添加失败')
  136. }
  137. loading.value = false // 加载结束
  138. }
  139. // 处理试管架激活状态变化
  140. const handleActivateChange = (update: { uuid: string; active: boolean }) => {
  141. const rack = tubeRacks.value.find((t) => t.uuid === update.uuid)
  142. if (rack) {
  143. rack.active = update.active
  144. }
  145. }
  146. const handleSampleUpdate = async ({
  147. projectIds,
  148. bloodType,
  149. }: {
  150. projectIds: number[]
  151. bloodType: string
  152. }): Promise<void> => {
  153. if (selectedSampleIdsInParent.value.length > 0) {
  154. // 创建 tubeRacks 的深拷贝
  155. const updatedTubeRacks = JSON.parse(JSON.stringify(tubeRacks.value))
  156. // 找到对应的 tubeRack
  157. const targetTubeRack = updatedTubeRacks.find(
  158. (t: DataItem) => t.uuid === UUID.value,
  159. )
  160. if (targetTubeRack) {
  161. targetTubeRack.tubeSettings = targetTubeRack.tubeSettings.map(
  162. (tube: TubeSetting) => {
  163. if (selectedSampleIdsInParent.value.includes(tube.tubeIndex)) {
  164. return {
  165. ...tube,
  166. projId: [...projectIds],
  167. bloodType: bloodType,
  168. }
  169. }
  170. return tube
  171. },
  172. )
  173. // 清空数组再重新赋值,确保响应式更新
  174. tubeRacks.value = []
  175. await nextTick()
  176. tubeRacks.value = updatedTubeRacks// 新赋值触发响应式
  177. console.log("🚀 ~ handleSampleUpdate ~ updatedTubeRacks:", updatedTubeRacks)
  178. const selectedTube = updatedTubeRacks.find((t: any) => t.uuid === UUID.value)
  179. console.log("🚀 ~ handleSampleUpdate ~ selectedTube:", selectedTube)
  180. testTubeStore.setTubeInfo(selectedTube)
  181. console.log("🚀 ~ handleSampleUpdate ~ testTubeStore.$state.tubeInfo:", testTubeStore.$state.tubeInfo)
  182. selectedProject.value = null // 选择后清空选中状态
  183. await nextTick()
  184. ElMessage({
  185. message: '样本信息已更新',
  186. type: 'success',
  187. duration: 2000,
  188. })
  189. }
  190. } else {
  191. ElMessage({
  192. message: '请先选择样本后再选择项目',
  193. type: 'warning',
  194. duration: 2000,
  195. })
  196. }
  197. }
  198. //声明组件实例
  199. const UUID = ref<string>('')
  200. // 当前选中的样本ID列表
  201. const selectedSampleIdsInParent = ref<number[]>([])
  202. // 添加一个刷新key
  203. const componentRefreshKey = ref(0)
  204. // 修改 handleConfirmProjectSelector 函数
  205. const handleConfirmProjectSelector = async () => {
  206. await updateTubeSettingsHandler()
  207. // 清空父组件选中样本列表
  208. selectedSampleIdsInParent.value = []
  209. // 找到当前操作的试管架并清空其选中状态
  210. const currentTubeRack = tubeRacks.value.find(rack => rack.uuid === UUID.value)
  211. if (currentTubeRack) {
  212. currentTubeRack.selectedSampleIds = []
  213. }
  214. // 重置其他相关状态
  215. showProjectSelector.value = false
  216. UUID.value = ''
  217. ElMessage({
  218. message: '样本已确认,选中状态已清空',
  219. type: 'success',
  220. duration: 2000,
  221. })
  222. }
  223. const tubeRackComponentInstance = ref()
  224. const showProjectSelector = ref(false)
  225. // 修改关闭项目选择器的方法
  226. const closeProjectSelector = () => {
  227. // 找到当前操作的试管架并清空其选中状态
  228. const currentTubeRack = tubeRacks.value.find(rack => rack.uuid === UUID.value)
  229. if (currentTubeRack) {
  230. currentTubeRack.selectedSampleIds = []
  231. }
  232. // 重置所有相关状态
  233. selectedSampleIdsInParent.value = []
  234. showProjectSelector.value = false
  235. UUID.value = ''
  236. }
  237. // 父组件代码
  238. const handleUpdateSelectedSamples = ({ sampleIds, uuid }: { sampleIds: number[]; uuid: string }) => {
  239. // 更新特定试管架的选中状态
  240. const tubeRack = tubeRacks.value.find(tube => tube.uuid === uuid)
  241. if (tubeRack) {
  242. // 如果是取消选中(sampleIds为空),则关闭弹窗并清空状态
  243. if (sampleIds.length === 0) {
  244. showProjectSelector.value = false
  245. selectedSampleIdsInParent.value = []
  246. tubeRack.selectedSampleIds = []
  247. UUID.value = ''
  248. } else {
  249. // 如果是新选中,则更新状态并打开弹窗
  250. tubeRack.selectedSampleIds = sampleIds
  251. selectedSampleIdsInParent.value = sampleIds
  252. UUID.value = uuid
  253. showProjectSelector.value = true
  254. }
  255. }
  256. }
  257. // 添加更新试管设置的方法
  258. const updateTubeSettingsHandler = async () => {
  259. const { uuid, setting } = settingTestTubeStore.currentConfig
  260. if (uuid && setting.tubeIndex >= 0) {
  261. try {
  262. const response = await updateTubeConfig({ uuid, setting })
  263. if (response.success) {
  264. ElMessage.success('设置更新成功')
  265. console.log(tubeRacks.value)
  266. settingTestTubeStore.clearConfig()
  267. } else {
  268. ElMessage.error('设置更新失败')
  269. }
  270. } catch (error) {
  271. console.error('更新试管设置失败:', error)
  272. ElMessage.error('设置更新失败')
  273. }
  274. }
  275. }
  276. </script>
  277. <style scoped lang="less">
  278. #configuration-container {
  279. position: relative;
  280. .el-message {
  281. width: 200px;
  282. height: 200px;
  283. }
  284. /* 主容器定高和滚动条样式 */
  285. .tube-rack-list {
  286. max-height: 1200px;
  287. /* 根据需要设置主容器的最大高度 */
  288. overflow-y: auto;
  289. overflow-x: hidden;
  290. width: 100%;
  291. box-sizing: border-box;
  292. /* 自定义滚动条样式 */
  293. &::-webkit-scrollbar {
  294. width: 8px;
  295. }
  296. &::-webkit-scrollbar-track {
  297. background: #f1f1f1;
  298. }
  299. &::-webkit-scrollbar-thumb {
  300. background: #888;
  301. border-radius: 4px;
  302. }
  303. &::-webkit-scrollbar-thumb:hover {
  304. background: #555;
  305. }
  306. }
  307. .add-tube {
  308. width: 100%;
  309. height: 100px;
  310. background-color: #f6f6f6;
  311. display: flex;
  312. align-items: center;
  313. justify-content: center;
  314. .icon {
  315. width: 60px;
  316. height: 100px;
  317. margin-right: 40px;
  318. }
  319. .text {
  320. font-size: 32px;
  321. color: #73bc54;
  322. font-weight: bold;
  323. }
  324. }
  325. /* 加载状态样式 */
  326. .loading-overlay {
  327. position: fixed;
  328. top: 0;
  329. left: 0;
  330. width: 100%;
  331. height: 100vh;
  332. display: flex;
  333. align-items: center;
  334. justify-content: center;
  335. background-color: rgba(255, 255, 255, 0.8);
  336. font-size: 24px;
  337. color: #333;
  338. z-index: 1000;
  339. }
  340. }
  341. </style>