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.

357 lines
8.4 KiB

  1. <template>
  2. <div id="changeUser-container">
  3. <!-- 顶部导航 -->
  4. <div class="header">
  5. <div class="header-left" @click.stop="goBack">
  6. <img src="@/assets/Index/left.svg" alt="返回" />
  7. <span class="title">患者信息</span>
  8. </div>
  9. </div>
  10. <!-- 主要内容区域 -->
  11. <div class="content">
  12. <div class="sample-section" v-for="(group, idx) in tubeGroups" :key="idx">
  13. <!-- 左侧标题栏 -->
  14. <div class="section-labels">
  15. <div class="label-column">
  16. <div class="label-item">
  17. <span class="label">条形码</span>
  18. </div>
  19. <div class="label-item">
  20. <span class="label">用户ID</span>
  21. </div>
  22. </div>
  23. </div>
  24. <!-- 右侧样本展示 -->
  25. <div class="samples-grid">
  26. <div class="sample-item" v-for="item in group" :key="item.tubeIndex">
  27. <div class="sample-content">
  28. <!-- 序号 -->
  29. <div class="item-index">{{ item.tubeIndex + 1 }}</div>
  30. <!-- 试管圆圈 -->
  31. <div class="tube-circle">
  32. <Tube
  33. :tube="item"
  34. :showNum="false"
  35. :showUserId="false"
  36. @clickTubeItem=""
  37. />
  38. </div>
  39. <!-- 输入框组 -->
  40. <div class="inputs">
  41. <input
  42. class="input-field"
  43. :class="{ onFocus: isFocused('barcode', item) }"
  44. v-model="item.sampleBarcode"
  45. placeholder="条形码"
  46. @focus="showKeyboard('barcode', item)"
  47. readonly
  48. />
  49. <input
  50. class="input-field"
  51. :class="{ onFocus: isFocused('userid', item) }"
  52. v-model="item.userid"
  53. placeholder="用户ID"
  54. @focus="showKeyboard('userid', item)"
  55. readonly
  56. />
  57. </div>
  58. </div>
  59. </div>
  60. </div>
  61. </div>
  62. </div>
  63. <!-- 底部按钮 -->
  64. <div class="footer">
  65. <button class="btn cancel" @click="goBack">取消</button>
  66. <button class="btn confirm" @click="confirmChange">确定</button>
  67. </div>
  68. <!-- 键盘组件 -->
  69. <transition name="slide-up">
  70. <div class="keyboard-container">
  71. <SimpleKeyboard
  72. v-if="keyboardVisible"
  73. :input="currentInputValue"
  74. @onChange="handleKeyboardInput"
  75. @onKeyPress="handleKeyPress"
  76. />
  77. </div>
  78. </transition>
  79. </div>
  80. </template>
  81. <script setup>
  82. import { computed, onActivated, ref, watch } from 'vue'
  83. import { useRouter } from 'vue-router'
  84. import * as R from 'ramda'
  85. import { useTestTubeStore, useConsumablesStore } from '../../../store'
  86. import { eventBus } from '../../../eventBus'
  87. import SimpleKeyboard from '../../../components/SimpleKeyboard.vue'
  88. import Tube from '../components/TestTube/Tube.vue'
  89. import { updateTubeConfig } from '../../../services'
  90. import { ElMessage } from 'element-plus'
  91. const router = useRouter()
  92. const consumables = useConsumablesStore()
  93. const tubeStore = useTestTubeStore()
  94. defineOptions({
  95. name: 'TubeUserId',
  96. })
  97. const tubeGroups = ref([
  98. R.clone(tubeStore.tubeRack.tubeSettings.slice(0, 5)),
  99. R.clone(tubeStore.tubeRack.tubeSettings.slice(5, 10)),
  100. ])
  101. const keyboardVisible = ref(false)
  102. const currentInputValue = ref('')
  103. const currentInput = ref({
  104. type: 'barcode',
  105. item: null,
  106. })
  107. const isFocused = (type, item) => {
  108. if (
  109. currentInput.value.item &&
  110. item.tubeIndex === currentInput.value.item.tubeIndex &&
  111. type === currentInput.value.type
  112. ) {
  113. return true
  114. }
  115. return false
  116. }
  117. //返回试管页面
  118. const goBack = () => {
  119. //router.push('/index/regular/test-tube')
  120. router.back()
  121. }
  122. //确认事件
  123. const confirmChange = async () => {
  124. const settings = R.flatten(tubeGroups.value)
  125. const res = await updateTubeConfig({
  126. uuid: tubeStore.tubeRack.uuid,
  127. setting: settings,
  128. })
  129. if (res.success) {
  130. tubeStore.tubeRack.tubeSettings = settings
  131. eventBus.emit('AppTubeSettingUpdateEvent');
  132. goBack()
  133. } else {
  134. ElMessage.error('更新失败')
  135. }
  136. }
  137. // 显示键盘
  138. const showKeyboard = (type, item) => {
  139. keyboardVisible.value = true
  140. currentInput.value = { type, item }
  141. currentInputValue.value =
  142. type === 'barcode' ? item.sampleBarcode : item.userid
  143. }
  144. // 处理键盘输入
  145. const handleKeyboardInput = (input) => {
  146. if (!currentInput.value.item) return
  147. const groupIdx = currentInput.value.item.tubeIndex < 5 ? 0 : 1
  148. const idxOffset = groupIdx === 1 ? 5 : 0
  149. const tubeIdx = currentInput.value.item.tubeIndex - idxOffset
  150. if (currentInput.value.type === 'barcode') {
  151. currentInput.value.item.sampleBarcode = input
  152. tubeGroups.value[groupIdx][tubeIdx].sampleBarcode = input
  153. } else {
  154. currentInput.value.item.userid = input
  155. tubeGroups.value[groupIdx][tubeIdx].userid = input
  156. }
  157. currentInputValue.value = input
  158. // console.log(tubeGroups.value[groupIdx])
  159. }
  160. // 处理键盘按键
  161. const handleKeyPress = (button) => {
  162. if (button === '{enter}') {
  163. keyboardVisible.value = false
  164. currentInputValue.value = ''
  165. }
  166. }
  167. </script>
  168. <style lang="less" scoped>
  169. #changeUser-container {
  170. width: 100%;
  171. height: 95vh;
  172. display: flex;
  173. flex-direction: column;
  174. position: relative;
  175. overflow: hidden;
  176. .header {
  177. height: 80px;
  178. background-color: #fff;
  179. padding: 0 20px;
  180. display: flex;
  181. align-items: center;
  182. .header-left {
  183. display: flex;
  184. align-items: center;
  185. gap: 12px;
  186. img {
  187. width: 24px;
  188. height: 24px;
  189. cursor: pointer;
  190. }
  191. .title {
  192. font-size: 28px;
  193. color: #303133;
  194. }
  195. }
  196. }
  197. .content {
  198. padding: 16px;
  199. display: flex;
  200. flex-direction: column;
  201. gap: 20px;
  202. overflow: hidden;
  203. .sample-section {
  204. border-radius: 8px;
  205. padding: 20px;
  206. display: flex;
  207. // height: 380px;
  208. .section-labels {
  209. width: 100px;
  210. display: flex;
  211. flex-direction: column-reverse;
  212. padding-bottom: 16px;
  213. .label-column {
  214. > * {
  215. box-sizing: border-box;
  216. }
  217. .label-item {
  218. margin-bottom: 16px;
  219. .label {
  220. font-size: 24px;
  221. font-weight: 600;
  222. color: #606266;
  223. }
  224. }
  225. }
  226. }
  227. .samples-grid {
  228. flex: 1;
  229. display: grid;
  230. grid-template-columns: repeat(5, 1fr);
  231. gap: 12px;
  232. .sample-item {
  233. // background-color: #f5f7fa;
  234. border-radius: 12px;
  235. padding: 12px;
  236. .sample-content {
  237. display: flex;
  238. flex-direction: column;
  239. align-items: center;
  240. .item-index {
  241. font-size: 22px;
  242. color: #333;
  243. margin-bottom: 8px;
  244. }
  245. .tube-circle {
  246. height: 80px;
  247. }
  248. .inputs {
  249. width: 100%;
  250. margin-top: 24px;
  251. .input-field {
  252. &.onFocus {
  253. border: solid 2px #333;
  254. }
  255. width: 100%;
  256. height: 36px;
  257. border: 1px solid #aaa;
  258. border-radius: 4px;
  259. margin-bottom: 14px;
  260. font-size: 20px;
  261. font-weight: 600;
  262. text-align: center;
  263. background-color: #fff;
  264. &::placeholder {
  265. color: #c0c4cc;
  266. font-size: 18px;
  267. }
  268. }
  269. }
  270. }
  271. }
  272. }
  273. }
  274. }
  275. .footer {
  276. height: 80px;
  277. padding: 10px 20px;
  278. background-color: #fff;
  279. display: flex;
  280. justify-content: center;
  281. gap: 16px;
  282. .btn {
  283. width: 320px;
  284. height: 60px;
  285. border-radius: 30px;
  286. font-size: 24px;
  287. font-weight: normal;
  288. &.cancel {
  289. background-color: #f5f7fa;
  290. color: #606266;
  291. border: 1px solid #dcdfe6;
  292. }
  293. &.confirm {
  294. background-color: #409eff;
  295. color: #fff;
  296. }
  297. }
  298. }
  299. .keyboard-container {
  300. position: absolute;
  301. bottom: 0;
  302. left: 0;
  303. width: 100%;
  304. height: 20vh;
  305. background-color: #fff;
  306. }
  307. // 键盘动画
  308. .slide-up-enter-active,
  309. .slide-up-leave-active {
  310. transition: transform 0.3s ease;
  311. }
  312. .slide-up-enter-from,
  313. .slide-up-leave-to {
  314. transform: translateY(100%);
  315. }
  316. }
  317. </style>