fix: 收紧智能体聊天历史访问范围

- 普通账号仅可访问本人 Agent 会话

- 超级管理员保留全量查询并限制筛选入口
This commit is contained in:
2026-08-03 14:49:31 +08:00
parent 866688b92f
commit 93db17b384
6 changed files with 370 additions and 30 deletions

View File

@@ -16,6 +16,7 @@ import tech.easyflow.common.domain.Result;
import tech.easyflow.common.entity.LoginAccount; import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil; import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.common.web.jsonbody.JsonBody; import tech.easyflow.common.web.jsonbody.JsonBody;
import tech.easyflow.system.service.CategoryPermissionService;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.List; import java.util.List;
@@ -25,37 +26,108 @@ import java.util.List;
public class ChatHistoryController { public class ChatHistoryController {
private final ChatHistoryManageService chatHistoryManageService; private final ChatHistoryManageService chatHistoryManageService;
private final CategoryPermissionService categoryPermissionService;
public ChatHistoryController(ChatHistoryManageService chatHistoryManageService) { /**
* 创建聊天历史控制器。
*
* @param chatHistoryManageService 聊天历史管理服务
* @param categoryPermissionService 账号权限服务
*/
public ChatHistoryController(ChatHistoryManageService chatHistoryManageService,
CategoryPermissionService categoryPermissionService) {
this.chatHistoryManageService = chatHistoryManageService; this.chatHistoryManageService = chatHistoryManageService;
this.categoryPermissionService = categoryPermissionService;
} }
/**
* 分页查询当前账号可见的 Agent 会话。
*
* @param query 会话筛选条件
* @return 会话分页结果
*/
@GetMapping("/sessions") @GetMapping("/sessions")
public Result<ChatSessionPage> listSessions(ChatSessionFilterQuery query) { public Result<ChatSessionPage> listSessions(ChatSessionFilterQuery query) {
return Result.ok(chatHistoryManageService.queryAdminSessions(query)); LoginAccount account = SaTokenUtil.getLoginAccount();
return Result.ok(chatHistoryManageService.queryAdminSessions(
account.getId(),
categoryPermissionService.isSuperAdmin(account),
query
));
} }
/**
* 获取当前账号可见的 Agent 会话详情。
*
* @param sessionId 会话 ID
* @return 会话详情
*/
@GetMapping("/sessions/{sessionId}") @GetMapping("/sessions/{sessionId}")
public Result<ChatSessionSummary> getSession(@PathVariable BigInteger sessionId) { public Result<ChatSessionSummary> getSession(@PathVariable BigInteger sessionId) {
return Result.ok(chatHistoryManageService.getAdminSession(sessionId)); LoginAccount account = SaTokenUtil.getLoginAccount();
return Result.ok(chatHistoryManageService.getAdminSession(
account.getId(),
categoryPermissionService.isSuperAdmin(account),
sessionId
));
} }
/**
* 分页查询当前账号可见会话的消息。
*
* @param sessionId 会话 ID
* @param query 消息分页条件
* @return 消息分页结果
*/
@GetMapping("/sessions/{sessionId}/messages") @GetMapping("/sessions/{sessionId}/messages")
public Result<ChatHistoryPage> queryMessages(@PathVariable BigInteger sessionId, ChatPageQuery query) { public Result<ChatHistoryPage> queryMessages(@PathVariable BigInteger sessionId, ChatPageQuery query) {
return Result.ok(chatHistoryManageService.queryAdminMessages(sessionId, query)); LoginAccount account = SaTokenUtil.getLoginAccount();
return Result.ok(chatHistoryManageService.queryAdminMessages(
account.getId(),
categoryPermissionService.isSuperAdmin(account),
sessionId,
query
));
} }
/**
* 查询当前账号可见会话的答案版本。
*
* @param sessionId 会话 ID
* @param roundId 对话轮次 ID
* @return 答案版本列表
*/
@GetMapping("/sessions/{sessionId}/rounds/{roundId}/variants") @GetMapping("/sessions/{sessionId}/rounds/{roundId}/variants")
public Result<List<ChatMessageRecord>> listRoundVariants(@PathVariable BigInteger sessionId, public Result<List<ChatMessageRecord>> listRoundVariants(@PathVariable BigInteger sessionId,
@PathVariable BigInteger roundId) { @PathVariable BigInteger roundId) {
return Result.ok(chatHistoryManageService.listAdminRoundVariants(sessionId, roundId)); LoginAccount account = SaTokenUtil.getLoginAccount();
return Result.ok(chatHistoryManageService.listAdminRoundVariants(
account.getId(),
categoryPermissionService.isSuperAdmin(account),
sessionId,
roundId
));
} }
/**
* 选择当前账号可见会话的答案版本。
*
* @param sessionId 会话 ID
* @param roundId 对话轮次 ID
* @param variantIndex 目标版本索引
* @return 选中的答案记录
*/
@PostMapping("/sessions/{sessionId}/rounds/{roundId}/selectVariant") @PostMapping("/sessions/{sessionId}/rounds/{roundId}/selectVariant")
public Result<ChatMessageRecord> selectRoundVariant(@PathVariable BigInteger sessionId, public Result<ChatMessageRecord> selectRoundVariant(@PathVariable BigInteger sessionId,
@PathVariable BigInteger roundId, @PathVariable BigInteger roundId,
@JsonBody(value = "variantIndex", required = true) Integer variantIndex) { @JsonBody(value = "variantIndex", required = true) Integer variantIndex) {
LoginAccount account = SaTokenUtil.getLoginAccount(); LoginAccount account = SaTokenUtil.getLoginAccount();
return Result.ok(chatHistoryManageService.selectAdminRoundVariant(sessionId, roundId, variantIndex, account.getId())); return Result.ok(chatHistoryManageService.selectAdminRoundVariant(
account.getId(),
categoryPermissionService.isSuperAdmin(account),
sessionId,
roundId,
variantIndex
));
} }
} }

