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.

369 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
  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. ReactionPlate,
  40. TubeSetting,
  41. } from '../../../types/Index/index'
  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<ReactionPlate[]>(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. // 先等待当前的更新完成
  88. await updateTubeSettingsHandler()
  89. router.push({
  90. path: '/index/change-user',
  91. })
  92. }
  93. //删除试管架
  94. const deleteHandle = async (uuid: string) => {
  95. const res = await deleteTube(uuid)
  96. if (res.success) {
  97. ElMessage({
  98. message: '删除成功',
  99. type: 'success',
  100. })
  101. getTubeData()
  102. } else {
  103. ElMessage({
  104. message: '删除失败',
  105. type: 'error',
  106. })
  107. }
  108. }
  109. // 添加新试管架
  110. const addTubeRack = async () => {
  111. loading.value = true // 开始加载
  112. const newTubeRack: DataItem = {
  113. uuid: `uuid-${Date.now()}`,
  114. active: false,
  115. lock: false,
  116. tubeSettings: Array.from({ length: 10 }, (_, index) => ({
  117. tubeIndex: index,
  118. userid: '',
  119. sampleBarcode: '',
  120. projId: [],
  121. bloodType: 'WHOLE_BLOOD',
  122. })),
  123. selectedSampleIds: [],
  124. }
  125. // 直接将新试管架添加到 tubeRacks 中
  126. tubeRacks.value.push(newTubeRack)
  127. // 向服务端发送添加请求
  128. const response = await addTestTube()
  129. if (response && response.success) {
  130. // 更新 tubeRacks 列表为最新数据,避免闪烁
  131. tubeRacks.value = [...tubeRacks.value]
  132. } else {
  133. console.error('试管架添加失败')
  134. }
  135. loading.value = false // 加载结束
  136. }
  137. // 处理试管架激活状态变化
  138. const handleActivateChange = (update: { uuid: string; active: boolean }) => {
  139. const rack = tubeRacks.value.find((t) => t.uuid === update.uuid)
  140. if (rack) {
  141. rack.active = update.active
  142. }
  143. }
  144. const handleSampleUpdate = async ({
  145. projectIds,
  146. bloodType,
  147. }: {
  148. projectIds: number[]
  149. bloodType: string
  150. }): Promise<void> => {
  151. if (selectedSampleIdsInParent.value.length > 0) {
  152. // 创建 tubeRacks 的深拷贝
  153. const updatedTubeRacks = JSON.parse(JSON.stringify(tubeRacks.value))
  154. // 找到对应的 tubeRack
  155. const targetTubeRack = updatedTubeRacks.find(
  156. (t: DataItem) => t.uuid === UUID.value,
  157. )
  158. if (targetTubeRack) {
  159. targetTubeRack.tubeSettings = targetTubeRack.tubeSettings.map(
  160. (tube: TubeSetting) => {
  161. if (selectedSampleIdsInParent.value.includes(tube.tubeIndex)) {
  162. return {
  163. ...tube,
  164. projId: [...projectIds],
  165. bloodType: bloodType,
  166. }
  167. }
  168. return tube
  169. },
  170. )
  171. // 清空数组再重新赋值,确保响应式更新
  172. tubeRacks.value = []
  173. await nextTick()
  174. tubeRacks.value = updatedTubeRacks// 新赋值触发响应式
  175. console.log("🚀 ~ handleSampleUpdate ~ updatedTubeRacks:", updatedTubeRacks)
  176. const selectedTube = updatedTubeRacks.find((t: any) => t.uuid === UUID.value)
  177. console.log("🚀 ~ handleSampleUpdate ~ selectedTube:", selectedTube)
  178. testTubeStore.setTubeInfo(selectedTube)
  179. console.log("🚀 ~ handleSampleUpdate ~ testTubeStore.$state.tubeInfo:", testTubeStore.$state.tubeInfo)
  180. selectedProject.value = null // 选择后清空选中状态
  181. await nextTick()
  182. ElMessage({
  183. message: '样本信息已更新',
  184. type: 'success',
  185. duration: 2000,
  186. })
  187. }
  188. } else {
  189. ElMessage({
  190. message: '请先选择样本后再选择项目',
  191. type: 'warning',
  192. duration: 2000,
  193. })
  194. }
  195. }
  196. //声明组件实例
  197. const projectSelectorInstance = ref()
  198. const UUID = ref<string>('')
  199. // 当前选中的样本ID列表
  200. const selectedSampleIdsInParent = ref<number[]>([])
  201. // 添加一个刷新key
  202. const componentRefreshKey = ref(0)
  203. // 修改 handleConfirmProjectSelector 函数
  204. const handleConfirmProjectSelector = async () => {
  205. await updateTubeSettingsHandler()
  206. // 清空父组件选中样本列表
  207. selectedSampleIdsInParent.value = []
  208. // 找到当前操作的试管架并清空其选中状态
  209. const currentTubeRack = tubeRacks.value.find(rack => rack.uuid === UUID.value)
  210. if (currentTubeRack) {
  211. currentTubeRack.selectedSampleIds = []
  212. }
  213. // 重置其他相关状态
  214. showProjectSelector.value = false
  215. UUID.value = ''
  216. ElMessage({
  217. message: '样本已确认,选中状态已清空',
  218. type: 'success',
  219. duration: 2000,
  220. })
  221. }
  222. const tubeRackComponentInstance = ref()
  223. const showProjectSelector = ref(false)
  224. // 修改关闭项目选择器的方法
  225. const closeProjectSelector = () => {
  226. // 找到当前操作的试管架并清空其选中状态
  227. const currentTubeRack = tubeRacks.value.find(rack => rack.uuid === UUID.value)
  228. if (currentTubeRack) {
  229. currentTubeRack.selectedSampleIds = []
  230. }
  231. // 重置所有相关状态
  232. selectedSampleIdsInParent.value = []
  233. showProjectSelector.value = false
  234. UUID.value = ''
  235. }
  236. // 父组件代码
  237. const handleUpdateSelectedSamples = ({ sampleIds, uuid }: { sampleIds: number[]; uuid: string }) => {
  238. // 更新特定试管架的选中状态
  239. const tubeRack = tubeRacks.value.find(tube => tube.uuid === uuid)
  240. if (tubeRack) {
  241. // 如果是取消选中(sampleIds为空),则关闭弹窗并清空状态
  242. if (sampleIds.length === 0) {
  243. showProjectSelector.value = false
  244. selectedSampleIdsInParent.value = []
  245. tubeRack.selectedSampleIds = []
  246. UUID.value = ''
  247. } else {
  248. // 如果是新选中,则更新状态并打开弹窗
  249. tubeRack.selectedSampleIds = sampleIds
  250. selectedSampleIdsInParent.value = sampleIds
  251. UUID.value = uuid
  252. showProjectSelector.value = true
  253. }
  254. }
  255. }
  256. // 添加更新试管设置的方法
  257. const updateTubeSettingsHandler = async () => {
  258. const { uuid, setting } = settingTestTubeStore.currentConfig
  259. if (uuid && setting.tubeIndex >= 0) {
  260. try {
  261. const response = await updateTubeConfig({ uuid, setting })
  262. if (response.success) {
  263. ElMessage.success('设置更新成功')
  264. console.log(tubeRacks.value)
  265. settingTestTubeStore.clearConfig()
  266. } else {
  267. ElMessage.error('设置更新失败')
  268. }
  269. } catch (error) {
  270. console.error('更新试管设置失败:', error)
  271. ElMessage.error('设置更新失败')
  272. }
  273. }
  274. }
  275. </script>
  276. <style scoped lang="less">
  277. #configuration-container {
  278. position: relative;
  279. .el-message {
  280. width: 200px;
  281. height: 200px;
  282. }
  283. /* 主容器定高和滚动条样式 */
  284. .tube-rack-list {
  285. max-height: 1200px;
  286. /* 根据需要设置主容器的最大高度 */
  287. overflow-y: auto;
  288. overflow-x: hidden;
  289. width: 100%;
  290. box-sizing: border-box;
  291. /* 自定义滚动条样式 */
  292. &::-webkit-scrollbar {
  293. width: 8px;
  294. }
  295. &::-webkit-scrollbar-track {
  296. background: #f1f1f1;
  297. }
  298. &::-webkit-scrollbar-thumb {
  299. background: #888;
  300. border-radius: 4px;
  301. }
  302. &::-webkit-scrollbar-thumb:hover {
  303. background: #555;
  304. }
  305. }
  306. .add-tube {
  307. width: 100%;
  308. height: 100px;
  309. background-color: #f6f6f6;
  310. display: flex;
  311. align-items: center;
  312. justify-content: center;
  313. .icon {
  314. width: 60px;
  315. height: 100px;
  316. margin-right: 40px;
  317. }
  318. .text {
  319. font-size: 32px;
  320. color: #73bc54;
  321. font-weight: bold;
  322. }
  323. }
  324. /* 加载状态样式 */
  325. .loading-overlay {
  326. position: fixed;
  327. top: 0;
  328. left: 0;
  329. width: 100%;
  330. height: 100vh;
  331. display: flex;
  332. align-items: center;
  333. justify-content: center;
  334. background-color: rgba(255, 255, 255, 0.8);
  335. font-size: 24px;
  336. color: #333;
  337. z-index: 1000;
  338. }
  339. }
  340. </style>