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.

355 lines
8.3 KiB

7 months ago
  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 lang="ts">
  82. import { ref } from 'vue'
  83. import { useRouter } from 'vue-router'
  84. import * as R from 'ramda'
  85. import { useTestTubeStore } from '../../../store'
  86. import SimpleKeyboard from '../../../components/SimpleKeyboard.vue'
  87. import Tube from '../components/TestTube/Tube.vue'
  88. import { updateTubeConfig } from '../../../services'
  89. import { eMessage } from '../utils'
  90. import { TubeSetting } from '@/websocket/socket'
  91. const router = useRouter()
  92. const tubeStore = useTestTubeStore()
  93. defineOptions({
  94. name: 'TubeUserId',
  95. })
  96. const tubeGroups = ref([
  97. R.clone(tubeStore.tubeRack.tubeSettings.slice(0, 5)),
  98. R.clone(tubeStore.tubeRack.tubeSettings.slice(5, 10)),
  99. ])
  100. const keyboardVisible = ref(false)
  101. const currentInputValue = ref('')
  102. const currentInput = ref<{type: string; item?: TubeSetting}>({
  103. type: 'barcode',
  104. item: undefined,
  105. })
  106. const isFocused = (type, item) => {
  107. if (
  108. currentInput.value.item &&
  109. item.tubeIndex === currentInput.value.item.tubeIndex &&
  110. type === currentInput.value.type
  111. ) {
  112. return true
  113. }
  114. return false
  115. }
  116. //返回试管页面
  117. const goBack = () => {
  118. //router.push('/index/regular/test-tube')
  119. router.back()
  120. }
  121. //确认事件
  122. const confirmChange = async () => {
  123. const settings = R.flatten(tubeGroups.value)
  124. const res = await updateTubeConfig({
  125. uuid: tubeStore.tubeRack.uuid,
  126. setting: settings,
  127. })
  128. if (res.success) {
  129. tubeStore.tubeRack.tubeSettings = settings
  130. goBack()
  131. } else {
  132. eMessage.error('更新失败')
  133. }
  134. }
  135. // 显示键盘
  136. const showKeyboard = (type, item) => {
  137. keyboardVisible.value = true
  138. currentInput.value = { type, item }
  139. currentInputValue.value =
  140. type === 'barcode' ? item.sampleBarcode : item.userid
  141. }
  142. // 处理键盘输入
  143. const handleKeyboardInput = (input) => {
  144. if (!currentInput.value.item) return
  145. const groupIdx = currentInput.value.item.tubeIndex < 5 ? 0 : 1
  146. const idxOffset = groupIdx === 1 ? 5 : 0
  147. const tubeIdx = currentInput.value.item.tubeIndex - idxOffset
  148. if (currentInput.value.type === 'barcode') {
  149. currentInput.value.item.sampleBarcode = input
  150. tubeGroups.value[groupIdx][tubeIdx].sampleBarcode = input
  151. } else {
  152. currentInput.value.item.userid = input
  153. tubeGroups.value[groupIdx][tubeIdx].userid = input
  154. }
  155. currentInputValue.value = input
  156. // console.log(tubeGroups.value[groupIdx])
  157. }
  158. // 处理键盘按键
  159. const handleKeyPress = (button) => {
  160. if (button === '{enter}') {
  161. keyboardVisible.value = false
  162. currentInputValue.value = ''
  163. }
  164. }
  165. </script>
  166. <style lang="less" scoped>
  167. #changeUser-container {
  168. width: 100%;
  169. height: 95vh;
  170. display: flex;
  171. flex-direction: column;
  172. position: relative;
  173. overflow: hidden;
  174. .header {
  175. height: 80px;
  176. background-color: #fff;
  177. padding: 0 20px;
  178. display: flex;
  179. align-items: center;
  180. .header-left {
  181. display: flex;
  182. align-items: center;
  183. gap: 12px;
  184. img {
  185. width: 24px;
  186. height: 24px;
  187. cursor: pointer;
  188. }
  189. .title {
  190. font-size: 28px;
  191. color: #303133;
  192. }
  193. }
  194. }
  195. .content {
  196. padding: 16px;
  197. display: flex;
  198. flex-direction: column;
  199. gap: 20px;
  200. overflow: hidden;
  201. .sample-section {
  202. border-radius: 8px;
  203. padding: 20px;
  204. display: flex;
  205. // height: 380px;
  206. .section-labels {
  207. width: 100px;
  208. display: flex;
  209. flex-direction: column-reverse;
  210. padding-bottom: 16px;
  211. .label-column {
  212. > * {
  213. box-sizing: border-box;
  214. }
  215. .label-item {
  216. margin-bottom: 16px;
  217. .label {
  218. font-size: 24px;
  219. font-weight: 600;
  220. color: #606266;
  221. }
  222. }
  223. }
  224. }
  225. .samples-grid {
  226. flex: 1;
  227. display: grid;
  228. grid-template-columns: repeat(5, 1fr);
  229. gap: 12px;
  230. .sample-item {
  231. // background-color: #f5f7fa;
  232. border-radius: 12px;
  233. padding: 12px;
  234. .sample-content {
  235. display: flex;
  236. flex-direction: column;
  237. align-items: center;
  238. .item-index {
  239. font-size: 22px;
  240. color: #333;
  241. margin-bottom: 8px;
  242. }
  243. .tube-circle {
  244. height: 80px;
  245. }
  246. .inputs {
  247. width: 100%;
  248. margin-top: 24px;
  249. .input-field {
  250. &.onFocus {
  251. // border: solid 2px #333;
  252. }
  253. width: 100%;
  254. height: 36px;
  255. border: 1px solid #aaa;
  256. border-radius: 4px;
  257. margin-bottom: 14px;
  258. font-size: 20px;
  259. font-weight: 600;
  260. text-align: center;
  261. background-color: #fff;
  262. &::placeholder {
  263. color: #c0c4cc;
  264. font-size: 18px;
  265. }
  266. }
  267. }
  268. }
  269. }
  270. }
  271. }
  272. }
  273. .footer {
  274. height: 80px;
  275. padding: 10px 20px;
  276. background-color: #fff;
  277. display: flex;
  278. justify-content: center;
  279. gap: 16px;
  280. .btn {
  281. width: 320px;
  282. height: 60px;
  283. border-radius: 30px;
  284. font-size: 24px;
  285. font-weight: normal;
  286. &.cancel {
  287. background-color: #f5f7fa;
  288. color: #606266;
  289. border: 1px solid #dcdfe6;
  290. }
  291. &.confirm {
  292. background-color: #409eff;
  293. color: #fff;
  294. }
  295. }
  296. }
  297. .keyboard-container {
  298. position: absolute;
  299. bottom: 0;
  300. left: 0;
  301. width: 100%;
  302. height: 20vh;
  303. background-color: #fff;
  304. }
  305. // 键盘动画
  306. .slide-up-enter-active,
  307. .slide-up-leave-active {
  308. transition: transform 0.3s ease;
  309. }
  310. .slide-up-enter-from,
  311. .slide-up-leave-to {
  312. transform: translateY(100%);
  313. }
  314. }
  315. </style>