View File

@@ -0,0 +1,82 @@
package tech.easyflow.admin.controller.ai;
import org.mockito.MockedStatic;
import org.testng.annotations.Test;
import tech.easyflow.chatlog.domain.dto.ChatSessionPage;
import tech.easyflow.chatlog.domain.dto.ChatSessionSummary;
import tech.easyflow.chatlog.domain.query.ChatSessionFilterQuery;
import tech.easyflow.chatlog.service.ChatHistoryManageService;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.system.service.CategoryPermissionService;
import java.math.BigInteger;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* {@link ChatHistoryController} 数据范围测试。
*/
public class ChatHistoryControllerTest {
/**
* 验证普通账号查询时将本人范围传给服务层。
*/
@Test
public void listSessionsShouldUseCurrentUserScopeForRegularAccount() {
BigInteger accountId = BigInteger.valueOf(20);
ChatHistoryManageService service = mock(ChatHistoryManageService.class);
CategoryPermissionService permissionService = mock(CategoryPermissionService.class);
ChatHistoryController controller = new ChatHistoryController(service, permissionService);
ChatSessionFilterQuery query = new ChatSessionFilterQuery();
LoginAccount account = loginAccount(accountId);
when(permissionService.isSuperAdmin(account)).thenReturn(false);
when(service.queryAdminSessions(accountId, false, query)).thenReturn(new ChatSessionPage());
try (MockedStatic<SaTokenUtil> saToken = mockStatic(SaTokenUtil.class)) {
saToken.when(SaTokenUtil::getLoginAccount).thenReturn(account);
controller.listSessions(query);
}
verify(service).queryAdminSessions(accountId, false, query);
}
/**
* 验证超级管理员查询详情时保留全量范围。
*/
@Test
public void getSessionShouldUseAllScopeForSuperAdmin() {
BigInteger accountId = BigInteger.ONE;
BigInteger sessionId = BigInteger.valueOf(30);
ChatHistoryManageService service = mock(ChatHistoryManageService.class);
CategoryPermissionService permissionService = mock(CategoryPermissionService.class);
ChatHistoryController controller = new ChatHistoryController(service, permissionService);
LoginAccount account = loginAccount(accountId);
when(permissionService.isSuperAdmin(account)).thenReturn(true);
when(service.getAdminSession(accountId, true, sessionId)).thenReturn(new ChatSessionSummary());
try (MockedStatic<SaTokenUtil> saToken = mockStatic(SaTokenUtil.class)) {
saToken.when(SaTokenUtil::getLoginAccount).thenReturn(account);
controller.getSession(sessionId);
}
verify(service).getAdminSession(accountId, true, sessionId);
}
/**
* 构造登录账号。
*
* @param accountId 账号 ID
* @return 登录账号
*/
private LoginAccount loginAccount(BigInteger accountId) {
LoginAccount account = new LoginAccount();
account.setId(accountId);
return account;
}
}

