feat: 初始化项目配置和文档- 添加 .editorconfig 文件,配置代码编辑规范

- 添加 .env 及相关文件,配置环境变量
- 添加 .eslintignore 和 .eslintrc.js 文件,配置 ESLint 规则
- 添加 .gitignore 文件,配置 Git忽略项
- 添加 .prettierignore 文件,配置 Prettier 忽略项
- 添加隐私政策文档,详细说明用户数据的收集和使用
This commit is contained in:
2025-08-23 20:31:46 +08:00
commit 37f3b6327c
1310 changed files with 210439 additions and 0 deletions

6
src/store/index.ts Normal file
View File

@@ -0,0 +1,6 @@
/**
* pinia
*/
import { createPinia } from 'pinia';
export default createPinia();

134
src/store/modules/chat.ts Normal file
View File

@@ -0,0 +1,134 @@
import { defineStore } from 'pinia';
import { io, Socket } from 'socket.io-client';
import { getToken } from '@/utils/token-util';
import { ChatConversation, ChatMessage } from '@/api/system/chat/model';
import {
pageChatConversation,
updateChatConversation
} from '@/api/system/chat';
import { emitter } from '@/utils/common';
const SOCKET_URL: string = import.meta.env.VITE_SOCKET_URL;
interface ConnectionOptions {
token: string;
userId: number;
isAdmin: boolean;
}
export interface ChatState {
socket: Socket | undefined;
conversations: ChatConversation[];
}
export const useChatStore = defineStore({
id: 'chat',
state: (): ChatState => ({
socket: undefined,
conversations: []
}),
getters: {
unReadLetter(): number {
return this.conversations.reduce((count, item) => count + item.unRead, 0);
},
unReadConversations(): ChatConversation[] {
return this.conversations
.filter((item) => item.unRead > 0)
.sort((a, b) => {
return (
new Date(b.updateTime).getTime() - new Date(a.updateTime).getTime()
);
});
}
},
actions: {
readConversation(id) {
const index = this.conversations.findIndex((item) => item.id === id);
if (index >= 0) {
updateChatConversation({
id: this.conversations[index].id,
unRead: 0
});
this.conversations.splice(index, 1);
}
},
async connectSocketIO(userId: number) {
console.log(
'---------------------------------connectSocketIO----------------------------------'
);
const options: ConnectionOptions = {
token: getToken() || '',
userId: userId,
isAdmin: true
};
const socket: Socket = io(SOCKET_URL, {
query: options,
transports: ['websocket', 'polling'],
timeout: 5000
});
socket.on('connect', () => {
this.socket = socket;
console.log(
'---------------------------------socket connect----------------------------------'
);
// 获取聊天列表
pageChatConversation({
keywords: '',
status: 1,
page: 1,
limit: 100,
onlyFake: true
}).then((res) => {
if (res?.list) {
this.conversations = res.list;
}
});
});
console.log(
'---------------------------------socket----------------------------------',
socket
);
console.log('收到socket消息>>>');
// 收到新消息
socket.on('message', (data: ChatMessage) => {
console.log('收到socket消息>>>');
const index = this.conversations.findIndex(
(item) =>
item.friendId === data.formUserId && item.userId === data.toUserId
);
let content = '';
if (data.type == 'image') {
content = '图片';
} else if (data.type === 'card') {
content = '卡片';
} else {
content = data.content;
}
if (index >= 0) {
this.conversations[index].unRead++;
this.conversations[index].content = content;
this.conversations[index].updateTime = Date.now();
} else {
this.conversations.push({
content: content,
friendInfo: data.formUserInfo,
userInfo: data.toUserInfo,
messages: [],
unRead: 1,
updateTime: Date.now(),
userId: data.toUserId,
friendId: data.formUserId
});
}
emitter.emit('message', data);
});
socket.on('connect_error', () => {
console.log('connect_error');
});
}
}
});

View File

