feat:口门对接待办
parent
ead8b19773
commit
de642e6322
208
AGENTS.md
208
AGENTS.md
|
|
@ -1,208 +0,0 @@
|
||||||
# AGENTS.md
|
|
||||||
|
|
||||||
This file provides guidance to agentic coding agents operating in this repository.
|
|
||||||
|
|
||||||
## Project Overview
|
|
||||||
|
|
||||||
**zcloud-gbs-primeport** - A Spring Boot application for port access control management built with COLA framework and DDD architecture.
|
|
||||||
|
|
||||||
## Build Commands
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Build the project
|
|
||||||
mvn clean install
|
|
||||||
|
|
||||||
# Build without running tests
|
|
||||||
mvn clean install -DskipTests
|
|
||||||
|
|
||||||
# Run the application
|
|
||||||
mvn spring-boot:run -pl start
|
|
||||||
|
|
||||||
# Package for deployment
|
|
||||||
mvn clean package
|
|
||||||
|
|
||||||
# Compile only
|
|
||||||
mvn compile
|
|
||||||
```
|
|
||||||
|
|
||||||
## Test Commands
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Run all tests
|
|
||||||
mvn test
|
|
||||||
|
|
||||||
# Run a single test class
|
|
||||||
mvn test -Dtest=ClassNameTest
|
|
||||||
|
|
||||||
# Run a single test method
|
|
||||||
mvn test -Dtest=ClassNameTest#methodName
|
|
||||||
|
|
||||||
# Run tests in a specific module
|
|
||||||
mvn test -pl web-app
|
|
||||||
```
|
|
||||||
|
|
||||||
## Code Style Guidelines
|
|
||||||
|
|
||||||
### Architecture (COLA + DDD)
|
|
||||||
|
|
||||||
This is a multi-module Maven project with strict layer separation:
|
|
||||||
|
|
||||||
```
|
|
||||||
start/ # Application entry point
|
|
||||||
web-adapter/ # Controllers (HTTP request handling)
|
|
||||||
web-client/ # DTOs + API interface definitions
|
|
||||||
web-app/ # Executors + Service implementations (business orchestration)
|
|
||||||
web-domain/ # Entities + Gateway interfaces (core business logic)
|
|
||||||
web-infrastructure/ # DOs + Mappers + Repository implementations (data persistence)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Naming Conventions
|
|
||||||
|
|
||||||
| Layer | Suffix | Example |
|
|
||||||
|-------|--------|---------|
|
|
||||||
| Entity | `E` | `MkmjE` |
|
|
||||||
| Data Object | `DO` | `MkmjDO` |
|
|
||||||
| Client Object | `CO` | `MkmjCO` |
|
|
||||||
| Command DTO | `Cmd` | `MkmjAddCmd`, `MkmjUpdateCmd` |
|
|
||||||
| Query DTO | `Qry` | `MkmjPageQry` |
|
|
||||||
| Service Interface | `ServiceI` | `MkmjServiceI` |
|
|
||||||
| Service Impl | `ServiceImpl` | `MkmjServiceImpl` |
|
|
||||||
| Gateway Interface | `Gateway` | `MkmjGateway` |
|
|
||||||
| Gateway Impl | `GatewayImpl` | `MkmjGatewayImpl` |
|
|
||||||
| Repository | `Repository` | `MkmjRepository` |
|
|
||||||
| Repository Impl | `RepositoryImpl` | `MkmjRepositoryImpl` |
|
|
||||||
| Mapper | `Mapper` | `MkmjMapper` |
|
|
||||||
| Add Executor | `AddExe` | `MkmjAddExe` |
|
|
||||||
| Update Executor | `UpdateExe` | `MkmjUpdateExe` |
|
|
||||||
| Remove Executor | `RemoveExe` | `MkmjRemoveExe` |
|
|
||||||
| Query Executor | `QueryExe` | `MkmjQueryExe` |
|
|
||||||
| Convertor | `CoConvertor` | `MkmjCoConvertor` |
|
|
||||||
|
|
||||||
### Import Guidelines
|
|
||||||
|
|
||||||
- Imports should be organized alphabetically
|
|
||||||
- Use `@AllArgsConstructor` for constructor injection (preferred over `@Autowired`)
|
|
||||||
- Example import order:
|
|
||||||
```java
|
|
||||||
import com.alibaba.cola.dto.PageResponse;
|
|
||||||
import com.zcloud.primeport.api.MkmjServiceI;
|
|
||||||
import com.zcloud.primeport.command.MkmjAddExe;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
```
|
|
||||||
|
|
||||||
### Annotations
|
|
||||||
|
|
||||||
- Use Lombok annotations: `@Data`, `@AllArgsConstructor`, `@NoArgsConstructor`, `@Builder`, `@RequiredArgsConstructor`
|
|
||||||
- Controller: `@RestController`, `@RequestMapping`, `@AllArgsConstructor`, `@Api`
|
|
||||||
- Service: `@Service`, `@AllArgsConstructor`
|
|
||||||
- Executor: `@Component`, `@AllArgsConstructor`
|
|
||||||
- Mapper: `@Mapper` (MyBatis)
|
|
||||||
- DO: `@Data`, `@TableName`, `@EqualsAndHashCode(callSuper = true)`
|
|
||||||
|
|
||||||
### CQRS Pattern
|
|
||||||
|
|
||||||
Write and read operations are separated:
|
|
||||||
|
|
||||||
- **Write**: `XxxAddExe`, `XxxUpdateExe`, `XxxRemoveExe` in `web-app/command/`
|
|
||||||
- **Read**: `XxxQueryExe` in `web-app/command/query/`
|
|
||||||
|
|
||||||
### Request Flow
|
|
||||||
|
|
||||||
```
|
|
||||||
Controller (web-adapter)
|
|
||||||
-> ServiceI (web-client)
|
|
||||||
-> ServiceImpl (web-app)
|
|
||||||
-> Executor (web-app/command)
|
|
||||||
-> Gateway (web-domain)
|
|
||||||
-> GatewayImpl -> Repository -> Mapper (web-infrastructure)
|
|
||||||
```
|
|
||||||
|
|
||||||
### MyBatis Plus Conventions
|
|
||||||
|
|
||||||
1. **Non-database fields in DO**: Use `@TableField(exist = false)`
|
|
||||||
```java
|
|
||||||
@ApiModelProperty(value = "摄像头数量")
|
|
||||||
@TableField(exist = false)
|
|
||||||
private Integer videoCount;
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Field naming**: MyBatis Plus auto-converts snake_case to camelCase. Write SQL with underscore:
|
|
||||||
```xml
|
|
||||||
SELECT m.hg_auth_area AS hgAuthArea, m.mkmj_name AS mkmjName FROM mkmj m
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Default ordering**: Use `ORDER BY m.create_time DESC` or appropriate ordering in XML mappers.
|
|
||||||
|
|
||||||
### Error Handling
|
|
||||||
|
|
||||||
- Use `BizException` from COLA for business exceptions:
|
|
||||||
```java
|
|
||||||
if (!res) {
|
|
||||||
throw new BizException("保存失败");
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- Use `@Transactional(rollbackFor = Exception.class)` for transactional methods.
|
|
||||||
|
|
||||||
### Validation
|
|
||||||
|
|
||||||
- Use JSR-303 annotations in Cmd classes:
|
|
||||||
```java
|
|
||||||
@NotEmpty(message = "口门名称不能为空")
|
|
||||||
private String mkmjName;
|
|
||||||
|
|
||||||
@NotNull(message = "口门级别不能为空")
|
|
||||||
private Integer mkmjLevel;
|
|
||||||
```
|
|
||||||
|
|
||||||
- Use `@Validated` in Controller methods:
|
|
||||||
```java
|
|
||||||
public SingleResponse<MkmjCO> add(@Validated @RequestBody MkmjAddCmd cmd)
|
|
||||||
```
|
|
||||||
|
|
||||||
### MapStruct Convertors
|
|
||||||
|
|
||||||
Use MapStruct for DO to CO conversions:
|
|
||||||
```java
|
|
||||||
@Mapper(componentModel = "spring")
|
|
||||||
public interface MkmjCoConvertor {
|
|
||||||
List<MkmjCO> converDOsToCOs(List<MkmjDO> mkmjDOs);
|
|
||||||
MkmjCO converDOToCO(MkmjDO mkmjDOs);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Adding New Features
|
|
||||||
|
|
||||||
When adding a new entity, create files in this order:
|
|
||||||
|
|
||||||
1. `web-client/dto/clientobject/XxxCO.java`
|
|
||||||
2. `web-client/dto/XxxAddCmd.java`, `XxxUpdateCmd.java`, `XxxPageQry.java`
|
|
||||||
3. `web-client/api/XxxServiceI.java`
|
|
||||||
4. `web-adapter/web/XxxController.java`
|
|
||||||
5. `web-domain/model/XxxE.java`
|
|
||||||
6. `web-domain/gateway/XxxGateway.java`
|
|
||||||
7. `web-infrastructure/dataobject/XxxDO.java`
|
|
||||||
8. `web-infrastructure/mapper/XxxMapper.java`
|
|
||||||
9. `web-infrastructure/resources/mapper/XxxDO.xml`
|
|
||||||
10. `web-infrastructure/repository/XxxRepository.java`
|
|
||||||
11. `web-infrastructure/repository/impl/XxxRepositoryImpl.java`
|
|
||||||
12. `web-infrastructure/gatewayimpl/XxxGatewayImpl.java`
|
|
||||||
13. `web-app/command/XxxAddExe.java`, `XxxUpdateExe.java`, `XxxRemoveExe.java`
|
|
||||||
14. `web-app/command/query/XxxQueryExe.java`
|
|
||||||
15. `web-app/command/convertor/XxxCoConvertor.java`
|
|
||||||
16. `web-app/service/XxxServiceImpl.java`
|
|
||||||
|
|
||||||
### Database
|
|
||||||
|
|
||||||
- PostgreSQL (driver version 42.6.0)
|
|
||||||
- DDL location: `web-infrastructure/src/main/resources/TableCreationDDL.sql`
|
|
||||||
- Multi-tenant support via `tenant_id` and `org_id` columns
|
|
||||||
- Soft delete via `delete_enum` column (use `'false'` for active records)
|
|
||||||
|
|
||||||
### Response Types (COLA)
|
|
||||||
|
|
||||||
- `Response` - Simple success/failure
|
|
||||||
- `SingleResponse<T>` - Single object response
|
|
||||||
- `MultiResponse<T>` - List response
|
|
||||||
- `PageResponse<T>` - Paginated list response
|
|
||||||
160
CLAUDE.md
160
CLAUDE.md
|
|
@ -1,160 +0,0 @@
|
||||||
# CLAUDE.md
|
|
||||||
|
|
||||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
||||||
|
|
||||||
## Project Overview
|
|
||||||
|
|
||||||
**zcloud-gbs-primeport** - 智慧云港-港口首进门禁管理系统
|
|
||||||
|
|
||||||
A Spring Boot application based on DDD (Domain-Driven Design) architecture using the COLA framework. Manages port/area access control with multi-level area management, vehicle approval, and personnel access control.
|
|
||||||
|
|
||||||
## Build and Run
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Build the project
|
|
||||||
mvn clean install
|
|
||||||
|
|
||||||
# Run the application (main class: com.zcloud.primeport.Application)
|
|
||||||
mvn spring-boot:run -pl start
|
|
||||||
|
|
||||||
# Package for deployment
|
|
||||||
mvn clean package
|
|
||||||
```
|
|
||||||
|
|
||||||
## DDD Architecture
|
|
||||||
|
|
||||||
This is a COLA-based multi-module Maven project with strict layer separation:
|
|
||||||
|
|
||||||
```
|
|
||||||
start/ # Application entry point (main class, configuration)
|
|
||||||
web-adapter/ # Adapter layer (Controllers) - HTTP request handling
|
|
||||||
web-client/ # Client layer (DTOs + API interface definitions)
|
|
||||||
web-app/ # Application layer (Command/Query executors) - Business orchestration
|
|
||||||
web-domain/ # Domain layer (Entity + Gateway) - Core business logic
|
|
||||||
web-infrastructure/ # Infrastructure layer (DO + Mapper) - Data persistence
|
|
||||||
```
|
|
||||||
|
|
||||||
### Key Architecture Patterns
|
|
||||||
|
|
||||||
**CQRS**: Read and write operations are separated
|
|
||||||
- Write operations: `XxxAddExe`, `XxxUpdateExe`, `XxxRemoveExe` in `web-app/command/`
|
|
||||||
- Read operations: `XxxQueryExe` in `web-app/command/query/`
|
|
||||||
|
|
||||||
**Naming Conventions**:
|
|
||||||
- Entities: `XxxE` (domain entities in `web-domain`)
|
|
||||||
- DTOs: `XxxCmd` (commands), `XxxQry` (queries), `XxxCO` (client objects)
|
|
||||||
- Data Objects: `XxxDO` (database objects in `web-infrastructure`)
|
|
||||||
- Gateways: `XxxGateway` interfaces in `web-domain`, implemented in `web-infrastructure`
|
|
||||||
|
|
||||||
**Request Flow**:
|
|
||||||
```
|
|
||||||
Controller (web-adapter)
|
|
||||||
→ ServiceI (web-client)
|
|
||||||
→ ServiceImpl (web-app)
|
|
||||||
→ Executor (web-app/command)
|
|
||||||
→ Gateway (web-domain)
|
|
||||||
→ Mapper (web-infrastructure)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Database Schema
|
|
||||||
|
|
||||||
Database DDL is located at: `web-infrastructure/src/main/resources/TableCreationDDL.sql`
|
|
||||||
|
|
||||||
### Core Tables (9 main business entities)
|
|
||||||
|
|
||||||
**门禁管理**
|
|
||||||
- `mkmj` - 门口信息管理表 (gate info: 一级/二级口门)
|
|
||||||
- `mkmj_gate` - 门口闸机表 (gate equipment)
|
|
||||||
- `mkmj_passage` - 口门门禁通道表 (passageways: 人行/车行/综合)
|
|
||||||
- `mkmj_approval_user` - 一级口门门禁审批人
|
|
||||||
- `video` - 摄像头表 (video monitoring)
|
|
||||||
|
|
||||||
**人员管理**
|
|
||||||
- `person_apply` - 人员申请审批信息 (personnel applications with audit workflow)
|
|
||||||
- `person_message` - 审批通过的人员信息 (approved personnel for access control sync)
|
|
||||||
|
|
||||||
**车辆管理**
|
|
||||||
- `vehicle_apply` - 车辆申请审批信息 (vehicle applications with audit workflow)
|
|
||||||
- `vehicle_audit` - 车辆审批
|
|
||||||
- `vehicle_message` - 审批通过的固化车辆信息
|
|
||||||
- `vehicle_black` - 车辆黑名单管理
|
|
||||||
- `vehicle_violations` - 车辆违规记录
|
|
||||||
|
|
||||||
### Key Business Concepts
|
|
||||||
|
|
||||||
**审核状态** - audit_flag:
|
|
||||||
- 1: 审核中
|
|
||||||
- 2: 审核通过
|
|
||||||
- 3: 审核驳回
|
|
||||||
- 4: 无需审批 (检查部门车辆/长期人员)
|
|
||||||
|
|
||||||
**车辆/人员所属类型** - belong_type:
|
|
||||||
- 1: 股份员工车辆/人员
|
|
||||||
- 2: 股份单位车辆
|
|
||||||
- 3: 分公司员工车辆/人员
|
|
||||||
- 4: 分公司单位车辆
|
|
||||||
- 5: 相关方车辆
|
|
||||||
- 6: 临时车辆/人员
|
|
||||||
- 7: 检查部门车辆
|
|
||||||
|
|
||||||
**口门级别** - mkmj_level:
|
|
||||||
- 1: 一级口门
|
|
||||||
- 2: 二级口门
|
|
||||||
|
|
||||||
**通道/闸机类型**:
|
|
||||||
- 1: 人行
|
|
||||||
- 2: 车行
|
|
||||||
- 3: 综合
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
- Uses Nacos for centralized configuration
|
|
||||||
- Database: MySQL (Note: DDL shows MySQL syntax, but pom.xml has PostgreSQL driver - confirm actual DB)
|
|
||||||
- MyBatis Plus for ORM
|
|
||||||
- Main application config: `start/src/main/resources/bootstrap.yml`
|
|
||||||
- Nacos connection: `start/src/main/resources/nacos.yml`
|
|
||||||
- Multi-tenant support via `tenant_id` and `org_id` columns
|
|
||||||
|
|
||||||
## Module Dependencies
|
|
||||||
|
|
||||||
All modules depend on `web-client`. The `start` module only depends on `web-adapter` and pulls in transitive dependencies.
|
|
||||||
|
|
||||||
Current git branch: `koumen` (门禁审批功能 - gate access approval)
|
|
||||||
Main branch: `master`
|
|
||||||
|
|
||||||
## Code Generation Pattern
|
|
||||||
|
|
||||||
When adding new features, follow the existing pattern across all layers:
|
|
||||||
1. Create CO in `web-client/src/main/java/com/zcloud/primeport/dto/clientobject/`
|
|
||||||
2. Create Cmd/Qry in `web-client/src/main/java/com/zcloud/primeport/dto/`
|
|
||||||
3. Create ServiceI in `web-client/src/main/java/com/zcloud/primeport/api/`
|
|
||||||
4. Create Controller in `web-adapter/src/main/java/com/zcloud/primeport/web/`
|
|
||||||
5. Create Entity in `web-domain/src/main/java/com/zcloud/primeport/domain/model/`
|
|
||||||
6. Create Gateway interface in `web-domain/src/main/java/com/zcloud/primeport/domain/gateway/`
|
|
||||||
7. Create DO in `web-infrastructure/src/main/java/com/zcloud/primeport/persistence/dataobject/`
|
|
||||||
8. Create Mapper in `web-infrastructure/src/main/java/com/zcloud/primeport/persistence/mapper/`
|
|
||||||
9. Create GatewayImpl in `web-infrastructure/src/main/java/com/zcloud/primeport/gatewayimpl/`
|
|
||||||
10. Create Executors in `web-app/src/main/java/com/zcloud/primeport/command/`
|
|
||||||
11. Create ServiceImpl in `web-app/src/main/java/com/zcloud/primeport/service/`
|
|
||||||
|
|
||||||
## MyBatis Plus Development Conventions
|
|
||||||
|
|
||||||
### DO (Data Object) Field Conventions
|
|
||||||
|
|
||||||
1. **Non-database fields**: When adding a field to DO that does not exist in the database table (e.g., association query results), use `@TableField(exist = false)` annotation:
|
|
||||||
```java
|
|
||||||
@ApiModelProperty(value = "摄像头数量")
|
|
||||||
@TableField(exist = false)
|
|
||||||
private Integer videoCount;
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Field naming**: MyBatis Plus automatically converts between underscore (snake_case) and camelCase. Write SQL with underscore column names directly - no need to manually convert to camelCase:
|
|
||||||
```xml
|
|
||||||
<!-- SQL 中直接使用下划线字段名 -->
|
|
||||||
SELECT m.hg_auth_area AS hgAuthArea, m.mkmj_name AS mkmjName FROM mkmj m
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Default ordering**: Unless specified otherwise, order by `create_time DESC` for list/page queries:
|
|
||||||
```xml
|
|
||||||
ORDER BY m.create_time DESC
|
|
||||||
```
|
|
||||||
|
|
@ -34,12 +34,12 @@
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-signature-canvas": "^1.1.0-alpha.2",
|
"react-signature-canvas": "^1.1.0-alpha.2",
|
||||||
"zy-react-library": "^1.2.9"
|
"zy-react-library": "^1.2.10"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@antfu/eslint-config": "^5.4.1",
|
"@antfu/eslint-config": "^5.4.1",
|
||||||
"@babel/plugin-proposal-decorators": "^7.19.3",
|
"@babel/plugin-proposal-decorators": "^7.19.3",
|
||||||
"@cqsjjb/scripts": "latest",
|
"@cqsjjb/scripts": "2.0.0",
|
||||||
"@eslint-react/eslint-plugin": "^2.2.2",
|
"@eslint-react/eslint-plugin": "^2.2.2",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^9.37.0",
|
"eslint": "^9.37.0",
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ package com.zcloud.primeport.command;
|
||||||
import com.alibaba.cola.dto.SingleResponse;
|
import com.alibaba.cola.dto.SingleResponse;
|
||||||
import com.jjb.saas.framework.auth.model.SSOUser;
|
import com.jjb.saas.framework.auth.model.SSOUser;
|
||||||
import com.jjb.saas.framework.auth.utils.AuthContext;
|
import com.jjb.saas.framework.auth.utils.AuthContext;
|
||||||
|
import com.zcloud.gbscommon.todolistmq.TodoListEventPusherUtil;
|
||||||
|
import com.zcloud.gbscommon.todolistmq.event.TodoListAddEvent;
|
||||||
import com.zcloud.gbscommon.zclouduser.facade.ZcloudUserFacade;
|
import com.zcloud.gbscommon.zclouduser.facade.ZcloudUserFacade;
|
||||||
import com.zcloud.gbscommon.zclouduser.response.ZcloudUserCo;
|
import com.zcloud.gbscommon.zclouduser.response.ZcloudUserCo;
|
||||||
import com.zcloud.primeport.domain.enums.AuditEnum;
|
import com.zcloud.primeport.domain.enums.AuditEnum;
|
||||||
|
|
@ -29,6 +31,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class ClosedAreaCarApplyAddExe {
|
public class ClosedAreaCarApplyAddExe {
|
||||||
private final ClosedAreaCarApplyGateway closedAreaCarApplyGateway;
|
private final ClosedAreaCarApplyGateway closedAreaCarApplyGateway;
|
||||||
|
private final TodoListEventPusherUtil todoListEventPusherUtil;
|
||||||
@DubboReference
|
@DubboReference
|
||||||
private ZcloudUserFacade zcloudUserFacade;
|
private ZcloudUserFacade zcloudUserFacade;
|
||||||
|
|
||||||
|
|
@ -60,6 +63,15 @@ public class ClosedAreaCarApplyAddExe {
|
||||||
boolean res = false;
|
boolean res = false;
|
||||||
try {
|
try {
|
||||||
res = closedAreaCarApplyGateway.add(closedAreaCarApplyE);
|
res = closedAreaCarApplyGateway.add(closedAreaCarApplyE);
|
||||||
|
TodoListAddEvent todoListAddEvent = new TodoListAddEvent();
|
||||||
|
todoListAddEvent.setForeignKey(closedAreaCarApplyE.getId());
|
||||||
|
todoListAddEvent.setForeignSubsidiaryKey(closedAreaCarApplyE.getId());
|
||||||
|
todoListAddEvent.setTitle("您有一条封闭区域审核,请及时进行审核。");
|
||||||
|
todoListAddEvent.setContent("待审核");
|
||||||
|
todoListAddEvent.setReceiveUser(cmd.getAuditPersonUserId());
|
||||||
|
todoListAddEvent.setPcFlag(1);
|
||||||
|
todoListAddEvent.setAppFlag(1);
|
||||||
|
todoListEventPusherUtil.sendMessageAddEvent(todoListAddEvent);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package com.zcloud.primeport.command;
|
package com.zcloud.primeport.command;
|
||||||
|
|
||||||
import com.alibaba.cola.exception.BizException;
|
import com.alibaba.cola.exception.BizException;
|
||||||
|
import com.zcloud.gbscommon.todolistmq.TodoListEventPusherUtil;
|
||||||
|
import com.zcloud.gbscommon.todolistmq.event.TodoListCompleteEvent;
|
||||||
import com.zcloud.gbscommon.utils.DateUtil;
|
import com.zcloud.gbscommon.utils.DateUtil;
|
||||||
import com.zcloud.primeport.domain.gateway.ClosedAreaCarApplyGateway;
|
import com.zcloud.primeport.domain.gateway.ClosedAreaCarApplyGateway;
|
||||||
import com.zcloud.primeport.domain.model.ClosedAreaCarApplyE;
|
import com.zcloud.primeport.domain.model.ClosedAreaCarApplyE;
|
||||||
|
|
@ -24,6 +26,7 @@ import java.util.Date;
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class ClosedAreaCarApplyUpdateExe {
|
public class ClosedAreaCarApplyUpdateExe {
|
||||||
private final ClosedAreaCarApplyGateway closedAreaCarApplyGateway;
|
private final ClosedAreaCarApplyGateway closedAreaCarApplyGateway;
|
||||||
|
private final TodoListEventPusherUtil todoListEventPusherUtil;
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void execute(ClosedAreaCarApplyUpdateCmd closedAreaCarApplyUpdateCmd) {
|
public void execute(ClosedAreaCarApplyUpdateCmd closedAreaCarApplyUpdateCmd) {
|
||||||
|
|
@ -43,6 +46,10 @@ public class ClosedAreaCarApplyUpdateExe {
|
||||||
closedAreaCarApplyE.setRefusalReason(auditCmd.getRefusalReason());
|
closedAreaCarApplyE.setRefusalReason(auditCmd.getRefusalReason());
|
||||||
closedAreaCarApplyE.setAuditTime(DateUtil.date2Str(new Date()));
|
closedAreaCarApplyE.setAuditTime(DateUtil.date2Str(new Date()));
|
||||||
closedAreaCarApplyGateway.update(closedAreaCarApplyE);
|
closedAreaCarApplyGateway.update(closedAreaCarApplyE);
|
||||||
|
|
||||||
|
TodoListCompleteEvent todoListCompleteEvent = new TodoListCompleteEvent();
|
||||||
|
todoListCompleteEvent.setForeignSubsidiaryKey(auditCmd.getId());
|
||||||
|
todoListEventPusherUtil.sendMessageCompleteEvent(todoListCompleteEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ package com.zcloud.primeport.command;
|
||||||
import com.alibaba.cola.dto.SingleResponse;
|
import com.alibaba.cola.dto.SingleResponse;
|
||||||
import com.jjb.saas.framework.auth.model.SSOUser;
|
import com.jjb.saas.framework.auth.model.SSOUser;
|
||||||
import com.jjb.saas.framework.auth.utils.AuthContext;
|
import com.jjb.saas.framework.auth.utils.AuthContext;
|
||||||
|
import com.zcloud.gbscommon.todolistmq.TodoListEventPusherUtil;
|
||||||
|
import com.zcloud.gbscommon.todolistmq.event.TodoListAddEvent;
|
||||||
import com.zcloud.gbscommon.zclouduser.facade.ZcloudUserFacade;
|
import com.zcloud.gbscommon.zclouduser.facade.ZcloudUserFacade;
|
||||||
import com.zcloud.gbscommon.zclouduser.response.ZcloudUserCo;
|
import com.zcloud.gbscommon.zclouduser.response.ZcloudUserCo;
|
||||||
import com.zcloud.primeport.domain.gateway.ClosedAreaPersonApplyGateway;
|
import com.zcloud.primeport.domain.gateway.ClosedAreaPersonApplyGateway;
|
||||||
|
|
@ -27,6 +29,8 @@ import org.springframework.transaction.annotation.Transactional;
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class ClosedAreaPersonApplyAddExe {
|
public class ClosedAreaPersonApplyAddExe {
|
||||||
private final ClosedAreaPersonApplyGateway closedAreaPersonApplyGateway;
|
private final ClosedAreaPersonApplyGateway closedAreaPersonApplyGateway;
|
||||||
|
private final TodoListEventPusherUtil todoListEventPusherUtil;
|
||||||
|
|
||||||
@DubboReference
|
@DubboReference
|
||||||
private ZcloudUserFacade zcloudUserFacade;
|
private ZcloudUserFacade zcloudUserFacade;
|
||||||
|
|
||||||
|
|
@ -54,6 +58,15 @@ public class ClosedAreaPersonApplyAddExe {
|
||||||
boolean res = false;
|
boolean res = false;
|
||||||
try {
|
try {
|
||||||
res = closedAreaPersonApplyGateway.add(closedAreaPersonApplyE);
|
res = closedAreaPersonApplyGateway.add(closedAreaPersonApplyE);
|
||||||
|
TodoListAddEvent todoListAddEvent = new TodoListAddEvent();
|
||||||
|
todoListAddEvent.setForeignKey(closedAreaPersonApplyE.getId());
|
||||||
|
todoListAddEvent.setForeignSubsidiaryKey(closedAreaPersonApplyE.getId());
|
||||||
|
todoListAddEvent.setTitle("您有一条封闭区域审核,请及时进行审核。");
|
||||||
|
todoListAddEvent.setContent("待审核");
|
||||||
|
todoListAddEvent.setReceiveUser(cmd.getAuditPersonUserId());
|
||||||
|
todoListAddEvent.setPcFlag(1);
|
||||||
|
todoListAddEvent.setAppFlag(1);
|
||||||
|
todoListEventPusherUtil.sendMessageAddEvent(todoListAddEvent);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package com.zcloud.primeport.command;
|
package com.zcloud.primeport.command;
|
||||||
|
|
||||||
import com.alibaba.cola.exception.BizException;
|
import com.alibaba.cola.exception.BizException;
|
||||||
|
import com.zcloud.gbscommon.todolistmq.TodoListEventPusherUtil;
|
||||||
|
import com.zcloud.gbscommon.todolistmq.event.TodoListCompleteEvent;
|
||||||
import com.zcloud.gbscommon.utils.DateUtil;
|
import com.zcloud.gbscommon.utils.DateUtil;
|
||||||
import com.zcloud.primeport.domain.gateway.ClosedAreaFgsPersonAreaGateway;
|
import com.zcloud.primeport.domain.gateway.ClosedAreaFgsPersonAreaGateway;
|
||||||
import com.zcloud.primeport.domain.gateway.ClosedAreaFgsPersonAuthGateway;
|
import com.zcloud.primeport.domain.gateway.ClosedAreaFgsPersonAuthGateway;
|
||||||
|
|
@ -33,6 +35,7 @@ public class ClosedAreaPersonApplyUpdateExe {
|
||||||
private final ClosedAreaPersonApplyGateway closedAreaPersonApplyGateway;
|
private final ClosedAreaPersonApplyGateway closedAreaPersonApplyGateway;
|
||||||
private final ClosedAreaFgsPersonAuthGateway areaFgsPersonAuthGateway;
|
private final ClosedAreaFgsPersonAuthGateway areaFgsPersonAuthGateway;
|
||||||
private final ClosedAreaFgsPersonAreaGateway areaFgsPersonAreaGateway;
|
private final ClosedAreaFgsPersonAreaGateway areaFgsPersonAreaGateway;
|
||||||
|
private final TodoListEventPusherUtil todoListEventPusherUtil;
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void execute(ClosedAreaPersonApplyUpdateCmd closedAreaPersonApplyUpdateCmd) {
|
public void execute(ClosedAreaPersonApplyUpdateCmd closedAreaPersonApplyUpdateCmd) {
|
||||||
|
|
@ -52,6 +55,9 @@ public class ClosedAreaPersonApplyUpdateExe {
|
||||||
closedAreaPersonApplyE.setRefusalReason(auditCmd.getRefusalReason());
|
closedAreaPersonApplyE.setRefusalReason(auditCmd.getRefusalReason());
|
||||||
closedAreaPersonApplyE.setAuditTime(DateUtil.date2Str(new Date()));
|
closedAreaPersonApplyE.setAuditTime(DateUtil.date2Str(new Date()));
|
||||||
closedAreaPersonApplyGateway.update(closedAreaPersonApplyE);
|
closedAreaPersonApplyGateway.update(closedAreaPersonApplyE);
|
||||||
|
TodoListCompleteEvent todoListCompleteEvent = new TodoListCompleteEvent();
|
||||||
|
todoListCompleteEvent.setForeignSubsidiaryKey(auditCmd.getId());
|
||||||
|
todoListEventPusherUtil.sendMessageCompleteEvent(todoListCompleteEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import com.alibaba.cola.dto.PageResponse;
|
||||||
import com.alibaba.cola.dto.SingleResponse;
|
import com.alibaba.cola.dto.SingleResponse;
|
||||||
import com.alibaba.cola.exception.BizException;
|
import com.alibaba.cola.exception.BizException;
|
||||||
import com.jjb.saas.framework.auth.utils.AuthContext;
|
import com.jjb.saas.framework.auth.utils.AuthContext;
|
||||||
|
import com.zcloud.gbscommon.todolistmq.TodoListEventPusherUtil;
|
||||||
|
import com.zcloud.gbscommon.todolistmq.event.TodoListAddEvent;
|
||||||
import com.zcloud.gbscommon.utils.DateUtil;
|
import com.zcloud.gbscommon.utils.DateUtil;
|
||||||
import com.zcloud.primeport.domain.gateway.PersonApplyGateway;
|
import com.zcloud.primeport.domain.gateway.PersonApplyGateway;
|
||||||
import com.zcloud.primeport.domain.gateway.XgfApplyPersonGateway;
|
import com.zcloud.primeport.domain.gateway.XgfApplyPersonGateway;
|
||||||
|
|
@ -38,6 +40,7 @@ import java.util.List;
|
||||||
public class PersonApplyAddExe {
|
public class PersonApplyAddExe {
|
||||||
private final PersonApplyGateway personApplyGateway;
|
private final PersonApplyGateway personApplyGateway;
|
||||||
private final XgfApplyPersonGateway xgfApplyPersonGateway;
|
private final XgfApplyPersonGateway xgfApplyPersonGateway;
|
||||||
|
private final TodoListEventPusherUtil todoListEventPusherUtil;
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public boolean execute(PersonApplyAddCmd cmd) {
|
public boolean execute(PersonApplyAddCmd cmd) {
|
||||||
|
|
@ -72,6 +75,15 @@ public class PersonApplyAddExe {
|
||||||
.applyCorpName(cmd.getPersonBelongType() != 4 ? AuthContext.getCurrentUser().getTenantName() : null)
|
.applyCorpName(cmd.getPersonBelongType() != 4 ? AuthContext.getCurrentUser().getTenantName() : null)
|
||||||
.projectId(cmd.getProjectId()).projectName(cmd.getProjectName()).informSignId(cmd.getInformSignId()).build();
|
.projectId(cmd.getProjectId()).projectName(cmd.getProjectName()).informSignId(cmd.getInformSignId()).build();
|
||||||
xgfApplyPersonGateway.save(build);
|
xgfApplyPersonGateway.save(build);
|
||||||
|
TodoListAddEvent todoListAddEvent = new TodoListAddEvent();
|
||||||
|
todoListAddEvent.setForeignKey(build.getId());
|
||||||
|
todoListAddEvent.setForeignSubsidiaryKey(build.getId());
|
||||||
|
todoListAddEvent.setTitle("您有一条口门审核,请及时进行审核。");
|
||||||
|
todoListAddEvent.setContent("待审核");
|
||||||
|
todoListAddEvent.setReceiveUser(cmd.getAuditUserId());
|
||||||
|
todoListAddEvent.setPcFlag(1);
|
||||||
|
todoListAddEvent.setAppFlag(1);
|
||||||
|
todoListEventPusherUtil.sendMessageAddEvent(todoListAddEvent);
|
||||||
List<XgfPersonApplyAddCmd.PersonApplyAddCmdExt> personApplyList = cmd.getPersonApplyList();
|
List<XgfPersonApplyAddCmd.PersonApplyAddCmdExt> personApplyList = cmd.getPersonApplyList();
|
||||||
// 相关方人员信息的保存
|
// 相关方人员信息的保存
|
||||||
ArrayList<PersonApplyE> personApplyES = new ArrayList<>();
|
ArrayList<PersonApplyE> personApplyES = new ArrayList<>();
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ public class PersonApplyUpdateExe {
|
||||||
.reasonsRefusal(cmd.getReasonsRefusal()).build();
|
.reasonsRefusal(cmd.getReasonsRefusal()).build();
|
||||||
build.setId(cmd.getId());
|
build.setId(cmd.getId());
|
||||||
personApplyGateway.xgfPersonAudit(build);
|
personApplyGateway.xgfPersonAudit(build);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
|
|
||||||
|
|
@ -82,8 +82,17 @@ public class VehicleApplyAddExe {
|
||||||
.auditDeptId(examTypeE.getAuditDeptId()).auditDeptName(examTypeE.getAuditDeptName()).auditCorpId(examTypeE.getAuditCorpId()).auditCorpName(examTypeE.getAuditCorpName()).auditStatus(AuditEnum.WAITING.getCode()).changeAfter(JSON.toJSONString(examTypeE)).build();
|
.auditDeptId(examTypeE.getAuditDeptId()).auditDeptName(examTypeE.getAuditDeptName()).auditCorpId(examTypeE.getAuditCorpId()).auditCorpName(examTypeE.getAuditCorpName()).auditStatus(AuditEnum.WAITING.getCode()).changeAfter(JSON.toJSONString(examTypeE)).build();
|
||||||
// 添加审批信息
|
// 添加审批信息
|
||||||
vehicleAuditGateway.add(build);
|
vehicleAuditGateway.add(build);
|
||||||
|
TodoListAddEvent todoListAddEvent = new TodoListAddEvent();
|
||||||
|
todoListAddEvent.setForeignKey(build.getId());
|
||||||
|
todoListAddEvent.setForeignSubsidiaryKey(build.getId());
|
||||||
|
todoListAddEvent.setTitle("您有一条口门审核,请及时进行审核。");
|
||||||
|
todoListAddEvent.setContent("待审核");
|
||||||
|
todoListAddEvent.setReceiveUser(cmd.getAuditUserId());
|
||||||
|
todoListAddEvent.setPcFlag(1);
|
||||||
|
todoListAddEvent.setAppFlag(1);
|
||||||
|
todoListEventPusherUtil.sendMessageAddEvent(todoListAddEvent);
|
||||||
// 发送待审核消息
|
// 发送待审核消息
|
||||||
todoListEventPusherUtil.sendMessageAddEvent(build.getSendEventObj());
|
// todoListEventPusherUtil.sendMessageAddEvent(build.getSendEventObj());
|
||||||
|
|
||||||
return add;
|
return add;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ public class VehicleApplyUpdateExe {
|
||||||
// 添加审批信息
|
// 添加审批信息
|
||||||
vehicleAuditGateway.add(build);
|
vehicleAuditGateway.add(build);
|
||||||
// 发送待审核待办
|
// 发送待审核待办
|
||||||
todoListEventPusherUtil.sendMessageAddEvent(build.getSendEventObj());
|
// todoListEventPusherUtil.sendMessageAddEvent(build.getSendEventObj());
|
||||||
if (!res) {
|
if (!res) {
|
||||||
throw new BizException("修改失败");
|
throw new BizException("修改失败");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package com.zcloud.primeport.command;
|
package com.zcloud.primeport.command;
|
||||||
|
|
||||||
import com.alibaba.cola.exception.BizException;
|
import com.alibaba.cola.exception.BizException;
|
||||||
|
import com.zcloud.gbscommon.todolistmq.TodoListEventPusherUtil;
|
||||||
|
import com.zcloud.gbscommon.todolistmq.event.TodoListCompleteEvent;
|
||||||
import com.zcloud.gbscommon.utils.DateUtil;
|
import com.zcloud.gbscommon.utils.DateUtil;
|
||||||
import com.zcloud.primeport.domain.gateway.VehicleApplyGateway;
|
import com.zcloud.primeport.domain.gateway.VehicleApplyGateway;
|
||||||
import com.zcloud.primeport.domain.gateway.VehicleAuditGateway;
|
import com.zcloud.primeport.domain.gateway.VehicleAuditGateway;
|
||||||
|
|
@ -26,6 +28,7 @@ import java.util.Date;
|
||||||
public class VehicleAuditUpdateExe {
|
public class VehicleAuditUpdateExe {
|
||||||
private final VehicleAuditGateway vehicleAuditGateway;
|
private final VehicleAuditGateway vehicleAuditGateway;
|
||||||
private final VehicleApplyGateway vehicleApplyGateway;
|
private final VehicleApplyGateway vehicleApplyGateway;
|
||||||
|
private final TodoListEventPusherUtil todoListEventPusherUtil;
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void execute(VehicleAuditUpdateCmd vehicleAuditUpdateCmd) {
|
public void execute(VehicleAuditUpdateCmd vehicleAuditUpdateCmd) {
|
||||||
|
|
@ -54,6 +57,9 @@ public class VehicleAuditUpdateExe {
|
||||||
vehicleApplyE.setStatusFlag(2);
|
vehicleApplyE.setStatusFlag(2);
|
||||||
vehicleApplyGateway.update(vehicleApplyE);
|
vehicleApplyGateway.update(vehicleApplyE);
|
||||||
vehicleAuditGateway.update(vehicleAuditE);
|
vehicleAuditGateway.update(vehicleAuditE);
|
||||||
|
TodoListCompleteEvent todoListCompleteEvent = new TodoListCompleteEvent();
|
||||||
|
todoListCompleteEvent.setForeignSubsidiaryKey(vehicleAuditE.getId());
|
||||||
|
todoListEventPusherUtil.sendMessageCompleteEvent(todoListCompleteEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ public class VehicleApplyServiceImpl implements VehicleApplyServiceI {
|
||||||
QueryWrapper<VehicleBlackDO> queryBlackWrapper = new QueryWrapper<>();
|
QueryWrapper<VehicleBlackDO> queryBlackWrapper = new QueryWrapper<>();
|
||||||
queryBlackWrapper.eq("licence_no", licenceNo);
|
queryBlackWrapper.eq("licence_no", licenceNo);
|
||||||
queryBlackWrapper.eq("delete_enum", "false");
|
queryBlackWrapper.eq("delete_enum", "false");
|
||||||
if (blackRepository.count(queryBlackWrapper) == 0) {
|
if (blackRepository.count(queryBlackWrapper) != 0) {
|
||||||
result.put("available", false);
|
result.put("available", false);
|
||||||
result.put("availableMessage", "车牌号已拉黑");
|
result.put("availableMessage", "车牌号已拉黑");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@ package com.zcloud.primeport.gatewayimpl;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||||
|
import com.zcloud.gbscommon.todolistmq.TodoListEventPusherUtil;
|
||||||
|
import com.zcloud.gbscommon.todolistmq.event.TodoListAddEvent;
|
||||||
|
import com.zcloud.gbscommon.todolistmq.event.TodoListCompleteEvent;
|
||||||
import com.zcloud.primeport.domain.gateway.PersonApplyGateway;
|
import com.zcloud.primeport.domain.gateway.PersonApplyGateway;
|
||||||
import com.zcloud.primeport.domain.model.PersonApplyE;
|
import com.zcloud.primeport.domain.model.PersonApplyE;
|
||||||
import com.zcloud.primeport.domain.model.XgfApplyPersonE;
|
import com.zcloud.primeport.domain.model.XgfApplyPersonE;
|
||||||
|
|
@ -31,6 +34,7 @@ public class PersonApplyGatewayImpl implements PersonApplyGateway {
|
||||||
private final PersonApplyRepository personApplyRepository;
|
private final PersonApplyRepository personApplyRepository;
|
||||||
private final XgfApplyPersonRepository xgfApplyPersonRepository;
|
private final XgfApplyPersonRepository xgfApplyPersonRepository;
|
||||||
private final PersonMessageRepository personMessageRepository;
|
private final PersonMessageRepository personMessageRepository;
|
||||||
|
private final TodoListEventPusherUtil todoListEventPusherUtil;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean add(PersonApplyE personApplyE) {
|
public Boolean add(PersonApplyE personApplyE) {
|
||||||
|
|
@ -102,6 +106,9 @@ public class PersonApplyGatewayImpl implements PersonApplyGateway {
|
||||||
});
|
});
|
||||||
personMessageRepository.saveBatch(personMessageDOS);
|
personMessageRepository.saveBatch(personMessageDOS);
|
||||||
}
|
}
|
||||||
|
TodoListCompleteEvent todoListCompleteEvent = new TodoListCompleteEvent();
|
||||||
|
todoListCompleteEvent.setForeignSubsidiaryKey(build.getId());
|
||||||
|
todoListEventPusherUtil.sendMessageCompleteEvent(todoListCompleteEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ public class VehicleAuditGatewayImpl implements VehicleAuditGateway {
|
||||||
VehicleAuditDO d = new VehicleAuditDO();
|
VehicleAuditDO d = new VehicleAuditDO();
|
||||||
BeanUtils.copyProperties(vehicleAuditE, d);
|
BeanUtils.copyProperties(vehicleAuditE, d);
|
||||||
vehicleAuditRepository.save(d);
|
vehicleAuditRepository.save(d);
|
||||||
|
vehicleAuditE.setId(d.getId());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
1273
口门信息管理 - 后端需求文档.md
1273
口门信息管理 - 后端需求文档.md
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue