Compare commits

..

21 Commits

Author SHA1 Message Date
Soybean
0a47fc264b docs(projects): update README.md 2024-01-10 11:37:19 +08:00
Soybean
edf43cdc25 docs(projects): update README.md 2024-01-04 00:55:09 +08:00
Soybean
5bd177dec6 docs(projects): update README.md 2023-12-29 16:07:44 +08:00
Soybean
223c0bbbdb docs(projects): update README.md 2023-11-28 10:49:34 +08:00
Soybean
3a916b1c4d docs(projects): update README.md 2023-11-27 15:59:58 +08:00
Soybean
ec4b5f3928 docs(projects): update README.md 2023-11-21 10:15:37 +08:00
Soybean
d149668dbd docs(projects): update README.md 2023-11-21 10:06:15 +08:00
Soybean
7c1b8dc968 docs(projects): update README.md 2023-11-17 11:00:55 +08:00
Soybean
1ea4817f6a docs(projects): update README.md 2023-11-14 12:35:02 +08:00
Soybean
ecbb96f3a5 Merge pull request #286 from yanbowe/main
perf(components): Optimize internationalized menu search code
2023-10-18 22:42:35 +08:00
燕博文
296a2d2f0e perf(components): Optimize menu search code 2023-10-18 21:13:05 +08:00
燕博文
8c1ef4b0fd perf(components): Optimize internationalized menu search code 2023-10-18 20:58:04 +08:00
Soybean
04d3330463 Merge pull request #285 from Kori000/main
feat: internationalized menu search
2023-10-18 00:01:11 +08:00
Kori
9e115daeb9 feat: internationalized menu search 2023-10-16 22:53:01 +08:00
Soybean
3eaf05bd4d chore(deps): update deps 2023-10-12 22:26:11 +08:00
Soybean
a195980547 Merge pull request #280 from Particaly/main
fix(projects): 修复路由命名为包含关系时导致导航数据出错的问题
2023-09-27 23:08:18 +08:00
J.S.Patrick
f04a929856 Update menu.ts 2023-09-27 08:43:12 +08:00
J.S.Patrick
5b8af29496 Update breadcrumb.ts
防止找不到顶级路由时报错
2023-09-26 13:50:04 +08:00
pantao
766369f911 fix(projects): 修复路由命名为包含关系时导致导航数据出错的问题 2023-09-25 17:16:25 +08:00
Soybean
f6c6dbd312 refactor(projects): remove plugin-web-update-notification 2023-09-21 01:08:28 +08:00
Soybean
783648f516 docs(projects): update README.md 2023-09-21 00:55:19 +08:00
34 changed files with 1077 additions and 5646 deletions

View File

@@ -1,4 +1,3 @@
!.env-config.ts
router-page.d.ts
*.svg
src-tauri/target

View File

@@ -72,5 +72,6 @@
"[html][css][less][scss][sass][markdown][yaml][yml][jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
}
},
"prettier": {}
}

View File

