chore(config): 初始化项目配置文件
- 添加 .editorconfig 文件统一代码风格 - 配置 .env.development 环境变量文件 - 创建 .env.example 环境变量示例文件 - 设置 .eslintignore 忽略检查规则 - 配置 .eslintrc.js 代码检查规则 - 添加 .gitignore 文件忽略版本控制 - 设置 .prettierignore 忽略格式化规则 - 新增隐私政策HTML页面文件 - 创建API密钥编辑组件基础结构
This commit is contained in:
129
src/config/menu.ts
Normal file
129
src/config/menu.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
export default [
|
||||
{
|
||||
path: '/assets/server',
|
||||
component: '/assets/server',
|
||||
meta: { title: '服务器管理', icon: 'AuditOutlined' }
|
||||
},
|
||||
{
|
||||
path: '/project',
|
||||
component: '/project',
|
||||
meta: { title: '项目管理', icon: 'CodeOutlined' }
|
||||
},
|
||||
{
|
||||
path: '/customer',
|
||||
component: '/customer',
|
||||
meta: { title: '客户管理', icon: 'CrownOutlined' }
|
||||
},
|
||||
{
|
||||
path: '/content/article',
|
||||
component: '/content/article',
|
||||
meta: { title: '文章管理', icon: 'FileSearchOutlined' }
|
||||
},
|
||||
{
|
||||
path: '/content/docs/:id',
|
||||
component: '/content/docs',
|
||||
meta: { title: '文档管理', icon: 'ReadOutlined' }
|
||||
},
|
||||
{
|
||||
path: '/task/index',
|
||||
component: '/task/index',
|
||||
meta: { title: '任务管理', icon: 'HistoryOutlined' }
|
||||
},
|
||||
{
|
||||
path: '/appstore',
|
||||
component: '/appstore',
|
||||
meta: { title: '应用管理', icon: 'AppstoreOutlined' }
|
||||
},
|
||||
{
|
||||
path: '/shop',
|
||||
redirect: '/shop/shopMerchantApply',
|
||||
meta: { title: '商城管理', icon: 'ShoppingOutlined' },
|
||||
children: [
|
||||
{
|
||||
path: '/shop/shopMerchantApply',
|
||||
component: '/shop/shopMerchantApply',
|
||||
meta: { title: '商户入驻申请', icon: 'UserAddOutlined' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/system',
|
||||
redirect: '/system/user',
|
||||
meta: { title: '系统管理', icon: 'SettingOutlined' },
|
||||
children: [
|
||||
{
|
||||
path: '/system/user',
|
||||
component: '/system/user'
|
||||
},
|
||||
{
|
||||
path: '/system/role',
|
||||
component: '/system/role',
|
||||
meta: { title: '角色管理', icon: 'IdcardOutlined' }
|
||||
},
|
||||
{
|
||||
path: '/system/menu',
|
||||
component: '/system/menu',
|
||||
meta: { title: '菜单管理', icon: 'AppstoreOutlined' }
|
||||
},
|
||||
{
|
||||
path: '/system/dictionary',
|
||||
component: '/system/dictionary',
|
||||
meta: { title: '字典管理', icon: 'ProfileOutlined' }
|
||||
},
|
||||
{
|
||||
path: '/system/organization',
|
||||
component: '/system/organization'
|
||||
},
|
||||
{
|
||||
path: '/system/file',
|
||||
component: '/system/file',
|
||||
meta: { title: '文件管理', icon: 'FolderOutlined' }
|
||||
},
|
||||
{
|
||||
path: '/system/login-record',
|
||||
component: '/system/login-record',
|
||||
meta: { title: '登录日志', icon: 'CalendarOutlined' }
|
||||
},
|
||||
{
|
||||
path: '/system/operation-record',
|
||||
component: '/system/operation-record',
|
||||
meta: { title: '操作日志', icon: 'FileSearchOutlined' }
|
||||
},
|
||||
{
|
||||
path: '/system/tenant',
|
||||
component: '/system/tenant',
|
||||
meta: { title: '租户管理', icon: 'TeamOutlined' }
|
||||
},
|
||||
{
|
||||
path: '/system/setting',
|
||||
component: '/system/setting',
|
||||
meta: { title: '系统设置', icon: 'SettingOutlined' }
|
||||
}
|
||||
]
|
||||
},
|
||||
// 账号中心
|
||||
{
|
||||
path: '/user',
|
||||
hide: true,
|
||||
redirect: '/user/profile',
|
||||
meta: { title: '账号中心' },
|
||||
children: [
|
||||
{
|
||||
path: '/user/profile',
|
||||
component: '/user/profile',
|
||||
meta: { title: '账号中心', hide: false }
|
||||
},
|
||||
{
|
||||
path: '/user/message',
|
||||
component: '/user/message',
|
||||
meta: { title: '我的消息', hide: false }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/register',
|
||||
hide: true,
|
||||
component: '/passport/register/index.vue',
|
||||
meta: { title: '免费注册' }
|
||||
}
|
||||
];
|
||||
396
src/config/performance.ts
Normal file
396
src/config/performance.ts
Normal file
@@ -0,0 +1,396 @@
|
||||
/**
|
||||
* 性能优化配置
|
||||
*/
|
||||
|
||||
// 性能配置接口
|
||||
export interface PerformanceConfig {
|
||||
// 缓存配置
|
||||
cache: {
|
||||
memory: {
|
||||
maxSize: number;
|
||||
defaultExpiry: number;
|
||||
};
|
||||
persistent: {
|
||||
maxSize: number;
|
||||
defaultExpiry: number;
|
||||
};
|
||||
};
|
||||
|
||||
// 懒加载配置
|
||||
lazyLoad: {
|
||||
delay: number;
|
||||
timeout: number;
|
||||
retries: number;
|
||||
retryDelay: number;
|
||||
};
|
||||
|
||||
// 虚拟滚动配置
|
||||
virtualScroll: {
|
||||
itemHeight: number;
|
||||
buffer: number;
|
||||
threshold: number;
|
||||
};
|
||||
|
||||
// API 请求配置
|
||||
api: {
|
||||
timeout: number;
|
||||
retries: number;
|
||||
retryDelay: number;
|
||||
concurrency: number;
|
||||
};
|
||||
|
||||
// 路由配置
|
||||
router: {
|
||||
preloadDelay: number;
|
||||
cacheSize: number;
|
||||
performanceThreshold: number;
|
||||
};
|
||||
|
||||
// 监控配置
|
||||
monitoring: {
|
||||
enabled: boolean;
|
||||
sampleRate: number;
|
||||
reportInterval: number;
|
||||
};
|
||||
}
|
||||
|
||||
// 默认性能配置
|
||||
export const defaultPerformanceConfig: PerformanceConfig = {
|
||||
cache: {
|
||||
memory: {
|
||||
maxSize: 200,
|
||||
defaultExpiry: 5 * 60 * 1000 // 5分钟
|
||||
},
|
||||
persistent: {
|
||||
maxSize: 100,
|
||||
defaultExpiry: 24 * 60 * 60 * 1000 // 24小时
|
||||
}
|
||||
},
|
||||
|
||||
lazyLoad: {
|
||||
delay: 200,
|
||||
timeout: 30000,
|
||||
retries: 3,
|
||||
retryDelay: 1000
|
||||
},
|
||||
|
||||
virtualScroll: {
|
||||
itemHeight: 50,
|
||||
buffer: 5,
|
||||
threshold: 100
|
||||
},
|
||||
|
||||
api: {
|
||||
timeout: 30000,
|
||||
retries: 3,
|
||||
retryDelay: 1000,
|
||||
concurrency: 5
|
||||
},
|
||||
|
||||
router: {
|
||||
preloadDelay: 2000,
|
||||
cacheSize: 20,
|
||||
performanceThreshold: 1000
|
||||
},
|
||||
|
||||
monitoring: {
|
||||
enabled: process.env.NODE_ENV === 'production',
|
||||
sampleRate: 0.1, // 10% 采样率
|
||||
reportInterval: 60000 // 1分钟上报一次
|
||||
}
|
||||
};
|
||||
|
||||
// 性能优化管理器
|
||||
export class PerformanceManager {
|
||||
private config: PerformanceConfig;
|
||||
private reportTimer: number | null = null;
|
||||
|
||||
constructor(config: Partial<PerformanceConfig> = {}) {
|
||||
this.config = { ...defaultPerformanceConfig, ...config };
|
||||
this.init();
|
||||
}
|
||||
|
||||
private init() {
|
||||
// 初始化性能监控
|
||||
if (this.config.monitoring.enabled) {
|
||||
this.startMonitoring();
|
||||
}
|
||||
|
||||
// 设置全局错误处理
|
||||
this.setupErrorHandling();
|
||||
|
||||
// 优化控制台输出
|
||||
this.optimizeConsole();
|
||||
}
|
||||
|
||||
// 开始性能监控
|
||||
private startMonitoring() {
|
||||
this.reportTimer = window.setInterval(() => {
|
||||
this.reportPerformance();
|
||||
}, this.config.monitoring.reportInterval);
|
||||
}
|
||||
|
||||
// 上报性能数据
|
||||
private reportPerformance() {
|
||||
if (Math.random() > this.config.monitoring.sampleRate) {
|
||||
return; // 采样控制
|
||||
}
|
||||
|
||||
try {
|
||||
const performanceData = this.collectPerformanceData();
|
||||
|
||||
// 这里可以发送到监控服务
|
||||
console.log('Performance Report:', performanceData);
|
||||
|
||||
// 可以发送到后端
|
||||
// this.sendToBackend(performanceData);
|
||||
} catch (error) {
|
||||
console.warn('Failed to report performance:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 收集性能数据
|
||||
private collectPerformanceData() {
|
||||
const navigation = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming;
|
||||
const memory = (performance as any).memory;
|
||||
|
||||
return {
|
||||
// 页面加载性能
|
||||
pageLoad: {
|
||||
domContentLoaded: navigation?.domContentLoadedEventEnd - navigation?.fetchStart,
|
||||
loadComplete: navigation?.loadEventEnd - navigation?.fetchStart,
|
||||
firstByte: navigation?.responseStart - navigation?.fetchStart
|
||||
},
|
||||
|
||||
// 内存使用
|
||||
memory: memory ? {
|
||||
used: Math.round(memory.usedJSHeapSize / 1024 / 1024),
|
||||
total: Math.round(memory.totalJSHeapSize / 1024 / 1024),
|
||||
limit: Math.round(memory.jsHeapSizeLimit / 1024 / 1024)
|
||||
} : null,
|
||||
|
||||
// 资源加载
|
||||
resources: this.getResourceMetrics(),
|
||||
|
||||
// 时间戳
|
||||
timestamp: Date.now()
|
||||
};
|
||||
}
|
||||
|
||||
// 获取资源指标
|
||||
private getResourceMetrics() {
|
||||
const resources = performance.getEntriesByType('resource');
|
||||
const metrics = {
|
||||
total: resources.length,
|
||||
slow: 0,
|
||||
failed: 0,
|
||||
avgDuration: 0
|
||||
};
|
||||
|
||||
let totalDuration = 0;
|
||||
|
||||
resources.forEach(resource => {
|
||||
const duration = resource.duration;
|
||||
totalDuration += duration;
|
||||
|
||||
if (duration > 2000) {
|
||||
metrics.slow++;
|
||||
}
|
||||
});
|
||||
|
||||
metrics.avgDuration = Math.round(totalDuration / resources.length);
|
||||
|
||||
return metrics;
|
||||
}
|
||||
|
||||
// 设置错误处理
|
||||
private setupErrorHandling() {
|
||||
// 全局错误处理
|
||||
window.addEventListener('error', (event) => {
|
||||
this.handleError('JavaScript Error', event.error);
|
||||
});
|
||||
|
||||
// Promise 错误处理
|
||||
window.addEventListener('unhandledrejection', (event) => {
|
||||
this.handleError('Unhandled Promise Rejection', event.reason);
|
||||
});
|
||||
|
||||
// Vue 错误处理
|
||||
if (window.Vue) {
|
||||
window.Vue.config.errorHandler = (error, instance, info) => {
|
||||
this.handleError('Vue Error', { error, instance, info });
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 处理错误
|
||||
private handleError(type: string, error: any) {
|
||||
console.error(`${type}:`, error);
|
||||
|
||||
// 可以发送错误到监控服务
|
||||
// this.reportError(type, error);
|
||||
}
|
||||
|
||||
// 优化控制台输出
|
||||
private optimizeConsole() {
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
// 生产环境禁用 console.log
|
||||
console.log = () => {};
|
||||
console.debug = () => {};
|
||||
console.info = () => {};
|
||||
}
|
||||
}
|
||||
|
||||
// 获取配置
|
||||
getConfig(): PerformanceConfig {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
// 更新配置
|
||||
updateConfig(newConfig: Partial<PerformanceConfig>) {
|
||||
this.config = { ...this.config, ...newConfig };
|
||||
}
|
||||
|
||||
// 清理资源
|
||||
destroy() {
|
||||
if (this.reportTimer) {
|
||||
clearInterval(this.reportTimer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 性能优化建议
|
||||
export class PerformanceAdvisor {
|
||||
// 分析性能并给出建议
|
||||
static analyzeAndAdvise() {
|
||||
const advice: string[] = [];
|
||||
|
||||
// 检查内存使用
|
||||
const memory = (performance as any).memory;
|
||||
if (memory && memory.usedJSHeapSize > memory.jsHeapSizeLimit * 0.8) {
|
||||
advice.push('内存使用过高,建议清理不必要的缓存和引用');
|
||||
}
|
||||
|
||||
// 检查资源加载
|
||||
const resources = performance.getEntriesByType('resource');
|
||||
const slowResources = resources.filter(r => r.duration > 2000);
|
||||
if (slowResources.length > 0) {
|
||||
advice.push(`发现 ${slowResources.length} 个加载缓慢的资源,建议优化`);
|
||||
}
|
||||
|
||||
// 检查页面加载时间
|
||||
const navigation = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming;
|
||||
if (navigation) {
|
||||
const loadTime = navigation.loadEventEnd - navigation.fetchStart;
|
||||
if (loadTime > 3000) {
|
||||
advice.push('页面加载时间过长,建议优化首屏渲染');
|
||||
}
|
||||
}
|
||||
|
||||
return advice;
|
||||
}
|
||||
|
||||
// 获取优化建议
|
||||
static getOptimizationTips() {
|
||||
return [
|
||||
'使用虚拟滚动处理长列表',
|
||||
'启用组件懒加载',
|
||||
'合理使用缓存策略',
|
||||
'优化图片资源大小',
|
||||
'减少不必要的重新渲染',
|
||||
'使用 Web Workers 处理复杂计算',
|
||||
'启用 HTTP/2 和资源压缩',
|
||||
'使用 CDN 加速静态资源'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// 全局性能管理器实例
|
||||
export const performanceManager = new PerformanceManager();
|
||||
|
||||
// 性能装饰器
|
||||
export function performanceTrack(name: string) {
|
||||
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
||||
const originalMethod = descriptor.value;
|
||||
|
||||
descriptor.value = function (...args: any[]) {
|
||||
const startTime = performance.now();
|
||||
|
||||
try {
|
||||
const result = originalMethod.apply(this, args);
|
||||
|
||||
// 如果是 Promise,等待完成后记录
|
||||
if (result && typeof result.then === 'function') {
|
||||
return result.finally(() => {
|
||||
const duration = performance.now() - startTime;
|
||||
console.log(`${name} 执行时间: ${duration.toFixed(2)}ms`);
|
||||
});
|
||||
}
|
||||
|
||||
const duration = performance.now() - startTime;
|
||||
console.log(`${name} 执行时间: ${duration.toFixed(2)}ms`);
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
const duration = performance.now() - startTime;
|
||||
console.log(`${name} 执行时间: ${duration.toFixed(2)}ms (出错)`);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
return descriptor;
|
||||
};
|
||||
}
|
||||
|
||||
// 性能检查工具
|
||||
export class PerformanceChecker {
|
||||
// 检查长任务
|
||||
static checkLongTasks() {
|
||||
if ('PerformanceObserver' in window) {
|
||||
const observer = new PerformanceObserver((list) => {
|
||||
list.getEntries().forEach((entry) => {
|
||||
console.warn(`长任务检测: ${entry.duration.toFixed(2)}ms`, entry);
|
||||
});
|
||||
});
|
||||
|
||||
observer.observe({ entryTypes: ['longtask'] });
|
||||
}
|
||||
}
|
||||
|
||||
// 检查布局抖动
|
||||
static checkLayoutShift() {
|
||||
if ('PerformanceObserver' in window) {
|
||||
const observer = new PerformanceObserver((list) => {
|
||||
let clsValue = 0;
|
||||
|
||||
list.getEntries().forEach((entry) => {
|
||||
if (!(entry as any).hadRecentInput) {
|
||||
clsValue += (entry as any).value;
|
||||
}
|
||||
});
|
||||
|
||||
if (clsValue > 0.1) {
|
||||
console.warn(`布局抖动过大: ${clsValue.toFixed(3)}`);
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe({ entryTypes: ['layout-shift'] });
|
||||
}
|
||||
}
|
||||
|
||||
// 检查首次输入延迟
|
||||
static checkFirstInputDelay() {
|
||||
if ('PerformanceObserver' in window) {
|
||||
const observer = new PerformanceObserver((list) => {
|
||||
list.getEntries().forEach((entry) => {
|
||||
const fid = (entry as any).processingStart - entry.startTime;
|
||||
if (fid > 100) {
|
||||
console.warn(`首次输入延迟过大: ${fid.toFixed(2)}ms`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
observer.observe({ entryTypes: ['first-input'] });
|
||||
}
|
||||
}
|
||||
}
|
||||
78
src/config/setting.ts
Normal file
78
src/config/setting.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
// 租户ID
|
||||
export const TENANT_ID = import.meta.env.VITE_TENANT_ID || 10258;
|
||||
// 模板ID
|
||||
export const TEMPLATE_ID = import.meta.env.VITE_TEMPLATE_ID || 10258;
|
||||
// appSecret
|
||||
export const APP_SECRET = import.meta.env.VITE_APP_SECRET || '';
|
||||
// 开发商官方网站
|
||||
export const domain = import.meta.env.VITE_DOMAIN || 'https://your-domain.com';
|
||||
// 主节点
|
||||
export const SERVER_API_URL = import.meta.env.VITE_SERVER_API_URL || 'https://your-api.com/api';
|
||||
// 模块节点
|
||||
export const MODULES_API_URL = localStorage.getItem('ApiUrl') || import.meta.env.VITE_API_URL;
|
||||
// 文件服务器地址
|
||||
export const FILE_SERVER = import.meta.env.VITE_FILE_SERVER || 'https://your-file-server.com';
|
||||
|
||||
/**
|
||||
* 以下配置一般不需要修改
|
||||
*/
|
||||
// 接口地址
|
||||
export const API_BASE_URL: string = import.meta.env.VITE_API_URL;
|
||||
export const PROJECT_NAME: string = import.meta.env.VITE_APP_NAME;
|
||||
// 不显示侧栏的路由
|
||||
export const HIDE_SIDEBARS: string[] = ['/home'];
|
||||
// 不显示页脚的路由
|
||||
export const HIDE_FOOTERS: string[] = [
|
||||
'/system/dictionary',
|
||||
'/system/organization',
|
||||
'/form/advanced'
|
||||
];
|
||||
// 页签同路由不同参数可重复打开的路由
|
||||
export const REPEATABLE_TABS: string[] = [];
|
||||
// 不需要登录的路由
|
||||
export const WHITE_LIST: string[] = [
|
||||
'/login',
|
||||
'/register',
|
||||
'/dealer/register',
|
||||
'/forget',
|
||||
'/wx-work-login',
|
||||
'/token-login',
|
||||
'/home',
|
||||
'/bszx/pay-cert/:id'
|
||||
];
|
||||
// 开启 KeepAlive 后仍然不需要缓存的路由地址
|
||||
export const KEEP_ALIVE_EXCLUDES: string[] = [];
|
||||
// 直接指定菜单数据
|
||||
// export const USER_MENUS = menu;
|
||||
export const USER_MENUS: Array<any> | undefined = undefined;
|
||||
// 首页名称, 为空则取第一个菜单的名称
|
||||
export const HOME_TITLE: string | undefined = undefined;
|
||||
// 首页路径, 为空则取第一个菜单的地址
|
||||
export const HOME_PATH: string | undefined = undefined;
|
||||
// 外层布局的路由地址
|
||||
export const LAYOUT_PATH = '/';
|
||||
// 刷新路由的路由地址
|
||||
export const REDIRECT_PATH = '/redirect';
|
||||
// 开启页签栏是否缓存组件
|
||||
//export const TAB_KEEP_ALIVE = !import.meta.env.DEV;
|
||||
export const TAB_KEEP_ALIVE = true;
|
||||
// token 传递的 header 名称
|
||||
export const TOKEN_HEADER_NAME = 'Authorization';
|
||||
// token 存储的名称
|
||||
export const TOKEN_STORE_NAME = 'access_token';
|
||||
// 主题配置存储的名称
|
||||
export const THEME_STORE_NAME = 'theme';
|
||||
// i18n 缓存的名称
|
||||
export const I18N_CACHE_NAME = 'i18n-lang';
|
||||
// 是否开启国际化功能
|
||||
export const I18N_ENABLE = true;
|
||||
// 高德地图 key , 自带的只能用于测试, 正式项目请自行到高德地图官网申请 key
|
||||
export const MAP_KEY = import.meta.env.VITE_MAP_KEY || '';
|
||||
// 高德地图 安全密钥
|
||||
export const MAP_CODE = import.meta.env.VITE_MAP_CODE || '';
|
||||
// WebSoftAdmin 授权码, 自带的只能用于演示, 正式项目请更换为自己的授权码
|
||||
export const LICENSE_CODE = import.meta.env.VITE_LICENSE_CODE || '';
|
||||
// 缩略图前缀
|
||||
export const FILE_THUMBNAIL = FILE_SERVER + '/thumbnail';
|
||||
// 文件下载前缀
|
||||
export const FILE_DOWNLOAD = FILE_SERVER + '/download';
|
||||
Reference in New Issue
Block a user