diff --git a/tansci-boot-ui/.env.development b/tansci-boot-ui/.env.development new file mode 100644 index 0000000..be64e7f --- /dev/null +++ b/tansci-boot-ui/.env.development @@ -0,0 +1 @@ +VITE_BASE_API = 'http://localhost:8081/' \ No newline at end of file diff --git a/tansci-boot-ui/.env.production b/tansci-boot-ui/.env.production new file mode 100644 index 0000000..be64e7f --- /dev/null +++ b/tansci-boot-ui/.env.production @@ -0,0 +1 @@ +VITE_BASE_API = 'http://localhost:8081/' \ No newline at end of file diff --git a/tansci-boot-ui/.gitignore b/tansci-boot-ui/.gitignore new file mode 100644 index 0000000..e6178df --- /dev/null +++ b/tansci-boot-ui/.gitignore @@ -0,0 +1,14 @@ +.vite-ssg-temp + +node_modules +.DS_Store +dist +dist-ssr +*.local + +# lock +yarn.lock +package-lock.json +pnpm-lock.yaml + +*.log diff --git a/tansci-boot-ui/.npmrc b/tansci-boot-ui/.npmrc new file mode 100644 index 0000000..cf04042 --- /dev/null +++ b/tansci-boot-ui/.npmrc @@ -0,0 +1,2 @@ +shamefully-hoist=true +strict-peer-dependencies=false diff --git a/tansci-boot-ui/index.html b/tansci-boot-ui/index.html new file mode 100644 index 0000000..7c81b02 --- /dev/null +++ b/tansci-boot-ui/index.html @@ -0,0 +1,13 @@ + + + + + + + Tansci Boot + + +
+ + + diff --git a/tansci-boot-ui/package.json b/tansci-boot-ui/package.json new file mode 100644 index 0000000..6488b7d --- /dev/null +++ b/tansci-boot-ui/package.json @@ -0,0 +1,31 @@ +{ + "name": "tansci-boot-ui", + "private": true, + "version": "1.0.0", + "scripts": { + "dev": "vite", + "build": "vite build", + "generate": "vite-ssg build", + "preview": "vite preview", + "typecheck": "vue-tsc --noEmit" + }, + "dependencies": { + "axios": "^1.3.4", + "element-plus": "^2.2.13", + "vue": "^3.2.36", + "vue-router": "^4.1.6" + }, + "devDependencies": { + "@iconify-json/ep": "^1.1.4", + "@types/node": "^18.14.0", + "@vitejs/plugin-vue": "^4.0.0", + "sass": "^1.52.1", + "typescript": "^4.7.2", + "unocss": "^0.49.7", + "unplugin-vue-components": "^0.24.0", + "vite": "^4.1.2", + "vite-ssg": "^0.22.1", + "vue-tsc": "^1.1.3" + }, + "license": "MIT" +} diff --git a/tansci-boot-ui/public/favicon.ico b/tansci-boot-ui/public/favicon.ico new file mode 100644 index 0000000..9a616a2 Binary files /dev/null and b/tansci-boot-ui/public/favicon.ico differ diff --git a/tansci-boot-ui/src/App.vue b/tansci-boot-ui/src/App.vue new file mode 100644 index 0000000..c314d67 --- /dev/null +++ b/tansci-boot-ui/src/App.vue @@ -0,0 +1,5 @@ + diff --git a/tansci-boot-ui/src/api/auth.ts b/tansci-boot-ui/src/api/auth.ts new file mode 100644 index 0000000..68d2a1e --- /dev/null +++ b/tansci-boot-ui/src/api/auth.ts @@ -0,0 +1,52 @@ +import request from '@/utils/request' + +// token key +const tokenKey:string = 'tansci_boot_token' + +// 获取token +export function getToken() { + return sessionStorage.getItem(tokenKey); +} + +// 存储token +export function setToken(token:string) { + sessionStorage.setItem(tokenKey, token); +} + +// 删除token +export function removeToken() { + sessionStorage.removeItem(tokenKey); +} + +// 登录 +export function login(data:any){ + return new Promise((resolve, reject) => { + request({ + url: '/system/security/login', + method: 'post', + data: { + username: data.username, + password: data.password, + code: data.code, + uuid: data.uuid + } + }).then((res:any) => { + var token = res.data + setToken(token) + resolve(token) + }).catch((e:any) => { + reject(e) + }) + }) +} + +// 登出 +export function logout(){ + request({ + url: '/system/security/logout', + method: 'get' + }).then(() => { + removeToken() + location.reload() + }) +} \ No newline at end of file diff --git a/tansci-boot-ui/src/assets/image/login-icon.png b/tansci-boot-ui/src/assets/image/login-icon.png new file mode 100644 index 0000000..02b3640 Binary files /dev/null and b/tansci-boot-ui/src/assets/image/login-icon.png differ diff --git a/tansci-boot-ui/src/assets/image/logo.png b/tansci-boot-ui/src/assets/image/logo.png new file mode 100644 index 0000000..529f725 Binary files /dev/null and b/tansci-boot-ui/src/assets/image/logo.png differ diff --git a/tansci-boot-ui/src/components/Submenu.vue b/tansci-boot-ui/src/components/Submenu.vue new file mode 100644 index 0000000..67c5367 --- /dev/null +++ b/tansci-boot-ui/src/components/Submenu.vue @@ -0,0 +1,25 @@ + + \ No newline at end of file diff --git a/tansci-boot-ui/src/components/TabsMenu.vue b/tansci-boot-ui/src/components/TabsMenu.vue new file mode 100644 index 0000000..ff6d845 --- /dev/null +++ b/tansci-boot-ui/src/components/TabsMenu.vue @@ -0,0 +1,158 @@ + + + \ No newline at end of file diff --git a/tansci-boot-ui/src/components/layout/Index.vue b/tansci-boot-ui/src/components/layout/Index.vue new file mode 100644 index 0000000..1ab5e11 --- /dev/null +++ b/tansci-boot-ui/src/components/layout/Index.vue @@ -0,0 +1,153 @@ + + + \ No newline at end of file diff --git a/tansci-boot-ui/src/composables/dark.ts b/tansci-boot-ui/src/composables/dark.ts new file mode 100644 index 0000000..5467599 --- /dev/null +++ b/tansci-boot-ui/src/composables/dark.ts @@ -0,0 +1,4 @@ +import { useDark, useToggle } from '@vueuse/core' + +export const isDark = useDark() +export const toggleDark = useToggle(isDark) diff --git a/tansci-boot-ui/src/composables/index.ts b/tansci-boot-ui/src/composables/index.ts new file mode 100644 index 0000000..e8d1566 --- /dev/null +++ b/tansci-boot-ui/src/composables/index.ts @@ -0,0 +1 @@ +export * from './dark' diff --git a/tansci-boot-ui/src/config/config.ts b/tansci-boot-ui/src/config/config.ts new file mode 100644 index 0000000..9dffdfc --- /dev/null +++ b/tansci-boot-ui/src/config/config.ts @@ -0,0 +1,8 @@ +// 全局不动配置项 只做导出不做修改 + +// 首页地址(默认) +export const HOME_URL: string = "/index"; + +// Tabs(黑名单地址,不需要添加到 tabs 的路由地址) +export const TABS_BLACK_LIST: string[] = ["/404", "/500", "/login"]; + diff --git a/tansci-boot-ui/src/env.d.ts b/tansci-boot-ui/src/env.d.ts new file mode 100644 index 0000000..2da5596 --- /dev/null +++ b/tansci-boot-ui/src/env.d.ts @@ -0,0 +1,8 @@ +/// + +declare module "*.vue" { + import { DefineComponent } from "vue"; + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types + const component: DefineComponent<{}, {}, any>; + export default component; +} diff --git a/tansci-boot-ui/src/main.ts b/tansci-boot-ui/src/main.ts new file mode 100644 index 0000000..e722932 --- /dev/null +++ b/tansci-boot-ui/src/main.ts @@ -0,0 +1,20 @@ +import { createApp } from 'vue' +import App from './App.vue' +import router from './router' +import ElementPlus from 'element-plus' +import 'element-plus/dist/index.css' +import './styles/index.scss' +import * as ElIcons from '@element-plus/icons-vue' +import zhCn from 'element-plus/es/locale/lang/zh-cn' +import 'uno.css' + +const app = createApp(App) +app.use(router) +app.use(ElementPlus,{ + locale: zhCn, + size: 'default', +}) +for (const icon in ElIcons) { + app.component(icon, (ElIcons as any)[icon]) +} +app.mount('#app'); diff --git a/tansci-boot-ui/src/router/common.ts b/tansci-boot-ui/src/router/common.ts new file mode 100644 index 0000000..a13698d --- /dev/null +++ b/tansci-boot-ui/src/router/common.ts @@ -0,0 +1,24 @@ +export default[ + { + path: '/', + redirect: 'login', + }, + { + path: '/login', + name: 'login', + meta: {title: "登录"}, + component: () => import("@/views/common/Login.vue"), + }, + { + path: '/404', + name: '404', + meta: {title: "404"}, + component: () => import('@/views/common/404.vue') + }, + { + path: '/500', + name: '500', + meta: {title: "500"}, + component: () => import('@/views/common/500.vue') + } +] \ No newline at end of file diff --git a/tansci-boot-ui/src/router/index.ts b/tansci-boot-ui/src/router/index.ts new file mode 100644 index 0000000..2b33c7e --- /dev/null +++ b/tansci-boot-ui/src/router/index.ts @@ -0,0 +1,14 @@ +import { createRouter, createWebHistory } from "vue-router" + +import routers from './routers' + +import common from './common' +const router = createRouter({ + history: createWebHistory(), + routes: [ + ...common, + ...routers + ] +}) + +export default router \ No newline at end of file diff --git a/tansci-boot-ui/src/router/routers.ts b/tansci-boot-ui/src/router/routers.ts new file mode 100644 index 0000000..2e05cdd --- /dev/null +++ b/tansci-boot-ui/src/router/routers.ts @@ -0,0 +1,84 @@ +import Layout from '@/components/layout/Index.vue' +export default[ + { + path: '/index', + name: 'index', + type: 0, + icon: 'HomeFilled', + meta: { title: "首页" }, + component: () => Layout, + children: [ + { + path: '/index', + name: 'index', + type: 0, + icon: 'HomeFilled', + meta: { title: "首页" }, + component: () => import('@/views/Index.vue') + } + ] + }, + { + path: '/system', + name: 'system', + type: 0, + icon: 'Grid', + meta: { title: "系统管理" }, + children: [ + { + path: '/menu', + name: 'menu', + type: 0, + icon: 'Grid', + meta: { title: "菜单管理" }, + component: () => Layout, + children: [ + { + path: '/menu', + name: 'menu', + type: 0, + icon: 'Grid', + meta: { title: "菜单管理" }, + component: () => import('@/views/system/Manu.vue') + }, + ] + }, + { + path: '/org', + name: 'org', + type: 0, + icon: 'QuestionFilled', + meta: { title: "组织管理" }, + component: () => Layout, + children: [ + { + path: '/org', + name: 'org', + type: 0, + icon: 'QuestionFilled', + meta: { title: "组织管理" }, + component: () => import('@/views/system/Org.vue') + } + ] + }, + { + path: '/user', + name: 'user', + type: 0, + icon: 'QuestionFilled', + meta: { title: "用户管理" }, + component: () => Layout, + children: [ + { + path: '/user', + name: 'user', + type: 0, + icon: 'QuestionFilled', + meta: { title: "用户管理" }, + component: () => import('@/views/system/User.vue') + } + ] + }, + ] + }, +] \ No newline at end of file diff --git a/tansci-boot-ui/src/styles/element/dark.scss b/tansci-boot-ui/src/styles/element/dark.scss new file mode 100644 index 0000000..1203d7a --- /dev/null +++ b/tansci-boot-ui/src/styles/element/dark.scss @@ -0,0 +1,25 @@ +$--colors: ( + "primary": ( + "base": #2F9688, + ), + "success": ( + "base": #21ba45, + ), + "warning": ( + "base": #f2711c, + ), + "danger": ( + "base": #db2828, + ), + "error": ( + "base": #db2828, + ), + "info": ( + "base": #42b8dd, + ) +); + + +@forward "element-plus/theme-chalk/src/dark/var.scss" with ( + $colors: $--colors +); diff --git a/tansci-boot-ui/src/styles/element/index.scss b/tansci-boot-ui/src/styles/element/index.scss new file mode 100644 index 0000000..9c03b1e --- /dev/null +++ b/tansci-boot-ui/src/styles/element/index.scss @@ -0,0 +1,33 @@ +$--colors: ( + "primary": ( + "base": #2F9688, + ), + "success": ( + "base": #21ba45, + ), + "warning": ( + "base": #f2711c, + ), + "danger": ( + "base": #db2828, + ), + "error": ( + "base": #db2828, + ), + "info": ( + "base": #42b8dd, + ) +); + +@forward "element-plus/theme-chalk/src/mixins/config.scss" with ( + $namespace: "el" +); + +@forward "element-plus/theme-chalk/src/common/var.scss" with ( + $colors: $--colors, + $button-padding-horizontal: ("default": 50px) +); + +@use "element-plus/theme-chalk/src/index.scss" as *; + +@use "./dark.scss"; diff --git a/tansci-boot-ui/src/styles/index.scss b/tansci-boot-ui/src/styles/index.scss new file mode 100644 index 0000000..eb91280 --- /dev/null +++ b/tansci-boot-ui/src/styles/index.scss @@ -0,0 +1,51 @@ +// import dark theme +@use "element-plus/theme-chalk/src/dark/css-vars.scss" as *; + +:root { + // 主题 + --theme: #2F9688; + + // 局部背景 + --el-bg-color: #eff4f9; +} + +body { + font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB","Microsoft YaHei", "微软雅黑", Arial, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + margin: 0; + padding: 0; + overflow: hidden; +} + +/** + * el-table 滚动条样式 + */ + .el-table__body-wrapper::-webkit-scrollbar { + width: 5px; + height: 1px; +} +.el-table__body-wrapper::-webkit-scrollbar-thumb { + background-color: #909399; + border-radius: 5px; +} +.el-table__body-wrapper::-webkit-scrollbar-track { + border-radius: 5px; + background: #ededed; +} + +/** +* 滚动条样式 +*/ +.scroll-div::-webkit-scrollbar{ + width: 5px; + height: 1px; +} +.scroll-div::-webkit-scrollbar-thumb { + border-radius: 5px; + background: #909399; +} +.scroll-div::-webkit-scrollbar-track { + border-radius: 5px; + background: #ededed; +} diff --git a/tansci-boot-ui/src/utils/request.ts b/tansci-boot-ui/src/utils/request.ts new file mode 100644 index 0000000..b3114b5 --- /dev/null +++ b/tansci-boot-ui/src/utils/request.ts @@ -0,0 +1,61 @@ +import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios' +import { showMessage } from './status' +import { ElMessage } from 'element-plus' +import { logout, getToken } from '@/api/auth' +import router from '../router' + +// 根据环境获得不同的代理模式 +const baseURL = import.meta.env.VITE_BASE_URL as string; +const axiosInstance: AxiosInstance = axios.create({ + baseURL: baseURL, + timeout: 30 * 1000, // 超时时间 + headers: { + 'Content-Type': 'application/json' + }, +}) + +// axios实例拦截请求 +axiosInstance.interceptors.request.use((config: AxiosRequestConfig) => { + // 设置token + if (getToken()) { + config.headers.Authorization = `Bearer ${getToken()}` + } + return config; + }, + (error: any) => { + return Promise.reject(error); + } +) + +// axios实例拦截响应 +axiosInstance.interceptors.response.use( + (response: AxiosResponse) => { + if (response.status === 200 && response.data.code == 200) { + return response; + } else { + ElMessage.warning(showMessage(response.status)); + if (response.data.code === 402) { + logout() + } + + if (response.data.code == 403 || response.data.code == 401){ + sessionStorage.clear(); + router.push({path: 'login'}); + } + return response; + } + }, + // 请求失败 + (error: any) => { + const {response} = error; + if (response) { + // 请求已发出,但是不在2xx的范围 + ElMessage.warning(showMessage(response.status)); + return Promise.reject(response.data); + } else { + ElMessage.warning('网络连接异常,请稍后再试!'); + } + } +) + +export default axiosInstance \ No newline at end of file diff --git a/tansci-boot-ui/src/utils/status.ts b/tansci-boot-ui/src/utils/status.ts new file mode 100644 index 0000000..e853e7c --- /dev/null +++ b/tansci-boot-ui/src/utils/status.ts @@ -0,0 +1,42 @@ +export const showMessage = (status:number|string) : string => { + let message:string = ""; + switch (status) { + case 400: + message = "请求错误(400)"; + break; + case 401: + // message = "未授权,请重新登录(401)"; + message = "用户名或密码错误"; + break; + case 403: + message = "拒绝访问(403)"; + break; + case 404: + message = "请求出错(404)"; + break; + case 408: + message = "请求超时(408)"; + break; + case 500: + message = "服务器错误(500)"; + break; + case 501: + message = "服务未实现(501)"; + break; + case 502: + message = "网络错误(502)"; + break; + case 503: + message = "服务不可用(503)"; + break; + case 504: + message = "网络超时(504)"; + break; + case 505: + message = "HTTP版本不受支持(505)"; + break; + default: + message = `未授权,请重新登录!`; + } + return `${message}`; +}; \ No newline at end of file diff --git a/tansci-boot-ui/src/views/Index.vue b/tansci-boot-ui/src/views/Index.vue new file mode 100644 index 0000000..248f498 --- /dev/null +++ b/tansci-boot-ui/src/views/Index.vue @@ -0,0 +1,22 @@ + + + \ No newline at end of file diff --git a/tansci-boot-ui/src/views/common/404.vue b/tansci-boot-ui/src/views/common/404.vue new file mode 100644 index 0000000..5da03b5 --- /dev/null +++ b/tansci-boot-ui/src/views/common/404.vue @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/tansci-boot-ui/src/views/common/500.vue b/tansci-boot-ui/src/views/common/500.vue new file mode 100644 index 0000000..0812692 --- /dev/null +++ b/tansci-boot-ui/src/views/common/500.vue @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/tansci-boot-ui/src/views/common/Login.vue b/tansci-boot-ui/src/views/common/Login.vue new file mode 100644 index 0000000..271adc1 --- /dev/null +++ b/tansci-boot-ui/src/views/common/Login.vue @@ -0,0 +1,159 @@ + + + diff --git a/tansci-boot-ui/src/views/system/Manu.vue b/tansci-boot-ui/src/views/system/Manu.vue new file mode 100644 index 0000000..39c495a --- /dev/null +++ b/tansci-boot-ui/src/views/system/Manu.vue @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/tansci-boot-ui/src/views/system/Org.vue b/tansci-boot-ui/src/views/system/Org.vue new file mode 100644 index 0000000..f27cf95 --- /dev/null +++ b/tansci-boot-ui/src/views/system/Org.vue @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/tansci-boot-ui/src/views/system/User.vue b/tansci-boot-ui/src/views/system/User.vue new file mode 100644 index 0000000..f27cf95 --- /dev/null +++ b/tansci-boot-ui/src/views/system/User.vue @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/tansci-boot-ui/tsconfig.json b/tansci-boot-ui/tsconfig.json new file mode 100644 index 0000000..cda7b16 --- /dev/null +++ b/tansci-boot-ui/tsconfig.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "typeRoots": [ + "node_modules/@types", // 默认值 + "src/types" + ], + "baseUrl": "./", + "target": "esnext", + "useDefineForClassFields": true, + "module": "esnext", + "moduleResolution": "node", + "strict": true, + "jsx": "preserve", + "sourceMap": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "lib": ["esnext", "dom"], + "paths": { + "@": ["src"], + "@/*": ["src/*"] + }, + "skipLibCheck": true + }, + "include": [ + "src/**/*.ts", + "src/**/*.d.ts", + "src/**/*.tsx", + "src/**/*.vue", + "src/**/**/*.vue" + ] +} diff --git a/tansci-boot-ui/vite.config.ts b/tansci-boot-ui/vite.config.ts new file mode 100644 index 0000000..533762d --- /dev/null +++ b/tansci-boot-ui/vite.config.ts @@ -0,0 +1,43 @@ +import { defineConfig } from 'vite' +import path from 'path' +import vue from '@vitejs/plugin-vue' +import Unocss from 'unocss/vite' +import { + presetAttributify, + presetIcons, + presetUno, + transformerDirectives, + transformerVariantGroup, +} from 'unocss' + +export default defineConfig({ + resolve: { + alias: { + '@': path.resolve(__dirname, 'src'), + }, + }, + css: { + preprocessorOptions: { + scss: { + additionalData: `@use "@/styles/element/index.scss" as *;`, + }, + }, + }, + plugins: [ + vue(), + Unocss({ + presets: [ + presetUno(), + presetAttributify(), + presetIcons({ + scale: 1.2, + warn: true, + }), + ], + transformers: [ + transformerDirectives(), + transformerVariantGroup(), + ] + }), + ] +})