fix(channel-conversation): address code review issues for Task 5

- Make frontend account filter case-insensitive in Conversation.vue
- Warn when bind dialog is submitted without selecting an account
- Reuse AccountSelector.isHealthy in resolvePersonTarget
- Expand ConversationService.bindAccount unit tests
- Update channel mismatch assertion in SendServiceResolveTargetTest
- Move currentConversationId declaration near tag binding state
This commit is contained in:
2026-07-08 17:58:35 +08:00
parent 2cdbc662f3
commit 78a46977ba
4 changed files with 61 additions and 10 deletions

View File

@@ -220,7 +220,9 @@ function formatAccountName(id: number | undefined) {
const filteredBindAccounts = computed(() => {
const channelType = currentBindConversation.value?.channelType
if (!channelType) return accounts.value
return accounts.value.filter((a: any) => a.channelType === channelType)
return accounts.value.filter((a: any) =>
a.channelType?.toLowerCase() === channelType?.toLowerCase()
)
})
function formatConversationType(type: number | undefined) {
@@ -337,7 +339,10 @@ function openBindAccount(row: any) {
}
async function handleBindAccount() {
if (!bindAccountForm.accountId || !currentBindConversation.value) return
if (!bindAccountForm.accountId || !currentBindConversation.value) {
ElMessage.warning('请选择账号')
return
}
try {
await bindConversationAccount(currentBindConversation.value.id, bindAccountForm)
ElMessage.success('绑定成功')
@@ -348,8 +353,8 @@ async function handleBindAccount() {
}
}
const currentConversationId = ref<number | undefined>()
const currentConversationId = ref<number | undefined>()
const bindTagsVisible = ref(false)
const bindTagsForm = reactive({
tagIds: [] as number[],

View File

@@ -364,13 +364,9 @@ public class SendService {
throw new BusinessException("租户未配置可用发送账号: channel=" + channelType.name().toLowerCase());
}
ChannelAccount account = accountMapper.selectById(accountId);
if (account == null || !tenantCode.equals(account.getTenantCode())
|| account.getStatus() == null || account.getStatus() != STATUS_ENABLED) {
if (!AccountSelector.isHealthy(account, tenantCode, channelType)) {
throw new BusinessException("租户没有可用的发送账号: channel=" + channelType.name().toLowerCase());
}
if (!Objects.equals(channelType.name().toLowerCase(), account.getChannelType())) {
throw new BusinessException("单聊发送账号渠道类型与目标身份不一致");
}
SendTarget target = new SendTarget();
target.setConversationId(null);
target.setPersonId(personId);

View File

@@ -12,6 +12,7 @@ import com.sino.mci.crm.repository.TagMapper;
import com.sino.mci.exception.BusinessException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@@ -81,7 +82,56 @@ class ConversationServiceTest {
BindConversationAccountRequest request = createBindRequest(10L);
conversationService.bindAccount("tenant", 1L, request);
verify(bindingMapper).insert(any(ChannelAccountConversation.class));
ArgumentCaptor<ChannelAccountConversation> captor = ArgumentCaptor.forClass(ChannelAccountConversation.class);
verify(bindingMapper).insert(captor.capture());
ChannelAccountConversation binding = captor.getValue();
assertEquals(10L, binding.getAccountId());
assertEquals(1L, binding.getConversationId());
assertEquals(1, binding.getBindingType());
assertEquals(0, binding.getSortOrder());
assertEquals(1, binding.getStatus());
}
@Test
void bindAccount_defaultsSortOrderToZeroWhenNull() {
Conversation conversation = createConversation();
ChannelAccount account = createAccount(10L, "wecom");
when(conversationMapper.selectById(1L)).thenReturn(conversation);
when(accountMapper.selectById(10L)).thenReturn(account);
BindConversationAccountRequest request = createBindRequest(10L);
request.setSortOrder(null);
conversationService.bindAccount("tenant", 1L, request);
ArgumentCaptor<ChannelAccountConversation> captor = ArgumentCaptor.forClass(ChannelAccountConversation.class);
verify(bindingMapper).insert(captor.capture());
assertEquals(0, captor.getValue().getSortOrder());
}
@Test
void bindAccount_rejectsConversationFromDifferentTenant() {
Conversation conversation = createConversation();
conversation.setTenantCode("other-tenant");
when(conversationMapper.selectById(1L)).thenReturn(conversation);
BindConversationAccountRequest request = createBindRequest(10L);
BusinessException ex = assertThrows(BusinessException.class,
() -> conversationService.bindAccount("tenant", 1L, request));
assertEquals("会话不存在", ex.getMessage());
}
@Test
void bindAccount_rejectsConversationNotFound() {
when(conversationMapper.selectById(1L)).thenReturn(null);
BindConversationAccountRequest request = createBindRequest(10L);
BusinessException ex = assertThrows(BusinessException.class,
() -> conversationService.bindAccount("tenant", 1L, request));
assertEquals("会话不存在", ex.getMessage());
}
private Conversation createConversation() {

View File

@@ -183,7 +183,7 @@ class SendServiceResolveTargetTest {
BusinessException ex = assertThrows(BusinessException.class,
() -> sendService.resolveTestTargets("tenant", createPersonRequest()));
assertEquals("单聊发送账号渠道类型与目标身份不一致", ex.getMessage());
assertEquals("租户没有可用的发送账号: channel=wecom", ex.getMessage());
}
private SendTestRequest createConversationRequest(String strategy) {