feat(aihr): add scoped case detail view
This commit is contained in:
+8
@@ -6,6 +6,7 @@ import org.dromara.common.core.enums.UserType;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.aihr.domain.AihrCaseDto.CurateRequest;
|
||||
import org.dromara.aihr.domain.AihrCaseDto.CurateResponse;
|
||||
import org.dromara.aihr.domain.AihrCaseDto.DetailResponse;
|
||||
import org.dromara.aihr.domain.AihrCaseDto.OrganizeRequest;
|
||||
import org.dromara.aihr.domain.AihrCaseDto.OrganizeResponse;
|
||||
import org.dromara.aihr.domain.AihrCaseDto.RecordResponse;
|
||||
@@ -16,6 +17,7 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
@@ -54,6 +56,12 @@ public class AihrCaseController {
|
||||
return R.ok(caseService.records(limit, currentProjectScopes()));
|
||||
}
|
||||
|
||||
@GetMapping("/records/{caseId}")
|
||||
public R<DetailResponse> detail(@PathVariable String caseId) {
|
||||
DetailResponse detail = caseService.detail(caseId, currentProjectScopes());
|
||||
return detail == null ? R.fail("案例不存在或无权访问") : R.ok(detail);
|
||||
}
|
||||
|
||||
private List<String> currentProjectScopes() {
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
if (loginUser != null && UserType.SYS_USER.getUserType().equals(loginUser.getUserType())) {
|
||||
|
||||
+8
-1
@@ -31,6 +31,13 @@ public final class AihrCaseDto {
|
||||
public record TagResponse(String text, String type) {
|
||||
}
|
||||
|
||||
public record RecordResponse(String title, String type, String status, String time, String owner, String summary) {
|
||||
public record RecordResponse(String caseId, String title, String type, String status, String time, String owner, String summary) {
|
||||
public RecordResponse(String title, String type, String status, String time, String owner, String summary) {
|
||||
this("", title, type, status, time, owner, summary);
|
||||
}
|
||||
}
|
||||
|
||||
public record DetailResponse(String caseId, String fileName, String title, String type, String status,
|
||||
String time, String owner, String transcript, String summary) {
|
||||
}
|
||||
}
|
||||
|
||||
+35
-1
@@ -6,6 +6,7 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.aihr.domain.AihrCaseDto.CurateRequest;
|
||||
import org.dromara.aihr.domain.AihrCaseDto.CurateResponse;
|
||||
import org.dromara.aihr.domain.AihrCaseDto.DetailResponse;
|
||||
import org.dromara.aihr.domain.AihrCaseDto.OrganizeRequest;
|
||||
import org.dromara.aihr.domain.AihrCaseDto.OrganizeResponse;
|
||||
import org.dromara.aihr.domain.AihrCaseDto.RecordResponse;
|
||||
@@ -79,6 +80,7 @@ public class AihrCaseService {
|
||||
List<SummaryResponse> summary = state.summary() == null ? localSummary(state).summary() : state.summary();
|
||||
String title = caseTitle(summary, state.fileName());
|
||||
RecordResponse record = new RecordResponse(
|
||||
state.id(),
|
||||
title,
|
||||
primaryTag(state.tags()),
|
||||
"已入库",
|
||||
@@ -104,7 +106,7 @@ public class AihrCaseService {
|
||||
}
|
||||
args.add(safeLimit);
|
||||
String sql = """
|
||||
SELECT title, type, status, update_time, owner, summary
|
||||
SELECT case_id, title, type, status, update_time, owner, summary
|
||||
FROM aihr_case_record
|
||||
WHERE tenant_id = '000000'
|
||||
""" + projectWhere + """
|
||||
@@ -112,6 +114,7 @@ public class AihrCaseService {
|
||||
LIMIT ?
|
||||
""";
|
||||
return jdbcTemplate.query(sql, (rs, rowNum) -> new RecordResponse(
|
||||
firstNonBlank(rs.getString("case_id"), ""),
|
||||
firstNonBlank(rs.getString("title"), "现场案例"),
|
||||
firstNonBlank(rs.getString("type"), "现场案例"),
|
||||
firstNonBlank(rs.getString("status"), "已入库"),
|
||||
@@ -121,6 +124,37 @@ public class AihrCaseService {
|
||||
), args.toArray());
|
||||
}
|
||||
|
||||
public DetailResponse detail(String caseId, List<String> projectScopes) {
|
||||
String normalizedCaseId = clean(caseId);
|
||||
if (normalizedCaseId.isBlank() || (projectScopes != null && projectScopes.isEmpty())) {
|
||||
return null;
|
||||
}
|
||||
ensureCaseTable();
|
||||
List<Object> args = new ArrayList<>();
|
||||
args.add(normalizedCaseId);
|
||||
String projectWhere = "";
|
||||
if (projectScopes != null) {
|
||||
projectWhere = " AND project_ext_org_id IN (" + placeholders(projectScopes.size()) + ")";
|
||||
args.addAll(projectScopes);
|
||||
}
|
||||
String sql = """
|
||||
SELECT case_id, file_name, title, type, status, update_time, owner, transcript, summary
|
||||
FROM aihr_case_record
|
||||
WHERE tenant_id = '000000' AND case_id = ?
|
||||
""" + projectWhere + " LIMIT 1";
|
||||
return jdbcTemplate.query(sql, (rs, rowNum) -> new DetailResponse(
|
||||
firstNonBlank(rs.getString("case_id"), normalizedCaseId),
|
||||
firstNonBlank(rs.getString("file_name"), "case-audio"),
|
||||
firstNonBlank(rs.getString("title"), "现场案例"),
|
||||
firstNonBlank(rs.getString("type"), "现场案例"),
|
||||
firstNonBlank(rs.getString("status"), "已入库"),
|
||||
rs.getTimestamp("update_time") == null ? "" : rs.getTimestamp("update_time").toLocalDateTime().format(TIME_FORMAT),
|
||||
firstNonBlank(rs.getString("owner"), "培训组"),
|
||||
firstNonBlank(rs.getString("transcript"), ""),
|
||||
firstNonBlank(rs.getString("summary"), "")
|
||||
), args.toArray()).stream().findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public List<String> projectScopesForAppUser(String identity) {
|
||||
String username = clean(identity);
|
||||
if (username.isBlank()) {
|
||||
|
||||
+16
@@ -58,6 +58,19 @@ class AihrCaseServiceTest {
|
||||
assertEquals("persisted-case", jdbcTemplate.lastCaseId);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Tag("dev")
|
||||
void detailReturnsPersistedCaseForAuthorizedProject() {
|
||||
PersistentCaseJdbcTemplate jdbcTemplate = new PersistentCaseJdbcTemplate();
|
||||
AihrCaseService service = new AihrCaseService(null, null, new ObjectMapper(), jdbcTemplate);
|
||||
|
||||
var detail = service.detail("persisted-case", List.of("P1"));
|
||||
|
||||
assertEquals("persisted-case", detail.caseId());
|
||||
assertEquals("业主投诉后完成跟进", detail.transcript());
|
||||
assertEquals("P1", jdbcTemplate.lastArgs[1]);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Tag("dev")
|
||||
void appCaseScopeMustMatchAnActiveProject() {
|
||||
@@ -84,10 +97,12 @@ class AihrCaseServiceTest {
|
||||
|
||||
private static final class PersistentCaseJdbcTemplate extends CaseJdbcTemplate {
|
||||
private String lastCaseId;
|
||||
private Object[] lastArgs = new Object[0];
|
||||
|
||||
@Override
|
||||
public <T> List<T> query(String sql, RowMapper<T> rowMapper, Object... args) {
|
||||
this.lastCaseId = String.valueOf(args[0]);
|
||||
this.lastArgs = args;
|
||||
try {
|
||||
ResultSet resultSet = mock(ResultSet.class);
|
||||
when(resultSet.getString("case_id")).thenReturn("persisted-case");
|
||||
@@ -95,6 +110,7 @@ class AihrCaseServiceTest {
|
||||
when(resultSet.getString("project_ext_org_id")).thenReturn("P1");
|
||||
when(resultSet.getString("transcript")).thenReturn("业主投诉后完成跟进");
|
||||
when(resultSet.getString("type")).thenReturn("投诉处理");
|
||||
when(resultSet.getString("title")).thenReturn("业主投诉案例");
|
||||
return List.of(rowMapper.mapRow(resultSet, 0));
|
||||
} catch (SQLException e) {
|
||||
throw new AssertionError(e);
|
||||
|
||||
Reference in New Issue
Block a user