@@ -0,0 +1,40 @@
/**
* 接收传参 store
*/
import { defineStore } from 'pinia';
export interface ParamsState {
title: string | null;
comments: string | null;
back: string | null;
redirect: string | null | undefined;
}
export const useParamsStore = defineStore({
id: 'params',
state: (): ParamsState => ({
// 标题
title: '操作成功',
// 描述
comments: '您的申请已提交',
// 当前页面路径
back: null,
// 跳转的页面
redirect: null
}),
getters: {},
actions: {
setTitle(value: string) {
this.title = value;
},
setComments(value: string) {
this.comments = value;
},
setBack(value: string) {
this.back = value;
},
setRedirect(value: string) {
this.redirect = value;
}
}
});

View File

@@ -0,0 +1,23 @@
/**
* 网站设置 store
*/
import { defineStore } from 'pinia';
import { CmsWebsiteSetting } from '@/api/cms/cmsWebsiteSetting/model';
export interface ParamsState {
setting: CmsWebsiteSetting | null;
}
export const useWebsiteSettingStore = defineStore({
id: 'setting',
state: (): ParamsState => ({
// 初始化时确保所有字段都已赋值
setting: null,
}),
getters: {},
actions: {
setSetting(value: CmsWebsiteSetting) {
this.setting = value;
},
},
});

View File

@@ -0,0 +1,70 @@
/**
* 租户信息 store
*/
import { defineStore } from 'pinia';
import { formatTreeData } from 'ele-admin-pro';
import type { MenuItem } from 'ele-admin-pro';
import { getTenantInfo } from '@/api/layout';
import { Tenant } from '@/api/system/tenant/model';
import { Company } from '@/api/system/company/model';
// const EXTRA_MENUS: any = [];
export interface UserState {
tenant: Tenant | null;
company: Company | null;
menus: MenuItem[] | null | undefined;
}
export const useTenantStore = defineStore({
id: 'tenant',
state: (): UserState => ({
// 租户信息
tenant: null,
// 企业信息
company: null,
// 当前登录用户的菜单
menus: null
}),
getters: {},
actions: {
/**
* 请求用户信息、权限、角色、菜单
*/
async fetchTenantInfo() {
const company = await getTenantInfo().catch(() => void 0);
if (!company) {
return {};
}
// 租户信息
this.company = company;
// 企业信息
if (company) {
this.company = company;
}
},
/**
* 更新租户信息
*/
setInfo(value: Tenant) {
this.tenant = value;
},
/**
* 更新菜单的 badge
*/
setMenuBadge(path: string, value?: number | string, color?: string) {
this.menus = formatTreeData(this.menus, (m) => {
if (path === m.path) {
return {
...m,
meta: {
...m.meta,
badge: value,
badgeColor: color
}
};
}
return m;
});
}
}
});

707
src/store/modules/theme.ts Normal file
View File

