Compare commits
3 Commits
Author | SHA1 | Date |
---|---|---|
|
65672708be | |
|
91b6deeb0d | |
|
a4876971a4 |
|
@ -3,8 +3,7 @@
|
||||||
VITE_API_PREFIX = '/dev-api'
|
VITE_API_PREFIX = '/dev-api'
|
||||||
|
|
||||||
# 接口地址
|
# 接口地址
|
||||||
# VITE_API_BASE_URL = 'http://pms.dtyx.net:9158/'
|
VITE_API_BASE_URL = 'http://pms.dtyx.net:9158/'
|
||||||
VITE_API_BASE_URL = 'http://localhost:8888/'
|
|
||||||
|
|
||||||
# 接口地址 (WebSocket)
|
# 接口地址 (WebSocket)
|
||||||
VITE_API_WS_URL = 'ws://localhost:8000'
|
VITE_API_WS_URL = 'ws://localhost:8000'
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
node_modules
|
|
|
@ -1,91 +0,0 @@
|
||||||
# 制度类型搜索接口实现指南
|
|
||||||
|
|
||||||
## 接口定义
|
|
||||||
|
|
||||||
### 请求接口
|
|
||||||
```
|
|
||||||
GET /api/regulation/types
|
|
||||||
Content-Type: application/json
|
|
||||||
```
|
|
||||||
|
|
||||||
### 请求参数
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"page": number, // 页码(可选,默认1)
|
|
||||||
"size": number, // 每页大小(可选,默认10)
|
|
||||||
"typeName": "string", // 类型名称(模糊搜索,可选)
|
|
||||||
"status": "string", // 状态筛选("1"启用,"0"禁用,可选)
|
|
||||||
"remark": "string" // 备注内容(模糊搜索,可选)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 响应格式
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"message": "success",
|
|
||||||
"data": {
|
|
||||||
"records": [
|
|
||||||
{
|
|
||||||
"typeId": "string",
|
|
||||||
"typeName": "string",
|
|
||||||
"sortOrder": number,
|
|
||||||
"isEnabled": "string",
|
|
||||||
"remark": "string",
|
|
||||||
"createBy": "string",
|
|
||||||
"createTime": "string",
|
|
||||||
"updateBy": "string",
|
|
||||||
"updateTime": "string",
|
|
||||||
"delFlag": "string"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"total": number, // 总记录数
|
|
||||||
"current": number, // 当前页码
|
|
||||||
"size": number, // 每页大小
|
|
||||||
"pages": number // 总页数
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 后端实现说明
|
|
||||||
|
|
||||||
后端已实现以下接口:
|
|
||||||
```java
|
|
||||||
@ApiOperation(value = "获取制度类型列表", httpMethod = "GET")
|
|
||||||
@GetMapping
|
|
||||||
public Result getRegulationTypes(
|
|
||||||
@RequestParam(defaultValue = "1") int page,
|
|
||||||
@RequestParam(defaultValue = "10") int size,
|
|
||||||
@RequestParam(required = false) String typeName,
|
|
||||||
@RequestParam(required = false) String status,
|
|
||||||
@RequestParam(required = false) String remark
|
|
||||||
) {
|
|
||||||
return regulationTypeService.getRegulationTypes(page, size, typeName, status, remark);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 前端集成说明
|
|
||||||
|
|
||||||
前端已完成以下功能:
|
|
||||||
1. ✅ 调整为GET请求接口
|
|
||||||
2. ✅ 参数名匹配后端接口(isEnabled → status)
|
|
||||||
3. ✅ 移除排序参数(后端不支持)
|
|
||||||
4. ✅ 简化搜索表单,只支持手动搜索
|
|
||||||
5. ✅ 保持原有功能不受影响
|
|
||||||
|
|
||||||
## 搜索流程
|
|
||||||
|
|
||||||
1. 用户在搜索表单中输入条件
|
|
||||||
2. 点击"搜索"按钮触发搜索
|
|
||||||
3. 调用后端GET接口 `/api/regulation/types`
|
|
||||||
4. 后端返回搜索结果
|
|
||||||
5. 前端展示搜索结果
|
|
||||||
|
|
||||||
## 参数说明
|
|
||||||
|
|
||||||
- **page**: 页码,默认1
|
|
||||||
- **size**: 每页大小,默认10
|
|
||||||
- **typeName**: 类型名称,支持模糊搜索
|
|
||||||
- **status**: 状态筛选,"1"表示启用,"0"表示禁用
|
|
||||||
- **remark**: 备注内容,支持模糊搜索
|
|
||||||
|
|
|
@ -1,125 +0,0 @@
|
||||||
# 制度公告搜索接口实现指南
|
|
||||||
|
|
||||||
## 接口定义
|
|
||||||
|
|
||||||
### 请求接口
|
|
||||||
```
|
|
||||||
GET /api/regulation
|
|
||||||
Content-Type: application/json
|
|
||||||
```
|
|
||||||
|
|
||||||
### 请求参数
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"page": number, // 页码(可选,默认1)
|
|
||||||
"size": number, // 每页大小(可选,默认10)
|
|
||||||
"status": "string", // 状态筛选(精确匹配,固定为"PUBLISHED")
|
|
||||||
"title": "string", // 制度标题(模糊搜索,可选)
|
|
||||||
"proposer": "string", // 公示人(模糊搜索,可选)
|
|
||||||
"confirmStatus": "string" // 确认状态(精确匹配,可选)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 响应格式
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"message": "success",
|
|
||||||
"data": {
|
|
||||||
"records": [
|
|
||||||
{
|
|
||||||
"regulationId": "string",
|
|
||||||
"title": "string",
|
|
||||||
"content": "string",
|
|
||||||
"regulationType": "string",
|
|
||||||
"status": "string",
|
|
||||||
"publishTime": "string",
|
|
||||||
"effectiveTime": "string",
|
|
||||||
"expireTime": "string",
|
|
||||||
"scope": "string",
|
|
||||||
"level": "string",
|
|
||||||
"version": "string",
|
|
||||||
"remark": "string",
|
|
||||||
"createBy": "string",
|
|
||||||
"updateBy": "string",
|
|
||||||
"createTime": "string",
|
|
||||||
"updateTime": "string",
|
|
||||||
"delFlag": "string",
|
|
||||||
"confirmStatus": "string"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"total": number, // 总记录数
|
|
||||||
"current": number, // 当前页码
|
|
||||||
"size": number, // 每页大小
|
|
||||||
"pages": number // 总页数
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 后端实现说明
|
|
||||||
|
|
||||||
后端已实现以下接口:
|
|
||||||
```java
|
|
||||||
@ApiOperation(value = "获取制度列表", httpMethod = "GET")
|
|
||||||
@GetMapping
|
|
||||||
public Result getRegulationList(
|
|
||||||
@RequestParam(defaultValue = "1") int page,
|
|
||||||
@RequestParam(defaultValue = "10") int size,
|
|
||||||
@RequestParam(required = false) String status,
|
|
||||||
@RequestParam(required = false) String type,
|
|
||||||
@RequestParam(required = false) String title,
|
|
||||||
@RequestParam(required = false) String proposer,
|
|
||||||
@RequestParam(required = false) String confirmStatus
|
|
||||||
) {
|
|
||||||
return regulationService.getRegulationList(page, size, status, type, title, proposer, confirmStatus);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 前端集成说明
|
|
||||||
|
|
||||||
前端已完成以下功能:
|
|
||||||
1. ✅ 删除前端搜索逻辑(防抖、实时搜索等)
|
|
||||||
2. ✅ 调整为GET请求接口
|
|
||||||
3. ✅ 参数名匹配后端接口(createByName → proposer)
|
|
||||||
4. ✅ 简化搜索表单,只支持手动搜索
|
|
||||||
5. ✅ 移除前端过滤逻辑,由后端处理状态筛选
|
|
||||||
6. ✅ 保持原有功能不受影响
|
|
||||||
|
|
||||||
## 搜索流程
|
|
||||||
|
|
||||||
1. 用户在搜索表单中输入条件
|
|
||||||
2. 点击"搜索"按钮触发搜索
|
|
||||||
3. 调用后端GET接口 `/api/regulation`
|
|
||||||
4. 后端返回搜索结果(已过滤为PUBLISHED状态的制度)
|
|
||||||
5. 前端展示搜索结果
|
|
||||||
|
|
||||||
## 参数说明
|
|
||||||
|
|
||||||
- **page**: 页码,默认1
|
|
||||||
- **size**: 每页大小,默认10
|
|
||||||
- **status**: 状态筛选,固定为"PUBLISHED"(已公告状态)
|
|
||||||
- **title**: 制度标题,支持模糊搜索
|
|
||||||
- **proposer**: 公示人,支持模糊搜索
|
|
||||||
- **confirmStatus**: 确认状态,精确匹配(如:confirmed、pending)
|
|
||||||
|
|
||||||
## 搜索功能特性
|
|
||||||
|
|
||||||
- **模糊搜索**:title 和 proposer 字段支持模糊匹配
|
|
||||||
- **精确筛选**:confirmStatus 字段精确匹配
|
|
||||||
- **分页查询**:支持分页和排序
|
|
||||||
- **状态过滤**:后端自动过滤为PUBLISHED状态的制度
|
|
||||||
- **性能优化**:使用数据库索引提升查询性能
|
|
||||||
|
|
||||||
## 业务逻辑说明
|
|
||||||
|
|
||||||
制度公告页面专门用于展示已经公告的制度,因此:
|
|
||||||
- 后端需要自动过滤为 `status = 'PUBLISHED'` 的制度
|
|
||||||
- 支持按确认状态(confirmStatus)进行筛选
|
|
||||||
- 前端不再需要手动过滤,完全依赖后端处理
|
|
||||||
- 用户可以查看制度详情、下载PDF文件、确认知晓制度
|
|
||||||
|
|
||||||
## 确认状态说明
|
|
||||||
|
|
||||||
- **confirmed**: 已确认 - 用户已确认知晓并遵守该制度
|
|
||||||
- **pending**: 待确认 - 用户尚未确认知晓该制度
|
|
||||||
- 空值: 全部 - 显示所有确认状态的制度
|
|
|
@ -1,117 +0,0 @@
|
||||||
# 制度公示搜索接口实现指南
|
|
||||||
|
|
||||||
## 接口定义
|
|
||||||
|
|
||||||
### 请求接口
|
|
||||||
```
|
|
||||||
GET /api/regulation
|
|
||||||
Content-Type: application/json
|
|
||||||
```
|
|
||||||
|
|
||||||
### 请求参数
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"page": number, // 页码(可选,默认1)
|
|
||||||
"size": number, // 每页大小(可选,默认10)
|
|
||||||
"status": "string", // 状态筛选(精确匹配,可选)
|
|
||||||
"type": "string", // 提案类型(精确匹配,可选)
|
|
||||||
"title": "string", // 提案标题(模糊搜索,可选)
|
|
||||||
"proposer": "string" // 提案人(模糊搜索,可选)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 响应格式
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"message": "success",
|
|
||||||
"data": {
|
|
||||||
"records": [
|
|
||||||
{
|
|
||||||
"regulationId": "string",
|
|
||||||
"title": "string",
|
|
||||||
"content": "string",
|
|
||||||
"regulationType": "string",
|
|
||||||
"status": "string",
|
|
||||||
"publishTime": "string",
|
|
||||||
"effectiveTime": "string",
|
|
||||||
"expireTime": "string",
|
|
||||||
"scope": "string",
|
|
||||||
"level": "string",
|
|
||||||
"version": "string",
|
|
||||||
"remark": "string",
|
|
||||||
"createBy": "string",
|
|
||||||
"updateBy": "string",
|
|
||||||
"createTime": "string",
|
|
||||||
"updateTime": "string",
|
|
||||||
"delFlag": "string",
|
|
||||||
"confirmStatus": "string"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"total": number, // 总记录数
|
|
||||||
"current": number, // 当前页码
|
|
||||||
"size": number, // 每页大小
|
|
||||||
"pages": number // 总页数
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 后端实现说明
|
|
||||||
|
|
||||||
后端已实现以下接口:
|
|
||||||
```java
|
|
||||||
@ApiOperation(value = "获取制度列表", httpMethod = "GET")
|
|
||||||
@GetMapping
|
|
||||||
public Result getRegulationList(
|
|
||||||
@RequestParam(defaultValue = "1") int page,
|
|
||||||
@RequestParam(defaultValue = "10") int size,
|
|
||||||
@RequestParam(required = false) String status,
|
|
||||||
@RequestParam(required = false) String type,
|
|
||||||
@RequestParam(required = false) String title,
|
|
||||||
@RequestParam(required = false) String proposer
|
|
||||||
) {
|
|
||||||
return regulationService.getRegulationList(page, size, status, type, title, proposer);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 前端集成说明
|
|
||||||
|
|
||||||
前端已完成以下功能:
|
|
||||||
1. ✅ 删除前端搜索逻辑(防抖、实时搜索等)
|
|
||||||
2. ✅ 调整为GET请求接口
|
|
||||||
3. ✅ 参数名匹配后端接口(createByName → proposer, regulationType → type)
|
|
||||||
4. ✅ 简化搜索表单,只支持手动搜索
|
|
||||||
5. ✅ 移除前端过滤逻辑,由后端处理状态筛选
|
|
||||||
6. ✅ 保持原有功能不受影响
|
|
||||||
|
|
||||||
## 搜索流程
|
|
||||||
|
|
||||||
1. 用户在搜索表单中输入条件
|
|
||||||
2. 点击"搜索"按钮触发搜索
|
|
||||||
3. 调用后端GET接口 `/api/regulation`
|
|
||||||
4. 后端返回搜索结果(已过滤掉草稿状态的提案)
|
|
||||||
5. 前端展示搜索结果
|
|
||||||
|
|
||||||
## 参数说明
|
|
||||||
|
|
||||||
- **page**: 页码,默认1
|
|
||||||
- **size**: 每页大小,默认10
|
|
||||||
- **status**: 状态筛选,精确匹配(如:PUBLISHED、APPROVED等)
|
|
||||||
- **type**: 提案类型,精确匹配(如:管理规范、操作流程、安全制度、其他)
|
|
||||||
- **title**: 提案标题,支持模糊搜索
|
|
||||||
- **proposer**: 提案人,支持模糊搜索
|
|
||||||
|
|
||||||
## 搜索功能特性
|
|
||||||
|
|
||||||
- **模糊搜索**:title 和 proposer 字段支持模糊匹配
|
|
||||||
- **精确筛选**:type 和 status 字段精确匹配
|
|
||||||
- **分页查询**:支持分页和排序
|
|
||||||
- **状态过滤**:后端自动过滤掉草稿状态的提案,只显示已公示及以上的提案
|
|
||||||
- **性能优化**:使用数据库索引提升查询性能
|
|
||||||
|
|
||||||
## 业务逻辑说明
|
|
||||||
|
|
||||||
制度公示页面专门用于展示已经公示或已通过的制度提案,因此:
|
|
||||||
- 后端需要自动过滤掉 `status = 'DRAFT'` 的提案
|
|
||||||
- 只返回 `status = 'PUBLISHED'` 或 `status = 'APPROVED'` 的提案
|
|
||||||
- 前端不再需要手动过滤,完全依赖后端处理
|
|
|
@ -1,108 +0,0 @@
|
||||||
# 制度提案搜索接口实现指南
|
|
||||||
|
|
||||||
## 接口定义
|
|
||||||
|
|
||||||
### 请求接口
|
|
||||||
```
|
|
||||||
GET /api/regulation
|
|
||||||
Content-Type: application/json
|
|
||||||
```
|
|
||||||
|
|
||||||
### 请求参数
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"page": number, // 页码(可选,默认1)
|
|
||||||
"size": number, // 每页大小(可选,默认10)
|
|
||||||
"status": "string", // 状态筛选(精确匹配,可选)
|
|
||||||
"type": "string", // 提案类型(精确匹配,可选)
|
|
||||||
"title": "string", // 提案标题(模糊搜索,可选)
|
|
||||||
"proposer": "string" // 提案人(模糊搜索,可选)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 响应格式
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"message": "success",
|
|
||||||
"data": {
|
|
||||||
"records": [
|
|
||||||
{
|
|
||||||
"regulationId": "string",
|
|
||||||
"title": "string",
|
|
||||||
"content": "string",
|
|
||||||
"regulationType": "string",
|
|
||||||
"status": "string",
|
|
||||||
"publishTime": "string",
|
|
||||||
"effectiveTime": "string",
|
|
||||||
"expireTime": "string",
|
|
||||||
"scope": "string",
|
|
||||||
"level": "string",
|
|
||||||
"version": "string",
|
|
||||||
"remark": "string",
|
|
||||||
"createBy": "string",
|
|
||||||
"updateBy": "string",
|
|
||||||
"createTime": "string",
|
|
||||||
"updateTime": "string",
|
|
||||||
"delFlag": "string",
|
|
||||||
"confirmStatus": "string"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"total": number, // 总记录数
|
|
||||||
"current": number, // 当前页码
|
|
||||||
"size": number, // 每页大小
|
|
||||||
"pages": number // 总页数
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 后端实现说明
|
|
||||||
|
|
||||||
后端已实现以下接口:
|
|
||||||
```java
|
|
||||||
@ApiOperation(value = "获取制度列表", httpMethod = "GET")
|
|
||||||
@GetMapping
|
|
||||||
public Result getRegulationList(
|
|
||||||
@RequestParam(defaultValue = "1") int page,
|
|
||||||
@RequestParam(defaultValue = "10") int size,
|
|
||||||
@RequestParam(required = false) String status,
|
|
||||||
@RequestParam(required = false) String type,
|
|
||||||
@RequestParam(required = false) String title,
|
|
||||||
@RequestParam(required = false) String proposer
|
|
||||||
) {
|
|
||||||
return regulationService.getRegulationList(page, size, status, type, title, proposer);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 前端集成说明
|
|
||||||
|
|
||||||
前端已完成以下功能:
|
|
||||||
1. ✅ 删除前端搜索逻辑(防抖、实时搜索等)
|
|
||||||
2. ✅ 调整为GET请求接口
|
|
||||||
3. ✅ 参数名匹配后端接口(createByName → proposer, regulationType → type)
|
|
||||||
4. ✅ 简化搜索表单,只支持手动搜索
|
|
||||||
5. ✅ 保持原有功能不受影响
|
|
||||||
|
|
||||||
## 搜索流程
|
|
||||||
|
|
||||||
1. 用户在搜索表单中输入条件
|
|
||||||
2. 点击"搜索"按钮触发搜索
|
|
||||||
3. 调用后端GET接口 `/api/regulation`
|
|
||||||
4. 后端返回搜索结果
|
|
||||||
5. 前端展示搜索结果
|
|
||||||
|
|
||||||
## 参数说明
|
|
||||||
|
|
||||||
- **page**: 页码,默认1
|
|
||||||
- **size**: 每页大小,默认10
|
|
||||||
- **status**: 状态筛选,精确匹配(如:DRAFT、PUBLISHED、APPROVED等)
|
|
||||||
- **type**: 提案类型,精确匹配(如:管理规范、操作流程、安全制度、其他)
|
|
||||||
- **title**: 提案标题,支持模糊搜索
|
|
||||||
- **proposer**: 提案人,支持模糊搜索
|
|
||||||
|
|
||||||
## 搜索功能特性
|
|
||||||
|
|
||||||
- **模糊搜索**:title 和 proposer 字段支持模糊匹配
|
|
||||||
- **精确筛选**:type 和 status 字段精确匹配
|
|
||||||
- **分页查询**:支持分页和排序
|
|
||||||
- **性能优化**:使用数据库索引提升查询性能
|
|
File diff suppressed because it is too large
Load Diff
|
@ -34,9 +34,7 @@
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"dayjs": "^1.11.4",
|
"dayjs": "^1.11.4",
|
||||||
"echarts": "^5.4.2",
|
"echarts": "^5.4.2",
|
||||||
"html2canvas": "^1.4.1",
|
|
||||||
"jsencrypt": "^3.3.2",
|
"jsencrypt": "^3.3.2",
|
||||||
"jspdf": "^3.0.1",
|
|
||||||
"lint-staged": "^15.2.10",
|
"lint-staged": "^15.2.10",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"mitt": "^3.0.0",
|
"mitt": "^3.0.0",
|
||||||
|
|
152
pnpm-lock.yaml
152
pnpm-lock.yaml
|
@ -68,15 +68,9 @@ importers:
|
||||||
echarts:
|
echarts:
|
||||||
specifier: ^5.4.2
|
specifier: ^5.4.2
|
||||||
version: 5.5.0
|
version: 5.5.0
|
||||||
html2canvas:
|
|
||||||
specifier: ^1.4.1
|
|
||||||
version: 1.4.1
|
|
||||||
jsencrypt:
|
jsencrypt:
|
||||||
specifier: ^3.3.2
|
specifier: ^3.3.2
|
||||||
version: 3.3.2
|
version: 3.3.2
|
||||||
jspdf:
|
|
||||||
specifier: ^3.0.1
|
|
||||||
version: 3.0.1
|
|
||||||
lint-staged:
|
lint-staged:
|
||||||
specifier: ^15.2.10
|
specifier: ^15.2.10
|
||||||
version: 15.2.10
|
version: 15.2.10
|
||||||
|
@ -469,10 +463,6 @@ packages:
|
||||||
resolution: {integrity: sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==}
|
resolution: {integrity: sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
'@babel/runtime@7.28.2':
|
|
||||||
resolution: {integrity: sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==}
|
|
||||||
engines: {node: '>=6.9.0'}
|
|
||||||
|
|
||||||
'@babel/template@7.24.0':
|
'@babel/template@7.24.0':
|
||||||
resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==}
|
resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
@ -1202,18 +1192,12 @@ packages:
|
||||||
resolution: {integrity: sha512-yuIv/WRffRzL7cBW+sla4HwBZrEXRNf1MKQ5SklPEadth+BKbDxiVG8A3iISN5B3yC4EeSCzMZP8llHTcUhOzQ==}
|
resolution: {integrity: sha512-yuIv/WRffRzL7cBW+sla4HwBZrEXRNf1MKQ5SklPEadth+BKbDxiVG8A3iISN5B3yC4EeSCzMZP8llHTcUhOzQ==}
|
||||||
deprecated: This is a stub types definition. query-string provides its own type definitions, so you do not need this installed.
|
deprecated: This is a stub types definition. query-string provides its own type definitions, so you do not need this installed.
|
||||||
|
|
||||||
'@types/raf@3.4.3':
|
|
||||||
resolution: {integrity: sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==}
|
|
||||||
|
|
||||||
'@types/sortablejs@1.15.8':
|
'@types/sortablejs@1.15.8':
|
||||||
resolution: {integrity: sha512-b79830lW+RZfwaztgs1aVPgbasJ8e7AXtZYHTELNXZPsERt4ymJdjV4OccDbHQAvHrCcFpbF78jkm0R6h/pZVg==}
|
resolution: {integrity: sha512-b79830lW+RZfwaztgs1aVPgbasJ8e7AXtZYHTELNXZPsERt4ymJdjV4OccDbHQAvHrCcFpbF78jkm0R6h/pZVg==}
|
||||||
|
|
||||||
'@types/svgo@2.6.4':
|
'@types/svgo@2.6.4':
|
||||||
resolution: {integrity: sha512-l4cmyPEckf8moNYHdJ+4wkHvFxjyW6ulm9l4YGaOxeyBWPhBOT0gvni1InpFPdzx1dKf/2s62qGITwxNWnPQng==}
|
resolution: {integrity: sha512-l4cmyPEckf8moNYHdJ+4wkHvFxjyW6ulm9l4YGaOxeyBWPhBOT0gvni1InpFPdzx1dKf/2s62qGITwxNWnPQng==}
|
||||||
|
|
||||||
'@types/trusted-types@2.0.7':
|
|
||||||
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
|
|
||||||
|
|
||||||
'@types/unist@2.0.10':
|
'@types/unist@2.0.10':
|
||||||
resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==}
|
resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==}
|
||||||
|
|
||||||
|
@ -1624,10 +1608,6 @@ packages:
|
||||||
balanced-match@1.0.2:
|
balanced-match@1.0.2:
|
||||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||||
|
|
||||||
base64-arraybuffer@1.0.2:
|
|
||||||
resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==}
|
|
||||||
engines: {node: '>= 0.6.0'}
|
|
||||||
|
|
||||||
base@0.11.2:
|
base@0.11.2:
|
||||||
resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==}
|
resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
@ -1672,11 +1652,6 @@ packages:
|
||||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
btoa@1.2.1:
|
|
||||||
resolution: {integrity: sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==}
|
|
||||||
engines: {node: '>= 0.4.0'}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
buffer-from@1.1.2:
|
buffer-from@1.1.2:
|
||||||
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
||||||
|
|
||||||
|
@ -1717,10 +1692,6 @@ packages:
|
||||||
caniuse-lite@1.0.30001620:
|
caniuse-lite@1.0.30001620:
|
||||||
resolution: {integrity: sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew==}
|
resolution: {integrity: sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew==}
|
||||||
|
|
||||||
canvg@3.0.11:
|
|
||||||
resolution: {integrity: sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==}
|
|
||||||
engines: {node: '>=10.0.0'}
|
|
||||||
|
|
||||||
capital-case@1.0.4:
|
capital-case@1.0.4:
|
||||||
resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==}
|
resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==}
|
||||||
|
|
||||||
|
@ -1912,9 +1883,6 @@ packages:
|
||||||
crypto-js@4.2.0:
|
crypto-js@4.2.0:
|
||||||
resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
|
resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
|
||||||
|
|
||||||
css-line-break@2.1.0:
|
|
||||||
resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==}
|
|
||||||
|
|
||||||
css-select@4.3.0:
|
css-select@4.3.0:
|
||||||
resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==}
|
resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==}
|
||||||
|
|
||||||
|
@ -2091,9 +2059,6 @@ packages:
|
||||||
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
|
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
|
||||||
engines: {node: '>= 4'}
|
engines: {node: '>= 4'}
|
||||||
|
|
||||||
dompurify@3.2.6:
|
|
||||||
resolution: {integrity: sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==}
|
|
||||||
|
|
||||||
domutils@1.7.0:
|
domutils@1.7.0:
|
||||||
resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==}
|
resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==}
|
||||||
|
|
||||||
|
@ -2647,9 +2612,6 @@ packages:
|
||||||
fastq@1.17.1:
|
fastq@1.17.1:
|
||||||
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
|
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
|
||||||
|
|
||||||
fflate@0.8.2:
|
|
||||||
resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==}
|
|
||||||
|
|
||||||
file-entry-cache@8.0.0:
|
file-entry-cache@8.0.0:
|
||||||
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
|
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
|
||||||
engines: {node: '>=16.0.0'}
|
engines: {node: '>=16.0.0'}
|
||||||
|
@ -2903,10 +2865,6 @@ packages:
|
||||||
resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==}
|
resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
html2canvas@1.4.1:
|
|
||||||
resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==}
|
|
||||||
engines: {node: '>=8.0.0'}
|
|
||||||
|
|
||||||
htmlparser2@3.10.1:
|
htmlparser2@3.10.1:
|
||||||
resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==}
|
resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==}
|
||||||
|
|
||||||
|
@ -3210,9 +3168,6 @@ packages:
|
||||||
jsonfile@6.1.0:
|
jsonfile@6.1.0:
|
||||||
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
|
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
|
||||||
|
|
||||||
jspdf@3.0.1:
|
|
||||||
resolution: {integrity: sha512-qaGIxqxetdoNnFQQXxTKUD9/Z7AloLaw94fFsOiJMxbfYdBbrBuhWmbzI8TVjrw7s3jBY1PFHofBKMV/wZPapg==}
|
|
||||||
|
|
||||||
keyv@4.5.4:
|
keyv@4.5.4:
|
||||||
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
||||||
|
|
||||||
|
@ -3678,9 +3633,6 @@ packages:
|
||||||
perfect-debounce@1.0.0:
|
perfect-debounce@1.0.0:
|
||||||
resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
|
resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
|
||||||
|
|
||||||
performance-now@2.1.0:
|
|
||||||
resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
|
|
||||||
|
|
||||||
picocolors@1.0.1:
|
picocolors@1.0.1:
|
||||||
resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
|
resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
|
||||||
|
|
||||||
|
@ -3862,9 +3814,6 @@ packages:
|
||||||
queue-microtask@1.2.3:
|
queue-microtask@1.2.3:
|
||||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||||
|
|
||||||
raf@3.4.1:
|
|
||||||
resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==}
|
|
||||||
|
|
||||||
randombytes@2.1.0:
|
randombytes@2.1.0:
|
||||||
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
||||||
|
|
||||||
|
@ -3888,9 +3837,6 @@ packages:
|
||||||
resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==}
|
resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==}
|
||||||
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
|
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
|
||||||
|
|
||||||
regenerator-runtime@0.13.11:
|
|
||||||
resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
|
|
||||||
|
|
||||||
regenerator-runtime@0.14.1:
|
regenerator-runtime@0.14.1:
|
||||||
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
|
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
|
||||||
|
|
||||||
|
@ -3965,10 +3911,6 @@ packages:
|
||||||
rfdc@1.4.1:
|
rfdc@1.4.1:
|
||||||
resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
|
resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
|
||||||
|
|
||||||
rgbcolor@1.0.1:
|
|
||||||
resolution: {integrity: sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==}
|
|
||||||
engines: {node: '>= 0.8.15'}
|
|
||||||
|
|
||||||
rollup@4.17.2:
|
rollup@4.17.2:
|
||||||
resolution: {integrity: sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==}
|
resolution: {integrity: sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==}
|
||||||
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||||
|
@ -4196,10 +4138,6 @@ packages:
|
||||||
resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==}
|
resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==}
|
||||||
deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility'
|
deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility'
|
||||||
|
|
||||||
stackblur-canvas@2.7.0:
|
|
||||||
resolution: {integrity: sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==}
|
|
||||||
engines: {node: '>=0.1.14'}
|
|
||||||
|
|
||||||
static-extend@0.1.2:
|
static-extend@0.1.2:
|
||||||
resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==}
|
resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
@ -4299,10 +4237,6 @@ packages:
|
||||||
svg-baker@1.7.0:
|
svg-baker@1.7.0:
|
||||||
resolution: {integrity: sha512-nibslMbkXOIkqKVrfcncwha45f97fGuAOn1G99YwnwTj8kF9YiM6XexPcUso97NxOm6GsP0SIvYVIosBis1xLg==}
|
resolution: {integrity: sha512-nibslMbkXOIkqKVrfcncwha45f97fGuAOn1G99YwnwTj8kF9YiM6XexPcUso97NxOm6GsP0SIvYVIosBis1xLg==}
|
||||||
|
|
||||||
svg-pathdata@6.0.3:
|
|
||||||
resolution: {integrity: sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==}
|
|
||||||
engines: {node: '>=12.0.0'}
|
|
||||||
|
|
||||||
svg-tags@1.0.0:
|
svg-tags@1.0.0:
|
||||||
resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==}
|
resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==}
|
||||||
|
|
||||||
|
@ -4340,9 +4274,6 @@ packages:
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
text-segmentation@1.0.3:
|
|
||||||
resolution: {integrity: sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==}
|
|
||||||
|
|
||||||
text-table@0.2.0:
|
text-table@0.2.0:
|
||||||
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
|
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
|
||||||
|
|
||||||
|
@ -4560,9 +4491,6 @@ packages:
|
||||||
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
|
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
|
||||||
engines: {node: '>= 0.4.0'}
|
engines: {node: '>= 0.4.0'}
|
||||||
|
|
||||||
utrie@1.0.2:
|
|
||||||
resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==}
|
|
||||||
|
|
||||||
v-viewer@3.0.13:
|
v-viewer@3.0.13:
|
||||||
resolution: {integrity: sha512-T8pgGzlF0ZCHVpD/32OKsD8MlpI6tqYP3n1XLcSjvGQMc0ABn8nJ4AumxvzAKVQrLRWtDTG6qRGAyCPCmi7ceA==}
|
resolution: {integrity: sha512-T8pgGzlF0ZCHVpD/32OKsD8MlpI6tqYP3n1XLcSjvGQMc0ABn8nJ4AumxvzAKVQrLRWtDTG6qRGAyCPCmi7ceA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -5143,8 +5071,6 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime: 0.14.1
|
regenerator-runtime: 0.14.1
|
||||||
|
|
||||||
'@babel/runtime@7.28.2': {}
|
|
||||||
|
|
||||||
'@babel/template@7.24.0':
|
'@babel/template@7.24.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/code-frame': 7.24.2
|
'@babel/code-frame': 7.24.2
|
||||||
|
@ -5871,18 +5797,12 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
query-string: 9.0.0
|
query-string: 9.0.0
|
||||||
|
|
||||||
'@types/raf@3.4.3':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@types/sortablejs@1.15.8': {}
|
'@types/sortablejs@1.15.8': {}
|
||||||
|
|
||||||
'@types/svgo@2.6.4':
|
'@types/svgo@2.6.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.12.12
|
'@types/node': 20.12.12
|
||||||
|
|
||||||
'@types/trusted-types@2.0.7':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@types/unist@2.0.10': {}
|
'@types/unist@2.0.10': {}
|
||||||
|
|
||||||
'@types/web-bluetooth@0.0.20': {}
|
'@types/web-bluetooth@0.0.20': {}
|
||||||
|
@ -6427,8 +6347,6 @@ snapshots:
|
||||||
|
|
||||||
balanced-match@1.0.2: {}
|
balanced-match@1.0.2: {}
|
||||||
|
|
||||||
base64-arraybuffer@1.0.2: {}
|
|
||||||
|
|
||||||
base@0.11.2:
|
base@0.11.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
cache-base: 1.0.1
|
cache-base: 1.0.1
|
||||||
|
@ -6497,8 +6415,6 @@ snapshots:
|
||||||
node-releases: 2.0.14
|
node-releases: 2.0.14
|
||||||
update-browserslist-db: 1.0.16(browserslist@4.23.0)
|
update-browserslist-db: 1.0.16(browserslist@4.23.0)
|
||||||
|
|
||||||
btoa@1.2.1: {}
|
|
||||||
|
|
||||||
buffer-from@1.1.2: {}
|
buffer-from@1.1.2: {}
|
||||||
|
|
||||||
builtin-modules@3.3.0: {}
|
builtin-modules@3.3.0: {}
|
||||||
|
@ -6542,18 +6458,6 @@ snapshots:
|
||||||
|
|
||||||
caniuse-lite@1.0.30001620: {}
|
caniuse-lite@1.0.30001620: {}
|
||||||
|
|
||||||
canvg@3.0.11:
|
|
||||||
dependencies:
|
|
||||||
'@babel/runtime': 7.28.2
|
|
||||||
'@types/raf': 3.4.3
|
|
||||||
core-js: 3.40.0
|
|
||||||
raf: 3.4.1
|
|
||||||
regenerator-runtime: 0.13.11
|
|
||||||
rgbcolor: 1.0.1
|
|
||||||
stackblur-canvas: 2.7.0
|
|
||||||
svg-pathdata: 6.0.3
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
capital-case@1.0.4:
|
capital-case@1.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
no-case: 3.0.4
|
no-case: 3.0.4
|
||||||
|
@ -6770,10 +6674,6 @@ snapshots:
|
||||||
|
|
||||||
crypto-js@4.2.0: {}
|
crypto-js@4.2.0: {}
|
||||||
|
|
||||||
css-line-break@2.1.0:
|
|
||||||
dependencies:
|
|
||||||
utrie: 1.0.2
|
|
||||||
|
|
||||||
css-select@4.3.0:
|
css-select@4.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
boolbase: 1.0.0
|
boolbase: 1.0.0
|
||||||
|
@ -6943,11 +6843,6 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
domelementtype: 2.3.0
|
domelementtype: 2.3.0
|
||||||
|
|
||||||
dompurify@3.2.6:
|
|
||||||
optionalDependencies:
|
|
||||||
'@types/trusted-types': 2.0.7
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
domutils@1.7.0:
|
domutils@1.7.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
dom-serializer: 0.2.2
|
dom-serializer: 0.2.2
|
||||||
|
@ -7635,8 +7530,6 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
reusify: 1.0.4
|
reusify: 1.0.4
|
||||||
|
|
||||||
fflate@0.8.2: {}
|
|
||||||
|
|
||||||
file-entry-cache@8.0.0:
|
file-entry-cache@8.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
flat-cache: 4.0.1
|
flat-cache: 4.0.1
|
||||||
|
@ -7884,11 +7777,6 @@ snapshots:
|
||||||
|
|
||||||
html-tags@3.3.1: {}
|
html-tags@3.3.1: {}
|
||||||
|
|
||||||
html2canvas@1.4.1:
|
|
||||||
dependencies:
|
|
||||||
css-line-break: 2.1.0
|
|
||||||
text-segmentation: 1.0.3
|
|
||||||
|
|
||||||
htmlparser2@3.10.1:
|
htmlparser2@3.10.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
domelementtype: 1.3.1
|
domelementtype: 1.3.1
|
||||||
|
@ -8151,18 +8039,6 @@ snapshots:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
|
|
||||||
jspdf@3.0.1:
|
|
||||||
dependencies:
|
|
||||||
'@babel/runtime': 7.28.2
|
|
||||||
atob: 2.1.2
|
|
||||||
btoa: 1.2.1
|
|
||||||
fflate: 0.8.2
|
|
||||||
optionalDependencies:
|
|
||||||
canvg: 3.0.11
|
|
||||||
core-js: 3.40.0
|
|
||||||
dompurify: 3.2.6
|
|
||||||
html2canvas: 1.4.1
|
|
||||||
|
|
||||||
keyv@4.5.4:
|
keyv@4.5.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
json-buffer: 3.0.1
|
json-buffer: 3.0.1
|
||||||
|
@ -8672,9 +8548,6 @@ snapshots:
|
||||||
|
|
||||||
perfect-debounce@1.0.0: {}
|
perfect-debounce@1.0.0: {}
|
||||||
|
|
||||||
performance-now@2.1.0:
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
picocolors@1.0.1: {}
|
picocolors@1.0.1: {}
|
||||||
|
|
||||||
picocolors@1.1.1: {}
|
picocolors@1.1.1: {}
|
||||||
|
@ -8891,11 +8764,6 @@ snapshots:
|
||||||
|
|
||||||
queue-microtask@1.2.3: {}
|
queue-microtask@1.2.3: {}
|
||||||
|
|
||||||
raf@3.4.1:
|
|
||||||
dependencies:
|
|
||||||
performance-now: 2.1.0
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
randombytes@2.1.0:
|
randombytes@2.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer: 5.2.1
|
safe-buffer: 5.2.1
|
||||||
|
@ -8927,9 +8795,6 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@eslint-community/regexpp': 4.10.0
|
'@eslint-community/regexpp': 4.10.0
|
||||||
|
|
||||||
regenerator-runtime@0.13.11:
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
regenerator-runtime@0.14.1: {}
|
regenerator-runtime@0.14.1: {}
|
||||||
|
|
||||||
regex-not@1.0.2:
|
regex-not@1.0.2:
|
||||||
|
@ -8990,9 +8855,6 @@ snapshots:
|
||||||
|
|
||||||
rfdc@1.4.1: {}
|
rfdc@1.4.1: {}
|
||||||
|
|
||||||
rgbcolor@1.0.1:
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
rollup@4.17.2:
|
rollup@4.17.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/estree': 1.0.5
|
'@types/estree': 1.0.5
|
||||||
|
@ -9247,9 +9109,6 @@ snapshots:
|
||||||
|
|
||||||
stable@0.1.8: {}
|
stable@0.1.8: {}
|
||||||
|
|
||||||
stackblur-canvas@2.7.0:
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
static-extend@0.1.2:
|
static-extend@0.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
define-property: 0.2.5
|
define-property: 0.2.5
|
||||||
|
@ -9366,9 +9225,6 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
svg-pathdata@6.0.3:
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
svg-tags@1.0.0: {}
|
svg-tags@1.0.0: {}
|
||||||
|
|
||||||
svgo@2.8.0:
|
svgo@2.8.0:
|
||||||
|
@ -9403,10 +9259,6 @@ snapshots:
|
||||||
commander: 2.20.3
|
commander: 2.20.3
|
||||||
source-map-support: 0.5.21
|
source-map-support: 0.5.21
|
||||||
|
|
||||||
text-segmentation@1.0.3:
|
|
||||||
dependencies:
|
|
||||||
utrie: 1.0.2
|
|
||||||
|
|
||||||
text-table@0.2.0: {}
|
text-table@0.2.0: {}
|
||||||
|
|
||||||
tippy.js@6.3.7:
|
tippy.js@6.3.7:
|
||||||
|
@ -9654,10 +9506,6 @@ snapshots:
|
||||||
|
|
||||||
utils-merge@1.0.1: {}
|
utils-merge@1.0.1: {}
|
||||||
|
|
||||||
utrie@1.0.2:
|
|
||||||
dependencies:
|
|
||||||
base64-arraybuffer: 1.0.2
|
|
||||||
|
|
||||||
v-viewer@3.0.13(viewerjs@1.11.6)(vue@3.5.12(typescript@5.0.4)):
|
v-viewer@3.0.13(viewerjs@1.11.6)(vue@3.5.12(typescript@5.0.4)):
|
||||||
dependencies:
|
dependencies:
|
||||||
lodash-es: 4.17.21
|
lodash-es: 4.17.21
|
||||||
|
|
|
@ -24,7 +24,7 @@ export function batchAddAttachment(businessType: string, formData: FormData) {
|
||||||
* @param businessType 业务类型
|
* @param businessType 业务类型
|
||||||
* @param formData 表单数据
|
* @param formData 表单数据
|
||||||
*/
|
*/
|
||||||
export function addAttachment(formData: FormData) {
|
export function addAttachment(formData: FormData) {
|
||||||
return request<AttachInfoData>({
|
return request<AttachInfoData>({
|
||||||
url: `/attach-info/model`,
|
url: `/attach-info/model`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
|
@ -39,7 +39,7 @@ export function addAttachment(formData: FormData) {
|
||||||
* @param businessType 业务类型
|
* @param businessType 业务类型
|
||||||
* @param formData 表单数据
|
* @param formData 表单数据
|
||||||
*/
|
*/
|
||||||
export function addAttachmentByDefectMarkPic(formData: FormData) {
|
export function addAttachmentByDefectMarkPic(formData: FormData) {
|
||||||
return request<AttachInfoData>({
|
return request<AttachInfoData>({
|
||||||
url: `/attach-info/defect_mark_pic`,
|
url: `/attach-info/defect_mark_pic`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
|
@ -54,7 +54,7 @@ export function addAttachmentByDefectMarkPic(formData: FormData) {
|
||||||
* @param businessType 业务类型
|
* @param businessType 业务类型
|
||||||
* @param formData 表单数据
|
* @param formData 表单数据
|
||||||
*/
|
*/
|
||||||
export function addAttachInsurance(formData: FormData) {
|
export function addAttachInsurance(formData: FormData) {
|
||||||
return request<AttachInfoData>({
|
return request<AttachInfoData>({
|
||||||
url: `/attach-info/insurance_file`,
|
url: `/attach-info/insurance_file`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
|
|
|
@ -1,64 +1,64 @@
|
||||||
/** 用户信息响应类型 */
|
/** 用户信息响应类型 */
|
||||||
export interface UserInfoResponse {
|
export interface UserInfoResponse {
|
||||||
code: number
|
code: number;
|
||||||
status: number
|
status: number;
|
||||||
success: boolean
|
success: boolean;
|
||||||
msg: string
|
msg: string;
|
||||||
data: {
|
data: {
|
||||||
user: UserDetail
|
user: UserDetail;
|
||||||
dept: DeptDetail
|
dept: DeptDetail;
|
||||||
roles: RoleDetail[]
|
roles: RoleDetail[];
|
||||||
posts: any[]
|
posts: any[];
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 用户详细信息 */
|
/** 用户详细信息 */
|
||||||
export interface UserDetail {
|
export interface UserDetail {
|
||||||
userId: string
|
userId: string;
|
||||||
account: string
|
account: string;
|
||||||
name: string
|
name: string;
|
||||||
status: number
|
status: number;
|
||||||
userCode: string
|
userCode: string;
|
||||||
userStatus: string
|
userStatus: string;
|
||||||
userType: string
|
userType: string;
|
||||||
mobile: string
|
mobile: string;
|
||||||
createTime: string
|
createTime: string;
|
||||||
avatar?: string
|
avatar?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 部门详细信息 */
|
/** 部门详细信息 */
|
||||||
export interface DeptDetail {
|
export interface DeptDetail {
|
||||||
deptId: string
|
deptId: string;
|
||||||
deptName: string
|
deptName: string;
|
||||||
parentId: string
|
parentId: string;
|
||||||
orderNum: number
|
orderNum: number;
|
||||||
leaderId: string
|
leaderId: string;
|
||||||
status: string
|
status: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 角色详细信息 */
|
/** 角色详细信息 */
|
||||||
export interface RoleDetail {
|
export interface RoleDetail {
|
||||||
roleId: string
|
roleId: string;
|
||||||
roleName: string
|
roleName: string;
|
||||||
roleCode: string | null
|
roleCode: string | null;
|
||||||
roleKey: string
|
roleKey: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 用户类型 - 兼容旧版本 */
|
/** 用户类型 - 兼容旧版本 */
|
||||||
export interface UserInfo {
|
export interface UserInfo {
|
||||||
id: string
|
id: string;
|
||||||
username: string
|
username: string;
|
||||||
nickname: string
|
nickname: string;
|
||||||
gender: 0 | 1 | 2
|
gender: 0 | 1 | 2;
|
||||||
email: string
|
email: string;
|
||||||
phone: string
|
phone: string;
|
||||||
avatar: string
|
avatar: string;
|
||||||
pwdResetTime: string
|
pwdResetTime: string;
|
||||||
pwdExpired: boolean
|
pwdExpired: boolean;
|
||||||
registrationDate: string
|
registrationDate: string;
|
||||||
deptName: string
|
deptName: string;
|
||||||
roles: string[]
|
roles: string[];
|
||||||
permissions: string[]
|
permissions: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 路由类型 */
|
/** 路由类型 */
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
// @/apis/bussiness/bussiness.js - 根据后端接口重新编写
|
||||||
|
import http from '@/utils/http';
|
||||||
|
|
||||||
|
const { request } = http;
|
||||||
|
|
||||||
|
// 获取文件夹列表(分页)
|
||||||
|
export function getFolderListApi(params) {
|
||||||
|
return request({
|
||||||
|
url: '/businessData/folder/list',
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
page: params?.page || 1,
|
||||||
|
pageSize: params?.pageSize || 10,
|
||||||
|
folderName: params?.folderName
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取文件列表(分页)
|
||||||
|
export function getFilesApi(params) {
|
||||||
|
return request({
|
||||||
|
url: '/businessData/file/list',
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
page: params?.page || 1,
|
||||||
|
pageSize: params?.pageSize || 10,
|
||||||
|
folderId: params?.folderId || 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建文件夹
|
||||||
|
export function createFolderApi(data) {
|
||||||
|
return request({
|
||||||
|
url: '/businessData/folder/creatFolder',
|
||||||
|
method: 'post',
|
||||||
|
data: {
|
||||||
|
name: data.name,
|
||||||
|
parentId: data.parentId || 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重命名文件夹
|
||||||
|
export function updateFolderApi(folderId, newName) {
|
||||||
|
return request({
|
||||||
|
url: '/businessData/folder/rename',
|
||||||
|
method: 'put',
|
||||||
|
params: {
|
||||||
|
folderId: folderId,
|
||||||
|
newName: newName
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除文件夹
|
||||||
|
export function deleteFolderApi(folderId) {
|
||||||
|
return request({
|
||||||
|
url: '/businessData/folder/delete',
|
||||||
|
method: 'delete',
|
||||||
|
params: {
|
||||||
|
folderId: folderId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上传文件
|
||||||
|
export function uploadFileApi(file, folderId, onUploadProgress, cancelToken) {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
|
||||||
|
return request({
|
||||||
|
url: '/businessData/file/add',
|
||||||
|
method: 'post',
|
||||||
|
params: {
|
||||||
|
folderId: folderId
|
||||||
|
},
|
||||||
|
data: formData,
|
||||||
|
onUploadProgress,
|
||||||
|
cancelToken,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下载文件
|
||||||
|
export function downloadFileApi(fileId) {
|
||||||
|
return request({
|
||||||
|
url: '/businessData/file/download',
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
fileId: fileId
|
||||||
|
},
|
||||||
|
responseType: 'blob'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除文件
|
||||||
|
export function deleteFileApi(fileId) {
|
||||||
|
return request({
|
||||||
|
url: '/businessData/file/delete',
|
||||||
|
method: 'delete',
|
||||||
|
params: {
|
||||||
|
fileId: fileId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 预览文件(后端没有提供预览接口,使用下载接口)
|
||||||
|
export function previewFileApi(fileId) {
|
||||||
|
return request({
|
||||||
|
url: '/businessData/file/download',
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
fileId: fileId
|
||||||
|
},
|
||||||
|
responseType: 'blob'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重命名文件(后端没有提供重命名接口,需要先删除再上传)
|
||||||
|
export function updateFileNameApi(fileId, data) {
|
||||||
|
// 注意:后端没有提供文件重命名接口,这里返回一个Promise.reject
|
||||||
|
return Promise.reject(new Error('后端暂不支持文件重命名功能'));
|
||||||
|
}
|
|
@ -1,49 +0,0 @@
|
||||||
import http from '@/utils/http'
|
|
||||||
import type * as T from '@/types/equipment.d'
|
|
||||||
|
|
||||||
const BASE_URL = '/equipment'
|
|
||||||
|
|
||||||
/** @desc 分页查询设备列表 */
|
|
||||||
export function pageEquipment(query: T.EquipmentPageQuery) {
|
|
||||||
return http.get<T.EquipmentResp[]>(`${BASE_URL}/page`, query)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @desc 查询设备列表 */
|
|
||||||
export function listEquipment(query?: T.EquipmentPageQuery) {
|
|
||||||
return http.get<T.EquipmentResp[]>(`${BASE_URL}/list`, query)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @desc 查询设备详情 */
|
|
||||||
export function getEquipmentDetail(equipmentId: string) {
|
|
||||||
return http.get<T.EquipmentResp>(`${BASE_URL}/detail/${equipmentId}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @desc 新增设备 */
|
|
||||||
export function createEquipment(data: T.EquipmentReq) {
|
|
||||||
return http.post(`${BASE_URL}`, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @desc 更新设备 */
|
|
||||||
export function updateEquipment(equipmentId: string, data: T.EquipmentReq) {
|
|
||||||
return http.put(`${BASE_URL}/${equipmentId}`, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @desc 删除设备 */
|
|
||||||
export function deleteEquipment(equipmentId: string) {
|
|
||||||
return http.del(`${BASE_URL}/${equipmentId}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @desc 设备状态变更 */
|
|
||||||
export function changeEquipmentStatus(equipmentId: string, status: string) {
|
|
||||||
return http.put(`${BASE_URL}/${equipmentId}/status`, { status })
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @desc 设备分配 */
|
|
||||||
export function assignEquipment(equipmentId: string, userId: string) {
|
|
||||||
return http.put(`${BASE_URL}/${equipmentId}/assign`, { userId })
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @desc 设备归还 */
|
|
||||||
export function returnEquipment(equipmentId: string) {
|
|
||||||
return http.put(`${BASE_URL}/${equipmentId}/return`)
|
|
||||||
}
|
|
|
@ -1,277 +0,0 @@
|
||||||
/**
|
|
||||||
* 设备列表查询请求
|
|
||||||
*/
|
|
||||||
export interface EquipmentListReq {
|
|
||||||
/** 最低价格 */
|
|
||||||
minPrice?: number
|
|
||||||
/** 最高价格 */
|
|
||||||
maxPrice?: number
|
|
||||||
/** 设备名称 */
|
|
||||||
equipmentName?: string
|
|
||||||
/** 设备类型 */
|
|
||||||
equipmentType?: string
|
|
||||||
/** 设备状态 */
|
|
||||||
equipmentStatus?: string
|
|
||||||
/** 设备序列号 */
|
|
||||||
equipmentSn?: string
|
|
||||||
/** 资产编号 */
|
|
||||||
assetCode?: string
|
|
||||||
/** 品牌 */
|
|
||||||
brand?: string
|
|
||||||
/** 位置状态 */
|
|
||||||
locationStatus?: string
|
|
||||||
/** 健康状态 */
|
|
||||||
healthStatus?: string
|
|
||||||
/** 负责人 */
|
|
||||||
responsiblePerson?: string
|
|
||||||
/** 使用状态 */
|
|
||||||
useStatus?: string
|
|
||||||
/** 项目ID */
|
|
||||||
projectId?: string
|
|
||||||
/** 使用人ID */
|
|
||||||
userId?: string
|
|
||||||
/** 设备型号 */
|
|
||||||
equipmentModel?: string
|
|
||||||
/** 配置规格/参数 */
|
|
||||||
specification?: string
|
|
||||||
/** 设备当前物理位置 */
|
|
||||||
physicalLocation?: string
|
|
||||||
/** 供应商名称 */
|
|
||||||
supplierName?: string
|
|
||||||
/** 采购订单号 */
|
|
||||||
purchaseOrder?: string
|
|
||||||
/** 维护人员 */
|
|
||||||
maintenancePerson?: string
|
|
||||||
/** 次户号 */
|
|
||||||
accountNumber?: string
|
|
||||||
/** 数量 */
|
|
||||||
quantity?: number
|
|
||||||
/** 单价 */
|
|
||||||
unitPrice?: number
|
|
||||||
/** 总价 */
|
|
||||||
totalPrice?: number
|
|
||||||
/** 盘点依据 */
|
|
||||||
inventoryBasis?: string
|
|
||||||
/** 动态记录 */
|
|
||||||
dynamicRecord?: string
|
|
||||||
/** 资产备注 */
|
|
||||||
assetRemark?: string
|
|
||||||
/** 采购时间开始 */
|
|
||||||
purchaseTimeStart?: string
|
|
||||||
/** 采购时间结束 */
|
|
||||||
purchaseTimeEnd?: string
|
|
||||||
/** 入库时间开始 */
|
|
||||||
inStockTimeStart?: string
|
|
||||||
/** 入库时间结束 */
|
|
||||||
inStockTimeEnd?: string
|
|
||||||
/** 启用时间开始 */
|
|
||||||
activationTimeStart?: string
|
|
||||||
/** 启用时间结束 */
|
|
||||||
activationTimeEnd?: string
|
|
||||||
/** 当前页码 */
|
|
||||||
pageNum?: number
|
|
||||||
/** 每页大小 */
|
|
||||||
pageSize?: number
|
|
||||||
/** 排序字段 */
|
|
||||||
orderBy?: string
|
|
||||||
/** 排序方向 */
|
|
||||||
orderDirection?: string
|
|
||||||
/** 页码 */
|
|
||||||
page?: number
|
|
||||||
/** 库存条码 */
|
|
||||||
inventoryBarcode?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分页响应格式
|
|
||||||
*/
|
|
||||||
export interface PageResult<T> {
|
|
||||||
code: number
|
|
||||||
msg: string
|
|
||||||
rows: T[]
|
|
||||||
total: number
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设备信息响应
|
|
||||||
*/
|
|
||||||
export interface EquipmentResp {
|
|
||||||
/** 设备ID */
|
|
||||||
equipmentId: string
|
|
||||||
/** 资产编号 */
|
|
||||||
assetCode?: string
|
|
||||||
/** 设备名称 */
|
|
||||||
equipmentName: string
|
|
||||||
/** 设备类型 */
|
|
||||||
equipmentType: string
|
|
||||||
/** 设备类型描述 */
|
|
||||||
equipmentTypeLabel?: string
|
|
||||||
/** 设备型号 */
|
|
||||||
equipmentModel: string
|
|
||||||
/** 设备SN */
|
|
||||||
equipmentSn: string
|
|
||||||
/** 品牌 */
|
|
||||||
brand?: string
|
|
||||||
/** 配置规格/参数 */
|
|
||||||
specification?: string
|
|
||||||
/** 设备状态 */
|
|
||||||
equipmentStatus: string
|
|
||||||
/** 设备状态描述 */
|
|
||||||
equipmentStatusLabel?: string
|
|
||||||
/** 使用状态 */
|
|
||||||
useStatus: string
|
|
||||||
/** 位置状态 */
|
|
||||||
locationStatus?: string
|
|
||||||
/** 位置状态描述 */
|
|
||||||
locationStatusLabel?: string
|
|
||||||
/** 设备当前物理位置 */
|
|
||||||
physicalLocation?: string
|
|
||||||
/** 负责人 */
|
|
||||||
responsiblePerson?: string
|
|
||||||
/** 健康状态 */
|
|
||||||
healthStatus?: string
|
|
||||||
/** 健康状态描述 */
|
|
||||||
healthStatusLabel?: string
|
|
||||||
/** 采购时间 */
|
|
||||||
purchaseTime?: string
|
|
||||||
/** 入库时间 */
|
|
||||||
inStockTime?: string
|
|
||||||
/** 启用时间 */
|
|
||||||
activationTime?: string
|
|
||||||
/** 预计报废时间 */
|
|
||||||
expectedScrapTime?: string
|
|
||||||
/** 实际报废时间 */
|
|
||||||
actualScrapTime?: string
|
|
||||||
/** 状态变更时间 */
|
|
||||||
statusChangeTime?: string
|
|
||||||
/** 采购订单 */
|
|
||||||
purchaseOrder?: string
|
|
||||||
/** 供应商名称 */
|
|
||||||
supplierName?: string
|
|
||||||
/** 采购价格 */
|
|
||||||
purchasePrice?: number
|
|
||||||
/** 当前净值 */
|
|
||||||
currentNetValue?: number
|
|
||||||
/** 折旧方法 */
|
|
||||||
depreciationMethod?: string
|
|
||||||
/** 折旧年限 */
|
|
||||||
depreciationYears?: number
|
|
||||||
/** 残值 */
|
|
||||||
salvageValue?: number
|
|
||||||
/** 保修截止日期 */
|
|
||||||
warrantyExpireDate?: string
|
|
||||||
/** 上次维护日期 */
|
|
||||||
lastMaintenanceDate?: string
|
|
||||||
/** 下次维护日期 */
|
|
||||||
nextMaintenanceDate?: string
|
|
||||||
/** 维护人员 */
|
|
||||||
maintenancePerson?: string
|
|
||||||
/** 库存条码 */
|
|
||||||
inventoryBarcode?: string
|
|
||||||
/** 资产备注 */
|
|
||||||
assetRemark?: string
|
|
||||||
/** 项目ID */
|
|
||||||
projectId?: string
|
|
||||||
/** 项目名称 */
|
|
||||||
projectName?: string
|
|
||||||
/** 使用人ID */
|
|
||||||
userId?: string
|
|
||||||
/** 使用人 */
|
|
||||||
name?: string
|
|
||||||
/** 创建时间 */
|
|
||||||
createTime?: string
|
|
||||||
/** 更新时间 */
|
|
||||||
updateTime?: string
|
|
||||||
/** 次户号 */
|
|
||||||
accountNumber?: string
|
|
||||||
/** 数量 */
|
|
||||||
quantity?: number
|
|
||||||
/** 单价 */
|
|
||||||
unitPrice?: number
|
|
||||||
/** 总价 */
|
|
||||||
totalPrice?: number
|
|
||||||
/** 盘点依据 */
|
|
||||||
inventoryBasis?: string
|
|
||||||
/** 动态记录 */
|
|
||||||
dynamicRecord?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设备请求
|
|
||||||
*/
|
|
||||||
export interface EquipmentReq {
|
|
||||||
/** 设备名称 */
|
|
||||||
equipmentName: string
|
|
||||||
/** 设备型号 */
|
|
||||||
equipmentModel: string
|
|
||||||
/** 设备类型 */
|
|
||||||
equipmentType: string
|
|
||||||
/** 设备状态 */
|
|
||||||
equipmentStatus: string
|
|
||||||
/** 使用状态 */
|
|
||||||
useStatus: string
|
|
||||||
/** 设备序列号 */
|
|
||||||
equipmentSn: string
|
|
||||||
/** 资产编号 */
|
|
||||||
assetCode?: string
|
|
||||||
/** 品牌 */
|
|
||||||
brand?: string
|
|
||||||
/** 配置规格/参数 */
|
|
||||||
specification?: string
|
|
||||||
/** 位置状态 */
|
|
||||||
locationStatus?: string
|
|
||||||
/** 设备当前物理位置 */
|
|
||||||
physicalLocation?: string
|
|
||||||
/** 负责人 */
|
|
||||||
responsiblePerson?: string
|
|
||||||
/** 健康状态 */
|
|
||||||
healthStatus?: string
|
|
||||||
/** 采购时间 */
|
|
||||||
purchaseTime?: string
|
|
||||||
/** 入库时间 */
|
|
||||||
inStockTime?: string
|
|
||||||
/** 启用时间 */
|
|
||||||
activationTime?: string
|
|
||||||
/** 预计报废时间 */
|
|
||||||
expectedScrapTime?: string
|
|
||||||
/** 实际报废时间 */
|
|
||||||
actualScrapTime?: string
|
|
||||||
/** 采购订单 */
|
|
||||||
purchaseOrder?: string
|
|
||||||
/** 供应商名称 */
|
|
||||||
supplierName?: string
|
|
||||||
/** 采购价格 */
|
|
||||||
purchasePrice?: number
|
|
||||||
/** 当前净值 */
|
|
||||||
currentNetValue?: number
|
|
||||||
/** 折旧方法 */
|
|
||||||
depreciationMethod?: string
|
|
||||||
/** 折旧年限 */
|
|
||||||
depreciationYears?: number
|
|
||||||
/** 残值 */
|
|
||||||
salvageValue?: number
|
|
||||||
/** 保修截止日期 */
|
|
||||||
warrantyExpireDate?: string
|
|
||||||
/** 上次维护日期 */
|
|
||||||
lastMaintenanceDate?: string
|
|
||||||
/** 下次维护日期 */
|
|
||||||
nextMaintenanceDate?: string
|
|
||||||
/** 维护人员 */
|
|
||||||
maintenancePerson?: string
|
|
||||||
/** 库存条码 */
|
|
||||||
inventoryBarcode?: string
|
|
||||||
/** 资产备注 */
|
|
||||||
assetRemark?: string
|
|
||||||
/** 次户号 */
|
|
||||||
accountNumber?: string
|
|
||||||
/** 数量 */
|
|
||||||
quantity?: number
|
|
||||||
/** 单价 */
|
|
||||||
unitPrice?: number
|
|
||||||
/** 总价 */
|
|
||||||
totalPrice?: number
|
|
||||||
/** 盘点依据 */
|
|
||||||
inventoryBasis?: string
|
|
||||||
/** 动态记录 */
|
|
||||||
dynamicRecord?: string
|
|
||||||
}
|
|
|
@ -16,7 +16,6 @@ export * as InsuranceTypeAPI from './insurance-type'
|
||||||
export * as HealthRecordAPI from './health-record'
|
export * as HealthRecordAPI from './health-record'
|
||||||
export * as InsuranceFileAPI from './insurance-file'
|
export * as InsuranceFileAPI from './insurance-file'
|
||||||
export * as EmployeeAPI from './employee'
|
export * as EmployeeAPI from './employee'
|
||||||
export * as RegulationAPI from './regulation'
|
|
||||||
|
|
||||||
export * from './area/type'
|
export * from './area/type'
|
||||||
export * from './auth/type'
|
export * from './auth/type'
|
||||||
|
|
|
@ -1,108 +0,0 @@
|
||||||
import http from '@/utils/http'
|
|
||||||
import {
|
|
||||||
type RegulationTypeSearchRequest,
|
|
||||||
type RegulationTypeSearchResponse,
|
|
||||||
type RegulationProposalSearchRequest,
|
|
||||||
type RegulationProposalSearchResponse
|
|
||||||
} from './type'
|
|
||||||
|
|
||||||
// 制度管理API接口
|
|
||||||
export const regulationApi = {
|
|
||||||
// 获取制度列表
|
|
||||||
getRegulationList: (params: {
|
|
||||||
page?: number
|
|
||||||
size?: number
|
|
||||||
status?: string
|
|
||||||
type?: string
|
|
||||||
title?: string
|
|
||||||
proposer?: string
|
|
||||||
}): Promise<RegulationProposalSearchResponse> => {
|
|
||||||
return http.get('/regulation', params)
|
|
||||||
},
|
|
||||||
|
|
||||||
// 获取制度详情
|
|
||||||
getRegulationDetail: (regulationId: string) => {
|
|
||||||
return http.get(`/regulation/${regulationId}`)
|
|
||||||
},
|
|
||||||
|
|
||||||
// 创建制度提案
|
|
||||||
createProposal: (data: {
|
|
||||||
title: string
|
|
||||||
content: string
|
|
||||||
regulationType: string
|
|
||||||
scope: string
|
|
||||||
level: string
|
|
||||||
remark?: string
|
|
||||||
createBy?: string
|
|
||||||
}) => {
|
|
||||||
return http.post('/regulation/proposal', data)
|
|
||||||
},
|
|
||||||
|
|
||||||
// 更新制度提案
|
|
||||||
updateProposal: (regulationId: string, data: any) => {
|
|
||||||
return http.put(`/regulation/proposal/${regulationId}`, data)
|
|
||||||
},
|
|
||||||
|
|
||||||
// 公示提案
|
|
||||||
publishProposal: (regulationId: string) => {
|
|
||||||
return http.post(`/regulation/proposal/${regulationId}/publish`)
|
|
||||||
},
|
|
||||||
|
|
||||||
// 删除制度提案
|
|
||||||
deleteProposal: (regulationId: string) => {
|
|
||||||
return http.del(`/regulation/proposal/${regulationId}`)
|
|
||||||
},
|
|
||||||
|
|
||||||
// 公示制度
|
|
||||||
publishRegulation: (regulationId: string) => {
|
|
||||||
return http.post(`/regulation/${regulationId}/approve`)
|
|
||||||
},
|
|
||||||
|
|
||||||
// 获取已公示制度列表
|
|
||||||
getPublishedRegulationList: (params: {
|
|
||||||
page: number
|
|
||||||
size: number
|
|
||||||
status: string
|
|
||||||
}) => {
|
|
||||||
return http.get('/regulation', params)
|
|
||||||
},
|
|
||||||
|
|
||||||
// 确认制度知晓
|
|
||||||
confirmRegulation: (regulationId: string) => {
|
|
||||||
return http.post(`/regulation/${regulationId}/confirm`)
|
|
||||||
},
|
|
||||||
|
|
||||||
// 搜索制度类型(后端搜索接口)
|
|
||||||
searchRegulationTypes: (params: {
|
|
||||||
page?: number
|
|
||||||
size?: number
|
|
||||||
typeName?: string
|
|
||||||
status?: string
|
|
||||||
remark?: string
|
|
||||||
}) => {
|
|
||||||
return http.get('/regulation/types', params)
|
|
||||||
},
|
|
||||||
|
|
||||||
// 创建制度类型
|
|
||||||
createRegulationType: (data: {
|
|
||||||
typeName: string
|
|
||||||
sortOrder?: number
|
|
||||||
isEnabled?: string
|
|
||||||
}) => {
|
|
||||||
return http.post('/regulation/types', data)
|
|
||||||
},
|
|
||||||
|
|
||||||
// 更新制度类型
|
|
||||||
updateRegulationType: (typeId: string, data: {
|
|
||||||
typeName: string
|
|
||||||
sortOrder?: number
|
|
||||||
isEnabled?: string
|
|
||||||
}) => {
|
|
||||||
return http.put(`/regulation/types/${typeId}`, data)
|
|
||||||
},
|
|
||||||
|
|
||||||
// 删除制度类型
|
|
||||||
deleteRegulationType: (typeId: string) => {
|
|
||||||
return http.del(`/regulation/types/${typeId}`)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,121 +0,0 @@
|
||||||
// 制度状态枚举
|
|
||||||
export enum RegulationStatus {
|
|
||||||
DRAFT = 'DRAFT', // 草稿
|
|
||||||
APPROVED = 'APPROVED', // 已通过
|
|
||||||
PUBLISHED = 'PUBLISHED', // 已公示
|
|
||||||
}
|
|
||||||
|
|
||||||
// 制度级别枚举
|
|
||||||
export enum RegulationLevel {
|
|
||||||
LOW = 'LOW', // 低
|
|
||||||
MEDIUM = 'MEDIUM', // 中
|
|
||||||
HIGH = 'HIGH' // 高
|
|
||||||
}
|
|
||||||
|
|
||||||
// 制度信息接口
|
|
||||||
export interface Regulation {
|
|
||||||
regulationId: string
|
|
||||||
title: string
|
|
||||||
content: string
|
|
||||||
regulationType: string
|
|
||||||
status: RegulationStatus
|
|
||||||
publishTime: string // 公示时间
|
|
||||||
effectiveTime: string
|
|
||||||
expireTime: string
|
|
||||||
scope: string
|
|
||||||
level: RegulationLevel
|
|
||||||
version: string
|
|
||||||
remark?: string
|
|
||||||
createBy: string
|
|
||||||
updateBy: string
|
|
||||||
createTime: string
|
|
||||||
updateTime: string
|
|
||||||
page: number
|
|
||||||
pageSize: number
|
|
||||||
delFlag: string
|
|
||||||
confirmStatus?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建提案请求接口
|
|
||||||
export interface CreateProposalRequest {
|
|
||||||
title: string
|
|
||||||
content: string
|
|
||||||
regulationType: string
|
|
||||||
scope: string
|
|
||||||
level: RegulationLevel
|
|
||||||
remark?: string
|
|
||||||
createBy?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 分页参数接口
|
|
||||||
export interface PaginationParams {
|
|
||||||
page: number
|
|
||||||
size: number
|
|
||||||
}
|
|
||||||
|
|
||||||
// 制度类型接口
|
|
||||||
export interface RegulationType {
|
|
||||||
typeId: string
|
|
||||||
typeName: string
|
|
||||||
sortOrder: number
|
|
||||||
isEnabled: string
|
|
||||||
remark?: string
|
|
||||||
createBy: string
|
|
||||||
createTime: string
|
|
||||||
updateBy: string
|
|
||||||
updateTime: string
|
|
||||||
delFlag: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建制度类型请求接口
|
|
||||||
export interface CreateRegulationTypeRequest {
|
|
||||||
typeName: string
|
|
||||||
sortOrder?: number
|
|
||||||
isEnabled?: string
|
|
||||||
remark?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新制度类型请求接口
|
|
||||||
export interface UpdateRegulationTypeRequest {
|
|
||||||
typeName: string
|
|
||||||
sortOrder?: number
|
|
||||||
isEnabled?: string
|
|
||||||
remark?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 制度类型搜索请求接口
|
|
||||||
export interface RegulationTypeSearchRequest {
|
|
||||||
page?: number
|
|
||||||
size?: number
|
|
||||||
typeName?: string
|
|
||||||
status?: string
|
|
||||||
remark?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 制度类型搜索响应接口
|
|
||||||
export interface RegulationTypeSearchResponse {
|
|
||||||
records: RegulationType[]
|
|
||||||
total: number
|
|
||||||
current: number
|
|
||||||
size: number
|
|
||||||
pages: number
|
|
||||||
}
|
|
||||||
|
|
||||||
// 制度提案搜索请求接口
|
|
||||||
export interface RegulationProposalSearchRequest {
|
|
||||||
page?: number
|
|
||||||
size?: number
|
|
||||||
status?: string
|
|
||||||
type?: string
|
|
||||||
title?: string
|
|
||||||
proposer?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 制度提案搜索响应接口
|
|
||||||
export interface RegulationProposalSearchResponse {
|
|
||||||
records: Regulation[]
|
|
||||||
total: number
|
|
||||||
current: number
|
|
||||||
size: number
|
|
||||||
pages: number
|
|
||||||
}
|
|
|
@ -42,11 +42,5 @@ export function updatePost(postId: string, data: T.PostUpdateReq) {
|
||||||
* 删除岗位
|
* 删除岗位
|
||||||
*/
|
*/
|
||||||
export function deletePost(postId: string) {
|
export function deletePost(postId: string) {
|
||||||
}
|
return http.del<any>(`${BASE_URL}/${postId}`);
|
||||||
|
}
|
||||||
/**
|
|
||||||
* 查询岗位下的用户信息
|
|
||||||
*/
|
|
||||||
export function getPostUsers(postId: string) {
|
|
||||||
return http.get<T.UserNewResp[]>(`${BASE_URL}/${postId}/user`);
|
|
||||||
}
|
|
|
@ -4,7 +4,6 @@ import http from '@/utils/http'
|
||||||
export type * from './type'
|
export type * from './type'
|
||||||
|
|
||||||
const BASE_URL = '/system/role'
|
const BASE_URL = '/system/role'
|
||||||
const BASE_URL_NEW = '/role'
|
|
||||||
|
|
||||||
/** @desc 查询角色列表(已废弃) */
|
/** @desc 查询角色列表(已废弃) */
|
||||||
export function listRole(query: T.RoleQuery) {
|
export function listRole(query: T.RoleQuery) {
|
||||||
|
@ -73,7 +72,7 @@ export function updateRolePermission(id: string, data: any) {
|
||||||
|
|
||||||
/** @desc 查询角色关联用户 */
|
/** @desc 查询角色关联用户 */
|
||||||
export function listRoleUser(id: string, query: T.RoleUserPageQuery) {
|
export function listRoleUser(id: string, query: T.RoleUserPageQuery) {
|
||||||
return http.get<PageRes<T.RoleUserResp[]>>(`${BASE_URL_NEW}/${id}/user`, query)
|
return http.get<PageRes<T.RoleUserResp[]>>(`${BASE_URL}/${id}/user`, query)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @desc 分配角色给用户 */
|
/** @desc 分配角色给用户 */
|
||||||
|
@ -88,5 +87,5 @@ export function unassignFromUsers(userRoleIds: Array<string | number>) {
|
||||||
|
|
||||||
/** @desc 查询角色关联用户 ID */
|
/** @desc 查询角色关联用户 ID */
|
||||||
export function listRoleUserId(id: string) {
|
export function listRoleUserId(id: string) {
|
||||||
return http.get(`${BASE_URL_NEW}/${id}/user`)
|
return http.get(`${BASE_URL}/${id}/user/id`)
|
||||||
}
|
}
|
||||||
|
|
53
src/main.ts
53
src/main.ts
|
@ -1,43 +1,46 @@
|
||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import ArcoVue, { Card, Drawer, Modal } from '@arco-design/web-vue'
|
|
||||||
import '@/styles/arco-ui/index.less'
|
|
||||||
// import '@arco-themes/vue-gi-demo/index.less'
|
|
||||||
// import '@arco-design/web-vue/dist/arco.css'
|
|
||||||
|
|
||||||
// 额外引入 Arco Design Icon图标库
|
|
||||||
import ArcoVueIcon from '@arco-design/web-vue/es/icon'
|
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import router from './router'
|
import router from './router'
|
||||||
|
import pinia from '@/stores'
|
||||||
|
|
||||||
// 使用动画库
|
// UI框架 - Arco Design
|
||||||
import 'animate.css/animate.min.css'
|
import ArcoVue, { Card, Drawer, Modal } from '@arco-design/web-vue'
|
||||||
|
import ArcoVueIcon from '@arco-design/web-vue/es/icon'
|
||||||
|
import '@/styles/arco-ui/index.less' // 自定义Arco样式
|
||||||
|
|
||||||
// 自定义过渡动画
|
// UI框架 - Element Plus
|
||||||
import '@/styles/css/transition.css'
|
import ElementPlus from 'element-plus'
|
||||||
|
import 'element-plus/dist/index.css'
|
||||||
|
|
||||||
// 导入全局scss主文件
|
// 动画相关
|
||||||
|
import 'animate.css/animate.min.css' // 第三方动画库
|
||||||
|
import '@/styles/css/transition.css' // 自定义过渡动画
|
||||||
|
|
||||||
|
// 样式主文件
|
||||||
import '@/styles/index.scss'
|
import '@/styles/index.scss'
|
||||||
|
|
||||||
// 支持SVG
|
// SVG支持
|
||||||
import 'virtual:svg-icons-register'
|
import 'virtual:svg-icons-register'
|
||||||
|
|
||||||
// 自定义指令
|
// 自定义指令
|
||||||
import directives from './directives'
|
import directives from './directives'
|
||||||
|
|
||||||
// 状态管理
|
// 初始化应用
|
||||||
import pinia from '@/stores'
|
|
||||||
|
|
||||||
// 对特定组件进行默认配置
|
|
||||||
Card.props.bordered = false
|
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
Modal._context = app._context
|
|
||||||
Drawer._context = app._context
|
|
||||||
|
|
||||||
|
// 配置Arco组件全局属性
|
||||||
|
Card.props.bordered = false // 设置Card组件默认不显示边框
|
||||||
|
Modal._context = app._context // 修复Modal组件上下文问题
|
||||||
|
Drawer._context = app._context // 修复Drawer组件上下文问题
|
||||||
|
|
||||||
|
// 安装插件
|
||||||
app.use(router)
|
app.use(router)
|
||||||
app.use(pinia)
|
.use(pinia)
|
||||||
app.use(ArcoVue)
|
.use(ArcoVue)
|
||||||
app.use(ArcoVueIcon)
|
.use(ArcoVueIcon)
|
||||||
app.use(directives)
|
.use(ElementPlus)
|
||||||
|
.use(directives)
|
||||||
|
|
||||||
app.mount('#app')
|
// 挂载应用
|
||||||
|
app.mount('#app')
|
|
@ -26,304 +26,203 @@ export const systemRoutes: RouteRecordRaw[] = [
|
||||||
// }
|
// }
|
||||||
// ],
|
// ],
|
||||||
// },
|
// },
|
||||||
// {
|
|
||||||
// path: '/regulation',
|
|
||||||
// name: 'Regulation',
|
|
||||||
// component: Layout,
|
|
||||||
// redirect: '/regulation/system-regulation',
|
|
||||||
// meta: { title: '制度管理', icon: 'file-text', hidden: false, sort: 1.5 },
|
|
||||||
// children: [
|
|
||||||
// {
|
|
||||||
// path: '/regulation/system-regulation',
|
|
||||||
// name: 'SystemRegulation',
|
|
||||||
// component: () => import('@/views/regulation/repository.vue'),
|
|
||||||
// meta: { title: '制度公告', icon: 'file-text', hidden: false },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/regulation/process-management',
|
|
||||||
// name: 'ProcessManagement',
|
|
||||||
// component: () => import('@/views/regulation/confirm.vue'),
|
|
||||||
// meta: { title: '制度公示', icon: 'workflow', hidden: false },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/regulation/proposal',
|
|
||||||
// name: 'RegulationProposal',
|
|
||||||
// component: () => import('@/views/regulation/proposal/index.vue'),
|
|
||||||
// meta: { title: '制度提案', icon: 'edit', hidden: false },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/regulation/type',
|
|
||||||
// name: 'RegulationType',
|
|
||||||
// component: () => import('@/views/regulation/type/index.vue'),
|
|
||||||
// meta: { title: '制度类型', icon: 'tag', hidden: false },
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
path: '/organization',
|
path: '/organization',
|
||||||
name: 'Organization',
|
name: 'Organization',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/organization/dept',
|
redirect: '/organization/hr/member',
|
||||||
meta: { title: '企业管理', icon: 'user-group', hidden: false, sort: 2 },
|
meta: { title: '组织架构', icon: 'user-group', hidden: false, sort: 2 },
|
||||||
children: [
|
children: [
|
||||||
// {
|
|
||||||
// path: '/organization/user',
|
|
||||||
// name: 'OrganizationUser',
|
|
||||||
// component: () => import('@/views/system/user/index.vue'),
|
|
||||||
// meta: { title: '用户管理', icon: 'user', hidden: false, sort: 2.25 },
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
path: '/organization/dept',
|
path: '/organization/hr',
|
||||||
name: 'OrganizationDept',
|
name: 'HRManagement',
|
||||||
component: () => import('@/views/system/dept/index.vue'),
|
component: () => import('@/components/ParentView/index.vue'),
|
||||||
meta: { title: '部门管理', icon: 'mind-mapping', hidden: false, sort: 2.5 },
|
redirect: '/organization/hr/member',
|
||||||
},
|
meta: { title: '人员管理', icon: 'user', hidden: false },
|
||||||
{
|
|
||||||
path: '/organization/post',
|
|
||||||
name: 'OrganizationPost',
|
|
||||||
component: () => import('@/views/system/post/index.vue'),
|
|
||||||
meta: { title: '岗位管理', icon: 'nav', hidden: false, sort: 2.75 },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/regulation',
|
|
||||||
name: 'Regulation',
|
|
||||||
// component: Layout,
|
|
||||||
redirect: '/regulation/system-regulation',
|
|
||||||
meta: { title: '制度管理', icon: 'file-text', hidden: false, sort: 1.5 },
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/regulation/system-regulation',
|
path: '/organization/hr/member',
|
||||||
name: 'SystemRegulation',
|
name: 'HRMember',
|
||||||
component: () => import('@/views/regulation/repository.vue'),
|
component: () => import('@/views/system/user/index.vue'),
|
||||||
meta: { title: '制度公告', icon: 'file-text', hidden: false },
|
meta: { title: '成员', icon: 'user', hidden: false },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/regulation/process-management',
|
path: '/organization/hr/dept',
|
||||||
name: 'ProcessManagement',
|
name: 'HRDept',
|
||||||
component: () => import('@/views/regulation/confirm.vue'),
|
component: () => import('@/views/system/dept/index.vue'),
|
||||||
meta: { title: '制度公示', icon: 'workflow', hidden: false },
|
meta: { title: '部门', icon: 'dept', hidden: false },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/regulation/proposal',
|
path: '/organization/hr/workload',
|
||||||
name: 'RegulationProposal',
|
name: 'HRWorkload',
|
||||||
component: () => import('@/views/regulation/proposal/index.vue'),
|
component: () => import('@/views/hr/workload/index.vue'),
|
||||||
meta: { title: '制度提案', icon: 'edit', hidden: false },
|
meta: { title: '任务管理', icon: 'workload', hidden: false },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/regulation/type',
|
path: '/organization/hr/attendance',
|
||||||
name: 'RegulationType',
|
name: 'HRAttendance',
|
||||||
component: () => import('@/views/regulation/type/index.vue'),
|
component: () => import('@/views/hr/attendance/index.vue'),
|
||||||
meta: { title: '制度类型', icon: 'tag', hidden: false },
|
meta: { title: '考勤', icon: 'attendance', hidden: false },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/organization/hr/performance',
|
||||||
|
name: 'HRPerformance',
|
||||||
|
component: () => import('@/components/ParentView/index.vue'),
|
||||||
|
meta: { title: '绩效', icon: 'performance', hidden: false },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/organization/hr/performance/dimention',
|
||||||
|
name: 'Dimention',
|
||||||
|
component: () => import('@/views/performance/setting/index.vue'),
|
||||||
|
meta: { title: '绩效维度', icon: 'performance', hidden: false },
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/organization/hr/performance/rule',
|
||||||
|
name: 'Rule',
|
||||||
|
component: () => import('@/views/performance/rule.vue'),
|
||||||
|
meta: { title: '绩效细则', icon: 'performance', hidden: false },
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/organization/hr/performance/my',
|
||||||
|
name: 'MyPerformance',
|
||||||
|
component: () => import('@/views/performance/my.vue'),
|
||||||
|
meta: { title: '我的绩效', icon: 'performance', hidden: false },
|
||||||
|
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/organization/hr/salary',
|
||||||
|
name: 'HRSalary',
|
||||||
|
component: () => import('@/components/ParentView/index.vue'),
|
||||||
|
redirect: '/organization/hr/salary/overview',
|
||||||
|
meta: { title: '工资', icon: 'salary', hidden: false },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/organization/hr/salary/overview',
|
||||||
|
name: 'HRSalaryOverview',
|
||||||
|
component: () => import('@/components/ParentView/index.vue'),
|
||||||
|
meta: { title: '工资概览', icon: 'salary', hidden: false },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/organization/hr/salary/payroll',
|
||||||
|
name: 'Payroll',
|
||||||
|
component: () => import('@/views/salary-management/index.vue'),
|
||||||
|
meta: { title: '工资单', icon: 'salary', hidden: false },
|
||||||
|
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// path: '/organization/hr/salary/insurance',
|
||||||
|
// name: 'HRInsurance',
|
||||||
|
// component: () => import('@/components/ParentView/index.vue'),
|
||||||
|
// redirect: '/organization/hr/salary/insurance/overview',
|
||||||
|
// meta: { title: '保险', icon: 'safety', hidden: false },
|
||||||
|
// children: [
|
||||||
|
// {
|
||||||
|
// path: '/organization/hr/salary/insurance/overview',
|
||||||
|
// name: 'HRInsuranceOverview',
|
||||||
|
// component: () => import('@/views/hr/salary/insurance/overview/index.vue'),
|
||||||
|
// meta: { title: '工作台概览', icon: 'dashboard', hidden: false },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// path: '/organization/hr/salary/insurance/my-insurance',
|
||||||
|
// name: 'HRMyInsurance',
|
||||||
|
// component: () => import('@/views/hr/salary/insurance/my-insurance/index.vue'),
|
||||||
|
// meta: { title: '我的保险', icon: 'shield', hidden: false },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// path: '/organization/hr/salary/insurance/health-records',
|
||||||
|
// name: 'HRHealthRecords',
|
||||||
|
// component: () => import('@/views/hr/salary/insurance/health-records/index.vue'),
|
||||||
|
// meta: { title: '健康档案', icon: 'heart', hidden: false },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// path: '/organization/hr/salary/insurance/policy-files',
|
||||||
|
// name: 'HRPolicyFiles',
|
||||||
|
// component: () => import('@/views/hr/salary/insurance/policy-files/index.vue'),
|
||||||
|
// meta: { title: '保单文件', icon: 'file', hidden: false },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// path: '/organization/hr/salary/insurance/personal-info',
|
||||||
|
// name: 'HRPersonalInfo',
|
||||||
|
// component: () => import('@/views/hr/salary/insurance/personal-info/index.vue'),
|
||||||
|
// meta: { title: '个人信息', icon: 'user', hidden: false },
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
path: '/organization/hr/salary/system-insurance/health-management',
|
||||||
|
name: 'HRSystemHealthManagement',
|
||||||
|
component: () => import('@/views/hr/salary/system-insurance/health-management/index.vue'),
|
||||||
|
meta: { title: '健康档案管理', icon: 'heart', hidden: false },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/organization/hr/salary/system-insurance',
|
||||||
|
name: 'HRSystemInsurance',
|
||||||
|
component: () => import('@/components/ParentView/index.vue'),
|
||||||
|
redirect: '/organization/hr/salary/system-insurance/overview',
|
||||||
|
meta: { title: '人员保险', icon: 'settings', hidden: false },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/organization/hr/salary/system-insurance/overview',
|
||||||
|
name: 'HRSystemInsuranceOverview',
|
||||||
|
component: () => import('@/views/hr/salary/system-insurance/overview/index.vue'),
|
||||||
|
meta: { title: '工作台概览', icon: 'dashboard', hidden: false },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/organization/hr/salary/system-insurance/management',
|
||||||
|
name: 'HRSystemInsuranceManagement',
|
||||||
|
component: () => import('@/views/hr/salary/system-insurance/management/index.vue'),
|
||||||
|
meta: { title: '保险管理', icon: 'shield', hidden: false },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/organization/hr/salary/system-insurance/file-management',
|
||||||
|
name: 'HRSystemFileManagement',
|
||||||
|
component: () => import('@/views/hr/salary/system-insurance/file-management/index.vue'),
|
||||||
|
meta: { title: '保单文件管理', icon: 'file', hidden: false },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/organization/hr/salary/system-insurance/company-management',
|
||||||
|
name: 'HRSystemCompanyManagement',
|
||||||
|
component: () => import('@/views/hr/salary/system-insurance/company-management/index.vue'),
|
||||||
|
meta: { title: '保险公司管理', icon: 'building', hidden: false },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/organization/hr/salary/system-insurance/type-management',
|
||||||
|
name: 'HRSystemTypeManagement',
|
||||||
|
component: () => import('@/views/hr/salary/system-insurance/type-management/index.vue'),
|
||||||
|
meta: { title: '保险类型管理', icon: 'category', hidden: false },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/organization/hr/salary/certification',
|
||||||
|
name: 'HRCertification',
|
||||||
|
component: () => import('@/views/hr/salary/certification/index.vue'),
|
||||||
|
meta: { title: '人员资质管理', icon: 'idcard', hidden: false },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/organization/hr/contribution',
|
||||||
|
name: 'HRContribution',
|
||||||
|
component: () => import('@/views/hr/contribution/index.vue'),
|
||||||
|
meta: { title: '责献积分制度', icon: 'contribution', hidden: false },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// path: '/organization/hr/workload',
|
path: '/organization/role',
|
||||||
// name: 'HRWorkload',
|
name: 'OrganizationRole',
|
||||||
// component: () => import('@/views/hr/workload/index.vue'),
|
component: () => import('@/views/system/role/index.vue'),
|
||||||
// meta: { title: '任务管理', icon: 'bookmark', hidden: false },
|
meta: { title: '角色管理', icon: 'role', hidden: false },
|
||||||
// },
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// {
|
|
||||||
// path: '/organization',
|
|
||||||
// name: 'Organization',
|
|
||||||
// component: Layout,
|
|
||||||
// redirect: '/organization/hr/member',
|
|
||||||
// meta: { title: '组织架构', icon: 'user-group', hidden: false, sort: 2 },
|
|
||||||
// children: [
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr',
|
|
||||||
// name: 'HRManagement',
|
|
||||||
// component: () => import('@/components/ParentView/index.vue'),
|
|
||||||
// redirect: '/organization/hr/member',
|
|
||||||
// meta: { title: '人员管理', icon: 'user', hidden: false },
|
|
||||||
// children: [
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/member',
|
|
||||||
// name: 'HRMember',
|
|
||||||
// component: () => import('@/views/system/user/index.vue'),
|
|
||||||
// meta: { title: '成员', icon: 'user', hidden: false },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/dept',
|
|
||||||
// name: 'HRDept',
|
|
||||||
// component: () => import('@/views/system/dept/index.vue'),
|
|
||||||
// meta: { title: '部门', icon: 'dept', hidden: false },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/workload',
|
|
||||||
// name: 'HRWorkload',
|
|
||||||
// component: () => import('@/views/hr/workload/index.vue'),
|
|
||||||
// meta: { title: '任务管理', icon: 'workload', hidden: false },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/attendance',
|
|
||||||
// name: 'HRAttendance',
|
|
||||||
// component: () => import('@/views/hr/attendance/index.vue'),
|
|
||||||
// meta: { title: '考勤', icon: 'attendance', hidden: false },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/performance',
|
|
||||||
// name: 'HRPerformance',
|
|
||||||
// component: () => import('@/components/ParentView/index.vue'),
|
|
||||||
// meta: { title: '绩效', icon: 'performance', hidden: false },
|
|
||||||
// children: [
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/performance/dimention',
|
|
||||||
// name: 'Dimention',
|
|
||||||
// component: () => import('@/views/performance/setting/index.vue'),
|
|
||||||
// meta: { title: '绩效维度', icon: 'performance', hidden: false },
|
|
||||||
//
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/performance/rule',
|
|
||||||
// name: 'Rule',
|
|
||||||
// component: () => import('@/views/performance/rule.vue'),
|
|
||||||
// meta: { title: '绩效细则', icon: 'performance', hidden: false },
|
|
||||||
//
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/performance/my',
|
|
||||||
// name: 'MyPerformance',
|
|
||||||
// component: () => import('@/views/performance/my.vue'),
|
|
||||||
// meta: { title: '我的绩效', icon: 'performance', hidden: false },
|
|
||||||
//
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/salary',
|
|
||||||
// name: 'HRSalary',
|
|
||||||
// component: () => import('@/components/ParentView/index.vue'),
|
|
||||||
// redirect: '/organization/hr/salary/overview',
|
|
||||||
// meta: { title: '工资', icon: 'salary', hidden: false },
|
|
||||||
// children: [
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/salary/overview',
|
|
||||||
// name: 'HRSalaryOverview',
|
|
||||||
// component: () => import('@/components/ParentView/index.vue'),
|
|
||||||
// meta: { title: '工资概览', icon: 'salary', hidden: false },
|
|
||||||
// children: [
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/salary/payroll',
|
|
||||||
// name: 'Payroll',
|
|
||||||
// component: () => import('@/views/salary-management/index.vue'),
|
|
||||||
// meta: { title: '工资单', icon: 'salary', hidden: false },
|
|
||||||
//
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
//
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/salary/insurance',
|
|
||||||
// name: 'HRInsurance',
|
|
||||||
// component: () => import('@/components/ParentView/index.vue'),
|
|
||||||
// redirect: '/organization/hr/salary/insurance/overview',
|
|
||||||
// meta: { title: '保险', icon: 'safety', hidden: false },
|
|
||||||
// children: [
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/salary/insurance/overview',
|
|
||||||
// name: 'HRInsuranceOverview',
|
|
||||||
// component: () => import('@/views/hr/salary/insurance/overview/index.vue'),
|
|
||||||
// meta: { title: '工作台概览', icon: 'dashboard', hidden: false },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/salary/insurance/my-insurance',
|
|
||||||
// name: 'HRMyInsurance',
|
|
||||||
// component: () => import('@/views/hr/salary/insurance/my-insurance/index.vue'),
|
|
||||||
// meta: { title: '我的保险', icon: 'shield', hidden: false },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/salary/insurance/health-records',
|
|
||||||
// name: 'HRHealthRecords',
|
|
||||||
// component: () => import('@/views/hr/salary/insurance/health-records/index.vue'),
|
|
||||||
// meta: { title: '健康档案', icon: 'heart', hidden: false },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/salary/insurance/policy-files',
|
|
||||||
// name: 'HRPolicyFiles',
|
|
||||||
// component: () => import('@/views/hr/salary/insurance/policy-files/index.vue'),
|
|
||||||
// meta: { title: '保单文件', icon: 'file', hidden: false },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/salary/insurance/personal-info',
|
|
||||||
// name: 'HRPersonalInfo',
|
|
||||||
// component: () => import('@/views/hr/salary/insurance/personal-info/index.vue'),
|
|
||||||
// meta: { title: '个人信息', icon: 'user', hidden: false },
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
//
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/salary/system-insurance/health-management',
|
|
||||||
// name: 'HRSystemHealthManagement',
|
|
||||||
// component: () => import('@/views/hr/salary/system-insurance/health-management/index.vue'),
|
|
||||||
// meta: { title: '健康档案管理', icon: 'heart', hidden: false },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/salary/system-insurance',
|
|
||||||
// name: 'HRSystemInsurance',
|
|
||||||
// component: () => import('@/components/ParentView/index.vue'),
|
|
||||||
// redirect: '/organization/hr/salary/system-insurance/overview',
|
|
||||||
// meta: { title: '人员保险', icon: 'settings', hidden: false },
|
|
||||||
// children: [
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/salary/system-insurance/overview',
|
|
||||||
// name: 'HRSystemInsuranceOverview',
|
|
||||||
// component: () => import('@/views/hr/salary/system-insurance/overview/index.vue'),
|
|
||||||
// meta: { title: '工作台概览', icon: 'dashboard', hidden: false },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/salary/system-insurance/management',
|
|
||||||
// name: 'HRSystemInsuranceManagement',
|
|
||||||
// component: () => import('@/views/hr/salary/system-insurance/management/index.vue'),
|
|
||||||
// meta: { title: '保险管理', icon: 'shield', hidden: false },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/salary/system-insurance/file-management',
|
|
||||||
// name: 'HRSystemFileManagement',
|
|
||||||
// component: () => import('@/views/hr/salary/system-insurance/file-management/index.vue'),
|
|
||||||
// meta: { title: '保单文件管理', icon: 'file', hidden: false },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/salary/system-insurance/company-management',
|
|
||||||
// name: 'HRSystemCompanyManagement',
|
|
||||||
// component: () => import('@/views/hr/salary/system-insurance/company-management/index.vue'),
|
|
||||||
// meta: { title: '保险公司管理', icon: 'building', hidden: false },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/salary/system-insurance/type-management',
|
|
||||||
// name: 'HRSystemTypeManagement',
|
|
||||||
// component: () => import('@/views/hr/salary/system-insurance/type-management/index.vue'),
|
|
||||||
// meta: { title: '保险类型管理', icon: 'category', hidden: false },
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/salary/certification',
|
|
||||||
// name: 'HRCertification',
|
|
||||||
// component: () => import('@/views/hr/salary/certification/index.vue'),
|
|
||||||
// meta: { title: '人员资质管理', icon: 'idcard', hidden: false },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/organization/hr/contribution',
|
|
||||||
// name: 'HRContribution',
|
|
||||||
// component: () => import('@/views/hr/contribution/index.vue'),
|
|
||||||
// meta: { title: '责献积分制度', icon: 'contribution', hidden: false },
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/organization/role',
|
|
||||||
// name: 'OrganizationRole',
|
|
||||||
// component: () => import('@/views/system/role/index.vue'),
|
|
||||||
// meta: { title: '角色管理', icon: 'role', hidden: false },
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
path: '/asset-management',
|
path: '/asset-management',
|
||||||
name: 'AssetManagement',
|
name: 'AssetManagement',
|
||||||
|
@ -533,86 +432,99 @@ export const systemRoutes: RouteRecordRaw[] = [
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/project-marketing',
|
path: '/project-management',
|
||||||
name: 'Projectmarketing',
|
name: 'ProjectManagement',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/project-marketing/project-marketing',
|
redirect: '/project-management/project-template/project-management',
|
||||||
meta: { title: '营销管理', icon: 'file-text', hidden: false, sort: 3 },
|
meta: { title: '项目管理', icon: 'apps', hidden: false, sort: 4 },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/project-marketing/contract/revenue-contract2',
|
path: '/project-management/contract/project-source',
|
||||||
name: 'RevenueContract2',
|
name: 'ProjectSource',
|
||||||
component: () => import('@/views/default/error/404.vue'),
|
|
||||||
meta: {
|
|
||||||
title: '市场营销(N)',
|
|
||||||
icon: 'dollar',
|
|
||||||
hidden: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/project-marketing/contract/procurement-business',
|
|
||||||
name: 'ProcurementBusiness',
|
|
||||||
component: () => import('@/components/ParentView/index.vue'),
|
component: () => import('@/components/ParentView/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: '招采业务',
|
title: '项目来源',
|
||||||
icon: 'dollar',
|
icon: 'dollar',
|
||||||
hidden: false,
|
hidden: false,
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/project-marketing/project-template/tender-documents',
|
path: '/project-management/contract/procurement-business',
|
||||||
name: 'TenderDocuments',
|
name: 'ProcurementBusiness',
|
||||||
component: () => import('@/views/project-management/bidding/tender-documents/index.vue'),
|
component: () => import('@/components/ParentView/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: '招标文件',
|
title: '招采业务',
|
||||||
icon: 'file-text',
|
icon: 'dollar',
|
||||||
|
hidden: false,
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/project-management/project-template/tender-documents',
|
||||||
|
name: 'TenderDocuments',
|
||||||
|
component: () => import('@/views/project-management/bidding/tender-documents/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '招标文件',
|
||||||
|
icon: 'file-text',
|
||||||
|
hidden: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/project-management/project-template/bid-documents',
|
||||||
|
name: 'BidDocuments',
|
||||||
|
component: () => import('@/views/project-management/bidding/bid-documents/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '投标文件',
|
||||||
|
icon: 'file-text',
|
||||||
|
hidden: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/project-management/project-template/award-notice',
|
||||||
|
name: 'AwardNotice',
|
||||||
|
component: () => import('@/views/project-management/bidding/award-notice/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '中标通知书',
|
||||||
|
icon: 'trophy',
|
||||||
|
hidden: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'project-management/project-template/information-retrieval',
|
||||||
|
name: 'InformationRetrieval',
|
||||||
|
component: () => import ('@/views/default/error/404.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '信息检索(N)',
|
||||||
|
icon: 'trophy',
|
||||||
|
hidden: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/project-management/contract/revenue-contract2',
|
||||||
|
name: 'RevenueContract2',
|
||||||
|
component: () => import('@/views/default/error/404.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '市场营销(N)',
|
||||||
|
icon: 'dollar',
|
||||||
hidden: false,
|
hidden: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/project-marketing/project-template/bid-documents',
|
path: '/project-management/project-source/privateproject',
|
||||||
name: 'BidDocuments',
|
name: 'PrivateProject',
|
||||||
component: () => import('@/views/project-management/bidding/bid-documents/index.vue'),
|
component: () => import('@/views/default/error/404.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: '投标文件',
|
title: '自建项目(N)',
|
||||||
icon: 'file-text',
|
icon: 'dollar',
|
||||||
hidden: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/project-marketing/project-template/award-notice',
|
|
||||||
name: 'AwardNotice',
|
|
||||||
component: () => import('@/views/project-management/bidding/award-notice/index.vue'),
|
|
||||||
meta: {
|
|
||||||
title: '中标通知书',
|
|
||||||
icon: 'trophy',
|
|
||||||
hidden: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/project-marketing/project-template/information-retrieval',
|
|
||||||
name: 'InformationRetrieval',
|
|
||||||
component: () => import ('@/views/project-management/bidding/information-retrieval/index.vue'),
|
|
||||||
meta: {
|
|
||||||
title: '信息检索(N)',
|
|
||||||
icon: 'trophy',
|
|
||||||
hidden: false,
|
hidden: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/project-marketing/order-management/order-management',
|
|
||||||
name: 'OrderManagement',
|
|
||||||
component: () => import('@/views/project-management/order-management/index.vue'),
|
|
||||||
meta: {
|
|
||||||
title: '订单管理',
|
|
||||||
icon: 'file-text',
|
|
||||||
hidden: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{ path: '/project-management/contract', name: 'ProjectContract', component: () => import('@/components/ParentView/index.vue'), redirect: '/project-management/contract/revenue-contract', meta: {
|
{ path: '/project-management/contract', name: 'ProjectContract', component: () => import('@/components/ParentView/index.vue'), redirect: '/project-management/contract/revenue-contract', meta: {
|
||||||
title: '合同管理',
|
title: '项目合同',
|
||||||
icon: 'file-text',
|
icon: 'file-text',
|
||||||
hidden: false,
|
hidden: false,
|
||||||
}, children: [
|
}, children: [
|
||||||
|
@ -647,136 +559,6 @@ export const systemRoutes: RouteRecordRaw[] = [
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
] },
|
] },
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/project-management',
|
|
||||||
name: 'ProjectManagement',
|
|
||||||
component: Layout,
|
|
||||||
redirect: '/project-management/project-template/project-management',
|
|
||||||
meta: { title: '项目管理', icon: 'apps', hidden: false, sort: 4 },
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: '/project-management/contract/project-source',
|
|
||||||
name: 'ProjectSource',
|
|
||||||
component: () => import('@/components/ParentView/index.vue'),
|
|
||||||
meta: {
|
|
||||||
title: '项目来源',
|
|
||||||
icon: 'dollar',
|
|
||||||
hidden: false,
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
// {
|
|
||||||
// path: '/project-management/contract/procurement-business',
|
|
||||||
// name: 'ProcurementBusiness',
|
|
||||||
// component: () => import('@/components/ParentView/index.vue'),
|
|
||||||
// meta: {
|
|
||||||
// title: '招采业务',
|
|
||||||
// icon: 'dollar',
|
|
||||||
// hidden: false,
|
|
||||||
// },
|
|
||||||
// children: [
|
|
||||||
// {
|
|
||||||
// path: '/project-management/project-template/tender-documents',
|
|
||||||
// name: 'TenderDocuments',
|
|
||||||
// component: () => import('@/views/project-management/bidding/tender-documents/index.vue'),
|
|
||||||
// meta: {
|
|
||||||
// title: '招标文件',
|
|
||||||
// icon: 'file-text',
|
|
||||||
// hidden: false,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/project-management/project-template/bid-documents',
|
|
||||||
// name: 'BidDocuments',
|
|
||||||
// component: () => import('@/views/project-management/bidding/bid-documents/index.vue'),
|
|
||||||
// meta: {
|
|
||||||
// title: '投标文件',
|
|
||||||
// icon: 'file-text',
|
|
||||||
// hidden: false,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/project-management/project-template/award-notice',
|
|
||||||
// name: 'AwardNotice',
|
|
||||||
// component: () => import('@/views/project-management/bidding/award-notice/index.vue'),
|
|
||||||
// meta: {
|
|
||||||
// title: '中标通知书',
|
|
||||||
// icon: 'trophy',
|
|
||||||
// hidden: false,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/project-management/project-template/information-retrieval',
|
|
||||||
// name: 'InformationRetrieval',
|
|
||||||
// component: () => import ('@/views/project-management/bidding/information-retrieval/index.vue'),
|
|
||||||
// meta: {
|
|
||||||
// title: '信息检索(N)',
|
|
||||||
// icon: 'trophy',
|
|
||||||
// hidden: false,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
//
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/project-management/contract/revenue-contract2',
|
|
||||||
// name: 'RevenueContract2',
|
|
||||||
// component: () => import('@/views/default/error/404.vue'),
|
|
||||||
// meta: {
|
|
||||||
// title: '市场营销(N)',
|
|
||||||
// icon: 'dollar',
|
|
||||||
// hidden: false,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
{
|
|
||||||
path: '/project-management/project-source/privateproject',
|
|
||||||
name: 'PrivateProject',
|
|
||||||
component: () => import('@/views/default/error/404.vue'),
|
|
||||||
meta: {
|
|
||||||
title: '自建项目(N)',
|
|
||||||
icon: 'dollar',
|
|
||||||
hidden: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
// { path: '/project-management/contract', name: 'ProjectContract', component: () => import('@/components/ParentView/index.vue'), redirect: '/project-management/contract/revenue-contract', meta: {
|
|
||||||
// title: '项目合同',
|
|
||||||
// icon: 'file-text',
|
|
||||||
// hidden: false,
|
|
||||||
// }, children: [
|
|
||||||
// {
|
|
||||||
// path: '/project-management/contract/revenue-contract',
|
|
||||||
// name: 'RevenueContract',
|
|
||||||
// component: () => import('@/views/project-management/contract/revenue-contract/index.vue'),
|
|
||||||
// meta: {
|
|
||||||
// title: '收入合同',
|
|
||||||
// icon: 'dollar',
|
|
||||||
// hidden: false,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/project-management/contract/expense-contract',
|
|
||||||
// name: 'ExpenseContract',
|
|
||||||
// component: () => import('@/views/project-management/contract/expense-contract/index.vue'),
|
|
||||||
// meta: {
|
|
||||||
// title: '支出合同',
|
|
||||||
// icon: 'credit-card',
|
|
||||||
// hidden: false,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: '/project-management/contract/cost-management',
|
|
||||||
// name: 'CostManagement',
|
|
||||||
// component: () => import('@/views/project-management/contract/cost-management/index.vue'),
|
|
||||||
// meta: {
|
|
||||||
// title: '成本费用',
|
|
||||||
// icon: 'bar-chart',
|
|
||||||
// hidden: false,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// ] },
|
|
||||||
{
|
{
|
||||||
path: '/project-management/project-template/project-aproval',
|
path: '/project-management/project-template/project-aproval',
|
||||||
name: 'ProjectTemplate',
|
name: 'ProjectTemplate',
|
||||||
|
@ -852,26 +634,6 @@ export const systemRoutes: RouteRecordRaw[] = [
|
||||||
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// 添加商务知识库
|
|
||||||
{
|
|
||||||
path: '/bussiness-knowledge',
|
|
||||||
name: 'bussinesskonwledge',
|
|
||||||
component: Layout,
|
|
||||||
redirect: '/bussiness-knowledge/data',
|
|
||||||
meta: { title: '商务资料知识库', icon: 'message', hidden: false, sort: 6 },
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: '/bussiness-konwledge/data',
|
|
||||||
name: 'bussiness-knowledge',
|
|
||||||
component: () => import('@/views/bussiness-data/bussiness.vue'),
|
|
||||||
meta: {
|
|
||||||
title: '商务数据库信息',
|
|
||||||
icon: 'info-circle',
|
|
||||||
hidden: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: 'project-management/project-implementation/',
|
path: 'project-management/project-implementation/',
|
||||||
name: 'Project-Implementation',
|
name: 'Project-Implementation',
|
||||||
|
@ -978,11 +740,11 @@ export const systemRoutes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
path: '/construction-operation-platform/implementation-workflow/data-processing/data-storage/attachment',
|
path: '/construction-operation-platform/implementation-workflow/data-processing/data-storage/attachment',
|
||||||
name: 'AttachmentManagement',
|
name: 'AttachmentManagement',
|
||||||
component: () => import('@/views/construction-operation-platform/implementation-workflow/data-processing/data-storage/index.vue'),
|
component: () => import('@/views/operation-platform/data-processing/data-storage/index.vue'),
|
||||||
meta: { title: '附件管理', icon: 'attachment', hidden: false },
|
meta: { title: '附件管理', icon: 'attachment', hidden: false },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/construction-operation-platform/implementation-workflow/data-processing/model-config',
|
path: '/construction-operation-platform/implementation-workflow/data-processing/data-storage/model-config',
|
||||||
name: 'ModelConfig',
|
name: 'ModelConfig',
|
||||||
component: () => import('@/views/construction-operation-platform/implementation-workflow/data-processing/model-config/index.vue'),
|
component: () => import('@/views/construction-operation-platform/implementation-workflow/data-processing/model-config/index.vue'),
|
||||||
meta: { title: '模型配置', icon: 'robot', hidden: false },
|
meta: { title: '模型配置', icon: 'robot', hidden: false },
|
||||||
|
@ -993,23 +755,8 @@ export const systemRoutes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
path: '/construction-operation-platform/implementation-workflow/data-processing/data-storage/preprocessed-data',
|
path: '/construction-operation-platform/implementation-workflow/data-processing/data-storage/preprocessed-data',
|
||||||
name: 'PreprocessedData',
|
name: 'PreprocessedData',
|
||||||
component: () => import('@/components/ParentView/index.vue'),
|
component: () => import('@/views/construction-operation-platform/implementation-workflow/data-processing/data-preprocessing/index.vue'),
|
||||||
redirect: '/construction-operation-platform/implementation-workflow/data-processing/data-storage',
|
|
||||||
meta: { title: '数据预处理', icon: 'filter', hidden: false },
|
meta: { title: '数据预处理', icon: 'filter', hidden: false },
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: '/construction-operation-platform/implementation-workflow/data-processing/data-storage/preprocessed-data/ImageBatchUpload',
|
|
||||||
name: 'ImageBatchUpload',
|
|
||||||
component: () => import('@/views/construction-operation-platform/implementation-workflow/data-processing/data-preprocessing/index.vue'),
|
|
||||||
meta: { title: '批量上传', icon: 'file', hidden: false },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/construction-operation-platform/implementation-workflow/data-processing/data-storage/preprocessed-data/ImageSorting',
|
|
||||||
name: 'ImageSorting',
|
|
||||||
component: () => import('@/views/construction-operation-platform/implementation-workflow/data-processing/image-sorting/index.vue'),
|
|
||||||
meta: { title: '图像分拣', icon: 'attachment', hidden: false },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/construction-operation-platform/implementation-workflow/data-processing/intelligent-inspection',
|
path: '/construction-operation-platform/implementation-workflow/data-processing/intelligent-inspection',
|
||||||
|
@ -1164,14 +911,32 @@ export const systemRoutes: RouteRecordRaw[] = [
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// ],
|
// 添加商务知识库
|
||||||
// },
|
{
|
||||||
|
path: '/bussiness-knowledge',
|
||||||
|
name: 'bussinesskonwledge',
|
||||||
|
component: Layout,
|
||||||
|
redirect: '/bussiness-knowledge/data',
|
||||||
|
meta: { title: '商务资料知识库', icon: 'message', hidden: false, sort: 6 },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/bussiness-konwledge/data',
|
||||||
|
name: 'bussiness-knowledge',
|
||||||
|
component: () => import('@/views/bussiness-data/bussiness.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '商务数据库信息',
|
||||||
|
icon: 'info-circle',
|
||||||
|
hidden: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/chat-platform',
|
path: '/chat-platform',
|
||||||
name: 'ChatPlatform',
|
name: 'ChatPlatform',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/chat-platform/options',
|
redirect: '/chat-platform/options',
|
||||||
meta: { title: '聊天平台', icon: 'message', hidden: false, sort: 6 },
|
meta: { title: '聊天平台', icon: 'message', hidden: false, sort: 7 },
|
||||||
children: [
|
children: [
|
||||||
// {
|
// {
|
||||||
// path: '/chat-platform/options',
|
// path: '/chat-platform/options',
|
||||||
|
@ -1185,36 +950,12 @@ export const systemRoutes: RouteRecordRaw[] = [
|
||||||
// }
|
// }
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// {
|
|
||||||
// path: '/user/profile',
|
|
||||||
// name: 'UserProfile',
|
|
||||||
// component: Layout,
|
|
||||||
// redirect: '/user/profile',
|
|
||||||
// meta: {
|
|
||||||
// title: '个人中心',
|
|
||||||
// icon: 'user',
|
|
||||||
// hidden: false,
|
|
||||||
// sort: 100,
|
|
||||||
// },
|
|
||||||
// children: [
|
|
||||||
// {
|
|
||||||
// path: '/user/profile',
|
|
||||||
// name: 'UsersProfile',
|
|
||||||
// component: () => import('@/views/user/profile/index.vue'),
|
|
||||||
// meta: {
|
|
||||||
// title: '个人中心',
|
|
||||||
// icon: 'user',
|
|
||||||
// hidden: false,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
path: '/enterprise-settings',
|
path: '/enterprise-settings',
|
||||||
name: 'EnterpriseSettings',
|
name: 'EnterpriseSettings',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/enterprise-settings/company-info',
|
redirect: '/enterprise-settings/company-info',
|
||||||
meta: { title: '企业设置', icon: 'setting', hidden: false, sort: 7 },
|
meta: { title: '企业设置', icon: 'setting', hidden: false, sort: 8 },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/enterprise-settings/company-info',
|
path: '/enterprise-settings/company-info',
|
||||||
|
@ -1263,7 +1004,7 @@ export const systemRoutes: RouteRecordRaw[] = [
|
||||||
name: 'EnterpriseDashboard',
|
name: 'EnterpriseDashboard',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/enterprise-dashboard/overview',
|
redirect: '/enterprise-dashboard/overview',
|
||||||
meta: { title: '企业看板', icon: 'dashboard', hidden: false, sort: 8 },
|
meta: { title: '企业看板', icon: 'dashboard', hidden: false, sort: 9},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/enterprise-dashboard/overview',
|
path: '/enterprise-dashboard/overview',
|
||||||
|
@ -1312,7 +1053,7 @@ export const systemRoutes: RouteRecordRaw[] = [
|
||||||
name: 'SystemResource',
|
name: 'SystemResource',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/system-resource/device-management/warehouse',
|
redirect: '/system-resource/device-management/warehouse',
|
||||||
meta: { title: '关于平台', icon: 'server', hidden: false, sort: 9 },
|
meta: { title: '关于平台', icon: 'server', hidden: false, sort: 10 },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/system-resource/device-management/warehouse',
|
path: '/system-resource/device-management/warehouse',
|
||||||
|
@ -1412,6 +1153,7 @@ export const systemRoutes: RouteRecordRaw[] = [
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
redirect: '/project-management/project-template/project-aproval',
|
redirect: '/project-management/project-template/project-aproval',
|
||||||
|
@ -1437,11 +1179,6 @@ export const constantRoutes: RouteRecordRaw[] = [
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// {
|
|
||||||
// path: '/user/profile',
|
|
||||||
// component: () => import('@/views/user/profile/index.vue'),
|
|
||||||
// meta: { hidden: true },
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
path: '/:pathMatch(.*)*',
|
path: '/:pathMatch(.*)*',
|
||||||
component: () => import('@/views/default/error/404.vue'),
|
component: () => import('@/views/default/error/404.vue'),
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
import { defineStore } from 'pinia'
|
|
||||||
import { ref } from 'vue'
|
|
||||||
|
|
||||||
export interface Regulation {
|
|
||||||
id: string
|
|
||||||
name: string
|
|
||||||
type: string
|
|
||||||
typeName: string
|
|
||||||
publisher: string
|
|
||||||
publishTime: string
|
|
||||||
effectiveDate: string
|
|
||||||
confirmStatus: 'pending' | 'confirmed'
|
|
||||||
content: string
|
|
||||||
scope: string
|
|
||||||
requirements: string
|
|
||||||
notes: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useRegulationStore = defineStore('regulation', () => {
|
|
||||||
// 已发布的制度列表
|
|
||||||
const publishedRegulations = ref<Regulation[]>([])
|
|
||||||
|
|
||||||
// 添加新发布的制度
|
|
||||||
const addPublishedRegulation = (regulation: Regulation) => {
|
|
||||||
publishedRegulations.value.unshift(regulation)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新制度确认状态
|
|
||||||
const updateRegulationConfirmStatus = (id: string, status: 'pending' | 'confirmed') => {
|
|
||||||
const regulation = publishedRegulations.value.find(item => item.id === id)
|
|
||||||
if (regulation) {
|
|
||||||
regulation.confirmStatus = status
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 批量确认所有制度
|
|
||||||
const confirmAllRegulations = () => {
|
|
||||||
publishedRegulations.value.forEach(regulation => {
|
|
||||||
regulation.confirmStatus = 'confirmed'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
publishedRegulations,
|
|
||||||
addPublishedRegulation,
|
|
||||||
updateRegulationConfirmStatus,
|
|
||||||
confirmAllRegulations
|
|
||||||
}
|
|
||||||
})
|
|
|
@ -4,9 +4,10 @@ import type { RouteRecordRaw } from 'vue-router'
|
||||||
import { mapTree, toTreeArray } from 'xe-utils'
|
import { mapTree, toTreeArray } from 'xe-utils'
|
||||||
import { cloneDeep, omit } from 'lodash-es'
|
import { cloneDeep, omit } from 'lodash-es'
|
||||||
import { constantRoutes, systemRoutes } from '@/router/route'
|
import { constantRoutes, systemRoutes } from '@/router/route'
|
||||||
import type { RouteItem } from '@/apis'
|
import { type RouteItem, getUserRouteWithAdapter } from '@/apis'
|
||||||
import { transformPathToName } from '@/utils'
|
import { transformPathToName } from '@/utils'
|
||||||
import { asyncRouteModules } from '@/router/asyncModules'
|
import { asyncRouteModules } from '@/router/asyncModules'
|
||||||
|
import { convertMenuData, type ApiMenuItem } from '@/utils/menuConverter'
|
||||||
|
|
||||||
const layoutComponentMap = {
|
const layoutComponentMap = {
|
||||||
Layout: () => import('@/layout/index.vue'),
|
Layout: () => import('@/layout/index.vue'),
|
||||||
|
@ -93,77 +94,91 @@ const storeSetup = () => {
|
||||||
// 获取路由数据并已通过适配器转换
|
// 获取路由数据并已通过适配器转换
|
||||||
// const { data } = await getUserRouteWithAdapter()
|
// const { data } = await getUserRouteWithAdapter()
|
||||||
const data = [{
|
const data = [{
|
||||||
id: 1000,
|
"id": 1000,
|
||||||
parentId: 0,
|
"parentId": 0,
|
||||||
title: '系统管理',
|
"title": "系统管理",
|
||||||
type: 1,
|
"type": 1,
|
||||||
path: '/system',
|
"path": "/system",
|
||||||
name: 'System',
|
"name": "System",
|
||||||
component: 'Layout',
|
"component": "Layout",
|
||||||
redirect: '/system/user',
|
"redirect": "/system/user",
|
||||||
icon: 'settings',
|
"icon": "settings",
|
||||||
isExternal: false,
|
"isExternal": false,
|
||||||
isCache: false,
|
"isCache": false,
|
||||||
isHidden: false,
|
"isHidden": false,
|
||||||
sort: 1,
|
"sort": 1,
|
||||||
children: [
|
"children": [
|
||||||
{
|
{
|
||||||
id: 1010,
|
"id": 1010,
|
||||||
parentId: 1000,
|
"parentId": 1000,
|
||||||
title: '用户管理',
|
"title": "用户管理",
|
||||||
type: 2,
|
"type": 2,
|
||||||
path: '/system/user',
|
"path": "/system/user",
|
||||||
name: 'SystemUser',
|
"name": "SystemUser",
|
||||||
component: 'system/user/index',
|
"component": "system/user/index",
|
||||||
icon: 'user',
|
"icon": "user",
|
||||||
isExternal: false,
|
"isExternal": false,
|
||||||
isCache: false,
|
"isCache": false,
|
||||||
isHidden: false,
|
"isHidden": false,
|
||||||
sort: 1,
|
"sort": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 1030,
|
"id": 1030,
|
||||||
parentId: 1000,
|
"parentId": 1000,
|
||||||
title: '角色管理',
|
"title": "角色管理",
|
||||||
type: 2,
|
"type": 2,
|
||||||
path: '/system/role',
|
"path": "/system/role",
|
||||||
name: 'SystemRole',
|
"name": "SystemRole",
|
||||||
component: 'system/role/index',
|
"component": "system/role/index",
|
||||||
icon: 'user-group',
|
"icon": "user-group",
|
||||||
isExternal: false,
|
"isExternal": false,
|
||||||
isCache: false,
|
"isCache": false,
|
||||||
isHidden: false,
|
"isHidden": false,
|
||||||
sort: 2,
|
"sort": 2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 1050,
|
"id": 1050,
|
||||||
parentId: 1000,
|
"parentId": 1000,
|
||||||
title: '菜单管理',
|
"title": "菜单管理",
|
||||||
type: 2,
|
"type": 2,
|
||||||
path: '/system/menu',
|
"path": "/system/menu",
|
||||||
name: 'SystemMenu',
|
"name": "SystemMenu",
|
||||||
component: 'system/menu/index',
|
"component": "system/menu/index",
|
||||||
icon: 'menu',
|
"icon": "menu",
|
||||||
isExternal: false,
|
"isExternal": false,
|
||||||
isCache: false,
|
"isCache": false,
|
||||||
isHidden: false,
|
"isHidden": false,
|
||||||
sort: 3,
|
"sort": 3
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 1070,
|
"id": 1070,
|
||||||
parentId: 1000,
|
"parentId": 1000,
|
||||||
title: '个人中心',
|
"title": "部门管理",
|
||||||
type: 2,
|
"type": 2,
|
||||||
path: '/user/profile',
|
"path": "/system/dept",
|
||||||
name: 'UserProfile',
|
"name": "SystemDept",
|
||||||
component: 'user/profile/index',
|
"component": "system/dept/index",
|
||||||
icon: 'user',
|
"icon": "mind-mapping",
|
||||||
isExternal: false,
|
"isExternal": false,
|
||||||
isCache: false,
|
"isCache": false,
|
||||||
isHidden: false,
|
"isHidden": false,
|
||||||
sort: 4,
|
"sort": 4
|
||||||
},
|
},
|
||||||
],
|
{
|
||||||
|
"id": 1090,
|
||||||
|
"parentId": 1000,
|
||||||
|
"title": "岗位管理",
|
||||||
|
"type": 2,
|
||||||
|
"path": "/system/post",
|
||||||
|
"name": "SystemPost",
|
||||||
|
"component": "system/post/index",
|
||||||
|
"icon": "settings",
|
||||||
|
"isExternal": false,
|
||||||
|
"isCache": false,
|
||||||
|
"isHidden": false,
|
||||||
|
"sort": 5
|
||||||
|
}
|
||||||
|
]
|
||||||
}]
|
}]
|
||||||
// 使用已转换的数据生成路由
|
// 使用已转换的数据生成路由
|
||||||
const asyncRoutes = formatAsyncRoutes(data as unknown as RouteItem[])
|
const asyncRoutes = formatAsyncRoutes(data as unknown as RouteItem[])
|
||||||
|
|
|
@ -70,6 +70,6 @@ declare global {
|
||||||
// for type re-export
|
// for type re-export
|
||||||
declare global {
|
declare global {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
|
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
|
||||||
import('vue')
|
import('vue')
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,179 +0,0 @@
|
||||||
export interface EquipmentPageQuery {
|
|
||||||
equipmentName?: string
|
|
||||||
equipmentType?: string
|
|
||||||
equipmentStatus?: string
|
|
||||||
equipmentSn?: string
|
|
||||||
assetCode?: string
|
|
||||||
brand?: string
|
|
||||||
locationStatus?: string
|
|
||||||
healthStatus?: string
|
|
||||||
responsiblePerson?: string
|
|
||||||
useStatus?: string
|
|
||||||
projectId?: string
|
|
||||||
userId?: string
|
|
||||||
equipmentModel?: string
|
|
||||||
specification?: string
|
|
||||||
physicalLocation?: string
|
|
||||||
supplierName?: string
|
|
||||||
maintenancePerson?: string
|
|
||||||
inventoryBarcode?: string
|
|
||||||
assetRemark?: string
|
|
||||||
// 新增搜索字段
|
|
||||||
usingDepartment?: string
|
|
||||||
invoice?: string
|
|
||||||
barcode?: string
|
|
||||||
importer?: string
|
|
||||||
page?: number
|
|
||||||
pageSize?: number
|
|
||||||
orderBy?: string
|
|
||||||
orderDirection?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EquipmentReq {
|
|
||||||
equipmentName: string
|
|
||||||
equipmentModel: string
|
|
||||||
equipmentType: string
|
|
||||||
equipmentStatus: string
|
|
||||||
useStatus: string
|
|
||||||
equipmentSn: string
|
|
||||||
assetCode?: string
|
|
||||||
brand?: string
|
|
||||||
specification?: string
|
|
||||||
locationStatus?: string
|
|
||||||
physicalLocation?: string
|
|
||||||
responsiblePerson?: string
|
|
||||||
healthStatus?: string
|
|
||||||
purchaseTime?: string
|
|
||||||
inStockTime?: string
|
|
||||||
activationTime?: string
|
|
||||||
expectedScrapTime?: string
|
|
||||||
actualScrapTime?: string
|
|
||||||
statusChangeTime?: string
|
|
||||||
purchaseOrder?: string
|
|
||||||
supplierName?: string
|
|
||||||
purchasePrice?: number
|
|
||||||
currentNetValue?: number
|
|
||||||
depreciationMethod?: string
|
|
||||||
depreciationYears?: number
|
|
||||||
salvageValue?: number
|
|
||||||
warrantyExpireDate?: string
|
|
||||||
lastMaintenanceDate?: string
|
|
||||||
nextMaintenanceDate?: string
|
|
||||||
maintenancePerson?: string
|
|
||||||
inventoryBarcode?: string
|
|
||||||
assetRemark?: string
|
|
||||||
// 新增字段
|
|
||||||
usingDepartment?: string
|
|
||||||
borrowingTime?: string
|
|
||||||
returnTime?: string
|
|
||||||
outStockTime?: string
|
|
||||||
totalUsageTime?: string
|
|
||||||
depreciationRate?: number
|
|
||||||
depreciationMethodDesc?: string
|
|
||||||
invoice?: string
|
|
||||||
invoiceStatus?: string
|
|
||||||
attachments?: string
|
|
||||||
photos?: string
|
|
||||||
barcode?: string
|
|
||||||
importer?: string
|
|
||||||
inventoryTimeStatus1?: string
|
|
||||||
inventoryTimeStatus2?: string
|
|
||||||
inventoryTimeStatus3?: string
|
|
||||||
inventoryCheckTimeStatus1?: string
|
|
||||||
inventoryCheckTimeStatus2?: string
|
|
||||||
inventoryCheckTimeStatus3?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EquipmentResp {
|
|
||||||
equipmentId: string
|
|
||||||
assetCode?: string
|
|
||||||
equipmentName: string
|
|
||||||
equipmentType: string
|
|
||||||
equipmentTypeLabel?: string
|
|
||||||
equipmentModel: string
|
|
||||||
equipmentSn: string
|
|
||||||
brand?: string
|
|
||||||
specification?: string
|
|
||||||
equipmentStatus: string
|
|
||||||
equipmentStatusLabel?: string
|
|
||||||
useStatus: string
|
|
||||||
locationStatus?: string
|
|
||||||
locationStatusLabel?: string
|
|
||||||
physicalLocation?: string
|
|
||||||
responsiblePerson?: string
|
|
||||||
healthStatus?: string
|
|
||||||
healthStatusLabel?: string
|
|
||||||
purchaseTime?: string
|
|
||||||
inStockTime?: string
|
|
||||||
activationTime?: string
|
|
||||||
expectedScrapTime?: string
|
|
||||||
actualScrapTime?: string
|
|
||||||
statusChangeTime?: string
|
|
||||||
purchaseOrder?: string
|
|
||||||
supplierName?: string
|
|
||||||
purchasePrice?: number
|
|
||||||
currentNetValue?: number
|
|
||||||
depreciationMethod?: string
|
|
||||||
depreciationYears?: number
|
|
||||||
salvageValue?: number
|
|
||||||
warrantyExpireDate?: string
|
|
||||||
lastMaintenanceDate?: string
|
|
||||||
nextMaintenanceDate?: string
|
|
||||||
maintenancePerson?: string
|
|
||||||
inventoryBarcode?: string
|
|
||||||
assetRemark?: string
|
|
||||||
// 新增字段
|
|
||||||
usingDepartment?: string
|
|
||||||
borrowingTime?: string
|
|
||||||
returnTime?: string
|
|
||||||
outStockTime?: string
|
|
||||||
totalUsageTime?: string
|
|
||||||
depreciationRate?: number
|
|
||||||
depreciationMethodDesc?: string
|
|
||||||
invoice?: string
|
|
||||||
invoiceStatus?: string
|
|
||||||
attachments?: string
|
|
||||||
photos?: string
|
|
||||||
barcode?: string
|
|
||||||
importer?: string
|
|
||||||
inventoryTimeStatus1?: string
|
|
||||||
inventoryTimeStatus2?: string
|
|
||||||
inventoryTimeStatus3?: string
|
|
||||||
inventoryCheckTimeStatus1?: string
|
|
||||||
inventoryCheckTimeStatus2?: string
|
|
||||||
inventoryCheckTimeStatus3?: string
|
|
||||||
projectId?: string
|
|
||||||
projectName?: string
|
|
||||||
userId?: string
|
|
||||||
name?: string
|
|
||||||
createTime?: string
|
|
||||||
updateTime?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EquipmentTypeOption {
|
|
||||||
label: string
|
|
||||||
value: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EquipmentStatusOption {
|
|
||||||
label: string
|
|
||||||
value: string
|
|
||||||
color: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LocationStatusOption {
|
|
||||||
label: string
|
|
||||||
value: string
|
|
||||||
color: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HealthStatusOption {
|
|
||||||
label: string
|
|
||||||
value: string
|
|
||||||
color: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DepreciationMethodOption {
|
|
||||||
label: string
|
|
||||||
value: string
|
|
||||||
}
|
|
|
@ -1,169 +0,0 @@
|
||||||
import jsPDF from 'jspdf'
|
|
||||||
import html2canvas from 'html2canvas'
|
|
||||||
|
|
||||||
// PDF生成器类
|
|
||||||
export class PDFGenerator {
|
|
||||||
// 生成制度PDF
|
|
||||||
static async generateRegulationPDF(regulation: any): Promise<Blob> {
|
|
||||||
// 创建临时HTML元素
|
|
||||||
const tempDiv = document.createElement('div')
|
|
||||||
tempDiv.style.position = 'absolute'
|
|
||||||
tempDiv.style.left = '-9999px'
|
|
||||||
tempDiv.style.top = '-9999px'
|
|
||||||
tempDiv.style.width = '800px'
|
|
||||||
tempDiv.style.padding = '40px'
|
|
||||||
tempDiv.style.backgroundColor = 'white'
|
|
||||||
tempDiv.style.fontFamily = 'Arial, sans-serif'
|
|
||||||
tempDiv.style.fontSize = '14px'
|
|
||||||
tempDiv.style.lineHeight = '1.6'
|
|
||||||
tempDiv.style.color = '#333'
|
|
||||||
|
|
||||||
// 添加水印样式
|
|
||||||
tempDiv.style.position = 'relative'
|
|
||||||
tempDiv.style.overflow = 'hidden'
|
|
||||||
|
|
||||||
// 生成HTML内容
|
|
||||||
tempDiv.innerHTML = `
|
|
||||||
<div style="position: relative; z-index: 1;">
|
|
||||||
<!-- 水印 -->
|
|
||||||
<div style="
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%) rotate(-45deg);
|
|
||||||
font-size: 48px;
|
|
||||||
color: rgba(200, 200, 200, 0.3);
|
|
||||||
font-weight: bold;
|
|
||||||
z-index: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
white-space: nowrap;
|
|
||||||
">迪特聚能科技</div>
|
|
||||||
|
|
||||||
<!-- 标题 -->
|
|
||||||
<h1 style="
|
|
||||||
text-align: center;
|
|
||||||
font-size: 24px;
|
|
||||||
font-weight: bold;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
color: #333;
|
|
||||||
">${regulation.title || '制度文档'}</h1>
|
|
||||||
|
|
||||||
<!-- 基本信息 -->
|
|
||||||
<div style="margin-bottom: 30px;">
|
|
||||||
<table style="width: 100%; border-collapse: collapse;">
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 8px 0; border-bottom: 1px solid #eee;"><strong>制度类型:</strong>${regulation.regulationType || '-'}</td>
|
|
||||||
<td style="padding: 8px 0; border-bottom: 1px solid #eee;"><strong>发布人:</strong>${regulation.createByName || regulation.createBy || '-'}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 8px 0; border-bottom: 1px solid #eee;"><strong>发布时间:</strong>${regulation.publishTime || '-'}</td>
|
|
||||||
<td style="padding: 8px 0; border-bottom: 1px solid #eee;"><strong>生效日期:</strong>${regulation.effectiveTime || '-'}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 8px 0; border-bottom: 1px solid #eee;"><strong>适用范围:</strong>${regulation.scope || '-'}</td>
|
|
||||||
<td style="padding: 8px 0; border-bottom: 1px solid #eee;"><strong>制度级别:</strong>${regulation.level || '-'}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 8px 0; border-bottom: 1px solid #eee;"><strong>版本:</strong>${regulation.version || '1.0'}</td>
|
|
||||||
<td style="padding: 8px 0; border-bottom: 1px solid #eee;"></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 分隔线 -->
|
|
||||||
<hr style="border: none; border-top: 2px solid #ddd; margin: 30px 0;">
|
|
||||||
|
|
||||||
<!-- 制度内容 -->
|
|
||||||
<div style="margin-bottom: 30px;">
|
|
||||||
<h2 style="font-size: 18px; font-weight: bold; margin-bottom: 15px; color: #333;">制度内容:</h2>
|
|
||||||
<div style="
|
|
||||||
white-space: pre-wrap;
|
|
||||||
word-wrap: break-word;
|
|
||||||
line-height: 1.8;
|
|
||||||
text-align: justify;
|
|
||||||
">${regulation.content || ''}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
${regulation.remark ? `
|
|
||||||
<!-- 备注信息 -->
|
|
||||||
<div style="margin-bottom: 30px;">
|
|
||||||
<h2 style="font-size: 18px; font-weight: bold; margin-bottom: 15px; color: #333;">备注:</h2>
|
|
||||||
<div style="
|
|
||||||
white-space: pre-wrap;
|
|
||||||
word-wrap: break-word;
|
|
||||||
line-height: 1.8;
|
|
||||||
text-align: justify;
|
|
||||||
">${regulation.remark}</div>
|
|
||||||
</div>
|
|
||||||
` : ''}
|
|
||||||
|
|
||||||
<!-- 页脚 -->
|
|
||||||
<div style="
|
|
||||||
margin-top: 50px;
|
|
||||||
padding-top: 20px;
|
|
||||||
border-top: 1px solid #ddd;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #666;
|
|
||||||
">
|
|
||||||
生成时间:${new Date().toLocaleString('zh-CN')} | 制度ID:${regulation.regulationId || '-'}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
|
|
||||||
// 添加到DOM
|
|
||||||
document.body.appendChild(tempDiv)
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 使用html2canvas转换为图片
|
|
||||||
const canvas = await html2canvas(tempDiv, {
|
|
||||||
scale: 2, // 提高清晰度
|
|
||||||
useCORS: true,
|
|
||||||
allowTaint: true,
|
|
||||||
backgroundColor: '#ffffff',
|
|
||||||
width: 800,
|
|
||||||
height: tempDiv.scrollHeight
|
|
||||||
})
|
|
||||||
|
|
||||||
// 创建PDF
|
|
||||||
const imgData = canvas.toDataURL('image/png')
|
|
||||||
const pdf = new jsPDF('p', 'mm', 'a4')
|
|
||||||
|
|
||||||
const imgWidth = 210 // A4宽度
|
|
||||||
const pageHeight = 295 // A4高度
|
|
||||||
const imgHeight = (canvas.height * imgWidth) / canvas.width
|
|
||||||
let heightLeft = imgHeight
|
|
||||||
let position = 0
|
|
||||||
|
|
||||||
// 添加第一页
|
|
||||||
pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight)
|
|
||||||
heightLeft -= pageHeight
|
|
||||||
|
|
||||||
// 添加后续页面
|
|
||||||
while (heightLeft >= 0) {
|
|
||||||
position = heightLeft - imgHeight
|
|
||||||
pdf.addPage()
|
|
||||||
pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight)
|
|
||||||
heightLeft -= pageHeight
|
|
||||||
}
|
|
||||||
|
|
||||||
// 返回PDF blob
|
|
||||||
return pdf.output('blob')
|
|
||||||
} finally {
|
|
||||||
// 清理临时元素
|
|
||||||
document.body.removeChild(tempDiv)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 下载PDF文件
|
|
||||||
static downloadPDF(blob: Blob, filename: string) {
|
|
||||||
const url = URL.createObjectURL(blob)
|
|
||||||
const link = document.createElement('a')
|
|
||||||
link.href = url
|
|
||||||
link.download = filename
|
|
||||||
document.body.appendChild(link)
|
|
||||||
link.click()
|
|
||||||
document.body.removeChild(link)
|
|
||||||
URL.revokeObjectURL(url)
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -105,16 +105,8 @@ const formData = reactive({
|
||||||
const fetchBusinessTypes = async () => {
|
const fetchBusinessTypes = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await getAttachBusinessTypes()
|
const res = await getAttachBusinessTypes()
|
||||||
console.log("res:",res);
|
|
||||||
if (res.data) {
|
if (res.data) {
|
||||||
res.data.forEach(item => {
|
businessTypes.value = res.data
|
||||||
const key = Object.keys(item)[0];
|
|
||||||
const value = item[key];
|
|
||||||
businessTypes.value.push({
|
|
||||||
name: value,
|
|
||||||
code:key
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取业务类型失败:', error)
|
console.error('获取业务类型失败:', error)
|
||||||
|
|
|
@ -1,603 +0,0 @@
|
||||||
<template>
|
|
||||||
<GiPageLayout>
|
|
||||||
<div class="data-preprocessing-container">
|
|
||||||
<!-- 上传进度框 -->
|
|
||||||
<div v-if="uploadState.visible" class="upload-progress-fixed">
|
|
||||||
<a-card :title="`上传进度 (${uploadState.percent}%)`" :bordered="false">
|
|
||||||
<a-progress
|
|
||||||
:percent="uploadState.percent"
|
|
||||||
:status="uploadState.status"
|
|
||||||
:stroke-width="16"
|
|
||||||
/>
|
|
||||||
<div class="progress-details">
|
|
||||||
<p><icon-file /> {{ uploadState.currentFile || '准备中...' }}</p>
|
|
||||||
<p><icon-check-circle /> 已完成 {{ uploadState.uploadedCount }}/{{ uploadState.totalCount }}</p>
|
|
||||||
<p><icon-clock-circle /> 状态: {{ getStatusText(uploadState.status) }}</p>
|
|
||||||
</div>
|
|
||||||
</a-card>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="step-panel">
|
|
||||||
<div class="step-header">
|
|
||||||
<h3>批量上传图片</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="data-selection">
|
|
||||||
<a-form :model="form" layout="vertical">
|
|
||||||
<!-- 项目选择 -->
|
|
||||||
<a-form-item label="所属项目" required>
|
|
||||||
<a-select
|
|
||||||
v-model="form.projectId"
|
|
||||||
placeholder="请选择项目"
|
|
||||||
allow-search
|
|
||||||
:filter-option="filterProjectOption"
|
|
||||||
>
|
|
||||||
<a-option
|
|
||||||
v-for="project in projectList"
|
|
||||||
:key="project.id"
|
|
||||||
:value="project.id"
|
|
||||||
:label="project.name"
|
|
||||||
/>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<!-- 图片来源选择 -->
|
|
||||||
<a-form-item label="图片来源" required>
|
|
||||||
<a-select
|
|
||||||
v-model="form.imageSource"
|
|
||||||
placeholder="请选择图片来源"
|
|
||||||
allow-search
|
|
||||||
:filter-option="filterSourceOption"
|
|
||||||
>
|
|
||||||
<a-option
|
|
||||||
v-for="source in imageSources"
|
|
||||||
:key="source.value"
|
|
||||||
:value="source.value"
|
|
||||||
:label="source.label"
|
|
||||||
/>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<!-- 文件夹操作 -->
|
|
||||||
<a-form-item label="文件操作">
|
|
||||||
<div class="folder-actions">
|
|
||||||
<a-upload
|
|
||||||
ref="uploadRef"
|
|
||||||
directory
|
|
||||||
:multiple="true"
|
|
||||||
:show-file-list="false"
|
|
||||||
accept="image/*"
|
|
||||||
:key="uploadKey"
|
|
||||||
@change="handleFolderSelect"
|
|
||||||
>
|
|
||||||
<template #upload-button>
|
|
||||||
<a-button type="outline">
|
|
||||||
<template #icon>
|
|
||||||
<icon-folder />
|
|
||||||
</template>
|
|
||||||
选择文件夹
|
|
||||||
</a-button>
|
|
||||||
</template>
|
|
||||||
</a-upload>
|
|
||||||
<a-button
|
|
||||||
type="outline"
|
|
||||||
status="warning"
|
|
||||||
@click="clearFileList"
|
|
||||||
:disabled="selectedFiles.length === 0"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<icon-delete />
|
|
||||||
</template>
|
|
||||||
清空列表
|
|
||||||
</a-button>
|
|
||||||
<a-button
|
|
||||||
type="primary"
|
|
||||||
:loading="uploading"
|
|
||||||
:disabled="!canUpload"
|
|
||||||
@click="handleUpload"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<icon-upload />
|
|
||||||
</template>
|
|
||||||
开始上传
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<!-- 文件列表 -->
|
|
||||||
<a-form-item v-if="selectedFiles.length > 0">
|
|
||||||
<div class="file-list-container">
|
|
||||||
<div class="file-list-header">
|
|
||||||
<span>已选择 {{ selectedFiles.length }} 个文件(选中 {{ checkedFiles.length }} 个)</span>
|
|
||||||
<a-checkbox
|
|
||||||
v-model="selectAll"
|
|
||||||
:indeterminate="indeterminate"
|
|
||||||
@change="handleSelectAllChange"
|
|
||||||
>
|
|
||||||
全选
|
|
||||||
</a-checkbox>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="file-table-wrapper">
|
|
||||||
<a-table
|
|
||||||
:data="selectedFiles"
|
|
||||||
:columns="fileColumns"
|
|
||||||
:row-selection="rowSelection"
|
|
||||||
:pagination="false"
|
|
||||||
row-key="uid"
|
|
||||||
size="small"
|
|
||||||
bordered
|
|
||||||
>
|
|
||||||
<!-- 表格列模板 -->
|
|
||||||
<template #thumbnail="{ record }">
|
|
||||||
<div class="thumbnail-cell">
|
|
||||||
<img
|
|
||||||
v-if="isImage(record.type)"
|
|
||||||
:src="record.preview"
|
|
||||||
class="thumbnail-image"
|
|
||||||
alt="预览"
|
|
||||||
/>
|
|
||||||
<div v-else class="file-icon">
|
|
||||||
<icon-file />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #fileType="{ record }">
|
|
||||||
<a-tag :color="getFileTypeColor(record.type)" size="small">
|
|
||||||
{{ record.type }}
|
|
||||||
</a-tag>
|
|
||||||
</template>
|
|
||||||
<template #fileSize="{ record }">
|
|
||||||
{{ formatFileSize(record.size) }}
|
|
||||||
</template>
|
|
||||||
</a-table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</GiPageLayout>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, reactive, computed, nextTick } from 'vue'
|
|
||||||
import { Message } from '@arco-design/web-vue'
|
|
||||||
import type { UploadItem } from '@arco-design/web-vue/es/upload'
|
|
||||||
import type { SelectOptionData, TableColumnData, TableRowSelection } from '@arco-design/web-vue'
|
|
||||||
import axios from 'axios'
|
|
||||||
|
|
||||||
import {
|
|
||||||
getProjectList,
|
|
||||||
getImageSources
|
|
||||||
} from '@/apis/industrial-image'
|
|
||||||
|
|
||||||
// 类型定义
|
|
||||||
interface FileItem {
|
|
||||||
uid: string
|
|
||||||
name: string
|
|
||||||
type: string
|
|
||||||
size: number
|
|
||||||
file: File
|
|
||||||
preview?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
type UploadStatus = 'waiting' | 'uploading' | 'success' | 'error'
|
|
||||||
|
|
||||||
// 数据状态
|
|
||||||
const projectList = ref([])
|
|
||||||
|
|
||||||
const imageSources = ref([])
|
|
||||||
|
|
||||||
// 获取项目列表
|
|
||||||
const fetchProjectList = async () => {
|
|
||||||
try {
|
|
||||||
const res = await getProjectList({ page: 1, pageSize: 1000 });
|
|
||||||
projectList.value = res.data.map(item => ({
|
|
||||||
name: item.projectName,
|
|
||||||
id: item.projectId
|
|
||||||
}))
|
|
||||||
} catch (error) {
|
|
||||||
Message.error('获取项目列表失败')
|
|
||||||
} finally {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取图片来源
|
|
||||||
const fetchImageSourceList = async () => {
|
|
||||||
try {
|
|
||||||
const res = await getImageSources();
|
|
||||||
res.data.forEach(item => {
|
|
||||||
const key = Object.keys(item)[0];
|
|
||||||
const value = item[key];
|
|
||||||
imageSources.value.push({
|
|
||||||
label: value,
|
|
||||||
value:key
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
Message.error('获取项目列表失败')
|
|
||||||
} finally {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const form = reactive({
|
|
||||||
projectId: undefined as number | undefined,
|
|
||||||
imageSource: undefined as string | undefined
|
|
||||||
})
|
|
||||||
|
|
||||||
const selectedFiles = ref<FileItem[]>([])
|
|
||||||
const checkedFiles = ref<string[]>([])
|
|
||||||
const uploading = ref(false)
|
|
||||||
const uploadRef = ref()
|
|
||||||
const uploadKey = ref(0)
|
|
||||||
|
|
||||||
const uploadState = reactive({
|
|
||||||
visible: false,
|
|
||||||
percent: 0,
|
|
||||||
status: 'waiting' as UploadStatus,
|
|
||||||
currentFile: '',
|
|
||||||
uploadedCount: 0,
|
|
||||||
totalCount: 0
|
|
||||||
})
|
|
||||||
|
|
||||||
// 计算属性
|
|
||||||
const canUpload = computed(() => {
|
|
||||||
return checkedFiles.value.length > 0
|
|
||||||
&& !!form.projectId
|
|
||||||
&& !!form.imageSource
|
|
||||||
&& !uploading.value
|
|
||||||
})
|
|
||||||
|
|
||||||
const selectAll = ref(false)
|
|
||||||
const indeterminate = computed(() => {
|
|
||||||
return checkedFiles.value.length > 0 &&
|
|
||||||
checkedFiles.value.length < selectedFiles.value.length
|
|
||||||
})
|
|
||||||
|
|
||||||
// 表格列配置
|
|
||||||
const fileColumns: TableColumnData[] = [
|
|
||||||
{
|
|
||||||
title: '选择',
|
|
||||||
dataIndex: 'selection',
|
|
||||||
type: 'selection',
|
|
||||||
width: 60,
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '预览',
|
|
||||||
dataIndex: 'thumbnail',
|
|
||||||
slotName: 'thumbnail',
|
|
||||||
width: 100,
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '文件名',
|
|
||||||
dataIndex: 'name',
|
|
||||||
ellipsis: true,
|
|
||||||
tooltip: true,
|
|
||||||
width: 300
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '类型',
|
|
||||||
dataIndex: 'type',
|
|
||||||
slotName: 'fileType',
|
|
||||||
width: 100,
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '大小',
|
|
||||||
dataIndex: 'size',
|
|
||||||
slotName: 'fileSize',
|
|
||||||
width: 100,
|
|
||||||
align: 'center'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
// 行选择配置
|
|
||||||
const rowSelection = reactive<TableRowSelection>({
|
|
||||||
type: 'checkbox',
|
|
||||||
showCheckedAll: false,
|
|
||||||
selectedRowKeys: checkedFiles,
|
|
||||||
onChange: (rowKeys: string[]) => {
|
|
||||||
checkedFiles.value = rowKeys
|
|
||||||
selectAll.value = rowKeys.length === selectedFiles.value.length
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 搜索过滤函数
|
|
||||||
const filterProjectOption = (inputValue: string, option: SelectOptionData) => {
|
|
||||||
return option.label.toLowerCase().includes(inputValue.toLowerCase())
|
|
||||||
}
|
|
||||||
|
|
||||||
const filterSourceOption = (inputValue: string, option: SelectOptionData) => {
|
|
||||||
return option.label.toLowerCase().includes(inputValue.toLowerCase())
|
|
||||||
}
|
|
||||||
|
|
||||||
// 文件选择处理
|
|
||||||
const handleFolderSelect = async (fileList: UploadItem[]) => {
|
|
||||||
// 1. 清空现有状态
|
|
||||||
clearFileList()
|
|
||||||
|
|
||||||
// 2. 处理新文件
|
|
||||||
const newFiles: FileItem[] = []
|
|
||||||
for (const item of fileList) {
|
|
||||||
const file = item.file
|
|
||||||
if (!file) continue
|
|
||||||
|
|
||||||
const fileType = file.type.split('/')[0] || 'unknown'
|
|
||||||
const preview = fileType === 'image' ? URL.createObjectURL(file) : undefined
|
|
||||||
|
|
||||||
newFiles.push({
|
|
||||||
uid: item.uid,
|
|
||||||
name: file.name,
|
|
||||||
type: fileType,
|
|
||||||
size: file.size,
|
|
||||||
file: file,
|
|
||||||
preview: preview
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 更新状态
|
|
||||||
selectedFiles.value = newFiles
|
|
||||||
checkedFiles.value = newFiles.map(f => f.uid)
|
|
||||||
selectAll.value = true
|
|
||||||
|
|
||||||
// 4. 重置上传组件(通过改变key强制重新创建组件)
|
|
||||||
uploadKey.value++
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清空文件列表
|
|
||||||
const clearFileList = () => {
|
|
||||||
// 释放预览URL
|
|
||||||
selectedFiles.value.forEach(file => {
|
|
||||||
if (file.preview) URL.revokeObjectURL(file.preview)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 重置状态
|
|
||||||
selectedFiles.value = []
|
|
||||||
checkedFiles.value = []
|
|
||||||
selectAll.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理全选变化
|
|
||||||
const handleSelectAllChange = (checked: boolean) => {
|
|
||||||
checkedFiles.value = checked ? selectedFiles.value.map(f => f.uid) : []
|
|
||||||
}
|
|
||||||
|
|
||||||
// 上传处理
|
|
||||||
const handleUpload = async () => {
|
|
||||||
if (!canUpload.value) {
|
|
||||||
Message.error('请完成所有必填项并选择文件')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重置上传状态
|
|
||||||
Object.assign(uploadState, {
|
|
||||||
visible: true,
|
|
||||||
percent: 0,
|
|
||||||
status: 'uploading',
|
|
||||||
currentFile: '',
|
|
||||||
uploadedCount: 0,
|
|
||||||
totalCount: checkedFiles.value.length
|
|
||||||
})
|
|
||||||
|
|
||||||
uploading.value = true
|
|
||||||
|
|
||||||
try {
|
|
||||||
const filesToUpload = selectedFiles.value.filter(f => checkedFiles.value.includes(f.uid))
|
|
||||||
|
|
||||||
const formData = new FormData()
|
|
||||||
|
|
||||||
// 添加所有图片文件到FormData
|
|
||||||
filesToUpload.forEach(file => {
|
|
||||||
formData.append('files', file);
|
|
||||||
});
|
|
||||||
|
|
||||||
let url =`http://pms.dtyx.net:9158/image/${form.projectId}/${form.imageSource}/upload-batch`;
|
|
||||||
let res = await axios.post(
|
|
||||||
url,
|
|
||||||
formData,
|
|
||||||
{
|
|
||||||
onUploadProgress: (progressEvent) => {
|
|
||||||
if (progressEvent.total) {
|
|
||||||
uploadedBytes = progressEvent.loaded
|
|
||||||
const elapsedTime = (Date.now() - startTime) / 1000
|
|
||||||
const speed = uploadedBytes / elapsedTime
|
|
||||||
uploadState.speed = `${formatFileSize(speed)}/s`
|
|
||||||
|
|
||||||
const remainingBytes = totalBytes - uploadedBytes
|
|
||||||
uploadState.remainingTime = formatTime(remainingBytes / speed)
|
|
||||||
|
|
||||||
uploadState.percent = Math.round((uploadedBytes / totalBytes) * 100)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'multipart/form-data'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
console.log("res:",res);
|
|
||||||
uploadState.status = 'success'
|
|
||||||
Message.success(`成功上传 ${filesToUpload.length} 个文件`)
|
|
||||||
} catch (error) {
|
|
||||||
uploadState.status = 'error'
|
|
||||||
Message.error('上传失败: ' + (error as Error).message)
|
|
||||||
} finally {
|
|
||||||
uploading.value = false
|
|
||||||
// 5秒后自动隐藏进度框
|
|
||||||
setTimeout(() => uploadState.visible = false, 5000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 辅助函数
|
|
||||||
const getStatusText = (status: UploadStatus) => {
|
|
||||||
const statusMap = {
|
|
||||||
waiting: '等待上传',
|
|
||||||
uploading: '上传中',
|
|
||||||
success: '上传成功',
|
|
||||||
error: '上传失败'
|
|
||||||
}
|
|
||||||
return statusMap[status] || status
|
|
||||||
}
|
|
||||||
|
|
||||||
const getFileTypeColor = (type: string) => {
|
|
||||||
const colors: Record<string, string> = {
|
|
||||||
image: 'arcoblue',
|
|
||||||
video: 'green',
|
|
||||||
audio: 'orange',
|
|
||||||
document: 'purple'
|
|
||||||
}
|
|
||||||
return colors[type.toLowerCase()] || 'gray'
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatFileSize = (bytes: number) => {
|
|
||||||
if (bytes === 0) return '0 B'
|
|
||||||
const k = 1024
|
|
||||||
const sizes = ['B', 'KB', 'MB', 'GB']
|
|
||||||
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
|
||||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
const isImage = (type: string) => type === 'image'
|
|
||||||
|
|
||||||
// 在组件挂载时获取项目列表
|
|
||||||
onMounted(() => {
|
|
||||||
fetchProjectList()
|
|
||||||
fetchImageSourceList()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="less">
|
|
||||||
.data-preprocessing-container {
|
|
||||||
position: relative;
|
|
||||||
padding: 20px;
|
|
||||||
min-height: calc(100vh - 40px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-panel {
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 24px;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-header {
|
|
||||||
margin-bottom: 24px;
|
|
||||||
border-bottom: 1px solid var(--color-border);
|
|
||||||
padding-bottom: 16px;
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--color-text-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.folder-actions {
|
|
||||||
display: flex;
|
|
||||||
gap: 12px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
> * {
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-list-container {
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 12px;
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-list-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
padding: 0 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-table-wrapper {
|
|
||||||
max-height: 500px;
|
|
||||||
overflow-y: auto;
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-table {
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
:deep(.arco-table-th) {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
z-index: 1;
|
|
||||||
background-color: var(--color-fill-2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.thumbnail-cell {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
height: 60px;
|
|
||||||
|
|
||||||
.thumbnail-image {
|
|
||||||
max-height: 60px;
|
|
||||||
max-width: 80px;
|
|
||||||
object-fit: contain;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-icon {
|
|
||||||
font-size: 24px;
|
|
||||||
color: var(--color-text-3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 上传进度框样式 */
|
|
||||||
.upload-progress-fixed {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 24px;
|
|
||||||
right: 24px;
|
|
||||||
width: 360px;
|
|
||||||
z-index: 1000;
|
|
||||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
|
|
||||||
border-radius: 8px;
|
|
||||||
animation: fadeIn 0.3s ease;
|
|
||||||
|
|
||||||
:deep(.arco-card-header) {
|
|
||||||
border-bottom: 1px solid var(--color-border);
|
|
||||||
padding-bottom: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-progress-text) {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-details {
|
|
||||||
margin-top: 12px;
|
|
||||||
font-size: 13px;
|
|
||||||
color: var(--color-text-2);
|
|
||||||
|
|
||||||
p {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin: 6px 0;
|
|
||||||
|
|
||||||
.arco-icon {
|
|
||||||
margin-right: 8px;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeIn {
|
|
||||||
from { opacity: 0; transform: translateY(10px); }
|
|
||||||
to { opacity: 1; transform: translateY(0); }
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -106,14 +106,12 @@ const getAudioUrl = (filePath: string): string => {
|
||||||
const openPreview = (item: PreviewItem) => {
|
const openPreview = (item: PreviewItem) => {
|
||||||
currentPreviewItem.value = item
|
currentPreviewItem.value = item
|
||||||
audioList.value = []
|
audioList.value = []
|
||||||
if(item.audios){
|
for (const audio of item.audios) {
|
||||||
for (const audio of item.audios) {
|
let temp={
|
||||||
let temp={
|
audioId:audio.audioId,
|
||||||
audioId:audio.audioId,
|
url:getAudioUrl(audio.filePath)
|
||||||
url:getAudioUrl(audio.filePath)
|
|
||||||
}
|
|
||||||
audioList.value.push(temp)
|
|
||||||
}
|
}
|
||||||
|
audioList.value.push(temp)
|
||||||
}
|
}
|
||||||
|
|
||||||
previewModalVisible.value = true
|
previewModalVisible.value = true
|
||||||
|
|
|
@ -251,22 +251,15 @@ const fetchPartList = async (projectId: string, turbineId: string) => {
|
||||||
|
|
||||||
// 处理筛选变化,获取图像列表
|
// 处理筛选变化,获取图像列表
|
||||||
const handleFilterChange = async () => {
|
const handleFilterChange = async () => {
|
||||||
// if (!filterParams.project) return
|
if (!filterParams.unit) return
|
||||||
|
|
||||||
loading.image = true
|
loading.image = true
|
||||||
try {
|
try {
|
||||||
let params = {
|
let params = {
|
||||||
projectId: filterParams.project
|
turbineId: filterParams.unit
|
||||||
}
|
|
||||||
if(filterParams.unit){
|
|
||||||
params = {
|
|
||||||
projectId: filterParams.project,
|
|
||||||
turbineId: filterParams.unit
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(filterParams.component){
|
if(filterParams.component){
|
||||||
params = {
|
params = {
|
||||||
projectId: filterParams.project,
|
|
||||||
turbineId: filterParams.unit,
|
turbineId: filterParams.unit,
|
||||||
partId: filterParams.component
|
partId: filterParams.component
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,198 +0,0 @@
|
||||||
<template>
|
|
||||||
<a-modal
|
|
||||||
:visible="visible"
|
|
||||||
title="招标详情"
|
|
||||||
width="800px"
|
|
||||||
:footer="false"
|
|
||||||
:mask-closable="false"
|
|
||||||
@update:visible="(val) => $emit('update:visible', val)"
|
|
||||||
>
|
|
||||||
<a-descriptions
|
|
||||||
:column="2"
|
|
||||||
bordered
|
|
||||||
:label-style="{ width: '120px', fontWeight: 'bold' }"
|
|
||||||
>
|
|
||||||
<a-descriptions-item label="项目名称">{{ detail.projectName }}</a-descriptions-item>
|
|
||||||
<a-descriptions-item label="招标单位">{{ detail.biddingUnit }}</a-descriptions-item>
|
|
||||||
<a-descriptions-item label="预算金额">{{ detail.budgetAmount }}万元</a-descriptions-item>
|
|
||||||
<a-descriptions-item label="截止时间">{{ detail.deadline }}</a-descriptions-item>
|
|
||||||
<a-descriptions-item label="爬取时间">{{ detail.crawlingTime }}</a-descriptions-item>
|
|
||||||
<a-descriptions-item label="项目地点">{{ detail.projectLocation }}</a-descriptions-item>
|
|
||||||
<a-descriptions-item label="项目周期">{{ detail.projectDuration }}</a-descriptions-item>
|
|
||||||
<a-descriptions-item label="招标范围">{{ detail.biddingScope }}</a-descriptions-item>
|
|
||||||
<a-descriptions-item label="资质要求">{{ detail.qualificationRequirements }}</a-descriptions-item>
|
|
||||||
<a-descriptions-item label="来源平台">
|
|
||||||
<a
|
|
||||||
:href="getPlatformUrl(detail.sourcePlatform)"
|
|
||||||
target="_blank"
|
|
||||||
class="platform-link"
|
|
||||||
>
|
|
||||||
{{ detail.sourcePlatform }}
|
|
||||||
</a>
|
|
||||||
</a-descriptions-item>
|
|
||||||
<a-descriptions-item label="招标文件">
|
|
||||||
<div class="file-display">
|
|
||||||
<a-link
|
|
||||||
v-if="detail.biddingDocuments"
|
|
||||||
:href="detail.biddingDocuments"
|
|
||||||
target="_blank"
|
|
||||||
class="file-link"
|
|
||||||
>
|
|
||||||
{{ displayedFileName }}
|
|
||||||
</a-link>
|
|
||||||
<span v-else class="no-file">暂无文件</span>
|
|
||||||
|
|
||||||
<a-upload
|
|
||||||
:show-file-list="false"
|
|
||||||
:before-upload="beforeUpload"
|
|
||||||
accept=".pdf,.doc,.docx"
|
|
||||||
style="margin-left: 10px"
|
|
||||||
>
|
|
||||||
<a-button
|
|
||||||
type="outline"
|
|
||||||
size="mini"
|
|
||||||
:loading="uploading"
|
|
||||||
>
|
|
||||||
<template #icon><icon-upload /></template>
|
|
||||||
{{ detail.biddingDocuments ? '重新上传' : '上传文件' }}
|
|
||||||
</a-button>
|
|
||||||
</a-upload>
|
|
||||||
</div>
|
|
||||||
</a-descriptions-item>
|
|
||||||
</a-descriptions>
|
|
||||||
|
|
||||||
<div class="content-section">
|
|
||||||
<h3>招标内容</h3>
|
|
||||||
<div class="content-text">{{ detail.biddingContent }}</div>
|
|
||||||
<ul v-if="detail.contentItems && detail.contentItems.length">
|
|
||||||
<li v-for="(item, index) in detail.contentItems" :key="index">{{ item }}</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</a-modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import type { BiddingDetail } from '../types'
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
visible: boolean
|
|
||||||
detail: BiddingDetail
|
|
||||||
uploading?: boolean
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:visible', 'upload'])
|
|
||||||
|
|
||||||
const displayedFileName = computed(() => {
|
|
||||||
if (!props.detail?.biddingDocuments) return ''
|
|
||||||
const url = props.detail.biddingDocuments
|
|
||||||
return url.split('/').pop() || '招标文件'
|
|
||||||
})
|
|
||||||
|
|
||||||
// 平台URL映射
|
|
||||||
const platformUrls: Record<string, string> = {
|
|
||||||
'中国招标投标网': 'https://www.cebpubservice.com/',
|
|
||||||
'国能e招': 'https://www.negc.cn/',
|
|
||||||
'中国节能': 'https://www.cecec.cn/',
|
|
||||||
'三峡招标': 'https://epp.ctg.com.cn/'
|
|
||||||
}
|
|
||||||
|
|
||||||
const getPlatformUrl = (platformName: string): string => {
|
|
||||||
return platformUrls[platformName] || '#'
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleUpload = () => {
|
|
||||||
emit('upload')
|
|
||||||
}
|
|
||||||
|
|
||||||
const beforeUpload = (file: File) => {
|
|
||||||
// 检查文件类型
|
|
||||||
const isValidType = [
|
|
||||||
'application/pdf',
|
|
||||||
'application/msword',
|
|
||||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
|
|
||||||
].includes(file.type)
|
|
||||||
|
|
||||||
// 检查文件大小 (限制10MB)
|
|
||||||
const isLt10M = file.size / 1024 / 1024 < 10
|
|
||||||
|
|
||||||
if (!isValidType) {
|
|
||||||
Message.error('只能上传PDF或Word文件!')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isLt10M) {
|
|
||||||
Message.error('文件大小不能超过10MB!')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 触发上传事件
|
|
||||||
emit('upload', file)
|
|
||||||
|
|
||||||
// 返回false阻止默认上传行为,由父组件处理
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="less">
|
|
||||||
.file-display {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-link {
|
|
||||||
color: #1890ff;
|
|
||||||
text-decoration: underline;
|
|
||||||
cursor: pointer;
|
|
||||||
max-width: 200px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
display: inline-block;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: #40a9ff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-file {
|
|
||||||
color: var(--color-text-3);
|
|
||||||
}
|
|
||||||
.platform-link {
|
|
||||||
color: #1890ff; /* 蓝色 */
|
|
||||||
text-decoration: underline; /* 下划线 */
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: #40a9ff; /* 悬停时变浅蓝色 */
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.content-section {
|
|
||||||
margin-top: 20px;
|
|
||||||
padding: 16px;
|
|
||||||
background-color: var(--color-fill-2);
|
|
||||||
border-radius: 4px;
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin-bottom: 12px;
|
|
||||||
color: var(--color-text-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-text {
|
|
||||||
margin-bottom: 12px;
|
|
||||||
line-height: 1.6;
|
|
||||||
color: var(--color-text-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
padding-left: 20px;
|
|
||||||
color: var(--color-text-2);
|
|
||||||
|
|
||||||
li {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,164 +0,0 @@
|
||||||
<template>
|
|
||||||
<a-modal
|
|
||||||
:visible="visible"
|
|
||||||
title="爬虫设置"
|
|
||||||
width="800px"
|
|
||||||
@cancel="handleCancel"
|
|
||||||
@ok="handleOk"
|
|
||||||
:mask-closable="false"
|
|
||||||
>
|
|
||||||
<a-form :model="form" layout="vertical">
|
|
||||||
<a-form-item label="爬取频率">
|
|
||||||
<a-select v-model="form.frequency">
|
|
||||||
<a-option value="hourly">每小时</a-option>
|
|
||||||
<a-option value="daily">每天</a-option>
|
|
||||||
<a-option value="weekly">每周</a-option>
|
|
||||||
<a-option value="monthly">每月</a-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item label="关键词过滤">
|
|
||||||
<a-input-tag
|
|
||||||
v-model="form.keywords"
|
|
||||||
placeholder="输入关键词后回车"
|
|
||||||
allow-clear
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item label="来源平台">
|
|
||||||
<a-checkbox-group v-model="form.platforms">
|
|
||||||
<a-row :gutter="[16, 16]">
|
|
||||||
<a-col :span="8">
|
|
||||||
<a-checkbox value="国能e招">国能e招</a-checkbox>
|
|
||||||
</a-col>
|
|
||||||
<a-col :span="8">
|
|
||||||
<a-checkbox value="中国节能">中国节能</a-checkbox>
|
|
||||||
</a-col>
|
|
||||||
<a-col :span="8">
|
|
||||||
<a-checkbox value="科幻集团">科幻集团</a-checkbox>
|
|
||||||
</a-col>
|
|
||||||
<a-col :span="8">
|
|
||||||
<a-checkbox value="三峡招标">三峡招标</a-checkbox>
|
|
||||||
</a-col>
|
|
||||||
<a-col :span="8">
|
|
||||||
<a-checkbox value="三峡采购">三峡采购</a-checkbox>
|
|
||||||
</a-col>
|
|
||||||
<a-col :span="8">
|
|
||||||
<a-checkbox value="北京京能">北京京能</a-checkbox>
|
|
||||||
</a-col>
|
|
||||||
<a-col :span="8">
|
|
||||||
<a-checkbox value="华润守正">华润守正</a-checkbox>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
</a-checkbox-group>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item label="自动通知">
|
|
||||||
<a-switch v-model="form.autoNotify" />
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<template v-if="form.autoNotify">
|
|
||||||
<a-form-item label="通知方式">
|
|
||||||
<a-checkbox-group v-model="form.notifyMethods">
|
|
||||||
<a-checkbox value="inApp">站内消息</a-checkbox>
|
|
||||||
<a-checkbox value="email">电子邮件</a-checkbox>
|
|
||||||
</a-checkbox-group>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item v-if="form.notifyMethods.includes('email')" label="通知邮箱">
|
|
||||||
<a-input v-model="form.notifyEmail" placeholder="请输入接收通知的邮箱" />
|
|
||||||
</a-form-item>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<a-divider />
|
|
||||||
|
|
||||||
<a-form-item label="爬虫日志">
|
|
||||||
<div class="log-container">
|
|
||||||
<div v-for="(log, index) in logs" :key="index" class="log-item">
|
|
||||||
[{{ log.time }}] {{ log.message }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
|
|
||||||
<template #footer>
|
|
||||||
<a-button @click="handleCancel">取消</a-button>
|
|
||||||
<a-button type="primary" @click="handleOk">保存设置</a-button>
|
|
||||||
</template>
|
|
||||||
</a-modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, reactive, watch } from 'vue'
|
|
||||||
import { Message } from '@arco-design/web-vue'
|
|
||||||
|
|
||||||
interface LogEntry {
|
|
||||||
time: string
|
|
||||||
message: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
visible: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:visible', 'save'])
|
|
||||||
|
|
||||||
const form = reactive({
|
|
||||||
frequency: 'daily',
|
|
||||||
keywords: ['风电', '叶片', '检查', '运维'],
|
|
||||||
platforms: ['国能e招', '中国节能', '三峡招标'],
|
|
||||||
autoNotify: true,
|
|
||||||
notifyMethods: ['inApp', 'email'],
|
|
||||||
notifyEmail: 'user@example.com'
|
|
||||||
})
|
|
||||||
|
|
||||||
const logs = ref<LogEntry[]>([
|
|
||||||
{ time: '2025-07-30 22:00', message: '爬虫任务已启动' },
|
|
||||||
{ time: '2025-07-30 21:00', message: '爬虫任务已启动' },
|
|
||||||
{ time: '2023-11-01 09:30', message: '成功爬取中国招标投标网数据' },
|
|
||||||
{ time: '2023-11-01 09:32', message: '成功爬取某省公共资源交易中心数据' },
|
|
||||||
{ time: '2023-11-02 10:15', message: '爬取企业自有招标平台失败:连接超时' }
|
|
||||||
])
|
|
||||||
|
|
||||||
const handleCancel = () => {
|
|
||||||
emit('update:visible', false)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleOk = () => {
|
|
||||||
Message.success('设置保存成功')
|
|
||||||
emit('save', form)
|
|
||||||
emit('update:visible', false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Watch for email notification toggle
|
|
||||||
watch(() => form.notifyMethods, (newVal) => {
|
|
||||||
if (!newVal.includes('email')) {
|
|
||||||
form.notifyEmail = ''
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="less">
|
|
||||||
.log-container {
|
|
||||||
height: 200px;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 8px;
|
|
||||||
border: 1px solid var(--color-border-2);
|
|
||||||
border-radius: 4px;
|
|
||||||
background-color: var(--color-fill-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.log-item {
|
|
||||||
padding: 4px 0;
|
|
||||||
font-family: monospace;
|
|
||||||
font-size: 13px;
|
|
||||||
color: var(--color-text-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.log-item:not(:last-child) {
|
|
||||||
border-bottom: 1px dashed var(--color-border-2);
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,344 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="project-table-container">
|
|
||||||
<a-table
|
|
||||||
:data="data"
|
|
||||||
:columns="columns"
|
|
||||||
:loading="loading"
|
|
||||||
:pagination="false"
|
|
||||||
:scroll="{ x: '100%', y: '100%' }"
|
|
||||||
row-key="id"
|
|
||||||
:stripe="false"
|
|
||||||
size="large"
|
|
||||||
>
|
|
||||||
<!-- 招标项目 -->
|
|
||||||
<template #projectName="{ record }">
|
|
||||||
<div class="project-name">
|
|
||||||
<span class="name-text">{{ record.projectName }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 招标单位 -->
|
|
||||||
<template #biddingUnit="{ record }">
|
|
||||||
<span class="bidding-unit">{{ record.biddingUnit }}</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 预算金额 -->
|
|
||||||
<template #budgetAmount="{ record }">
|
|
||||||
<span class="budget-text">{{ record.budgetAmount }}</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 截止时间 -->
|
|
||||||
<template #deadline="{ record }">
|
|
||||||
<span class="date-text">{{ record.deadline }}</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 爬取时间 -->
|
|
||||||
<template #crawlingTime="{ record }">
|
|
||||||
<span class="date-text">{{ record.crawlingTime }}</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 来源平台 -->
|
|
||||||
<template #sourcePlatform="{ record }">
|
|
||||||
<span class="source-text">{{ record.sourcePlatform }}</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 招标文件 -->
|
|
||||||
<template #biddingDocuments="{ record }">
|
|
||||||
<span class="doc-text">{{ record.biddingDocuments }}</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 状态 -->
|
|
||||||
<template #status="{ record }">
|
|
||||||
<a-tag :color="getStatusColor(record.status)">
|
|
||||||
{{ getStatusText(record.status) }}
|
|
||||||
</a-tag>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 操作 -->
|
|
||||||
<template #action="{ record }">
|
|
||||||
<div class="action-buttons">
|
|
||||||
<a-button size="small" @click="handleView(record)">
|
|
||||||
详情
|
|
||||||
</a-button>
|
|
||||||
<a-button
|
|
||||||
type="primary"
|
|
||||||
size="small"
|
|
||||||
@click="handleEnter(record)"
|
|
||||||
>
|
|
||||||
报名
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</a-table>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { computed } from 'vue'
|
|
||||||
import type { TableColumnData } from '@arco-design/web-vue'
|
|
||||||
import type { ProjectData } from '../types'
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
data: ProjectData[]
|
|
||||||
loading?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Emits {
|
|
||||||
(e: 'view', project: ProjectData): void
|
|
||||||
(e: 'enter', project: ProjectData): void
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
|
||||||
loading: false
|
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits<Emits>()
|
|
||||||
|
|
||||||
// 表格列配置
|
|
||||||
const columns: TableColumnData[] = [
|
|
||||||
{
|
|
||||||
title: '招标项目',
|
|
||||||
dataIndex: 'projectName',
|
|
||||||
slotName: 'projectName',
|
|
||||||
width: 300,
|
|
||||||
ellipsis: true,
|
|
||||||
tooltip: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '招标单位',
|
|
||||||
dataIndex: ' biddingUnit',
|
|
||||||
slotName: 'biddingUnit',
|
|
||||||
width: 120,
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '预算金额',
|
|
||||||
dataIndex: 'budgetAmount',
|
|
||||||
slotName: 'budgetAmount',
|
|
||||||
width: 120,
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '截止时间',
|
|
||||||
dataIndex: 'deadline',
|
|
||||||
slotName: 'deadline',
|
|
||||||
width: 150,
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '爬取时间',
|
|
||||||
dataIndex: 'crawlingTime',
|
|
||||||
slotName: 'crawlingTime',
|
|
||||||
width: 150,
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '来源平台',
|
|
||||||
dataIndex: 'sourcePlatform',
|
|
||||||
slotName: 'sourcePlatform',
|
|
||||||
width: 150,
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '招标文件',
|
|
||||||
dataIndex: ' biddingDocuments',
|
|
||||||
slotName: 'biddingDocuments',
|
|
||||||
width: 150,
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '状态',
|
|
||||||
dataIndex: 'status',
|
|
||||||
slotName: 'status',
|
|
||||||
width: 120,
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '操作',
|
|
||||||
dataIndex: 'action',
|
|
||||||
slotName: 'action',
|
|
||||||
width: 150,
|
|
||||||
align: 'center',
|
|
||||||
fixed: 'right'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
// 获取状态颜色
|
|
||||||
const getStatusColor = (status: string) => {
|
|
||||||
const colorMap: Record<string, string> = {
|
|
||||||
'not_started': 'gray',
|
|
||||||
'in_progress': 'blue',
|
|
||||||
'completed': 'green',
|
|
||||||
'paused': 'orange',
|
|
||||||
'cancelled': 'red'
|
|
||||||
}
|
|
||||||
return colorMap[status] || 'gray'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取状态文本
|
|
||||||
const getStatusText = (status: string) => {
|
|
||||||
const textMap: Record<string, string> = {
|
|
||||||
'not_started': '未开始',
|
|
||||||
'in_progress': '进行中',
|
|
||||||
'completed': '已完成',
|
|
||||||
'paused': '已暂停',
|
|
||||||
'cancelled': '已取消'
|
|
||||||
}
|
|
||||||
return textMap[status] || status
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取进度颜色
|
|
||||||
const getProgressColor = (progress: number) => {
|
|
||||||
if (progress === 0) return '#d9d9d9'
|
|
||||||
if (progress === 100) return '#52c41a'
|
|
||||||
if (progress >= 70) return '#1890ff'
|
|
||||||
if (progress >= 40) return '#faad14'
|
|
||||||
return '#ff4d4f'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 事件处理
|
|
||||||
const handleView = (record: ProjectData) => {
|
|
||||||
emit('view', record)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleEnter = (record: ProjectData) => {
|
|
||||||
emit('enter', record)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="less">
|
|
||||||
.project-table-container {
|
|
||||||
height: 100%;
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.project-name {
|
|
||||||
.name-text {
|
|
||||||
font-weight: 500;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.unit-count {
|
|
||||||
font-weight: 600;
|
|
||||||
color: #1890ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.date-text {
|
|
||||||
color: #666;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-container {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 12px;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.progress-text {
|
|
||||||
font-size: 12px;
|
|
||||||
color: #666;
|
|
||||||
font-weight: 500;
|
|
||||||
min-width: 35px;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-buttons {
|
|
||||||
display: flex;
|
|
||||||
gap: 8px;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-table) {
|
|
||||||
.arco-table-thead {
|
|
||||||
.arco-table-th {
|
|
||||||
background-color: #fafafa;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #333;
|
|
||||||
border-bottom: 1px solid #e8e8e8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.arco-table-tbody {
|
|
||||||
.arco-table-tr {
|
|
||||||
&:hover {
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.arco-table-td {
|
|
||||||
border-bottom: 1px solid #f0f0f0;
|
|
||||||
padding: 16px 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-tag) {
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 12px;
|
|
||||||
padding: 2px 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-progress-line-outer) {
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-progress-line-inner) {
|
|
||||||
border-radius: 4px;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 状态标签样式
|
|
||||||
:deep(.arco-tag-gray) {
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
border-color: #d9d9d9;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-tag-blue) {
|
|
||||||
background-color: #e6f7ff;
|
|
||||||
border-color: #91d5ff;
|
|
||||||
color: #1890ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-tag-green) {
|
|
||||||
background-color: #f6ffed;
|
|
||||||
border-color: #b7eb8f;
|
|
||||||
color: #52c41a;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-tag-orange) {
|
|
||||||
background-color: #fff7e6;
|
|
||||||
border-color: #ffd591;
|
|
||||||
color: #fa8c16;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-tag-red) {
|
|
||||||
background-color: #fff1f0;
|
|
||||||
border-color: #ffccc7;
|
|
||||||
color: #ff4d4f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 响应式处理
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
:deep(.arco-table-td) {
|
|
||||||
padding: 12px 8px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-buttons {
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-container {
|
|
||||||
gap: 8px;
|
|
||||||
|
|
||||||
.progress-text {
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,415 +0,0 @@
|
||||||
<template>
|
|
||||||
<GiPageLayout>
|
|
||||||
<div class="project-list-container">
|
|
||||||
<!-- 顶部搜索和操作区域 -->
|
|
||||||
<div class="header-section">
|
|
||||||
<div class="search-area">
|
|
||||||
<a-input-search
|
|
||||||
v-model="searchKeyword"
|
|
||||||
placeholder="搜索项目名称"
|
|
||||||
allow-clear
|
|
||||||
@search="handleSearch"
|
|
||||||
@clear="handleClear"
|
|
||||||
style="width: 300px"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="action-area">
|
|
||||||
<a-space>
|
|
||||||
<a-button type="primary" @click="startCrawler">
|
|
||||||
<template #icon><icon-play-arrow /></template>
|
|
||||||
开始爬虫
|
|
||||||
</a-button>
|
|
||||||
<a-button @click="refreshData">
|
|
||||||
<template #icon><icon-refresh /></template>
|
|
||||||
刷新数据
|
|
||||||
</a-button>
|
|
||||||
<a-button @click="exportData">
|
|
||||||
<template #icon><icon-download /></template>
|
|
||||||
导出数据
|
|
||||||
</a-button>
|
|
||||||
<a-button @click="openCrawlerSettings">
|
|
||||||
<template #icon><icon-settings /></template>
|
|
||||||
爬虫设置
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 选项卡区域 -->
|
|
||||||
<div class="tabs-section">
|
|
||||||
<a-tabs
|
|
||||||
v-model:active-key="activeTab"
|
|
||||||
type="line"
|
|
||||||
size="large"
|
|
||||||
@change="handleTabChange"
|
|
||||||
>
|
|
||||||
<a-tab-pane key="all" tab="信息检索" title="信息检索">
|
|
||||||
<ProjectTable
|
|
||||||
:data="pagedData"
|
|
||||||
:loading="loading"
|
|
||||||
@view="handleView"
|
|
||||||
@enter="handleEnter"
|
|
||||||
/>
|
|
||||||
<div class="pagination-wrapper">
|
|
||||||
<a-pagination
|
|
||||||
v-model:current="currentPage"
|
|
||||||
v-model:page-size="pageSize"
|
|
||||||
:total="totalItems"
|
|
||||||
show-total
|
|
||||||
show-jumper
|
|
||||||
show-page-size
|
|
||||||
:page-size-options="[10, 20, 50, 100]"
|
|
||||||
@change="handlePageChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</a-tab-pane>
|
|
||||||
<a-tab-pane key="my" tab="投标响应" title="投标响应">
|
|
||||||
<ProjectTable
|
|
||||||
:data="myPagedData"
|
|
||||||
:loading="loading"
|
|
||||||
@view="handleView"
|
|
||||||
@enter="handleEnter"
|
|
||||||
/>
|
|
||||||
<div class="pagination-wrapper">
|
|
||||||
<a-pagination
|
|
||||||
v-model:current="myCurrentPage"
|
|
||||||
v-model:page-size="pageSize"
|
|
||||||
:total="myTotalItems"
|
|
||||||
show-total
|
|
||||||
show-jumper
|
|
||||||
show-page-size
|
|
||||||
:page-size-options="[10, 20, 50, 100]"
|
|
||||||
@change="handleMyPageChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</a-tab-pane>
|
|
||||||
</a-tabs>
|
|
||||||
</div>
|
|
||||||
<CrawlerSettings
|
|
||||||
v-model:visible="crawlerSettingsVisible"
|
|
||||||
@save="handleSaveSettings"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</GiPageLayout>
|
|
||||||
<BiddingDetailModal
|
|
||||||
v-model:visible="detailVisible"
|
|
||||||
:detail="currentDetail"
|
|
||||||
:uploading="uploading"
|
|
||||||
@upload="handleUploadDocument"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, reactive, computed, onMounted } from 'vue'
|
|
||||||
import { Message } from '@arco-design/web-vue'
|
|
||||||
import ProjectTable from './components/InformationTable.vue'
|
|
||||||
import CrawlerSettings from './components/CrawlerSettings.vue'
|
|
||||||
import BiddingDetailModal from './components/BiddingDetailModal.vue'
|
|
||||||
|
|
||||||
import type { ProjectData, TabKey,BiddingDetail } from './types'
|
|
||||||
import { ProjectStatus } from './types'
|
|
||||||
|
|
||||||
defineOptions({ name: 'ProjectList' })
|
|
||||||
|
|
||||||
// 响应式数据
|
|
||||||
const loading = ref(false)
|
|
||||||
const activeTab = ref<TabKey>('all')
|
|
||||||
const searchKeyword = ref('')
|
|
||||||
|
|
||||||
const crawlerSettingsVisible = ref(false)
|
|
||||||
|
|
||||||
// 分页相关数据
|
|
||||||
const currentPage = ref(1)
|
|
||||||
const myCurrentPage = ref(1)
|
|
||||||
const pageSize = ref(10)
|
|
||||||
|
|
||||||
// 添加状态
|
|
||||||
const detailVisible = ref(false)
|
|
||||||
const uploading = ref(false)
|
|
||||||
const currentDetail = ref<BiddingDetail>({
|
|
||||||
id: 0,
|
|
||||||
projectName: '',
|
|
||||||
biddingUnit: '',
|
|
||||||
budgetAmount: 0,
|
|
||||||
deadline: '',
|
|
||||||
crawlingTime: '',
|
|
||||||
projectLocation: '',
|
|
||||||
projectDuration: '',
|
|
||||||
biddingScope: '',
|
|
||||||
qualificationRequirements: '',
|
|
||||||
sourcePlatform: '',
|
|
||||||
biddingDocuments: '',
|
|
||||||
biddingContent: '',
|
|
||||||
contentItems: []
|
|
||||||
})
|
|
||||||
|
|
||||||
// 项目数据
|
|
||||||
const projectList = ref<ProjectData[]>([
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
projectName: 'A风场2023年检查',
|
|
||||||
biddingUnit: 15,
|
|
||||||
budgetAmount:111,
|
|
||||||
deadline: '2023-10-01',
|
|
||||||
crawlingTime: '2023-12-31',
|
|
||||||
sourcePlatform:"中国招标投标网",
|
|
||||||
biddingDocuments:"333.pdf",
|
|
||||||
status: ProjectStatus.IN_PROGRESS,
|
|
||||||
manager: '张三',
|
|
||||||
isMyProject: true
|
|
||||||
},
|
|
||||||
// 添加更多示例数据用于测试分页
|
|
||||||
...Array.from({ length: 25 }, (_, i) => ({
|
|
||||||
id: i + 2,
|
|
||||||
projectName: `项目${i + 2}`,
|
|
||||||
biddingUnit: Math.floor(Math.random() * 20) + 1,
|
|
||||||
budgetAmount: Math.floor(Math.random() * 1000) + 100,
|
|
||||||
deadline: `2023-${(Math.floor(Math.random() * 12) + 1).toString().padStart(2, '0')}-${(Math.floor(Math.random() * 28) + 1).toString().padStart(2, '0')}`,
|
|
||||||
crawlingTime: `2023-${(Math.floor(Math.random() * 12) + 1).toString().padStart(2, '0')}-${(Math.floor(Math.random() * 28) + 1).toString().padStart(2, '0')}`,
|
|
||||||
sourcePlatform: "中国招标投标网",
|
|
||||||
biddingDocuments: `文档${i + 2}.pdf`,
|
|
||||||
status: Math.random() > 0.5 ? ProjectStatus.IN_PROGRESS : ProjectStatus.COMPLETED,
|
|
||||||
manager: ['张三', '李四', '王五'][Math.floor(Math.random() * 3)],
|
|
||||||
isMyProject: Math.random() > 0.7
|
|
||||||
}))
|
|
||||||
])
|
|
||||||
|
|
||||||
const handleSaveSettings = (settings: any) => {
|
|
||||||
console.log('Saved settings:', settings)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理查看详情
|
|
||||||
const handleView = (project: ProjectData) => {
|
|
||||||
// 这里应该根据项目ID获取详细数据,这里简化处理
|
|
||||||
currentDetail.value = {
|
|
||||||
id: project.id,
|
|
||||||
projectName: project.projectName,
|
|
||||||
biddingUnit: project.biddingUnit.toString(),
|
|
||||||
budgetAmount: project.budgetAmount,
|
|
||||||
deadline: project.deadline,
|
|
||||||
crawlingTime: project.crawlingTime,
|
|
||||||
projectLocation: '内蒙古自治区', // 示例数据
|
|
||||||
projectDuration: '6个月', // 示例数据
|
|
||||||
biddingScope: '风电场50台机组叶片检查服务', // 示例数据
|
|
||||||
qualificationRequirements: '具备风电叶片检查资质', // 示例数据
|
|
||||||
sourcePlatform: project.sourcePlatform,
|
|
||||||
biddingDocuments: project.biddingDocuments,
|
|
||||||
biddingContent: '本项目为某风电场2023年叶片检查服务采购,包括但不限于:',
|
|
||||||
contentItems: [
|
|
||||||
'叶片外观检查',
|
|
||||||
'无损检测',
|
|
||||||
'缺陷记录与评估',
|
|
||||||
'检查报告编制'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
detailVisible.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算属性 - 根据搜索关键词过滤项目
|
|
||||||
const filteredProjects = computed(() => {
|
|
||||||
if (!searchKeyword.value) {
|
|
||||||
return projectList.value
|
|
||||||
}
|
|
||||||
return projectList.value.filter(project =>
|
|
||||||
project.projectName.toLowerCase().includes(searchKeyword.value.toLowerCase())
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 计算属性 - 我的项目
|
|
||||||
const myProjects = computed(() => {
|
|
||||||
return filteredProjects.value.filter(project => project.isMyProject)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 分页相关计算属性
|
|
||||||
const totalItems = computed(() => filteredProjects.value.length)
|
|
||||||
const myTotalItems = computed(() => myProjects.value.length)
|
|
||||||
|
|
||||||
const pagedData = computed(() => {
|
|
||||||
const start = (currentPage.value - 1) * pageSize.value
|
|
||||||
const end = start + pageSize.value
|
|
||||||
return filteredProjects.value.slice(start, end)
|
|
||||||
})
|
|
||||||
|
|
||||||
const myPagedData = computed(() => {
|
|
||||||
const start = (myCurrentPage.value - 1) * pageSize.value
|
|
||||||
const end = start + pageSize.value
|
|
||||||
return myProjects.value.slice(start, end)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 搜索处理
|
|
||||||
const handleSearch = (value: string) => {
|
|
||||||
searchKeyword.value = value
|
|
||||||
currentPage.value = 1 // 搜索时重置到第一页
|
|
||||||
myCurrentPage.value = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleClear = () => {
|
|
||||||
searchKeyword.value = ''
|
|
||||||
currentPage.value = 1 // 清空搜索时重置到第一页
|
|
||||||
myCurrentPage.value = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// 选项卡切换
|
|
||||||
const handleTabChange = (key: string) => {
|
|
||||||
activeTab.value = key as TabKey
|
|
||||||
}
|
|
||||||
|
|
||||||
// 分页变化处理
|
|
||||||
const handlePageChange = (page: number) => {
|
|
||||||
currentPage.value = page
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleMyPageChange = (page: number) => {
|
|
||||||
myCurrentPage.value = page
|
|
||||||
}
|
|
||||||
|
|
||||||
// 刷新数据
|
|
||||||
const refreshData = async () => {
|
|
||||||
loading.value = true
|
|
||||||
try {
|
|
||||||
// 模拟API请求
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 800))
|
|
||||||
Message.success('数据已刷新')
|
|
||||||
} catch (error) {
|
|
||||||
Message.error('刷新失败')
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 开始爬虫
|
|
||||||
const startCrawler = () => {
|
|
||||||
Message.info('开始爬虫任务')
|
|
||||||
// 这里添加爬虫启动逻辑
|
|
||||||
}
|
|
||||||
|
|
||||||
// 导出数据
|
|
||||||
const exportData = () => {
|
|
||||||
Message.info('导出数据')
|
|
||||||
// 这里添加数据导出逻辑
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打开爬虫设置
|
|
||||||
const openCrawlerSettings = () => {
|
|
||||||
crawlerSettingsVisible.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleUploadDocument = async (file: File) => {
|
|
||||||
uploading.value = true
|
|
||||||
|
|
||||||
try {
|
|
||||||
const formData = new FormData()
|
|
||||||
formData.append('file', file)
|
|
||||||
formData.append('projectId', currentDetail.value.id.toString())
|
|
||||||
|
|
||||||
// 替换为实际API调用
|
|
||||||
const response = await uploadBiddingDocument(formData)
|
|
||||||
|
|
||||||
Message.success('文件上传成功')
|
|
||||||
currentDetail.value.biddingDocuments = response.data.fileUrl
|
|
||||||
} catch (error) {
|
|
||||||
Message.error(`文件上传失败: ${error.message}`)
|
|
||||||
} finally {
|
|
||||||
uploading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 模拟上传API
|
|
||||||
const uploadBiddingDocument = (formData: FormData) => {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
const file = formData.get('file') as File
|
|
||||||
const projectId = formData.get('projectId')
|
|
||||||
const extension = file.name.split('.').pop()
|
|
||||||
resolve({
|
|
||||||
data: {
|
|
||||||
fileUrl: `https://your-api-domain.com/uploads/${projectId}.${extension}`
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}, 1500)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
// 初始化加载数据
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="less">
|
|
||||||
.project-list-container {
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-section {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-area {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-area {
|
|
||||||
display: flex;
|
|
||||||
gap: 12px;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tabs-section {
|
|
||||||
flex: 1;
|
|
||||||
min-height: 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pagination-wrapper {
|
|
||||||
margin-top: 16px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-tabs-content) {
|
|
||||||
flex: 1;
|
|
||||||
min-height: 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-tabs-pane) {
|
|
||||||
flex: 1;
|
|
||||||
min-height: 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-tabs-nav-tab) {
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-tabs-nav-tab-list) {
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 响应式处理
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.header-section {
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 16px;
|
|
||||||
align-items: stretch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-area {
|
|
||||||
flex: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-area {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,64 +0,0 @@
|
||||||
// 项目状态枚举
|
|
||||||
export enum ProjectStatus {
|
|
||||||
NOT_STARTED = 'not_started',
|
|
||||||
IN_PROGRESS = 'in_progress',
|
|
||||||
COMPLETED = 'completed',
|
|
||||||
PAUSED = 'paused',
|
|
||||||
CANCELLED = 'cancelled'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 项目数据接口
|
|
||||||
export interface ProjectData {
|
|
||||||
id: number
|
|
||||||
projectName: string
|
|
||||||
unitCount: number
|
|
||||||
startDate: string
|
|
||||||
endDate: string
|
|
||||||
status: ProjectStatus
|
|
||||||
progress: number
|
|
||||||
manager: string
|
|
||||||
isMyProject: boolean
|
|
||||||
description?: string
|
|
||||||
location?: string
|
|
||||||
client?: string
|
|
||||||
budget?: number
|
|
||||||
team?: string[]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 选项卡类型
|
|
||||||
export type TabKey = 'all' | 'my' | 'pending'
|
|
||||||
|
|
||||||
// 项目筛选条件
|
|
||||||
export interface ProjectFilter {
|
|
||||||
keyword?: string
|
|
||||||
status?: ProjectStatus
|
|
||||||
manager?: string
|
|
||||||
dateRange?: [string, string]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 项目统计信息
|
|
||||||
export interface ProjectStats {
|
|
||||||
total: number
|
|
||||||
inProgress: number
|
|
||||||
completed: number
|
|
||||||
notStarted: number
|
|
||||||
myProjects: number
|
|
||||||
}
|
|
||||||
|
|
||||||
// 招标详情
|
|
||||||
export interface BiddingDetail {
|
|
||||||
id: number
|
|
||||||
projectName: string
|
|
||||||
biddingUnit: string
|
|
||||||
budgetAmount: number
|
|
||||||
deadline: string
|
|
||||||
crawlingTime: string
|
|
||||||
projectLocation: string
|
|
||||||
projectDuration: string
|
|
||||||
biddingScope: string
|
|
||||||
qualificationRequirements: string
|
|
||||||
sourcePlatform: string
|
|
||||||
biddingDocuments: string
|
|
||||||
biddingContent: string
|
|
||||||
contentItems?: string[]
|
|
||||||
}
|
|
|
@ -1,28 +1,28 @@
|
||||||
<template>
|
<template>
|
||||||
<GiPageLayout>
|
<GiPageLayout>
|
||||||
<GiTable
|
<GiTable
|
||||||
row-key="contractId"
|
row-key="id"
|
||||||
title="收入合同管理"
|
title="收入合同管理"
|
||||||
:data="dataList"
|
:data="dataList"
|
||||||
:columns="tableColumns"
|
:columns="tableColumns"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:scroll="{ x: '100%', y: '100%', minWidth: 1600 }"
|
:scroll="{ x: '100%', y: '100%', minWidth: 1600 }"
|
||||||
:pagination="pagination"
|
:pagination="pagination"
|
||||||
@page-change="onPageChange"
|
@page-change="onPageChange"
|
||||||
@page-size-change="onPageSizeChange"
|
@page-size-change="onPageSizeChange"
|
||||||
@refresh="search"
|
@refresh="search"
|
||||||
>
|
>
|
||||||
<template #top>
|
<template #top>
|
||||||
<GiForm
|
<GiForm
|
||||||
v-model="searchForm"
|
v-model="searchForm"
|
||||||
search
|
search
|
||||||
:columns="queryFormColumns"
|
:columns="queryFormColumns"
|
||||||
size="medium"
|
size="medium"
|
||||||
@search="search"
|
@search="search"
|
||||||
@reset="reset"
|
@reset="reset"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #toolbar-left>
|
<template #toolbar-left>
|
||||||
<a-space>
|
<a-space>
|
||||||
<a-button type="primary" @click="openAddModal">
|
<a-button type="primary" @click="openAddModal">
|
||||||
|
@ -35,35 +35,30 @@
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-space>
|
</a-space>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 合同状态 -->
|
<!-- 合同状态 -->
|
||||||
<template #contractStatus="{ record }">
|
<template #status="{ record }">
|
||||||
<a-tag :color="getStatusColor(record.contractStatus)">
|
<a-tag :color="getStatusColor(record.status)">
|
||||||
{{ getStatusText(record.contractStatus) }}
|
{{ getStatusText(record.status) }}
|
||||||
</a-tag>
|
</a-tag>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 合同金额 -->
|
<!-- 合同金额 -->
|
||||||
<template #amount="{ record }">
|
<template #contractAmount="{ record }">
|
||||||
<span class="font-medium text-green-600">¥{{ record.amount.toLocaleString() }}万</span>
|
<span class="font-medium text-green-600">¥{{ record.contractAmount.toLocaleString() }}万</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 已收款金额 -->
|
<!-- 已收款金额 -->
|
||||||
<template #receivedAmount="{ record }">
|
<template #receivedAmount="{ record }">
|
||||||
<span class="font-medium text-blue-600">¥{{ record.receivedAmount.toLocaleString() }}万</span>
|
<span class="font-medium text-blue-600">¥{{ record.receivedAmount.toLocaleString() }}万</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 已结算金额 -->
|
|
||||||
<template #settlementAmount="{ record }">
|
|
||||||
<span class="font-medium text-orange-600">¥{{ record.settlementAmount.toLocaleString() }}万</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 操作列 -->
|
<!-- 操作列 -->
|
||||||
<template #action="{ record }">
|
<template #action="{ record }">
|
||||||
<a-space>
|
<a-space>
|
||||||
<a-link @click="viewDetail(record)">详情</a-link>
|
<a-link @click="viewDetail(record)">详情</a-link>
|
||||||
<a-link @click="editRecord(record)" v-if="record.contractStatus === 'draft'">编辑</a-link>
|
<a-link @click="editRecord(record)" v-if="record.status === 'draft'">编辑</a-link>
|
||||||
<a-link @click="approveContract(record)" v-if="record.contractStatus === 'pending'">审批</a-link>
|
<a-link @click="approveContract(record)" v-if="record.status === 'pending'">审批</a-link>
|
||||||
<a-link @click="viewPayment(record)">收款记录</a-link>
|
<a-link @click="viewPayment(record)">收款记录</a-link>
|
||||||
</a-space>
|
</a-space>
|
||||||
</template>
|
</template>
|
||||||
|
@ -75,38 +70,38 @@
|
||||||
import { ref, reactive, onMounted } from 'vue'
|
import { ref, reactive, onMounted } from 'vue'
|
||||||
import { Message } from '@arco-design/web-vue'
|
import { Message } from '@arco-design/web-vue'
|
||||||
import type { TableColumnData } from '@arco-design/web-vue'
|
import type { TableColumnData } from '@arco-design/web-vue'
|
||||||
import { getContractList, type ContractQueryParams, type ContractData } from '@/apis/contract'
|
|
||||||
|
|
||||||
// 搜索表单
|
// 搜索表单
|
||||||
let searchForm = reactive({
|
let searchForm = reactive({
|
||||||
code: '',
|
contractName: '',
|
||||||
customer: '',
|
contractCode: '',
|
||||||
contractStatus: '',
|
client: '',
|
||||||
|
status: '',
|
||||||
signDate: '',
|
signDate: '',
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 10
|
size: 10
|
||||||
})
|
})
|
||||||
|
|
||||||
// 查询条件配置
|
// 查询条件配置
|
||||||
const queryFormColumns = [
|
const queryFormColumns = [
|
||||||
{
|
{
|
||||||
field: 'code',
|
field: 'contractName',
|
||||||
label: '合同编号',
|
label: '合同名称',
|
||||||
type: 'input' as const,
|
type: 'input' as const,
|
||||||
props: {
|
props: {
|
||||||
placeholder: '请输入合同编号'
|
placeholder: '请输入合同名称'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'customer',
|
field: 'client',
|
||||||
label: '客户名称',
|
label: '客户',
|
||||||
type: 'input' as const,
|
type: 'input' as const,
|
||||||
props: {
|
props: {
|
||||||
placeholder: '请输入客户名称'
|
placeholder: '请输入客户名称'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'contractStatus',
|
field: 'status',
|
||||||
label: '合同状态',
|
label: '合同状态',
|
||||||
type: 'select' as const,
|
type: 'select' as const,
|
||||||
props: {
|
props: {
|
||||||
|
@ -125,33 +120,83 @@ const queryFormColumns = [
|
||||||
|
|
||||||
// 表格列配置
|
// 表格列配置
|
||||||
const tableColumns: TableColumnData[] = [
|
const tableColumns: TableColumnData[] = [
|
||||||
{ title: '合同编号', dataIndex: 'code', width: 150 },
|
{ title: '合同编号', dataIndex: 'contractCode', width: 150 },
|
||||||
{ title: '合同内容', dataIndex: 'contractText', width: 250, ellipsis: true, tooltip: true },
|
{ title: '合同名称', dataIndex: 'contractName', width: 250, ellipsis: true, tooltip: true },
|
||||||
{ title: '客户名称', dataIndex: 'customer', width: 200, ellipsis: true, tooltip: true },
|
{ title: '客户名称', dataIndex: 'client', width: 200, ellipsis: true, tooltip: true },
|
||||||
{ title: '合同金额', dataIndex: 'amount', slotName: 'amount', width: 120 },
|
{ title: '合同金额', dataIndex: 'contractAmount', slotName: 'contractAmount', width: 120 },
|
||||||
{ title: '已收款金额', dataIndex: 'receivedAmount', slotName: 'receivedAmount', width: 120 },
|
{ title: '已收款金额', dataIndex: 'receivedAmount', slotName: 'receivedAmount', width: 120 },
|
||||||
{ title: '已结算金额', dataIndex: 'settlementAmount', slotName: 'settlementAmount', width: 120 },
|
{ title: '未收款金额', dataIndex: 'pendingAmount', width: 120 },
|
||||||
{ title: '签订日期', dataIndex: 'signDate', width: 120 },
|
{ title: '签署日期', dataIndex: 'signDate', width: 120 },
|
||||||
{ title: '付款日期', dataIndex: 'paymentDate', width: 120 },
|
{ title: '开始日期', dataIndex: 'startDate', width: 120 },
|
||||||
{ title: '履约期限', dataIndex: 'performanceDeadline', width: 120 },
|
{ title: '结束日期', dataIndex: 'endDate', width: 120 },
|
||||||
{ title: '合同状态', dataIndex: 'contractStatus', slotName: 'contractStatus', width: 100 },
|
{ title: '合同状态', dataIndex: 'status', slotName: 'status', width: 100 },
|
||||||
{ title: '业务员', dataIndex: 'salespersonName', width: 100 },
|
{ title: '项目经理', dataIndex: 'projectManager', width: 100 },
|
||||||
{ title: '部门', dataIndex: 'salespersonDeptName', width: 120 },
|
{ title: '销售经理', dataIndex: 'salesManager', width: 100 },
|
||||||
{ title: '项目名称', dataIndex: 'projectName', width: 200, ellipsis: true, tooltip: true },
|
{ title: '完成进度', dataIndex: 'progress', width: 100 },
|
||||||
{ title: '产品或服务', dataIndex: 'productService', width: 200, ellipsis: true, tooltip: true },
|
{ title: '备注', dataIndex: 'remark', width: 200, ellipsis: true, tooltip: true },
|
||||||
{ title: '期限', dataIndex: 'duration', width: 100 },
|
|
||||||
{ title: '备注', dataIndex: 'notes', width: 200, ellipsis: true, tooltip: true },
|
|
||||||
{ title: '操作', slotName: 'action', width: 200, fixed: 'right' }
|
{ title: '操作', slotName: 'action', width: 200, fixed: 'right' }
|
||||||
]
|
]
|
||||||
|
|
||||||
// 数据状态
|
// 数据状态
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const dataList = ref<ContractData[]>([])
|
const dataList = ref([
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
contractCode: 'RC2024001',
|
||||||
|
contractName: '华能新能源风电场叶片检测服务合同',
|
||||||
|
client: '华能新能源股份有限公司',
|
||||||
|
contractAmount: 320,
|
||||||
|
receivedAmount: 192,
|
||||||
|
pendingAmount: 128,
|
||||||
|
signDate: '2024-02-20',
|
||||||
|
startDate: '2024-03-01',
|
||||||
|
endDate: '2024-04-30',
|
||||||
|
status: 'executing',
|
||||||
|
projectManager: '张项目经理',
|
||||||
|
salesManager: '李销售经理',
|
||||||
|
progress: '60%',
|
||||||
|
remark: '项目进展顺利,客户满意度高'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
contractCode: 'RC2024002',
|
||||||
|
contractName: '大唐风电场防雷检测项目合同',
|
||||||
|
client: '大唐新能源股份有限公司',
|
||||||
|
contractAmount: 268,
|
||||||
|
receivedAmount: 134,
|
||||||
|
pendingAmount: 134,
|
||||||
|
signDate: '2024-02-25',
|
||||||
|
startDate: '2024-03-05',
|
||||||
|
endDate: '2024-04-20',
|
||||||
|
status: 'executing',
|
||||||
|
projectManager: '王项目经理',
|
||||||
|
salesManager: '赵销售经理',
|
||||||
|
progress: '45%',
|
||||||
|
remark: '按计划执行中'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
contractCode: 'RC2024003',
|
||||||
|
contractName: '中广核风电场设备维护服务合同',
|
||||||
|
client: '中广核新能源投资有限公司',
|
||||||
|
contractAmount: 450,
|
||||||
|
receivedAmount: 450,
|
||||||
|
pendingAmount: 0,
|
||||||
|
signDate: '2024-01-15',
|
||||||
|
startDate: '2024-01-20',
|
||||||
|
endDate: '2024-01-31',
|
||||||
|
status: 'completed',
|
||||||
|
projectManager: '刘项目经理',
|
||||||
|
salesManager: '孙销售经理',
|
||||||
|
progress: '100%',
|
||||||
|
remark: '项目已完成,客户验收通过'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
const pagination = reactive({
|
const pagination = reactive({
|
||||||
current: 1,
|
current: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
total: 0,
|
total: 3,
|
||||||
showTotal: true,
|
showTotal: true,
|
||||||
showPageSize: true
|
showPageSize: true
|
||||||
})
|
})
|
||||||
|
@ -185,38 +230,20 @@ const getStatusText = (status: string) => {
|
||||||
// 搜索和重置
|
// 搜索和重置
|
||||||
const search = async () => {
|
const search = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
setTimeout(() => {
|
||||||
const params: ContractQueryParams = {
|
|
||||||
...searchForm,
|
|
||||||
type: 'revenue', // 只查询收入合同
|
|
||||||
page: searchForm.page,
|
|
||||||
pageSize: searchForm.pageSize
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await getContractList(params)
|
|
||||||
|
|
||||||
if (response.code === 0) {
|
|
||||||
dataList.value = response.rows || []
|
|
||||||
pagination.total = response.total || 0
|
|
||||||
} else {
|
|
||||||
Message.error(response.msg || '获取合同列表失败')
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取合同列表失败:', error)
|
|
||||||
Message.error('获取合同列表失败')
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
Object.assign(searchForm, {
|
Object.assign(searchForm, {
|
||||||
code: '',
|
contractName: '',
|
||||||
customer: '',
|
contractCode: '',
|
||||||
contractStatus: '',
|
client: '',
|
||||||
|
status: '',
|
||||||
signDate: '',
|
signDate: '',
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 10
|
size: 10
|
||||||
})
|
})
|
||||||
pagination.current = 1
|
pagination.current = 1
|
||||||
search()
|
search()
|
||||||
|
@ -230,7 +257,7 @@ const onPageChange = (page: number) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPageSizeChange = (size: number) => {
|
const onPageSizeChange = (size: number) => {
|
||||||
searchForm.pageSize = size
|
searchForm.size = size
|
||||||
searchForm.page = 1
|
searchForm.page = 1
|
||||||
pagination.pageSize = size
|
pagination.pageSize = size
|
||||||
pagination.current = 1
|
pagination.current = 1
|
||||||
|
@ -246,20 +273,20 @@ const exportContract = () => {
|
||||||
Message.info('导出合同功能开发中...')
|
Message.info('导出合同功能开发中...')
|
||||||
}
|
}
|
||||||
|
|
||||||
const viewDetail = (record: ContractData) => {
|
const viewDetail = (record: any) => {
|
||||||
Message.info(`查看合同详情: ${record.contractText}`)
|
Message.info(`查看合同详情: ${record.contractName}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const editRecord = (record: ContractData) => {
|
const editRecord = (record: any) => {
|
||||||
Message.info(`编辑合同: ${record.contractText}`)
|
Message.info(`编辑合同: ${record.contractName}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const approveContract = (record: ContractData) => {
|
const approveContract = (record: any) => {
|
||||||
Message.info(`审批合同: ${record.contractText}`)
|
Message.info(`审批合同: ${record.contractName}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const viewPayment = (record: ContractData) => {
|
const viewPayment = (record: any) => {
|
||||||
Message.info(`查看收款记录: ${record.contractText}`)
|
Message.info(`查看收款记录: ${record.contractName}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
|
|
||||||
</style>
|
|
|
@ -1,439 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="process-management">
|
|
||||||
<a-card title="制度公示管理" :bordered="false">
|
|
||||||
<!-- 搜索区域 -->
|
|
||||||
<div class="search-container">
|
|
||||||
<a-form layout="inline" :model="searchForm" class="search-form">
|
|
||||||
<a-form-item label="提案标题">
|
|
||||||
<a-input
|
|
||||||
v-model="searchForm.title"
|
|
||||||
placeholder="请输入提案标题"
|
|
||||||
allow-clear
|
|
||||||
style="width: 200px"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item label="提案人">
|
|
||||||
<a-input
|
|
||||||
v-model="searchForm.proposer"
|
|
||||||
placeholder="请输入提案人"
|
|
||||||
allow-clear
|
|
||||||
style="width: 150px"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item label="状态">
|
|
||||||
<a-select
|
|
||||||
v-model="searchForm.status"
|
|
||||||
placeholder="请选择状态"
|
|
||||||
allow-clear
|
|
||||||
style="width: 150px"
|
|
||||||
>
|
|
||||||
<a-option value="">全部</a-option>
|
|
||||||
<a-option value="PUBLISHED">已公告</a-option>
|
|
||||||
<a-option value="APPROVED">已公示</a-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item>
|
|
||||||
<a-space>
|
|
||||||
<a-button type="primary" @click="search">
|
|
||||||
<template #icon><icon-search /></template>
|
|
||||||
搜索
|
|
||||||
</a-button>
|
|
||||||
<a-button @click="reset">
|
|
||||||
<template #icon><icon-refresh /></template>
|
|
||||||
重置
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a-table
|
|
||||||
:columns="columns"
|
|
||||||
:data="tableData"
|
|
||||||
:loading="loading"
|
|
||||||
:pagination="pagination"
|
|
||||||
@page-change="handlePageChange"
|
|
||||||
@page-size-change="handlePageSizeChange"
|
|
||||||
>
|
|
||||||
<template #toolbar-left>
|
|
||||||
<span class="search-result-info">
|
|
||||||
共找到 <strong>{{ pagination.total }}</strong> 条记录
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
<template #status="{ record }">
|
|
||||||
<a-tag :color="getStatusColor(record.status)">
|
|
||||||
{{ getStatusText(record.status) }}
|
|
||||||
</a-tag>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #level="{ record }">
|
|
||||||
<a-tag :color="getLevelColor(record.level)">
|
|
||||||
{{ getLevelText(record.level) }}
|
|
||||||
</a-tag>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #operations="{ record }">
|
|
||||||
<a-space>
|
|
||||||
<a-button type="text" size="small" @click="handleView(record)">
|
|
||||||
查看详情
|
|
||||||
</a-button>
|
|
||||||
<a-button
|
|
||||||
v-if="record.status === RegulationStatus.PUBLISHED"
|
|
||||||
type="text"
|
|
||||||
size="small"
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
已公告
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</template>
|
|
||||||
</a-table>
|
|
||||||
</a-card>
|
|
||||||
|
|
||||||
<!-- 提案详情弹窗 -->
|
|
||||||
<a-modal
|
|
||||||
v-model:visible="detailModalVisible"
|
|
||||||
title="提案详情"
|
|
||||||
width="800px"
|
|
||||||
:footer="false"
|
|
||||||
>
|
|
||||||
<div class="proposal-detail" v-if="currentProposal">
|
|
||||||
<div class="detail-header">
|
|
||||||
<h3>{{ currentProposal.title }}</h3>
|
|
||||||
<div class="detail-meta">
|
|
||||||
<span>提案人: {{ currentProposal.createByName }}</span>
|
|
||||||
<span>提案类型: {{ currentProposal.regulationType }}</span>
|
|
||||||
<span>适用范围: {{ currentProposal.scope }}</span>
|
|
||||||
<span>级别: <a-tag :color="getLevelColor(currentProposal.level)">{{ getLevelText(currentProposal.level) }}</a-tag></span>
|
|
||||||
<span>创建时间: {{ formatDate(currentProposal.createTime) }}</span>
|
|
||||||
<span>状态: <a-tag :color="getStatusColor(currentProposal.status)">{{ getStatusText(currentProposal.status) }}</a-tag></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a-divider />
|
|
||||||
|
|
||||||
<div class="detail-content">
|
|
||||||
<h4>提案内容</h4>
|
|
||||||
<div class="content-text">{{ currentProposal.content }}</div>
|
|
||||||
|
|
||||||
<h4>备注</h4>
|
|
||||||
<div class="content-text">{{ currentProposal.remark || '暂无备注' }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a-divider />
|
|
||||||
|
|
||||||
<div class="detail-footer">
|
|
||||||
<a-button
|
|
||||||
v-if="currentProposal.status === RegulationStatus.PUBLISHED"
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
已自动公示
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-modal>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, reactive, onMounted } from 'vue'
|
|
||||||
import { Message } from '@arco-design/web-vue'
|
|
||||||
import { IconSearch, IconRefresh } from '@arco-design/web-vue/es/icon'
|
|
||||||
import { useRegulationStore } from '@/stores/modules/regulation'
|
|
||||||
import { regulationApi } from '@/apis/regulation'
|
|
||||||
import {
|
|
||||||
RegulationStatus,
|
|
||||||
RegulationLevel,
|
|
||||||
type Regulation,
|
|
||||||
type RegulationType
|
|
||||||
} from '@/apis/regulation/type'
|
|
||||||
|
|
||||||
defineOptions({ name: 'ProcessManagement' })
|
|
||||||
|
|
||||||
// 表格列定义
|
|
||||||
const columns = [
|
|
||||||
{ title: '提案标题', dataIndex: 'title', key: 'title', width: 200 },
|
|
||||||
{ title: '提案人', dataIndex: 'createByName', key: 'createByName', width: 120 },
|
|
||||||
{ title: '提案类型', dataIndex: 'regulationType', key: 'regulationType', width: 120 },
|
|
||||||
{ title: '状态', dataIndex: 'status', key: 'status', slotName: 'status', width: 100 },
|
|
||||||
{ title: '级别', dataIndex: 'level', key: 'level', slotName: 'level', width: 80 },
|
|
||||||
{ title: '创建时间', dataIndex: 'createTime', key: 'createTime', width: 180 },
|
|
||||||
{ title: '操作', key: 'operations', slotName: 'operations', width: 150 }
|
|
||||||
]
|
|
||||||
|
|
||||||
// 搜索表单
|
|
||||||
const searchForm = reactive({
|
|
||||||
title: '',
|
|
||||||
proposer: '',
|
|
||||||
status: ''
|
|
||||||
})
|
|
||||||
|
|
||||||
// 表格数据
|
|
||||||
const tableData = ref<Regulation[]>([])
|
|
||||||
const loading = ref(false)
|
|
||||||
const pagination = reactive({
|
|
||||||
current: 1,
|
|
||||||
pageSize: 10,
|
|
||||||
total: 0,
|
|
||||||
showTotal: true,
|
|
||||||
showJumper: true,
|
|
||||||
showPageSize: true
|
|
||||||
})
|
|
||||||
|
|
||||||
const currentProposal = ref<Regulation | null>(null)
|
|
||||||
|
|
||||||
// 详情相关
|
|
||||||
const detailModalVisible = ref(false)
|
|
||||||
|
|
||||||
// 当前用户
|
|
||||||
const currentUser = ref('管理者') // 从用户认证系统获取当前用户ID
|
|
||||||
|
|
||||||
// 制度管理store
|
|
||||||
const regulationStore = useRegulationStore()
|
|
||||||
|
|
||||||
// 获取状态颜色
|
|
||||||
const getStatusColor = (status: RegulationStatus) => {
|
|
||||||
const colors = {
|
|
||||||
[RegulationStatus.PUBLISHED]: 'purple',
|
|
||||||
[RegulationStatus.APPROVED]: 'green',
|
|
||||||
}
|
|
||||||
return colors[status] || 'purple'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取状态文本
|
|
||||||
const getStatusText = (status: RegulationStatus) => {
|
|
||||||
const texts = {
|
|
||||||
[RegulationStatus.PUBLISHED]: '已公告',
|
|
||||||
[RegulationStatus.APPROVED]: '已公示',
|
|
||||||
}
|
|
||||||
return texts[status] || '已公告'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 格式化日期
|
|
||||||
const formatDate = (dateString: string) => {
|
|
||||||
if (!dateString) return '-'
|
|
||||||
const date = new Date(dateString)
|
|
||||||
return date.toLocaleDateString('zh-CN', {
|
|
||||||
year: 'numeric',
|
|
||||||
month: '2-digit',
|
|
||||||
day: '2-digit',
|
|
||||||
hour: '2-digit',
|
|
||||||
minute: '2-digit'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取级别颜色
|
|
||||||
const getLevelColor = (level: RegulationLevel) => {
|
|
||||||
const colors = {
|
|
||||||
[RegulationLevel.LOW]: 'blue',
|
|
||||||
[RegulationLevel.MEDIUM]: 'orange',
|
|
||||||
[RegulationLevel.HIGH]: 'red'
|
|
||||||
}
|
|
||||||
return colors[level] || 'blue'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取级别文本
|
|
||||||
const getLevelText = (level: RegulationLevel) => {
|
|
||||||
const texts = {
|
|
||||||
[RegulationLevel.LOW]: '低',
|
|
||||||
[RegulationLevel.MEDIUM]: '中',
|
|
||||||
[RegulationLevel.HIGH]: '高'
|
|
||||||
}
|
|
||||||
return texts[level] || '中'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取表格数据 - 使用后端搜索接口
|
|
||||||
const getTableData = async () => {
|
|
||||||
loading.value = true
|
|
||||||
try {
|
|
||||||
// 构建请求参数
|
|
||||||
const requestParams: any = {
|
|
||||||
page: pagination.current,
|
|
||||||
size: pagination.pageSize,
|
|
||||||
title: searchForm.title || undefined,
|
|
||||||
proposer: searchForm.proposer || undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
if (searchForm.status) {
|
|
||||||
// 用户选择了特定状态
|
|
||||||
requestParams.status = searchForm.status
|
|
||||||
const response = await regulationApi.getRegulationList(requestParams)
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
tableData.value = response.data.records
|
|
||||||
pagination.total = response.data.total
|
|
||||||
pagination.current = response.data.current
|
|
||||||
} else {
|
|
||||||
Message.error('搜索失败')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 用户没有选择状态,默认显示已公示和已公告的提案
|
|
||||||
// 分别查询已公告和已公示的提案
|
|
||||||
const [publishedResponse, approvedResponse] = await Promise.all([
|
|
||||||
regulationApi.getRegulationList({
|
|
||||||
...requestParams,
|
|
||||||
status: RegulationStatus.PUBLISHED
|
|
||||||
}),
|
|
||||||
regulationApi.getRegulationList({
|
|
||||||
...requestParams,
|
|
||||||
status: RegulationStatus.APPROVED
|
|
||||||
})
|
|
||||||
])
|
|
||||||
|
|
||||||
if (publishedResponse.status === 200 && approvedResponse.status === 200) {
|
|
||||||
// 合并两个结果
|
|
||||||
const allRecords = [
|
|
||||||
...publishedResponse.data.records,
|
|
||||||
...approvedResponse.data.records
|
|
||||||
]
|
|
||||||
|
|
||||||
// 按创建时间排序
|
|
||||||
allRecords.sort((a, b) => new Date(b.createTime).getTime() - new Date(a.createTime).getTime())
|
|
||||||
|
|
||||||
tableData.value = allRecords
|
|
||||||
pagination.total = allRecords.length
|
|
||||||
pagination.current = 1
|
|
||||||
} else {
|
|
||||||
Message.error('搜索失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('搜索制度公示失败:', error)
|
|
||||||
Message.error('搜索失败')
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 搜索
|
|
||||||
const search = () => {
|
|
||||||
pagination.current = 1
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重置
|
|
||||||
const reset = () => {
|
|
||||||
Object.assign(searchForm, {
|
|
||||||
title: '',
|
|
||||||
proposer: '',
|
|
||||||
status: ''
|
|
||||||
})
|
|
||||||
pagination.current = 1
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查看
|
|
||||||
const handleView = (record: Regulation) => {
|
|
||||||
currentProposal.value = record
|
|
||||||
detailModalVisible.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 分页事件
|
|
||||||
const handlePageChange = (page: number) => {
|
|
||||||
pagination.current = page
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
const handlePageSizeChange = (pageSize: number) => {
|
|
||||||
pagination.pageSize = pageSize
|
|
||||||
pagination.current = 1
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
getTableData()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.process-management {
|
|
||||||
.arco-card {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-container {
|
|
||||||
padding: 16px;
|
|
||||||
background: var(--color-bg-2);
|
|
||||||
border-radius: 6px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
|
|
||||||
.search-form {
|
|
||||||
.arco-form-item {
|
|
||||||
margin-bottom: 0;
|
|
||||||
margin-right: 16px;
|
|
||||||
|
|
||||||
.arco-form-item-label {
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--color-text-1);
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.arco-input,
|
|
||||||
.arco-select {
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arco-btn {
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-result-info {
|
|
||||||
color: var(--color-text-2);
|
|
||||||
font-size: 14px;
|
|
||||||
|
|
||||||
strong {
|
|
||||||
color: var(--color-text-1);
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.proposal-detail {
|
|
||||||
.detail-header {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin-bottom: 12px;
|
|
||||||
color: var(--color-text-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-meta {
|
|
||||||
display: flex;
|
|
||||||
gap: 16px;
|
|
||||||
color: var(--color-text-3);
|
|
||||||
font-size: 14px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-content {
|
|
||||||
h4 {
|
|
||||||
margin: 16px 0 8px 0;
|
|
||||||
color: var(--color-text-1);
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-text {
|
|
||||||
color: var(--color-text-2);
|
|
||||||
line-height: 1.6;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
padding: 12px;
|
|
||||||
background: var(--color-fill-1);
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-footer {
|
|
||||||
display: flex;
|
|
||||||
gap: 12px;
|
|
||||||
justify-content: center;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,108 +0,0 @@
|
||||||
<template>
|
|
||||||
<GiPageLayout
|
|
||||||
:margin="true"
|
|
||||||
:default-collapsed="false"
|
|
||||||
:header-style="isDesktop ? { padding: 0, borderBottomWidth: 0 } : { borderBottomWidth: '1px' } "
|
|
||||||
>
|
|
||||||
<template v-if="isDesktop" #left>
|
|
||||||
<a-tabs v-model:active-key="activeKey" type="rounded" position="left" hide-content size="large" @change="change">
|
|
||||||
<a-tab-pane v-for="(item) in menuList" :key="item.key">
|
|
||||||
<template #title>
|
|
||||||
<div style="display: flex; align-items: center">
|
|
||||||
<GiSvgIcon :name="item.icon" :size="18" style="margin-right: 4px" />
|
|
||||||
{{ item.name }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</a-tab-pane>
|
|
||||||
</a-tabs>
|
|
||||||
</template>
|
|
||||||
<template #header>
|
|
||||||
<a-tabs v-if="!isDesktop" v-model:active-key="activeKey" type="rounded" position="top" size="large" @change="change">
|
|
||||||
<a-tab-pane v-for="(item) in menuList" :key="item.key" :title="item.name">
|
|
||||||
<template #title>
|
|
||||||
<div style="display: flex; align-items: center">
|
|
||||||
<GiSvgIcon :name="item.icon" :size="18" style="margin-right: 4px" />
|
|
||||||
{{ item.name }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</a-tab-pane>
|
|
||||||
</a-tabs>
|
|
||||||
</template>
|
|
||||||
<transition name="fade-slide" mode="out-in" appear>
|
|
||||||
<component :is="menuList.find((item) => item.key === activeKey)?.value"></component>
|
|
||||||
</transition>
|
|
||||||
</GiPageLayout>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="tsx">
|
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
|
||||||
import SystemRegulation from './repository.vue'
|
|
||||||
import RegulationProposal from './proposal/index.vue'
|
|
||||||
import RegulationType from './type/index.vue'
|
|
||||||
import ProcessManagement from './confirm.vue'
|
|
||||||
import { useDevice } from '@/hooks'
|
|
||||||
|
|
||||||
defineOptions({ name: 'RegulationManagement' })
|
|
||||||
|
|
||||||
const { isDesktop } = useDevice()
|
|
||||||
|
|
||||||
const data = [
|
|
||||||
{ name: '制度公告', key: 'system-regulation', icon: 'file-text', value: SystemRegulation, path: '/regulation/system-regulation' },
|
|
||||||
{ name: '制度提案', key: 'proposal', icon: 'edit', value: RegulationProposal, path: '/regulation/proposal' },
|
|
||||||
{ name: '制度公示', key: 'process-management', icon: 'workflow', value: ProcessManagement, path: '/regulation/process-management' },
|
|
||||||
{ name: '制度类型', key: 'type', icon: 'tag', value: RegulationType, path: '/regulation/type' },
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
const menuList = computed(() => {
|
|
||||||
return data
|
|
||||||
})
|
|
||||||
|
|
||||||
const route = useRoute()
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
// 根据当前路由确定激活的标签页
|
|
||||||
const activeKey = computed(() => {
|
|
||||||
const currentPath = route.path
|
|
||||||
const menuItem = menuList.value.find(item => item.path === currentPath)
|
|
||||||
return menuItem ? menuItem.key : menuList.value[0].key
|
|
||||||
})
|
|
||||||
watch(
|
|
||||||
() => route.path,
|
|
||||||
() => {
|
|
||||||
// 路由变化时会自动更新activeKey
|
|
||||||
},
|
|
||||||
{ immediate: true },
|
|
||||||
)
|
|
||||||
const change = (key: string | number) => {
|
|
||||||
const menuItem = menuList.value.find(item => item.key === key)
|
|
||||||
if (menuItem) {
|
|
||||||
router.push(menuItem.path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.gi_page {
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-tabs-nav-vertical.arco-tabs-nav-type-line .arco-tabs-tab) {
|
|
||||||
margin: 0;
|
|
||||||
padding: 8px 16px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: var(--color-fill-1);
|
|
||||||
|
|
||||||
.arco-tabs-tab-title {
|
|
||||||
&::before {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.arco-tabs-tab-active {
|
|
||||||
background: rgba(var(--primary-6), 0.08);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,907 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="regulation-proposal">
|
|
||||||
<a-card title="制度提案管理" :bordered="false">
|
|
||||||
<template #extra>
|
|
||||||
<a-button type="primary" @click="handleAdd">
|
|
||||||
<template #icon>
|
|
||||||
<GiSvgIcon name="plus" />
|
|
||||||
</template>
|
|
||||||
新增制度提案
|
|
||||||
</a-button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 搜索区域 -->
|
|
||||||
<div class="search-container">
|
|
||||||
<a-form layout="inline" :model="searchForm" class="search-form">
|
|
||||||
<a-form-item label="提案标题">
|
|
||||||
<a-input
|
|
||||||
v-model="searchForm.title"
|
|
||||||
placeholder="请输入提案标题"
|
|
||||||
allow-clear
|
|
||||||
style="width: 200px"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item label="提案人">
|
|
||||||
<a-input
|
|
||||||
v-model="searchForm.proposer"
|
|
||||||
placeholder="请输入提案人"
|
|
||||||
allow-clear
|
|
||||||
style="width: 150px"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item label="状态">
|
|
||||||
<a-select
|
|
||||||
v-model="searchForm.status"
|
|
||||||
placeholder="请选择状态"
|
|
||||||
allow-clear
|
|
||||||
style="width: 150px"
|
|
||||||
>
|
|
||||||
<a-option value="">全部</a-option>
|
|
||||||
<a-option value="DRAFT">草稿</a-option>
|
|
||||||
<a-option value="PUBLISHED">已公告</a-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item>
|
|
||||||
<a-space>
|
|
||||||
<a-button type="primary" @click="search">
|
|
||||||
<template #icon><icon-search /></template>
|
|
||||||
搜索
|
|
||||||
</a-button>
|
|
||||||
<a-button @click="reset">
|
|
||||||
<template #icon><icon-refresh /></template>
|
|
||||||
重置
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a-table
|
|
||||||
:columns="columns"
|
|
||||||
:data="tableData"
|
|
||||||
:loading="loading"
|
|
||||||
:pagination="pagination"
|
|
||||||
@page-change="handlePageChange"
|
|
||||||
@page-size-change="handlePageSizeChange"
|
|
||||||
>
|
|
||||||
<template #toolbar-left>
|
|
||||||
<span class="search-result-info">
|
|
||||||
共找到 <strong>{{ pagination.total }}</strong> 条记录
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
<template #status="{ record }">
|
|
||||||
<a-tag :color="getStatusColor(record.status)">
|
|
||||||
{{ getStatusText(record.status) }}
|
|
||||||
</a-tag>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #level="{ record }">
|
|
||||||
<a-tag :color="getLevelColor(record.level)">
|
|
||||||
{{ getLevelText(record.level) }}
|
|
||||||
</a-tag>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #operations="{ record }">
|
|
||||||
<a-space>
|
|
||||||
<a-button type="text" size="small" @click="handleView(record)">
|
|
||||||
查看详情
|
|
||||||
</a-button>
|
|
||||||
<a-button
|
|
||||||
v-if="record.status === RegulationStatus.DRAFT"
|
|
||||||
type="text"
|
|
||||||
size="small"
|
|
||||||
@click="handleEdit(record)"
|
|
||||||
>
|
|
||||||
编辑
|
|
||||||
</a-button>
|
|
||||||
<a-button
|
|
||||||
v-if="record.status === RegulationStatus.DRAFT"
|
|
||||||
type="primary"
|
|
||||||
size="small"
|
|
||||||
@click="handleConfirm(record)"
|
|
||||||
>
|
|
||||||
确认公示
|
|
||||||
</a-button>
|
|
||||||
<a-button
|
|
||||||
v-if="record.status !== RegulationStatus.DRAFT"
|
|
||||||
type="text"
|
|
||||||
size="small"
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
已公示
|
|
||||||
</a-button>
|
|
||||||
<a-popconfirm
|
|
||||||
v-if="record.status === RegulationStatus.DRAFT"
|
|
||||||
content="确定要删除这个提案吗?"
|
|
||||||
@ok="handleDelete(record)"
|
|
||||||
>
|
|
||||||
<a-button type="text" size="small" status="danger">
|
|
||||||
删除
|
|
||||||
</a-button>
|
|
||||||
</a-popconfirm>
|
|
||||||
</a-space>
|
|
||||||
</template>
|
|
||||||
</a-table>
|
|
||||||
</a-card>
|
|
||||||
|
|
||||||
<!-- 提案表单弹窗 -->
|
|
||||||
<a-modal
|
|
||||||
v-model:visible="modalVisible"
|
|
||||||
:title="modalTitle"
|
|
||||||
width="900px"
|
|
||||||
@ok="handleSubmit"
|
|
||||||
@cancel="handleCancel"
|
|
||||||
class="proposal-form-modal"
|
|
||||||
>
|
|
||||||
<a-form
|
|
||||||
ref="formRef"
|
|
||||||
:model="formData"
|
|
||||||
:rules="rules"
|
|
||||||
layout="vertical"
|
|
||||||
class="proposal-form"
|
|
||||||
>
|
|
||||||
<a-row :gutter="24">
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="提案标题" field="title" class="form-item">
|
|
||||||
<a-input
|
|
||||||
v-model="formData.title"
|
|
||||||
placeholder="请输入提案标题"
|
|
||||||
class="form-input"
|
|
||||||
allow-clear
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="提案类型" field="regulationType" class="form-item">
|
|
||||||
<a-select
|
|
||||||
v-model="formData.regulationType"
|
|
||||||
placeholder="请选择提案类型"
|
|
||||||
class="form-select"
|
|
||||||
allow-clear
|
|
||||||
>
|
|
||||||
<a-option
|
|
||||||
v-for="type in regulationTypes"
|
|
||||||
:key="type.typeId"
|
|
||||||
:value="type.typeName"
|
|
||||||
:disabled="type.isEnabled === '0'"
|
|
||||||
>
|
|
||||||
{{ type.typeName }}
|
|
||||||
</a-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
|
|
||||||
<a-row :gutter="24">
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="适用范围" field="scope" class="form-item">
|
|
||||||
<a-input
|
|
||||||
v-model="formData.scope"
|
|
||||||
placeholder="请输入适用范围"
|
|
||||||
class="form-input"
|
|
||||||
allow-clear
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="制度级别" field="level" class="form-item">
|
|
||||||
<a-select
|
|
||||||
v-model="formData.level"
|
|
||||||
placeholder="请选择制度级别"
|
|
||||||
class="form-select"
|
|
||||||
allow-clear
|
|
||||||
>
|
|
||||||
<a-option :value="RegulationLevel.LOW">低</a-option>
|
|
||||||
<a-option :value="RegulationLevel.MEDIUM">中</a-option>
|
|
||||||
<a-option :value="RegulationLevel.HIGH">高</a-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
|
|
||||||
<a-form-item label="提案内容" field="content" class="form-item">
|
|
||||||
<a-textarea
|
|
||||||
v-model="formData.content"
|
|
||||||
placeholder="请详细描述提案的具体内容,包括制度的目的、适用范围、具体规定等"
|
|
||||||
:rows="8"
|
|
||||||
class="form-textarea"
|
|
||||||
allow-clear
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item label="备注" field="remark" class="form-item">
|
|
||||||
<a-textarea
|
|
||||||
v-model="formData.remark"
|
|
||||||
placeholder="请输入其他补充说明(可选)"
|
|
||||||
:rows="3"
|
|
||||||
class="form-textarea"
|
|
||||||
allow-clear
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
</a-modal>
|
|
||||||
|
|
||||||
<!-- 提案详情弹窗 -->
|
|
||||||
<a-modal
|
|
||||||
v-model:visible="detailModalVisible"
|
|
||||||
title="提案详情"
|
|
||||||
width="800px"
|
|
||||||
:footer="false"
|
|
||||||
>
|
|
||||||
<div class="proposal-detail" v-if="currentProposal">
|
|
||||||
<div class="detail-header">
|
|
||||||
<h3>{{ currentProposal.title }}</h3>
|
|
||||||
<div class="detail-meta">
|
|
||||||
<span>提案人: {{ currentProposal.createByName }}</span>
|
|
||||||
<span>提案类型: {{ currentProposal.regulationType }}</span>
|
|
||||||
<span>适用范围: {{ currentProposal.scope }}</span>
|
|
||||||
<span>级别: <a-tag :color="getLevelColor(currentProposal.level)">{{ getLevelText(currentProposal.level) }}</a-tag></span>
|
|
||||||
<span>创建时间: {{ formatDate(currentProposal.createTime) }}</span>
|
|
||||||
<span>状态: <a-tag :color="getStatusColor(currentProposal.status)">{{ getStatusText(currentProposal.status) }}</a-tag></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a-divider />
|
|
||||||
|
|
||||||
<div class="detail-content">
|
|
||||||
<h4>提案内容</h4>
|
|
||||||
<div class="content-text">{{ currentProposal.content }}</div>
|
|
||||||
|
|
||||||
<h4>备注</h4>
|
|
||||||
<div class="content-text">{{ currentProposal.remark || '暂无备注' }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a-divider />
|
|
||||||
|
|
||||||
<div class="detail-footer">
|
|
||||||
<a-button
|
|
||||||
v-if="currentProposal.status === RegulationStatus.DRAFT && currentProposal.createByName === currentUser"
|
|
||||||
type="primary"
|
|
||||||
@click="handleConfirm(currentProposal)"
|
|
||||||
>
|
|
||||||
确认公示
|
|
||||||
</a-button>
|
|
||||||
<a-button @click="detailModalVisible = false">
|
|
||||||
关闭
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-modal>
|
|
||||||
|
|
||||||
<!-- 确认公示弹窗 -->
|
|
||||||
<a-modal
|
|
||||||
v-model:visible="confirmModalVisible"
|
|
||||||
title="确认公示提案"
|
|
||||||
width="600px"
|
|
||||||
@ok="submitConfirm"
|
|
||||||
@cancel="confirmModalVisible = false"
|
|
||||||
>
|
|
||||||
<div class="confirm-content">
|
|
||||||
<div class="confirm-header">
|
|
||||||
<GiSvgIcon name="exclamation-circle" style="color: #faad14; font-size: 24px; margin-right: 8px;" />
|
|
||||||
<span style="font-weight: 500; font-size: 16px;">公示确认</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="confirm-body">
|
|
||||||
<p>您即将公示提案《<strong>{{ currentProposal?.title }}</strong>》</p>
|
|
||||||
<p>公示后:</p>
|
|
||||||
<ul>
|
|
||||||
<li>该提案将进入制度公示页面</li>
|
|
||||||
<li>其他用户可以在制度公示页面查看此提案</li>
|
|
||||||
<li>提案将进入正式的公示流程</li>
|
|
||||||
<li>您将无法再编辑此提案</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="confirm-footer">
|
|
||||||
<a-checkbox v-model="agreeDisplay">
|
|
||||||
我已仔细阅读并确认公示此提案
|
|
||||||
</a-checkbox>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-modal>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, reactive, onMounted } from 'vue'
|
|
||||||
import { Message } from '@arco-design/web-vue'
|
|
||||||
import { IconSearch, IconRefresh } from '@arco-design/web-vue/es/icon'
|
|
||||||
import { useRegulationStore } from '@/stores/modules/regulation'
|
|
||||||
import { regulationApi } from '@/apis/regulation'
|
|
||||||
import {
|
|
||||||
RegulationStatus,
|
|
||||||
RegulationLevel,
|
|
||||||
type Regulation,
|
|
||||||
type RegulationType,
|
|
||||||
type RegulationProposalSearchRequest
|
|
||||||
} from '@/apis/regulation/type'
|
|
||||||
|
|
||||||
defineOptions({ name: 'RegulationProposal' })
|
|
||||||
|
|
||||||
// 表格列定义
|
|
||||||
const columns = [
|
|
||||||
{ title: '提案标题', dataIndex: 'title', key: 'title', width: 220 },
|
|
||||||
{ title: '提案人', dataIndex: 'createByName', key: 'createByName', width: 130 },
|
|
||||||
{ title: '提案类型', dataIndex: 'regulationType', key: 'regulationType', width: 130 },
|
|
||||||
{ title: '状态', dataIndex: 'status', key: 'status', slotName: 'status', width: 110 },
|
|
||||||
{ title: '级别', dataIndex: 'level', key: 'level', slotName: 'level', width: 90 },
|
|
||||||
{ title: '创建时间', dataIndex: 'createTime', key: 'createTime', width: 200 },
|
|
||||||
{ title: '操作', key: 'operations', slotName: 'operations', width: 320 }
|
|
||||||
]
|
|
||||||
|
|
||||||
// 搜索表单
|
|
||||||
const searchForm = reactive({
|
|
||||||
title: '',
|
|
||||||
proposer: '',
|
|
||||||
status: ''
|
|
||||||
})
|
|
||||||
|
|
||||||
// 表格数据
|
|
||||||
const tableData = ref<Regulation[]>([])
|
|
||||||
const loading = ref(false)
|
|
||||||
const pagination = reactive({
|
|
||||||
current: 1,
|
|
||||||
pageSize: 10,
|
|
||||||
total: 0,
|
|
||||||
showTotal: true,
|
|
||||||
showJumper: true,
|
|
||||||
showPageSize: true
|
|
||||||
})
|
|
||||||
|
|
||||||
// 弹窗相关
|
|
||||||
const modalVisible = ref(false)
|
|
||||||
const modalTitle = ref('新增制度提案')
|
|
||||||
const formRef = ref()
|
|
||||||
const formData = reactive({
|
|
||||||
regulationId: '',
|
|
||||||
title: '',
|
|
||||||
regulationType: '',
|
|
||||||
content: '',
|
|
||||||
scope: '',
|
|
||||||
level: RegulationLevel.MEDIUM,
|
|
||||||
remark: ''
|
|
||||||
})
|
|
||||||
|
|
||||||
const currentProposal = ref<Regulation | null>(null)
|
|
||||||
const detailModalVisible = ref(false)
|
|
||||||
const confirmModalVisible = ref(false)
|
|
||||||
const agreeDisplay = ref(false)
|
|
||||||
|
|
||||||
// 当前用户
|
|
||||||
const currentUser = ref('管理者') // 从用户认证系统获取当前用户ID
|
|
||||||
|
|
||||||
// 制度管理store
|
|
||||||
const regulationStore = useRegulationStore()
|
|
||||||
|
|
||||||
// 制度类型列表
|
|
||||||
const regulationTypes = ref<RegulationType[]>([])
|
|
||||||
|
|
||||||
// 表单验证规则
|
|
||||||
const rules = {
|
|
||||||
title: [{ required: true, message: '请输入提案标题' }],
|
|
||||||
regulationType: [{ required: true, message: '请选择提案类型' }],
|
|
||||||
content: [{ required: true, message: '请输入提案内容' }],
|
|
||||||
scope: [{ required: true, message: '请输入适用范围' }]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取状态颜色
|
|
||||||
const getStatusColor = (status: RegulationStatus) => {
|
|
||||||
const colors = {
|
|
||||||
[RegulationStatus.DRAFT]: 'blue',
|
|
||||||
[RegulationStatus.VOTING]: 'orange',
|
|
||||||
[RegulationStatus.REJECTED]: 'red',
|
|
||||||
[RegulationStatus.PUBLISHED]: 'purple',
|
|
||||||
[RegulationStatus.APPROVED]: 'green',
|
|
||||||
[RegulationStatus.ARCHIVED]: 'gray'
|
|
||||||
}
|
|
||||||
return colors[status] || 'blue'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取状态文本
|
|
||||||
const getStatusText = (status: RegulationStatus) => {
|
|
||||||
const texts = {
|
|
||||||
[RegulationStatus.DRAFT]: '草稿',
|
|
||||||
[RegulationStatus.VOTING]: '投票中',
|
|
||||||
[RegulationStatus.REJECTED]: '已否决',
|
|
||||||
[RegulationStatus.PUBLISHED]: '已公告',
|
|
||||||
[RegulationStatus.APPROVED]: '已公示',
|
|
||||||
[RegulationStatus.ARCHIVED]: '已归档'
|
|
||||||
}
|
|
||||||
return texts[status] || '草稿'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 格式化日期
|
|
||||||
const formatDate = (dateString: string) => {
|
|
||||||
if (!dateString) return '-'
|
|
||||||
const date = new Date(dateString)
|
|
||||||
return date.toLocaleDateString('zh-CN', {
|
|
||||||
year: 'numeric',
|
|
||||||
month: '2-digit',
|
|
||||||
day: '2-digit',
|
|
||||||
hour: '2-digit',
|
|
||||||
minute: '2-digit'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取级别颜色
|
|
||||||
const getLevelColor = (level: RegulationLevel) => {
|
|
||||||
const colors = {
|
|
||||||
[RegulationLevel.LOW]: 'blue',
|
|
||||||
[RegulationLevel.MEDIUM]: 'orange',
|
|
||||||
[RegulationLevel.HIGH]: 'red'
|
|
||||||
}
|
|
||||||
return colors[level] || 'blue'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取级别文本
|
|
||||||
const getLevelText = (level: RegulationLevel) => {
|
|
||||||
const texts = {
|
|
||||||
[RegulationLevel.LOW]: '低',
|
|
||||||
[RegulationLevel.MEDIUM]: '中',
|
|
||||||
[RegulationLevel.HIGH]: '高'
|
|
||||||
}
|
|
||||||
return texts[level] || '中'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取制度类型列表
|
|
||||||
const getRegulationTypes = async () => {
|
|
||||||
try {
|
|
||||||
const response = await regulationApi.searchRegulationTypes()
|
|
||||||
if (response.status === 200) {
|
|
||||||
regulationTypes.value = response.data.records || response.data
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取制度类型列表失败:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取表格数据 - 使用后端搜索接口
|
|
||||||
const getTableData = async () => {
|
|
||||||
loading.value = true
|
|
||||||
try {
|
|
||||||
const response = await regulationApi.getRegulationList({
|
|
||||||
page: pagination.current,
|
|
||||||
size: pagination.pageSize,
|
|
||||||
title: searchForm.title || undefined,
|
|
||||||
proposer: searchForm.proposer || undefined,
|
|
||||||
status: searchForm.status || undefined
|
|
||||||
})
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
tableData.value = response.data.records
|
|
||||||
pagination.total = response.data.total
|
|
||||||
pagination.current = response.data.current
|
|
||||||
} else {
|
|
||||||
Message.error('搜索失败')
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('搜索制度提案失败:', error)
|
|
||||||
Message.error('搜索失败')
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 搜索
|
|
||||||
const search = () => {
|
|
||||||
pagination.current = 1
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重置
|
|
||||||
const reset = () => {
|
|
||||||
Object.assign(searchForm, {
|
|
||||||
title: '',
|
|
||||||
proposer: '',
|
|
||||||
status: ''
|
|
||||||
})
|
|
||||||
pagination.current = 1
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 新增
|
|
||||||
const handleAdd = () => {
|
|
||||||
modalTitle.value = '新增制度提案'
|
|
||||||
modalVisible.value = true
|
|
||||||
resetForm()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 编辑
|
|
||||||
const handleEdit = (record: Regulation) => {
|
|
||||||
|
|
||||||
modalTitle.value = '编辑制度提案'
|
|
||||||
modalVisible.value = true
|
|
||||||
Object.assign(formData, {
|
|
||||||
regulationId: record.regulationId,
|
|
||||||
title: record.title,
|
|
||||||
regulationType: record.regulationType,
|
|
||||||
content: record.content,
|
|
||||||
scope: record.scope,
|
|
||||||
level: record.level,
|
|
||||||
remark: record.remark
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查看
|
|
||||||
const handleView = (record: Regulation) => {
|
|
||||||
currentProposal.value = record
|
|
||||||
detailModalVisible.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确认公示
|
|
||||||
const handleConfirm = (record: Regulation) => {
|
|
||||||
currentProposal.value = record
|
|
||||||
confirmModalVisible.value = true
|
|
||||||
agreeDisplay.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除
|
|
||||||
const handleDelete = async (record: Regulation) => {
|
|
||||||
try {
|
|
||||||
await regulationApi.deleteProposal(record.regulationId)
|
|
||||||
Message.success('删除成功')
|
|
||||||
getTableData()
|
|
||||||
} catch (error) {
|
|
||||||
console.error('删除失败:', error)
|
|
||||||
Message.error('删除失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提交确认公示
|
|
||||||
const submitConfirm = async () => {
|
|
||||||
if (!agreeDisplay.value) {
|
|
||||||
Message.warning('请先确认公示此提案')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (currentProposal.value) {
|
|
||||||
console.log('准备公示提案:', currentProposal.value.regulationId)
|
|
||||||
// 使用公示制度API
|
|
||||||
const response = await regulationApi.publishRegulation(currentProposal.value.regulationId)
|
|
||||||
console.log('公示响应:', response)
|
|
||||||
|
|
||||||
Message.success('提案公示成功,已进入公示流程')
|
|
||||||
confirmModalVisible.value = false
|
|
||||||
getTableData() // 刷新列表
|
|
||||||
|
|
||||||
// 如果是从详情弹窗发起的确认,也关闭详情弹窗
|
|
||||||
if (detailModalVisible.value) {
|
|
||||||
detailModalVisible.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('公示失败:', error)
|
|
||||||
console.error('错误详情:', error.response || error)
|
|
||||||
Message.error('公示失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提交表单
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
try {
|
|
||||||
await formRef.value.validate()
|
|
||||||
|
|
||||||
if (formData.regulationId) {
|
|
||||||
// 更新
|
|
||||||
await regulationApi.updateProposal(formData.regulationId, {
|
|
||||||
title: formData.title,
|
|
||||||
regulationType: formData.regulationType,
|
|
||||||
content: formData.content,
|
|
||||||
scope: formData.scope,
|
|
||||||
level: formData.level,
|
|
||||||
remark: formData.remark
|
|
||||||
})
|
|
||||||
Message.success('更新成功')
|
|
||||||
} else {
|
|
||||||
// 新增
|
|
||||||
const createData = {
|
|
||||||
title: formData.title,
|
|
||||||
regulationType: formData.regulationType,
|
|
||||||
content: formData.content,
|
|
||||||
scope: formData.scope,
|
|
||||||
level: formData.level,
|
|
||||||
remark: formData.remark,
|
|
||||||
createByName: currentUser.value
|
|
||||||
}
|
|
||||||
console.log('新增提案数据:', createData)
|
|
||||||
const response = await regulationApi.createProposal(createData)
|
|
||||||
console.log('新增提案响应:', response)
|
|
||||||
Message.success('提案提交成功')
|
|
||||||
}
|
|
||||||
|
|
||||||
modalVisible.value = false
|
|
||||||
getTableData()
|
|
||||||
} catch (error) {
|
|
||||||
console.error('操作失败:', error)
|
|
||||||
Message.error('操作失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 取消
|
|
||||||
const handleCancel = () => {
|
|
||||||
modalVisible.value = false
|
|
||||||
resetForm()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重置表单
|
|
||||||
const resetForm = () => {
|
|
||||||
Object.assign(formData, {
|
|
||||||
regulationId: '',
|
|
||||||
title: '',
|
|
||||||
regulationType: '',
|
|
||||||
content: '',
|
|
||||||
scope: '',
|
|
||||||
level: RegulationLevel.MEDIUM,
|
|
||||||
remark: ''
|
|
||||||
})
|
|
||||||
formRef.value?.resetFields()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 分页事件
|
|
||||||
const handlePageChange = (page: number) => {
|
|
||||||
pagination.current = page
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
const handlePageSizeChange = (pageSize: number) => {
|
|
||||||
pagination.pageSize = pageSize
|
|
||||||
pagination.current = 1
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
getTableData()
|
|
||||||
getRegulationTypes()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.regulation-proposal {
|
|
||||||
.arco-card {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-container {
|
|
||||||
padding: 16px;
|
|
||||||
background: var(--color-bg-2);
|
|
||||||
border-radius: 6px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
|
|
||||||
.search-form {
|
|
||||||
.arco-form-item {
|
|
||||||
margin-bottom: 0;
|
|
||||||
margin-right: 16px;
|
|
||||||
|
|
||||||
.arco-form-item-label {
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--color-text-1);
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.arco-input,
|
|
||||||
.arco-select {
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arco-btn {
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-result-info {
|
|
||||||
color: var(--color-text-2);
|
|
||||||
font-size: 14px;
|
|
||||||
|
|
||||||
strong {
|
|
||||||
color: var(--color-text-1);
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提案表单美化样式
|
|
||||||
.proposal-form-modal {
|
|
||||||
.arco-modal-body {
|
|
||||||
padding: 24px 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arco-modal-header {
|
|
||||||
padding: 20px 32px 16px;
|
|
||||||
border-bottom: 1px solid var(--color-border);
|
|
||||||
|
|
||||||
.arco-modal-title {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--color-text-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.arco-modal-footer {
|
|
||||||
padding: 16px 32px 24px;
|
|
||||||
border-top: 1px solid var(--color-border);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.proposal-form {
|
|
||||||
.form-item {
|
|
||||||
margin-bottom: 24px;
|
|
||||||
|
|
||||||
.arco-form-item-label {
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--color-text-1);
|
|
||||||
margin-bottom: 8px;
|
|
||||||
font-size: 14px;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
color: #ff4d4f;
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.arco-form-item-error {
|
|
||||||
margin-top: 6px;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-input,
|
|
||||||
.form-select {
|
|
||||||
border-radius: 6px;
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border-color: var(--color-primary-light-3);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus,
|
|
||||||
&.arco-input-focus,
|
|
||||||
&.arco-select-focus {
|
|
||||||
border-color: var(--color-primary);
|
|
||||||
box-shadow: 0 0 0 2px rgba(var(--primary-6), 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.arco-input-inner {
|
|
||||||
padding: 8px 12px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-textarea {
|
|
||||||
border-radius: 6px;
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border-color: var(--color-primary-light-3);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus,
|
|
||||||
&.arco-textarea-focus {
|
|
||||||
border-color: var(--color-primary);
|
|
||||||
box-shadow: 0 0 0 2px rgba(var(--primary-6), 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.arco-textarea-inner {
|
|
||||||
padding: 12px;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 选择框样式优化
|
|
||||||
.arco-select {
|
|
||||||
.arco-select-view {
|
|
||||||
padding: 8px 12px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arco-select-arrow {
|
|
||||||
color: var(--color-text-3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 占位符样式
|
|
||||||
.arco-input-inner::placeholder,
|
|
||||||
.arco-textarea-inner::placeholder {
|
|
||||||
color: var(--color-text-3);
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清空按钮样式
|
|
||||||
.arco-input-clear-btn,
|
|
||||||
.arco-textarea-clear-btn {
|
|
||||||
color: var(--color-text-3);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--color-text-2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.proposal-detail {
|
|
||||||
.detail-header {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin-bottom: 12px;
|
|
||||||
color: var(--color-text-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-meta {
|
|
||||||
display: flex;
|
|
||||||
gap: 16px;
|
|
||||||
color: var(--color-text-3);
|
|
||||||
font-size: 14px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-content {
|
|
||||||
h4 {
|
|
||||||
margin: 16px 0 8px 0;
|
|
||||||
color: var(--color-text-1);
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-text {
|
|
||||||
color: var(--color-text-2);
|
|
||||||
line-height: 1.6;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
padding: 12px;
|
|
||||||
background: var(--color-fill-1);
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-footer {
|
|
||||||
display: flex;
|
|
||||||
gap: 12px;
|
|
||||||
justify-content: center;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.confirm-content {
|
|
||||||
.confirm-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
padding-bottom: 12px;
|
|
||||||
border-bottom: 1px solid var(--color-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.confirm-body {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin-bottom: 12px;
|
|
||||||
color: var(--color-text-1);
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
margin: 12px 0;
|
|
||||||
padding-left: 20px;
|
|
||||||
|
|
||||||
li {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
color: var(--color-text-2);
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.confirm-footer {
|
|
||||||
padding-top: 16px;
|
|
||||||
border-top: 1px solid var(--color-border);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,467 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="system-regulation">
|
|
||||||
<a-card title="已公告制度确认" :bordered="false">
|
|
||||||
<!-- 搜索区域 -->
|
|
||||||
<div class="search-container">
|
|
||||||
<a-form layout="inline" :model="searchForm" class="search-form">
|
|
||||||
<a-form-item label="制度标题">
|
|
||||||
<a-input
|
|
||||||
v-model="searchForm.title"
|
|
||||||
placeholder="请输入制度标题"
|
|
||||||
allow-clear
|
|
||||||
style="width: 200px"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item label="公示人">
|
|
||||||
<a-input
|
|
||||||
v-model="searchForm.proposer"
|
|
||||||
placeholder="请输入公示人"
|
|
||||||
allow-clear
|
|
||||||
style="width: 150px"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item label="确认状态">
|
|
||||||
<a-select
|
|
||||||
v-model="searchForm.confirmStatus"
|
|
||||||
placeholder="请选择状态"
|
|
||||||
allow-clear
|
|
||||||
style="width: 150px"
|
|
||||||
>
|
|
||||||
<a-option value="">全部</a-option>
|
|
||||||
<a-option value="CONFIRMED">已确认</a-option>
|
|
||||||
<a-option value="PENDING">待确认</a-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item>
|
|
||||||
<a-space>
|
|
||||||
<a-button type="primary" @click="search">
|
|
||||||
<template #icon><icon-search /></template>
|
|
||||||
搜索
|
|
||||||
</a-button>
|
|
||||||
<a-button @click="reset">
|
|
||||||
<template #icon><icon-refresh /></template>
|
|
||||||
重置
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a-table
|
|
||||||
:columns="columns"
|
|
||||||
:data="tableData"
|
|
||||||
:loading="loading"
|
|
||||||
:pagination="pagination"
|
|
||||||
@page-change="onPageChange"
|
|
||||||
@page-size-change="onPageSizeChange"
|
|
||||||
>
|
|
||||||
<template #toolbar-left>
|
|
||||||
<span class="search-result-info">
|
|
||||||
共找到 <strong>{{ pagination.total }}</strong> 条记录
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
<template #confirmStatus="{ record }">
|
|
||||||
<a-tag :color="record.confirmStatus === 'CONFIRMED' ? 'green' : 'orange'">
|
|
||||||
{{ record.confirmStatus === 'CONFIRMED' ? '已确认' : '待确认' }}
|
|
||||||
</a-tag>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #operations="{ record }">
|
|
||||||
<a-space>
|
|
||||||
<a-button type="text" size="small" @click="handleView(record)">
|
|
||||||
查看详情
|
|
||||||
</a-button>
|
|
||||||
<a-button type="text" size="small" @click="handleDownload(record)">
|
|
||||||
下载
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</template>
|
|
||||||
</a-table>
|
|
||||||
</a-card>
|
|
||||||
|
|
||||||
<!-- 制度详情弹窗 -->
|
|
||||||
<a-modal
|
|
||||||
v-model:visible="detailModalVisible"
|
|
||||||
title="制度详情"
|
|
||||||
width="800px"
|
|
||||||
:footer="false"
|
|
||||||
>
|
|
||||||
<div class="regulation-detail" v-if="currentRegulation">
|
|
||||||
<div class="detail-header">
|
|
||||||
<h3>{{ currentRegulation.title }}</h3>
|
|
||||||
<div class="detail-meta">
|
|
||||||
<span>公示人: {{ currentRegulation.createByName }}</span>
|
|
||||||
<span>公示时间: {{ currentRegulation.publishTime }}</span>
|
|
||||||
<span>生效日期: {{ currentRegulation.effectiveTime }}</span>
|
|
||||||
<span>确认状态:
|
|
||||||
<a-tag :color="currentRegulation.confirmStatus === 'CONFIRMED' ? 'green' : 'orange'">
|
|
||||||
{{ currentRegulation.confirmStatus === 'CONFIRMED' ? '已确认' : '待确认' }}
|
|
||||||
</a-tag>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a-divider />
|
|
||||||
|
|
||||||
<div class="detail-content">
|
|
||||||
<h4>制度内容</h4>
|
|
||||||
<div class="content-text">{{ currentRegulation.content }}</div>
|
|
||||||
|
|
||||||
<h4>适用范围</h4>
|
|
||||||
<div class="content-text">{{ currentRegulation.scope }}</div>
|
|
||||||
|
|
||||||
<h4>实施要求</h4>
|
|
||||||
<div class="content-text">{{ currentRegulation.requirements }}</div>
|
|
||||||
|
|
||||||
<h4>注意事项</h4>
|
|
||||||
<div class="content-text">{{ currentRegulation.notes }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a-divider />
|
|
||||||
|
|
||||||
<div class="detail-footer">
|
|
||||||
<a-button
|
|
||||||
v-if="currentRegulation.confirmStatus !== 'CONFIRMED'"
|
|
||||||
type="primary"
|
|
||||||
@click="handleConfirm(currentRegulation)"
|
|
||||||
>
|
|
||||||
确认知晓并遵守
|
|
||||||
</a-button>
|
|
||||||
<a-button
|
|
||||||
v-else
|
|
||||||
type="primary"
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
已确认知晓
|
|
||||||
</a-button>
|
|
||||||
<a-button @click="handleDownload(currentRegulation)">
|
|
||||||
下载制度文件
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-modal>
|
|
||||||
|
|
||||||
<!-- 确认承诺弹窗 -->
|
|
||||||
<a-modal
|
|
||||||
v-model:visible="confirmModalVisible"
|
|
||||||
title="制度确认承诺"
|
|
||||||
width="600px"
|
|
||||||
@ok="submitConfirm"
|
|
||||||
@cancel="confirmModalVisible = false"
|
|
||||||
>
|
|
||||||
<div class="confirm-content">
|
|
||||||
<p>我确认已仔细阅读并理解《{{ currentRegulation?.title }}》的全部内容,承诺:</p>
|
|
||||||
<ul>
|
|
||||||
<li>严格遵守该制度的各项规定</li>
|
|
||||||
<li>认真履行相关职责和义务</li>
|
|
||||||
<li>如有违反,愿意承担相应责任</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<a-checkbox v-model="agreeTerms">
|
|
||||||
我已阅读并同意上述承诺
|
|
||||||
</a-checkbox>
|
|
||||||
</div>
|
|
||||||
</a-modal>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, reactive, onMounted } from 'vue'
|
|
||||||
import type { Regulation } from '@/apis/regulation/type'
|
|
||||||
import { Message } from '@arco-design/web-vue'
|
|
||||||
import { IconSearch, IconRefresh } from '@arco-design/web-vue/es/icon'
|
|
||||||
import { useRegulationStore } from '@/stores/modules/regulation'
|
|
||||||
import { regulationApi } from '@/apis/regulation'
|
|
||||||
import { PDFGenerator } from '@/utils/pdfGenerator'
|
|
||||||
|
|
||||||
defineOptions({ name: 'SystemRegulation' })
|
|
||||||
|
|
||||||
// 表格列定义
|
|
||||||
const columns = [
|
|
||||||
{ title: '制度名称', dataIndex: 'title', key: 'title' },
|
|
||||||
{ title: '制度类型', dataIndex: 'regulationType', key: 'regulationType' },
|
|
||||||
{ title: '公示人', dataIndex: 'createByName', key: 'createByName' },
|
|
||||||
{ title: '公示时间', dataIndex: 'publishTime', key: 'publishTime' },
|
|
||||||
{ title: '生效日期', dataIndex: 'effectiveTime', key: 'effectiveTime' },
|
|
||||||
{ title: '确认状态', dataIndex: 'confirmStatus', key: 'confirmStatus', slotName: 'confirmStatus' },
|
|
||||||
{ title: '操作', key: 'operations', slotName: 'operations', width: 250 }
|
|
||||||
]
|
|
||||||
|
|
||||||
// 表格数据
|
|
||||||
const tableData = ref<Regulation[]>([])
|
|
||||||
const loading = ref(false)
|
|
||||||
const pagination = reactive({
|
|
||||||
current: 1,
|
|
||||||
pageSize: 10,
|
|
||||||
total: 0,
|
|
||||||
showTotal: true,
|
|
||||||
showJumper: true,
|
|
||||||
showPageSize: true
|
|
||||||
})
|
|
||||||
|
|
||||||
// 搜索表单
|
|
||||||
const searchForm = reactive({
|
|
||||||
title: '',
|
|
||||||
proposer: '',
|
|
||||||
confirmStatus: ''
|
|
||||||
})
|
|
||||||
|
|
||||||
// 弹窗相关
|
|
||||||
const detailModalVisible = ref(false)
|
|
||||||
const confirmModalVisible = ref(false)
|
|
||||||
const currentRegulation = ref<Regulation | null>(null)
|
|
||||||
const agreeTerms = ref(false)
|
|
||||||
|
|
||||||
// 制度管理store
|
|
||||||
const regulationStore = useRegulationStore()
|
|
||||||
|
|
||||||
// 获取表格数据 - 使用后端搜索接口
|
|
||||||
const getTableData = async () => {
|
|
||||||
loading.value = true
|
|
||||||
try {
|
|
||||||
const response = await regulationApi.getRegulationList({
|
|
||||||
page: pagination.current,
|
|
||||||
size: pagination.pageSize,
|
|
||||||
status: "PUBLISHED",
|
|
||||||
title: searchForm.title || undefined,
|
|
||||||
proposer: searchForm.proposer || undefined,
|
|
||||||
confirmStatus: searchForm.confirmStatus || undefined
|
|
||||||
})
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
|
|
||||||
|
|
||||||
// 确保每个记录都有 confirmStatus 字段
|
|
||||||
const records = response.data.records.map((record: any) => ({
|
|
||||||
...record,
|
|
||||||
confirmStatus: record.confirmStatus || 'PENDING'
|
|
||||||
}))
|
|
||||||
|
|
||||||
tableData.value = records
|
|
||||||
pagination.pageSize = response.data.size
|
|
||||||
pagination.current = response.data.current
|
|
||||||
pagination.total = response.data.total
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Message.error('搜索失败')
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('搜索已公告制度失败:', error)
|
|
||||||
Message.error('搜索失败')
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 搜索
|
|
||||||
const search = () => {
|
|
||||||
pagination.current = 1
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重置
|
|
||||||
const reset = () => {
|
|
||||||
Object.assign(searchForm, {
|
|
||||||
title: '',
|
|
||||||
proposer: '',
|
|
||||||
confirmStatus: ''
|
|
||||||
})
|
|
||||||
pagination.current = 1
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 分页事件
|
|
||||||
const onPageChange = (page: number) => {
|
|
||||||
pagination.current = page
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
const onPageSizeChange = (pageSize: number) => {
|
|
||||||
pagination.pageSize = pageSize
|
|
||||||
pagination.current = 1
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查看详情
|
|
||||||
const handleView = (record: any) => {
|
|
||||||
currentRegulation.value = record
|
|
||||||
detailModalVisible.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确认知晓
|
|
||||||
const handleConfirm = (record: any) => {
|
|
||||||
currentRegulation.value = record
|
|
||||||
confirmModalVisible.value = true
|
|
||||||
agreeTerms.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 下载
|
|
||||||
const handleDownload = async (record: any) => {
|
|
||||||
try {
|
|
||||||
const loadingMessage = Message.loading('正在生成PDF文件...', 0)
|
|
||||||
|
|
||||||
// 生成PDF
|
|
||||||
const pdfBlob = await PDFGenerator.generateRegulationPDF(record)
|
|
||||||
|
|
||||||
// 关闭加载提示
|
|
||||||
loadingMessage.close()
|
|
||||||
|
|
||||||
// 生成文件名
|
|
||||||
const filename = `${record.title}_${new Date().toISOString().split('T')[0]}.pdf`
|
|
||||||
|
|
||||||
// 下载PDF
|
|
||||||
PDFGenerator.downloadPDF(pdfBlob, filename)
|
|
||||||
|
|
||||||
Message.success('PDF文件下载成功')
|
|
||||||
} catch (error) {
|
|
||||||
Message.error('PDF生成失败')
|
|
||||||
console.error('PDF生成错误:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提交确认
|
|
||||||
const submitConfirm = async () => {
|
|
||||||
if (!agreeTerms.value) {
|
|
||||||
Message.warning('请先同意承诺条款')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (currentRegulation.value) {
|
|
||||||
await regulationApi.confirmRegulation(currentRegulation.value.regulationId)
|
|
||||||
|
|
||||||
Message.success('确认成功,您已承诺遵守该制度')
|
|
||||||
confirmModalVisible.value = false
|
|
||||||
|
|
||||||
// 立即刷新数据,确保状态同步
|
|
||||||
await getTableData()
|
|
||||||
|
|
||||||
// 如果详情弹窗是打开的,也更新详情弹窗中的数据
|
|
||||||
if (detailModalVisible.value && currentRegulation.value) {
|
|
||||||
const updatedRecord = tableData.value.find(item => item.regulationId === currentRegulation.value.regulationId)
|
|
||||||
if (updatedRecord) {
|
|
||||||
currentRegulation.value = updatedRecord
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('确认失败:', error)
|
|
||||||
Message.error('确认失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
getTableData()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.system-regulation {
|
|
||||||
.arco-card {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-container {
|
|
||||||
padding: 16px;
|
|
||||||
background: var(--color-bg-2);
|
|
||||||
border-radius: 6px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
|
|
||||||
.search-form {
|
|
||||||
.arco-form-item {
|
|
||||||
margin-bottom: 0;
|
|
||||||
margin-right: 16px;
|
|
||||||
|
|
||||||
.arco-form-item-label {
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--color-text-1);
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.arco-input,
|
|
||||||
.arco-select {
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arco-btn {
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-result-info {
|
|
||||||
color: var(--color-text-2);
|
|
||||||
font-size: 14px;
|
|
||||||
|
|
||||||
strong {
|
|
||||||
color: var(--color-text-1);
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.regulation-detail {
|
|
||||||
.detail-header {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin-bottom: 12px;
|
|
||||||
color: var(--color-text-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-meta {
|
|
||||||
display: flex;
|
|
||||||
gap: 16px;
|
|
||||||
color: var(--color-text-3);
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-content {
|
|
||||||
h4 {
|
|
||||||
margin: 16px 0 8px 0;
|
|
||||||
color: var(--color-text-1);
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-text {
|
|
||||||
color: var(--color-text-2);
|
|
||||||
line-height: 1.6;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
padding: 12px;
|
|
||||||
background: var(--color-fill-1);
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-footer {
|
|
||||||
display: flex;
|
|
||||||
gap: 12px;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.confirm-content {
|
|
||||||
p {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
color: var(--color-text-1);
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
padding-left: 20px;
|
|
||||||
|
|
||||||
li {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
color: var(--color-text-2);
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,404 +0,0 @@
|
||||||
<template>
|
|
||||||
<GiPageLayout>
|
|
||||||
<GiTable
|
|
||||||
row-key="typeId"
|
|
||||||
title="制度类型管理"
|
|
||||||
:data="dataList"
|
|
||||||
:columns="tableColumns"
|
|
||||||
:loading="loading"
|
|
||||||
:scroll="{ x: '100%', y: '100%', minWidth: 1000 }"
|
|
||||||
:pagination="pagination"
|
|
||||||
@page-change="onPageChange"
|
|
||||||
@page-size-change="onPageSizeChange"
|
|
||||||
@refresh="search"
|
|
||||||
>
|
|
||||||
<template #top>
|
|
||||||
<div class="search-container">
|
|
||||||
<a-form layout="inline" :model="searchForm" class="search-form">
|
|
||||||
<a-form-item label="类型名称">
|
|
||||||
<a-input
|
|
||||||
v-model="searchForm.typeName"
|
|
||||||
placeholder="请输入类型名称"
|
|
||||||
allow-clear
|
|
||||||
style="width: 200px"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item label="状态">
|
|
||||||
<a-select
|
|
||||||
v-model="searchForm.status"
|
|
||||||
placeholder="请选择状态"
|
|
||||||
allow-clear
|
|
||||||
style="width: 150px"
|
|
||||||
>
|
|
||||||
<a-option value="">全部</a-option>
|
|
||||||
<a-option value="1">启用</a-option>
|
|
||||||
<a-option value="0">禁用</a-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item label="备注">
|
|
||||||
<a-input
|
|
||||||
v-model="searchForm.remark"
|
|
||||||
placeholder="请输入备注内容"
|
|
||||||
allow-clear
|
|
||||||
style="width: 200px"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item>
|
|
||||||
<a-space>
|
|
||||||
<a-button type="primary" @click="search">
|
|
||||||
<template #icon><icon-search /></template>
|
|
||||||
搜索
|
|
||||||
</a-button>
|
|
||||||
<a-button @click="reset">
|
|
||||||
<template #icon><icon-refresh /></template>
|
|
||||||
重置
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #toolbar-left>
|
|
||||||
<a-space>
|
|
||||||
<a-button type="primary" @click="openAddModal">
|
|
||||||
<template #icon><icon-plus /></template>
|
|
||||||
<template #default>新增类型</template>
|
|
||||||
</a-button>
|
|
||||||
<span class="search-result-info">
|
|
||||||
共找到 <strong>{{ pagination.total }}</strong> 条记录
|
|
||||||
</span>
|
|
||||||
</a-space>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 启用状态 -->
|
|
||||||
<template #isEnabled="{ record }">
|
|
||||||
<a-tag :color="record.isEnabled === '1' ? 'green' : 'red'">
|
|
||||||
{{ record.isEnabled === '1' ? '启用' : '禁用' }}
|
|
||||||
</a-tag>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 操作列 -->
|
|
||||||
<template #action="{ record }">
|
|
||||||
<a-space>
|
|
||||||
<a-link @click="editRecord(record)">编辑</a-link>
|
|
||||||
<a-popconfirm
|
|
||||||
content="确定要删除这个制度类型吗?"
|
|
||||||
@ok="deleteRecord(record)"
|
|
||||||
>
|
|
||||||
<a-link status="danger">删除</a-link>
|
|
||||||
</a-popconfirm>
|
|
||||||
</a-space>
|
|
||||||
</template>
|
|
||||||
</GiTable>
|
|
||||||
|
|
||||||
<!-- 新增/编辑弹窗 -->
|
|
||||||
<a-modal
|
|
||||||
v-model:visible="modalVisible"
|
|
||||||
:title="modalTitle"
|
|
||||||
width="600px"
|
|
||||||
@ok="handleSubmit"
|
|
||||||
@cancel="handleCancel"
|
|
||||||
>
|
|
||||||
<a-form
|
|
||||||
ref="formRef"
|
|
||||||
:model="formData"
|
|
||||||
:rules="rules"
|
|
||||||
layout="vertical"
|
|
||||||
>
|
|
||||||
<a-form-item label="类型名称" field="typeName">
|
|
||||||
<a-input v-model="formData.typeName" placeholder="请输入制度类型名称" />
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item label="排序" field="sortOrder">
|
|
||||||
<a-input-number
|
|
||||||
v-model="formData.sortOrder"
|
|
||||||
placeholder="请输入排序值"
|
|
||||||
:min="0"
|
|
||||||
:max="999"
|
|
||||||
style="width: 100%"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item label="状态" field="isEnabled">
|
|
||||||
<a-radio-group v-model="formData.isEnabled">
|
|
||||||
<a-radio value="1">启用</a-radio>
|
|
||||||
<a-radio value="0">禁用</a-radio>
|
|
||||||
</a-radio-group>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item label="备注" field="remark">
|
|
||||||
<a-textarea
|
|
||||||
v-model="formData.remark"
|
|
||||||
placeholder="请输入备注信息"
|
|
||||||
:rows="3"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
</a-modal>
|
|
||||||
</GiPageLayout>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, reactive, onMounted, watch } from 'vue'
|
|
||||||
import { Message } from '@arco-design/web-vue'
|
|
||||||
import { IconSearch, IconRefresh } from '@arco-design/web-vue/es/icon'
|
|
||||||
import { regulationApi } from '@/apis/regulation'
|
|
||||||
import {
|
|
||||||
type RegulationType,
|
|
||||||
type CreateRegulationTypeRequest,
|
|
||||||
type UpdateRegulationTypeRequest,
|
|
||||||
type RegulationTypeSearchRequest
|
|
||||||
} from '@/apis/regulation/type'
|
|
||||||
|
|
||||||
defineOptions({ name: 'RegulationType' })
|
|
||||||
|
|
||||||
// 表格列定义
|
|
||||||
const tableColumns = [
|
|
||||||
{ title: '类型名称', dataIndex: 'typeName', key: 'typeName', width: 150 },
|
|
||||||
{ title: '备注', dataIndex: 'remark', key: 'remark', width: 200 },
|
|
||||||
{ title: '状态', dataIndex: 'isEnabled', key: 'isEnabled', slotName: 'isEnabled', width: 100 },
|
|
||||||
{ title: '创建人', dataIndex: 'createrName', key: 'createrName', width: 120 },
|
|
||||||
{ title: '创建时间', dataIndex: 'createTime', key: 'createTime', width: 180 },
|
|
||||||
{ title: '排序', dataIndex: 'sortOrder', key: 'sortOrder', width: 100 },
|
|
||||||
{ title: '操作', key: 'action', slotName: 'action', width: 150, fixed: 'right' }
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 表格数据
|
|
||||||
const dataList = ref<RegulationType[]>([])
|
|
||||||
const loading = ref(false)
|
|
||||||
const pagination = reactive({
|
|
||||||
current: 1,
|
|
||||||
pageSize: 10,
|
|
||||||
total: 0,
|
|
||||||
showTotal: true,
|
|
||||||
showJumper: true,
|
|
||||||
showPageSize: true
|
|
||||||
})
|
|
||||||
|
|
||||||
// 查询表单
|
|
||||||
const searchForm = reactive({
|
|
||||||
typeName: '',
|
|
||||||
status: '',
|
|
||||||
remark: ''
|
|
||||||
})
|
|
||||||
|
|
||||||
// 弹窗相关
|
|
||||||
const modalVisible = ref(false)
|
|
||||||
const modalTitle = ref('新增制度类型')
|
|
||||||
const formRef = ref()
|
|
||||||
const formData = reactive({
|
|
||||||
typeId: '',
|
|
||||||
typeName: '',
|
|
||||||
sortOrder: 0,
|
|
||||||
isEnabled: '1',
|
|
||||||
remark: ''
|
|
||||||
})
|
|
||||||
|
|
||||||
// 表单验证规则
|
|
||||||
const rules = {
|
|
||||||
typeName: [{ required: true, message: '请输入制度类型名称' }],
|
|
||||||
sortOrder: [{ required: true, message: '请输入排序值' }],
|
|
||||||
isEnabled: [{ required: true, message: '请选择状态' }]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取表格数据
|
|
||||||
const getTableData = async () => {
|
|
||||||
loading.value = true
|
|
||||||
try {
|
|
||||||
// 使用后端搜索接口
|
|
||||||
const response = await regulationApi.searchRegulationTypes({
|
|
||||||
page: pagination.current,
|
|
||||||
size: pagination.pageSize,
|
|
||||||
typeName: searchForm.typeName || undefined,
|
|
||||||
status: searchForm.status || undefined,
|
|
||||||
remark: searchForm.remark || undefined,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
dataList.value = response.data.records || response.data
|
|
||||||
pagination.total = response.data.total || response.data.length
|
|
||||||
pagination.current = response.data.current || 1
|
|
||||||
} else {
|
|
||||||
Message.error('搜索失败')
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('搜索制度类型失败:', error)
|
|
||||||
Message.error('搜索失败')
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 搜索
|
|
||||||
const search = () => {
|
|
||||||
pagination.current = 1
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 重置
|
|
||||||
const reset = () => {
|
|
||||||
Object.assign(searchForm, {
|
|
||||||
typeName: '',
|
|
||||||
status: '',
|
|
||||||
remark: ''
|
|
||||||
})
|
|
||||||
pagination.current = 1
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 分页事件
|
|
||||||
const onPageChange = (page: number) => {
|
|
||||||
pagination.current = page
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
const onPageSizeChange = (pageSize: number) => {
|
|
||||||
pagination.pageSize = pageSize
|
|
||||||
pagination.current = 1
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 新增
|
|
||||||
const openAddModal = () => {
|
|
||||||
modalTitle.value = '新增制度类型'
|
|
||||||
modalVisible.value = true
|
|
||||||
resetForm()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 编辑
|
|
||||||
const editRecord = (record: RegulationType) => {
|
|
||||||
modalTitle.value = '编辑制度类型'
|
|
||||||
modalVisible.value = true
|
|
||||||
Object.assign(formData, {
|
|
||||||
typeId: record.typeId,
|
|
||||||
typeName: record.typeName,
|
|
||||||
sortOrder: record.sortOrder,
|
|
||||||
isEnabled: record.isEnabled,
|
|
||||||
remark: record.remark || ''
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除
|
|
||||||
const deleteRecord = async (record: RegulationType) => {
|
|
||||||
try {
|
|
||||||
await regulationApi.deleteRegulationType(record.typeId)
|
|
||||||
Message.success('删除成功')
|
|
||||||
getTableData()
|
|
||||||
} catch (error) {
|
|
||||||
console.error('删除失败:', error)
|
|
||||||
Message.error('删除失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提交表单
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
try {
|
|
||||||
await formRef.value.validate()
|
|
||||||
|
|
||||||
if (formData.typeId) {
|
|
||||||
// 更新
|
|
||||||
const updateData: UpdateRegulationTypeRequest = {
|
|
||||||
typeName: formData.typeName,
|
|
||||||
sortOrder: formData.sortOrder,
|
|
||||||
isEnabled: formData.isEnabled,
|
|
||||||
remark: formData.remark
|
|
||||||
}
|
|
||||||
await regulationApi.updateRegulationType(formData.typeId, updateData)
|
|
||||||
Message.success('更新成功')
|
|
||||||
} else {
|
|
||||||
// 新增
|
|
||||||
const createData: CreateRegulationTypeRequest = {
|
|
||||||
typeName: formData.typeName,
|
|
||||||
sortOrder: formData.sortOrder,
|
|
||||||
isEnabled: formData.isEnabled,
|
|
||||||
remark: formData.remark
|
|
||||||
}
|
|
||||||
await regulationApi.createRegulationType(createData)
|
|
||||||
Message.success('新增成功')
|
|
||||||
}
|
|
||||||
|
|
||||||
modalVisible.value = false
|
|
||||||
getTableData()
|
|
||||||
} catch (error) {
|
|
||||||
console.error('操作失败:', error)
|
|
||||||
Message.error('操作失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 取消
|
|
||||||
const handleCancel = () => {
|
|
||||||
modalVisible.value = false
|
|
||||||
resetForm()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重置表单
|
|
||||||
const resetForm = () => {
|
|
||||||
Object.assign(formData, {
|
|
||||||
typeId: '',
|
|
||||||
typeName: '',
|
|
||||||
sortOrder: 0,
|
|
||||||
isEnabled: '1',
|
|
||||||
remark: ''
|
|
||||||
})
|
|
||||||
formRef.value?.resetFields()
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
getTableData()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.regulation-type {
|
|
||||||
.arco-card {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-container {
|
|
||||||
padding: 16px;
|
|
||||||
background: var(--color-bg-2);
|
|
||||||
border-radius: 6px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
|
|
||||||
.search-form {
|
|
||||||
.arco-form-item {
|
|
||||||
margin-bottom: 0;
|
|
||||||
margin-right: 16px;
|
|
||||||
|
|
||||||
.arco-form-item-label {
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--color-text-1);
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.arco-input,
|
|
||||||
.arco-select {
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arco-btn {
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-result-info {
|
|
||||||
color: var(--color-text-2);
|
|
||||||
font-size: 14px;
|
|
||||||
|
|
||||||
strong {
|
|
||||||
color: var(--color-text-1);
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,313 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="device-detail-container">
|
|
||||||
<a-card title="设备基本信息">
|
|
||||||
<a-descriptions :data="basicInfo" layout="vertical" bordered />
|
|
||||||
</a-card>
|
|
||||||
|
|
||||||
<a-card title="设备状态信息" style="margin-top: 16px">
|
|
||||||
<a-descriptions :data="statusInfo" layout="vertical" bordered />
|
|
||||||
</a-card>
|
|
||||||
|
|
||||||
<a-card title="设备详细信息" style="margin-top: 16px">
|
|
||||||
<a-tabs>
|
|
||||||
<a-tab-pane key="maintenance" tab="维护记录">
|
|
||||||
<div class="maintenance-section">
|
|
||||||
<a-button type="primary" @click="handleAddMaintenance">
|
|
||||||
添加维护记录
|
|
||||||
</a-button>
|
|
||||||
<a-divider />
|
|
||||||
<a-table :data="maintenanceRecords" :columns="maintenanceColumns" row-key="id" size="small" />
|
|
||||||
</div>
|
|
||||||
</a-tab-pane>
|
|
||||||
<a-tab-pane key="usage" tab="使用记录">
|
|
||||||
<div class="usage-section">
|
|
||||||
<a-table :data="usageRecords" :columns="usageColumns" row-key="id" size="small" />
|
|
||||||
</div>
|
|
||||||
</a-tab-pane>
|
|
||||||
<a-tab-pane key="location" tab="位置变更">
|
|
||||||
<div class="location-section">
|
|
||||||
<a-table :data="locationRecords" :columns="locationColumns" row-key="id" size="small" />
|
|
||||||
</div>
|
|
||||||
</a-tab-pane>
|
|
||||||
<a-tab-pane key="files" tab="相关文件">
|
|
||||||
<div class="files-section">
|
|
||||||
<a-upload
|
|
||||||
:file-list="fileList"
|
|
||||||
:custom-request="handleFileUpload"
|
|
||||||
:show-upload-list="{ showPreviewIcon: true, showRemoveIcon: true }"
|
|
||||||
>
|
|
||||||
<a-button>
|
|
||||||
<template #icon>
|
|
||||||
<IconUpload />
|
|
||||||
</template>
|
|
||||||
上传文件
|
|
||||||
</a-button>
|
|
||||||
</a-upload>
|
|
||||||
</div>
|
|
||||||
</a-tab-pane>
|
|
||||||
</a-tabs>
|
|
||||||
</a-card>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { onMounted, ref } from 'vue'
|
|
||||||
import { useRoute } from 'vue-router'
|
|
||||||
import { IconUpload } from '@arco-design/web-vue/es/icon'
|
|
||||||
import { getEquipmentDetail } from '@/apis/equipment'
|
|
||||||
import type { EquipmentResp } from '@/types/equipment.d'
|
|
||||||
|
|
||||||
defineOptions({ name: 'DeviceDetail' })
|
|
||||||
|
|
||||||
const route = useRoute()
|
|
||||||
const deviceId = route.params.id as string
|
|
||||||
|
|
||||||
// 设备基本信息
|
|
||||||
const basicInfo = ref([
|
|
||||||
{ label: '设备名称', value: '' },
|
|
||||||
{ label: '设备类型', value: '' },
|
|
||||||
{ label: '设备型号', value: '' },
|
|
||||||
{ label: '序列号', value: '' },
|
|
||||||
{ label: '品牌', value: '' },
|
|
||||||
{ label: '资产编号', value: '' },
|
|
||||||
{ label: '负责人', value: '' },
|
|
||||||
{ label: '物理位置', value: '' },
|
|
||||||
{ label: '配置规格', value: '' },
|
|
||||||
{ label: '备注', value: '' },
|
|
||||||
])
|
|
||||||
|
|
||||||
// 设备状态信息
|
|
||||||
const statusInfo = ref([
|
|
||||||
{ label: '设备状态', value: '' },
|
|
||||||
{ label: '使用状态', value: '' },
|
|
||||||
{ label: '位置状态', value: '' },
|
|
||||||
{ label: '健康状态', value: '' },
|
|
||||||
{ label: '当前使用人', value: '' },
|
|
||||||
{ label: '所属项目', value: '' },
|
|
||||||
{ label: '创建时间', value: '' },
|
|
||||||
{ label: '更新时间', value: '' },
|
|
||||||
])
|
|
||||||
|
|
||||||
// 维护记录
|
|
||||||
const maintenanceRecords = ref([
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
maintenanceType: '定期保养',
|
|
||||||
maintenancePerson: '张师傅',
|
|
||||||
maintenanceTime: '2024-06-01 10:00:00',
|
|
||||||
description: '更换机油,检查设备运行状态',
|
|
||||||
cost: 500,
|
|
||||||
status: '已完成',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
maintenanceType: '故障维修',
|
|
||||||
maintenancePerson: '李师傅',
|
|
||||||
maintenanceTime: '2024-05-15 14:30:00',
|
|
||||||
description: '修复传感器故障',
|
|
||||||
cost: 1200,
|
|
||||||
status: '已完成',
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
const maintenanceColumns = [
|
|
||||||
{ title: '维护类型', dataIndex: 'maintenanceType', key: 'maintenanceType' },
|
|
||||||
{ title: '维护人员', dataIndex: 'maintenancePerson', key: 'maintenancePerson' },
|
|
||||||
{ title: '维护时间', dataIndex: 'maintenanceTime', key: 'maintenanceTime' },
|
|
||||||
{ title: '维护描述', dataIndex: 'description', key: 'description' },
|
|
||||||
{ title: '维护费用', dataIndex: 'cost', key: 'cost' },
|
|
||||||
{ title: '状态', dataIndex: 'status', key: 'status' },
|
|
||||||
]
|
|
||||||
|
|
||||||
// 使用记录
|
|
||||||
const usageRecords = ref([
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
userName: '张三',
|
|
||||||
projectName: '项目A',
|
|
||||||
startTime: '2024-06-01 09:00:00',
|
|
||||||
endTime: '2024-06-01 18:00:00',
|
|
||||||
usagePurpose: '现场检测',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
userName: '李四',
|
|
||||||
projectName: '项目B',
|
|
||||||
startTime: '2024-05-30 08:00:00',
|
|
||||||
endTime: '2024-05-30 17:00:00',
|
|
||||||
usagePurpose: '安全巡检',
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
const usageColumns = [
|
|
||||||
{ title: '使用人', dataIndex: 'userName', key: 'userName' },
|
|
||||||
{ title: '项目名称', dataIndex: 'projectName', key: 'projectName' },
|
|
||||||
{ title: '开始时间', dataIndex: 'startTime', key: 'startTime' },
|
|
||||||
{ title: '结束时间', dataIndex: 'endTime', key: 'endTime' },
|
|
||||||
{ title: '使用目的', dataIndex: 'usagePurpose', key: 'usagePurpose' },
|
|
||||||
]
|
|
||||||
|
|
||||||
// 位置变更记录
|
|
||||||
const locationRecords = ref([
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
oldLocation: '仓库A',
|
|
||||||
newLocation: '现场B',
|
|
||||||
changeTime: '2024-06-01 08:00:00',
|
|
||||||
changeReason: '项目需要',
|
|
||||||
operator: '管理员',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
oldLocation: '现场B',
|
|
||||||
newLocation: '仓库A',
|
|
||||||
changeTime: '2024-05-30 18:00:00',
|
|
||||||
changeReason: '项目结束',
|
|
||||||
operator: '管理员',
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
const locationColumns = [
|
|
||||||
{ title: '原位置', dataIndex: 'oldLocation', key: 'oldLocation' },
|
|
||||||
{ title: '新位置', dataIndex: 'newLocation', key: 'newLocation' },
|
|
||||||
{ title: '变更时间', dataIndex: 'changeTime', key: 'changeTime' },
|
|
||||||
{ title: '变更原因', dataIndex: 'changeReason', key: 'changeReason' },
|
|
||||||
{ title: '操作人', dataIndex: 'operator', key: 'operator' },
|
|
||||||
]
|
|
||||||
|
|
||||||
// 文件列表
|
|
||||||
const fileList = ref([
|
|
||||||
{
|
|
||||||
uid: '1',
|
|
||||||
name: '设备说明书.pdf',
|
|
||||||
status: 'done',
|
|
||||||
url: 'https://example.com/manual.pdf',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
uid: '2',
|
|
||||||
name: '维护记录.xlsx',
|
|
||||||
status: 'done',
|
|
||||||
url: 'https://example.com/maintenance.xlsx',
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
// 获取设备类型文本
|
|
||||||
const getEquipmentTypeText = (type: string) => {
|
|
||||||
const typeMap: Record<string, string> = {
|
|
||||||
1: '检测设备',
|
|
||||||
2: '安全设备',
|
|
||||||
3: '车辆',
|
|
||||||
}
|
|
||||||
return typeMap[type] || type
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取设备状态文本
|
|
||||||
const getEquipmentStatusText = (status: string) => {
|
|
||||||
const statusMap: Record<string, string> = {
|
|
||||||
normal: '正常',
|
|
||||||
maintenance: '维修中',
|
|
||||||
scrapped: '报废',
|
|
||||||
}
|
|
||||||
return statusMap[status] || status
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取使用状态文本
|
|
||||||
const getUseStatusText = (status: string) => {
|
|
||||||
return status === '1' ? '使用中' : '空闲'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取位置状态文本
|
|
||||||
const getLocationStatusText = (status: string) => {
|
|
||||||
const statusMap: Record<string, string> = {
|
|
||||||
in_stock: '库存中',
|
|
||||||
allocated: '已分配',
|
|
||||||
repair: '维修中',
|
|
||||||
scrap: '待报废',
|
|
||||||
scrapped: '已报废',
|
|
||||||
borrowed: '外借中',
|
|
||||||
lost: '丢失',
|
|
||||||
}
|
|
||||||
return statusMap[status] || status
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取健康状态文本
|
|
||||||
const getHealthStatusText = (status: string) => {
|
|
||||||
const statusMap: Record<string, string> = {
|
|
||||||
excellent: '优秀',
|
|
||||||
good: '良好',
|
|
||||||
normal: '一般',
|
|
||||||
poor: '较差',
|
|
||||||
bad: '差',
|
|
||||||
}
|
|
||||||
return statusMap[status] || status
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加载设备详情
|
|
||||||
const loadDeviceDetail = async () => {
|
|
||||||
try {
|
|
||||||
const res = await getEquipmentDetail(deviceId)
|
|
||||||
const device = res.data as EquipmentResp
|
|
||||||
|
|
||||||
// 更新基本信息
|
|
||||||
basicInfo.value = [
|
|
||||||
{ label: '设备名称', value: device.equipmentName },
|
|
||||||
{ label: '设备类型', value: getEquipmentTypeText(device.equipmentType) },
|
|
||||||
{ label: '设备型号', value: device.equipmentModel },
|
|
||||||
{ label: '序列号', value: device.equipmentSn },
|
|
||||||
{ label: '品牌', value: device.brand || '-' },
|
|
||||||
{ label: '资产编号', value: device.assetCode || '-' },
|
|
||||||
{ label: '负责人', value: device.responsiblePerson || '-' },
|
|
||||||
{ label: '物理位置', value: device.physicalLocation || '-' },
|
|
||||||
{ label: '配置规格', value: device.specification || '-' },
|
|
||||||
{ label: '备注', value: device.assetRemark || '-' },
|
|
||||||
]
|
|
||||||
|
|
||||||
// 更新状态信息
|
|
||||||
statusInfo.value = [
|
|
||||||
{ label: '设备状态', value: getEquipmentStatusText(device.equipmentStatus) },
|
|
||||||
{ label: '使用状态', value: getUseStatusText(device.useStatus) },
|
|
||||||
{ label: '位置状态', value: getLocationStatusText(device.locationStatus || '') },
|
|
||||||
{ label: '健康状态', value: getHealthStatusText(device.healthStatus || '') },
|
|
||||||
{ label: '当前使用人', value: device.name || '-' },
|
|
||||||
{ label: '所属项目', value: device.projectName || '-' },
|
|
||||||
{ label: '创建时间', value: device.createTime || '-' },
|
|
||||||
{ label: '更新时间', value: device.updateTime || '-' },
|
|
||||||
]
|
|
||||||
} catch (error) {
|
|
||||||
console.error('加载设备详情失败:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加维护记录
|
|
||||||
const handleAddMaintenance = () => {
|
|
||||||
// TODO: 实现添加维护记录的逻辑
|
|
||||||
console.log('添加维护记录')
|
|
||||||
}
|
|
||||||
|
|
||||||
// 文件上传处理
|
|
||||||
const handleFileUpload = (options: any) => {
|
|
||||||
// TODO: 实现文件上传逻辑
|
|
||||||
console.log('文件上传:', options)
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (deviceId) {
|
|
||||||
loadDeviceDetail()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.device-detail-container {
|
|
||||||
padding: 16px;
|
|
||||||
background: #f5f5f5;
|
|
||||||
min-height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
.maintenance-section,
|
|
||||||
.usage-section,
|
|
||||||
.location-section,
|
|
||||||
.files-section {
|
|
||||||
padding: 16px 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,5 +1,4 @@
|
||||||
<template>
|
<template>
|
||||||
|
|
||||||
<GiPageLayout>
|
<GiPageLayout>
|
||||||
<div>
|
<div>
|
||||||
<a-radio-group v-model="viewType" type="button" size="small" style="margin-bottom: 16px;">
|
<a-radio-group v-model="viewType" type="button" size="small" style="margin-bottom: 16px;">
|
||||||
|
@ -52,7 +51,6 @@
|
||||||
<a-link v-permission="['system:dept:update']" title="修改" @click="onUpdate(record)">修改</a-link>
|
<a-link v-permission="['system:dept:update']" title="修改" @click="onUpdate(record)">修改</a-link>
|
||||||
<a-link
|
<a-link
|
||||||
v-permission="['system:dept:delete']"
|
v-permission="['system:dept:delete']"
|
||||||
:disabled="record.children && record.children.length > 0"
|
|
||||||
status="danger"
|
status="danger"
|
||||||
title="删除"
|
title="删除"
|
||||||
@click="onDelete(record)"
|
@click="onDelete(record)"
|
||||||
|
@ -73,14 +71,14 @@
|
||||||
:collapsable="true"
|
:collapsable="true"
|
||||||
:horizontal="false"
|
:horizontal="false"
|
||||||
:define-menus="menus"
|
:define-menus="menus"
|
||||||
|
:expand-all="true"
|
||||||
:default-expand-level="999"
|
:default-expand-level="999"
|
||||||
:props="{ id: 'deptId', parentId: 'parentId', label: 'deptName', children: 'children' }"
|
:props="{ id: 'deptId', parentId: 'parentId', label: 'deptName', children: 'children' }"
|
||||||
center
|
center
|
||||||
:node-add="handleAdd"
|
:node-add="handleAdd"
|
||||||
:node-delete="onDelete"
|
:node-delete="onDelete"
|
||||||
:node-edit="onUpdate"
|
:node-edit="onUpdate"
|
||||||
:expanded-keys="nodeExpandedKeys"
|
@on-expand-all="bool => nodeExpandAll = bool"
|
||||||
@node-click="(node) => toggleExpand(node.deptId)"
|
|
||||||
>
|
>
|
||||||
</Vue3TreeOrg>
|
</Vue3TreeOrg>
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
|
@ -94,7 +92,6 @@
|
||||||
import 'vue3-tree-org/lib/vue3-tree-org.css'
|
import 'vue3-tree-org/lib/vue3-tree-org.css'
|
||||||
import { Vue3TreeOrg } from 'vue3-tree-org'
|
import { Vue3TreeOrg } from 'vue3-tree-org'
|
||||||
import type { TableInstance } from '@arco-design/web-vue'
|
import type { TableInstance } from '@arco-design/web-vue'
|
||||||
import { Message } from '@arco-design/web-vue'
|
|
||||||
import DeptAddModal from './DeptAddModal.vue'
|
import DeptAddModal from './DeptAddModal.vue'
|
||||||
import { type DeptQuery, type DeptResp, deleteDept, getDeptTree } from '@/apis/system/dept'
|
import { type DeptQuery, type DeptResp, deleteDept, getDeptTree } from '@/apis/system/dept'
|
||||||
import type GiTable from '@/components/GiTable/index.vue'
|
import type GiTable from '@/components/GiTable/index.vue'
|
||||||
|
@ -102,8 +99,6 @@ import { useDownload, useTable } from '@/hooks'
|
||||||
import { isMobile } from '@/utils'
|
import { isMobile } from '@/utils'
|
||||||
import has from '@/utils/has'
|
import has from '@/utils/has'
|
||||||
|
|
||||||
const $message = Message
|
|
||||||
|
|
||||||
defineOptions({ name: 'SystemDept' })
|
defineOptions({ name: 'SystemDept' })
|
||||||
|
|
||||||
const queryForm = reactive<DeptQuery>({})
|
const queryForm = reactive<DeptQuery>({})
|
||||||
|
@ -116,21 +111,10 @@ const {
|
||||||
} = useTable<DeptResp>(() => getDeptTree(queryForm), {
|
} = useTable<DeptResp>(() => getDeptTree(queryForm), {
|
||||||
immediate: true,
|
immediate: true,
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
if (isFirstLoad.value) {
|
// nextTick(() => {
|
||||||
// 初始全部展开:递归收集所有节点 id
|
// tableRef.value?.tableRef?.expandAll(true)
|
||||||
const collectKeys = (nodes: DeptResp[]): string[] => {
|
// })
|
||||||
let keys: string[] = []
|
// 移除自动全部展开,保持默认折叠
|
||||||
nodes.forEach(node => {
|
|
||||||
keys.push(node.deptId)
|
|
||||||
if (node.children && node.children.length) {
|
|
||||||
keys = keys.concat(collectKeys(node.children))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return keys
|
|
||||||
}
|
|
||||||
expandedKeys.value = collectKeys(tableData.value)
|
|
||||||
isFirstLoad.value = false
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
// 查看视图类型
|
// 查看视图类型
|
||||||
|
@ -142,9 +126,9 @@ const menus = [
|
||||||
{ name: '删除部门', command: 'delete' },
|
{ name: '删除部门', command: 'delete' },
|
||||||
]
|
]
|
||||||
// 所有节点展开状态
|
// 所有节点展开状态
|
||||||
|
const nodeExpandAll = ref<boolean>(true)
|
||||||
// 表格视图展开的节点
|
// 表格视图展开的节点
|
||||||
const expandedKeys = ref<string[]>([])
|
const expandedKeys = ref<string[]>([])
|
||||||
const isFirstLoad = ref(true)
|
|
||||||
// 过滤树
|
// 过滤树
|
||||||
const searchData = (name: string) => {
|
const searchData = (name: string) => {
|
||||||
const loop = (data: DeptResp[]) => {
|
const loop = (data: DeptResp[]) => {
|
||||||
|
@ -201,13 +185,6 @@ const reset = () => {
|
||||||
|
|
||||||
// 删除
|
// 删除
|
||||||
const onDelete = (record: DeptResp) => {
|
const onDelete = (record: DeptResp) => {
|
||||||
// 检查是否存在子节点
|
|
||||||
if (record.children && record.children.length > 0) {
|
|
||||||
// 如果有子节点,显示提示信息
|
|
||||||
$message.warning('该部门存在子部门,无法直接删除')
|
|
||||||
return Promise.reject()
|
|
||||||
}
|
|
||||||
|
|
||||||
return handleDelete(() => deleteDept(record.deptId), {
|
return handleDelete(() => deleteDept(record.deptId), {
|
||||||
content: `是否确定删除部门「${record.deptName}」?`,
|
content: `是否确定删除部门「${record.deptName}」?`,
|
||||||
showModal: true,
|
showModal: true,
|
||||||
|
@ -243,20 +220,6 @@ const onExpand = (expanded: boolean, record: DeptResp) => {
|
||||||
expandedKeys.value = expandedKeys.value.filter(k => k !== key)
|
expandedKeys.value = expandedKeys.value.filter(k => k !== key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加一个方法来切换所有节点的展开/收缩状态
|
|
||||||
const toggleExpandAll = () => {
|
|
||||||
nodeExpandAll.value = !nodeExpandAll.value
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改: 添加响应式展开状态和切换方法
|
|
||||||
const nodeExpandedKeys = ref<string[]>([])
|
|
||||||
const toggleExpand = (deptId: string) => {
|
|
||||||
const index = nodeExpandedKeys.value.indexOf(deptId)
|
|
||||||
index > -1
|
|
||||||
? nodeExpandedKeys.value.splice(index, 1)
|
|
||||||
: nodeExpandedKeys.value.push(deptId)
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|
|
@ -27,8 +27,8 @@
|
||||||
<a-radio :value="0">停用</a-radio>
|
<a-radio :value="0">停用</a-radio>
|
||||||
</a-radio-group>
|
</a-radio-group>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item field="remark" label="说明">
|
<a-form-item field="remark" label="备注">
|
||||||
<a-textarea v-model="formData.remark" placeholder="请输入岗位说明" allow-clear />
|
<a-textarea v-model="formData.remark" placeholder="请输入备注" allow-clear />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
|
|
@ -2,226 +2,29 @@
|
||||||
<a-drawer
|
<a-drawer
|
||||||
v-model:visible="visible"
|
v-model:visible="visible"
|
||||||
title="岗位详情"
|
title="岗位详情"
|
||||||
width="720px"
|
width="500px"
|
||||||
|
:footer="false"
|
||||||
unmount-on-close
|
unmount-on-close
|
||||||
class="post-detail-drawer"
|
|
||||||
@close="() => visible = false"
|
|
||||||
>
|
>
|
||||||
<a-spin :loading="loading" class="detail-container">
|
<a-descriptions
|
||||||
<div class="detail-card">
|
:data="detailData"
|
||||||
<!-- 岗位标题和状态 -->
|
:column="1"
|
||||||
<div class="detail-header">
|
:align="{ label: 'right' }"
|
||||||
<div class="post-name">{{ primaryInfo?.name || '-' }}</div>
|
label-style="width: 120px"
|
||||||
<a-tag class="status-tag" :color="getStatusColor(primaryInfo?.status)">
|
size="medium"
|
||||||
{{ getStatusText(primaryInfo?.status) }}
|
:loading="loading"
|
||||||
</a-tag>
|
border
|
||||||
</div>
|
>
|
||||||
|
<template #label="{ label }">{{ label }}</template>
|
||||||
<!-- 标签页菜单 -->
|
<template #value="{ value }">
|
||||||
<a-tabs v-model:active-key="activeTab" class="detail-tabs" type="card">
|
<span v-if="value !== undefined && value !== null">{{ value }}</span>
|
||||||
<!-- 1. 基本信息 -->
|
<span v-else>-</span>
|
||||||
<a-tab-pane key="basic" title="基本信息">
|
</template>
|
||||||
<div class="tab-content">
|
</a-descriptions>
|
||||||
<div class="info-grid">
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">岗位名称</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.name || '-' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">所属部门</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.deptName || '技术部' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">直接上级岗位</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.superior || '技术总监' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">岗位等级/职级</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.level || 'P5' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">编写日期/版本号</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.version || '2024-06-01 / V1.0' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">岗位编号</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.id || '10001' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">工作地点</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.location || '上海/远程' }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 岗位目的 -->
|
|
||||||
<div class="section-title">岗位目的</div>
|
|
||||||
<div class="content-container">
|
|
||||||
<div class="content-text">{{ primaryInfo?.summary || '负责公司核心产品开发,支撑业务增长。' }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-tab-pane>
|
|
||||||
|
|
||||||
<!-- 2. 工作职责 -->
|
|
||||||
<a-tab-pane key="tasks" title="工作职责">
|
|
||||||
<div class="tab-content">
|
|
||||||
<!-- 主要职责与工作任务 -->
|
|
||||||
<div class="section-title">主要职责与工作任务</div>
|
|
||||||
<div class="content-container">
|
|
||||||
<ul>
|
|
||||||
<li v-for="(task, idx) in (primaryInfo?.tasks || ['负责XXX产品的需求分析、架构设计、核心模块编码和单元测试。', '制定并执行季度社交媒体营销计划,提升品牌曝光度和用户互动率。'])" :key="idx">{{ task }}</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 工作权限 -->
|
|
||||||
<div class="section-title">工作权限</div>
|
|
||||||
<div class="content-container">
|
|
||||||
<ul>
|
|
||||||
<li v-for="(perm, idx) in (primaryInfo?.permissions || ['有权审批部门内5000元以下的采购申请。', '有权对项目团队成员的工作任务进行分配和调整。'])" :key="idx">{{ perm }}</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 汇报关系 -->
|
|
||||||
<div class="section-title">汇报关系</div>
|
|
||||||
<div class="info-grid">
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">直接上级</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.superior || '技术总监' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">直接下级</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.subordinates || '无' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">协作关系</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.collaboration || '与产品部、销售部、客服部紧密合作' }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-tab-pane>
|
|
||||||
|
|
||||||
<!-- 3. 任职资格 -->
|
|
||||||
<a-tab-pane key="qualifications" title="任职资格">
|
|
||||||
<div class="tab-content">
|
|
||||||
<div class="info-grid">
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">教育背景</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.education || '本科及以上学历,计算机相关专业' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">工作经验</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.experience || '5年以上相关工作经验' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">专业知识与技能</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.skills || '精通Java/Python,良好的沟通与团队协作能力' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">证书/执照</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.certificates || 'PMP、注册会计师等' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">其他要求</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.otherRequirements || '英语流利,能适应短期出差' }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-tab-pane>
|
|
||||||
|
|
||||||
<!-- 4. 工作条件 -->
|
|
||||||
<a-tab-pane key="conditions" title="工作条件">
|
|
||||||
<div class="tab-content">
|
|
||||||
<div class="info-grid">
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">工作环境</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.workEnv || '办公室/远程' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">工作时间</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.workTime || '标准工时,偶有加班' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">出差要求</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.travel || '偶尔出差' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">体力要求</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.physical || '无特殊要求' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">特殊设备/工具</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.tools || '电脑、办公软件' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">健康与安全</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.health || '注意用眼卫生' }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-tab-pane>
|
|
||||||
|
|
||||||
<!-- 5. 绩效与薪酬 -->
|
|
||||||
<a-tab-pane key="performance" title="绩效与薪酬">
|
|
||||||
<div class="tab-content">
|
|
||||||
<!-- 绩效衡量标准 -->
|
|
||||||
<div class="section-title">绩效衡量标准</div>
|
|
||||||
<div class="content-container">
|
|
||||||
<div class="content-text">{{ primaryInfo?.performance || '根据项目按时交付率、代码质量、产品性能指标提升情况进行评估。' }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 薪酬范围 -->
|
|
||||||
<div class="section-title">薪酬范围</div>
|
|
||||||
<div class="content-container">
|
|
||||||
<div class="content-text salary-value">{{ primaryInfo?.salaryRange || '20-30万/年' }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-tab-pane>
|
|
||||||
|
|
||||||
<!-- 6. 企业文化与发展 -->
|
|
||||||
<a-tab-pane key="culture" title="企业文化与发展">
|
|
||||||
<div class="tab-content">
|
|
||||||
<!-- 公司文化与价值观要求 -->
|
|
||||||
<div class="section-title">公司文化与价值观要求</div>
|
|
||||||
<div class="content-container">
|
|
||||||
<div class="content-text">{{ primaryInfo?.culture || '客户第一、创新、诚信、合作' }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 职业发展路径 -->
|
|
||||||
<div class="section-title">职业发展路径</div>
|
|
||||||
<div class="content-container">
|
|
||||||
<div class="content-text">{{ primaryInfo?.careerPath || '可晋升为高级工程师、技术经理,或横向发展至产品/项目管理岗位。' }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-tab-pane>
|
|
||||||
|
|
||||||
<!-- 7. 时间信息 -->
|
|
||||||
<a-tab-pane key="time" title="时间信息">
|
|
||||||
<div class="tab-content">
|
|
||||||
<div class="info-grid">
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">创建时间</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.createTime || '-' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<div class="info-label">更新时间</div>
|
|
||||||
<div class="info-value">{{ primaryInfo?.updateTime || '-' }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-tab-pane>
|
|
||||||
</a-tabs>
|
|
||||||
</div>
|
|
||||||
</a-spin>
|
|
||||||
|
|
||||||
<template #footer>
|
|
||||||
<div class="footer-actions">
|
|
||||||
<a-button type="primary" @click="handleClose">关闭详情</a-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</a-drawer>
|
</a-drawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { nextTick, ref } from 'vue'
|
|
||||||
import { getPostDetail } from '@/apis/system/post'
|
import { getPostDetail } from '@/apis/system/post'
|
||||||
import { useLoading } from '@/hooks'
|
import { useLoading } from '@/hooks'
|
||||||
|
|
||||||
|
@ -229,300 +32,35 @@ defineOptions({ name: 'PostDetailDrawer' })
|
||||||
|
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
const { loading, setLoading } = useLoading()
|
const { loading, setLoading } = useLoading()
|
||||||
const primaryInfo = ref<any>(null)
|
const detailData = ref<Array<{ label: string; value: any }>>([])
|
||||||
const activeTab = ref('basic')
|
|
||||||
|
|
||||||
// 获取详情
|
// 获取详情
|
||||||
const getDetail = async (id: string) => {
|
const getDetail = async (id: string) => {
|
||||||
try {
|
try {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
primaryInfo.value = null
|
const { data } = await getPostDetail(id)
|
||||||
const response = await getPostDetail(id)
|
if (data) {
|
||||||
const data = response?.data || response
|
detailData.value = [
|
||||||
if (data && typeof data === 'object') {
|
{ label: '岗位名称', value: data.postName },
|
||||||
primaryInfo.value = {
|
{ label: '岗位排序', value: data.postSort },
|
||||||
id: data.postId ?? data.id ?? '10001',
|
{ label: '状态', value: Number(data.status) === 1 ? '正常' : '停用' },
|
||||||
name: data.postName ?? data.name ?? '-',
|
{ label: '备注', value: data.remark },
|
||||||
status: data.status,
|
{ label: '创建时间', value: data.createTime },
|
||||||
department: data.department ?? data.deptName ?? '技术部',
|
{ label: '更新时间', value: data.updateTime },
|
||||||
superior: data.superior ?? '技术总监',
|
]
|
||||||
level: data.level ?? 'P5',
|
|
||||||
version: data.version ?? '2024-06-01 / V1.0',
|
|
||||||
location: data.location ?? '上海/远程',
|
|
||||||
summary: data.summary ?? '负责公司核心产品开发,支撑业务增长。',
|
|
||||||
tasks: data.tasks ?? [
|
|
||||||
'负责XXX产品的需求分析、架构设计、核心模块编码和单元测试。',
|
|
||||||
'制定并执行季度社交媒体营销计划,提升品牌曝光度和用户互动率。',
|
|
||||||
],
|
|
||||||
permissions: data.permissions ?? [
|
|
||||||
'有权审批部门内5000元以下的采购申请。',
|
|
||||||
'有权对项目团队成员的工作任务进行分配和调整。',
|
|
||||||
],
|
|
||||||
subordinates: data.subordinates ?? '无',
|
|
||||||
collaboration: data.collaboration ?? '与产品部、销售部、客服部紧密合作',
|
|
||||||
education: data.education ?? '本科及以上学历,计算机相关专业',
|
|
||||||
experience: data.experience ?? '5年以上相关工作经验',
|
|
||||||
skills: data.skills ?? '精通Java/Python,良好的沟通与团队协作能力',
|
|
||||||
certificates: data.certificates ?? 'PMP、注册会计师等',
|
|
||||||
otherRequirements: data.otherRequirements ?? '英语流利,能适应短期出差',
|
|
||||||
workEnv: data.workEnv ?? '办公室/远程',
|
|
||||||
workTime: data.workTime ?? '标准工时,偶有加班',
|
|
||||||
travel: data.travel ?? '偶尔出差',
|
|
||||||
physical: data.physical ?? '无特殊要求',
|
|
||||||
tools: data.tools ?? '电脑、办公软件',
|
|
||||||
health: data.health ?? '注意用眼卫生',
|
|
||||||
performance: data.performance ?? '根据项目按时交付率、代码质量、产品性能指标提升情况进行评估。',
|
|
||||||
careerPath: data.careerPath ?? '可晋升为高级工程师、技术经理,或横向发展至产品/项目管理岗位。',
|
|
||||||
salaryRange: data.salaryRange ?? '20-30万/年',
|
|
||||||
culture: data.culture ?? '客户第一、创新、诚信、合作',
|
|
||||||
createTime: data.createTime,
|
|
||||||
updateTime: data.updateTime,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
|
||||||
console.error('获取岗位详情失败:', error)
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取状态文本
|
// 查看详情
|
||||||
const getStatusText = (status: number | string) => {
|
|
||||||
if (status === 1 || status === '1') return '正常'
|
|
||||||
if (status === 0 || status === '0') return '停用'
|
|
||||||
return '未知状态'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取状态标签颜色
|
|
||||||
const getStatusColor = (status: number | string) => {
|
|
||||||
if (status === 1 || status === '1') return 'rgb(82, 196, 26)'
|
|
||||||
if (status === 0 || status === '0') return 'rgb(245, 34, 45)'
|
|
||||||
return 'rgb(150, 150, 150)'
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleClose = () => {
|
|
||||||
visible.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
const onDetail = async (id: string) => {
|
const onDetail = async (id: string) => {
|
||||||
if (!id) return
|
|
||||||
visible.value = true
|
visible.value = true
|
||||||
activeTab.value = 'basic' // 重置到第一个标签页
|
|
||||||
await nextTick()
|
|
||||||
await getDetail(id)
|
await getDetail(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
onDetail,
|
onDetail,
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.post-detail-drawer {
|
|
||||||
--primary-color: #3498db;
|
|
||||||
--light-bg: #f9fafc;
|
|
||||||
--border-color: #eaeaea;
|
|
||||||
--label-color: #666;
|
|
||||||
--value-color: #333;
|
|
||||||
--group-title-color: #555;
|
|
||||||
--group-bg: #f5f7fa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-container {
|
|
||||||
padding: 16px 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-card {
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
|
|
||||||
padding: 20px;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
padding-bottom: 15px;
|
|
||||||
border-bottom: 1px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.post-name {
|
|
||||||
font-size: 20px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--value-color);
|
|
||||||
margin-right: 15px;
|
|
||||||
letter-spacing: 0.5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-tag {
|
|
||||||
padding: 4px 12px;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
border: none;
|
|
||||||
color: white !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-tabs {
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-content {
|
|
||||||
padding: 20px 0;
|
|
||||||
max-height: 500px;
|
|
||||||
overflow-y: auto;
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 自定义滚动条样式 */
|
|
||||||
.tab-content::-webkit-scrollbar {
|
|
||||||
width: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-content::-webkit-scrollbar-track {
|
|
||||||
background: #f1f1f1;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-content::-webkit-scrollbar-thumb {
|
|
||||||
background: #c1c1c1;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-content::-webkit-scrollbar-thumb:hover {
|
|
||||||
background: #a8a8a8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
||||||
gap: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-item {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background: white;
|
|
||||||
padding: 12px 15px;
|
|
||||||
border-radius: 6px;
|
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.03);
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
transition: transform 0.2s, box-shadow 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-item:hover {
|
|
||||||
transform: translateY(-2px);
|
|
||||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-label {
|
|
||||||
font-size: 14px;
|
|
||||||
color: var(--label-color);
|
|
||||||
margin-bottom: 6px;
|
|
||||||
font-weight: 500;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-label::after {
|
|
||||||
content: ':';
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-value {
|
|
||||||
font-size: 16px;
|
|
||||||
color: var(--value-color);
|
|
||||||
font-weight: 500;
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
|
|
||||||
.salary-value {
|
|
||||||
color: #e74c3c;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-container {
|
|
||||||
padding: 16px;
|
|
||||||
background: white;
|
|
||||||
border-radius: 6px;
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-text {
|
|
||||||
color: var(--value-color);
|
|
||||||
line-height: 1.7;
|
|
||||||
font-size: 15px;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-title {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--group-title-color);
|
|
||||||
margin-top: 20px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
padding-bottom: 8px;
|
|
||||||
border-bottom: 1px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-title:first-child {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer-actions {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
padding: 16px 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 标签页样式优化 */
|
|
||||||
:deep(.arco-tabs-nav) {
|
|
||||||
background-color: var(--light-bg);
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 4px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-tabs-nav-tab) {
|
|
||||||
background-color: transparent;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-tabs-tab) {
|
|
||||||
border-radius: 6px;
|
|
||||||
margin: 0 2px;
|
|
||||||
padding: 8px 16px;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 14px;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
border: 2px solid transparent;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-tabs-tab:hover) {
|
|
||||||
background-color: rgba(52, 152, 219, 0.1);
|
|
||||||
color: var(--primary-color);
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-tabs-tab-active) {
|
|
||||||
background-color: var(--primary-color);
|
|
||||||
color: white !important;
|
|
||||||
border-color: var(--primary-color);
|
|
||||||
box-shadow: 0 2px 8px rgba(52, 152, 219, 0.3);
|
|
||||||
font-weight: 700 !important;
|
|
||||||
font-size: 15px !important;
|
|
||||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-tabs-content) {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arco-tabs-tabpane) {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,14 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<GiPageLayout>
|
<GiPageLayout>
|
||||||
<GiTable
|
<GiTable
|
||||||
row-key="postId"
|
row-key="postId"
|
||||||
:data="dataList"
|
:data="dataList"
|
||||||
:columns="tableColumns"
|
:columns="tableColumns"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:scroll="{ x: '100%', y: '100%', minWidth: 1200 }"
|
:scroll="{ x: '100%', y: '100%', minWidth: 1200 }"
|
||||||
:pagination="pagination"
|
:pagination="pagination"
|
||||||
:disabled-tools="['size']"
|
:disabled-tools="['size']"
|
||||||
@refresh="search"
|
@refresh="search"
|
||||||
>
|
>
|
||||||
<template #top>
|
<template #top>
|
||||||
<GiForm v-model="queryForm" search :columns="queryFormColumns" size="medium" @search="search" @reset="reset"></GiForm>
|
<GiForm v-model="queryForm" search :columns="queryFormColumns" size="medium" @search="search" @reset="reset"></GiForm>
|
||||||
|
@ -24,59 +24,14 @@
|
||||||
{{ Number(record.status) === 1 ? '正常' : '停用' }}
|
{{ Number(record.status) === 1 ? '正常' : '停用' }}
|
||||||
</a-tag>
|
</a-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #postName="{ record }">
|
|
||||||
<a-dropdown trigger="hover" @visible-change="(visible) => onDropdownVisibleChange(visible, record)">
|
|
||||||
<a-link type="primary" :title="`点击查询 ${record.postName} 岗位下的用户信息`" @click="onPostClick(record)">
|
|
||||||
{{ record.postName }}
|
|
||||||
<template #icon>
|
|
||||||
<icon-user style="margin-right: 4px; font-size: 12px; color: #666;" />
|
|
||||||
<icon-down />
|
|
||||||
</template>
|
|
||||||
</a-link>
|
|
||||||
<template #content>
|
|
||||||
<a-doption
|
|
||||||
:value="record.postId"
|
|
||||||
:disabled="userLoadingMap[record.postId]"
|
|
||||||
>
|
|
||||||
<div v-if="userLoadingMap[record.postId]" class="loading-container">
|
|
||||||
<a-spin size="mini" />
|
|
||||||
<span style="margin-left: 8px;">加载中...</span>
|
|
||||||
</div>
|
|
||||||
<div v-else-if="postUsersMap[record.postId]?.length">
|
|
||||||
<div class="user-list">
|
|
||||||
<div class="user-list-header">
|
|
||||||
<span class="user-count">该岗位下有 {{ postUsersMap[record.postId].length }} 个用户</span>
|
|
||||||
</div>
|
|
||||||
<div class="user-item" v-for="user in postUsersMap[record.postId]" :key="user.userId">
|
|
||||||
<a-avatar :size="24" :src="user.avatar">
|
|
||||||
{{ user.name?.charAt(0) || user.account?.charAt(0) || 'U' }}
|
|
||||||
</a-avatar>
|
|
||||||
<div class="user-info">
|
|
||||||
<div class="user-name clickable" @click="onUserClick(user)" :title="`点击查看 ${user.name || user.account} 的详细信息`">{{ user.name || user.account }}</div>
|
|
||||||
<div class="user-detail">
|
|
||||||
<span v-if="user.mobile">手机: {{ user.mobile }}</span>
|
|
||||||
<span v-if="user.email">邮箱: {{ user.email }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-else class="no-users">
|
|
||||||
该岗位暂无用户
|
|
||||||
</div>
|
|
||||||
</a-doption>
|
|
||||||
</template>
|
|
||||||
</a-dropdown>
|
|
||||||
</template>
|
|
||||||
<template #action="{ record }">
|
<template #action="{ record }">
|
||||||
<a-space>
|
<a-space>
|
||||||
<a-link v-permission="['system:post:query']" title="详情" @click="onDetail(record)">详情</a-link>
|
|
||||||
<a-link v-permission="['system:post:update']" title="修改" @click="onUpdate(record)">修改</a-link>
|
<a-link v-permission="['system:post:update']" title="修改" @click="onUpdate(record)">修改</a-link>
|
||||||
<a-link
|
<a-link
|
||||||
v-permission="['system:post:delete']"
|
v-permission="['system:post:delete']"
|
||||||
status="danger"
|
status="danger"
|
||||||
title="删除"
|
title="删除"
|
||||||
@click="onDelete(record)"
|
@click="onDelete(record)"
|
||||||
>
|
>
|
||||||
删除
|
删除
|
||||||
</a-link>
|
</a-link>
|
||||||
|
@ -86,18 +41,15 @@
|
||||||
|
|
||||||
<PostAddModal ref="PostAddModalRef" @save-success="search" />
|
<PostAddModal ref="PostAddModalRef" @save-success="search" />
|
||||||
<PostDetailDrawer ref="PostDetailDrawerRef" />
|
<PostDetailDrawer ref="PostDetailDrawerRef" />
|
||||||
<UserDetailDrawer ref="UserDetailDrawerRef" />
|
|
||||||
</GiPageLayout>
|
</GiPageLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { TableColumnData } from '@arco-design/web-vue'
|
import type { TableColumnData, TableInstance } from '@arco-design/web-vue'
|
||||||
import PostAddModal from './PostAddModal.vue'
|
import PostAddModal from './PostAddModal.vue'
|
||||||
import PostDetailDrawer from './PostDetailDrawer.vue'
|
import PostDetailDrawer from './PostDetailDrawer.vue'
|
||||||
import UserDetailDrawer from '../user/UserDetailDrawer.vue'
|
import { deletePost, pagePost,listPost } from '@/apis/system/post'
|
||||||
import { deletePost, listPost, getPostUsers } from '@/apis/system/post'
|
import type { PostVO, PostPageQuery } from '@/apis/system/type'
|
||||||
import type { PostVO } from '@/apis/system/type'
|
|
||||||
import type { UserNewResp } from '@/apis/system/type'
|
|
||||||
import { useResetReactive, useTable } from '@/hooks'
|
import { useResetReactive, useTable } from '@/hooks'
|
||||||
import { isMobile } from '@/utils'
|
import { isMobile } from '@/utils'
|
||||||
import has from '@/utils/has'
|
import has from '@/utils/has'
|
||||||
|
@ -128,7 +80,7 @@ const queryFormColumns: ColumnItem[] = reactive([
|
||||||
props: {
|
props: {
|
||||||
options: [
|
options: [
|
||||||
{ label: '正常', value: 1 },
|
{ label: '正常', value: 1 },
|
||||||
{ label: '停用', value: 0 },
|
{ label: '停用', value: 0 }
|
||||||
],
|
],
|
||||||
placeholder: '请选择状态',
|
placeholder: '请选择状态',
|
||||||
},
|
},
|
||||||
|
@ -141,14 +93,10 @@ const {
|
||||||
pagination,
|
pagination,
|
||||||
search,
|
search,
|
||||||
handleDelete,
|
handleDelete,
|
||||||
} = useTable((params) => listPost({
|
} = useTable((params) => listPost({
|
||||||
...queryForm,
|
...queryForm,
|
||||||
}), { immediate: true })
|
}), { immediate: true })
|
||||||
|
|
||||||
// 岗位用户数据
|
|
||||||
const postUsersMap = ref<Record<string, UserNewResp[]>>({})
|
|
||||||
const userLoadingMap = ref<Record<string, boolean>>({})
|
|
||||||
|
|
||||||
const tableColumns = ref<TableColumnData[]>([
|
const tableColumns = ref<TableColumnData[]>([
|
||||||
{
|
{
|
||||||
title: '序号',
|
title: '序号',
|
||||||
|
@ -157,51 +105,50 @@ const tableColumns = ref<TableColumnData[]>([
|
||||||
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize),
|
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize),
|
||||||
fixed: !isMobile() ? 'left' : undefined,
|
fixed: !isMobile() ? 'left' : undefined,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '岗位名称',
|
title: '岗位名称',
|
||||||
dataIndex: 'postName',
|
dataIndex: 'postName',
|
||||||
slotName: 'postName',
|
minWidth: 140,
|
||||||
minWidth: 140,
|
ellipsis: true,
|
||||||
ellipsis: true,
|
|
||||||
tooltip: true,
|
tooltip: true,
|
||||||
fixed: !isMobile() ? 'left' : undefined,
|
fixed: !isMobile() ? 'left' : undefined,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '岗位排序',
|
title: '岗位排序',
|
||||||
dataIndex: 'postSort',
|
dataIndex: 'postSort',
|
||||||
minWidth: 100,
|
minWidth: 100,
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
tooltip: true,
|
tooltip: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '状态',
|
title: '状态',
|
||||||
dataIndex: 'status',
|
dataIndex: 'status',
|
||||||
slotName: 'status',
|
slotName: 'status',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: 100,
|
width: 100
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '说明',
|
title: '备注',
|
||||||
dataIndex: 'remark',
|
dataIndex: 'remark',
|
||||||
minWidth: 180,
|
minWidth: 180,
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
tooltip: true,
|
tooltip: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '创建时间',
|
title: '创建时间',
|
||||||
dataIndex: 'createTime',
|
dataIndex: 'createTime',
|
||||||
minWidth: 180,
|
minWidth: 180,
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
tooltip: true,
|
tooltip: true,
|
||||||
sortable: {
|
sortable: {
|
||||||
sortDirections: ['ascend', 'descend'],
|
sortDirections: ['ascend', 'descend'],
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
dataIndex: 'action',
|
dataIndex: 'action',
|
||||||
slotName: 'action',
|
slotName: 'action',
|
||||||
width: 200,
|
width: 160,
|
||||||
fixed: !isMobile() ? 'right' : undefined,
|
fixed: !isMobile() ? 'right' : undefined,
|
||||||
show: has.hasPermOr(['system:post:update', 'system:post:delete']),
|
show: has.hasPermOr(['system:post:update', 'system:post:delete']),
|
||||||
},
|
},
|
||||||
|
@ -221,66 +168,8 @@ const onDelete = (record: PostVO) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 下拉框显示状态变化时自动加载数据
|
|
||||||
const onDropdownVisibleChange = async (visible: boolean, record: PostVO) => {
|
|
||||||
if (visible && !postUsersMap.value[record.postId] && !userLoadingMap.value[record.postId]) {
|
|
||||||
// 设置加载状态
|
|
||||||
userLoadingMap.value[record.postId] = true
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await getPostUsers(record.postId)
|
|
||||||
|
|
||||||
if (response.success && response.data) {
|
|
||||||
postUsersMap.value[record.postId] = response.data
|
|
||||||
} else {
|
|
||||||
postUsersMap.value[record.postId] = []
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取岗位用户信息失败:', error)
|
|
||||||
postUsersMap.value[record.postId] = []
|
|
||||||
} finally {
|
|
||||||
userLoadingMap.value[record.postId] = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 点击岗位名称触发用户查询
|
|
||||||
const onPostClick = async (record: PostVO) => {
|
|
||||||
// 如果已经加载过该岗位的用户数据,直接返回
|
|
||||||
if (postUsersMap.value[record.postId]) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置加载状态
|
|
||||||
userLoadingMap.value[record.postId] = true
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await getPostUsers(record.postId)
|
|
||||||
|
|
||||||
if (response.success && response.data) {
|
|
||||||
postUsersMap.value[record.postId] = response.data
|
|
||||||
} else {
|
|
||||||
postUsersMap.value[record.postId] = []
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取岗位用户信息失败:', error)
|
|
||||||
postUsersMap.value[record.postId] = []
|
|
||||||
} finally {
|
|
||||||
userLoadingMap.value[record.postId] = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 点击用户详情
|
|
||||||
const onUserClick = (user: UserNewResp) => {
|
|
||||||
UserDetailDrawerRef.value?.onOpen(user.userId)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const PostAddModalRef = ref<InstanceType<typeof PostAddModal>>()
|
const PostAddModalRef = ref<InstanceType<typeof PostAddModal>>()
|
||||||
const PostDetailDrawerRef = ref<InstanceType<typeof PostDetailDrawer>>()
|
const PostDetailDrawerRef = ref<InstanceType<typeof PostDetailDrawer>>()
|
||||||
const UserDetailDrawerRef = ref<InstanceType<typeof UserDetailDrawer>>()
|
|
||||||
|
|
||||||
// 新增
|
// 新增
|
||||||
const onAdd = () => {
|
const onAdd = () => {
|
||||||
|
@ -298,80 +187,4 @@ const onDetail = (record: PostVO) => {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss"></style>
|
||||||
.loading-container {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-list {
|
|
||||||
min-width: 300px;
|
|
||||||
max-width: 400px;
|
|
||||||
|
|
||||||
.user-list-header {
|
|
||||||
padding: 8px 12px;
|
|
||||||
border-bottom: 1px solid #f0f0f0;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
|
|
||||||
.user-count {
|
|
||||||
font-size: 12px;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 8px 12px;
|
|
||||||
border-bottom: 1px solid #f5f5f5;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-info {
|
|
||||||
margin-left: 8px;
|
|
||||||
flex: 1;
|
|
||||||
|
|
||||||
.user-name {
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #333;
|
|
||||||
margin-bottom: 2px;
|
|
||||||
|
|
||||||
&.clickable {
|
|
||||||
cursor: pointer;
|
|
||||||
color: #165dff;
|
|
||||||
transition: color 0.2s ease;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: #0e42d2;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-detail {
|
|
||||||
font-size: 12px;
|
|
||||||
color: #666;
|
|
||||||
|
|
||||||
span {
|
|
||||||
margin-right: 8px;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-users {
|
|
||||||
padding: 16px;
|
|
||||||
text-align: center;
|
|
||||||
color: #999;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,13 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<a-modal
|
<a-modal
|
||||||
v-model:visible="visible"
|
v-model:visible="visible"
|
||||||
title="分配角色"
|
title="分配角色"
|
||||||
:mask-closable="false"
|
:mask-closable="false"
|
||||||
:esc-to-close="false"
|
:esc-to-close="false"
|
||||||
:width="width >= 1100 ? 1100 : '100%'"
|
:width="width >= 1100 ? 1100 : '100%'"
|
||||||
draggable
|
draggable
|
||||||
@before-ok="save"
|
@before-ok="save"
|
||||||
@close="reset"
|
@close="reset"
|
||||||
>
|
>
|
||||||
<UserSelect v-if="visible" ref="UserSelectRef" v-model:value="selectedUsers" :role-id="dataId" @select-user="onSelectUser" />
|
<UserSelect v-if="visible" ref="UserSelectRef" v-model:value="selectedUsers" :role-id="dataId" @select-user="onSelectUser" />
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
@ -17,7 +17,6 @@
|
||||||
import { Message } from '@arco-design/web-vue'
|
import { Message } from '@arco-design/web-vue'
|
||||||
import { useWindowSize } from '@vueuse/core'
|
import { useWindowSize } from '@vueuse/core'
|
||||||
import { assignToUsers } from '@/apis/system/role'
|
import { assignToUsers } from '@/apis/system/role'
|
||||||
// 根据角色分配用户
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'save-success'): void
|
(e: 'save-success'): void
|
||||||
|
|
|
@ -98,11 +98,21 @@ const columns: TableInstance['columns'] = [
|
||||||
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize),
|
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize),
|
||||||
fixed: !isMobile() ? 'left' : undefined,
|
fixed: !isMobile() ? 'left' : undefined,
|
||||||
},
|
},
|
||||||
{ title: '用户名', dataIndex: 'name', slotName: 'name', minWidth: 120, ellipsis: true, tooltip: true },
|
{
|
||||||
{ title: '性别', dataIndex: 'gender', slotName: 'gender', align: 'center' },
|
title: '昵称',
|
||||||
|
dataIndex: 'nickname',
|
||||||
|
slotName: 'nickname',
|
||||||
|
minWidth: 130,
|
||||||
|
ellipsis: true,
|
||||||
|
tooltip: true,
|
||||||
|
fixed: !isMobile() ? 'left' : undefined,
|
||||||
|
},
|
||||||
|
{ title: '用户名', dataIndex: 'username', slotName: 'username', minWidth: 120, ellipsis: true, tooltip: true },
|
||||||
{ title: '状态', dataIndex: 'status', slotName: 'status', align: 'center' },
|
{ title: '状态', dataIndex: 'status', slotName: 'status', align: 'center' },
|
||||||
|
{ title: '性别', dataIndex: 'gender', slotName: 'gender', align: 'center' },
|
||||||
{ title: '所属部门', dataIndex: 'deptName', minWidth: 140, ellipsis: true, tooltip: true },
|
{ title: '所属部门', dataIndex: 'deptName', minWidth: 140, ellipsis: true, tooltip: true },
|
||||||
{ title: '角色', dataIndex: 'roleNames', slotName: 'roleNames', minWidth: 165 },
|
{ title: '角色', dataIndex: 'roleNames', slotName: 'roleNames', minWidth: 165 },
|
||||||
|
{ title: '描述', dataIndex: 'description', minWidth: 130, ellipsis: true, tooltip: true },
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
dataIndex: 'action',
|
dataIndex: 'action',
|
||||||
|
@ -132,7 +142,7 @@ const onMulDelete = () => {
|
||||||
content: `是否确定取消分配角色给所选的${selectedKeys.value.length}个用户?`,
|
content: `是否确定取消分配角色给所选的${selectedKeys.value.length}个用户?`,
|
||||||
hideCancel: false,
|
hideCancel: false,
|
||||||
onOk: async () => {
|
onOk: async () => {
|
||||||
await unassignFromUsers(selectedKeys.value.map(id => String(id)))
|
await unassignFromUsers(selectedKeys.value)
|
||||||
Message.success('取消成功')
|
Message.success('取消成功')
|
||||||
search()
|
search()
|
||||||
},
|
},
|
||||||
|
@ -141,7 +151,7 @@ const onMulDelete = () => {
|
||||||
|
|
||||||
// 删除
|
// 删除
|
||||||
const onDelete = (record: RoleUserResp) => {
|
const onDelete = (record: RoleUserResp) => {
|
||||||
return handleDelete(() => unassignFromUsers([String(record.id)]), {
|
return handleDelete(() => unassignFromUsers([record.id]), {
|
||||||
content: `是否确定取消分配角色给用户「${record.nickname}(${record.username})」?`,
|
content: `是否确定取消分配角色给用户「${record.nickname}(${record.username})」?`,
|
||||||
successTip: '取消成功',
|
successTip: '取消成功',
|
||||||
showModal: true,
|
showModal: true,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
|
<h1>这个暂时写不了,角色管理采用菜单权限的设置</h1>
|
||||||
<GiPageLayout :header-style="{ padding: 0, borderBottom: 'none' }">
|
<GiPageLayout :header-style="{ padding: 0, borderBottom: 'none' }">
|
||||||
<template #left>
|
<template #left>
|
||||||
<RoleTree @node-click="handleSelectRole" />
|
<RoleTree @node-click="handleSelectRole" />
|
||||||
|
@ -18,7 +19,6 @@
|
||||||
import RoleTree from './tree/index.vue'
|
import RoleTree from './tree/index.vue'
|
||||||
import Permission from './components/Permission.vue'
|
import Permission from './components/Permission.vue'
|
||||||
import RoleUser from './components/RoleUser.vue'
|
import RoleUser from './components/RoleUser.vue'
|
||||||
import {listRoleUserId} from "@/apis";
|
|
||||||
|
|
||||||
defineOptions({ name: 'SystemRole' })
|
defineOptions({ name: 'SystemRole' })
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ const save = async () => {
|
||||||
try {
|
try {
|
||||||
const isInvalid = await formRef.value?.formRef?.validate()
|
const isInvalid = await formRef.value?.formRef?.validate()
|
||||||
if (isInvalid) return false
|
if (isInvalid) return false
|
||||||
await updateUserRole({ roleIds: form.roleIds.map(id => String(id)) }, dataId.value)
|
await updateUserRole({ roleIds: form.roleIds }, dataId.value)
|
||||||
Message.success('分配成功')
|
Message.success('分配成功')
|
||||||
emit('save-success')
|
emit('save-success')
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -93,7 +93,7 @@ const handleSubmit = async () => {
|
||||||
|
|
||||||
await bindUserRole({
|
await bindUserRole({
|
||||||
userId: props.userData.userId,
|
userId: props.userData.userId,
|
||||||
roleIds: selectedRoles.value.map(id => String(id))
|
roleIds: selectedRoles.value
|
||||||
})
|
})
|
||||||
|
|
||||||
Message.success('角色分配成功')
|
Message.success('角色分配成功')
|
||||||
|
|
|
@ -313,17 +313,17 @@ const columns: TableInstance['columns'] = [
|
||||||
},
|
},
|
||||||
{ title: '账号', dataIndex: 'account', minWidth: 140, ellipsis: true, tooltip: true },
|
{ title: '账号', dataIndex: 'account', minWidth: 140, ellipsis: true, tooltip: true },
|
||||||
{ title: '员工编码', dataIndex: 'userCode', minWidth: 120, ellipsis: true, tooltip: true },
|
{ title: '员工编码', dataIndex: 'userCode', minWidth: 120, ellipsis: true, tooltip: true },
|
||||||
{ title: '性别', dataIndex: 'gender', slotName: 'gender', align: 'center', width: 80 },
|
|
||||||
{ title: '手机号', dataIndex: 'mobile', minWidth: 170, ellipsis: true, tooltip: true },
|
|
||||||
{ title: '所属部门', dataIndex: 'deptName', minWidth: 180, ellipsis: true, tooltip: true },
|
|
||||||
{ title: '学历', dataIndex: 'educationLabel', width: 100, ellipsis: true, tooltip: true, show: false },
|
|
||||||
{ title: '专业', dataIndex: 'majorField', width: 120, ellipsis: true, tooltip: true, show: false },
|
|
||||||
{ title: '在职状态', dataIndex: 'userStatus', slotName: 'userStatus', align: 'center', width: 100 },
|
{ title: '在职状态', dataIndex: 'userStatus', slotName: 'userStatus', align: 'center', width: 100 },
|
||||||
{ title: '员工性质', dataIndex: 'userType', slotName: 'userType', align: 'center', width: 100 },
|
{ title: '员工性质', dataIndex: 'userType', slotName: 'userType', align: 'center', width: 100 },
|
||||||
{ title: '角色', dataIndex: 'roleName', slotName: 'roleName', minWidth: 185 },
|
{ title: '性别', dataIndex: 'gender', slotName: 'gender', align: 'center', width: 80 },
|
||||||
{ title: '邮箱', dataIndex: 'email', slotName: 'email', minWidth: 170, ellipsis: true, tooltip: true },
|
{ title: '所属部门', dataIndex: 'deptName', minWidth: 180, ellipsis: true, tooltip: true },
|
||||||
|
{ title: '角色', dataIndex: 'roleIds', slotName: 'roleIds', minWidth: 165 },
|
||||||
|
{ title: '手机号', dataIndex: 'mobile', minWidth: 170, ellipsis: true, tooltip: true },
|
||||||
|
{ title: '邮箱', dataIndex: 'email', minWidth: 170, ellipsis: true, tooltip: true },
|
||||||
{ title: '入职日期', dataIndex: 'hiredate', width: 120, ellipsis: true, tooltip: true },
|
{ title: '入职日期', dataIndex: 'hiredate', width: 120, ellipsis: true, tooltip: true },
|
||||||
{ title: '出生日期', dataIndex: 'birthdate', width: 120, ellipsis: true, tooltip: true, show: false },
|
{ title: '出生日期', dataIndex: 'birthdate', width: 120, ellipsis: true, tooltip: true, show: false },
|
||||||
|
{ title: '学历', dataIndex: 'educationLabel', width: 100, ellipsis: true, tooltip: true, show: false },
|
||||||
|
{ title: '专业', dataIndex: 'majorField', width: 120, ellipsis: true, tooltip: true, show: false },
|
||||||
{ title: '工作方向', dataIndex: 'workField', width: 120, ellipsis: true, tooltip: true, show: false },
|
{ title: '工作方向', dataIndex: 'workField', width: 120, ellipsis: true, tooltip: true, show: false },
|
||||||
{ title: '身份证', dataIndex: 'identityCard', width: 180, ellipsis: true, tooltip: true, show: false },
|
{ title: '身份证', dataIndex: 'identityCard', width: 180, ellipsis: true, tooltip: true, show: false },
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,25 +17,25 @@
|
||||||
</template>
|
</template>
|
||||||
</a-upload>
|
</a-upload>
|
||||||
<div class="name">
|
<div class="name">
|
||||||
<span style="margin-right: 10px">{{ userInfo.name }}</span>
|
<span style="margin-right: 10px">{{ userInfo.nickname }}</span>
|
||||||
<icon-edit :size="16" class="btn" @click="onUpdate" />
|
<icon-edit :size="16" class="btn" @click="onUpdate" />
|
||||||
</div>
|
</div>
|
||||||
<div class="id">
|
<div class="id">
|
||||||
<GiSvgIcon name="id" :size="16" />
|
<GiSvgIcon name="id" :size="16" />
|
||||||
<span>{{ userInfo.userId }}</span>
|
<span>{{ userInfo.id }}</span>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<footer>
|
<footer>
|
||||||
<a-descriptions :column="4" size="large">
|
<a-descriptions :column="4" size="large">
|
||||||
<a-descriptions-item :span="4">
|
<a-descriptions-item :span="4">
|
||||||
<template #label> <icon-user /><span style="margin-left: 5px">用户名</span></template>
|
<template #label> <icon-user /><span style="margin-left: 5px">用户名</span></template>
|
||||||
{{ userInfo.account }}
|
{{ userInfo.username }}
|
||||||
<icon-man v-if="userInfo.gender === 1" style="color: #19bbf1" />
|
<icon-man v-if="userInfo.gender === 1" style="color: #19bbf1" />
|
||||||
<icon-woman v-else-if="userInfo.gender === 2" style="color: #fa7fa9" />
|
<icon-woman v-else-if="userInfo.gender === 2" style="color: #fa7fa9" />
|
||||||
</a-descriptions-item>
|
</a-descriptions-item>
|
||||||
<a-descriptions-item :span="4">
|
<a-descriptions-item :span="4">
|
||||||
<template #label> <icon-phone /><span style="margin-left: 5px">手机</span></template>
|
<template #label> <icon-phone /><span style="margin-left: 5px">手机</span></template>
|
||||||
{{ userInfo.mobile || '暂无' }}
|
{{ userInfo.phone || '暂无' }}
|
||||||
</a-descriptions-item>
|
</a-descriptions-item>
|
||||||
<a-descriptions-item :span="4">
|
<a-descriptions-item :span="4">
|
||||||
<template #label> <icon-email /><span style="margin-left: 5px">邮箱</span></template>
|
<template #label> <icon-email /><span style="margin-left: 5px">邮箱</span></template>
|
||||||
|
@ -47,12 +47,12 @@
|
||||||
</a-descriptions-item>
|
</a-descriptions-item>
|
||||||
<a-descriptions-item :span="4">
|
<a-descriptions-item :span="4">
|
||||||
<template #label> <icon-user-group /><span style="margin-left: 5px">角色</span></template>
|
<template #label> <icon-user-group /><span style="margin-left: 5px">角色</span></template>
|
||||||
{{ userInfo.roles?.map(role => role.roleName).join(', ') || '暂无' }}
|
{{ userInfo.roles.join(',') }}
|
||||||
</a-descriptions-item>
|
</a-descriptions-item>
|
||||||
</a-descriptions>
|
</a-descriptions>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">注册于 {{ userInfo.createTime }}</div>
|
<div class="footer">注册于 {{ userInfo.registrationDate }}</div>
|
||||||
</a-card>
|
</a-card>
|
||||||
|
|
||||||
<a-modal v-model:visible="visible" title="上传头像" :width="width >= 400 ? 400 : '100%'" :footer="false" draggable @close="reset">
|
<a-modal v-model:visible="visible" title="上传头像" :width="width >= 400 ? 400 : '100%'" :footer="false" draggable @close="reset">
|
||||||
|
@ -102,22 +102,19 @@ import { uploadAvatar } from '@/apis/system'
|
||||||
import 'vue-cropper/dist/index.css'
|
import 'vue-cropper/dist/index.css'
|
||||||
import { useUserStore } from '@/stores'
|
import { useUserStore } from '@/stores'
|
||||||
import getAvatar from '@/utils/avatar'
|
import getAvatar from '@/utils/avatar'
|
||||||
import XG_DEBUG from 'xgplayer/es/utils/debug'
|
|
||||||
import config = XG_DEBUG.config
|
|
||||||
|
|
||||||
const { width } = useWindowSize()
|
const { width } = useWindowSize()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const userInfo = computed(() => userStore.userInfo)
|
const userInfo = computed(() => userStore.userInfo)
|
||||||
|
|
||||||
const avatar = computed(() => ({
|
const avatar = {
|
||||||
uid: '-2',
|
uid: '-2',
|
||||||
name: 'avatar.png',
|
name: 'avatar.png',
|
||||||
url: userInfo.value.avatar || getAvatar(userInfo.value.avatar, undefined),
|
url: userInfo.value.avatar,
|
||||||
}))
|
}
|
||||||
|
const avatarList = ref<FileItem[]>([avatar])
|
||||||
const avatarList = computed<FileItem[]>(() => [avatar.value])
|
const fileRef = ref(reactive({ name: 'avatar.png' }))
|
||||||
const fileRef = ref<File | null>(null)
|
const options: cropperOptions = reactive({
|
||||||
const options = reactive<cropperOptions>({
|
|
||||||
img: '',
|
img: '',
|
||||||
autoCrop: true,
|
autoCrop: true,
|
||||||
autoCropWidth: 160,
|
autoCropWidth: 160,
|
||||||
|
@ -131,14 +128,13 @@ const options = reactive<cropperOptions>({
|
||||||
outputType: 'png',
|
outputType: 'png',
|
||||||
})
|
})
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
|
|
||||||
// 打开裁剪框
|
// 打开裁剪框
|
||||||
const onBeforeUpload = (file: File): boolean => {
|
const onBeforeUpload = (file: File): boolean => {
|
||||||
fileRef.value = file
|
fileRef.value = file
|
||||||
const reader = new FileReader()
|
const reader = new FileReader()
|
||||||
reader.readAsDataURL(file)
|
reader.readAsDataURL(file)
|
||||||
reader.onload = () => {
|
reader.onload = () => {
|
||||||
options.img = reader.result as string
|
options.img = reader.result
|
||||||
}
|
}
|
||||||
visible.value = true
|
visible.value = true
|
||||||
return false
|
return false
|
||||||
|
|
Loading…
Reference in New Issue