Compare commits

..

57 Commits

Author SHA1 Message Date
Soybean
92cabdb5d4 chore(projects): release v0.10.3 tauri branch 2023-06-15 19:40:53 +08:00
Soybean
de2829fde7 chore(projects): release v0.10.3 2023-06-15 19:26:12 +08:00
Soybean
c1bee4046c chore(projects): add vite-plugin-vue-devtools 2023-06-15 19:25:32 +08:00
Soybean
473095b01b fix(styles): fix toggle-lang bg 2023-06-15 01:00:14 +08:00
Soybean
e6abf93457 chore(deps): update deps 2023-06-14 23:59:43 +08:00
Soybean
882f281482 chore(deps): decrease vite-plugin-page-route 2023-06-12 13:35:05 +08:00
Soybean
0b2f68ac04 chore(projects): update deps & update package.json 2023-06-12 01:30:50 +08:00
Soybean
2ca2b766f8 fix(projects): fix userRoleOptions 2023-06-10 12:05:57 +08:00
Soybean
da611fb10b perf(projects): use transformObjectToOption to generate option of object labels 2023-06-08 23:56:27 +08:00
Soybean
eb8e49e23c perf(projects): remove useless code 2023-06-08 23:38:14 +08:00
Soybean
0907d38c06 chore(projects): update deps & update unocss deprecated api exclude 2023-06-08 23:05:08 +08:00
Soybean
2a9b725c6a docs(projects): update CHANGELOG.md by regenerate changelog 2023-06-07 22:50:59 +08:00
Soybean
8f24a94ed3 docs(projects): update README.md 2023-06-07 02:22:13 +08:00
Soybean
4eefc95baa docs(projects): update README.md picture url 2023-06-07 02:16:18 +08:00
Soybean
1681c34a52 docs(projects): update README.md 2023-06-07 02:06:40 +08:00
Soybean
47ab0184b7 chore(deps): update deps 2023-06-07 01:48:55 +08:00
Soybean
58591f660a chore(projects): update @soybeanjs/cli and generate total changelog 2023-06-07 01:46:09 +08:00
Soybean
3c7e1cf442 docs(projects): update README.md 2023-06-05 02:13:15 +08:00
Soybean
055d4cce33 docs(projects): generate full CHANGELOG.md 2023-06-05 02:00:59 +08:00
Soybean
a3dfe61a7b chore(projects): remove bumpp & add release script 2023-06-05 01:57:23 +08:00
Soybean
f9d47c081f chore(deps): update deps 2023-06-05 01:55:09 +08:00
Soybean
ff5bf62989 docs(projects): CHANGELOG.md 2023-05-31 18:25:40 +00:00
Soybean
1f6d079644 chore: release v0.10.2 2023-06-01 02:24:57 +08:00
Soybean
5c085a1986 fix(components): fix mix-menu layout when the locale is English (fixed 241) 2023-06-01 02:24:26 +08:00
Soybean
9a23817473 chore(projects): update deps and use soy lint-staged replace lint-staged 2023-06-01 02:10:07 +08:00
Soybean
56ea8937f6 docs(projects): fix README.md: example image link 2023-05-31 09:28:34 +08:00
Soybean
4f51263501 docs(projects): update README.md: update example image url [更新示例图片的链接] 2023-05-31 02:32:06 +08:00
Soybean
bb2eab60f4 docs(projects): CHANGELOG.md 2023-05-30 18:20:40 +00:00
Soybean
44e4c04811 chore: release v0.10.1 2023-05-31 02:19:56 +08:00
Soybean
b5839eab26 docs(projects): update README.md 2023-05-31 02:18:19 +08:00
Soybean
780ac75bf6 chore(projects): add switch for pageRoute plugin [添加自动生成路由的插件的开关] 2023-05-31 01:52:57 +08:00
Soybean
a252138594 docs(projects): CHANGELOG.md 2023-05-30 17:47:56 +00:00
Soybean
270a055072 chore: release v0.10.0 2023-05-31 01:47:13 +08:00
Soybean
08e194efe9 perf(projects): move changing document title by locale to global event of composables & add appLoading unmount 2023-05-31 01:44:49 +08:00
Soybean
5f6caab338 docs(projects): update CHANGELOG.md 2023-05-31 01:35:04 +08:00
Soybean
5aaa318142 chore(projects): remove useless packages, update lint-staged config, add githublogen 2023-05-31 01:33:46 +08:00
Soybean
cebbef680f chore(deps): update deps 2023-05-31 01:08:31 +08:00
Soybean
0abde46ef4 fix(projects): hide the drawer when it is initial mobile mode [初始化时为移动端布局则隐藏侧边栏] fixed #238 2023-05-26 13:08:35 +08:00
Soybean
f2b518ed26 feat(projects): support mobile layout [支持移动端布局] 2023-05-26 03:27:41 +08:00
Soybean
c6207f35e1 Merge pull request #237 from abstain23/fix-i18n
fix(projects): 修复面包屑导航下拉菜单语言显示问题
2023-05-25 21:13:45 +08:00
cc
ee8fa04814 fix(projects): 修复面包屑导航下拉菜单语言显示问题 2023-05-25 21:11:42 +08:00
Soybean
7b746fa053 perf(projects): complete dynamic route translate [补充动态路由的翻译] 2023-05-24 23:17:29 +08:00
Soybean
b7fea53107 Merge pull request #234 from chhinsras/main
Add Khmer Translation
2023-05-24 23:03:23 +08:00
Chhin Sras
f89f3e6a38 Added Khmer Translation 2023-05-24 21:07:35 +07:00
Chhin Sras
a0da2f6e16 Delete actions-template-sync.yml 2023-05-24 15:52:05 +07:00
Chhin Sras
3b5380e0d1 Update Sras.md 2023-05-24 15:38:43 +07:00
Chhin Sras
35276bfe41 Update and rename .github/workflows/actions-template-sync.yml to actions-template-sync.yml 2023-05-24 15:30:10 +07:00
Chhin Sras
215c1ecbd9 Update and rename sync-from-template.yml to actions-template-sync.yml 2023-05-24 15:24:51 +07:00
Chhin Sras
1698b21d7a Create Sras.md 2023-05-24 15:18:35 +07:00
Chhin Sras
ca1e66be47 Rename sync-from-template to sync-from-template.yml 2023-05-24 15:13:58 +07:00
Chhin Sras
22bf2823e8 Update and rename actions-template-sync to sync-from-template 2023-05-24 15:12:03 +07:00
Chhin Sras
32e98f1b3a Create actions-template-sync 2023-05-24 15:06:44 +07:00
Soybean
c1c4335ce7 build(projects): update deps and fix style [升级依赖&修复代码格式] 2023-05-24 00:17:00 +08:00
Soybean
6c50662280 Merge pull request #233 from fast-crud/优化README.md
优化readme.md
2023-05-24 00:12:44 +08:00
xiaojunnuo
f3a1707b94 docs(projects): readme.md 二次开发的项目内容换行 2023-05-23 17:52:06 +08:00
xiaojunnuo
6ea755f2a8 docs(projects): 优化README.md 2023-05-23 17:43:00 +08:00
Soybean
a989b44a15 docs(projects): update README.md [更新README.md] 2023-05-22 23:04:57 +08:00
79 changed files with 9398 additions and 6123 deletions

View File

@@ -1 +1,2 @@
VITE_HTTP_PROXY=Y
VITE_SOYBEAN_ROUTE_PLUGIN=Y

View File

@@ -2,3 +2,4 @@
components.d.ts
router-page.d.ts
*.svg
src-tauri/target

View File

@@ -1,27 +1,25 @@
name: Release
on:
push:
tags:
- "v*.**"
permissions:
contents: write
on:
push:
tags:
- "v*"
jobs:
release:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v3
- uses: actions/setup-node@v3
with:
node-version: 16.x
- name: Create github releases
run: npx changelogithub
- run: npx githublogen
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

2
.npmrc
View File

@@ -1,4 +1,2 @@
registry=https://registry.npmmirror.com/
shamefully-hoist=true
strict-peer-dependencies=false
auto-install-peers=true

8
.vscode/launch.json vendored
View File