@@ -0,0 +1,707 @@
/**
* 主题状态管理
*/
import { defineStore } from 'pinia';
import {
changeColor,
screenWidth,
screenHeight,
contentWidth,
contentHeight,
WEAK_CLASS,
BODY_LIMIT_CLASS,
DISABLES_CLASS
} from 'ele-admin-pro/es';
import type {
TabItem,
HeadStyleType,
SideStyleType,
LayoutStyleType,
SideMenuStyleType,
TabStyleType,
TabRemoveOption
} from 'ele-admin-pro/es';
import {
TAB_KEEP_ALIVE,
KEEP_ALIVE_EXCLUDES,
THEME_STORE_NAME
} from '@/config/setting';
// import { getCache } from '@/api/system/cache';
/**
* state 默认值
*/
const DEFAULT_STATE: ThemeState = Object.freeze({
// 页签数据
tabs: [],
// 是否折叠侧栏
collapse: false,
// 是否折叠一级侧栏
sideNavCollapse: true,
// 内容区域是否全屏
bodyFullscreen: false,
// 是否开启页签栏
showTabs: false,
// 是否开启页脚
showFooter: false,
// 顶栏风格: light(亮色), dark(暗色), primary(主色)
headStyle: 'light',
// 侧栏风格: light(亮色), dark(暗色)
sideStyle: 'light',
// 布局风格: side(默认), top(顶栏导航), mix(混合导航)
layoutStyle: 'mix',
// 侧栏菜单风格: default(默认), mix(双排侧栏)
sideMenuStyle: 'default',
// 页签风格: default(默认), dot(圆点), card(卡片)
tabStyle: 'default',
// 路由切换动画
transitionName: 'fade',
// 是否固定顶栏
fixedHeader: false,
// 是否固定侧栏
fixedSidebar: false,
// 是否固定主体
fixedBody: true,
// 内容区域宽度铺满
bodyFull: true,
// logo 是否自适应宽度
logoAutoSize: false,
// 侧栏是否彩色图标
colorfulIcon: false,
// 侧栏是否只保持一个子菜单展开
sideUniqueOpen: true,
// 是否是色弱模式
weakMode: false,
// 是否是暗黑模式
darkMode: false,
// 主题色
color: '',
// 主页的组件名称
homeComponents: [],
// 刷新路由时的参数
routeReload: null,
// 屏幕宽度
screenWidth: screenWidth(),
// 屏幕高度
screenHeight: screenHeight(),
// 内容区域宽度
contentWidth: contentWidth(),
// 内容区域高度
contentHeight: contentHeight(),
// 是否开启响应式
styleResponsive: true
});
// 延时操作定时器
let disableTransitionTimer: number, updateContentSizeTimer: number;
/**
* 读取缓存配置
*/
function getCacheSetting(): any {
try {
const value = localStorage.getItem(THEME_STORE_NAME);
// 加载redis缓存
// getCache('theme').then((data) => {
// if (typeof data === 'object') {
// // 写入本地缓存
// localStorage.setItem(THEME_STORE_NAME, JSON.stringify(data));
// return data;
// }
// });
if (value) {
const cache = JSON.parse(value);
// 加载本地缓存
if (typeof cache === 'object') {
return cache;
}
}
} catch (e) {
console.error(e);
}
return {};
}
/**
* 缓存配置
*/
function cacheSetting(key: string, value: any) {
const cache = getCacheSetting();
if (cache[key] !== value) {
cache[key] = value;
// console.log(value);
// localStorage.setItem(THEME_STORE_NAME, JSON.stringify(cache));
// updateCacheTheme({
// key: 'theme',
// content: JSON.stringify(cache)
// }).then((res) => {
// console.log(res);
// });
}
}
/**
* 开关响应式布局
*/
function changeStyleResponsive(styleResponsive: boolean) {
if (styleResponsive) {
document.body.classList.remove(BODY_LIMIT_CLASS);
} else {
document.body.classList.add(BODY_LIMIT_CLASS);
}
}
/**
* 切换色弱模式
*/
function changeWeakMode(weakMode: boolean) {
if (weakMode) {
document.body.classList.add(WEAK_CLASS);
} else {
document.body.classList.remove(WEAK_CLASS);
}
}
/**
* 切换主题
*/
function changeTheme(value?: string | null, dark?: boolean) {
return new Promise<void>((resolve, reject) => {
try {
changeColor(value, dark);
resolve();
} catch (e) {
reject(e);
}
});
}
/**
* 切换布局时禁用过渡动画
*/
function disableTransition() {
disableTransitionTimer && clearTimeout(disableTransitionTimer);
document.body.classList.add(DISABLES_CLASS);
disableTransitionTimer = setTimeout(() => {
document.body.classList.remove(DISABLES_CLASS);
}, 100) as unknown as number;
}
export const useThemeStore = defineStore({
id: 'theme',
state: (): ThemeState => {
const state = { ...DEFAULT_STATE };
// 读取本地缓存
const cache = getCacheSetting();
Object.keys(state).forEach((key) => {
if (typeof cache[key] !== 'undefined') {
state[key] = cache[key];
}
});
return state;
},
getters: {
// 需要 keep-alive 的组件
keepAliveInclude(): string[] {
if (!TAB_KEEP_ALIVE || !this.showTabs) {
return [];
}
const components = new Set<string>();
const { reloadPath, reloadHome } = this.routeReload || {};
this.tabs?.forEach((t) => {
const isAlive = t.meta?.keepAlive !== false;
const isExclude = KEEP_ALIVE_EXCLUDES.includes(t.path as string);
const isReload = reloadPath && reloadPath === t.fullPath;
if (isAlive && !isExclude && !isReload && t.components) {
t.components.forEach((c) => {
if (typeof c === 'string' && c) {
components.add(c);
}
});
}
});
if (!reloadHome) {
this.homeComponents?.forEach((c) => {
if (typeof c === 'string' && c) {
components.add(c);
}
});
}
return Array.from(components);
}
},
actions: {
setTabs(value: TabItem[]) {
this.tabs = value;
//cacheSetting('tabs', value);
},
setCollapse(value: boolean) {
this.collapse = value;
this.delayUpdateContentSize(800);
},
setSideNavCollapse(value: boolean) {
this.sideNavCollapse = value;
this.delayUpdateContentSize(800);
},
setBodyFullscreen(value: boolean) {
disableTransition();
this.bodyFullscreen = value;
this.delayUpdateContentSize(800);
},
setShowTabs(value: boolean) {
this.showTabs = value;
cacheSetting('showTabs', value);
this.delayUpdateContentSize();
},
setShowFooter(value: boolean) {
this.showFooter = value;
cacheSetting('showFooter', value);
this.delayUpdateContentSize();
},
setHeadStyle(value: HeadStyleType) {
this.headStyle = value;
cacheSetting('headStyle', value);
},
setSideStyle(value: SideStyleType) {
this.sideStyle = value;
cacheSetting('sideStyle', value);
},
setLayoutStyle(value: LayoutStyleType) {
disableTransition();
this.layoutStyle = value;
cacheSetting('layoutStyle', value);
this.delayUpdateContentSize();
},
setSideMenuStyle(value: SideMenuStyleType) {
disableTransition();
this.sideMenuStyle = value;
cacheSetting('sideMenuStyle', value);
this.delayUpdateContentSize();
},
setTabStyle(value: TabStyleType) {
this.tabStyle = value;
cacheSetting('tabStyle', value);
},
setTransitionName(value: string) {
this.transitionName = value;
cacheSetting('transitionName', value);
},
setFixedHeader(value: boolean) {
disableTransition();
this.fixedHeader = value;
cacheSetting('fixedHeader', value);
},
setFixedSidebar(value: boolean) {
disableTransition();
this.fixedSidebar = value;
cacheSetting('fixedSidebar', value);
},
setFixedBody(value: boolean) {
disableTransition();
this.fixedBody = value;
cacheSetting('fixedBody', value);
},
setBodyFull(value: boolean) {
this.bodyFull = value;
cacheSetting('bodyFull', value);
this.delayUpdateContentSize();
},
setLogoAutoSize(value: boolean) {
disableTransition();
this.logoAutoSize = value;
cacheSetting('logoAutoSize', value);
},
setColorfulIcon(value: boolean) {
this.colorfulIcon = value;
cacheSetting('colorfulIcon', value);
},
setSideUniqueOpen(value: boolean) {
this.sideUniqueOpen = value;
cacheSetting('sideUniqueOpen', value);
},
setStyleResponsive(value: boolean) {
changeStyleResponsive(value);
this.styleResponsive = value;
cacheSetting('styleResponsive', value);
},
/**
* 切换色弱模式
* @param value 是否是色弱模式
*/
setWeakMode(value: boolean) {
return new Promise<void>((resolve) => {
changeWeakMode(value);
this.weakMode = value;
cacheSetting('weakMode', value);
resolve();
});
},
/**
* 切换暗黑模式
* @param value 是否是暗黑模式
*/
setDarkMode(value: boolean) {
return new Promise<void>((resolve, reject) => {
changeTheme(this.color, value)
.then(() => {
this.darkMode = value;
cacheSetting('darkMode', value);
resolve();
})
.catch((e) => {
reject(e);
});
});
},
/**
* 切换主题色
* @param value 主题色
*/
setColor(value?: string) {
return new Promise<void>((resolve, reject) => {
changeTheme(value, this.darkMode)
.then(() => {
this.color = value;
cacheSetting('color', value);
resolve();
})
.catch((e) => {
reject(e);
});
});
},
/**
* 设置主页路由对应的组件名称
* @param components 组件名称
*/
setHomeComponents(components: string[]) {
this.homeComponents = components;
},
/**
* 设置刷新路由信息
* @param option 路由刷新参数
*/
setRouteReload(option: RouteReloadOption | null) {
this.routeReload = option;
},
/**
* 更新屏幕尺寸
*/
updateScreenSize() {
this.screenWidth = screenWidth();
this.screenHeight = screenHeight();
this.updateContentSize();
},
/**
* 更新内容区域尺寸
*/
updateContentSize() {
this.contentWidth = contentWidth();
this.contentHeight = contentHeight();
},
/**
* 延时更新内容区域尺寸
* @param delay 延迟时间
*/
delayUpdateContentSize(delay?: number) {
updateContentSizeTimer && clearTimeout(updateContentSizeTimer);
updateContentSizeTimer = setTimeout(() => {
this.updateContentSize();
}, delay ?? 100) as unknown as number;
},
/**
* 重置设置
*/
resetSetting() {
return new Promise<void>((resolve, reject) => {
disableTransition();
this.showTabs = DEFAULT_STATE.showTabs;
this.showFooter = DEFAULT_STATE.showFooter;
this.headStyle = DEFAULT_STATE.headStyle;
this.sideStyle = DEFAULT_STATE.sideStyle;
this.layoutStyle = DEFAULT_STATE.layoutStyle;
this.sideMenuStyle = DEFAULT_STATE.sideMenuStyle;
this.tabStyle = DEFAULT_STATE.tabStyle;
this.transitionName = DEFAULT_STATE.transitionName;
this.fixedHeader = DEFAULT_STATE.fixedHeader;
this.fixedSidebar = DEFAULT_STATE.fixedSidebar;
this.fixedBody = DEFAULT_STATE.fixedBody;
this.bodyFull = DEFAULT_STATE.bodyFull;
this.logoAutoSize = DEFAULT_STATE.logoAutoSize;
this.colorfulIcon = DEFAULT_STATE.colorfulIcon;
this.sideUniqueOpen = DEFAULT_STATE.sideUniqueOpen;
this.styleResponsive = DEFAULT_STATE.styleResponsive;
this.weakMode = DEFAULT_STATE.weakMode;
this.darkMode = DEFAULT_STATE.darkMode;
this.color = DEFAULT_STATE.color;
localStorage.removeItem(THEME_STORE_NAME);
Promise.all([
changeStyleResponsive(this.styleResponsive),
changeWeakMode(this.weakMode),
changeTheme(this.color, this.darkMode)
])
.then(() => {
resolve();
})
.catch((e) => {
reject(e);
});
});
},
/**
* 恢复主题
*/
recoverTheme() {
// 关闭响应式布局
if (!this.styleResponsive) {
changeStyleResponsive(false);
}
// 恢复色弱模式
if (this.weakMode) {
changeWeakMode(true);
}
// 恢复主题色
if (this.color || this.darkMode) {
changeTheme(this.color, this.darkMode).catch((e) => {
console.error(e);
});
}
},
/**
* 添加页签或更新相同 key 的页签数据
* @param data 页签数据
*/
tabAdd(data: TabItem | TabItem[]) {
if (Array.isArray(data)) {
data.forEach((d) => {
this.tabAdd(d);
});
return;
}
const i = this.tabs.findIndex((d) => d.key === data.key);
if (i === -1) {
this.setTabs(this.tabs.concat([data]));
} else if (data.fullPath !== this.tabs[i].fullPath) {
this.setTabs(
this.tabs
.slice(0, i)
.concat([data])
.concat(this.tabs.slice(i + 1))
);
}
},
/**
* 关闭页签
* @param key 页签 key
*/
async tabRemove({
key,
active
}: TabRemoveOption): Promise<TabRemoveResult> {
const i = this.tabs.findIndex((t) => t.key === key || t.fullPath === key);
if (i === -1) {
return {};
}
const t = this.tabs[i];
if (!t.closable) {
return Promise.reject();
}
const path = this.tabs[i - 1]?.fullPath;
this.setTabs(this.tabs.filter((_d, j) => j !== i));
return t.key === active ? { path, home: !path } : {};
},
/**
* 关闭左侧页签
*/
async tabRemoveLeft({
key,
active
}: TabRemoveOption): Promise<TabRemoveResult> {
let index = -1; // 选中页签的 index
for (let i = 0; i < this.tabs.length; i++) {
if (this.tabs[i].key === active) {
index = i;
}
if (this.tabs[i].key === key) {
if (i === 0) {
break;
}
const temp = this.tabs.filter((d, j) => !d.closable && j < i);
if (temp.length === i + 1) {
break;
}
const path = index === -1 ? void 0 : this.tabs[i].fullPath;
this.setTabs(temp.concat(this.tabs.slice(i)));
return { path };
}
}
return Promise.reject();
},
/**
* 关闭右侧页签
*/
async tabRemoveRight({
key,
active
}: TabRemoveOption): Promise<TabRemoveResult> {
if (this.tabs.length) {
let index = -1; // 选中页签的 index
for (let i = 0; i < this.tabs.length; i++) {
if (this.tabs[i].key === active) {
index = i;
}
if (this.tabs[i].key === key) {
if (i === this.tabs.length - 1) {
return Promise.reject();
}
const temp = this.tabs.filter((d, j) => !d.closable && j > i);
if (temp.length === this.tabs.length - i - 1) {
return Promise.reject();
}
const path = index === -1 ? this.tabs[i].fullPath : void 0;
this.setTabs(
this.tabs
.slice(0, i + 1)
.concat(this.tabs.filter((d, j) => !d.closable && j > i))
);
return { path };
}
}
// 主页时关闭全部
const temp = this.tabs.filter((d) => !d.closable);
if (temp.length !== this.tabs.length) {
this.setTabs(temp);
return { home: index !== -1 };
}
}
return Promise.reject();
},
/**
* 关闭其它页签
*/
async tabRemoveOther({
key,
active
}: TabRemoveOption): Promise<TabRemoveResult> {
let index = -1; // 选中页签的 index
let path: string | undefined; // 关闭后跳转的 path
const temp = this.tabs.filter((d, i) => {
if (d.key === active) {
index = i;
}
if (d.key === key) {
path = d.fullPath;
}
return !d.closable || d.key === key;
});
if (temp.length === this.tabs.length) {
return Promise.reject();
}
this.setTabs(temp);
if (index === -1) {
return {};
}
return key === active ? {} : { path, home: !path };
},
/**
* 关闭全部页签
* @param active 选中页签的 key
*/
async tabRemoveAll(active: string): Promise<TabRemoveResult> {
const t = this.tabs.find((d) => d.key === active);
const home = typeof t !== 'undefined' && t.closable === true; // 是否跳转主页
const temp = this.tabs.filter((d) => !d.closable);
if (temp.length === this.tabs.length) {
return Promise.reject();
}
this.setTabs(temp);
return { home };
},
/**
* 修改页签
* @param data 页签数据
*/
tabSetItem(data: TabItem) {
let i = -1;
if (data.key) {
i = this.tabs.findIndex((d) => d.key === data.key);
} else if (data.fullPath) {
i = this.tabs.findIndex((d) => d.fullPath === data.fullPath);
} else if (data.path) {
i = this.tabs.findIndex((d) => d.path === data.path);
}
if (i !== -1) {
const item = { ...this.tabs[i] };
if (data.title) {
item.title = data.title;
}
if (typeof data.closable === 'boolean') {
item.closable = data.closable;
}
if (data.components) {
item.components = data.components;
}
this.setTabs(
this.tabs
.slice(0, i)
.concat([item])
.concat(this.tabs.slice(i + 1))
);
}
}
}
});
/**
* 主题 State 类型
*/
export interface ThemeState {
tabs: TabItem[];
collapse: boolean;
sideNavCollapse: boolean;
bodyFullscreen: boolean;
showTabs: boolean;
showFooter: boolean;
headStyle: HeadStyleType;
sideStyle: SideStyleType;
layoutStyle: LayoutStyleType;
sideMenuStyle: SideMenuStyleType;
tabStyle: TabStyleType;
transitionName: string;
fixedHeader: boolean;
fixedSidebar: boolean;
fixedBody: boolean;
bodyFull: boolean;
logoAutoSize: boolean;
colorfulIcon: boolean;
sideUniqueOpen: boolean;
weakMode: boolean;
darkMode: boolean;
color?: string | null;
homeComponents: string[];
routeReload: RouteReloadOption | null;
screenWidth: number;
screenHeight: number;
contentWidth: number;
contentHeight: number;
styleResponsive: boolean;
}
/**
* 设置路由刷新方法的参数
*/
export interface RouteReloadOption {
// 是否是刷新主页
reloadHome?: boolean;
// 要刷新的页签路由地址
reloadPath?: string;
}
/**
* 关闭页签返回类型
*/
export interface TabRemoveResult {
// 关闭后要跳转的地址
path?: string;
// 关闭后是否跳转到主页
home?: boolean;
}

