0.1.0
parent
e900da1c54
commit
ce3e802edc
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"pomdtr.excalidraw-editor",
|
||||
"editorconfig.editorconfig",
|
||||
"lokalise.i18n-ally"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
server:
|
||||
addr: ":8080"
|
||||
mode: "debug"
|
||||
|
||||
database:
|
||||
driver: "mysql"
|
||||
host: "unis-sip-mysql.ns-dv9ov434.svc"
|
||||
port: 3306
|
||||
username: "root"
|
||||
password: "5tzz94jd"
|
||||
dbname: "unis_sip"
|
||||
charset: "utf8mb4"
|
||||
|
||||
jwt:
|
||||
secret: "unis-sip-secret-key"
|
||||
expiretime: 86400 # 24小时
|
|
@ -0,0 +1,172 @@
|
|||
-- 创建系统用户表
|
||||
CREATE TABLE sys_user (
|
||||
user_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键,用户ID',
|
||||
dept_id BIGINT(20) DEFAULT NULL COMMENT '部门ID',
|
||||
login_name VARCHAR(30) NOT NULL COMMENT '登录账号',
|
||||
user_name VARCHAR(30) DEFAULT '' COMMENT '用户昵称',
|
||||
email VARCHAR(50) DEFAULT '' COMMENT '用户邮箱',
|
||||
phonenumber VARCHAR(11) DEFAULT '' COMMENT '手机号码',
|
||||
sex CHAR(1) DEFAULT '0' COMMENT '用户性别(0男 1女 2未知)',
|
||||
avatar VARCHAR(100) DEFAULT '' COMMENT '头像路径',
|
||||
password VARCHAR(50) DEFAULT '' COMMENT '密码',
|
||||
salt VARCHAR(20) DEFAULT '' COMMENT '盐加密',
|
||||
status CHAR(1) DEFAULT '0' COMMENT '帐号状态(0正常 1停用)',
|
||||
login_ip VARCHAR(128) DEFAULT '' COMMENT '最后登录IP',
|
||||
login_date DATETIME DEFAULT NULL COMMENT '最后登录时间',
|
||||
create_at DATETIME NOT NULL COMMENT '创建时间',
|
||||
update_at DATETIME NOT NULL COMMENT '更新时间',
|
||||
delete_at DATETIME DEFAULT NULL COMMENT '删除时间,软删除',
|
||||
PRIMARY KEY (user_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统用户表';
|
||||
|
||||
-- 创建系统角色表
|
||||
CREATE TABLE sys_role (
|
||||
role_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键,角色ID',
|
||||
role_name VARCHAR(30) NOT NULL COMMENT '角色名称',
|
||||
role_key VARCHAR(100) NOT NULL COMMENT '角色权限字符串',
|
||||
data_scope CHAR(1) DEFAULT '1' COMMENT '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)',
|
||||
status CHAR(1) NOT NULL COMMENT '角色状态(0正常 1停用)',
|
||||
create_time DATETIME DEFAULT NULL COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT NULL COMMENT '更新时间',
|
||||
delete_at DATETIME DEFAULT NULL COMMENT '删除时间',
|
||||
PRIMARY KEY (role_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统角色表';
|
||||
|
||||
-- 初始化角色数据
|
||||
INSERT INTO sys_role (role_id, role_name, role_key, data_scope, status, create_time) VALUES
|
||||
(1, '超级管理员', 'admin', '1', '0', NOW()),
|
||||
(2, '普通角色', 'common', '2', '0', NOW());
|
||||
|
||||
-- 初始化用户数据
|
||||
INSERT INTO sys_user (user_id, login_name, user_name, password, salt, status, create_at, update_at) VALUES
|
||||
(1, 'admin', 'admin', '123456', 'salt', '0', NOW(), NOW()),
|
||||
(2, 'mula', 'mula', '123456', 'salt', '0', NOW(), NOW()),
|
||||
(3, 'jsm', 'jsm', '123456', 'salt', '0', NOW(), NOW());
|
||||
|
||||
-- 创建用户角色关系表
|
||||
CREATE TABLE sys_user_role (
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
user_id BIGINT(20) NOT NULL COMMENT '用户ID',
|
||||
role_id BIGINT(20) NOT NULL COMMENT '角色ID',
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户角色关系表';
|
||||
|
||||
-- 初始化用户角色关联关系
|
||||
INSERT INTO sys_user_role (user_id, role_id) VALUES
|
||||
(1, 1), -- admin用户关联超级管理员角色
|
||||
(2, 2), -- mula用户关联普通角色
|
||||
(3, 2); -- jsm用户关联普通角色
|
||||
|
||||
-- 创建部门表
|
||||
CREATE TABLE sys_dept (
|
||||
dept_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '部门id',
|
||||
parent_id BIGINT(20) DEFAULT 0 COMMENT '父部门id',
|
||||
dept_name VARCHAR(30) DEFAULT '' COMMENT '部门名称',
|
||||
order_num INT(4) DEFAULT 0 COMMENT '显示顺序',
|
||||
leader VARCHAR(20) DEFAULT NULL COMMENT '负责人',
|
||||
phone VARCHAR(11) DEFAULT NULL COMMENT '联系电话',
|
||||
email VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
|
||||
status CHAR(1) DEFAULT '0' COMMENT '部门状态(0正常 1停用)',
|
||||
create_time DATETIME DEFAULT NULL COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT NULL COMMENT '更新时间',
|
||||
delete_at DATETIME DEFAULT NULL COMMENT '删除时间',
|
||||
PRIMARY KEY (dept_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='部门表';
|
||||
|
||||
-- 创建菜单权限表
|
||||
CREATE TABLE sys_menu (
|
||||
menu_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '菜单ID',
|
||||
menu_name VARCHAR(50) NOT NULL COMMENT '菜单名称',
|
||||
parent_id BIGINT(20) DEFAULT 0 COMMENT '父菜单ID',
|
||||
order_num INT(4) DEFAULT 0 COMMENT '显示顺序',
|
||||
path VARCHAR(200) DEFAULT '' COMMENT '路由地址',
|
||||
component VARCHAR(255) DEFAULT NULL COMMENT '组件路径',
|
||||
is_frame INT(1) DEFAULT 1 COMMENT '是否为外链(0是 1否)',
|
||||
menu_type CHAR(1) DEFAULT '' COMMENT '菜单类型(M目录 C菜单 F按钮)',
|
||||
visible CHAR(1) DEFAULT '0' COMMENT '菜单状态(0显示 1隐藏)',
|
||||
perms VARCHAR(100) DEFAULT NULL COMMENT '权限标识',
|
||||
icon VARCHAR(100) DEFAULT '#' COMMENT '菜单图标',
|
||||
status CHAR(1) DEFAULT '0' COMMENT '菜单状态(0正常 1停用)',
|
||||
create_time DATETIME DEFAULT NULL COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT NULL COMMENT '更新时间',
|
||||
delete_at DATETIME DEFAULT NULL COMMENT '删除时间',
|
||||
PRIMARY KEY (menu_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='菜单权限表';
|
||||
|
||||
-- 创建角色菜单关系表
|
||||
CREATE TABLE sys_role_menu (
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
role_id BIGINT(20) NOT NULL COMMENT '角色ID',
|
||||
menu_id BIGINT(20) NOT NULL COMMENT '菜单ID',
|
||||
PRIMARY KEY(id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色和菜单关系表';
|
||||
|
||||
-- 初始化部门数据
|
||||
INSERT INTO sys_dept (dept_id, parent_id, dept_name, order_num, create_time) VALUES
|
||||
(1, 0, '紫光汇智', 1, NOW()),
|
||||
(2, 1, 'VDI事业部门', 1, NOW()),
|
||||
(3, 1, '营销中心', 2, NOW()),
|
||||
(4, 1, '产品中心', 3, NOW());
|
||||
|
||||
-- 初始化菜单数据
|
||||
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, menu_type, visible, perms, icon, create_time) VALUES
|
||||
-- 一级菜单
|
||||
(1, '系统管理', 0, 1, 'system', NULL, 'M', '0', '', 'system', NOW()),
|
||||
(2, '项目管理', 0, 2, 'project', NULL, 'M', '0', '', 'project', NOW()),
|
||||
-- 系统管理子菜单
|
||||
(100, '用户管理', 1, 1, 'user', 'system/user/index', 'C', '0', 'system:user:list', 'user', NOW()),
|
||||
(101, '角色管理', 1, 2, 'role', 'system/role/index', 'C', '0', 'system:role:list', 'role', NOW()),
|
||||
(102, '菜单管理', 1, 3, 'menu', 'system/menu/index', 'C', '0', 'system:menu:list', 'menu', NOW()),
|
||||
-- 项目管理子菜单
|
||||
(200, '项目信息管理', 2, 1, 'info', 'project/info/index', 'C', '0', 'project:info:list', 'info', NOW()),
|
||||
(201, '合同信息管理', 2, 2, 'contract', 'project/contract/index', 'C', '0', 'project:contract:list', 'contract', NOW());
|
||||
|
||||
-- 初始化角色菜单关系
|
||||
INSERT INTO sys_role_menu (role_id, menu_id) VALUES
|
||||
-- admin角色系统管理权限
|
||||
(1, 1), (1, 100), (1, 101), (1, 102),
|
||||
-- common角色项目管理权限
|
||||
(2, 2), (2, 200), (2, 201);
|
||||
|
||||
-- 创建字典类型表
|
||||
CREATE TABLE sys_dict_type (
|
||||
dict_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '字典主键',
|
||||
dict_name VARCHAR(100) DEFAULT '' COMMENT '字典名称',
|
||||
dict_type VARCHAR(100) DEFAULT '' COMMENT '字典类型',
|
||||
status CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
|
||||
create_time DATETIME DEFAULT NULL COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT NULL COMMENT '更新时间',
|
||||
delete_at DATETIME DEFAULT NULL COMMENT '删除时间',
|
||||
PRIMARY KEY (dict_id),
|
||||
UNIQUE KEY dict_type (dict_type)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='字典类型表';
|
||||
|
||||
-- 创建字典数据表
|
||||
CREATE TABLE sys_dict_data (
|
||||
dict_code BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '字典编码',
|
||||
dict_sort INT(4) DEFAULT 0 COMMENT '字典排序',
|
||||
dict_label VARCHAR(100) DEFAULT '' COMMENT '字典标签',
|
||||
dict_value VARCHAR(100) DEFAULT '' COMMENT '字典键值',
|
||||
dict_type VARCHAR(100) DEFAULT '' COMMENT '字典类型',
|
||||
status CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
|
||||
create_time DATETIME DEFAULT NULL COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT NULL COMMENT '更新时间',
|
||||
delete_at DATETIME DEFAULT NULL COMMENT '删除时间',
|
||||
PRIMARY KEY (dict_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='字典数据表';
|
||||
|
||||
-- 初始化字典类型数据
|
||||
INSERT INTO sys_dict_type (dict_id, dict_name, dict_type, status, create_time) VALUES
|
||||
(1, '用户性别', 'sys_user_sex', '0', NOW()),
|
||||
(2, '合同类别', 'contract_type', '0', NOW());
|
||||
|
||||
-- 初始化字典数据
|
||||
INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, status, create_time) VALUES
|
||||
-- 用户性别数据
|
||||
(1, '男', '0', 'sys_user_sex', '0', NOW()),
|
||||
(2, '女', '1', 'sys_user_sex', '0', NOW()),
|
||||
(3, '未知', '2', 'sys_user_sex', '0', NOW()),
|
||||
-- 合同类别数据
|
||||
(1, '直签', '1', 'contract_type', '0', NOW()),
|
||||
(2, '代理商签', '2', 'contract_type', '0', NOW());
|
||||
|
|
@ -0,0 +1 @@
|
|||
./hello.sh
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
while :; do
|
||||
{ echo -ne "HTTP/1.1 200 OK\r\nContent-Length: $(echo -n "Hello, World!")\r\n\r\nHello, World!"; } | nc -l -p 8080 -q 1
|
||||
done
|
|
@ -0,0 +1,100 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.7.0</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<groupId>com.unissense.sip</groupId>
|
||||
<artifactId>unis-sip</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<name>unis-sip</name>
|
||||
<description>Unis Service Information Platform</description>
|
||||
|
||||
<properties>
|
||||
<java.version>11</java.version>
|
||||
<mybatis-plus.version>3.5.2</mybatis-plus.version>
|
||||
<mysql.version>8.0.31</mysql.version>
|
||||
<jwt.version>0.9.1</jwt.version>
|
||||
<lombok.version>1.18.24</lombok.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring Boot -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- MyBatis Plus -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>${mybatis-plus.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- MySQL -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>${mysql.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JWT -->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>${jwt.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Security -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Redis -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,312 @@
|
|||
> SIP是售后服务平台(Service Information Platform)
|
||||
|
||||
# 系统架构
|
||||
后端采用Spring Boot+JWT+Mybatis-Plus+Redis+Mysql
|
||||
前端采用vue3 + element-plus + ts
|
||||
|
||||
|
||||
# 数据库设计
|
||||
采用mysql数据库,采用ORM框架进行数据库操作。数据库版本为8.0.31。
|
||||
测试的数据库连接信息如下:mysql://root:5tzz94jd@unis-sip-mysql.ns-dv9ov434.svc:3306/unis_sip?charset=utf8mb4&parseTime=True&loc=Local
|
||||
|
||||
## 系统表
|
||||
|
||||
### 系统用户表(sys_user)
|
||||
主要用于管理系统用户账号信息,包含用户的基本信息、登录信息和状态等。
|
||||
|
||||
| 字段名 | 类型 | 长度 | 允许空 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|--------|------|
|
||||
| user_id | bigint | 20 | 否 | - | 主键,用户ID,自增 |
|
||||
| dept_id | bigint | 20 | 是 | null | 部门ID |
|
||||
| login_name | varchar | 30 | 否 | - | 登录账号 |
|
||||
| user_name | varchar | 30 | 是 | '' | 用户昵称 |
|
||||
| email | varchar | 50 | 是 | '' | 用户邮箱 |
|
||||
| phonenumber | varchar | 11 | 是 | '' | 手机号码 |
|
||||
| sex | char | 1 | 是 | '0' | 用户性别(0男 1女 2未知) |
|
||||
| avatar | varchar | 100 | 是 | '' | 头像路径 |
|
||||
| password | varchar | 50 | 是 | '' | 密码 |
|
||||
| salt | varchar | 20 | 是 | '' | 盐加密 |
|
||||
| status | char | 1 | 是 | '0' | 帐号状态(0正常 1停用) |
|
||||
| login_ip | varchar | 128 | 是 | '' | 最后登录IP |
|
||||
| login_date | datetime | - | 是 | null | 最后登录时间 |
|
||||
| create_at | datetime | - | 否 | - | 创建时间 |
|
||||
| update_at | datetime | - | 否 | - | 更新时间 |
|
||||
| delete_at | datetime | - | 是 | null | 删除时间,软删除 |
|
||||
|
||||
索引:
|
||||
- PRIMARY KEY (user_id)
|
||||
|
||||
### 字典类型表(sys_dict_type)
|
||||
主要用于管理系统中的各种码表类型定义,包括字典名称、类型和状态等。
|
||||
|
||||
| 字段名 | 类型 | 长度 | 允许空 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|--------|------|
|
||||
| dict_id | bigint | 20 | 否 | - | 主键,字典ID,自增 |
|
||||
| dict_name | varchar | 100 | 是 | '' | 字典名称 |
|
||||
| dict_type | varchar | 100 | 是 | '' | 字典类型 |
|
||||
| status | char | 1 | 是 | '0' | 状态(0正常 1停用) |
|
||||
| create_at | datetime | - | 否 | - | 创建时间 |
|
||||
| update_at | datetime | - | 否 | - | 更新时间 |
|
||||
| delete_at | datetime | - | 是 | null | 删除时间,软删除 |
|
||||
| remark | varchar | 500 | 是 | null | 备注 |
|
||||
|
||||
索引:
|
||||
- PRIMARY KEY (dict_id)
|
||||
- UNIQUE KEY idx_dict_type (dict_type)
|
||||
|
||||
### 字典数据表(sys_dict_data)
|
||||
主要用于存储字典类型下的字典项数据,包括字典标签、键值和排序等。
|
||||
|
||||
| 字段名 | 类型 | 长度 | 允许空 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|--------|------|
|
||||
| dict_code | bigint | 20 | 否 | - | 主键,字典编码,自增 |
|
||||
| dict_sort | int | 4 | 是 | 0 | 字典排序 |
|
||||
| dict_label | varchar | 100 | 是 | '' | 字典标签 |
|
||||
| dict_value | varchar | 100 | 是 | '' | 字典键值 |
|
||||
| dict_type | varchar | 100 | 是 | '' | 字典类型 |
|
||||
| css_class | varchar | 100 | 是 | null | 样式属性(其他样式扩展) |
|
||||
| is_default | char | 1 | 是 | 'N' | 是否默认(Y是 N否) |
|
||||
| status | char | 1 | 是 | '0' | 状态(0正常 1停用) |
|
||||
| create_at | datetime | - | 否 | - | 创建时间 |
|
||||
| update_at | datetime | - | 否 | - | 更新时间 |
|
||||
| remark | varchar | 500 | 是 | null | 备注 |
|
||||
|
||||
索引:
|
||||
- PRIMARY KEY (dict_code)
|
||||
- KEY idx_dict_type (dict_type)
|
||||
|
||||
### 系统角色表(sys_role)
|
||||
主要用于管理系统角色权限,包含角色的基本信息、数据权限范围和状态等。
|
||||
|
||||
| 字段名 | 类型 | 长度 | 允许空 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|--------|------|
|
||||
| role_id | bigint | 20 | 否 | - | 主键,角色ID,自增 |
|
||||
| role_name | varchar | 30 | 否 | - | 角色名称 |
|
||||
| role_key | varchar | 100 | 否 | - | 角色权限字符串 |
|
||||
| data_scope | char | 1 | 是 | '1' | 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限) |
|
||||
| status | char | 1 | 否 | - | 角色状态(0正常 1停用) |
|
||||
| create_time | datetime | - | 是 | null | 创建时间 |
|
||||
| update_time | datetime | - | 是 | null | 更新时间 |
|
||||
| delete_at | datetime | - | 是 | null | 删除时间 |
|
||||
|
||||
索引:
|
||||
- PRIMARY KEY (role_id)
|
||||
|
||||
### 用户角色关系表(sys_user_role)
|
||||
主要用于管理用户和角色的多对多关联关系。
|
||||
|
||||
| 字段名 | 类型 | 长度 | 允许空 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|--------|------|
|
||||
| id | bigint | 20 | 否 | - | 主键ID,自增 |
|
||||
| user_id | bigint | 20 | 否 | - | 用户ID |
|
||||
| role_id | bigint | 20 | 否 | - | 角色ID |
|
||||
|
||||
索引:
|
||||
- PRIMARY KEY (id)
|
||||
|
||||
### 部门信息表(sys_dept)
|
||||
主要用于管理组织架构,包含部门的基本信息、层级关系和联系方式等。
|
||||
|
||||
| 字段名 | 类型 | 长度 | 允许空 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|--------|------|
|
||||
| dept_id | bigint | 20 | 否 | - | 主键,部门id,自增 |
|
||||
| parent_id | bigint | 20 | 是 | 0 | 父部门id |
|
||||
| ancestors | varchar | 50 | 是 | '' | 祖级列表 |
|
||||
| dept_name | varchar | 30 | 是 | '' | 部门名称 |
|
||||
| order_num | int | 4 | 是 | 0 | 显示顺序 |
|
||||
| contact_person | varchar | 20 | 是 | null | 联系人 |
|
||||
| contact_phone | varchar | 11 | 是 | null | 联系电话 |
|
||||
| contact_email | varchar | 50 | 是 | null | 联系邮箱 |
|
||||
| status | char | 1 | 是 | '0' | 部门状态:0-正常,1-停用 |
|
||||
| create_at | datetime | - | 否 | - | 创建时间 |
|
||||
| update_at | datetime | - | 否 | - | 更新时间 |
|
||||
| delete_at | datetime | - | 是 | null | 删除时间,软删除 |
|
||||
|
||||
索引:
|
||||
- PRIMARY KEY (dept_id)
|
||||
|
||||
### 菜单权限表(sys_menu)
|
||||
主要用于管理系统菜单权限,包含菜单的基本信息、层级关系和权限标识等。
|
||||
|
||||
| 字段名 | 类型 | 长度 | 允许空 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|--------|------|
|
||||
| menu_id | bigint | 20 | 否 | - | 主键,菜单ID,自增 |
|
||||
| menu_name | varchar | 50 | 否 | - | 菜单名称 |
|
||||
| parent_id | bigint | 20 | 是 | 0 | 父菜单ID |
|
||||
| order_num | int | 4 | 是 | 0 | 显示顺序 |
|
||||
| url | varchar | 200 | 是 | '#' | 路由地址 |
|
||||
| target | varchar | 20 | 是 | '' | 打开方式(menuItem页签 menuBlank新窗口) |
|
||||
| menu_type | char | 1 | 是 | '' | 菜单类型(M模块 C菜单 F按钮) |
|
||||
| perms | varchar | 100 | 是 | null | 权限标识 |
|
||||
| icon | varchar | 100 | 是 | '#' | 菜单图标 |
|
||||
| create_at | datetime | - | 否 | - | 创建时间 |
|
||||
| update_at | datetime | - | 否 | - | 更新时间 |
|
||||
| delete_at | datetime | - | 是 | null | 删除时间 |
|
||||
| remark | varchar | 500 | 是 | '' | 备注 |
|
||||
|
||||
索引:
|
||||
- PRIMARY KEY (menu_id)
|
||||
|
||||
### 角色菜单关系表(sys_role_menu)
|
||||
主要用于管理角色和菜单的多对多关联关系。
|
||||
|
||||
| 字段名 | 类型 | 长度 | 允许空 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|--------|------|
|
||||
| id | bigint | 20 | 否 | - | 主键ID,自增 |
|
||||
| role_id | bigint | 20 | 否 | - | 角色ID |
|
||||
| menu_id | bigint | 20 | 否 | - | 菜单ID |
|
||||
|
||||
索引:
|
||||
- PRIMARY KEY (id)
|
||||
|
||||
|
||||
## 业务表
|
||||
|
||||
### 产品编码表(product_code)
|
||||
主要用于存储产品的基本信息,包括产品型号、规格等。
|
||||
|
||||
| 字段名 | 类型 | 长度 | 允许空 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|--------|------|
|
||||
| id | bigint | - | 否 | - | 主键,自增 |
|
||||
| product_code | varchar | 64 | 否 | - | 产品编码,唯一 |
|
||||
| product_name | varchar | 128 | 否 | - | 产品名称 |
|
||||
| model | varchar | 64 | 否 | - | 产品代码 |
|
||||
| description | text | - | 是 | null | 产品描述 |
|
||||
| unit | varchar | 16 | 否 | '个' | 单位 |
|
||||
| remark | varchar | 512 | 是 | null | 备注 |
|
||||
| created_at | datetime | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | datetime | - | 否 | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | datetime | - | 是 | null | 删除时间,软删除 |
|
||||
|
||||
索引:
|
||||
- PRIMARY KEY (id)
|
||||
- UNIQUE KEY idx_product_code (product_code)
|
||||
- KEY idx_model (model)
|
||||
|
||||
### 项目信息表(project_info)
|
||||
主要用于存储项目的基本信息,包括项目状态、客户信息等。
|
||||
|
||||
| 字段名 | 类型 | 长度 | 允许空 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|--------|------|
|
||||
| id | bigint | - | 否 | - | 主键,自增 |
|
||||
| project_code | varchar | 32 | 否 | - | 项目编号,唯一 |
|
||||
| project_name | varchar | 128 | 否 | - | 项目名称 |
|
||||
| customer_name | varchar | 64 | 否 | - | 客户名称 |
|
||||
| customer_contact | varchar | 32 | 是 | null | 客户联系人 |
|
||||
| customer_phone | varchar | 20 | 是 | null | 客户联系电话 |
|
||||
| customer_email | varchar | 64 | 是 | null | 客户邮箱 |
|
||||
| project_status | tinyint | - | 否 | 1 | 项目状态:1-进行中,2-已签合同,3-已交付,99-已终止 |
|
||||
| bg_property | tinyint | - | 否 | - | BG属性:1-商业,2-行业 |
|
||||
| industry_code | tinyint | - | 否 | - | 行业编码 |
|
||||
| project_manager | varchar | 32 | 否 | - | 项目经理 |
|
||||
| project_manager_phone | varchar | 20 | 是 | null | 项目经理电话 |
|
||||
| project_manager_email | varchar | 64 | 是 | null | 项目经理邮箱 |
|
||||
| start_date | date | - | 否 | - | 项目开始日期 |
|
||||
| description | text | - | 是 | null | 项目描述 |
|
||||
| created_at | datetime | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | datetime | - | 否 | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | datetime | - | 是 | null | 删除时间,软删除 |
|
||||
|
||||
索引:
|
||||
- PRIMARY KEY (id)
|
||||
- UNIQUE KEY idx_project_code (project_code)
|
||||
- KEY idx_customer_name (customer_name)
|
||||
- KEY idx_project_status (project_status)
|
||||
|
||||
### 合同信息表(order_info)
|
||||
主要用于存储项目的合同信息,与项目信息表为一对多关系。
|
||||
|
||||
| 字段名 | 类型 | 长度 | 允许空 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|--------|------|
|
||||
| id | bigint | - | 否 | - | 主键,自增 |
|
||||
| project_code | varchar | 32 | 否 | - | 关联项目编号 |
|
||||
| order_code | varchar | 32 | 否 | - | 合同编号,唯一 |
|
||||
| order_name | varchar | 128 | 否 | - | 合同名称 |
|
||||
| customer_name | varchar | 64 | 否 | - | 客户名称 |
|
||||
| customer_contact | varchar | 32 | 是 | null | 客户联系人 |
|
||||
| customer_phone | varchar | 20 | 是 | null | 客户联系电话 |
|
||||
| customer_email | varchar | 64 | 是 | null | 客户邮箱 |
|
||||
| order_type | tinyint | - | 否 | - | 合同类型:1-直签合同,2-代理商合同 |
|
||||
| order_dept | varchar | 32 | 否 | - | 归属代表处编码 |
|
||||
| partener_dept | varchar | 32 | 否 | - | 代理商编码 |
|
||||
| order_date | date | - | 否 | - | 合同签定日期 |
|
||||
| order_status | tinyint | - | 否 | 1 | 合同状态:1-待审核,2-已审核,3-已驳回 |
|
||||
| remark | varchar | 512 | 是 | null | 备注 |
|
||||
| created_at | datetime | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | datetime | - | 否 | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | datetime | - | 是 | null | 删除时间,软删除 |
|
||||
|
||||
索引:
|
||||
- PRIMARY KEY (id)
|
||||
- UNIQUE KEY idx_order_code (order_code)
|
||||
|
||||
### 合同清单表(order_list)
|
||||
主要用于记录合同包含的产品信息,包括产品编码、单价和数量等。
|
||||
|
||||
| 字段名 | 类型 | 长度 | 允许空 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|--------|------|
|
||||
| id | bigint | - | 否 | - | 主键,自增 |
|
||||
| order_code | varchar | 32 | 否 | - | 关联合同编号 |
|
||||
| product_code | varchar | 64 | 否 | - | 产品编码,关联产品编码表 |
|
||||
| quantity | int | - | 否 | 1 | 数量 |
|
||||
| price | decimal | 10,2 | 否 | 0 | 单价 |
|
||||
| amount | decimal | 10,2 | 否 | 0 | 总价 |
|
||||
| remark | varchar | 512 | 是 | null | 备注 |
|
||||
| created_at | datetime | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | datetime | - | 否 | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | datetime | - | 是 | null | 删除时间,软删除 |
|
||||
|
||||
索引:
|
||||
- PRIMARY KEY (id)
|
||||
- KEY idx_order_id (order_id)
|
||||
- KEY idx_product_code (product_code)
|
||||
|
||||
### 发货记录表(order_delivery)
|
||||
主要用于记录产品的发货信息,包括发货时间、物流信息等。
|
||||
|
||||
| 字段名 | 类型 | 长度 | 允许空 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|--------|------|
|
||||
| id | bigint | - | 否 | - | 主键,自增 |
|
||||
| order_code | varchar | 32 | 否 | - | 关联合同编号 |
|
||||
| delivery_code | varchar | 32 | 否 | - | 发货单号,唯一 |
|
||||
| delivery_date | date | - | 否 | - | 发货日期 |
|
||||
| delivery_type | tinyint | - | 否 | 1 | 发货方式:1-快递,2-物流,3-自提 |
|
||||
| logistics_company | varchar | 64 | 是 | null | 物流公司 |
|
||||
| logistics_code | varchar | 32 | 是 | null | 物流单号 |
|
||||
| receiver_name | varchar | 32 | 否 | - | 收货人姓名 |
|
||||
| receiver_phone | varchar | 20 | 否 | - | 收货人电话 |
|
||||
| receiver_address | varchar | 256 | 否 | - | 收货地址 |
|
||||
| delivery_status | tinyint | - | 否 | 1 | 发货状态:1-待发货,2-已发货,3-已签收 |
|
||||
| sign_time | datetime | - | 是 | null | 签收时间 |
|
||||
| remark | varchar | 512 | 是 | null | 备注 |
|
||||
| created_at | datetime | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | datetime | - | 否 | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | datetime | - | 是 | null | 删除时间,软删除 |
|
||||
|
||||
索引:
|
||||
- PRIMARY KEY (id)
|
||||
- UNIQUE KEY idx_delivery_code (delivery_code)
|
||||
- KEY idx_order_id (order_id)
|
||||
- KEY idx_delivery_status (delivery_status)
|
||||
|
||||
### 发货清单表(delivery_list)
|
||||
主要用于记录每个发货单包含的具体产品信息,包括产品编码和序列号等。
|
||||
|
||||
| 字段名 | 类型 | 长度 | 允许空 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|--------|------|
|
||||
| id | bigint | - | 否 | - | 主键,自增 |
|
||||
| delivery_code | varchar | 32 | 否 | - | 关联发货单编号 |
|
||||
| product_code | varchar | 64 | 否 | - | 产品编码,关联产品编码表 |
|
||||
| serial_number | varchar | 64 | 否 | - | 产品序列号 |
|
||||
| remark | varchar | 512 | 是 | null | 备注 |
|
||||
| created_at | datetime | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | datetime | - | 否 | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | datetime | - | 是 | null | 删除时间,软删除 |
|
||||
|
||||
索引:
|
||||
- PRIMARY KEY (id)
|
||||
- KEY idx_delivery_id (delivery_id)
|
||||
- KEY idx_product_code (product_code)
|
||||
- UNIQUE KEY idx_serial_number (serial_number)
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.unissense.sip;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
@MapperScan("com.unissense.sip.mapper")
|
||||
public class UnisSipApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(UnisSipApplication.class, args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.unissense.sip.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
@Configuration
|
||||
public class SecurityConfig {
|
||||
@Bean
|
||||
public BCryptPasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.unissense.sip.controller;
|
||||
|
||||
import com.unissense.sip.dto.LoginRequest;
|
||||
import com.unissense.sip.dto.LoginResponse;
|
||||
import com.unissense.sip.service.SysUserService;
|
||||
import com.unissense.sip.utils.CaptchaUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
public class AuthController {
|
||||
|
||||
@Autowired
|
||||
private SysUserService userService;
|
||||
|
||||
@Autowired
|
||||
private StringRedisTemplate redisTemplate;
|
||||
|
||||
@GetMapping("/captcha")
|
||||
public void getCaptcha(@RequestParam String username, HttpServletResponse response) throws Exception {
|
||||
StringBuilder captcha = new StringBuilder();
|
||||
BufferedImage image = CaptchaUtils.generateCaptchaImage(captcha);
|
||||
|
||||
// 将验证码存入Redis,设置60秒过期
|
||||
String captchaKey = "captcha:" + username;
|
||||
redisTemplate.opsForValue().set(captchaKey, captcha.toString(), 60, TimeUnit.SECONDS);
|
||||
|
||||
// 输出图片
|
||||
response.setContentType(MediaType.IMAGE_PNG_VALUE);
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
ImageIO.write(image, "png", os);
|
||||
response.getOutputStream().write(os.toByteArray());
|
||||
}
|
||||
|
||||
@PostMapping("/login")
|
||||
public LoginResponse login(@RequestBody LoginRequest loginRequest) {
|
||||
return userService.login(loginRequest);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.unissense.sip.controller;
|
||||
|
||||
import com.unissense.sip.entity.SysDept;
|
||||
import com.unissense.sip.service.SysDeptService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/depts")
|
||||
public class SysDeptController {
|
||||
|
||||
@Autowired
|
||||
private SysDeptService sysDeptService;
|
||||
|
||||
@GetMapping("/{deptCode}")
|
||||
public ResponseEntity<SysDept> getDeptByCode(@PathVariable String deptCode) {
|
||||
SysDept dept = sysDeptService.getByDeptCode(deptCode);
|
||||
return dept != null ? ResponseEntity.ok(dept) : ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<Boolean> createDept(@RequestBody SysDept dept) {
|
||||
boolean success = sysDeptService.createDept(dept);
|
||||
return success ? ResponseEntity.ok(true) : ResponseEntity.badRequest().build();
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<?> listDepts() {
|
||||
return ResponseEntity.ok(sysDeptService.list());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package com.unissense.sip.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.unissense.sip.entity.SysDictData;
|
||||
import com.unissense.sip.service.SysDictDataService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 字典数据Controller
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/dict/data")
|
||||
public class SysDictDataController {
|
||||
|
||||
@Autowired
|
||||
private SysDictDataService dictDataService;
|
||||
|
||||
/**
|
||||
* 获取字典数据列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public Page<SysDictData> list(
|
||||
@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
|
||||
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
|
||||
SysDictData dictData) {
|
||||
LambdaQueryWrapper<SysDictData> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(dictData.getDictType() != null, SysDictData::getDictType, dictData.getDictType())
|
||||
.like(dictData.getDictLabel() != null, SysDictData::getDictLabel, dictData.getDictLabel())
|
||||
.eq(dictData.getStatus() != null, SysDictData::getStatus, dictData.getStatus())
|
||||
.orderByAsc(SysDictData::getDictSort);
|
||||
return dictDataService.page(new Page<>(pageNum, pageSize), wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据字典类型查询字典数据信息
|
||||
*/
|
||||
@GetMapping(value = "/type/{dictType}")
|
||||
public List<SysDictData> dictType(@PathVariable String dictType) {
|
||||
return dictDataService.selectDictDataByType(dictType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字典数据详细信息
|
||||
*/
|
||||
@GetMapping("/{dictCode}")
|
||||
public SysDictData getInfo(@PathVariable Long dictCode) {
|
||||
return dictDataService.getById(dictCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增字典数据
|
||||
*/
|
||||
@PostMapping
|
||||
public boolean add(@RequestBody SysDictData dict) {
|
||||
dict.setCreateTime(LocalDateTime.now());
|
||||
return dictDataService.save(dict);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改字典数据
|
||||
*/
|
||||
@PutMapping
|
||||
public boolean edit(@RequestBody SysDictData dict) {
|
||||
dict.setUpdateTime(LocalDateTime.now());
|
||||
return dictDataService.updateById(dict);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除字典数据
|
||||
*/
|
||||
@DeleteMapping("/{dictCode}")
|
||||
public boolean remove(@PathVariable Long dictCode) {
|
||||
return dictDataService.removeById(dictCode);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package com.unissense.sip.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.unissense.sip.entity.SysDictType;
|
||||
import com.unissense.sip.service.SysDictTypeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 字典类型Controller
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system/dict/type")
|
||||
public class SysDictTypeController {
|
||||
|
||||
@Autowired
|
||||
private SysDictTypeService dictTypeService;
|
||||
|
||||
/**
|
||||
* 获取字典类型列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public Page<SysDictType> list(
|
||||
@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
|
||||
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
|
||||
SysDictType dictType) {
|
||||
LambdaQueryWrapper<SysDictType> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.like(dictType.getDictName() != null, SysDictType::getDictName, dictType.getDictName())
|
||||
.like(dictType.getDictType() != null, SysDictType::getDictType, dictType.getDictType())
|
||||
.eq(dictType.getStatus() != null, SysDictType::getStatus, dictType.getStatus())
|
||||
.orderByAsc(SysDictType::getDictId);
|
||||
return dictTypeService.page(new Page<>(pageNum, pageSize), wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字典类型详细信息
|
||||
*/
|
||||
@GetMapping("/{dictId}")
|
||||
public SysDictType getInfo(@PathVariable Long dictId) {
|
||||
return dictTypeService.getById(dictId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增字典类型
|
||||
*/
|
||||
@PostMapping
|
||||
public boolean add(@RequestBody SysDictType dict) {
|
||||
dict.setCreateTime(LocalDateTime.now());
|
||||
return dictTypeService.save(dict);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改字典类型
|
||||
*/
|
||||
@PutMapping
|
||||
public boolean edit(@RequestBody SysDictType dict) {
|
||||
dict.setUpdateTime(LocalDateTime.now());
|
||||
return dictTypeService.updateById(dict);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除字典类型
|
||||
*/
|
||||
@DeleteMapping("/{dictId}")
|
||||
public boolean remove(@PathVariable Long dictId) {
|
||||
return dictTypeService.removeById(dictId);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.unissense.sip.controller;
|
||||
|
||||
import com.unissense.sip.entity.SysMenu;
|
||||
import com.unissense.sip.service.SysMenuService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/menus")
|
||||
public class SysMenuController {
|
||||
|
||||
@Autowired
|
||||
private SysMenuService sysMenuService;
|
||||
|
||||
@GetMapping("/{menuCode}")
|
||||
public ResponseEntity<SysMenu> getMenuByCode(@PathVariable String menuCode) {
|
||||
SysMenu menu = sysMenuService.getByMenuCode(menuCode);
|
||||
return menu != null ? ResponseEntity.ok(menu) : ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<Boolean> createMenu(@RequestBody SysMenu menu) {
|
||||
boolean success = sysMenuService.createMenu(menu);
|
||||
return success ? ResponseEntity.ok(true) : ResponseEntity.badRequest().build();
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<?> listMenus() {
|
||||
return ResponseEntity.ok(sysMenuService.list());
|
||||
}
|
||||
|
||||
@GetMapping("/children/{parentId}")
|
||||
public ResponseEntity<List<SysMenu>> getChildrenMenus(@PathVariable Long parentId) {
|
||||
List<SysMenu> children = sysMenuService.getChildrenMenus(parentId);
|
||||
return ResponseEntity.ok(children);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.unissense.sip.controller;
|
||||
|
||||
import com.unissense.sip.entity.SysRole;
|
||||
import com.unissense.sip.service.SysRoleService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/roles")
|
||||
public class SysRoleController {
|
||||
|
||||
@Autowired
|
||||
private SysRoleService sysRoleService;
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<Boolean> createRole(@RequestBody SysRole role) {
|
||||
boolean success = sysRoleService.createRole(role);
|
||||
return success ? ResponseEntity.ok(true) : ResponseEntity.badRequest().build();
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<?> listRoles() {
|
||||
return ResponseEntity.ok(sysRoleService.list());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.unissense.sip.controller;
|
||||
|
||||
import com.unissense.sip.entity.SysUser;
|
||||
import com.unissense.sip.service.SysUserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/users")
|
||||
public class SysUserController {
|
||||
|
||||
@Autowired
|
||||
private SysUserService sysUserService;
|
||||
|
||||
@GetMapping("/{username}")
|
||||
public ResponseEntity<SysUser> getUserByUsername(@PathVariable String username) {
|
||||
SysUser user = sysUserService.getByUsername(username);
|
||||
return user != null ? ResponseEntity.ok(user) : ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<Boolean> createUser(@RequestBody SysUser user) {
|
||||
boolean result = sysUserService.createUser(user);
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
@GetMapping("/test")
|
||||
public ResponseEntity<String> test() {
|
||||
return ResponseEntity.ok("User API is working!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.unissense.sip.controller;
|
||||
|
||||
import com.unissense.sip.service.SysUserRoleService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/user-roles")
|
||||
public class SysUserRoleController {
|
||||
|
||||
@Autowired
|
||||
private SysUserRoleService sysUserRoleService;
|
||||
|
||||
@GetMapping("/user/{userId}/roles")
|
||||
public ResponseEntity<List<Long>> getUserRoles(@PathVariable Long userId) {
|
||||
List<Long> roleIds = sysUserRoleService.getRoleIdsByUserId(userId);
|
||||
return ResponseEntity.ok(roleIds);
|
||||
}
|
||||
|
||||
@PostMapping("/user/{userId}/roles")
|
||||
public ResponseEntity<Boolean> assignRoles(
|
||||
@PathVariable Long userId,
|
||||
@RequestBody List<Long> roleIds) {
|
||||
boolean success = sysUserRoleService.assignRoles(userId, roleIds);
|
||||
return success ? ResponseEntity.ok(true) : ResponseEntity.badRequest().build();
|
||||
}
|
||||
|
||||
@DeleteMapping("/user/{userId}/roles")
|
||||
public ResponseEntity<Boolean> removeUserRoles(@PathVariable Long userId) {
|
||||
boolean success = sysUserRoleService.removeUserRoles(userId);
|
||||
return success ? ResponseEntity.ok(true) : ResponseEntity.badRequest().build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.unissense.sip.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class LoginRequest {
|
||||
private String username;
|
||||
private String password;
|
||||
private String captcha;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.unissense.sip.dto;
|
||||
|
||||
import com.unissense.sip.entity.SysMenu;
|
||||
import com.unissense.sip.entity.SysUser;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class LoginResponse {
|
||||
private String token;
|
||||
private SysUser user;
|
||||
private List<String> roles;
|
||||
private List<SysMenu> menus;
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.unissense.sip.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("sys_dept")
|
||||
public class SysDept {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long deptId;
|
||||
|
||||
private Long parentId;
|
||||
|
||||
private String deptName;
|
||||
|
||||
private Integer orderNum;
|
||||
|
||||
private String leader;
|
||||
|
||||
private String phone;
|
||||
|
||||
private String email;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private String deptCode;
|
||||
|
||||
private LocalDateTime deleteAt;
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
private String createBy;
|
||||
|
||||
private LocalDateTime createTime;
|
||||
|
||||
private String updateBy;
|
||||
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
private String remark;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.unissense.sip.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("sys_dict_data")
|
||||
public class SysDictData {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long dictCode;
|
||||
|
||||
private Long dictSort;
|
||||
|
||||
private String dictLabel;
|
||||
|
||||
private String dictValue;
|
||||
|
||||
private String dictType;
|
||||
|
||||
private String cssClass;
|
||||
|
||||
private String listClass;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private String createBy;
|
||||
|
||||
private LocalDateTime createTime;
|
||||
|
||||
private String updateBy;
|
||||
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
private String remark;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.unissense.sip.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("sys_dict_type")
|
||||
public class SysDictType {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long dictId;
|
||||
|
||||
private String dictName;
|
||||
|
||||
private String dictType;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private String createBy;
|
||||
|
||||
private LocalDateTime createTime;
|
||||
|
||||
private String updateBy;
|
||||
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
private String remark;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package com.unissense.sip.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("sys_menu")
|
||||
public class SysMenu {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long menuId;
|
||||
|
||||
private Long parentId;
|
||||
|
||||
private String menuName;
|
||||
|
||||
private String path;
|
||||
|
||||
private String component;
|
||||
|
||||
private String perms;
|
||||
|
||||
private String icon;
|
||||
|
||||
private Integer type;
|
||||
|
||||
private Integer orderNum;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private String menuCode;
|
||||
|
||||
private LocalDateTime deleteAt;
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
private String createBy;
|
||||
|
||||
private LocalDateTime createTime;
|
||||
|
||||
private String updateBy;
|
||||
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
private String remark;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.unissense.sip.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("sys_role")
|
||||
public class SysRole {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long roleId;
|
||||
|
||||
private String roleName;
|
||||
|
||||
private String roleKey;
|
||||
|
||||
private Integer roleSort;
|
||||
|
||||
private String dataScope;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private LocalDateTime deleteAt;
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
private String createBy;
|
||||
|
||||
private LocalDateTime createTime;
|
||||
|
||||
private String updateBy;
|
||||
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
private String remark;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.unissense.sip.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@TableName("sys_role_menu")
|
||||
public class SysRoleMenu {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private Long roleId;
|
||||
|
||||
private Long menuId;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package com.unissense.sip.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("sys_user")
|
||||
public class SysUser {
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
|
||||
private String email;
|
||||
|
||||
private String phone;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private LocalDateTime createTime;
|
||||
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
private LocalDateTime deleteAt;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.unissense.sip.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@TableName("sys_user_role")
|
||||
public class SysUserRole {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private Long userId;
|
||||
|
||||
private Long roleId;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.unissense.sip.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.unissense.sip.entity.SysDept;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SysDeptMapper extends BaseMapper<SysDept> {
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.unissense.sip.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.unissense.sip.entity.SysDictData;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SysDictDataMapper extends BaseMapper<SysDictData> {
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.unissense.sip.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.unissense.sip.entity.SysDictType;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SysDictTypeMapper extends BaseMapper<SysDictType> {
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.unissense.sip.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.unissense.sip.entity.SysMenu;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SysMenuMapper extends BaseMapper<SysMenu> {
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.unissense.sip.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.unissense.sip.entity.SysRole;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SysRoleMapper extends BaseMapper<SysRole> {
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.unissense.sip.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.unissense.sip.entity.SysRoleMenu;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SysRoleMenuMapper extends BaseMapper<SysRoleMenu> {
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.unissense.sip.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.unissense.sip.entity.SysUser;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SysUserMapper extends BaseMapper<SysUser> {
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.unissense.sip.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.unissense.sip.entity.SysUserRole;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SysUserRoleMapper extends BaseMapper<SysUserRole> {
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.unissense.sip.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.unissense.sip.entity.SysDept;
|
||||
|
||||
public interface SysDeptService extends IService<SysDept> {
|
||||
/**
|
||||
* 根据部门编码查询部门
|
||||
* @param deptCode 部门编码
|
||||
* @return 部门信息
|
||||
*/
|
||||
SysDept getByDeptCode(String deptCode);
|
||||
|
||||
/**
|
||||
* 创建新部门
|
||||
* @param dept 部门信息
|
||||
* @return 是否创建成功
|
||||
*/
|
||||
boolean createDept(SysDept dept);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.unissense.sip.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.unissense.sip.entity.SysDictData;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 字典数据Service接口
|
||||
*/
|
||||
public interface SysDictDataService extends IService<SysDictData> {
|
||||
|
||||
/**
|
||||
* 根据字典类型查询字典数据列表
|
||||
*
|
||||
* @param dictType 字典类型
|
||||
* @return 字典数据列表
|
||||
*/
|
||||
List<SysDictData> selectDictDataByType(String dictType);
|
||||
|
||||
/**
|
||||
* 根据字典类型和字典键值查询字典数据信息
|
||||
*
|
||||
* @param dictType 字典类型
|
||||
* @param dictValue 字典键值
|
||||
* @return 字典标签
|
||||
*/
|
||||
String selectDictLabel(String dictType, String dictValue);
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.unissense.sip.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.unissense.sip.entity.SysDictType;
|
||||
|
||||
/**
|
||||
* 字典类型Service接口
|
||||
*/
|
||||
public interface SysDictTypeService extends IService<SysDictType> {
|
||||
|
||||
/**
|
||||
* 根据字典类型查询字典数据
|
||||
*
|
||||
* @param dictType 字典类型
|
||||
* @return 字典数据
|
||||
*/
|
||||
SysDictType selectDictTypeByType(String dictType);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.unissense.sip.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.unissense.sip.entity.SysMenu;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface SysMenuService extends IService<SysMenu> {
|
||||
/**
|
||||
* 根据菜单编码查询菜单
|
||||
* @param menuCode 菜单编码
|
||||
* @return 菜单信息
|
||||
*/
|
||||
SysMenu getByMenuCode(String menuCode);
|
||||
|
||||
/**
|
||||
* 创建新菜单
|
||||
* @param menu 菜单信息
|
||||
* @return 是否创建成功
|
||||
*/
|
||||
boolean createMenu(SysMenu menu);
|
||||
|
||||
/**
|
||||
* 获取子菜单列表
|
||||
* @param parentId 父菜单ID
|
||||
* @return 子菜单列表
|
||||
*/
|
||||
List<SysMenu> getChildrenMenus(Long parentId);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.unissense.sip.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.unissense.sip.entity.SysRoleMenu;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface SysRoleMenuService extends IService<SysRoleMenu> {
|
||||
/**
|
||||
* 获取角色的菜单ID列表
|
||||
* @param roleId 角色ID
|
||||
* @return 菜单ID列表
|
||||
*/
|
||||
List<Long> getMenuIdsByRoleId(Long roleId);
|
||||
|
||||
/**
|
||||
* 为角色分配菜单
|
||||
* @param roleId 角色ID
|
||||
* @param menuIds 菜单ID列表
|
||||
* @return 是否分配成功
|
||||
*/
|
||||
boolean assignMenus(Long roleId, List<Long> menuIds);
|
||||
|
||||
/**
|
||||
* 删除角色的所有菜单
|
||||
* @param roleId 角色ID
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
boolean removeRoleMenus(Long roleId);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.unissense.sip.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.unissense.sip.entity.SysRole;
|
||||
|
||||
public interface SysRoleService extends IService<SysRole> {
|
||||
|
||||
/**
|
||||
* 创建新角色
|
||||
* @param role 角色信息
|
||||
* @return 是否创建成功
|
||||
*/
|
||||
boolean createRole(SysRole role);
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.unissense.sip.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.unissense.sip.entity.SysUserRole;
|
||||
import com.unissense.sip.entity.SysMenu;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface SysUserRoleService extends IService<SysUserRole> {
|
||||
/**
|
||||
* 获取用户的角色ID列表
|
||||
* @param userId 用户ID
|
||||
* @return 角色ID列表
|
||||
*/
|
||||
List<Long> getRoleIdsByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 为用户分配角色
|
||||
* @param userId 用户ID
|
||||
* @param roleIds 角色ID列表
|
||||
* @return 是否分配成功
|
||||
*/
|
||||
boolean assignRoles(Long userId, List<Long> roleIds);
|
||||
|
||||
/**
|
||||
* 删除用户的所有角色
|
||||
* @param userId 用户ID
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
boolean removeUserRoles(Long userId);
|
||||
|
||||
/**
|
||||
* 获取用户的角色标识列表
|
||||
* @param userId 用户ID
|
||||
* @return 角色标识列表
|
||||
*/
|
||||
List<String> getRoleKeysByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 获取用户的菜单列表
|
||||
* @param userId 用户ID
|
||||
* @return 菜单列表
|
||||
*/
|
||||
List<SysMenu> getMenusByUserId(Long userId);
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.unissense.sip.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.unissense.sip.dto.LoginRequest;
|
||||
import com.unissense.sip.dto.LoginResponse;
|
||||
import com.unissense.sip.entity.SysMenu;
|
||||
import com.unissense.sip.entity.SysUser;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface SysUserService extends IService<SysUser> {
|
||||
/**
|
||||
* 根据用户名查询用户
|
||||
* @param username 用户名
|
||||
* @return 用户对象
|
||||
*/
|
||||
SysUser getByUsername(String username);
|
||||
|
||||
/**
|
||||
* 创建新用户
|
||||
* @param user 用户信息
|
||||
* @return 是否创建成功
|
||||
*/
|
||||
boolean createUser(SysUser user);
|
||||
|
||||
/**
|
||||
* 用户登录
|
||||
* @param loginRequest 登录请求
|
||||
* @return 登录响应
|
||||
*/
|
||||
LoginResponse login(LoginRequest loginRequest);
|
||||
|
||||
/**
|
||||
* 获取用户角色列表
|
||||
* @param userId 用户ID
|
||||
* @return 角色标识列表
|
||||
*/
|
||||
List<String> getUserRoles(Long userId);
|
||||
|
||||
/**
|
||||
* 获取用户菜单权限
|
||||
* @param userId 用户ID
|
||||
* @return 菜单列表
|
||||
*/
|
||||
List<SysMenu> getUserMenus(Long userId);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.unissense.sip.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.unissense.sip.entity.SysDept;
|
||||
import com.unissense.sip.mapper.SysDeptMapper;
|
||||
import com.unissense.sip.service.SysDeptService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Service
|
||||
public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> implements SysDeptService {
|
||||
|
||||
@Override
|
||||
public SysDept getByDeptCode(String deptCode) {
|
||||
return this.getOne(new LambdaQueryWrapper<SysDept>()
|
||||
.eq(SysDept::getDeptCode, deptCode)
|
||||
.isNull(SysDept::getDeleteAt));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createDept(SysDept dept) {
|
||||
dept.setCreateAt(LocalDateTime.now());
|
||||
return this.save(dept);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package com.unissense.sip.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.unissense.sip.entity.SysDictData;
|
||||
import com.unissense.sip.mapper.SysDictDataMapper;
|
||||
import com.unissense.sip.service.SysDictDataService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 字典数据Service实现类
|
||||
*/
|
||||
@Service
|
||||
public class SysDictDataServiceImpl extends ServiceImpl<SysDictDataMapper, SysDictData> implements SysDictDataService {
|
||||
|
||||
@Override
|
||||
public List<SysDictData> selectDictDataByType(String dictType) {
|
||||
LambdaQueryWrapper<SysDictData> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(SysDictData::getDictType, dictType)
|
||||
.orderByAsc(SysDictData::getDictSort);
|
||||
return list(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String selectDictLabel(String dictType, String dictValue) {
|
||||
LambdaQueryWrapper<SysDictData> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(SysDictData::getDictType, dictType)
|
||||
.eq(SysDictData::getDictValue, dictValue);
|
||||
SysDictData dictData = getOne(wrapper);
|
||||
return dictData != null ? dictData.getDictLabel() : "";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package com.unissense.sip.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.unissense.sip.entity.SysDictType;
|
||||
import com.unissense.sip.mapper.SysDictTypeMapper;
|
||||
import com.unissense.sip.service.SysDictTypeService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 字典类型Service实现类
|
||||
*/
|
||||
@Service
|
||||
public class SysDictTypeServiceImpl extends ServiceImpl<SysDictTypeMapper, SysDictType> implements SysDictTypeService {
|
||||
|
||||
@Override
|
||||
public SysDictType selectDictTypeByType(String dictType) {
|
||||
LambdaQueryWrapper<SysDictType> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(SysDictType::getDictType, dictType);
|
||||
return getOne(wrapper);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.unissense.sip.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.unissense.sip.entity.SysMenu;
|
||||
import com.unissense.sip.mapper.SysMenuMapper;
|
||||
import com.unissense.sip.service.SysMenuService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {
|
||||
|
||||
@Override
|
||||
public SysMenu getByMenuCode(String menuCode) {
|
||||
return this.getOne(new LambdaQueryWrapper<SysMenu>()
|
||||
.eq(SysMenu::getMenuCode, menuCode)
|
||||
.isNull(SysMenu::getDeleteAt));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createMenu(SysMenu menu) {
|
||||
menu.setCreateAt(LocalDateTime.now());
|
||||
return this.save(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SysMenu> getChildrenMenus(Long parentId) {
|
||||
return this.list(new LambdaQueryWrapper<SysMenu>()
|
||||
.eq(SysMenu::getParentId, parentId)
|
||||
.isNull(SysMenu::getDeleteAt)
|
||||
.orderByAsc(SysMenu::getOrderNum));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package com.unissense.sip.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.unissense.sip.entity.SysRoleMenu;
|
||||
import com.unissense.sip.mapper.SysRoleMenuMapper;
|
||||
import com.unissense.sip.service.SysRoleMenuService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class SysRoleMenuServiceImpl extends ServiceImpl<SysRoleMenuMapper, SysRoleMenu> implements SysRoleMenuService {
|
||||
|
||||
@Override
|
||||
public List<Long> getMenuIdsByRoleId(Long roleId) {
|
||||
return this.list(new LambdaQueryWrapper<SysRoleMenu>()
|
||||
.eq(SysRoleMenu::getRoleId, roleId))
|
||||
.stream()
|
||||
.map(SysRoleMenu::getMenuId)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean assignMenus(Long roleId, List<Long> menuIds) {
|
||||
// 先删除原有的角色菜单关系
|
||||
this.removeRoleMenus(roleId);
|
||||
|
||||
// 构建新的角色菜单关系
|
||||
List<SysRoleMenu> roleMenus = new ArrayList<>();
|
||||
for (Long menuId : menuIds) {
|
||||
SysRoleMenu roleMenu = new SysRoleMenu();
|
||||
roleMenu.setRoleId(roleId);
|
||||
roleMenu.setMenuId(menuId);
|
||||
roleMenus.add(roleMenu);
|
||||
}
|
||||
|
||||
// 批量保存新的角色菜单关系
|
||||
return this.saveBatch(roleMenus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeRoleMenus(Long roleId) {
|
||||
return this.remove(new LambdaQueryWrapper<SysRoleMenu>()
|
||||
.eq(SysRoleMenu::getRoleId, roleId));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.unissense.sip.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.unissense.sip.entity.SysRole;
|
||||
import com.unissense.sip.mapper.SysRoleMapper;
|
||||
import com.unissense.sip.service.SysRoleService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Service
|
||||
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {
|
||||
|
||||
@Override
|
||||
public boolean createRole(SysRole role) {
|
||||
role.setCreateAt(LocalDateTime.now());
|
||||
return this.save(role);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package com.unissense.sip.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.unissense.sip.entity.SysUserRole;
|
||||
import com.unissense.sip.entity.SysRole;
|
||||
import com.unissense.sip.entity.SysMenu;
|
||||
import com.unissense.sip.mapper.SysUserRoleMapper;
|
||||
import com.unissense.sip.service.SysUserRoleService;
|
||||
import com.unissense.sip.service.SysRoleService;
|
||||
import com.unissense.sip.service.SysMenuService;
|
||||
import com.unissense.sip.service.SysRoleMenuService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Collections;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class SysUserRoleServiceImpl extends ServiceImpl<SysUserRoleMapper, SysUserRole> implements SysUserRoleService {
|
||||
|
||||
@Autowired
|
||||
private SysRoleService roleService;
|
||||
|
||||
@Autowired
|
||||
private SysMenuService menuService;
|
||||
|
||||
@Autowired
|
||||
private SysRoleMenuService roleMenuService;
|
||||
|
||||
@Override
|
||||
public List<Long> getRoleIdsByUserId(Long userId) {
|
||||
List<SysUserRole> userRoles = this.list(new LambdaQueryWrapper<SysUserRole>()
|
||||
.eq(SysUserRole::getUserId, userId));
|
||||
return userRoles.stream()
|
||||
.map(SysUserRole::getRoleId)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean assignRoles(Long userId, List<Long> roleIds) {
|
||||
// 先删除用户现有的角色
|
||||
this.removeUserRoles(userId);
|
||||
|
||||
// 分配新的角色
|
||||
List<SysUserRole> userRoles = roleIds.stream().map(roleId -> {
|
||||
SysUserRole userRole = new SysUserRole();
|
||||
userRole.setUserId(userId);
|
||||
userRole.setRoleId(roleId);
|
||||
return userRole;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
return this.saveBatch(userRoles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeUserRoles(Long userId) {
|
||||
return this.remove(new LambdaQueryWrapper<SysUserRole>()
|
||||
.eq(SysUserRole::getUserId, userId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getRoleKeysByUserId(Long userId) {
|
||||
List<Long> roleIds = this.getRoleIdsByUserId(userId);
|
||||
if (roleIds.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return roleService.listByIds(roleIds).stream()
|
||||
.map(SysRole::getRoleKey)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SysMenu> getMenusByUserId(Long userId) {
|
||||
List<Long> roleIds = this.getRoleIdsByUserId(userId);
|
||||
if (roleIds.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 获取所有角色对应的菜单ID
|
||||
List<Long> menuIds = roleIds.stream()
|
||||
.flatMap(roleId -> roleMenuService.getMenuIdsByRoleId(roleId).stream())
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (menuIds.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 查询菜单列表
|
||||
return menuService.listByIds(menuIds);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package com.unissense.sip.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.unissense.sip.dto.LoginRequest;
|
||||
import com.unissense.sip.dto.LoginResponse;
|
||||
import com.unissense.sip.entity.SysMenu;
|
||||
import com.unissense.sip.entity.SysUser;
|
||||
import com.unissense.sip.mapper.SysUserMapper;
|
||||
import com.unissense.sip.service.SysUserRoleService;
|
||||
import com.unissense.sip.service.SysUserService;
|
||||
import com.unissense.sip.utils.JwtUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
|
||||
@Override
|
||||
public List<SysMenu> getUserMenus(Long userId) {
|
||||
return userRoleService.getMenusByUserId(userId);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private BCryptPasswordEncoder passwordEncoder;
|
||||
|
||||
@Autowired
|
||||
private JwtUtils jwtUtils;
|
||||
|
||||
@Autowired
|
||||
private StringRedisTemplate redisTemplate;
|
||||
|
||||
@Autowired
|
||||
private SysUserRoleService userRoleService;
|
||||
|
||||
@Override
|
||||
public SysUser getByUsername(String username) {
|
||||
return this.getOne(new LambdaQueryWrapper<SysUser>()
|
||||
.eq(SysUser::getUsername, username)
|
||||
.isNull(SysUser::getDeleteAt));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createUser(SysUser user) {
|
||||
user.setCreateTime(LocalDateTime.now());
|
||||
user.setUpdateTime(LocalDateTime.now());
|
||||
user.setStatus(1); // 默认启用状态
|
||||
user.setPassword(passwordEncoder.encode(user.getPassword()));
|
||||
return this.save(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoginResponse login(LoginRequest loginRequest) {
|
||||
// 验证验证码
|
||||
String captchaKey = "captcha:" + loginRequest.getUsername();
|
||||
String captcha = redisTemplate.opsForValue().get(captchaKey);
|
||||
if (captcha == null || !captcha.equalsIgnoreCase(loginRequest.getCaptcha())) {
|
||||
throw new RuntimeException("验证码错误或已过期");
|
||||
}
|
||||
redisTemplate.delete(captchaKey);
|
||||
|
||||
// 验证用户名和密码
|
||||
SysUser user = getByUsername(loginRequest.getUsername());
|
||||
if (user == null || !passwordEncoder.matches(loginRequest.getPassword(), user.getPassword())) {
|
||||
throw new RuntimeException("用户名或密码错误");
|
||||
}
|
||||
|
||||
// 生成token
|
||||
String token = jwtUtils.generateToken(user.getUsername());
|
||||
|
||||
// 获取用户角色和菜单权限
|
||||
List<String> roles = getUserRoles(user.getId());
|
||||
List<SysMenu> menus = userRoleService.getMenusByUserId(user.getId());
|
||||
|
||||
// 构建响应
|
||||
LoginResponse response = new LoginResponse();
|
||||
response.setToken(token);
|
||||
response.setUser(user);
|
||||
response.setRoles(roles);
|
||||
response.setMenus(menus);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getUserRoles(Long userId) {
|
||||
return userRoleService.getRoleKeysByUserId(userId);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package com.unissense.sip.utils;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Random;
|
||||
|
||||
public class CaptchaUtils {
|
||||
private static final String CHARACTERS = "2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
|
||||
private static final int WIDTH = 90;
|
||||
private static final int HEIGHT = 40;
|
||||
private static final int LENGTH = 4;
|
||||
private static final int LINES = 5;
|
||||
|
||||
public static BufferedImage generateCaptchaImage(StringBuilder captcha) {
|
||||
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g2d = image.createGraphics();
|
||||
|
||||
// 设置背景色
|
||||
g2d.setColor(Color.WHITE);
|
||||
g2d.fillRect(0, 0, WIDTH, HEIGHT);
|
||||
|
||||
// 生成随机字符
|
||||
Random random = new Random();
|
||||
g2d.setFont(new Font("Arial", Font.BOLD, 28));
|
||||
|
||||
for (int i = 0; i < LENGTH; i++) {
|
||||
String ch = String.valueOf(CHARACTERS.charAt(random.nextInt(CHARACTERS.length())));
|
||||
captcha.append(ch);
|
||||
g2d.setColor(new Color(random.nextInt(88), random.nextInt(188), random.nextInt(255)));
|
||||
g2d.drawString(ch, (i * 20) + 10, 30);
|
||||
}
|
||||
|
||||
// 添加干扰线
|
||||
for (int i = 0; i < LINES; i++) {
|
||||
g2d.setColor(new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255)));
|
||||
g2d.drawLine(random.nextInt(WIDTH), random.nextInt(HEIGHT),
|
||||
random.nextInt(WIDTH), random.nextInt(HEIGHT));
|
||||
}
|
||||
|
||||
g2d.dispose();
|
||||
return image;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package com.unissense.sip.utils;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Component
|
||||
public class JwtUtils {
|
||||
|
||||
@Value("${jwt.secret}")
|
||||
private String secret;
|
||||
|
||||
@Value("${jwt.expiretime}")
|
||||
private long expireTime;
|
||||
|
||||
public String generateToken(String username) {
|
||||
Date now = new Date();
|
||||
Date expiration = new Date(now.getTime() + expireTime * 1000);
|
||||
|
||||
return Jwts.builder()
|
||||
.setSubject(username)
|
||||
.setIssuedAt(now)
|
||||
.setExpiration(expiration)
|
||||
.signWith(SignatureAlgorithm.HS256, secret)
|
||||
.compact();
|
||||
}
|
||||
|
||||
public String getUsernameFromToken(String token) {
|
||||
Claims claims = Jwts.parser()
|
||||
.setSigningKey(secret)
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
|
||||
return claims.getSubject();
|
||||
}
|
||||
|
||||
public boolean validateToken(String token) {
|
||||
try {
|
||||
Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://unis-sip-mysql.ns-dv9ov434.svc:3306/unis_sip?useSSL=false&serverTimezone=UTC
|
||||
username: root
|
||||
password: 5tzz94jd
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
|
||||
# MyBatis Plus配置
|
||||
mybatis-plus:
|
||||
mapper-locations: classpath*:/mapper/**/*.xml
|
||||
type-aliases-package: com.unis.sip.entity
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
global-config:
|
||||
db-config:
|
||||
logic-delete-field: deleteAt
|
||||
logic-delete-value: now()
|
||||
logic-not-delete-value: null
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
|
||||
jwt:
|
||||
secret: unis-sip-secret-key
|
||||
expiretime: 86400000 # 24 hours in milliseconds
|
|
@ -0,0 +1,26 @@
|
|||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://unis-sip-mysql.ns-dv9ov434.svc:3306/unis_sip?useSSL=false&serverTimezone=UTC
|
||||
username: root
|
||||
password: 5tzz94jd
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
|
||||
# MyBatis Plus配置
|
||||
mybatis-plus:
|
||||
mapper-locations: classpath*:/mapper/**/*.xml
|
||||
type-aliases-package: com.unis.sip.entity
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
global-config:
|
||||
db-config:
|
||||
logic-delete-field: deleteAt
|
||||
logic-delete-value: now()
|
||||
logic-not-delete-value: null
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
|
||||
jwt:
|
||||
secret: unis-sip-secret-key
|
||||
expiretime: 86400000 # 24 hours in milliseconds
|
|
@ -0,0 +1,45 @@
|
|||
/home/devbox/project/src/main/java/com/unissense/sip/service/SysDictDataService.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/service/impl/SysRoleServiceImpl.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/service/SysRoleService.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/controller/SysRoleController.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/controller/SysUserController.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/entity/SysRole.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/service/impl/SysDeptServiceImpl.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/UnisSipApplication.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/entity/SysUser.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/controller/SysUserRoleController.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/controller/AuthController.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/mapper/SysDeptMapper.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/dto/LoginRequest.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/controller/SysDictDataController.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/entity/SysUserRole.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/service/SysUserRoleService.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/service/impl/SysRoleMenuServiceImpl.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/utils/CaptchaUtils.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/service/impl/SysMenuServiceImpl.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/entity/SysDictType.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/mapper/SysRoleMenuMapper.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/mapper/SysMenuMapper.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/service/SysUserService.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/entity/SysDept.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/entity/SysDictData.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/controller/SysDeptController.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/mapper/SysDictTypeMapper.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/utils/JwtUtils.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/mapper/SysDictDataMapper.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/mapper/SysUserRoleMapper.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/service/impl/SysUserServiceImpl.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/entity/SysRoleMenu.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/controller/SysMenuController.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/service/impl/SysDictDataServiceImpl.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/mapper/SysRoleMapper.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/entity/SysMenu.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/controller/SysDictTypeController.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/dto/LoginResponse.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/service/SysDictTypeService.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/service/SysDeptService.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/service/SysRoleMenuService.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/service/impl/SysDictTypeServiceImpl.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/service/impl/SysUserRoleServiceImpl.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/service/SysMenuService.java
|
||||
/home/devbox/project/src/main/java/com/unissense/sip/mapper/SysUserMapper.java
|
|
@ -0,0 +1,228 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>售后服务平台</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css">
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100vh;
|
||||
}
|
||||
.layout-container {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.header {
|
||||
background-color: #001529;
|
||||
color: #fff;
|
||||
padding: 0 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 60px;
|
||||
}
|
||||
.logo {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.main-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
.sidebar {
|
||||
width: 220px;
|
||||
height: 100%;
|
||||
background-color: #001529;
|
||||
transition: width 0.3s;
|
||||
}
|
||||
.sidebar.collapsed {
|
||||
width: 64px;
|
||||
}
|
||||
.content {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
overflow-y: auto;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
.user-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
color: #fff;
|
||||
}
|
||||
.el-menu {
|
||||
border-right: none !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<div class="layout-container">
|
||||
<header class="header">
|
||||
<div class="logo">
|
||||
<el-button type="text" style="color: #fff" @click="toggleSidebar">
|
||||
<el-icon><Fold v-if="!isCollapse" /><Expand v-else /></el-icon>
|
||||
</el-button>
|
||||
<span v-show="!isCollapse">售后服务平台</span>
|
||||
</div>
|
||||
<div class="user-info">
|
||||
<el-dropdown @command="handleCommand">
|
||||
<span class="el-dropdown-link">
|
||||
{{ userInfo.userName }}<el-icon class="el-icon--right"><arrow-down /></el-icon>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="profile">个人信息</el-dropdown-item>
|
||||
<el-dropdown-item command="password">修改密码</el-dropdown-item>
|
||||
<el-dropdown-item divided command="logout">退出登录</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</header>
|
||||
<div class="main-container">
|
||||
<div class="sidebar" :class="{ collapsed: isCollapse }">
|
||||
<el-menu
|
||||
:default-active="activeMenu"
|
||||
:collapse="isCollapse"
|
||||
background-color="#001529"
|
||||
text-color="#fff"
|
||||
active-text-color="#409EFF"
|
||||
:unique-opened="true"
|
||||
:collapse-transition="false"
|
||||
@select="handleSelect">
|
||||
<template v-for="menu in menus" :key="menu.menuId">
|
||||
<el-sub-menu v-if="menu.children && menu.children.length" :index="menu.menuId.toString()">
|
||||
<template #title>
|
||||
<el-icon><component :is="menu.icon || 'Menu'" /></el-icon>
|
||||
<span>{{ menu.menuName }}</span>
|
||||
</template>
|
||||
<el-menu-item
|
||||
v-for="child in menu.children"
|
||||
:key="child.menuId"
|
||||
:index="child.menuId.toString()">
|
||||
<el-icon><component :is="child.icon || 'Menu'" /></el-icon>
|
||||
<template #title>{{ child.menuName }}</template>
|
||||
</el-menu-item>
|
||||
</el-sub-menu>
|
||||
<el-menu-item v-else :index="menu.menuId.toString()">
|
||||
<el-icon><component :is="menu.icon || 'Menu'" /></el-icon>
|
||||
<template #title>{{ menu.menuName }}</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-menu>
|
||||
</div>
|
||||
<main class="content">
|
||||
<iframe :src="currentUrl" frameborder="0" style="width: 100%; height: 100%;"></iframe>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
|
||||
<script src="https://unpkg.com/element-plus"></script>
|
||||
<script src="https://unpkg.com/@element-plus/icons-vue"></script>
|
||||
<script>
|
||||
const { createApp, ref, onMounted } = Vue
|
||||
|
||||
const app = createApp({
|
||||
setup() {
|
||||
const isCollapse = ref(false)
|
||||
const activeMenu = ref('')
|
||||
const currentUrl = ref('')
|
||||
const menus = ref([])
|
||||
const userInfo = ref({
|
||||
userName: ''
|
||||
})
|
||||
|
||||
const toggleSidebar = () => {
|
||||
isCollapse.value = !isCollapse.value
|
||||
}
|
||||
|
||||
const handleSelect = (index) => {
|
||||
const findMenu = (menus, id) => {
|
||||
for (const menu of menus) {
|
||||
if (menu.menuId.toString() === id) return menu
|
||||
if (menu.children) {
|
||||
const found = findMenu(menu.children, id)
|
||||
if (found) return found
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
const menu = findMenu(menus.value, index)
|
||||
if (menu && menu.url) {
|
||||
currentUrl.value = menu.url
|
||||
}
|
||||
}
|
||||
|
||||
const handleCommand = (command) => {
|
||||
switch (command) {
|
||||
case 'logout':
|
||||
fetch('/api/logout', { method: 'POST' })
|
||||
.then(() => window.location.href = '/login')
|
||||
break
|
||||
case 'profile':
|
||||
currentUrl.value = '/profile'
|
||||
break
|
||||
case 'password':
|
||||
currentUrl.value = '/password'
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 获取用户信息和菜单数据
|
||||
Promise.all([
|
||||
fetch('/api/user/info').then(res => res.json()),
|
||||
fetch('/api/user/menus').then(res => res.json())
|
||||
])
|
||||
.then(([userRes, menuRes]) => {
|
||||
if (userRes.code === 0) {
|
||||
userInfo.value = userRes.data
|
||||
}
|
||||
if (menuRes.code === 0) {
|
||||
menus.value = menuRes.data
|
||||
if (menus.value.length > 0) {
|
||||
const firstMenu = menus.value[0]
|
||||
activeMenu.value = firstMenu.menuId.toString()
|
||||
if (firstMenu.url) {
|
||||
currentUrl.value = firstMenu.url
|
||||
} else if (firstMenu.children && firstMenu.children.length > 0) {
|
||||
currentUrl.value = firstMenu.children[0].url
|
||||
activeMenu.value = firstMenu.children[0].menuId.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
ElementPlus.ElMessage.error('获取用户信息失败')
|
||||
})
|
||||
})
|
||||
|
||||
return {
|
||||
isCollapse,
|
||||
activeMenu,
|
||||
currentUrl,
|
||||
menus,
|
||||
userInfo,
|
||||
toggleSidebar,
|
||||
handleSelect,
|
||||
handleCommand
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
app.use(ElementPlus)
|
||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||
app.component(key, component)
|
||||
}
|
||||
app.mount('#app')
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,94 @@
|
|||
// 登录和权限管理相关的JavaScript代码
|
||||
const auth = {
|
||||
// 存储登录信息
|
||||
setLoginInfo(loginResponse) {
|
||||
localStorage.setItem('token', loginResponse.token);
|
||||
localStorage.setItem('user', JSON.stringify(loginResponse.user));
|
||||
localStorage.setItem('roles', JSON.stringify(loginResponse.roles));
|
||||
localStorage.setItem('menus', JSON.stringify(loginResponse.menus));
|
||||
},
|
||||
|
||||
// 清除登录信息
|
||||
clearLoginInfo() {
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('user');
|
||||
localStorage.removeItem('roles');
|
||||
localStorage.removeItem('menus');
|
||||
},
|
||||
|
||||
// 获取用户信息
|
||||
getUser() {
|
||||
const userStr = localStorage.getItem('user');
|
||||
return userStr ? JSON.parse(userStr) : null;
|
||||
},
|
||||
|
||||
// 获取用户角色
|
||||
getRoles() {
|
||||
const rolesStr = localStorage.getItem('roles');
|
||||
return rolesStr ? JSON.parse(rolesStr) : [];
|
||||
},
|
||||
|
||||
// 获取用户菜单
|
||||
getMenus() {
|
||||
const menusStr = localStorage.getItem('menus');
|
||||
return menusStr ? JSON.parse(menusStr) : [];
|
||||
},
|
||||
|
||||
// 生成菜单树
|
||||
generateMenuTree(menus) {
|
||||
const menuMap = {};
|
||||
const menuTree = [];
|
||||
|
||||
// 创建菜单映射
|
||||
menus.forEach(menu => {
|
||||
menuMap[menu.menuId] = {
|
||||
...menu,
|
||||
children: []
|
||||
};
|
||||
});
|
||||
|
||||
// 构建菜单树
|
||||
menus.forEach(menu => {
|
||||
const menuItem = menuMap[menu.menuId];
|
||||
if (menu.parentId === 0) {
|
||||
menuTree.push(menuItem);
|
||||
} else {
|
||||
const parentMenu = menuMap[menu.parentId];
|
||||
if (parentMenu) {
|
||||
parentMenu.children.push(menuItem);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return menuTree;
|
||||
},
|
||||
|
||||
// 渲染菜单
|
||||
renderMenu(menuTree) {
|
||||
const menuHtml = menuTree.map(menu => {
|
||||
if (menu.children && menu.children.length > 0) {
|
||||
return `
|
||||
<el-sub-menu index="${menu.menuId}">
|
||||
<template #title>
|
||||
<el-icon><component is="${menu.icon || 'Menu'}"></component></el-icon>
|
||||
<span>${menu.menuName}</span>
|
||||
</template>
|
||||
${this.renderMenu(menu.children)}
|
||||
</el-sub-menu>
|
||||
`;
|
||||
} else {
|
||||
return `
|
||||
<el-menu-item index="${menu.path}">
|
||||
<el-icon><component is="${menu.icon || 'Document'}"></component></el-icon>
|
||||
<span>${menu.menuName}</span>
|
||||
</el-menu-item>
|
||||
`;
|
||||
}
|
||||
}).join('');
|
||||
|
||||
return menuHtml;
|
||||
}
|
||||
};
|
||||
|
||||
// 导出auth对象
|
||||
export default auth;
|
|
@ -0,0 +1,136 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>登录 - 售后服务平台</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css">
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #f5f7fa;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
}
|
||||
.login-container {
|
||||
width: 400px;
|
||||
padding: 40px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.login-title {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
color: #303133;
|
||||
font-size: 24px;
|
||||
}
|
||||
.captcha-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
.captcha-img {
|
||||
height: 40px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<div class="login-container">
|
||||
<h2 class="login-title">售后服务平台</h2>
|
||||
<el-form :model="loginForm" :rules="rules" ref="loginFormRef">
|
||||
<el-form-item prop="username">
|
||||
<el-input v-model="loginForm.username" placeholder="请输入账号" prefix-icon="User"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input v-model="loginForm.password" type="password" placeholder="请输入密码" prefix-icon="Lock" show-password></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="captcha">
|
||||
<div class="captcha-container">
|
||||
<el-input v-model="loginForm.captcha" placeholder="请输入验证码" style="flex: 1;"></el-input>
|
||||
<img :src="captchaUrl" class="captcha-img" @click="refreshCaptcha" alt="验证码">
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" style="width: 100%" @click="handleLogin">登录</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
|
||||
<script src="https://unpkg.com/element-plus"></script>
|
||||
<script src="https://unpkg.com/@element-plus/icons-vue"></script>
|
||||
<script>
|
||||
const { createApp, ref } = Vue
|
||||
const app = createApp({
|
||||
setup() {
|
||||
const loginFormRef = ref(null)
|
||||
const loginForm = ref({
|
||||
username: '',
|
||||
password: '',
|
||||
captcha: ''
|
||||
})
|
||||
const captchaUrl = ref('/api/captcha')
|
||||
|
||||
const rules = {
|
||||
username: [{ required: true, message: '请输入账号', trigger: 'blur' }],
|
||||
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
|
||||
captcha: [{ required: true, message: '请输入验证码', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
const refreshCaptcha = () => {
|
||||
captchaUrl.value = `/api/captcha?t=${new Date().getTime()}`
|
||||
}
|
||||
|
||||
const handleLogin = () => {
|
||||
loginFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
fetch('/api/login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(loginForm.value)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.code === 0) {
|
||||
window.location.href = '/'
|
||||
} else {
|
||||
ElementPlus.ElMessage.error(data.message)
|
||||
refreshCaptcha()
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
ElementPlus.ElMessage.error('登录失败,请稍后重试')
|
||||
refreshCaptcha()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
loginFormRef,
|
||||
loginForm,
|
||||
rules,
|
||||
captchaUrl,
|
||||
handleLogin,
|
||||
refreshCaptcha
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
app.use(ElementPlus)
|
||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||
app.component(key, component)
|
||||
}
|
||||
app.mount('#app')
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue