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.Expert; import com.kaidi.oa.repository.ExpertRepository; 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.ArrayList; import java.util.List; /** * Declaration expert pool (申报专家库). field (专业领域) is one of 给排水 / * 环境工程 / 市政 / 财务 / 法律 / 水利; expertType is one of 评审专家 / 咨询专家 / * 行业专家; status is one of 在库 / 暂停. */ @RestController @RequestMapping("/api/oa/experts") public class ExpertController { private final ExpertRepository expertRepo; public ExpertController(ExpertRepository expertRepo) { this.expertRepo = expertRepo; } @GetMapping public ApiResp> list(@RequestParam(required = false) String expertType) { List list; if (expertType != null && !expertType.isBlank()) { list = expertRepo.findByExpertType(expertType); } else { list = expertRepo.findAll(); } return ApiResp.ok(list); } @GetMapping("/{id}") public ApiResp get(@PathVariable Long id) { return ApiResp.ok(expertRepo.findById(id) .orElseThrow(() -> new NotFoundException("expert not found: " + id))); } public record CreateExpertRequest( String name, String field, String org, String title, String expertType, String phone, String status) { } @PostMapping public ApiResp create(@RequestBody CreateExpertRequest req) { if (req.name() == null || req.name().isBlank()) { throw new ApiException(400, "name is required"); } Expert e = new Expert(); e.setName(req.name()); e.setField(req.field()); e.setOrg(req.org()); e.setTitle(req.title()); e.setExpertType(req.expertType()); e.setPhone(req.phone()); e.setStatus(req.status() == null || req.status().isBlank() ? "在库" : req.status()); e.setCreatedAt(Instant.now()); return ApiResp.ok(expertRepo.save(e)); } @PatchMapping("/{id}") public ApiResp update(@PathVariable Long id, @RequestBody CreateExpertRequest req) { Expert e = expertRepo.findById(id) .orElseThrow(() -> new NotFoundException("expert not found: " + id)); if (req.name() != null && !req.name().isBlank()) e.setName(req.name()); if (req.field() != null) e.setField(req.field()); if (req.org() != null) e.setOrg(req.org()); if (req.title() != null) e.setTitle(req.title()); if (req.expertType() != null && !req.expertType().isBlank()) e.setExpertType(req.expertType()); if (req.phone() != null) e.setPhone(req.phone()); if (req.status() != null && !req.status().isBlank()) e.setStatus(req.status()); return ApiResp.ok(expertRepo.save(e)); } @DeleteMapping("/{id}") public ApiResp delete(@PathVariable Long id) { if (!expertRepo.existsById(id)) { throw new NotFoundException("expert not found: " + id); } expertRepo.deleteById(id); return ApiResp.ok(null); } /** * GET /experts/match?declType=高企 — 按申报类型关键词匹配「在库」专家。 * 规则:declType 用逗号分隔可传多个关键词;专家 field 或 expertType 含任一关键词则命中; * 仅返回 status=在库 的专家,按 field 字母序排列。 * 补完 Gap 6 缺口:「按擅长项目类型匹配」端点。 */ @GetMapping("/match") public ApiResp> match(@RequestParam(required = false) String declType) { List active = expertRepo.findByStatus("在库"); if (declType == null || declType.isBlank()) { return ApiResp.ok(active); } String[] keywords = declType.split("[,,]"); List matched = new ArrayList<>(); for (Expert ex : active) { String haystack = ((ex.getField() == null ? "" : ex.getField()) + " " + (ex.getExpertType() == null ? "" : ex.getExpertType())).toLowerCase(); for (String kw : keywords) { if (kw != null && !kw.isBlank() && haystack.contains(kw.trim().toLowerCase())) { matched.add(ex); break; } } } return ApiResp.ok(matched); } }