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.

447 lines
11 KiB

8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
7 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
7 months ago
8 months ago
8 months ago
7 months ago
7 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
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="add-emergency-container">
  3. <!-- 添加急诊 -->
  4. <div class="page-header" @click="goBack">
  5. <img class="page-header-icon" src="@/assets/Index/left.svg" />
  6. <div class="page-header-title">添加急诊</div>
  7. </div>
  8. <div class="emergency-userid">
  9. <el-row>
  10. <el-col :span="5">
  11. <label>样本条形码</label>
  12. </el-col>
  13. <el-col :span="12" style="padding-left: 20px">
  14. <input
  15. type="text"
  16. placeholder="请输入样本条形码信息"
  17. @focus="showKeyboard('sampleBarcode')"
  18. style="width: 400px"
  19. :value="emergencyPosition.sampleBarcode"
  20. readonly
  21. />
  22. </el-col>
  23. </el-row>
  24. <el-row>
  25. <el-col :span="5">
  26. <label>用户ID</label>
  27. </el-col>
  28. <el-col :span="12" style="padding-left: 20px">
  29. <input
  30. type="text"
  31. placeholder="请输入用户ID信息"
  32. @focus="showKeyboard('userid')"
  33. :value="emergencyPosition.userid"
  34. style="width: 400px"
  35. readonly
  36. />
  37. </el-col>
  38. </el-row>
  39. </div>
  40. <hr style="height: 1px; border: none" />
  41. <!-- 急诊项目 -->
  42. <div class="emergency-project">
  43. <!-- 项目选择内容根据需要添加 -->
  44. <div class="project-title">
  45. <span>项目选择</span>
  46. </div>
  47. <div class="project-list">
  48. <div
  49. v-for="item in consumableStore.projectsAvailable"
  50. :key="item.projId"
  51. class="project-item"
  52. :style="projectStyle(item)"
  53. @click="selectProject(item)"
  54. >
  55. <span class="proj-name">{{ item.projName }}</span>
  56. <span> {{ item.num }}</span>
  57. </div>
  58. </div>
  59. <div class="project-title">
  60. <span>血液类型</span>
  61. </div>
  62. <div class="type-list">
  63. <div
  64. v-for="item in settingTubeStore.bloodTypes"
  65. :key="item.key"
  66. @click="selectBloodType(item)"
  67. class="blood-button"
  68. :class="{ active: emergencyPosition.bloodType === item.key }"
  69. >
  70. {{ item.name }}
  71. </div>
  72. </div>
  73. </div>
  74. <hr style="height: 1px; border: none" />
  75. <!-- 急诊控制 -->
  76. <div class="emergency-btns" style="padding: 50px 0">
  77. <el-button class="cancel-button" @click="goBack">取消</el-button>
  78. <el-button class="ok-button" @click="confirmHandle">确定</el-button>
  79. </div>
  80. <!-- 键盘 -->
  81. <transition name="slide-up">
  82. <div class="keyboard" v-if="keyboardVisible">
  83. <SimpleKeyboard
  84. :input="currentInputValue"
  85. @onChange="handleKeyboardInput"
  86. @onKeyPress="handleKeyPress"
  87. />
  88. </div>
  89. </transition>
  90. </div>
  91. </template>
  92. <script setup lang="ts">
  93. import { ref, onMounted, onUnmounted } from 'vue'
  94. import { useRouter } from 'vue-router'
  95. import { insertEmergency } from '@/services/Index/index'
  96. import {
  97. useEmergencyStore,
  98. useConsumablesStore,
  99. useDeviceStore,
  100. useSettingTestTubeStore,
  101. } from '@/store'
  102. import type { AddEmergencyInfo } from '@/types/Index'
  103. import type { BloodType, ReactionPlateGroup } from '@/websocket/socket'
  104. import { eMessage } from '../utils'
  105. defineOptions({
  106. name: 'EmergencyForm',
  107. })
  108. const consumableStore = useConsumablesStore()
  109. const emergencyStore = useEmergencyStore()
  110. const deviceStore = useDeviceStore()
  111. const settingTubeStore = useSettingTestTubeStore()
  112. const isProjectActivated = (item: ReactionPlateGroup) => {
  113. return emergencyPosition.value.projIds.includes(item.projId!)
  114. }
  115. //项目选中样式及背景色
  116. const projectStyle = (item: ReactionPlateGroup) => {
  117. const activated = isProjectActivated(item)
  118. if (activated) {
  119. return {
  120. border: 'solid 1px transparent',
  121. backgroundColor: consumableStore.projIdColorMap[item.projId!],
  122. color: '#FFF',
  123. }
  124. } else {
  125. return {
  126. border: `solid 1px ${consumableStore.projIdColorMap[item.projId!]}`,
  127. backgroundColor: '#FFF',
  128. color: consumableStore.projIdColorMap[item.projId!],
  129. }
  130. }
  131. }
  132. // 急诊位数据
  133. const emergencyPosition = ref<AddEmergencyInfo>({
  134. sampleBarcode: '', // 样本条形码
  135. userid: '', // 用户ID
  136. projIds: [], // 项目选择
  137. bloodType: '', // 血液类型
  138. })
  139. const router = useRouter()
  140. const goBack = () => {
  141. router.go(-1)
  142. }
  143. const confirmHandle = async () => {
  144. // if (deviceStore.deviceState.workState === 'WORKING') {
  145. // eMessage.error('设备正在运行,无法添加急诊')
  146. // return
  147. // }
  148. const emergencyInfo = emergencyPosition.value
  149. if (emergencyInfo.projIds.length === 0) {
  150. eMessage.error('请选择项目')
  151. return
  152. }
  153. if (!emergencyInfo.bloodType) {
  154. eMessage.error('请选择血液类型')
  155. return
  156. }
  157. const res = await insertEmergency(emergencyPosition.value)
  158. if (res && res.success) {
  159. goBack()
  160. } else {
  161. res && res.data && res.data.info && eMessage.error(res.data.info)
  162. }
  163. }
  164. const selectProject = (item: ReactionPlateGroup) => {
  165. const projectIndex = emergencyPosition.value.projIds.findIndex(
  166. (proj) => proj === item.projId,
  167. )
  168. if (projectIndex > -1) {
  169. emergencyPosition.value.projIds.splice(projectIndex, 1)
  170. } else {
  171. emergencyPosition.value.projIds.push(item.projId!)
  172. }
  173. }
  174. const selectBloodType = (item: { key: BloodType }) => {
  175. emergencyPosition.value.bloodType = item.key
  176. }
  177. // 处理回显数据
  178. onMounted(() => {
  179. if (!emergencyStore.emergencyInfo) {
  180. return
  181. }
  182. if (
  183. deviceStore.deviceState.workState === 'IDLE' ||
  184. (deviceStore.deviceState.workState === 'PAUSE' &&
  185. emergencyStore.emergencyInfo!.state === 'TO_BE_PROCESSED')
  186. ) {
  187. emergencyPosition.value = {
  188. sampleBarcode: emergencyStore.emergencyInfo.sampleBarcode,
  189. userid: emergencyStore.emergencyInfo.userid,
  190. projIds: emergencyStore.emergencyInfo.projIds,
  191. bloodType: emergencyStore.emergencyInfo.bloodType,
  192. }
  193. }
  194. })
  195. // 键盘相关状态
  196. const keyboardVisible = ref(false)
  197. const currentInputValue = ref('')
  198. const currentInputField = ref<'sampleBarcode' | 'userid' | ''>('')
  199. // 显示键盘
  200. const showKeyboard = (field: 'sampleBarcode' | 'userid') => {
  201. // 清空当前输入值,避免累加
  202. if (field == 'sampleBarcode') {
  203. currentInputValue.value = emergencyPosition.value.sampleBarcode
  204. }
  205. if (field == 'userid') {
  206. currentInputValue.value = emergencyPosition.value.userid
  207. }
  208. currentInputField.value = field
  209. keyboardVisible.value = true
  210. }
  211. // 处理键盘输入
  212. const handleKeyboardInput = (value: string) => {
  213. if (!currentInputField.value) return
  214. // 更新当前输入值
  215. currentInputValue.value = value
  216. // 更新对应字段的值
  217. if (currentInputField.value === 'sampleBarcode') {
  218. emergencyPosition.value.sampleBarcode = value
  219. } else {
  220. emergencyPosition.value.userid = value
  221. }
  222. }
  223. // 处理键盘按键
  224. const handleKeyPress = (button: string) => {
  225. if (button === '{enter}') {
  226. hideKeyboard()
  227. } else if (button === '{bksp}') {
  228. // 处理退格键
  229. const value = currentInputValue.value
  230. if (value.length > 0) {
  231. const newValue = value.slice(0, -1)
  232. handleKeyboardInput(newValue)
  233. }
  234. }
  235. }
  236. // 隐藏键盘
  237. const hideKeyboard = () => {
  238. keyboardVisible.value = false
  239. currentInputField.value = ''
  240. currentInputValue.value = ''
  241. }
  242. // 在组件卸载时清理状态
  243. onUnmounted(() => {
  244. hideKeyboard()
  245. })
  246. </script>
  247. <style lang="less" scoped>
  248. input {
  249. margin-bottom: 20px;
  250. padding: 8px 5px;
  251. border: 1px solid #ccc;
  252. border-radius: 4px;
  253. font-size: 32px;
  254. transition: box-shadow 0.2s ease;
  255. border-radius: 10px;
  256. &::placeholder {
  257. font-size: 32px;
  258. font-weight: 100;
  259. color: #d8d8d8;
  260. }
  261. }
  262. label {
  263. margin-bottom: 8px;
  264. font-size: 32px;
  265. font-weight: 700;
  266. }
  267. #add-emergency-container {
  268. > * {
  269. box-sizing: border-box;
  270. }
  271. margin: 0;
  272. padding: 0;
  273. position: relative;
  274. height: 100%;
  275. width: 100%;
  276. background-color: #f4f6f9;
  277. box-sizing: border-box;
  278. hr {
  279. background-color: #e0e0e0;
  280. }
  281. .page-header {
  282. width: 100%;
  283. height: 100px;
  284. display: flex;
  285. align-items: center;
  286. background-color: #ffffff;
  287. box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
  288. border-radius: 8px;
  289. .page-header-icon {
  290. width: 16.14px;
  291. height: 26.76px;
  292. margin: 0 20px;
  293. cursor: pointer;
  294. transition: transform 0.2s ease;
  295. &:hover {
  296. transform: scale(1.1);
  297. /* 放大效果 */
  298. }
  299. }
  300. .page-header-title {
  301. font-size: 36px;
  302. font-weight: 900;
  303. line-height: 1.2;
  304. color: #333;
  305. }
  306. }
  307. .emergency-userid {
  308. margin-top: 40px;
  309. margin-left: 60px;
  310. }
  311. .emergency-project {
  312. width: 100%;
  313. padding: 20px 40px;
  314. border-radius: 10px;
  315. margin-top: 20px;
  316. .project-title {
  317. width: 100%;
  318. text-align: left;
  319. margin-bottom: 10px;
  320. font-size: 32px;
  321. font-weight: 600;
  322. }
  323. .project-list {
  324. display: flex;
  325. align-items: center;
  326. gap: 12px;
  327. .project-item {
  328. display: flex;
  329. flex-direction: column;
  330. align-items: center;
  331. gap: 5px;
  332. padding: 8px 16px;
  333. font-size: 24px;
  334. border-radius: 8px;
  335. min-width: 64px;
  336. .proj-name {
  337. font-weight: 600;
  338. }
  339. }
  340. margin-bottom: 24px;
  341. }
  342. .type-list {
  343. display: flex;
  344. align-items: center;
  345. gap: 12px;
  346. padding: 10px 0 10px;
  347. .blood-button {
  348. border: 1px solid #5c94fe;
  349. border-radius: 8px;
  350. padding: 8px 16px;
  351. color: #4a90e2;
  352. font-size: 32px;
  353. &.active {
  354. border: 1px solid transparent;
  355. background-color: #4a90e2;
  356. color: #fff;
  357. }
  358. }
  359. }
  360. }
  361. .emergency-btns {
  362. width: 100%;
  363. height: 120px;
  364. display: flex;
  365. margin-top: 30px;
  366. display: flex;
  367. justify-content: center;
  368. align-items: center;
  369. .cancel-button,
  370. .ok-button {
  371. width: 360px;
  372. height: 100px;
  373. border-radius: 30px;
  374. font-size: 36px;
  375. font-weight: 400;
  376. margin: 0 10px;
  377. border: none;
  378. }
  379. .ok-button {
  380. background-color: #528dfe;
  381. color: white;
  382. box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  383. }
  384. .cancel-button {
  385. background-color: #f2f2f2;
  386. color: black;
  387. box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  388. }
  389. }
  390. .keyboard {
  391. position: fixed;
  392. bottom: 0;
  393. left: 0;
  394. width: 100%;
  395. height: 300px;
  396. background-color: #f5f7fa;
  397. border-top-left-radius: 16px;
  398. border-top-right-radius: 16px;
  399. box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.1);
  400. z-index: 1000;
  401. }
  402. // 键盘动画
  403. .slide-up-enter-active,
  404. .slide-up-leave-active {
  405. transition: transform 0.3s ease;
  406. }
  407. .slide-up-enter-from,
  408. .slide-up-leave-to {
  409. transform: translateY(100%);
  410. }
  411. }
  412. </style>