| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531 |
- import {
- getDictData,
- getMultipleDictData
- } from '@/api/services/dict';
- import storage from '@/utils/storage';
- import staticDict from '@/utils/staticDict';
- // 全局字典缓存对象,用于存储已加载的字典数据
- const dictCache = {
- // 缓存的字典数据,格式为 { dictType: [{label, value, ...}, ...] }
- data: {},
- // 缓存过期时间,单位为毫秒
- expireTime: 1000 * 60 * 60, // 1小时
- // 缓存最后更新时间
- lastUpdateTime: {},
- // 正在加载的字典类型,用于防止重复请求
- loading: {}
- };
- /**
- * 字典数据加载Mixin
- * 使用方式:
- * 1. 在组件中导入 import dictMixin from '@/utils/mixins/dictMixin';
- * 2. 在组件的mixins选项中注册 mixins: [dictMixin]
- * 3. 在组件的data中定义需要的字典类型 dictTypeList: ['sys_user_sex', 'sys_normal_disable', ...]
- * 4. 在组件的methods中调用 getDictLabel 等方法使用字典数据
- * 5. 在模板中直接使用 dictData 对象获取字典项 v-for="item in dictData.sys_user_sex"
- */
- export default {
- data() {
- return {
- // 组件中的字典数据
- dictData: {},
- // 定义组件需要加载的字典类型
- dictTypeList: [],
- // 字典加载状态
- dictLoading: false
- };
- },
- created() {
- // 组件创建时,如果有定义dictTypeList,则自动加载字典数据
- if (this.dictTypeList && this.dictTypeList.length > 0) {
- console.log(`[DictMixin] Component created, loading dictionaries: ${this.dictTypeList.join(', ')}`);
- this.loadDict();
- }
- },
- methods: {
- /**
- * 加载字典数据
- * @param {Array} dictTypes - 字典类型数组,如果不传则使用组件中定义的dictTypeList
- * @returns {Promise} - 返回字典加载的Promise对象
- */
- loadDict(dictTypes) {
- const types = dictTypes || this.dictTypeList;
- if (!types || types.length === 0) {
- return Promise.resolve({});
- }
- // 标记加载中
- this.dictLoading = true;
- // 需要从服务器获取的字典类型
- const needFetch = [];
- // 检查是否有静态字典或缓存
- types.forEach(type => {
- // 先检查是否有静态字典
- if (staticDict[type]) {
- // 使用静态字典数据
- console.log(`[DictMixin] Using static dictionary for ${type}`);
- this.$set(this.dictData, type, staticDict[type]);
- } else {
- // 检查缓存
- const cachedDict = this.getDictFromCache(type);
- if (cachedDict) {
- // 已有缓存,直接使用
- console.log(`[DictMixin] Using cached dictionary for ${type}`);
- this.$set(this.dictData, type, cachedDict);
- } else if (!dictCache.loading[type]) {
- // 需要从服务器获取,并且当前没有其他组件正在加载
- console.log(`[DictMixin] Need to fetch dictionary ${type} from server`);
- needFetch.push(type);
- } else {
- console.log(
- `[DictMixin] Dictionary ${type} is already being loaded by another component, waiting...`
- );
- }
- }
- });
- // 如果所有字典都已缓存或使用静态数据,直接返回
- if (needFetch.length === 0) {
- this.dictLoading = false;
- // 检查是否有正在加载的字典,如果有,等待它们完成
- const loadingTypes = types.filter(type => dictCache.loading[type]);
- if (loadingTypes.length > 0) {
- return this.waitForDictLoading(loadingTypes);
- }
- return Promise.resolve(this.dictData);
- }
- // 从服务器获取字典数据
- return this.fetchDictData(needFetch).then(res => {
- this.dictLoading = false;
- console.log("this.dictData", this.dictData);
- return this.dictData;
- }).catch(err => {
- this.dictLoading = false;
- console.error('加载字典数据失败:', err);
- return Promise.reject(err);
- });
- },
- /**
- * 等待指定类型的字典加载完成
- * @param {Array} types - 字典类型数组
- * @returns {Promise} - 返回等待的Promise对象
- */
- waitForDictLoading(types) {
- return new Promise(resolve => {
- const checkInterval = setInterval(() => {
- const stillLoading = types.some(type => dictCache.loading[type]);
- if (!stillLoading) {
- clearInterval(checkInterval);
- // 加载完成后,从缓存中获取数据
- types.forEach(type => {
- const cachedDict = this.getDictFromCache(type);
- if (cachedDict) {
- this.$set(this.dictData, type, cachedDict);
- }
- });
- resolve(this.dictData);
- }
- }, 50);
- });
- },
- /**
- * 从服务器获取字典数据
- * - 单个字典类型 → 单次请求
- * - 多个字典类型 → 并发请求
- * - 支持部分失败:失败的字典会忽略,成功的字典会返回
- *
- * @param {Array} dictTypes - 字典类型数组
- * @returns {Promise<Object|Array>}
- * - 单个字典时返回 dictList 数组
- * - 多个字典时返回 { dictType: dictList } 的 Map
- */
- fetchDictData(dictTypes) {
- // 标记这些字典类型正在加载
- dictTypes.forEach(type => {
- dictCache.loading[type] = true;
- });
- // --- 单个字典类型 ---
- if (dictTypes.length === 1) {
- const dictType = dictTypes[0];
- console.log(`[DictMixin] Fetching single dictionary: ${dictType}`);
- return getDictData(dictType).then(res => {
- if (res.data.code === 200) {
- let dictList = [];
- if (dictType === 'mall_product_category') {
- dictList.push({
- dictLabel: '推荐',
- dictValue: '-1'
- });
- dictList.push(...res.data.data);
- } else {
- dictList = res.data.data;
- }
- // 更新组件数据和缓存
- this.$set(this.dictData, dictType, dictList);
- this.updateDictCache(dictType, dictList);
- delete dictCache.loading[dictType];
- return dictList;
- } else {
- console.error(`获取字典[${dictType}]数据失败:`, res.data.msg);
- delete dictCache.loading[dictType];
- return Promise.reject(res.data.msg);
- }
- }).catch(err => {
- delete dictCache.loading[dictType];
- throw err;
- });
- }
- // --- 多个字典类型,并发请求 ---
- console.log(`[DictMixin] Concurrently fetching ${dictTypes.length} dictionaries: ${dictTypes.join(', ')}`);
- const requests = dictTypes.map(dictType => {
- return getDictData(dictType).then(res => {
- if (res.data.code === 200) {
- let dictList = [];
- if (dictType === 'mall_product_category') {
- dictList.push({
- dictLabel: '推荐',
- dictValue: '-1'
- });
- dictList.push(...res.data.data);
- } else {
- dictList = res.data.data;
- }
- this.$set(this.dictData, dictType, dictList);
- this.updateDictCache(dictType, dictList);
- delete dictCache.loading[dictType];
- return {
- dictType,
- dictList,
- success: true
- };
- } else {
- console.error(`获取字典[${dictType}]数据失败:`, res.data.msg);
- delete dictCache.loading[dictType];
- return {
- dictType,
- dictList: [],
- success: false,
- msg: res.data.msg
- };
- }
- }).catch(err => {
- console.error(`获取字典[${dictType}]异常:`, err);
- delete dictCache.loading[dictType];
- return {
- dictType,
- dictList: [],
- success: false,
- msg: err
- };
- });
- });
- // 等所有请求完成
- return Promise.allSettled(requests).then(results => {
- const dictMap = {};
- const failed = [];
- results.forEach(r => {
- if (r.status === 'fulfilled') {
- const {
- dictType,
- dictList,
- success,
- msg
- } = r.value;
- if (success) {
- dictMap[dictType] = dictList;
- } else {
- failed.push({
- dictType,
- msg
- });
- }
- } else {
- // 理论上不会走这里,因为 catch 已经返回对象了
- console.error(`字典请求失败:`, r.reason);
- }
- });
- console.log(
- `[DictMixin] Loaded ${Object.keys(dictMap).length} dictionaries, failed ${failed.length}`
- );
- if (failed.length > 0) {
- console.warn('以下字典加载失败:', failed);
- }
- return dictMap;
- });
- },
- /**
- * 从服务器获取字典数据
- * @param {Array} dictTypes - 字典类型数组
- * @returns {Promise} - 返回字典获取的Promise对象
- */
- // fetchDictData(dictTypes) {
- // // 标记这些字典类型正在加载
- // dictTypes.forEach(type => {
- // dictCache.loading[type] = true;
- // });
- // if (dictTypes.length === 1) {
- // // 单个字典类型,直接获取
- // console.log(`[DictMixin] Fetching single dictionary: ${dictTypes[0]}`);
- // return getDictData(dictTypes[0]).then(res => {
- // if (res.data.code === 200) {
- // const dictType = dictTypes[0];
- // var dictList = []
- // if(dictType === 'mall_product_category'){
- // dictList.push({
- // dictLabel:'推荐',
- // dictValue:'-1'
- // })
- // // 展开数组追加
- // dictList.push(...res.data.data);
- // }else{
- // dictList = res.data.data
- // }
- // // 更新组件字典数据
- // this.$set(this.dictData, dictType, dictList);
- // // 更新缓存
- // this.updateDictCache(dictType, dictList);
- // // 取消加载标记
- // delete dictCache.loading[dictType];
- // return dictList;
- // } else {
- // console.error(`获取字典[${dictTypes[0]}]数据失败:`, res.data.msg);
- // // 取消加载标记
- // delete dictCache.loading[dictTypes[0]];
- // return Promise.reject(res.data.msg);
- // }
- // }).catch(err => {
- // // 发生错误时取消加载标记
- // delete dictCache.loading[dictTypes[0]];
- // throw err;
- // });
- // } else {
- // // 多个字典类型,批量获取
- // console.log(`[DictMixin] Batch fetching ${dictTypes.length} dictionaries: ${dictTypes.join(', ')}`);
- // return getMultipleDictData(dictTypes).then(res => {
- // if (res.data.code === 200) {
- // const dictMap = res.data.data || {};
- // // 更新组件字典数据和缓存
- // Object.keys(dictMap).forEach(dictType => {
- // const dictList = dictMap[dictType] || [];
- // // 更新组件字典数据
- // this.$set(this.dictData, dictType, dictList);
- // // 更新缓存
- // this.updateDictCache(dictType, dictList);
- // // 取消加载标记
- // delete dictCache.loading[dictType];
- // });
- // console.log(`[DictMixin] Successfully loaded ${Object.keys(dictMap).length} dictionaries`);
- // return dictMap;
- // } else {
- // console.error(`获取字典数据失败:`, res.data.msg);
- // // 取消所有加载标记
- // dictTypes.forEach(type => {
- // delete dictCache.loading[type];
- // });
- // return Promise.reject(res.data.msg);
- // }
- // }).catch(err => {
- // // 发生错误时取消所有加载标记
- // dictTypes.forEach(type => {
- // delete dictCache.loading[type];
- // });
- // throw err;
- // });
- // }
- // },
- /**
- * 从缓存中获取字典数据
- * @param {String} dictType - 字典类型
- * @returns {Array|null} - 返回字典数据,不存在或已过期则返回null
- */
- getDictFromCache(dictType) {
- // 判断是否有缓存
- if (!dictCache.data[dictType]) {
- return null;
- }
- // 判断缓存是否过期
- const lastUpdateTime = dictCache.lastUpdateTime[dictType] || 0;
- const now = Date.now();
- if (now - lastUpdateTime > dictCache.expireTime) {
- // 缓存已过期,删除缓存
- delete dictCache.data[dictType];
- delete dictCache.lastUpdateTime[dictType];
- return null;
- }
- // 返回缓存的字典数据
- return dictCache.data[dictType];
- },
- /**
- * 更新字典缓存
- * @param {String} dictType - 字典类型
- * @param {Array} dictList - 字典数据列表
- */
- updateDictCache(dictType, dictList) {
- dictCache.data[dictType] = dictList;
- dictCache.lastUpdateTime[dictType] = Date.now();
- // 更新本地存储
- try {
- // 只存储最后更新时间,具体数据保存在内存中
- storage.setDict(`dict_time_${dictType}`, dictCache.lastUpdateTime[dictType]);
- } catch (e) {
- console.error('更新字典缓存失败:', e);
- }
- },
- /**
- * 清除字典缓存
- * @param {String} dictType - 字典类型,不传则清除所有缓存
- */
- clearDictCache(dictType) {
- if (dictType) {
- delete dictCache.data[dictType];
- delete dictCache.lastUpdateTime[dictType];
- storage.removeDict(`dict_time_${dictType}`);
- } else {
- dictCache.data = {};
- dictCache.lastUpdateTime = {};
- // 清除所有字典相关的本地存储
- const keys = Object.keys(localStorage);
- keys.forEach(key => {
- if (key.startsWith('dict_time_')) {
- storage.removeDict(key);
- }
- });
- }
- },
- /**
- * 根据字典值获取对应的字典标签
- * @param {String} dictType - 字典类型
- * @param {String|Number} value - 字典值
- * @param {String} defaultLabel - 默认标签
- * @returns {String} - 字典标签
- */
- getDictLabel(dictType, value, defaultLabel = '') {
- // 首先检查组件数据
- const dictList = this.dictData[dictType];
- if (dictList) {
- const item = dictList.find(dict => dict.dictValue === value);
- if (item) return item.dictLabel;
- }
- // 再检查静态字典
- // const staticDictList = staticDict[dictType];
- // if (staticDictList) {
- // const item = staticDictList.find(dict => dict.value === value);
- // if (item) return item.label;
- // }
- // 都没找到,返回默认值
- return defaultLabel;
- },
- /**
- * 根据字典标签获取对应的字典值
- * @param {String} dictType - 字典类型
- * @param {String} label - 字典标签
- * @param {String|Number} defaultValue - 默认值
- * @returns {String|Number} - 字典值
- */
- getDictValue(dictType, label, defaultValue = '') {
- // 首先检查组件数据
- const dictList = this.dictData[dictType];
- if (dictList) {
- const item = dictList.find(dict => dict.label === label);
- if (item) return item.value;
- }
- // 再检查静态字典
- const staticDictList = staticDict[dictType];
- if (staticDictList) {
- const item = staticDictList.find(dict => dict.label === label);
- if (item) return item.value;
- }
- // 都没找到,返回默认值
- return defaultValue;
- },
- /**
- * 获取字典列表
- * @param {String} dictType - 字典类型
- * @returns {Array} - 字典列表
- */
- getDictList(dictType) {
- // 首先检查组件数据
- const dictList = this.dictData[dictType];
- if (dictList) return dictList;
- // 再检查静态字典
- return staticDict[dictType] || [];
- },
- /**
- * 获取字典类型对应的样式类
- * @param {String} dictType - 字典类型
- * @param {String|Number} value - 字典值
- * @param {String} defaultClass - 默认样式类
- * @returns {String} - 字典项的样式类
- */
- getDictClass(dictType, value, defaultClass = '') {
- // 首先检查组件数据
- const dictList = this.dictData[dictType];
- if (dictList) {
- const item = dictList.find(dict => dict.dictValue === value);
- if (item && item.listClass) return item.listClass;
- }
- // 再检查静态字典
- // const staticDictList = staticDict[dictType];
- // if (staticDictList) {
- // const item = staticDictList.find(dict => dict.value === value);
- // if (item && item.listClass) return item.listClass;
- // }
- // 都没找到,返回默认值
- return defaultClass;
- }
- }
- };
|