diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100755
index 0000000..87ebf2a
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,7 @@
+{
+ "recommendations": [
+ "pomdtr.excalidraw-editor",
+ "editorconfig.editorconfig",
+ "lokalise.i18n-ally"
+ ]
+}
\ No newline at end of file
diff --git a/configs/config.yaml b/configs/config.yaml
new file mode 100644
index 0000000..1034dfd
--- /dev/null
+++ b/configs/config.yaml
@@ -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小时
\ No newline at end of file
diff --git a/db-init.sql b/db-init.sql
new file mode 100644
index 0000000..1b22a67
--- /dev/null
+++ b/db-init.sql
@@ -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());
+
diff --git a/entrypoint.sh b/entrypoint.sh
new file mode 100755
index 0000000..5fddb40
--- /dev/null
+++ b/entrypoint.sh
@@ -0,0 +1 @@
+./hello.sh
\ No newline at end of file
diff --git a/hello.sh b/hello.sh
new file mode 100755
index 0000000..2b2fb28
--- /dev/null
+++ b/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
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..68780d6
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,100 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.7.0
+
+
+
+ com.unissense.sip
+ unis-sip
+ 1.0.0
+ unis-sip
+ Unis Service Information Platform
+
+
+ 11
+ 3.5.2
+ 8.0.31
+ 0.9.1
+ 1.18.24
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+ ${mybatis-plus.version}
+
+
+
+
+ mysql
+ mysql-connector-java
+ ${mysql.version}
+
+
+
+
+ io.jsonwebtoken
+ jjwt
+ ${jwt.version}
+
+
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+ true
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/project.md b/project.md
new file mode 100644
index 0000000..89dd51b
--- /dev/null
+++ b/project.md
@@ -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)
+
+
diff --git a/src/main/java/com/unissense/sip/UnisSipApplication.java b/src/main/java/com/unissense/sip/UnisSipApplication.java
new file mode 100644
index 0000000..bff41dd
--- /dev/null
+++ b/src/main/java/com/unissense/sip/UnisSipApplication.java
@@ -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);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/config/SecurityConfig.java b/src/main/java/com/unissense/sip/config/SecurityConfig.java
new file mode 100644
index 0000000..c964921
--- /dev/null
+++ b/src/main/java/com/unissense/sip/config/SecurityConfig.java
@@ -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();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/controller/AuthController.java b/src/main/java/com/unissense/sip/controller/AuthController.java
new file mode 100644
index 0000000..0a47207
--- /dev/null
+++ b/src/main/java/com/unissense/sip/controller/AuthController.java
@@ -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);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/controller/SysDeptController.java b/src/main/java/com/unissense/sip/controller/SysDeptController.java
new file mode 100644
index 0000000..d77b2d1
--- /dev/null
+++ b/src/main/java/com/unissense/sip/controller/SysDeptController.java
@@ -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 getDeptByCode(@PathVariable String deptCode) {
+ SysDept dept = sysDeptService.getByDeptCode(deptCode);
+ return dept != null ? ResponseEntity.ok(dept) : ResponseEntity.notFound().build();
+ }
+
+ @PostMapping
+ public ResponseEntity 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());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/controller/SysDictDataController.java b/src/main/java/com/unissense/sip/controller/SysDictDataController.java
new file mode 100644
index 0000000..98a81fd
--- /dev/null
+++ b/src/main/java/com/unissense/sip/controller/SysDictDataController.java
@@ -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 list(
+ @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
+ @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
+ SysDictData dictData) {
+ LambdaQueryWrapper 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 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);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/controller/SysDictTypeController.java b/src/main/java/com/unissense/sip/controller/SysDictTypeController.java
new file mode 100644
index 0000000..aa30bb6
--- /dev/null
+++ b/src/main/java/com/unissense/sip/controller/SysDictTypeController.java
@@ -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 list(
+ @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
+ @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
+ SysDictType dictType) {
+ LambdaQueryWrapper 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);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/controller/SysMenuController.java b/src/main/java/com/unissense/sip/controller/SysMenuController.java
new file mode 100644
index 0000000..9216e28
--- /dev/null
+++ b/src/main/java/com/unissense/sip/controller/SysMenuController.java
@@ -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 getMenuByCode(@PathVariable String menuCode) {
+ SysMenu menu = sysMenuService.getByMenuCode(menuCode);
+ return menu != null ? ResponseEntity.ok(menu) : ResponseEntity.notFound().build();
+ }
+
+ @PostMapping
+ public ResponseEntity 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> getChildrenMenus(@PathVariable Long parentId) {
+ List children = sysMenuService.getChildrenMenus(parentId);
+ return ResponseEntity.ok(children);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/controller/SysRoleController.java b/src/main/java/com/unissense/sip/controller/SysRoleController.java
new file mode 100644
index 0000000..0a385f6
--- /dev/null
+++ b/src/main/java/com/unissense/sip/controller/SysRoleController.java
@@ -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 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());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/controller/SysUserController.java b/src/main/java/com/unissense/sip/controller/SysUserController.java
new file mode 100644
index 0000000..81fd918
--- /dev/null
+++ b/src/main/java/com/unissense/sip/controller/SysUserController.java
@@ -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 getUserByUsername(@PathVariable String username) {
+ SysUser user = sysUserService.getByUsername(username);
+ return user != null ? ResponseEntity.ok(user) : ResponseEntity.notFound().build();
+ }
+
+ @PostMapping
+ public ResponseEntity createUser(@RequestBody SysUser user) {
+ boolean result = sysUserService.createUser(user);
+ return ResponseEntity.ok(result);
+ }
+
+ @GetMapping("/test")
+ public ResponseEntity test() {
+ return ResponseEntity.ok("User API is working!");
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/controller/SysUserRoleController.java b/src/main/java/com/unissense/sip/controller/SysUserRoleController.java
new file mode 100644
index 0000000..2c3d1f3
--- /dev/null
+++ b/src/main/java/com/unissense/sip/controller/SysUserRoleController.java
@@ -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> getUserRoles(@PathVariable Long userId) {
+ List roleIds = sysUserRoleService.getRoleIdsByUserId(userId);
+ return ResponseEntity.ok(roleIds);
+ }
+
+ @PostMapping("/user/{userId}/roles")
+ public ResponseEntity assignRoles(
+ @PathVariable Long userId,
+ @RequestBody List roleIds) {
+ boolean success = sysUserRoleService.assignRoles(userId, roleIds);
+ return success ? ResponseEntity.ok(true) : ResponseEntity.badRequest().build();
+ }
+
+ @DeleteMapping("/user/{userId}/roles")
+ public ResponseEntity removeUserRoles(@PathVariable Long userId) {
+ boolean success = sysUserRoleService.removeUserRoles(userId);
+ return success ? ResponseEntity.ok(true) : ResponseEntity.badRequest().build();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/dto/LoginRequest.java b/src/main/java/com/unissense/sip/dto/LoginRequest.java
new file mode 100644
index 0000000..ff11d31
--- /dev/null
+++ b/src/main/java/com/unissense/sip/dto/LoginRequest.java
@@ -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;
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/dto/LoginResponse.java b/src/main/java/com/unissense/sip/dto/LoginResponse.java
new file mode 100644
index 0000000..8d50dbe
--- /dev/null
+++ b/src/main/java/com/unissense/sip/dto/LoginResponse.java
@@ -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 roles;
+ private List menus;
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/entity/SysDept.java b/src/main/java/com/unissense/sip/entity/SysDept.java
new file mode 100644
index 0000000..480790c
--- /dev/null
+++ b/src/main/java/com/unissense/sip/entity/SysDept.java
@@ -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;
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/entity/SysDictData.java b/src/main/java/com/unissense/sip/entity/SysDictData.java
new file mode 100644
index 0000000..4c11e16
--- /dev/null
+++ b/src/main/java/com/unissense/sip/entity/SysDictData.java
@@ -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;
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/entity/SysDictType.java b/src/main/java/com/unissense/sip/entity/SysDictType.java
new file mode 100644
index 0000000..1e87dea
--- /dev/null
+++ b/src/main/java/com/unissense/sip/entity/SysDictType.java
@@ -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;
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/entity/SysMenu.java b/src/main/java/com/unissense/sip/entity/SysMenu.java
new file mode 100644
index 0000000..268f5d2
--- /dev/null
+++ b/src/main/java/com/unissense/sip/entity/SysMenu.java
@@ -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;
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/entity/SysRole.java b/src/main/java/com/unissense/sip/entity/SysRole.java
new file mode 100644
index 0000000..7644be3
--- /dev/null
+++ b/src/main/java/com/unissense/sip/entity/SysRole.java
@@ -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;
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/entity/SysRoleMenu.java b/src/main/java/com/unissense/sip/entity/SysRoleMenu.java
new file mode 100644
index 0000000..8c59453
--- /dev/null
+++ b/src/main/java/com/unissense/sip/entity/SysRoleMenu.java
@@ -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;
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/entity/SysUser.java b/src/main/java/com/unissense/sip/entity/SysUser.java
new file mode 100644
index 0000000..7a332ad
--- /dev/null
+++ b/src/main/java/com/unissense/sip/entity/SysUser.java
@@ -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;
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/entity/SysUserRole.java b/src/main/java/com/unissense/sip/entity/SysUserRole.java
new file mode 100644
index 0000000..3541cb8
--- /dev/null
+++ b/src/main/java/com/unissense/sip/entity/SysUserRole.java
@@ -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;
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/mapper/SysDeptMapper.java b/src/main/java/com/unissense/sip/mapper/SysDeptMapper.java
new file mode 100644
index 0000000..4d26e91
--- /dev/null
+++ b/src/main/java/com/unissense/sip/mapper/SysDeptMapper.java
@@ -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 {
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/mapper/SysDictDataMapper.java b/src/main/java/com/unissense/sip/mapper/SysDictDataMapper.java
new file mode 100644
index 0000000..34b5f8e
--- /dev/null
+++ b/src/main/java/com/unissense/sip/mapper/SysDictDataMapper.java
@@ -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 {
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/mapper/SysDictTypeMapper.java b/src/main/java/com/unissense/sip/mapper/SysDictTypeMapper.java
new file mode 100644
index 0000000..ba1075b
--- /dev/null
+++ b/src/main/java/com/unissense/sip/mapper/SysDictTypeMapper.java
@@ -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 {
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/mapper/SysMenuMapper.java b/src/main/java/com/unissense/sip/mapper/SysMenuMapper.java
new file mode 100644
index 0000000..9aa3919
--- /dev/null
+++ b/src/main/java/com/unissense/sip/mapper/SysMenuMapper.java
@@ -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 {
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/mapper/SysRoleMapper.java b/src/main/java/com/unissense/sip/mapper/SysRoleMapper.java
new file mode 100644
index 0000000..e983033
--- /dev/null
+++ b/src/main/java/com/unissense/sip/mapper/SysRoleMapper.java
@@ -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 {
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/mapper/SysRoleMenuMapper.java b/src/main/java/com/unissense/sip/mapper/SysRoleMenuMapper.java
new file mode 100644
index 0000000..085d39d
--- /dev/null
+++ b/src/main/java/com/unissense/sip/mapper/SysRoleMenuMapper.java
@@ -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 {
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/mapper/SysUserMapper.java b/src/main/java/com/unissense/sip/mapper/SysUserMapper.java
new file mode 100644
index 0000000..6f7c3f0
--- /dev/null
+++ b/src/main/java/com/unissense/sip/mapper/SysUserMapper.java
@@ -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 {
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/mapper/SysUserRoleMapper.java b/src/main/java/com/unissense/sip/mapper/SysUserRoleMapper.java
new file mode 100644
index 0000000..188a25e
--- /dev/null
+++ b/src/main/java/com/unissense/sip/mapper/SysUserRoleMapper.java
@@ -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 {
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/service/SysDeptService.java b/src/main/java/com/unissense/sip/service/SysDeptService.java
new file mode 100644
index 0000000..3097b38
--- /dev/null
+++ b/src/main/java/com/unissense/sip/service/SysDeptService.java
@@ -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 {
+ /**
+ * 根据部门编码查询部门
+ * @param deptCode 部门编码
+ * @return 部门信息
+ */
+ SysDept getByDeptCode(String deptCode);
+
+ /**
+ * 创建新部门
+ * @param dept 部门信息
+ * @return 是否创建成功
+ */
+ boolean createDept(SysDept dept);
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/service/SysDictDataService.java b/src/main/java/com/unissense/sip/service/SysDictDataService.java
new file mode 100644
index 0000000..8cab0f5
--- /dev/null
+++ b/src/main/java/com/unissense/sip/service/SysDictDataService.java
@@ -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 {
+
+ /**
+ * 根据字典类型查询字典数据列表
+ *
+ * @param dictType 字典类型
+ * @return 字典数据列表
+ */
+ List selectDictDataByType(String dictType);
+
+ /**
+ * 根据字典类型和字典键值查询字典数据信息
+ *
+ * @param dictType 字典类型
+ * @param dictValue 字典键值
+ * @return 字典标签
+ */
+ String selectDictLabel(String dictType, String dictValue);
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/service/SysDictTypeService.java b/src/main/java/com/unissense/sip/service/SysDictTypeService.java
new file mode 100644
index 0000000..dd02eda
--- /dev/null
+++ b/src/main/java/com/unissense/sip/service/SysDictTypeService.java
@@ -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 {
+
+ /**
+ * 根据字典类型查询字典数据
+ *
+ * @param dictType 字典类型
+ * @return 字典数据
+ */
+ SysDictType selectDictTypeByType(String dictType);
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/service/SysMenuService.java b/src/main/java/com/unissense/sip/service/SysMenuService.java
new file mode 100644
index 0000000..f8814b1
--- /dev/null
+++ b/src/main/java/com/unissense/sip/service/SysMenuService.java
@@ -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 {
+ /**
+ * 根据菜单编码查询菜单
+ * @param menuCode 菜单编码
+ * @return 菜单信息
+ */
+ SysMenu getByMenuCode(String menuCode);
+
+ /**
+ * 创建新菜单
+ * @param menu 菜单信息
+ * @return 是否创建成功
+ */
+ boolean createMenu(SysMenu menu);
+
+ /**
+ * 获取子菜单列表
+ * @param parentId 父菜单ID
+ * @return 子菜单列表
+ */
+ List getChildrenMenus(Long parentId);
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/service/SysRoleMenuService.java b/src/main/java/com/unissense/sip/service/SysRoleMenuService.java
new file mode 100644
index 0000000..3eb1bfe
--- /dev/null
+++ b/src/main/java/com/unissense/sip/service/SysRoleMenuService.java
@@ -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 {
+ /**
+ * 获取角色的菜单ID列表
+ * @param roleId 角色ID
+ * @return 菜单ID列表
+ */
+ List getMenuIdsByRoleId(Long roleId);
+
+ /**
+ * 为角色分配菜单
+ * @param roleId 角色ID
+ * @param menuIds 菜单ID列表
+ * @return 是否分配成功
+ */
+ boolean assignMenus(Long roleId, List menuIds);
+
+ /**
+ * 删除角色的所有菜单
+ * @param roleId 角色ID
+ * @return 是否删除成功
+ */
+ boolean removeRoleMenus(Long roleId);
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/service/SysRoleService.java b/src/main/java/com/unissense/sip/service/SysRoleService.java
new file mode 100644
index 0000000..67a5925
--- /dev/null
+++ b/src/main/java/com/unissense/sip/service/SysRoleService.java
@@ -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 {
+
+ /**
+ * 创建新角色
+ * @param role 角色信息
+ * @return 是否创建成功
+ */
+ boolean createRole(SysRole role);
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/service/SysUserRoleService.java b/src/main/java/com/unissense/sip/service/SysUserRoleService.java
new file mode 100644
index 0000000..a6481f6
--- /dev/null
+++ b/src/main/java/com/unissense/sip/service/SysUserRoleService.java
@@ -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 {
+ /**
+ * 获取用户的角色ID列表
+ * @param userId 用户ID
+ * @return 角色ID列表
+ */
+ List getRoleIdsByUserId(Long userId);
+
+ /**
+ * 为用户分配角色
+ * @param userId 用户ID
+ * @param roleIds 角色ID列表
+ * @return 是否分配成功
+ */
+ boolean assignRoles(Long userId, List roleIds);
+
+ /**
+ * 删除用户的所有角色
+ * @param userId 用户ID
+ * @return 是否删除成功
+ */
+ boolean removeUserRoles(Long userId);
+
+ /**
+ * 获取用户的角色标识列表
+ * @param userId 用户ID
+ * @return 角色标识列表
+ */
+ List getRoleKeysByUserId(Long userId);
+
+ /**
+ * 获取用户的菜单列表
+ * @param userId 用户ID
+ * @return 菜单列表
+ */
+ List getMenusByUserId(Long userId);
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/service/SysUserService.java b/src/main/java/com/unissense/sip/service/SysUserService.java
new file mode 100644
index 0000000..f81ab90
--- /dev/null
+++ b/src/main/java/com/unissense/sip/service/SysUserService.java
@@ -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 {
+ /**
+ * 根据用户名查询用户
+ * @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 getUserRoles(Long userId);
+
+ /**
+ * 获取用户菜单权限
+ * @param userId 用户ID
+ * @return 菜单列表
+ */
+ List getUserMenus(Long userId);
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/service/impl/SysDeptServiceImpl.java b/src/main/java/com/unissense/sip/service/impl/SysDeptServiceImpl.java
new file mode 100644
index 0000000..0779140
--- /dev/null
+++ b/src/main/java/com/unissense/sip/service/impl/SysDeptServiceImpl.java
@@ -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 implements SysDeptService {
+
+ @Override
+ public SysDept getByDeptCode(String deptCode) {
+ return this.getOne(new LambdaQueryWrapper()
+ .eq(SysDept::getDeptCode, deptCode)
+ .isNull(SysDept::getDeleteAt));
+ }
+
+ @Override
+ public boolean createDept(SysDept dept) {
+ dept.setCreateAt(LocalDateTime.now());
+ return this.save(dept);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/service/impl/SysDictDataServiceImpl.java b/src/main/java/com/unissense/sip/service/impl/SysDictDataServiceImpl.java
new file mode 100644
index 0000000..69f448e
--- /dev/null
+++ b/src/main/java/com/unissense/sip/service/impl/SysDictDataServiceImpl.java
@@ -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 implements SysDictDataService {
+
+ @Override
+ public List selectDictDataByType(String dictType) {
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
+ wrapper.eq(SysDictData::getDictType, dictType)
+ .orderByAsc(SysDictData::getDictSort);
+ return list(wrapper);
+ }
+
+ @Override
+ public String selectDictLabel(String dictType, String dictValue) {
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
+ wrapper.eq(SysDictData::getDictType, dictType)
+ .eq(SysDictData::getDictValue, dictValue);
+ SysDictData dictData = getOne(wrapper);
+ return dictData != null ? dictData.getDictLabel() : "";
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/service/impl/SysDictTypeServiceImpl.java b/src/main/java/com/unissense/sip/service/impl/SysDictTypeServiceImpl.java
new file mode 100644
index 0000000..9a3b018
--- /dev/null
+++ b/src/main/java/com/unissense/sip/service/impl/SysDictTypeServiceImpl.java
@@ -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 implements SysDictTypeService {
+
+ @Override
+ public SysDictType selectDictTypeByType(String dictType) {
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
+ wrapper.eq(SysDictType::getDictType, dictType);
+ return getOne(wrapper);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/service/impl/SysMenuServiceImpl.java b/src/main/java/com/unissense/sip/service/impl/SysMenuServiceImpl.java
new file mode 100644
index 0000000..9cf5909
--- /dev/null
+++ b/src/main/java/com/unissense/sip/service/impl/SysMenuServiceImpl.java
@@ -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 implements SysMenuService {
+
+ @Override
+ public SysMenu getByMenuCode(String menuCode) {
+ return this.getOne(new LambdaQueryWrapper()
+ .eq(SysMenu::getMenuCode, menuCode)
+ .isNull(SysMenu::getDeleteAt));
+ }
+
+ @Override
+ public boolean createMenu(SysMenu menu) {
+ menu.setCreateAt(LocalDateTime.now());
+ return this.save(menu);
+ }
+
+ @Override
+ public List getChildrenMenus(Long parentId) {
+ return this.list(new LambdaQueryWrapper()
+ .eq(SysMenu::getParentId, parentId)
+ .isNull(SysMenu::getDeleteAt)
+ .orderByAsc(SysMenu::getOrderNum));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/service/impl/SysRoleMenuServiceImpl.java b/src/main/java/com/unissense/sip/service/impl/SysRoleMenuServiceImpl.java
new file mode 100644
index 0000000..e9bc1f3
--- /dev/null
+++ b/src/main/java/com/unissense/sip/service/impl/SysRoleMenuServiceImpl.java
@@ -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 implements SysRoleMenuService {
+
+ @Override
+ public List getMenuIdsByRoleId(Long roleId) {
+ return this.list(new LambdaQueryWrapper()
+ .eq(SysRoleMenu::getRoleId, roleId))
+ .stream()
+ .map(SysRoleMenu::getMenuId)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public boolean assignMenus(Long roleId, List menuIds) {
+ // 先删除原有的角色菜单关系
+ this.removeRoleMenus(roleId);
+
+ // 构建新的角色菜单关系
+ List 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()
+ .eq(SysRoleMenu::getRoleId, roleId));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/service/impl/SysRoleServiceImpl.java b/src/main/java/com/unissense/sip/service/impl/SysRoleServiceImpl.java
new file mode 100644
index 0000000..51a0334
--- /dev/null
+++ b/src/main/java/com/unissense/sip/service/impl/SysRoleServiceImpl.java
@@ -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 implements SysRoleService {
+
+ @Override
+ public boolean createRole(SysRole role) {
+ role.setCreateAt(LocalDateTime.now());
+ return this.save(role);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/service/impl/SysUserRoleServiceImpl.java b/src/main/java/com/unissense/sip/service/impl/SysUserRoleServiceImpl.java
new file mode 100644
index 0000000..d70bb7b
--- /dev/null
+++ b/src/main/java/com/unissense/sip/service/impl/SysUserRoleServiceImpl.java
@@ -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 implements SysUserRoleService {
+
+ @Autowired
+ private SysRoleService roleService;
+
+ @Autowired
+ private SysMenuService menuService;
+
+ @Autowired
+ private SysRoleMenuService roleMenuService;
+
+ @Override
+ public List getRoleIdsByUserId(Long userId) {
+ List userRoles = this.list(new LambdaQueryWrapper()
+ .eq(SysUserRole::getUserId, userId));
+ return userRoles.stream()
+ .map(SysUserRole::getRoleId)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ @Transactional
+ public boolean assignRoles(Long userId, List roleIds) {
+ // 先删除用户现有的角色
+ this.removeUserRoles(userId);
+
+ // 分配新的角色
+ List 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()
+ .eq(SysUserRole::getUserId, userId));
+ }
+
+ @Override
+ public List getRoleKeysByUserId(Long userId) {
+ List roleIds = this.getRoleIdsByUserId(userId);
+ if (roleIds.isEmpty()) {
+ return Collections.emptyList();
+ }
+ return roleService.listByIds(roleIds).stream()
+ .map(SysRole::getRoleKey)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public List getMenusByUserId(Long userId) {
+ List roleIds = this.getRoleIdsByUserId(userId);
+ if (roleIds.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ // 获取所有角色对应的菜单ID
+ List menuIds = roleIds.stream()
+ .flatMap(roleId -> roleMenuService.getMenuIdsByRoleId(roleId).stream())
+ .distinct()
+ .collect(Collectors.toList());
+
+ if (menuIds.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ // 查询菜单列表
+ return menuService.listByIds(menuIds);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/service/impl/SysUserServiceImpl.java b/src/main/java/com/unissense/sip/service/impl/SysUserServiceImpl.java
new file mode 100644
index 0000000..024429c
--- /dev/null
+++ b/src/main/java/com/unissense/sip/service/impl/SysUserServiceImpl.java
@@ -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 implements SysUserService {
+ @Override
+ public List 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()
+ .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 roles = getUserRoles(user.getId());
+ List 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 getUserRoles(Long userId) {
+ return userRoleService.getRoleKeysByUserId(userId);
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/utils/CaptchaUtils.java b/src/main/java/com/unissense/sip/utils/CaptchaUtils.java
new file mode 100644
index 0000000..fda629e
--- /dev/null
+++ b/src/main/java/com/unissense/sip/utils/CaptchaUtils.java
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/unissense/sip/utils/JwtUtils.java b/src/main/java/com/unissense/sip/utils/JwtUtils.java
new file mode 100644
index 0000000..509570e
--- /dev/null
+++ b/src/main/java/com/unissense/sip/utils/JwtUtils.java
@@ -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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
new file mode 100644
index 0000000..cafc828
--- /dev/null
+++ b/src/main/resources/application.yml
@@ -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
\ No newline at end of file
diff --git a/target/classes/application.yml b/target/classes/application.yml
new file mode 100644
index 0000000..cafc828
--- /dev/null
+++ b/target/classes/application.yml
@@ -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
\ No newline at end of file
diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
new file mode 100644
index 0000000..dc378ac
--- /dev/null
+++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
@@ -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
diff --git a/template/index.html b/template/index.html
new file mode 100644
index 0000000..fa65b71
--- /dev/null
+++ b/template/index.html
@@ -0,0 +1,228 @@
+
+
+
+
+
+ 售后服务平台
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/template/js/auth.js b/template/js/auth.js
new file mode 100644
index 0000000..2f7f636
--- /dev/null
+++ b/template/js/auth.js
@@ -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 `
+
+
+
+ ${menu.menuName}
+
+ ${this.renderMenu(menu.children)}
+
+ `;
+ } else {
+ return `
+
+
+ ${menu.menuName}
+
+ `;
+ }
+ }).join('');
+
+ return menuHtml;
+ }
+};
+
+// 导出auth对象
+export default auth;
\ No newline at end of file
diff --git a/template/login.html b/template/login.html
new file mode 100644
index 0000000..d5f21be
--- /dev/null
+++ b/template/login.html
@@ -0,0 +1,136 @@
+
+
+
+
+
+ 登录 - 售后服务平台
+
+
+
+
+
+
+
售后服务平台
+
+
+
+
+
+
+
+
+
+
+
![验证码]()
+
+
+
+ 登录
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file