@@ -7,6 +7,14 @@
"name": "Vue debugger",
"url": "http://localhost:3200",
"webRoot": "${workspaceFolder}"
},
{
"type": "node",
"request": "launch",
"name": "TS debugger",
"skipFiles": ["<node_internals>/**"],
"runtimeArgs": ["--loader", "tsx"],
"program": "${relativeFile}"
}
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -19,6 +19,19 @@
- **权限路由**:提供前端静态和后端动态两种路由模式,基于 mock 的动态路由能快速实现后端动态路由
- **请求函数**:基于 axios 的完善的请求函数封装,提供 Promise 和 hooks 两种请求函数,加入请求结果数据转换的适配器
## SoybeanJS 工具库
- [@soybeanjs/cli](https://github.com/soybeanjs/cli): SoybeanJS 命令行工具包含发布、git 和依赖等相关的实用命令
- [@soybeanjs/changelog](https://github.com/soybeanjs/changelog): 根据 git tags 和 commits 生成 changelog [示例](./CHANGELOG.md)
- [eslint-config-soybeanjs](https://github.com/soybeanjs/eslint-config): SoybeanJS 的 eslint 预设配置
- [@soybeanjs/materials](https://github.com/soybeanjs/materials): SoybeanJS 的物料仓库
- [@soybeanjs/vite-plugin-vue-page-route](https://github.com/soybeanjs/vite-plugin-vue-page-route): SoybeanAdmin 的路由插件
## 基于 SoybeanAdmin 二次开发的项目
- [electron-mock-admin](https://github.com/lixin59/electron-mock-api): 一个 Mock Api 管理系统,帮助前端开发伙伴快速实现接口的 mock。
- [T-Shell](https://github.com/TheBlindM/T-Shell): 是一个可配置命令提示的终端模拟器和 SSH 客户端。
## 在线预览
- [Soybean Admin 预览地址](https://soybean.pro/)
@@ -29,12 +42,12 @@
## 代码仓库
- [github](https://github.com/honghuangdc/soybean-admin)
- [tauri 版](https://github.com/honghuangdc/soybean-admin/tree/tauri)
- [精简版](https://github.com/honghuangdc/soybean-admin/tree/thin)
- [gitee](https://gitee.com/honghuangdc/soybean-admin)
- [tauri 版](https://gitee.com/honghuangdc/soybean-admin/tree/tauri)
- [精简版](https://gitee.com/honghuangdc/soybean-admin/tree/thin)
| 仓库 | github 地址 | gitee 镜像 | 预览 |
| -------------- | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | --------------------------------------------------------- |
| soybean-admin | [github](https://github.com/honghuangdc/soybean-admin) | [gitee](https://gitee.com/honghuangdc/soybean-admin) | [预览](https://soybean.pro/) |
| tauri 版 | [tauri 版](https://github.com/honghuangdc/soybean-admin/tree/tauri) | [tauri 版](https://gitee.com/honghuangdc/soybean-admin/tree/tauri) | |
| 精简版 | [精简版](https://github.com/honghuangdc/soybean-admin/tree/thin) | [精简版](https://gitee.com/honghuangdc/soybean-admin/tree/thin) | |
| 集成 fast-crud | [集成 fast-crud](https://github.com/honghuangdc/soybean-admin/tree/fast-crud) | [集成 fast-crud](https://gitee.com/honghuangdc/soybean-admin/tree/fast-crud) | [预览](http://fast-crud.docmirror.cn/soybean/#/crud/demo) |
## 更新日志
@@ -54,13 +67,15 @@
![](https://s2.loli.net/2022/05/16/rSnNHLdpuvkKxWq.png)
![](https://s2.loli.net/2023/06/07/O39EKNa675FZIuS.png)
![](https://s2.loli.net/2022/05/18/Mt6YZqmDxO8v4uR.png)
![](https://s2.loli.net/2022/05/16/ktH5dcG3fuFOoKA.png)
![](https://s2.loli.net/2023/06/07/zhmWnFlPTfDpot8.png)
![](https://s2.loli.net/2022/05/16/VPl6Ru1iCAhLcS4.png)
![](https://s2.loli.net/2022/05/16/bRlAKuHW7ZVh9DT.png)
![](https://s2.loli.net/2023/06/07/n6Dy1HXBvuPc9oT.png)
![](https://s2.loli.net/2022/06/07/rY8TyAftM5dxspv.png)
@@ -68,6 +83,12 @@
![](https://s2.loli.net/2022/06/07/rRSG6mEZpujOACT.png)
<div align="center">
<img style="width:380px;margin-right:18px;border:1px solid #dedede;" src="https://s2.loli.net/2023/06/07/A5Nonc9vI6pB1lr.png" />
&nbsp;
<img style="width:380px;border:1px solid #dedede;" src="https://s2.loli.net/2023/06/07/VwBjqEhTke3OxXF.png" />
</div>
## 安装使用
- 环境配置
@@ -119,10 +140,6 @@ docker run --name soybean -p 80:80 -d soybeanjs/soybean-admin:v0.9.6
项目已用 simple-git-hooks 代替了 husky, 旧版本用了 husky执行 pnpm soy init-git-hooks 进行初始化配置
## 基于 SoybeanAdmin 二次开发的项目
[electron-mock-admin](https://github.com/lixin59/electron-mock-api): 一个 Mock Api 管理系统帮助前端开发伙伴快速实现接口的mock。
[T-Shell](https://github.com/TheBlindM/T-Shell): 是一个可配置命令提示的终端模拟器和 SSH客户端。
## 浏览器支持
本地开发推荐使用`Chrome 90+` 浏览器
@@ -142,17 +159,13 @@ docker run --name soybean -p 80:80 -d soybeanjs/soybean-admin:v0.9.6
`Soybean Admin` 是完全开源免费的项目,在帮助开发者更方便地进行中大型管理系统开发,同时也提供微信和 QQ 交流群,使用问题欢迎在群内提问。
<div style="display:flex;">
<!-- <div style="padding-right:24px;">
<p>微信交流群</p>
<img src="https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/soybeanjs-wechat0503.jpeg" style="width:200px" />
</div> -->
<div style="padding-right:24px;">
<p>QQ交流群</p>
<img src="https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/qq-soybean-admin.jpg" style="width:200px" />
<img src="https://i.loli.net/2021/11/24/1J6REWXiHomU2kM.jpg" style="width:200px" />
</div>
<div>
<p>添加本人微信,欢迎来技术交流,业务咨询</p>
<img src="https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/soybeanjs.jpeg" style="width:180px" />
<img src="https://s2.loli.net/2023/06/07/sVyCUFBvzQ9f5b7.jpg" style="width:200px" />
</div>
</div>
@@ -164,4 +177,4 @@ docker run --name soybean -p 80:80 -d soybeanjs/soybean-admin:v0.9.6
## License
[MIT © Soybean-2021](./LICENSE)
本项目基于[MIT © Soybean-2021](./LICENSE) 协议,仅供参考学习,商用时请保留作者的版权信息,作者不对软件做担保和负责。

View File

@@ -3,6 +3,7 @@ import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import unocss from '@unocss/vite';
import progress from 'vite-plugin-progress';
import VueDevtools from 'vite-plugin-vue-devtools';
import pageRoute from '@soybeanjs/vite-plugin-vue-page-route';
import unplugin from './unplugin';
import mock from './mock';
@@ -22,11 +23,11 @@ export function setupVitePlugins(viteEnv: ImportMetaEnv): (PluginOption | Plugin
}
}),
vueJsx(),
VueDevtools(),
...unplugin(viteEnv),
unocss(),
mock(viteEnv),
progress(),
pageRoute()
progress()
];
if (viteEnv.VITE_VISUALIZER === 'Y') {
@@ -38,6 +39,9 @@ export function setupVitePlugins(viteEnv: ImportMetaEnv): (PluginOption | Plugin
if (viteEnv.VITE_PWA === 'Y' || viteEnv.VITE_VERCEL === 'Y') {
plugins.push(pwa());
}
if (viteEnv.VITE_SOYBEAN_ROUTE_PLUGIN === 'Y') {
plugins.push(pageRoute());
}
return plugins;
}

View File

@@ -1,21 +0,0 @@
{
"types": {
"feat": { "title": "🚀 Features" },
"perf": { "title": "🔥 Performance" },
"fix": { "title": "🩹 Fixes" },
"refactor": { "title": "💅 Refactors" },
"docs": { "title": "📖 Documentation" },
"types": { "title": "🌊 Types" },
"chore": { "title": "🏡 Chore" },
"test": { "title": "🧪 Tests" },
"style": { "title": "🎨 Styles" },
"ci": { "title": "🤖 CI" }
},
"scopeMap": {},
"titles": {
"breakingChanges": "🚨 Breaking Changes"
},
"contributors": true,
"capitalize": true,
"group": true
}

View File

@@ -1,295 +0,0 @@
export type ListItem = {
id?: number;
children?: ListItem[];
[key: string]: any;
};
export type BaseMockOptions = { name: string; copyTimes?: number; list: ListItem[]; idGenerator: number };
type CopyListParams = { originList: ListItem[]; newList: ListItem[]; options: BaseMockOptions; parentId?: number };
function copyList(props: CopyListParams) {
const { originList, newList, options, parentId } = props;
for (const item of originList) {
const newItem: ListItem = { ...item, parentId };
newItem.id = options.idGenerator;
options.idGenerator += 1;
newList.push(newItem);
if (item.children) {
newItem.children = [];
copyList({
originList: item.children,
newList: newItem.children,
options,
parentId: newItem.id
});
}
}
}
function delById(req: Service.MockOption, list: any[]) {
for (let i = 0; i < list.length; i += 1) {
const item = list[i];
if (item.id === parseInt(req.query.id, 10)) {
list.splice(i, 1);
break;
}
if (item.children && item.children.length > 0) {
delById(req, item.children);
}
}
}
function findById(id: number, list: ListItem[]): any {
for (const item of list) {
if (item.id === id) {
return item;
}
if (item.children && item.children.length > 0) {
const sub = findById(id, item.children);
if (sub !== null && sub !== undefined) {
return sub;
}
}
}
return null;
}
function matchWithArrayCondition(value: any[], item: ListItem, key: string) {
if (value.length === 0) {
return true;
}
let matched = false;
for (const i of value) {
if (item[key] instanceof Array) {
for (const j of item[key]) {
if (i === j) {
matched = true;
break;
}
}
if (matched) {
break;
}
} else if (item[key] === i || (typeof item[key] === 'string' && item[key].indexOf(`${i}`) >= 0)) {
matched = true;
break;
}
if (matched) {
break;
}
}
return matched;
}
function matchWithObjectCondition(value: any, item: ListItem, key: string) {
let matched = true;
for (const key2 of Object.keys(value)) {
const v = value[key2];
if (v && item[key] && v !== item[key][key2]) {
matched = false;
break;
}
}
return matched;
}
function searchFromList(list: ListItem[], query: any) {
const filter = (item: ListItem) => {
let allFound = true; // 是否所有条件都符合
for (const key of Object.keys(query)) {
const value = query[key];
if (value === undefined || value === null || value === '') {
// no nothing
} else if (value instanceof Array) {
// 如果条件中的value是数组的话只要查到一个就行
const matched = matchWithArrayCondition(value, item, key);
if (!matched) {
allFound = false;
}
} else if (value instanceof Object) {
// 如果条件中的value是对象的话需要每个key都匹配
const matched = matchWithObjectCondition(value, item, key);
if (!matched) {
allFound = false;
}
} else if (item[key] !== value) {
allFound = false;
}
}
return allFound;
};
return list.filter(filter);
}
export default {
buildMock(options: BaseMockOptions) {
const name = options.name;
if (!options.copyTimes) {
options.copyTimes = 29;
}
const list: any[] = [];
for (let i = 0; i < options.copyTimes; i += 1) {
copyList({
originList: options.list,
newList: list,
options
});
}
options.list = list;
return [
{
path: `/mock/${name}/page`,
method: 'post',
handle(req: Service.MockOption) {
let data = [...list];
let limit = 20;
let offset = 0;
for (const item of list) {
if (item.children && item.children.length === 0) {
item.hasChildren = false;
item.lazy = false;
}
}
let orderAsc: any;
let orderProp: any;
if (req && req.body) {
const { page, query } = req.body;
if (page.limit) {
limit = parseInt(page.limit, 10);
}
if (page.offset) {
offset = parseInt(page.offset, 10);
}
if (Object.keys(query).length > 0) {
data = searchFromList(list, query);
}
}
const start = offset;
let end = offset + limit;
if (data.length < end) {
end = data.length;
}
if (orderProp) {
// 排序
data.sort((a, b) => {
let ret = 0;
if (a[orderProp] > b[orderProp]) {
ret = 1;
} else if (a[orderProp] < b[orderProp]) {
ret = -1;
}
return orderAsc ? ret : -ret;
});
}
const records = data.slice(start, end);
const lastOffset = data.length - (data.length % limit);
if (offset > lastOffset) {
offset = lastOffset;
}
return {
code: 200,
message: 'success',
data: {
records,
total: data.length,
limit,
offset
}
};
}
},
{
path: `/mock/${name}/get`,
method: 'get',
handle(req: Service.MockOption) {
let id = req.query.id;
id = parseInt(id, 10);
let current = null;
for (const item of list) {
if (item.id === id) {
current = item;
break;
}
}
return {
code: 200,
message: 'success',
data: current
};
}
},
{
path: `/mock/${name}/add`,
method: 'post',
handle(req: Service.MockOption) {
req.body.id = options.idGenerator;
options.idGenerator += 1;
list.unshift(req.body);
return {
code: 200,
message: 'success',
data: req.body.id
};
}
},
{
path: `/mock/${name}/update`,
method: 'post',
handle(req: Service.MockOption) {
const item = findById(req.body.id, list);
if (item) {
Object.assign(item, req.body);
}
return {
code: 200,
message: 'success',
data: null
};
}
},
{
path: `/mock/${name}/delete`,
method: 'post',
handle(req: Service.MockOption) {
delById(req, list);
return {
code: 200,
message: 'success',
data: null
};
}
},
{
path: `/mock/${name}/batchDelete`,
method: 'post',
handle(req: Service.MockOption) {
const ids = req.body.ids;
for (let i = list.length - 1; i >= 0; i -= 1) {
const item = list[i];
if (ids.indexOf(item.id) >= 0) {
list.splice(i, 1);
}
}
return {
code: 200,
message: 'success',
data: null
};
}
},
{
path: `/mock/${name}/all`,
method: 'post',
handle() {
return {
code: 200,
message: 'success',
data: list
};
}
}
];
}
};

View File

@@ -1,5 +0,0 @@
import demo from './modules/demo';
import headerGroup from './modules/header-group';
const crudApis = [...demo, ...headerGroup];
export default crudApis;

View File

@@ -1,56 +0,0 @@
import type { MethodType, MockMethod } from 'vite-plugin-mock';
import type { BaseMockOptions } from '../base';
import mockBase from '../base';
import MockOption = Service.MockOption;
const options: BaseMockOptions = {
name: 'crud/demo',
idGenerator: 0,
list: [
{
select: '1',
text: '文本测试',
copyable: '文本可复制',
avatar: 'http://greper.handsfree.work/extends/avatar.jpg',
richtext: '富文本',
datetime: '2023-01-30 11:11:11'
},
{
select: '2'
},
{
select: '0'
}
]
};
const mockedApis = mockBase.buildMock(options);
const apis: MockMethod[] = [
{
url: `/mock/${options.name}/dict`,
method: 'get',
response: () => {
return {
code: 200,
message: '',
data: [
{ value: '0', label: '关', color: 'warning' },
{ value: '1', label: '开', color: 'success' },
{ value: '2', label: '停' }
]
};
}
}
];
for (const mockedApi of mockedApis) {
apis.push({
url: mockedApi.path,
method: mockedApi.method as MethodType,
response: (request: MockOption) => {
return mockedApi.handle(request);
}
});
}
export default apis;

View File

@@ -1,46 +0,0 @@
import type { MethodType, MockMethod } from 'vite-plugin-mock';
import type { BaseMockOptions } from '../base';
import mockBase from '../base';
import MockOption = Service.MockOption;
const options: BaseMockOptions = {
name: 'crud/header-group',
idGenerator: 0,
list: [
{
name: '张三',
age: 18,
province: '广东省',
city: '深圳市',
county: '南山区',
street: '粤海街道'
},
{
name: '李四',
age: 26,
province: '浙江省',
city: '杭州市',
county: '西湖区',
street: '西湖街道'
},
{
name: '王五',
age: 24
}
]
};
const mockedApis = mockBase.buildMock(options);
const apis: MockMethod[] = [];
for (const mockedApi of mockedApis) {
apis.push({
url: mockedApi.path,
method: mockedApi.method as MethodType,
response: (request: MockOption) => {
return mockedApi.handle(request);
}
});
}
export default apis;

View File

@@ -1,6 +1,5 @@
import auth from './auth';
import route from './route';
import management from './management';
import crud from './crud';
export default [...auth, ...route, ...management, ...crud];
export default [...auth, ...route, ...management];

View File

@@ -12,7 +12,8 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
meta: {
title: '分析页',
requiresAuth: true,
icon: 'icon-park-outline:analysis'
icon: 'icon-park-outline:analysis',
i18nTitle: 'message.routes.dashboard.analysis'
}
},
{
@@ -22,14 +23,16 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
meta: {
title: '工作台',
requiresAuth: true,
icon: 'icon-park-outline:workbench'
icon: 'icon-park-outline:workbench',
i18nTitle: 'message.routes.dashboard.workbench'
}
}
],
meta: {
title: '仪表盘',
icon: 'mdi:monitor-dashboard',
order: 1
order: 1,
i18nTitle: 'message.routes.dashboard._value'
}
},
{
@@ -43,6 +46,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: 'vue文档',
i18nTitle: 'message.routes.document.vue',
requiresAuth: true,
icon: 'logos:vue'
}
@@ -53,6 +57,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: 'vite文档',
i18nTitle: 'message.routes.document.vite',
requiresAuth: true,
icon: 'logos:vitejs'
}
@@ -63,6 +68,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: 'naive文档',
i18nTitle: 'message.routes.document.naive',
requiresAuth: true,
icon: 'logos:naiveui'
}
@@ -73,6 +79,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '项目文档',
i18nTitle: 'message.routes.document.project',
requiresAuth: true,
localIcon: 'logo'
}
@@ -82,6 +89,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
path: '/document/project-link',
meta: {
title: '项目文档(外链)',
i18nTitle: 'message.routes.document.project-link',
requiresAuth: true,
localIcon: 'logo',
href: 'https://docs.soybean.pro/'
@@ -90,6 +98,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
],
meta: {
title: '文档',
i18nTitle: 'message.routes.document._value',
icon: 'mdi:file-document-multiple-outline',
order: 2
}
@@ -105,6 +114,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '按钮',
i18nTitle: 'message.routes.component.button',
requiresAuth: true,
icon: 'mdi:button-cursor'
}
@@ -115,6 +125,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '卡片',
i18nTitle: 'message.routes.component.card',
requiresAuth: true,
icon: 'mdi:card-outline'
}
@@ -125,6 +136,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '表格',
i18nTitle: 'message.routes.component.table',
requiresAuth: true,
icon: 'mdi:table-large'
}
@@ -132,6 +144,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
],
meta: {
title: '组件示例',
i18nTitle: 'message.routes.component._value',
icon: 'cib:app-store',
order: 3
}
@@ -152,6 +165,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: 'ECharts',
i18nTitle: 'message.routes.plugin.charts.echarts',
requiresAuth: true,
icon: 'simple-icons:apacheecharts'
}
@@ -162,6 +176,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: 'AntV',
i18nTitle: 'message.routes.plugin.charts.antv',
requiresAuth: true,
icon: 'simple-icons:antdesign'
}
@@ -169,6 +184,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
],
meta: {
title: '图表',
i18nTitle: 'message.routes.plugin.charts._value',
icon: 'mdi:chart-areaspline'
}
},
@@ -178,6 +194,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '地图',
i18nTitle: 'message.routes.plugin.map',
requiresAuth: true,
icon: 'mdi:map'
}
@@ -188,6 +205,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '视频',
i18nTitle: 'message.routes.plugin.video',
requiresAuth: true,
icon: 'mdi:video'
}
@@ -203,6 +221,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '富文本编辑器',
i18nTitle: 'message.routes.plugin.editor.quill',
requiresAuth: true,
icon: 'mdi:file-document-edit-outline'
}
@@ -213,6 +232,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: 'markdown编辑器',
i18nTitle: 'message.routes.plugin.editor.markdown',
requiresAuth: true,
icon: 'ri:markdown-line'
}
@@ -220,6 +240,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
],
meta: {
title: '编辑器',
i18nTitle: 'message.routes.plugin.editor._value',
icon: 'icon-park-outline:editor'
}
},
@@ -229,6 +250,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: 'Swiper插件',
i18nTitle: 'message.routes.plugin.swiper',
requiresAuth: true,
icon: 'simple-icons:swiper'
}
@@ -239,6 +261,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '剪贴板',
i18nTitle: 'message.routes.plugin.copy',
requiresAuth: true,
icon: 'mdi:clipboard-outline'
}
@@ -249,6 +272,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '图标',
i18nTitle: 'message.routes.plugin.icon',
requiresAuth: true,
localIcon: 'custom-icon'
}
@@ -259,6 +283,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '打印',
i18nTitle: 'message.routes.plugin.print',
requiresAuth: true,
icon: 'mdi:printer'
}
@@ -266,6 +291,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
],
meta: {
title: '插件示例',
i18nTitle: 'message.routes.plugin._value',
icon: 'clarity:plugin-line',
order: 4
}
@@ -281,6 +307,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '权限切换',
i18nTitle: 'message.routes.auth-demo.permission',
requiresAuth: true,
icon: 'ic:round-construction'
}
@@ -291,6 +318,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '超级管理员可见',
i18nTitle: 'message.routes.auth-demo.super',
requiresAuth: true,
icon: 'ic:round-supervisor-account'
}
@@ -298,6 +326,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
],
meta: {
title: '权限示例',
i18nTitle: 'message.routes.auth-demo._value',
icon: 'ic:baseline-security',
order: 5
}
@@ -313,6 +342,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: 'Tab',
i18nTitle: 'message.routes.function.tab',
requiresAuth: true,
icon: 'ic:round-tab'
}
@@ -345,6 +375,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
],
meta: {
title: '功能',
i18nTitle: 'message.routes.function._value',
icon: 'icon-park-outline:all-application',
order: 6
}
@@ -360,6 +391,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '异常页403',
i18nTitle: 'message.routes.exception.403',
requiresAuth: true,
icon: 'ic:baseline-block'
}
@@ -370,6 +402,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '异常页404',
i18nTitle: 'message.routes.exception.404',
requiresAuth: true,
icon: 'ic:baseline-web-asset-off'
}
@@ -380,12 +413,14 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '异常页500',
i18nTitle: 'message.routes.exception.500',
requiresAuth: true,
icon: 'ic:baseline-wifi-off'
}
}
],
meta: {
i18nTitle: 'message.routes.exception._value',
title: '异常页',
icon: 'ant-design:exception-outlined',
order: 7
@@ -407,6 +442,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '二级菜单',
i18nTitle: 'message.routes.multi-menu.first.second',
requiresAuth: true,
icon: 'mdi:menu'
}
@@ -422,6 +458,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '三级菜单',
i18nTitle: 'message.routes.multi-menu.first.second-new.third',
requiresAuth: true,
icon: 'mdi:menu'
}
@@ -429,18 +466,21 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
],
meta: {
title: '二级菜单(有子菜单)',
i18nTitle: 'message.routes.multi-menu.first.second-new._value',
icon: 'mdi:menu'
}
}
],
meta: {
title: '一级菜单',
i18nTitle: 'message.routes.multi-menu.first._value',
icon: 'mdi:menu'
}
}
],
meta: {
title: '多级菜单',
i18nTitle: 'message.routes.multi-menu._value',
icon: 'carbon:menu',
order: 8
}
@@ -456,6 +496,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '权限管理',
i18nTitle: 'message.routes.management.auth',
requiresAuth: true,
icon: 'ic:baseline-security'
}
@@ -466,6 +507,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '角色管理',
i18nTitle: 'message.routes.management.role',
requiresAuth: true,
icon: 'carbon:user-role'
}
@@ -476,6 +518,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '用户管理',
i18nTitle: 'message.routes.management.user',
requiresAuth: true,
icon: 'ic:round-manage-accounts'
}
@@ -486,6 +529,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '路由管理',
i18nTitle: 'message.routes.management.route',
requiresAuth: true,
icon: 'material-symbols:route'
}
@@ -493,6 +537,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
],
meta: {
title: '系统管理',
i18nTitle: 'message.routes.management._value',
icon: 'carbon:cloud-service-management',
order: 9
}
@@ -503,7 +548,9 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '关于',
i18nTitle: 'message.routes.about',
requiresAuth: true,
keepAlive: true,
singleLayout: 'basic',
icon: 'fluent:book-information-24-regular',
order: 10
@@ -523,7 +570,8 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
meta: {
title: '分析页',
requiresAuth: true,
icon: 'icon-park-outline:analysis'
icon: 'icon-park-outline:analysis',
i18nTitle: 'message.routes.dashboard.analysis'
}
},
{
@@ -533,14 +581,16 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
meta: {
title: '工作台',
requiresAuth: true,
icon: 'icon-park-outline:workbench'
icon: 'icon-park-outline:workbench',
i18nTitle: 'message.routes.dashboard.workbench'
}
}
],
meta: {
title: '仪表盘',
icon: 'mdi:monitor-dashboard',
order: 1
order: 1,
i18nTitle: 'message.routes.dashboard._value'
}
},
{
@@ -554,6 +604,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: 'vue文档',
i18nTitle: 'message.routes.document.vue',
requiresAuth: true,
icon: 'logos:vue'
}
@@ -564,6 +615,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: 'vite文档',
i18nTitle: 'message.routes.document.vite',
requiresAuth: true,
icon: 'logos:vitejs'
}
@@ -574,6 +626,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: 'naive文档',
i18nTitle: 'message.routes.document.naive',
requiresAuth: true,
icon: 'logos:naiveui'
}
@@ -584,6 +637,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '项目文档',
i18nTitle: 'message.routes.document.project',
requiresAuth: true,
localIcon: 'logo'
}
@@ -593,6 +647,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
path: '/document/project-link',
meta: {
title: '项目文档(外链)',
i18nTitle: 'message.routes.document.project-link',
requiresAuth: true,
localIcon: 'logo',
href: 'https://docs.soybean.pro/'
@@ -601,6 +656,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
],
meta: {
title: '文档',
i18nTitle: 'message.routes.document._value',
icon: 'mdi:file-document-multiple-outline',
order: 2
}
@@ -616,6 +672,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '按钮',
i18nTitle: 'message.routes.component.button',
requiresAuth: true,
icon: 'mdi:button-cursor'
}
@@ -626,6 +683,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '卡片',
i18nTitle: 'message.routes.component.card',
requiresAuth: true,
icon: 'mdi:card-outline'
}
@@ -636,6 +694,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '表格',
i18nTitle: 'message.routes.component.table',
requiresAuth: true,
icon: 'mdi:table-large'
}
@@ -643,6 +702,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
],
meta: {
title: '组件示例',
i18nTitle: 'message.routes.component._value',
icon: 'cib:app-store',
order: 3
}
@@ -663,6 +723,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: 'ECharts',
i18nTitle: 'message.routes.plugin.charts.echarts',
requiresAuth: true,
icon: 'simple-icons:apacheecharts'
}
@@ -673,6 +734,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: 'AntV',
i18nTitle: 'message.routes.plugin.charts.antv',
requiresAuth: true,
icon: 'simple-icons:antdesign'
}
@@ -680,6 +742,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
],
meta: {
title: '图表',
i18nTitle: 'message.routes.plugin.charts._value',
icon: 'mdi:chart-areaspline'
}
},
@@ -689,6 +752,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '地图',
i18nTitle: 'message.routes.plugin.map',
requiresAuth: true,
icon: 'mdi:map'
}
@@ -699,6 +763,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '视频',
i18nTitle: 'message.routes.plugin.video',
requiresAuth: true,
icon: 'mdi:video'
}
@@ -714,6 +779,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '富文本编辑器',
i18nTitle: 'message.routes.plugin.editor.quill',
requiresAuth: true,
icon: 'mdi:file-document-edit-outline'
}
@@ -724,6 +790,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: 'markdown编辑器',
i18nTitle: 'message.routes.plugin.editor.markdown',
requiresAuth: true,
icon: 'ri:markdown-line'
}
@@ -731,6 +798,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
],
meta: {
title: '编辑器',
i18nTitle: 'message.routes.plugin.editor._value',
icon: 'icon-park-outline:editor'
}
},
@@ -740,6 +808,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: 'Swiper插件',
i18nTitle: 'message.routes.plugin.swiper',
requiresAuth: true,
icon: 'simple-icons:swiper'
}
@@ -750,6 +819,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '剪贴板',
i18nTitle: 'message.routes.plugin.copy',
requiresAuth: true,
icon: 'mdi:clipboard-outline'
}
@@ -760,6 +830,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '图标',
i18nTitle: 'message.routes.plugin.icon',
requiresAuth: true,
localIcon: 'custom-icon'
}
@@ -770,6 +841,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '打印',
i18nTitle: 'message.routes.plugin.print',
requiresAuth: true,
icon: 'mdi:printer'
}
@@ -777,6 +849,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
],
meta: {
title: '插件示例',
i18nTitle: 'message.routes.plugin._value',
icon: 'clarity:plugin-line',
order: 4
}
@@ -792,13 +865,26 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '权限切换',
i18nTitle: 'message.routes.auth-demo.permission',
requiresAuth: true,
icon: 'ic:round-construction'
}
},
{
name: 'auth-demo_super',
path: '/auth-demo/super',
component: 'self',
meta: {
title: '超级管理员可见',
i18nTitle: 'message.routes.auth-demo.super',
requiresAuth: true,
icon: 'ic:round-supervisor-account'
}
}
],
meta: {
title: '权限示例',
i18nTitle: 'message.routes.auth-demo._value',
icon: 'ic:baseline-security',
order: 5
}
@@ -814,6 +900,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: 'Tab',
i18nTitle: 'message.routes.function.tab',
requiresAuth: true,
icon: 'ic:round-tab'
}
@@ -846,6 +933,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
],
meta: {
title: '功能',
i18nTitle: 'message.routes.function._value',
icon: 'icon-park-outline:all-application',
order: 6
}
@@ -861,6 +949,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '异常页403',
i18nTitle: 'message.routes.exception.403',
requiresAuth: true,
icon: 'ic:baseline-block'
}
@@ -871,6 +960,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '异常页404',
i18nTitle: 'message.routes.exception.404',
requiresAuth: true,
icon: 'ic:baseline-web-asset-off'
}
@@ -881,12 +971,14 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '异常页500',
i18nTitle: 'message.routes.exception.500',
requiresAuth: true,
icon: 'ic:baseline-wifi-off'
}
}
],
meta: {
i18nTitle: 'message.routes.exception._value',
title: '异常页',
icon: 'ant-design:exception-outlined',
order: 7
@@ -908,6 +1000,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '二级菜单',
i18nTitle: 'message.routes.multi-menu.first.second',
requiresAuth: true,
icon: 'mdi:menu'
}
@@ -923,6 +1016,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '三级菜单',
i18nTitle: 'message.routes.multi-menu.first.second-new.third',
requiresAuth: true,
icon: 'mdi:menu'
}
@@ -930,18 +1024,21 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
],
meta: {
title: '二级菜单(有子菜单)',
i18nTitle: 'message.routes.multi-menu.first.second-new._value',
icon: 'mdi:menu'
}
}
],
meta: {
title: '一级菜单',
i18nTitle: 'message.routes.multi-menu.first._value',
icon: 'mdi:menu'
}
}
],
meta: {
title: '多级菜单',
i18nTitle: 'message.routes.multi-menu._value',
icon: 'carbon:menu',
order: 8
}
@@ -957,6 +1054,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '权限管理',
i18nTitle: 'message.routes.management.auth',
requiresAuth: true,
icon: 'ic:baseline-security'
}
@@ -967,6 +1065,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '角色管理',
i18nTitle: 'message.routes.management.role',
requiresAuth: true,
icon: 'carbon:user-role'
}
@@ -977,6 +1076,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '用户管理',
i18nTitle: 'message.routes.management.user',
requiresAuth: true,
icon: 'ic:round-manage-accounts'
}
@@ -987,6 +1087,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '路由管理',
i18nTitle: 'message.routes.management.route',
requiresAuth: true,
icon: 'material-symbols:route'
}
@@ -994,6 +1095,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
],
meta: {
title: '系统管理',
i18nTitle: 'message.routes.management._value',
icon: 'carbon:cloud-service-management',
order: 9
}
@@ -1004,7 +1106,9 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '关于',
i18nTitle: 'message.routes.about',
requiresAuth: true,
keepAlive: true,
singleLayout: 'basic',
icon: 'fluent:book-information-24-regular',
order: 10
@@ -1024,14 +1128,27 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
meta: {
title: '分析页',
requiresAuth: true,
icon: 'icon-park-outline:analysis'
icon: 'icon-park-outline:analysis',
i18nTitle: 'message.routes.dashboard.analysis'
}
},
{
name: 'dashboard_workbench',
path: '/dashboard/workbench',
component: 'self',
meta: {
title: '工作台',
requiresAuth: true,
icon: 'icon-park-outline:workbench',
i18nTitle: 'message.routes.dashboard.workbench'
}
}
],
meta: {
title: '仪表盘',
icon: 'mdi:monitor-dashboard',
order: 1
order: 1,
i18nTitle: 'message.routes.dashboard._value'
}
},
{
@@ -1045,13 +1162,26 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '权限切换',
i18nTitle: 'message.routes.auth-demo.permission',
requiresAuth: true,
icon: 'ic:round-construction'
}
},
{
name: 'auth-demo_super',
path: '/auth-demo/super',
component: 'self',
meta: {
title: '超级管理员可见',
i18nTitle: 'message.routes.auth-demo.super',
requiresAuth: true,
icon: 'ic:round-supervisor-account'
}
}
],
meta: {
title: '权限示例',
i18nTitle: 'message.routes.auth-demo._value',
icon: 'ic:baseline-security',
order: 5
}
@@ -1072,6 +1202,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '二级菜单',
i18nTitle: 'message.routes.multi-menu.first.second',
requiresAuth: true,
icon: 'mdi:menu'
}
@@ -1087,6 +1218,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '三级菜单',
i18nTitle: 'message.routes.multi-menu.first.second-new.third',
requiresAuth: true,
icon: 'mdi:menu'
}
@@ -1094,20 +1226,23 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
],
meta: {
title: '二级菜单(有子菜单)',
i18nTitle: 'message.routes.multi-menu.first.second-new._value',
icon: 'mdi:menu'
}
}
],
meta: {
title: '一级菜单',
i18nTitle: 'message.routes.multi-menu.first._value',
icon: 'mdi:menu'
}
}
],
meta: {
title: '多级菜单',
i18nTitle: 'message.routes.multi-menu._value',
icon: 'carbon:menu',
order: 7
order: 8
}
},
{
@@ -1116,10 +1251,12 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self',
meta: {
title: '关于',
i18nTitle: 'message.routes.about',
requiresAuth: true,
keepAlive: true,
singleLayout: 'basic',
icon: 'fluent:book-information-24-regular',
order: 8
order: 10
}
}
]