145
src/store/modules/user.ts Normal file
View File

@@ -0,0 +1,145 @@
/**
* 登录用户 store
*/
import { defineStore } from 'pinia';
import { formatMenus, toTreeData, formatTreeData } from 'ele-admin-pro/es';
import type { MenuItemType } from 'ele-admin-pro/es';
import type { User } from '@/api/system/user/model';
import { TOKEN_STORE_NAME, USER_MENUS } from '@/config/setting';
import {getUserInfo} from '@/api/layout';
import { initialization } from '@/api/layout';
import {clone} from "@/api/system/menu";
import { message } from 'ant-design-vue/es';
// import { isExternalLink } from 'ele-admin-pro';
const EXTRA_MENUS: any = [];
export interface UserState {
info: User | null;
menus: MenuItemType[] | null | undefined;
authorities: (string | undefined)[];
roles: (string | undefined)[];
}
export const useUserStore = defineStore({
id: 'user',
state: (): UserState => ({
// 当前登录用户的信息
info: null,
// 当前登录用户的菜单
menus: null,
// 当前登录用户的权限
authorities: [],
// 当前登录用户的角色
roles: []
}),
getters: {},
actions: {
/**
* 请求用户信息、权限、角色、菜单
*/
async fetchUserInfo() {
// const company = await getTenantInfo().catch(() => void 0);
const result = await getUserInfo().catch(() => {});
if (!result) {
return {};
}
// 系统初始化
if (!result.installed && result.username === 'superAdmin') {
const hide = message.loading('正在分配资源请勿刷新页面...', 500);
// @ts-ignore
clone({tenantId: Number(result.templateId)}).then(() => {
if (result.authorities?.length == 0) {
result.roles?.map((d) => {
if (d.roleCode === 'superAdmin') {
initialization(d.roleId).then(() => {
hide();
location.reload();
return false;
});
}
});
}
})
}
// 修复权限开关
// if (result.authorities?.length == 0) {
// result.roles?.map((d) => {
// if (d.roleCode === 'superAdmin') {
// initialization(d.roleId).then(() => {
// location.reload();
// return false;
// });
// }
// });
// }
// 用户信息
this.info = result;
// 缓存租户信息
localStorage.setItem('TenantName', `${this.info.tenantName}`);
// 缓存企业信息
if (this.info.companyInfo) {
localStorage.setItem(
'CompanyLogo',
`${this.info.companyInfo?.companyLogo}`
);
localStorage.setItem('PlanId', `${this.info.companyInfo?.planId}`);
localStorage.setItem(
'ModulesUrl',
`${this.info.companyInfo.modulesUrl}`
);
}
// 用户权限
this.authorities =
result.authorities
?.filter((d) => !!d.authority)
?.map((d) => d.authority) ?? [];
// 用户角色
this.roles = result.roles?.map((d) => d.roleCode) ?? [];
// 获取token
const token = localStorage.getItem(TOKEN_STORE_NAME);
// 用户菜单, 过滤掉按钮类型并转为 children 形式
const { menus, homePath } = formatMenus(
USER_MENUS ??
toTreeData({
data: result.authorities
?.filter((d) => d.menuType !== 1)
.map((d) => {
// 改造子模块的访问路径
if (d.modulesUrl) {
d.component = `${d.modulesUrl}${d.path}?token=${token}`;
}
return d;
}),
idField: 'menuId',
parentIdField: 'parentId'
}).concat(EXTRA_MENUS)
);
this.menus = menus;
return { menus, homePath };
},
/**
* 更新用户信息
*/
setInfo(value: User) {
this.info = value;
},
/**
* 更新菜单的 badge
*/
setMenuBadge(path: string, value?: number | string, color?: string) {
this.menus = formatTreeData(this.menus, (m) => {
if (path === m.path) {
return {
...m,
meta: {
...m.meta,
badge: value,
badgeColor: color
}
};
}
return m;
});
}
}
});