SNAPSHOT W7 已部署稳定态 — 凯迪ERP+OA一体化平台 (MET 73.3%)
恢复点(restore point)。别人改崩后可 git reset --hard 回到此提交。 == 此快照内容 == - 后端 oa-backend: 734 控制器 / 711 实体 (Spring Boot 3.2.5 + SQLite, 端口8091) - 前端 modern-ui/app: Vue3+Vite, 约700页 (构建产物已在 oa-backend/src/main/resources/static) - 数据库 oa-backend/data/oa.db: 含全部演示数据 (强制入库, 6.6MB) - 交接文档 go.md + go-code-reference/endpoints/entities/database.md - 多代理建设脚本 .claude/wf-*.js == 状态 == - 对 凯迪科技ERP_20260507.xlsx 合规 MET ~73.3% (PARTIAL 75: 34可建+6种子/bug+35外部硬天花板) - 安全: 5轮红队+5轮复检, default-deny分级鉴权, 连续零可利用 - W3~W7 累计补完436缺口; W8末轮(40缺口)为半成品(源码树可编译但未集成) - 运行: cd oa-backend; java -jar build/libs/oa-backend-0.1.0.jar --server.port=8091; admin/123456 == 排除(gitignore, 可再生) == node_modules / oa-backend/build / .jdks / *.log / Backup-ERP-* / 弃用的OFBiz核心(只保留modern-ui) 完整文件夹备份见同目录 Backup-ERP-20260615-191517/ (含上述全部, 仅缺 node_modules) 时间戳: 20260615-191517 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
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<ArchiveVault>> list(@RequestParam(required = false) String storeType,
|
||||
@RequestParam(required = false) Boolean onlyEnabled) {
|
||||
List<ArchiveVault> 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<ArchiveVault> get(@PathVariable Long id) {
|
||||
return ApiResp.ok(require(id));
|
||||
}
|
||||
|
||||
/** 该档案库已上架(非销毁)实体盒数,用于容量占用展示。 */
|
||||
@GetMapping("/{id}/usage")
|
||||
public ApiResp<VaultUsage> 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<ArchiveVault> 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<ArchiveVault> 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<Void> 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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user