Compare commits
1 Commits
legacy
...
tauri-v0.1
Author | SHA1 | Date | |
---|---|---|---|
|
c70b2299a9 |
@@ -1,3 +1,4 @@
|
||||
!.env-config.ts
|
||||
router-page.d.ts
|
||||
|
||||
*.svg
|
||||
src-tauri/target
|
||||
|
3
.vscode/settings.json
vendored
@@ -72,6 +72,5 @@
|
||||
"[html][css][less][scss][sass][markdown][yaml][yml][jsonc]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"prettier": {}
|
||||
}
|
||||
}
|
||||
|
21
README.md
@@ -5,25 +5,6 @@
|
||||
|
||||
[](./LICENSE)  
|
||||
|
||||
## 注意 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 的动态权限路由,开箱即用的中后台前端解决方案,也可用于学习参考。
|
||||
@@ -184,7 +165,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>添加本人微信,欢迎来业务咨询(技术交流请加QQ群)</p>
|
||||
<p>添加本人微信,欢迎来技术交流,业务咨询</p>
|
||||
<img src="https://s2.loli.net/2023/06/07/sVyCUFBvzQ9f5b7.jpg" style="width:200px" />
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -5,6 +5,7 @@ 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';
|
||||
@@ -27,7 +28,15 @@ export function setupVitePlugins(viteEnv: ImportMetaEnv): (PluginOption | Plugin
|
||||
...unplugin(viteEnv),
|
||||
unocss(),
|
||||
mock(viteEnv),
|
||||
progress()
|
||||
progress(),
|
||||
webUpdateNotice({
|
||||
notificationProps: {
|
||||
title: '👋 有新版本了',
|
||||
description: '点击刷新页面获取最新版本',
|
||||
buttonText: '刷新',
|
||||
dismissButtonText: '忽略'
|
||||
}
|
||||
})
|
||||
];
|
||||
|
||||
if (viteEnv.VITE_VISUALIZER === 'Y') {
|
||||
|
@@ -3,6 +3,10 @@
|
||||
<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>
|
||||
|
49
package.json
@@ -38,10 +38,13 @@
|
||||
"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",
|
||||
@@ -59,8 +62,8 @@
|
||||
"@antv/g2": "4.2.10",
|
||||
"@better-scroll/core": "2.5.1",
|
||||
"@soybeanjs/vue-materials": "0.2.0",
|
||||
"@vueuse/core": "10.5.0",
|
||||
"axios": "1.5.1",
|
||||
"@vueuse/core": "10.4.1",
|
||||
"axios": "1.5.0",
|
||||
"clipboard": "2.0.11",
|
||||
"colord": "2.9.3",
|
||||
"crypto-js": "4.1.1",
|
||||
@@ -68,56 +71,58 @@
|
||||
"echarts": "5.4.3",
|
||||
"form-data": "4.0.0",
|
||||
"lodash-es": "4.17.21",
|
||||
"naive-ui": "2.35.0",
|
||||
"naive-ui": "2.34.4",
|
||||
"pinia": "2.1.6",
|
||||
"print-js": "1.6.0",
|
||||
"qs": "6.11.2",
|
||||
"socket.io-client": "4.7.2",
|
||||
"swiper": "10.3.1",
|
||||
"swiper": "10.2.0",
|
||||
"ua-parser-js": "1.0.36",
|
||||
"vditor": "3.9.6",
|
||||
"vditor": "3.9.5",
|
||||
"vue": "3.3.4",
|
||||
"vue-i18n": "9.5.0",
|
||||
"vue-router": "4.2.5",
|
||||
"vue-i18n": "9.4.1",
|
||||
"vue-router": "4.2.4",
|
||||
"vuedraggable": "4.1.0",
|
||||
"wangeditor": "4.7.15",
|
||||
"xgplayer": "3.0.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@amap/amap-jsapi-types": "0.0.13",
|
||||
"@iconify/json": "2.2.128",
|
||||
"@iconify/json": "2.2.118",
|
||||
"@iconify/vue": "4.1.1",
|
||||
"@soybeanjs/cli": "0.7.4",
|
||||
"@plugin-web-update-notification/vite": "^1.6.5",
|
||||
"@soybeanjs/cli": "0.7.1",
|
||||
"@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.8.4",
|
||||
"@types/node": "20.6.3",
|
||||
"@types/qs": "6.9.8",
|
||||
"@types/ua-parser-js": "0.7.37",
|
||||
"@unocss/preset-uno": "0.56.5",
|
||||
"@unocss/transformer-directives": "0.56.5",
|
||||
"@unocss/vite": "0.56.5",
|
||||
"@vitejs/plugin-vue": "4.4.0",
|
||||
"@unocss/preset-uno": "0.56.0",
|
||||
"@unocss/transformer-directives": "0.56.0",
|
||||
"@unocss/vite": "0.56.0",
|
||||
"@vitejs/plugin-vue": "4.3.4",
|
||||
"@vitejs/plugin-vue-jsx": "3.0.2",
|
||||
"cross-env": "7.0.3",
|
||||
"eslint": "8.51.0",
|
||||
"eslint-config-soybeanjs": "0.5.7",
|
||||
"eslint": "8.49.0",
|
||||
"eslint-config-soybeanjs": "0.5.6",
|
||||
"mockjs": "1.1.0",
|
||||
"rollup-plugin-visualizer": "5.9.2",
|
||||
"sass": "1.69.3",
|
||||
"sass": "1.67.0",
|
||||
"simple-git-hooks": "2.9.0",
|
||||
"tsx": "3.13.0",
|
||||
"tsx": "3.12.10",
|
||||
"typescript": "5.2.2",
|
||||
"unplugin-icons": "0.17.0",
|
||||
"unplugin-vue-components": "0.25.2",
|
||||
"vite": "4.4.11",
|
||||
"vite": "4.4.9",
|
||||
"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.5",
|
||||
"vue-tsc": "1.8.19"
|
||||
"vite-plugin-vue-devtools": "1.0.0-rc.4",
|
||||
"vue-tsc": "1.8.13"
|
||||
},
|
||||
"pnpm": {
|
||||
"patchedDependencies": {
|
||||
@@ -126,7 +131,7 @@
|
||||
},
|
||||
"simple-git-hooks": {
|
||||
"commit-msg": "pnpm soy git-commit-verify",
|
||||
"pre-commit": "pnpm typecheck && pnpm soy lint-staged"
|
||||
"pre-commit": "pnpm typecheck && pnpm lint"
|
||||
},
|
||||
"soybean": {
|
||||
"useSoybeanToken": true
|
||||
|
2149
pnpm-lock.yaml
generated
3
src-tauri/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
4302
src-tauri/Cargo.lock
generated
Normal file
28
src-tauri/Cargo.toml
Normal 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
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
tauri_build::build()
|
||||
}
|
BIN
src-tauri/icons/128x128.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
BIN
src-tauri/icons/128x128@2x.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
src-tauri/icons/32x32.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src-tauri/icons/Square107x107Logo.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
src-tauri/icons/Square142x142Logo.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
src-tauri/icons/Square150x150Logo.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
src-tauri/icons/Square284x284Logo.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
src-tauri/icons/Square30x30Logo.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
src-tauri/icons/Square310x310Logo.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
src-tauri/icons/Square44x44Logo.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
src-tauri/icons/Square71x71Logo.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
src-tauri/icons/Square89x89Logo.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
src-tauri/icons/StoreLogo.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
src-tauri/icons/icon.icns
Normal file
BIN
src-tauri/icons/icon.ico
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
src-tauri/icons/icon.png
Normal file
After Width: | Height: | Size: 42 KiB |
10
src-tauri/src/main.rs
Normal 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
@@ -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.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
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@@ -34,7 +34,6 @@ 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';
|
||||
|
||||
@@ -83,12 +82,14 @@ watch(show, async val => {
|
||||
|
||||
/** 查询 */
|
||||
function search() {
|
||||
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 ?? '';
|
||||
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 = '';
|
||||
}
|
||||
}
|
||||
|
||||
function handleClose() {
|
||||
|
@@ -12,9 +12,7 @@
|
||||
@mouseenter="handleMouse(item)"
|
||||
>
|
||||
<svg-icon :icon="item.meta.icon" :local-icon="item.meta.localIcon" />
|
||||
<span class="flex-1 ml-5px">
|
||||
{{ (item.meta?.i18nTitle && $t(item.meta?.i18nTitle)) || item.meta?.title }}
|
||||
</span>
|
||||
<span class="flex-1 ml-5px">{{ item.meta?.title }}</span>
|
||||
<icon-ant-design-enter-outlined class="icon text-20px p-2px mr-3px" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -25,7 +23,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { useThemeStore } from '@/store';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
defineOptions({ name: 'SearchResult' });
|
||||
|
||||
|
@@ -1,4 +1,3 @@
|
||||
import { getTopLevelMenu } from './helpers';
|
||||
/**
|
||||
* 获取面包屑数据
|
||||
* @param activeKey - 当前页面路由的key
|
||||
@@ -18,9 +17,13 @@ export function getBreadcrumbByRouteKey(activeKey: string, menus: App.GlobalMenu
|
||||
*/
|
||||
function getBreadcrumbMenu(activeKey: string, menus: App.GlobalMenuOption[]) {
|
||||
const breadcrumbMenu: App.GlobalMenuOption[] = [];
|
||||
const topLevelMenu = getTopLevelMenu(activeKey, menus);
|
||||
const options = topLevelMenu ? getBreadcrumbMenuItem(activeKey, topLevelMenu as App.GlobalMenuOption) : [];
|
||||
breadcrumbMenu.push(...options);
|
||||
menus.some(menu => {
|
||||
const flag = activeKey.includes(menu.routeName);
|
||||
if (flag) {
|
||||
breadcrumbMenu.push(...getBreadcrumbMenuItem(activeKey, menu));
|
||||
}
|
||||
return flag;
|
||||
});
|
||||
return breadcrumbMenu;
|
||||
}
|
||||
|
||||
|
@@ -17,18 +17,3 @@ 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;
|
||||
});
|
||||
}
|
||||
|
@@ -63,29 +63,18 @@ 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[] = [];
|
||||
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);
|
||||
}
|
||||
});
|
||||
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));
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|