Просмотр исходного кода

perf: 封装通用下拉组件(可走字典,可走option)

xyh 5 месяцев назад
Родитель
Сommit
66f91357ec
1 измененных файлов с 158 добавлено и 0 удалено
  1. 158 0
      src/components/DictSelect/index.vue

+ 158 - 0
src/components/DictSelect/index.vue

@@ -0,0 +1,158 @@
+<template>
+  <el-select
+    popper-class="custom_select"
+    v-model="valueId"
+    :placeholder="placeholder"
+    class="width100"
+    :clearable="clearable"
+    :collapse-tags-tooltip="collapseTags ? collapseTagsTooltip : false"
+    :collapse-tags="collapseTags"
+    :disabled="disabled"
+    :multiple="multiple"
+    :allow-create="allowCreate"
+    :filterable="allowCreate || filterable"
+    @change="change"
+  >
+    <el-option
+      v-for="item in list"
+      :key="item.value"
+      :label="item.label"
+      :value="item.value"
+    ></el-option>
+  </el-select>
+</template>
+
+<script>
+import { getDicts } from '@/api/system/dict/data';
+
+export default {
+  name: 'DictSelect',
+  props: {
+    value: {
+      default: '',
+      type: [String, Number, Array],
+    },
+    // 支持只传入 dictName 或者直接传入 dictOptions(数组)
+    dictName: {
+      default: '',
+      type: String,
+    },
+    dictOptions: {
+      default: () => [],
+      type: Array,
+    },
+    multiple: {
+      default: false,
+      type: Boolean,
+    },
+    disabled: {
+      default: false,
+      type: Boolean,
+    },
+    allowCreate: {
+      default: false,
+      type: Boolean,
+    },
+    filterable: {
+      default: false,
+      type: Boolean,
+    },
+    clearable: {
+      default: true,
+      type: Boolean,
+    },
+    placeholder: {
+      default: '请选择',
+      type: String,
+    },
+    // 多选模式下是否折叠Tag
+    collapseTags: {
+      default: false,
+      type: Boolean,
+    },
+    // collapseTags为true时, 当鼠标悬停于折叠标签的文本时,是否显示所有选中的标签
+    collapseTagsTooltip: {
+      default: true,
+      type: Boolean,
+    },
+  },
+  data() {
+    return {
+      list: [],
+      loading: false,
+    };
+  },
+  computed: {
+    valueId: {
+      get() {
+        return this.value;
+      },
+      set(val) {
+        this.$emit('input', val); // Vue 2 使用 v-model 时,触发的是 input 事件
+      },
+    },
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    change(e) {
+      this.$emit('change', e);
+    },
+    getList() {
+      // 优先使用 dictOptions
+      if (this.dictOptions && this.dictOptions.length > 0) {
+        // 深拷贝一份数据,避免直接修改 props
+        this.list = JSON.parse(JSON.stringify(this.dictOptions));
+        return;
+      }
+
+      // 如果没有 dictOptions,则从 dictName 获取
+      if (this.dictName) {
+        this.loading = true;
+        getDicts(this.dictName).then((resp) => {
+          if (resp.code === 200) {
+            // 确保数据格式正确
+            this.list = resp.data.map((p) => ({
+              label: p.dictLabel || p.label,
+              value: p.dictValue !== undefined ? p.dictValue : p.value,
+              elTagType: p.listClass,
+            }));
+          }
+        }).finally(() => {
+          this.loading = false;
+        });
+      } else {
+        this.list = [];
+      }
+    },
+  },
+  watch: {
+    dictName: {
+      handler(newVal, oldVal) {
+        // 只有当 dictName 真正改变时才重新获取数据
+        if (newVal !== oldVal) {
+          this.getList();
+        }
+      },
+      immediate: true,
+    },
+    dictOptions: {
+      handler(newVal) {
+        // 深度监听 dictOptions 的变化
+        if (newVal && newVal.length > 0) {
+          this.list = JSON.parse(JSON.stringify(newVal));
+        } else if (this.dictName) {
+          // 如果 dictOptions 为空但有 dictName,则从字典获取数据
+          this.getList();
+        } else {
+          this.list = [];
+        }
+      },
+      deep: true,
+    },
+  },
+};
+</script>
+
+<style></style>