StepPage.vue 8.2 KB

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