package com.kaidi.oa.web; import com.kaidi.oa.common.ApiException; import com.kaidi.oa.common.ApiResp; import com.kaidi.oa.common.NotFoundException; import com.kaidi.oa.domain.ArchivePhysicalItem; import com.kaidi.oa.domain.ArchiveVault; import com.kaidi.oa.repository.ArchivePhysicalItemRepository; import com.kaidi.oa.repository.ArchiveVaultRepository; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; 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 java.time.Instant; import java.util.List; /** * 资料室·虚拟档案库管理(Module 1「档案库管理」缺口补深)。维护对应实体库房 / 密集架 / * 电子存储区 / 云存储的虚拟档案库,支持按年度、部门、保密等级、保存期限维度建库。 * 实体盒上架时落库到此处档案库,电子档记云存储 ID。写口默认受 default-deny(ADMIN/APPROVER) 保护。 */ @RestController @RequestMapping("/api/oa/archive-vaults") public class ArchiveVaultController { private final ArchiveVaultRepository vaultRepo; private final ArchivePhysicalItemRepository itemRepo; public ArchiveVaultController(ArchiveVaultRepository vaultRepo, ArchivePhysicalItemRepository itemRepo) { this.vaultRepo = vaultRepo; this.itemRepo = itemRepo; } @GetMapping public ApiResp> list(@RequestParam(required = false) String storeType, @RequestParam(required = false) Boolean onlyEnabled) { List list; if (storeType != null && !storeType.isBlank()) { list = vaultRepo.findByStoreType(storeType); } else if (Boolean.TRUE.equals(onlyEnabled)) { list = vaultRepo.findByEnabledTrue(); } else { list = vaultRepo.findAll(); } return ApiResp.ok(list); } @GetMapping("/{id}") public ApiResp get(@PathVariable Long id) { return ApiResp.ok(require(id)); } /** 该档案库已上架(非销毁)实体盒数,用于容量占用展示。 */ @GetMapping("/{id}/usage") public ApiResp usage(@PathVariable Long id) { ArchiveVault v = require(id); long used = itemRepo.findByVaultId(id).stream() .filter(i -> !"已销毁".equals(i.getStatus())) .count(); int cap = v.getCapacity() == null ? 0 : v.getCapacity(); return ApiResp.ok(new VaultUsage(id, v.getName(), cap, used, cap <= 0 ? null : Math.max(0, cap - used))); } public record VaultUsage(Long vaultId, String name, int capacity, long used, Long remaining) { } public record VaultRequest( String name, String storeType, String roomNo, String cloudId, String dimYear, String dimDept, String dimSecLevel, String dimRetention, Integer capacity, Boolean enabled, String remark) { } @PostMapping public ApiResp create(@RequestBody VaultRequest req) { if (req.name() == null || req.name().isBlank()) { throw new ApiException(400, "档案库名称(name) 不能为空"); } ArchiveVault v = new ArchiveVault(); v.setCode("VL-" + (vaultRepo.count() + 1)); apply(v, req, true); v.setCreatedAt(Instant.now()); return ApiResp.ok(vaultRepo.save(v)); } @PatchMapping("/{id}") public ApiResp update(@PathVariable Long id, @RequestBody VaultRequest req) { ArchiveVault v = require(id); apply(v, req, false); return ApiResp.ok(vaultRepo.save(v)); } @DeleteMapping("/{id}") public ApiResp delete(@PathVariable Long id) { ArchiveVault v = require(id); long inUse = itemRepo.findByVaultId(id).stream() .filter(i -> !"已销毁".equals(i.getStatus())) .count(); if (inUse > 0) { throw new ApiException(409, "该档案库内仍有 " + inUse + " 个在库盒/卷,不能删除"); } vaultRepo.delete(v); return ApiResp.ok(); } private void apply(ArchiveVault v, VaultRequest req, boolean create) { if (req.name() != null && !req.name().isBlank()) v.setName(req.name().trim()); if (req.storeType() != null) v.setStoreType(req.storeType()); else if (create) v.setStoreType("实体库房"); if (req.roomNo() != null) v.setRoomNo(req.roomNo()); if (req.cloudId() != null) v.setCloudId(req.cloudId()); if (req.dimYear() != null) v.setDimYear(req.dimYear()); if (req.dimDept() != null) v.setDimDept(req.dimDept()); if (req.dimSecLevel() != null) v.setDimSecLevel(req.dimSecLevel()); if (req.dimRetention() != null) v.setDimRetention(req.dimRetention()); if (req.capacity() != null) v.setCapacity(req.capacity()); if (req.enabled() != null) v.setEnabled(req.enabled()); else if (create) v.setEnabled(Boolean.TRUE); if (req.remark() != null) v.setRemark(req.remark()); } private ArchiveVault require(Long id) { return vaultRepo.findById(id) .orElseThrow(() -> new NotFoundException("archive vault not found: " + id)); } }