Pārlūkot izejas kodu

merge: 合并 feature/dev_cmj_clean 到 feature/dev_smart02_cmj

cmj 1 mēnesi atpakaļ
vecāks
revīzija
83e0e13a69

+ 5 - 0
apps/smart-pharmacy/src/api/method/dict.ts

@@ -78,3 +78,8 @@ export function listMatUsageNameDictMethod() {
 export function listExpressStateDictMethod() {
   return listDictByCodeMethod('express_state');
 }
+
+/** 煎药方式字典(decoction_type) */
+export function listDecoctionTypeDictMethod() {
+  return listDictByCodeMethod('decoction_type');
+}

+ 4 - 1
apps/smart-pharmacy/src/api/method/system.ts

@@ -271,6 +271,7 @@ export function getRoleMethod(id: string) {
   return http.get<SystemModel.Role, TransformData>(
     `/manager/system/role/${id}`,
     {
+      cacheFor: 0,
       transform(data) {
         return fromRole(data);
       },
@@ -470,7 +471,9 @@ export function listDecoctionCentersAllMethod() {
       params: { enterpriseType: 1 },
       cacheFor: 60_000,
       transform(data) {
-        return normalizeEnterpriseList(data).map((item) => fromEnterprise(item));
+        return normalizeEnterpriseList(data).map((item) =>
+          fromEnterprise(item),
+        );
       },
     },
   );

+ 3 - 4
apps/smart-pharmacy/src/api/model/prescription.ts

@@ -221,10 +221,9 @@ export function fromPrescription(
 ): PrescriptionModel.Prescription {
   const id =
     data?.id === undefined || data?.id === null ? '' : String(data.id);
-  const decoctionMethod =
-    data?.decoctionMethod ??
-    data?.isBehalfName ??
-    resolveDecoctionMethod(data?.isBehalf);
+  const decoctionMethod = String(
+    data?.isBehalf ?? data?.decoctionMethod ?? '',
+  );
 
   return {
     ...fromRow({

+ 7 - 0
apps/smart-pharmacy/src/api/model/process-node-dict.ts

@@ -1,4 +1,5 @@
 import {
+  listDecoctionTypeDictMethod,
   listDeliveryMethodDictMethod,
   listExpressStateDictMethod,
   listLogisticsCompanyDictMethod,
@@ -24,6 +25,7 @@ export { resolveDictLabel as resolveZyjxLabel };
 export { resolveDictLabel as resolveZyRouteLabel };
 export { resolveDictLabel as resolveMatUsageNameLabel };
 export { resolveDictLabel as resolveExpressStateLabel };
+export { resolveDictLabel as resolveDecoctionTypeLabel };
 
 /** 获取流程节点字典映射(带缓存) */
 export const getProcessNodeLabelMap = createDictLabelMapGetter(
@@ -51,6 +53,11 @@ export const getExpressStateLabelMap = createDictLabelMapGetter(
   listExpressStateDictMethod,
 );
 
+/** 获取煎药方式字典映射(带缓存) */
+export const getDecoctionTypeLabelMap = createDictLabelMapGetter(
+  listDecoctionTypeDictMethod,
+);
+
 let cachedLogisticsCompanyMap: Map<string, string> | null = null;
 let loadingLogisticsCompanyPromise: Promise<Map<string, string>> | null = null;
 

+ 1 - 1
apps/smart-pharmacy/src/preferences.ts

@@ -14,7 +14,7 @@ export const overridesPreferences = defineOverridesPreferences({
     authPageLayout: 'panel-center',
     layout: 'sidebar-nav',
     enablePreferences: false,
-    defaultHomePath: '/prescription/management',
+    defaultHomePath: '',
   },
   logo: {
     source: import.meta.env.VITE_APP_LOGO || '',

+ 36 - 10
apps/smart-pharmacy/src/router/guard.ts

@@ -16,6 +16,31 @@ import { useAuthStore } from '#/store';
 
 import { generateAccess } from './access';
 
+type AccessibleMenu = {
+  children?: AccessibleMenu[];
+  path?: string;
+};
+
+/** 取权限菜单中第一个可访问的叶子页面路径 */
+function getFirstAccessiblePath(menus: AccessibleMenu[]): string | undefined {
+  for (const menu of menus) {
+    if (menu.children?.length) {
+      const childPath = getFirstAccessiblePath(menu.children);
+      if (childPath) return childPath;
+    } else if (menu.path) {
+      return menu.path;
+    }
+  }
+}
+
+function isHomeEntryPath(path: string) {
+  return (
+    path === DEFAULT_PATH ||
+    (!!preferences.app.defaultHomePath &&
+      path === preferences.app.defaultHomePath)
+  );
+}
+
 /**
  * 通用守卫配置
  * @param router
@@ -62,7 +87,8 @@ function setupAccessGuard(router: Router) {
         return decodeURIComponent(
           (to.query?.redirect as string) ||
             userStore.userInfo?.homePath ||
-            preferences.app.defaultHomePath,
+            preferences.app.defaultHomePath ||
+            DEFAULT_PATH,
         );
       }
       return true;
@@ -82,7 +108,7 @@ function setupAccessGuard(router: Router) {
           path: LOGIN_PATH,
           // 如不需要,直接删除 query
           query:
-            to.fullPath === preferences.app.defaultHomePath
+            isHomeEntryPath(to.fullPath)
               ? {}
               : { redirect: encodeURIComponent(to.fullPath) },
           // 携带当前跳转的页面,登录后重新跳转该页面
@@ -122,8 +148,7 @@ function setupAccessGuard(router: Router) {
       // 则会在菜单中显示,但是访问会被重定向到403
       routes: accessRoutes,
     });
-    const path =
-      to.path === DEFAULT_PATH ? preferences.app.defaultHomePath : to.path;
+    const firstAccessiblePath = getFirstAccessiblePath(accessibleMenus);
     const redirect =
       decodeURIComponent(<string>from.query.redirect) === DEFAULT_PATH
         ? void 0
@@ -131,21 +156,22 @@ function setupAccessGuard(router: Router) {
 
     if (!userInfo.homePath) {
       userStore.updateHomePath(
-        preferences.app.defaultHomePath || accessibleMenus[0]?.path,
+        firstAccessiblePath || preferences.app.defaultHomePath,
       );
     }
 
+    const resolvedHomePath =
+      userStore.userInfo?.homePath ||
+      firstAccessiblePath ||
+      preferences.app.defaultHomePath;
+
     // 保存菜单信息和路由信息
     accessStore.setAccessMenus(accessibleMenus);
     accessStore.setAccessRoutes(accessibleRoutes);
     accessStore.setIsAccessChecked(true);
     setLastCheckedUserId(userInfo.userId);
     const redirectPath = (redirect ??
-      (path === preferences.app.defaultHomePath
-        ? userInfo.homePath ||
-          preferences.app.defaultHomePath ||
-          accessibleMenus[0]?.path
-        : to.fullPath)) as string;
+      (isHomeEntryPath(to.path) ? resolvedHomePath : to.fullPath)) as string;
 
     return {
       ...router.resolve(decodeURIComponent(redirectPath)),

+ 1 - 4
apps/smart-pharmacy/src/store/auth.ts

@@ -3,7 +3,6 @@ import { useRouter } from 'vue-router';
 
 import { DEFAULT_PATH, LOGIN_PATH } from '@vben/constants';
 import { $t } from '@vben/locales';
-import { preferences } from '@vben/preferences';
 import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';
 
 import { useRequest } from '@six/request';
@@ -32,9 +31,7 @@ export const useAuthStore = defineStore('auth', () => {
     resetAccessState(accessStore);
     const userInfo = await userinfo.send(data.accessToken);
 
-    await router.push(
-      userInfo.homePath || preferences.app.defaultHomePath || DEFAULT_PATH,
-    );
+    await router.push(userInfo.homePath || DEFAULT_PATH);
     if (userInfo.realName) {
       notification.success({
         description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.realName}`,

+ 24 - 0
apps/smart-pharmacy/src/views/prescription/management/data.ts

@@ -6,6 +6,7 @@ import type { PrescriptionModel } from '#/api';
 
 import {
   listCampusByParentApiMethod,
+  listDecoctionTypeDictMethod,
   listMedicalInstitutionsMethod,
   listDecoctionCentersAllMethod,
   listProcessNodeDictMethod,
@@ -175,6 +176,29 @@ export function useUserSearchFormSchema(): VbenFormSchema[] {
         maxTagCount: 'responsive',
       },
     },
+    {
+      component: 'Input',
+      fieldName: 'patientName',
+      label: $t('prescription.list.patientName'),
+      componentProps: {
+        allowClear: true,
+        placeholder: '请输入',
+      },
+    },
+    {
+      component: 'ApiSelect',
+      fieldName: 'decoctionMethod',
+      label: $t('prescription.list.decoctionMethod'),
+      componentProps: {
+        allowClear: true,
+        api: listDecoctionTypeDictMethod,
+        class: 'w-full',
+        labelField: 'dictName',
+        valueField: 'dictValue',
+        mode: 'multiple',
+        maxTagCount: 'responsive',
+      },
+    },
   ];
 }
 

+ 10 - 12
apps/smart-pharmacy/src/views/prescription/management/detail.vue

@@ -265,11 +265,9 @@ watch(prescriptionId, loadDetail, { immediate: true });
       <div class="prescription-detail rounded-lg bg-card p-6 shadow-sm">
         <div class="border-border mb-6 flex items-center justify-between border-b pb-4">
           <div class="flex items-center gap-4">
-            <span class="text-foreground text-lg font-semibold">煎药中心处方</span>
-            <span class="text-muted-foreground">|</span>
-            <span class="text-foreground/80">
-              处方号:{{ header.number || header.id || '-' }}
-            </span>
+            <span class="text-foreground text-lg font-semibold">处方号:{{ header.number || header.id || '-' }}</span>
+            <span class="text-muted-foreground"></span>
+            <span class="text-foreground/80"></span>
           </div>
           <div class="text-foreground/80 flex items-center gap-2">
             <span>{{ header.date }}</span>
@@ -317,7 +315,7 @@ watch(prescriptionId, loadDetail, { immediate: true });
           <Tabs.TabPane key="prescription" tab="处方详情">
             <div class="space-y-6">
               <div class="bg-muted/50 rounded-lg p-4">
-                <h3 class="text-foreground/90 mb-4 text-sm font-medium">煎药要求</h3>
+                <h3 class="text-foreground mb-4 text-sm font-semibold">煎药要求</h3>
                 <Descriptions :column="4" :size="'small'">
                   <Descriptions.Item label="中药类型">
                     {{ prescriptionDetails.chineseMedicineType }}
@@ -353,7 +351,7 @@ watch(prescriptionId, loadDetail, { immediate: true });
               </div>
 
               <div class="bg-muted/50 rounded-lg p-4">
-                <h3 class="text-foreground/90 mb-4 text-sm font-medium">配送信息</h3>
+                <h3 class="text-foreground mb-4 text-sm font-semibold">配送信息</h3>
                 <Descriptions :column="4" :size="'small'">
                   <Descriptions.Item label="配送方式">
                     {{ deliveryInfo.deliveryMethod }}
@@ -367,7 +365,7 @@ watch(prescriptionId, loadDetail, { immediate: true });
                   <Descriptions.Item label="收件电话">
                     {{ deliveryInfo.recipientPhone }}
                   </Descriptions.Item>
-                  <Descriptions.Item label="收件省市" :span="2">
+                  <Descriptions.Item label="收件省市" :span="2">
                     {{ deliveryInfo.provinceCity }}
                   </Descriptions.Item>
                   <Descriptions.Item label="详细地址" :span="2">
@@ -377,7 +375,7 @@ watch(prescriptionId, loadDetail, { immediate: true });
               </div>
 
               <div class="bg-muted/50 rounded-lg p-4">
-                <h3 class="text-foreground/90 mb-4 text-sm font-medium">
+                <h3 class="text-foreground mb-4 text-sm font-semibold">
                   用药信息和金额
                 </h3>
                 <Descriptions :column="4" :size="'small'">
@@ -424,7 +422,7 @@ watch(prescriptionId, loadDetail, { immediate: true });
               </div>
 
               <div class="bg-muted/50 rounded-lg p-4">
-                <h3 class="text-foreground/90 mb-4 text-sm font-medium">就诊信息</h3>
+                <h3 class="text-foreground mb-4 text-sm font-semibold">就诊信息</h3>
                 <Descriptions :column="4" :size="'small'">
                   <Descriptions.Item label="门诊/住院">
                     {{ doctorInfo.outpatientType }}
@@ -529,7 +527,7 @@ watch(prescriptionId, loadDetail, { immediate: true });
             <div class="bg-muted/50 rounded-lg p-4">
               <div class="grid grid-cols-2 gap-4">
                 <div class="bg-card rounded-lg p-4">
-                  <h3 class="text-foreground/90 mb-4 text-sm font-medium">
+                  <h3 class="text-foreground mb-4 text-sm font-semibold">
                     处方流转流程
                   </h3>
                   <div
@@ -579,7 +577,7 @@ watch(prescriptionId, loadDetail, { immediate: true });
                 </div>
 
                 <div class="bg-card rounded-lg p-4">
-                  <h3 class="text-foreground/90 mb-4 text-sm font-medium">物流跟踪</h3>
+                  <h3 class="text-foreground mb-4 text-sm font-semibold">物流跟踪</h3>
                   <template
                     v-if="
                       logisticsInfo.company ||

+ 23 - 11
apps/smart-pharmacy/src/views/prescription/management/list.vue

@@ -12,9 +12,11 @@ import { Page } from '@vben/common-ui';
 import { useVbenVxeGrid } from '#/adapter/vxe-table';
 import { listPrescriptionsMethod } from '#/api';
 import {
+  getDecoctionTypeLabelMap,
   getDeliveryMethodLabelMap,
   getLogisticsCompanyLabelMap,
   getProcessNodeLabelMap,
+  resolveDecoctionTypeLabel,
   resolveDeliveryMethodLabel,
   resolveLogisticsCompanyLabel,
   resolveProcessNodeLabel,
@@ -36,17 +38,23 @@ const [Grid] = useVbenVxeGrid({
     proxyConfig: {
       ajax: {
         async query({ page }, formValues) {
-          const [result, processNodeMap, deliveryMethodMap, logisticsCompanyMap] =
-            await Promise.all([
-              listPrescriptionsMethod(
-                page.currentPage,
-                page.pageSize,
-                formValues,
-              ),
-              getProcessNodeLabelMap(),
-              getDeliveryMethodLabelMap(),
-              getLogisticsCompanyLabelMap(),
-            ]);
+          const [
+            result,
+            processNodeMap,
+            deliveryMethodMap,
+            logisticsCompanyMap,
+            decoctionTypeMap,
+          ] = await Promise.all([
+            listPrescriptionsMethod(
+              page.currentPage,
+              page.pageSize,
+              formValues,
+            ),
+            getProcessNodeLabelMap(),
+            getDeliveryMethodLabelMap(),
+            getLogisticsCompanyLabelMap(),
+            getDecoctionTypeLabelMap(),
+          ]);
           return {
             ...result,
             items: result.items.map((item) => ({
@@ -55,6 +63,10 @@ const [Grid] = useVbenVxeGrid({
                 item.processStatus,
                 processNodeMap,
               ),
+              decoctionMethod: resolveDecoctionTypeLabel(
+                item.decoctionMethod,
+                decoctionTypeMap,
+              ),
               deliveryMethod: resolveDeliveryMethodLabel(
                 item.deliveryMethod,
                 deliveryMethodMap,