版本发布

This commit is contained in:
icssoa
2025-07-21 16:47:04 +08:00
parent 1abed7a2e1
commit 6d8193880a
307 changed files with 41718 additions and 0 deletions

137
cool/store/dict.ts Normal file
View File

@@ -0,0 +1,137 @@
import { reactive } from "vue";
import { service } from "../service";
import type { DictKey } from "../types";
import { forInObject, isNull, parse } from "../utils";
// 字典项类型定义
export type DictItem = {
id: number; // 字典项ID
typeId: number; // 字典类型ID
label: string; // 显示标签
name: string; // 可选名称
value: any; // 字典项值
orderNum: number; // 排序号
parentId?: number | null; // 父级ID可选
};
// 字典数据类型定义
export type DictData = {
key: string; // 字典key
list: DictItem[]; // 字典项列表
};
// 字典管理类
export class Dict {
private data: DictData[] = reactive([]); // 存储所有字典数据
constructor() {}
/**
* 获取指定key的字典数据
* @param key 字典key
* @returns 字典数据
*/
find(key: string) {
return this.data.find((e) => e.key == key);
}
/**
* 获取指定key的字典项列表
* @param key 字典key
* @returns 字典项数组
*/
get(key: DictKey): DictItem[] {
return this.find(key)?.list ?? new Array<DictItem>();
}
/**
* 获取指定key和value的字典项
* @param key 字典key
* @param value 字典项值
* @returns 字典项或null
*/
getItem(key: DictKey, value: any): DictItem | null {
const item = this.get(key).find((e) => e.value == value);
if (isNull(item)) {
return null;
}
return item!;
}
/**
* 获取指定key和多个value的字典项数组
* @param key 字典key
* @param values 字典项值数组
* @returns 字典项数组
*/
getItems(key: DictKey, values: any[]): DictItem[] {
return values.map((e) => this.getItem(key, e)).filter((e) => !isNull(e)) as DictItem[];
}
/**
* 获取指定key和value的字典项的label
* @param key 字典key
* @param value 字典项值
* @returns 字典项label字符串
*/
getItemLabel(key: DictKey, value: any): string {
const item = this.getItem(key, value);
if (isNull(item) || isNull(item?.label)) {
return "";
}
return item!.label;
}
/**
* 刷新字典数据
* @param types 可选指定需要刷新的字典key数组
*/
async refresh(types?: DictKey[] | null): Promise<void> {
const res = await service.dict.info.data({ types });
// 遍历返回的字典数据
forInObject(res, (arr, key) => {
let list: DictItem[] = [];
(arr as UTSJSONObject[]).forEach((e) => {
e["label"] = e["name"];
const d = parse<DictItem>(e);
if (d != null) {
list.push(d);
}
});
const item = this.find(key);
// 如果不存在则新增,否则更新
if (isNull(item)) {
this.data.push({
key,
list
});
} else {
item!.list = list;
}
});
// #ifdef H5
console.log("[DICT]", this.data);
// #endif
}
}
// 单例字典对象
export const dict = new Dict();
/**
* 获取字典实例
* @returns Dict实例
*/
export function useDict() {
return dict;
}

17
cool/store/index.ts Normal file
View File

@@ -0,0 +1,17 @@
import { Dict, dict } from "./dict";
import { User, user } from "./user";
type Store = {
user: User;
dict: Dict;
};
export function useStore(): Store {
return {
user,
dict
};
}
export * from "./dict";
export * from "./user";

197
cool/store/user.ts Normal file
View File

@@ -0,0 +1,197 @@
import { reactive } from "vue";
import type { UserInfoEntity } from "../types";
import { forInObject, isNull, parse, storage } from "../utils";
import { service } from "../service";
import { router } from "../router";
/**
* Token类型定义
* @property token 访问token
* @property expire token过期时间
* @property refreshToken 刷新token
* @property refreshExpire 刷新token过期时间
*/
export type Token = {
token: string;
expire: number;
refreshToken: string;
refreshExpire: number;
};
export class User {
/**
* 用户信息响应式对象属性结构见UserInfoEntity
*/
info = reactive<UserInfoEntity>({});
/**
* 当前token字符串或null
*/
token: string | null = null;
constructor() {
// 获取本地用户信息
const userInfo = storage.get("userInfo");
// 获取本地token
const token = storage.get("token") as string | null;
// 如果token为空字符串则置为null
this.token = token == "" ? null : token;
// 初始化用户信息
this.set(userInfo!);
}
/**
* 获取用户信息(从服务端拉取最新信息并更新本地)
* @returns Promise<void>
*/
async get() {
if (this.token != null) {
await service.user.info
.person({})
.then((res) => {
if (!isNull(res)) {
this.set(res);
}
})
.catch(() => {
this.logout();
});
}
}
/**
* 设置用户信息并存储到本地
* @param data 用户信息对象
*/
set(data: any) {
if (isNull(data)) {
return;
}
// 先清空原有信息
this.remove();
// 逐项赋值到响应式info对象
forInObject(data, (value, key) => {
this.info[key] = value;
});
// 持久化到本地存储
storage.set("userInfo", data, 0);
}
/**
* 更新用户信息(本地与服务端同步)
* @param data 新的用户信息
*/
async update(data: UserInfoEntity) {
if (isNull(data) || this.isNull()) {
return;
}
const params = { ...data };
// 本地同步更新
forInObject(params as any, (value, key) => {
this.info[key] = value;
});
// 同步到服务端
await service.user.info.updatePerson(params);
}
/**
* 移除用户信息(仅清空本地响应式对象,不清除本地存储)
*/
remove() {
forInObject({ ...this.info } as any, (_, key) => {
// #ifdef APP
this.info[key] = null;
// #endif
// #ifndef APP
delete this.info[key];
// #endif
});
}
/**
* 判断用户信息是否为空以id字段为准
* @returns boolean
*/
isNull() {
return isNull(this.info["id"]);
}
/**
* 清除本地所有用户信息和token
*/
clear() {
storage.remove("userInfo");
storage.remove("token");
storage.remove("refreshToken");
this.token = null;
this.remove();
}
/**
* 退出登录,清除所有信息并跳转到登录页
*/
logout() {
this.clear();
router.login();
}
/**
* 设置token并存储到本地
* @param data Token对象
*/
setToken(data: Token) {
this.token = data.token;
// 访问token提前5秒过期防止边界问题
storage.set("token", data.token, data.expire - 5);
// 刷新token提前5秒过期
storage.set("refreshToken", data.refreshToken, data.refreshExpire - 5);
}
/**
* 刷新token调用服务端接口自动更新本地token
* @returns Promise<string> 新的token
*/
refreshToken(): Promise<string> {
return new Promise((resolve, reject) => {
service.user.login
.refreshToken({
refreshToken: storage.get("refreshToken")
})
.then((res) => {
const token = parse<Token>(res);
if (token != null) {
this.setToken(token);
resolve(token.token);
}
})
.catch((err) => {
reject(err);
});
});
}
}
/**
* 单例用户对象,项目全局唯一
*/
export const user = new User();
/**
* 获取用户单例实例组合式API用法
* @returns User
*/
export function useUser() {
return user;
}