View File

@@ -1,6 +1,6 @@
{
"name": "soybean-admin",
"version": "0.9.9",
"version": "0.10.3",
"description": "A fresh and elegant admin template, based on Vue3、Vite3、TypeScript、NaiveUI and UnoCSS. 一个基于Vue3、Vite3、TypeScript、NaiveUI and UnoCSS的清新优雅的中后台模版。",
"author": {
"name": "Soybean",
@@ -38,92 +38,88 @@
"dev": "cross-env VITE_SERVICE_ENV=dev vite",
"dev:test": "cross-env VITE_SERVICE_ENV=test vite",
"dev:prod": "cross-env VITE_SERVICE_ENV=prod vite",
"dev:tauri": "pnpm tauri dev",
"build": "npm run typecheck && cross-env VITE_SERVICE_ENV=prod vite build",
"build:dev": "npm run typecheck && cross-env VITE_SERVICE_ENV=dev vite build",
"build:test": "npm run typecheck && cross-env VITE_SERVICE_ENV=test vite build",
"build:vercel": "cross-env VITE_HASH_ROUTE=Y VITE_VERCEL=Y vite build",
"build:tauri": "pnpm tauri build",
"tauri-icon": "pnpm tauri icon ./public/logo.png",
"preview": "vite preview",
"typecheck": "vue-tsc --noEmit --skipLibCheck",
"lint": "eslint . --fix --ext .js,.jsx,.mjs,.json,.ts,.tsx,.vue",
"format": "soy prettier-format",
"lint": "eslint . --fix",
"format": "soy prettier-write",
"commit": "soy git-commit",
"cleanup": "soy cleanup",
"update-pkg": "soy update-pkg",
"update-pkg": "soy ncu",
"release": "soy release",
"tsx": "tsx",
"logo": "tsx ./scripts/logo.ts",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
"release": "standard-version",
"prepare": "soy init-git-hooks"
"prepare": "soy init-simple-git-hooks"
},
"dependencies": {
"@ant-design/icons-vue": "^6.1.0",
"@fast-crud/fast-crud": "^1.13.6",
"@fast-crud/fast-extends": "^1.13.6",
"@fast-crud/ui-naive": "^1.13.6",
"@fast-crud/ui-interface": "^1.13.6",
"@antv/data-set": "^0.11.8",
"@antv/g2": "^4.2.10",
"@better-scroll/core": "^2.5.1",
"@soybeanjs/vue-materials": "^0.1.9",
"@vueuse/core": "^10.1.2",
"@antv/data-set": "0.11.8",
"@antv/g2": "4.2.10",
"@better-scroll/core": "2.5.1",
"@soybeanjs/vue-materials": "0.2.0",
"@vueuse/core": "10.1.2",
"axios": "1.4.0",
"clipboard": "^2.0.11",
"colord": "^2.9.3",
"crypto-js": "^4.1.1",
"dayjs": "^1.11.7",
"echarts": "^5.4.2",
"form-data": "^4.0.0",
"lodash-es": "^4.17.21",
"clipboard": "2.0.11",
"colord": "2.9.3",
"crypto-js": "4.1.1",
"dayjs": "1.11.8",
"echarts": "5.4.2",
"form-data": "4.0.0",
"lodash-es": "4.17.21",
"naive-ui": "2.34.4",
"pinia": "^2.1.3",
"print-js": "^1.6.0",
"qs": "^6.11.2",
"swiper": "^9.3.2",
"ua-parser-js": "^1.0.35",
"vditor": "^3.9.2",
"pinia": "2.1.4",
"print-js": "1.6.0",
"qs": "6.11.2",
"swiper": "9.4.1",
"ua-parser-js": "1.0.35",
"vditor": "3.9.3",
"vue": "3.3.4",
"vue-i18n": "^9.2.2",
"vue-router": "^4.2.1",
"vuedraggable": "^4.1.0",
"wangeditor": "^4.7.15",
"xgplayer": "^3.0.2"
"vue-i18n": "9.2.2",
"vue-router": "4.2.2",
"vuedraggable": "4.1.0",
"wangeditor": "4.7.15",
"xgplayer": "3.0.4"
},
"devDependencies": {
"@amap/amap-jsapi-types": "^0.0.13",
"@iconify/json": "^2.2.67",
"@iconify/vue": "^4.1.1",
"@soybeanjs/cli": "^0.1.9",
"@soybeanjs/vite-plugin-vue-page-route": "^0.0.5",
"@types/bmapgl": "^0.0.7",
"@types/crypto-js": "^4.1.1",
"@types/node": "20.2.1",
"@types/qs": "^6.9.7",
"@types/ua-parser-js": "^0.7.36",
"@unocss/preset-uno": "^0.52.0",
"@unocss/transformer-directives": "^0.52.0",
"@unocss/vite": "^0.52.0",
"@vitejs/plugin-vue": "^4.2.3",
"@vitejs/plugin-vue-jsx": "^3.0.1",
"conventional-changelog": "^3.1.25",
"cross-env": "^7.0.3",
"eslint": "^8.41.0",
"eslint-config-soybeanjs": "^0.3.7",
"lint-staged": "13.2.2",
"mockjs": "^1.1.0",
"rollup-plugin-visualizer": "^5.9.0",
"sass": "^1.62.1",
"simple-git-hooks": "^2.8.1",
"standard-version": "^9.5.0",
"tsx": "^3.12.7",
"typescript": "5.0.4",
"unplugin-icons": "^0.16.1",
"unplugin-vue-components": "0.24.1",
"vite": "^4.3.8",
"vite-plugin-compression": "^0.5.1",
"@amap/amap-jsapi-types": "0.0.13",
"@iconify/json": "2.2.78",
"@iconify/vue": "4.1.1",
"@soybeanjs/cli": "0.6.2",
"@soybeanjs/vite-plugin-vue-page-route": "0.0.5",
"@tauri-apps/cli": "^1.3.1",
"@types/bmapgl": "0.0.7",
"@types/crypto-js": "4.1.1",
"@types/node": "20.3.1",
"@types/qs": "6.9.7",
"@types/ua-parser-js": "0.7.36",
"@unocss/preset-uno": "0.53.1",
"@unocss/transformer-directives": "0.53.1",
"@unocss/vite": "0.53.1",
"@vitejs/plugin-vue": "4.2.3",
"@vitejs/plugin-vue-jsx": "3.0.1",
"cross-env": "7.0.3",
"eslint": "8.42.0",
"eslint-config-soybeanjs": "0.4.9",
"mockjs": "1.1.0",
"rollup-plugin-visualizer": "5.9.2",
"sass": "1.63.4",
"simple-git-hooks": "2.8.1",
"tsx": "3.12.7",
"typescript": "5.1.3",
"unplugin-icons": "0.16.3",
"unplugin-vue-components": "0.25.1",
"vite": "4.3.9",
"vite-plugin-compression": "0.5.1",
"vite-plugin-mock": "2.9.8",
"vite-plugin-progress": "^0.0.7",
"vite-plugin-pwa": "^0.15.0",
"vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-progress": "0.0.7",
"vite-plugin-pwa": "0.16.4",
"vite-plugin-svg-icons": "2.0.1",
"vite-plugin-vue-devtools": "0.2.0",
"vue-tsc": "1.6.5"
},
"pnpm": {
@@ -133,9 +129,9 @@
},
"simple-git-hooks": {
"commit-msg": "pnpm soy git-commit-verify",
"pre-commit": "pnpm typecheck && pnpm lint-staged"
"pre-commit": "pnpm typecheck && pnpm lint"
},
"lint-staged": {
"*.{js,jsx,mjs,json,ts,tsx,vue}": "eslint . --fix"
"soybean": {
"useSoybeanToken": true
}
}

7976
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

3
src-tauri/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
# Generated by Cargo
# will have compiled files and executables
/target/

4302
src-tauri/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

28
src-tauri/Cargo.toml Normal file
View File

@@ -0,0 +1,28 @@
[package]
name = "app"
version = "0.1.0"
description = "A Tauri App"
authors = ["you"]
license = ""
repository = ""
default-run = "app"
edition = "2021"
rust-version = "1.57"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]
tauri-build = { version = "1.1.1", features = [] }
[dependencies]
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
tauri = { version = "1.1.1", features = ["api-all"] }
[features]
# by default Tauri runs in production mode
# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
default = [ "custom-protocol" ]
# this feature is used for production builds where `devPath` points to the filesystem
# DO NOT remove this
custom-protocol = [ "tauri/custom-protocol" ]

