7
0

4 کامیت‌ها 10753b5d3c ... 7b746d1a99

نویسنده SHA1 پیام تاریخ
  lujialiang 7b746d1a99 Merge branch 'feature_241128_lujl' of http://git.cestong.com.cn/cecf/observe-admin into feature_241128_lujl 2 هفته پیش
  lujialiang d3bd6c9453 chore: 字典值使用字符串匹配 2 هفته پیش
  lujialiang 27dc1ba140 chore: 调整页面使用字典映射功能 2 هفته پیش
  lujialiang c967332684 feat: 新增字典映射功能 2 هفته پیش

+ 2 - 1
src/enum/index.ts

@@ -3,5 +3,6 @@ export enum SetupStoreId {
   Theme = 'theme-store',
   Auth = 'auth-store',
   Route = 'route-store',
-  Tab = 'tab-store'
+  Tab = 'tab-store',
+  Dict = 'dict-store'
 }

+ 74 - 0
src/store/modules/dict/index.ts

@@ -0,0 +1,74 @@
+import { defineStore } from 'pinia';
+import { reactive } from 'vue';
+import { SetupStoreId } from '@/enum';
+import { getDicts } from '@/service/api';
+
+interface dictItem {
+  label: string;
+  value: string;
+}
+
+interface StoreState {
+  dictionaries: { [key: string]: dictItem[] };
+  loading: boolean;
+  errors: Error | null;
+  pendingRequests: Map<any, any>;
+}
+
+export const useDictStore = defineStore(SetupStoreId.Dict, () => {
+  const store = reactive<StoreState>({
+    dictionaries: {},
+    loading: false,
+    errors: null,
+    pendingRequests: new Map() // 用于跟踪正在进行的请求
+  });
+  async function loadDict(type: string) {
+    if (store.dictionaries[type]) return store.dictionaries[type];
+
+    // 检查是否有正在进行的相同请求
+    if (store.pendingRequests.has(type)) {
+      return store.pendingRequests.get(type);
+    }
+
+    store.loading = true;
+    store.errors = null;
+
+    // 创建一个新的 Promise 来跟踪这个请求
+    const requestPromise = getDicts(type)
+      .then(({ data }) => {
+        store.dictionaries[type] = data;
+        return data;
+      })
+      .catch(error => {
+        store.errors = error;
+        throw error;
+      })
+      .finally(() => {
+        store.loading = false;
+        store.pendingRequests.delete(type); // 请求完成后移除
+      });
+
+    // 将请求存储在 pendingRequests 中
+    store.pendingRequests.set(type, requestPromise);
+
+    // 返回请求的 Promise
+    return requestPromise;
+  }
+
+  function findNameByValue(options: dictItem[], value: string, separator: string = ',') {
+    return options.flatMap(option => (option.value === value.toString() ? option.label : [])).join(separator);
+  }
+
+  function findNameByDict(dictKey: string, value: string, separator: string = ',') {
+    if (store.dictionaries[dictKey]) {
+      return findNameByValue(store.dictionaries[dictKey], value, separator);
+    }
+    loadDict(dictKey);
+    return '-';
+  }
+  return {
+    loadDict,
+    findNameByDict,
+    findNameByValue
+  };
+});

+ 6 - 17
src/views/admin/log/sys-login-log/index.vue

@@ -1,12 +1,15 @@
 <script setup lang="tsx">
 import { useTable, useTableOperate, useTableScroll } from '@/hooks/common/table';
 import { $t } from '@/locales';
-import { fetchLoginlogDel, fetchLoginlogList, getDicts } from '@/service/api';
+import { fetchLoginlogDel, fetchLoginlogList } from '@/service/api';
 import { Button } from 'ant-design-vue';
 import dayjs from 'dayjs';
 import { ref } from 'vue';
 import MOperateDrawer from './modules/m-operate-drawer.vue';
 import MSearch from './modules/m-search.vue';
