feat: 适配5.x后端,重构前端架构
主要变更: 1. 重构API目录结构,采用模块化设计,适配5.x后端接口规范 2. 优化布局组件,提升用户界面体验 3. 增强国际化支持,完善多语言配置 4. 新增权限控制功能,支持前端路由权限管理 5. 优化认证流程,支持JWT认证机制 6. 新增中间件和插件,提升系统扩展性 7. 优化状态管理,采用更清晰的模块化设计 8. 新增搜索框、广告等组件,丰富页面功能 9. 更改包管理工具从npm到pnpm,提升依赖管理效率 10. 完善配置系统,支持多环境配置 适配5.x后端特性: - 采用新的API接口规范 - 支持JWT认证机制 - 适配后端权限控制体系 - 支持后端国际化接口 - 优化数据交互方式
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
# 离线图标模式使用说明
|
||||
|
||||
## 概述
|
||||
|
||||
本项目支持离线图标模式,图标数据可以本地缓存,减少对在线 API 的依赖。
|
||||
|
||||
## 工作原理
|
||||
|
||||
1. **优先从本地加载**:客户端优先从 `/public/icons/` 目录加载图标数据
|
||||
2. **在线回退**:如果本地没有缓存,自动从 Iconify API 获取
|
||||
3. **服务端处理**:服务端始终使用在线 API(因为服务端无法访问 public 目录)
|
||||
|
||||
## 下载图标到本地
|
||||
|
||||
### 快速开始
|
||||
|
||||
```bash
|
||||
# 进入下载脚本目录
|
||||
cd web/scripts/download-icons
|
||||
|
||||
# 运行下载脚本(无需额外依赖)
|
||||
node download-icons.cjs
|
||||
```
|
||||
|
||||
### 下载结果
|
||||
|
||||
脚本会下载以下图标集到 `web/public/icons/` 目录:
|
||||
|
||||
- `ant-design.json` - 830 个 Ant Design 图标
|
||||
- `simple-icons.json` - 3393 个品牌图标
|
||||
- `mdi.json` - 9032 个 Material Design Icons
|
||||
- `material-symbols.json` - 15161 个 Material Symbols
|
||||
- `tabler.json` - 5986 个 Tabler Icons
|
||||
- `ph.json` - 9072 个 Phosphor Icons
|
||||
- `lucide.json` - 1669 个 Lucide Icons
|
||||
|
||||
**总计:45,143 个图标**
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
web/
|
||||
├── public/
|
||||
│ └── icons/
|
||||
│ ├── index.json # 图标索引文件
|
||||
│ ├── ant-design.json # Ant Design 图标集
|
||||
│ ├── simple-icons.json # Simple Icons 图标集
|
||||
│ ├── mdi.json # MDI 图标集
|
||||
│ ├── material-symbols.json # Material Symbols 图标集
|
||||
│ ├── tabler.json # Tabler Icons 图标集
|
||||
│ ├── ph.json # Phosphor Icons 图标集
|
||||
│ └── lucide.json # Lucide Icons 图标集
|
||||
└── scripts/
|
||||
└── download-icons/
|
||||
├── download-icons.cjs # 下载脚本
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<Icon icon="ant-design:home-outlined" />
|
||||
<Icon icon="simple-icons:gitee" />
|
||||
<Icon icon="mdi:account" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Icon } from '~/components/icon'
|
||||
</script>
|
||||
```
|
||||
|
||||
## 支持的图标集
|
||||
|
||||
| 图标集 | 数量 | 说明 |
|
||||
|--------|------|------|
|
||||
| ant-design | 830 | Ant Design 官方图标 |
|
||||
| simple-icons | 3393 | 品牌图标(GitHub、Gitee 等) |
|
||||
| mdi | 9032 | Material Design Icons |
|
||||
| material-symbols | 15161 | Google Material Symbols |
|
||||
| tabler | 5986 | Tabler Icons |
|
||||
| ph | 9072 | Phosphor Icons |
|
||||
| lucide | 1669 | Lucide Icons |
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **首次加载**:首次使用时需要下载图标数据到本地
|
||||
2. **网络要求**:如果本地没有缓存,需要网络连接才能获取图标
|
||||
3. **更新图标**:如需更新图标集,重新运行下载脚本即可
|
||||
4. **文件大小**:完整的图标集较大,但已优化为 JSON 格式,加载速度快
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 图标不显示
|
||||
|
||||
1. 检查浏览器控制台是否有错误信息
|
||||
2. 确认 `/public/icons/` 目录下有对应的 JSON 文件
|
||||
3. 检查网络连接(如果本地没有缓存)
|
||||
|
||||
### 下载失败
|
||||
|
||||
1. 检查网络连接
|
||||
2. 确认 Node.js 版本 >= 14
|
||||
3. 尝试手动下载图标数据
|
||||
|
||||
## 性能优化
|
||||
|
||||
- 图标数据会在内存中缓存,避免重复加载
|
||||
- 使用 CDN 加速图标 SVG 的加载
|
||||
- 已下载 45,143 个图标,覆盖大部分常用场景
|
||||
|
||||
## 技术细节
|
||||
|
||||
### 加载策略
|
||||
|
||||
```typescript
|
||||
// 客户端优先从本地加载
|
||||
if (process.client) {
|
||||
try {
|
||||
// 1. 尝试从本地加载
|
||||
icons = await fetch(`/icons/${prefix}.json`)
|
||||
} catch (localError) {
|
||||
// 2. 本地加载失败,回退到在线 API
|
||||
icons = await fetch(`https://api.iconify.design/collection?prefix=${prefix}`)
|
||||
}
|
||||
} else {
|
||||
// 3. 服务端始终使用在线 API
|
||||
icons = await fetch(`https://api.iconify.design/collection?prefix=${prefix}`)
|
||||
}
|
||||
```
|
||||
|
||||
### 缓存机制
|
||||
|
||||
- 内存缓存:避免重复请求
|
||||
- 本地文件:持久化存储
|
||||
- 在线回退:确保可用性
|
||||
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const https = require('https');
|
||||
|
||||
const ICON_SETS = [
|
||||
'ant-design',
|
||||
'simple-icons',
|
||||
'mdi',
|
||||
'material-symbols',
|
||||
'tabler',
|
||||
'ph',
|
||||
'lucide'
|
||||
];
|
||||
|
||||
const OUTPUT_DIR = path.join(__dirname, '../../public/icons');
|
||||
|
||||
function fetchJson(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
https.get(url, (res) => {
|
||||
let data = '';
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
resolve(JSON.parse(data));
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}).on('error', reject);
|
||||
});
|
||||
}
|
||||
|
||||
async function downloadIconSet(prefix) {
|
||||
try {
|
||||
console.log(`Downloading ${prefix} icons...`);
|
||||
|
||||
const data = await fetchJson(`https://api.iconify.design/collection?prefix=${prefix}`);
|
||||
|
||||
const iconList = data.uncategorized || [];
|
||||
if (data.categories) {
|
||||
for (const category in data.categories) {
|
||||
iconList.push(...(data.categories[category] || []));
|
||||
}
|
||||
}
|
||||
|
||||
const icons = iconList.map(v => `${prefix}:${v}`);
|
||||
|
||||
const outputPath = path.join(OUTPUT_DIR, `${prefix}.json`);
|
||||
fs.writeFileSync(outputPath, JSON.stringify(icons, null, 2));
|
||||
|
||||
console.log(`✓ Downloaded ${icons.length} ${prefix} icons to ${outputPath}`);
|
||||
return icons;
|
||||
} catch (error) {
|
||||
console.error(`✗ Failed to download ${prefix} icons:`, error.message);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async function downloadAllIcons() {
|
||||
console.log('Starting icon download...\n');
|
||||
|
||||
if (!fs.existsSync(OUTPUT_DIR)) {
|
||||
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
const allIcons = {};
|
||||
|
||||
for (const prefix of ICON_SETS) {
|
||||
const icons = await downloadIconSet(prefix);
|
||||
if (icons.length > 0) {
|
||||
allIcons[prefix] = icons;
|
||||
}
|
||||
}
|
||||
|
||||
const indexPath = path.join(OUTPUT_DIR, 'index.json');
|
||||
fs.writeFileSync(indexPath, JSON.stringify(allIcons, null, 2));
|
||||
|
||||
console.log(`\n✓ All icons downloaded successfully!`);
|
||||
console.log(`✓ Index file created at ${indexPath}`);
|
||||
console.log(`\nTotal icon sets: ${Object.keys(allIcons).length}`);
|
||||
console.log(`Total icons: ${Object.values(allIcons).reduce((sum, icons) => sum + icons.length, 0)}`);
|
||||
}
|
||||
|
||||
downloadAllIcons().catch(console.error);
|
||||
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const bindingsPath = path.join(__dirname, '../node_modules/oxc-parser/src-js/bindings.js');
|
||||
|
||||
console.log('Patching oxc-parser bindings.js...');
|
||||
|
||||
let content = fs.readFileSync(bindingsPath, 'utf8');
|
||||
|
||||
// 在 requireNative 函数之前添加回退逻辑
|
||||
const fallbackPatch = `
|
||||
// Fallback to JavaScript implementation when native binding is not available
|
||||
const loadNative = () => {
|
||||
try {
|
||||
return requireNative();
|
||||
} catch (error) {
|
||||
console.warn('Native binding not available, using JavaScript fallback:', error.message);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
`;
|
||||
|
||||
// 替换 requireNative 调用
|
||||
content = content.replace(
|
||||
/nativeBinding = requireNative\(\)/g,
|
||||
'nativeBinding = loadNative()'
|
||||
);
|
||||
|
||||
// 在文件开头添加回退函数
|
||||
content = content.replace(
|
||||
/const loadErrors = \[\]/g,
|
||||
fallbackPatch + 'const loadErrors = []'
|
||||
);
|
||||
|
||||
// 修改错误处理,当 nativeBinding 为 null 时继续
|
||||
content = content.replace(
|
||||
/if \(!nativeBinding\) \{[\s\S]*?throw new Error\(nativeBindingError\([\s\S]*?\)\)[\s\S]*?\}/g,
|
||||
`if (!nativeBinding) {
|
||||
console.warn('Using JavaScript fallback for oxc-parser');
|
||||
}`
|
||||
);
|
||||
|
||||
fs.writeFileSync(bindingsPath, content, 'utf8');
|
||||
|
||||
console.log('✓ Patched oxc-parser bindings.js successfully');
|
||||
console.log('✓ JavaScript fallback enabled for oxc-parser');
|
||||
Reference in New Issue
Block a user