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 filteredBindAccounts = computed(() => {
|
||||||
const channelType = currentBindConversation.value?.channelType
|
const channelType = currentBindConversation.value?.channelType
|
||||||
if (!channelType) return accounts.value
|
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) {
|
function formatConversationType(type: number | undefined) {
|
||||||
@@ -337,7 +339,10 @@ function openBindAccount(row: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleBindAccount() {
|
async function handleBindAccount() {
|
||||||
if (!bindAccountForm.accountId || !currentBindConversation.value) return
|
if (!bindAccountForm.accountId || !currentBindConversation.value) {
|
||||||
|
ElMessage.warning('请选择账号')
|
||||||
|
return
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
await bindConversationAccount(currentBindConversation.value.id, bindAccountForm)
|
await bindConversationAccount(currentBindConversation.value.id, bindAccountForm)
|
||||||
ElMessage.success('绑定成功')
|
ElMessage.success('绑定成功')
|
||||||
@@ -348,8 +353,8 @@ async function handleBindAccount() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentConversationId = ref<number | undefined>()
|
|
||||||
|
|
||||||
|
const currentConversationId = ref<number | undefined>()
|
||||||
const bindTagsVisible = ref(false)
|
const bindTagsVisible = ref(false)
|
||||||
const bindTagsForm = reactive({
|
const bindTagsForm = reactive({
|
||||||
tagIds: [] as number[],
|
tagIds: [] as number[],
|
||||||
|
|||||||
@@ -364,13 +364,9 @@ public class SendService {
|
|||||||
throw new BusinessException("租户未配置可用发送账号: channel=" + channelType.name().toLowerCase());
|
throw new BusinessException("租户未配置可用发送账号: channel=" + channelType.name().toLowerCase());
|
||||||
}
|
}
|
||||||
ChannelAccount account = accountMapper.selectById(accountId);
|
ChannelAccount account = accountMapper.selectById(accountId);
|
||||||
if (account == null || !tenantCode.equals(account.getTenantCode())
|
if (!AccountSelector.isHealthy(account, tenantCode, channelType)) {
|
||||||
|| account.getStatus() == null || account.getStatus() != STATUS_ENABLED) {
|
|
||||||
throw new BusinessException("租户没有可用的发送账号: channel=" + channelType.name().toLowerCase());
|
throw new BusinessException("租户没有可用的发送账号: channel=" + channelType.name().toLowerCase());
|
||||||
}
|
}
|
||||||
if (!Objects.equals(channelType.name().toLowerCase(), account.getChannelType())) {
|
|
||||||
throw new BusinessException("单聊发送账号渠道类型与目标身份不一致");
|
|
||||||
}
|
|
||||||
SendTarget target = new SendTarget();
|
SendTarget target = new SendTarget();
|
||||||
target.setConversationId(null);
|
target.setConversationId(null);
|
||||||
target.setPersonId(personId);
|
target.setPersonId(personId);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import com.sino.mci.crm.repository.TagMapper;
|
|||||||
import com.sino.mci.exception.BusinessException;
|
import com.sino.mci.exception.BusinessException;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
@@ -81,7 +82,56 @@ class ConversationServiceTest {
|
|||||||
BindConversationAccountRequest request = createBindRequest(10L);
|
BindConversationAccountRequest request = createBindRequest(10L);
|
||||||
conversationService.bindAccount("tenant", 1L, request);
|
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() {
|
private Conversation createConversation() {
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ class SendServiceResolveTargetTest {
|
|||||||
|
|
||||||
BusinessException ex = assertThrows(BusinessException.class,
|
BusinessException ex = assertThrows(BusinessException.class,
|
||||||
() -> sendService.resolveTestTargets("tenant", createPersonRequest()));
|
() -> sendService.resolveTestTargets("tenant", createPersonRequest()));
|
||||||
assertEquals("单聊发送账号渠道类型与目标身份不一致", ex.getMessage());
|
assertEquals("租户没有可用的发送账号: channel=wecom", ex.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
private SendTestRequest createConversationRequest(String strategy) {
|
private SendTestRequest createConversationRequest(String strategy) {
|
||||||
|
|||||||
Reference in New Issue
Block a user