Jelajahi Sumber

feat(组件): 添加SmartPageProvider组件,支持统一加载字典信息

shizhongming 2 tahun lalu
induk
melakukan
893398171f

+ 87 - 3
src/components/Form/src/smart-boot/components/SmartApiSelectDict.vue

@@ -1,19 +1,103 @@
 <template>
-  <ApiSelect v-bind="$attrs" value-field="dictItemCode" label-field="dictItemName" :api="api" />
+  <Select
+    v-if="computedHasProvider"
+    v-bind="$attrs"
+    :options="computedOptions"
+    v-model:value="state"
+    @change="handleChange"
+  >
+    <template #[item]="data" v-for="item in Object.keys($slots)">
+      <slot :name="item" v-bind="data || {}"></slot>
+    </template>
+    <template #suffixIcon v-if="loadingRef">
+      <LoadingOutlined spin />
+    </template>
+    <template #notFoundContent v-if="loadingRef">
+      <span>
+        <LoadingOutlined spin class="mr-1" />
+        {{ t('component.form.apiSelectNotFound') }}
+      </span>
+    </template>
+  </Select>
+  <ApiSelect
+    v-else
+    v-bind="$attrs"
+    value-field="dictItemCode"
+    label-field="dictItemName"
+    :api="api"
+  />
 </template>
 
 <script lang="ts" setup>
+  import { type PropType, ref, Ref, unref, watch } from 'vue';
+  import type { SelectValue } from 'ant-design-vue/es/select';
+
+  import { computed, inject } from 'vue';
+  import { Select } from 'ant-design-vue';
   import ApiSelect from '../../components/ApiSelect.vue';
   import { propTypes } from '@/utils/propTypes';
   import { ApiServiceEnum, defHttp } from '@/utils/http/axios';
-  import { type PropType } from 'vue';
-  import type { SelectValue } from 'ant-design-vue/es/select';
+  import { SmartProviderConstants } from '@/components/SmartPageProvider';
+  import { LoadingOutlined } from '@ant-design/icons-vue';
+  import { useRuleFormItem } from '@/hooks/component/useFormItem';
+  import { useI18n } from '@/hooks/web/useI18n';
+
+  type OptionsItem = { label?: string; value?: string; disabled?: boolean; [name: string]: any };
 
   const props = defineProps({
     dictCode: propTypes.string.isRequired,
     value: { type: [Array, Object, String, Number] as PropType<SelectValue> },
+    numberToString: propTypes.bool,
   });
 
+  const emit = defineEmits(['change', 'update:value']);
+
+  const { t } = useI18n();
+
+  const registerHandler = inject(SmartProviderConstants.dictRegisterKey) as Function | undefined;
+  if (registerHandler) {
+    registerHandler(props.dictCode);
+  }
+  /**
+   * 加载状态
+   */
+  const loadingRef = inject(SmartProviderConstants.dictLoadingKey) as Ref<boolean> | undefined;
+  /**
+   * 是否有注入
+   */
+  const computedHasProvider = computed(() => {
+    return registerHandler !== undefined;
+  });
+
+  /**
+   * 注入OPTIONS
+   */
+  const dictDataRef = inject(SmartProviderConstants.dictData) as Ref<Recordable<any[]>> | undefined;
+  const computedOptions = computed(() => {
+    if (!dictDataRef) {
+      return [];
+    }
+    const dictData = unref(dictDataRef)?.[props.dictCode];
+    if (!dictData) {
+      return [];
+    }
+    return dictData;
+  });
+
+  const emitData = ref<OptionsItem[]>([]);
+  const [state] = useRuleFormItem(props, 'value', 'change', emitData);
+
+  watch(
+    () => state.value,
+    (v) => {
+      emit('update:value', v);
+    },
+  );
+
+  function handleChange(_, ...args) {
+    emitData.value = args;
+  }
+
   const api = () => {
     return defHttp.post({
       service: ApiServiceEnum.SMART_SYSTEM,

+ 3 - 0
src/components/SmartPageProvider/index.ts

@@ -0,0 +1,3 @@
+export { default as SmartPageProvider } from './src/SmartPageProvider.vue';
+
+export * from './src/constants';

+ 11 - 0
src/components/SmartPageProvider/src/SmartPageProvider.vue

@@ -0,0 +1,11 @@
+<template>
+  <div class="full-height">
+    <slot></slot>
+  </div>
+</template>
+
+<script setup lang="ts">
+  import { useProviderDict } from './hooks/useProviderDict';
+
+  useProviderDict();
+</script>

+ 6 - 0
src/components/SmartPageProvider/src/constants.ts

@@ -0,0 +1,6 @@
+export enum SmartProviderConstants {
+  dictRegisterKey = 'SMART_PROVIDER_DICT_SELECT_REGISTER',
+  dictLoadingKey = 'SMART_PROVIDER_DICT_SELECT_LOADING',
+  dictData = 'SMART_PROVIDER_DICT_SELECT_DATA',
+  dictMap = 'SMART_PROVIDER_DICT_SELECT_MAP',
+}

+ 78 - 0
src/components/SmartPageProvider/src/hooks/useProviderDict.ts

@@ -0,0 +1,78 @@
+import { computed, onMounted, provide, reactive, ref, unref } from 'vue';
+import { SmartProviderConstants } from '@/components/SmartPageProvider/src/constants';
+import { ApiServiceEnum, defHttp } from '@/utils/http/axios';
+
+export const useProviderDict = () => {
+  const dictCodeList = reactive<string[]>([]);
+  // 字典加载状态
+  const dictLoadingRef = ref(false);
+
+  /**
+   * 字典数据
+   */
+  const dictMapRef = ref<Recordable<any[]>>({});
+
+  const computedDictMap = computed(() => {
+    const result: Recordable<Recordable> = {};
+
+    Object.keys(unref(dictMapRef)).forEach((key) => {
+      const list = unref(dictMapRef)[key];
+      const itemMap: Recordable = {};
+      list.forEach((item) => {
+        itemMap[item.dictItemCode] = item.dictItemName;
+      });
+      result[key] = itemMap;
+    });
+
+    return result;
+  });
+
+  onMounted(() => loadDictData());
+
+  /**
+   * 批量加载字典数据
+   */
+  const loadDictData = async () => {
+    if (dictCodeList.length === 0) {
+      return;
+    }
+    try {
+      dictLoadingRef.value = true;
+      const result =
+        (await defHttp.post({
+          service: ApiServiceEnum.SMART_SYSTEM,
+          url: 'sys/dict/batchListItemByCode',
+          data: dictCodeList,
+        })) || {};
+      const dictMap: Recordable<any[]> = {};
+      for (const key in result) {
+        dictMap[key] = result[key].map((item) => {
+          return {
+            ...item,
+            label: `${item.dictItemCode}-${item.dictItemName}`,
+            value: item.dictItemCode,
+          };
+        });
+      }
+      dictMapRef.value = dictMap;
+    } finally {
+      dictLoadingRef.value = false;
+    }
+  };
+
+  /**
+   * 注入注册函数
+   */
+  provide(SmartProviderConstants.dictRegisterKey, (code: string) => {
+    dictCodeList.push(code);
+  });
+
+  /**
+   * 注入字典加载状态
+   */
+  provide(SmartProviderConstants.dictLoadingKey, dictLoadingRef);
+
+  provide(SmartProviderConstants.dictData, dictMapRef);
+
+  provide(SmartProviderConstants.dictMap, computedDictMap);
+};