3
src-tauri/build.rs Normal file
View File

@@ -0,0 +1,3 @@
fn main() {
tauri_build::build()
}

BIN
src-tauri/icons/128x128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
src-tauri/icons/32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
src-tauri/icons/icon.icns Normal file

Binary file not shown.

BIN
src-tauri/icons/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
src-tauri/icons/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

10
src-tauri/src/main.rs Normal file
View File

@@ -0,0 +1,10 @@
#![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]
fn main() {
tauri::Builder::default()
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

60
src-tauri/tauri.conf.json Normal file
View File

@@ -0,0 +1,60 @@
{
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
"build": {
"beforeBuildCommand": "npm run build",
"beforeDevCommand": "npm run dev",
"devPath": "http://localhost:3200",
"distDir": "../dist"
},
"package": {
"productName": "soybean-admin",
"version": "0.1.0"
},
"tauri": {
"allowlist": {
"all": true
},
"bundle": {
"active": true,
"category": "DeveloperTool",
"copyright": "",
"deb": {
"depends": []
},
"externalBin": [],
"icon": ["icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico"],
"identifier": "cn.soybeanjs.tauri-admin",
"longDescription": "",
"macOS": {
"entitlements": null,
"exceptionDomain": "",
"frameworks": [],
"providerShortName": null,
"signingIdentity": null
},
"resources": [],
"shortDescription": "",
"targets": "all",
"windows": {
"certificateThumbprint": null,
"digestAlgorithm": "sha256",
"timestampUrl": ""
}
},
"security": {
"csp": null
},
"updater": {
"active": false
},
"windows": [
{
"fullscreen": false,
"height": 800,
"resizable": true,
"title": "soybean-admin",
"width": 1000
}
]
}
}

View File

@@ -7,34 +7,20 @@
class="h-full"
>
<naive-provider>
<fs-ui-context>
<router-view />
</fs-ui-context>
<router-view />
</naive-provider>
</n-config-provider>
</template>
<script setup lang="ts">
import { watch } from 'vue';
import { useRoute } from 'vue-router';
import { dateZhCN, zhCN } from 'naive-ui';
import { useI18n } from 'vue-i18n';
import { subscribeStore, useThemeStore } from '@/store';
import { useGlobalEvents } from '@/composables';
const theme = useThemeStore();
const { locale, t } = useI18n();
const route = useRoute();
subscribeStore();
useGlobalEvents();
watch(
() => locale.value,
() => {
document.title = route.meta.i18nTitle ? t(route.meta.i18nTitle) : route.meta.title;
}
);
</script>
<style scoped></style>

View File

@@ -1,14 +1,34 @@
import { effectScope, onScopeDispose, watch } from 'vue';
import { useRoute } from 'vue-router';
import { useEventListener } from '@vueuse/core';
import { useI18n } from 'vue-i18n';
import { useTabStore, useThemeStore } from '@/store';
/** 全局事件 */
export function useGlobalEvents() {
const theme = useThemeStore();
const tab = useTabStore();
const route = useRoute();
const { locale, t } = useI18n();
const scope = effectScope();
/** 页面离开时缓存多页签数据 */
useEventListener(window, 'beforeunload', () => {
theme.cacheThemeSettings();
tab.cacheTabRoutes();
});
scope.run(() => {
// 国际化切换时更新浏览器标签文本
watch(
() => locale.value,
() => {
document.title = route.meta.i18nTitle ? t(route.meta.i18nTitle) : route.meta.title;
}
);
});
onScopeDispose(() => {
scope.stop();
});
}

View File

@@ -1,5 +1,5 @@
import { h } from 'vue';
import SvgIcon from '~/src/components/custom/svg-icon.vue';
import SvgIcon from '@/components/custom/svg-icon.vue';
/**
* 图标渲染

View File

@@ -1,4 +1,4 @@
import { computed } from 'vue';
import { computed, watch } from 'vue';
import { breakpointsTailwind, useBreakpoints } from '@vueuse/core';
import { useAppStore, useThemeStore } from '@/store';
@@ -63,6 +63,16 @@ export function useBasicLayout() {
return w;
});
watch(
isMobile,
newValue => {
if (newValue) {
app.setSiderCollapse(true);
}
},
{ immediate: true }
);
return {
mode,
isMobile,

6
src/constants/_shared.ts Normal file
View File

@@ -0,0 +1,6 @@
export function transformObjectToOption<T extends object>(obj: T) {
return Object.entries(obj).map(([value, label]) => ({
value,
label
})) as Common.OptionWithKey<keyof T>[];
}

View File

@@ -1,3 +1,5 @@
import { transformObjectToOption } from './_shared';
export const loginModuleLabels: Record<UnionKey.LoginModule, string> = {
'pwd-login': '账密登录',
'code-login': '手机验证码登录',
@@ -11,23 +13,14 @@ export const userRoleLabels: Record<Auth.RoleType, string> = {
admin: '管理员',
user: '普通用户'
};
export const userRoleOptions: Common.OptionWithKey<Auth.RoleType>[] = [
{ value: 'super', label: userRoleLabels.super },
{ value: 'admin', label: userRoleLabels.admin },
{ value: 'user', label: userRoleLabels.user }
];
export const userRoleOptions = transformObjectToOption(userRoleLabels);
/** 用户性别 */
export const genderLabels: Record<UserManagement.GenderKey, string> = {
0: '女',
1: '男'
};
export const genderOptions: Common.OptionWithKey<UserManagement.GenderKey>[] = [
{ value: '0', label: genderLabels['0'] },
{ value: '1', label: genderLabels['1'] }
];
export const genderOptions = transformObjectToOption(genderLabels);
/** 用户状态 */
export const userStatusLabels: Record<UserManagement.UserStatusKey, string> = {
@@ -36,10 +29,4 @@ export const userStatusLabels: Record<UserManagement.UserStatusKey, string> = {
3: '冻结',
4: '软删除'
};
export const userStatusOptions: Common.OptionWithKey<UserManagement.UserStatusKey>[] = [
{ value: '1', label: userStatusLabels['1'] },
{ value: '2', label: userStatusLabels['2'] },
{ value: '3', label: userStatusLabels['3'] },
{ value: '4', label: userStatusLabels['4'] }
];
export const userStatusOptions = transformObjectToOption(userStatusLabels);

View File

@@ -1,81 +1,31 @@
import { transformObjectToOption } from './_shared';
export const themeLayoutModeLabels: Record<UnionKey.ThemeLayoutMode, string> = {
vertical: '左侧菜单模式',
horizontal: '顶部菜单模式',
'vertical-mix': '左侧菜单混合模式',
'horizontal-mix': '顶部菜单混合模式'
};
export const themeLayoutModeOptions: Common.OptionWithKey<UnionKey.ThemeLayoutMode>[] = [
{
value: 'vertical',
label: themeLayoutModeLabels.vertical
},
{
value: 'horizontal',
label: themeLayoutModeLabels.horizontal
},
{
value: 'vertical-mix',
label: themeLayoutModeLabels['vertical-mix']
},
{
value: 'horizontal-mix',
label: themeLayoutModeLabels['horizontal-mix']
}
];
export const themeLayoutModeOptions = transformObjectToOption(themeLayoutModeLabels);
export const themeScrollModeLabels: Record<UnionKey.ThemeScrollMode, string> = {
wrapper: '外层滚动',
content: '主体滚动'
};
export const themeScrollModeOptions: Common.OptionWithKey<UnionKey.ThemeScrollMode>[] = [
{
value: 'wrapper',
label: themeScrollModeLabels.wrapper
},
{
value: 'content',
label: themeScrollModeLabels.content
}
];
export const themeScrollModeOptions = transformObjectToOption(themeScrollModeLabels);
export const themeTabModeLabels: Record<UnionKey.ThemeTabMode, string> = {
chrome: '谷歌风格',
button: '按钮风格'
};
export const themeTabModeOptions: Common.OptionWithKey<UnionKey.ThemeTabMode>[] = [
{
value: 'chrome',
label: themeTabModeLabels.chrome
},
{
value: 'button',
label: themeTabModeLabels.button
}
];
export const themeTabModeOptions = transformObjectToOption(themeTabModeLabels);
export const themeHorizontalMenuPositionLabels: Record<UnionKey.ThemeHorizontalMenuPosition, string> = {
'flex-start': '居左',
center: '居中',
'flex-end': '居右'
};
export const themeHorizontalMenuPositionOptions: Common.OptionWithKey<UnionKey.ThemeHorizontalMenuPosition>[] = [
{
value: 'flex-start',
label: themeHorizontalMenuPositionLabels['flex-start']
},
{
value: 'center',
label: themeHorizontalMenuPositionLabels.center
},
{
value: 'flex-end',
label: themeHorizontalMenuPositionLabels['flex-end']
}
];
export const themeHorizontalMenuPositionOptions = transformObjectToOption(themeHorizontalMenuPositionLabels);
export const themeAnimateModeLabels: Record<UnionKey.ThemeAnimateMode, string> = {
'zoom-fade': '渐变',
@@ -85,30 +35,4 @@ export const themeAnimateModeLabels: Record<UnionKey.ThemeAnimateMode, string> =
'fade-bottom': '底部消退',
'fade-scale': '缩放消退'
};
export const themeAnimateModeOptions: Common.OptionWithKey<UnionKey.ThemeAnimateMode>[] = [
{
value: 'zoom-fade',
label: themeAnimateModeLabels['zoom-fade']
},
{
value: 'zoom-out',
label: themeAnimateModeLabels['zoom-out']
},
{
value: 'fade-slide',
label: themeAnimateModeLabels['fade-slide']
},
{
value: 'fade',
label: themeAnimateModeLabels.fade
},
{
value: 'fade-bottom',
label: themeAnimateModeLabels['fade-bottom']
},
{
value: 'fade-scale',
label: themeAnimateModeLabels['fade-scale']
}
];
export const themeAnimateModeOptions = transformObjectToOption(themeAnimateModeLabels);

View File

@@ -1,6 +1,7 @@
<template>
<admin-layout
:mode="mode"
:is-mobile="isMobile"
:scroll-mode="theme.scrollMode"
:scroll-el-id="app.scrollElId"
:full-content="app.contentFull"
@@ -16,6 +17,7 @@
:footer-visible="theme.footer.visible"
:fixed-footer="theme.footer.fixed"
:right-footer="theme.footer.right"
@click-mobile-sider-mask="app.setSiderCollapse(true)"
>
<template #header>
<global-header v-bind="headerProps" />
@@ -46,7 +48,7 @@ defineOptions({ name: 'BasicLayout' });
const app = useAppStore();
const theme = useThemeStore();
const { mode, headerProps, siderVisible, siderWidth, siderCollapsedWidth } = useBasicLayout();
const { mode, isMobile, headerProps, siderVisible, siderWidth, siderCollapsedWidth } = useBasicLayout();
</script>
<style lang="scss">

View File

@@ -9,7 +9,7 @@
v-if="theme.header.crumb.showIcon"
class="inline-block align-text-bottom mr-4px text-16px"
/>
<span>{{ breadcrumb.i18nTitle ? t(breadcrumb.i18nTitle) : breadcrumb.label }}</span>
<span>{{ breadcrumb.label }}</span>
</span>
</n-dropdown>
<template v-else>
@@ -19,9 +19,9 @@
class="inline-block align-text-bottom mr-4px text-16px"
:class="{ 'text-#BBBBBB': theme.header.inverted }"
/>
<span :class="{ 'text-#BBBBBB': theme.header.inverted }">{{
breadcrumb.i18nTitle ? t(breadcrumb.i18nTitle) : breadcrumb.label
}}</span>
<span :class="{ 'text-#BBBBBB': theme.header.inverted }">
{{ breadcrumb.label }}
</span>
</template>
</n-breadcrumb-item>
</template>
@@ -45,7 +45,13 @@ const routeStore = useRouteStore();
const { routerPush } = useRouterPush();
const breadcrumbs = computed(() =>
getBreadcrumbByRouteKey(route.name as string, routeStore.menus as App.GlobalMenuOption[], routePath('root'))
getBreadcrumbByRouteKey(route.name as string, routeStore.menus as App.GlobalMenuOption[], routePath('root')).map(
item => ({
...item,
label: item.i18nTitle ? t(item.i18nTitle) : item.label,
options: item.options?.map(oItem => ({ ...oItem, label: oItem.i18nTitle ? t(oItem.i18nTitle) : oItem.label }))
})
)
);
function dropdownSelect(key: string) {

View File

@@ -1,5 +1,5 @@
<template>
<hover-container class="w-40px h-full">
<hover-container class="w-40px h-full" :inverted="theme.header.inverted">
<n-dropdown :options="options" trigger="hover" :value="language" @select="handleSelect">
<icon-cil:language class="text-18px outline-transparent" />
</n-dropdown>
@@ -9,8 +9,10 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useThemeStore } from '@/store';
import { localStg } from '@/utils';
const theme = useThemeStore();
const { locale } = useI18n();
const language = ref<I18nType.langType>(localStg.get('lang') || 'zh-CN');
@@ -22,6 +24,10 @@ const options = [
{
label: 'English',
key: 'en'
},
{
label: 'ភាសាខ្មែរ',
key: 'km-KH'
}
];
const handleSelect = (key: string) => {

View File

@@ -6,7 +6,7 @@
>
<component :is="icon" :class="[isMini ? 'text-16px' : 'text-20px']" />
<p
class="text-12px overflow-hidden transition-height duration-300 ease-in-out"
class="w-full text-center ellipsis-text text-12px transition-height duration-300 ease-in-out"
:class="[isMini ? 'h-0 pt-0' : 'h-24px pt-4px']"
>
{{ label }}

View File

@@ -1,6 +1,6 @@
<template>
<dark-mode-container class="flex h-full" :inverted="theme.sider.inverted" @mouseleave="resetFirstDegreeMenus">
<div class="flex-1 flex-col-stretch h-full">
<div class="flex-1-hidden flex-col-stretch h-full">
<global-logo :show-title="false" :style="{ height: theme.header.height + 'px' }" />
<n-scrollbar class="flex-1-hidden">
<mix-menu-detail

View File

@@ -1,6 +1,6 @@
<template>
<div ref="tabRef" class="flex h-full pr-18px" :class="[isChromeMode ? 'items-end' : 'items-center gap-12px']">
<AdminTab
<PageTab
v-for="item in tab.tabs"
:key="item.fullPath"
:mode="theme.tab.mode"
@@ -20,7 +20,7 @@
/>
</template>
{{ item.meta.i18nTitle ? t(item.meta.i18nTitle) : item.meta.title }}
</AdminTab>
</PageTab>
</div>
<context-menu
:visible="dropdown.visible"
@@ -34,7 +34,7 @@
<script setup lang="ts">
import { computed, nextTick, reactive, ref, watch } from 'vue';
import { AdminTab } from '@soybeanjs/vue-materials';
import { PageTab } from '@soybeanjs/vue-materials';
import { useTabStore, useThemeStore } from '@/store';
import { t } from '@/locales';
import { ContextMenu } from './components';

View File

@@ -7,7 +7,7 @@ const locale: LocaleMessages<I18nType.Schema> = {
},
routes: {
dashboard: {
dashboard: 'Dashboard',
_value: 'Dashboard',
analysis: 'Analysis',
workbench: 'Workbench'
},

View File

@@ -1,9 +1,11 @@
import zhCN from './zh-cn';
import en from './en';
import kmKH from './km-KH';
const locales = {
'zh-CN': zhCN,
en
en,
'km-KH': kmKH
};
export type LocaleKey = keyof typeof locales;

85
src/locales/lang/km-KH.ts Normal file
View File

@@ -0,0 +1,85 @@
import type { LocaleMessages } from 'vue-i18n';
const locale: LocaleMessages<I18nType.Schema> = {
message: {
system: {
title: 'ប្រព័ន្ធគ្រប់គ្រង'
},
routes: {
dashboard: {
_value: 'ផ្ទាំងទិន្នន័យ',
analysis: 'ផ្ទាំងវិភាគ',
workbench: 'ផ្ទាំងការងារ'
},
document: {
_value: 'ឯកសារ',
vue: 'ឯកសារ​ Vue',
vite: 'ឯកសារ​ Vite',
naive: 'ឯកសារ NaiveUI',
project: 'ឯកសារគម្រោង',
'project-link': 'ឯកសារគម្រោង(href)'
},
component: {
_value: 'សមាស​ភាគ',
button: 'ប៊ូតុង',
card: 'កាត',
table: 'តារាង'
},
plugin: {
_value: 'មុខងារជំនួយ',
charts: {
_value: 'តារាង​ Chart',
echarts: 'តារាង ECharts',
antv: 'AntV'
},
copy: 'ចម្លង',
editor: {
_value: 'កែប្រែ',
quill: 'Quill',
markdown: 'Markdown'
},
icon: 'អាយខន',
map: 'ផែនទី',
print: 'បោះពុម្ភ',
swiper: 'Swiper',
video: 'វីដេអូ'
},
'auth-demo': {
_value: 'ឌីមូ Auth',
permission: 'បិទ/បើកការអនុញ្ញាត',
super: 'Super Auth'
},
function: {
_value: 'មុខងារ',
tab: 'ថេបប្រព័ន្ធ'
},
exception: {
_value: 'ករណីពិេសស',
403: '403',
404: '404',
500: '500'
},
'multi-menu': {
_value: 'ម៉ឺនុយពហុដឺក្រេ',
first: {
_value: 'ដឺក្រេទី១',
second: 'ដែក្រេទី២',
'second-new': {
_value: 'ដឺក្រេទី២មានអនុក្រោម',
third: 'ដឺក្រេទី៣'
}
}
},
management: {
_value: 'ការគ្រប់គ្រងប្រព័ន្ធ',
auth: 'Auth',
role: 'សិទ្ធី',
route: 'ផ្លូវប្រព័ន្ធ',
user: 'អ្នកប្រើប្រាស់'
},
about: 'អំពីប្រព័ន្ធ'
}
}
};
export default locale;

View File

@@ -7,7 +7,7 @@ const locale: LocaleMessages<I18nType.Schema> = {
},
routes: {
dashboard: {
dashboard: '仪表盘',
_value: '仪表盘',
analysis: '分析页',
workbench: '工作台'
},

View File

@@ -3,7 +3,7 @@ import App from './App.vue';
import AppLoading from './components/common/app-loading.vue';
import { setupDirectives } from './directives';
import { setupRouter } from './router';
import { setupAssets, setupFastCrud } from './plugins';
import { setupAssets } from './plugins';
import { setupStore } from './store';
import { setupI18n } from './locales';
@@ -29,7 +29,7 @@ async function setupApp() {
setupI18n(app);
setupFastCrud(app);
appLoading.unmount();
// mount app
app.mount('#app');

View File

@@ -1,11 +0,0 @@
html:root {
--baseColor: #fff;
}
/* 深色模式 */
html.dark:root {
--baseColor: #000;
}
.fs-container {
background-color: var(--baseColor);
}

View File

@@ -1,171 +0,0 @@
import type { App } from 'vue';
import type { FsSetupOptions, PageQuery } from '@fast-crud/fast-crud';
// eslint-disable-next-line import/order
import { FastCrud } from '@fast-crud/fast-crud';
import '@fast-crud/fast-crud/dist/style.css';
import './common.scss';
import type { FsUploaderOptions } from '@fast-crud/fast-extends';
import {
FsExtendsCopyable,
FsExtendsEditor,
FsExtendsJson,
FsExtendsTime,
FsExtendsUploader
} from '@fast-crud/fast-extends';
import '@fast-crud/fast-extends/dist/style.css';
import UiNaive from '@fast-crud/ui-naive';
import axios from 'axios';
import type { VueI18n } from 'vue-i18n';
import { mockRequest, request } from '@/service/request';
import { setupNaive } from '@/plugins/fast-crud/naive';
/**
* fast-crud的安装方法
* 注意在App.vue中需要用fs-ui-context组件包裹RouterView让fs-crud拥有message、notification、dialog的能力
* @param app
* @param options
*/
export type FsSetupOpts = {
i18n?: VueI18n;
};
function install(app: App, options: FsSetupOpts = {}) {
// 安装naive ui 常用组件
setupNaive(app);
app.use(UiNaive);
app.use(FastCrud, {
i18n: options.i18n,
async dictRequest(context: { url: string }) {
const url = context.url;
let res: Service.SuccessResult | Service.FailedResult;
if (url && url.startsWith('/mock')) {
// 如果是crud开头的dict请求视为mock
res = await mockRequest.get(url.replace('/mock', ''));
} else {
res = await request.get(url);
}
res = res || {};
return res.data || [];
},
/**
* useCrud时会被执行
*/
commonOptions() {
return {
table: {
size: 'small',
pagination: false
},
search: {
options: {
size: 'medium'
}
},
rowHandle: {
buttons: {
view: { text: null, icon: 'EyeOutlined', size: 'small' },
edit: { text: null, icon: 'EditOutlined', size: 'small' },
remove: { type: 'error', text: null, icon: 'DeleteOutlined', size: 'small' }
},
dropdown: {
more: { size: 'small' }
}
},
request: {
// 查询参数转换
transformQuery: (query: PageQuery) => {
const { page, form, sort } = query;
const limit = page.pageSize;
const currentPage = page.currentPage ?? 1;
const offset = limit * (currentPage - 1);
return {
page: {
limit,
offset
},
query: form,
sort: sort || {}
};
},
// page请求结果转换
transformRes: originPageRes => {
const { res } = originPageRes;
const pageSize = res.limit;
let currentPage = res.offset / pageSize;
if (res.offset % pageSize === 0) {
currentPage += 1;
}
return { currentPage, pageSize, ...res };
}
},
form: {
display: 'flex', // 表单布局
labelWidth: '120px' // 表单label宽度
}
};
// 从 useCrud({permission}) 里获取permission参数去设置各个按钮的权限
// const crudPermission = useCrudPermission(context);
// return crudPermission.merge(opts);
}
} as FsSetupOptions);
// fast-extends里面的扩展组件均为异步组件只有在使用时才会被加载并不会影响首页加载速度
// 安装editor
app.use(FsExtendsEditor, {
// 编辑器的公共配置
wangEditor: {}
});
app.use(FsExtendsJson);
app.use(FsExtendsCopyable);
// 安装uploader 公共参数
const uploaderOptions: FsUploaderOptions = {
defaultType: 'form',
form: {
action: 'http://www.docmirror.cn:7070/api/upload/form/upload',
name: 'file',
withCredentials: false,
uploadRequest: async props => {
const { action, file, onProgress } = props;
const data = new FormData();
data.append('file', file);
const res = await axios.post(action, data, {
headers: {
'Content-Type': 'multipart/form-data'
},
timeout: 60000,
onUploadProgress(progress) {
onProgress({ percent: Math.round((progress.loaded / progress.total!) * 100) });
}
});
// 上传完成后的结果一般返回个url 或者key,具体看你的后台返回啥
return res.data.data;
},
async successHandle(ret: string) {
// 上传完成后的结果处理, 此处应转换格式为{url:xxx,key:xxx}
return {
url: `http://www.docmirror.cn:7070${ret}`,
key: ret.replace('/api/upload/form/download?key=', '')
};
}
}
};
app.use(FsExtendsUploader, uploaderOptions);
// 安装editor
app.use(FsExtendsEditor, {
// 编辑器的公共配置
wangEditor: {}
});
app.use(FsExtendsJson);
app.use(FsExtendsTime);
app.use(FsExtendsCopyable);
}
export default {
install
};
export function setupFastCrud(app: App<Element>, options: FsSetupOpts = {}) {
install(app, options);
}

View File

@@ -1,59 +0,0 @@
import type { App } from 'vue';
import * as NaiveUI from 'naive-ui';
const naive = NaiveUI.create({
components: [
NaiveUI.NInput,
NaiveUI.NButton,
NaiveUI.NForm,
NaiveUI.NFormItem,
NaiveUI.NCheckboxGroup,
NaiveUI.NCheckbox,
NaiveUI.NIcon,
NaiveUI.NDropdown,
NaiveUI.NTooltip,
NaiveUI.NTabs,
NaiveUI.NTabPane,
NaiveUI.NCard,
NaiveUI.NRow,
NaiveUI.NCol,
NaiveUI.NDrawer,
NaiveUI.NDrawerContent,
NaiveUI.NDivider,
NaiveUI.NSwitch,
NaiveUI.NBadge,
NaiveUI.NAlert,
NaiveUI.NTag,
NaiveUI.NProgress,
NaiveUI.NDatePicker,
NaiveUI.NGrid,
NaiveUI.NGridItem,
NaiveUI.NDataTable,
NaiveUI.NPagination,
NaiveUI.NSelect,
NaiveUI.NRadioGroup,
NaiveUI.NRadio,
NaiveUI.NInputGroup,
NaiveUI.NTable,
NaiveUI.NInputNumber,
NaiveUI.NLoadingBarProvider,
NaiveUI.NModal,
NaiveUI.NUpload,
NaiveUI.NTree,
NaiveUI.NSpin,
NaiveUI.NTimePicker,
// add by fs
NaiveUI.NCascader,
NaiveUI.NRadioButton,
NaiveUI.NTreeSelect,
NaiveUI.NImageGroup,
NaiveUI.NImage,
NaiveUI.NCollapse,
NaiveUI.NCollapseItem
]
});
export function setupNaive(app: App<Element>) {
app.use(naive);
}

View File

@@ -1,5 +1,3 @@
import { setupFastCrud } from '@/plugins/fast-crud';
import setupAssets from './assets';
export { setupFastCrud };
export { setupAssets };

View File

@@ -1,45 +0,0 @@
const component: any = {
name: 'crud',
path: '/crud',
component: 'basic',
meta: {
title: 'CRUD示例',
requiresAuth: true,
icon: 'mdi:table-large',
order: 4
},
children: [
{
name: 'crud_demo',
path: '/crud/demo',
component: 'self',
meta: {
title: '基本示例',
requiresAuth: true,
icon: 'mdi:button-cursor'
}
},
{
name: 'crud_header_group',
path: '/crud/header_group',
component: 'self',
meta: {
title: '多级表头',
requiresAuth: true,
icon: 'mdi:button-cursor'
}
},
{
name: 'crud_doc',
path: '/crud/doc',
component: 'self',
meta: {
title: 'FastCrud文档',
requiresAuth: true,
icon: 'logos:vue'
}
}
]
};
export default component;

View File

@@ -30,7 +30,7 @@ const dashboard: AuthRoute.Route = {
title: '仪表盘',
icon: 'mdi:monitor-dashboard',
order: 1,
i18nTitle: 'message.routes.dashboard.dashboard'
i18nTitle: 'message.routes.dashboard._value'
}
};

View File

@@ -1,6 +1,6 @@
import { nextTick } from 'vue';
import { defineStore } from 'pinia';
import { SCROLL_EL_ID } from '@soybeanjs/vue-materials';
import { LAYOUT_SCROLL_EL_ID } from '@soybeanjs/vue-materials';
interface AppState {
/** 滚动元素的id */
@@ -21,7 +21,7 @@ interface AppState {
export const useAppStore = defineStore('app-store', {
state: (): AppState => ({
scrollElId: SCROLL_EL_ID,
scrollElId: LAYOUT_SCROLL_EL_ID,
contentFull: false,
disableMainXScroll: false,
reloadFlag: true,

View File

@@ -66,6 +66,8 @@ interface ImportMetaEnv {
readonly VITE_PROD_MOCK?: 'Y' | 'N';
/** hash路由模式 */
readonly VITE_HASH_ROUTE?: 'Y' | 'N';
/** 是否应用自动生成路由的插件 */
readonly VITE_SOYBEAN_ROUTE_PLUGIN?: 'Y' | 'N';
/** 是否是部署的vercel */
readonly VITE_VERCEL?: 'Y' | 'N';
}

View File

@@ -7,9 +7,3 @@ declare namespace BMap {
}
declare const TMap: any;
declare module 'unplugin-vue-define-options/vite' {
const plugin: (options?: import('unplugin-vue-define-options/dist/unplugin.d-59ddef99').B) => import('vite').Plugin;
export default plugin;
}

View File

@@ -30,12 +30,6 @@ declare namespace PageRoute {
| 'component_button'
| 'component_card'
| 'component_table'
| 'crud'
| 'crud_demo'
| 'crud_doc'
| 'crud_header'
| 'crud_header_group'
| 'crud_source'
| 'dashboard'
| 'dashboard_analysis'
| 'dashboard_workbench'
@@ -95,10 +89,6 @@ declare namespace PageRoute {
| 'component_button'
| 'component_card'
| 'component_table'
| 'crud_demo'
| 'crud_doc'
| 'crud_header_group'
| 'crud_source'
| 'dashboard_analysis'
| 'dashboard_workbench'
| 'document_naive'

View File

@@ -254,7 +254,7 @@ declare namespace App {
hasChildren: boolean;
icon?: import('vue').Component;
i18nTitle?: string;
options?: import('naive-ui/es/dropdown/src/interface').DropdownMixedOption[];
options?: (import('naive-ui/es/dropdown/src/interface').DropdownMixedOption & { i18nTitle?: string })[];
};
/** 多页签Tab的路由 */
@@ -302,7 +302,7 @@ declare namespace App {
}
declare namespace I18nType {
type langType = 'en' | 'zh-CN';
type langType = 'en' | 'zh-CN' | 'km-KH';
interface Schema {
system: {
@@ -310,7 +310,7 @@ declare namespace I18nType {
};
routes: {
dashboard: {
dashboard: string;
_value: string;
analysis: string;
workbench: string;
};

View File

@@ -1,6 +1,6 @@
<template>
<div class="h-full">
<n-card title="当前页面只有super才能看到" class="h-full shadow-sm rounded-16px"> </n-card>
<n-card title="当前页面只有super才能看到" class="h-full shadow-sm rounded-16px"></n-card>
</div>
</template>

View File

@@ -1,43 +0,0 @@
import type { UserPageQuery } from '@fast-crud/fast-crud';
import { mockRequest } from '@/service/request';
const request = mockRequest;
const apiPrefix = '/crud/demo';
export type DemoRecord = {
id: number;
[key: string]: any;
};
function resHandle(res: any) {
return res.data;
}
export async function GetList(query: UserPageQuery) {
const res = await request.post(`${apiPrefix}/page`, query);
return resHandle(res);
}
export async function AddObj(obj: DemoRecord) {
const res = await request.post(`${apiPrefix}/add`, obj);
return resHandle(res);
}
export async function UpdateObj(obj: DemoRecord) {
const res = await request.post(`${apiPrefix}/update`, obj);
return resHandle(res);
}
export async function DelObj(id: number) {
const res = await request.post(`${apiPrefix}/delete`, { id });
return resHandle(res);
}
export async function GetObj(id: number) {
const res = await request.get(`${apiPrefix}/info`, { params: { id } });
return resHandle(res);
}
export async function BatchDelete(ids: number[]) {
const res = await request.post(`${apiPrefix}/batchDelete`, { ids });
return resHandle(res);
}

View File

@@ -1,114 +0,0 @@
import type { AddReq, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes } from '@fast-crud/fast-crud';
import { dict } from '@fast-crud/fast-crud';
import dayjs from 'dayjs';
import * as api from './api';
export default function createCrudOptions(): CreateCrudOptionsRet {
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return api.GetList(query);
};
const editRequest = async (ctx: EditReq) => {
const { form, row } = ctx;
form.id = row.id;
return api.UpdateObj(form);
};
const delRequest = async (ctx: DelReq) => {
const { row } = ctx;
return api.DelObj(row.id);
};
const addRequest = async (req: AddReq) => {
const { form } = req;
return api.AddObj(form);
};
return {
crudOptions: {
container: {
is: 'fs-layout-card'
},
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
columns: {
id: {
title: 'ID',
key: 'id',
type: 'number',
column: {
width: 50
},
form: {
show: false
}
},
datetime: {
title: '时间',
type: 'datetime',
// naive 默认仅支持数字类型时间戳作为日期输入与输出
// 字符串类型的时间需要转换格式
valueBuilder(context) {
const { value, row, key } = context;
if (value) {
// naive 默认仅支持时间戳作为日期输入与输出
row[key] = dayjs(value).valueOf();
}
},
valueResolve(context) {
const { value, form, key } = context;
if (value) {
form[key] = dayjs(value).format('YYYY-MM-DD HH:mm:ss');
}
}
},
select: {
title: '状态',
search: { show: true },
type: 'dict-select',
dict: dict({
url: '/mock/crud/demo/dict'
})
},
text: {
title: '文本',
type: 'text',
search: { show: true }
},
copyable: {
title: '可复制',
type: ['text', 'copyable'],
search: { show: true }
},
avatar: {
title: '头像裁剪',
type: 'cropper-uploader'
},
upload: {
title: '文件上传',
type: 'file-uploader'
},
richtext: {
title: '富文本',
type: 'editor-wang5',
column: {
// cell中不显示
show: false
},
form: {
col: {
// 横跨两列
span: 24
},
component: {
style: {
height: '300px'
}
}
}
}
}
}
};
}

View File

@@ -1,28 +0,0 @@
<template>
<div class="h-full">
<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted } from 'vue';
import { useFs } from '@fast-crud/fast-crud';
import createCrudOptions from './crud';
export default defineComponent({
name: 'ComponentCrud',
setup() {
const { crudRef, crudBinding, crudExpose } = useFs({ createCrudOptions });
// 页面打开后获取列表数据
onMounted(() => {
crudExpose.doRefresh();
});
return {
crudBinding,
crudRef
};
}
});
</script>

View File

@@ -1,13 +0,0 @@
<template>
<div class="h-full">
<iframe class="wh-full" :src="src"></iframe>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const src = ref('http://fast-crud.docmirror.cn/');
</script>
<style scoped></style>

View File

@@ -1,43 +0,0 @@
import type { UserPageQuery } from '@fast-crud/fast-crud';
import { mockRequest } from '@/service/request';
const request = mockRequest;
const apiPrefix = '/crud/header-group';
export type HeaderGroupRecord = {
id: number;
[key: string]: any;
};
function resHandle(res: any) {
return res.data;
}
export async function GetList(query: UserPageQuery) {
const res = await request.post(`${apiPrefix}/page`, query);
return resHandle(res);
}
export async function AddObj(obj: HeaderGroupRecord) {
const res = await request.post(`${apiPrefix}/add`, obj);
return resHandle(res);
}
export async function UpdateObj(obj: HeaderGroupRecord) {
const res = await request.post(`${apiPrefix}/update`, obj);
return resHandle(res);
}
export async function DelObj(id: number) {
const res = await request.post(`${apiPrefix}/delete`, { id });
return resHandle(res);
}
export async function GetObj(id: number) {
const res = await request.get(`${apiPrefix}/info`, { params: { id } });
return resHandle(res);
}
export async function BatchDelete(ids: number[]) {
const res = await request.post(`${apiPrefix}/batchDelete`, { ids });
return resHandle(res);
}

View File

@@ -1,96 +0,0 @@
import type { CreateCrudOptionsRet, UserPageQuery, UserPageRes } from '@fast-crud/fast-crud';
import type { HeaderGroupRecord } from './api';
import * as api from './api';
export default function createCrudOptions(): CreateCrudOptionsRet {
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return api.GetList(query);
};
const editRequest = async (ctx: { form: HeaderGroupRecord; row: HeaderGroupRecord }) => {
const { form, row } = ctx;
form.id = row.id;
return api.UpdateObj(form);
};
const delRequest = async (ctx: { row: HeaderGroupRecord }) => {
const { row } = ctx;
return api.DelObj(row.id);
};
const addRequest = async (ctx: { form: HeaderGroupRecord }) => {
const { form } = ctx;
return api.AddObj(form);
};
return {
crudOptions: {
container: {
// is: 'fs-layout-card'
},
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
form: {
layout: 'flex',
labelWidth: '100px' // 表单label宽度
},
table: { size: 'small' },
columns: {
id: {
title: 'ID',
key: 'id',
type: 'number',
column: {
width: 50
},
form: {
show: false
}
},
user: {
title: '用户信息',
children: {
name: {
title: '姓名',
type: 'text'
},
age: {
title: '年龄',
type: 'number'
}
}
},
address: {
title: '地址',
children: {
area: {
title: '地区',
children: {
province: {
title: '省',
type: 'text',
search: { show: true }
},
city: {
title: '市',
search: { show: true },
type: 'text'
},
county: {
title: '区',
search: { show: true },
type: 'text'
}
}
},
street: {
title: '街道',
type: 'text'
}
}
}
}
}
};
}

View File

@@ -1,32 +0,0 @@
<template>
<div class="h-full fs-page-header-group">
<fs-crud ref="crudRef" v-bind="crudBinding" />
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted } from 'vue';
import { useFs } from '@fast-crud/fast-crud';
import createCrudOptions from './crud';
export default defineComponent({
name: 'CrudHeaderGroup',
setup() {
const { crudRef, crudBinding, crudExpose } = useFs({ createCrudOptions });
// 页面打开后获取列表数据
onMounted(() => {
crudExpose.doRefresh();
});
return {
crudBinding,
crudRef
};
}
});
</script>
<style lang="scss">
.fs-page-header-group {
}
</style>

View File

@@ -1,13 +0,0 @@
<template>
<div class="h-full">
<iframe class="wh-full" :src="src"></iframe>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const src = ref('https://github.com/fast-crud/fast-crud');
</script>
<style scoped></style>

View File

@@ -16,10 +16,6 @@ export const views: Record<
component_button: () => import('./component/button/index.vue'),
component_card: () => import('./component/card/index.vue'),
component_table: () => import('./component/table/index.vue'),
crud_demo: () => import('./crud/demo/index.vue'),
crud_doc: () => import('./crud/doc/index.vue'),
crud_header_group: () => import('./crud/header_group/index.vue'),
crud_source: () => import('./crud/source/index.vue'),
dashboard_analysis: () => import('./dashboard/analysis/index.vue'),
dashboard_workbench: () => import('./dashboard/workbench/index.vue'),
document_naive: () => import('./document/naive/index.vue'),

View File

@@ -3,7 +3,11 @@ import presetUno from '@unocss/preset-uno';
import transformerDirectives from '@unocss/transformer-directives';
export default defineConfig({
exclude: ['node_modules', 'dist', '.git', '.husky', '.vscode', 'public', 'build', 'mock', './stats.html'],
content: {
pipeline: {
exclude: ['node_modules', 'dist', '.git', '.husky', '.vscode', 'public', 'build', 'mock', './stats.html']
}
},
presets: [presetUno({ dark: 'class' })],
transformers: [transformerDirectives()],
shortcuts: {