【Vue】RuoYi-Vue vue3版本 字典TypeScrpit化

本文适用于希望将RuoYi-Vue3项目转化为TypeScript版本,或希望将‘字典’功能模块从RuoYi-Vue3中独立出来,并在其他TypeScript项目中使用的同学。
文章感谢 Ruoyi团队 原代码地址项目 RuoYi-Cloud-Vue3

文章环境说明

pagekage version 备注
vue ^3.4.21 这个都懂得吧
typescript ^5.5.4 同上
pinia ^2.2.2 状态管理库
pinia-plugin-persistedstate ^3.2.3 状态管理库持久化/不需要可以不安装

文章不讲解 piniapinia-plugin-persistedstate 使用方法,可以点击查看官方文档

先写一个判空函数

如果你已经定义了自己的判空函数,那么可以跳过此段落。如果你还没有定义判空函数,可以将以下代码保存为一个新文件,并放置在您希望的位置,比如我将它放在了'/src/utils/assert'路径下。在接下来的内容中,我们将主要使用isEmpty函数,您也可以根据自己的需要将isEmpty替换为您自己的判空函数。

// '@/utils/assert'

// 采取类型
const takeType = (data: unknown) => Object.prototype.toString.call(data).slice(8, -1);
// 是否是假值
export const isFakeValue = <T = unknown>(data: T | undefined | null | ''): data is undefined | null | '' =>
  ['', null, undefined].includes(data as any);
// 是不是数组
export const isArr = <T = any>(data: unknown): data is T[] =>
  typeof Array.isArray === 'undefined' ? takeType(data) === 'Array' : Array.isArray(data);
// 是不是对象
export const isObj = <T extends Record<string, any> = Record<string, any>>(data: unknown): data is T =>
  takeType(data) === 'Object';
// 是不是空对象
export const isEmptyObj = (data: unknown): data is {} => isObj(data) && Object.keys(data).length === 0;
// 是不是空数组
export const isEmptyArr = (data: unknown): data is any[] => isArr(data) && data.length === 0;
// 是不是空,主要使用函数
export const isEmpty = (data: unknown): boolean => {
  if (isFake(data)) return true;
  const type = takeType(data);
  switch (type) {
    case 'String':
      return (data as string).length === 0;
    case 'Number':
      return (data as number) === 0;
    case 'Object':
      return isEmptyObj(data);
    case 'Array':
      return isEmptyArr(data);
    case 'Boolean':
      return data as boolean;
    case 'Map':
      return (data as Map<any, any>).size === 0;
    case 'Set':
      return (data as Set<any>).size === 0;
    default:
      return false;
  }
};

创建 dictionaryStore

在你所在 store 目录下创建 dictionaryStore.ts,不多说了看注释吧,记得替加入你的请求函数!!!!

import { isEmpty } from '#utils/assert'; // 导入空函数 可以替换你的判空函数
import { acceptHMRUpdate, defineStore } from 'pinia';

// 以下类型根据你的项目需求扩展

// 字典的 key 和 value 类型定义
export interface IDictionaryValue {
  value: string;
  label: string;
  tagType?: string;
  tagClass?: string;
}

// 字典类型定义,用于存储字典的 key 和 value
interface IDictionaries {
  key: string;
  value: IDictionaryValue[];
}

// State 类型定义,用于在组件中使用 store 的状态和函数
export interface IDictionaryState {
  dictionaries: IDictionaries[];
}

// 获取返回的类型
interface GetDictionaryResults {
  dictLabel: string;
  dictValue: string;
  listClass?: string;
  cssClass?: string;
}

export const useDictionaryStore = defineStore('dictionaryStore', {
  // 初始化状态
  state: (): IDictionaryState => ({
    dictionaries: []
  }),
  // 定义 actions 方法
  actions: {
    // 获取字典
    getDict(key: string) {
      if (isEmpty(key)) return null;
      try {
        const results = this.dictionaries.find((item) => item.key === key);
        if (!results) return null;
        return results.value;
      } catch {
        return null;
      }
    },
    // 设置字典
    setDict(key: string, value: IDictionaryValue[]) {
      if (isEmpty(key)) return;
      this.dictionaries.push({ key, value });
    },
    // 移除字典
    removeDict(key: string) {
      if (isEmpty(key)) return false;
      try {
        const index = this.dictionaries.findIndex((item) => item.key === key);
        if (index === -1) {
          return false;
        } else {
          this.dictionaries.splice(index, 1);
          return true;
        }
      } catch {
        return false;
      }
    },
    // 清空字典列表(重置)
    clearDict() {
      this.dictionaries = [];
    },
    // 获取字典数据(异步)
    async fetchDict(key: string): Promise<IDictionaryValue[] | null> {
      try {
        ////// 此处替换为实际获取字典的方法 请求方法 //////
        ////// 此处替换为实际获取字典的方法 请求方法//////
        ////// 此处替换为实际获取字典的方法 请求方法 //////
        ////// 此处替换为实际获取字典的方法 请求方法 //////
        const value = [] as GetDictionaryResults[];
        const v: IDictionaryValue[] = value.map((p) => ({
          label: p.dictLabel,
          value: p.dictValue,
          elTagType: p.listClass,
          elTagClass: p.cssClass,
        }));
        this.setDict(key, v);
        return v;
      } catch {
        return null;
      }
    }
  },
  // 持久化配置,启用 pinia-plugin-persistedstate 插件后可用 如果不需要就删掉
  persist: true
});

