소스 검색

story-73 浸泡管理
story-74 煎煮管理
story-75 打包管理(无打印)
story-76 打包复核管理(无打印)

cc12458 1 개월 전
부모
커밋
377765cdf3

+ 63 - 7
src/api/pda.api.ts

@@ -2,8 +2,8 @@ import type { ResponseData } from 'alova';
 import PharmacyHttpClient from '@request/pharmacy.request.ts';
 import { requestMethodFactory } from '@/platform/request.ts';
 
-import type { SoakModel, StepModel } from '@/model/step.model.ts';
-import { fromSoakModel } from '@/model/step.model.ts';
+import type { DecoctionModel, PackModel, SoakModel, StepModel } from '@/model/step.model.ts';
+import { fromDecoctionModel, fromPackModel, fromSoakModel } from '@/model/step.model.ts';
 
 export function getDataMethod(no: string) {
   return requestMethodFactory(
@@ -96,7 +96,7 @@ export function setDataMethod(url: string, data: ResponseData) {
  * 调配节点保存
  * @param data
  */
-export function setDeployDataMethod (data: Record<string, any>) {
+export function setDeployDataMethod(data: ResponseData) {
   return requestMethodFactory(PharmacyHttpClient.Post('/file/saveCoreFile', data));
 }
 
@@ -104,10 +104,8 @@ export function setDeployDataMethod (data: Record<string, any>) {
  * 调配复核节点保存
  * @param data
  */
-export function setDeployRecheckDataMethod (data: Record<string, any>) {
-  return requestMethodFactory(
-    PharmacyHttpClient.Post('/prescription/prescriptionCore/reviewPrescription', data)
-  );
+export function setDeployRecheckDataMethod(data: ResponseData) {
+  return requestMethodFactory(PharmacyHttpClient.Post('/prescription/prescriptionCore/reviewPrescription', data));
 }
 
 export function getSoakDataMethod(id: string) {
@@ -122,3 +120,61 @@ export function setSoakDataMethod(model: Partial<SoakModel>, picture?: string[])
     }),
   );
 }
+
+/**
+ * 煎煮节点获取
+ * @param id
+ */
+export function getDecoctionDataMethod(id: string) {
+  return PharmacyHttpClient.Get<DecoctionModel, ResponseData>(`/web/pda/decoct/${id}`, { transform: fromDecoctionModel });
+}
+
+/**
+ * 煎煮节点保存
+ * @param model
+ * @param picture
+ */
+export function setDecoctionDataMethod(model: Partial<DecoctionModel>, picture?: string[]) {
+  return requestMethodFactory(
+    PharmacyHttpClient.Put('/web/pda/decoct/edit', {
+      ...model,
+      image: picture?.join(',') ?? '',
+    }),
+  );
+}
+
+/**
+ * 打包节点获取
+ * @param id
+ */
+export function getPackDataMethod(id: string) {
+  return PharmacyHttpClient.Get<PackModel, ResponseData>(`/web/pda/Pack/${id}`, { transform: fromPackModel });
+}
+
+/**
+ * 打包节点保存
+ * @param model
+ * @param picture
+ */
+export function setPackDataMethod(model: Partial<PackModel>, picture?: string[]) {
+  return requestMethodFactory(
+    PharmacyHttpClient.Put('/web/pda/Pack/edit', {
+      ...model,
+      image: picture?.join(',') ?? '',
+    }),
+  );
+}
+
+/**
+ * 打包复核节点保存
+ * @param model
+ * @param picture
+ */
+export function setPackRecheckDataMethod(model: Partial<PackModel>, picture?: string[]) {
+  return requestMethodFactory(
+    PharmacyHttpClient.Put('/web/pda/Pack/addPackReview', {
+      ...model,
+      image: picture?.join(',') ?? '',
+    }),
+  );
+}

+ 42 - 0
src/model/step.model.ts

@@ -67,3 +67,45 @@ export function fromSoakModel(data?: ResponseData) {
     data,
   ) as SoakModel;
 }
+
+export interface DecoctionModel extends ResponseData {
+  decoctNote: string;
+  startConcentrationDose: string;
+  endConcentrationDose: string;
+  deviceCode: string;
+
+  images: string;
+}
+
+export function fromDecoctionModel(data?: ResponseData) {
+  return Object.assign(
+    {
+      decoctNote: data?.decoctNote ?? '',
+      startConcentrationDose: data?.startConcentrationDose ?? '',
+      endConcentrationDose: data?.endConcentrationDose ?? '',
+      deviceCode: data?.deviceCode ?? '',
+    },
+    data,
+  ) as DecoctionModel;
+}
+
+export interface PackModel extends ResponseData {
+  packingNote: string;
+  packageDose: string;
+  packageNumber: string;
+  deviceCode: string;
+
+  images: string;
+}
+
+export function fromPackModel(data?: ResponseData) {
+  return Object.assign(
+    {
+      packingNote: data?.packingNote ?? '',
+      packageDose: data?.packageDose ?? '',
+      packageNumber: data?.packageNumber ?? '',
+      deviceCode: data?.deviceCode ?? '',
+    },
+    data,
+  ) as PackModel;
+}

+ 83 - 0
src/module/step/StepDecoction.vue

@@ -0,0 +1,83 @@
+<script setup lang="ts">
+import { showSuccessToast } from 'vant';
+
+import { useForm, useWatcher } from 'alova/client';
+import { getDecoctionDataMethod, setDecoctionDataMethod } from '@/api/pda.api.ts';
+import { type DecoctionModel, fromDecoctionModel } from '@/model/step.model.ts';
+import { useStepStore } from '@/stores';
+
+import type { ScanData } from '@/core/hook/useScan.ts';
+
+const emits = defineEmits<{ back: [delta?: number] }>();
+
+const storeStore = useStepStore();
+const { dataset } = storeToRefs(storeStore);
+
+const {
+  loading: submitting,
+  form: model,
+  send,
+} = useForm(setDecoctionDataMethod, { immediate: false, initialForm: fromDecoctionModel() }).onSuccess(() => {
+  showSuccessToast(`操作成功`);
+  emits('back');
+});
+
+const { data, loading } = useWatcher(() => getDecoctionDataMethod(dataset.value!.id), [dataset], { immediate: true, initialData: {} })
+  .onSuccess(({ data }) => {
+    for (const [key, value] of Object.entries(data)) model.value[key as keyof DecoctionModel] = value;
+  })
+  .onError(({ error: message }) => {
+    showDialog({ title: '温馨提示', message, closeOnClickOverlay: true }).then(() => emits('back'));
+  });
+
+defineExpose({
+  scan(data: ScanData) {
+    model.value.deviceCode = data?.code ?? '';
+  },
+});
+</script>
+
+<template>
+  <van-toast :show="loading" type="loading" forbid-click />
+
+  <van-cell title="煎药方案" :value="data.schemeName" />
+  <van-cell title="压力模式" :value="data.pressurePattern" />
+  <van-cell title="剂型" :value="data.dosageForm" />
+  <van-cell title="煎煮时间" :value="data.decoctTime ? `${data.decoctTime} min` : ''" />
+  <van-cell title="先煎时间" :value="data.preDecoctTime ? `${data.preDecoctTime} min` : ''" />
+  <van-cell title="一煎时间" :value="data.firstDecoctTime ? `${data.firstDecoctTime} min` : ''" />
+  <van-cell title="二煎时间" :value="data.secondDecoctTime ? `${data.secondDecoctTime} min` : ''" />
+  <van-cell title="后下时间" :value="data.backDownTime ? `${data.backDownTime} min` : ''" />
+
+  <van-field class="suffix" v-model="model.startConcentrationDose" :readonly="submitting" type="digit" label="开始浓缩药量" placeholder="请输入开始浓缩药量">
+    <template #extra>
+      <div v-if="model.startConcentrationDose">ml</div>
+    </template>
+  </van-field>
+  <van-field class="suffix" v-model="model.endConcentrationDose" :readonly="submitting" type="digit" label="结束浓缩药量" placeholder="请输入结束浓缩药量">
+    <template #extra>
+      <div v-if="model.endConcentrationDose">ml</div>
+    </template>
+  </van-field>
+
+  <slot name="scanner" title="扫描设备" :disabled="submitting"></slot>
+  <slot name="uploader" :disabled="submitting"></slot>
+
+  <van-field v-model="model.decoctNote" :readonly="submitting" rows="2" autosize label="煎煮备注" type="textarea" placeholder="请输入备注内容" />
+  <slot name="submit" title="煎煮节点上传" :submitting="submitting" :submit="send"></slot>
+</template>
+
+<style scoped lang="scss">
+.van-field.suffix {
+  :deep(.van-field__value) {
+    flex: none;
+    //width: min-content;
+    //min-width: 120px;
+    max-width: 170px;
+
+    input {
+      text-align: center;
+    }
+  }
+}
+</style>

+ 1 - 1
src/module/step/StepDeploy.vue

@@ -35,7 +35,7 @@ const {
 
 <template>
   <slot name="uploader" :disabled="submitting"></slot>
-  <van-field v-model="model.comments" :readonly="submitting" rows="2" autosize label="调配备注" type="textarea" placeholder="请输入备注" />
+  <van-field v-model="model.comments" :readonly="submitting" rows="2" autosize label="调配备注" type="textarea" placeholder="请输入备注内容" />
   <slot name="submit" title="调配节点上传" :submitting="submitting" :submit="send"></slot>
 </template>
 

+ 1 - 1
src/module/step/StepDeployRecheck.vue

@@ -67,7 +67,7 @@ function submit(picture: string[]) {
     </template>
   </van-field>
   <slot name="uploader" :disabled="submitting"></slot>
-  <van-field v-model="model.comments" :readonly="submitting" rows="2" autosize label="调配复核备注" type="textarea" placeholder="请输入备注" />
+  <van-field v-model="model.comments" :readonly="submitting" rows="2" autosize label="调配复核备注" type="textarea" placeholder="请输入备注内容" />
   <slot name="submit" title="调配复核节点上传" :submitting="submitting" :submit="submit"></slot>
 </template>
 

+ 67 - 0
src/module/step/StepPack.vue

@@ -0,0 +1,67 @@
+<script setup lang="ts">
+import { showSuccessToast } from 'vant';
+
+import { useForm, useWatcher } from 'alova/client';
+import { getPackDataMethod, setPackDataMethod } from '@/api/pda.api.ts';
+import { fromPackModel, type PackModel } from '@/model/step.model.ts';
+import { useStepStore } from '@/stores';
+
+import type { ScanData } from '@/core/hook/useScan.ts';
+
+const emits = defineEmits<{ back: [delta?: number] }>();
+
+const storeStore = useStepStore();
+const { dataset } = storeToRefs(storeStore);
+
+const {
+  loading: submitting,
+  form: model,
+  send,
+} = useForm(setPackDataMethod, { immediate: false, initialForm: fromPackModel() }).onSuccess(() => {
+  showSuccessToast(`操作成功`);
+  emits('back');
+});
+
+const { data, loading } = useWatcher(() => getPackDataMethod(dataset.value!.id), [dataset], { immediate: true, initialData: {} })
+  .onSuccess(({ data }) => {
+    for (const [key, value] of Object.entries(data)) model.value[key as keyof PackModel] = value;
+  })
+  .onError(({ error: message }) => {
+    showDialog({ title: '温馨提示', message, closeOnClickOverlay: true }).then(() => emits('back'));
+  });
+
+defineExpose({
+  scan(data: ScanData) {
+    model.value.deviceCode = data?.code ?? '';
+  },
+});
+</script>
+
+<template>
+  <van-toast :show="loading" type="loading" forbid-click />
+
+  <van-cell title="包装量" :value="data.packageDose ? `${data.packageDose} ml` : ''" />
+  <van-cell title="包数" :value="data.packageNumber ? `${data.packageNumber} 包` : ''" />
+
+  <slot name="scanner" title="扫描设备" :disabled="submitting"></slot>
+  <slot name="uploader" :disabled="submitting"></slot>
+
+  <van-field v-model="model.packingNote" :readonly="submitting" rows="2" autosize label="打包备注" type="textarea" placeholder="请输入备注内容" />
+
+  <slot name="submit" title="打包节点上传" :submitting="submitting" :submit="send"></slot>
+</template>
+
+<style scoped lang="scss">
+.van-field.suffix {
+  :deep(.van-field__value) {
+    flex: none;
+    //width: min-content;
+    //min-width: 120px;
+    max-width: 170px;
+
+    input {
+      text-align: center;
+    }
+  }
+}
+</style>

+ 83 - 0
src/module/step/StepPackRecheck.vue

@@ -0,0 +1,83 @@
+<script setup lang="ts">
+import { showNotify, showSuccessToast } from 'vant';
+
+import { useForm, useWatcher } from 'alova/client';
+import { getPackDataMethod, setPackRecheckDataMethod } from '@/api/pda.api.ts';
+import { fromPackModel, type PackModel } from '@/model/step.model.ts';
+import { useStepStore } from '@/stores';
+
+const emits = defineEmits<{ back: [delta?: number] }>();
+
+const storeStore = useStepStore();
+const { dataset } = storeToRefs(storeStore);
+
+const {
+  loading: submitting,
+  form: model,
+  send,
+} = useForm(setPackRecheckDataMethod, { immediate: false, initialForm: fromPackModel() }).onSuccess(() => {
+  showSuccessToast(`操作成功`);
+  emits('back');
+});
+
+const { loading } = useWatcher(() => getPackDataMethod(dataset.value!.id), [dataset], { immediate: true, initialData: {} })
+  .onSuccess(({ data }) => {
+    for (const [key, value] of Object.entries(data)) model.value[key as keyof PackModel] = value;
+  })
+  .onError(({ error: message }) => {
+    showDialog({ title: '温馨提示', message, closeOnClickOverlay: true }).then(() => emits('back'));
+  });
+
+function submit(picture: string[]) {
+  let message = '';
+  if (!+model.value.packageDose) {
+    message = '请输入包装量';
+  } else if (!+model.value.packageNumber) {
+    message = '请输入包数';
+  }
+  if (message) {
+    showNotify({ message, type: 'warning' });
+  } else {
+    send(picture);
+  }
+}
+</script>
+
+<template>
+  <van-toast :show="loading" type="loading" forbid-click />
+
+  <van-field class="suffix" v-model="model.packageDose" :readonly="submitting" type="digit" label="包装量" placeholder="请输入包装量">
+    <template #extra>
+      <div v-if="model.packageDose">ml</div>
+    </template>
+  </van-field>
+  <van-field class="suffix" v-model="model.packageNumber" :readonly="submitting" type="digit" label="包数" placeholder="请输入包数">
+    <template #extra>
+      <div v-if="model.packageNumber">包</div>
+    </template>
+  </van-field>
+
+  <slot name="uploader" :disabled="submitting"></slot>
+
+  <van-field v-model="model.packingNote" :readonly="submitting" rows="2" autosize label="打包复核备注" type="textarea" placeholder="请输入备注内容" />
+
+  <slot name="submit" title="打包复核节点上传" :submitting="submitting" :submit="submit"></slot>
+  <!--<teleport to="#bottom-handle">
+    <van-button block :loading="submitting">打印标签</van-button>
+  </teleport>-->
+</template>
+
+<style scoped lang="scss">
+.van-field.suffix {
+  :deep(.van-field__value) {
+    flex: none;
+    //width: min-content;
+    //min-width: 120px;
+    max-width: 170px;
+
+    input {
+      text-align: center;
+    }
+  }
+}
+</style>

+ 18 - 14
src/module/step/StepSoak.vue

@@ -1,9 +1,11 @@
 <script setup lang="ts">
-import { useStepStore } from '@/stores';
+import { showNotify, showSuccessToast } from 'vant';
+
 import { useForm, useWatcher } from 'alova/client';
 import { getSoakDataMethod, setSoakDataMethod } from '@/api/pda.api.ts';
-import { showNotify, showSuccessToast } from 'vant';
-import { fromSoakModel } from '@/model/step.model.ts';
+import { fromSoakModel, type SoakModel } from '@/model/step.model.ts';
+import { useStepStore } from '@/stores';
+
 import type { ScanData } from '@/core/hook/useScan.ts';
 
 const emits = defineEmits<{ back: [delta?: number] }>();
@@ -20,12 +22,9 @@ const {
   emits('back');
 });
 
-const soakingTimeFieldReadonly = ref(false);
-useWatcher(() => getSoakDataMethod(dataset.value!.id), [dataset], { immediate: true })
+const { data, loading } = useWatcher(() => getSoakDataMethod(dataset.value!.id), [dataset], { immediate: true, initialData: {} })
   .onSuccess(({ data }) => {
-    console.log(data);
-    model.value = data;
-    soakingTimeFieldReadonly.value = data?.soakingTime != null;
+    for (const [key, value] of Object.entries(data)) model.value[key as keyof SoakModel] = value;
   })
   .onError(({ error: message }) => {
     showDialog({ title: '温馨提示', message, closeOnClickOverlay: true }).then(() => emits('back'));
@@ -51,19 +50,24 @@ defineExpose({
 </script>
 
 <template>
+  <van-toast :show="loading" type="loading" forbid-click />
+
   <van-field class="suffix" v-model="model.soakingWaterValue" :readonly="submitting" type="digit" label="浸泡水量" placeholder="请输入浸泡水量">
     <template #extra>
       <div v-if="model.soakingWaterValue">ml</div>
     </template>
   </van-field>
-  <van-field class="suffix" v-model="model.soakingTime" :readonly="submitting || soakingTimeFieldReadonly" type="digit" label="浸泡时间" placeholder="请输入浸泡时间">
+  <van-field class="suffix" v-model="model.soakingTime" :readonly="submitting || !!data.soakingTime" type="digit" label="浸泡时间" placeholder="请输入浸泡时间">
     <template #extra>
       <div v-if="model.soakingTime">min</div>
     </template>
   </van-field>
+
   <slot name="scanner" title="扫描桶号" :disabled="submitting"></slot>
   <slot name="uploader" :disabled="submitting"></slot>
-  <van-field v-model="model.soakingNote" :readonly="submitting" rows="2" autosize label="浸泡备注" type="textarea" placeholder="请输入备注" />
+
+  <van-field v-model="model.soakingNote" :readonly="submitting" rows="2" autosize label="浸泡备注" type="textarea" placeholder="请输入备注内容" />
+
   <slot name="submit" title="浸泡节点上传" :submitting="submitting" :submit="submit"></slot>
 </template>
 
@@ -71,13 +75,13 @@ defineExpose({
 .van-field.suffix {
   :deep(.van-field__value) {
     flex: none;
-    width: min-content;
-    min-width: 80px;
+    //width: min-content;
+    //min-width: 120px;
+    max-width: 170px;
 
     input {
       text-align: center;
-      }
     }
   }
+}
 </style>
-

+ 1 - 1
src/pages/StepPage.vue

@@ -169,7 +169,7 @@ const afterRead: UploaderAfterRead = async (listItem) => {
               </van-field>
             </template>
             <template v-slot:submit="{ title, submitting, submit }">
-              <div class="my-4 px-4">
+              <div class="flex my-4 px-4 gap-4" id="bottom-handle">
                 <van-button type="primary" block :loading="submitting" @click="submit(picture)">{{ title }}</van-button>
               </div>
             </template>

+ 23 - 1
src/router/menu.ts

@@ -4,7 +4,14 @@ export interface Menu {
   component: Component;
 }
 
-export type MenuPath = '/step/deploy' | '/step/deploy-recheck' | '/step/soak';
+export type MenuPath =
+  | '/step/deploy'
+  | '/step/deploy-recheck'
+  | '/step/soak'
+  | '/step/decoction'
+  | '/step/pack'
+  | '/step/pack-recheck'
+  ;
 
 export const menus: Record<MenuPath, Menu> = {
   '/step/deploy': {
@@ -22,6 +29,21 @@ export const menus: Record<MenuPath, Menu> = {
     title: '浸泡管理',
     component: defineAsyncComponent(() => import(`@/module/step/StepSoak.vue`)),
   },
+  '/step/decoction': {
+    index: 41,
+    title: '煎煮管理',
+    component: defineAsyncComponent(() => import(`@/module/step/StepDecoction.vue`)),
+  },
+  '/step/pack': {
+    index: 51,
+    title: '打包管理',
+    component: defineAsyncComponent(() => import(`@/module/step/StepPack.vue`)),
+  },
+  '/step/pack-recheck': {
+    index: 52,
+    title: '打包复核管理',
+    component: defineAsyncComponent(() => import(`@/module/step/StepPackRecheck.vue`)),
+  },
 } as const;
 
 export const defaultMenus = Object.entries(menus)