|
@@ -1,148 +1,120 @@
|
|
|
<script setup lang="ts">
|
|
|
-import { useStepStore } from '@/stores';
|
|
|
-import { useRequest } from 'alova/client';
|
|
|
import { getDataMethod } from '@/api/pda.api.ts';
|
|
|
-import { defaultMenus } from '@/model/menu.model.ts';
|
|
|
-import { tryOnBeforeMount, tryOnUnmounted } from '@vueuse/core';
|
|
|
+import { uploadMethod } from '@/api/file.api.ts';
|
|
|
+import { type ScanData, useScan } from '@/core/hook/useScan.ts';
|
|
|
+import { useStep } from '@/core/hook/useStep.ts';
|
|
|
+import { useStepStore } from '@/stores';
|
|
|
+import type { UploaderAfterRead, UploaderFileListItem } from 'vant';
|
|
|
+import { nextTick } from 'vue';
|
|
|
|
|
|
-const router = useRouter();
|
|
|
-const route = useRoute();
|
|
|
const stepStore = useStepStore();
|
|
|
-const { dataset } = storeToRefs(stepStore);
|
|
|
+const { dataset, id, mode } = storeToRefs(stepStore);
|
|
|
+const loaded = computed(() => !!id.value);
|
|
|
|
|
|
-const navTitle = computed(() => defaultMenus.find((menu) => menu.path === `/step/${route.params.mode}`)?.name ?? import.meta.env.SIX_TITLE);
|
|
|
-const tabTitle = computed(() => navTitle.value?.replace('管理', '确认'));
|
|
|
+const keyword = ref('');
|
|
|
const tabIndex = ref(0);
|
|
|
+const { menu, tabTitle, next, prev } = useStep(mode, id);
|
|
|
+
|
|
|
+watchEffect(() => {
|
|
|
+ keyword.value = id.value;
|
|
|
+ nextTick(() => {
|
|
|
+ tabIndex.value = id.value ? 3 : 0;
|
|
|
+ if (!id.value) stepStore.$reset();
|
|
|
+ });
|
|
|
+});
|
|
|
|
|
|
-const loaded = computed(() => !!data.value?.no);
|
|
|
-const readonly = ref(false);
|
|
|
-const keyword = ref<string>(dataset.value?.no ?? '');
|
|
|
-
|
|
|
-const ignoreParentScanner = ref(false);
|
|
|
-provide('ignoreParentScanner', ignoreParentScanner);
|
|
|
-let onCleanup = () => {};
|
|
|
-tryOnBeforeMount(() => {
|
|
|
- if (window.bridge) {
|
|
|
- onCleanup = window.bridge.addEventListener('scan', event => {
|
|
|
- const detail = event.detail;
|
|
|
- if ( detail.code !== 0 || detail.data?.code == null ) return;
|
|
|
- if (ignoreParentScanner.value) {
|
|
|
- event.stopPropagation();
|
|
|
- event.preventDefault();
|
|
|
- } else {
|
|
|
- keyword.value = event.detail.data?.code ?? '';
|
|
|
- const toast = showLoadingToast({ message: '查询中...', duration: 0 });
|
|
|
- search().finally(() => toast.close());
|
|
|
- }
|
|
|
- });
|
|
|
- } else if (window.platform) {
|
|
|
- const update = (event: CustomEvent) => {
|
|
|
- if (ignoreParentScanner.value) {
|
|
|
- event.stopPropagation();
|
|
|
- event.preventDefault();
|
|
|
- } else {
|
|
|
- keyword.value = event.detail.code;
|
|
|
- const toast = showLoadingToast({ message: '查询中...', duration: 0 });
|
|
|
- search().finally(() => toast.close());
|
|
|
- }
|
|
|
- };
|
|
|
- platform.addEventListener('scan', update)
|
|
|
- onCleanup = () => { platform.removeEventListener('scan', update) }
|
|
|
+const step = useTemplateRef<{ scan?: (data: ScanData) => void }>('step');
|
|
|
+
|
|
|
+const { scanValue, scan } = useScan((data) => {
|
|
|
+ /* 组件内扫描按钮 */
|
|
|
+ if (tabIndex.value === 3 && typeof step.value?.scan === 'function') {
|
|
|
+ scanValue.value = data.code;
|
|
|
+ step.value.scan(data);
|
|
|
+ } else {
|
|
|
+ keyword.value = data.code;
|
|
|
+ onSearch();
|
|
|
}
|
|
|
});
|
|
|
-tryOnUnmounted(() => onCleanup?.());
|
|
|
-
|
|
|
-const {
|
|
|
- data,
|
|
|
- loading,
|
|
|
- send: search,
|
|
|
-} = useRequest(() => getDataMethod(keyword.value?.trim()), {
|
|
|
- immediate: false,
|
|
|
- initialData: { ...dataset.value },
|
|
|
-})
|
|
|
- .onSuccess(async ({ data }) => {
|
|
|
- keyword.value = data.no;
|
|
|
- dataset.value = data;
|
|
|
-
|
|
|
- const { mode, value } = route.params;
|
|
|
-
|
|
|
- if (value) {
|
|
|
- await router.push({ path: `${keyword.value}`, replace: true });
|
|
|
- } else {
|
|
|
- await router.push({ path: `${mode}/${keyword.value}` });
|
|
|
- }
|
|
|
- tabIndex.value = 3;
|
|
|
- })
|
|
|
- .onError(() => {
|
|
|
- keyword.value = '';
|
|
|
- });
|
|
|
|
|
|
-watch(loading, (value) => {
|
|
|
+async function onSearch() {
|
|
|
+ const value = keyword.value?.trim?.();
|
|
|
if (value) {
|
|
|
- showLoadingToast({ forbidClick: true, duration: 0, message: '加载中...' });
|
|
|
- } else {
|
|
|
+ showLoadingToast({ forbidClick: true, duration: 0, message: '查询中...' });
|
|
|
+ try {
|
|
|
+ dataset.value = await getDataMethod(keyword.value.trim());
|
|
|
+ await next(dataset.value.no);
|
|
|
+ } catch (_: unknown) {
|
|
|
+ keyword.value = '';
|
|
|
+ }
|
|
|
closeToast();
|
|
|
+ } else {
|
|
|
+ showNotify({ message: '请使用设备按钮进行扫码', type: 'warning' });
|
|
|
}
|
|
|
-});
|
|
|
+}
|
|
|
|
|
|
-function back(delta?: number) {
|
|
|
- stepStore.$reset();
|
|
|
- data.value = { ...dataset.value! };
|
|
|
- keyword.value = '';
|
|
|
- delta ??= route.params.value ? -2 : -1;
|
|
|
- tabIndex.value = 0;
|
|
|
- router.go(delta);
|
|
|
+function onBack() {
|
|
|
+ prev();
|
|
|
}
|
|
|
+
|
|
|
+const files = ref<UploaderFileListItem[]>([]);
|
|
|
+const picture = computed(() => files.value.filter((file) => file.status === 'done' && file.url != null).map((file) => file.url));
|
|
|
+const afterRead: UploaderAfterRead = async (listItem) => {
|
|
|
+ if (listItem && !Array.isArray(listItem)) listItem = [listItem];
|
|
|
+ for (const item of listItem) {
|
|
|
+ if (!item?.file) continue;
|
|
|
+ item.status = 'uploading';
|
|
|
+ item.message = '上传中...';
|
|
|
+ try {
|
|
|
+ item.url = await uploadMethod(item.file!);
|
|
|
+ item.status = 'done';
|
|
|
+ } catch (error) {
|
|
|
+ console.error('[file] 文件上传失败', error);
|
|
|
+ item.status = 'failed';
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
<div class="page page__home flex flex-col size-full">
|
|
|
<header class="flex-none">
|
|
|
- <van-nav-bar :title="navTitle" left-text="返回" left-arrow @click-left="back()" />
|
|
|
- <van-search
|
|
|
- v-model="keyword"
|
|
|
- input-align="center"
|
|
|
- placeholder="请使用设备按钮进行扫码"
|
|
|
- :readonly="readonly || loading || loaded"
|
|
|
- :show-action="loaded"
|
|
|
- @search="keyword && search()"
|
|
|
- @cancel="back(-1)"
|
|
|
- />
|
|
|
+ <van-nav-bar :title="menu?.title" left-text="返回" left-arrow @click-left="onBack()" />
|
|
|
+ <van-search v-model="keyword" input-align="center" placeholder="请使用设备按钮进行扫码" @search="onSearch()" :readonly="loaded" :show-action="loaded" @cancel="onBack()" />
|
|
|
</header>
|
|
|
<van-tabs class="content flex-auto overflow-hidden" v-model:active="tabIndex">
|
|
|
<van-tab title="就诊信息">
|
|
|
<van-cell-group>
|
|
|
- <van-cell title="患者" :value="data.patient?.name" />
|
|
|
- <van-cell title="性别" :value="data.patient?.gender" />
|
|
|
- <van-cell title="年龄" :value="data.patient?.age" />
|
|
|
- <van-cell title="手机号" :value="data.patient?.phone" />
|
|
|
- <van-cell title="医院" :value="data.patient?.hospital" />
|
|
|
- <van-cell title="门诊/住院" :value="data.patient?.category" />
|
|
|
- <van-cell title="科室/病区" :value="[data.patient?.department, data.patient?.area].filter((v) => !!v).join('/')" />
|
|
|
- <van-cell title="病床" :value="data.patient?.bed" />
|
|
|
- <van-cell title="临床诊断" :value="data.patient?.name" />
|
|
|
- <van-cell title="开方医生" :value="data.doctor?.name" />
|
|
|
+ <van-cell title="患者" :value="dataset?.patient?.name" />
|
|
|
+ <van-cell title="性别" :value="dataset?.patient?.gender" />
|
|
|
+ <van-cell title="年龄" :value="dataset?.patient?.age" />
|
|
|
+ <van-cell title="手机号" :value="dataset?.patient?.phone" />
|
|
|
+ <van-cell title="医院" :value="dataset?.patient?.hospital" />
|
|
|
+ <van-cell title="门诊/住院" :value="dataset?.patient?.category" />
|
|
|
+ <van-cell title="科室/病区" :value="[dataset?.patient?.department, dataset?.patient?.area].filter((v) => !!v).join('/')" />
|
|
|
+ <van-cell title="病床" :value="dataset?.patient?.bed" />
|
|
|
+ <van-cell title="临床诊断" :value="dataset?.patient?.name" />
|
|
|
+ <van-cell title="开方医生" :value="dataset?.doctor?.name" />
|
|
|
</van-cell-group>
|
|
|
</van-tab>
|
|
|
<van-tab title="处方信息">
|
|
|
<van-cell-group>
|
|
|
- <van-cell title="处方类型" :value="data.prescription?.category" />
|
|
|
- <van-cell title="处方状态" :value="data.order?.state" />
|
|
|
- <van-cell title="总金额" :value="data.prescription?.totalPrice" />
|
|
|
- <van-cell title="剂型" :value="data.prescription?.dosageForm" />
|
|
|
- <van-cell title="剂数" :value="data.prescription?.count" />
|
|
|
- <van-cell title="处方用法" :value="data.prescription?.method" />
|
|
|
- <van-cell title="服药频次" :value="data.prescription?.frequency" />
|
|
|
- <van-cell title="服药时间" :value="data.prescription?.frequencyTime" />
|
|
|
- <van-cell title="煎药量" :value="data.prescription?.volume" />
|
|
|
- <van-cell title="是否代煎" :value="data.prescription?.decoction" />
|
|
|
- <van-cell title="开方医生备注" :value="data.prescription?.remark1" />
|
|
|
- <van-cell title="配送方式" :value="data.prescription?.dispatch?.method" />
|
|
|
- <van-cell title="收货人" :value="data.prescription?.dispatch?.name" />
|
|
|
- <van-cell title="收货电话" :value="data.prescription?.dispatch?.phone" />
|
|
|
- <van-cell title="收货地址" :value="data.prescription?.dispatch?.address" value-class="flex-2" />
|
|
|
- <van-cell title="嘱托" :value="data.prescription?.entrust" />
|
|
|
- <van-cell title="药师备注" :value="data.prescription?.remark2" />
|
|
|
+ <van-cell title="处方类型" :value="dataset?.prescription?.category" />
|
|
|
+ <van-cell title="处方状态" :value="dataset?.order?.state" />
|
|
|
+ <van-cell title="总金额" :value="dataset?.prescription?.totalPrice" />
|
|
|
+ <van-cell title="剂型" :value="dataset?.prescription?.dosageForm" />
|
|
|
+ <van-cell title="剂数" :value="dataset?.prescription?.count" />
|
|
|
+ <van-cell title="处方用法" :value="dataset?.prescription?.method" />
|
|
|
+ <van-cell title="服药频次" :value="dataset?.prescription?.frequency" />
|
|
|
+ <van-cell title="服药时间" :value="dataset?.prescription?.frequencyTime" />
|
|
|
+ <van-cell title="煎药量" :value="dataset?.prescription?.volume" />
|
|
|
+ <van-cell title="是否代煎" :value="dataset?.prescription?.decoction" />
|
|
|
+ <van-cell title="开方医生备注" :value="dataset?.prescription?.remark1" />
|
|
|
+ <van-cell title="配送方式" :value="dataset?.prescription?.dispatch?.method" />
|
|
|
+ <van-cell title="收货人" :value="dataset?.prescription?.dispatch?.name" />
|
|
|
+ <van-cell title="收货电话" :value="dataset?.prescription?.dispatch?.phone" />
|
|
|
+ <van-cell title="收货地址" :value="dataset?.prescription?.dispatch?.address" value-class="flex-2" />
|
|
|
+ <van-cell title="嘱托" :value="dataset?.prescription?.entrust" />
|
|
|
+ <van-cell title="药师备注" :value="dataset?.prescription?.remark2" />
|
|
|
</van-cell-group>
|
|
|
</van-tab>
|
|
|
<van-tab title="药品信息">
|
|
@@ -161,7 +133,7 @@ function back(delta?: number) {
|
|
|
</tr>
|
|
|
</thead>
|
|
|
<tbody>
|
|
|
- <tr v-for="(medicine, index) in data.medicines" :key="medicine.id">
|
|
|
+ <tr v-for="(medicine, index) in dataset?.medicines" :key="medicine.id">
|
|
|
<th scope="row">{{ index + 1 }}</th>
|
|
|
<td class="w-24">{{ medicine.name }}</td>
|
|
|
<td>{{ medicine.size }}</td>
|
|
@@ -175,8 +147,34 @@ function back(delta?: number) {
|
|
|
</tbody>
|
|
|
</table>
|
|
|
</van-tab>
|
|
|
- <van-tab :title="tabTitle">
|
|
|
- <router-view :title="navTitle" @back="back"></router-view>
|
|
|
+ <van-tab :title="tabTitle" :disabled="!loaded">
|
|
|
+ <router-view>
|
|
|
+ <component ref="step" :is="menu?.component" @back="onBack()">
|
|
|
+ <template v-slot:scanner="{ title, disabled }">
|
|
|
+ <van-field
|
|
|
+ :label="title"
|
|
|
+ :readonly="disabled"
|
|
|
+ placeholder="请使用设备按钮进行扫码"
|
|
|
+ right-icon="scan"
|
|
|
+ @click-right-icon="!disabled && scan()"
|
|
|
+ v-model="scanValue"
|
|
|
+ @update:model-value="scan($event)"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ <template v-slot:uploader="{ disabled }">
|
|
|
+ <van-field label="拍照上传">
|
|
|
+ <template #input>
|
|
|
+ <van-uploader v-model="files" :after-read="afterRead" :disabled="disabled" />
|
|
|
+ </template>
|
|
|
+ </van-field>
|
|
|
+ </template>
|
|
|
+ <template v-slot:submit="{ title, submitting, submit }">
|
|
|
+ <div class="my-4 px-4">
|
|
|
+ <van-button type="primary" block :loading="submitting" @click="submit(picture)">{{ title }}</van-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </component>
|
|
|
+ </router-view>
|
|
|
</van-tab>
|
|
|
</van-tabs>
|
|
|
</div>
|