// HMR 热更新
if (import.meta.hot) {
  import.meta.hot.accept(acceptHMRUpdate(useDictionaryStore, import.meta.hot));
}

创建 useDictionary

在你的习惯存放hook的位置创建 useDictionary,博主的存放的位置是 src/hook/ 下。不多说了看代码吧

import { ref, type ToRefs, toRefs } from 'vue';

import { type IDictionaryValue, useDictionaryStore } from '#store/modules/dictionaryStore';
import { isEmpty } from '#utils/assert';

interface IUseDictionaryOptions {
  // 重置本次字典?(重置后需要重新拉取字典)
  reset?: boolean;
}

// 字典结果类型,使用泛型约束字典key的类型,便于ts的类型推断
type DictionaryResults<T extends string> = {
  [key in T]: IDictionaryValue[];
};

/**
 * 获取数据字典 useDictionary
 * @param dictKey 字典key
 * @param options 配置
 * @returns ToRefs<DictionaryResults<T>>
 */
export default function useDictionary<T extends string>(
  dictKey: T[],
  options?: IUseDictionaryOptions,
): ToRefs<DictionaryResults<T>> {
  // 定义一个响应式变量res,初始值为空对象,并指定其类型为DictionaryResults<T>
  const res = ref<DictionaryResults<T>>({} as DictionaryResults<T>);
   // 调用useDictionaryStore钩子函数,获取字典存储Store对象
  const store = useDictionaryStore();
  // 重置本次字典?(重置后需要重新拉取字典)
  if (options?.reset) {
    // 遍历dictKey数组,对每个字典类型执行store.removeDict操作
    dictKey.forEach((dictType: string) => store.removeDict(dictType));
  }
  return (() => {
   // 遍历dictKey数组,对每个字典类型执行异步操作
    dictKey.forEach(async (dictType: string) => {
      // 将res对象中对应字典类型的值初始化为空数组
      res.value[dictType as keyof DictionaryResults<T>] = [];
      // 从store中获取对应字典类型的值
      const dict = store.getDict(dictType);
      // 判断获取到的字典是否为空
      if (isEmpty(dict)) {
        // 如果字典为空,则从服务器异步拉取字典数据
        const data = await store.fetchDict(dictType);
        // 如果拉取到的数据不为空,则将其赋值给res对象中对应字典类型的值
        if (data) {
          res.value[dictType as keyof DictionaryResults<T>] = data;
        }
      } else {
        // 如果字典不为空,则直接将其赋值给res对象中对应字典类型的值
        res.value[dictType as keyof DictionaryResults<T>] = dict;
      }
    });
    // 使用 toRefs 将其返回,让它解构是还有响应式
    return toRefs<DictionaryResults<T>>(res.value);
  })();
}

看看效果

以上基本完成,看看效果 根据输入dictkey值返回响应对象

image.png
image.png
image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 选择qi:是表达式 标签选择器 类选择器 属性选择器 继承属性: color,font,text-align,li...
    love2013阅读 2,452评论 0 11
  • 前言 首先祝看到这篇文章的同学大家新年好呀,先讲一下我为啥要写这个小程序,是这样,我上上个星期放假回来就开始我的兼...
    零零写代码像菜虚困阅读 542评论 0 1
  • Web前端技术由 html、css 和 javascript 三大部分构成,是一个庞大而复杂的技术体系,其复杂程度...
    hnscdg阅读 711评论 0 0
  • Web前端技术由html、css和 javascript三大部分构成,是一个庞大而复杂的技术体系,其复杂程度不低于...
    Hebborn_hb阅读 344评论 0 1
  • 我在深夜里想起的故事 都在黑暗中死去了 灯光也是喑哑 飞蛾满地灰痕 我在失眠里梦到的你 都在十九岁时死去了 埋在盛...
    尔音依旧阅读 237评论 0 6

友情链接更多精彩内容