StepTabPage.vue 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. <script setup lang="ts">
  2. import type { UploaderAfterRead, UploaderFileListItem } from 'vant';
  3. import { uploadMethod } from '@/api/file.api.ts';
  4. import { useStepStore } from '@/stores';
  5. import { type ScanData, useScan } from '@/core/hook/useScan.ts';
  6. import type StepWrapper from '@/components/StepWrapper.vue';
  7. const stepStore = useStepStore();
  8. const { dataset, id } = storeToRefs(stepStore);
  9. const loaded = computed(() => !!id.value);
  10. const stepWrapper = useTemplateRef<InstanceType<typeof StepWrapper>>('step-wrapper');
  11. const stepChild = useTemplateRef<{ scan?: (data: ScanData) => void; reset?: () => void }>('step-child');
  12. const tabIndex = ref(0);
  13. const { scanValue, scan } = useScan((data) => {
  14. /* 组件内扫描按钮 */
  15. if (tabIndex.value === 3 && typeof stepChild.value?.scan === 'function') {
  16. scanValue.value = data.code;
  17. stepChild.value?.scan?.(data);
  18. } else {
  19. stepWrapper.value?.search(data.code);
  20. }
  21. });
  22. const onBack = () => stepWrapper?.value?.back?.()
  23. const files = ref<UploaderFileListItem[]>([]);
  24. const picture = computed(() => files.value.filter((file) => file.status === 'done' && file.url != null).map((file) => file.url));
  25. const afterRead: UploaderAfterRead = async (listItem) => {
  26. if (listItem && !Array.isArray(listItem)) listItem = [listItem];
  27. for (const item of listItem) {
  28. if (!item?.file) continue;
  29. item.status = 'uploading';
  30. item.message = '上传中...';
  31. try {
  32. item.url = await uploadMethod(item.file!);
  33. item.status = 'done';
  34. } catch (error) {
  35. console.error('[file] 文件上传失败', error);
  36. item.status = 'failed';
  37. }
  38. }
  39. };
  40. watch(
  41. id,
  42. (value, oldValue) => {
  43. setTimeout(() => { tabIndex.value = value ? 3 : 0; }, 20);
  44. if (value !== oldValue) {
  45. stepChild?.value?.reset?.();
  46. scanValue.value = '';
  47. files.value = [];
  48. }
  49. },
  50. { immediate: true },
  51. );
  52. </script>
  53. <template>
  54. <StepWrapper ref="step-wrapper">
  55. <template #default="{ title, component }">
  56. <van-tabs class="content flex-auto overflow-hidden" v-model:active="tabIndex">
  57. <van-tab title="就诊信息">
  58. <van-cell-group>
  59. <van-cell title="患者" :value="dataset?.patient?.name" />
  60. <van-cell title="性别" :value="dataset?.patient?.gender" />
  61. <van-cell title="年龄" :value="dataset?.patient?.age" />
  62. <van-cell title="手机号" :value="dataset?.patient?.phone" />
  63. <van-cell title="医院" :value="dataset?.patient?.hospital" />
  64. <van-cell title="门诊/住院" :value="dataset?.patient?.category" />
  65. <van-cell title="科室/病区" :value="[dataset?.patient?.department, dataset?.patient?.area].filter((v) => !!v).join('/')" />
  66. <van-cell title="病床" :value="dataset?.patient?.bed" />
  67. <van-cell title="临床诊断" :value="dataset?.patient?.name" />
  68. <van-cell title="开方医生" :value="dataset?.doctor?.name" />
  69. </van-cell-group>
  70. </van-tab>
  71. <van-tab title="处方信息">
  72. <van-cell-group>
  73. <van-cell title="处方类型" :value="dataset?.prescription?.category" />
  74. <van-cell title="处方状态" :value="dataset?.order?.state" />
  75. <van-cell title="总金额" :value="dataset?.prescription?.totalPrice" />
  76. <van-cell title="剂型" :value="dataset?.prescription?.dosageForm" />
  77. <van-cell title="剂数" :value="dataset?.prescription?.count" />
  78. <van-cell title="处方用法" :value="dataset?.prescription?.method" />
  79. <van-cell title="服药频次" :value="dataset?.prescription?.frequency" />
  80. <van-cell title="服药时间" :value="dataset?.prescription?.frequencyTime" />
  81. <van-cell title="煎药量" :value="dataset?.prescription?.volume" />
  82. <van-cell title="是否代煎" :value="dataset?.prescription?.decoction" />
  83. <van-cell title="开方医生备注" :value="dataset?.prescription?.remark1" />
  84. <van-cell title="配送方式" :value="dataset?.prescription?.dispatch?.method" />
  85. <van-cell title="收货人" :value="dataset?.prescription?.dispatch?.name" />
  86. <van-cell title="收货电话" :value="dataset?.prescription?.dispatch?.phone" />
  87. <van-cell title="收货地址" :value="dataset?.prescription?.dispatch?.address" value-class="flex-2" />
  88. <van-cell title="嘱托" :value="dataset?.prescription?.entrust" />
  89. <van-cell title="药师备注" :value="dataset?.prescription?.remark2" />
  90. </van-cell-group>
  91. </van-tab>
  92. <van-tab title="药品信息">
  93. <table class="min-w-[600px] w-full">
  94. <thead>
  95. <tr>
  96. <th scope="col"></th>
  97. <th scope="col">药品名称</th>
  98. <th scope="col">药品规格</th>
  99. <th scope="col">剂量</th>
  100. <th scope="col">单位</th>
  101. <th scope="col">用法</th>
  102. <th scope="col">零售价</th>
  103. <th scope="col">产地</th>
  104. <th scope="col">小计</th>
  105. </tr>
  106. </thead>
  107. <tbody>
  108. <tr v-for="(medicine, index) in dataset?.medicines" :key="medicine.id">
  109. <th scope="row">{{ index + 1 }}</th>
  110. <td class="w-24">{{ medicine.name }}</td>
  111. <td>{{ medicine.size }}</td>
  112. <td style="text-align: right">{{ medicine.dosage }}</td>
  113. <td>{{ medicine.unit }}</td>
  114. <td>{{ medicine.usage }}</td>
  115. <td>{{ medicine.place }}</td>
  116. <td style="text-align: right">{{ medicine.unitPrice }}</td>
  117. <td style="text-align: right">{{ medicine.totalPrice }}</td>
  118. </tr>
  119. </tbody>
  120. </table>
  121. </van-tab>
  122. <van-tab :title="title" :disabled="!loaded">
  123. <router-view>
  124. <component ref="step-child" :is="component" @back="onBack()">
  125. <template v-slot:scanner="{ title, disabled }">
  126. <van-field
  127. :label="title"
  128. :readonly="disabled"
  129. placeholder="请使用设备按钮进行扫码"
  130. right-icon="scan"
  131. @click-right-icon="!disabled && scan()"
  132. v-model="scanValue"
  133. @update:model-value="scan($event)"
  134. />
  135. </template>
  136. <template v-slot:uploader="{ disabled }">
  137. <van-field label="拍照上传">
  138. <template #input>
  139. <van-uploader v-model="files" :after-read="afterRead" :disabled="disabled" capture="camera" />
  140. </template>
  141. </van-field>
  142. </template>
  143. <template v-slot:submit="{ title, submitting, submit }">
  144. <div class="flex my-4 px-4 gap-4" id="bottom-handle">
  145. <van-button type="primary" block :loading="submitting" @click="submit(picture)">{{ title }} </van-button>
  146. </div>
  147. </template>
  148. </component>
  149. </router-view>
  150. </van-tab>
  151. </van-tabs>
  152. </template>
  153. </StepWrapper>
  154. </template>
  155. <style scoped lang="scss">
  156. .content {
  157. display: flex;
  158. flex-direction: column;
  159. :deep(.van-tabs__wrap) {
  160. flex: none;
  161. }
  162. :deep(.van-tabs__content) {
  163. flex: auto;
  164. overflow: auto;
  165. }
  166. //--van-cell-text-color: #fff
  167. --van-cell-value-color: var(--van-text-color);
  168. --van-cell-text-color: var(--van-text-color-2);
  169. table {
  170. border-collapse: collapse;
  171. border: 2px solid rgb(140 140 140);
  172. font-size: 14px;
  173. letter-spacing: 1px;
  174. }
  175. thead,
  176. tfoot {
  177. background-color: rgb(228 240 245);
  178. }
  179. th,
  180. td {
  181. border: 1px solid rgb(160 160 160);
  182. padding: 8px 10px;
  183. text-align: center;
  184. }
  185. }
  186. </style>
  187. <style>
  188. .flex-2 {
  189. flex: 2;
  190. }
  191. </style>