@@ -5,6 +5,25 @@
[![license](https://img.shields.io/badge/license-MIT-green.svg)](./LICENSE) ![](https://img.shields.io/github/stars/honghuangdc/soybean-admin) ![](https://img.shields.io/github/forks/honghuangdc/soybean-admin)
## 注意 SoybeanAdmin 正在重构,全新 1.0 即将发布
Soybean Admin v1.0 :
- [x] 采用基于 pnpm 的 monorepo 管理项目
- [x] 第三方 soybeanjs 的工具库直接抽离到项目中(ElegantRouter除外),不再作为依赖
- [x] 采用全新的路由插件 ElegantRouter
- [x] 使用基于 ApiFox 的远程 mock 代替本地 mock
- [x] 基于现有路由插件迁移至新路由插件的指南
- [x] 代码实现遵循 SoybeanJS 的代码规范
- [ ] 项目的 main 分支保留系统核心部分,示例页面和无关核心的插件移至 example 分支
- [ ] 完整 1.0 版本的文档
1.0 源代码:[v1.0-beta](https://github.com/honghuangdc/soybean-admin/tree/v1.0-beta)
> 同时推出开源的 [AntDesignVue 版本](https://github.com/soybeanjs/soybean-admin-antd) 和 ElementPlus 版本
> 新开项目建议直接使用 [v1.0-beta](https://github.com/honghuangdc/soybean-admin/tree/v1.0-beta) 或 [AntDesignVue 版本](https://github.com/soybeanjs/soybean-admin-antd)
## 简介
[Soybean Admin](https://github.com/honghuangdc/soybean-admin) 是一个基于 Vue3、Vite3、TypeScript、NaiveUI、Pinia 和 UnoCSS 的清新优雅的中后台模版,它使用了最新流行的前端技术栈,内置丰富的主题配置,有着极高的代码规范,基于文件的路由系统以及基于 Mock 的动态权限路由,开箱即用的中后台前端解决方案,也可用于学习参考。
@@ -165,7 +184,7 @@ docker run -d -p 80:80 soybean-admin-image
<img src="https://i.loli.net/2021/11/24/1J6REWXiHomU2kM.jpg" style="width:200px" />
</div>
<div>
<p>添加本人微信,欢迎来技术交流,业务咨询</p>
<p>添加本人微信,欢迎来业务咨询(技术交流请加QQ群)</p>
<img src="https://s2.loli.net/2023/06/07/sVyCUFBvzQ9f5b7.jpg" style="width:200px" />
</div>
</div>

View File

@@ -5,7 +5,6 @@ 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 { webUpdateNotice } from '@plugin-web-update-notification/vite';
import unplugin from './unplugin';
import mock from './mock';
import visualizer from './visualizer';
@@ -28,15 +27,7 @@ export function setupVitePlugins(viteEnv: ImportMetaEnv): (PluginOption | Plugin
...unplugin(viteEnv),
unocss(),
mock(viteEnv),
progress(),
webUpdateNotice({
notificationProps: {
title: '👋 有新版本了',
description: '点击刷新页面获取最新版本',
buttonText: '刷新',
dismissButtonText: '忽略'
}
})
progress()
];
if (viteEnv.VITE_VISUALIZER === 'Y') {

View File

@@ -3,10 +3,6 @@
<html lang="zh-cmn-Hans">
<head>
<meta charset="UTF-8" />
<meta http-equiv="Expires" content="0" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Cache-control" content="no-cache" />
<meta http-equiv="Cache" content="no-cache" />
<link rel="icon" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>%VITE_APP_NAME%</title>

View File

@@ -38,13 +38,10 @@
"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",
@@ -62,8 +59,8 @@
"@antv/g2": "4.2.10",
"@better-scroll/core": "2.5.1",
"@soybeanjs/vue-materials": "0.2.0",
"@vueuse/core": "10.4.1",
"axios": "1.5.0",
"@vueuse/core": "10.5.0",
"axios": "1.5.1",
"clipboard": "2.0.11",
"colord": "2.9.3",
"crypto-js": "4.1.1",
@@ -71,58 +68,56 @@
"echarts": "5.4.3",
"form-data": "4.0.0",
"lodash-es": "4.17.21",
"naive-ui": "2.34.4",
"naive-ui": "2.35.0",
"pinia": "2.1.6",
"print-js": "1.6.0",
"qs": "6.11.2",
"socket.io-client": "4.7.2",
"swiper": "10.2.0",
"swiper": "10.3.1",
"ua-parser-js": "1.0.36",
"vditor": "3.9.5",
"vditor": "3.9.6",
"vue": "3.3.4",
"vue-i18n": "9.4.1",
"vue-router": "4.2.4",
"vue-i18n": "9.5.0",
"vue-router": "4.2.5",
"vuedraggable": "4.1.0",
"wangeditor": "4.7.15",
"xgplayer": "3.0.9"
},
"devDependencies": {
"@amap/amap-jsapi-types": "0.0.13",
"@iconify/json": "2.2.118",
"@iconify/json": "2.2.128",
"@iconify/vue": "4.1.1",
"@plugin-web-update-notification/vite": "^1.6.5",
"@soybeanjs/cli": "0.7.1",
"@soybeanjs/cli": "0.7.4",
"@soybeanjs/vite-plugin-vue-page-route": "0.0.10",
"@tauri-apps/cli": "^1.3.1",
"@types/bmapgl": "0.0.7",
"@types/crypto-js": "4.1.2",
"@types/node": "20.6.3",
"@types/node": "20.8.4",
"@types/qs": "6.9.8",
"@types/ua-parser-js": "0.7.37",
"@unocss/preset-uno": "0.56.0",
"@unocss/transformer-directives": "0.56.0",
"@unocss/vite": "0.56.0",
"@vitejs/plugin-vue": "4.3.4",
"@unocss/preset-uno": "0.56.5",
"@unocss/transformer-directives": "0.56.5",
"@unocss/vite": "0.56.5",
"@vitejs/plugin-vue": "4.4.0",
"@vitejs/plugin-vue-jsx": "3.0.2",
"cross-env": "7.0.3",
"eslint": "8.49.0",
"eslint-config-soybeanjs": "0.5.6",
"eslint": "8.51.0",
"eslint-config-soybeanjs": "0.5.7",
"mockjs": "1.1.0",
"rollup-plugin-visualizer": "5.9.2",
"sass": "1.67.0",
"sass": "1.69.3",
"simple-git-hooks": "2.9.0",
"tsx": "3.12.10",
"tsx": "3.13.0",
"typescript": "5.2.2",
"unplugin-icons": "0.17.0",
"unplugin-vue-components": "0.25.2",
"vite": "4.4.9",
"vite": "4.4.11",
"vite-plugin-compression": "0.5.1",
"vite-plugin-mock": "2.9.8",
"vite-plugin-progress": "0.0.7",
"vite-plugin-pwa": "0.16.5",
"vite-plugin-svg-icons": "2.0.1",
"vite-plugin-vue-devtools": "1.0.0-rc.4",
"vue-tsc": "1.8.13"
"vite-plugin-vue-devtools": "1.0.0-rc.5",
"vue-tsc": "1.8.19"
},
"pnpm": {
"patchedDependencies": {
@@ -131,7 +126,7 @@
},
"simple-git-hooks": {
"commit-msg": "pnpm soy git-commit-verify",
"pre-commit": "pnpm typecheck && pnpm lint"
"pre-commit": "pnpm typecheck && pnpm soy lint-staged"
},
"soybean": {
"useSoybeanToken": true

2149
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

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

4302
src-tauri/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +0,0 @@
[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" ]

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

View File

@@ -1,10 +0,0 @@
#![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");
}

View File

@@ -1,60 +0,0 @@
{
"$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.10.4"
},
"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

@@ -34,6 +34,7 @@ import { useRouter } from 'vue-router';
import { onKeyStroke, useDebounceFn } from '@vueuse/core';
import { useRouteStore } from '@/store';
import { useBasicLayout } from '@/composables';
import { $t } from '@/locales';
import SearchResult from './search-result.vue';
import SearchFooter from './search-footer.vue';
@@ -82,14 +83,12 @@ watch(show, async val => {
/** 查询 */
function search() {
resultOptions.value = routeStore.searchMenus.filter(
menu => keyword.value && menu.meta?.title.toLocaleLowerCase().includes(keyword.value.toLocaleLowerCase().trim())
);
if (resultOptions.value?.length > 0) {
activePath.value = resultOptions.value[0].path;
} else {
activePath.value = '';
}
resultOptions.value = routeStore.searchMenus.filter(menu => {
const trimKeyword = keyword.value.toLocaleLowerCase().trim();
const title = (menu.meta.i18nTitle ? $t(menu.meta.i18nTitle) : menu.meta.title).toLocaleLowerCase();
return trimKeyword && title.includes(trimKeyword);
});
activePath.value = resultOptions.value[0]?.path ?? '';
}
function handleClose() {

View File

@@ -12,7 +12,9 @@
@mouseenter="handleMouse(item)"
>
<svg-icon :icon="item.meta.icon" :local-icon="item.meta.localIcon" />
<span class="flex-1 ml-5px">{{ item.meta?.title }}</span>
<span class="flex-1 ml-5px">
{{ (item.meta?.i18nTitle && $t(item.meta?.i18nTitle)) || item.meta?.title }}
</span>
<icon-ant-design-enter-outlined class="icon text-20px p-2px mr-3px" />
</div>
</template>
@@ -23,6 +25,7 @@
<script lang="ts" setup>
import { computed } from 'vue';
import { useThemeStore } from '@/store';
import { $t } from '@/locales';
defineOptions({ name: 'SearchResult' });

View File

@@ -1,3 +1,4 @@
import { getTopLevelMenu } from './helpers';
/**
* 获取面包屑数据
* @param activeKey - 当前页面路由的key
@@ -17,13 +18,9 @@ export function getBreadcrumbByRouteKey(activeKey: string, menus: App.GlobalMenu
*/
function getBreadcrumbMenu(activeKey: string, menus: App.GlobalMenuOption[]) {
const breadcrumbMenu: App.GlobalMenuOption[] = [];
menus.some(menu => {
const flag = activeKey.includes(menu.routeName);
if (flag) {
breadcrumbMenu.push(...getBreadcrumbMenuItem(activeKey, menu));
}
return flag;
});
const topLevelMenu = getTopLevelMenu(activeKey, menus);
const options = topLevelMenu ? getBreadcrumbMenuItem(activeKey, topLevelMenu as App.GlobalMenuOption) : [];
breadcrumbMenu.push(...options);
return breadcrumbMenu;
}

View File

@@ -17,3 +17,18 @@ function getConstantRouteName(route: AuthRoute.Route) {
}
return names;
}
/**
* 根据路由名称查找顶级菜单
* @param routeName - 当前页面路由的key
* @param menus - 菜单数据
*/
export function getTopLevelMenu(routeName: string, menus: App.GlobalMenuOption[]): App.GlobalMenuOption | undefined {
return menus.find(item => {
if (item.routeName === routeName) return true;
if (Array.isArray(item.children)) {
return getTopLevelMenu(routeName, item.children);
}
return false;
});
}

View File

@@ -63,18 +63,29 @@ export function translateMenuLabel(menus: App.GlobalMenuOption[]): App.GlobalMen
* @param menus - 菜单数据
*/
export function getActiveKeyPathsOfMenus(activeKey: string, menus: App.GlobalMenuOption[]) {
const keys = menus.map(menu => getActiveKeyPathsOfMenu(activeKey, menu)).flat(1);
return keys;
}
function getActiveKeyPathsOfMenu(activeKey: string, menu: App.GlobalMenuOption) {
const keys: string[] = [];
if (activeKey.startsWith(menu.routeName)) {
keys.push(menu.routeName);
}
if (menu.children) {
keys.push(...menu.children.map(item => getActiveKeyPathsOfMenu(activeKey, item as App.GlobalMenuOption)).flat(1));
const lists: App.GlobalMenuOption[] = [];
function traverse(list: App.GlobalMenuOption[], parent: App.GlobalMenuOption | null = null) {
list.forEach((t: App.GlobalMenuOption) => {
lists.push(t);
if (parent) {
t.parent = parent;
}
if (t.children) {
traverse(t.children, t);
}
});
}
traverse(JSON.parse(JSON.stringify(menus)));
lists.forEach((t: App.GlobalMenuOption) => {
if (t.routeName === activeKey) {
let temp = t;
while (temp) {
keys.push(temp.routeName);
temp = temp.parent as App.GlobalMenuOption;
}
}
});
return keys;
}