View File

@@ -10,19 +10,54 @@ import tech.easyflow.chatlog.domain.query.ChatSessionFilterQuery;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.List; import java.util.List;
/**
* Agent 聊天历史管理服务。
*/
public interface ChatHistoryManageService { public interface ChatHistoryManageService {
ChatSessionPage queryUserSessions(BigInteger userId, BigInteger assistantId, ChatPageQuery query); ChatSessionPage queryUserSessions(BigInteger userId, BigInteger assistantId, ChatPageQuery query);
ChatSessionPage queryAdminSessions(ChatSessionFilterQuery query); /**
* 按当前管理端账号的数据范围查询 Agent 会话。
*
* @param requesterId 当前账号 ID
* @param superAdmin 当前账号是否为超级管理员
* @param query 会话筛选条件
* @return 会话分页结果
*/
ChatSessionPage queryAdminSessions(BigInteger requesterId,
boolean superAdmin,
ChatSessionFilterQuery query);
ChatSessionSummary getUserSession(BigInteger userId, BigInteger sessionId); ChatSessionSummary getUserSession(BigInteger userId, BigInteger sessionId);
ChatSessionSummary getAdminSession(BigInteger sessionId); /**
* 获取当前管理端账号可见的 Agent 会话。
*
* @param requesterId 当前账号 ID
* @param superAdmin 当前账号是否为超级管理员
* @param sessionId 会话 ID
* @return 会话摘要
*/
ChatSessionSummary getAdminSession(BigInteger requesterId,
boolean superAdmin,
BigInteger sessionId);
ChatHistoryPage queryUserMessages(BigInteger userId, BigInteger sessionId, ChatPageQuery query); ChatHistoryPage queryUserMessages(BigInteger userId, BigInteger sessionId, ChatPageQuery query);
ChatHistoryPage queryAdminMessages(BigInteger sessionId, ChatPageQuery query); /**
* 查询当前管理端账号可见会话的消息。
*
* @param requesterId 当前账号 ID
* @param superAdmin 当前账号是否为超级管理员
* @param sessionId 会话 ID
* @param query 消息分页条件
* @return 消息分页结果
*/
ChatHistoryPage queryAdminMessages(BigInteger requesterId,
boolean superAdmin,
BigInteger sessionId,
ChatPageQuery query);
void renameUserSession(BigInteger userId, BigInteger sessionId, String title, BigInteger operatorId); void renameUserSession(BigInteger userId, BigInteger sessionId, String title, BigInteger operatorId);
@@ -32,7 +67,33 @@ public interface ChatHistoryManageService {
ChatMessageRecord selectUserRoundVariant(BigInteger userId, BigInteger sessionId, BigInteger roundId, Integer variantIndex, BigInteger operatorId); ChatMessageRecord selectUserRoundVariant(BigInteger userId, BigInteger sessionId, BigInteger roundId, Integer variantIndex, BigInteger operatorId);
List<ChatMessageRecord> listAdminRoundVariants(BigInteger sessionId, BigInteger roundId); /**
* 查询当前管理端账号可见会话的答案版本。
*
* @param requesterId 当前账号 ID
* @param superAdmin 当前账号是否为超级管理员
* @param sessionId 会话 ID
* @param roundId 对话轮次 ID
* @return 答案版本列表
*/
List<ChatMessageRecord> listAdminRoundVariants(BigInteger requesterId,
boolean superAdmin,
BigInteger sessionId,
BigInteger roundId);
ChatMessageRecord selectAdminRoundVariant(BigInteger sessionId, BigInteger roundId, Integer variantIndex, BigInteger operatorId); /**
* 选择当前管理端账号可见会话的答案版本。
*
* @param requesterId 当前账号 ID同时作为操作人 ID
* @param superAdmin 当前账号是否为超级管理员
* @param sessionId 会话 ID
* @param roundId 对话轮次 ID
* @param variantIndex 目标版本索引
* @return 选中的答案记录
*/
ChatMessageRecord selectAdminRoundVariant(BigInteger requesterId,
boolean superAdmin,
BigInteger sessionId,
BigInteger roundId,
Integer variantIndex);
} }

View File

@@ -18,6 +18,9 @@ import tech.easyflow.common.web.exceptions.BusinessException;
import java.math.BigInteger; import java.math.BigInteger;
/**
* Agent 聊天历史管理服务实现。
*/
@Service @Service
public class ChatHistoryManageServiceImpl implements ChatHistoryManageService { public class ChatHistoryManageServiceImpl implements ChatHistoryManageService {
@@ -29,6 +32,15 @@ public class ChatHistoryManageServiceImpl implements ChatHistoryManageService {
private final ChatRoundOperateService chatRoundOperateService; private final ChatRoundOperateService chatRoundOperateService;
private final ChatAnalyticalDBRepository chatAnalyticalDBRepository; private final ChatAnalyticalDBRepository chatAnalyticalDBRepository;
/**
* 创建 Agent 聊天历史管理服务。
*
* @param chatSessionQueryService 会话查询服务
* @param chatSessionCommandService 会话命令服务
* @param chatHistoryQueryService 历史消息查询服务
* @param chatRoundOperateService 对话轮次操作服务
* @param chatAnalyticalDBRepository 聊天分析库仓储
*/
public ChatHistoryManageServiceImpl(ChatSessionQueryService chatSessionQueryService, public ChatHistoryManageServiceImpl(ChatSessionQueryService chatSessionQueryService,
ChatSessionCommandService chatSessionCommandService, ChatSessionCommandService chatSessionCommandService,
ChatHistoryQueryService chatHistoryQueryService, ChatHistoryQueryService chatHistoryQueryService,
@@ -46,11 +58,22 @@ public class ChatHistoryManageServiceImpl implements ChatHistoryManageService {
return chatSessionQueryService.pageSessions(userId, assistantId, AGENT_ASSISTANT_CODE, query); return chatSessionQueryService.pageSessions(userId, assistantId, AGENT_ASSISTANT_CODE, query);
} }
/**
* {@inheritDoc}
*/
@Override @Override
public ChatSessionPage queryAdminSessions(ChatSessionFilterQuery query) { public ChatSessionPage queryAdminSessions(BigInteger requesterId,
boolean superAdmin,
ChatSessionFilterQuery query) {
ChatSessionFilterQuery effectiveQuery = query == null ? new ChatSessionFilterQuery() : query; ChatSessionFilterQuery effectiveQuery = query == null ? new ChatSessionFilterQuery() : query;
// 管理端聊天历史已经切换为 Agent 专属入口,类型由服务端固定,避免客户端绕过。 // 管理端聊天历史已经切换为 Agent 专属入口,类型由服务端固定,避免客户端绕过。
effectiveQuery.setAssistantCode(AGENT_ASSISTANT_CODE); effectiveQuery.setAssistantCode(AGENT_ASSISTANT_CODE);
if (!superAdmin) {
requireRequesterId(requesterId);
// 普通账号的数据范围由服务端覆盖,客户端无法通过筛选参数扩大范围。
effectiveQuery.setUserId(requesterId);
effectiveQuery.setUserAccount(null);
}
return chatAnalyticalDBRepository.pageSessions(effectiveQuery); return chatAnalyticalDBRepository.pageSessions(effectiveQuery);
} }
@@ -68,14 +91,25 @@ public class ChatHistoryManageServiceImpl implements ChatHistoryManageService {
return summary; return summary;
} }
/**
* {@inheritDoc}
*/
@Override @Override
public ChatSessionSummary getAdminSession(BigInteger sessionId) { public ChatSessionSummary getAdminSession(BigInteger requesterId,
boolean superAdmin,
BigInteger sessionId) {
ChatSessionSummary summary = chatAnalyticalDBRepository.getSession(sessionId); ChatSessionSummary summary = chatAnalyticalDBRepository.getSession(sessionId);
if (summary == null if (summary == null
|| Integer.valueOf(1).equals(summary.getIsDeleted()) || Integer.valueOf(1).equals(summary.getIsDeleted())
|| !AGENT_ASSISTANT_CODE.equals(summary.getAssistantCode())) { || !AGENT_ASSISTANT_CODE.equals(summary.getAssistantCode())) {
throw new BusinessException("Agent 会话不存在"); throw new BusinessException("Agent 会话不存在");
} }
if (!superAdmin) {
requireRequesterId(requesterId);
if (summary.getUserId() == null || !summary.getUserId().equals(requesterId)) {
throw new BusinessException(403, 403, "无权访问该会话");
}
}
return summary; return summary;
} }
@@ -89,9 +123,15 @@ public class ChatHistoryManageServiceImpl implements ChatHistoryManageService {
return chatHistoryQueryService.queryHistoryMessages(sessionId, query); return chatHistoryQueryService.queryHistoryMessages(sessionId, query);
} }
/**
* {@inheritDoc}
*/
@Override @Override
public ChatHistoryPage queryAdminMessages(BigInteger sessionId, ChatPageQuery query) { public ChatHistoryPage queryAdminMessages(BigInteger requesterId,
ChatSessionSummary summary = getAdminSession(sessionId); boolean superAdmin,
BigInteger sessionId,
ChatPageQuery query) {
ChatSessionSummary summary = getAdminSession(requesterId, superAdmin, sessionId);
ChatHistoryPage firstPage = restoreRecentMessages(summary, query); ChatHistoryPage firstPage = restoreRecentMessages(summary, query);
if (firstPage != null) { if (firstPage != null) {
return firstPage; return firstPage;
@@ -126,16 +166,29 @@ public class ChatHistoryManageServiceImpl implements ChatHistoryManageService {
return chatRoundOperateService.selectVariant(sessionId, roundId, variantIndex, operatorId); return chatRoundOperateService.selectVariant(sessionId, roundId, variantIndex, operatorId);
} }
/**
* {@inheritDoc}
*/
@Override @Override
public java.util.List<ChatMessageRecord> listAdminRoundVariants(BigInteger sessionId, BigInteger roundId) { public java.util.List<ChatMessageRecord> listAdminRoundVariants(BigInteger requesterId,
getAdminSession(sessionId); boolean superAdmin,
BigInteger sessionId,
BigInteger roundId) {
getAdminSession(requesterId, superAdmin, sessionId);
return chatRoundOperateService.listVariants(sessionId, roundId); return chatRoundOperateService.listVariants(sessionId, roundId);
} }
/**
* {@inheritDoc}
*/
@Override @Override
public ChatMessageRecord selectAdminRoundVariant(BigInteger sessionId, BigInteger roundId, Integer variantIndex, BigInteger operatorId) { public ChatMessageRecord selectAdminRoundVariant(BigInteger requesterId,
getAdminSession(sessionId); boolean superAdmin,
return chatRoundOperateService.selectVariant(sessionId, roundId, variantIndex, operatorId); BigInteger sessionId,
BigInteger roundId,
Integer variantIndex) {
getAdminSession(requesterId, superAdmin, sessionId);
return chatRoundOperateService.selectVariant(sessionId, roundId, variantIndex, requesterId);
} }
private ChatHistoryPage restoreRecentMessages(ChatSessionSummary summary, ChatPageQuery query) { private ChatHistoryPage restoreRecentMessages(ChatSessionSummary summary, ChatPageQuery query) {
@@ -157,4 +210,15 @@ public class ChatHistoryManageServiceImpl implements ChatHistoryManageService {
page.setTotal(Math.max(total, records.size())); page.setTotal(Math.max(total, records.size()));
return page; return page;
} }
/**
* 校验受限查询必须携带当前账号 ID。
*
* @param requesterId 当前账号 ID
*/
private void requireRequesterId(BigInteger requesterId) {
if (requesterId == null) {
throw new BusinessException(403, 403, "无权访问聊天记录");
}
}
} }

View File

@@ -110,12 +110,29 @@ public class ChatHistoryManageServiceImplTest {
ChatSessionFilterQuery query = new ChatSessionFilterQuery(); ChatSessionFilterQuery query = new ChatSessionFilterQuery();
query.setAssistantCode("BOT"); query.setAssistantCode("BOT");
service.queryAdminSessions(query); service.queryAdminSessions(BigInteger.ONE, true, query);
Assert.assertEquals("AGENT", query.getAssistantCode()); Assert.assertEquals("AGENT", query.getAssistantCode());
Assert.assertSame(query, chatAnalyticalDBRepository.lastPageQuery); Assert.assertSame(query, chatAnalyticalDBRepository.lastPageQuery);
} }
/**
* 验证普通账号列表由服务端强制限定为本人,并忽略用户账号筛选。
*/
@Test
public void queryAdminSessionsShouldForceCurrentUserForRegularAccount() {
BigInteger requesterId = BigInteger.valueOf(2004);
ChatSessionFilterQuery query = new ChatSessionFilterQuery();
query.setUserId(BigInteger.valueOf(9999));
query.setUserAccount("other-user");
service.queryAdminSessions(requesterId, false, query);
Assert.assertEquals(requesterId, query.getUserId());
Assert.assertNull(query.getUserAccount());
Assert.assertEquals("AGENT", query.getAssistantCode());
}
/** /**
* 验证管理端可以读取正式 Agent 会话。 * 验证管理端可以读取正式 Agent 会话。
*/ */
@@ -125,11 +142,31 @@ public class ChatHistoryManageServiceImplTest {
ChatSessionSummary summary = session(sessionId, "AGENT", 0); ChatSessionSummary summary = session(sessionId, "AGENT", 0);
chatAnalyticalDBRepository.sessionResult = summary; chatAnalyticalDBRepository.sessionResult = summary;
ChatSessionSummary result = service.getAdminSession(sessionId); ChatSessionSummary result = service.getAdminSession(BigInteger.ONE, true, sessionId);
Assert.assertSame(summary, result); Assert.assertSame(summary, result);
} }
/**
* 验证普通账号只能读取归属于本人的 Agent 会话。
*/
@Test
public void getAdminSessionShouldRejectForeignSessionForRegularAccount() {
BigInteger requesterId = BigInteger.valueOf(2005);
BigInteger sessionId = BigInteger.valueOf(3005);
ChatSessionSummary summary = session(sessionId, "AGENT", 0);
summary.setUserId(BigInteger.valueOf(9999));
chatAnalyticalDBRepository.sessionResult = summary;
BusinessException exception = Assert.assertThrows(
BusinessException.class,
() -> service.getAdminSession(requesterId, false, sessionId)
);
Assert.assertEquals(403, exception.getHttpStatus());
Assert.assertEquals("无权访问该会话", exception.getMessage());
}
/** /**
* 验证正式 Agent 会话可以继续读取历史消息。 * 验证正式 Agent 会话可以继续读取历史消息。
*/ */
@@ -148,7 +185,7 @@ public class ChatHistoryManageServiceImplTest {
ChatPageQuery query = new ChatPageQuery(); ChatPageQuery query = new ChatPageQuery();
query.setPageNumber(2); query.setPageNumber(2);
ChatHistoryPage result = service.queryAdminMessages(sessionId, query); ChatHistoryPage result = service.queryAdminMessages(BigInteger.ONE, true, sessionId, query);
Assert.assertSame(expectedPage, result); Assert.assertSame(expectedPage, result);
} }
@@ -163,7 +200,7 @@ public class ChatHistoryManageServiceImplTest {
BusinessException exception = Assert.assertThrows( BusinessException exception = Assert.assertThrows(
BusinessException.class, BusinessException.class,
() -> service.getAdminSession(sessionId) () -> service.getAdminSession(BigInteger.ONE, true, sessionId)
); );
Assert.assertEquals("Agent 会话不存在", exception.getMessage()); Assert.assertEquals("Agent 会话不存在", exception.getMessage());
@@ -179,7 +216,12 @@ public class ChatHistoryManageServiceImplTest {
Assert.assertThrows( Assert.assertThrows(
BusinessException.class, BusinessException.class,
() -> service.queryAdminMessages(sessionId, new ChatPageQuery()) () -> service.queryAdminMessages(
BigInteger.ONE,
true,
sessionId,
new ChatPageQuery()
)
); );
} }
@@ -193,7 +235,12 @@ public class ChatHistoryManageServiceImplTest {
Assert.assertThrows( Assert.assertThrows(
BusinessException.class, BusinessException.class,
() -> service.listAdminRoundVariants(sessionId, BigInteger.ONE) () -> service.listAdminRoundVariants(
BigInteger.ONE,
true,
sessionId,
BigInteger.ONE
)
); );
} }
@@ -208,10 +255,11 @@ public class ChatHistoryManageServiceImplTest {
Assert.assertThrows( Assert.assertThrows(
BusinessException.class, BusinessException.class,
() -> service.selectAdminRoundVariant( () -> service.selectAdminRoundVariant(
BigInteger.TEN,
true,
sessionId, sessionId,
BigInteger.ONE, BigInteger.ONE,
1, 1
BigInteger.TEN
) )
); );
} }