+import { useDictStore } from '@/store/modules/dict'
+const { findNameByDict, findNameByValue } = useDictStore()
+
 const { tableWrapperRef, scrollConfig } = useTableScroll();
 const apiParams = ref({
   pageIndex: 1,
@@ -50,15 +53,8 @@ const {
       align: 'center',
       minWidth: 100,
       customRender: ({ record }) => {
-        let statusMap = {
-          '1': '停用',
-          '2': '正常',
-        }
-        let typeMap = {
-          '1': 'error',
-          '2': 'success',
-        }
-        return <a-tag color={typeMap[record.status]}>{statusMap[record.status]}</a-tag>
+        let colors = [{ label: 'error', value: '1' }, { label: 'success', value: '2' }]
+        return <a-tag color={findNameByValue(colors, record.status)}>{findNameByDict('sys_common_status', record.status)}</a-tag>
       }
     },
     {
@@ -129,13 +125,6 @@ function handleRowDetail(row: AntDesign.TableData) {
   editingData.value = row
   openDrawer()
 }
-
-const deptStatus = ref<CommonType.Option<string>[]>([]);
-async function getDeptStatusOptions() {
-  const { data } = await getDicts('sys_common_status')
-  deptStatus.value = data || []
-}
-getDeptStatusOptions()
 </script>
 
 <template>

+ 6 - 17
src/views/admin/log/sys-oper-log/index.vue

@@ -1,7 +1,7 @@
 <script setup lang="tsx">
 import { useTable, useTableOperate, useTableScroll } from '@/hooks/common/table';
 import { $t } from '@/locales';
-import { fetchOperDel, fetchOperList, getDicts } from '@/service/api';
+import { fetchOperDel, fetchOperList } from '@/service/api';
 import { Button } from 'ant-design-vue';
 import { map, pick } from 'lodash';
 import dayjs from 'dayjs';
@@ -9,6 +9,9 @@ import { ref } from 'vue';
 import MOperateDrawer from './modules/m-operate-drawer.vue';
 import MSearch from './modules/m-search.vue';
 import { excel } from '@/utils/download'
+import { useDictStore } from '@/store/modules/dict'
+const { findNameByDict, findNameByValue } = useDictStore()
+
 const { tableWrapperRef, scrollConfig } = useTableScroll();
 const apiParams = ref({
   pageIndex: 1,
@@ -59,15 +62,8 @@ const {
       align: 'center',
       minWidth: 100,
       customRender: ({ record }) => {
-        let statusMap = {
-          '1': '停用',
-          '2': '正常',
-        }
-        let typeMap = {
-          '1': 'error',
-          '2': 'success',
-        }
-        return <a-tag color={typeMap[record.status]}>{statusMap[record.status]}</a-tag>
+        let colors = [{ label: 'error', value: '1' }, { label: 'success', value: '2' }]
+        return <a-tag color={findNameByValue(colors, record.status)}>{findNameByDict('sys_common_status', record.status)}</a-tag>
       }
     },
     {
@@ -132,13 +128,6 @@ function handleRowDetail(row: AntDesign.TableData) {
   openDrawer()
 }
 
-const deptStatus = ref<CommonType.Option<string>[]>([]);
-async function getDeptStatusOptions() {
-  const { data } = await getDicts('sys_common_status')
-  deptStatus.value = data || []
-}
-getDeptStatusOptions()
-
 // 导出excel
 function handleExcel() {
   let keysToPick = ['id', 'title', 'businessType', 'method', 'operName', 'operIp', 'operLocation', 'status', 'operUrl', 'operTime']

+ 5 - 10
src/views/admin/log/sys-oper-log/modules/m-operate-drawer.vue

@@ -1,9 +1,11 @@
 <script setup lang="ts">
 import { useAntdForm } from '@/hooks/common/form';
 import { $t } from '@/locales';
-import { getDicts } from '@/service/api';
-import { computed, reactive, ref, watch, nextTick } from 'vue';
+import { computed, reactive, watch, nextTick } from 'vue';
 import dayjs from 'dayjs';
+import { useDictStore } from '@/store/modules/dict'
+const { findNameByDict } = useDictStore()
+
 defineOptions({
   name: 'MOperateDrawer'
 });
@@ -60,12 +62,6 @@ function createDefaultModel(): Model {
   };
 }
 
-const commonStatus = ref<CommonType.Option<string>[]>([]);
-async function getDeptStatusOptions() {
-  const { data } = await getDicts('sys_common_status')
-  commonStatus.value = data || []
-}
-
 async function handleInitModel() {
   Object.assign(model, createDefaultModel());
   if (props.operateType === 'detail' && props.rowData) {
@@ -82,7 +78,6 @@ watch(visible, () => {
   if (visible.value) {
     handleInitModel()
     resetFields()
-    getDeptStatusOptions()
   }
 });
 </script>
@@ -123,7 +118,7 @@ watch(visible, () => {
         </ACol>
         <ACol :span="12" :md="12" :xs="24">
           <AFormItem label="操作状态">
-            {{ model.status }}
+            {{ findNameByDict('sys_common_status', model.status) }}
           </AFormItem>
         </ACol>
         <ACol :span="12" :md="12" :xs="24">

+ 16 - 25
src/views/admin/log/sys-oper-log/modules/m-search.vue

@@ -1,8 +1,11 @@
 <script setup lang="ts">
 import { useAntdForm, useFormRules } from '@/hooks/common/form';
 import { $t } from '@/locales';
-import { fetchGetdeptTreeList, getDicts } from '@/service/api';
+import { fetchGetdeptTreeList } from '@/service/api';
 import { computed, onMounted, ref } from 'vue';
+import { useDictStore } from '@/store/modules/dict'
+const { loadDict } = useDictStore()
+
 defineOptions({
   name: 'MSearch'
 });
@@ -28,10 +31,10 @@ const rules = computed<Record<RuleKey, App.Global.FormRule>>(() => {
     phone: patternRules.phone
   };
 });
-onMounted(()=>{
+onMounted(() => {
   getDeptTree()
 })
-async function getDeptTree(){
+async function getDeptTree() {
   const { data } = await fetchGetdeptTreeList()
   departOptions.value = data
 }
@@ -46,35 +49,23 @@ async function search() {
 }
 
 const normalStatus = ref<CommonType.Option<string>[]>([]);
-async function getDeptStatusOptions() {
-  const { data } = await getDicts('sys_common_status')
+loadDict('sys_common_status').then((data) => {
   normalStatus.value = data || []
-}
-getDeptStatusOptions()
+})
 
 </script>
 
 <template>
   <ACard :title="$t('common.search')" :bordered="false" class="card-wrapper">
-    <AForm
-      ref="formRef"
-      :model="model"
-      :rules="rules"
-      :label-col="{
-        span: 5,
-        md: 7
-      }"
-    >
+    <AForm ref="formRef" :model="model" :rules="rules" :label-col="{
+      span: 5,
+      md: 7
+    }">
       <ARow :gutter="[16, 16]" wrap>
         <ACol :span="24" :md="12" :lg="6">
           <AFormItem label="状态" name="status" class="m-0">
-            <ASelect
-              v-model:value="model.status"
-              placeholder="请选择状态"
-              :options="normalStatus"
-              @change="search"
-              allowClear
-            />
+            <ASelect v-model:value="model.status" placeholder="请选择状态" :options="normalStatus" @change="search"
+              allowClear />
           </AFormItem>
         </ACol>
         <ACol :span="24" :md="12" :lg="6">
@@ -87,8 +78,8 @@ getDeptStatusOptions()
             <ADatePicker v-model:value.trim="model.endTime" show-time placeholder="请选择创建结束时间" @ok="search" />
           </AFormItem>
         </ACol>
-        
-        
+
+
         <div class="flex-1">
           <AFormItem class="m-0">
             <div class="w-full flex-y-center justify-end gap-12px">

+ 6 - 17
src/views/admin/sys-dept/index.vue

@@ -1,12 +1,15 @@
 <script setup lang="tsx">
 import { useTable, useTableOperate, useTableScroll } from '@/hooks/common/table';
 import { $t } from '@/locales';
-import { fetchDeptDel, fetchDeptList, getDicts } from '@/service/api';
+import { fetchDeptDel, fetchDeptList } from '@/service/api';
 import { Button, Popconfirm } from 'ant-design-vue';
 import dayjs from 'dayjs';
 import { ref } from 'vue';
 import MOperateDrawer from './modules/m-operate-drawer.vue';
 import MSearch from './modules/m-search.vue';
+import { useDictStore } from '@/store/modules/dict'
+const { findNameByDict, findNameByValue } = useDictStore()
+
 const { tableWrapperRef, scrollConfig } = useTableScroll();
 const apiParams = ref({
   pageIndex: 1,
@@ -49,15 +52,8 @@ const {
       align: 'center',
       minWidth: 100,
       customRender: ({ record }) => {
-        let statusMap = {
-          '1': '停用',
-          '2': '正常',
-        }
-        let typeMap = {
-          '1': 'error',
-          '2': 'success',
-        }
-        return <a-tag color={typeMap[record.status]}>{statusMap[record.status]}</a-tag>
+        let colors = [{ label: 'error', value: '1' }, { label: 'success', value: '2' }]
+        return <a-tag color={findNameByValue(colors, record.status)}>{findNameByDict('sys_normal_disable', record.status)}</a-tag>
       }
     },
     {
@@ -125,13 +121,6 @@ function handleRowEdit(row: AntDesign.TableData) {
   editingData.value = row
   openDrawer()
 }
-
-const deptStatus = ref<CommonType.Option<string>[]>([]);
-async function getDeptStatusOptions() {
-  const { data } = await getDicts('sys_normal_disable')
-  deptStatus.value = data || []
-}
-getDeptStatusOptions()
 </script>
 
 <template>

+ 6 - 5
src/views/admin/sys-dept/modules/m-operate-drawer.vue

@@ -1,8 +1,11 @@
 <script setup lang="ts">
 import { useAntdForm, useFormRules } from '@/hooks/common/form';
 import { $t } from '@/locales';
-import { fetchDeptAdd, fetchDeptList, getDicts, fetchDeptDetail, fetchDeptEdit } from '@/service/api';
+import { fetchDeptAdd, fetchDeptList, fetchDeptDetail, fetchDeptEdit } from '@/service/api';
 import { computed, reactive, ref, watch } from 'vue';
+import { useDictStore } from '@/store/modules/dict'
+const { loadDict } = useDictStore()
+
 defineOptions({
   name: 'DeptOperateDrawer'
 });
@@ -76,10 +79,9 @@ async function getDeptList() {
 }
 
 const deptStatus = ref<CommonType.Option<string>[]>([]);
-async function getDeptStatusOptions() {
-  const { data } = await getDicts('sys_normal_disable')
+loadDict('sys_normal_disable').then((data) => {
   deptStatus.value = data || []
-}
+})
 
 async function getDeptDetails() {
   let deptId = props.rowData?.deptId + ''
@@ -131,7 +133,6 @@ watch(visible, () => {
     handleInitModel()
     resetFields()
     getDeptList()
-    getDeptStatusOptions()
   }
 });
 </script>

+ 6 - 5
src/views/admin/sys-dept/modules/m-search.vue

@@ -1,8 +1,11 @@
 <script setup lang="ts">
 import { useAntdForm, useFormRules } from '@/hooks/common/form';
 import { $t } from '@/locales';
-import { fetchGetdeptTreeList, getDicts } from '@/service/api';
+import { fetchGetdeptTreeList } from '@/service/api';
 import { computed, onMounted, ref } from 'vue';
+import { useDictStore } from '@/store/modules/dict'
+const { loadDict } = useDictStore()
+
 defineOptions({
   name: 'MSearch'
 });
@@ -46,11 +49,9 @@ async function search() {
 }
 
 const deptStatus = ref<CommonType.Option<string>[]>([]);
-async function getDeptStatusOptions() {
-  const { data } = await getDicts('sys_normal_disable')
+loadDict('sys_normal_disable').then((data) => {
   deptStatus.value = data || []
-}
-getDeptStatusOptions()
+})
 
 </script>
 

+ 5 - 17
src/views/admin/sys-post/index.vue

@@ -1,13 +1,15 @@
 <script setup lang="tsx">
 import { useTable, useTableOperate, useTableScroll } from '@/hooks/common/table';
 import { $t } from '@/locales';
-import { fetchPostDel, fetchPostList, getDicts } from '@/service/api';
+import { fetchPostDel, fetchPostList } from '@/service/api';
 import { Button, Popconfirm } from 'ant-design-vue';
 import { map, pick } from 'lodash';
 import dayjs from 'dayjs';
 import { ref } from 'vue';
 import MOperateDrawer from './modules/m-operate-drawer.vue';
 import MSearch from './modules/m-search.vue';
+import { useDictStore } from '@/store/modules/dict'
+const { findNameByDict, findNameByValue } = useDictStore()
 import { excel } from '@/utils/download'
 const { tableWrapperRef, scrollConfig } = useTableScroll();
 const apiParams = ref({
@@ -65,15 +67,8 @@ const {
       align: 'center',
       minWidth: 100,
       customRender: ({ record }) => {
-        let statusMap = {
-          '1': '停用',
-          '2': '正常',
-        }
-        let typeMap = {
-          '1': 'error',
-          '2': 'success',
-        }
-        return <a-tag color={typeMap[record.status]}>{statusMap[record.status]}</a-tag>
+        let colors = [{ label: 'error', value: '1' }, { label: 'success', value: '2' }]
+        return <a-tag color={findNameByValue(colors, record.status)}>{findNameByDict('sys_normal_disable', record.status)}</a-tag>
       }
     },
     {
@@ -140,13 +135,6 @@ function handleRowEdit(id: number) {
   handleEdit(id, 'postId')
 }
 
-const deptStatus = ref<CommonType.Option<string>[]>([]);
-async function getDeptStatusOptions() {
-  const { data } = await getDicts('sys_normal_disable')
-  deptStatus.value = data || []
-}
-getDeptStatusOptions()
-
 // 导出excel
 function handleExcel() {
   let keysToPick = ['postId', 'postCode', 'postName', 'sort', 'createdAt']

+ 9 - 8
src/views/admin/sys-post/modules/m-operate-drawer.vue

@@ -1,8 +1,11 @@
 <script setup lang="ts">
 import { useAntdForm, useFormRules } from '@/hooks/common/form';
 import { $t } from '@/locales';
-import { getDicts, fetchPostDetail, fetchPostAdd, fetchPostEdit } from '@/service/api';
+import { fetchPostDetail, fetchPostAdd, fetchPostEdit } from '@/service/api';
 import { computed, reactive, ref, watch } from 'vue';
+import { useDictStore } from '@/store/modules/dict'
+const { loadDict } = useDictStore()
+
 defineOptions({
   name: 'MOperateDrawer'
 });
@@ -65,11 +68,10 @@ const rules: Record<RuleKey, App.Global.FormRule> = {
   remark: defaultRequiredRule,
 };
 
-const deptStatus = ref<CommonType.Option<string>[]>([]);
-async function getDeptStatusOptions() {
-  const { data } = await getDicts('sys_normal_disable')
-  deptStatus.value = data || []
-}
+const postStatus = ref<CommonType.Option<string>[]>([]);
+loadDict('sys_normal_disable').then((data) => {
+  postStatus.value = data || []
+})
 
 async function getDeptDetails() {
   let postId = props.rowData?.postId + ''
@@ -119,7 +121,6 @@ watch(visible, () => {
   if (visible.value) {
     handleInitModel()
     resetFields()
-    getDeptStatusOptions()
   }
 });
 </script>
@@ -147,7 +148,7 @@ watch(visible, () => {
         <ACol :span="12" :md="12" :xs="24">
           <AFormItem :label="$t('page.admin.sysPost.status')" name="status">
             <ARadioGroup v-model:value="model.status">
-              <ARadio v-for="item in deptStatus" :key="item.value" :value="item.value">
+              <ARadio v-for="item in postStatus" :key="item.value" :value="item.value">
                 {{ item.label }}
               </ARadio>
             </ARadioGroup>

+ 8 - 7
src/views/admin/sys-post/modules/m-search.vue

@@ -3,6 +3,9 @@ import { useAntdForm, useFormRules } from '@/hooks/common/form';
 import { $t } from '@/locales';
 import { fetchGetdeptTreeList, getDicts } from '@/service/api';
 import { computed, onMounted, ref } from 'vue';
+import { useDictStore } from '@/store/modules/dict'
+const { loadDict } = useDictStore()
+
 defineOptions({
   name: 'MSearch'
 });
@@ -45,12 +48,10 @@ async function search() {
   emit('search');
 }
 
-const normalStatus = ref<CommonType.Option<string>[]>([]);
-async function getDeptStatusOptions() {
-  const { data } = await getDicts('sys_normal_disable')
-  normalStatus.value = data || []
-}
-getDeptStatusOptions()
+const postStatus = ref<CommonType.Option<string>[]>([]);
+loadDict('sys_normal_disable').then((data) => {
+  postStatus.value = data || []
+})
 
 </script>
 
@@ -82,7 +83,7 @@ getDeptStatusOptions()
             <ASelect
               v-model:value="model.status"
               placeholder="请选择岗位状态"
-              :options="normalStatus"
+              :options="postStatus"
               @change="search"
               allowClear
             />