一、后端功能开源
1. 项目结构
代码均已放到system包下
2. sql脚本
脚本放与resources/sql目录下cloud.sql也已提交
/*
Navicat Premium Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 80036 (8.0.36-0ubuntu0.22.04.1)
Source Host : localhost:3306
Source Schema : cloud
Target Server Type : MySQL
Target Server Version : 80036 (8.0.36-0ubuntu0.22.04.1)
File Encoding : 65001
Date: 02/06/2024 18:30:47
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for sys_file
-- ----------------------------
DROP TABLE IF EXISTS `sys_file`;
CREATE TABLE `sys_file` (
`file_id` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
`file_type` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL COMMENT '文件类型(1:WORD,2:EXCEL,3:PPT,4:PDF,5:TXT)',
`file_size` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL COMMENT '文件大小',
`file_location` varchar(1000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL COMMENT '文件地址',
`store_name` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL COMMENT '文件存储名',
`show_name` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL COMMENT '文件显示名',
`remark` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL COMMENT '备注',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_user` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL COMMENT '创建人',
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
`update_user` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL COMMENT '修改人',
`del_flag` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL COMMENT '删除标志',
PRIMARY KEY (`file_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC COMMENT='附件';
-- ----------------------------
-- Records of sys_file
-- ----------------------------
BEGIN;
COMMIT;
-- ----------------------------
-- Table structure for sys_module
-- ----------------------------
DROP TABLE IF EXISTS `sys_module`;
CREATE TABLE `sys_module` (
`module_id` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '菜单ID',
`module_name` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '菜单名',
`module_url` varchar(258) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '菜单链接',
`module_code` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '菜单编码',
`sort_code` int DEFAULT NULL COMMENT '排序码',
`parent_id` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '父菜单ID',
`parent_name` varchar(60) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '父菜单名',
PRIMARY KEY (`module_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC COMMENT='菜单资源表';
-- ----------------------------
-- Records of sys_module
-- ----------------------------
BEGIN;
INSERT INTO `sys_module` (`module_id`, `module_name`, `module_url`, `module_code`, `sort_code`, `parent_id`, `parent_name`) VALUES ('001', '算法小生', NULL, NULL, 1, '-1', NULL);
INSERT INTO `sys_module` (`module_id`, `module_name`, `module_url`, `module_code`, `sort_code`, `parent_id`, `parent_name`) VALUES ('1797210739841884160', '机构管理', '/org', 'org', 1, '001', '算法小生');
INSERT INTO `sys_module` (`module_id`, `module_name`, `module_url`, `module_code`, `sort_code`, `parent_id`, `parent_name`) VALUES ('1797210846234599424', '菜单管理', '/module', 'module', 2, '001', '算法小生');
INSERT INTO `sys_module` (`module_id`, `module_name`, `module_url`, `module_code`, `sort_code`, `parent_id`, `parent_name`) VALUES ('1797210920687689728', '用户管理', '/user', 'user', 3, '001', '算法小生');
INSERT INTO `sys_module` (`module_id`, `module_name`, `module_url`, `module_code`, `sort_code`, `parent_id`, `parent_name`) VALUES ('1797211013025292288', '菜单管理', '/role', 'role', 4, '001', '算法小生');
COMMIT;
-- ----------------------------
-- Table structure for sys_org
-- ----------------------------
DROP TABLE IF EXISTS `sys_org`;
CREATE TABLE `sys_org` (
`org_id` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '机构ID',
`org_code` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '机构编码',
`org_name` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '机构名称',
`parent_id` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '父机构ID',
`parent_code` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '父机构编码',
`parent_name` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '父机构名称',
`sort_code` int DEFAULT NULL COMMENT '排序码',
`remark` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '备注',
`del_flag` varchar(11) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '删除标记 0正常 1删除',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_user` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '创建人',
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
`update_user` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '修改人',
PRIMARY KEY (`org_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC COMMENT='机构信息表';
-- ----------------------------
-- Records of sys_org
-- ----------------------------
BEGIN;
INSERT INTO `sys_org` (`org_id`, `org_code`, `org_name`, `parent_id`, `parent_code`, `parent_name`, `sort_code`, `remark`, `del_flag`, `create_time`, `create_user`, `update_time`, `update_user`) VALUES ('1797211572465754112', '001.001', '欢迎关注我', NULL, '001', '算法小生', 1, '', '0', '2024-06-02 18:20:04', 'admin', NULL, NULL);
INSERT INTO `sys_org` (`org_id`, `org_code`, `org_name`, `parent_id`, `parent_code`, `parent_name`, `sort_code`, `remark`, `del_flag`, `create_time`, `create_user`, `update_time`, `update_user`) VALUES ('4037a607-de4a-11e7-b521-4437e6437701', '001', '算法小生', '-1', '-1', NULL, 1, '', '0', '2023-08-01 13:31:21', 'admin', NULL, NULL);
COMMIT;
-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`role_id` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '角色ID',
`role_name` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '角色名',
`remark` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`role_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC COMMENT='角色信息表';
-- ----------------------------
-- Records of sys_role
-- ----------------------------
BEGIN;
INSERT INTO `sys_role` (`role_id`, `role_name`, `remark`) VALUES ('admin', '管理员', '各组织机构管理员');
INSERT INTO `sys_role` (`role_id`, `role_name`, `remark`) VALUES ('normal', '一般用户', '普通用户');
INSERT INTO `sys_role` (`role_id`, `role_name`, `remark`) VALUES ('super-admin', '超级管理员', ' 系统管理员,全部管理功能,不能删除!!');
COMMIT;
-- ----------------------------
-- Table structure for sys_role_module
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_module`;
CREATE TABLE `sys_role_module` (
`role_id` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '角色ID',
`module_id` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '菜单ID'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC COMMENT='角色与菜单资源关系表';
-- ----------------------------
-- Records of sys_role_module
-- ----------------------------
BEGIN;
INSERT INTO `sys_role_module` (`role_id`, `module_id`) VALUES ('super-admin', '001');
INSERT INTO `sys_role_module` (`role_id`, `module_id`) VALUES ('super-admin', '1797210739841884160');
INSERT INTO `sys_role_module` (`role_id`, `module_id`) VALUES ('super-admin', '1797210846234599424');
INSERT INTO `sys_role_module` (`role_id`, `module_id`) VALUES ('super-admin', '1797210920687689728');
INSERT INTO `sys_role_module` (`role_id`, `module_id`) VALUES ('super-admin', '1797211013025292288');
INSERT INTO `sys_role_module` (`role_id`, `module_id`) VALUES ('normal', '1797210846234599424');
COMMIT;
-- ----------------------------
-- Table structure for usr_user
-- ----------------------------
DROP TABLE IF EXISTS `usr_user`;
CREATE TABLE `usr_user` (
`user_id` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '用户ID',
`username` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '用户名',
`account` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '用户账号',
`password` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '密码',
`org_code` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '机构编码',
`role_id` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '角色ID',
`department` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '部门',
`title` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '职称',
`employee_number` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '工号',
`state` varchar(2) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '状态 0启用 1禁用',
`phone_number` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '手机号码',
`gender` varchar(2) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '性别 0男 1女',
`del_flag` varchar(11) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '删除标记 0正常 1删除',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_user` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '创建人',
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
`update_user` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '修改人',
PRIMARY KEY (`user_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC COMMENT='用户信息表';
-- ----------------------------
-- Records of usr_user
-- ----------------------------
BEGIN;
INSERT INTO `usr_user` (`user_id`, `username`, `account`, `password`, `org_code`, `role_id`, `department`, `title`, `employee_number`, `state`, `phone_number`, `gender`, `del_flag`, `create_time`, `create_user`, `update_time`, `update_user`) VALUES ('1', '超级管理员', 'admin', 'c4ca4238a0b923820dcc509a6f75849b', '001', 'super-admin', NULL, NULL, NULL, '0', '1234567990', '', '0', '2023-07-24 16:18:36', 'admin', '2024-06-02 18:02:49', 'admin');
INSERT INTO `usr_user` (`user_id`, `username`, `account`, `password`, `org_code`, `role_id`, `department`, `title`, `employee_number`, `state`, `phone_number`, `gender`, `del_flag`, `create_time`, `create_user`, `update_time`, `update_user`) VALUES ('1797211702321405952', 'shen', 'shen', 'e10adc3949ba59abbe56e057f20f883e', '001.001', 'normal', NULL, NULL, NULL, '0', NULL, NULL, '0', '2024-06-02 18:20:35', 'admin', '2024-06-02 18:28:03', 'admin');
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
3. 核心代码
菜单模块服务实现类
package online.shenjian.cloud.api.system.service.impl;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import online.shenjian.cloud.client.cloud.dto.system.module.ModuleDto;
import online.shenjian.cloud.client.cloud.dto.system.module.ModuleQueryDto;
import online.shenjian.cloud.client.cloud.dto.system.module.ModuleTreeDto;
import online.shenjian.cloud.api.system.mapper.ModuleMapper;
import online.shenjian.cloud.api.system.mapper.RoleModuleMapper;
import online.shenjian.cloud.api.system.model.Module;
import online.shenjian.cloud.api.system.model.RoleModule;
import online.shenjian.cloud.api.system.service.ModuleService;
import online.shenjian.cloud.api.utils.TreeUtils;
import io.micrometer.common.util.StringUtils;
import online.shenjian.cloud.common.utils.CommonDtoUtils;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author shenjian
* @since 2023/8/1
*/
@Service
public class ModuleServiceImpl implements ModuleService {
private ModuleMapper moduleMapper;
private RoleModuleMapper roleModuleMapper;
public ModuleServiceImpl(ModuleMapper moduleMapper, RoleModuleMapper roleModuleMapper) {
this.moduleMapper = moduleMapper;
this.roleModuleMapper = roleModuleMapper;
}
@Override
public List<ModuleTreeDto> initModuleInfoTree() {
QueryWrapper<Module> queryWrapper = new QueryWrapper<>();
List<Module> moduleList = moduleMapper.selectList(queryWrapper);
List<ModuleTreeDto> moduleTreeDtoList = TreeUtils.listModuleTree(moduleList, "-1");
return moduleTreeDtoList;
}
@Override
public IPage<ModuleDto> listModule(ModuleQueryDto moduleQueryDto) {
IPage<Module> page = new Page<>(moduleQueryDto.getPageNumber(), moduleQueryDto.getPageSize());
QueryWrapper<Module> queryWrapper = new QueryWrapper<>();
// 查询该组织机构下所有信息
queryWrapper.likeRight("parent_id", moduleQueryDto.getParentId());
if (StringUtils.isNotBlank(moduleQueryDto.getModuleName())) {
queryWrapper.like("module_name", moduleQueryDto.getModuleName());
}
queryWrapper.orderByAsc("sort_code");
IPage<Module> iPage = moduleMapper.selectPage(page, queryWrapper);
List<ModuleDto> patientDtoList = CommonDtoUtils.transformList(iPage.getRecords(), ModuleDto.class);
IPage<ModuleDto> resultPage = new Page<>(iPage.getCurrent(), iPage.getSize(), iPage.getTotal());
resultPage.setRecords(patientDtoList);
return resultPage;
}
@Override
public Boolean saveModule(ModuleDto moduleDto) {
Module module = CommonDtoUtils.transform(moduleDto, Module.class);
module.setModuleId(IdUtil.getSnowflakeNextIdStr());
moduleMapper.insert(module);
return true;
}
@Override
public void deleteModule(String moduleId) {
if (StringUtils.isBlank(moduleId)) {
return ;
}
Module module = new Module();
module.setModuleId(moduleId);
moduleMapper.deleteById(module);
QueryWrapper<RoleModule> roleModuleQueryWrapper = new QueryWrapper<>();
roleModuleQueryWrapper.eq("module_id", moduleId);
roleModuleMapper.delete(roleModuleQueryWrapper);
}
@Override
public Boolean updateModule(ModuleDto moduleDto) {
if (StringUtils.isBlank(moduleDto.getModuleId())) {
return false;
}
Module module = CommonDtoUtils.transform(moduleDto, Module.class);
moduleMapper.updateById(module);
return true;
}
}
package online.shenjian.cloud.api.system.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import online.shenjian.cloud.client.cloud.dto.system.module.ModuleDto;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* 菜单信息加强版Mapper
*
* @author shenjian
* @since 2023/8/10
*/
@Repository
public interface ModulePlusMapper extends BaseMapper<ModuleDto> {
String querySql = "SELECT " +
" m.module_name, m.module_code, rm.role_id " +
" FROM " +
" sys_module AS m " +
" LEFT JOIN sys_role_module AS rm ON m.module_id = rm.module_id";
String wrapperSql = "SELECT * FROM ( " + querySql + " ) AS q ${ew.customSqlSegment}";
@Select(wrapperSql)
List<ModuleDto> list(@Param("ew") Wrapper queryWrapper);
}
4. 代码访问链接
https://github.com/SJshenjian/cloud
https://gitee.com/SJshenjian/cloud
喜欢的话麻烦点个star ~ 或 在公众号 算法小生打个赏~
下一篇文章将开源RBAC相关的管理页面
二、前端页面开源
1. 效果展示
2. 核心代码
vue.config.js
let ip = process.env.VUE_APP_IP
let outputDir = process.env.OUTPUT_DIR
let assetsDir = process.env.ASSETS_DIR
let indexPath = process.env.INDEX_PATH
const version = new Date().getTime();
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const TerserWebpackPlugin = require("terser-webpack-plugin");
const isProduction = process.env.NODE_ENV === 'production'
const path = require('path')
const webpack = require("webpack");
module.exports = {
lintOnSave: false, // 关闭eslint
publicPath:'./',
outputDir: outputDir, // 输出文件目录
assetsDir: assetsDir,
indexPath: indexPath,
// 去除生产环境的productionSourceMap
productionSourceMap: false,
chainWebpack: config => {
// webpack 会默认给commonChunk打进chunk-vendors,所以需要对webpack的配置进行delete
config.optimization.delete('splitChunks')
// prefetch,此插件是用来告诉浏览器在页面加载完成后,利用空闲时间提前获取用户未来可能会访问的内容
config.plugins.delete("prefetch")
// if (!isProduction) {
// config.plugin('webpack-bundle-analyzer')
// .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
// }
},
css: {
loaderOptions:{
sass:{
additionalData:'@import "@/styles/themes.scss";'
}
},
// 是否使用css分离插件 ExtractTextPlugin
extract: {
// 修改打包后css文件名 // css打包文件,添加时间戳
filename: `assert/css/str[name].[chunkhash].${version}.css`,
chunkFilename: `assert/css/str[name].[chunkhash].${version}.css`
}
},
configureWebpack: {
output: isProduction ? { // 输出重构 打包编译后的 文件名称 【模块名称.版本号.时间戳】
filename: `assert/js/str[name].[chunkhash].${version}.js`,
chunkFilename: `assert/js/str[id].[chunkhash].${version}.js`
} : {},
// 开启分离js
optimization: isProduction ? {
runtimeChunk: 'single',
splitChunks: {
// 表示选择哪些 chunks 进行分割,可选值有:async,initial和all
chunks: 'all',
maxInitialRequests: Infinity,
// 表示新分离出的chunk必须大于等于minSize,默认为30000,约30kb。
minSize: 1000 * 60,
// 表示按需加载文件时,并行请求的最大数目。默认为5。
maxAsyncRequests: 5,
// 表示拆分出的chunk的名称连接符。默认为~。如chunk~vendors.js
automaticNameDelimiter: '~',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name(module) {
// 排除node_modules 然后吧 @ 替换为空 ,考虑到服务器的兼容
const match = module.context && module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/);
const packageName = match ? match[1] : 'default-package-name';
return `npm.${packageName.replace('@', '')}`
}
}
}
}
} : {},
// 取消webpack警告的性能提示
performance: isProduction ? {
hints: 'warning',
//入口起点的最大体积
maxEntrypointSize: 1000 * 500,
//生成文件的最大体积
maxAssetSize: 1000 * 1000,
//只给出 js 文件的性能提示
assetFilter: function (assetFilename) {
return assetFilename.endsWith('.js');
}
} : {},
plugins: isProduction ? [
// 只打包改变的文件 用于根据模块的相对路径生成 hash 作为模块 id, 一般用于生产环境
new webpack.ids.HashedModuleIdsPlugin({
context: __dirname,
hashFunction: 'sha256',
hashDigest: 'hex',
hashDigestLength: 20,
}),
// nginx也要开启压缩
new CompressionWebpackPlugin({
algorithm: 'gzip',
test: /\.(js|css)$/,// 匹配文件名
threshold: 10000, // 对超过10k的数据压缩
deleteOriginalAssets: false, // 不删除源文件
minRatio: 0.8 // 压缩比
}),
new TerserWebpackPlugin ()
]: [],
module: {
rules: [
{
test: path.resolve(__dirname, 'node_modules/leader-line/'),
use: [
{
// 解决leader-line报错问题
loader: 'skeleton-loader',
options: {
procedure: content => `${content}export default LeaderLine`
}
}
]
}
]
}
},
// 配置代理
devServer:{
port:8089,
open: true,
proxy:{
'/api':{
target:'http://' + ip,
changeOrigin: true,
pathRewrite:{
'^/api':'' //请求的时候使用这个api就可以
}
}
}
}
}
用户新增页面
<!--
* 用户创建
* @author shenjian
* @since 2023/08/8
-->
<template>
<div class="user-add">
<el-dialog class="new-dialog"
v-model="myAddFlag" :width="width" align-center
title="用户管理 新增" :show-close="false" destroy-on-close
:close-on-click-modal="false">
<el-form :model="form" :rules="formRules" ref="form" label-width="100px">
<el-row>
<el-col :span="10">
<el-form-item prop="orgCode" label="所属机构:">
<OrgTreeSelect v-model="form.orgCode" :tree="tree" style="width: 100%"></OrgTreeSelect>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item prop="username" label="用户姓名:">
<el-input v-model="form.username" placeholder="请输入用户姓名"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="10">
<el-form-item prop="account" label="登录帐号:">
<el-input v-model="form.account" placeholder="请输入登录帐号"></el-input>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item prop="phoneNumber" label="手机号码:">
<el-input v-model="form.phoneNumber" placeholder="请输入手机号码"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="10">
<el-form-item prop="roleId" label="用户角色:">
<el-select v-model="form.roleId" placeholder="请选择用户角色" style="width:100%">
<el-option v-for="item in roleList" size="small" :key="item.roleId" :label="item.roleName" :value="item.roleId"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item prop="employeeNumber" label="工号:">
<el-input v-model="form.employeeNumber" placeholder="请输入工号"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="10">
<el-form-item prop="department" label="科室:">
<el-input v-model="form.department" placeholder="请输入科室"></el-input>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item prop="title" label="职称:">
<el-input v-model="form.title" placeholder="请输入职称"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="20">
<el-form-item prop="state" label="状态:" required>
<el-radio-group v-model="form.state" style="width:100%">
<el-radio :label="'0'">启用</el-radio>
<el-radio :label="'1'">禁用</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button :icon="Close" @click="cancel">取消</el-button>
<el-button type="primary" :icon="Check" @click="save('form')">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script>
import {Check, Close} from "@element-plus/icons-vue";
import {isMobile} from "@/util/validate";
import OrgTreeSelect from "@/components/tree/OrgTreeSelect.vue";
import {ElMessageBox} from "element-plus";
export default {
name: 'addUser',
components: {OrgTreeSelect},
computed: {
Check() {
return Check
},
Close() {
return Close
}
},
props: ['addFlag', 'currentTreeNode'],
created() {
this.listTree()
this.listRole()
},
data () {
let orgCodeValidator = (ruler, value, callback) => {
if (this.$isEmpty(value)) {
callback(new Error('请选择所属机构!'))
} else {
callback()
}
};
let roleIdValidator = (ruler, value, callback) => {
if (this.$isEmpty(value)) {
callback(new Error('请选择用户角色!'))
} else {
callback()
}
};
let usernameValidator = (ruler, value, callback) => {
if (this.$isEmpty(value)) {
callback(new Error('请输入用户姓名!'))
} else {
callback()
}
};
let accountValidator = (ruler, value, callback) => {
if (this.$isEmpty(value)) {
callback(new Error('请输入登录账号!'))
} else {
callback()
}
};
let phoneValidator = (ruler, value, callback) => {
if (this.$isEmpty(value)) {
callback(new Error('请输入手机号码!'))
} else if (!isMobile(value)) {
callback(new Error('手机号码格式错误,请重新输入!'))
} else {
callback()
}
};
return {
myAddFlag: false,
roleList: [],
tree: [],
form: {
orgCode: '',
username: '',
account: '',
phoneNumber: '',
roleId: '',
employeeNumber: '',
department: '',
title: '',
state: '0'
},
width: this.$isMobileDevice ? '80%' : '50%',
formRules: {
orgCode: [
{validator: orgCodeValidator, trigger: ['blur', 'change'], required: true}
],
username: [
{validator: usernameValidator, trigger: 'blur', required: true}
],
account: [
{validator: accountValidator, trigger: 'blur', required: true}
],
roleId: [
{validator: roleIdValidator, trigger: ['blur', 'change'], required: true}
],
phoneNumber: [
{validator: phoneValidator, trigger: 'blur', required: true}
],
},
}
},
watch: {
addFlag: {
handler(newVal, oldVal) {
this.myAddFlag = newVal
},
immediate: true,
},
currentTreeNode: {
handler(newVal, oldVal) {
this.form.parentName = newVal['label']
this.form.parentCode = newVal['userCode']
},
immediate: true,
}
},
methods: {
// 取消
cancel() {
this.form = {
orgCode: '',
username: '',
account: '',
phoneNumber: '',
roleId: '',
employeeNumber: '',
department: '',
title: '',
state: '0'
},
this.$emit("updateAddFlag", false)
},
listRole() {
const self = this
self.$http.post('/role/list', {pageNumber: 1, pageSize: 30}, 'apiUrl').then(res => {
self.roleList = res.records
})
},
listTree() {
const self = this
self.$http.post('/org/initOrgInfoTree', {}, 'apiUrl').then(res => {
self.tree = res
})
},
updateCurrentTreeNode(val) {
this.form.orgCode = val.orgCode
},
// 保存
save (formName) {
const self = this
self.$refs[formName].validate(async (valid) => {
if (valid) {
self.$http.post('/user/save', self.form, 'apiUrl', {body: 'json'}).then((res) => {
if (res === false || res === undefined) {
return false
}
ElMessageBox.alert(res, '提示', {
confirmButtonText: '确认',
})
this.cancel()
this.$emit('listData', '')
})
}
})
}
}
}
</script>
<style>
.new-dialog .el-dialog__footer {
background-color: #daebfb;
padding-bottom: 10px;
}
.new-dialog .el-dialog__title {
color: white
}
.new-dialog .el-dialog__header {
background-color: #132EBE;
margin-right: 0px;
}
</style>
角色列表页面
<!--
* 角色列表
* @author shenjian
* @since 2023/08/07
-->
<template>
<div class="role">
<el-row>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
<el-row>
<el-col :xs="24" :sm="24" :md="24" :lg="18" :xl="14">
<el-form :inline="true" style="height: 20px; margin: 20px 20px 20px 20px">
<el-form-item label="角色名称:">
<el-input v-model="query.roleName" placeholder="请输入角色名称" clearable></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" :icon="Search" style="margin-left: 20px;" @click="listData">查询</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
<el-row style="margin: 20px 20px 20px 20px">
<el-col :xs="19" :sm="19" :md="19" :lg="20" :xl="21">
<el-row>
<el-col :xs="4" :sm="4" :md="4" :lg="4" :xl="4">
<span style="font-weight: bolder">角色管理</span>
</el-col>
<el-col :xs="20" :sm="20" :md="20" :lg="20" :xl="20" style="float: right;">
<el-button type="primary" size="small" class="iconfont icon-quanxianyuechi-xianxing" style="margin-left: 20px; font-size: 12px; float: right" @click="handleAuth">
<span style="margin-left: 4px;">权限分配</span></el-button>
<el-button type="primary" size="small" :icon="Delete" style="margin-left: 20px; float: right" @click="handleDelete">删除</el-button>
<el-button type="primary" size="small" :icon="Edit" style="margin-left: 20px; float: right" @click="handleEdit">编辑</el-button>
<el-button type="primary" size="small" :icon="Plus" style="margin-left: 20px; float: right" @click="handleAdd">增加</el-button>
</el-col>
</el-row>
<el-row style="margin-top: 10px">
<el-table :data="dataList" @current-change="handleCurrentChange" border highlight-current-row :header-cell-style="setRowClass" :cell-style="{ textAlign: 'center' }" stripe>
<el-table-column prop="roleId" label="角色编码"> </el-table-column>
<el-table-column prop="roleName" label="角色名称"> </el-table-column>
<el-table-column prop="status" label="状态">
<template v-slot="scope">{{ scope.row.status === '0' ? '不使用' : '使用' }}</template>
</el-table-column>
<el-table-column prop="category" label="是否评估机构">
<template v-slot="scope">{{ scope.row.category === '0' ? '否' : '是' }}</template>
</el-table-column>
<el-table-column prop="remark" label="备注"></el-table-column>
</el-table>
</el-row>
<el-row style="float:right; margin-top: 15px;">
<pagination
background
@pagination="updatePageInfo"
:page-size="page.pageSize"
v-model:current-page="page.pageNumber"
:total="page.total"
></pagination>
</el-row>
</el-col>
<el-col :xs="5" :sm="5" :md="5" :lg="4" :xl="3">
<el-row style="font-weight: bolder; margin-left: 20px">菜单树</el-row>
<el-row style="margin-top: 10px; margin-left: 20px">
<div class="checkbox-tree">
<el-tree :data="tree" :indent="50" show-checkbox :default-checked-keys="checkedKeys" node-key="moduleId" ref="tree">
<template #default="{ node }">
<span class="custom-tree-node">
<i v-if="node.isLeaf && node.isLeaf === true" class="iconfont icon-24gl-fileEmpty" ref="icon" style="font-size: 20px; color: #A4B3D6; cursor: pointer;"></i>
<i v-else class="iconfont icon-wenjianjia-guan_folder-close" style="font-size: 20px; color: #EBD47B; cursor: pointer"></i>
<span style="margin-left: 5px">{{ node.label }}</span>
</span>
</template>
</el-tree>
</div>
</el-row>
</el-col>
</el-row>
</el-col>
</el-row>
</div>
<div>
<add-role v-if="visible.add" :addFlag="visible.add" :currentTreeNode="currentTreeNode" @updateAddFlag="updateAddFlag" @listData="listData"></add-role>
<edit-role v-if="visible.edit" :editFlag="visible.edit" :currentRow="currentRow" @updateEditFlag="updateEditFlag" @listData="listData"></edit-role>
</div>
</template>
<script>
import {Delete, Edit, Plus, Search} from "@element-plus/icons-vue";
import Pagination from "@/components/pagination/Index.vue";
import AddRole from "@/views/system/role/Add.vue";
import {ElMessageBox} from "element-plus";
import EditRole from "@/views/system/role/Edit.vue";
export default {
name: 'role',
computed: {
Delete() {
return Delete
},
Edit() {
return Edit
},
Plus() {
return Plus
},
Search() {
return Search
}
},
components: {EditRole, AddRole, Pagination},
data() {
return {
tree: [],
dataList: [],
// 查询条件
query: {
roleName: '',
},
// 选中树节点信息
currentTreeNode: '',
// 表格选中行信息
currentRow: '',
visible: {
add: false,
edit: false
},
checkedKeys: [],
page: {
pageNumber: 1,
pageSize: 10,
total: 10
}
}
},
created() {
this.listData()
},
methods: {
listData(ignoreTree) {
if (!ignoreTree) {
this.listTree()
}
const self = this
self.currentRow = ''
self.query['pageNumber'] = self.page.pageNumber
self.query['pageSize'] = self.page.pageSize
self.$http.post('/role/list', self.query, 'apiUrl').then(res => {
self.dataList = res.records
self.page.total = res.total
})
},
listTree() {
const self = this
self.$http.post('/module/initModuleInfoTree', {}, 'apiUrl').then(res => {
self.tree = res
})
},
handleCurrentChange (val) {
if (val) {
this.currentRow = val
this.getCheckedKey()
}
},
setRowClass () {
return {background: '#F3F3F3', textAlign: 'center', color: 'black'}
},
updatePageInfo (data) {
const self = this
self.page.pageNumber = data.pageNumber
self.page.pageSize = data.pageSize
self.listData()
},
updateCurrentTreeNode(val) {
this.currentTreeNode = val;
this.listData(true)
},
// 更新新建对话框展示
updateAddFlag() {
this.visible.add = false
},
updateEditFlag() {
this.visible.edit = false
},
handleAdd() {
const self = this
self.visible.add = true
},
handleEdit() {
const self = this
if (self.currentRow === '') {
self.$message.warning('请选择一条需要编辑的数据!')
return
}
self.visible.edit = true
},
// 权限分配
handleAuth() {
const self = this
if (self.currentRow === '') {
self.$message.warning('请选择需要分配权限的数据!')
return
}
self.saveRoleAuth()
},
getCheckedKey () {
const self = this
self.$http.get('/role/getRoleModule', {roleId: self.currentRow.roleId}, 'apiUrl').then(res => {
if (res === undefined) {
self.$refs.tree.setCheckedKeys([])
} else {
self.$refs.tree.setCheckedKeys(res)
}
})
},
saveRoleAuth () {
const self = this
let keys = self.$refs.tree.getCheckedKeys()
// 与言语不同,不可以选择父节点否则组件显示存在问题
// const parentKeys = self.$refs.tree.getHalfCheckedKeys()
// keys = keys.concat(parentKeys)
const data = {
moduleIds: keys,
roleId: self.currentRow.roleId
}
self.$confirm('确认为' + self.currentRow.roleName + '授权吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
self.$http.post('/role/auth', data, 'apiUrl', {body: 'json'}).then((res) => {
if (res === false || res === undefined) {
return false
}
self.$message({
message: '授权成功',
type: 'success'
})
})
}).catch(() => {
console.log("")
})
},
handleDelete() {
const self = this
if (self.currentRow === '') {
self.$message.warning('请选择需要删除的数据!')
return
}
ElMessageBox.confirm(
'确定要删除[' + self.currentRow.roleName + ']吗?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
).then(() => {
self.$http.get('/role/delete', {'roleId': self.currentRow.roleId}, 'apiUrl', {body: 'json'}).then((res) => {
if (res === false || res === undefined) {
return false
}
self.$message({
message: '删除成功!',
type: 'success'
})
this.listData()
})
}).catch(() => {
console.log("")
})
}
}
}
</script>
<style>
</style>
3. 源码获取
前端页面已提交至git 或者关注公众号算法小生加群交流
https://github.com/SJshenjian/cloud-web
默认用户名密码admin 1