cc12458 2 týždňov pred
rodič
commit
e8a3a23bb8

+ 1 - 1
request/system.request.ts

@@ -28,5 +28,5 @@ async function analysisResponseBody(response: Response, method: Method) {
   const { code, msg, data, ...external } = body;
   if (code !== 200) throw method.meta?.exception?.(msg, response, method) ?? msg;
   ['success', 'warn', 'error'].forEach((key) => Reflect.deleteProperty(external, key));
-  return Object.assign({}, external, data);
+  return Array.isArray(data) ? Object.assign(data, external) : Object.assign({}, external, data);
 }

+ 29 - 2
src/api/account.api.ts

@@ -5,6 +5,13 @@ import type { ResponseData } from 'alova';
 import { requestMethodFactory } from '@/platform/request.ts';
 import type { AccountModel } from '@model/account.model.ts';
 
+import { defaultMenus, type MenuPath, menus as menusMap } from '@/router/menu.ts';
+
+interface AccountData {
+  token: string;
+  account: AccountModel;
+}
+
 export function loginMethod(data: { username: string; password: string }) {
   return requestMethodFactory(
     PharmacyHttpClient.Post<string, ResponseData>(`/login/v2`, data, {
@@ -17,7 +24,7 @@ export function loginMethod(data: { username: string; password: string }) {
 
 export function getAccountMethod(token: string) {
   return requestMethodFactory(
-    SystemHttpClient.Get<{ token: string; account: AccountModel }, ResponseData>(`/user/getInfo`, {
+    SystemHttpClient.Get<AccountData, ResponseData>(`/user/getInfo`, {
       headers: { Authorization: token },
       transform(data) {
         const user = data?.user;
@@ -27,10 +34,30 @@ export function getAccountMethod(token: string) {
             id: user?.userId?.toString(),
             name: user?.nickName ?? user?.userName ?? '',
             username: user?.userName,
-            nickname: user?.nickName
+            nickname: user?.nickName,
           },
         };
       },
     }),
   );
 }
+
+export function getMenusMethod({ token, ...account }: AccountData) {
+  return requestMethodFactory(
+    SystemHttpClient.Get<AccountData & { menus: typeof defaultMenus }, ResponseData[]>(`/menu/getPdaRouters`, {
+      headers: { Authorization: token },
+      transform(data) {
+        let menus;
+        if (Array.isArray(data)) {
+          menus = data.map(({ path, meta }) => {
+            const name = meta?.title || (menusMap[path as MenuPath]?.title ?? '');
+            return { path, name };
+          }).filter(Boolean);
+        } else {
+          menus = defaultMenus;
+        }
+        return Object.assign(account, { token, menus });
+      },
+    }),
+  );
+}

BIN
src/assets/images/empty.png


+ 9 - 2
src/core/hook/useStep.ts

@@ -1,11 +1,18 @@
 import { type Menu, type MenuPath, menus } from '@/router/menu.ts';
 
-export function useStep(mode: Ref<string>, id: Ref<string>) {
+export function useStep(mode: Ref<string>, id: Ref<string>, title?: Ref<string>) {
   const menu = shallowRef<Menu | void>();
   const tabTitle = computed(() => menu.value?.title.replace('管理', '确认') ?? '确认');
 
   watchEffect(() => {
-    menu.value = menus[`/step/${mode.value}` as MenuPath] ?? { title: import.meta.env.SIX_TITLE };
+    const _menu = menus[`/step/${mode.value}` as MenuPath];
+    if (!_menu) {
+      menu.value = { title: import.meta.env.SIX_TITLE!! } as any;
+    } else if (title?.value) {
+      menu.value = { ..._menu, title: title?.value };
+    } else {
+      menu.value = _menu;
+    }
   });
 
   const router = useRouter();

+ 11 - 0
src/module/step/StepPutaway.vue

@@ -0,0 +1,11 @@
+<script setup lang="ts">
+
+</script>
+
+<template>
+  $END$
+</template>
+
+<style scoped lang="scss">
+
+</style>

+ 8 - 1
src/pages/HomePage.vue

@@ -25,6 +25,13 @@ function logout() {
     },
   });
 }
+
+const step = useStepStore();
+const go = (menu: { path: string; name?: string }) => {
+  step.$reset();
+  step.title = menu.name;
+  router.push({ path: menu.path });
+};
 </script>
 
 <template>
@@ -32,7 +39,7 @@ function logout() {
     <van-nav-bar :title="navTitle" left-text="退出" left-arrow @click-left="logout" :right-text="navText" />
     <div class="mt-8">
       <van-cell-group inset>
-        <van-cell v-for="menu in menus" :key="menu.path" size="large" is-link :title="menu.name" :to="menu.path" />
+        <van-cell v-for="menu in menus" :key="menu.path" size="large" is-link :title="menu.name" @click="go(menu)" />
       </van-cell-group>
     </div>
   </div>

+ 15 - 9
src/pages/LoginPage.vue

@@ -1,23 +1,29 @@
 <script setup lang="ts">
 import { showSuccessToast } from 'vant';
 import { useSerialRequest } from 'alova/client';
-import { getAccountMethod, loginMethod } from '@/api/account.api.ts';
+import { getAccountMethod, getMenusMethod, loginMethod } from '@/api/account.api.ts';
 import { useAccountStore } from '@/stores';
-import { defaultMenus } from '@/router/menu.ts';
 
 const router = useRouter();
 const store = useAccountStore();
 const { token, account, menus } = storeToRefs(store);
 
 const title = import.meta.env.SIX_TITLE;
-const { loading: submitting, send: submit } = useSerialRequest([() => loginMethod(toRaw(model)), (token) => getAccountMethod(token)], { immediate: false }).onSuccess(
+const { loading: submitting, send: submit } = useSerialRequest([() => loginMethod(toRaw(model)), (token) => getAccountMethod(token), (data) => getMenusMethod(data)], { immediate: false }).onSuccess(
   ({ data }) => {
-    token.value = data.token;
-    account.value = data.account;
-    menus.value = defaultMenus;
-    router.replace({ name: 'home' }).then(() => {
-      showSuccessToast(`登录成功`);
-    });
+    if (data.menus?.length) {
+      token.value = data.token;
+      account.value = data.account;
+      menus.value = data.menus;
+      router.replace({ name: 'home' }).then(() => {
+        showSuccessToast(`登录成功`);
+      });
+    } else {
+      showDialog({
+        title: '温馨提示',
+        message: `请联系管理员配置所需的功能菜单`
+      })
+    }
   },
 );
 

+ 25 - 0
src/pages/NotFound.vue

@@ -0,0 +1,25 @@
+<script setup lang="ts">
+import Empty from '@/assets/images/empty.png?url';
+import { useRouter } from 'vue-router';
+
+const router = useRouter();
+
+function back() {
+  if (window.history.length > 1) router.back();
+  else router.replace({ name: 'home' });
+}
+</script>
+
+<template>
+  <div style="text-align: center; margin-top: 100px">
+    <van-empty :image="Empty" image-size="120" description="页面未找到">
+      <van-button type="primary" round class="bottom-button" @click="back()">返回</van-button>
+    </van-empty>
+  </div>
+</template>
+
+<style scoped lang="scss">
+.bottom-button {
+  width: 60vw;
+}
+</style>

+ 2 - 2
src/pages/StepPage.vue

@@ -10,12 +10,12 @@ import { useStep } from '@/core/hook/useStep.ts';
 import { type ScanData, useScan } from '@/core/hook/useScan.ts';
 
 const stepStore = useStepStore();
-const { dataset, id, mode } = storeToRefs(stepStore);
+const { dataset, id, mode, title } = storeToRefs(stepStore);
 const loaded = computed(() => !!id.value);
 
 const keyword = ref('');
 const tabIndex = ref(0);
-const { menu, tabTitle, next, prev } = useStep(mode, id);
+const { menu, tabTitle, next, prev } = useStep(mode, id, title);
 
 watchEffect(() => {
   keyword.value = id.value;

+ 5 - 1
src/router/index.ts

@@ -1,5 +1,8 @@
 import { createRouter, createWebHistory } from 'vue-router';
 import { AccountGuard } from '@/router/account.guard.ts';
+import { stepMode } from '@/router/menu.ts';
+
+import NotFound from '@/pages/NotFound.vue';
 
 const router = createRouter({
   history: createWebHistory(import.meta.env.BASE_URL),
@@ -20,7 +23,7 @@ const router = createRouter({
           meta: { title: '' },
         },
         {
-          path: `step/:mode`,
+          path: `step/:mode(${stepMode.join('|')})`,
           component: () => import(`@/pages/StepPage.vue`),
           children: [
             {
@@ -33,6 +36,7 @@ const router = createRouter({
       beforeEnter: [AccountGuard.grant],
     },
     { path: '', redirect: '/home' },
+    { path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound },
   ],
 });
 

+ 14 - 8
src/router/menu.ts

@@ -4,14 +4,15 @@ export interface Menu {
   component: Component;
 }
 
-export type MenuPath =
-  | '/step/deploy'
-  | '/step/deploy-recheck'
-  | '/step/soak'
-  | '/step/decoction'
-  | '/step/pack'
-  | '/step/pack-recheck'
-  ;
+export const stepMode = [
+  'deploy', 'deploy-recheck',
+  'soak',
+  'decoction',
+  'pack', 'pack-recheck',
+  'putaway',
+] as const;
+
+export type MenuPath = `/step/${(typeof stepMode)[number]}`;
 
 export const menus: Record<MenuPath, Menu> = {
   '/step/deploy': {
@@ -44,6 +45,11 @@ export const menus: Record<MenuPath, Menu> = {
     title: '打包复核管理',
     component: defineAsyncComponent(() => import(`@/module/step/StepPackRecheck.vue`)),
   },
+  '/step/putaway': {
+    index: 61,
+    title: '上架取药管理',
+    component: defineAsyncComponent(() => import(`@/module/step/StepPutaway.vue`)),
+  },
 } as const;
 
 export const defaultMenus = Object.entries(menus)

+ 3 - 1
src/stores/step.store.ts

@@ -3,6 +3,8 @@ import type { StepModel } from '@/model/step.model.ts';
 import { useRouteParams } from '@vueuse/router';
 
 export const useStepStore = defineStore('step', () => {
+  const title = ref<string | void>(import.meta.env.SIX_TITLE);
+
   const id = useRouteParams<string>('value');
   const mode = useRouteParams<string>('mode');
   const dataset = shallowRef<StepModel>();
@@ -11,5 +13,5 @@ export const useStepStore = defineStore('step', () => {
     dataset.value = void 0;
   }
 
-  return { dataset, id, mode, $reset };
+  return { dataset, id, mode, title, $reset };
 });