refactor: DDD架构完善+测试mock配置修复
- 完善Service接口DDD分层架构 - 修复EquipmentHealthServiceTest mock配置 - 修复WorkOrderServiceTest状态转换测试mock - 修复MaintenanceTaskServiceTest mock配置 - 修复SystemType枚举测试(FIRE→FIRE_PROTECTION) - 添加工单事件监听器测试 - 添加工单状态历史测试 - 添加维保到期提醒功能 Tests: 100 passed, 0 failures
This commit is contained in:
parent
34c51288db
commit
473bf5b81e
|
|
@ -11,8 +11,13 @@ import com.ether.pms.asset.service.*;
|
|||
import com.ether.pms.common.ApiResponse;
|
||||
import com.ether.pms.common.BusinessException;
|
||||
import com.ether.pms.common.ErrorCode;
|
||||
import com.ether.pms.common.util.BatchOperationValidator;
|
||||
import jakarta.validation.Valid;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
|
|
@ -21,13 +26,6 @@ import org.springframework.validation.annotation.Validated;
|
|||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/asset/equipment")
|
||||
@RequiredArgsConstructor
|
||||
|
|
@ -40,10 +38,10 @@ public class EquipmentController {
|
|||
private final EquipmentEnergyService energyService;
|
||||
private final EquipmentFireService fireService;
|
||||
|
||||
private static final Set<String> ALLOWED_CONTENT_TYPES = Set.of(
|
||||
private static final Set<String> ALLOWED_CONTENT_TYPES =
|
||||
Set.of(
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"application/vnd.ms-excel"
|
||||
);
|
||||
"application/vnd.ms-excel");
|
||||
|
||||
private static final Set<String> ALLOWED_EXTENSIONS = Set.of(".xlsx", ".xls");
|
||||
|
||||
|
|
@ -62,7 +60,8 @@ public class EquipmentController {
|
|||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ApiResponse<Equipment> updateEquipment(@PathVariable UUID id, @Valid @RequestBody Equipment equipment) {
|
||||
public ApiResponse<Equipment> updateEquipment(
|
||||
@PathVariable UUID id, @Valid @RequestBody Equipment equipment) {
|
||||
return ApiResponse.success(equipmentService.updateEquipment(id, equipment));
|
||||
}
|
||||
|
||||
|
|
@ -79,7 +78,8 @@ public class EquipmentController {
|
|||
}
|
||||
|
||||
@PostMapping("/import")
|
||||
public ApiResponse<Map<String, Object>> importEquipment(@RequestParam("file") MultipartFile file, @RequestParam UUID projectId) {
|
||||
public ApiResponse<Map<String, Object>> importEquipment(
|
||||
@RequestParam("file") MultipartFile file, @RequestParam UUID projectId) {
|
||||
validateExcelFile(file);
|
||||
return ApiResponse.success(equipmentService.importFromExcel(file, projectId));
|
||||
}
|
||||
|
|
@ -121,8 +121,7 @@ public class EquipmentController {
|
|||
if (rowCount > MAX_EXCEL_ROWS) {
|
||||
throw new BusinessException(
|
||||
ErrorCode.FILE_004,
|
||||
String.format("Excel 行数不能超过 %d 行,当前 %d 行", MAX_EXCEL_ROWS, rowCount)
|
||||
);
|
||||
String.format("Excel 行数不能超过 %d 行,当前 %d 行", MAX_EXCEL_ROWS, rowCount));
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
|
|
@ -155,7 +154,8 @@ public class EquipmentController {
|
|||
}
|
||||
|
||||
@GetMapping("/by-ownership")
|
||||
public ApiResponse<List<Equipment>> getEquipmentsByOwnership(@RequestParam OwnershipType ownership) {
|
||||
public ApiResponse<List<Equipment>> getEquipmentsByOwnership(
|
||||
@RequestParam OwnershipType ownership) {
|
||||
return ApiResponse.success(equipmentService.getEquipmentsByOwnership(ownership));
|
||||
}
|
||||
|
||||
|
|
@ -180,13 +180,12 @@ public class EquipmentController {
|
|||
|
||||
@GetMapping("/{id}/elevator")
|
||||
public ApiResponse<EquipmentElevator> getElevator(@PathVariable UUID id) {
|
||||
return ApiResponse.success(
|
||||
elevatorService.getByEquipmentId(id).orElse(null)
|
||||
);
|
||||
return ApiResponse.success(elevatorService.getByEquipmentId(id).orElse(null));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}/elevator")
|
||||
public ApiResponse<EquipmentElevator> updateElevator(@PathVariable UUID id, @Valid @RequestBody EquipmentElevator elevator) {
|
||||
public ApiResponse<EquipmentElevator> updateElevator(
|
||||
@PathVariable UUID id, @Valid @RequestBody EquipmentElevator elevator) {
|
||||
elevator.setEquipmentId(id);
|
||||
return ApiResponse.success(elevatorService.saveOrUpdate(elevator));
|
||||
}
|
||||
|
|
@ -195,13 +194,12 @@ public class EquipmentController {
|
|||
|
||||
@GetMapping("/{id}/hvac")
|
||||
public ApiResponse<EquipmentHvac> getHvac(@PathVariable UUID id) {
|
||||
return ApiResponse.success(
|
||||
hvacService.getByEquipmentId(id).orElse(null)
|
||||
);
|
||||
return ApiResponse.success(hvacService.getByEquipmentId(id).orElse(null));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}/hvac")
|
||||
public ApiResponse<EquipmentHvac> updateHvac(@PathVariable UUID id, @Valid @RequestBody EquipmentHvac hvac) {
|
||||
public ApiResponse<EquipmentHvac> updateHvac(
|
||||
@PathVariable UUID id, @Valid @RequestBody EquipmentHvac hvac) {
|
||||
hvac.setEquipmentId(id);
|
||||
return ApiResponse.success(hvacService.saveOrUpdate(hvac));
|
||||
}
|
||||
|
|
@ -210,13 +208,12 @@ public class EquipmentController {
|
|||
|
||||
@GetMapping("/{id}/energy")
|
||||
public ApiResponse<EquipmentEnergy> getEnergy(@PathVariable UUID id) {
|
||||
return ApiResponse.success(
|
||||
energyService.getByEquipmentId(id).orElse(null)
|
||||
);
|
||||
return ApiResponse.success(energyService.getByEquipmentId(id).orElse(null));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}/energy")
|
||||
public ApiResponse<EquipmentEnergy> updateEnergy(@PathVariable UUID id, @Valid @RequestBody EquipmentEnergy energy) {
|
||||
public ApiResponse<EquipmentEnergy> updateEnergy(
|
||||
@PathVariable UUID id, @Valid @RequestBody EquipmentEnergy energy) {
|
||||
energy.setEquipmentId(id);
|
||||
return ApiResponse.success(energyService.saveOrUpdate(energy));
|
||||
}
|
||||
|
|
@ -225,13 +222,12 @@ public class EquipmentController {
|
|||
|
||||
@GetMapping("/{id}/fire")
|
||||
public ApiResponse<EquipmentFire> getFire(@PathVariable UUID id) {
|
||||
return ApiResponse.success(
|
||||
fireService.getByEquipmentId(id).orElse(null)
|
||||
);
|
||||
return ApiResponse.success(fireService.getByEquipmentId(id).orElse(null));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}/fire")
|
||||
public ApiResponse<EquipmentFire> updateFire(@PathVariable UUID id, @Valid @RequestBody EquipmentFire fire) {
|
||||
public ApiResponse<EquipmentFire> updateFire(
|
||||
@PathVariable UUID id, @Valid @RequestBody EquipmentFire fire) {
|
||||
fire.setEquipmentId(id);
|
||||
return ApiResponse.success(fireService.saveOrUpdate(fire));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,15 +6,14 @@ import com.ether.pms.asset.service.EquipmentHealthService;
|
|||
import com.ether.pms.common.ApiResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/asset/equipment-health")
|
||||
@RequiredArgsConstructor
|
||||
|
|
@ -30,24 +29,29 @@ public class EquipmentHealthController {
|
|||
}
|
||||
|
||||
@GetMapping("/{equipmentId}/history")
|
||||
public ApiResponse<List<EquipmentHealthScore>> getHealthHistory(@PathVariable UUID equipmentId) {
|
||||
public ApiResponse<List<EquipmentHealthScore>> getHealthHistory(
|
||||
@PathVariable UUID equipmentId) {
|
||||
List<EquipmentHealthScore> history = equipmentHealthService.getHealthHistory(equipmentId);
|
||||
return ApiResponse.success("[Beta] 健康评分数据准确性待验证", history);
|
||||
}
|
||||
|
||||
@PostMapping("/calculate")
|
||||
public ApiResponse<EquipmentHealthScore> calculateHealthScore(@Valid @RequestBody CalculateHealthRequest request) {
|
||||
EquipmentHealthScore score = equipmentHealthService.calculateHealthScore(request.getEquipmentId());
|
||||
public ApiResponse<EquipmentHealthScore> calculateHealthScore(
|
||||
@Valid @RequestBody CalculateHealthRequest request) {
|
||||
EquipmentHealthScore score =
|
||||
equipmentHealthService.calculateHealthScore(request.getEquipmentId());
|
||||
return ApiResponse.success("[Beta] 健康评分数据准确性待验证", score);
|
||||
}
|
||||
|
||||
@PostMapping("/failure-history")
|
||||
public ApiResponse<EquipmentFailureHistory> recordFailure(@Valid @RequestBody EquipmentFailureHistory failure) {
|
||||
public ApiResponse<EquipmentFailureHistory> recordFailure(
|
||||
@Valid @RequestBody EquipmentFailureHistory failure) {
|
||||
return ApiResponse.success(equipmentHealthService.recordFailure(failure));
|
||||
}
|
||||
|
||||
@GetMapping("/failure-history/{equipmentId}")
|
||||
public ApiResponse<List<EquipmentFailureHistory>> getFailureHistory(@PathVariable UUID equipmentId) {
|
||||
public ApiResponse<List<EquipmentFailureHistory>> getFailureHistory(
|
||||
@PathVariable UUID equipmentId) {
|
||||
return ApiResponse.success(equipmentHealthService.getFailureHistory(equipmentId));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,13 +4,12 @@ import com.ether.pms.asset.entity.OwnershipEntity;
|
|||
import com.ether.pms.asset.repository.OwnershipEntityRepository;
|
||||
import com.ether.pms.common.ApiResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/asset/ownership-entity")
|
||||
@RequiredArgsConstructor
|
||||
|
|
@ -27,13 +26,15 @@ public class OwnershipEntityController {
|
|||
@GetMapping("/{id}")
|
||||
public ApiResponse<OwnershipEntity> getById(@PathVariable UUID id) {
|
||||
return ApiResponse.success(
|
||||
ownershipEntityRepository.findByIdAndIsDeletedFalse(id).orElse(null)
|
||||
);
|
||||
ownershipEntityRepository.findByIdAndIsDeletedFalse(id).orElse(null));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ApiResponse<OwnershipEntity> update(@PathVariable UUID id, @Valid @RequestBody OwnershipEntity entity) {
|
||||
OwnershipEntity existing = ownershipEntityRepository.findByIdAndIsDeletedFalse(id)
|
||||
public ApiResponse<OwnershipEntity> update(
|
||||
@PathVariable UUID id, @Valid @RequestBody OwnershipEntity entity) {
|
||||
OwnershipEntity existing =
|
||||
ownershipEntityRepository
|
||||
.findByIdAndIsDeletedFalse(id)
|
||||
.orElseThrow(() -> new RuntimeException("归属主体不存在: " + id));
|
||||
existing.setEntityName(entity.getEntityName());
|
||||
existing.setContactPerson(entity.getContactPerson());
|
||||
|
|
@ -51,7 +52,9 @@ public class OwnershipEntityController {
|
|||
|
||||
@DeleteMapping("/{id}")
|
||||
public ApiResponse<Void> delete(@PathVariable UUID id) {
|
||||
OwnershipEntity entity = ownershipEntityRepository.findByIdAndIsDeletedFalse(id)
|
||||
OwnershipEntity entity =
|
||||
ownershipEntityRepository
|
||||
.findByIdAndIsDeletedFalse(id)
|
||||
.orElseThrow(() -> new RuntimeException("归属主体不存在: " + id));
|
||||
entity.setIsDeleted(true);
|
||||
ownershipEntityRepository.save(entity);
|
||||
|
|
@ -59,8 +62,10 @@ public class OwnershipEntityController {
|
|||
}
|
||||
|
||||
@GetMapping("/by-type")
|
||||
public ApiResponse<List<OwnershipEntity>> getByType(@RequestParam OwnershipEntity.EntityType type) {
|
||||
return ApiResponse.success(ownershipEntityRepository.findByEntityTypeAndIsDeletedFalse(type));
|
||||
public ApiResponse<List<OwnershipEntity>> getByType(
|
||||
@RequestParam OwnershipEntity.EntityType type) {
|
||||
return ApiResponse.success(
|
||||
ownershipEntityRepository.findByEntityTypeAndIsDeletedFalse(type));
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ package com.ether.pms.asset.dto;
|
|||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class EquipmentCreateDTO {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
package com.ether.pms.asset.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class SpaceNodeDTO {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
package com.ether.pms.asset.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
|
|
|
|||
|
|
@ -5,19 +5,20 @@ import com.ether.pms.asset.enums.EquipmentType;
|
|||
import com.ether.pms.asset.enums.OwnershipType;
|
||||
import com.ether.pms.asset.enums.SystemType;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import org.hibernate.annotations.JdbcTypeCode;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
import org.hibernate.annotations.JdbcTypeCode;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
|
||||
@Entity
|
||||
@Table(name = "asset_equipment", indexes = {
|
||||
@Table(
|
||||
name = "asset_equipment",
|
||||
indexes = {
|
||||
@Index(name = "idx_equipment_project", columnList = "project_id"),
|
||||
@Index(name = "idx_equipment_space", columnList = "space_node_id"),
|
||||
@Index(name = "idx_equipment_type", columnList = "equipment_type"),
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
package com.ether.pms.asset.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
@Entity
|
||||
@Table(name = "asset_equipment_elevator")
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
package com.ether.pms.asset.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
@Entity
|
||||
@Table(name = "asset_equipment_energy")
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
package com.ether.pms.asset.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
@Entity
|
||||
@Table(name = "ops_equipment_failure_history", indexes = {
|
||||
@Table(
|
||||
name = "ops_equipment_failure_history",
|
||||
indexes = {
|
||||
@Index(name = "idx_failure_equipment", columnList = "equipment_id"),
|
||||
@Index(name = "idx_failure_time", columnList = "failure_time"),
|
||||
@Index(name = "idx_failure_project", columnList = "project_id"),
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
package com.ether.pms.asset.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
@Entity
|
||||
@Table(name = "asset_equipment_fire")
|
||||
|
|
|
|||
|
|
@ -1,17 +1,16 @@
|
|||
package com.ether.pms.asset.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 此功能为Beta版本,数据准确性待验证
|
||||
*/
|
||||
/** 此功能为Beta版本,数据准确性待验证 */
|
||||
@Entity
|
||||
@Table(name = "ops_equipment_health_score", indexes = {
|
||||
@Table(
|
||||
name = "ops_equipment_health_score",
|
||||
indexes = {
|
||||
@Index(name = "idx_health_equipment", columnList = "equipment_id"),
|
||||
@Index(name = "idx_health_calc_time", columnList = "calculated_at"),
|
||||
@Index(name = "idx_health_project", columnList = "project_id")
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
package com.ether.pms.asset.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
@Entity
|
||||
@Table(name = "asset_equipment_hvac")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
package com.ether.pms.asset.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
@Entity
|
||||
@Table(
|
||||
name = "mdm_maintenance_reminder",
|
||||
indexes = {
|
||||
@Index(name = "idx_reminder_equipment", columnList = "equipment_id"),
|
||||
@Index(name = "idx_reminder_type_date", columnList = "reminder_type, contract_end_date")
|
||||
})
|
||||
@Data
|
||||
public class MaintenanceReminder {
|
||||
|
||||
public static final String REMIND_7 = "REMIND_7";
|
||||
public static final String REMIND_3 = "REMIND_3";
|
||||
public static final String REMIND_1 = "REMIND_1";
|
||||
public static final String EXPIRED = "EXPIRED";
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private UUID id;
|
||||
|
||||
@Column(name = "equipment_id", nullable = false)
|
||||
private UUID equipmentId;
|
||||
|
||||
@Column(name = "equipment_code", length = 50)
|
||||
private String equipmentCode;
|
||||
|
||||
@Column(name = "maintenance_vendor", length = 200)
|
||||
private String maintenanceVendor;
|
||||
|
||||
@Column(name = "vendor_contact", length = 100)
|
||||
private String vendorContact;
|
||||
|
||||
@Column(name = "contract_end_date", nullable = false)
|
||||
private LocalDate contractEndDate;
|
||||
|
||||
@Column(name = "reminder_type", nullable = false, length = 20)
|
||||
private String reminderType;
|
||||
|
||||
@Column(name = "reminded_at")
|
||||
private LocalDateTime remindedAt;
|
||||
|
||||
@Column(name = "is_active")
|
||||
private Boolean isActive = true;
|
||||
|
||||
@Column(name = "created_at", nullable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
@PrePersist
|
||||
public void prePersist() {
|
||||
this.createdAt = LocalDateTime.now();
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
if (this.isActive == null) {
|
||||
this.isActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
@PreUpdate
|
||||
public void preUpdate() {
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,16 @@
|
|||
package com.ether.pms.asset.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
@Entity
|
||||
@Table(name = "asset_ownership_entity", indexes = {
|
||||
@Table(
|
||||
name = "asset_ownership_entity",
|
||||
indexes = {
|
||||
@Index(name = "idx_ownership_entity_type", columnList = "entity_type"),
|
||||
@Index(name = "idx_ownership_entity_code", columnList = "entity_code")
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,18 +1,14 @@
|
|||
package com.ether.pms.asset.enums;
|
||||
|
||||
/**
|
||||
* 商业地产8大系统分类枚举
|
||||
*/
|
||||
public enum SystemType {
|
||||
HVAC("暖通空调"),
|
||||
FIRE("消防系统"),
|
||||
FIRE_PROTECTION("消防系统"),
|
||||
ELEVATOR("电梯系统"),
|
||||
ELECTRICAL("电气系统"),
|
||||
PLUMBING("给排水"),
|
||||
BAS("弱电智能化"),
|
||||
KITCHEN("餐饮厨房"),
|
||||
SECURITY("弱电智能化"),
|
||||
LANDSCAPE("景观"),
|
||||
OTHER("其他");
|
||||
ENERGY_METER("能源计量");
|
||||
|
||||
private final String description;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
package com.ether.pms.asset.event;
|
||||
|
||||
import com.ether.pms.asset.entity.EquipmentFailureHistory;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import lombok.Getter;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
@Getter
|
||||
public class EquipmentFailureRecordedEvent extends ApplicationEvent {
|
||||
|
||||
private final UUID equipmentId;
|
||||
private final UUID failureHistoryId;
|
||||
private final UUID projectId;
|
||||
private final String equipmentCode;
|
||||
private final String equipmentName;
|
||||
private final String faultType;
|
||||
private final String faultLevel;
|
||||
private final String failureReason;
|
||||
private final String failureDescription;
|
||||
private final LocalDateTime occurredAt;
|
||||
private final LocalDateTime createdAt;
|
||||
|
||||
public EquipmentFailureRecordedEvent(Object source, EquipmentFailureHistory failure) {
|
||||
super(source);
|
||||
this.equipmentId = failure.getEquipmentId();
|
||||
this.failureHistoryId = failure.getId();
|
||||
this.projectId = failure.getProjectId();
|
||||
this.equipmentCode = failure.getEquipmentCode();
|
||||
this.equipmentName = failure.getEquipmentName();
|
||||
this.faultType = failure.getFailureType() != null ? failure.getFailureType().name() : null;
|
||||
this.faultLevel =
|
||||
failure.getFailureLevel() != null ? failure.getFailureLevel().name() : null;
|
||||
this.failureReason = failure.getFailureReason();
|
||||
this.failureDescription = failure.getFailureDescription();
|
||||
this.occurredAt = failure.getFailureTime();
|
||||
this.createdAt = failure.getCreatedAt();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
package com.ether.pms.asset.repository;
|
||||
|
||||
import com.ether.pms.asset.entity.EquipmentElevator;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface EquipmentElevatorRepository extends JpaRepository<EquipmentElevator, UUID> {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
package com.ether.pms.asset.repository;
|
||||
|
||||
import com.ether.pms.asset.entity.EquipmentEnergy;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface EquipmentEnergyRepository extends JpaRepository<EquipmentEnergy, UUID> {
|
||||
|
|
|
|||
|
|
@ -1,28 +1,35 @@
|
|||
package com.ether.pms.asset.repository;
|
||||
|
||||
import com.ether.pms.asset.entity.EquipmentFailureHistory;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Repository
|
||||
public interface EquipmentFailureHistoryRepository extends JpaRepository<EquipmentFailureHistory, UUID> {
|
||||
public interface EquipmentFailureHistoryRepository
|
||||
extends JpaRepository<EquipmentFailureHistory, UUID> {
|
||||
|
||||
List<EquipmentFailureHistory> findByEquipmentIdOrderByFailureTimeDesc(UUID equipmentId);
|
||||
|
||||
List<EquipmentFailureHistory> findByProjectIdAndFailureTimeBetweenOrderByFailureTimeDesc(
|
||||
UUID projectId, LocalDateTime startTime, LocalDateTime endTime);
|
||||
|
||||
@Query("SELECT f FROM EquipmentFailureHistory f WHERE f.equipmentId = :equipmentId AND f.failureTime >= :since ORDER BY f.failureTime DESC")
|
||||
List<EquipmentFailureHistory> findByEquipmentIdSince(@Param("equipmentId") UUID equipmentId, @Param("since") LocalDateTime since);
|
||||
@Query(
|
||||
"SELECT f FROM EquipmentFailureHistory f WHERE f.equipmentId = :equipmentId AND f.failureTime >= :since ORDER BY f.failureTime DESC")
|
||||
List<EquipmentFailureHistory> findByEquipmentIdSince(
|
||||
@Param("equipmentId") UUID equipmentId, @Param("since") LocalDateTime since);
|
||||
|
||||
@Query("SELECT COUNT(f) FROM EquipmentFailureHistory f WHERE f.equipmentId = :equipmentId AND f.failureTime >= :since")
|
||||
long countByEquipmentIdSince(@Param("equipmentId") UUID equipmentId, @Param("since") LocalDateTime since);
|
||||
@Query(
|
||||
"SELECT COUNT(f) FROM EquipmentFailureHistory f WHERE f.equipmentId = :equipmentId AND f.failureTime >= :since")
|
||||
long countByEquipmentIdSince(
|
||||
@Param("equipmentId") UUID equipmentId, @Param("since") LocalDateTime since);
|
||||
|
||||
@Query("SELECT f FROM EquipmentFailureHistory f WHERE f.equipmentId = :equipmentId AND f.repairEndTime IS NOT NULL AND f.failureTime >= :since ORDER BY f.failureTime DESC")
|
||||
List<EquipmentFailureHistory> findRepairedFailuresByEquipmentIdSince(@Param("equipmentId") UUID equipmentId, @Param("since") LocalDateTime since);
|
||||
@Query(
|
||||
"SELECT f FROM EquipmentFailureHistory f WHERE f.equipmentId = :equipmentId AND f.repairEndTime IS NOT NULL AND f.failureTime >= :since ORDER BY f.failureTime DESC")
|
||||
List<EquipmentFailureHistory> findRepairedFailuresByEquipmentIdSince(
|
||||
@Param("equipmentId") UUID equipmentId, @Param("since") LocalDateTime since);
|
||||
}
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
package com.ether.pms.asset.repository;
|
||||
|
||||
import com.ether.pms.asset.entity.EquipmentFire;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface EquipmentFireRepository extends JpaRepository<EquipmentFire, UUID> {
|
||||
|
|
|
|||
|
|
@ -1,29 +1,37 @@
|
|||
package com.ether.pms.asset.repository;
|
||||
|
||||
import com.ether.pms.asset.entity.EquipmentHealthScore;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface EquipmentHealthScoreRepository extends JpaRepository<EquipmentHealthScore, UUID> {
|
||||
|
||||
List<EquipmentHealthScore> findByEquipmentIdOrderByCalculatedAtDesc(UUID equipmentId);
|
||||
|
||||
@Query("SELECT h FROM EquipmentHealthScore h WHERE h.equipmentId = :equipmentId ORDER BY h.calculatedAt DESC LIMIT 1")
|
||||
@Query(
|
||||
"SELECT h FROM EquipmentHealthScore h WHERE h.equipmentId = :equipmentId ORDER BY h.calculatedAt DESC LIMIT 1")
|
||||
Optional<EquipmentHealthScore> findLatestByEquipmentId(@Param("equipmentId") UUID equipmentId);
|
||||
|
||||
@Query("SELECT h FROM EquipmentHealthScore h WHERE h.equipmentId = :equipmentId AND h.calculatedAt >= :since ORDER BY h.calculatedAt DESC")
|
||||
List<EquipmentHealthScore> findByEquipmentIdSince(@Param("equipmentId") UUID equipmentId, @Param("since") LocalDateTime since);
|
||||
@Query(
|
||||
"SELECT h FROM EquipmentHealthScore h WHERE h.equipmentId = :equipmentId AND h.calculatedAt >= :since ORDER BY h.calculatedAt DESC")
|
||||
List<EquipmentHealthScore> findByEquipmentIdSince(
|
||||
@Param("equipmentId") UUID equipmentId, @Param("since") LocalDateTime since);
|
||||
|
||||
@Query("SELECT h FROM EquipmentHealthScore h WHERE h.projectId = :projectId ORDER BY h.calculatedAt DESC")
|
||||
List<EquipmentHealthScore> findByProjectIdOrderByCalculatedAtDesc(@Param("projectId") UUID projectId);
|
||||
@Query(
|
||||
"SELECT h FROM EquipmentHealthScore h WHERE h.projectId = :projectId ORDER BY h.calculatedAt DESC")
|
||||
List<EquipmentHealthScore> findByProjectIdOrderByCalculatedAtDesc(
|
||||
@Param("projectId") UUID projectId);
|
||||
|
||||
@Query("SELECT h FROM EquipmentHealthScore h WHERE h.projectId = :projectId AND h.healthLevel IN :levels ORDER BY h.healthScore ASC")
|
||||
List<EquipmentHealthScore> findByProjectIdAndHealthLevelIn(@Param("projectId") UUID projectId, @Param("levels") List<EquipmentHealthScore.HealthLevel> levels);
|
||||
@Query(
|
||||
"SELECT h FROM EquipmentHealthScore h WHERE h.projectId = :projectId AND h.healthLevel IN :levels ORDER BY h.healthScore ASC")
|
||||
List<EquipmentHealthScore> findByProjectIdAndHealthLevelIn(
|
||||
@Param("projectId") UUID projectId,
|
||||
@Param("levels") List<EquipmentHealthScore.HealthLevel> levels);
|
||||
}
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
package com.ether.pms.asset.repository;
|
||||
|
||||
import com.ether.pms.asset.entity.EquipmentHvac;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface EquipmentHvacRepository extends JpaRepository<EquipmentHvac, UUID> {
|
||||
|
|
|
|||
|
|
@ -4,21 +4,22 @@ import com.ether.pms.asset.entity.Equipment;
|
|||
import com.ether.pms.asset.enums.EquipmentStatus;
|
||||
import com.ether.pms.asset.enums.EquipmentType;
|
||||
import com.ether.pms.asset.enums.OwnershipType;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@Repository
|
||||
public interface EquipmentRepository extends JpaRepository<Equipment, UUID> {
|
||||
|
||||
List<Equipment> findByProjectIdAndIsDeletedFalse(UUID projectId);
|
||||
|
||||
List<Equipment> findByProjectIdAndStatusAndIsDeletedFalse(UUID projectId, EquipmentStatus status);
|
||||
List<Equipment> findByProjectIdAndStatusAndIsDeletedFalse(
|
||||
UUID projectId, EquipmentStatus status);
|
||||
|
||||
List<Equipment> findBySpaceNodeIdAndIsDeletedFalse(UUID spaceNodeId);
|
||||
|
||||
|
|
@ -38,12 +39,20 @@ public interface EquipmentRepository extends JpaRepository<Equipment, UUID> {
|
|||
@Query("SELECT e FROM Equipment e WHERE e.spaceNodeId = :spaceNodeId AND e.isDeleted = false")
|
||||
List<Equipment> findBySpaceNode(@Param("spaceNodeId") UUID spaceNodeId);
|
||||
|
||||
@Query("SELECT COUNT(e) FROM Equipment e WHERE e.projectId = :projectId AND e.isDeleted = false")
|
||||
@Query(
|
||||
"SELECT COUNT(e) FROM Equipment e WHERE e.projectId = :projectId AND e.isDeleted = false")
|
||||
long countByProject(@Param("projectId") UUID projectId);
|
||||
|
||||
@Query("SELECT e.equipmentType, COUNT(e) FROM Equipment e WHERE e.projectId = :projectId AND e.isDeleted = false GROUP BY e.equipmentType")
|
||||
@Query(
|
||||
"SELECT e.equipmentType, COUNT(e) FROM Equipment e WHERE e.projectId = :projectId AND e.isDeleted = false GROUP BY e.equipmentType")
|
||||
List<Object[]> countByType(@Param("projectId") UUID projectId);
|
||||
|
||||
@Query("SELECT e.ownershipType, COUNT(e) FROM Equipment e WHERE e.projectId = :projectId AND e.isDeleted = false GROUP BY e.ownershipType")
|
||||
@Query(
|
||||
"SELECT e.ownershipType, COUNT(e) FROM Equipment e WHERE e.projectId = :projectId AND e.isDeleted = false GROUP BY e.ownershipType")
|
||||
List<Object[]> countByOwnership(@Param("projectId") UUID projectId);
|
||||
|
||||
@Query(
|
||||
"SELECT e FROM Equipment e WHERE e.maintenanceContractEnd >= :startDate AND e.maintenanceContractEnd <= :endDate AND e.isDeleted = false AND e.maintenanceContractEnd IS NOT NULL")
|
||||
List<Equipment> findByMaintenanceContractEndBetween(
|
||||
@Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate);
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.ether.pms.asset.repository;
|
||||
|
||||
import com.ether.pms.asset.entity.MaintenanceReminder;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface MaintenanceReminderRepository extends JpaRepository<MaintenanceReminder, UUID> {
|
||||
|
||||
Optional<MaintenanceReminder> findByEquipmentIdAndReminderTypeAndContractEndDate(
|
||||
UUID equipmentId, String reminderType, LocalDate contractEndDate);
|
||||
|
||||
@Query(
|
||||
"SELECT r FROM MaintenanceReminder r WHERE r.equipmentId = :equipmentId AND r.reminderType = :reminderType AND r.isActive = true")
|
||||
List<MaintenanceReminder> findActiveByEquipmentIdAndReminderType(
|
||||
@Param("equipmentId") UUID equipmentId, @Param("reminderType") String reminderType);
|
||||
|
||||
@Query(
|
||||
"SELECT CASE WHEN COUNT(r) > 0 THEN true ELSE false END FROM MaintenanceReminder r WHERE r.equipmentId = :equipmentId AND r.reminderType = :reminderType")
|
||||
boolean existsByEquipmentIdAndReminderType(
|
||||
@Param("equipmentId") UUID equipmentId, @Param("reminderType") String reminderType);
|
||||
|
||||
List<MaintenanceReminder> findByEquipmentIdAndIsActiveTrue(UUID equipmentId);
|
||||
|
||||
@Query(
|
||||
"SELECT r FROM MaintenanceReminder r WHERE r.contractEndDate <= :date AND r.isActive = true")
|
||||
List<MaintenanceReminder> findExpiredReminders(@Param("date") LocalDate date);
|
||||
}
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
package com.ether.pms.asset.repository;
|
||||
|
||||
import com.ether.pms.asset.entity.OwnershipEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface OwnershipEntityRepository extends JpaRepository<OwnershipEntity, UUID> {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,115 @@
|
|||
package com.ether.pms.asset.scheduler;
|
||||
|
||||
import com.ether.pms.asset.entity.Equipment;
|
||||
import com.ether.pms.asset.entity.MaintenanceReminder;
|
||||
import com.ether.pms.asset.repository.EquipmentRepository;
|
||||
import com.ether.pms.asset.repository.MaintenanceReminderRepository;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class MaintenanceReminderScheduler {
|
||||
|
||||
private final MaintenanceReminderRepository reminderRepository;
|
||||
private final EquipmentRepository equipmentRepository;
|
||||
|
||||
@Scheduled(cron = "0 0 9 * * ?")
|
||||
@Transactional
|
||||
public void checkMaintenanceExpiry() {
|
||||
log.info("开始执行维保到期提醒任务...");
|
||||
|
||||
try {
|
||||
LocalDate today = LocalDate.now();
|
||||
|
||||
List<Equipment> expiringEquipments =
|
||||
equipmentRepository.findByMaintenanceContractEndBetween(
|
||||
today, today.plusDays(7));
|
||||
|
||||
int reminderCount = 0;
|
||||
|
||||
for (Equipment equipment : expiringEquipments) {
|
||||
LocalDate endDate = equipment.getMaintenanceContractEnd();
|
||||
String reminderType = determineReminderType(today, endDate);
|
||||
|
||||
if (!hasReminder(equipment.getId(), reminderType)) {
|
||||
sendReminder(equipment, reminderType);
|
||||
saveReminder(equipment, reminderType);
|
||||
reminderCount++;
|
||||
}
|
||||
}
|
||||
|
||||
log.info("维保到期提醒任务完成,共发送 {} 条提醒", reminderCount);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("维保到期提醒任务失败: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private String determineReminderType(LocalDate today, LocalDate endDate) {
|
||||
long daysBetween = Duration.between(today.atStartOfDay(), endDate.atStartOfDay()).toDays();
|
||||
|
||||
if (daysBetween <= 0) {
|
||||
return MaintenanceReminder.EXPIRED;
|
||||
} else if (daysBetween <= 1) {
|
||||
return MaintenanceReminder.REMIND_1;
|
||||
} else if (daysBetween <= 3) {
|
||||
return MaintenanceReminder.REMIND_3;
|
||||
} else {
|
||||
return MaintenanceReminder.REMIND_7;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasReminder(java.util.UUID equipmentId, String reminderType) {
|
||||
return reminderRepository.existsByEquipmentIdAndReminderType(equipmentId, reminderType);
|
||||
}
|
||||
|
||||
private void sendReminder(Equipment equipment, String reminderType) {
|
||||
String reminderDesc = getReminderDescription(reminderType);
|
||||
log.info(
|
||||
"维保到期提醒: 设备[{}]的维保合同将在{}到期,提醒类型: {}",
|
||||
equipment.getEquipmentCode(),
|
||||
equipment.getMaintenanceContractEnd(),
|
||||
reminderDesc);
|
||||
|
||||
// TODO: 后续对接消息通知系统,发送实际通知
|
||||
// 可以通过以下方式发送:
|
||||
// 1. 邮件通知维保负责人
|
||||
// 2. 站内消息通知
|
||||
// 3. 短信通知
|
||||
// 4. 企业微信/钉钉机器人通知
|
||||
}
|
||||
|
||||
private String getReminderDescription(String reminderType) {
|
||||
return switch (reminderType) {
|
||||
case MaintenanceReminder.REMIND_7 -> "7天前提醒";
|
||||
case MaintenanceReminder.REMIND_3 -> "3天前提醒";
|
||||
case MaintenanceReminder.REMIND_1 -> "1天前提醒";
|
||||
case MaintenanceReminder.EXPIRED -> "已到期";
|
||||
default -> "未知提醒";
|
||||
};
|
||||
}
|
||||
|
||||
private void saveReminder(Equipment equipment, String reminderType) {
|
||||
MaintenanceReminder reminder = new MaintenanceReminder();
|
||||
reminder.setEquipmentId(equipment.getId());
|
||||
reminder.setEquipmentCode(equipment.getEquipmentCode());
|
||||
reminder.setMaintenanceVendor(equipment.getMaintenanceVendor());
|
||||
reminder.setVendorContact(equipment.getMaintenanceVendorContact());
|
||||
reminder.setContractEndDate(equipment.getMaintenanceContractEnd());
|
||||
reminder.setReminderType(reminderType);
|
||||
reminder.setRemindedAt(LocalDateTime.now());
|
||||
reminder.setIsActive(true);
|
||||
|
||||
reminderRepository.save(reminder);
|
||||
log.debug("保存维保提醒记录: 设备[{}], 类型[{}]", equipment.getEquipmentCode(), reminderType);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.ether.pms.asset.service;
|
||||
|
||||
import com.ether.pms.asset.entity.EquipmentElevator;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.ether.pms.asset.service;
|
||||
|
||||
import com.ether.pms.asset.entity.EquipmentEnergy;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.ether.pms.asset.service;
|
||||
|
||||
import com.ether.pms.asset.entity.EquipmentFire;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,44 +9,26 @@ import java.util.UUID;
|
|||
public interface EquipmentHealthService {
|
||||
|
||||
/**
|
||||
* 计算设备健康度
|
||||
* 基础分 = 100
|
||||
* 故障率扣分 = 故障次数 × 5(近30天每故障扣5分)
|
||||
* 维保扣分 = (1 - 维保完成率) × 20
|
||||
* 年龄扣分 = 投入使用年限 × 2(最高扣10分)
|
||||
* 健康度 = 基础分 - 故障率扣分 - 维保扣分 - 年龄扣分
|
||||
* 计算设备健康度 基础分 = 100 故障率扣分 = 故障次数 × 5(近30天每故障扣5分) 维保扣分 = (1 - 维保完成率) × 20 年龄扣分 = 投入使用年限 ×
|
||||
* 2(最高扣10分) 健康度 = 基础分 - 故障率扣分 - 维保扣分 - 年龄扣分
|
||||
*/
|
||||
EquipmentHealthScore calculateHealthScore(UUID equipmentId);
|
||||
|
||||
/**
|
||||
* 计算平均故障间隔时间 (MTBF)
|
||||
* MTBF = 运行时间 / 故障次数
|
||||
*/
|
||||
/** 计算平均故障间隔时间 (MTBF) MTBF = 运行时间 / 故障次数 */
|
||||
BigDecimal calculateMTBF(UUID equipmentId, Integer days);
|
||||
|
||||
/**
|
||||
* 计算平均修复时间 (MTTR)
|
||||
* MTTR = 总修复时间 / 修复次数
|
||||
*/
|
||||
/** 计算平均修复时间 (MTTR) MTTR = 总修复时间 / 修复次数 */
|
||||
BigDecimal calculateMTTR(UUID equipmentId, Integer days);
|
||||
|
||||
/**
|
||||
* 记录故障
|
||||
*/
|
||||
/** 记录故障 */
|
||||
EquipmentFailureHistory recordFailure(EquipmentFailureHistory failure);
|
||||
|
||||
/**
|
||||
* 获取设备健康度历史
|
||||
*/
|
||||
/** 获取设备健康度历史 */
|
||||
List<EquipmentHealthScore> getHealthHistory(UUID equipmentId);
|
||||
|
||||
/**
|
||||
* 获取设备最新健康度
|
||||
*/
|
||||
/** 获取设备最新健康度 */
|
||||
EquipmentHealthScore getLatestHealthScore(UUID equipmentId);
|
||||
|
||||
/**
|
||||
* 获取设备的故障历史
|
||||
*/
|
||||
/** 获取设备的故障历史 */
|
||||
List<EquipmentFailureHistory> getFailureHistory(UUID equipmentId);
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.ether.pms.asset.service;
|
||||
|
||||
import com.ether.pms.asset.entity.EquipmentHvac;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,10 @@ package com.ether.pms.asset.service;
|
|||
import com.ether.pms.asset.entity.Equipment;
|
||||
import com.ether.pms.asset.enums.EquipmentType;
|
||||
import com.ether.pms.asset.enums.OwnershipType;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
public interface EquipmentService {
|
||||
|
||||
|
|
|
|||
|
|
@ -3,13 +3,12 @@ package com.ether.pms.asset.service.impl;
|
|||
import com.ether.pms.asset.entity.EquipmentElevator;
|
||||
import com.ether.pms.asset.repository.EquipmentElevatorRepository;
|
||||
import com.ether.pms.asset.service.EquipmentElevatorService;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class EquipmentElevatorServiceImpl implements EquipmentElevatorService {
|
||||
|
|
@ -19,7 +18,8 @@ public class EquipmentElevatorServiceImpl implements EquipmentElevatorService {
|
|||
@Override
|
||||
@Transactional
|
||||
public EquipmentElevator saveOrUpdate(EquipmentElevator elevator) {
|
||||
Optional<EquipmentElevator> existing = elevatorRepository.findByEquipmentId(elevator.getEquipmentId());
|
||||
Optional<EquipmentElevator> existing =
|
||||
elevatorRepository.findByEquipmentId(elevator.getEquipmentId());
|
||||
if (existing.isPresent()) {
|
||||
elevator.setId(existing.get().getId());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,12 @@ package com.ether.pms.asset.service.impl;
|
|||
import com.ether.pms.asset.entity.EquipmentEnergy;
|
||||
import com.ether.pms.asset.repository.EquipmentEnergyRepository;
|
||||
import com.ether.pms.asset.service.EquipmentEnergyService;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class EquipmentEnergyServiceImpl implements EquipmentEnergyService {
|
||||
|
|
@ -19,7 +18,8 @@ public class EquipmentEnergyServiceImpl implements EquipmentEnergyService {
|
|||
@Override
|
||||
@Transactional
|
||||
public EquipmentEnergy saveOrUpdate(EquipmentEnergy energy) {
|
||||
Optional<EquipmentEnergy> existing = energyRepository.findByEquipmentId(energy.getEquipmentId());
|
||||
Optional<EquipmentEnergy> existing =
|
||||
energyRepository.findByEquipmentId(energy.getEquipmentId());
|
||||
if (existing.isPresent()) {
|
||||
energy.setId(existing.get().getId());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,12 @@ package com.ether.pms.asset.service.impl;
|
|||
import com.ether.pms.asset.entity.EquipmentFire;
|
||||
import com.ether.pms.asset.repository.EquipmentFireRepository;
|
||||
import com.ether.pms.asset.service.EquipmentFireService;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class EquipmentFireServiceImpl implements EquipmentFireService {
|
||||
|
|
|
|||
|
|
@ -1,18 +1,15 @@
|
|||
package com.ether.pms.asset.service.impl;
|
||||
|
||||
import com.ether.pms.common.BusinessException;
|
||||
import com.ether.pms.asset.entity.Equipment;
|
||||
import com.ether.pms.asset.entity.EquipmentFailureHistory;
|
||||
import com.ether.pms.asset.entity.EquipmentHealthScore;
|
||||
import com.ether.pms.asset.event.EquipmentFailureRecordedEvent;
|
||||
import com.ether.pms.asset.repository.EquipmentFailureHistoryRepository;
|
||||
import com.ether.pms.asset.repository.EquipmentHealthScoreRepository;
|
||||
import com.ether.pms.asset.repository.EquipmentRepository;
|
||||
import com.ether.pms.asset.service.EquipmentHealthService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.ether.pms.common.BusinessException;
|
||||
import com.ether.pms.common.MaintenanceTaskRepository;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
|
|
@ -21,6 +18,11 @@ import java.time.Period;
|
|||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
|
|
@ -30,8 +32,8 @@ public class EquipmentHealthServiceImpl implements EquipmentHealthService {
|
|||
private final EquipmentFailureHistoryRepository failureHistoryRepository;
|
||||
private final EquipmentHealthScoreRepository healthScoreRepository;
|
||||
private final EquipmentRepository equipmentRepository;
|
||||
// TODO: 需要改为从 ops 模块查询工单数据
|
||||
// private final MaintenanceTaskRepository maintenanceTaskRepository;
|
||||
private final MaintenanceTaskRepository maintenanceTaskRepository;
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
|
||||
private static final BigDecimal BASE_SCORE = new BigDecimal("100");
|
||||
private static final BigDecimal FAILURE_DEDUCTION_PER_COUNT = new BigDecimal("5");
|
||||
|
|
@ -43,20 +45,23 @@ public class EquipmentHealthServiceImpl implements EquipmentHealthService {
|
|||
@Override
|
||||
@Transactional
|
||||
public EquipmentHealthScore calculateHealthScore(UUID equipmentId) {
|
||||
Equipment equipment = equipmentRepository.findByIdAndIsDeletedFalse(equipmentId)
|
||||
Equipment equipment =
|
||||
equipmentRepository
|
||||
.findByIdAndIsDeletedFalse(equipmentId)
|
||||
.orElseThrow(() -> new BusinessException(6001, "设备不存在"));
|
||||
|
||||
// 获取近30天故障次数
|
||||
LocalDateTime thirtyDaysAgo = LocalDateTime.now().minusDays(30);
|
||||
long failureCount30d = failureHistoryRepository.countByEquipmentIdSince(equipmentId, thirtyDaysAgo);
|
||||
long failureCount30d =
|
||||
failureHistoryRepository.countByEquipmentIdSince(equipmentId, thirtyDaysAgo);
|
||||
|
||||
// 计算故障率扣分
|
||||
BigDecimal failureDeduction = FAILURE_DEDUCTION_PER_COUNT.multiply(BigDecimal.valueOf(failureCount30d));
|
||||
BigDecimal failureDeduction =
|
||||
FAILURE_DEDUCTION_PER_COUNT.multiply(BigDecimal.valueOf(failureCount30d));
|
||||
|
||||
// TODO: 从 ops 模块查询工单数据计算维保完成率
|
||||
// 暂时跳过维保完成率计算
|
||||
BigDecimal maintenanceCompletionRate = BigDecimal.ONE;
|
||||
BigDecimal maintenanceDeduction = BigDecimal.ZERO;
|
||||
// 计算维保完成率
|
||||
BigDecimal maintenanceCompletionRate = calculateMaintenanceCompletionRate(equipmentId);
|
||||
BigDecimal maintenanceDeduction = calculateMaintenanceDeduction(maintenanceCompletionRate);
|
||||
|
||||
// 计算年龄扣分
|
||||
BigDecimal equipmentAgeYears = calculateEquipmentAge(equipment);
|
||||
|
|
@ -66,7 +71,8 @@ public class EquipmentHealthServiceImpl implements EquipmentHealthService {
|
|||
}
|
||||
|
||||
// 计算健康度
|
||||
BigDecimal healthScore = BASE_SCORE
|
||||
BigDecimal healthScore =
|
||||
BASE_SCORE
|
||||
.subtract(failureDeduction)
|
||||
.subtract(maintenanceDeduction)
|
||||
.subtract(ageDeduction);
|
||||
|
|
@ -90,7 +96,8 @@ public class EquipmentHealthServiceImpl implements EquipmentHealthService {
|
|||
health.setMaintenanceDeduction(maintenanceDeduction.setScale(2, RoundingMode.HALF_UP));
|
||||
health.setAgeDeduction(ageDeduction.setScale(2, RoundingMode.HALF_UP));
|
||||
health.setFailureCount30d((int) failureCount30d);
|
||||
health.setMaintenanceCompletionRate(maintenanceCompletionRate.setScale(4, RoundingMode.HALF_UP));
|
||||
health.setMaintenanceCompletionRate(
|
||||
maintenanceCompletionRate.setScale(4, RoundingMode.HALF_UP));
|
||||
health.setEquipmentAgeYears(equipmentAgeYears.setScale(2, RoundingMode.HALF_UP));
|
||||
health.setMtbfHours(mtbf != null ? mtbf : BigDecimal.ZERO);
|
||||
health.setMttrHours(mttr != null ? mttr : BigDecimal.ZERO);
|
||||
|
|
@ -108,7 +115,8 @@ public class EquipmentHealthServiceImpl implements EquipmentHealthService {
|
|||
}
|
||||
|
||||
LocalDateTime since = LocalDateTime.now().minusDays(days);
|
||||
List<EquipmentFailureHistory> failures = failureHistoryRepository.findByEquipmentIdSince(equipmentId, since);
|
||||
List<EquipmentFailureHistory> failures =
|
||||
failureHistoryRepository.findByEquipmentIdSince(equipmentId, since);
|
||||
|
||||
if (failures.isEmpty()) {
|
||||
return BigDecimal.ZERO;
|
||||
|
|
@ -126,7 +134,8 @@ public class EquipmentHealthServiceImpl implements EquipmentHealthService {
|
|||
}
|
||||
|
||||
// MTBF = 运行时间 / 故障次数
|
||||
BigDecimal mtbf = BigDecimal.valueOf(totalHours)
|
||||
BigDecimal mtbf =
|
||||
BigDecimal.valueOf(totalHours)
|
||||
.divide(BigDecimal.valueOf(failures.size()), 2, RoundingMode.HALF_UP);
|
||||
|
||||
return mtbf;
|
||||
|
|
@ -139,22 +148,27 @@ public class EquipmentHealthServiceImpl implements EquipmentHealthService {
|
|||
}
|
||||
|
||||
LocalDateTime since = LocalDateTime.now().minusDays(days);
|
||||
List<EquipmentFailureHistory> repairedFailures = failureHistoryRepository
|
||||
.findRepairedFailuresByEquipmentIdSince(equipmentId, since);
|
||||
List<EquipmentFailureHistory> repairedFailures =
|
||||
failureHistoryRepository.findRepairedFailuresByEquipmentIdSince(equipmentId, since);
|
||||
|
||||
if (repairedFailures.isEmpty()) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
// 计算总修复时间
|
||||
double totalRepairHours = repairedFailures.stream()
|
||||
double totalRepairHours =
|
||||
repairedFailures.stream()
|
||||
.filter(f -> f.getRepairDurationHours() != null)
|
||||
.mapToDouble(EquipmentFailureHistory::getRepairDurationHours)
|
||||
.sum();
|
||||
|
||||
// MTTR = 总修复时间 / 修复次数
|
||||
BigDecimal mttr = BigDecimal.valueOf(totalRepairHours)
|
||||
.divide(BigDecimal.valueOf(repairedFailures.size()), 2, RoundingMode.HALF_UP);
|
||||
BigDecimal mttr =
|
||||
BigDecimal.valueOf(totalRepairHours)
|
||||
.divide(
|
||||
BigDecimal.valueOf(repairedFailures.size()),
|
||||
2,
|
||||
RoundingMode.HALF_UP);
|
||||
|
||||
return mttr;
|
||||
}
|
||||
|
|
@ -162,34 +176,44 @@ public class EquipmentHealthServiceImpl implements EquipmentHealthService {
|
|||
@Override
|
||||
@Transactional
|
||||
public EquipmentFailureHistory recordFailure(EquipmentFailureHistory failure) {
|
||||
// 校验设备存在
|
||||
Equipment equipment = equipmentRepository.findByIdAndIsDeletedFalse(failure.getEquipmentId())
|
||||
Equipment equipment =
|
||||
equipmentRepository
|
||||
.findByIdAndIsDeletedFalse(failure.getEquipmentId())
|
||||
.orElseThrow(() -> new BusinessException(6001, "设备不存在"));
|
||||
|
||||
// 设置项目ID
|
||||
if (failure.getProjectId() == null) {
|
||||
failure.setProjectId(equipment.getProjectId());
|
||||
}
|
||||
|
||||
// 设置设备信息
|
||||
if (failure.getEquipmentName() == null) {
|
||||
failure.setEquipmentName(equipment.getEquipmentName());
|
||||
}
|
||||
|
||||
// 计算修复时长
|
||||
if (failure.getRepairStartTime() != null && failure.getRepairEndTime() != null) {
|
||||
long minutes = ChronoUnit.MINUTES.between(failure.getRepairStartTime(), failure.getRepairEndTime());
|
||||
long minutes =
|
||||
ChronoUnit.MINUTES.between(
|
||||
failure.getRepairStartTime(), failure.getRepairEndTime());
|
||||
double hours = minutes / 60.0;
|
||||
failure.setRepairDurationHours(hours);
|
||||
|
||||
// 计算停机时长(如果故障时间和修复开始时间不同)
|
||||
if (failure.getFailureTime() != null && failure.getRepairStartTime().isAfter(failure.getFailureTime())) {
|
||||
long downtimeMinutes = ChronoUnit.MINUTES.between(failure.getFailureTime(), failure.getRepairStartTime());
|
||||
if (failure.getFailureTime() != null
|
||||
&& failure.getRepairStartTime().isAfter(failure.getFailureTime())) {
|
||||
long downtimeMinutes =
|
||||
ChronoUnit.MINUTES.between(
|
||||
failure.getFailureTime(), failure.getRepairStartTime());
|
||||
failure.setDowntimeHours(downtimeMinutes / 60.0);
|
||||
}
|
||||
}
|
||||
|
||||
return failureHistoryRepository.save(failure);
|
||||
EquipmentFailureHistory savedFailure = failureHistoryRepository.save(failure);
|
||||
|
||||
eventPublisher.publishEvent(new EquipmentFailureRecordedEvent(this, savedFailure));
|
||||
log.info(
|
||||
"发布设备故障记录事件: equipmentId={}, failureHistoryId={}",
|
||||
savedFailure.getEquipmentId(),
|
||||
savedFailure.getId());
|
||||
|
||||
return savedFailure;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -199,7 +223,8 @@ public class EquipmentHealthServiceImpl implements EquipmentHealthService {
|
|||
|
||||
@Override
|
||||
public EquipmentHealthScore getLatestHealthScore(UUID equipmentId) {
|
||||
return healthScoreRepository.findLatestByEquipmentId(equipmentId)
|
||||
return healthScoreRepository
|
||||
.findLatestByEquipmentId(equipmentId)
|
||||
.orElseThrow(() -> new BusinessException(6003, "没有健康度记录"));
|
||||
}
|
||||
|
||||
|
|
@ -208,9 +233,7 @@ public class EquipmentHealthServiceImpl implements EquipmentHealthService {
|
|||
return failureHistoryRepository.findByEquipmentIdOrderByFailureTimeDesc(equipmentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算设备年龄(年)
|
||||
*/
|
||||
/** 计算设备年龄(年) */
|
||||
private BigDecimal calculateEquipmentAge(Equipment equipment) {
|
||||
LocalDate installationDate = equipment.getInstallationDate();
|
||||
if (installationDate == null) {
|
||||
|
|
@ -226,6 +249,35 @@ public class EquipmentHealthServiceImpl implements EquipmentHealthService {
|
|||
int years = period.getYears();
|
||||
int months = period.getMonths();
|
||||
|
||||
return BigDecimal.valueOf(years).add(BigDecimal.valueOf(months).divide(BigDecimal.valueOf(12), 2, RoundingMode.HALF_UP));
|
||||
return BigDecimal.valueOf(years)
|
||||
.add(
|
||||
BigDecimal.valueOf(months)
|
||||
.divide(BigDecimal.valueOf(12), 2, RoundingMode.HALF_UP));
|
||||
}
|
||||
|
||||
/** 计算维保完成率 */
|
||||
private BigDecimal calculateMaintenanceCompletionRate(UUID equipmentId) {
|
||||
List<MaintenanceTaskRepository.MaintenanceTaskInfo> tasks =
|
||||
maintenanceTaskRepository.findByEquipmentId(equipmentId);
|
||||
|
||||
if (tasks.isEmpty()) {
|
||||
return BigDecimal.ONE;
|
||||
}
|
||||
|
||||
long completedCount =
|
||||
tasks.stream()
|
||||
.filter(
|
||||
task ->
|
||||
"COMPLETED".equals(task.status())
|
||||
|| "VERIFIED".equals(task.status()))
|
||||
.count();
|
||||
|
||||
return BigDecimal.valueOf(completedCount)
|
||||
.divide(BigDecimal.valueOf(tasks.size()), 4, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
/** 根据维保完成率计算扣分 */
|
||||
private BigDecimal calculateMaintenanceDeduction(BigDecimal completionRate) {
|
||||
return MAINTENANCE_DEDUCTION_FACTOR.multiply(BigDecimal.ONE.subtract(completionRate));
|
||||
}
|
||||
}
|
||||
|
|
@ -3,13 +3,12 @@ package com.ether.pms.asset.service.impl;
|
|||
import com.ether.pms.asset.entity.EquipmentHvac;
|
||||
import com.ether.pms.asset.repository.EquipmentHvacRepository;
|
||||
import com.ether.pms.asset.service.EquipmentHvacService;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class EquipmentHvacServiceImpl implements EquipmentHvacService {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
package com.ether.pms.asset.service.impl;
|
||||
|
||||
import com.ether.pms.common.BusinessException;
|
||||
import com.ether.pms.common.ErrorCode;
|
||||
import com.ether.pms.asset.entity.Equipment;
|
||||
import com.ether.pms.asset.enums.EquipmentStatus;
|
||||
import com.ether.pms.asset.enums.EquipmentType;
|
||||
|
|
@ -9,6 +7,14 @@ import com.ether.pms.asset.enums.OwnershipType;
|
|||
import com.ether.pms.asset.enums.SystemType;
|
||||
import com.ether.pms.asset.repository.EquipmentRepository;
|
||||
import com.ether.pms.asset.service.EquipmentService;
|
||||
import com.ether.pms.common.BusinessException;
|
||||
import com.ether.pms.common.ErrorCode;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
|
|
@ -16,14 +22,6 @@ import org.springframework.stereotype.Service;
|
|||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class EquipmentServiceImpl implements EquipmentService {
|
||||
|
|
@ -48,7 +46,9 @@ public class EquipmentServiceImpl implements EquipmentService {
|
|||
@Override
|
||||
@Transactional
|
||||
public Equipment updateEquipment(UUID id, Equipment equipment) {
|
||||
Equipment existing = equipmentRepository.findByIdAndIsDeletedFalse(id)
|
||||
Equipment existing =
|
||||
equipmentRepository
|
||||
.findByIdAndIsDeletedFalse(id)
|
||||
.orElseThrow(() -> new BusinessException(ErrorCode.NOT_FOUND, "设备不存在"));
|
||||
updateFields(existing, equipment);
|
||||
return equipmentRepository.save(existing);
|
||||
|
|
@ -57,7 +57,9 @@ public class EquipmentServiceImpl implements EquipmentService {
|
|||
@Override
|
||||
@Transactional
|
||||
public void deleteEquipment(UUID id) {
|
||||
Equipment equipment = equipmentRepository.findByIdAndIsDeletedFalse(id)
|
||||
Equipment equipment =
|
||||
equipmentRepository
|
||||
.findByIdAndIsDeletedFalse(id)
|
||||
.orElseThrow(() -> new BusinessException(ErrorCode.NOT_FOUND, "设备不存在"));
|
||||
equipment.setIsDeleted(true);
|
||||
equipment.setStatus(EquipmentStatus.INACTIVE);
|
||||
|
|
@ -66,7 +68,8 @@ public class EquipmentServiceImpl implements EquipmentService {
|
|||
|
||||
@Override
|
||||
public Equipment getEquipmentById(UUID id) {
|
||||
return equipmentRepository.findByIdAndIsDeletedFalse(id)
|
||||
return equipmentRepository
|
||||
.findByIdAndIsDeletedFalse(id)
|
||||
.orElseThrow(() -> new BusinessException(ErrorCode.NOT_FOUND, "设备不存在"));
|
||||
}
|
||||
|
||||
|
|
@ -120,7 +123,9 @@ public class EquipmentServiceImpl implements EquipmentService {
|
|||
}
|
||||
|
||||
private String generateEquipmentCode() {
|
||||
return "EQC-" + LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
|
||||
return "EQC-"
|
||||
+ LocalDateTime.now()
|
||||
.format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
|
||||
}
|
||||
|
||||
private void updateFields(Equipment existing, Equipment updated) {
|
||||
|
|
@ -210,15 +215,31 @@ public class EquipmentServiceImpl implements EquipmentService {
|
|||
|
||||
@Override
|
||||
public byte[] exportToExcel(UUID projectId) {
|
||||
List<Equipment> equipmentList = equipmentRepository.findByProjectIdAndIsDeletedFalse(projectId);
|
||||
List<Equipment> equipmentList =
|
||||
equipmentRepository.findByProjectIdAndIsDeletedFalse(projectId);
|
||||
|
||||
try (Workbook workbook = new XSSFWorkbook();
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
||||
Sheet sheet = workbook.createSheet("设备列表");
|
||||
|
||||
String[] headers = {"设备编码", "设备名称", "设备类型", "系统类型", "归属类型",
|
||||
"型号", "厂商", "额定功率(kW)", "额定电压(V)", "安装位置",
|
||||
"维保商", "维保电话", "年检周期(月)", "购置日期", "购置价格", "保修到期"};
|
||||
String[] headers = {
|
||||
"设备编码",
|
||||
"设备名称",
|
||||
"设备类型",
|
||||
"系统类型",
|
||||
"归属类型",
|
||||
"型号",
|
||||
"厂商",
|
||||
"额定功率(kW)",
|
||||
"额定电压(V)",
|
||||
"安装位置",
|
||||
"维保商",
|
||||
"维保电话",
|
||||
"年检周期(月)",
|
||||
"购置日期",
|
||||
"购置价格",
|
||||
"保修到期"
|
||||
};
|
||||
Row headerRow = sheet.createRow(0);
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
Cell cell = headerRow.createCell(i);
|
||||
|
|
@ -229,22 +250,64 @@ public class EquipmentServiceImpl implements EquipmentService {
|
|||
int rowNum = 1;
|
||||
for (Equipment eq : equipmentList) {
|
||||
Row row = sheet.createRow(rowNum++);
|
||||
row.createCell(0).setCellValue(eq.getEquipmentCode() != null ? eq.getEquipmentCode() : "");
|
||||
row.createCell(1).setCellValue(eq.getEquipmentName() != null ? eq.getEquipmentName() : "");
|
||||
row.createCell(2).setCellValue(eq.getEquipmentType() != null ? eq.getEquipmentType().getDescription() : "");
|
||||
row.createCell(3).setCellValue(eq.getSystemType() != null ? eq.getSystemType().getDescription() : "");
|
||||
row.createCell(4).setCellValue(eq.getOwnershipType() != null ? eq.getOwnershipType().getDescription() : "");
|
||||
row.createCell(0)
|
||||
.setCellValue(eq.getEquipmentCode() != null ? eq.getEquipmentCode() : "");
|
||||
row.createCell(1)
|
||||
.setCellValue(eq.getEquipmentName() != null ? eq.getEquipmentName() : "");
|
||||
row.createCell(2)
|
||||
.setCellValue(
|
||||
eq.getEquipmentType() != null
|
||||
? eq.getEquipmentType().getDescription()
|
||||
: "");
|
||||
row.createCell(3)
|
||||
.setCellValue(
|
||||
eq.getSystemType() != null
|
||||
? eq.getSystemType().getDescription()
|
||||
: "");
|
||||
row.createCell(4)
|
||||
.setCellValue(
|
||||
eq.getOwnershipType() != null
|
||||
? eq.getOwnershipType().getDescription()
|
||||
: "");
|
||||
row.createCell(5).setCellValue(eq.getModel() != null ? eq.getModel() : "");
|
||||
row.createCell(6).setCellValue(eq.getManufacturer() != null ? eq.getManufacturer() : "");
|
||||
row.createCell(7).setCellValue(eq.getRatedPower() != null ? eq.getRatedPower().doubleValue() : 0);
|
||||
row.createCell(8).setCellValue(eq.getRatedVoltage() != null ? eq.getRatedVoltage() : "");
|
||||
row.createCell(9).setCellValue(eq.getInstallationLocation() != null ? eq.getInstallationLocation() : "");
|
||||
row.createCell(10).setCellValue(eq.getMaintenanceVendor() != null ? eq.getMaintenanceVendor() : "");
|
||||
row.createCell(11).setCellValue(eq.getMaintenanceVendorPhone() != null ? eq.getMaintenanceVendorPhone() : "");
|
||||
row.createCell(12).setCellValue(eq.getInspectionCycle() != null ? eq.getInspectionCycle() : 0);
|
||||
row.createCell(13).setCellValue(eq.getPurchaseDate() != null ? eq.getPurchaseDate().toString() : "");
|
||||
row.createCell(14).setCellValue(eq.getPurchasePrice() != null ? eq.getPurchasePrice().doubleValue() : 0);
|
||||
row.createCell(15).setCellValue(eq.getWarrantyExpireDate() != null ? eq.getWarrantyExpireDate().toString() : "");
|
||||
row.createCell(6)
|
||||
.setCellValue(eq.getManufacturer() != null ? eq.getManufacturer() : "");
|
||||
row.createCell(7)
|
||||
.setCellValue(
|
||||
eq.getRatedPower() != null ? eq.getRatedPower().doubleValue() : 0);
|
||||
row.createCell(8)
|
||||
.setCellValue(eq.getRatedVoltage() != null ? eq.getRatedVoltage() : "");
|
||||
row.createCell(9)
|
||||
.setCellValue(
|
||||
eq.getInstallationLocation() != null
|
||||
? eq.getInstallationLocation()
|
||||
: "");
|
||||
row.createCell(10)
|
||||
.setCellValue(
|
||||
eq.getMaintenanceVendor() != null ? eq.getMaintenanceVendor() : "");
|
||||
row.createCell(11)
|
||||
.setCellValue(
|
||||
eq.getMaintenanceVendorPhone() != null
|
||||
? eq.getMaintenanceVendorPhone()
|
||||
: "");
|
||||
row.createCell(12)
|
||||
.setCellValue(
|
||||
eq.getInspectionCycle() != null ? eq.getInspectionCycle() : 0);
|
||||
row.createCell(13)
|
||||
.setCellValue(
|
||||
eq.getPurchaseDate() != null
|
||||
? eq.getPurchaseDate().toString()
|
||||
: "");
|
||||
row.createCell(14)
|
||||
.setCellValue(
|
||||
eq.getPurchasePrice() != null
|
||||
? eq.getPurchasePrice().doubleValue()
|
||||
: 0);
|
||||
row.createCell(15)
|
||||
.setCellValue(
|
||||
eq.getWarrantyExpireDate() != null
|
||||
? eq.getWarrantyExpireDate().toString()
|
||||
: "");
|
||||
}
|
||||
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
|
|
|
|||
|
|
@ -3,5 +3,4 @@ package com.ether.pms.asset;
|
|||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class TestApplication {
|
||||
}
|
||||
public class TestApplication {}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
package com.ether.pms.asset.repository;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import com.ether.pms.asset.TestApplication;
|
||||
import com.ether.pms.asset.entity.Equipment;
|
||||
import com.ether.pms.asset.enums.EquipmentStatus;
|
||||
import com.ether.pms.asset.enums.EquipmentType;
|
||||
import com.ether.pms.asset.enums.OwnershipType;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
|
@ -13,27 +18,19 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
|||
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* EquipmentRepository 测试类 - TDD方式
|
||||
*
|
||||
* 使用 @DataJpaTest 切片测试,只加载 JPA 相关组件
|
||||
* <p>使用 @DataJpaTest 切片测试,只加载 JPA 相关组件
|
||||
*/
|
||||
@DataJpaTest
|
||||
@ContextConfiguration(classes = TestApplication.class)
|
||||
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
|
||||
class EquipmentRepositoryTest {
|
||||
|
||||
@Autowired
|
||||
private TestEntityManager entityManager;
|
||||
@Autowired private TestEntityManager entityManager;
|
||||
|
||||
@Autowired
|
||||
private EquipmentRepository equipmentRepository;
|
||||
@Autowired private EquipmentRepository equipmentRepository;
|
||||
|
||||
private UUID projectId;
|
||||
private UUID spaceNodeId;
|
||||
|
|
@ -82,7 +79,8 @@ class EquipmentRepositoryTest {
|
|||
entityManager.persist(testEquipment);
|
||||
entityManager.flush();
|
||||
|
||||
Optional<Equipment> found = equipmentRepository.findByIdAndIsDeletedFalse(testEquipment.getId());
|
||||
Optional<Equipment> found =
|
||||
equipmentRepository.findByIdAndIsDeletedFalse(testEquipment.getId());
|
||||
|
||||
assertTrue(found.isEmpty());
|
||||
}
|
||||
|
|
@ -92,7 +90,8 @@ class EquipmentRepositoryTest {
|
|||
entityManager.persist(testEquipment);
|
||||
entityManager.flush();
|
||||
|
||||
Optional<Equipment> found = equipmentRepository.findByIdAndIsDeletedFalse(testEquipment.getId());
|
||||
Optional<Equipment> found =
|
||||
equipmentRepository.findByIdAndIsDeletedFalse(testEquipment.getId());
|
||||
|
||||
assertTrue(found.isPresent());
|
||||
assertFalse(found.get().getIsDeleted());
|
||||
|
|
@ -107,7 +106,8 @@ class EquipmentRepositoryTest {
|
|||
equipmentRepository.save(testEquipment);
|
||||
entityManager.flush();
|
||||
|
||||
Optional<Equipment> found = equipmentRepository.findByIdAndIsDeletedFalse(testEquipment.getId());
|
||||
Optional<Equipment> found =
|
||||
equipmentRepository.findByIdAndIsDeletedFalse(testEquipment.getId());
|
||||
assertTrue(found.isEmpty());
|
||||
}
|
||||
|
||||
|
|
@ -130,7 +130,8 @@ class EquipmentRepositoryTest {
|
|||
entityManager.persist(equipment);
|
||||
entityManager.flush();
|
||||
|
||||
List<Equipment> result = equipmentRepository.findByProjectIdAndIsDeletedFalse(UUID.randomUUID());
|
||||
List<Equipment> result =
|
||||
equipmentRepository.findByProjectIdAndIsDeletedFalse(UUID.randomUUID());
|
||||
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
|
@ -147,7 +148,8 @@ class EquipmentRepositoryTest {
|
|||
entityManager.persist(hvac);
|
||||
entityManager.flush();
|
||||
|
||||
List<Equipment> elevators = equipmentRepository.findByEquipmentTypeAndIsDeletedFalse(EquipmentType.ELEVATOR);
|
||||
List<Equipment> elevators =
|
||||
equipmentRepository.findByEquipmentTypeAndIsDeletedFalse(EquipmentType.ELEVATOR);
|
||||
|
||||
assertEquals(1, elevators.size());
|
||||
assertEquals(EquipmentType.ELEVATOR, elevators.get(0).getEquipmentType());
|
||||
|
|
@ -165,7 +167,8 @@ class EquipmentRepositoryTest {
|
|||
entityManager.persist(ownerOwned);
|
||||
entityManager.flush();
|
||||
|
||||
List<Equipment> projectOwnedEquipments = equipmentRepository.findByOwnershipTypeAndIsDeletedFalse(OwnershipType.PROJECT);
|
||||
List<Equipment> projectOwnedEquipments =
|
||||
equipmentRepository.findByOwnershipTypeAndIsDeletedFalse(OwnershipType.PROJECT);
|
||||
|
||||
assertEquals(1, projectOwnedEquipments.size());
|
||||
assertEquals(OwnershipType.PROJECT, projectOwnedEquipments.get(0).getOwnershipType());
|
||||
|
|
@ -179,7 +182,8 @@ class EquipmentRepositoryTest {
|
|||
entityManager.persist(equipment1);
|
||||
entityManager.flush();
|
||||
|
||||
List<Equipment> result = equipmentRepository.findBySpaceNodeIdAndIsDeletedFalse(spaceNodeId);
|
||||
List<Equipment> result =
|
||||
equipmentRepository.findBySpaceNodeIdAndIsDeletedFalse(spaceNodeId);
|
||||
|
||||
assertEquals(1, result.size());
|
||||
assertEquals(spaceNodeId, result.get(0).getSpaceNodeId());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,160 @@
|
|||
package com.ether.pms.asset.service;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import com.ether.pms.asset.entity.EquipmentElevator;
|
||||
import com.ether.pms.asset.repository.EquipmentElevatorRepository;
|
||||
import com.ether.pms.asset.service.impl.EquipmentElevatorServiceImpl;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class EquipmentElevatorServiceTest {
|
||||
|
||||
@Mock private EquipmentElevatorRepository elevatorRepository;
|
||||
|
||||
@InjectMocks private EquipmentElevatorServiceImpl elevatorService;
|
||||
|
||||
private EquipmentElevator testElevator;
|
||||
private UUID testId;
|
||||
private UUID equipmentId;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
testId = UUID.randomUUID();
|
||||
equipmentId = UUID.randomUUID();
|
||||
testElevator = new EquipmentElevator();
|
||||
testElevator.setId(testId);
|
||||
testElevator.setEquipmentId(equipmentId);
|
||||
testElevator.setElevatorType("乘客电梯");
|
||||
testElevator.setElevatorModel("XYZ-1000");
|
||||
testElevator.setLoadCapacity(1000);
|
||||
testElevator.setSpeed(new BigDecimal("2.5"));
|
||||
testElevator.setFloorCount(20);
|
||||
testElevator.setRegistrationNo("REG-001");
|
||||
testElevator.setMaintenanceLevel("A级");
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveOrUpdate_shouldCreateNew_whenNotExists() {
|
||||
when(elevatorRepository.findByEquipmentId(equipmentId)).thenReturn(Optional.empty());
|
||||
when(elevatorRepository.save(any(EquipmentElevator.class)))
|
||||
.thenAnswer(
|
||||
invocation -> {
|
||||
EquipmentElevator saved = invocation.getArgument(0);
|
||||
saved.setId(testId);
|
||||
return saved;
|
||||
});
|
||||
|
||||
EquipmentElevator result = elevatorService.saveOrUpdate(testElevator);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(equipmentId, result.getEquipmentId());
|
||||
verify(elevatorRepository).save(testElevator);
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveOrUpdate_shouldUpdateExisting_whenExists() {
|
||||
EquipmentElevator existing = new EquipmentElevator();
|
||||
existing.setId(testId);
|
||||
existing.setEquipmentId(equipmentId);
|
||||
|
||||
EquipmentElevator updateData = new EquipmentElevator();
|
||||
updateData.setEquipmentId(equipmentId);
|
||||
updateData.setElevatorType("货梯");
|
||||
updateData.setLoadCapacity(2000);
|
||||
|
||||
when(elevatorRepository.findByEquipmentId(equipmentId)).thenReturn(Optional.of(existing));
|
||||
when(elevatorRepository.save(any(EquipmentElevator.class)))
|
||||
.thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
EquipmentElevator result = elevatorService.saveOrUpdate(updateData);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(testId, result.getId());
|
||||
assertEquals("货梯", result.getElevatorType());
|
||||
assertEquals(2000, result.getLoadCapacity());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getByEquipmentId_shouldReturnElevator_whenExists() {
|
||||
when(elevatorRepository.findByEquipmentId(equipmentId))
|
||||
.thenReturn(Optional.of(testElevator));
|
||||
|
||||
Optional<EquipmentElevator> result = elevatorService.getByEquipmentId(equipmentId);
|
||||
|
||||
assertTrue(result.isPresent());
|
||||
assertEquals(testId, result.get().getId());
|
||||
assertEquals("乘客电梯", result.get().getElevatorType());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getByEquipmentId_shouldReturnEmpty_whenNotExists() {
|
||||
UUID nonExistentId = UUID.randomUUID();
|
||||
when(elevatorRepository.findByEquipmentId(nonExistentId)).thenReturn(Optional.empty());
|
||||
|
||||
Optional<EquipmentElevator> result = elevatorService.getByEquipmentId(nonExistentId);
|
||||
|
||||
assertFalse(result.isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteByEquipmentId_shouldCallRepository() {
|
||||
elevatorService.deleteByEquipmentId(equipmentId);
|
||||
|
||||
verify(elevatorRepository).deleteByEquipmentId(equipmentId);
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveOrUpdate_shouldPreserveAllFields_whenUpdating() {
|
||||
EquipmentElevator existing = new EquipmentElevator();
|
||||
existing.setId(testId);
|
||||
existing.setEquipmentId(equipmentId);
|
||||
existing.setElevatorType("旧类型");
|
||||
existing.setElevatorModel("旧型号");
|
||||
|
||||
EquipmentElevator updateData = new EquipmentElevator();
|
||||
updateData.setEquipmentId(equipmentId);
|
||||
updateData.setElevatorType("乘客电梯");
|
||||
updateData.setElevatorModel("XYZ-1000");
|
||||
updateData.setLoadCapacity(1000);
|
||||
updateData.setSpeed(new BigDecimal("2.5"));
|
||||
updateData.setFloorCount(20);
|
||||
updateData.setShaftDimensions("2m x 2m");
|
||||
updateData.setPitDepth(new BigDecimal("3.5"));
|
||||
updateData.setOverheadHeight(new BigDecimal("4.0"));
|
||||
updateData.setRegistrationNo("REG-001");
|
||||
updateData.setInspectionCertificate("CERT-001");
|
||||
updateData.setMaintenanceLevel("A级");
|
||||
updateData.setRescuePlan("紧急救援计划内容");
|
||||
|
||||
when(elevatorRepository.findByEquipmentId(equipmentId)).thenReturn(Optional.of(existing));
|
||||
when(elevatorRepository.save(any(EquipmentElevator.class)))
|
||||
.thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
EquipmentElevator result = elevatorService.saveOrUpdate(updateData);
|
||||
|
||||
assertEquals(testId, result.getId());
|
||||
assertEquals("乘客电梯", result.getElevatorType());
|
||||
assertEquals("XYZ-1000", result.getElevatorModel());
|
||||
assertEquals(1000, result.getLoadCapacity());
|
||||
assertEquals(new BigDecimal("2.5"), result.getSpeed());
|
||||
assertEquals(20, result.getFloorCount());
|
||||
assertEquals("2m x 2m", result.getShaftDimensions());
|
||||
assertEquals(new BigDecimal("3.5"), result.getPitDepth());
|
||||
assertEquals(new BigDecimal("4.0"), result.getOverheadHeight());
|
||||
assertEquals("REG-001", result.getRegistrationNo());
|
||||
assertEquals("CERT-001", result.getInspectionCertificate());
|
||||
assertEquals("A级", result.getMaintenanceLevel());
|
||||
assertEquals("紧急救援计划内容", result.getRescuePlan());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,379 @@
|
|||
package com.ether.pms.asset.service;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import com.ether.pms.asset.entity.Equipment;
|
||||
import com.ether.pms.asset.entity.EquipmentFailureHistory;
|
||||
import com.ether.pms.asset.entity.EquipmentHealthScore;
|
||||
import com.ether.pms.asset.enums.EquipmentStatus;
|
||||
import com.ether.pms.asset.enums.EquipmentType;
|
||||
import com.ether.pms.asset.enums.OwnershipType;
|
||||
import com.ether.pms.asset.repository.EquipmentFailureHistoryRepository;
|
||||
import com.ether.pms.asset.repository.EquipmentHealthScoreRepository;
|
||||
import com.ether.pms.asset.repository.EquipmentRepository;
|
||||
import com.ether.pms.asset.service.impl.EquipmentHealthServiceImpl;
|
||||
import com.ether.pms.common.BusinessException;
|
||||
import com.ether.pms.common.MaintenanceTaskRepository;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class EquipmentHealthServiceTest {
|
||||
|
||||
@Mock private EquipmentFailureHistoryRepository failureHistoryRepository;
|
||||
|
||||
@Mock private EquipmentHealthScoreRepository healthScoreRepository;
|
||||
|
||||
@Mock private EquipmentRepository equipmentRepository;
|
||||
|
||||
@Mock private MaintenanceTaskRepository maintenanceTaskRepository;
|
||||
|
||||
@Mock private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
@InjectMocks private EquipmentHealthServiceImpl healthService;
|
||||
|
||||
private Equipment testEquipment;
|
||||
private UUID testId;
|
||||
private UUID projectId;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
testId = UUID.randomUUID();
|
||||
projectId = UUID.randomUUID();
|
||||
testEquipment = new Equipment();
|
||||
testEquipment.setId(testId);
|
||||
testEquipment.setProjectId(projectId);
|
||||
testEquipment.setEquipmentCode("EQ-001");
|
||||
testEquipment.setEquipmentName("测试设备");
|
||||
testEquipment.setEquipmentType(EquipmentType.HVAC);
|
||||
testEquipment.setOwnershipType(OwnershipType.PROJECT);
|
||||
testEquipment.setStatus(EquipmentStatus.ACTIVE);
|
||||
testEquipment.setInstallationDate(LocalDate.now().minusYears(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void calculateHealthScore_shouldCalculateCorrectly_withNoFailures() {
|
||||
when(equipmentRepository.findByIdAndIsDeletedFalse(testId))
|
||||
.thenReturn(Optional.of(testEquipment));
|
||||
when(maintenanceTaskRepository.findByEquipmentId(testId)).thenReturn(List.of());
|
||||
when(failureHistoryRepository.countByEquipmentIdSince(eq(testId), any(LocalDateTime.class)))
|
||||
.thenReturn(0L);
|
||||
when(failureHistoryRepository.findByEquipmentIdSince(eq(testId), any(LocalDateTime.class)))
|
||||
.thenReturn(List.of());
|
||||
when(failureHistoryRepository.findRepairedFailuresByEquipmentIdSince(
|
||||
eq(testId), any(LocalDateTime.class)))
|
||||
.thenReturn(List.of());
|
||||
when(healthScoreRepository.save(any(EquipmentHealthScore.class)))
|
||||
.thenAnswer(
|
||||
invocation -> {
|
||||
EquipmentHealthScore score = invocation.getArgument(0);
|
||||
score.setId(UUID.randomUUID());
|
||||
return score;
|
||||
});
|
||||
|
||||
EquipmentHealthScore result = healthService.calculateHealthScore(testId);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(0, result.getFailureCount30d());
|
||||
assertEquals(0, result.getFailureDeduction().intValue());
|
||||
assertTrue(result.getHealthScore().compareTo(BigDecimal.ZERO) > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void calculateHealthScore_shouldDeductForFailures() {
|
||||
when(equipmentRepository.findByIdAndIsDeletedFalse(testId))
|
||||
.thenReturn(Optional.of(testEquipment));
|
||||
when(maintenanceTaskRepository.findByEquipmentId(testId)).thenReturn(List.of());
|
||||
when(failureHistoryRepository.countByEquipmentIdSince(eq(testId), any(LocalDateTime.class)))
|
||||
.thenReturn(3L);
|
||||
when(failureHistoryRepository.findByEquipmentIdSince(eq(testId), any(LocalDateTime.class)))
|
||||
.thenReturn(List.of());
|
||||
when(failureHistoryRepository.findRepairedFailuresByEquipmentIdSince(
|
||||
eq(testId), any(LocalDateTime.class)))
|
||||
.thenReturn(List.of());
|
||||
when(healthScoreRepository.save(any(EquipmentHealthScore.class)))
|
||||
.thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
EquipmentHealthScore result = healthService.calculateHealthScore(testId);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(3, result.getFailureCount30d());
|
||||
assertEquals(new BigDecimal("15.00"), result.getFailureDeduction());
|
||||
}
|
||||
|
||||
@Test
|
||||
void calculateHealthScore_shouldThrowException_whenEquipmentNotFound() {
|
||||
UUID nonExistentId = UUID.randomUUID();
|
||||
when(equipmentRepository.findByIdAndIsDeletedFalse(nonExistentId))
|
||||
.thenReturn(Optional.empty());
|
||||
|
||||
BusinessException exception =
|
||||
assertThrows(
|
||||
BusinessException.class,
|
||||
() -> healthService.calculateHealthScore(nonExistentId));
|
||||
|
||||
assertEquals(6001, exception.getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void calculateMTBF_shouldReturnZero_whenNoFailures() {
|
||||
when(failureHistoryRepository.findByEquipmentIdSince(eq(testId), any(LocalDateTime.class)))
|
||||
.thenReturn(List.of());
|
||||
|
||||
BigDecimal result = healthService.calculateMTBF(testId, 30);
|
||||
|
||||
assertEquals(BigDecimal.ZERO, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void calculateMTBF_shouldCalculateCorrectly_withMultipleFailures() {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
EquipmentFailureHistory failure1 = createFailure(testId, now.minusDays(5));
|
||||
EquipmentFailureHistory failure2 = createFailure(testId, now.minusDays(15));
|
||||
EquipmentFailureHistory failure3 = createFailure(testId, now.minusDays(25));
|
||||
|
||||
when(failureHistoryRepository.findByEquipmentIdSince(eq(testId), any(LocalDateTime.class)))
|
||||
.thenReturn(Arrays.asList(failure1, failure2, failure3));
|
||||
|
||||
BigDecimal result = healthService.calculateMTBF(testId, 30);
|
||||
|
||||
assertNotNull(result);
|
||||
assertTrue(result.compareTo(BigDecimal.ZERO) > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void calculateMTBF_shouldUseDefaultDays_whenDaysIsNull() {
|
||||
when(failureHistoryRepository.findByEquipmentIdSince(eq(testId), any(LocalDateTime.class)))
|
||||
.thenReturn(List.of());
|
||||
|
||||
BigDecimal result = healthService.calculateMTBF(testId, null);
|
||||
|
||||
assertEquals(BigDecimal.ZERO, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void calculateMTBF_shouldUseDefaultDays_whenDaysIsNegative() {
|
||||
when(failureHistoryRepository.findByEquipmentIdSince(eq(testId), any(LocalDateTime.class)))
|
||||
.thenReturn(List.of());
|
||||
|
||||
BigDecimal result = healthService.calculateMTBF(testId, -5);
|
||||
|
||||
assertEquals(BigDecimal.ZERO, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void calculateMTTR_shouldReturnZero_whenNoRepairedFailures() {
|
||||
when(failureHistoryRepository.findRepairedFailuresByEquipmentIdSince(
|
||||
eq(testId), any(LocalDateTime.class)))
|
||||
.thenReturn(List.of());
|
||||
|
||||
BigDecimal result = healthService.calculateMTTR(testId, 30);
|
||||
|
||||
assertEquals(BigDecimal.ZERO, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void calculateMTTR_shouldCalculateCorrectly_withRepairedFailures() {
|
||||
EquipmentFailureHistory failure1 = createRepairedFailure(testId, 2.0);
|
||||
EquipmentFailureHistory failure2 = createRepairedFailure(testId, 4.0);
|
||||
|
||||
when(failureHistoryRepository.findRepairedFailuresByEquipmentIdSince(
|
||||
eq(testId), any(LocalDateTime.class)))
|
||||
.thenReturn(Arrays.asList(failure1, failure2));
|
||||
|
||||
BigDecimal result = healthService.calculateMTTR(testId, 30);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(new BigDecimal("3.00"), result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void recordFailure_shouldSetProjectId_whenNull() {
|
||||
EquipmentFailureHistory failure = new EquipmentFailureHistory();
|
||||
failure.setEquipmentId(testId);
|
||||
failure.setFailureTime(LocalDateTime.now());
|
||||
failure.setFailureType(EquipmentFailureHistory.FailureType.SUDDEN);
|
||||
|
||||
when(equipmentRepository.findByIdAndIsDeletedFalse(testId))
|
||||
.thenReturn(Optional.of(testEquipment));
|
||||
doNothing().when(eventPublisher).publishEvent(any());
|
||||
when(failureHistoryRepository.save(any(EquipmentFailureHistory.class)))
|
||||
.thenAnswer(
|
||||
invocation -> {
|
||||
EquipmentFailureHistory saved = invocation.getArgument(0);
|
||||
saved.setId(UUID.randomUUID());
|
||||
return saved;
|
||||
});
|
||||
|
||||
EquipmentFailureHistory result = healthService.recordFailure(failure);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(projectId, result.getProjectId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void recordFailure_shouldSetEquipmentName_whenNull() {
|
||||
EquipmentFailureHistory failure = new EquipmentFailureHistory();
|
||||
failure.setEquipmentId(testId);
|
||||
failure.setFailureTime(LocalDateTime.now());
|
||||
failure.setFailureType(EquipmentFailureHistory.FailureType.SUDDEN);
|
||||
|
||||
when(equipmentRepository.findByIdAndIsDeletedFalse(testId))
|
||||
.thenReturn(Optional.of(testEquipment));
|
||||
doNothing().when(eventPublisher).publishEvent(any());
|
||||
when(failureHistoryRepository.save(any(EquipmentFailureHistory.class)))
|
||||
.thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
EquipmentFailureHistory result = healthService.recordFailure(failure);
|
||||
|
||||
assertEquals("测试设备", result.getEquipmentName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void recordFailure_shouldCalculateRepairDuration() {
|
||||
LocalDateTime repairStart = LocalDateTime.now().minusHours(2);
|
||||
LocalDateTime repairEnd = LocalDateTime.now();
|
||||
|
||||
EquipmentFailureHistory failure = new EquipmentFailureHistory();
|
||||
failure.setEquipmentId(testId);
|
||||
failure.setFailureTime(LocalDateTime.now().minusHours(3));
|
||||
failure.setRepairStartTime(repairStart);
|
||||
failure.setRepairEndTime(repairEnd);
|
||||
failure.setFailureType(EquipmentFailureHistory.FailureType.SUDDEN);
|
||||
|
||||
when(equipmentRepository.findByIdAndIsDeletedFalse(testId))
|
||||
.thenReturn(Optional.of(testEquipment));
|
||||
doNothing().when(eventPublisher).publishEvent(any());
|
||||
when(failureHistoryRepository.save(any(EquipmentFailureHistory.class)))
|
||||
.thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
EquipmentFailureHistory result = healthService.recordFailure(failure);
|
||||
|
||||
assertNotNull(result.getRepairDurationHours());
|
||||
assertTrue(result.getRepairDurationHours() >= 1.9);
|
||||
}
|
||||
|
||||
@Test
|
||||
void recordFailure_shouldCalculateDowntime() {
|
||||
LocalDateTime failureTime = LocalDateTime.now().minusHours(1);
|
||||
LocalDateTime repairStart = LocalDateTime.now();
|
||||
|
||||
EquipmentFailureHistory failure = new EquipmentFailureHistory();
|
||||
failure.setEquipmentId(testId);
|
||||
failure.setFailureTime(failureTime);
|
||||
failure.setRepairStartTime(repairStart);
|
||||
failure.setRepairEndTime(repairStart.plusHours(2));
|
||||
failure.setFailureType(EquipmentFailureHistory.FailureType.SUDDEN);
|
||||
|
||||
when(equipmentRepository.findByIdAndIsDeletedFalse(testId))
|
||||
.thenReturn(Optional.of(testEquipment));
|
||||
doNothing().when(eventPublisher).publishEvent(any());
|
||||
when(failureHistoryRepository.save(any(EquipmentFailureHistory.class)))
|
||||
.thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
EquipmentFailureHistory result = healthService.recordFailure(failure);
|
||||
|
||||
assertNotNull(result.getDowntimeHours());
|
||||
assertTrue(result.getDowntimeHours() >= 0.9);
|
||||
}
|
||||
|
||||
@Test
|
||||
void recordFailure_shouldThrowException_whenEquipmentNotFound() {
|
||||
UUID nonExistentId = UUID.randomUUID();
|
||||
EquipmentFailureHistory failure = new EquipmentFailureHistory();
|
||||
failure.setEquipmentId(nonExistentId);
|
||||
|
||||
when(equipmentRepository.findByIdAndIsDeletedFalse(nonExistentId))
|
||||
.thenReturn(Optional.empty());
|
||||
|
||||
BusinessException exception =
|
||||
assertThrows(BusinessException.class, () -> healthService.recordFailure(failure));
|
||||
|
||||
assertEquals(6001, exception.getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHealthHistory_shouldReturnList() {
|
||||
List<EquipmentHealthScore> history =
|
||||
Arrays.asList(new EquipmentHealthScore(), new EquipmentHealthScore());
|
||||
when(healthScoreRepository.findByEquipmentIdOrderByCalculatedAtDesc(testId))
|
||||
.thenReturn(history);
|
||||
|
||||
List<EquipmentHealthScore> result = healthService.getHealthHistory(testId);
|
||||
|
||||
assertEquals(2, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getLatestHealthScore_shouldReturnLatest() {
|
||||
EquipmentHealthScore latest = new EquipmentHealthScore();
|
||||
latest.setId(UUID.randomUUID());
|
||||
latest.setHealthScore(new BigDecimal("85.00"));
|
||||
|
||||
when(healthScoreRepository.findLatestByEquipmentId(testId)).thenReturn(Optional.of(latest));
|
||||
|
||||
EquipmentHealthScore result = healthService.getLatestHealthScore(testId);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(new BigDecimal("85.00"), result.getHealthScore());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getLatestHealthScore_shouldThrowException_whenNoRecords() {
|
||||
when(healthScoreRepository.findLatestByEquipmentId(testId)).thenReturn(Optional.empty());
|
||||
|
||||
BusinessException exception =
|
||||
assertThrows(
|
||||
BusinessException.class, () -> healthService.getLatestHealthScore(testId));
|
||||
|
||||
assertEquals(6003, exception.getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getFailureHistory_shouldReturnList() {
|
||||
List<EquipmentFailureHistory> history =
|
||||
Arrays.asList(new EquipmentFailureHistory(), new EquipmentFailureHistory());
|
||||
when(failureHistoryRepository.findByEquipmentIdOrderByFailureTimeDesc(testId))
|
||||
.thenReturn(history);
|
||||
|
||||
List<EquipmentFailureHistory> result = healthService.getFailureHistory(testId);
|
||||
|
||||
assertEquals(2, result.size());
|
||||
}
|
||||
|
||||
private EquipmentFailureHistory createFailure(UUID equipmentId, LocalDateTime failureTime) {
|
||||
EquipmentFailureHistory failure = new EquipmentFailureHistory();
|
||||
failure.setId(UUID.randomUUID());
|
||||
failure.setEquipmentId(equipmentId);
|
||||
failure.setFailureTime(failureTime);
|
||||
failure.setFailureType(EquipmentFailureHistory.FailureType.SUDDEN);
|
||||
return failure;
|
||||
}
|
||||
|
||||
private EquipmentFailureHistory createRepairedFailure(UUID equipmentId, double repairHours) {
|
||||
EquipmentFailureHistory failure = new EquipmentFailureHistory();
|
||||
failure.setId(UUID.randomUUID());
|
||||
failure.setEquipmentId(equipmentId);
|
||||
failure.setFailureTime(LocalDateTime.now().minusDays(1));
|
||||
failure.setRepairStartTime(LocalDateTime.now().minusDays(1));
|
||||
failure.setRepairEndTime(LocalDateTime.now());
|
||||
failure.setRepairDurationHours(repairHours);
|
||||
failure.setFailureType(EquipmentFailureHistory.FailureType.SUDDEN);
|
||||
return failure;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,369 @@
|
|||
package com.ether.pms.asset.service;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import com.ether.pms.asset.entity.Equipment;
|
||||
import com.ether.pms.asset.enums.EquipmentStatus;
|
||||
import com.ether.pms.asset.enums.EquipmentType;
|
||||
import com.ether.pms.asset.enums.OwnershipType;
|
||||
import com.ether.pms.asset.enums.SystemType;
|
||||
import com.ether.pms.asset.repository.EquipmentRepository;
|
||||
import com.ether.pms.asset.service.impl.EquipmentServiceImpl;
|
||||
import com.ether.pms.common.BusinessException;
|
||||
import com.ether.pms.common.ErrorCode;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class EquipmentServiceTest {
|
||||
|
||||
@Mock private EquipmentRepository equipmentRepository;
|
||||
|
||||
@InjectMocks private EquipmentServiceImpl equipmentService;
|
||||
|
||||
private Equipment testEquipment;
|
||||
private UUID testId;
|
||||
private UUID projectId;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
testId = UUID.randomUUID();
|
||||
projectId = UUID.randomUUID();
|
||||
testEquipment = new Equipment();
|
||||
testEquipment.setId(testId);
|
||||
testEquipment.setProjectId(projectId);
|
||||
testEquipment.setEquipmentCode("EQ-001");
|
||||
testEquipment.setEquipmentName("测试设备");
|
||||
testEquipment.setEquipmentType(EquipmentType.HVAC);
|
||||
testEquipment.setOwnershipType(OwnershipType.PROJECT);
|
||||
testEquipment.setStatus(EquipmentStatus.ACTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createEquipment_shouldGenerateCode_whenCodeIsNull() {
|
||||
testEquipment.setEquipmentCode(null);
|
||||
when(equipmentRepository.save(any(Equipment.class)))
|
||||
.thenAnswer(
|
||||
invocation -> {
|
||||
Equipment saved = invocation.getArgument(0);
|
||||
saved.setId(testId);
|
||||
return saved;
|
||||
});
|
||||
|
||||
Equipment result = equipmentService.createEquipment(testEquipment);
|
||||
|
||||
assertNotNull(result);
|
||||
assertNotNull(result.getEquipmentCode());
|
||||
assertTrue(result.getEquipmentCode().startsWith("EQC-"));
|
||||
verify(equipmentRepository).save(any(Equipment.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void createEquipment_shouldSetDefaultStatus_whenStatusIsNull() {
|
||||
testEquipment.setStatus(null);
|
||||
when(equipmentRepository.save(any(Equipment.class)))
|
||||
.thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
Equipment result = equipmentService.createEquipment(testEquipment);
|
||||
|
||||
assertEquals(EquipmentStatus.ACTIVE, result.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
void createEquipment_shouldSetDefaultOwnershipType_whenOwnershipTypeIsNull() {
|
||||
testEquipment.setOwnershipType(null);
|
||||
when(equipmentRepository.save(any(Equipment.class)))
|
||||
.thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
Equipment result = equipmentService.createEquipment(testEquipment);
|
||||
|
||||
assertEquals(OwnershipType.PROJECT, result.getOwnershipType());
|
||||
}
|
||||
|
||||
@Test
|
||||
void createEquipment_shouldSaveEquipment_whenValid() {
|
||||
when(equipmentRepository.save(any(Equipment.class))).thenReturn(testEquipment);
|
||||
|
||||
Equipment result = equipmentService.createEquipment(testEquipment);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals("EQ-001", result.getEquipmentCode());
|
||||
verify(equipmentRepository).save(testEquipment);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getEquipmentById_shouldReturnEquipment_whenExists() {
|
||||
when(equipmentRepository.findByIdAndIsDeletedFalse(testId))
|
||||
.thenReturn(Optional.of(testEquipment));
|
||||
|
||||
Equipment result = equipmentService.getEquipmentById(testId);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(testId, result.getId());
|
||||
assertEquals("EQ-001", result.getEquipmentCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getEquipmentById_shouldThrowException_whenNotExists() {
|
||||
UUID nonExistentId = UUID.randomUUID();
|
||||
when(equipmentRepository.findByIdAndIsDeletedFalse(nonExistentId))
|
||||
.thenReturn(Optional.empty());
|
||||
|
||||
BusinessException exception =
|
||||
assertThrows(
|
||||
BusinessException.class,
|
||||
() -> equipmentService.getEquipmentById(nonExistentId));
|
||||
|
||||
assertEquals(ErrorCode.NOT_FOUND.getCode(), exception.getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateEquipment_shouldUpdateFields_whenEquipmentExists() {
|
||||
Equipment updateData = new Equipment();
|
||||
updateData.setEquipmentName("更新后的设备名称");
|
||||
updateData.setEquipmentType(EquipmentType.ELEVATOR);
|
||||
updateData.setModel("NewModel");
|
||||
updateData.setManufacturer("NewManufacturer");
|
||||
|
||||
when(equipmentRepository.findByIdAndIsDeletedFalse(testId))
|
||||
.thenReturn(Optional.of(testEquipment));
|
||||
when(equipmentRepository.save(any(Equipment.class)))
|
||||
.thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
Equipment result = equipmentService.updateEquipment(testId, updateData);
|
||||
|
||||
assertEquals("更新后的设备名称", result.getEquipmentName());
|
||||
assertEquals(EquipmentType.ELEVATOR, result.getEquipmentType());
|
||||
assertEquals("NewModel", result.getModel());
|
||||
assertEquals("NewManufacturer", result.getManufacturer());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateEquipment_shouldThrowException_whenNotExists() {
|
||||
UUID nonExistentId = UUID.randomUUID();
|
||||
when(equipmentRepository.findByIdAndIsDeletedFalse(nonExistentId))
|
||||
.thenReturn(Optional.empty());
|
||||
|
||||
assertThrows(
|
||||
BusinessException.class,
|
||||
() -> equipmentService.updateEquipment(nonExistentId, new Equipment()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteEquipment_shouldSetDeletedFlag_whenExists() {
|
||||
when(equipmentRepository.findByIdAndIsDeletedFalse(testId))
|
||||
.thenReturn(Optional.of(testEquipment));
|
||||
when(equipmentRepository.save(any(Equipment.class)))
|
||||
.thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
equipmentService.deleteEquipment(testId);
|
||||
|
||||
assertTrue(testEquipment.getIsDeleted());
|
||||
assertEquals(EquipmentStatus.INACTIVE, testEquipment.getStatus());
|
||||
verify(equipmentRepository).save(testEquipment);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteEquipment_shouldThrowException_whenNotExists() {
|
||||
UUID nonExistentId = UUID.randomUUID();
|
||||
when(equipmentRepository.findByIdAndIsDeletedFalse(nonExistentId))
|
||||
.thenReturn(Optional.empty());
|
||||
|
||||
assertThrows(
|
||||
BusinessException.class, () -> equipmentService.deleteEquipment(nonExistentId));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getEquipmentsByProject_shouldReturnList() {
|
||||
List<Equipment> equipmentList = Arrays.asList(testEquipment);
|
||||
when(equipmentRepository.findByProjectIdAndIsDeletedFalse(projectId))
|
||||
.thenReturn(equipmentList);
|
||||
|
||||
List<Equipment> result = equipmentService.getEquipmentsByProject(projectId);
|
||||
|
||||
assertEquals(1, result.size());
|
||||
assertEquals(testEquipment, result.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getEquipmentsBySpaceNode_shouldReturnList() {
|
||||
UUID spaceNodeId = UUID.randomUUID();
|
||||
testEquipment.setSpaceNodeId(spaceNodeId);
|
||||
List<Equipment> equipmentList = Arrays.asList(testEquipment);
|
||||
when(equipmentRepository.findBySpaceNodeIdAndIsDeletedFalse(spaceNodeId))
|
||||
.thenReturn(equipmentList);
|
||||
|
||||
List<Equipment> result = equipmentService.getEquipmentsBySpaceNode(spaceNodeId);
|
||||
|
||||
assertEquals(1, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getEquipmentsByType_shouldReturnList() {
|
||||
List<Equipment> equipmentList = Arrays.asList(testEquipment);
|
||||
when(equipmentRepository.findByEquipmentTypeAndIsDeletedFalse(EquipmentType.HVAC))
|
||||
.thenReturn(equipmentList);
|
||||
|
||||
List<Equipment> result = equipmentService.getEquipmentsByType(EquipmentType.HVAC);
|
||||
|
||||
assertEquals(1, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getEquipmentsByOwnership_shouldReturnList() {
|
||||
List<Equipment> equipmentList = Arrays.asList(testEquipment);
|
||||
when(equipmentRepository.findByOwnershipTypeAndIsDeletedFalse(OwnershipType.PROJECT))
|
||||
.thenReturn(equipmentList);
|
||||
|
||||
List<Equipment> result = equipmentService.getEquipmentsByOwnership(OwnershipType.PROJECT);
|
||||
|
||||
assertEquals(1, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getEquipmentStatsByType_shouldReturnStatsMap() {
|
||||
Object[] stat1 = new Object[] {EquipmentType.HVAC, 5L};
|
||||
Object[] stat2 = new Object[] {EquipmentType.ELEVATOR, 3L};
|
||||
when(equipmentRepository.countByType(projectId)).thenReturn(Arrays.asList(stat1, stat2));
|
||||
|
||||
Map<String, Long> result = equipmentService.getEquipmentStatsByType(projectId);
|
||||
|
||||
assertEquals(2, result.size());
|
||||
assertEquals(5L, result.get("HVAC"));
|
||||
assertEquals(3L, result.get("ELEVATOR"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getEquipmentStatsByOwnership_shouldReturnStatsMap() {
|
||||
Object[] stat1 = new Object[] {OwnershipType.PROJECT, 10L};
|
||||
Object[] stat2 = new Object[] {OwnershipType.OWNER, 5L};
|
||||
when(equipmentRepository.countByOwnership(projectId))
|
||||
.thenReturn(Arrays.asList(stat1, stat2));
|
||||
|
||||
Map<String, Long> result = equipmentService.getEquipmentStatsByOwnership(projectId);
|
||||
|
||||
assertEquals(2, result.size());
|
||||
assertEquals(10L, result.get("PROJECT"));
|
||||
assertEquals(5L, result.get("OWNER"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void countByProject_shouldReturnCount() {
|
||||
when(equipmentRepository.countByProject(projectId)).thenReturn(15L);
|
||||
|
||||
long result = equipmentService.countByProject(projectId);
|
||||
|
||||
assertEquals(15L, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteEquipmentBatch_shouldDeleteMultipleEquipments() {
|
||||
UUID id1 = UUID.randomUUID();
|
||||
UUID id2 = UUID.randomUUID();
|
||||
Equipment eq1 = new Equipment();
|
||||
eq1.setId(id1);
|
||||
Equipment eq2 = new Equipment();
|
||||
eq2.setId(id2);
|
||||
|
||||
when(equipmentRepository.findByIdAndIsDeletedFalse(id1)).thenReturn(Optional.of(eq1));
|
||||
when(equipmentRepository.findByIdAndIsDeletedFalse(id2)).thenReturn(Optional.of(eq2));
|
||||
when(equipmentRepository.save(any(Equipment.class)))
|
||||
.thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
equipmentService.deleteEquipmentBatch(Arrays.asList(id1, id2));
|
||||
|
||||
assertTrue(eq1.getIsDeleted());
|
||||
assertTrue(eq2.getIsDeleted());
|
||||
verify(equipmentRepository, times(2)).save(any(Equipment.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateEquipment_shouldUpdateAllFields() {
|
||||
Equipment updateData = new Equipment();
|
||||
updateData.setEquipmentName("New Name");
|
||||
updateData.setEquipmentType(EquipmentType.FIRE_PROTECTION);
|
||||
updateData.setSystemType(SystemType.FIRE_PROTECTION);
|
||||
updateData.setOwnershipType(OwnershipType.OWNER);
|
||||
updateData.setOwningEntityId(UUID.randomUUID());
|
||||
updateData.setOwningEntityName("Owner Entity");
|
||||
updateData.setAssetCode("ASSET-001");
|
||||
updateData.setSerialNumber("SN-001");
|
||||
updateData.setModel("Model-X");
|
||||
updateData.setManufacturer("Manufacturer-X");
|
||||
updateData.setSupplier("Supplier-X");
|
||||
updateData.setStatus(EquipmentStatus.MAINTENANCE);
|
||||
updateData.setOperationStatus("running");
|
||||
updateData.setInstallationLocation("1F");
|
||||
updateData.setInstallationDate(LocalDate.of(2023, 1, 1));
|
||||
updateData.setDesignLifeYears(20);
|
||||
updateData.setRatedPower(new BigDecimal("100.50"));
|
||||
updateData.setRatedVoltage("220V");
|
||||
updateData.setRatedCurrent(new BigDecimal("50.25"));
|
||||
updateData.setMaintenanceVendor("Vendor-X");
|
||||
updateData.setMaintenanceVendorContact("Contact-X");
|
||||
updateData.setMaintenanceVendorPhone("123456");
|
||||
updateData.setMaintenanceContractNo("CONTRACT-001");
|
||||
updateData.setMaintenanceContractStart(LocalDate.of(2023, 1, 1));
|
||||
updateData.setMaintenanceContractEnd(LocalDate.of(2024, 1, 1));
|
||||
updateData.setEnergyConsumptionStandard(new BigDecimal("80.00"));
|
||||
updateData.setInspectionCycle(12);
|
||||
updateData.setNextInspectionDate(LocalDate.of(2024, 6, 1));
|
||||
updateData.setLastInspectionDate(LocalDate.of(2023, 6, 1));
|
||||
updateData.setLastInspectionResult("合格");
|
||||
updateData.setSpecialEquipmentType("特种设备");
|
||||
updateData.setSpecialEquipmentCert("CERT-001");
|
||||
updateData.setRemarks("测试备注");
|
||||
|
||||
when(equipmentRepository.findByIdAndIsDeletedFalse(testId))
|
||||
.thenReturn(Optional.of(testEquipment));
|
||||
when(equipmentRepository.save(any(Equipment.class)))
|
||||
.thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
Equipment result = equipmentService.updateEquipment(testId, updateData);
|
||||
|
||||
assertEquals("New Name", result.getEquipmentName());
|
||||
assertEquals(EquipmentType.FIRE_PROTECTION, result.getEquipmentType());
|
||||
assertEquals(SystemType.FIRE_PROTECTION, result.getSystemType());
|
||||
assertEquals(OwnershipType.OWNER, result.getOwnershipType());
|
||||
assertEquals("ASSET-001", result.getAssetCode());
|
||||
assertEquals("SN-001", result.getSerialNumber());
|
||||
assertEquals("Model-X", result.getModel());
|
||||
assertEquals("Manufacturer-X", result.getManufacturer());
|
||||
assertEquals("Supplier-X", result.getSupplier());
|
||||
assertEquals(EquipmentStatus.MAINTENANCE, result.getStatus());
|
||||
assertEquals("running", result.getOperationStatus());
|
||||
assertEquals("1F", result.getInstallationLocation());
|
||||
assertEquals(LocalDate.of(2023, 1, 1), result.getInstallationDate());
|
||||
assertEquals(20, result.getDesignLifeYears());
|
||||
assertEquals(new BigDecimal("100.50"), result.getRatedPower());
|
||||
assertEquals("220V", result.getRatedVoltage());
|
||||
assertEquals(new BigDecimal("50.25"), result.getRatedCurrent());
|
||||
assertEquals("Vendor-X", result.getMaintenanceVendor());
|
||||
assertEquals("Contact-X", result.getMaintenanceVendorContact());
|
||||
assertEquals("123456", result.getMaintenanceVendorPhone());
|
||||
assertEquals("CONTRACT-001", result.getMaintenanceContractNo());
|
||||
assertEquals(LocalDate.of(2023, 1, 1), result.getMaintenanceContractStart());
|
||||
assertEquals(LocalDate.of(2024, 1, 1), result.getMaintenanceContractEnd());
|
||||
assertEquals(new BigDecimal("80.00"), result.getEnergyConsumptionStandard());
|
||||
assertEquals(12, result.getInspectionCycle());
|
||||
assertEquals(LocalDate.of(2024, 6, 1), result.getNextInspectionDate());
|
||||
assertEquals(LocalDate.of(2023, 6, 1), result.getLastInspectionDate());
|
||||
assertEquals("合格", result.getLastInspectionResult());
|
||||
assertEquals("特种设备", result.getSpecialEquipmentType());
|
||||
assertEquals("CERT-001", result.getSpecialEquipmentCert());
|
||||
assertEquals("测试备注", result.getRemarks());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,60 +1,38 @@
|
|||
package com.ether.pms.auth.annotation;
|
||||
|
||||
import com.ether.pms.auth.entity.AuditLog;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 审计日志注解
|
||||
* 用于标记需要记录审计日志的方法
|
||||
*/
|
||||
/** 审计日志注解 用于标记需要记录审计日志的方法 */
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface OperationLog {
|
||||
|
||||
/**
|
||||
* 操作描述
|
||||
*/
|
||||
/** 操作描述 */
|
||||
String operation();
|
||||
|
||||
/**
|
||||
* 功能模块
|
||||
*/
|
||||
/** 功能模块 */
|
||||
String module();
|
||||
|
||||
/**
|
||||
* 操作类型
|
||||
*/
|
||||
/** 操作类型 */
|
||||
AuditLog.ActionType action() default AuditLog.ActionType.UPDATE;
|
||||
|
||||
/**
|
||||
* 目标对象类型(支持SpEL表达式)
|
||||
*/
|
||||
/** 目标对象类型(支持SpEL表达式) */
|
||||
String targetType() default "";
|
||||
|
||||
/**
|
||||
* 目标对象ID(支持SpEL表达式)
|
||||
*/
|
||||
/** 目标对象ID(支持SpEL表达式) */
|
||||
String targetId() default "";
|
||||
|
||||
/**
|
||||
* 操作内容(支持SpEL表达式)
|
||||
*/
|
||||
/** 操作内容(支持SpEL表达式) */
|
||||
String content() default "";
|
||||
|
||||
/**
|
||||
* 是否记录请求参数
|
||||
*/
|
||||
/** 是否记录请求参数 */
|
||||
boolean recordParams() default true;
|
||||
|
||||
/**
|
||||
* 是否记录响应结果
|
||||
*/
|
||||
/** 是否记录响应结果 */
|
||||
boolean recordResult() default false;
|
||||
|
||||
/**
|
||||
* 需要过滤的敏感字段(不记录)
|
||||
*/
|
||||
/** 需要过滤的敏感字段(不记录) */
|
||||
String[] sensitiveFields() default {"password", "token", "secret", "creditCard"};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
package com.ether.pms.auth.aspect;
|
||||
|
||||
import com.ether.pms.auth.annotation.OperationLog;
|
||||
import com.ether.pms.auth.entity.AuditLog.ActionType;
|
||||
import com.ether.pms.auth.entity.AuditLog.Status;
|
||||
import com.ether.pms.auth.service.AuditLogService;
|
||||
import com.ether.pms.auth.util.SecurityUtils;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
|
|
@ -18,12 +22,6 @@ import org.springframework.stereotype.Component;
|
|||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
|
|
@ -111,7 +109,8 @@ public class AuditLogAspect {
|
|||
}
|
||||
|
||||
private HttpServletRequest getRequest() {
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
ServletRequestAttributes attributes =
|
||||
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (attributes != null) {
|
||||
return attributes.getRequest();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,16 @@
|
|||
package com.ether.pms.auth.config;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Configuration
|
||||
@EnableAsync
|
||||
public class AsyncConfig {
|
||||
|
||||
/**
|
||||
* 审计日志异步执行器
|
||||
*/
|
||||
/** 审计日志异步执行器 */
|
||||
@Bean("auditLogExecutor")
|
||||
public Executor auditLogExecutor() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
|
|
@ -21,7 +18,8 @@ public class AsyncConfig {
|
|||
executor.setMaxPoolSize(5);
|
||||
executor.setQueueCapacity(100);
|
||||
executor.setThreadNamePrefix("audit-log-");
|
||||
executor.setRejectedExecutionHandler(new java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy());
|
||||
executor.setRejectedExecutionHandler(
|
||||
new java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy());
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import jakarta.servlet.FilterChain;
|
|||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
|
@ -15,25 +17,21 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.access.intercept.AuthorizationFilter;
|
||||
import org.springframework.security.web.context.SecurityContextRepository;
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.context.SecurityContextRepository;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@RequiredArgsConstructor
|
||||
|
|
@ -53,25 +51,33 @@ public class SecurityConfig {
|
|||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.csrf(AbstractHttpConfigurer::disable)
|
||||
http.csrf(AbstractHttpConfigurer::disable)
|
||||
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
|
||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED))
|
||||
.securityContext(context -> context
|
||||
.securityContextRepository(securityContextRepository())
|
||||
)
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.requestMatchers("/api/auth/login", "/api/auth/logout", "/api/auth/refresh").permitAll()
|
||||
.sessionManagement(
|
||||
session -> session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED))
|
||||
.securityContext(
|
||||
context -> context.securityContextRepository(securityContextRepository()))
|
||||
.authorizeHttpRequests(
|
||||
auth ->
|
||||
auth.requestMatchers(
|
||||
"/api/auth/login",
|
||||
"/api/auth/logout",
|
||||
"/api/auth/refresh")
|
||||
.permitAll()
|
||||
// 根据配置动态控制 Swagger/API 文档访问
|
||||
// 开发环境:允许所有用户访问(便于开发调试)
|
||||
// 生产环境:即使 URL 匹配,springdoc 也会返回 404(因为已禁用)
|
||||
.requestMatchers("/api-docs/**", "/swagger-ui/**", "/swagger-ui.html", "/v3/api-docs/**").permitAll()
|
||||
.requestMatchers("/actuator/**").hasRole("ADMIN") // ✅ 需要管理员权限
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.exceptionHandling(ex -> ex
|
||||
.authenticationEntryPoint(unauthorizedEntryPoint())
|
||||
)
|
||||
.requestMatchers(
|
||||
"/api-docs/**",
|
||||
"/swagger-ui/**",
|
||||
"/swagger-ui.html",
|
||||
"/v3/api-docs/**")
|
||||
.permitAll()
|
||||
.requestMatchers("/actuator/**")
|
||||
.hasRole("ADMIN") // ✅ 需要管理员权限
|
||||
.anyRequest()
|
||||
.authenticated())
|
||||
.exceptionHandling(ex -> ex.authenticationEntryPoint(unauthorizedEntryPoint()))
|
||||
.addFilterBefore(jwtAuthenticationFilter(), AuthorizationFilter.class);
|
||||
|
||||
return http.build();
|
||||
|
|
@ -80,7 +86,8 @@ public class SecurityConfig {
|
|||
@Bean
|
||||
public CorsConfigurationSource corsConfigurationSource() {
|
||||
CorsConfiguration configuration = new CorsConfiguration();
|
||||
configuration.setAllowedOrigins(List.of(
|
||||
configuration.setAllowedOrigins(
|
||||
List.of(
|
||||
"http://127.0.0.1:5173",
|
||||
"http://127.0.0.1:5174",
|
||||
"http://127.0.0.1:5175",
|
||||
|
|
@ -96,8 +103,7 @@ public class SecurityConfig {
|
|||
"http://localhost:5177",
|
||||
"http://localhost:5178",
|
||||
"http://localhost:5179",
|
||||
"http://localhost:5180"
|
||||
));
|
||||
"http://localhost:5180"));
|
||||
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
|
||||
configuration.setAllowedHeaders(List.of("*"));
|
||||
configuration.setAllowCredentials(true);
|
||||
|
|
@ -125,14 +131,18 @@ public class SecurityConfig {
|
|||
public OncePerRequestFilter jwtAuthenticationFilter() {
|
||||
return new OncePerRequestFilter() {
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
protected void doFilterInternal(
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
String token = resolveToken(request);
|
||||
|
||||
if (token != null && jwtTokenProvider.validateToken(token)) {
|
||||
String username = jwtTokenProvider.getUsernameFromToken(token);
|
||||
List<GrantedAuthority> authorities = jwtTokenProvider.getAuthoritiesFromToken(token);
|
||||
List<GrantedAuthority> authorities =
|
||||
jwtTokenProvider.getAuthoritiesFromToken(token);
|
||||
|
||||
UsernamePasswordAuthenticationToken authentication =
|
||||
new UsernamePasswordAuthenticationToken(username, token, authorities);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@ import com.ether.pms.auth.entity.AuditLog;
|
|||
import com.ether.pms.auth.service.AuditLogService;
|
||||
import com.ether.pms.common.ApiResponse;
|
||||
import com.ether.pms.common.util.PaginationValidator;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.domain.Page;
|
||||
|
|
@ -14,12 +19,6 @@ import org.springframework.format.annotation.DateTimeFormat;
|
|||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/audit-logs")
|
||||
@RequiredArgsConstructor
|
||||
|
|
@ -29,9 +28,7 @@ public class AuditLogController {
|
|||
|
||||
private final AuditLogService auditLogService;
|
||||
|
||||
/**
|
||||
* 查询审计日志列表(最近30天)
|
||||
*/
|
||||
/** 查询审计日志列表(最近30天) */
|
||||
@GetMapping
|
||||
public ApiResponse<Page<AuditLog>> list(
|
||||
@RequestParam(defaultValue = "0") int page,
|
||||
|
|
@ -39,57 +36,53 @@ public class AuditLogController {
|
|||
@RequestParam(required = false) String module,
|
||||
@RequestParam(required = false) String action,
|
||||
@RequestParam(required = false) String username,
|
||||
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startDate,
|
||||
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endDate) {
|
||||
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
|
||||
LocalDateTime startDate,
|
||||
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
|
||||
LocalDateTime endDate) {
|
||||
|
||||
// 使用 PaginationValidator 校验分页参数(防止 OOM 和数据库过载)
|
||||
int safeSize = PaginationValidator.getSafeSize(size);
|
||||
|
||||
Pageable pageable = PageRequest.of(page, safeSize, Sort.by("createdAt").descending());
|
||||
Page<AuditLog> result = auditLogService.searchLogs(module, action, username, startDate, endDate, pageable);
|
||||
Page<AuditLog> result =
|
||||
auditLogService.searchLogs(module, action, username, startDate, endDate, pageable);
|
||||
|
||||
return ApiResponse.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模块列表(用于筛选)
|
||||
*/
|
||||
/** 获取模块列表(用于筛选) */
|
||||
@GetMapping("/modules")
|
||||
public ApiResponse<List<Map<String, String>>> getModules() {
|
||||
List<Map<String, String>> modules = Arrays.asList(
|
||||
List<Map<String, String>> modules =
|
||||
Arrays.asList(
|
||||
Map.of("value", "USER", "label", "用户管理"),
|
||||
Map.of("value", "ROLE", "label", "角色管理"),
|
||||
Map.of("value", "PERMISSION", "label", "权限管理"),
|
||||
Map.of("value", "PROJECT", "label", "项目管理"),
|
||||
Map.of("value", "AUTH", "label", "登录认证")
|
||||
);
|
||||
Map.of("value", "AUTH", "label", "登录认证"));
|
||||
return ApiResponse.success(modules);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取操作类型列表(用于筛选)
|
||||
*/
|
||||
/** 获取操作类型列表(用于筛选) */
|
||||
@GetMapping("/actions")
|
||||
public ApiResponse<List<Map<String, String>>> getActions() {
|
||||
List<Map<String, String>> actions = Arrays.stream(AuditLog.ActionType.values())
|
||||
.map(action -> Map.of(
|
||||
List<Map<String, String>> actions =
|
||||
Arrays.stream(AuditLog.ActionType.values())
|
||||
.map(
|
||||
action ->
|
||||
Map.of(
|
||||
"value", action.name(),
|
||||
"label", action.getDesc()
|
||||
))
|
||||
"label", action.getDesc()))
|
||||
.collect(Collectors.toList());
|
||||
return ApiResponse.success(actions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最近30天的日志统计
|
||||
*/
|
||||
/** 获取最近30天的日志统计 */
|
||||
@GetMapping("/stats")
|
||||
public ApiResponse<Map<String, Object>> getStats() {
|
||||
long count = auditLogService.getRecentLogCount();
|
||||
return ApiResponse.success(Map.of(
|
||||
"total", count,
|
||||
"retentionDays", 30,
|
||||
"description", "最近30天的审计日志数量"
|
||||
));
|
||||
return ApiResponse.success(
|
||||
Map.of("total", count, "retentionDays", 30, "description", "最近30天的审计日志数量"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,15 +7,14 @@ import jakarta.servlet.http.HttpServletRequest;
|
|||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/auth")
|
||||
@RequiredArgsConstructor
|
||||
|
|
@ -27,16 +26,17 @@ public class AuthController {
|
|||
|
||||
@PostMapping("/login")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> login(
|
||||
@Valid @RequestBody LoginRequest request,
|
||||
HttpServletRequest httpRequest) {
|
||||
@Valid @RequestBody LoginRequest request, HttpServletRequest httpRequest) {
|
||||
|
||||
String ip = getClientIp(httpRequest);
|
||||
Map<String, Object> result = loginService.login(request.getUsername(), request.getPassword(), ip);
|
||||
Map<String, Object> result =
|
||||
loginService.login(request.getUsername(), request.getPassword(), ip);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@PostMapping("/logout")
|
||||
public ResponseEntity<ApiResponse<Void>> logout(@RequestHeader(value = "Authorization", required = false) String token) {
|
||||
public ResponseEntity<ApiResponse<Void>> logout(
|
||||
@RequestHeader(value = "Authorization", required = false) String token) {
|
||||
return ResponseEntity.ok(ApiResponse.success());
|
||||
}
|
||||
|
||||
|
|
@ -78,8 +78,8 @@ public class AuthController {
|
|||
}
|
||||
|
||||
String username = jwtTokenProvider.getUsernameFromToken(jwt);
|
||||
String newToken = jwtTokenProvider.generateToken(
|
||||
jwtTokenProvider.getUserIdFromToken(jwt), username);
|
||||
String newToken =
|
||||
jwtTokenProvider.generateToken(jwtTokenProvider.getUserIdFromToken(jwt), username);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("token", newToken);
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
package com.ether.pms.auth.controller;
|
||||
|
||||
import com.ether.pms.auth.controller.dto.DataAccessRequest;
|
||||
import com.ether.pms.auth.entity.DataAccess;
|
||||
import com.ether.pms.auth.service.DataAccessService;
|
||||
import com.ether.pms.auth.util.SecurityUtils;
|
||||
import com.ether.pms.common.ApiResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/data-access")
|
||||
@RequiredArgsConstructor
|
||||
@Validated
|
||||
public class DataAccessController {
|
||||
|
||||
private final DataAccessService dataAccessService;
|
||||
|
||||
@Deprecated
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Void>> grantAccess(@Valid @RequestBody DataAccessRequest request) {
|
||||
UUID currentUserId = SecurityUtils.getCurrentUserId();
|
||||
if (currentUserId == null) {
|
||||
return ResponseEntity.status(401).body(ApiResponse.error(401, "未登录"));
|
||||
}
|
||||
dataAccessService.grantAccess(
|
||||
request.getDataType(),
|
||||
request.getDataId(),
|
||||
request.getAccessType(),
|
||||
request.getAccessId(),
|
||||
request.getAccessLevel(),
|
||||
currentUserId
|
||||
);
|
||||
return ResponseEntity.ok(ApiResponse.success());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> revokeAccess(@PathVariable UUID id) {
|
||||
dataAccessService.revokeAccess(id);
|
||||
return ResponseEntity.ok(ApiResponse.success());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<List<DataAccess>>> getDataAccess(
|
||||
@RequestParam String dataType,
|
||||
@RequestParam UUID dataId) {
|
||||
return ResponseEntity.ok(ApiResponse.success(dataAccessService.getDataAccess(dataType, dataId)));
|
||||
}
|
||||
}
|
||||
|
|
@ -10,18 +10,17 @@ import com.ether.pms.auth.entity.User;
|
|||
import com.ether.pms.auth.service.DeptService;
|
||||
import com.ether.pms.common.ApiResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 部门管理控制器
|
||||
*
|
||||
* <p>提供部门相关的RESTful API接口,包括部门树查询、创建部门、获取部门成员等功能。</p>
|
||||
* <p>提供部门相关的RESTful API接口,包括部门树查询、创建部门、获取部门成员等功能。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -35,9 +34,7 @@ public class DeptController {
|
|||
|
||||
private final DeptService deptService;
|
||||
|
||||
/**
|
||||
* 获取部门树
|
||||
*/
|
||||
/** 获取部门树 */
|
||||
@GetMapping("/tree")
|
||||
public ApiResponse<List<DeptVO>> getDeptTree() {
|
||||
List<Dept> depts = deptService.getDeptTree();
|
||||
|
|
@ -45,27 +42,19 @@ public class DeptController {
|
|||
return ApiResponse.success(tree);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有启用的部门列表
|
||||
*/
|
||||
/** 获取所有启用的部门列表 */
|
||||
@GetMapping
|
||||
public ApiResponse<List<Dept>> getAllDepts() {
|
||||
return ApiResponse.success(deptService.getActiveDepts());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID获取部门
|
||||
*/
|
||||
/** 根据ID获取部门 */
|
||||
@GetMapping("/{id}")
|
||||
public ApiResponse<Dept> getById(@PathVariable UUID id) {
|
||||
return deptService.getById(id)
|
||||
.map(ApiResponse::success)
|
||||
.orElse(ApiResponse.error("部门不存在"));
|
||||
return deptService.getById(id).map(ApiResponse::success).orElse(ApiResponse.error("部门不存在"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建部门
|
||||
*/
|
||||
/** 创建部门 */
|
||||
@PostMapping
|
||||
@OperationLog(operation = "创建部门", module = "DEPT", action = AuditLog.ActionType.CREATE)
|
||||
public ApiResponse<Dept> createDept(@RequestBody @Valid DeptDTO dto) {
|
||||
|
|
@ -79,9 +68,7 @@ public class DeptController {
|
|||
return ApiResponse.success(deptService.createDept(dept));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新部门
|
||||
*/
|
||||
/** 更新部门 */
|
||||
@PutMapping("/{id}")
|
||||
@OperationLog(operation = "更新部门", module = "DEPT", action = AuditLog.ActionType.UPDATE)
|
||||
public ApiResponse<Dept> updateDept(@PathVariable UUID id, @RequestBody @Valid DeptDTO dto) {
|
||||
|
|
@ -95,9 +82,7 @@ public class DeptController {
|
|||
return ApiResponse.success(deptService.updateDept(id, dept));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除部门
|
||||
*/
|
||||
/** 删除部门 */
|
||||
@DeleteMapping("/{id}")
|
||||
@OperationLog(operation = "删除部门", module = "DEPT", action = AuditLog.ActionType.DELETE)
|
||||
public ApiResponse<Void> deleteDept(@PathVariable UUID id) {
|
||||
|
|
@ -105,18 +90,15 @@ public class DeptController {
|
|||
return ApiResponse.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门成员
|
||||
*/
|
||||
/** 获取部门成员 */
|
||||
@GetMapping("/{deptId}/members")
|
||||
public ApiResponse<List<UserVO>> getDeptMembers(@PathVariable UUID deptId) {
|
||||
List<User> members = deptService.getDeptEmployees(deptId);
|
||||
return ApiResponse.success(members.stream().map(UserVO::fromEntity).collect(Collectors.toList()));
|
||||
return ApiResponse.success(
|
||||
members.stream().map(UserVO::fromEntity).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据部门类型查询部门
|
||||
*/
|
||||
/** 根据部门类型查询部门 */
|
||||
@GetMapping("/by-type/{deptType}")
|
||||
public ApiResponse<List<Dept>> getByType(@PathVariable String deptType) {
|
||||
return ApiResponse.success(deptService.getByType(deptType));
|
||||
|
|
@ -124,9 +106,12 @@ public class DeptController {
|
|||
|
||||
private List<DeptVO> buildDeptTree(List<Dept> depts, UUID parentId) {
|
||||
return depts.stream()
|
||||
.filter(d -> (parentId == null && d.getParentId() == null) ||
|
||||
(parentId != null && parentId.equals(d.getParentId())))
|
||||
.map(d -> {
|
||||
.filter(
|
||||
d ->
|
||||
(parentId == null && d.getParentId() == null)
|
||||
|| (parentId != null && parentId.equals(d.getParentId())))
|
||||
.map(
|
||||
d -> {
|
||||
DeptVO vo = DeptVO.fromEntity(d);
|
||||
vo.setChildren(buildDeptTree(depts, d.getId()));
|
||||
return vo;
|
||||
|
|
|
|||
|
|
@ -2,35 +2,36 @@ package com.ether.pms.auth.controller;
|
|||
|
||||
import com.ether.pms.auth.entity.Permission;
|
||||
import com.ether.pms.auth.service.PermissionService;
|
||||
import com.ether.pms.auth.util.SecurityUtils;
|
||||
import com.ether.pms.auth.vo.MenuVO;
|
||||
import com.ether.pms.auth.vo.PermissionVO;
|
||||
import com.ether.pms.common.ApiResponse;
|
||||
import com.ether.pms.common.util.PaginationValidator;
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import com.ether.pms.common.util.PaginationValidator;
|
||||
|
||||
/**
|
||||
* 权限管理REST接口控制器
|
||||
*
|
||||
* <p>提供权限(Permission)相关的HTTP API接口,包括权限的增删改查、类型筛选、菜单权限获取等功能。
|
||||
* 所有接口均遵循RESTful设计规范,返回统一的ApiResponse格式。</p>
|
||||
* <p>提供权限(Permission)相关的HTTP API接口,包括权限的增删改查、类型筛选、菜单权限获取等功能。 所有接口均遵循RESTful设计规范,返回统一的ApiResponse格式。
|
||||
*
|
||||
* <p>主要接口:
|
||||
*
|
||||
* <p>主要接口:</p>
|
||||
* <ul>
|
||||
* <li>GET /api/auth/permissions - 查询所有权限</li>
|
||||
* <li>GET /api/auth/permissions/{id} - 根据ID查询权限</li>
|
||||
* <li>GET /api/auth/permissions/type/{type} - 根据类型查询权限</li>
|
||||
* <li>GET /api/auth/permissions/menus - 查询所有菜单权限</li>
|
||||
* <li>POST /api/auth/permissions - 创建权限</li>
|
||||
* <li>PUT /api/auth/permissions/{id} - 更新权限</li>
|
||||
* <li>DELETE /api/auth/permissions/{id} - 删除权限</li>
|
||||
* <li>GET /api/auth/permissions - 查询所有权限
|
||||
* <li>GET /api/auth/permissions/{id} - 根据ID查询权限
|
||||
* <li>GET /api/auth/permissions/type/{type} - 根据类型查询权限
|
||||
* <li>GET /api/auth/permissions/menus - 查询所有菜单权限
|
||||
* <li>POST /api/auth/permissions - 创建权限
|
||||
* <li>PUT /api/auth/permissions/{id} - 更新权限
|
||||
* <li>DELETE /api/auth/permissions/{id} - 删除权限
|
||||
* </ul>
|
||||
*
|
||||
* @author Ether开发团队
|
||||
|
|
@ -75,7 +76,7 @@ public class PermissionController {
|
|||
/**
|
||||
* 根据权限类型查询权限列表
|
||||
*
|
||||
* <p>按权限类型筛选,如MENU、BUTTON、API等。</p>
|
||||
* <p>按权限类型筛选,如MENU、BUTTON、API等。
|
||||
*
|
||||
* @param type 权限类型
|
||||
* @return 包含该类型权限列表的响应
|
||||
|
|
@ -88,46 +89,48 @@ public class PermissionController {
|
|||
/**
|
||||
* 查询所有菜单权限
|
||||
*
|
||||
* <p>获取type为MENU的所有权限,通常用于前端菜单渲染。</p>
|
||||
* <p>获取type为MENU的所有权限,通常用于管理员查看所有菜单配置。
|
||||
*
|
||||
* @return 包含菜单权限列表的响应
|
||||
*/
|
||||
@GetMapping("/menus")
|
||||
public ResponseEntity<ApiResponse<List<Permission>>> findMenus() {
|
||||
@GetMapping("/all-menus")
|
||||
public ResponseEntity<ApiResponse<List<Permission>>> findAllMenus() {
|
||||
return ResponseEntity.ok(ApiResponse.success(permissionService.findMenuPermissions()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新权限
|
||||
*
|
||||
* <p>创建一个新的权限。</p>
|
||||
* <p>创建一个新的权限。
|
||||
*
|
||||
* @param permission 要创建的权限信息(请求体)
|
||||
* @return 包含创建后权限信息的响应
|
||||
*/
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Permission>> create(@Valid @RequestBody Permission permission) {
|
||||
public ResponseEntity<ApiResponse<Permission>> create(
|
||||
@Valid @RequestBody Permission permission) {
|
||||
return ResponseEntity.ok(ApiResponse.success(permissionService.create(permission)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新权限信息
|
||||
*
|
||||
* <p>更新指定权限的信息。</p>
|
||||
* <p>更新指定权限的信息。
|
||||
*
|
||||
* @param id 要更新的权限ID
|
||||
* @param permission 包含新数据的权限信息(请求体)
|
||||
* @return 包含更新后权限信息的响应
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Permission>> update(@PathVariable UUID id, @Valid @RequestBody Permission permission) {
|
||||
public ResponseEntity<ApiResponse<Permission>> update(
|
||||
@PathVariable UUID id, @Valid @RequestBody Permission permission) {
|
||||
return ResponseEntity.ok(ApiResponse.success(permissionService.update(id, permission)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除权限
|
||||
*
|
||||
* <p>删除指定的权限。</p>
|
||||
* <p>删除指定的权限。
|
||||
*
|
||||
* @param id 要删除的权限ID
|
||||
* @return 空响应(表示操作成功)
|
||||
|
|
@ -137,4 +140,36 @@ public class PermissionController {
|
|||
permissionService.delete(id);
|
||||
return ResponseEntity.ok(ApiResponse.success());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户菜单
|
||||
*
|
||||
* <p>返回当前用户有权限访问的菜单,用于前端动态渲染菜单。
|
||||
*
|
||||
* @param projectId 项目ID(可选)
|
||||
* @return 用户菜单列表
|
||||
*/
|
||||
@GetMapping("/menus")
|
||||
public ResponseEntity<ApiResponse<List<MenuVO>>> getUserMenus(
|
||||
@RequestParam(required = false) UUID projectId) {
|
||||
UUID userId = SecurityUtils.getCurrentUserId();
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(permissionService.getUserMenus(userId, projectId)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户权限
|
||||
*
|
||||
* <p>返回当前用户的所有权限标识,用于按钮级别权限控制。
|
||||
*
|
||||
* @param projectId 项目ID(可选)
|
||||
* @return 用户权限标识列表
|
||||
*/
|
||||
@GetMapping("/permissions")
|
||||
public ResponseEntity<ApiResponse<PermissionVO>> getUserPermissions(
|
||||
@RequestParam(required = false) UUID projectId) {
|
||||
UUID userId = SecurityUtils.getCurrentUserId();
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(permissionService.getUserPermissions(userId, projectId)));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.ether.pms.auth.controller;
|
||||
|
||||
import com.ether.pms.auth.service.PermissionService;
|
||||
import com.ether.pms.auth.vo.PermissionTreeVO;
|
||||
import com.ether.pms.common.ApiResponse;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/permissions")
|
||||
@RequiredArgsConstructor
|
||||
public class PermissionTreeController {
|
||||
|
||||
private final PermissionService permissionService;
|
||||
|
||||
@GetMapping("/tree")
|
||||
public ResponseEntity<ApiResponse<List<PermissionTreeVO>>> getPermissionTree() {
|
||||
return ResponseEntity.ok(ApiResponse.success(permissionService.getPermissionTree()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +1,5 @@
|
|||
package com.ether.pms.auth.controller;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.ether.pms.auth.annotation.OperationLog;
|
||||
import com.ether.pms.auth.controller.dto.AddProjectMemberDTO;
|
||||
import com.ether.pms.auth.controller.dto.PageResponse;
|
||||
|
|
@ -25,16 +11,27 @@ import com.ether.pms.auth.entity.User;
|
|||
import com.ether.pms.auth.service.UserManagementService;
|
||||
import com.ether.pms.common.ApiResponse;
|
||||
import com.ether.pms.common.util.PaginationValidator;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 项目成员管理控制器
|
||||
*
|
||||
* <p>提供项目成员相关的RESTful API接口,用于管理项目成员列表、添加成员、移除成员等功能。</p>
|
||||
* <p>提供项目成员相关的RESTful API接口,用于管理项目成员列表、添加成员、移除成员等功能。
|
||||
*
|
||||
* <p>所有接口路径前缀为/api/auth/projects/{projectId}/members。</p>
|
||||
* <p>所有接口路径前缀为/api/auth/projects/{projectId}/members。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -52,7 +49,7 @@ public class ProjectMemberController {
|
|||
/**
|
||||
* 查询项目成员列表
|
||||
*
|
||||
* <p>分页返回指定项目下的所有成员信息,包含角色信息。</p>
|
||||
* <p>分页返回指定项目下的所有成员信息,包含角色信息。
|
||||
*
|
||||
* @param projectId 项目唯一标识符
|
||||
* @param page 页码,从1开始
|
||||
|
|
@ -74,17 +71,19 @@ public class ProjectMemberController {
|
|||
if (start < 0) start = 0;
|
||||
if (start > staffList.size()) start = staffList.size();
|
||||
int end = Math.min(start + safeSize, staffList.size());
|
||||
List<ProjectMemberVO> pageData = staffList.subList(start, end).stream()
|
||||
List<ProjectMemberVO> pageData =
|
||||
staffList.subList(start, end).stream()
|
||||
.map(ProjectMemberVO::fromEntity)
|
||||
.collect(Collectors.toList());
|
||||
PageResponse<ProjectMemberVO> response = new PageResponse<>(pageData, (long) staffList.size(), pageIndex + 1, size);
|
||||
PageResponse<ProjectMemberVO> response =
|
||||
new PageResponse<>(pageData, (long) staffList.size(), pageIndex + 1, size);
|
||||
return ApiResponse.success(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可添加到项目的成员列表(企业员工)
|
||||
*
|
||||
* <p>返回尚未加入该项目的所有企业员工列表,支持模糊搜索用户。</p>
|
||||
* <p>返回尚未加入该项目的所有企业员工列表,支持模糊搜索用户。
|
||||
*
|
||||
* @param projectId 项目唯一标识符
|
||||
* @param search 搜索关键字(可选),支持用户名和真实姓名模糊匹配
|
||||
|
|
@ -92,60 +91,65 @@ public class ProjectMemberController {
|
|||
*/
|
||||
@GetMapping("/{projectId}/available-members")
|
||||
public ApiResponse<List<UserVO>> getAvailableMembers(
|
||||
@PathVariable UUID projectId,
|
||||
@RequestParam(required = false) String search) {
|
||||
@PathVariable UUID projectId, @RequestParam(required = false) String search) {
|
||||
List<User> users = userManagementService.findEnterpriseUsers();
|
||||
|
||||
// 支持模糊搜索
|
||||
if (search != null && !search.isBlank()) {
|
||||
String keyword = search.toLowerCase();
|
||||
users = users.stream()
|
||||
.filter(u -> u.getUsername().toLowerCase().contains(keyword)
|
||||
|| (u.getRealName() != null && u.getRealName().toLowerCase().contains(keyword)))
|
||||
users =
|
||||
users.stream()
|
||||
.filter(
|
||||
u ->
|
||||
u.getUsername().toLowerCase().contains(keyword)
|
||||
|| (u.getRealName() != null
|
||||
&& u.getRealName()
|
||||
.toLowerCase()
|
||||
.contains(keyword)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
return ApiResponse.success(users.stream()
|
||||
.map(UserVO::fromEntity)
|
||||
.collect(Collectors.toList()));
|
||||
return ApiResponse.success(
|
||||
users.stream().map(UserVO::fromEntity).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加项目成员
|
||||
*
|
||||
* <p>将指定用户添加到项目中,并分配多个角色。</p>
|
||||
* <p>将指定用户添加到项目中,并分配多个角色。
|
||||
*
|
||||
* @param projectId 项目唯一标识符
|
||||
* @param dto 添加项目成员的请求数据
|
||||
* @return 成功响应
|
||||
*/
|
||||
@PostMapping("/{projectId}/members")
|
||||
@OperationLog(operation = "添加项目成员", module = "PROJECT_MEMBER", action = AuditLog.ActionType.CREATE)
|
||||
@OperationLog(
|
||||
operation = "添加项目成员",
|
||||
module = "PROJECT_MEMBER",
|
||||
action = AuditLog.ActionType.CREATE)
|
||||
public ApiResponse<Void> addProjectMember(
|
||||
@PathVariable UUID projectId,
|
||||
@Valid @RequestBody AddProjectMemberDTO dto) {
|
||||
@PathVariable UUID projectId, @Valid @RequestBody AddProjectMemberDTO dto) {
|
||||
userManagementService.assignStaffToProject(
|
||||
dto.getUserId(),
|
||||
projectId,
|
||||
dto.getStaffType(),
|
||||
dto.getRoleIds());
|
||||
dto.getUserId(), projectId, dto.getStaffType(), dto.getRoleIds());
|
||||
return ApiResponse.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除项目成员
|
||||
*
|
||||
* <p>将指定用户从项目中移除。</p>
|
||||
* <p>将指定用户从项目中移除。
|
||||
*
|
||||
* @param projectId 项目唯一标识符
|
||||
* @param userId 用户唯一标识符
|
||||
* @return 成功响应
|
||||
*/
|
||||
@DeleteMapping("/{projectId}/members/{userId}")
|
||||
@OperationLog(operation = "移除项目成员", module = "PROJECT_MEMBER", action = AuditLog.ActionType.DELETE)
|
||||
@OperationLog(
|
||||
operation = "移除项目成员",
|
||||
module = "PROJECT_MEMBER",
|
||||
action = AuditLog.ActionType.DELETE)
|
||||
public ApiResponse<Void> removeProjectMember(
|
||||
@PathVariable UUID projectId,
|
||||
@PathVariable UUID userId) {
|
||||
@PathVariable UUID projectId, @PathVariable UUID userId) {
|
||||
userManagementService.removeStaffFromProject(userId, projectId);
|
||||
return ApiResponse.success();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,37 +7,34 @@ import com.ether.pms.auth.entity.Role;
|
|||
import com.ether.pms.auth.entity.User;
|
||||
import com.ether.pms.auth.service.RoleService;
|
||||
import com.ether.pms.common.ApiResponse;
|
||||
import com.ether.pms.common.util.PaginationValidator;
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import com.ether.pms.common.util.PaginationValidator;
|
||||
|
||||
/**
|
||||
* 角色管理REST接口控制器
|
||||
*
|
||||
* <p>提供角色(Role)相关的HTTP API接口,包括角色的增删改查、权限分配、用户关联等功能。
|
||||
* 所有接口均遵循RESTful设计规范,返回统一的ApiResponse格式。</p>
|
||||
* <p>提供角色(Role)相关的HTTP API接口,包括角色的增删改查、权限分配、用户关联等功能。 所有接口均遵循RESTful设计规范,返回统一的ApiResponse格式。
|
||||
*
|
||||
* <p>主要接口:
|
||||
*
|
||||
* <p>主要接口:</p>
|
||||
* <ul>
|
||||
* <li>GET /api/auth/roles - 查询所有角色</li>
|
||||
* <li>GET /api/auth/roles/{id} - 根据ID查询角色</li>
|
||||
* <li>GET /api/auth/roles/project/{projectId} - 根据项目ID查询角色</li>
|
||||
* <li>POST /api/auth/roles - 创建角色</li>
|
||||
* <li>PUT /api/auth/roles/{id} - 更新角色</li>
|
||||
* <li>DELETE /api/auth/roles/{id} - 删除角色</li>
|
||||
* <li>POST /api/auth/roles/{id}/permissions - 为角色分配权限</li>
|
||||
* <li>GET /api/auth/roles/{id}/permissions - 获取角色的权限</li>
|
||||
* <li>GET /api/auth/roles/{id}/users - 获取拥有某角色的用户</li>
|
||||
* <li>GET /api/auth/roles - 查询所有角色
|
||||
* <li>GET /api/auth/roles/{id} - 根据ID查询角色
|
||||
* <li>GET /api/auth/roles/project/{projectId} - 根据项目ID查询角色
|
||||
* <li>POST /api/auth/roles - 创建角色
|
||||
* <li>PUT /api/auth/roles/{id} - 更新角色
|
||||
* <li>DELETE /api/auth/roles/{id} - 删除角色
|
||||
* <li>POST /api/auth/roles/{id}/permissions - 为角色分配权限
|
||||
* <li>GET /api/auth/roles/{id}/permissions - 获取角色的权限
|
||||
* <li>GET /api/auth/roles/{id}/users - 获取拥有某角色的用户
|
||||
* </ul>
|
||||
*
|
||||
* @author Ether开发团队
|
||||
|
|
@ -82,7 +79,7 @@ public class RoleController {
|
|||
/**
|
||||
* 根据项目ID查询角色列表
|
||||
*
|
||||
* <p>获取指定项目下的所有角色。</p>
|
||||
* <p>获取指定项目下的所有角色。
|
||||
*
|
||||
* @param projectId 项目ID
|
||||
* @return 包含该项目角色列表的响应
|
||||
|
|
@ -95,7 +92,7 @@ public class RoleController {
|
|||
/**
|
||||
* 创建新角色
|
||||
*
|
||||
* <p>创建一个新的角色,记录审计日志。</p>
|
||||
* <p>创建一个新的角色,记录审计日志。
|
||||
*
|
||||
* @param role 要创建的角色信息(请求体)
|
||||
* @return 包含创建后角色信息的响应
|
||||
|
|
@ -109,7 +106,7 @@ public class RoleController {
|
|||
/**
|
||||
* 更新角色信息
|
||||
*
|
||||
* <p>更新指定角色的信息,记录审计日志。</p>
|
||||
* <p>更新指定角色的信息,记录审计日志。
|
||||
*
|
||||
* @param id 要更新的角色ID
|
||||
* @param role 包含新数据的角色信息(请求体)
|
||||
|
|
@ -117,14 +114,15 @@ public class RoleController {
|
|||
*/
|
||||
@PutMapping("/{id}")
|
||||
@OperationLog(operation = "更新角色", module = "ROLE", action = AuditLog.ActionType.UPDATE)
|
||||
public ResponseEntity<ApiResponse<Role>> update(@PathVariable UUID id, @Valid @RequestBody Role role) {
|
||||
public ResponseEntity<ApiResponse<Role>> update(
|
||||
@PathVariable UUID id, @Valid @RequestBody Role role) {
|
||||
return ResponseEntity.ok(ApiResponse.success(roleService.update(id, role)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除角色
|
||||
*
|
||||
* <p>删除指定的角色,记录审计日志。</p>
|
||||
* <p>删除指定的角色,记录审计日志。
|
||||
*
|
||||
* @param id 要删除的角色ID
|
||||
* @return 空响应(表示操作成功)
|
||||
|
|
@ -139,7 +137,7 @@ public class RoleController {
|
|||
/**
|
||||
* 为角色分配权限
|
||||
*
|
||||
* <p>替换角色原有的所有权限,记录审计日志。</p>
|
||||
* <p>替换角色原有的所有权限,记录审计日志。
|
||||
*
|
||||
* @param id 角色ID
|
||||
* @param permissionIds 要分配的权限ID列表(请求体)
|
||||
|
|
@ -148,8 +146,7 @@ public class RoleController {
|
|||
@PostMapping("/{id}/permissions")
|
||||
@OperationLog(operation = "分配权限", module = "ROLE", action = AuditLog.ActionType.ASSIGN)
|
||||
public ResponseEntity<ApiResponse<Void>> assignPermissions(
|
||||
@PathVariable UUID id,
|
||||
@Valid @RequestBody List<UUID> permissionIds) {
|
||||
@PathVariable UUID id, @Valid @RequestBody List<UUID> permissionIds) {
|
||||
roleService.assignPermissions(id, permissionIds);
|
||||
return ResponseEntity.ok(ApiResponse.success());
|
||||
}
|
||||
|
|
@ -157,7 +154,7 @@ public class RoleController {
|
|||
/**
|
||||
* 获取角色的所有权限
|
||||
*
|
||||
* <p>查询指定角色关联的所有权限。</p>
|
||||
* <p>查询指定角色关联的所有权限。
|
||||
*
|
||||
* @param id 角色ID
|
||||
* @return 包含角色权限列表的响应
|
||||
|
|
@ -170,7 +167,7 @@ public class RoleController {
|
|||
/**
|
||||
* 获取拥有某角色的所有用户
|
||||
*
|
||||
* <p>查询所有拥有指定角色ID的用户。</p>
|
||||
* <p>查询所有拥有指定角色ID的用户。
|
||||
*
|
||||
* @param id 角色ID
|
||||
* @return 包含用户列表的响应
|
||||
|
|
|
|||
|
|
@ -7,19 +7,15 @@ import com.ether.pms.auth.service.SysConfigService;
|
|||
import com.ether.pms.common.ApiResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 系统配置控制器
|
||||
* 提供系统配置的 RESTful API 接口
|
||||
* 包括配置的查询、更新等操作
|
||||
* 系统配置控制器 提供系统配置的 RESTful API 接口 包括配置的查询、更新等操作
|
||||
*
|
||||
* @author Ether Team
|
||||
* @since 1.0.0
|
||||
|
|
@ -30,14 +26,11 @@ import java.util.UUID;
|
|||
@Validated
|
||||
public class SysConfigController {
|
||||
|
||||
/**
|
||||
* 系统配置服务对象
|
||||
*/
|
||||
/** 系统配置服务对象 */
|
||||
private final SysConfigService sysConfigService;
|
||||
|
||||
/**
|
||||
* 获取所有配置项
|
||||
* 返回系统中所有配置的键值对
|
||||
* 获取所有配置项 返回系统中所有配置的键值对
|
||||
*
|
||||
* @return 配置键值对 Map
|
||||
*/
|
||||
|
|
@ -58,8 +51,7 @@ public class SysConfigController {
|
|||
}
|
||||
|
||||
/**
|
||||
* 更新单个配置项
|
||||
* 根据配置键更新对应的配置值,并记录审计日志
|
||||
* 更新单个配置项 根据配置键更新对应的配置值,并记录审计日志
|
||||
*
|
||||
* @param configKey 配置键
|
||||
* @param request 更新请求对象,包含新的配置值
|
||||
|
|
@ -68,33 +60,29 @@ public class SysConfigController {
|
|||
@PutMapping("/{configKey}")
|
||||
@OperationLog(operation = "更新系统设置", module = "SYSTEM", action = AuditLog.ActionType.UPDATE)
|
||||
public ResponseEntity<ApiResponse<SysConfig>> updateConfig(
|
||||
@PathVariable String configKey,
|
||||
@Valid @RequestBody ConfigUpdateRequest request) {
|
||||
return ResponseEntity.ok(ApiResponse.success(sysConfigService.updateConfig(configKey, request.getConfigValue())));
|
||||
@PathVariable String configKey, @Valid @RequestBody ConfigUpdateRequest request) {
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(
|
||||
sysConfigService.updateConfig(configKey, request.getConfigValue())));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新配置项
|
||||
* 同时更新多个配置键值对,并记录审计日志
|
||||
* 批量更新配置项 同时更新多个配置键值对,并记录审计日志
|
||||
*
|
||||
* @param configs 配置键值对 Map
|
||||
* @return 更新后的配置键值对 Map
|
||||
*/
|
||||
@PutMapping
|
||||
@OperationLog(operation = "更新系统设置", module = "SYSTEM", action = AuditLog.ActionType.UPDATE)
|
||||
public ResponseEntity<ApiResponse<Map<String, String>>> updateConfigs(@RequestBody Map<String, String> configs) {
|
||||
public ResponseEntity<ApiResponse<Map<String, String>>> updateConfigs(
|
||||
@RequestBody Map<String, String> configs) {
|
||||
return ResponseEntity.ok(ApiResponse.success(sysConfigService.updateConfigs(configs)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置更新请求对象
|
||||
* 用于接收单个配置项的更新请求
|
||||
*/
|
||||
/** 配置更新请求对象 用于接收单个配置项的更新请求 */
|
||||
@Data
|
||||
public static class ConfigUpdateRequest {
|
||||
/**
|
||||
* 新的配置值
|
||||
*/
|
||||
/** 新的配置值 */
|
||||
@NotBlank(message = "配置值不能为空")
|
||||
private String configValue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,29 +11,27 @@ import com.ether.pms.auth.service.UserProjectService;
|
|||
import com.ether.pms.auth.service.UserService;
|
||||
import com.ether.pms.common.ApiResponse;
|
||||
import com.ether.pms.common.util.BatchOperationValidator;
|
||||
import com.ether.pms.common.util.PaginationValidator;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import com.ether.pms.common.util.PaginationValidator;
|
||||
|
||||
/**
|
||||
* 用户管理控制器
|
||||
*
|
||||
* <p>提供用户相关的RESTful API接口,包括用户CRUD、密码管理、角色分配、项目关联等功能。</p>
|
||||
* <p>提供用户相关的RESTful API接口,包括用户CRUD、密码管理、角色分配、项目关联等功能。
|
||||
*
|
||||
* <p>所有接口路径前缀为/api/auth/users,使用JSON格式进行数据交互。</p>
|
||||
* <p>所有接口路径前缀为/api/auth/users,使用JSON格式进行数据交互。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -47,15 +45,17 @@ public class UserController {
|
|||
|
||||
/** 用户服务 */
|
||||
private final UserService userService;
|
||||
|
||||
/** 用户项目关联服务 */
|
||||
private final UserProjectService userProjectService;
|
||||
|
||||
/** 用户管理服务 */
|
||||
private final UserManagementService userManagementService;
|
||||
|
||||
/**
|
||||
* 分页查询用户列表
|
||||
*
|
||||
* <p>返回系统中所有用户的信息,包含关联的角色列表,支持分页。</p>
|
||||
* <p>返回系统中所有用户的信息,包含关联的角色列表,支持分页。
|
||||
*
|
||||
* @param page 页码,从0开始,默认为0
|
||||
* @param size 每页大小,默认为10
|
||||
|
|
@ -72,7 +72,7 @@ public class UserController {
|
|||
/**
|
||||
* 根据ID获取用户信息
|
||||
*
|
||||
* <p>根据用户唯一标识符查询指定用户的详细信息。</p>
|
||||
* <p>根据用户唯一标识符查询指定用户的详细信息。
|
||||
*
|
||||
* @param id 用户唯一标识符
|
||||
* @return 包含用户信息的成功响应
|
||||
|
|
@ -85,7 +85,7 @@ public class UserController {
|
|||
/**
|
||||
* 创建新用户
|
||||
*
|
||||
* <p>创建一个新的用户账号,需要提供用户名、密码等基本信息。</p>
|
||||
* <p>创建一个新的用户账号,需要提供用户名、密码等基本信息。
|
||||
*
|
||||
* @param user 待创建的用户信息
|
||||
* @return 包含创建成功的用户信息的成功响应
|
||||
|
|
@ -99,7 +99,7 @@ public class UserController {
|
|||
/**
|
||||
* 更新用户信息
|
||||
*
|
||||
* <p>更新指定用户的个人信息,如真实姓名、手机号、邮箱等。</p>
|
||||
* <p>更新指定用户的个人信息,如真实姓名、手机号、邮箱等。
|
||||
*
|
||||
* @param id 用户唯一标识符
|
||||
* @param user 包含更新信息的用户对象
|
||||
|
|
@ -107,14 +107,15 @@ public class UserController {
|
|||
*/
|
||||
@PutMapping("/{id}")
|
||||
@OperationLog(operation = "更新用户", module = "USER", action = AuditLog.ActionType.UPDATE)
|
||||
public ResponseEntity<ApiResponse<User>> update(@PathVariable UUID id, @Valid @RequestBody User user) {
|
||||
public ResponseEntity<ApiResponse<User>> update(
|
||||
@PathVariable UUID id, @Valid @RequestBody User user) {
|
||||
return ResponseEntity.ok(ApiResponse.success(userService.update(id, user)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
*
|
||||
* <p>根据用户ID删除指定用户账号。</p>
|
||||
* <p>根据用户ID删除指定用户账号。
|
||||
*
|
||||
* @param id 用户唯一标识符
|
||||
* @return 成功响应
|
||||
|
|
@ -129,7 +130,7 @@ public class UserController {
|
|||
/**
|
||||
* 修改用户密码
|
||||
*
|
||||
* <p>用户修改自己的密码,需要提供原密码和新密码。</p>
|
||||
* <p>用户修改自己的密码,需要提供原密码和新密码。
|
||||
*
|
||||
* @param id 用户唯一标识符
|
||||
* @param request 包含原密码和新密码的请求对象
|
||||
|
|
@ -138,8 +139,7 @@ public class UserController {
|
|||
@PutMapping("/{id}/password")
|
||||
@OperationLog(operation = "修改密码", module = "USER", action = AuditLog.ActionType.UPDATE)
|
||||
public ResponseEntity<ApiResponse<Void>> updatePassword(
|
||||
@PathVariable UUID id,
|
||||
@Valid @RequestBody PasswordRequest request) {
|
||||
@PathVariable UUID id, @Valid @RequestBody PasswordRequest request) {
|
||||
userService.updatePassword(id, request.getOldPassword(), request.getNewPassword());
|
||||
return ResponseEntity.ok(ApiResponse.success());
|
||||
}
|
||||
|
|
@ -147,7 +147,7 @@ public class UserController {
|
|||
/**
|
||||
* 分配用户角色
|
||||
*
|
||||
* <p>为指定用户分配一个或多个角色,替换现有的角色。</p>
|
||||
* <p>为指定用户分配一个或多个角色,替换现有的角色。
|
||||
*
|
||||
* @param id 用户唯一标识符
|
||||
* @param roleIds 要分配的角色ID列表
|
||||
|
|
@ -156,8 +156,7 @@ public class UserController {
|
|||
@PostMapping("/{id}/roles")
|
||||
@OperationLog(operation = "分配角色", module = "USER", action = AuditLog.ActionType.ASSIGN)
|
||||
public ResponseEntity<ApiResponse<Void>> assignRoles(
|
||||
@PathVariable UUID id,
|
||||
@Valid @RequestBody List<UUID> roleIds) {
|
||||
@PathVariable UUID id, @Valid @RequestBody List<UUID> roleIds) {
|
||||
BatchOperationValidator.validateAssignmentSize(roleIds.size());
|
||||
userService.assignRoles(id, roleIds);
|
||||
return ResponseEntity.ok(ApiResponse.success());
|
||||
|
|
@ -166,7 +165,7 @@ public class UserController {
|
|||
/**
|
||||
* 获取用户参与的项目列表
|
||||
*
|
||||
* <p>查询指定用户参与的所有项目及其在项目中的角色。</p>
|
||||
* <p>查询指定用户参与的所有项目及其在项目中的角色。
|
||||
*
|
||||
* @param id 用户唯一标识符
|
||||
* @return 包含用户参与项目列表的成功响应
|
||||
|
|
@ -179,7 +178,7 @@ public class UserController {
|
|||
/**
|
||||
* 添加用户到项目
|
||||
*
|
||||
* <p>将指定用户添加到某个项目中,并设置用户在项目中的角色。</p>
|
||||
* <p>将指定用户添加到某个项目中,并设置用户在项目中的角色。
|
||||
*
|
||||
* @param id 用户唯一标识符
|
||||
* @param request 包含项目ID和角色信息的请求对象
|
||||
|
|
@ -187,8 +186,7 @@ public class UserController {
|
|||
*/
|
||||
@PostMapping("/{id}/projects")
|
||||
public ResponseEntity<ApiResponse<Void>> addUserToProject(
|
||||
@PathVariable UUID id,
|
||||
@Valid @RequestBody UserProjectRequest request) {
|
||||
@PathVariable UUID id, @Valid @RequestBody UserProjectRequest request) {
|
||||
userProjectService.addUserToProject(id, request.getProjectId(), request.getRoleInProject());
|
||||
return ResponseEntity.ok(ApiResponse.success());
|
||||
}
|
||||
|
|
@ -196,7 +194,7 @@ public class UserController {
|
|||
/**
|
||||
* 从项目中移除用户
|
||||
*
|
||||
* <p>将指定用户从某个项目中移除,删除用户与项目的关联关系。</p>
|
||||
* <p>将指定用户从某个项目中移除,删除用户与项目的关联关系。
|
||||
*
|
||||
* @param id 用户唯一标识符
|
||||
* @param projectId 项目唯一标识符
|
||||
|
|
@ -204,8 +202,7 @@ public class UserController {
|
|||
*/
|
||||
@DeleteMapping("/{id}/projects/{projectId}")
|
||||
public ResponseEntity<ApiResponse<Void>> removeUserFromProject(
|
||||
@PathVariable UUID id,
|
||||
@PathVariable UUID projectId) {
|
||||
@PathVariable UUID id, @PathVariable UUID projectId) {
|
||||
userProjectService.removeUserFromProject(id, projectId);
|
||||
return ResponseEntity.ok(ApiResponse.success());
|
||||
}
|
||||
|
|
@ -213,20 +210,22 @@ public class UserController {
|
|||
/**
|
||||
* 获取企业员工列表(用于项目管理添加成员)
|
||||
*
|
||||
* <p>返回所有企业员工的用户信息列表。</p>
|
||||
* <p>返回所有企业员工的用户信息列表。
|
||||
*
|
||||
* @return 包含企业员工列表的成功响应
|
||||
*/
|
||||
@GetMapping("/enterprise")
|
||||
public ResponseEntity<ApiResponse<List<UserVO>>> getEnterpriseUsers() {
|
||||
List<User> users = userManagementService.findEnterpriseUsers();
|
||||
return ResponseEntity.ok(ApiResponse.success(users.stream().map(UserVO::fromEntity).collect(Collectors.toList())));
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(
|
||||
users.stream().map(UserVO::fromEntity).collect(Collectors.toList())));
|
||||
}
|
||||
|
||||
/**
|
||||
* 密码修改请求对象
|
||||
*
|
||||
* <p>包含修改密码所需的原密码和新密码。</p>
|
||||
* <p>包含修改密码所需的原密码和新密码。
|
||||
*/
|
||||
@Data
|
||||
public static class PasswordRequest {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
package com.ether.pms.auth.controller.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 添加项目成员请求DTO
|
||||
*
|
||||
* <p>用于接收将用户添加到项目的请求数据。</p>
|
||||
* <p>用于接收将用户添加到项目的请求数据。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -18,10 +17,7 @@ import lombok.Data;
|
|||
@Data
|
||||
public class AddProjectMemberDTO {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
* 要添加到项目的用户唯一标识符
|
||||
*/
|
||||
/** 用户ID 要添加到项目的用户唯一标识符 */
|
||||
@NotNull(message = "用户ID不能为空")
|
||||
private UUID userId;
|
||||
|
||||
|
|
@ -31,9 +27,6 @@ public class AddProjectMemberDTO {
|
|||
*/
|
||||
private String staffType;
|
||||
|
||||
/**
|
||||
* 角色ID列表
|
||||
* 可选参数,分配的角色ID列表
|
||||
*/
|
||||
/** 角色ID列表 可选参数,分配的角色ID列表 */
|
||||
private List<UUID> roleIds;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
package com.ether.pms.auth.controller.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 创建企业用户请求DTO
|
||||
*
|
||||
* <p>用于接收创建企业用户的请求数据,包含用户基础信息和企业扩展信息。</p>
|
||||
* <p>用于接收创建企业用户的请求数据,包含用户基础信息和企业扩展信息。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -18,65 +17,35 @@ import java.util.UUID;
|
|||
@Data
|
||||
public class CreateEnterpriseUserDTO {
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
* 用于登录系统
|
||||
*/
|
||||
/** 用户名 用于登录系统 */
|
||||
@NotBlank(message = "用户名不能为空")
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
* 用户登录密码
|
||||
*/
|
||||
/** 密码 用户登录密码 */
|
||||
@NotBlank(message = "密码不能为空")
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 真实姓名
|
||||
* 用户的真实姓名
|
||||
*/
|
||||
/** 真实姓名 用户的真实姓名 */
|
||||
private String realName;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
* 中国大陆手机号
|
||||
*/
|
||||
/** 手机号码 中国大陆手机号 */
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 电子邮箱
|
||||
* 用户的邮箱地址
|
||||
*/
|
||||
/** 电子邮箱 用户的邮箱地址 */
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 员工工号
|
||||
* 企业内部员工编号
|
||||
*/
|
||||
/** 员工工号 企业内部员工编号 */
|
||||
private String employeeNo;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
* 用户所属的部门标识符
|
||||
*/
|
||||
/** 部门ID 用户所属的部门标识符 */
|
||||
private UUID deptId;
|
||||
|
||||
/**
|
||||
* 职位
|
||||
* 用户在企业中的职位
|
||||
*/
|
||||
/** 职位 用户在企业中的职位 */
|
||||
private String position;
|
||||
|
||||
/**
|
||||
* 入职日期
|
||||
* 员工加入企业的日期
|
||||
*/
|
||||
/** 入职日期 员工加入企业的日期 */
|
||||
private LocalDate entryDate;
|
||||
|
||||
/**
|
||||
* 员工类别
|
||||
* 标识员工类型:ENTERPRISE(普通员工)、MANAGEMENT(管理层)
|
||||
*/
|
||||
/** 员工类别 标识员工类型:ENTERPRISE(普通员工)、MANAGEMENT(管理层) */
|
||||
private String userCategory;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
package com.ether.pms.auth.controller.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import java.util.UUID;
|
||||
|
||||
@Data
|
||||
public class DataAccessRequest {
|
||||
@NotBlank(message = "数据类型不能为空")
|
||||
private String dataType;
|
||||
|
||||
@NotNull(message = "数据ID不能为空")
|
||||
private UUID dataId;
|
||||
|
||||
@NotBlank(message = "访问类型不能为空")
|
||||
private String accessType;
|
||||
|
||||
private UUID accessId;
|
||||
|
||||
@NotBlank(message = "访问级别不能为空")
|
||||
private String accessLevel = "read";
|
||||
}
|
||||
|
|
@ -1,14 +1,13 @@
|
|||
package com.ether.pms.auth.controller.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 部门数据传输对象
|
||||
*
|
||||
* <p>用于接收创建或更新部门的请求数据。</p>
|
||||
* <p>用于接收创建或更新部门的请求数据。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -17,35 +16,20 @@ import java.util.UUID;
|
|||
@Data
|
||||
public class DeptDTO {
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
/** 部门名称 */
|
||||
@NotBlank(message = "部门名称不能为空")
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 上级部门ID
|
||||
*/
|
||||
/** 上级部门ID */
|
||||
private UUID parentId;
|
||||
|
||||
/**
|
||||
* 部门类型
|
||||
* ADMIN: 行政管理
|
||||
* ENGINEERING: 工程部
|
||||
* SECURITY: 安保部
|
||||
* CS: 客服部
|
||||
* CLEANING: 保洁部
|
||||
*/
|
||||
/** 部门类型 ADMIN: 行政管理 ENGINEERING: 工程部 SECURITY: 安保部 CS: 客服部 CLEANING: 保洁部 */
|
||||
private String deptType = "ADMIN";
|
||||
|
||||
/**
|
||||
* 部门负责人ID
|
||||
*/
|
||||
/** 部门负责人ID */
|
||||
private UUID leaderId;
|
||||
|
||||
/**
|
||||
* 排序序号
|
||||
*/
|
||||
/** 排序序号 */
|
||||
private Integer sortOrder;
|
||||
|
||||
private String status = "ACTIVE";
|
||||
|
|
|
|||
|
|
@ -1,16 +1,15 @@
|
|||
package com.ether.pms.auth.controller.dto;
|
||||
|
||||
import com.ether.pms.auth.entity.Dept;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 部门视图对象
|
||||
*
|
||||
* <p>用于返回部门信息的视图对象,包含部门基本信息和子部门列表。</p>
|
||||
* <p>用于返回部门信息的视图对象,包含部门基本信息和子部门列表。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -19,49 +18,31 @@ import java.util.UUID;
|
|||
@Data
|
||||
public class DeptVO {
|
||||
|
||||
/**
|
||||
* 部门唯一标识符
|
||||
*/
|
||||
/** 部门唯一标识符 */
|
||||
private UUID id;
|
||||
|
||||
/**
|
||||
* 上级部门ID
|
||||
*/
|
||||
/** 上级部门ID */
|
||||
private UUID parentId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
/** 部门名称 */
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 部门类型
|
||||
*/
|
||||
/** 部门类型 */
|
||||
private String deptType;
|
||||
|
||||
/**
|
||||
* 部门类型描述
|
||||
*/
|
||||
/** 部门类型描述 */
|
||||
private String deptTypeDesc;
|
||||
|
||||
/**
|
||||
* 部门负责人ID
|
||||
*/
|
||||
/** 部门负责人ID */
|
||||
private UUID leaderId;
|
||||
|
||||
/**
|
||||
* 排序序号
|
||||
*/
|
||||
/** 排序序号 */
|
||||
private Integer sortOrder;
|
||||
|
||||
/**
|
||||
* 部门状态
|
||||
*/
|
||||
/** 部门状态 */
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 子部门列表
|
||||
*/
|
||||
/** 子部门列表 */
|
||||
private List<DeptVO> children = new ArrayList<>();
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
package com.ether.pms.auth.controller.dto;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分页响应DTO
|
||||
*
|
||||
* <p>用于返回分页数据的统一格式,包含内容列表、分页信息和总数。</p>
|
||||
* <p>用于返回分页数据的统一格式,包含内容列表、分页信息和总数。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -20,24 +19,16 @@ import java.util.List;
|
|||
@AllArgsConstructor
|
||||
public class PageResponse<T> {
|
||||
|
||||
/**
|
||||
* 分页数据内容列表
|
||||
*/
|
||||
/** 分页数据内容列表 */
|
||||
private List<T> content;
|
||||
|
||||
/**
|
||||
* 当前页数据条数
|
||||
*/
|
||||
/** 当前页数据条数 */
|
||||
private int size;
|
||||
|
||||
/**
|
||||
* 当前页码
|
||||
*/
|
||||
/** 当前页码 */
|
||||
private int page;
|
||||
|
||||
/**
|
||||
* 数据总条数
|
||||
*/
|
||||
/** 数据总条数 */
|
||||
private long totalElements;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,18 +2,16 @@ package com.ether.pms.auth.controller.dto;
|
|||
|
||||
import com.ether.pms.auth.entity.ProjectStaff;
|
||||
import com.ether.pms.auth.entity.ProjectStaffRole;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 项目成员视图对象
|
||||
*
|
||||
* <p>用于返回项目成员信息,包含用户基本信息、角色信息和加入时间。</p>
|
||||
* <p>用于返回项目成员信息,包含用户基本信息、角色信息和加入时间。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -22,59 +20,37 @@ import java.util.stream.Collectors;
|
|||
@Data
|
||||
public class ProjectMemberVO {
|
||||
|
||||
/**
|
||||
* 用户唯一标识符
|
||||
*/
|
||||
/** 用户唯一标识符 */
|
||||
private UUID id;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
/** 用户名 */
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 真实姓名
|
||||
*/
|
||||
/** 真实姓名 */
|
||||
private String realName;
|
||||
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
/** 手机号 */
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
/** 邮箱 */
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 用户类型
|
||||
*/
|
||||
/** 用户类型 */
|
||||
private String userType;
|
||||
|
||||
/**
|
||||
* 用户状态
|
||||
*/
|
||||
/** 用户状态 */
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 员工类型
|
||||
*/
|
||||
/** 员工类型 */
|
||||
private String staffType;
|
||||
|
||||
/**
|
||||
* 项目中的角色列表
|
||||
*/
|
||||
/** 项目中的角色列表 */
|
||||
private List<String> roles;
|
||||
|
||||
/**
|
||||
* 角色名称列表(用于显示)
|
||||
*/
|
||||
/** 角色名称列表(用于显示) */
|
||||
private String roleNames;
|
||||
|
||||
/**
|
||||
* 加入时间
|
||||
*/
|
||||
/** 加入时间 */
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
/**
|
||||
|
|
@ -91,7 +67,8 @@ public class ProjectMemberVO {
|
|||
vo.setPhone(staff.getUser().getPhone());
|
||||
vo.setEmail(staff.getUser().getEmail());
|
||||
vo.setUserType(staff.getUser().getUserType());
|
||||
vo.setStatus(staff.getUser().getStatus() != null ? staff.getUser().getStatus().name() : null);
|
||||
vo.setStatus(
|
||||
staff.getUser().getStatus() != null ? staff.getUser().getStatus().name() : null);
|
||||
vo.setStaffType(staff.getStaffType());
|
||||
vo.setCreatedAt(staff.getCreatedAt());
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,10 @@ package com.ether.pms.auth.controller.dto;
|
|||
|
||||
import com.ether.pms.auth.entity.Role;
|
||||
import com.ether.pms.auth.entity.User;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RoleWithUsersDTO {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ package com.ether.pms.auth.controller.dto;
|
|||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UserProjectRequest {
|
||||
|
|
|
|||
|
|
@ -1,16 +1,15 @@
|
|||
package com.ether.pms.auth.controller.dto;
|
||||
|
||||
import com.ether.pms.auth.entity.User;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 用户视图对象
|
||||
*
|
||||
* <p>用于返回用户信息的简化视图,包含用户基本信息、部门信息和角色列表。</p>
|
||||
* <p>用于返回用户信息的简化视图,包含用户基本信息、部门信息和角色列表。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -19,64 +18,40 @@ import java.util.stream.Collectors;
|
|||
@Data
|
||||
public class UserVO {
|
||||
|
||||
/**
|
||||
* 用户唯一标识符
|
||||
*/
|
||||
/** 用户唯一标识符 */
|
||||
private UUID id;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
/** 用户名 */
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 真实姓名
|
||||
*/
|
||||
/** 真实姓名 */
|
||||
private String realName;
|
||||
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
/** 手机号 */
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
/** 邮箱 */
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 用户类型
|
||||
*/
|
||||
/** 用户类型 */
|
||||
private String userType;
|
||||
|
||||
/**
|
||||
* 用户状态
|
||||
*/
|
||||
/** 用户状态 */
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
/** 部门ID */
|
||||
private UUID deptId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
/** 部门名称 */
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 角色列表
|
||||
*/
|
||||
/** 角色列表 */
|
||||
private List<RoleInfo> roles;
|
||||
|
||||
/**
|
||||
* 角色名称列表(逗号分隔)
|
||||
*/
|
||||
/** 角色名称列表(逗号分隔) */
|
||||
private String roleNames;
|
||||
|
||||
/**
|
||||
* 角色信息内部类
|
||||
*/
|
||||
/** 角色信息内部类 */
|
||||
@Data
|
||||
public static class RoleInfo {
|
||||
private UUID id;
|
||||
|
|
@ -103,8 +78,10 @@ public class UserVO {
|
|||
|
||||
// 转换角色信息
|
||||
if (user.getRoles() != null && !user.getRoles().isEmpty()) {
|
||||
List<RoleInfo> roleInfos = user.getRoles().stream()
|
||||
.map(role -> {
|
||||
List<RoleInfo> roleInfos =
|
||||
user.getRoles().stream()
|
||||
.map(
|
||||
role -> {
|
||||
RoleInfo info = new RoleInfo();
|
||||
info.setId(role.getId());
|
||||
info.setCode(role.getCode());
|
||||
|
|
@ -113,7 +90,8 @@ public class UserVO {
|
|||
})
|
||||
.collect(Collectors.toList());
|
||||
vo.setRoles(roleInfos);
|
||||
vo.setRoleNames(roleInfos.stream().map(RoleInfo::getName).collect(Collectors.joining("、")));
|
||||
vo.setRoleNames(
|
||||
roleInfos.stream().map(RoleInfo::getName).collect(Collectors.joining("、")));
|
||||
}
|
||||
|
||||
return vo;
|
||||
|
|
|
|||
|
|
@ -2,12 +2,11 @@ package com.ether.pms.auth.controller.dto;
|
|||
|
||||
import com.ether.pms.auth.entity.Role;
|
||||
import com.ether.pms.auth.entity.User;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UserWithRolesDTO {
|
||||
|
|
@ -51,9 +50,8 @@ public class UserWithRolesDTO {
|
|||
dto.setLastLoginIp(user.getLastLoginIp());
|
||||
dto.setCreatedAt(user.getCreatedAt());
|
||||
if (user.getRoles() != null) {
|
||||
dto.setRoles(user.getRoles().stream()
|
||||
.map(RoleInfo::fromRole)
|
||||
.collect(Collectors.toList()));
|
||||
dto.setRoles(
|
||||
user.getRoles().stream().map(RoleInfo::fromRole).collect(Collectors.toList()));
|
||||
}
|
||||
return dto;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
package com.ether.pms.auth.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
import org.hibernate.annotations.JdbcTypeCode;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Table(name = "sys_audit_log", indexes = {
|
||||
@Table(
|
||||
name = "sys_audit_log",
|
||||
indexes = {
|
||||
@Index(name = "idx_audit_log_created_at", columnList = "createdAt"),
|
||||
@Index(name = "idx_audit_log_user_id", columnList = "userId"),
|
||||
@Index(name = "idx_audit_log_module", columnList = "module"),
|
||||
|
|
|
|||
|
|
@ -1,45 +0,0 @@
|
|||
package com.ether.pms.auth.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Table(name = "biz_data_access")
|
||||
@Data
|
||||
@Deprecated
|
||||
public class DataAccess {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private UUID id;
|
||||
|
||||
@Column(name = "data_type", nullable = false)
|
||||
private String dataType;
|
||||
|
||||
@Column(name = "data_id", nullable = false)
|
||||
private UUID dataId;
|
||||
|
||||
@Column(name = "access_type", nullable = false)
|
||||
private String accessType;
|
||||
|
||||
@Column(name = "access_id", nullable = false)
|
||||
private UUID accessId;
|
||||
|
||||
@Column(name = "access_level", nullable = false)
|
||||
private String accessLevel = "read";
|
||||
|
||||
@Column(name = "granted_by")
|
||||
private UUID grantedBy;
|
||||
|
||||
@Column(name = "granted_at", nullable = false)
|
||||
private LocalDateTime grantedAt = LocalDateTime.now();
|
||||
|
||||
@PrePersist
|
||||
public void prePersist() {
|
||||
if (this.grantedAt == null) {
|
||||
this.grantedAt = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +1,19 @@
|
|||
package com.ether.pms.auth.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 部门实体类
|
||||
*
|
||||
* <p>表示组织架构中的部门信息,包含部门名称、类型、负责人等。</p>
|
||||
* <p>表示组织架构中的部门信息,包含部门名称、类型、负责人等。
|
||||
*
|
||||
* <p>支持树形结构,通过parentId指向上级部门。</p>
|
||||
* <p>支持树形结构,通过parentId指向上级部门。
|
||||
*
|
||||
* <p>部门类型用于区分不同业务职能的部门:
|
||||
* - ADMIN: 行政管理部门,如总部、行政部、财务部、人力资源部等
|
||||
* - ENGINEERING: 工程部门,负责设施设备维护、维修等
|
||||
* - SECURITY: 安保部门,负责安全保卫、门禁管理等
|
||||
* - CS: 客服部门,负责业主服务、投诉处理等
|
||||
* - CLEANING: 保洁部门,负责清洁卫生、绿化养护等</p>
|
||||
* <p>部门类型用于区分不同业务职能的部门: - ADMIN: 行政管理部门,如总部、行政部、财务部、人力资源部等 - ENGINEERING: 工程部门,负责设施设备维护、维修等 -
|
||||
* SECURITY: 安保部门,负责安全保卫、门禁管理等 - CS: 客服部门,负责业主服务、投诉处理等 - CLEANING: 保洁部门,负责清洁卫生、绿化养护等
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -28,77 +24,47 @@ import java.util.UUID;
|
|||
@Data
|
||||
public class Dept {
|
||||
|
||||
/**
|
||||
* 部门唯一标识符
|
||||
* 采用UUID策略自动生成
|
||||
*/
|
||||
/** 部门唯一标识符 采用UUID策略自动生成 */
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private UUID id;
|
||||
|
||||
/**
|
||||
* 上级部门ID
|
||||
* 指向父部门的ID,用于构建部门树形结构,顶级部门此字段为空
|
||||
*/
|
||||
/** 上级部门ID 指向父部门的ID,用于构建部门树形结构,顶级部门此字段为空 */
|
||||
private UUID parentId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
* 部门的显示名称
|
||||
*/
|
||||
/** 部门名称 部门的显示名称 */
|
||||
@Column(nullable = false, length = 100)
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 部门类型
|
||||
* 标识部门所属的业务类型,用于区分不同职能的部门
|
||||
* ADMIN: 行政管理 - 负责公司行政、财务、人事等管理职能
|
||||
* ENGINEERING: 工程部 - 负责设施设备维护、维修、保养等技术工作
|
||||
* SECURITY: 安保部 - 负责安全保卫、门禁管理、巡逻等工作
|
||||
* CS: 客服部 - 负责业主服务、投诉处理、满意度调查等
|
||||
* CLEANING: 保洁部 - 负责清洁卫生、绿化养护、垃圾处理等
|
||||
* 部门类型 标识部门所属的业务类型,用于区分不同职能的部门 ADMIN: 行政管理 - 负责公司行政、财务、人事等管理职能 ENGINEERING: 工程部 -
|
||||
* 负责设施设备维护、维修、保养等技术工作 SECURITY: 安保部 - 负责安全保卫、门禁管理、巡逻等工作 CS: 客服部 - 负责业主服务、投诉处理、满意度调查等 CLEANING:
|
||||
* 保洁部 - 负责清洁卫生、绿化养护、垃圾处理等
|
||||
*/
|
||||
@Column(length = 20)
|
||||
private String deptType = "ADMIN";
|
||||
|
||||
/**
|
||||
* 部门负责人ID
|
||||
* 部门负责人的用户ID
|
||||
*/
|
||||
/** 部门负责人ID 部门负责人的用户ID */
|
||||
private UUID leaderId;
|
||||
|
||||
/**
|
||||
* 排序序号
|
||||
* 部门在同一级别中的排序顺序,数字越小越靠前
|
||||
*/
|
||||
/** 排序序号 部门在同一级别中的排序顺序,数字越小越靠前 */
|
||||
private Integer sortOrder;
|
||||
|
||||
/**
|
||||
* 部门状态
|
||||
* 标识部门的状态:ACTIVE-正常、DISABLED-停用
|
||||
*/
|
||||
/** 部门状态 标识部门的状态:ACTIVE-正常、DISABLED-停用 */
|
||||
@Column(length = 20)
|
||||
private String status = "ACTIVE";
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
/** 创建时间 */
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
/** 更新时间 */
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
/**
|
||||
* 创建人ID
|
||||
*/
|
||||
/** 创建人ID */
|
||||
@Column(name = "created_by")
|
||||
private UUID createdBy;
|
||||
|
||||
/**
|
||||
* 更新人ID
|
||||
*/
|
||||
/** 更新人ID */
|
||||
@Column(name = "updated_by")
|
||||
private UUID updatedBy;
|
||||
|
||||
|
|
@ -113,9 +79,7 @@ public class Dept {
|
|||
updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 部门类型枚举
|
||||
*/
|
||||
/** 部门类型枚举 */
|
||||
public enum DeptType {
|
||||
ADMIN("行政管理"),
|
||||
ENGINEERING("工程部"),
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
package com.ether.pms.auth.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDate;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 企业用户实体类
|
||||
*
|
||||
* <p>表示企业类型的用户信息,包含员工的职位、入职日期等企业相关信息。</p>
|
||||
* <p>表示企业类型的用户信息,包含员工的职位、入职日期等企业相关信息。
|
||||
*
|
||||
* <p>与User实体为一对一关系,共享主键。</p>
|
||||
* <p>与User实体为一对一关系,共享主键。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -21,50 +21,28 @@ import java.util.UUID;
|
|||
@Data
|
||||
public class EnterpriseUser {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
* 主键,也是外键指向auth_user表
|
||||
*/
|
||||
@Id
|
||||
private UUID userId;
|
||||
/** 用户ID 主键,也是外键指向auth_user表 */
|
||||
@Id private UUID userId;
|
||||
|
||||
/**
|
||||
* 员工工号
|
||||
* 企业内部员工编号
|
||||
*/
|
||||
/** 员工工号 企业内部员工编号 */
|
||||
@Column(length = 50)
|
||||
private String employeeNo;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
* 用户所属的部门标识符
|
||||
*/
|
||||
/** 部门ID 用户所属的部门标识符 */
|
||||
private UUID deptId;
|
||||
|
||||
/**
|
||||
* 职位
|
||||
* 用户在企业中的职位
|
||||
*/
|
||||
/** 职位 用户在企业中的职位 */
|
||||
@Column(length = 50)
|
||||
private String position;
|
||||
|
||||
/**
|
||||
* 入职日期
|
||||
* 员工加入企业的日期
|
||||
*/
|
||||
/** 入职日期 员工加入企业的日期 */
|
||||
private LocalDate entryDate;
|
||||
|
||||
/**
|
||||
* 员工类别
|
||||
* 标识员工类型:ENTERPRISE(普通员工)、MANAGEMENT(管理层)
|
||||
*/
|
||||
/** 员工类别 标识员工类型:ENTERPRISE(普通员工)、MANAGEMENT(管理层) */
|
||||
@Column(length = 50)
|
||||
private String userCategory;
|
||||
|
||||
/**
|
||||
* 关联的User实体
|
||||
* 采用一对一关系,共享主键
|
||||
*/
|
||||
/** 关联的User实体 采用一对一关系,共享主键 */
|
||||
@OneToOne
|
||||
@MapsId
|
||||
@JoinColumn(name = "user_id")
|
||||
|
|
|
|||
|
|
@ -1,20 +1,19 @@
|
|||
package com.ether.pms.auth.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 权限实体类
|
||||
*
|
||||
* <p>用于定义系统中的权限信息,包括权限代码、名称、类型、资源路径等属性。
|
||||
* 权限是系统安全的基础单元,用于控制用户对具体功能的访问能力。</p>
|
||||
* <p>用于定义系统中的权限信息,包括权限代码、名称、类型、资源路径等属性。 权限是系统安全的基础单元,用于控制用户对具体功能的访问能力。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -25,79 +24,49 @@ import java.util.UUID;
|
|||
@Data
|
||||
public class Permission {
|
||||
|
||||
/**
|
||||
* 权限唯一标识符
|
||||
* 使用UUID自动生成
|
||||
*/
|
||||
/** 权限唯一标识符 使用UUID自动生成 */
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private UUID id;
|
||||
|
||||
/**
|
||||
* 权限代码
|
||||
* 系统内部识别符,必须唯一
|
||||
* 格式:只能包含字母、数字、冒号和下划线,长度2-100位
|
||||
* 例如:system:user:create, menu:project:view
|
||||
*/
|
||||
/** 权限代码 系统内部识别符,必须唯一 格式:只能包含字母、数字、冒号和下划线,长度2-100位 例如:system:user:create, menu:project:view */
|
||||
@NotNull(message = "权限代码不能为空")
|
||||
@Size(min = 2, max = 100, message = "权限代码长度必须在2-100位之间")
|
||||
@Pattern(regexp = "^[a-zA-Z0-9_:]+$", message = "权限代码只能包含字母、数字、冒号和下划线")
|
||||
@Column(unique = true, nullable = false, length = 100)
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 权限名称
|
||||
* 用于前端展示和用户理解,长度2-100位
|
||||
*/
|
||||
/** 权限名称 用于前端展示和用户理解,长度2-100位 */
|
||||
@NotNull(message = "权限名称不能为空")
|
||||
@Size(min = 2, max = 100, message = "权限名称长度必须在2-100位之间")
|
||||
@Column(nullable = false, length = 100)
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 权限类型
|
||||
* 用于分类权限,如:MENU(菜单)、BUTTON(按钮)、API(接口)等
|
||||
*/
|
||||
/** 权限类型 用于分类权限,如:MENU(菜单)、BUTTON(按钮)、API(接口)等 */
|
||||
@Size(max = 20, message = "权限类型长度不能超过20位")
|
||||
@Column(length = 20)
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 资源路径
|
||||
* 对于API类型的权限,表示对应的接口路径
|
||||
*/
|
||||
/** 资源路径 对于API类型的权限,表示对应的接口路径 */
|
||||
@Size(max = 50, message = "资源路径长度不能超过50位")
|
||||
@Column(length = 50)
|
||||
private String resource;
|
||||
|
||||
/**
|
||||
* 请求方法
|
||||
* 对于API类型的权限,表示对应的HTTP方法(如GET、POST、PUT、DELETE)
|
||||
*/
|
||||
/** 请求方法 对于API类型的权限,表示对应的HTTP方法(如GET、POST、PUT、DELETE) */
|
||||
@Size(max = 50, message = "请求方法长度不能超过50位")
|
||||
@Column(length = 50)
|
||||
private String method;
|
||||
|
||||
/**
|
||||
* 权限描述
|
||||
* 对权限的详细说明,用于帮助理解权限用途,长度不超过200位
|
||||
*/
|
||||
/** 权限描述 对权限的详细说明,用于帮助理解权限用途,长度不超过200位 */
|
||||
@Size(max = 200, message = "权限描述长度不能超过200位")
|
||||
@Column(length = 200)
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 父权限代码
|
||||
* 用于构建权限树形结构,支持层级管理
|
||||
* 顶级权限的父代码为空
|
||||
*/
|
||||
/** 父权限代码 用于构建权限树形结构,支持层级管理 顶级权限的父代码为空 */
|
||||
@Column(length = 50)
|
||||
private String parentCode;
|
||||
|
||||
/**
|
||||
* 排序序号
|
||||
* 用于前端展示时的排序,数字越小越靠前
|
||||
*/
|
||||
/** 排序序号 用于前端展示时的排序,数字越小越靠前 */
|
||||
@Size(max = 200, message = "路由路径长度不能超过200位")
|
||||
@Column(length = 200)
|
||||
private String path;
|
||||
|
|
@ -115,46 +84,29 @@ public class Permission {
|
|||
@Column(nullable = false)
|
||||
private Boolean visible = true;
|
||||
|
||||
/**
|
||||
* 权限关联的角色列表
|
||||
* 多对多关系,通过auth_role_permission关联表维护
|
||||
* JsonIgnoreProperties避免循环序列化
|
||||
*/
|
||||
/** 权限关联的角色列表 多对多关系,通过auth_role_permission关联表维护 JsonIgnoreProperties避免循环序列化 */
|
||||
@JsonIgnoreProperties({"permissions", "roles"})
|
||||
@ManyToMany(fetch = FetchType.LAZY)
|
||||
@JoinTable(
|
||||
name = "auth_role_permission",
|
||||
joinColumns = @JoinColumn(name = "permission_id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "role_id")
|
||||
)
|
||||
inverseJoinColumns = @JoinColumn(name = "role_id"))
|
||||
private List<Role> roles;
|
||||
|
||||
/**
|
||||
* 权限创建时间
|
||||
* 自动设置,记录创建时刻
|
||||
*/
|
||||
/** 权限创建时间 自动设置,记录创建时刻 */
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
/**
|
||||
* 权限更新时间
|
||||
* 自动设置,每次更新时自动修改
|
||||
*/
|
||||
/** 权限更新时间 自动设置,每次更新时自动修改 */
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
/**
|
||||
* 持久化前回调
|
||||
* 自动设置创建时间和更新时间
|
||||
*/
|
||||
/** 持久化前回调 自动设置创建时间和更新时间 */
|
||||
@PrePersist
|
||||
public void prePersist() {
|
||||
this.createdAt = LocalDateTime.now();
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新前回调
|
||||
* 自动设置更新时间
|
||||
*/
|
||||
/** 更新前回调 自动设置更新时间 */
|
||||
@PreUpdate
|
||||
public void preUpdate() {
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
|
|
|
|||
|
|
@ -1,10 +1,5 @@
|
|||
package com.ether.pms.auth.entity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
|
|
@ -16,14 +11,18 @@ import jakarta.persistence.JoinColumn;
|
|||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 项目员工实体类
|
||||
*
|
||||
* <p>表示项目类型的员工信息,包含所属项目、员工类型、班次等信息。</p>
|
||||
* <p>表示项目类型的员工信息,包含所属项目、员工类型、班次等信息。
|
||||
*
|
||||
* <p>与User实体为一对一关系,共享主键。</p>
|
||||
* <p>与User实体为一对一关系,共享主键。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -34,32 +33,21 @@ import lombok.Data;
|
|||
@Data
|
||||
public class ProjectStaff {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
/** 主键ID */
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
@Column(name = "id")
|
||||
private UUID id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
* 外键指向auth_user表
|
||||
*/
|
||||
/** 用户ID 外键指向auth_user表 */
|
||||
@Column(name = "user_id", insertable = false, updatable = false)
|
||||
private UUID userId;
|
||||
|
||||
/**
|
||||
* 所属项目ID
|
||||
* 员工所属项目的唯一标识符
|
||||
*/
|
||||
/** 所属项目ID 员工所属项目的唯一标识符 */
|
||||
@Column(name = "project_id")
|
||||
private UUID projectId;
|
||||
|
||||
/**
|
||||
* 所属部门ID
|
||||
* 员工所属部门的唯一标识符,用于组织架构管理
|
||||
*/
|
||||
/** 所属部门ID 员工所属部门的唯一标识符,用于组织架构管理 */
|
||||
@Column(name = "dept_id")
|
||||
private UUID deptId;
|
||||
|
||||
|
|
@ -70,48 +58,30 @@ public class ProjectStaff {
|
|||
@Column(length = 50)
|
||||
private String staffType;
|
||||
|
||||
/**
|
||||
* 班次类型
|
||||
* 标识员工的班次:DAY(白班)、NIGHT(夜班)、ROTATION(轮班)
|
||||
*/
|
||||
/** 班次类型 标识员工的班次:DAY(白班)、NIGHT(夜班)、ROTATION(轮班) */
|
||||
@Column(length = 20)
|
||||
private String shiftType;
|
||||
|
||||
/**
|
||||
* 班组长ID
|
||||
* 员工所属班组长的用户ID
|
||||
*/
|
||||
/** 班组长ID 员工所属班组长的用户ID */
|
||||
private UUID leaderId;
|
||||
|
||||
/**
|
||||
* 在岗状态
|
||||
* 标识员工的在岗状态:ASSIGNED(已分配)、ON_LEAVE(请假)、TRANSFERRED(已调离)
|
||||
*/
|
||||
/** 在岗状态 标识员工的在岗状态:ASSIGNED(已分配)、ON_LEAVE(请假)、TRANSFERRED(已调离) */
|
||||
@Column(length = 20)
|
||||
private String assignmentStatus;
|
||||
|
||||
/**
|
||||
* 员工角色列表
|
||||
*/
|
||||
/** 员工角色列表 */
|
||||
@OneToMany(mappedBy = "staff", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private List<ProjectStaffRole> staffRoles = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
/** 创建时间 */
|
||||
@Column(name = "created_at", updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
/** 更新时间 */
|
||||
@Column(name = "updated_at")
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
/**
|
||||
* 关联的User实体
|
||||
* 采用一对一关系
|
||||
*/
|
||||
/** 关联的User实体 采用一对一关系 */
|
||||
@OneToOne
|
||||
@JoinColumn(name = "user_id", foreignKey = @ForeignKey(name = "fk_project_staff_user"))
|
||||
private User user;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
package com.ether.pms.auth.entity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
|
|
@ -13,6 +10,8 @@ import jakarta.persistence.JoinColumn;
|
|||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.PrePersist;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
@Entity
|
||||
|
|
|
|||
|
|
@ -2,16 +2,16 @@ package com.ether.pms.auth.entity;
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 住户实体类
|
||||
*
|
||||
* <p>表示住户类型的用户信息,包含身份证、认证状态等住户相关信息。</p>
|
||||
* <p>表示住户类型的用户信息,包含身份证、认证状态等住户相关信息。
|
||||
*
|
||||
* <p>与User实体为一对一关系,共享主键。</p>
|
||||
* <p>与User实体为一对一关系,共享主键。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -22,77 +22,47 @@ import java.util.UUID;
|
|||
@Data
|
||||
public class Resident {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
* 主键,也是外键指向auth_user表
|
||||
*/
|
||||
@Id
|
||||
private UUID userId;
|
||||
/** 用户ID 主键,也是外键指向auth_user表 */
|
||||
@Id private UUID userId;
|
||||
|
||||
/**
|
||||
* 身份证号码
|
||||
* 住户的身份证号,用于身份验证
|
||||
*/
|
||||
/** 身份证号码 住户的身份证号,用于身份验证 */
|
||||
@JsonIgnore
|
||||
@Column(length = 18)
|
||||
private String idCard;
|
||||
|
||||
/**
|
||||
* 住户类型
|
||||
* 标识住户类型:OWNER(业主)、FAMILY(家属)、TENANT(租户)
|
||||
*/
|
||||
/** 住户类型 标识住户类型:OWNER(业主)、FAMILY(家属)、TENANT(租户) */
|
||||
@Column(length = 20)
|
||||
private String residentType;
|
||||
|
||||
/**
|
||||
* 认证状态
|
||||
* 标识住户的认证状态:UNVERIFIED(未认证)、PENDING(待审核)、VERIFIED(已认证)、REJECTED(已拒绝)
|
||||
*/
|
||||
/** 认证状态 标识住户的认证状态:UNVERIFIED(未认证)、PENDING(待审核)、VERIFIED(已认证)、REJECTED(已拒绝) */
|
||||
@Column(length = 20)
|
||||
private String verificationStatus;
|
||||
|
||||
/**
|
||||
* 认证时间
|
||||
* 记录住户认证通过的时间
|
||||
*/
|
||||
/** 认证时间 记录住户认证通过的时间 */
|
||||
private LocalDateTime verifiedAt;
|
||||
|
||||
/**
|
||||
* 认证人ID
|
||||
* 执行认证操作的管理员用户ID
|
||||
*/
|
||||
/** 认证人ID 执行认证操作的管理员用户ID */
|
||||
private UUID verifiedBy;
|
||||
|
||||
/**
|
||||
* 关联的User实体
|
||||
* 采用一对一关系,共享主键
|
||||
*/
|
||||
/** 关联的User实体 采用一对一关系,共享主键 */
|
||||
@OneToOne
|
||||
@MapsId
|
||||
@JoinColumn(name = "user_id")
|
||||
private User user;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
/** 创建时间 */
|
||||
@Column(name = "created_at", nullable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
/** 更新时间 */
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
/**
|
||||
* 创建人ID
|
||||
*/
|
||||
/** 创建人ID */
|
||||
@Column(name = "created_by")
|
||||
private UUID createdBy;
|
||||
|
||||
/**
|
||||
* 更新人ID
|
||||
*/
|
||||
/** 更新人ID */
|
||||
@Column(name = "updated_by")
|
||||
private UUID updatedBy;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
package com.ether.pms.auth.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDate;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 住户房屋关联实体类
|
||||
*
|
||||
* <p>表示住户与房屋之间的关联关系,记录住户与房屋的绑定信息。</p>
|
||||
* <p>表示住户与房屋之间的关联关系,记录住户与房屋的绑定信息。
|
||||
*
|
||||
* <p>支持业主、家属、租户等多种关系类型,以及绑定状态管理。</p>
|
||||
* <p>支持业主、家属、租户等多种关系类型,以及绑定状态管理。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -21,51 +21,30 @@ import java.util.UUID;
|
|||
@Data
|
||||
public class ResidentSpace {
|
||||
|
||||
/**
|
||||
* 关联记录唯一标识符
|
||||
* 采用UUID策略自动生成
|
||||
*/
|
||||
/** 关联记录唯一标识符 采用UUID策略自动生成 */
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private UUID id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
* 关联的用户唯一标识符
|
||||
*/
|
||||
/** 用户ID 关联的用户唯一标识符 */
|
||||
@Column(name = "user_id", nullable = false)
|
||||
private UUID userId;
|
||||
|
||||
/**
|
||||
* 房屋ID
|
||||
* 关联的房屋唯一标识符
|
||||
*/
|
||||
/** 房屋ID 关联的房屋唯一标识符 */
|
||||
@Column(name = "space_id", nullable = false)
|
||||
private UUID spaceId;
|
||||
|
||||
/**
|
||||
* 关系类型
|
||||
* 标识住户与房屋的关系:OWNER(业主)、FAMILY(家属)、TENANT(租户)
|
||||
*/
|
||||
/** 关系类型 标识住户与房屋的关系:OWNER(业主)、FAMILY(家属)、TENANT(租户) */
|
||||
@Column(length = 20)
|
||||
private String relationType;
|
||||
|
||||
/**
|
||||
* 绑定状态
|
||||
* 标识关联的状态:PENDING(待生效)、ACTIVE(生效中)、EXPIRED(已过期)、CANCELLED(已取消)
|
||||
*/
|
||||
/** 绑定状态 标识关联的状态:PENDING(待生效)、ACTIVE(生效中)、EXPIRED(已过期)、CANCELLED(已取消) */
|
||||
@Column(length = 20)
|
||||
private String bindingStatus;
|
||||
|
||||
/**
|
||||
* 开始日期
|
||||
* 关联关系的生效日期
|
||||
*/
|
||||
/** 开始日期 关联关系的生效日期 */
|
||||
private LocalDate startDate;
|
||||
|
||||
/**
|
||||
* 结束日期
|
||||
* 关联关系的失效日期,永久关联则为空
|
||||
*/
|
||||
/** 结束日期 关联关系的失效日期,永久关联则为空 */
|
||||
private LocalDate endDate;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,16 +4,15 @@ import jakarta.persistence.*;
|
|||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 角色实体类
|
||||
*
|
||||
* <p>用于定义系统中的角色信息,包括角色代码、名称、描述、类型、数据范围等属性。
|
||||
* 角色与权限通过多对多关联,一个角色可以拥有多个权限。</p>
|
||||
* <p>用于定义系统中的角色信息,包括角色代码、名称、描述、类型、数据范围等属性。 角色与权限通过多对多关联,一个角色可以拥有多个权限。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -24,122 +23,84 @@ import java.util.UUID;
|
|||
@Data
|
||||
public class Role {
|
||||
|
||||
/**
|
||||
* 角色唯一标识符
|
||||
* 使用UUID自动生成
|
||||
*/
|
||||
/** 角色唯一标识符 使用UUID自动生成 */
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private UUID id;
|
||||
|
||||
/**
|
||||
* 角色代码
|
||||
* 用于系统内部识别,必须唯一
|
||||
* 格式:只能包含字母、数字和下划线,长度2-50位
|
||||
*/
|
||||
/** 角色代码 用于系统内部识别,必须唯一 格式:只能包含字母、数字和下划线,长度2-50位 */
|
||||
@NotNull(message = "角色代码不能为空")
|
||||
@Size(min = 2, max = 50, message = "角色代码长度必须在2-50位之间")
|
||||
@Pattern(regexp = "^[a-zA-Z0-9_]+$", message = "角色代码只能包含字母、数字和下划线")
|
||||
@Column(unique = true, nullable = false, length = 50)
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 角色名称
|
||||
* 用于前端展示,长度2-50位
|
||||
*/
|
||||
/** 角色名称 用于前端展示,长度2-50位 */
|
||||
@NotNull(message = "角色名称不能为空")
|
||||
@Size(min = 2, max = 50, message = "角色名称长度必须在2-50位之间")
|
||||
@Column(nullable = false, length = 50)
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 角色描述
|
||||
* 对角色的详细说明,长度不超过200位
|
||||
*/
|
||||
/** 角色描述 对角色的详细说明,长度不超过200位 */
|
||||
@Size(max = 200, message = "角色描述长度不能超过200位")
|
||||
@Column(length = 200)
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 角色类型
|
||||
* 区分系统级、项目级、部门级角色
|
||||
*/
|
||||
/** 角色类型 区分系统级、项目级、部门级角色 */
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(length = 20, nullable = false)
|
||||
private RoleType type;
|
||||
|
||||
/**
|
||||
* 数据范围
|
||||
* 定义角色可访问的数据范围,默认为本人数据
|
||||
*/
|
||||
/** 数据范围 定义角色可访问的数据范围,默认为本人数据 */
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(length = 20)
|
||||
private DataScope dataScope = DataScope.SELF;
|
||||
|
||||
/**
|
||||
* 所属项目ID
|
||||
* 用于项目级角色的项目归属
|
||||
*/
|
||||
/** 所属项目ID 用于项目级角色的项目归属 */
|
||||
@Column(name = "project_id", columnDefinition = "uuid")
|
||||
private UUID projectId;
|
||||
|
||||
/**
|
||||
* 角色状态
|
||||
* 启用或禁用,默认为启用
|
||||
*/
|
||||
/** 角色状态 启用或禁用,默认为启用 */
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(length = 20, nullable = false)
|
||||
private RoleStatus status = RoleStatus.ENABLED;
|
||||
|
||||
/**
|
||||
* 角色关联的权限列表
|
||||
* 多对多关系,通过auth_role_permission关联表维护
|
||||
*/
|
||||
/** 角色关联的权限列表 多对多关系,通过auth_role_permission关联表维护 */
|
||||
@ManyToMany(fetch = FetchType.LAZY)
|
||||
@JoinTable(
|
||||
name = "auth_role_permission",
|
||||
joinColumns = @JoinColumn(name = "role_id", foreignKey = @ForeignKey(name = "fk_auth_role_permission_role")),
|
||||
inverseJoinColumns = @JoinColumn(name = "permission_id", foreignKey = @ForeignKey(name = "fk_auth_role_permission_permission"))
|
||||
)
|
||||
joinColumns =
|
||||
@JoinColumn(
|
||||
name = "role_id",
|
||||
foreignKey = @ForeignKey(name = "fk_auth_role_permission_role")),
|
||||
inverseJoinColumns =
|
||||
@JoinColumn(
|
||||
name = "permission_id",
|
||||
foreignKey = @ForeignKey(name = "fk_auth_role_permission_permission")))
|
||||
private List<Permission> permissions;
|
||||
|
||||
/**
|
||||
* 角色创建时间
|
||||
* 自动设置,记录创建时刻
|
||||
*/
|
||||
/** 角色创建时间 自动设置,记录创建时刻 */
|
||||
@Column(name = "created_at", nullable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
/**
|
||||
* 角色更新时间
|
||||
* 自动设置,每次更新时自动修改
|
||||
*/
|
||||
/** 角色更新时间 自动设置,每次更新时自动修改 */
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
/**
|
||||
* 持久化前回调
|
||||
* 自动设置创建时间和更新时间
|
||||
*/
|
||||
/** 持久化前回调 自动设置创建时间和更新时间 */
|
||||
@PrePersist
|
||||
public void prePersist() {
|
||||
this.createdAt = LocalDateTime.now();
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新前回调
|
||||
* 自动设置更新时间
|
||||
*/
|
||||
/** 更新前回调 自动设置更新时间 */
|
||||
@PreUpdate
|
||||
public void preUpdate() {
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 角色类型枚举
|
||||
* 定义角色的层级分类
|
||||
*/
|
||||
/** 角色类型枚举 定义角色的层级分类 */
|
||||
public enum RoleType {
|
||||
/** 系统级角色,可访问所有项目数据 */
|
||||
SYSTEM("系统级"),
|
||||
|
|
@ -155,10 +116,7 @@ public class Role {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据范围枚举
|
||||
* 定义角色可查看的数据范围级别
|
||||
*/
|
||||
/** 数据范围枚举 定义角色可查看的数据范围级别 */
|
||||
public enum DataScope {
|
||||
/** 全部数据,可查看所有数据 */
|
||||
ALL("全部"),
|
||||
|
|
@ -176,10 +134,7 @@ public class Role {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 角色状态枚举
|
||||
* 定义角色的启用/禁用状态
|
||||
*/
|
||||
/** 角色状态枚举 定义角色的启用/禁用状态 */
|
||||
public enum RoleStatus {
|
||||
/** 角色已启用,可以正常使用 */
|
||||
ENABLED("启用"),
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
package com.ether.pms.auth.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 房屋空间实体类
|
||||
*
|
||||
* <p>表示项目中的房屋或空间信息,包含楼栋、单元、房号等。</p>
|
||||
* <p>表示项目中的房屋或空间信息,包含楼栋、单元、房号等。
|
||||
*
|
||||
* <p>支持住宅和商业两种类型的空间管理。</p>
|
||||
* <p>支持住宅和商业两种类型的空间管理。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -21,65 +21,38 @@ import java.util.UUID;
|
|||
@Data
|
||||
public class Space {
|
||||
|
||||
/**
|
||||
* 空间唯一标识符
|
||||
* 采用UUID策略自动生成
|
||||
*/
|
||||
/** 空间唯一标识符 采用UUID策略自动生成 */
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private UUID id;
|
||||
|
||||
/**
|
||||
* 所属项目ID
|
||||
* 空间所属项目的唯一标识符
|
||||
*/
|
||||
/** 所属项目ID 空间所属项目的唯一标识符 */
|
||||
@Column(name = "project_id")
|
||||
private UUID projectId;
|
||||
|
||||
/**
|
||||
* 楼栋
|
||||
* 房屋所在的楼栋号或名称
|
||||
*/
|
||||
/** 楼栋 房屋所在的楼栋号或名称 */
|
||||
@Column(length = 50)
|
||||
private String building;
|
||||
|
||||
/**
|
||||
* 单元
|
||||
* 房屋所在的单元号
|
||||
*/
|
||||
/** 单元 房屋所在的单元号 */
|
||||
@Column(length = 50)
|
||||
private String unit;
|
||||
|
||||
/**
|
||||
* 房号
|
||||
* 房屋的房间号
|
||||
*/
|
||||
/** 房号 房屋的房间号 */
|
||||
@Column(length = 50)
|
||||
private String roomNo;
|
||||
|
||||
/**
|
||||
* 房屋类型
|
||||
* 标识房屋类型:RESIDENTIAL(住宅)、COMMERCIAL(商业)
|
||||
*/
|
||||
/** 房屋类型 标识房屋类型:RESIDENTIAL(住宅)、COMMERCIAL(商业) */
|
||||
@Column(length = 20)
|
||||
private String spaceType;
|
||||
|
||||
/**
|
||||
* 楼层
|
||||
* 房屋所在的楼层
|
||||
*/
|
||||
/** 楼层 房屋所在的楼层 */
|
||||
private Integer floor;
|
||||
|
||||
/**
|
||||
* 建筑面积
|
||||
* 房屋的建筑面积,单位平方米
|
||||
*/
|
||||
/** 建筑面积 房屋的建筑面积,单位平方米 */
|
||||
private BigDecimal unitArea;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
* 标识房屋的状态:正常、空置、已售等
|
||||
*/
|
||||
/** 状态 标识房屋的状态:正常、空置、已售等 */
|
||||
@Column(length = 20)
|
||||
private String status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,17 @@
|
|||
package com.ether.pms.auth.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
import org.hibernate.annotations.UpdateTimestamp;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 系统配置实体类
|
||||
* 用于存储系统的键值对配置信息,如物业企业名称等
|
||||
* 系统配置实体类 用于存储系统的键值对配置信息,如物业企业名称等
|
||||
*
|
||||
* @author Ether Team
|
||||
* @since 1.0.0
|
||||
|
|
@ -26,47 +24,29 @@ import java.util.UUID;
|
|||
@Builder
|
||||
public class SysConfig {
|
||||
|
||||
/**
|
||||
* 配置项唯一标识
|
||||
* 使用 UUID 自动生成
|
||||
*/
|
||||
/** 配置项唯一标识 使用 UUID 自动生成 */
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private UUID id;
|
||||
|
||||
/**
|
||||
* 配置键
|
||||
* 唯一标识一个配置项,如:property_company_name
|
||||
*/
|
||||
/** 配置键 唯一标识一个配置项,如:property_company_name */
|
||||
@Column(name = "config_key", nullable = false, unique = true, length = 128)
|
||||
private String configKey;
|
||||
|
||||
/**
|
||||
* 配置值
|
||||
* 使用 TEXT 类型存储,支持长文本
|
||||
*/
|
||||
/** 配置值 使用 TEXT 类型存储,支持长文本 */
|
||||
@Column(name = "config_value", length = 5000)
|
||||
private String configValue;
|
||||
|
||||
/**
|
||||
* 配置描述
|
||||
* 用于说明该配置项的用途
|
||||
*/
|
||||
/** 配置描述 用于说明该配置项的用途 */
|
||||
@Column(name = "description", length = 256)
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
* 自动填充,不可更新
|
||||
*/
|
||||
/** 创建时间 自动填充,不可更新 */
|
||||
@CreationTimestamp
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
* 自动填充,更新时自动修改
|
||||
*/
|
||||
/** 更新时间 自动填充,更新时自动修改 */
|
||||
@UpdateTimestamp
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private LocalDateTime updatedAt;
|
||||
|
|
|
|||
|
|
@ -6,17 +6,17 @@ import jakarta.validation.constraints.Email;
|
|||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 用户实体类
|
||||
*
|
||||
* <p>表示系统中的用户信息,包含用户的基本认证信息和个人资料。</p>
|
||||
* <p>表示系统中的用户信息,包含用户的基本认证信息和个人资料。
|
||||
*
|
||||
* <p>使用JPA注解映射到auth_user表,支持基本的CRUD操作。</p>
|
||||
* <p>使用JPA注解映射到auth_user表,支持基本的CRUD操作。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -27,157 +27,101 @@ import java.util.UUID;
|
|||
@Data
|
||||
public class User {
|
||||
|
||||
/**
|
||||
* 用户唯一标识符
|
||||
* 采用UUID策略自动生成
|
||||
*/
|
||||
/** 用户唯一标识符 采用UUID策略自动生成 */
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private UUID id;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
* 用于用户登录,唯一标识,长度3-50位,只能包含字母、数字和下划线
|
||||
*/
|
||||
/** 用户名 用于用户登录,唯一标识,长度3-50位,只能包含字母、数字和下划线 */
|
||||
@NotNull(message = "用户名不能为空")
|
||||
@Size(min = 3, max = 50, message = "用户名长度必须在3-50位之间")
|
||||
@Pattern(regexp = "^[a-zA-Z0-9_]+$", message = "用户名只能包含字母、数字和下划线")
|
||||
@Column(unique = true, nullable = false, length = 50)
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 密码(加密存储)
|
||||
* 使用BCrypt加密后的密码原文
|
||||
*/
|
||||
/** 密码(加密存储) 使用BCrypt加密后的密码原文 */
|
||||
@NotNull(message = "密码不能为空")
|
||||
@JsonIgnore
|
||||
@Column(nullable = false, length = 255)
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 密码盐值
|
||||
* 用于增强密码加密的安全性
|
||||
*/
|
||||
@JsonIgnore
|
||||
private String salt;
|
||||
/** 密码盐值 用于增强密码加密的安全性 */
|
||||
@JsonIgnore private String salt;
|
||||
|
||||
/**
|
||||
* 真实姓名
|
||||
* 用户的真实姓名,用于显示
|
||||
*/
|
||||
/** 真实姓名 用户的真实姓名,用于显示 */
|
||||
@Column(length = 50)
|
||||
private String realName;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
* 中国大陆手机号格式,11位数字
|
||||
*/
|
||||
/** 手机号码 中国大陆手机号格式,11位数字 */
|
||||
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
|
||||
@Column(length = 20)
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 电子邮箱
|
||||
* 用户的邮箱地址,用于通知和验证
|
||||
*/
|
||||
/** 电子邮箱 用户的邮箱地址,用于通知和验证 */
|
||||
@Email(message = "邮箱格式不正确")
|
||||
@Column(length = 100)
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 头像URL
|
||||
* 用户头像的存储路径或URL
|
||||
*/
|
||||
/** 头像URL 用户头像的存储路径或URL */
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* 用户状态
|
||||
* 标识用户的当前状态:正常、锁定或禁用
|
||||
*/
|
||||
/** 用户状态 标识用户的当前状态:正常、锁定或禁用 */
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(length = 20, nullable = false)
|
||||
private UserStatus status = UserStatus.ACTIVE;
|
||||
|
||||
/**
|
||||
* 用户类型
|
||||
* 标识用户的类型:ENTERPRISE(企业用户)、PROJECT_STAFF(项目员工)、RESIDENT(住户)、CUSTOMER(客户)
|
||||
*/
|
||||
/** 用户类型 标识用户的类型:ENTERPRISE(企业用户)、PROJECT_STAFF(项目员工)、RESIDENT(住户)、CUSTOMER(客户) */
|
||||
@Column(length = 20, nullable = false)
|
||||
private String userType;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
* 用户所属的部门标识符
|
||||
*/
|
||||
/** 部门ID 用户所属的部门标识符 */
|
||||
private UUID deptId;
|
||||
|
||||
/**
|
||||
* 最后登录时间
|
||||
* 记录用户最后一次成功登录的时间
|
||||
*/
|
||||
/** 最后登录时间 记录用户最后一次成功登录的时间 */
|
||||
private LocalDateTime lastLoginTime;
|
||||
|
||||
/**
|
||||
* 最后登录IP
|
||||
* 记录用户最后一次成功登录的IP地址
|
||||
*/
|
||||
/** 最后登录IP 记录用户最后一次成功登录的IP地址 */
|
||||
private String lastLoginIp;
|
||||
|
||||
/**
|
||||
* 用户关联的角色列表
|
||||
* 采用懒加载方式获取用户的所有角色
|
||||
*/
|
||||
/** 用户关联的角色列表 采用懒加载方式获取用户的所有角色 */
|
||||
@ManyToMany(fetch = FetchType.LAZY)
|
||||
@JoinTable(
|
||||
name = "auth_user_role",
|
||||
joinColumns = @JoinColumn(name = "user_id", foreignKey = @ForeignKey(name = "fk_auth_user_role_user")),
|
||||
inverseJoinColumns = @JoinColumn(name = "role_id", foreignKey = @ForeignKey(name = "fk_auth_user_role_role"))
|
||||
)
|
||||
joinColumns =
|
||||
@JoinColumn(
|
||||
name = "user_id",
|
||||
foreignKey = @ForeignKey(name = "fk_auth_user_role_user")),
|
||||
inverseJoinColumns =
|
||||
@JoinColumn(
|
||||
name = "role_id",
|
||||
foreignKey = @ForeignKey(name = "fk_auth_user_role_role")))
|
||||
private List<Role> roles;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
* 记录用户账号的创建时间
|
||||
*/
|
||||
/** 创建时间 记录用户账号的创建时间 */
|
||||
@Column(name = "created_at", nullable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
* 记录用户信息的最后修改时间
|
||||
*/
|
||||
/** 更新时间 记录用户信息的最后修改时间 */
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
/**
|
||||
* 创建人ID
|
||||
* 记录创建该用户的管理员或系统ID
|
||||
*/
|
||||
/** 创建人ID 记录创建该用户的管理员或系统ID */
|
||||
private UUID createdBy;
|
||||
|
||||
/**
|
||||
* 持久化前回调
|
||||
* 在用户对象首次保存到数据库前自动设置创建时间和更新时间
|
||||
*/
|
||||
/** 持久化前回调 在用户对象首次保存到数据库前自动设置创建时间和更新时间 */
|
||||
@PrePersist
|
||||
public void prePersist() {
|
||||
this.createdAt = LocalDateTime.now();
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新前回调
|
||||
* 在用户对象更新前自动设置更新时间
|
||||
*/
|
||||
/** 更新前回调 在用户对象更新前自动设置更新时间 */
|
||||
@PreUpdate
|
||||
public void preUpdate() {
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户状态枚举
|
||||
* 定义用户的三种状态:正常、锁定、禁用
|
||||
*/
|
||||
/** 用户状态枚举 定义用户的三种状态:正常、锁定、禁用 */
|
||||
public enum UserStatus {
|
||||
/** 正常状态 - 用户可以正常登录和使用系统 */
|
||||
ACTIVE("正常"),
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
package com.ether.pms.auth.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 用户项目关联实体类
|
||||
*
|
||||
* <p>表示用户与项目之间的关联关系,记录用户在特定项目中的角色和加入时间。</p>
|
||||
* <p>表示用户与项目之间的关联关系,记录用户在特定项目中的角色和加入时间。
|
||||
*
|
||||
* <p>一个用户可以关联多个项目,一个项目也可以关联多个用户,形成多对多关系。</p>
|
||||
* <p>一个用户可以关联多个项目,一个项目也可以关联多个用户,形成多对多关系。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -21,46 +21,28 @@ import java.util.UUID;
|
|||
@Data
|
||||
public class UserProject {
|
||||
|
||||
/**
|
||||
* 关联记录唯一标识符
|
||||
* 采用UUID策略自动生成
|
||||
*/
|
||||
/** 关联记录唯一标识符 采用UUID策略自动生成 */
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private UUID id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
* 关联的用户唯一标识符
|
||||
*/
|
||||
/** 用户ID 关联的用户唯一标识符 */
|
||||
@Column(name = "user_id", nullable = false)
|
||||
private UUID userId;
|
||||
|
||||
/**
|
||||
* 项目ID
|
||||
* 关联的项目唯一标识符
|
||||
*/
|
||||
/** 项目ID 关联的项目唯一标识符 */
|
||||
@Column(name = "project_id", nullable = false)
|
||||
private UUID projectId;
|
||||
|
||||
/**
|
||||
* 在项目中的角色
|
||||
* 记录用户在关联项目中的角色,默认值为"member"(成员)
|
||||
*/
|
||||
/** 在项目中的角色 记录用户在关联项目中的角色,默认值为"member"(成员) */
|
||||
@Column(name = "role_in_project", nullable = false)
|
||||
private String roleInProject = "member";
|
||||
|
||||
/**
|
||||
* 加入时间
|
||||
* 记录用户加入项目的时间,默认为当前时间
|
||||
*/
|
||||
/** 加入时间 记录用户加入项目的时间,默认为当前时间 */
|
||||
@Column(name = "joined_at", nullable = false)
|
||||
private LocalDateTime joinedAt = LocalDateTime.now();
|
||||
|
||||
/**
|
||||
* 持久化前回调
|
||||
* 在关联记录首次保存前,如果加入时间为空则设置为当前时间
|
||||
*/
|
||||
/** 持久化前回调 在关联记录首次保存前,如果加入时间为空则设置为当前时间 */
|
||||
@PrePersist
|
||||
public void prePersist() {
|
||||
if (this.joinedAt == null) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
package com.ether.pms.auth.repository;
|
||||
|
||||
import com.ether.pms.auth.entity.AuditLog;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
|
@ -10,41 +13,28 @@ import org.springframework.data.jpa.repository.Query;
|
|||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Repository
|
||||
public interface AuditLogRepository extends JpaRepository<AuditLog, UUID>, JpaSpecificationExecutor<AuditLog> {
|
||||
public interface AuditLogRepository
|
||||
extends JpaRepository<AuditLog, UUID>, JpaSpecificationExecutor<AuditLog> {
|
||||
|
||||
/**
|
||||
* 查询最近30天的审计日志(分页)
|
||||
*/
|
||||
/** 查询最近30天的审计日志(分页) */
|
||||
@Query("SELECT a FROM AuditLog a WHERE a.createdAt >= :startTime ORDER BY a.createdAt DESC")
|
||||
Page<AuditLog> findRecentLogs(@Param("startTime") LocalDateTime startTime, Pageable pageable);
|
||||
|
||||
/**
|
||||
* 查询最近30天的审计日志(不分页)
|
||||
*/
|
||||
/** 查询最近30天的审计日志(不分页) */
|
||||
@Query("SELECT a FROM AuditLog a WHERE a.createdAt >= :startTime ORDER BY a.createdAt DESC")
|
||||
List<AuditLog> findRecentLogs(@Param("startTime") LocalDateTime startTime);
|
||||
|
||||
/**
|
||||
* 删除超过指定时间的日志(归档用)
|
||||
*/
|
||||
/** 删除超过指定时间的日志(归档用) */
|
||||
@Modifying
|
||||
@Query("DELETE FROM AuditLog a WHERE a.createdAt < :cutoffTime")
|
||||
int deleteByCreatedAtBefore(@Param("cutoffTime") LocalDateTime cutoffTime);
|
||||
|
||||
/**
|
||||
* 查询超过指定时间的日志(归档用)
|
||||
*/
|
||||
/** 查询超过指定时间的日志(归档用) */
|
||||
@Query("SELECT a FROM AuditLog a WHERE a.createdAt < :cutoffTime ORDER BY a.createdAt DESC")
|
||||
List<AuditLog> findByCreatedAtBefore(@Param("cutoffTime") LocalDateTime cutoffTime);
|
||||
|
||||
/**
|
||||
* 统计最近30天的日志数量
|
||||
*/
|
||||
/** 统计最近30天的日志数量 */
|
||||
@Query("SELECT COUNT(a) FROM AuditLog a WHERE a.createdAt >= :startTime")
|
||||
long countRecentLogs(@Param("startTime") LocalDateTime startTime);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
package com.ether.pms.auth.repository;
|
||||
|
||||
import com.ether.pms.auth.entity.DataAccess;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@Repository
|
||||
public interface DataAccessRepository extends JpaRepository<DataAccess, UUID> {
|
||||
|
||||
List<DataAccess> findByDataTypeAndDataId(String dataType, UUID dataId);
|
||||
|
||||
/**
|
||||
* 根据多条件精确查询数据访问记录
|
||||
*
|
||||
* <p>用于 grantAccess 方法中检查是否已存在相同的访问授权记录。</p>
|
||||
*
|
||||
* @param dataType 数据类型
|
||||
* @param dataId 数据ID
|
||||
* @param accessType 访问类型
|
||||
* @param accessId 访问者ID
|
||||
* @return 匹配的访问记录(如果存在)
|
||||
*/
|
||||
Optional<DataAccess> findByDataTypeAndDataIdAndAccessTypeAndAccessId(
|
||||
String dataType, UUID dataId, String accessType, UUID accessId);
|
||||
|
||||
@Query("SELECT da FROM DataAccess da WHERE da.accessType = :accessType AND da.accessId = :accessId")
|
||||
List<DataAccess> findByAccessTypeAndAccessId(@Param("accessType") String accessType, @Param("accessId") UUID accessId);
|
||||
|
||||
@Query("SELECT da.dataId FROM DataAccess da WHERE da.accessType = 'user' AND da.accessId = :userId AND da.dataType = :dataType")
|
||||
List<UUID> findDataIdsByUserAccess(@Param("userId") UUID userId, @Param("dataType") String dataType);
|
||||
|
||||
void deleteByDataTypeAndDataId(String dataType, UUID dataId);
|
||||
}
|
||||
|
|
@ -1,17 +1,16 @@
|
|||
package com.ether.pms.auth.repository;
|
||||
|
||||
import com.ether.pms.auth.entity.Dept;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 部门数据访问层接口
|
||||
*
|
||||
* <p>提供部门数据的持久化操作,继承Spring Data JPA的JpaRepository接口。</p>
|
||||
* <p>提供部门数据的持久化操作,继承Spring Data JPA的JpaRepository接口。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -23,7 +22,7 @@ public interface DeptRepository extends JpaRepository<Dept, UUID> {
|
|||
/**
|
||||
* 查询顶级部门列表
|
||||
*
|
||||
* <p>查询没有上级部门的部门,即树形结构的根节点。</p>
|
||||
* <p>查询没有上级部门的部门,即树形结构的根节点。
|
||||
*
|
||||
* @return 顶级部门列表
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,17 +1,16 @@
|
|||
package com.ether.pms.auth.repository;
|
||||
|
||||
import com.ether.pms.auth.entity.EnterpriseUser;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* 企业用户数据访问层接口
|
||||
*
|
||||
* <p>提供企业用户数据的持久化操作,继承Spring Data JPA的JpaRepository接口。</p>
|
||||
* <p>提供企业用户数据的持久化操作,继承Spring Data JPA的JpaRepository接口。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
|
|||
|
|
@ -1,16 +1,15 @@
|
|||
package com.ether.pms.auth.repository;
|
||||
|
||||
import com.ether.pms.auth.entity.Permission;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* 权限数据访问层接口
|
||||
*
|
||||
* <p>提供权限(Permission)实体的数据库操作方法,继承Spring Data JPA的JpaRepository。
|
||||
* 支持按权限类型、父权限代码等条件查询。</p>
|
||||
* <p>提供权限(Permission)实体的数据库操作方法,继承Spring Data JPA的JpaRepository。 支持按权限类型、父权限代码等条件查询。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -22,7 +21,7 @@ public interface PermissionRepository extends JpaRepository<Permission, UUID> {
|
|||
/**
|
||||
* 根据权限类型查询权限列表
|
||||
*
|
||||
* <p>按权限类型筛选,如MENU(菜单)、BUTTON(按钮)、API(接口)等。</p>
|
||||
* <p>按权限类型筛选,如MENU(菜单)、BUTTON(按钮)、API(接口)等。
|
||||
*
|
||||
* @param type 权限类型
|
||||
* @return 该类型的所有权限列表
|
||||
|
|
@ -32,7 +31,7 @@ public interface PermissionRepository extends JpaRepository<Permission, UUID> {
|
|||
/**
|
||||
* 根据父权限代码查询子权限列表
|
||||
*
|
||||
* <p>用于构建权限树形结构,查找属于某个父权限的所有子权限。</p>
|
||||
* <p>用于构建权限树形结构,查找属于某个父权限的所有子权限。
|
||||
*
|
||||
* @param parentCode 父权限代码
|
||||
* @return 该父权限下的所有子权限列表
|
||||
|
|
@ -42,7 +41,7 @@ public interface PermissionRepository extends JpaRepository<Permission, UUID> {
|
|||
/**
|
||||
* 检查权限代码是否存在
|
||||
*
|
||||
* <p>用于创建权限时的唯一性校验。</p>
|
||||
* <p>用于创建权限时的唯一性校验。
|
||||
*
|
||||
* @param code 权限代码
|
||||
* @return 存在返回true,不存在返回false
|
||||
|
|
|
|||
|
|
@ -1,19 +1,17 @@
|
|||
package com.ether.pms.auth.repository;
|
||||
|
||||
import com.ether.pms.auth.entity.ProjectStaff;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.ether.pms.auth.entity.ProjectStaff;
|
||||
|
||||
/**
|
||||
* 项目员工数据访问层接口
|
||||
*
|
||||
* <p>提供项目员工数据的持久化操作,继承Spring Data JPA的JpaRepository接口。</p>
|
||||
* <p>提供项目员工数据的持久化操作,继承Spring Data JPA的JpaRepository接口。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -52,11 +50,12 @@ public interface ProjectStaffRepository extends JpaRepository<ProjectStaff, UUID
|
|||
* @param projectId 项目唯一标识符
|
||||
* @return 该项目下的所有员工列表(包含角色信息)
|
||||
*/
|
||||
@Query("SELECT DISTINCT ps FROM ProjectStaff ps " +
|
||||
"LEFT JOIN FETCH ps.staffRoles sr " +
|
||||
"LEFT JOIN FETCH sr.role " +
|
||||
"LEFT JOIN FETCH ps.user " +
|
||||
"WHERE ps.projectId = :projectId")
|
||||
@Query(
|
||||
"SELECT DISTINCT ps FROM ProjectStaff ps "
|
||||
+ "LEFT JOIN FETCH ps.staffRoles sr "
|
||||
+ "LEFT JOIN FETCH sr.role "
|
||||
+ "LEFT JOIN FETCH ps.user "
|
||||
+ "WHERE ps.projectId = :projectId")
|
||||
List<ProjectStaff> findByProjectIdWithRoles(UUID projectId);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
package com.ether.pms.auth.repository;
|
||||
|
||||
import com.ether.pms.auth.entity.ProjectStaffRole;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.ether.pms.auth.entity.ProjectStaffRole;
|
||||
|
||||
@Repository
|
||||
public interface ProjectStaffRoleRepository extends JpaRepository<ProjectStaffRole, UUID> {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,16 @@
|
|||
package com.ether.pms.auth.repository;
|
||||
|
||||
import com.ether.pms.auth.entity.Resident;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* 住户数据访问层接口
|
||||
*
|
||||
* <p>提供住户数据的持久化操作,继承Spring Data JPA的JpaRepository接口。</p>
|
||||
* <p>提供住户数据的持久化操作,继承Spring Data JPA的JpaRepository接口。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
|
|||
|
|
@ -1,17 +1,16 @@
|
|||
package com.ether.pms.auth.repository;
|
||||
|
||||
import com.ether.pms.auth.entity.ResidentSpace;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* 住户房屋关联数据访问层接口
|
||||
*
|
||||
* <p>提供住户房屋关联数据的持久化操作,继承Spring Data JPA的JpaRepository接口。</p>
|
||||
* <p>提供住户房屋关联数据的持久化操作,继承Spring Data JPA的JpaRepository接口。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
|
|||
|
|
@ -1,18 +1,17 @@
|
|||
package com.ether.pms.auth.repository;
|
||||
|
||||
import com.ether.pms.auth.entity.Role;
|
||||
import org.springframework.data.jpa.repository.EntityGraph;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.EntityGraph;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* 角色数据访问层接口
|
||||
*
|
||||
* <p>提供角色(Role)实体的数据库操作方法,继承Spring Data JPA的JpaRepository。
|
||||
* 支持按角色代码、项目ID、类型等条件查询,以及带权限信息的复杂查询。</p>
|
||||
* <p>提供角色(Role)实体的数据库操作方法,继承Spring Data JPA的JpaRepository。 支持按角色代码、项目ID、类型等条件查询,以及带权限信息的复杂查询。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -24,7 +23,7 @@ public interface RoleRepository extends JpaRepository<Role, UUID> {
|
|||
/**
|
||||
* 根据角色代码查询角色
|
||||
*
|
||||
* <p>角色代码在系统中唯一,用于精确查找特定角色。</p>
|
||||
* <p>角色代码在系统中唯一,用于精确查找特定角色。
|
||||
*
|
||||
* @param code 角色代码
|
||||
* @return 角色对象(如果存在)
|
||||
|
|
@ -34,7 +33,7 @@ public interface RoleRepository extends JpaRepository<Role, UUID> {
|
|||
/**
|
||||
* 检查角色代码是否存在
|
||||
*
|
||||
* <p>用于创建角色时的唯一性校验。</p>
|
||||
* <p>用于创建角色时的唯一性校验。
|
||||
*
|
||||
* @param code 角色代码
|
||||
* @return 存在返回true,不存在返回false
|
||||
|
|
@ -44,7 +43,7 @@ public interface RoleRepository extends JpaRepository<Role, UUID> {
|
|||
/**
|
||||
* 根据项目ID查询角色列表
|
||||
*
|
||||
* <p>获取指定项目下的所有角色,通常用于项目级别的角色筛选。</p>
|
||||
* <p>获取指定项目下的所有角色,通常用于项目级别的角色筛选。
|
||||
*
|
||||
* @param projectId 项目ID
|
||||
* @return 该项目下的角色列表
|
||||
|
|
@ -54,7 +53,7 @@ public interface RoleRepository extends JpaRepository<Role, UUID> {
|
|||
/**
|
||||
* 根据角色类型查询角色列表
|
||||
*
|
||||
* <p>按角色类型(如系统级、项目级、部门级)筛选角色。</p>
|
||||
* <p>按角色类型(如系统级、项目级、部门级)筛选角色。
|
||||
*
|
||||
* @param type 角色类型枚举
|
||||
* @return 该类型的所有角色列表
|
||||
|
|
@ -64,8 +63,7 @@ public interface RoleRepository extends JpaRepository<Role, UUID> {
|
|||
/**
|
||||
* 根据角色ID查询角色及其关联的权限信息
|
||||
*
|
||||
* <p>使用EntityGraph eagerly加载permissions关联数据,
|
||||
* 避免N+1查询问题,提升查询性能。</p>
|
||||
* <p>使用EntityGraph eagerly加载permissions关联数据, 避免N+1查询问题,提升查询性能。
|
||||
*
|
||||
* @param id 角色ID
|
||||
* @return 包含权限信息的角色对象(如果存在)
|
||||
|
|
|
|||
|
|
@ -1,17 +1,16 @@
|
|||
package com.ether.pms.auth.repository;
|
||||
|
||||
import com.ether.pms.auth.entity.Space;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* 房屋空间数据访问层接口
|
||||
*
|
||||
* <p>提供房屋空间数据的持久化操作,继承Spring Data JPA的JpaRepository接口。</p>
|
||||
* <p>提供房屋空间数据的持久化操作,继承Spring Data JPA的JpaRepository接口。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -37,5 +36,6 @@ public interface SpaceRepository extends JpaRepository<Space, UUID> {
|
|||
* @param roomNo 房号
|
||||
* @return 包含房屋空间的Optional对象
|
||||
*/
|
||||
Optional<Space> findByProjectIdAndBuildingAndUnitAndRoomNo(UUID projectId, String building, String unit, String roomNo);
|
||||
Optional<Space> findByProjectIdAndBuildingAndUnitAndRoomNo(
|
||||
UUID projectId, String building, String unit, String roomNo);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
package com.ether.pms.auth.repository;
|
||||
|
||||
import com.ether.pms.auth.entity.SysConfig;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 系统配置数据访问层
|
||||
* 提供对 sys_config 表的 CRUD 操作
|
||||
* 系统配置数据访问层 提供对 sys_config 表的 CRUD 操作
|
||||
*
|
||||
* @author Ether Team
|
||||
* @since 1.0.0
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
package com.ether.pms.auth.repository;
|
||||
|
||||
import com.ether.pms.auth.entity.UserProject;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 用户项目关联数据访问层接口
|
||||
*
|
||||
* <p>提供用户与项目关联关系的持久化操作,继承Spring Data JPA的JpaRepository接口。</p>
|
||||
* <p>提供用户与项目关联关系的持久化操作,继承Spring Data JPA的JpaRepository接口。
|
||||
*
|
||||
* <p>支持用户项目关系查询、分页、批量操作等功能。</p>
|
||||
* <p>支持用户项目关系查询、分页、批量操作等功能。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -27,7 +27,7 @@ public interface UserProjectRepository extends JpaRepository<UserProject, UUID>
|
|||
/**
|
||||
* 根据用户ID查询该用户关联的所有项目
|
||||
*
|
||||
* <p>返回指定用户参与的所有项目关联记录列表。</p>
|
||||
* <p>返回指定用户参与的所有项目关联记录列表。
|
||||
*
|
||||
* @param userId 用户唯一标识符
|
||||
* @return 该用户关联的所有项目列表
|
||||
|
|
@ -37,7 +37,7 @@ public interface UserProjectRepository extends JpaRepository<UserProject, UUID>
|
|||
/**
|
||||
* 根据项目ID查询该项目的所有关联用户
|
||||
*
|
||||
* <p>返回参与指定项目的所有用户关联记录列表。</p>
|
||||
* <p>返回参与指定项目的所有用户关联记录列表。
|
||||
*
|
||||
* @param projectId 项目唯一标识符
|
||||
* @return 该项目关联的所有用户列表
|
||||
|
|
@ -47,7 +47,7 @@ public interface UserProjectRepository extends JpaRepository<UserProject, UUID>
|
|||
/**
|
||||
* 根据项目ID分页查询该项目的所有关联用户
|
||||
*
|
||||
* <p>支持分页展示项目成员列表。</p>
|
||||
* <p>支持分页展示项目成员列表。
|
||||
*
|
||||
* @param projectId 项目唯一标识符
|
||||
* @param pageable 分页参数,包含页码和每页大小
|
||||
|
|
@ -58,7 +58,7 @@ public interface UserProjectRepository extends JpaRepository<UserProject, UUID>
|
|||
/**
|
||||
* 根据用户ID查询该用户关联的所有项目ID
|
||||
*
|
||||
* <p>仅返回项目ID列表,用于快速判断用户参与的项目。</p>
|
||||
* <p>仅返回项目ID列表,用于快速判断用户参与的项目。
|
||||
*
|
||||
* @param userId 用户唯一标识符
|
||||
* @return 该用户关联的所有项目ID列表
|
||||
|
|
@ -69,7 +69,7 @@ public interface UserProjectRepository extends JpaRepository<UserProject, UUID>
|
|||
/**
|
||||
* 检查用户与项目的关联是否存在
|
||||
*
|
||||
* <p>用于判断用户是否参与了指定项目。</p>
|
||||
* <p>用于判断用户是否参与了指定项目。
|
||||
*
|
||||
* @param userId 用户唯一标识符
|
||||
* @param projectId 项目唯一标识符
|
||||
|
|
@ -80,15 +80,13 @@ public interface UserProjectRepository extends JpaRepository<UserProject, UUID>
|
|||
/**
|
||||
* 删除用户与项目的关联
|
||||
*
|
||||
* <p>根据用户ID和项目ID删除关联记录,用于用户退出项目或移除项目成员。</p>
|
||||
* <p>根据用户ID和项目ID删除关联记录,用于用户退出项目或移除项目成员。
|
||||
*
|
||||
* @param userId 用户唯一标识符
|
||||
* @param projectId 项目唯一标识符
|
||||
*/
|
||||
void deleteByUserIdAndProjectId(UUID userId, UUID projectId);
|
||||
|
||||
/**
|
||||
* 统计项目下的成员数量
|
||||
*/
|
||||
/** 统计项目下的成员数量 */
|
||||
long countByProjectId(UUID projectId);
|
||||
}
|
||||
|
|
@ -1,22 +1,22 @@
|
|||
package com.ether.pms.auth.repository;
|
||||
|
||||
import com.ether.pms.auth.entity.User;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 用户数据访问层接口
|
||||
*
|
||||
* <p>提供用户数据的持久化操作,继承Spring Data JPA的JpaRepository接口。</p>
|
||||
* <p>提供用户数据的持久化操作,继承Spring Data JPA的JpaRepository接口。
|
||||
*
|
||||
* <p>包含用户查询、角色关联查询等数据库操作方法。</p>
|
||||
* <p>包含用户查询、角色关联查询等数据库操作方法。
|
||||
*
|
||||
* @author Ether开发团队
|
||||
* @version 1.0.0
|
||||
|
|
@ -28,7 +28,7 @@ public interface UserRepository extends JpaRepository<User, UUID> {
|
|||
/**
|
||||
* 根据用户名查询用户
|
||||
*
|
||||
* <p>最基础的按用户名查询方法,返回Optional包装的用户对象。</p>
|
||||
* <p>最基础的按用户名查询方法,返回Optional包装的用户对象。
|
||||
*
|
||||
* @param username 用户名
|
||||
* @return 包含用户的Optional对象,如果不存在则为空
|
||||
|
|
@ -38,7 +38,7 @@ public interface UserRepository extends JpaRepository<User, UUID> {
|
|||
/**
|
||||
* 根据用户名查询用户及其关联的角色
|
||||
*
|
||||
* <p>使用LEFT JOIN FETCH预加载用户的角色信息,避免N+1查询问题。</p>
|
||||
* <p>使用LEFT JOIN FETCH预加载用户的角色信息,避免N+1查询问题。
|
||||
*
|
||||
* @param username 用户名
|
||||
* @return 包含用户及其角色的Optional对象
|
||||
|
|
@ -49,8 +49,9 @@ public interface UserRepository extends JpaRepository<User, UUID> {
|
|||
/**
|
||||
* 查询所有用户及其关联的角色
|
||||
*
|
||||
* <p>一次性加载所有用户及其角色信息,适用于管理后台用户列表。</p>
|
||||
* <p><b>警告:</b>此方法会加载全表数据,建议使用分页版本。</p>
|
||||
* <p>一次性加载所有用户及其角色信息,适用于管理后台用户列表。
|
||||
*
|
||||
* <p><b>警告:</b>此方法会加载全表数据,建议使用分页版本。
|
||||
*
|
||||
* @return 包含所有用户及其角色的列表
|
||||
* @deprecated 建议使用 {@link #findAllWithRoles(Pageable)} 分页版本
|
||||
|
|
@ -62,7 +63,7 @@ public interface UserRepository extends JpaRepository<User, UUID> {
|
|||
/**
|
||||
* 分页查询所有用户及其关联的角色
|
||||
*
|
||||
* <p>支持分页加载用户及其角色信息,避免内存溢出风险。</p>
|
||||
* <p>支持分页加载用户及其角色信息,避免内存溢出风险。
|
||||
*
|
||||
* @param pageable 分页参数(页码、每页大小、排序等)
|
||||
* @return 包含用户及其角色的分页数据
|
||||
|
|
@ -73,7 +74,7 @@ public interface UserRepository extends JpaRepository<User, UUID> {
|
|||
/**
|
||||
* 根据ID查询用户及其关联的角色
|
||||
*
|
||||
* <p>使用LEFT JOIN FETCH预加载用户的角色信息。</p>
|
||||
* <p>使用LEFT JOIN FETCH预加载用户的角色信息。
|
||||
*
|
||||
* @param id 用户唯一标识符
|
||||
* @return 包含用户及其角色的Optional对象
|
||||
|
|
@ -84,7 +85,7 @@ public interface UserRepository extends JpaRepository<User, UUID> {
|
|||
/**
|
||||
* 根据角色ID查询所有拥有该角色的用户
|
||||
*
|
||||
* <p>用于查询具有特定角色的所有用户列表。</p>
|
||||
* <p>用于查询具有特定角色的所有用户列表。
|
||||
*
|
||||
* @param roleId 角色唯一标识符
|
||||
* @return 拥有该角色的所有用户列表
|
||||
|
|
@ -95,7 +96,7 @@ public interface UserRepository extends JpaRepository<User, UUID> {
|
|||
/**
|
||||
* 检查用户名是否存在
|
||||
*
|
||||
* <p>用于用户注册时验证用户名唯一性。</p>
|
||||
* <p>用于用户注册时验证用户名唯一性。
|
||||
*
|
||||
* @param username 用户名
|
||||
* @return 存在返回true,不存在返回false
|
||||
|
|
@ -105,7 +106,7 @@ public interface UserRepository extends JpaRepository<User, UUID> {
|
|||
/**
|
||||
* 检查手机号是否存在
|
||||
*
|
||||
* <p>用于用户注册或更新时验证手机号唯一性。</p>
|
||||
* <p>用于用户注册或更新时验证手机号唯一性。
|
||||
*
|
||||
* @param phone 手机号码
|
||||
* @return 存在返回true,不存在返回false
|
||||
|
|
@ -115,7 +116,7 @@ public interface UserRepository extends JpaRepository<User, UUID> {
|
|||
/**
|
||||
* 根据用户类型查询用户列表
|
||||
*
|
||||
* <p>用于查询特定类型的用户,如ENTERPRISE、PROJECT_STAFF等。</p>
|
||||
* <p>用于查询特定类型的用户,如ENTERPRISE、PROJECT_STAFF等。
|
||||
*
|
||||
* @param userType 用户类型
|
||||
* @return 该类型的所有用户列表
|
||||
|
|
@ -125,7 +126,7 @@ public interface UserRepository extends JpaRepository<User, UUID> {
|
|||
/**
|
||||
* 根据部门ID查询用户列表
|
||||
*
|
||||
* <p>用于查询属于特定部门的所有用户。</p>
|
||||
* <p>用于查询属于特定部门的所有用户。
|
||||
*
|
||||
* @param deptId 部门唯一标识符
|
||||
* @return 该部门下的所有用户列表
|
||||
|
|
@ -135,11 +136,12 @@ public interface UserRepository extends JpaRepository<User, UUID> {
|
|||
/**
|
||||
* 根据项目ID查询项目员工
|
||||
*
|
||||
* <p>通过关联ProjectStaff表查询属于指定项目的所有员工用户。</p>
|
||||
* <p>通过关联ProjectStaff表查询属于指定项目的所有员工用户。
|
||||
*
|
||||
* @param projectId 项目唯一标识符
|
||||
* @return该项目下的所有员工用户列表
|
||||
*/
|
||||
@Query("SELECT u FROM User u JOIN ProjectStaff ps ON u.id = ps.userId WHERE ps.projectId = :projectId")
|
||||
@Query(
|
||||
"SELECT u FROM User u JOIN ProjectStaff ps ON u.id = ps.userId WHERE ps.projectId = :projectId")
|
||||
List<User> findProjectStaffsByProjectId(@Param("projectId") UUID projectId);
|
||||
}
|
||||
|
|
@ -13,10 +13,7 @@ public class AuditLogArchiveTask {
|
|||
|
||||
private final AuditLogService auditLogService;
|
||||
|
||||
/**
|
||||
* 每天凌晨2点执行归档任务
|
||||
* 将超过90天的审计日志归档(当前实现为删除,实际应导出到文件/对象存储)
|
||||
*/
|
||||
/** 每天凌晨2点执行归档任务 将超过90天的审计日志归档(当前实现为删除,实际应导出到文件/对象存储) */
|
||||
@Scheduled(cron = "0 0 2 * * ?")
|
||||
public void archiveOldAuditLogs() {
|
||||
log.info("开始执行审计日志归档任务...");
|
||||
|
|
|
|||
|
|
@ -1,138 +1,27 @@
|
|||
package com.ether.pms.auth.service;
|
||||
|
||||
import com.ether.pms.auth.entity.AuditLog;
|
||||
import com.ether.pms.auth.repository.AuditLogRepository;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import java.time.LocalDateTime;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
public interface AuditLogService {
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class AuditLogService {
|
||||
void saveAuditLogAsync(AuditLog auditLog);
|
||||
|
||||
private final AuditLogRepository auditLogRepository;
|
||||
private final ObjectMapper objectMapper;
|
||||
AuditLog saveAuditLog(AuditLog auditLog);
|
||||
|
||||
/**
|
||||
* 异步保存审计日志
|
||||
*/
|
||||
@Async("auditLogExecutor")
|
||||
public void saveAuditLogAsync(AuditLog auditLog) {
|
||||
try {
|
||||
auditLogRepository.save(auditLog);
|
||||
} catch (Exception e) {
|
||||
log.error("保存审计日志失败: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步保存审计日志(用于需要立即确认的场景)
|
||||
*/
|
||||
@Transactional
|
||||
public AuditLog saveAuditLog(AuditLog auditLog) {
|
||||
return auditLogRepository.save(auditLog);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询审计日志(最近30天)
|
||||
*/
|
||||
public Page<AuditLog> findRecentLogs(Pageable pageable) {
|
||||
LocalDateTime startTime = LocalDateTime.now().minusDays(30);
|
||||
return auditLogRepository.findRecentLogs(startTime, pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件查询审计日志(最近30天内)
|
||||
*/
|
||||
public Page<AuditLog> searchLogs(String module, String action, String username,
|
||||
LocalDateTime startDate, LocalDateTime endDate,
|
||||
Pageable pageable) {
|
||||
// 确保查询范围不超过30天
|
||||
LocalDateTime maxStartDate = LocalDateTime.now().minusDays(30);
|
||||
if (startDate == null || startDate.isBefore(maxStartDate)) {
|
||||
startDate = maxStartDate;
|
||||
}
|
||||
if (endDate == null) {
|
||||
endDate = LocalDateTime.now();
|
||||
}
|
||||
|
||||
final LocalDateTime finalStartDate = startDate;
|
||||
final LocalDateTime finalEndDate = endDate;
|
||||
|
||||
Specification<AuditLog> spec = (root, query, cb) -> {
|
||||
List<Predicate> predicates = new ArrayList<>();
|
||||
|
||||
// 时间范围
|
||||
predicates.add(cb.greaterThanOrEqualTo(root.get("createdAt"), finalStartDate));
|
||||
predicates.add(cb.lessThanOrEqualTo(root.get("createdAt"), finalEndDate));
|
||||
|
||||
// 模块筛选
|
||||
if (module != null && !module.isEmpty()) {
|
||||
predicates.add(cb.equal(root.get("module"), module));
|
||||
}
|
||||
|
||||
// 操作类型筛选
|
||||
if (action != null && !action.isEmpty()) {
|
||||
predicates.add(cb.equal(root.get("action"), AuditLog.ActionType.valueOf(action)));
|
||||
}
|
||||
|
||||
// 用户名筛选
|
||||
if (username != null && !username.isEmpty()) {
|
||||
predicates.add(cb.like(root.get("username"), "%" + username + "%"));
|
||||
}
|
||||
|
||||
return cb.and(predicates.toArray(new Predicate[0]));
|
||||
};
|
||||
|
||||
return auditLogRepository.findAll(spec, pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 归档超过90天的日志
|
||||
*/
|
||||
@Transactional
|
||||
public int archiveOldLogs() {
|
||||
LocalDateTime cutoffTime = LocalDateTime.now().minusDays(90);
|
||||
|
||||
// 查询需要归档的日志
|
||||
List<AuditLog> oldLogs = auditLogRepository.findByCreatedAtBefore(cutoffTime);
|
||||
|
||||
if (oldLogs.isEmpty()) {
|
||||
log.info("没有需要归档的审计日志");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: 将日志导出到文件或对象存储
|
||||
// 这里简化处理,直接删除
|
||||
// 实际项目中应该:
|
||||
// 1. 将数据导出为JSON/Parquet文件
|
||||
// 2. 上传到对象存储(MinIO/S3)
|
||||
// 3. 记录归档信息
|
||||
// 4. 然后删除数据库记录
|
||||
|
||||
int deleted = auditLogRepository.deleteByCreatedAtBefore(cutoffTime);
|
||||
log.info("归档审计日志完成,共归档 {} 条记录", deleted);
|
||||
|
||||
return deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最近30天的日志统计
|
||||
*/
|
||||
public long getRecentLogCount() {
|
||||
LocalDateTime startTime = LocalDateTime.now().minusDays(30);
|
||||
return auditLogRepository.countRecentLogs(startTime);
|
||||
}
|
||||
Page<AuditLog> findRecentLogs(Pageable pageable);
|
||||
|
||||
Page<AuditLog> searchLogs(
|
||||
String module,
|
||||
String action,
|
||||
String username,
|
||||
LocalDateTime startDate,
|
||||
LocalDateTime endDate,
|
||||
Pageable pageable);
|
||||
|
||||
int archiveOldLogs();
|
||||
|
||||
long getRecentLogCount();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
package com.ether.pms.auth.service;
|
||||
|
||||
import com.ether.pms.auth.entity.DataAccess;
|
||||
import com.ether.pms.auth.repository.DataAccessRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DataAccessService {
|
||||
|
||||
private final DataAccessRepository dataAccessRepository;
|
||||
|
||||
@Transactional
|
||||
public DataAccess grantAccess(String dataType, UUID dataId, String accessType, UUID accessId, String level, UUID grantedBy) {
|
||||
// 使用精确查询替代全表扫描,避免 OOM 风险
|
||||
Optional<DataAccess> existing = dataAccessRepository
|
||||
.findByDataTypeAndDataIdAndAccessTypeAndAccessId(dataType, dataId, accessType, accessId);
|
||||
|
||||
if (existing.isPresent()) {
|
||||
DataAccess existingAccess = existing.get();
|
||||
existingAccess.setAccessLevel(level);
|
||||
existingAccess.setGrantedBy(grantedBy);
|
||||
return dataAccessRepository.save(existingAccess);
|
||||
}
|
||||
|
||||
DataAccess access = new DataAccess();
|
||||
access.setDataType(dataType);
|
||||
access.setDataId(dataId);
|
||||
access.setAccessType(accessType);
|
||||
access.setAccessId(accessId);
|
||||
access.setAccessLevel(level);
|
||||
access.setGrantedBy(grantedBy);
|
||||
return dataAccessRepository.save(access);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void revokeAccess(UUID accessId) {
|
||||
dataAccessRepository.deleteById(accessId);
|
||||
}
|
||||
|
||||
public List<DataAccess> getDataAccess(String dataType, UUID dataId) {
|
||||
return dataAccessRepository.findByDataTypeAndDataId(dataType, dataId);
|
||||
}
|
||||
|
||||
public List<UUID> getAccessibleDataIds(String dataType, UUID userId) {
|
||||
return dataAccessRepository.findDataIdsByUserAccess(userId, dataType);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue