doc: sql in README #2
Generated
+1
@@ -5,6 +5,7 @@
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$/src/beckend" />
|
||||
<option name="gradleJvm" value="25" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$/src/beckend" />
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="PyShadowingBuiltinsInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="ignoredNames">
|
||||
<list>
|
||||
<option value="id" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SqlDialectMappings">
|
||||
<file url="file://$PROJECT_DIR$/schema.sql" dialect="MariaDB" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -5,122 +5,123 @@
|
||||
[完整信息](./API.md)
|
||||
|
||||
- /api
|
||||
- /test
|
||||
- /hello
|
||||
- /v1
|
||||
- /auth
|
||||
- /login
|
||||
- /logout
|
||||
- /relogin
|
||||
- /ask-code
|
||||
- /register
|
||||
- /reset
|
||||
- /departments
|
||||
- /email
|
||||
- /evaluation-records
|
||||
- /finance
|
||||
- /items
|
||||
- /memos
|
||||
- /personnel
|
||||
- /project-groups
|
||||
- /proof-images
|
||||
- /usages
|
||||
- /users
|
||||
- /test
|
||||
- /hello
|
||||
- /v1
|
||||
- /auth
|
||||
- /login
|
||||
- /logout
|
||||
- /relogin
|
||||
- /ask-code
|
||||
- /register
|
||||
- /reset
|
||||
- /departments
|
||||
- /email
|
||||
- /evaluation-records
|
||||
- /finance
|
||||
- /items
|
||||
- /memos
|
||||
- /personnel
|
||||
- /project-groups
|
||||
- /proof-images
|
||||
- /usages
|
||||
- /users
|
||||
|
||||
## 预计完成的 API 列表
|
||||
|
||||
### 1. **物品管理 (Items)** - `/api/`
|
||||
### 1. **物品管理 (Items)**
|
||||
|
||||
| 端点 | 方法 | 功能说明 |
|
||||
|---------------------------------|---------------------|----------------|
|
||||
| `items/` | GET/POST/PUT/DELETE | 物品 CRUD 操作 |
|
||||
| `items/{id}/upload_images/` | POST | 上传物品图片 |
|
||||
| `items/{id}/set_primary_image/` | POST | 设置主图片 |
|
||||
| `items/{id}/borrow/` | POST | 借用物品 |
|
||||
| `items/{id}/return_item/` | POST | 归还物品 |
|
||||
| `items/available/` | GET | 获取可用物品列表 |
|
||||
| `items/in_use/` | GET | 获取使用中的物品列表 |
|
||||
| `usages/` | GET/POST/PUT/DELETE | 物品使用记录 CRUD 操作 |
|
||||
| `usages/{id}/upload_images/` | POST | 上传使用记录图片 |
|
||||
| `usages/current/` | GET | 获取当前使用中的记录 |
|
||||
| `usages/by_user/` | GET | 根据用户姓名获取使用记录 |
|
||||
| `items/categories/`(原 `item_categories/`) | GET/POST/PUT/DELETE | 物品类别 CRUD 操作 |
|
||||
| `users/` | GET | 获取用户列表(只读) |
|
||||
| `items/images/`(原 `item-images/`) | GET/POST/PUT/DELETE | 物品图片 CRUD 操作 |
|
||||
| `usages/images/`(原 `usage-images/`) | GET/POST/PUT/DELETE | 使用记录图片 CRUD 操作 |
|
||||
| 端点 | 方法 | 功能说明 |
|
||||
|----------------------------------------------|---------------------|--------------------------|
|
||||
| `items/` | GET/POST/PUT/DELETE | 物品 CRUD 操作 |
|
||||
| `items/{id}/upload_images/` | POST | 上传物品图片 |
|
||||
| `items/{id}/set_primary_image/` | POST | 设置主图片 |
|
||||
| `items/{id}/borrow/` | POST | 借用物品 |
|
||||
| `items/{id}/return_item/` | POST | 归还物品 |
|
||||
| `items/available/` | GET | 获取可用物品列表 |
|
||||
| `items/in_use/` | GET | 获取使用中的物品列表 |
|
||||
| `usages/` | GET/POST/PUT/DELETE | 物品使用记录 CRUD 操作 |
|
||||
| `usages/{id}/upload_images/` | POST | 上传使用记录图片 |
|
||||
| `usages/current/` | GET | 获取当前使用中的记录 |
|
||||
| `usages/by_user/` | GET | 根据用户姓名获取使用记录 |
|
||||
| `items/categories/`(原 `item_categories/`) | GET/POST/PUT/DELETE | 物品类别 CRUD 操作 |
|
||||
| `users/` | GET | 获取用户列表(只读) |
|
||||
| `items/images/`(原 `item-images/`) | GET/POST/PUT/DELETE | 物品图片 CRUD 操作 |
|
||||
| `usages/images/`(原 `usage-images/`) | GET/POST/PUT/DELETE | 使用记录图片 CRUD 操作 |
|
||||
|
||||
---
|
||||
|
||||
### 2. **人员管理 (Personnel)** - `/api/`
|
||||
### 2. **人员管理 (Personnel)**
|
||||
|
||||
| 端点 | 方法 | 功能说明 |
|
||||
|---------------------------------|---------------------|------------------|
|
||||
| `personnel/` | GET/POST/PUT/DELETE | 人员信息 CRUD 操作 |
|
||||
| 端点 | 方法 | 功能说明 |
|
||||
|---------------------------------|---------------------|----------------------------------|
|
||||
| `personnel/` | GET/POST/PUT/DELETE | 人员信息 CRUD 操作 |
|
||||
| `personnel/statistics/` | GET | 获取人员统计信息(按部门和职位) |
|
||||
| `personnel/{id}/set_inactive/` | POST | 设置人员为已卸任状态 |
|
||||
| `personnel/{id}/set_active/` | POST | 设置人员为在职状态 |
|
||||
| `personnel/{id}/` | DELETE | 删除人员(发送邮件通知) |
|
||||
| `personnel/check_expired/` | POST | 检查并更新已到期的人员状态 |
|
||||
| `project-groups/` | GET/POST/PUT/DELETE | 项目组 CRUD 操作 |
|
||||
| `project-groups/by_department/` | GET | 按部门获取项目组 |
|
||||
| `project-groups/{id}/` | DELETE | 删除项目组(发送邮件通知) |
|
||||
| `personnel/{id}/set_inactive/` | POST | 设置人员为已卸任状态 |
|
||||
| `personnel/{id}/set_active/` | POST | 设置人员为在职状态 |
|
||||
| `personnel/{id}/` | DELETE | 删除人员(发送邮件通知) |
|
||||
| `personnel/check_expired/` | POST | 检查并更新已到期的人员状态 |
|
||||
| `project-groups/` | GET/POST/PUT/DELETE | 项目组 CRUD 操作 |
|
||||
| `project-groups/by_department/` | GET | 按部门获取项目组 |
|
||||
| `project-groups/{id}/` | DELETE | 删除项目组(发送邮件通知) |
|
||||
|
||||
**搜索/过滤字段**: `name`, `student_id`, `phone`, `email`, `grade_major`
|
||||
|
||||
---
|
||||
|
||||
### 3. **财务管理 (Finance)** - `/api/`
|
||||
### 3. **财务管理 (Finance)**
|
||||
|
||||
| 端点 | 方法 | 功能说明 |
|
||||
|-------------------------------|---------------------|------------------|
|
||||
| `finance/` | GET/POST/PUT/DELETE | 财务记录 CRUD 操作 |
|
||||
| `finance/{id}/upload_images/` | POST | 上传财务凭证图片 |
|
||||
| `finance/{id}/` | DELETE | 删除财务记录(发送邮件通知) |
|
||||
| `departments/` | GET/POST/PUT/DELETE | 部门 CRUD 操作 |
|
||||
| `departments/{id}/` | DELETE | 删除部门(发送邮件通知) |
|
||||
| `finance/categories/`(原 `finance_categories/`) | GET/POST/PUT/DELETE | 财务分类 CRUD 操作 |
|
||||
| `proof-images/` | GET/POST/PUT/DELETE | 财务凭证图片 CRUD 操作 |
|
||||
| `proof-images/{id}/` | DELETE | 删除凭证图片(自动删除物理文件) |
|
||||
| 端点 | 方法 | 功能说明 |
|
||||
|---------------------------------------------------|---------------------|----------------------------------|
|
||||
| `finance/` | GET/POST/PUT/DELETE | 财务记录 CRUD 操作 |
|
||||
| `finance/{id}/upload_images/` | POST | 上传财务凭证图片 |
|
||||
| `finance/{id}/` | DELETE | 删除财务记录(发送邮件通知) |
|
||||
| `departments/` | GET/POST/PUT/DELETE | 部门 CRUD 操作 |
|
||||
| `departments/{id}/` | DELETE | 删除部门(发送邮件通知) |
|
||||
| `finance/categories/`(原 `finance_categories/`) | GET/POST/PUT/DELETE | 财务分类 CRUD 操作 |
|
||||
| `proof-images/` | GET/POST/PUT/DELETE | 财务凭证图片 CRUD 操作 |
|
||||
| `proof-images/{id}/` | DELETE | 删除凭证图片(自动删除物理文件) |
|
||||
|
||||
---
|
||||
|
||||
### 4. **邮件通知 (Email Notice)** - `/api/`
|
||||
### 4. **邮件通知 (Email Notice)**
|
||||
|
||||
| 端点 | 方法 | 功能说明 |
|
||||
|--------------------------|----------|----------------|
|
||||
| 端点 | 方法 | 功能说明 |
|
||||
|--------------------------|----------|-----------------------------|
|
||||
| `notification-settings/` | GET/POST | 获取/更新通知设置和邮箱列表 |
|
||||
| `toggle-email-status/` | POST | 切换邮箱启用/禁用状态 |
|
||||
| `toggle-email-status/` | POST | 切换邮箱启用/禁用状态 |
|
||||
|
||||
**功能**: 管理邮件通知的全局开关和收件人列表
|
||||
|
||||
---
|
||||
|
||||
### 5. **备忘录 (Memo)** - `/api/`
|
||||
### 5. **备忘录 (Memo)**
|
||||
|
||||
| 端点 | 方法 | 功能说明 |
|
||||
|----------------------------|---------------------|-------------|
|
||||
| 端点 | 方法 | 功能说明 |
|
||||
|----------------------------|---------------------|------------------|
|
||||
| `memos/` | GET/POST/PUT/DELETE | 备忘录 CRUD 操作 |
|
||||
| `memos/{id}/upload_image/` | POST | 上传备忘录图片 |
|
||||
| `memos/{id}/delete_image/` | DELETE | 删除备忘录图片 |
|
||||
| `memos/{id}/upload_image/` | POST | 上传备忘录图片 |
|
||||
| `memos/{id}/delete_image/` | DELETE | 删除备忘录图片 |
|
||||
|
||||
**搜索字段**: `title`, `content`
|
||||
**默认排序**: 按更新时间倒序
|
||||
|
||||
---
|
||||
|
||||
### 6. **考评系统 (Evaluation)** - `/api/`
|
||||
### 6. **考评系统 (Evaluation)**
|
||||
|
||||
| 端点 | 方法 | 功能说明 |
|
||||
|-----------------------------------------|---------------------|------------------------|
|
||||
| `evaluation-records/` | GET/POST/PUT/DELETE | 考评记录 CRUD 操作 |
|
||||
| `evaluation-records/personnel-summary/` | GET | 获取人员考评汇总(按人员、部门、年级分组) |
|
||||
| `evaluation-records/personnel-records/` | GET | 获取某个人员的所有考评记录 |
|
||||
| `evaluation-records/delete-personnel/` | DELETE | 删除某个人员的所有考评记录 |
|
||||
| `evaluation-records/export/` | GET | 导出考评记录为 Excel(每个人一个表格) |
|
||||
| `evaluation-records/download-template/` | GET | 下载人员导入样表 |
|
||||
| `evaluation-records/import/` | POST | 导入考评记录(支持 Excel/CSV) |
|
||||
| 端点 | 方法 | 功能说明 |
|
||||
|-----------------------------------------|---------------------|--------------------------------------------|
|
||||
| `evaluation-records/` | GET/POST/PUT/DELETE | 考评记录 CRUD 操作 |
|
||||
| `evaluation-records/personnel-summary/` | GET | 获取人员考评汇总(按人员、部门、年级分组) |
|
||||
| `evaluation-records/personnel-records/` | GET | 获取某个人员的所有考评记录 |
|
||||
| `evaluation-records/delete-personnel/` | DELETE | 删除某个人员的所有考评记录 |
|
||||
| `evaluation-records/export/` | GET | 导出考评记录为 Excel(每个人一个表格) |
|
||||
| `evaluation-records/download-template/` | GET | 下载人员导入样表 |
|
||||
| `evaluation-records/import/` | POST | 导入考评记录(支持 Excel/CSV) |
|
||||
|
||||
**功能**:
|
||||
|
||||
- 支持批量导入和导出
|
||||
- 样表格式:只需部门、年级、姓名(初始分39分)
|
||||
- 完整格式:包含详细的加分/扣分记录
|
||||
@@ -130,17 +131,56 @@
|
||||
|
||||
### 7. **认证相关**
|
||||
|
||||
| 端点 | 方法 | 功能说明 |
|
||||
|----------------------|----------|-------------|
|
||||
这是原先的 Django REST Framework JWT 认证端点,主要用于获取和刷新 JWT 令牌。
|
||||
现在改用 `/api/v1/auth/` 端点来处理登录、注册、重置密码等操作。
|
||||
|
||||
| 端点 | 方法 | 功能说明 |
|
||||
|----------------------|----------|-----------------|
|
||||
| `api/token/` | POST | JWT 令牌获取 |
|
||||
| `api/token/refresh/` | POST | JWT 令牌刷新 |
|
||||
| `admin/` | GET/POST | Django 管理后台 |
|
||||
|
||||
---
|
||||
|
||||
## 认证方式
|
||||
#### 认证方式
|
||||
|
||||
所有 API 均使用 **JWT 认证**(除了需要特殊处理的端点):
|
||||
|
||||
```
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
## 数据库结构
|
||||
|
||||
[schema.sql](./schema.sql)。
|
||||
|
||||
- users (系统用户/认证信息)
|
||||
- departments (组织/部门)
|
||||
- parent_id -> departments.id (自关联父级)
|
||||
- personnel (人员信息)
|
||||
- user_id -> users.id
|
||||
- department_id -> departments.id
|
||||
- categories (物品类别)
|
||||
- parent_id -> categories.id (自关联父级)
|
||||
- items (物品基本信息)
|
||||
- category_id -> categories.id
|
||||
- created_by -> personnel.id
|
||||
- item_transactions (物品出入库流水)
|
||||
- item_id -> items.id (ON DELETE CASCADE)
|
||||
- operator_id -> personnel.id
|
||||
- borrow_records (借用/归还记录)
|
||||
- item_id -> items.id (ON DELETE CASCADE)
|
||||
- borrower_id -> personnel.id (ON DELETE CASCADE)
|
||||
- approver_id -> personnel.id
|
||||
- memos (备忘/备注)
|
||||
- author_id -> personnel.id
|
||||
- related_item_id -> items.id
|
||||
- finance_records (财务相关记录)
|
||||
- related_item_id -> items.id
|
||||
- recorded_by -> personnel.id
|
||||
- email_notices (邮件通知规则/历史)
|
||||
- evaluations (物品/服务评价)
|
||||
- related_item_id -> items.id
|
||||
- evaluator_id -> personnel.id
|
||||
- attachments (文件附件存储索引表)
|
||||
- uploaded_by -> personnel.id
|
||||
|
||||
+228
@@ -0,0 +1,228 @@
|
||||
-- 用户表(若项目使用 Django auth,可忽略或与 auth_user 对应)
|
||||
DROP TABLE IF EXISTS account;
|
||||
CREATE TABLE account
|
||||
(
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
username VARCHAR(150) NOT NULL UNIQUE,
|
||||
password VARCHAR(128) NOT NULL,
|
||||
email VARCHAR(254),
|
||||
full_name VARCHAR(200),
|
||||
is_active TINYINT(1) NOT NULL DEFAULT 1,
|
||||
is_staff TINYINT(1) NOT NULL DEFAULT 0,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4
|
||||
COLLATE = utf8mb4_unicode_ci COMMENT ='系统用户/认证信息';
|
||||
|
||||
-- 部门表
|
||||
DROP TABLE IF EXISTS departments;
|
||||
CREATE TABLE departments
|
||||
(
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
code VARCHAR(50),
|
||||
parent_id BIGINT UNSIGNED,
|
||||
description TEXT,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_departments_parent FOREIGN KEY (parent_id) REFERENCES departments (id) ON DELETE SET NULL
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT ='组织/部门';
|
||||
|
||||
-- 人员表(可映射到 Django 的 profile)
|
||||
DROP TABLE IF EXISTS personnel;
|
||||
CREATE TABLE personnel
|
||||
(
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id BIGINT UNSIGNED, -- 关联 account 表(可为空)
|
||||
employee_no VARCHAR(64) UNIQUE,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
department_id BIGINT UNSIGNED,
|
||||
phone VARCHAR(50),
|
||||
email VARCHAR(254),
|
||||
role VARCHAR(100),
|
||||
is_active TINYINT(1) NOT NULL DEFAULT 1,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_personnel_user FOREIGN KEY (user_id) REFERENCES account (id) ON DELETE SET NULL,
|
||||
CONSTRAINT fk_personnel_department FOREIGN KEY (department_id) REFERENCES departments (id) ON DELETE SET NULL
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT ='人员信息';
|
||||
|
||||
-- 物品类别
|
||||
DROP TABLE IF EXISTS categories;
|
||||
CREATE TABLE categories
|
||||
(
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(150) NOT NULL,
|
||||
parent_id BIGINT UNSIGNED,
|
||||
description TEXT,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_categories_parent FOREIGN KEY (parent_id) REFERENCES categories (id) ON DELETE SET NULL
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT ='物品类别';
|
||||
|
||||
-- 物品(物品主表)
|
||||
DROP TABLE IF EXISTS items;
|
||||
CREATE TABLE items
|
||||
(
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
code VARCHAR(100) NOT NULL UNIQUE, -- 物品编号/资产编号
|
||||
name VARCHAR(200) NOT NULL,
|
||||
category_id BIGINT UNSIGNED,
|
||||
model VARCHAR(150),
|
||||
brand VARCHAR(150),
|
||||
location VARCHAR(200),
|
||||
total_quantity INT NOT NULL DEFAULT 0,
|
||||
available_quantity INT NOT NULL DEFAULT 0,
|
||||
unit VARCHAR(30) DEFAULT '件',
|
||||
price DECIMAL(12, 2) DEFAULT NULL,
|
||||
purchase_date DATE DEFAULT NULL,
|
||||
supplier VARCHAR(200) DEFAULT NULL,
|
||||
status VARCHAR(50) DEFAULT 'normal', -- 如 normal/disabled/lost/repair
|
||||
description TEXT,
|
||||
image_path VARCHAR(500),
|
||||
created_by BIGINT UNSIGNED,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_items_category FOREIGN KEY (category_id) REFERENCES categories (id) ON DELETE SET NULL,
|
||||
CONSTRAINT fk_items_creator FOREIGN KEY (created_by) REFERENCES personnel (id) ON DELETE SET NULL,
|
||||
INDEX (name),
|
||||
INDEX (code)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT ='物品基本信息';
|
||||
|
||||
-- 物品库存/流水(每次入库/出库/调整都记录)
|
||||
DROP TABLE IF EXISTS item_transactions;
|
||||
CREATE TABLE item_transactions
|
||||
(
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
item_id BIGINT UNSIGNED NOT NULL,
|
||||
trans_type ENUM ('IN','OUT','ADJUST','TRANSFER') NOT NULL,
|
||||
quantity INT NOT NULL,
|
||||
from_location VARCHAR(200),
|
||||
to_location VARCHAR(200),
|
||||
related_id BIGINT UNSIGNED, -- 可关联采购单/借用记录/调拨单 id
|
||||
operator_id BIGINT UNSIGNED, -- personnel 操作者
|
||||
note TEXT,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_trans_item FOREIGN KEY (item_id) REFERENCES items (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_trans_operator FOREIGN KEY (operator_id) REFERENCES personnel (id) ON DELETE SET NULL,
|
||||
INDEX (item_id),
|
||||
INDEX (trans_type)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT ='物品出入库与调整流水';
|
||||
|
||||
-- 借用记录(借/还)
|
||||
DROP TABLE IF EXISTS borrow_records;
|
||||
CREATE TABLE borrow_records
|
||||
(
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
item_id BIGINT UNSIGNED NOT NULL,
|
||||
borrower_id BIGINT UNSIGNED NOT NULL, -- personnel id
|
||||
quantity INT NOT NULL DEFAULT 1,
|
||||
borrow_date DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
due_date DATETIME DEFAULT NULL,
|
||||
return_date DATETIME DEFAULT NULL,
|
||||
status ENUM ('BORROWED','RETURNED','OVERDUE','CANCELED') NOT NULL DEFAULT 'BORROWED',
|
||||
approver_id BIGINT UNSIGNED DEFAULT NULL,
|
||||
note TEXT,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_borrow_item FOREIGN KEY (item_id) REFERENCES items (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_borrow_borrower FOREIGN KEY (borrower_id) REFERENCES personnel (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_borrow_approver FOREIGN KEY (approver_id) REFERENCES personnel (id) ON DELETE SET NULL,
|
||||
INDEX (borrower_id),
|
||||
INDEX (status)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT ='借用/归还记录';
|
||||
|
||||
-- 备忘/便签
|
||||
DROP TABLE IF EXISTS memos;
|
||||
CREATE TABLE memos
|
||||
(
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
title VARCHAR(200),
|
||||
content TEXT,
|
||||
author_id BIGINT UNSIGNED,
|
||||
related_item_id BIGINT UNSIGNED,
|
||||
is_public TINYINT(1) NOT NULL DEFAULT 0,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_memo_author FOREIGN KEY (author_id) REFERENCES personnel (id) ON DELETE SET NULL,
|
||||
CONSTRAINT fk_memo_item FOREIGN KEY (related_item_id) REFERENCES items (id) ON DELETE SET NULL
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT ='备忘/备注';
|
||||
|
||||
-- 财务记录(采购/报销等)
|
||||
DROP TABLE IF EXISTS finance_records;
|
||||
CREATE TABLE finance_records
|
||||
(
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
record_no VARCHAR(100) UNIQUE,
|
||||
type ENUM ('PURCHASE','REFUND','REPAIR','DEPRECIATION','OTHER') NOT NULL,
|
||||
related_item_id BIGINT UNSIGNED,
|
||||
amount DECIMAL(14, 2) NOT NULL DEFAULT 0.00,
|
||||
currency VARCHAR(10) DEFAULT 'CNY',
|
||||
vendor VARCHAR(200),
|
||||
occurred_at DATETIME,
|
||||
recorded_by BIGINT UNSIGNED,
|
||||
note TEXT,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_finance_item FOREIGN KEY (related_item_id) REFERENCES items (id) ON DELETE SET NULL,
|
||||
CONSTRAINT fk_finance_user FOREIGN KEY (recorded_by) REFERENCES personnel (id) ON DELETE SET NULL,
|
||||
INDEX (record_no)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT ='财务相关记录';
|
||||
|
||||
-- 邮件通知规则/历史
|
||||
DROP TABLE IF EXISTS email_notices;
|
||||
CREATE TABLE email_notices
|
||||
(
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(200),
|
||||
target_emails TEXT, -- 以逗号分隔或 JSON 数组
|
||||
subject VARCHAR(300),
|
||||
body TEXT,
|
||||
enabled TINYINT(1) NOT NULL DEFAULT 1,
|
||||
schedule_cron VARCHAR(100), -- 若使用定时任务
|
||||
last_sent_at DATETIME,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT ='邮件通知规则/历史';
|
||||
|
||||
-- 评价/反馈(evaluation 模块对应)
|
||||
DROP TABLE IF EXISTS evaluations;
|
||||
CREATE TABLE evaluations
|
||||
(
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
related_item_id BIGINT UNSIGNED,
|
||||
evaluator_id BIGINT UNSIGNED,
|
||||
score TINYINT UNSIGNED, -- 1-5
|
||||
comment TEXT,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_evaluation_item FOREIGN KEY (related_item_id) REFERENCES items (id) ON DELETE SET NULL,
|
||||
CONSTRAINT fk_evaluation_user FOREIGN KEY (evaluator_id) REFERENCES personnel (id) ON DELETE SET NULL
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT ='物品/服务评价';
|
||||
|
||||
-- 附件表(文件存储路径)
|
||||
DROP TABLE IF EXISTS attachments;
|
||||
CREATE TABLE attachments
|
||||
(
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
related_table VARCHAR(100), -- 指示关联表,如 'items','memos'
|
||||
related_id BIGINT UNSIGNED, -- 关联记录 ID
|
||||
file_name VARCHAR(300),
|
||||
file_path VARCHAR(1000),
|
||||
file_size BIGINT UNSIGNED,
|
||||
content_type VARCHAR(200),
|
||||
uploaded_by BIGINT UNSIGNED,
|
||||
uploaded_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_attachments_user FOREIGN KEY (uploaded_by) REFERENCES personnel (id) ON DELETE SET NULL,
|
||||
INDEX (related_table, related_id)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT ='文件附件存储索引表';
|
||||
@@ -1,56 +1,39 @@
|
||||
package club.itstudio.itmanager.entity
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.reflect.full.createInstance
|
||||
import kotlin.reflect.full.declaredMemberProperties
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.javaField
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
|
||||
interface DataCopy {
|
||||
|
||||
fun <T : Any> toAnotherObject(
|
||||
toClass: KClass<T>,
|
||||
otherProperties: Map<String, Any?>
|
||||
otherProperties: Map<String, Any?> = emptyMap()
|
||||
): T {
|
||||
try {
|
||||
val voProperties = toClass.declaredMemberProperties
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val sourceProps = this::class.memberProperties
|
||||
.associate { it.name to (it as KProperty1<Any, *>).get(this) }
|
||||
return try {
|
||||
val vo = toClass.createInstance()
|
||||
for (voProperty in voProperties)
|
||||
copyFieldData(voProperty, otherProperties, vo)
|
||||
return vo
|
||||
for (prop in toClass.declaredMemberProperties) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val mutableProp = prop as? KMutableProperty1<Any, Any?> ?: continue
|
||||
val value = when {
|
||||
sourceProps.containsKey(prop.name) -> sourceProps[prop.name]
|
||||
otherProperties.containsKey(prop.name) -> otherProperties[prop.name]
|
||||
else -> continue
|
||||
}
|
||||
mutableProp.isAccessible = true
|
||||
mutableProp.set(vo, value)
|
||||
}
|
||||
vo
|
||||
} catch (e: ReflectiveOperationException) {
|
||||
throw RuntimeException(
|
||||
"${toClass.simpleName} has no fields.",
|
||||
e
|
||||
"Failed to instantiate ${toClass.simpleName}. Does it have a no-arg constructor?", e
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyFieldData(
|
||||
toProperty: KProperty<*>,
|
||||
otherProperties: Map<String, Any?>,
|
||||
another: Any
|
||||
) {
|
||||
try {
|
||||
val thisProperty = this::class.memberProperties
|
||||
.firstOrNull { it.name == toProperty.name }
|
||||
|
||||
val value =
|
||||
if (thisProperty != null) {
|
||||
thisProperty.getter.call(this)
|
||||
} else if (otherProperties.containsKey(toProperty.name))
|
||||
otherProperties[toProperty.name]
|
||||
else
|
||||
throw RuntimeException(
|
||||
"Property ${toProperty.name} not found."
|
||||
)
|
||||
|
||||
val field = toProperty.javaField!!
|
||||
field.isAccessible = true
|
||||
field.set(another, value)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,13 @@ import kotlinx.serialization.Serializable
|
||||
@TableName("account")
|
||||
data class Account(
|
||||
@TableId(type = IdType.AUTO)
|
||||
val id: Int? = null,
|
||||
val id: Long? = null,
|
||||
val username: String = "",
|
||||
val password: String = "",
|
||||
val email: String = "",
|
||||
val role: String = "",
|
||||
val registerTime: LocalDateTime? = null
|
||||
val email: String? = null,
|
||||
val fullName: String? = null,
|
||||
val isActive: Boolean = true,
|
||||
val isStaff: Boolean = false,
|
||||
val createdAt: LocalDateTime? = null,
|
||||
val updatedAt: LocalDateTime? = null
|
||||
) : DataCopy
|
||||
@@ -0,0 +1,23 @@
|
||||
package club.itstudio.itmanager.entity.dto
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType
|
||||
import com.baomidou.mybatisplus.annotation.TableId
|
||||
import com.baomidou.mybatisplus.annotation.TableName
|
||||
import club.itstudio.itmanager.entity.DataCopy
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@TableName("attachments")
|
||||
data class Attachment(
|
||||
@TableId(type = IdType.AUTO)
|
||||
val id: Long? = null,
|
||||
val relatedTable: String? = null,
|
||||
val relatedId: Long? = null,
|
||||
val fileName: String? = null,
|
||||
val filePath: String? = null,
|
||||
val fileSize: Long? = null,
|
||||
val contentType: String? = null,
|
||||
val uploadedBy: Long? = null,
|
||||
val uploadedAt: LocalDateTime? = null
|
||||
) : DataCopy
|
||||
@@ -0,0 +1,26 @@
|
||||
package club.itstudio.itmanager.entity.dto
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType
|
||||
import com.baomidou.mybatisplus.annotation.TableId
|
||||
import com.baomidou.mybatisplus.annotation.TableName
|
||||
import club.itstudio.itmanager.entity.DataCopy
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@TableName("borrow_records")
|
||||
data class BorrowRecord(
|
||||
@TableId(type = IdType.AUTO)
|
||||
val id: Long? = null,
|
||||
val itemId: Long = 0,
|
||||
val borrowerId: Long = 0,
|
||||
val quantity: Int = 1,
|
||||
val borrowDate: LocalDateTime? = null,
|
||||
val dueDate: LocalDateTime? = null,
|
||||
val returnDate: LocalDateTime? = null,
|
||||
val status: String = "BORROWED", // BORROWED / RETURNED / OVERDUE / CANCELED
|
||||
val approverId: Long? = null,
|
||||
val note: String? = null,
|
||||
val createdAt: LocalDateTime? = null,
|
||||
val updatedAt: LocalDateTime? = null
|
||||
) : DataCopy
|
||||
@@ -0,0 +1,20 @@
|
||||
package club.itstudio.itmanager.entity.dto
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType
|
||||
import com.baomidou.mybatisplus.annotation.TableId
|
||||
import com.baomidou.mybatisplus.annotation.TableName
|
||||
import club.itstudio.itmanager.entity.DataCopy
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@TableName("categories")
|
||||
data class Category(
|
||||
@TableId(type = IdType.AUTO)
|
||||
val id: Long? = null,
|
||||
val name: String = "",
|
||||
val parentId: Long? = null,
|
||||
val description: String? = null,
|
||||
val createdAt: LocalDateTime? = null,
|
||||
val updatedAt: LocalDateTime? = null
|
||||
) : DataCopy
|
||||
@@ -0,0 +1,21 @@
|
||||
package club.itstudio.itmanager.entity.dto
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType
|
||||
import com.baomidou.mybatisplus.annotation.TableId
|
||||
import com.baomidou.mybatisplus.annotation.TableName
|
||||
import club.itstudio.itmanager.entity.DataCopy
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@TableName("departments")
|
||||
data class Department(
|
||||
@TableId(type = IdType.AUTO)
|
||||
val id: Long? = null,
|
||||
val name: String = "",
|
||||
val code: String? = null,
|
||||
val parentId: Long? = null,
|
||||
val description: String? = null,
|
||||
val createdAt: LocalDateTime? = null,
|
||||
val updatedAt: LocalDateTime? = null
|
||||
) : DataCopy
|
||||
@@ -0,0 +1,24 @@
|
||||
package club.itstudio.itmanager.entity.dto
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType
|
||||
import com.baomidou.mybatisplus.annotation.TableId
|
||||
import com.baomidou.mybatisplus.annotation.TableName
|
||||
import club.itstudio.itmanager.entity.DataCopy
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@TableName("email_notices")
|
||||
data class EmailNotice(
|
||||
@TableId(type = IdType.AUTO)
|
||||
val id: Long? = null,
|
||||
val name: String? = null,
|
||||
val targetEmails: String? = null,
|
||||
val subject: String? = null,
|
||||
val body: String? = null,
|
||||
val enabled: Boolean = true,
|
||||
val scheduleCron: String? = null,
|
||||
val lastSentAt: LocalDateTime? = null,
|
||||
val createdAt: LocalDateTime? = null,
|
||||
val updatedAt: LocalDateTime? = null
|
||||
) : DataCopy
|
||||
@@ -0,0 +1,20 @@
|
||||
package club.itstudio.itmanager.entity.dto
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType
|
||||
import com.baomidou.mybatisplus.annotation.TableId
|
||||
import com.baomidou.mybatisplus.annotation.TableName
|
||||
import club.itstudio.itmanager.entity.DataCopy
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@TableName("evaluations")
|
||||
data class Evaluation(
|
||||
@TableId(type = IdType.AUTO)
|
||||
val id: Long? = null,
|
||||
val relatedItemId: Long? = null,
|
||||
val evaluatorId: Long? = null,
|
||||
val score: Short? = null, // 1-5
|
||||
val comment: String? = null,
|
||||
val createdAt: LocalDateTime? = null
|
||||
) : DataCopy
|
||||
@@ -0,0 +1,26 @@
|
||||
package club.itstudio.itmanager.entity.dto
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType
|
||||
import com.baomidou.mybatisplus.annotation.TableId
|
||||
import com.baomidou.mybatisplus.annotation.TableName
|
||||
import club.itstudio.itmanager.entity.DataCopy
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.math.BigDecimal
|
||||
|
||||
@Serializable
|
||||
@TableName("finance_records")
|
||||
data class FinanceRecord(
|
||||
@TableId(type = IdType.AUTO)
|
||||
val id: Long? = null,
|
||||
val recordNo: String? = null,
|
||||
val type: String = "", // PURCHASE / REFUND / REPAIR / DEPRECIATION / OTHER
|
||||
val relatedItemId: Long? = null,
|
||||
val amount: BigDecimal = BigDecimal.ZERO,
|
||||
val currency: String = "CNY",
|
||||
val vendor: String? = null,
|
||||
val occurredAt: LocalDateTime? = null,
|
||||
val recordedBy: Long? = null,
|
||||
val note: String? = null,
|
||||
val createdAt: LocalDateTime? = null
|
||||
) : DataCopy
|
||||
@@ -0,0 +1,35 @@
|
||||
package club.itstudio.itmanager.entity.dto
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType
|
||||
import com.baomidou.mybatisplus.annotation.TableId
|
||||
import com.baomidou.mybatisplus.annotation.TableName
|
||||
import club.itstudio.itmanager.entity.DataCopy
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.math.BigDecimal
|
||||
|
||||
@Serializable
|
||||
@TableName("items")
|
||||
data class Item(
|
||||
@TableId(type = IdType.AUTO)
|
||||
val id: Long? = null,
|
||||
val code: String = "",
|
||||
val name: String = "",
|
||||
val categoryId: Long? = null,
|
||||
val model: String? = null,
|
||||
val brand: String? = null,
|
||||
val location: String? = null,
|
||||
val totalQuantity: Int = 0,
|
||||
val availableQuantity: Int = 0,
|
||||
val unit: String = "件",
|
||||
val price: BigDecimal? = null,
|
||||
val purchaseDate: LocalDate? = null,
|
||||
val supplier: String? = null,
|
||||
val status: String = "normal",
|
||||
val description: String? = null,
|
||||
val imagePath: String? = null,
|
||||
val createdBy: Long? = null,
|
||||
val createdAt: LocalDateTime? = null,
|
||||
val updatedAt: LocalDateTime? = null
|
||||
) : DataCopy
|
||||
@@ -0,0 +1,24 @@
|
||||
package club.itstudio.itmanager.entity.dto
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType
|
||||
import com.baomidou.mybatisplus.annotation.TableId
|
||||
import com.baomidou.mybatisplus.annotation.TableName
|
||||
import club.itstudio.itmanager.entity.DataCopy
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@TableName("item_transactions")
|
||||
data class ItemTransaction(
|
||||
@TableId(type = IdType.AUTO)
|
||||
val id: Long? = null,
|
||||
val itemId: Long = 0,
|
||||
val transType: String = "", // IN / OUT / ADJUST / TRANSFER
|
||||
val quantity: Int = 0,
|
||||
val fromLocation: String? = null,
|
||||
val toLocation: String? = null,
|
||||
val relatedId: Long? = null,
|
||||
val operatorId: Long? = null,
|
||||
val note: String? = null,
|
||||
val createdAt: LocalDateTime? = null
|
||||
) : DataCopy
|
||||
@@ -0,0 +1,22 @@
|
||||
package club.itstudio.itmanager.entity.dto
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType
|
||||
import com.baomidou.mybatisplus.annotation.TableId
|
||||
import com.baomidou.mybatisplus.annotation.TableName
|
||||
import club.itstudio.itmanager.entity.DataCopy
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@TableName("memos")
|
||||
data class Memo(
|
||||
@TableId(type = IdType.AUTO)
|
||||
val id: Long? = null,
|
||||
val title: String? = null,
|
||||
val content: String? = null,
|
||||
val authorId: Long? = null,
|
||||
val relatedItemId: Long? = null,
|
||||
val isPublic: Boolean = false,
|
||||
val createdAt: LocalDateTime? = null,
|
||||
val updatedAt: LocalDateTime? = null
|
||||
) : DataCopy
|
||||
@@ -0,0 +1,25 @@
|
||||
package club.itstudio.itmanager.entity.dto
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType
|
||||
import com.baomidou.mybatisplus.annotation.TableId
|
||||
import com.baomidou.mybatisplus.annotation.TableName
|
||||
import club.itstudio.itmanager.entity.DataCopy
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@TableName("personnel")
|
||||
data class Personnel(
|
||||
@TableId(type = IdType.AUTO)
|
||||
val id: Long? = null,
|
||||
val userId: Long? = null,
|
||||
val employeeNo: String? = null,
|
||||
val name: String = "",
|
||||
val departmentId: Long? = null,
|
||||
val phone: String? = null,
|
||||
val email: String? = null,
|
||||
val role: String? = null,
|
||||
val isActive: Boolean = true,
|
||||
val createdAt: LocalDateTime? = null,
|
||||
val updatedAt: LocalDateTime? = null
|
||||
) : DataCopy
|
||||
@@ -0,0 +1,8 @@
|
||||
package club.itstudio.itmanager.mapper
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper
|
||||
import club.itstudio.itmanager.entity.dto.Attachment
|
||||
import org.apache.ibatis.annotations.Mapper
|
||||
|
||||
@Mapper
|
||||
interface AttachmentMapper : BaseMapper<Attachment>
|
||||
@@ -0,0 +1,8 @@
|
||||
package club.itstudio.itmanager.mapper
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper
|
||||
import club.itstudio.itmanager.entity.dto.BorrowRecord
|
||||
import org.apache.ibatis.annotations.Mapper
|
||||
|
||||
@Mapper
|
||||
interface BorrowRecordMapper : BaseMapper<BorrowRecord>
|
||||
@@ -0,0 +1,8 @@
|
||||
package club.itstudio.itmanager.mapper
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper
|
||||
import club.itstudio.itmanager.entity.dto.Category
|
||||
import org.apache.ibatis.annotations.Mapper
|
||||
|
||||
@Mapper
|
||||
interface CategoryMapper : BaseMapper<Category>
|
||||
@@ -0,0 +1,8 @@
|
||||
package club.itstudio.itmanager.mapper
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper
|
||||
import club.itstudio.itmanager.entity.dto.Department
|
||||
import org.apache.ibatis.annotations.Mapper
|
||||
|
||||
@Mapper
|
||||
interface DepartmentMapper : BaseMapper<Department>
|
||||
@@ -0,0 +1,8 @@
|
||||
package club.itstudio.itmanager.mapper
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper
|
||||
import club.itstudio.itmanager.entity.dto.EmailNotice
|
||||
import org.apache.ibatis.annotations.Mapper
|
||||
|
||||
@Mapper
|
||||
interface EmailNoticeMapper : BaseMapper<EmailNotice>
|
||||
@@ -0,0 +1,8 @@
|
||||
package club.itstudio.itmanager.mapper
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper
|
||||
import club.itstudio.itmanager.entity.dto.Evaluation
|
||||
import org.apache.ibatis.annotations.Mapper
|
||||
|
||||
@Mapper
|
||||
interface EvaluationMapper : BaseMapper<Evaluation>
|
||||
@@ -0,0 +1,8 @@
|
||||
package club.itstudio.itmanager.mapper
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper
|
||||
import club.itstudio.itmanager.entity.dto.FinanceRecord
|
||||
import org.apache.ibatis.annotations.Mapper
|
||||
|
||||
@Mapper
|
||||
interface FinanceRecordMapper : BaseMapper<FinanceRecord>
|
||||
@@ -0,0 +1,8 @@
|
||||
package club.itstudio.itmanager.mapper
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper
|
||||
import club.itstudio.itmanager.entity.dto.Item
|
||||
import org.apache.ibatis.annotations.Mapper
|
||||
|
||||
@Mapper
|
||||
interface ItemMapper : BaseMapper<Item>
|
||||
@@ -0,0 +1,8 @@
|
||||
package club.itstudio.itmanager.mapper
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper
|
||||
import club.itstudio.itmanager.entity.dto.ItemTransaction
|
||||
import org.apache.ibatis.annotations.Mapper
|
||||
|
||||
@Mapper
|
||||
interface ItemTransactionMapper : BaseMapper<ItemTransaction>
|
||||
@@ -0,0 +1,8 @@
|
||||
package club.itstudio.itmanager.mapper
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper
|
||||
import club.itstudio.itmanager.entity.dto.Memo
|
||||
import org.apache.ibatis.annotations.Mapper
|
||||
|
||||
@Mapper
|
||||
interface MemoMapper : BaseMapper<Memo>
|
||||
@@ -0,0 +1,8 @@
|
||||
package club.itstudio.itmanager.mapper
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper
|
||||
import club.itstudio.itmanager.entity.dto.Personnel
|
||||
import org.apache.ibatis.annotations.Mapper
|
||||
|
||||
@Mapper
|
||||
interface PersonnelMapper : BaseMapper<Personnel>
|
||||
@@ -0,0 +1,6 @@
|
||||
package club.itstudio.itmanager.service
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService
|
||||
import club.itstudio.itmanager.entity.dto.Attachment
|
||||
|
||||
interface AttachmentService : IService<Attachment>
|
||||
@@ -0,0 +1,6 @@
|
||||
package club.itstudio.itmanager.service
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService
|
||||
import club.itstudio.itmanager.entity.dto.BorrowRecord
|
||||
|
||||
interface BorrowRecordService : IService<BorrowRecord>
|
||||
@@ -0,0 +1,6 @@
|
||||
package club.itstudio.itmanager.service
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService
|
||||
import club.itstudio.itmanager.entity.dto.Category
|
||||
|
||||
interface CategoryService : IService<Category>
|
||||
@@ -0,0 +1,6 @@
|
||||
package club.itstudio.itmanager.service
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService
|
||||
import club.itstudio.itmanager.entity.dto.Department
|
||||
|
||||
interface DepartmentService : IService<Department>
|
||||
@@ -0,0 +1,6 @@
|
||||
package club.itstudio.itmanager.service
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService
|
||||
import club.itstudio.itmanager.entity.dto.EmailNotice
|
||||
|
||||
interface EmailNoticeService : IService<EmailNotice>
|
||||
@@ -0,0 +1,6 @@
|
||||
package club.itstudio.itmanager.service
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService
|
||||
import club.itstudio.itmanager.entity.dto.Evaluation
|
||||
|
||||
interface EvaluationService : IService<Evaluation>
|
||||
@@ -0,0 +1,6 @@
|
||||
package club.itstudio.itmanager.service
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService
|
||||
import club.itstudio.itmanager.entity.dto.FinanceRecord
|
||||
|
||||
interface FinanceRecordService : IService<FinanceRecord>
|
||||
@@ -0,0 +1,6 @@
|
||||
package club.itstudio.itmanager.service
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService
|
||||
import club.itstudio.itmanager.entity.dto.Item
|
||||
|
||||
interface ItemService : IService<Item>
|
||||
@@ -0,0 +1,6 @@
|
||||
package club.itstudio.itmanager.service
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService
|
||||
import club.itstudio.itmanager.entity.dto.ItemTransaction
|
||||
|
||||
interface ItemTransactionService : IService<ItemTransaction>
|
||||
@@ -0,0 +1,6 @@
|
||||
package club.itstudio.itmanager.service
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService
|
||||
import club.itstudio.itmanager.entity.dto.Memo
|
||||
|
||||
interface MemoService : IService<Memo>
|
||||
@@ -0,0 +1,6 @@
|
||||
package club.itstudio.itmanager.service
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService
|
||||
import club.itstudio.itmanager.entity.dto.Personnel
|
||||
|
||||
interface PersonnelService : IService<Personnel>
|
||||
+9
-11
@@ -10,7 +10,7 @@ import club.itstudio.itmanager.entity.vo.response.ReloginVO
|
||||
import club.itstudio.itmanager.mapper.AccountMapper
|
||||
import club.itstudio.itmanager.service.AccountService
|
||||
import club.itstudio.itmanager.utils.Const
|
||||
import club.itstudio.itmanager.utils.DateUtils.getCurrentDateTime
|
||||
|
||||
import club.itstudio.itmanager.utils.FlowUtils
|
||||
import club.itstudio.itmanager.utils.JwtUtils
|
||||
import org.springframework.amqp.core.AmqpTemplate
|
||||
@@ -31,7 +31,6 @@ class AccountServiceImpl(
|
||||
private val amqpTemplate: AmqpTemplate,
|
||||
private val stringRedisTemplate: ReactiveStringRedisTemplate,
|
||||
private val encoder: PasswordEncoder
|
||||
|
||||
) : ServiceImpl<AccountMapper, Account>(), AccountService {
|
||||
|
||||
override fun findByUsername(username: String): Mono<UserDetails> {
|
||||
@@ -40,7 +39,7 @@ class AccountServiceImpl(
|
||||
.map { account ->
|
||||
User.withUsername(username)
|
||||
.password(account.password)
|
||||
.roles(account.role)
|
||||
.roles(if (account.isStaff) "STAFF" else "USER")
|
||||
.build()
|
||||
}
|
||||
}
|
||||
@@ -82,7 +81,7 @@ class AccountServiceImpl(
|
||||
val (email, code, username, password) = vo
|
||||
|
||||
return verifyCode(email, code).flatMap { error ->
|
||||
if (!error.isBlank()) {
|
||||
if (error.isNotBlank()) {
|
||||
return@flatMap Mono.just(error)
|
||||
}
|
||||
|
||||
@@ -98,12 +97,11 @@ class AccountServiceImpl(
|
||||
|
||||
val encodedPassword = encoder.encode(password)
|
||||
val account = Account(
|
||||
null,
|
||||
username,
|
||||
encodedPassword!!,
|
||||
email,
|
||||
"user",
|
||||
getCurrentDateTime()
|
||||
username = username,
|
||||
password = encodedPassword!!,
|
||||
email = email,
|
||||
isActive = true,
|
||||
isStaff = false
|
||||
)
|
||||
|
||||
Mono.fromCallable { this.save(account) }
|
||||
@@ -124,7 +122,7 @@ class AccountServiceImpl(
|
||||
val (email, code, password) = vo
|
||||
|
||||
return verifyCode(email, code).flatMap { error ->
|
||||
if (!error.isBlank()) {
|
||||
if (error.isNotBlank()) {
|
||||
return@flatMap Mono.just(error)
|
||||
}
|
||||
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package club.itstudio.itmanager.service.impl
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
|
||||
import club.itstudio.itmanager.entity.dto.Attachment
|
||||
import club.itstudio.itmanager.mapper.AttachmentMapper
|
||||
import club.itstudio.itmanager.service.AttachmentService
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class AttachmentServiceImpl : ServiceImpl<AttachmentMapper, Attachment>(), AttachmentService
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package club.itstudio.itmanager.service.impl
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
|
||||
import club.itstudio.itmanager.entity.dto.BorrowRecord
|
||||
import club.itstudio.itmanager.mapper.BorrowRecordMapper
|
||||
import club.itstudio.itmanager.service.BorrowRecordService
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class BorrowRecordServiceImpl : ServiceImpl<BorrowRecordMapper, BorrowRecord>(), BorrowRecordService
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package club.itstudio.itmanager.service.impl
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
|
||||
import club.itstudio.itmanager.entity.dto.Category
|
||||
import club.itstudio.itmanager.mapper.CategoryMapper
|
||||
import club.itstudio.itmanager.service.CategoryService
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class CategoryServiceImpl : ServiceImpl<CategoryMapper, Category>(), CategoryService
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package club.itstudio.itmanager.service.impl
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
|
||||
import club.itstudio.itmanager.entity.dto.Department
|
||||
import club.itstudio.itmanager.mapper.DepartmentMapper
|
||||
import club.itstudio.itmanager.service.DepartmentService
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class DepartmentServiceImpl : ServiceImpl<DepartmentMapper, Department>(), DepartmentService
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package club.itstudio.itmanager.service.impl
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
|
||||
import club.itstudio.itmanager.entity.dto.EmailNotice
|
||||
import club.itstudio.itmanager.mapper.EmailNoticeMapper
|
||||
import club.itstudio.itmanager.service.EmailNoticeService
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class EmailNoticeServiceImpl : ServiceImpl<EmailNoticeMapper, EmailNotice>(), EmailNoticeService
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package club.itstudio.itmanager.service.impl
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
|
||||
import club.itstudio.itmanager.entity.dto.Evaluation
|
||||
import club.itstudio.itmanager.mapper.EvaluationMapper
|
||||
import club.itstudio.itmanager.service.EvaluationService
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class EvaluationServiceImpl : ServiceImpl<EvaluationMapper, Evaluation>(), EvaluationService
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package club.itstudio.itmanager.service.impl
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
|
||||
import club.itstudio.itmanager.entity.dto.FinanceRecord
|
||||
import club.itstudio.itmanager.mapper.FinanceRecordMapper
|
||||
import club.itstudio.itmanager.service.FinanceRecordService
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class FinanceRecordServiceImpl : ServiceImpl<FinanceRecordMapper, FinanceRecord>(), FinanceRecordService
|
||||
@@ -0,0 +1,10 @@
|
||||
package club.itstudio.itmanager.service.impl
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
|
||||
import club.itstudio.itmanager.entity.dto.Item
|
||||
import club.itstudio.itmanager.mapper.ItemMapper
|
||||
import club.itstudio.itmanager.service.ItemService
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class ItemServiceImpl : ServiceImpl<ItemMapper, Item>(), ItemService
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package club.itstudio.itmanager.service.impl
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
|
||||
import club.itstudio.itmanager.entity.dto.ItemTransaction
|
||||
import club.itstudio.itmanager.mapper.ItemTransactionMapper
|
||||
import club.itstudio.itmanager.service.ItemTransactionService
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class ItemTransactionServiceImpl : ServiceImpl<ItemTransactionMapper, ItemTransaction>(), ItemTransactionService
|
||||
@@ -0,0 +1,10 @@
|
||||
package club.itstudio.itmanager.service.impl
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
|
||||
import club.itstudio.itmanager.entity.dto.Memo
|
||||
import club.itstudio.itmanager.mapper.MemoMapper
|
||||
import club.itstudio.itmanager.service.MemoService
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class MemoServiceImpl : ServiceImpl<MemoMapper, Memo>(), MemoService
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package club.itstudio.itmanager.service.impl
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
|
||||
import club.itstudio.itmanager.entity.dto.Personnel
|
||||
import club.itstudio.itmanager.mapper.PersonnelMapper
|
||||
import club.itstudio.itmanager.service.PersonnelService
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class PersonnelServiceImpl : ServiceImpl<PersonnelMapper, Personnel>(), PersonnelService
|
||||
@@ -4,13 +4,14 @@ import reactor.core.publisher.Mono
|
||||
|
||||
object Const {
|
||||
const val FLOW_LIMIT_ORDER = -101
|
||||
|
||||
|
||||
const val JWT_BLACK_LIST = "jwt:blacklist:"
|
||||
const val VERIFY_EMAIL_LIMIT = "verify:email:limit:"
|
||||
const val VERIFY_EMAIL_DATA = "verify:email:data:"
|
||||
|
||||
const val FLOW_LIMIT_COUNTER = "flow:counter:"
|
||||
const val FLOW_LIMIT_BLOCK = "flow:block:"
|
||||
|
||||
val INTERNAL_ERROR_MONO = Mono.just("something went wrong. Please contact the administrator.")
|
||||
|
||||
const val INTERNAL_ERROR_STR = "something went wrong. Please contact the administrator."
|
||||
val INTERNAL_ERROR_MONO = Mono.just(INTERNAL_ERROR_STR)
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import com.auth0.jwt.JWT
|
||||
import com.auth0.jwt.JWTVerifier
|
||||
import com.auth0.jwt.algorithms.Algorithm
|
||||
import com.auth0.jwt.interfaces.DecodedJWT
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.data.redis.core.StringRedisTemplate
|
||||
import org.springframework.security.core.userdetails.User
|
||||
@@ -16,14 +17,15 @@ import java.util.concurrent.TimeUnit
|
||||
class JwtUtils(
|
||||
@param:Value($$"${spring.security.jwt.key}")
|
||||
private val key: String,
|
||||
|
||||
@param:Value($$"${spring.security.jwt.expire-hours}")
|
||||
private val expireHours: Int,
|
||||
|
||||
private val template: StringRedisTemplate,
|
||||
private val algorithm: Algorithm = Algorithm.HMAC256(key),
|
||||
private val jwtVerifier: JWTVerifier = JWT.require(algorithm).build()
|
||||
private val template: StringRedisTemplate
|
||||
) {
|
||||
private val algorithm: Algorithm = Algorithm.HMAC256(key)
|
||||
private val jwtVerifier: JWTVerifier = JWT.require(algorithm).build()
|
||||
private val logger = LoggerFactory.getLogger(this::class.java)
|
||||
|
||||
fun invalidateJwt(headerToken: String?): Boolean {
|
||||
val token = this.convertToToken(headerToken) ?: return false
|
||||
try {
|
||||
@@ -31,7 +33,7 @@ class JwtUtils(
|
||||
val id = jwt.id
|
||||
return deleteToken(id, jwt.expiresAt)
|
||||
} catch (e: Exception) {
|
||||
println(e.message)
|
||||
logger.error("Error occurred while invalidating JWT", e)
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -62,14 +64,14 @@ class JwtUtils(
|
||||
else decodedJWT
|
||||
|
||||
} catch (e: Exception) {
|
||||
println(e.message)
|
||||
logger.error("Error occurred while resolving JWT", e)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun createJwt(
|
||||
details: UserDetails,
|
||||
id: Int,
|
||||
id: Long,
|
||||
username: String
|
||||
): String {
|
||||
return JWT.create()
|
||||
@@ -94,7 +96,7 @@ class JwtUtils(
|
||||
.build()
|
||||
}
|
||||
|
||||
fun toId(jwt: DecodedJWT) = jwt.claims["id"]?.asInt() ?: -1
|
||||
fun toId(jwt: DecodedJWT) = jwt.claims["id"]?.asLong() ?: -1L
|
||||
|
||||
fun expiresTime(): Date {
|
||||
val cal = Calendar.getInstance()
|
||||
|
||||
Reference in New Issue
Block a user