小程序初始提交

This commit is contained in:
jdc
2025-11-13 10:36:23 +08:00
parent f26b4f9a2f
commit 5db3b180eb
447 changed files with 83351 additions and 0 deletions

View File

@@ -0,0 +1,136 @@
import { reactive } from "vue";
import { request } from "../service";
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: string): DictItem[] {
return this.find(key)?.list ?? new Array<DictItem>();
}
/**
* 获取指定key和value的字典项
* @param key 字典key
* @param value 字典项值
* @returns 字典项或null
*/
getItem(key: string, 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: string, 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: string, 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?: string[] | null): Promise<void> {
const res = await request({
url: "/app/dict/info/data",
method: "POST",
data: { types }
});
if (res == null) {
return;
}
// 遍历返回的字典数据
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();

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";

View File

@@ -0,0 +1,185 @@
import { computed, ref } from "vue";
import { forInObject, isNull, isObject, parse, storage } from "../utils";
import { router } from "../router";
import { request } from "../service";
import type { UserInfo } from "@/types";
export type Token = {
token: string; // 访问token
expire: number; // token过期时间
refreshToken: string; // 刷新token
refreshExpire: number; // 刷新token过期时间
};
export class User {
/**
* 用户信息,响应式对象
*/
info = ref<UserInfo | null>(null);
/**
* 当前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;
// 初始化用户信息
if (userInfo != null && isObject(userInfo)) {
this.set(userInfo);
}
}
/**
* 获取用户信息(从服务端拉取最新信息并更新本地)
* @returns Promise<void>
*/
async get() {
if (this.token != null) {
await request({
url: "/app/user/info/person"
})
.then((res) => {
if (res != null) {
this.set(res);
}
})
.catch(() => {
// this.logout();
});
}
}
/**
* 设置用户信息并存储到本地
* @param data 用户信息对象
*/
set(data: any) {
if (isNull(data)) {
return;
}
// 设置
this.info.value = parse<UserInfo>(data)!;
// 持久化到本地存储
storage.set("userInfo", data, 0);
}
/**
* 更新用户信息(本地与服务端同步)
* @param data 新的用户信息
*/
async update(data: any) {
if (isNull(data) || isNull(this.info.value)) {
return;
}
// 本地同步更新
forInObject(data, (value, key) => {
this.info.value![key] = value;
});
// 同步到服务端
await request({
url: "/app/user/info/updatePerson",
method: "POST",
data
});
}
/**
* 移除用户信息
*/
remove() {
this.info.value = null;
storage.remove("userInfo");
}
/**
* 判断用户信息是否为空
* @returns boolean
*/
isNull() {
return this.info.value == null;
}
/**
* 清除本地所有用户信息和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) => {
request({
url: "/app/user/login/refreshToken",
method: "POST",
data: {
refreshToken: storage.get("refreshToken")
}
})
.then((res) => {
if (res != null) {
const token = parse<Token>(res);
if (token != null) {
this.setToken(token);
resolve(token.token);
}
}
})
.catch((err) => {
reject(err);
});
});
}
}
/**
* 单例用户对象,项目全局唯一
*/
export const user = new User();
/**
* 用户信息,响应式对象
*/
export const userInfo = computed(() => user.info.value);