View File

@@ -4,6 +4,7 @@ import type { ChatTimeTimelineItem } from '@easyflow/types';
import { computed, onMounted, ref } from 'vue'; import { computed, onMounted, ref } from 'vue';
import { useEasyFlowDrawer } from '@easyflow/common-ui'; import { useEasyFlowDrawer } from '@easyflow/common-ui';
import { useUserStore } from '@easyflow/stores';
import { import {
ChatTimeHistoryMapper, ChatTimeHistoryMapper,
ChatTimeTimelineBuilder, ChatTimeTimelineBuilder,
@@ -28,6 +29,7 @@ import { api } from '#/api/request';
import ChatHistoryDetailDrawer from '#/components/chat-history/ChatHistoryDetailDrawer.vue'; import ChatHistoryDetailDrawer from '#/components/chat-history/ChatHistoryDetailDrawer.vue';
import ListPageShell from '#/components/page/ListPageShell.vue'; import ListPageShell from '#/components/page/ListPageShell.vue';
const userStore = useUserStore();
const agentOptions = ref<any[]>([]); const agentOptions = ref<any[]>([]);
const agentLoading = ref(false); const agentLoading = ref(false);
const sessions = ref<any[]>([]); const sessions = ref<any[]>([]);
@@ -91,6 +93,9 @@ const hasMoreMessages = computed(
const selectedSessionId = computed(() => const selectedSessionId = computed(() =>
String(currentSession.value?.id || ''), String(currentSession.value?.id || ''),
); );
const isSuperAdmin = computed(() =>
userStore.userRoles.includes('super_admin'),
);
onMounted(async () => { onMounted(async () => {
await Promise.all([fetchAgents(), fetchSessions()]); await Promise.all([fetchAgents(), fetchSessions()]);
@@ -119,7 +124,9 @@ async function fetchSessions() {
const [, res] = await tryit(api.get)('/api/v1/chatHistory/sessions', { const [, res] = await tryit(api.get)('/api/v1/chatHistory/sessions', {
params: { params: {
assistantId: query.value.assistantId, assistantId: query.value.assistantId,
userAccount: query.value.userAccount || undefined, userAccount: isSuperAdmin.value
? query.value.userAccount || undefined
: undefined,
startTime: query.value.timeRange?.[0], startTime: query.value.timeRange?.[0],
endTime: query.value.timeRange?.[1], endTime: query.value.timeRange?.[1],
pageNumber: query.value.pageNumber, pageNumber: query.value.pageNumber,
@@ -394,6 +401,7 @@ function closeDetail() {
@change="handleSearch" @change="handleSearch"
/> />
<ElInput <ElInput
v-if="isSuperAdmin"
v-model="query.userAccount" v-model="query.userAccount"
class="chat-history-page__filter-control is-input" class="chat-history-page__filter-control is-input"
placeholder="搜索聊天用户" placeholder="搜索聊天用户"
@@ -472,7 +480,12 @@ function closeDetail() {
</template> </template>
</ElTableColumn> </ElTableColumn>
<ElTableColumn prop="userAccount" label="聊天用户" min-width="160"> <ElTableColumn
v-if="isSuperAdmin"
prop="userAccount"
label="聊天用户"
min-width="160"
>
<template #default="{ row }"> <template #default="{ row }">
<span class="chat-history-page__user-cell"> <span class="chat-history-page__user-cell">
{{ row.userAccount || '-' }} {{ row.userAccount || '-' }}