sysDict.vue 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. <!-- 组件使用文档: https://gitee.com/zuohuaijun/Admin.NET/pulls/1559 -->
  2. <script setup lang="ts">
  3. import { reactive, watch } from 'vue';
  4. import { DictItem } from '/@/types/global';
  5. import { useUserInfo } from '/@/stores/userInfo';
  6. const emit = defineEmits(['update:modelValue']);
  7. const dictList = useUserInfo().dictList;
  8. const props = defineProps({
  9. modelValue: {
  10. type: [String, Number, Boolean, null],
  11. default: null,
  12. required: true,
  13. },
  14. code: {
  15. type: String,
  16. required: true,
  17. },
  18. propLabel: {
  19. type: String,
  20. default: 'label',
  21. },
  22. propValue: {
  23. type: String,
  24. default: 'value',
  25. },
  26. onItemFilter: {
  27. type: Function,
  28. default: (dict: any): boolean => dict,
  29. },
  30. onItemFormatter: {
  31. type: Function as (dict: any) => (string | undefined | null),
  32. default: () => undefined
  33. },
  34. renderAs: {
  35. type: String,
  36. default: 'tag',
  37. validator(value: string) {
  38. return ['tag', 'select', 'radio'].includes(value);
  39. },
  40. },
  41. });
  42. const state = reactive({
  43. dict: {} as DictItem | undefined,
  44. dictData: [] as DictItem[],
  45. value: null as any,
  46. });
  47. const setDictValue = (value: any) => {
  48. state.value = value;
  49. state.dictData = dictList[props.code]?.filter(props.onItemFilter) ?? [];
  50. state.dict = state.dictData.find((x: any) => x[props.propValue] == state.value);
  51. if (state.dict && !['success', 'warning', 'info', 'primary', 'danger'].includes(state.dict.tagType ?? '')) state.dict.tagType = 'primary';
  52. };
  53. watch(
  54. () => props.modelValue,
  55. (newValue) => setDictValue(newValue),
  56. { immediate: true }
  57. );
  58. </script>
  59. <template>
  60. <!-- 渲染标签 -->
  61. <template v-if="props.renderAs === 'tag'">
  62. <el-tag v-if="state.dict" v-bind="$attrs" :type="state.dict.tagType" :style="state.dict.styleSetting" :class="state.dict.classSetting">{{ onItemFormatter(state.dict) ?? state.dict[props.propLabel] }}</el-tag>
  63. <span v-else>{{ state.value }}</span>
  64. </template>
  65. <!-- 渲染选择器 -->
  66. <template v-if="props.renderAs === 'select'">
  67. <el-select v-model="state.value" v-bind="$attrs" @change="(newValue: any) => emit('update:modelValue', newValue)">
  68. <el-option :label="onItemFormatter(item) ?? item[props.propLabel]" :value="item[props.propValue]" v-for="(item, index) in state.dictData" :key="index" />
  69. </el-select>
  70. </template>
  71. <!-- 渲染单选框 -->
  72. <template v-if="props.renderAs === 'radio'">
  73. <el-radio-group v-model="state.value" v-bind="$attrs" @change="(newValue: any) => emit('update:modelValue', newValue)">
  74. <el-radio :value="item[props.propValue]" v-for="(item, index) in state.dictData" :key="index">{{ onItemFormatter(item) ?? item[props.propLabel] }}</el-radio>
  75. </el-radio-group>
  76. </template>
  77. </template>
  78. <style scoped lang="scss"></style>