├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── sql ├── quartz.sql ├── ry_20230223.sql └── tool_excel.sql ├── src ├── controller │ ├── chat_controller.rs │ ├── common_controller.rs │ ├── dept_controller.rs │ ├── dict_controller.rs │ ├── excel_controller.rs │ ├── menu_controller.rs │ ├── mod.rs │ ├── monitor_controller.rs │ ├── notice_controller.rs │ ├── post_controller.rs │ ├── role_controller.rs │ ├── swagger_controller.rs │ └── user_controller.rs ├── entity │ ├── excel_entity.rs │ ├── mod.rs │ ├── sys_captcha_entity.rs │ ├── sys_dept_entity.rs │ ├── sys_dict_data_entity.rs │ ├── sys_dict_type_entity.rs │ ├── sys_menu_entity.rs │ ├── sys_notice_entity.rs │ ├── sys_post_entity.rs │ ├── sys_role_entity.rs │ ├── sys_role_menu_entity.rs │ ├── sys_user_entity.rs │ ├── sys_user_post_entity.rs │ └── sys_user_role_entity.rs ├── main.rs ├── mapper │ ├── captcha_mapper.rs │ ├── dept_mapper.rs │ ├── dict_mapper.rs │ ├── excel_mapper.rs │ ├── menu_mapper.rs │ ├── mod.rs │ ├── notice_mapper.rs │ ├── post_mapper.rs │ ├── role_mapper.rs │ ├── role_menu_mapper.rs │ ├── user_mapper.rs │ ├── user_post_mapper.rs │ ├── user_role_mapper.rs │ └── xml │ │ ├── dept_xml.html │ │ ├── dict_xml.html │ │ ├── excel_xml.html │ │ ├── menu_xml.html │ │ ├── notice_xml.html │ │ ├── post_xml.html │ │ ├── role_menu_xml.html │ │ ├── role_xml.html │ │ ├── user_role_xml.html │ │ └── user_xml.html ├── model │ ├── chat_model.rs │ ├── common_model.rs │ ├── dept_model.rs │ ├── dict_model.rs │ ├── excel_model.rs │ ├── menu_model.rs │ ├── mod.rs │ ├── monitor_model.rs │ ├── notice_model.rs │ ├── post_model.rs │ ├── role_model.rs │ ├── swagger_model.rs │ └── user_model.rs ├── router │ ├── dept_router.rs │ ├── dict_router.rs │ ├── excel_router.rs │ ├── menu_router.rs │ ├── mod.rs │ ├── monitor_router.rs │ ├── notice_router.rs │ ├── post_router.rs │ ├── role_router.rs │ └── user_router.rs ├── service │ ├── dept_service.rs │ ├── dict_service.rs │ ├── excel_service.rs │ ├── menu_service.rs │ ├── mod.rs │ ├── monitor_service.rs │ ├── notice_service.rs │ ├── post_service.rs │ ├── role_service.rs │ └── user_service.rs ├── utils │ ├── captcha.rs │ ├── func.rs │ ├── md5.rs │ ├── mod.rs │ ├── mysql.rs │ ├── redis.rs │ ├── res.rs │ ├── system.rs │ └── webtoken.rs └── websocket │ ├── excel_websocket.rs │ └── mod.rs ├── static └── text1.txt └── ui ├── .env.development ├── .env.production ├── .env.staging ├── .github └── FUNDING.yml ├── .gitignore ├── bin ├── build.bat ├── package.bat └── run-web.bat ├── html └── ie.html ├── index.html ├── package.json ├── public └── favicon.ico ├── src ├── App.vue ├── api │ ├── login.js │ ├── menu.js │ ├── monitor │ │ ├── cache.js │ │ ├── job.js │ │ ├── jobLog.js │ │ ├── logininfor.js │ │ ├── online.js │ │ ├── operlog.js │ │ └── server.js │ ├── system │ │ ├── config.js │ │ ├── dept.js │ │ ├── dict │ │ │ ├── data.js │ │ │ └── type.js │ │ ├── menu.js │ │ ├── notice.js │ │ ├── post.js │ │ ├── role.js │ │ └── user.js │ └── tool │ │ ├── excel.js │ │ └── gen.js ├── assets │ ├── 401_images │ │ └── 401.gif │ ├── 404_images │ │ ├── 404.png │ │ └── 404_cloud.png │ ├── icons │ │ └── svg │ │ │ ├── 404.svg │ │ │ ├── bug.svg │ │ │ ├── build.svg │ │ │ ├── button.svg │ │ │ ├── cascader.svg │ │ │ ├── chart.svg │ │ │ ├── checkbox.svg │ │ │ ├── clipboard.svg │ │ │ ├── code.svg │ │ │ ├── color.svg │ │ │ ├── component.svg │ │ │ ├── dashboard.svg │ │ │ ├── date-range.svg │ │ │ ├── date.svg │ │ │ ├── dict.svg │ │ │ ├── documentation.svg │ │ │ ├── download.svg │ │ │ ├── drag.svg │ │ │ ├── druid.svg │ │ │ ├── edit.svg │ │ │ ├── education.svg │ │ │ ├── email.svg │ │ │ ├── example.svg │ │ │ ├── excel.svg │ │ │ ├── exit-fullscreen.svg │ │ │ ├── eye-open.svg │ │ │ ├── eye.svg │ │ │ ├── form.svg │ │ │ ├── fullscreen.svg │ │ │ ├── github.svg │ │ │ ├── guide.svg │ │ │ ├── icon.svg │ │ │ ├── input.svg │ │ │ ├── international.svg │ │ │ ├── job.svg │ │ │ ├── language.svg │ │ │ ├── link.svg │ │ │ ├── list.svg │ │ │ ├── lock.svg │ │ │ ├── log.svg │ │ │ ├── logininfor.svg │ │ │ ├── message.svg │ │ │ ├── money.svg │ │ │ ├── monitor.svg │ │ │ ├── nested.svg │ │ │ ├── number.svg │ │ │ ├── online.svg │ │ │ ├── password.svg │ │ │ ├── pdf.svg │ │ │ ├── people.svg │ │ │ ├── peoples.svg │ │ │ ├── phone.svg │ │ │ ├── post.svg │ │ │ ├── qq.svg │ │ │ ├── question.svg │ │ │ ├── radio.svg │ │ │ ├── rate.svg │ │ │ ├── redis-list.svg │ │ │ ├── redis.svg │ │ │ ├── row.svg │ │ │ ├── search.svg │ │ │ ├── select.svg │ │ │ ├── server.svg │ │ │ ├── shopping.svg │ │ │ ├── size.svg │ │ │ ├── skill.svg │ │ │ ├── slider.svg │ │ │ ├── star.svg │ │ │ ├── swagger.svg │ │ │ ├── switch.svg │ │ │ ├── system.svg │ │ │ ├── tab.svg │ │ │ ├── table.svg │ │ │ ├── textarea.svg │ │ │ ├── theme.svg │ │ │ ├── time-range.svg │ │ │ ├── time.svg │ │ │ ├── tool.svg │ │ │ ├── tree-table.svg │ │ │ ├── tree.svg │ │ │ ├── upload.svg │ │ │ ├── user.svg │ │ │ ├── validCode.svg │ │ │ ├── wechat.svg │ │ │ └── zip.svg │ ├── images │ │ ├── dark.svg │ │ ├── light.svg │ │ ├── login-background.jpg │ │ └── profile.jpg │ ├── logo │ │ └── logo.png │ └── styles │ │ ├── btn.scss │ │ ├── element-ui.scss │ │ ├── index.scss │ │ ├── mixin.scss │ │ ├── ruoyi.scss │ │ ├── sidebar.scss │ │ ├── transition.scss │ │ └── variables.module.scss ├── components │ ├── Breadcrumb │ │ └── index.vue │ ├── Crontab │ │ ├── day.vue │ │ ├── hour.vue │ │ ├── index.vue │ │ ├── min.vue │ │ ├── month.vue │ │ ├── result.vue │ │ ├── second.vue │ │ ├── week.vue │ │ └── year.vue │ ├── DictTag │ │ └── index.vue │ ├── Editor │ │ └── index.vue │ ├── FileUpload │ │ └── index.vue │ ├── Hamburger │ │ └── index.vue │ ├── HeaderSearch │ │ └── index.vue │ ├── IconSelect │ │ ├── index.vue │ │ └── requireIcons.js │ ├── ImagePreview │ │ └── index.vue │ ├── ImageUpload │ │ └── index.vue │ ├── Pagination │ │ └── index.vue │ ├── ParentView │ │ └── index.vue │ ├── RightToolbar │ │ └── index.vue │ ├── RuoYi │ │ ├── Doc │ │ │ └── index.vue │ │ └── Git │ │ │ └── index.vue │ ├── Screenfull │ │ └── index.vue │ ├── SizeSelect │ │ └── index.vue │ ├── SvgIcon │ │ ├── index.vue │ │ └── svgicon.js │ ├── TopNav │ │ └── index.vue │ ├── TreeSelect │ │ └── index.vue │ ├── UploadImg.vue │ └── iFrame │ │ └── index.vue ├── directive │ ├── common │ │ └── copyText.js │ ├── index.js │ └── permission │ │ ├── hasPermi.js │ │ └── hasRole.js ├── layout │ ├── components │ │ ├── AppMain.vue │ │ ├── IframeToggle │ │ │ └── index.vue │ │ ├── InnerLink │ │ │ └── index.vue │ │ ├── Navbar.vue │ │ ├── Settings │ │ │ └── index.vue │ │ ├── Sidebar │ │ │ ├── Link.vue │ │ │ ├── Logo.vue │ │ │ ├── SidebarItem.vue │ │ │ └── index.vue │ │ ├── TagsView │ │ │ ├── ScrollPane.vue │ │ │ └── index.vue │ │ └── index.js │ └── index.vue ├── main.js ├── permission.js ├── plugins │ ├── auth.js │ ├── cache.js │ ├── download.js │ ├── index.js │ ├── modal.js │ └── tab.js ├── router │ └── index.js ├── settings.js ├── store │ ├── index.js │ └── modules │ │ ├── app.js │ │ ├── dict.js │ │ ├── permission.js │ │ ├── settings.js │ │ ├── tagsView.js │ │ └── user.js ├── utils │ ├── auth.js │ ├── dict.js │ ├── dynamicTitle.js │ ├── errorCode.js │ ├── index.js │ ├── jsencrypt.js │ ├── permission.js │ ├── request.js │ ├── ruoyi.js │ ├── scroll-to.js │ ├── theme.js │ └── validate.js └── views │ ├── error │ ├── 401.vue │ └── 404.vue │ ├── index.vue │ ├── login.vue │ ├── monitor │ ├── cache │ │ ├── index.vue │ │ └── list.vue │ ├── druid │ │ └── index.vue │ ├── job │ │ ├── index.vue │ │ └── log.vue │ ├── logininfor │ │ └── index.vue │ ├── online │ │ └── index.vue │ ├── operlog │ │ └── index.vue │ └── server │ │ └── index.vue │ ├── redirect │ └── index.vue │ ├── register.vue │ ├── system │ ├── chat │ │ └── index.vue │ ├── config │ │ └── index.vue │ ├── dept │ │ └── index.vue │ ├── dict │ │ ├── data.vue │ │ └── index.vue │ ├── menu │ │ └── index.vue │ ├── notice │ │ └── index.vue │ ├── post │ │ └── index.vue │ ├── role │ │ ├── authUser.vue │ │ ├── index.vue │ │ └── selectUser.vue │ └── user │ │ ├── authRole.vue │ │ ├── index.vue │ │ └── profile │ │ ├── index.vue │ │ ├── resetPwd.vue │ │ ├── userAvatar.vue │ │ └── userInfo.vue │ └── tool │ ├── build │ └── index.vue │ ├── excel │ └── index.vue │ ├── gen │ ├── basicInfoForm.vue │ ├── editTable.vue │ ├── genInfoForm.vue │ ├── importTable.vue │ └── index.vue │ └── swagger │ └── index.vue ├── vite.config.js └── vite └── plugins ├── auto-import.js ├── compression.js ├── index.js ├── setup-extend.js └── svg-icon.js /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /.idea 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "salvo-admin" 3 | version = "0.2.1" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | salvo = { version = "0.73.0", features = [ 10 | "serve-static", 11 | "oapi", 12 | "logging", 13 | "catch-panic", 14 | "websocket", 15 | "session", 16 | ] } 17 | captcha = "0.0.9" 18 | md5 = "0.7.0" 19 | jsonwebtoken = "8" 20 | serde = { version = "1", features = ["derive"] } 21 | serde_json = "1" 22 | rbs = { version = "4.5" } 23 | rbatis = { version = "4.5", features = ["debug_mode"] } 24 | rbdc-mysql = { version = "4.5" } 25 | tokio = { version = "1", features = ["full"] } 26 | tokio-stream = { version = "0.1.14", features = ["net"] } 27 | futures-util = "0.3" 28 | once_cell = "1.16.0" 29 | uuid = { version = "1.3.2", features = [ 30 | "v4", # Lets you generate random UUIDs 31 | "fast-rng", # Use a faster (but still sufficiently random) RNG 32 | "macro-diagnostics", # Enable better diagnostics for compile-time UUIDs 33 | ] } 34 | redis = { version = "0.23.0", features = ["tokio-comp"] } 35 | sysinfo = "0.30.1" 36 | byte-unit = "5.1.2" 37 | tracing = "0.1" 38 | tracing-subscriber = "0.3" 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Savlo 3 |

4 |

salvo-admin

5 |

基于salvo和Ruoyi-Vue3的rust快速开发框架

6 | 7 | ## 简介 8 | 9 | * [salvo](https://github.com/salvo-rs/salvo) 是一个极其简单且功能强大的 Rust Web 后端框架. 仅仅需要基础 Rust 知识即可开发后端服务。 10 | * [Ruoyi-vue3](https://github.com/yangzongzhuan/RuoYi-Vue3) Vue3 + Element Plus + Vite 版本 11 | 12 | ## 环境 13 | 14 | os:windows 10
15 | rust:1.81.0
16 | salvo:0.73.0
17 | 18 | ## 运行 19 | 20 | ```bash 21 | # 克隆项目 22 | git clone https://github.com/lyqgit/salvo-admin.git 23 | 24 | # 进入项目目录 25 | cd salvo-admin 26 | 27 | # 启动后端服务 28 | cargo run 29 | 30 | # 后端访问地址 http://localhost:8090 31 | # 后端文档访问地址 http://localhost:8090/swagger-ui (加入了用户名和密码验证) 32 | 33 | # 进入前台项目目录 34 | cd ui 35 | 36 | # 安装依赖 37 | yarn --registry=https://registry.npmmirror.com 38 | 39 | # 启动前端服务 40 | yarn dev 41 | 42 | # 构建测试环境 yarn build:stage 43 | # 构建生产环境 yarn build:prod 44 | # 前端访问地址 http://localhost:80 45 | ``` 46 | 47 | ## 账号 48 | 49 | ### admin admin123 50 | ### ry ry123 51 | 52 | ## 接口文档账号 53 | 54 | ### admin salvo-admin2023 55 | 56 | ## 问题 57 | 58 | ### 当js无法访问后台接口时,可以尝试修改vite.config.js target: 'http://127.0.0.1:8090', 59 | 60 | ## 内置功能 61 | 62 | 1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。 63 | 2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 64 | 3. 岗位管理:配置系统用户所属担任职务。 65 | 4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。 66 | 5. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。 67 | 6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。 68 | 7. excel管理:嵌入[e-sheet](https://github.com/lyqgit/e-sheet),web excel支持多人协同编辑---beta。 69 | 8. 公告管理:配置系统公告信息。 -------------------------------------------------------------------------------- /sql/tool_excel.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `tool_excel` ( 2 | `excel_id` longtext COLLATE utf8_unicode_ci NOT NULL, 3 | `excel_name` text COLLATE utf8_unicode_ci NOT NULL, 4 | `excel_data` longtext COLLATE utf8_unicode_ci, 5 | `user_id` bigint(20) NOT NULL, 6 | `create_time` datetime DEFAULT NULL, 7 | `update_time` datetime DEFAULT NULL, 8 | PRIMARY KEY (`excel_id`(100)) USING BTREE 9 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='在线文档'; -------------------------------------------------------------------------------- /src/controller/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod common_controller; 2 | pub mod user_controller; 3 | pub mod dict_controller; 4 | pub mod menu_controller; 5 | pub mod role_controller; 6 | pub mod dept_controller; 7 | pub mod post_controller; 8 | pub mod chat_controller; 9 | pub mod swagger_controller; 10 | pub mod monitor_controller; 11 | 12 | pub mod excel_controller; 13 | pub mod notice_controller; -------------------------------------------------------------------------------- /src/controller/monitor_controller.rs: -------------------------------------------------------------------------------- 1 | use salvo::{oapi::endpoint}; 2 | use crate::utils::res::{ match_ok_common_result_no_error, Res, ResObj}; 3 | use crate::service::monitor_service; 4 | use crate::model::monitor_model::ServerInfo; 5 | 6 | #[endpoint( 7 | tags("系统"), 8 | responses( 9 | (status_code = 200,body=ResObj,description ="部门列表") 10 | ), 11 | )] 12 | pub async fn get_server_info()->Res{ 13 | match_ok_common_result_no_error(monitor_service::get_sys_info().await) 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/entity/excel_entity.rs: -------------------------------------------------------------------------------- 1 | use rbatis::rbdc::datetime::DateTime; 2 | use serde::{Serialize, Deserialize}; 3 | 4 | #[derive(Debug,Serialize,Deserialize,Clone)] 5 | pub struct ToolExcelEntity{ 6 | pub excel_id:Option, 7 | pub excel_name:Option, 8 | pub excel_data:Option, 9 | pub user_id:Option, 10 | pub create_time:Option, 11 | pub update_time:Option, 12 | } -------------------------------------------------------------------------------- /src/entity/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod sys_user_entity; 2 | pub mod sys_captcha_entity; 3 | pub mod sys_role_entity; 4 | pub mod sys_menu_entity; 5 | pub mod sys_dict_data_entity; 6 | pub mod sys_dict_type_entity; 7 | pub mod sys_role_menu_entity; 8 | pub mod sys_dept_entity; 9 | pub mod sys_post_entity; 10 | pub mod sys_user_role_entity; 11 | pub mod sys_user_post_entity; 12 | pub mod excel_entity; 13 | pub mod sys_notice_entity; -------------------------------------------------------------------------------- /src/entity/sys_captcha_entity.rs: -------------------------------------------------------------------------------- 1 | use serde::{Serialize,Deserialize}; 2 | use rbatis::rbdc::datetime::DateTime; 3 | 4 | #[derive(Debug,Serialize,Deserialize,Clone)] 5 | pub struct SysCaptcha{ 6 | pub id:i64, 7 | pub code:String, 8 | pub create_time:DateTime, 9 | pub expire_time:i128, 10 | } -------------------------------------------------------------------------------- /src/entity/sys_dept_entity.rs: -------------------------------------------------------------------------------- 1 | use rbatis::rbdc::datetime::DateTime; 2 | use serde::{Serialize, Deserialize}; 3 | 4 | #[derive(Debug,Serialize,Deserialize,Clone)] 5 | pub struct SysDeptEntity{ 6 | pub dept_id:Option, 7 | pub parent_id:Option, 8 | pub ancestors:Option, 9 | pub dept_name:Option, 10 | pub order_num:Option, 11 | pub leader:Option, 12 | pub phone:Option, 13 | pub email:Option, 14 | pub status:Option, 15 | pub del_flag:Option, 16 | pub create_by:Option, 17 | pub create_time:Option, 18 | pub update_by:Option, 19 | pub update_time:Option, 20 | } -------------------------------------------------------------------------------- /src/entity/sys_dict_data_entity.rs: -------------------------------------------------------------------------------- 1 | use salvo::oapi::ToSchema; 2 | use serde::{Serialize,Deserialize}; 3 | use rbatis::rbdc::datetime::DateTime; 4 | 5 | #[derive(Debug,Serialize,Deserialize,Clone,ToSchema)] 6 | #[salvo(schema(rename_all="camelCase"))] 7 | pub struct SysDictData{ 8 | #[serde(rename(serialize="dictCode"))] 9 | pub dict_code:i64, 10 | #[serde(rename(serialize="dictSort"))] 11 | pub dict_sort:i8, 12 | #[serde(rename(serialize="dictLabel"))] 13 | pub dict_label:String, 14 | #[serde(rename(serialize="dictValue"))] 15 | pub dict_value:String, 16 | #[serde(rename(serialize="dictType"))] 17 | pub dict_type:String, 18 | #[serde(rename(serialize="cssClass"))] 19 | pub css_class:Option, 20 | #[serde(rename(serialize="listClass"))] 21 | pub list_class:Option, 22 | #[serde(rename(serialize="isDefault"))] 23 | pub is_default:String, 24 | pub status:String, 25 | #[serde(rename(serialize="createBy"))] 26 | pub create_by:String, 27 | #[serde(rename(serialize="createTime"))] 28 | pub create_time:DateTime, 29 | #[serde(rename(serialize="updateBy"))] 30 | pub update_by:String, 31 | #[serde(rename(serialize="updateTime"))] 32 | pub update_time:Option, 33 | pub remark:Option 34 | } 35 | 36 | 37 | #[derive(Debug,Serialize,Deserialize,Clone,ToSchema)] 38 | pub struct SysDictDataEntity{ 39 | pub dict_code:i64, 40 | pub dict_sort:i8, 41 | pub dict_label:String, 42 | pub dict_value:String, 43 | pub dict_type:String, 44 | pub css_class:Option, 45 | pub list_class:Option, 46 | pub is_default:String, 47 | pub status:String, 48 | pub create_by:String, 49 | pub create_time:DateTime, 50 | pub update_by:String, 51 | pub update_time:Option, 52 | pub remark:Option 53 | } -------------------------------------------------------------------------------- /src/entity/sys_dict_type_entity.rs: -------------------------------------------------------------------------------- 1 | use salvo::oapi::ToSchema; 2 | use serde::{Serialize,Deserialize}; 3 | use rbatis::rbdc::datetime::DateTime; 4 | 5 | #[derive(Debug,Serialize,Deserialize,Clone,ToSchema)] 6 | #[salvo(schema(rename_all="camelCase"))] 7 | pub struct SysDictType{ 8 | #[serde(rename(serialize="dictId"))] 9 | pub dict_id:i64, 10 | #[serde(rename(serialize="dictName"))] 11 | pub dict_name:String, 12 | #[serde(rename(serialize="dictType"))] 13 | pub dict_type:String, 14 | pub status:String, 15 | #[serde(rename(serialize="createBy"))] 16 | pub create_by:String, 17 | #[serde(rename(serialize="createTime"))] 18 | pub create_time:DateTime, 19 | #[serde(rename(serialize="updateBy"))] 20 | pub update_by:Option, 21 | #[serde(rename(serialize="updateTime"))] 22 | pub update_time:Option, 23 | pub remark:Option 24 | } 25 | 26 | 27 | #[derive(Debug,Serialize,Deserialize,Clone,ToSchema)] 28 | pub struct ModifySysDictType{ 29 | #[serde(rename(deserialize="dictId"))] 30 | pub dict_id:i64, 31 | #[serde(rename(deserialize="dictName"))] 32 | pub dict_name:String, 33 | #[serde(rename(deserialize="dictType"))] 34 | pub dict_type:String, 35 | pub status:String, 36 | #[serde(rename(deserialize="createBy"))] 37 | pub create_by:String, 38 | #[serde(rename(deserialize="createTime"))] 39 | pub create_time:DateTime, 40 | #[serde(rename(deserialize="updateBy"))] 41 | pub update_by:Option, 42 | #[serde(rename(deserialize="updateTime"))] 43 | pub update_time:Option, 44 | pub remark:Option 45 | } -------------------------------------------------------------------------------- /src/entity/sys_menu_entity.rs: -------------------------------------------------------------------------------- 1 | use serde::{Serialize,Deserialize}; 2 | use rbatis::rbdc::datetime::DateTime; 3 | 4 | #[derive(Debug,Serialize,Deserialize,Clone)] 5 | pub struct SysMenu{ 6 | pub menu_id:i64, 7 | pub menu_name:String, 8 | pub parent_id:i64, 9 | pub order_num:i64, 10 | pub path:String, 11 | pub component:Option, 12 | pub query:Option, 13 | pub is_frame:i8, 14 | pub is_cache:i8, 15 | pub menu_type:String, 16 | pub visible:String, 17 | pub status:String, 18 | pub perms:Option, 19 | pub icon:String, 20 | pub create_by:String, 21 | pub create_time:DateTime, 22 | pub update_by:String, 23 | pub update_time:Option, 24 | pub remark:String, 25 | } -------------------------------------------------------------------------------- /src/entity/sys_notice_entity.rs: -------------------------------------------------------------------------------- 1 | use serde::{Serialize,Deserialize}; 2 | use rbatis::rbdc::datetime::DateTime; 3 | 4 | #[derive(Debug,Serialize,Deserialize,Clone)] 5 | pub struct SysNoticeEntity{ 6 | pub notice_id:Option, 7 | pub notice_title:Option, 8 | pub notice_type:Option, 9 | pub notice_content:Option, 10 | pub status:Option, 11 | pub create_by:Option, 12 | pub create_time:Option, 13 | pub update_by:Option, 14 | pub update_time:Option, 15 | pub remark:Option, 16 | } -------------------------------------------------------------------------------- /src/entity/sys_post_entity.rs: -------------------------------------------------------------------------------- 1 | use serde::{Serialize,Deserialize}; 2 | use rbatis::rbdc::datetime::DateTime; 3 | 4 | #[derive(Debug,Serialize,Deserialize,Clone)] 5 | pub struct SysPostEntity{ 6 | pub post_id:Option, 7 | pub post_code:Option, 8 | pub post_name:Option, 9 | pub post_sort:Option, 10 | pub status:Option, 11 | pub create_by:Option, 12 | pub create_time:Option, 13 | pub update_by:Option, 14 | pub update_time:Option, 15 | pub remark:Option, 16 | } -------------------------------------------------------------------------------- /src/entity/sys_role_entity.rs: -------------------------------------------------------------------------------- 1 | use serde::{Serialize, Deserialize}; 2 | use rbatis::rbdc::datetime::DateTime; 3 | use crate::model::role_model::SysRoleList; 4 | 5 | #[derive(Debug,Serialize,Deserialize,Clone)] 6 | pub struct SysRole{ 7 | pub role_id:i64, 8 | pub role_name:String, 9 | pub role_key:String, 10 | pub role_sort:i64, 11 | pub data_scope:String, 12 | pub menu_check_strictly:i8, 13 | pub dept_check_strictly:i8, 14 | pub status:String, 15 | pub del_flag:String, 16 | pub create_by:String, 17 | pub create_time:DateTime, 18 | pub update_by:Option, 19 | pub update_time:Option, 20 | pub remark:Option, 21 | } 22 | 23 | impl SysRole { 24 | #[allow(dead_code)] 25 | #[allow(unused_must_use)] 26 | pub fn into_sys_role_list(self)->SysRoleList{ 27 | SysRoleList{ 28 | role_id: Some(self.role_id), 29 | role_name: Some(self.role_name), 30 | role_key: Some(self.role_key), 31 | role_sort: Some(self.role_sort), 32 | data_scope: Some(self.data_scope), 33 | menu_check_strictly: Some(self.menu_check_strictly), 34 | dept_check_strictly: Some(self.dept_check_strictly), 35 | status: Some(self.status), 36 | del_flag: Some(self.del_flag), 37 | create_by: Some(self.create_by), 38 | create_time: Some(self.create_time), 39 | update_by: self.update_by, 40 | update_time: self.update_time, 41 | remark: self.remark 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/entity/sys_role_menu_entity.rs: -------------------------------------------------------------------------------- 1 | use serde::{Serialize,Deserialize}; 2 | 3 | #[derive(Debug,Serialize,Deserialize,Clone)] 4 | pub struct SysRoleMenuEntity{ 5 | pub role_id:i64, 6 | pub menu_id:i64, 7 | } -------------------------------------------------------------------------------- /src/entity/sys_user_post_entity.rs: -------------------------------------------------------------------------------- 1 | use serde::{Serialize,Deserialize}; 2 | 3 | #[derive(Debug,Serialize,Deserialize,Clone)] 4 | pub struct SysUserPostEntity { 5 | pub user_id: i64, 6 | pub post_id: i64, 7 | } -------------------------------------------------------------------------------- /src/entity/sys_user_role_entity.rs: -------------------------------------------------------------------------------- 1 | use serde::{Serialize,Deserialize}; 2 | 3 | #[derive(Debug,Serialize,Deserialize,Clone)] 4 | pub struct SysUserRoleEntity { 5 | pub user_id: i64, 6 | pub role_id: i64, 7 | } -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use once_cell::sync::Lazy; 2 | use rbatis::RBatis; 3 | use redis::Client; 4 | use salvo::conn::TcpListener; 5 | use salvo::{Listener, Server}; 6 | use salvo::http::request::set_global_secure_max_size; 7 | use tracing; 8 | 9 | mod controller; 10 | mod entity; 11 | mod mapper; 12 | mod model; 13 | mod router; 14 | mod service; 15 | mod utils; 16 | 17 | mod websocket; 18 | 19 | pub static GLOBAL_DB: Lazy = Lazy::new(|| RBatis::new()); 20 | 21 | pub static GLOBAL_REDIS: Lazy = 22 | Lazy::new(|| Client::open("redis://127.0.0.1/").expect("连接redis失败")); 23 | 24 | #[tokio::main] 25 | async fn main() { 26 | tracing_subscriber::fmt().init(); 27 | 28 | // 连接数据库 29 | utils::mysql::init_db().await; 30 | tracing::info!("数据库连接成功"); 31 | 32 | // 连接redis 33 | GLOBAL_REDIS.get_connection().expect("连接redis失败"); 34 | tracing::info!("redis连接成功"); 35 | 36 | let service = router::init_service(); 37 | 38 | // 设置服务器最大接收数据 39 | set_global_secure_max_size(64 * 1024 * 100); 40 | 41 | Server::new(TcpListener::new("0.0.0.0:8090").bind().await) 42 | .serve(service) 43 | .await; 44 | } 45 | -------------------------------------------------------------------------------- /src/mapper/captcha_mapper.rs: -------------------------------------------------------------------------------- 1 | use crate::entity::sys_captcha_entity::SysCaptcha; 2 | use rbatis::{crud,impl_select}; 3 | 4 | crud!(SysCaptcha{},"sys_captcha"); 5 | 6 | impl_select!(SysCaptcha{select_captcha_by_code(code:String)=>"`where code = #{code} limit 1`"}); -------------------------------------------------------------------------------- /src/mapper/dept_mapper.rs: -------------------------------------------------------------------------------- 1 | use rbatis::{crud,html_sql}; 2 | use rbatis::executor::Executor; 3 | use rbatis::rbdc::db::ExecResult; 4 | use crate::entity::sys_dept_entity::SysDeptEntity; 5 | use crate::model::dept_model::DeptList; 6 | 7 | #[html_sql("src/mapper/xml/dept_xml.html")] 8 | pub async fn get_dept_by_user_id(rb: &mut dyn Executor,user_id:i32)->rbatis::Result>{ 9 | impled!() 10 | } 11 | 12 | #[html_sql("src/mapper/xml/dept_xml.html")] 13 | pub async fn get_dept_list(rb: &mut dyn Executor,dept_name:Option,status:Option)->rbatis::Result>{ 14 | impled!() 15 | } 16 | 17 | #[html_sql("src/mapper/xml/dept_xml.html")] 18 | pub async fn get_dept_tree_by_id(rb: &mut dyn Executor,dept_id:i64)->rbatis::Result>{ 19 | impled!() 20 | } 21 | 22 | #[html_sql("src/mapper/xml/dept_xml.html")] 23 | pub async fn get_dept_by_id(rb: &mut dyn Executor,dept_id:i64)->rbatis::Result>{ 24 | impled!() 25 | } 26 | 27 | #[html_sql("src/mapper/xml/dept_xml.html")] 28 | pub async fn get_dept_list_exclude_id(rb: &mut dyn Executor,dept_id:i64)->rbatis::Result>{ 29 | impled!() 30 | } 31 | 32 | #[html_sql("src/mapper/xml/dept_xml.html")] 33 | pub async fn del_dept_by_id(rb: &mut dyn Executor,dept_id:String)->rbatis::Result{ 34 | impled!() 35 | } 36 | 37 | crud!(SysDeptEntity{},"sys_dept"); -------------------------------------------------------------------------------- /src/mapper/excel_mapper.rs: -------------------------------------------------------------------------------- 1 | use rbatis::{crud,html_sql}; 2 | use rbatis::executor::Executor; 3 | use crate::entity::excel_entity::ToolExcelEntity; 4 | use crate::model::excel_model::{ExcelList,ExcelDetail}; 5 | 6 | #[html_sql("src/mapper/xml/excel_xml.html")] 7 | pub async fn get_excel_list_by_id(rb: &mut dyn Executor,user_id:i32)->rbatis::Result>{ 8 | impled!() 9 | } 10 | 11 | #[html_sql("src/mapper/xml/excel_xml.html")] 12 | pub async fn get_excel_list(rb: &mut dyn Executor)->rbatis::Result>{ 13 | impled!() 14 | } 15 | 16 | #[html_sql("src/mapper/xml/excel_xml.html")] 17 | pub async fn get_excel_detail_by_id(rb: &mut dyn Executor,excel_id:String)->rbatis::Result>{ 18 | impled!() 19 | } 20 | 21 | crud!(ToolExcelEntity{},"tool_excel"); -------------------------------------------------------------------------------- /src/mapper/menu_mapper.rs: -------------------------------------------------------------------------------- 1 | use rbatis::{html_sql, executor::Executor,crud}; 2 | use crate::entity::sys_menu_entity::SysMenu; 3 | use crate::model::menu_model::SysMenuPage; 4 | 5 | #[html_sql("src/mapper/xml/menu_xml.html")] 6 | pub async fn select_menus_by_role_id(rb: &mut dyn Executor,is_admin:bool,id:String)->rbatis::Result>{ 7 | impled!() 8 | } 9 | 10 | #[html_sql("src/mapper/xml/menu_xml.html")] 11 | pub async fn select_menus_by_user_id(rb: &mut dyn Executor,is_admin:bool,id:i32)->rbatis::Result>{ 12 | impled!() 13 | } 14 | 15 | #[html_sql("src/mapper/xml/menu_xml.html")] 16 | pub async fn select_menus_list(rb: &mut dyn Executor,menu_name:Option,status:Option)->rbatis::Result>{ 17 | impled!() 18 | } 19 | 20 | #[html_sql("src/mapper/xml/menu_xml.html")] 21 | pub async fn select_menus_by_id(rb: &mut dyn Executor,menu_id:i64)->rbatis::Result>{ 22 | impled!() 23 | } 24 | 25 | crud!(SysMenu{}); 26 | -------------------------------------------------------------------------------- /src/mapper/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod captcha_mapper; 2 | pub mod user_mapper; 3 | pub mod role_mapper; 4 | pub mod menu_mapper; 5 | pub mod dict_mapper; 6 | pub mod role_menu_mapper; 7 | pub mod dept_mapper; 8 | pub mod post_mapper; 9 | pub mod user_role_mapper; 10 | pub mod user_post_mapper; 11 | 12 | pub mod excel_mapper; 13 | pub mod notice_mapper; 14 | -------------------------------------------------------------------------------- /src/mapper/notice_mapper.rs: -------------------------------------------------------------------------------- 1 | use rbatis::executor::Executor; 2 | use rbatis::{crud, html_sql}; 3 | use rbatis::rbdc::db::ExecResult; 4 | use crate::entity::sys_notice_entity::SysNoticeEntity; 5 | use crate::model::notice_model::SysNoticeList; 6 | 7 | #[html_sql("src/mapper/xml/notice_xml.html")] 8 | pub async fn get_notice_page(rb: &mut dyn Executor,page_num:u64,page_size:u64,notice_title:Option,notice_type:Option,status:Option)->rbatis::Result>{ 9 | impled!() 10 | } 11 | 12 | #[html_sql("src/mapper/xml/notice_xml.html")] 13 | pub async fn get_notice_count(rb: &mut dyn Executor,notice_title:Option,notice_type:Option,status:Option)->rbatis::Result{ 14 | impled!() 15 | } 16 | 17 | #[html_sql("src/mapper/xml/notice_xml.html")] 18 | pub async fn get_notice_by_id(rb: &mut dyn Executor,notice_id:i64)->rbatis::Result>{ 19 | impled!() 20 | } 21 | 22 | #[html_sql("src/mapper/xml/notice_xml.html")] 23 | pub async fn del_notice_by_id(rb: &mut dyn Executor,notice_id:String)->rbatis::Result{ 24 | impled!() 25 | } 26 | 27 | #[html_sql("src/mapper/xml/notice_xml.html")] 28 | pub async fn get_notice_list(rb: &mut dyn Executor)->rbatis::Result>{ 29 | impled!() 30 | } 31 | 32 | #[html_sql("src/mapper/xml/notice_xml.html")] 33 | pub async fn get_notice_list_by_user_id(rb: &mut dyn Executor,user_id:i32)->rbatis::Result>{ 34 | impled!() 35 | } 36 | 37 | 38 | crud!(SysNoticeEntity{},"sys_notice"); -------------------------------------------------------------------------------- /src/mapper/post_mapper.rs: -------------------------------------------------------------------------------- 1 | use rbatis::executor::Executor; 2 | use rbatis::{crud, html_sql}; 3 | use rbatis::rbdc::db::ExecResult; 4 | use crate::entity::sys_post_entity::SysPostEntity; 5 | use crate::model::post_model::SysPostList; 6 | 7 | #[html_sql("src/mapper/xml/post_xml.html")] 8 | pub async fn get_post_page(rb: &mut dyn Executor,page_num:u64,page_size:u64,post_code:Option,post_name:Option,status:Option)->rbatis::Result>{ 9 | impled!() 10 | } 11 | 12 | #[html_sql("src/mapper/xml/post_xml.html")] 13 | pub async fn get_post_count(rb: &mut dyn Executor,post_code:Option,post_name:Option,status:Option)->rbatis::Result{ 14 | impled!() 15 | } 16 | 17 | #[html_sql("src/mapper/xml/post_xml.html")] 18 | pub async fn get_post_by_id(rb: &mut dyn Executor,post_id:i64)->rbatis::Result>{ 19 | impled!() 20 | } 21 | 22 | #[html_sql("src/mapper/xml/post_xml.html")] 23 | pub async fn del_post_by_id(rb: &mut dyn Executor,post_id:String)->rbatis::Result{ 24 | impled!() 25 | } 26 | 27 | #[html_sql("src/mapper/xml/post_xml.html")] 28 | pub async fn get_post_list(rb: &mut dyn Executor)->rbatis::Result>{ 29 | impled!() 30 | } 31 | 32 | #[html_sql("src/mapper/xml/post_xml.html")] 33 | pub async fn get_post_list_by_user_id(rb: &mut dyn Executor,user_id:i32)->rbatis::Result>{ 34 | impled!() 35 | } 36 | 37 | 38 | crud!(SysPostEntity{},"sys_post"); -------------------------------------------------------------------------------- /src/mapper/role_menu_mapper.rs: -------------------------------------------------------------------------------- 1 | use rbatis::{crud,html_sql}; 2 | use rbatis::executor::Executor; 3 | use rbatis::rbdc::db::ExecResult; 4 | use crate::entity::sys_role_menu_entity::SysRoleMenuEntity; 5 | 6 | #[html_sql("src/mapper/xml/role_menu_xml.html")] 7 | pub async fn del_role_menu_by_role_id(rb: &mut dyn Executor,role_id:String)->rbatis::Result{ 8 | impled!() 9 | } 10 | 11 | #[html_sql("src/mapper/xml/role_menu_xml.html")] 12 | pub async fn get_menu_id_by_role_id(rb: &mut dyn Executor,role_id:i32)->rbatis::Result>{ 13 | impled!() 14 | } 15 | 16 | crud!(SysRoleMenuEntity{},"sys_role_menu"); -------------------------------------------------------------------------------- /src/mapper/user_mapper.rs: -------------------------------------------------------------------------------- 1 | use crate::entity::sys_user_entity::{SysUser, SysUserEntity,AddSysUserEntity}; 2 | use rbatis::{crud, html_sql, impl_select}; 3 | use rbatis::executor::Executor; 4 | use rbatis::rbdc::datetime::DateTime; 5 | use rbatis::rbdc::db::ExecResult; 6 | use crate::model::user_model::SysUserList; 7 | 8 | crud!(SysUser{},"sys_user"); 9 | 10 | impl_select!(SysUser{select_user_by_up(username:String,password:String)=>"`where user_name = #{username} and password = #{password} limit 1`"}); 11 | 12 | #[html_sql("src/mapper/xml/user_xml.html")] 13 | pub async fn get_user_page(rb: &mut dyn Executor,page_num:u64,page_size:u64,user_name:Option,phone_number:Option,status:Option,begin_time:Option,end_time:Option,dept_id:Option)->rbatis::Result>{ 14 | impled!() 15 | } 16 | 17 | #[html_sql("src/mapper/xml/user_xml.html")] 18 | pub async fn get_user_count(rb: &mut dyn Executor,user_name:Option,phone_number:Option,status:Option,begin_time:Option,end_time:Option,dept_id:Option)->rbatis::Result{ 19 | impled!() 20 | } 21 | 22 | #[html_sql("src/mapper/xml/user_xml.html")] 23 | pub async fn get_user_by_id(rb: &mut dyn Executor,user_id:Option)->rbatis::Result>{ 24 | impled!() 25 | } 26 | 27 | #[html_sql("src/mapper/xml/user_xml.html")] 28 | pub async fn update_user_status_by_id(rb: &mut dyn Executor,status:String,user_id:i64)->rbatis::Result{ 29 | impled!() 30 | } 31 | 32 | crud!(SysUserEntity{},"sys_user"); 33 | crud!(AddSysUserEntity{},"sys_user"); 34 | -------------------------------------------------------------------------------- /src/mapper/user_post_mapper.rs: -------------------------------------------------------------------------------- 1 | use rbatis::crud; 2 | use crate::entity::sys_user_post_entity::SysUserPostEntity; 3 | 4 | crud!(SysUserPostEntity{},"sys_user_post"); 5 | -------------------------------------------------------------------------------- /src/mapper/user_role_mapper.rs: -------------------------------------------------------------------------------- 1 | use rbatis::{crud,html_sql}; 2 | use rbatis::executor::Executor; 3 | use rbatis::rbdc::db::ExecResult; 4 | use crate::entity::sys_user_role_entity::SysUserRoleEntity; 5 | 6 | crud!(SysUserRoleEntity{},"sys_user_role"); 7 | 8 | #[html_sql("src/mapper/xml/user_role_xml.html")] 9 | pub async fn select_role_id_by_user_id(rb: &mut dyn Executor,user_id:i64)->rbatis::Result>{ 10 | impled!() 11 | } 12 | 13 | #[html_sql("src/mapper/xml/user_role_xml.html")] 14 | pub async fn del_by_role_and_user_id(rb: &mut dyn Executor,user_id:i64,role_id:String)->rbatis::Result{ 15 | impled!() 16 | } 17 | 18 | #[html_sql("src/mapper/xml/user_role_xml.html")] 19 | pub async fn del_by_role_and_user_id_more(rb: &mut dyn Executor,user_id:String,role_id:i64)->rbatis::Result{ 20 | impled!() 21 | } -------------------------------------------------------------------------------- /src/mapper/xml/dept_xml.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 21 | 30 | 40 | 46 | 47 | `delete from sys_dept` 48 | 49 | `dept_id = ( ${dept_id} )` 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/mapper/xml/excel_xml.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 16 | 25 | -------------------------------------------------------------------------------- /src/mapper/xml/menu_xml.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 19 | 20 | 32 | 33 | 39 | -------------------------------------------------------------------------------- /src/mapper/xml/notice_xml.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 22 | 28 | 43 | 44 | `delete from sys_notice` 45 | 46 | `1 = 1 and notice_id in ( ${notice_id} )` 47 | 48 | 49 | 52 | -------------------------------------------------------------------------------- /src/mapper/xml/post_xml.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 22 | 28 | 43 | 44 | `delete from sys_post` 45 | 46 | `1 = 1 and post_id in ( ${post_id} )` 47 | 48 | 49 | 52 | -------------------------------------------------------------------------------- /src/mapper/xml/role_menu_xml.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | `delete from sys_role_menu` 6 | 7 | `role_id in ( ${role_id} )` 8 | 9 | 10 | 11 | 17 | 18 | -------------------------------------------------------------------------------- /src/mapper/xml/user_role_xml.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | `delete from sys_user_role` 11 | 12 | `user_id in ( ${user_id} ) and role_id = #{role_id}` 13 | 14 | 15 | 16 | `delete from sys_user_role` 17 | 18 | `user_id in ( ${user_id} ) and role_id = #{role_id}` 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/model/chat_model.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize,Serialize}; 2 | use salvo::oapi::{ToSchema}; 3 | 4 | #[derive(Debug,Deserialize)] 5 | pub struct ChatRxMsg{ 6 | pub token:String, 7 | pub name:String, 8 | pub msg:String, 9 | } 10 | 11 | #[derive(Debug,Serialize,ToSchema)] 12 | pub struct ChatTxMsg{ 13 | pub name:String, 14 | pub msg:String, 15 | } 16 | -------------------------------------------------------------------------------- /src/model/common_model.rs: -------------------------------------------------------------------------------- 1 | use salvo::oapi::{ToSchema}; 2 | use serde::{Serialize}; 3 | 4 | #[derive(Debug,Serialize,ToSchema)] 5 | pub struct ResObj{ 6 | pub code:i32, 7 | pub data:Option, 8 | pub msg:String 9 | } 10 | 11 | #[derive(Debug,Serialize,ToSchema)] 12 | pub struct Page{ 13 | pub rows:Vec, 14 | pub total:u64, 15 | } -------------------------------------------------------------------------------- /src/model/dept_model.rs: -------------------------------------------------------------------------------- 1 | use salvo::{oapi::{ToSchema}}; 2 | use salvo::oapi::ToParameters; 3 | use serde::{Serialize,Deserialize}; 4 | 5 | #[derive(Debug,Serialize,ToSchema,Deserialize,Clone)] 6 | #[salvo(schema(rename_all="camelCase"))] 7 | #[serde(rename_all(serialize="camelCase"))] 8 | pub struct DeptList{ 9 | pub dept_id:Option, 10 | pub parent_id:Option, 11 | pub ancestors:Option, 12 | pub dept_name:Option, 13 | pub order_num:Option, 14 | pub leader:Option, 15 | pub phone:Option, 16 | pub email:Option, 17 | pub status:Option, 18 | pub del_flag:Option, 19 | pub create_by:Option, 20 | pub create_time:Option, 21 | pub update_by:Option, 22 | pub update_time:Option, 23 | } 24 | 25 | #[derive(Debug,Serialize,ToParameters,Deserialize,Clone)] 26 | #[salvo(parameters(rename_all="camelCase"))] 27 | #[serde(rename_all(deserialize="camelCase"))] 28 | #[salvo(parameters(default_parameter_in = Query))] 29 | pub struct DeptListPayload{ 30 | pub dept_name:Option, 31 | pub status:Option, 32 | } 33 | 34 | #[derive(Debug,Serialize,ToSchema,Deserialize,Clone)] 35 | #[salvo(schema(rename_all="camelCase"))] 36 | #[serde(rename_all(deserialize="camelCase"))] 37 | pub struct DeptModifyPayload{ 38 | pub dept_id:Option, 39 | pub parent_id:i64, 40 | pub dept_name:String, 41 | pub order_num:i8, 42 | pub leader:Option, 43 | pub phone:Option, 44 | pub email:Option, 45 | pub status:Option, 46 | } 47 | 48 | #[derive(Debug,Serialize,ToSchema,Clone)] 49 | pub struct DeptTree{ 50 | #[serde(skip_serializing_if = "Option::is_none")] 51 | #[salvo(schema(value_type=Option>))] 52 | pub children:Option>, 53 | pub id:i64, 54 | pub label:String, 55 | } 56 | -------------------------------------------------------------------------------- /src/model/excel_model.rs: -------------------------------------------------------------------------------- 1 | use salvo::{oapi::{ToSchema}}; 2 | use serde::{Serialize,Deserialize}; 3 | use rbatis::rbdc::datetime::DateTime; 4 | 5 | #[derive(Debug,Serialize,ToSchema,Deserialize,Clone)] 6 | #[salvo(schema(rename_all="camelCase"))] 7 | #[serde(rename_all(deserialize="camelCase"))] 8 | pub struct ExcelModifyPayload{ 9 | pub excel_id:Option, 10 | pub excel_name:Option, 11 | pub excel_data:Option, 12 | } 13 | 14 | #[derive(Debug,Serialize,ToSchema,Deserialize,Clone)] 15 | #[salvo(schema(rename_all="camelCase"))] 16 | #[serde(rename_all(serialize="camelCase"))] 17 | pub struct ExcelList{ 18 | pub excel_id:Option, 19 | pub excel_name:Option, 20 | } 21 | 22 | #[derive(Debug,Serialize,ToSchema,Deserialize,Clone)] 23 | #[salvo(schema(rename_all="camelCase"))] 24 | #[serde(rename_all(serialize="camelCase"))] 25 | pub struct ExcelDetail{ 26 | pub excel_id:Option, 27 | pub excel_name:Option, 28 | pub excel_data:Option, 29 | pub create_time:Option, 30 | pub update_time:Option, 31 | } 32 | -------------------------------------------------------------------------------- /src/model/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod common_model; 2 | pub mod user_model; 3 | pub mod menu_model; 4 | pub mod dict_model; 5 | pub mod role_model; 6 | pub mod dept_model; 7 | pub mod post_model; 8 | pub mod chat_model; 9 | pub mod swagger_model; 10 | pub mod monitor_model; 11 | pub mod excel_model; 12 | pub mod notice_model; -------------------------------------------------------------------------------- /src/model/monitor_model.rs: -------------------------------------------------------------------------------- 1 | use salvo::{oapi::{ToSchema}}; 2 | use serde::{Serialize,Deserialize}; 3 | 4 | #[derive(Debug,Serialize,ToSchema,Deserialize,Clone)] 5 | #[salvo(schema(rename_all="camelCase"))] 6 | #[serde(rename_all(serialize="camelCase"))] 7 | pub struct Cpu{ 8 | pub cpu_num:usize, 9 | pub used:f32, 10 | pub brand:String, 11 | pub frequency:u64, 12 | } 13 | 14 | #[derive(Debug,Serialize,ToSchema,Deserialize,Clone)] 15 | #[salvo(schema(rename_all="camelCase"))] 16 | #[serde(rename_all(serialize="camelCase"))] 17 | pub struct Mem{ 18 | pub total:String, 19 | pub used:String, 20 | pub total_swap:String, 21 | pub used_swap:String, 22 | } 23 | 24 | #[derive(Debug,Serialize,ToSchema,Deserialize,Clone)] 25 | #[salvo(schema(rename_all="camelCase"))] 26 | #[serde(rename_all(serialize="camelCase"))] 27 | pub struct Sys{ 28 | pub os_name:Option, 29 | pub os_version:Option, 30 | pub host_name:Option, 31 | pub kernel_version:Option, 32 | } 33 | 34 | #[derive(Debug,Serialize,ToSchema,Deserialize,Clone)] 35 | #[salvo(schema(rename_all="camelCase"))] 36 | #[serde(rename_all(serialize="camelCase"))] 37 | pub struct SysFiles{ 38 | pub name:String, // 硬盘名称 39 | pub sys_type_name:String, // 文件系统 40 | pub type_name:String, // 盘符类型 41 | pub total:String, 42 | pub free:String, 43 | } 44 | 45 | #[derive(Debug,Serialize,ToSchema,Deserialize,Clone)] 46 | #[salvo(schema(rename_all="camelCase"))] 47 | #[serde(rename_all(serialize="camelCase"))] 48 | pub struct ServerInfo{ 49 | pub cpu:Cpu, 50 | pub mem:Mem, 51 | pub sys:Sys, 52 | pub sys_files:Vec 53 | } 54 | -------------------------------------------------------------------------------- /src/model/notice_model.rs: -------------------------------------------------------------------------------- 1 | use serde::{Serialize,Deserialize}; 2 | use rbatis::rbdc::datetime::DateTime; 3 | use salvo::oapi::{ToParameters, ToSchema}; 4 | 5 | #[derive(Debug,Serialize,Deserialize,ToSchema,Clone)] 6 | #[salvo(schema(rename_all="camelCase"))] 7 | #[serde(rename_all(serialize="camelCase"))] 8 | pub struct SysNoticeList{ 9 | pub notice_id:Option, 10 | pub notice_title:Option, 11 | pub notice_type:Option, 12 | pub notice_content:Option, 13 | pub status:Option, 14 | pub create_by:Option, 15 | pub create_time:Option, 16 | pub update_by:Option, 17 | pub update_time:Option, 18 | pub remark:Option, 19 | } 20 | 21 | #[derive(Debug,Serialize,Deserialize,ToParameters,Clone)] 22 | #[salvo(parameters(rename_all="camelCase"))] 23 | #[serde(rename_all(deserialize="camelCase"))] 24 | #[salvo(parameters(default_parameter_in = Query))] 25 | pub struct SysNoticeListPayload{ 26 | pub page_num:u64, 27 | pub page_size:u64, 28 | pub notice_title:Option, 29 | pub notice_type:Option, 30 | pub status:Option, 31 | } 32 | 33 | #[derive(Debug,Serialize,Deserialize,ToSchema,Clone)] 34 | #[salvo(schema(rename_all="camelCase"))] 35 | #[serde(rename_all(deserialize="camelCase"))] 36 | pub struct SysNoticeModifyPayload{ 37 | pub notice_id:Option, 38 | pub notice_title:Option, 39 | pub notice_type:Option, 40 | pub notice_content:Option, 41 | pub status:Option, 42 | pub remark:Option, 43 | } 44 | -------------------------------------------------------------------------------- /src/model/post_model.rs: -------------------------------------------------------------------------------- 1 | use serde::{Serialize,Deserialize}; 2 | use rbatis::rbdc::datetime::DateTime; 3 | use salvo::oapi::{ToParameters, ToSchema}; 4 | 5 | #[derive(Debug,Serialize,Deserialize,ToSchema,Clone)] 6 | #[salvo(schema(rename_all="camelCase"))] 7 | #[serde(rename_all(serialize="camelCase"))] 8 | pub struct SysPostList{ 9 | pub post_id:Option, 10 | pub post_code:Option, 11 | pub post_name:Option, 12 | pub post_sort:Option, 13 | pub status:Option, 14 | pub create_by:Option, 15 | pub create_time:Option, 16 | pub update_by:Option, 17 | pub update_time:Option, 18 | } 19 | 20 | #[derive(Debug,Serialize,Deserialize,ToParameters,Clone)] 21 | #[salvo(parameters(rename_all="camelCase"))] 22 | #[serde(rename_all(deserialize="camelCase"))] 23 | #[salvo(parameters(default_parameter_in = Query))] 24 | pub struct SysPostListPayload{ 25 | pub page_num:u64, 26 | pub page_size:u64, 27 | pub post_code:Option, 28 | pub post_name:Option, 29 | pub status:Option, 30 | } 31 | 32 | #[derive(Debug,Serialize,Deserialize,ToSchema,Clone)] 33 | #[salvo(schema(rename_all="camelCase"))] 34 | #[serde(rename_all(deserialize="camelCase"))] 35 | pub struct SysPostModifyPayload{ 36 | pub post_id:Option, 37 | pub post_code:Option, 38 | pub post_name:Option, 39 | pub post_sort:Option, 40 | pub status:Option, 41 | pub remark:Option, 42 | } 43 | -------------------------------------------------------------------------------- /src/model/swagger_model.rs: -------------------------------------------------------------------------------- 1 | use serde::{Serialize,Deserialize}; 2 | 3 | #[derive(Debug,Serialize,Deserialize)] 4 | pub struct SwaggerAuth{ 5 | pub username:String, 6 | pub password:String, 7 | } 8 | -------------------------------------------------------------------------------- /src/router/dept_router.rs: -------------------------------------------------------------------------------- 1 | use salvo::Router; 2 | use crate::controller::{dept_controller}; 3 | 4 | pub fn init_router()->Router{ 5 | let router = Router::new(); 6 | router.push( 7 | Router::with_path("/system/dept/list").get(dept_controller::get_dept_list) 8 | ).push( 9 | Router::with_path("/system/dept").post(dept_controller::post_add_dept).put(dept_controller::put_edit_dept) 10 | ).push( 11 | Router::with_path("/system/dept/").get(dept_controller::get_dept_by_id).delete(dept_controller::del_dept_by_id) 12 | ).push( 13 | Router::with_path("/system/dept/list/exclude/").get(dept_controller::get_dept_list_exclude_id) 14 | ) 15 | } -------------------------------------------------------------------------------- /src/router/dict_router.rs: -------------------------------------------------------------------------------- 1 | use salvo::Router; 2 | use crate::controller::{dict_controller}; 3 | 4 | pub fn init_router()->Router{ 5 | let router = Router::new(); 6 | router.push( 7 | Router::with_path("/system/dict/type/list").get(dict_controller::get_dict_list) 8 | ) 9 | .push( 10 | Router::with_path("/system/dict/data/list").get(dict_controller::get_dict_data_list) 11 | ) 12 | .push( 13 | Router::with_path("/system/dict/data").post(dict_controller::post_add_dict_data).put(dict_controller::put_edit_dict_data) 14 | ) 15 | .push( 16 | Router::with_path("/system/dict/data/").delete(dict_controller::del_dict_type_data).get(dict_controller::get_dict_type_data_by_id) 17 | ) 18 | .push( 19 | Router::with_path("/system/dict/data/type/").get(dict_controller::get_dict_list_by_type) 20 | ) 21 | .push( 22 | Router::with_path("/system/dict/type/optionselect").get(dict_controller::get_all_dict_type) 23 | ) 24 | .push( 25 | Router::with_path("/system/dict/type/").get(dict_controller::get_dict_by_id).delete(dict_controller::del_dict_type) 26 | ) 27 | .push( 28 | Router::with_path("/system/dict/type").post(dict_controller::add_dict_type).put(dict_controller::edit_dict_type) 29 | ) 30 | } -------------------------------------------------------------------------------- /src/router/excel_router.rs: -------------------------------------------------------------------------------- 1 | use salvo::Router; 2 | use crate::controller::excel_controller; 3 | 4 | pub fn init_router()->Router{ 5 | let router = Router::new(); 6 | router.push( 7 | Router::with_path("/tool/excel/add").post(excel_controller::post_add_excel) 8 | ).push( 9 | Router::with_path("/tool/excel/edit").post(excel_controller::post_edit_excel) 10 | ).push( 11 | Router::with_path("/tool/excel/user/list").get(excel_controller::get_excel_list_by_user_id) 12 | ).push( 13 | Router::with_path("/tool/excel/list").get(excel_controller::get_excel_list) 14 | ).push( 15 | Router::with_path("/tool/excel/").get(excel_controller::get_excel_detail_by_excel_id) 16 | ) 17 | } -------------------------------------------------------------------------------- /src/router/menu_router.rs: -------------------------------------------------------------------------------- 1 | use salvo::Router; 2 | use crate::controller::{menu_controller}; 3 | 4 | pub fn init_router()->Router{ 5 | let router = Router::new(); 6 | router.push( 7 | Router::with_path("/system/menu/list").get(menu_controller::get_menu_list) 8 | ) 9 | .push( 10 | Router::with_path("/system/menu").post(menu_controller::add_menu).put(menu_controller::put_edit_menu) 11 | ) 12 | .push( 13 | Router::with_path("/system/menu/").delete(menu_controller::del_menu_by_id).get(menu_controller::get_menu_by_id) 14 | ) 15 | .push( 16 | Router::with_path("/system/menu/treeselect").get(menu_controller::get_menu_tree) 17 | ) 18 | .push( 19 | Router::with_path("/system/menu/roleMenuTreeselect/").get(menu_controller::get_role_menu_tree_by_user_id) 20 | ) 21 | } -------------------------------------------------------------------------------- /src/router/monitor_router.rs: -------------------------------------------------------------------------------- 1 | use salvo::Router; 2 | use crate::controller::monitor_controller; 3 | 4 | pub fn init_router()->Router{ 5 | let router = Router::new(); 6 | router.push( 7 | Router::with_path("/monitor/server").get(monitor_controller::get_server_info) 8 | ) 9 | } -------------------------------------------------------------------------------- /src/router/notice_router.rs: -------------------------------------------------------------------------------- 1 | use salvo::Router; 2 | use crate::controller::notice_controller; 3 | 4 | pub fn init_router() ->Router{ 5 | let router = Router::new(); 6 | router.push( 7 | Router::with_path("/system/notice/list").get(notice_controller::get_notice_page) 8 | ).push( 9 | Router::with_path("/system/notice").post(notice_controller::notice_add_notice).put(notice_controller::put_edit_notice) 10 | ).push( 11 | Router::with_path("/system/notice/").get(notice_controller::get_notice_by_id).delete(notice_controller::del_notice_by_id) 12 | ) 13 | } -------------------------------------------------------------------------------- /src/router/post_router.rs: -------------------------------------------------------------------------------- 1 | use salvo::Router; 2 | use crate::controller::post_controller; 3 | 4 | pub fn init_router() ->Router{ 5 | let router = Router::new(); 6 | router.push( 7 | Router::with_path("/system/post/list").get(post_controller::get_post_page) 8 | ).push( 9 | Router::with_path("/system/post").post(post_controller::post_add_post).put(post_controller::put_edit_post) 10 | ).push( 11 | Router::with_path("/system/post/").get(post_controller::get_post_by_id).delete(post_controller::del_post_by_id) 12 | ) 13 | } -------------------------------------------------------------------------------- /src/router/role_router.rs: -------------------------------------------------------------------------------- 1 | use salvo::Router; 2 | use crate::controller::{role_controller}; 3 | 4 | pub fn init_router()->Router{ 5 | let router = Router::new(); 6 | router.push( 7 | Router::with_path("/system/role/list").get(role_controller::get_roles_by_page) 8 | ) 9 | .push( 10 | Router::with_path("/system/role").post(role_controller::post_add_role).put(role_controller::put_edit_role) 11 | ) 12 | .push( 13 | Router::with_path("/system/role/changeStatus").put(role_controller::put_edit_role_status) 14 | ) 15 | .push( 16 | Router::with_path("/system/role/").delete(role_controller::del_role_by_id).get(role_controller::get_role_by_id) 17 | ) 18 | .push( 19 | Router::with_path("/system/role/authUser/allocatedList").get(role_controller::get_users_by_role_id_page) 20 | ) 21 | .push( 22 | Router::with_path("/system/role/authUser/unallocatedList").get(role_controller::get_users_by_not_in_role_id_page) 23 | ) 24 | .push( 25 | Router::with_path("/system/role/authUser/cancel").put(role_controller::del_user_role) 26 | ) 27 | .push( 28 | Router::with_path("/system/role/authUser/cancelAll").put(role_controller::del_user_role_all) 29 | ) 30 | .push( 31 | Router::with_path("/system/role/authUser/selectAll").put(role_controller::put_bind_more_user_and_simple_role) 32 | ) 33 | } -------------------------------------------------------------------------------- /src/service/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod user_service; 2 | pub mod role_service; 3 | pub mod menu_service; 4 | pub mod dict_service; 5 | pub mod dept_service; 6 | pub mod post_service; 7 | pub mod monitor_service; 8 | pub mod excel_service; 9 | pub mod notice_service; 10 | -------------------------------------------------------------------------------- /src/service/monitor_service.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::system; 2 | use crate::model::monitor_model::ServerInfo; 3 | 4 | pub async fn get_sys_info()->Result{ 5 | Ok(ServerInfo{ 6 | cpu:system::get_cpu_info(), 7 | mem:system::get_mem_info(), 8 | sys:system::get_sys_info(), 9 | sys_files: system::get_disk_info(), 10 | }) 11 | } -------------------------------------------------------------------------------- /src/utils/captcha.rs: -------------------------------------------------------------------------------- 1 | use captcha::Captcha; 2 | use captcha::filters::Noise; 3 | 4 | #[allow(dead_code)] 5 | pub fn create_captcha()->(String,Option){ 6 | let mut captcha_obj = Captcha::new(); 7 | captcha_obj.add_chars(5) 8 | .apply_filter(Noise::new(0.1)) 9 | .view(300, 120); 10 | // .save(Path::new("static/captcha.png")) 11 | // .expect("save failed"); 12 | (captcha_obj.chars_as_string(),captcha_obj.as_base64()) 13 | } -------------------------------------------------------------------------------- /src/utils/md5.rs: -------------------------------------------------------------------------------- 1 | use md5::compute; 2 | 3 | #[allow(dead_code)] 4 | pub fn create_md5(dig:String)->String{ 5 | let digest = compute(dig); 6 | return format!("{:x}",digest) 7 | } -------------------------------------------------------------------------------- /src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod captcha; 2 | pub mod webtoken; 3 | pub mod res; 4 | pub mod md5; 5 | pub mod redis; 6 | pub mod func; 7 | pub mod mysql; 8 | 9 | pub mod system; -------------------------------------------------------------------------------- /src/utils/mysql.rs: -------------------------------------------------------------------------------- 1 | use crate::GLOBAL_DB; 2 | 3 | // 连接数据库 4 | pub async fn init_db() { 5 | GLOBAL_DB.link( 6 | rbdc_mysql::driver::MysqlDriver {}, 7 | "mysql://root:123456@localhost/ry-vue", 8 | ).await.expect("数据库连接失败"); 9 | } -------------------------------------------------------------------------------- /src/utils/redis.rs: -------------------------------------------------------------------------------- 1 | use redis::{Client,Commands,ToRedisArgs,RedisResult,FromRedisValue}; 2 | use crate::GLOBAL_REDIS; 3 | 4 | #[allow(dead_code)] 5 | pub fn set_ex(key:K,value:V,second:usize)->RedisResult<()>{ 6 | let _:() = Client::set_ex(&mut GLOBAL_REDIS.clone(),key,value,second)?; 7 | Ok(()) 8 | } 9 | 10 | #[allow(dead_code)] 11 | pub fn get(key:K)->RedisResult{ 12 | let t:T = Client::get(&mut GLOBAL_REDIS.clone(),key)?; 13 | Ok(t) 14 | } 15 | 16 | #[allow(dead_code)] 17 | #[allow(unused_must_use)] 18 | pub fn del(key:K)->RedisResult<()>{ 19 | let _:() = Client::del(&mut GLOBAL_REDIS.clone(),key)?; 20 | Ok(()) 21 | } -------------------------------------------------------------------------------- /src/utils/system.rs: -------------------------------------------------------------------------------- 1 | use sysinfo::{ Disks, System }; 2 | use crate::model::monitor_model::{ Cpu,Mem,Sys,SysFiles }; 3 | use byte_unit::Byte; 4 | 5 | pub fn get_cpu_info()->Cpu{ 6 | let mut sys = System::new_all(); 7 | sys.refresh_all(); 8 | let global_cpu = sys.global_cpu_info(); 9 | Cpu{ cpu_num:sys.cpus().len(), used: global_cpu.cpu_usage(), brand: global_cpu.name().to_string(), frequency: global_cpu.frequency() } 10 | } 11 | 12 | pub fn u64_to_gb(size:u64)->String{ 13 | let byte = Byte::from_u64(size); 14 | format!("{byte:#.9}") 15 | } 16 | 17 | pub fn get_mem_info()->Mem{ 18 | let mut sys = System::new_all(); 19 | sys.refresh_all(); 20 | Mem{ 21 | total: u64_to_gb(sys.total_memory()), 22 | used: u64_to_gb(sys.used_memory()), 23 | total_swap: u64_to_gb(sys.total_swap()), 24 | used_swap: u64_to_gb(sys.used_swap()), 25 | } 26 | } 27 | 28 | pub fn get_sys_info()->Sys{ 29 | let mut sys = System::new_all(); 30 | sys.refresh_all(); 31 | Sys{ 32 | os_name: System::name(), 33 | os_version: System::os_version(), 34 | host_name: System::host_name(), 35 | kernel_version: System::kernel_version(), 36 | } 37 | } 38 | 39 | pub fn get_disk_info()->Vec{ 40 | let disks = Disks::new_with_refreshed_list(); 41 | let mut sys_file_vec = Vec::::new(); 42 | for disk in &disks { 43 | sys_file_vec.push(SysFiles{ 44 | name: disk.name().to_str().map_or(String::new(), |v| v.to_string()), 45 | sys_type_name: disk.file_system().to_str().map_or(String::new(), |v| v.to_string()), 46 | type_name: disk.kind().to_string(), 47 | total: u64_to_gb(disk.total_space()), 48 | free: u64_to_gb(disk.available_space()), 49 | }) 50 | }; 51 | sys_file_vec 52 | } -------------------------------------------------------------------------------- /src/utils/webtoken.rs: -------------------------------------------------------------------------------- 1 | use jsonwebtoken::{encode,Header,EncodingKey,errors::Result,DecodingKey,Validation,decode,TokenData}; 2 | use serde::{Serialize,Deserialize}; 3 | use rbatis::rbdc::datetime::DateTime; 4 | 5 | #[derive(Debug,Serialize,Deserialize)] 6 | pub struct MyClaims{ 7 | pub id:i32, 8 | pub username:String, 9 | pub time:i64, 10 | pub exp:usize 11 | } 12 | 13 | #[allow(dead_code)] 14 | pub fn create_token(id:i32,username:String)->Result{ 15 | let time = DateTime::now(); 16 | let my_claims = MyClaims{id,username,time:time.unix_timestamp()+3600*6,exp: (time.unix_timestamp() + 3600 * 6) as usize }; 17 | encode(&Header::default(), &my_claims, &EncodingKey::from_secret("salvo_claims".as_ref())) 18 | } 19 | 20 | #[allow(dead_code)] 21 | pub fn verify_token(token:&str)->Result>{ 22 | decode::(token, &DecodingKey::from_secret("salvo_claims".as_ref()), &Validation::default()) 23 | } -------------------------------------------------------------------------------- /src/websocket/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | pub mod excel_websocket; -------------------------------------------------------------------------------- /static/text1.txt: -------------------------------------------------------------------------------- 1 | 测试静态文件 -------------------------------------------------------------------------------- /ui/.env.development: -------------------------------------------------------------------------------- 1 | # 页面标题 2 | VITE_APP_TITLE = 若依管理系统 3 | 4 | # 开发环境配置 5 | VITE_APP_ENV = 'development' 6 | 7 | # 若依管理系统/开发环境 8 | VITE_APP_BASE_API = '/dev-api' 9 | -------------------------------------------------------------------------------- /ui/.env.production: -------------------------------------------------------------------------------- 1 | # 页面标题 2 | VITE_APP_TITLE = 若依管理系统 3 | 4 | # 生产环境配置 5 | VITE_APP_ENV = 'production' 6 | 7 | # 若依管理系统/生产环境 8 | VITE_APP_BASE_API = '/prod-api' 9 | 10 | # 是否在打包时开启压缩,支持 gzip 和 brotli 11 | VITE_BUILD_COMPRESS = gzip -------------------------------------------------------------------------------- /ui/.env.staging: -------------------------------------------------------------------------------- 1 | # 页面标题 2 | VITE_APP_TITLE = 若依管理系统 3 | 4 | # 生产环境配置 5 | VITE_APP_ENV = 'staging' 6 | 7 | # 若依管理系统/生产环境 8 | VITE_APP_BASE_API = '/stage-api' 9 | 10 | # 是否在打包时开启压缩,支持 gzip 和 brotli 11 | VITE_BUILD_COMPRESS = gzip -------------------------------------------------------------------------------- /ui/.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: http://doc.ruoyi.vip/ruoyi-vue/other/donate.html 2 | -------------------------------------------------------------------------------- /ui/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | **/*.log 8 | 9 | tests/**/coverage/ 10 | tests/e2e/reports 11 | selenium-debug.log 12 | 13 | # Editor directories and files 14 | .idea 15 | .vscode 16 | *.suo 17 | *.ntvs* 18 | *.njsproj 19 | *.sln 20 | *.local 21 | 22 | package-lock.json 23 | pnpm-lock.yaml 24 | yarn.lock 25 | -------------------------------------------------------------------------------- /ui/bin/build.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyqgit/salvo-admin/d2b345cd17bb049410bb2dfb95eea9427beadccc/ui/bin/build.bat -------------------------------------------------------------------------------- /ui/bin/package.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyqgit/salvo-admin/d2b345cd17bb049410bb2dfb95eea9427beadccc/ui/bin/package.bat -------------------------------------------------------------------------------- /ui/bin/run-web.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyqgit/salvo-admin/d2b345cd17bb049410bb2dfb95eea9427beadccc/ui/bin/run-web.bat -------------------------------------------------------------------------------- /ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ruoyi", 3 | "version": "3.8.5", 4 | "description": "若依管理系统", 5 | "author": "若依", 6 | "license": "MIT", 7 | "scripts": { 8 | "dev": "vite", 9 | "build:prod": "vite build", 10 | "build:stage": "vite build --mode staging", 11 | "preview": "vite preview" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://gitee.com/y_project/RuoYi-Vue.git" 16 | }, 17 | "dependencies": { 18 | "@element-plus/icons-vue": "2.0.10", 19 | "@form-create/designer": "^3.2.7", 20 | "@form-create/element-ui": "^3.2.11", 21 | "@vueup/vue-quill": "1.1.0", 22 | "@vueuse/core": "9.5.0", 23 | "axios": "0.27.2", 24 | "e-sheet": "^1.2.11", 25 | "echarts": "5.4.0", 26 | "element-plus": "2.2.27", 27 | "element-ui": "^2.15.14", 28 | "file-saver": "2.0.5", 29 | "fuse.js": "6.6.2", 30 | "js-cookie": "3.0.1", 31 | "jsencrypt": "3.3.1", 32 | "nprogress": "0.2.0", 33 | "pinia": "2.0.22", 34 | "vue": "3.2.45", 35 | "vue-cropper": "1.0.3", 36 | "vue-router": "4.1.4", 37 | "xlsx": "^0.18.5" 38 | }, 39 | "devDependencies": { 40 | "@vitejs/plugin-vue": "3.1.0", 41 | "@vue/compiler-sfc": "3.2.45", 42 | "sass": "1.56.1", 43 | "unplugin-auto-import": "0.11.4", 44 | "vite": "3.2.3", 45 | "vite-plugin-compression": "0.5.1", 46 | "vite-plugin-svg-icons": "2.0.1", 47 | "vite-plugin-vue-setup-extend": "0.4.0" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ui/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyqgit/salvo-admin/d2b345cd17bb049410bb2dfb95eea9427beadccc/ui/public/favicon.ico -------------------------------------------------------------------------------- /ui/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | -------------------------------------------------------------------------------- /ui/src/api/login.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 登录方法 4 | export function login(username, password, code, uuid) { 5 | const data = { 6 | username, 7 | password, 8 | code, 9 | uuid 10 | } 11 | return request({ 12 | url: '/login', 13 | headers: { 14 | isToken: false 15 | }, 16 | method: 'post', 17 | data: data 18 | }) 19 | } 20 | 21 | // 注册方法 22 | export function register(data) { 23 | return request({ 24 | url: '/register', 25 | headers: { 26 | isToken: false 27 | }, 28 | method: 'post', 29 | data: data 30 | }) 31 | } 32 | 33 | // 获取用户详细信息 34 | export function getInfo() { 35 | return request({ 36 | url: '/getInfo', 37 | method: 'get' 38 | }) 39 | } 40 | 41 | // 退出方法 42 | export function logout() { 43 | return request({ 44 | url: '/logout', 45 | method: 'post' 46 | }) 47 | } 48 | 49 | // 获取验证码 50 | export function getCodeImg() { 51 | return request({ 52 | url: '/captchaImage', 53 | headers: { 54 | isToken: false 55 | }, 56 | method: 'get', 57 | timeout: 20000 58 | }) 59 | } -------------------------------------------------------------------------------- /ui/src/api/menu.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 获取路由 4 | export const getRouters = () => { 5 | return request({ 6 | url: '/getRouters', 7 | method: 'get' 8 | }) 9 | } -------------------------------------------------------------------------------- /ui/src/api/monitor/cache.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询缓存详细 4 | export function getCache() { 5 | return request({ 6 | url: '/monitor/cache', 7 | method: 'get' 8 | }) 9 | } 10 | 11 | // 查询缓存名称列表 12 | export function listCacheName() { 13 | return request({ 14 | url: '/monitor/cache/getNames', 15 | method: 'get' 16 | }) 17 | } 18 | 19 | // 查询缓存键名列表 20 | export function listCacheKey(cacheName) { 21 | return request({ 22 | url: '/monitor/cache/getKeys/' + cacheName, 23 | method: 'get' 24 | }) 25 | } 26 | 27 | // 查询缓存内容 28 | export function getCacheValue(cacheName, cacheKey) { 29 | return request({ 30 | url: '/monitor/cache/getValue/' + cacheName + '/' + cacheKey, 31 | method: 'get' 32 | }) 33 | } 34 | 35 | // 清理指定名称缓存 36 | export function clearCacheName(cacheName) { 37 | return request({ 38 | url: '/monitor/cache/clearCacheName/' + cacheName, 39 | method: 'delete' 40 | }) 41 | } 42 | 43 | // 清理指定键名缓存 44 | export function clearCacheKey(cacheKey) { 45 | return request({ 46 | url: '/monitor/cache/clearCacheKey/' + cacheKey, 47 | method: 'delete' 48 | }) 49 | } 50 | 51 | // 清理全部缓存 52 | export function clearCacheAll() { 53 | return request({ 54 | url: '/monitor/cache/clearCacheAll', 55 | method: 'delete' 56 | }) 57 | } 58 | -------------------------------------------------------------------------------- /ui/src/api/monitor/job.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询定时任务调度列表 4 | export function listJob(query) { 5 | return request({ 6 | url: '/monitor/job/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询定时任务调度详细 13 | export function getJob(jobId) { 14 | return request({ 15 | url: '/monitor/job/' + jobId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 新增定时任务调度 21 | export function addJob(data) { 22 | return request({ 23 | url: '/monitor/job', 24 | method: 'post', 25 | data: data 26 | }) 27 | } 28 | 29 | // 修改定时任务调度 30 | export function updateJob(data) { 31 | return request({ 32 | url: '/monitor/job', 33 | method: 'put', 34 | data: data 35 | }) 36 | } 37 | 38 | // 删除定时任务调度 39 | export function delJob(jobId) { 40 | return request({ 41 | url: '/monitor/job/' + jobId, 42 | method: 'delete' 43 | }) 44 | } 45 | 46 | // 任务状态修改 47 | export function changeJobStatus(jobId, status) { 48 | const data = { 49 | jobId, 50 | status 51 | } 52 | return request({ 53 | url: '/monitor/job/changeStatus', 54 | method: 'put', 55 | data: data 56 | }) 57 | } 58 | 59 | 60 | // 定时任务立即执行一次 61 | export function runJob(jobId, jobGroup) { 62 | const data = { 63 | jobId, 64 | jobGroup 65 | } 66 | return request({ 67 | url: '/monitor/job/run', 68 | method: 'put', 69 | data: data 70 | }) 71 | } -------------------------------------------------------------------------------- /ui/src/api/monitor/jobLog.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询调度日志列表 4 | export function listJobLog(query) { 5 | return request({ 6 | url: '/monitor/jobLog/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 删除调度日志 13 | export function delJobLog(jobLogId) { 14 | return request({ 15 | url: '/monitor/jobLog/' + jobLogId, 16 | method: 'delete' 17 | }) 18 | } 19 | 20 | // 清空调度日志 21 | export function cleanJobLog() { 22 | return request({ 23 | url: '/monitor/jobLog/clean', 24 | method: 'delete' 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /ui/src/api/monitor/logininfor.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询登录日志列表 4 | export function list(query) { 5 | return request({ 6 | url: '/monitor/logininfor/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 删除登录日志 13 | export function delLogininfor(infoId) { 14 | return request({ 15 | url: '/monitor/logininfor/' + infoId, 16 | method: 'delete' 17 | }) 18 | } 19 | 20 | // 解锁用户登录状态 21 | export function unlockLogininfor(userName) { 22 | return request({ 23 | url: '/monitor/logininfor/unlock/' + userName, 24 | method: 'get' 25 | }) 26 | } 27 | 28 | // 清空登录日志 29 | export function cleanLogininfor() { 30 | return request({ 31 | url: '/monitor/logininfor/clean', 32 | method: 'delete' 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /ui/src/api/monitor/online.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询在线用户列表 4 | export function list(query) { 5 | return request({ 6 | url: '/monitor/online/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 强退用户 13 | export function forceLogout(tokenId) { 14 | return request({ 15 | url: '/monitor/online/' + tokenId, 16 | method: 'delete' 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /ui/src/api/monitor/operlog.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询操作日志列表 4 | export function list(query) { 5 | return request({ 6 | url: '/monitor/operlog/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 删除操作日志 13 | export function delOperlog(operId) { 14 | return request({ 15 | url: '/monitor/operlog/' + operId, 16 | method: 'delete' 17 | }) 18 | } 19 | 20 | // 清空操作日志 21 | export function cleanOperlog() { 22 | return request({ 23 | url: '/monitor/operlog/clean', 24 | method: 'delete' 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /ui/src/api/monitor/server.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 获取服务信息 4 | export function getServer() { 5 | return request({ 6 | url: '/monitor/server', 7 | method: 'get' 8 | }) 9 | } -------------------------------------------------------------------------------- /ui/src/api/system/config.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询参数列表 4 | export function listConfig(query) { 5 | return request({ 6 | url: '/system/config/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询参数详细 13 | export function getConfig(configId) { 14 | return request({ 15 | url: '/system/config/' + configId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 根据参数键名查询参数值 21 | export function getConfigKey(configKey) { 22 | return request({ 23 | url: '/system/config/configKey/' + configKey, 24 | method: 'get' 25 | }) 26 | } 27 | 28 | // 新增参数配置 29 | export function addConfig(data) { 30 | return request({ 31 | url: '/system/config', 32 | method: 'post', 33 | data: data 34 | }) 35 | } 36 | 37 | // 修改参数配置 38 | export function updateConfig(data) { 39 | return request({ 40 | url: '/system/config', 41 | method: 'put', 42 | data: data 43 | }) 44 | } 45 | 46 | // 删除参数配置 47 | export function delConfig(configId) { 48 | return request({ 49 | url: '/system/config/' + configId, 50 | method: 'delete' 51 | }) 52 | } 53 | 54 | // 刷新参数缓存 55 | export function refreshCache() { 56 | return request({ 57 | url: '/system/config/refreshCache', 58 | method: 'delete' 59 | }) 60 | } 61 | -------------------------------------------------------------------------------- /ui/src/api/system/dept.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询部门列表 4 | export function listDept(query) { 5 | return request({ 6 | url: '/system/dept/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询部门列表(排除节点) 13 | export function listDeptExcludeChild(deptId) { 14 | return request({ 15 | url: '/system/dept/list/exclude/' + deptId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 查询部门详细 21 | export function getDept(deptId) { 22 | return request({ 23 | url: '/system/dept/' + deptId, 24 | method: 'get' 25 | }) 26 | } 27 | 28 | // 新增部门 29 | export function addDept(data) { 30 | return request({ 31 | url: '/system/dept', 32 | method: 'post', 33 | data: data 34 | }) 35 | } 36 | 37 | // 修改部门 38 | export function updateDept(data) { 39 | return request({ 40 | url: '/system/dept', 41 | method: 'put', 42 | data: data 43 | }) 44 | } 45 | 46 | // 删除部门 47 | export function delDept(deptId) { 48 | return request({ 49 | url: '/system/dept/' + deptId, 50 | method: 'delete' 51 | }) 52 | } -------------------------------------------------------------------------------- /ui/src/api/system/dict/data.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询字典数据列表 4 | export function listData(query) { 5 | return request({ 6 | url: '/system/dict/data/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询字典数据详细 13 | export function getData(dictCode) { 14 | return request({ 15 | url: '/system/dict/data/' + dictCode, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 根据字典类型查询字典数据信息 21 | export function getDicts(dictType) { 22 | return request({ 23 | url: '/system/dict/data/type/' + dictType, 24 | method: 'get' 25 | }) 26 | } 27 | 28 | // 新增字典数据 29 | export function addData(data) { 30 | return request({ 31 | url: '/system/dict/data', 32 | method: 'post', 33 | data: data 34 | }) 35 | } 36 | 37 | // 修改字典数据 38 | export function updateData(data) { 39 | return request({ 40 | url: '/system/dict/data', 41 | method: 'put', 42 | data: data 43 | }) 44 | } 45 | 46 | // 删除字典数据 47 | export function delData(dictCode) { 48 | return request({ 49 | url: '/system/dict/data/' + dictCode, 50 | method: 'delete' 51 | }) 52 | } 53 | -------------------------------------------------------------------------------- /ui/src/api/system/dict/type.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询字典类型列表 4 | export function listType(query) { 5 | return request({ 6 | url: '/system/dict/type/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询字典类型详细 13 | export function getType(dictId) { 14 | return request({ 15 | url: '/system/dict/type/' + dictId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 新增字典类型 21 | export function addType(data) { 22 | return request({ 23 | url: '/system/dict/type', 24 | method: 'post', 25 | data: data 26 | }) 27 | } 28 | 29 | // 修改字典类型 30 | export function updateType(data) { 31 | return request({ 32 | url: '/system/dict/type', 33 | method: 'put', 34 | data: data 35 | }) 36 | } 37 | 38 | // 删除字典类型 39 | export function delType(dictId) { 40 | return request({ 41 | url: '/system/dict/type/' + dictId, 42 | method: 'delete' 43 | }) 44 | } 45 | 46 | // 刷新字典缓存 47 | export function refreshCache() { 48 | return request({ 49 | url: '/system/dict/type/refreshCache', 50 | method: 'delete' 51 | }) 52 | } 53 | 54 | // 获取字典选择框列表 55 | export function optionselect() { 56 | return request({ 57 | url: '/system/dict/type/optionselect', 58 | method: 'get' 59 | }) 60 | } 61 | -------------------------------------------------------------------------------- /ui/src/api/system/menu.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询菜单列表 4 | export function listMenu(query) { 5 | return request({ 6 | url: '/system/menu/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询菜单详细 13 | export function getMenu(menuId) { 14 | return request({ 15 | url: '/system/menu/' + menuId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 查询菜单下拉树结构 21 | export function treeselect() { 22 | return request({ 23 | url: '/system/menu/treeselect', 24 | method: 'get' 25 | }) 26 | } 27 | 28 | // 根据角色ID查询菜单下拉树结构 29 | export function roleMenuTreeselect(roleId) { 30 | return request({ 31 | url: '/system/menu/roleMenuTreeselect/' + roleId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | // 新增菜单 37 | export function addMenu(data) { 38 | return request({ 39 | url: '/system/menu', 40 | method: 'post', 41 | data: data 42 | }) 43 | } 44 | 45 | // 修改菜单 46 | export function updateMenu(data) { 47 | return request({ 48 | url: '/system/menu', 49 | method: 'put', 50 | data: data 51 | }) 52 | } 53 | 54 | // 删除菜单 55 | export function delMenu(menuId) { 56 | return request({ 57 | url: '/system/menu/' + menuId, 58 | method: 'delete' 59 | }) 60 | } -------------------------------------------------------------------------------- /ui/src/api/system/notice.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询公告列表 4 | export function listNotice(query) { 5 | return request({ 6 | url: '/system/notice/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询公告详细 13 | export function getNotice(noticeId) { 14 | return request({ 15 | url: '/system/notice/' + noticeId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 新增公告 21 | export function addNotice(data) { 22 | return request({ 23 | url: '/system/notice', 24 | method: 'post', 25 | data: data 26 | }) 27 | } 28 | 29 | // 修改公告 30 | export function updateNotice(data) { 31 | return request({ 32 | url: '/system/notice', 33 | method: 'put', 34 | data: data 35 | }) 36 | } 37 | 38 | // 删除公告 39 | export function delNotice(noticeId) { 40 | return request({ 41 | url: '/system/notice/' + noticeId, 42 | method: 'delete' 43 | }) 44 | } -------------------------------------------------------------------------------- /ui/src/api/system/post.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询岗位列表 4 | export function listPost(query) { 5 | return request({ 6 | url: '/system/post/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询岗位详细 13 | export function getPost(postId) { 14 | return request({ 15 | url: '/system/post/' + postId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 新增岗位 21 | export function addPost(data) { 22 | return request({ 23 | url: '/system/post', 24 | method: 'post', 25 | data: data 26 | }) 27 | } 28 | 29 | // 修改岗位 30 | export function updatePost(data) { 31 | return request({ 32 | url: '/system/post', 33 | method: 'put', 34 | data: data 35 | }) 36 | } 37 | 38 | // 删除岗位 39 | export function delPost(postId) { 40 | return request({ 41 | url: '/system/post/' + postId, 42 | method: 'delete' 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /ui/src/api/tool/excel.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 创建excel 4 | export function addExcel(data) { 5 | return request({ 6 | url: '/tool/excel/add', 7 | method: 'post', 8 | data 9 | }) 10 | } 11 | 12 | // 修改excel 13 | export function editExcel(data) { 14 | return request({ 15 | url: '/tool/excel/edit', 16 | method: 'post', 17 | data 18 | }) 19 | } 20 | 21 | // 获取excel列表 22 | export function getExcelList() { 23 | return request({ 24 | url: '/tool/excel/list', 25 | method: 'get' 26 | }) 27 | } 28 | 29 | // 获取excel列表 30 | export function getExcelById(excelIdd) { 31 | return request({ 32 | url: '/tool/excel/'+excelIdd, 33 | method: 'get' 34 | }) 35 | } -------------------------------------------------------------------------------- /ui/src/api/tool/gen.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询生成表数据 4 | export function listTable(query) { 5 | return request({ 6 | url: '/tool/gen/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | // 查询db数据库列表 12 | export function listDbTable(query) { 13 | return request({ 14 | url: '/tool/gen/db/list', 15 | method: 'get', 16 | params: query 17 | }) 18 | } 19 | 20 | // 查询表详细信息 21 | export function getGenTable(tableId) { 22 | return request({ 23 | url: '/tool/gen/' + tableId, 24 | method: 'get' 25 | }) 26 | } 27 | 28 | // 修改代码生成信息 29 | export function updateGenTable(data) { 30 | return request({ 31 | url: '/tool/gen', 32 | method: 'put', 33 | data: data 34 | }) 35 | } 36 | 37 | // 导入表 38 | export function importTable(data) { 39 | return request({ 40 | url: '/tool/gen/importTable', 41 | method: 'post', 42 | params: data 43 | }) 44 | } 45 | 46 | // 预览生成代码 47 | export function previewTable(tableId) { 48 | return request({ 49 | url: '/tool/gen/preview/' + tableId, 50 | method: 'get' 51 | }) 52 | } 53 | 54 | // 删除表数据 55 | export function delTable(tableId) { 56 | return request({ 57 | url: '/tool/gen/' + tableId, 58 | method: 'delete' 59 | }) 60 | } 61 | 62 | // 生成代码(自定义路径) 63 | export function genCode(tableName) { 64 | return request({ 65 | url: '/tool/gen/genCode/' + tableName, 66 | method: 'get' 67 | }) 68 | } 69 | 70 | // 同步数据库 71 | export function synchDb(tableName) { 72 | return request({ 73 | url: '/tool/gen/synchDb/' + tableName, 74 | method: 'get' 75 | }) 76 | } 77 | -------------------------------------------------------------------------------- /ui/src/assets/401_images/401.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyqgit/salvo-admin/d2b345cd17bb049410bb2dfb95eea9427beadccc/ui/src/assets/401_images/401.gif -------------------------------------------------------------------------------- /ui/src/assets/404_images/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyqgit/salvo-admin/d2b345cd17bb049410bb2dfb95eea9427beadccc/ui/src/assets/404_images/404.png -------------------------------------------------------------------------------- /ui/src/assets/404_images/404_cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyqgit/salvo-admin/d2b345cd17bb049410bb2dfb95eea9427beadccc/ui/src/assets/404_images/404_cloud.png -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/404.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/bug.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/build.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/chart.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/checkbox.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/clipboard.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/code.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/documentation.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/download.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/drag.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/druid.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/edit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/education.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/email.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/example.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/excel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/exit-fullscreen.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/eye-open.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/eye.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/fullscreen.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/guide.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/input.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/international.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/job.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/language.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/link.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/list.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/lock.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/log.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/logininfor.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/message.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/money.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/monitor.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/nested.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/password.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/pdf.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/people.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/peoples.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/phone.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/post.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/question.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/radio.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/rate.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/row.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/search.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/select.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/server.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/size.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/skill.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/slider.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/star.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/swagger.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/switch.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/tab.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/table.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/textarea.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/theme.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/time.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/tree-table.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/tree.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/upload.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/user.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/validCode.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/wechat.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/icons/svg/zip.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/assets/images/login-background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyqgit/salvo-admin/d2b345cd17bb049410bb2dfb95eea9427beadccc/ui/src/assets/images/login-background.jpg -------------------------------------------------------------------------------- /ui/src/assets/images/profile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyqgit/salvo-admin/d2b345cd17bb049410bb2dfb95eea9427beadccc/ui/src/assets/images/profile.jpg -------------------------------------------------------------------------------- /ui/src/assets/logo/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyqgit/salvo-admin/d2b345cd17bb049410bb2dfb95eea9427beadccc/ui/src/assets/logo/logo.png -------------------------------------------------------------------------------- /ui/src/assets/styles/btn.scss: -------------------------------------------------------------------------------- 1 | @import './variables.module.scss'; 2 | 3 | @mixin colorBtn($color) { 4 | background: $color; 5 | 6 | &:hover { 7 | color: $color; 8 | 9 | &:before, 10 | &:after { 11 | background: $color; 12 | } 13 | } 14 | } 15 | 16 | .blue-btn { 17 | @include colorBtn($blue) 18 | } 19 | 20 | .light-blue-btn { 21 | @include colorBtn($light-blue) 22 | } 23 | 24 | .red-btn { 25 | @include colorBtn($red) 26 | } 27 | 28 | .pink-btn { 29 | @include colorBtn($pink) 30 | } 31 | 32 | .green-btn { 33 | @include colorBtn($green) 34 | } 35 | 36 | .tiffany-btn { 37 | @include colorBtn($tiffany) 38 | } 39 | 40 | .yellow-btn { 41 | @include colorBtn($yellow) 42 | } 43 | 44 | .pan-btn { 45 | font-size: 14px; 46 | color: #fff; 47 | padding: 14px 36px; 48 | border-radius: 8px; 49 | border: none; 50 | outline: none; 51 | transition: 600ms ease all; 52 | position: relative; 53 | display: inline-block; 54 | 55 | &:hover { 56 | background: #fff; 57 | 58 | &:before, 59 | &:after { 60 | width: 100%; 61 | transition: 600ms ease all; 62 | } 63 | } 64 | 65 | &:before, 66 | &:after { 67 | content: ''; 68 | position: absolute; 69 | top: 0; 70 | right: 0; 71 | height: 2px; 72 | width: 0; 73 | transition: 400ms ease all; 74 | } 75 | 76 | &::after { 77 | right: inherit; 78 | top: inherit; 79 | left: 0; 80 | bottom: 0; 81 | } 82 | } 83 | 84 | .custom-button { 85 | display: inline-block; 86 | line-height: 1; 87 | white-space: nowrap; 88 | cursor: pointer; 89 | background: #fff; 90 | color: #fff; 91 | -webkit-appearance: none; 92 | text-align: center; 93 | box-sizing: border-box; 94 | outline: 0; 95 | margin: 0; 96 | padding: 10px 15px; 97 | font-size: 14px; 98 | border-radius: 4px; 99 | } 100 | -------------------------------------------------------------------------------- /ui/src/assets/styles/element-ui.scss: -------------------------------------------------------------------------------- 1 | // cover some element-ui styles 2 | 3 | .el-breadcrumb__inner, 4 | .el-breadcrumb__inner a { 5 | font-weight: 400 !important; 6 | } 7 | 8 | .el-upload { 9 | input[type="file"] { 10 | display: none !important; 11 | } 12 | } 13 | 14 | .el-upload__input { 15 | display: none; 16 | } 17 | 18 | .cell { 19 | .el-tag { 20 | margin-right: 0px; 21 | } 22 | } 23 | 24 | .small-padding { 25 | .cell { 26 | padding-left: 5px; 27 | padding-right: 5px; 28 | } 29 | } 30 | 31 | .fixed-width { 32 | .el-button--mini { 33 | padding: 7px 10px; 34 | width: 60px; 35 | } 36 | } 37 | 38 | .status-col { 39 | .cell { 40 | padding: 0 10px; 41 | text-align: center; 42 | 43 | .el-tag { 44 | margin-right: 0px; 45 | } 46 | } 47 | } 48 | 49 | // to fixed https://github.com/ElemeFE/element/issues/2461 50 | .el-dialog { 51 | transform: none; 52 | left: 0; 53 | position: relative; 54 | margin: 0 auto; 55 | } 56 | 57 | // refine element ui upload 58 | .upload-container { 59 | .el-upload { 60 | width: 100%; 61 | 62 | .el-upload-dragger { 63 | width: 100%; 64 | height: 200px; 65 | } 66 | } 67 | } 68 | 69 | // dropdown 70 | .el-dropdown-menu { 71 | a { 72 | display: block 73 | } 74 | } 75 | 76 | // fix date-picker ui bug in filter-item 77 | .el-range-editor.el-input__inner { 78 | display: inline-flex !important; 79 | } 80 | 81 | // to fix el-date-picker css style 82 | .el-range-separator { 83 | box-sizing: content-box; 84 | } 85 | 86 | .el-menu--collapse 87 | > div 88 | > .el-submenu 89 | > .el-submenu__title 90 | .el-submenu__icon-arrow { 91 | display: none; 92 | } 93 | 94 | .el-dropdown .el-dropdown-link{ 95 | color: var(--el-color-primary) !important; 96 | } -------------------------------------------------------------------------------- /ui/src/assets/styles/mixin.scss: -------------------------------------------------------------------------------- 1 | @mixin clearfix { 2 | &:after { 3 | content: ""; 4 | display: table; 5 | clear: both; 6 | } 7 | } 8 | 9 | @mixin scrollBar { 10 | &::-webkit-scrollbar-track-piece { 11 | background: #d3dce6; 12 | } 13 | 14 | &::-webkit-scrollbar { 15 | width: 6px; 16 | } 17 | 18 | &::-webkit-scrollbar-thumb { 19 | background: #99a9bf; 20 | border-radius: 20px; 21 | } 22 | } 23 | 24 | @mixin relative { 25 | position: relative; 26 | width: 100%; 27 | height: 100%; 28 | } 29 | 30 | @mixin pct($pct) { 31 | width: #{$pct}; 32 | position: relative; 33 | margin: 0 auto; 34 | } 35 | 36 | @mixin triangle($width, $height, $color, $direction) { 37 | $width: $width/2; 38 | $color-border-style: $height solid $color; 39 | $transparent-border-style: $width solid transparent; 40 | height: 0; 41 | width: 0; 42 | 43 | @if $direction==up { 44 | border-bottom: $color-border-style; 45 | border-left: $transparent-border-style; 46 | border-right: $transparent-border-style; 47 | } 48 | 49 | @else if $direction==right { 50 | border-left: $color-border-style; 51 | border-top: $transparent-border-style; 52 | border-bottom: $transparent-border-style; 53 | } 54 | 55 | @else if $direction==down { 56 | border-top: $color-border-style; 57 | border-left: $transparent-border-style; 58 | border-right: $transparent-border-style; 59 | } 60 | 61 | @else if $direction==left { 62 | border-right: $color-border-style; 63 | border-top: $transparent-border-style; 64 | border-bottom: $transparent-border-style; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /ui/src/assets/styles/transition.scss: -------------------------------------------------------------------------------- 1 | // global transition css 2 | 3 | /* fade */ 4 | .fade-enter-active, 5 | .fade-leave-active { 6 | transition: opacity 0.28s; 7 | } 8 | 9 | .fade-enter, 10 | .fade-leave-active { 11 | opacity: 0; 12 | } 13 | 14 | /* fade-transform */ 15 | .fade-transform--move, 16 | .fade-transform-leave-active, 17 | .fade-transform-enter-active { 18 | transition: all .5s; 19 | } 20 | 21 | .fade-transform-enter { 22 | opacity: 0; 23 | transform: translateX(-30px); 24 | } 25 | 26 | .fade-transform-leave-to { 27 | opacity: 0; 28 | transform: translateX(30px); 29 | } 30 | 31 | /* breadcrumb transition */ 32 | .breadcrumb-enter-active, 33 | .breadcrumb-leave-active { 34 | transition: all .5s; 35 | } 36 | 37 | .breadcrumb-enter, 38 | .breadcrumb-leave-active { 39 | opacity: 0; 40 | transform: translateX(20px); 41 | } 42 | 43 | .breadcrumb-move { 44 | transition: all .5s; 45 | } 46 | 47 | .breadcrumb-leave-active { 48 | position: absolute; 49 | } 50 | -------------------------------------------------------------------------------- /ui/src/assets/styles/variables.module.scss: -------------------------------------------------------------------------------- 1 | // base color 2 | $blue: #324157; 3 | $light-blue: #3A71A8; 4 | $red: #C03639; 5 | $pink: #E65D6E; 6 | $green: #30B08F; 7 | $tiffany: #4AB7BD; 8 | $yellow: #FEC171; 9 | $panGreen: #30B08F; 10 | 11 | // 默认菜单主题风格 12 | $base-menu-color: #bfcbd9; 13 | $base-menu-color-active: #f4f4f5; 14 | $base-menu-background: #304156; 15 | $base-logo-title-color: #ffffff; 16 | 17 | $base-menu-light-color: rgba(0, 0, 0, 0.7); 18 | $base-menu-light-background: #ffffff; 19 | $base-logo-light-title-color: #001529; 20 | 21 | $base-sub-menu-background: #1f2d3d; 22 | $base-sub-menu-hover: #001528; 23 | 24 | // 自定义暗色菜单风格 25 | /** 26 | $base-menu-color:hsla(0,0%,100%,.65); 27 | $base-menu-color-active:#fff; 28 | $base-menu-background:#001529; 29 | $base-logo-title-color: #ffffff; 30 | 31 | $base-menu-light-color:rgba(0,0,0,.70); 32 | $base-menu-light-background:#ffffff; 33 | $base-logo-light-title-color: #001529; 34 | 35 | $base-sub-menu-background:#000c17; 36 | $base-sub-menu-hover:#001528; 37 | */ 38 | 39 | $--color-primary: #409EFF; 40 | $--color-success: #67C23A; 41 | $--color-warning: #E6A23C; 42 | $--color-danger: #F56C6C; 43 | $--color-info: #909399; 44 | 45 | $base-sidebar-width: 200px; 46 | 47 | // the :export directive is the magic sauce for webpack 48 | // https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass 49 | :export { 50 | menuColor: $base-menu-color; 51 | menuLightColor: $base-menu-light-color; 52 | menuColorActive: $base-menu-color-active; 53 | menuBackground: $base-menu-background; 54 | menuLightBackground: $base-menu-light-background; 55 | subMenuBackground: $base-sub-menu-background; 56 | subMenuHover: $base-sub-menu-hover; 57 | sideBarWidth: $base-sidebar-width; 58 | logoTitleColor: $base-logo-title-color; 59 | logoLightTitleColor: $base-logo-light-title-color; 60 | primaryColor: $--color-primary; 61 | successColor: $--color-success; 62 | dangerColor: $--color-danger; 63 | infoColor: $--color-info; 64 | warningColor: $--color-warning; 65 | } 66 | -------------------------------------------------------------------------------- /ui/src/components/Breadcrumb/index.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 53 | 54 | -------------------------------------------------------------------------------- /ui/src/components/DictTag/index.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 44 | 45 | -------------------------------------------------------------------------------- /ui/src/components/Hamburger/index.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 29 | 30 | 42 | -------------------------------------------------------------------------------- /ui/src/components/IconSelect/index.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 50 | 51 | -------------------------------------------------------------------------------- /ui/src/components/IconSelect/requireIcons.js: -------------------------------------------------------------------------------- 1 | let icons = [] 2 | const modules = import.meta.glob('./../../assets/icons/svg/*.svg'); 3 | for (const path in modules) { 4 | const p = path.split('assets/icons/svg/')[1].split('.svg')[0]; 5 | icons.push(p); 6 | } 7 | 8 | export default icons -------------------------------------------------------------------------------- /ui/src/components/ParentView/index.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /ui/src/components/RuoYi/Doc/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /ui/src/components/RuoYi/Git/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | -------------------------------------------------------------------------------- /ui/src/components/Screenfull/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /ui/src/components/SizeSelect/index.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 38 | 39 | -------------------------------------------------------------------------------- /ui/src/components/SvgIcon/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 36 | 37 | 54 | -------------------------------------------------------------------------------- /ui/src/components/SvgIcon/svgicon.js: -------------------------------------------------------------------------------- 1 | import * as components from '@element-plus/icons-vue' 2 | 3 | export default { 4 | install: (app) => { 5 | for (const key in components) { 6 | const componentConfig = components[key]; 7 | app.component(componentConfig.name, componentConfig); 8 | } 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /ui/src/components/iFrame/index.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 25 | -------------------------------------------------------------------------------- /ui/src/layout/components/Sidebar/Link.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 41 | -------------------------------------------------------------------------------- /ui/src/layout/components/index.js: -------------------------------------------------------------------------------- 1 | export { default as AppMain } from './AppMain' 2 | export { default as Navbar } from './Navbar' 3 | export { default as Settings } from './Settings' 4 | export { default as TagsView } from './TagsView/index.vue' 5 | -------------------------------------------------------------------------------- /ui/src/permission.js: -------------------------------------------------------------------------------- 1 | import router from './router' 2 | import { ElMessage } from 'element-plus' 3 | import NProgress from 'nprogress' 4 | import 'nprogress/nprogress.css' 5 | import { getToken } from '@/utils/auth' 6 | import { isHttp } from '@/utils/validate' 7 | import { isRelogin } from '@/utils/request' 8 | import useUserStore from '@/store/modules/user' 9 | import useSettingsStore from '@/store/modules/settings' 10 | import usePermissionStore from '@/store/modules/permission' 11 | 12 | NProgress.configure({ showSpinner: false }); 13 | 14 | const whiteList = ['/login', '/register']; 15 | 16 | router.beforeEach((to, from, next) => { 17 | NProgress.start() 18 | if (getToken()) { 19 | to.meta.title && useSettingsStore().setTitle(to.meta.title) 20 | /* has token*/ 21 | if (to.path === '/login') { 22 | next({ path: '/' }) 23 | NProgress.done() 24 | } else { 25 | if (useUserStore().roles.length === 0) { 26 | isRelogin.show = true 27 | // 判断当前用户是否已拉取完user_info信息 28 | useUserStore().getInfo().then(() => { 29 | isRelogin.show = false 30 | usePermissionStore().generateRoutes().then(accessRoutes => { 31 | // 根据roles权限生成可访问的路由表 32 | accessRoutes.forEach(route => { 33 | if (!isHttp(route.path)) { 34 | router.addRoute(route) // 动态添加可访问路由表 35 | } 36 | }) 37 | next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 38 | }) 39 | }).catch(err => { 40 | isRelogin.show = false 41 | useUserStore().logOut().then(() => { 42 | ElMessage.error(err) 43 | next({ path: '/' }) 44 | }) 45 | }) 46 | } else { 47 | next() 48 | } 49 | } 50 | } else { 51 | // 没有token 52 | if (whiteList.indexOf(to.path) !== -1) { 53 | // 在免登录白名单,直接进入 54 | next() 55 | } else { 56 | next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页 57 | NProgress.done() 58 | } 59 | } 60 | }) 61 | 62 | router.afterEach(() => { 63 | NProgress.done() 64 | }) 65 | -------------------------------------------------------------------------------- /ui/src/plugins/auth.js: -------------------------------------------------------------------------------- 1 | import useUserStore from '@/store/modules/user' 2 | 3 | function authPermission(permission) { 4 | const all_permission = "*:*:*"; 5 | const permissions = useUserStore().permissions 6 | if (permission && permission.length > 0) { 7 | return permissions.some(v => { 8 | return all_permission === v || v === permission 9 | }) 10 | } else { 11 | return false 12 | } 13 | } 14 | 15 | function authRole(role) { 16 | const super_admin = "admin"; 17 | const roles = useUserStore().roles 18 | if (role && role.length > 0) { 19 | return roles.some(v => { 20 | return super_admin === v || v === role 21 | }) 22 | } else { 23 | return false 24 | } 25 | } 26 | 27 | export default { 28 | // 验证用户是否具备某权限 29 | hasPermi(permission) { 30 | return authPermission(permission); 31 | }, 32 | // 验证用户是否含有指定权限,只需包含其中一个 33 | hasPermiOr(permissions) { 34 | return permissions.some(item => { 35 | return authPermission(item) 36 | }) 37 | }, 38 | // 验证用户是否含有指定权限,必须全部拥有 39 | hasPermiAnd(permissions) { 40 | return permissions.every(item => { 41 | return authPermission(item) 42 | }) 43 | }, 44 | // 验证用户是否具备某角色 45 | hasRole(role) { 46 | return authRole(role); 47 | }, 48 | // 验证用户是否含有指定角色,只需包含其中一个 49 | hasRoleOr(roles) { 50 | return roles.some(item => { 51 | return authRole(item) 52 | }) 53 | }, 54 | // 验证用户是否含有指定角色,必须全部拥有 55 | hasRoleAnd(roles) { 56 | return roles.every(item => { 57 | return authRole(item) 58 | }) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ui/src/plugins/cache.js: -------------------------------------------------------------------------------- 1 | const sessionCache = { 2 | set (key, value) { 3 | if (!sessionStorage) { 4 | return 5 | } 6 | if (key != null && value != null) { 7 | sessionStorage.setItem(key, value) 8 | } 9 | }, 10 | get (key) { 11 | if (!sessionStorage) { 12 | return null 13 | } 14 | if (key == null) { 15 | return null 16 | } 17 | return sessionStorage.getItem(key) 18 | }, 19 | setJSON (key, jsonValue) { 20 | if (jsonValue != null) { 21 | this.set(key, JSON.stringify(jsonValue)) 22 | } 23 | }, 24 | getJSON (key) { 25 | const value = this.get(key) 26 | if (value != null) { 27 | return JSON.parse(value) 28 | } 29 | }, 30 | remove (key) { 31 | sessionStorage.removeItem(key); 32 | } 33 | } 34 | const localCache = { 35 | set (key, value) { 36 | if (!localStorage) { 37 | return 38 | } 39 | if (key != null && value != null) { 40 | localStorage.setItem(key, value) 41 | } 42 | }, 43 | get (key) { 44 | if (!localStorage) { 45 | return null 46 | } 47 | if (key == null) { 48 | return null 49 | } 50 | return localStorage.getItem(key) 51 | }, 52 | setJSON (key, jsonValue) { 53 | if (jsonValue != null) { 54 | this.set(key, JSON.stringify(jsonValue)) 55 | } 56 | }, 57 | getJSON (key) { 58 | const value = this.get(key) 59 | if (value != null) { 60 | return JSON.parse(value) 61 | } 62 | }, 63 | remove (key) { 64 | localStorage.removeItem(key); 65 | } 66 | } 67 | 68 | export default { 69 | /** 70 | * 会话级缓存 71 | */ 72 | session: sessionCache, 73 | /** 74 | * 本地缓存 75 | */ 76 | local: localCache 77 | } 78 | -------------------------------------------------------------------------------- /ui/src/plugins/index.js: -------------------------------------------------------------------------------- 1 | import tab from './tab' 2 | import auth from './auth' 3 | import cache from './cache' 4 | import modal from './modal' 5 | import download from './download' 6 | 7 | export default function installPlugins(app){ 8 | // 页签操作 9 | app.config.globalProperties.$tab = tab 10 | // 认证对象 11 | app.config.globalProperties.$auth = auth 12 | // 缓存对象 13 | app.config.globalProperties.$cache = cache 14 | // 模态框对象 15 | app.config.globalProperties.$modal = modal 16 | // 下载文件 17 | app.config.globalProperties.$download = download 18 | } 19 | -------------------------------------------------------------------------------- /ui/src/plugins/modal.js: -------------------------------------------------------------------------------- 1 | import { ElMessage, ElMessageBox, ElNotification, ElLoading } from 'element-plus' 2 | 3 | let loadingInstance; 4 | 5 | export default { 6 | // 消息提示 7 | msg(content) { 8 | ElMessage.info(content) 9 | }, 10 | // 错误消息 11 | msgError(content) { 12 | ElMessage.error(content) 13 | }, 14 | // 成功消息 15 | msgSuccess(content) { 16 | ElMessage.success(content) 17 | }, 18 | // 警告消息 19 | msgWarning(content) { 20 | ElMessage.warning(content) 21 | }, 22 | // 弹出提示 23 | alert(content) { 24 | ElMessageBox.alert(content, "系统提示") 25 | }, 26 | // 错误提示 27 | alertError(content) { 28 | ElMessageBox.alert(content, "系统提示", { type: 'error' }) 29 | }, 30 | // 成功提示 31 | alertSuccess(content) { 32 | ElMessageBox.alert(content, "系统提示", { type: 'success' }) 33 | }, 34 | // 警告提示 35 | alertWarning(content) { 36 | ElMessageBox.alert(content, "系统提示", { type: 'warning' }) 37 | }, 38 | // 通知提示 39 | notify(content) { 40 | ElNotification.info(content) 41 | }, 42 | // 错误通知 43 | notifyError(content) { 44 | ElNotification.error(content); 45 | }, 46 | // 成功通知 47 | notifySuccess(content) { 48 | ElNotification.success(content) 49 | }, 50 | // 警告通知 51 | notifyWarning(content) { 52 | ElNotification.warning(content) 53 | }, 54 | // 确认窗体 55 | confirm(content) { 56 | return ElMessageBox.confirm(content, "系统提示", { 57 | confirmButtonText: '确定', 58 | cancelButtonText: '取消', 59 | type: "warning", 60 | }) 61 | }, 62 | // 提交内容 63 | prompt(content) { 64 | return ElMessageBox.prompt(content, "系统提示", { 65 | confirmButtonText: '确定', 66 | cancelButtonText: '取消', 67 | type: "warning", 68 | }) 69 | }, 70 | // 打开遮罩层 71 | loading(content) { 72 | loadingInstance = ElLoading.service({ 73 | lock: true, 74 | text: content, 75 | background: "rgba(0, 0, 0, 0.7)", 76 | }) 77 | }, 78 | // 关闭遮罩层 79 | closeLoading() { 80 | loadingInstance.close(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /ui/src/settings.js: -------------------------------------------------------------------------------- 1 | export default { 2 | /** 3 | * 网页标题 4 | */ 5 | title: import.meta.env.VITE_APP_TITLE, 6 | /** 7 | * 侧边栏主题 深色主题theme-dark,浅色主题theme-light 8 | */ 9 | sideTheme: 'theme-dark', 10 | /** 11 | * 是否系统布局配置 12 | */ 13 | showSettings: false, 14 | 15 | /** 16 | * 是否显示顶部导航 17 | */ 18 | topNav: false, 19 | 20 | /** 21 | * 是否显示 tagsView 22 | */ 23 | tagsView: true, 24 | 25 | /** 26 | * 是否固定头部 27 | */ 28 | fixedHeader: false, 29 | 30 | /** 31 | * 是否显示logo 32 | */ 33 | sidebarLogo: true, 34 | 35 | /** 36 | * 是否显示动态标题 37 | */ 38 | dynamicTitle: false, 39 | 40 | /** 41 | * @type {string | array} 'production' | ['production', 'development'] 42 | * @description Need show err logs component. 43 | * The default is only used in the production env 44 | * If you want to also use it in dev, you can pass ['production', 'development'] 45 | */ 46 | errorLog: 'production' 47 | } 48 | -------------------------------------------------------------------------------- /ui/src/store/index.js: -------------------------------------------------------------------------------- 1 | const store = createPinia() 2 | 3 | export default store -------------------------------------------------------------------------------- /ui/src/store/modules/app.js: -------------------------------------------------------------------------------- 1 | import Cookies from 'js-cookie' 2 | 3 | const useAppStore = defineStore( 4 | 'app', 5 | { 6 | state: () => ({ 7 | sidebar: { 8 | opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true, 9 | withoutAnimation: false, 10 | hide: false 11 | }, 12 | device: 'desktop', 13 | size: Cookies.get('size') || 'default' 14 | }), 15 | actions: { 16 | toggleSideBar(withoutAnimation) { 17 | if (this.sidebar.hide) { 18 | return false; 19 | } 20 | this.sidebar.opened = !this.sidebar.opened 21 | this.sidebar.withoutAnimation = withoutAnimation 22 | if (this.sidebar.opened) { 23 | Cookies.set('sidebarStatus', 1) 24 | } else { 25 | Cookies.set('sidebarStatus', 0) 26 | } 27 | }, 28 | closeSideBar({ withoutAnimation }) { 29 | Cookies.set('sidebarStatus', 0) 30 | this.sidebar.opened = false 31 | this.sidebar.withoutAnimation = withoutAnimation 32 | }, 33 | toggleDevice(device) { 34 | this.device = device 35 | }, 36 | setSize(size) { 37 | this.size = size; 38 | Cookies.set('size', size) 39 | }, 40 | toggleSideBarHide(status) { 41 | this.sidebar.hide = status 42 | } 43 | } 44 | }) 45 | 46 | export default useAppStore 47 | -------------------------------------------------------------------------------- /ui/src/store/modules/dict.js: -------------------------------------------------------------------------------- 1 | const useDictStore = defineStore( 2 | 'dict', 3 | { 4 | state: () => ({ 5 | dict: new Array() 6 | }), 7 | actions: { 8 | // 获取字典 9 | getDict(_key) { 10 | if (_key == null && _key == "") { 11 | return null; 12 | } 13 | try { 14 | for (let i = 0; i < this.dict.length; i++) { 15 | if (this.dict[i].key == _key) { 16 | return this.dict[i].value; 17 | } 18 | } 19 | } catch (e) { 20 | return null; 21 | } 22 | }, 23 | // 设置字典 24 | setDict(_key, value) { 25 | if (_key !== null && _key !== "") { 26 | this.dict.push({ 27 | key: _key, 28 | value: value 29 | }); 30 | } 31 | }, 32 | // 删除字典 33 | removeDict(_key) { 34 | var bln = false; 35 | try { 36 | for (let i = 0; i < this.dict.length; i++) { 37 | if (this.dict[i].key == _key) { 38 | this.dict.splice(i, 1); 39 | return true; 40 | } 41 | } 42 | } catch (e) { 43 | bln = false; 44 | } 45 | return bln; 46 | }, 47 | // 清空字典 48 | cleanDict() { 49 | this.dict = new Array(); 50 | }, 51 | // 初始字典 52 | initDict() { 53 | } 54 | } 55 | }) 56 | 57 | export default useDictStore 58 | -------------------------------------------------------------------------------- /ui/src/store/modules/settings.js: -------------------------------------------------------------------------------- 1 | import defaultSettings from '@/settings' 2 | import { useDynamicTitle } from '@/utils/dynamicTitle' 3 | 4 | const { sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle } = defaultSettings 5 | 6 | const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || '' 7 | 8 | const useSettingsStore = defineStore( 9 | 'settings', 10 | { 11 | state: () => ({ 12 | title: '', 13 | theme: storageSetting.theme || '#409EFF', 14 | sideTheme: storageSetting.sideTheme || sideTheme, 15 | showSettings: showSettings, 16 | topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav, 17 | tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView, 18 | fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader, 19 | sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo, 20 | dynamicTitle: storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle 21 | }), 22 | actions: { 23 | // 修改布局设置 24 | changeSetting(data) { 25 | const { key, value } = data 26 | if (this.hasOwnProperty(key)) { 27 | this[key] = value 28 | } 29 | }, 30 | // 设置网页标题 31 | setTitle(title) { 32 | this.title = title 33 | useDynamicTitle(); 34 | } 35 | } 36 | }) 37 | 38 | export default useSettingsStore 39 | -------------------------------------------------------------------------------- /ui/src/utils/auth.js: -------------------------------------------------------------------------------- 1 | import Cookies from 'js-cookie' 2 | 3 | const TokenKey = 'Admin-Token' 4 | 5 | export function getToken() { 6 | return Cookies.get(TokenKey) 7 | } 8 | 9 | export function setToken(token) { 10 | return Cookies.set(TokenKey, token) 11 | } 12 | 13 | export function removeToken() { 14 | return Cookies.remove(TokenKey) 15 | } 16 | -------------------------------------------------------------------------------- /ui/src/utils/dict.js: -------------------------------------------------------------------------------- 1 | import useDictStore from '@/store/modules/dict' 2 | import { getDicts } from '@/api/system/dict/data' 3 | 4 | /** 5 | * 获取字典数据 6 | */ 7 | export function useDict(...args) { 8 | const res = ref({}); 9 | return (() => { 10 | args.forEach((dictType, index) => { 11 | res.value[dictType] = []; 12 | const dicts = useDictStore().getDict(dictType); 13 | if (dicts) { 14 | res.value[dictType] = dicts; 15 | } else { 16 | getDicts(dictType).then(resp => { 17 | res.value[dictType] = resp.data.map(p => ({ label: p.dictLabel, value: p.dictValue, elTagType: p.listClass, elTagClass: p.cssClass })) 18 | useDictStore().setDict(dictType, res.value[dictType]); 19 | }) 20 | } 21 | }) 22 | return toRefs(res.value); 23 | })() 24 | } -------------------------------------------------------------------------------- /ui/src/utils/dynamicTitle.js: -------------------------------------------------------------------------------- 1 | import store from '@/store' 2 | import defaultSettings from '@/settings' 3 | import useSettingsStore from '@/store/modules/settings' 4 | 5 | /** 6 | * 动态修改标题 7 | */ 8 | export function useDynamicTitle() { 9 | const settingsStore = useSettingsStore(); 10 | if (settingsStore.dynamicTitle) { 11 | document.title = settingsStore.title + ' - ' + defaultSettings.title; 12 | } else { 13 | document.title = defaultSettings.title; 14 | } 15 | } -------------------------------------------------------------------------------- /ui/src/utils/errorCode.js: -------------------------------------------------------------------------------- 1 | export default { 2 | '401': '认证失败,无法访问系统资源', 3 | '403': '当前操作没有权限', 4 | '404': '访问资源不存在', 5 | 'default': '系统未知错误,请反馈给管理员' 6 | } 7 | -------------------------------------------------------------------------------- /ui/src/utils/jsencrypt.js: -------------------------------------------------------------------------------- 1 | import JSEncrypt from 'jsencrypt/bin/jsencrypt.min' 2 | 3 | // 密钥对生成 http://web.chacuo.net/netrsakeypair 4 | 5 | const publicKey = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdH\n' + 6 | 'nzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==' 7 | 8 | const privateKey = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY\n' + 9 | '7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKN\n' + 10 | 'PuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gA\n' + 11 | 'kM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWow\n' + 12 | 'cSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99Ecv\n' + 13 | 'DQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthh\n' + 14 | 'YhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3\n' + 15 | 'UP8iWi1Qw0Y=' 16 | 17 | // 加密 18 | export function encrypt(txt) { 19 | const encryptor = new JSEncrypt() 20 | encryptor.setPublicKey(publicKey) // 设置公钥 21 | return encryptor.encrypt(txt) // 对数据进行加密 22 | } 23 | 24 | // 解密 25 | export function decrypt(txt) { 26 | const encryptor = new JSEncrypt() 27 | encryptor.setPrivateKey(privateKey) // 设置私钥 28 | return encryptor.decrypt(txt) // 对数据进行解密 29 | } 30 | 31 | -------------------------------------------------------------------------------- /ui/src/utils/permission.js: -------------------------------------------------------------------------------- 1 | import useUserStore from '@/store/modules/user' 2 | 3 | /** 4 | * 字符权限校验 5 | * @param {Array} value 校验值 6 | * @returns {Boolean} 7 | */ 8 | export function checkPermi(value) { 9 | if (value && value instanceof Array && value.length > 0) { 10 | const permissions = useUserStore().permissions 11 | const permissionDatas = value 12 | const all_permission = "*:*:*"; 13 | 14 | const hasPermission = permissions.some(permission => { 15 | return all_permission === permission || permissionDatas.includes(permission) 16 | }) 17 | 18 | if (!hasPermission) { 19 | return false 20 | } 21 | return true 22 | } else { 23 | console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`) 24 | return false 25 | } 26 | } 27 | 28 | /** 29 | * 角色权限校验 30 | * @param {Array} value 校验值 31 | * @returns {Boolean} 32 | */ 33 | export function checkRole(value) { 34 | if (value && value instanceof Array && value.length > 0) { 35 | const roles = useUserStore().roles 36 | const permissionRoles = value 37 | const super_admin = "admin"; 38 | 39 | const hasRole = roles.some(role => { 40 | return super_admin === role || permissionRoles.includes(role) 41 | }) 42 | 43 | if (!hasRole) { 44 | return false 45 | } 46 | return true 47 | } else { 48 | console.error(`need roles! Like checkRole="['admin','editor']"`) 49 | return false 50 | } 51 | } -------------------------------------------------------------------------------- /ui/src/utils/scroll-to.js: -------------------------------------------------------------------------------- 1 | Math.easeInOutQuad = function(t, b, c, d) { 2 | t /= d / 2 3 | if (t < 1) { 4 | return c / 2 * t * t + b 5 | } 6 | t-- 7 | return -c / 2 * (t * (t - 2) - 1) + b 8 | } 9 | 10 | // requestAnimationFrame for Smart Animating http://goo.gl/sx5sts 11 | var requestAnimFrame = (function() { 12 | return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) } 13 | })() 14 | 15 | /** 16 | * Because it's so fucking difficult to detect the scrolling element, just move them all 17 | * @param {number} amount 18 | */ 19 | function move(amount) { 20 | document.documentElement.scrollTop = amount 21 | document.body.parentNode.scrollTop = amount 22 | document.body.scrollTop = amount 23 | } 24 | 25 | function position() { 26 | return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop 27 | } 28 | 29 | /** 30 | * @param {number} to 31 | * @param {number} duration 32 | * @param {Function} callback 33 | */ 34 | export function scrollTo(to, duration, callback) { 35 | const start = position() 36 | const change = to - start 37 | const increment = 20 38 | let currentTime = 0 39 | duration = (typeof (duration) === 'undefined') ? 500 : duration 40 | var animateScroll = function() { 41 | // increment the time 42 | currentTime += increment 43 | // find the value with the quadratic in-out easing function 44 | var val = Math.easeInOutQuad(currentTime, start, change, duration) 45 | // move the document.body 46 | move(val) 47 | // do the animation unless its over 48 | if (currentTime < duration) { 49 | requestAnimFrame(animateScroll) 50 | } else { 51 | if (callback && typeof (callback) === 'function') { 52 | // the animation is done so lets callback 53 | callback() 54 | } 55 | } 56 | } 57 | animateScroll() 58 | } 59 | -------------------------------------------------------------------------------- /ui/src/utils/theme.js: -------------------------------------------------------------------------------- 1 | // 处理主题样式 2 | export function handleThemeStyle(theme) { 3 | document.documentElement.style.setProperty('--el-color-primary', theme) 4 | for (let i = 1; i <= 9; i++) { 5 | document.documentElement.style.setProperty(`--el-color-primary-light-${i}`, `${getLightColor(theme, i / 10)}`) 6 | } 7 | for (let i = 1; i <= 9; i++) { 8 | document.documentElement.style.setProperty(`--el-color-primary-dark-${i}`, `${getDarkColor(theme, i / 10)}`) 9 | } 10 | } 11 | 12 | // hex颜色转rgb颜色 13 | export function hexToRgb(str) { 14 | str = str.replace('#', '') 15 | let hexs = str.match(/../g) 16 | for (let i = 0; i < 3; i++) { 17 | hexs[i] = parseInt(hexs[i], 16) 18 | } 19 | return hexs 20 | } 21 | 22 | // rgb颜色转Hex颜色 23 | export function rgbToHex(r, g, b) { 24 | let hexs = [r.toString(16), g.toString(16), b.toString(16)] 25 | for (let i = 0; i < 3; i++) { 26 | if (hexs[i].length == 1) { 27 | hexs[i] = `0${hexs[i]}` 28 | } 29 | } 30 | return `#${hexs.join('')}` 31 | } 32 | 33 | // 变浅颜色值 34 | export function getLightColor(color, level) { 35 | let rgb = hexToRgb(color) 36 | for (let i = 0; i < 3; i++) { 37 | rgb[i] = Math.floor((255 - rgb[i]) * level + rgb[i]) 38 | } 39 | return rgbToHex(rgb[0], rgb[1], rgb[2]) 40 | } 41 | 42 | // 变深颜色值 43 | export function getDarkColor(color, level) { 44 | let rgb = hexToRgb(color) 45 | for (let i = 0; i < 3; i++) { 46 | rgb[i] = Math.floor(rgb[i] * (1 - level)) 47 | } 48 | return rgbToHex(rgb[0], rgb[1], rgb[2]) 49 | } 50 | -------------------------------------------------------------------------------- /ui/src/views/error/401.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 43 | 44 | 83 | -------------------------------------------------------------------------------- /ui/src/views/monitor/druid/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | -------------------------------------------------------------------------------- /ui/src/views/redirect/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /ui/src/views/system/user/profile/userInfo.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 57 | -------------------------------------------------------------------------------- /ui/src/views/tool/build/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /ui/src/views/tool/gen/basicInfoForm.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 49 | -------------------------------------------------------------------------------- /ui/src/views/tool/swagger/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 11 | -------------------------------------------------------------------------------- /ui/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig, loadEnv } from 'vite' 2 | import path from 'path' 3 | import createVitePlugins from './vite/plugins' 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig(({ mode, command }) => { 7 | const env = loadEnv(mode, process.cwd()) 8 | const { VITE_APP_ENV } = env 9 | return { 10 | // 部署生产环境和开发环境下的URL。 11 | // 默认情况下,vite 会假设你的应用是被部署在一个域名的根路径上 12 | // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。 13 | base: VITE_APP_ENV === 'production' ? '/' : '/', 14 | plugins: [ 15 | createVitePlugins(env, command === 'build'), 16 | ], 17 | resolve: { 18 | // https://cn.vitejs.dev/config/#resolve-alias 19 | alias: { 20 | // 设置路径 21 | '~': path.resolve(__dirname, './'), 22 | // 设置别名 23 | '@': path.resolve(__dirname, './src') 24 | }, 25 | // https://cn.vitejs.dev/config/#resolve-extensions 26 | extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'] 27 | }, 28 | // vite 相关配置 29 | server: { 30 | port: 80, 31 | host: true, 32 | open: true, 33 | proxy: { 34 | // https://cn.vitejs.dev/config/#server-proxy 35 | '/dev-api': { 36 | target: 'http://localhost:8090', 37 | changeOrigin: true, 38 | rewrite: (p) => p.replace(/^\/dev-api/, '') 39 | } 40 | } 41 | }, 42 | //fix:error:stdin>:7356:1: warning: "@charset" must be the first rule in the file 43 | css: { 44 | postcss: { 45 | plugins: [ 46 | { 47 | postcssPlugin: 'internal:charset-removal', 48 | AtRule: { 49 | charset: (atRule) => { 50 | if (atRule.name === 'charset') { 51 | atRule.remove(); 52 | } 53 | } 54 | } 55 | } 56 | ] 57 | } 58 | } 59 | } 60 | }) 61 | -------------------------------------------------------------------------------- /ui/vite/plugins/auto-import.js: -------------------------------------------------------------------------------- 1 | import autoImport from 'unplugin-auto-import/vite' 2 | 3 | export default function createAutoImport() { 4 | return autoImport({ 5 | imports: [ 6 | 'vue', 7 | 'vue-router', 8 | 'pinia' 9 | ], 10 | dts: false 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /ui/vite/plugins/compression.js: -------------------------------------------------------------------------------- 1 | import compression from 'vite-plugin-compression' 2 | 3 | export default function createCompression(env) { 4 | const { VITE_BUILD_COMPRESS } = env 5 | const plugin = [] 6 | if (VITE_BUILD_COMPRESS) { 7 | const compressList = VITE_BUILD_COMPRESS.split(',') 8 | if (compressList.includes('gzip')) { 9 | // http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件 10 | plugin.push( 11 | compression({ 12 | ext: '.gz', 13 | deleteOriginFile: false 14 | }) 15 | ) 16 | } 17 | if (compressList.includes('brotli')) { 18 | plugin.push( 19 | compression({ 20 | ext: '.br', 21 | algorithm: 'brotliCompress', 22 | deleteOriginFile: false 23 | }) 24 | ) 25 | } 26 | } 27 | return plugin 28 | } 29 | -------------------------------------------------------------------------------- /ui/vite/plugins/index.js: -------------------------------------------------------------------------------- 1 | import vue from '@vitejs/plugin-vue' 2 | 3 | import createAutoImport from './auto-import' 4 | import createSvgIcon from './svg-icon' 5 | import createCompression from './compression' 6 | import createSetupExtend from './setup-extend' 7 | 8 | export default function createVitePlugins(viteEnv, isBuild = false) { 9 | const vitePlugins = [vue()] 10 | vitePlugins.push(createAutoImport()) 11 | vitePlugins.push(createSetupExtend()) 12 | vitePlugins.push(createSvgIcon(isBuild)) 13 | isBuild && vitePlugins.push(...createCompression(viteEnv)) 14 | return vitePlugins 15 | } 16 | -------------------------------------------------------------------------------- /ui/vite/plugins/setup-extend.js: -------------------------------------------------------------------------------- 1 | import setupExtend from 'vite-plugin-vue-setup-extend' 2 | 3 | export default function createSetupExtend() { 4 | return setupExtend() 5 | } 6 | -------------------------------------------------------------------------------- /ui/vite/plugins/svg-icon.js: -------------------------------------------------------------------------------- 1 | import { createSvgIconsPlugin } from 'vite-plugin-svg-icons' 2 | import path from 'path' 3 | 4 | export default function createSvgIcon(isBuild) { 5 | return createSvgIconsPlugin({ 6 | iconDirs: [path.resolve(process.cwd(), 'src/assets/icons/svg')], 7 | symbolId: 'icon-[dir]-[name]', 8 | svgoOptions: isBuild 9 | }) 10 | } 11 | --------------------------------------------------------------------------------