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:
@@ -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[],
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user