fix(send-routing): address re-review issues
- Set conversationScene=EXTERNAL in SendEndToEndTest and align account to WECHAT_PERSONAL - Replace literal account type code with AccountType.WECHAT_PERSONAL.getCode() - Use replaceFirst for webhook URL placeholder in WeComBotSender - Remove unused selectDefaultAccount overload - Hide scene selector for single-chat conversations in admin-web
This commit is contained in:
@@ -30,7 +30,7 @@
|
|||||||
<el-table-column prop="channelType" label="渠道" />
|
<el-table-column prop="channelType" label="渠道" />
|
||||||
<el-table-column prop="conversationScene" label="场景" width="100">
|
<el-table-column prop="conversationScene" label="场景" width="100">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ formatConversationScene(row.conversationScene) }}
|
{{ formatConversationScene(row.conversationScene, row.conversationType) }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="channelConversationId" label="渠道会话ID" show-overflow-tooltip />
|
<el-table-column prop="channelConversationId" label="渠道会话ID" show-overflow-tooltip />
|
||||||
@@ -76,7 +76,7 @@
|
|||||||
<el-form-item label="渠道">
|
<el-form-item label="渠道">
|
||||||
<el-input v-model="dialogForm.channelType" placeholder="wecom" />
|
<el-input v-model="dialogForm.channelType" placeholder="wecom" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="场景">
|
<el-form-item v-if="dialogForm.conversationType === 2" label="场景">
|
||||||
<el-select v-model="dialogForm.conversationScene" placeholder="选择场景" style="width: 100%">
|
<el-select v-model="dialogForm.conversationScene" placeholder="选择场景" style="width: 100%">
|
||||||
<el-option label="内部群" :value="1" />
|
<el-option label="内部群" :value="1" />
|
||||||
<el-option label="外部群" :value="2" />
|
<el-option label="外部群" :value="2" />
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
<el-form-item label="渠道">
|
<el-form-item label="渠道">
|
||||||
<el-input v-model="dialogForm.channelType" placeholder="wecom" />
|
<el-input v-model="dialogForm.channelType" placeholder="wecom" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="场景">
|
<el-form-item v-if="dialogForm.conversationType === 2" label="场景">
|
||||||
<el-select v-model="dialogForm.conversationScene" placeholder="选择场景" style="width: 100%">
|
<el-select v-model="dialogForm.conversationScene" placeholder="选择场景" style="width: 100%">
|
||||||
<el-option label="内部群" :value="1" />
|
<el-option label="内部群" :value="1" />
|
||||||
<el-option label="外部群" :value="2" />
|
<el-option label="外部群" :value="2" />
|
||||||
@@ -326,6 +326,12 @@ watch([searchQuery, typeFilter], () => {
|
|||||||
currentPage.value = 1
|
currentPage.value = 1
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(() => dialogForm.conversationType, (val) => {
|
||||||
|
if (val === 1) {
|
||||||
|
dialogForm.conversationScene = undefined
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
function resetDialogForm() {
|
function resetDialogForm() {
|
||||||
dialogForm.conversationType = 2
|
dialogForm.conversationType = 2
|
||||||
dialogForm.channelType = 'wecom'
|
dialogForm.channelType = 'wecom'
|
||||||
@@ -401,7 +407,8 @@ function formatConversationType(type: number | undefined) {
|
|||||||
return type ?? '-'
|
return type ?? '-'
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatConversationScene(scene: number | undefined) {
|
function formatConversationScene(scene: number | undefined, type?: number) {
|
||||||
|
if (type === 1) return '-'
|
||||||
if (scene === 1) return '内部群'
|
if (scene === 1) return '内部群'
|
||||||
if (scene === 2) return '外部群'
|
if (scene === 2) return '外部群'
|
||||||
return scene ?? '-'
|
return scene ?? '-'
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ public class WeComBotSender {
|
|||||||
String customUrl = getString(extra, "webhook_url");
|
String customUrl = getString(extra, "webhook_url");
|
||||||
if (customUrl != null && !customUrl.isBlank()) {
|
if (customUrl != null && !customUrl.isBlank()) {
|
||||||
if (customUrl.contains("%s")) {
|
if (customUrl.contains("%s")) {
|
||||||
return customUrl.replace("%s", key);
|
return customUrl.replaceFirst("%s", key);
|
||||||
}
|
}
|
||||||
return customUrl;
|
return customUrl;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -742,10 +742,6 @@ public class SendService {
|
|||||||
return CollectionUtils.isEmpty(accounts) ? null : accounts.get(0);
|
return CollectionUtils.isEmpty(accounts) ? null : accounts.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Long selectDefaultAccount(String tenantCode, ChannelType channelType) {
|
|
||||||
return selectDefaultAccount(tenantCode, channelType, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Long selectDefaultAccount(String tenantCode, ChannelType channelType, Set<Integer> accountTypes) {
|
private Long selectDefaultAccount(String tenantCode, ChannelType channelType, Set<Integer> accountTypes) {
|
||||||
List<ChannelAccount> accounts = accountMapper.selectList(
|
List<ChannelAccount> accounts = accountMapper.selectList(
|
||||||
new LambdaQueryWrapper<ChannelAccount>()
|
new LambdaQueryWrapper<ChannelAccount>()
|
||||||
|
|||||||
@@ -52,10 +52,11 @@ class SendEndToEndTest {
|
|||||||
.andReturn().getResponse().getContentAsString();
|
.andReturn().getResponse().getContentAsString();
|
||||||
Long subjectId = ((Number) com.jayway.jsonpath.JsonPath.read(subjectResponse, "$.data.id")).longValue();
|
Long subjectId = ((Number) com.jayway.jsonpath.JsonPath.read(subjectResponse, "$.data.id")).longValue();
|
||||||
|
|
||||||
// 2. 创建渠道账号
|
// 2. 创建外部群发送账号(pywechat 个人号)
|
||||||
|
String accountCode = "wxid-e2e-" + UUID.randomUUID().toString().substring(0, 8);
|
||||||
String accountPayload = String.format(
|
String accountPayload = String.format(
|
||||||
"{\"accountType\":1,\"channelType\":\"wecom\",\"subjectId\":%d,\"accountId\":\"ZhangSan\",\"accountName\":\"张三\"}",
|
"{\"accountType\":3,\"channelType\":\"wechat_personal\",\"subjectId\":%d,\"accountId\":\"%s\",\"accountName\":\"张三\"}",
|
||||||
subjectId);
|
subjectId, accountCode);
|
||||||
String accountResponse = mockMvc.perform(post("/msg-platform/api/v1/channel-account")
|
String accountResponse = mockMvc.perform(post("/msg-platform/api/v1/channel-account")
|
||||||
.contextPath("/msg-platform")
|
.contextPath("/msg-platform")
|
||||||
.header("Authorization", authToken)
|
.header("Authorization", authToken)
|
||||||
@@ -67,10 +68,20 @@ class SendEndToEndTest {
|
|||||||
.andReturn().getResponse().getContentAsString();
|
.andReturn().getResponse().getContentAsString();
|
||||||
Long accountId = ((Number) com.jayway.jsonpath.JsonPath.read(accountResponse, "$.data.id")).longValue();
|
Long accountId = ((Number) com.jayway.jsonpath.JsonPath.read(accountResponse, "$.data.id")).longValue();
|
||||||
|
|
||||||
// 3. 创建会话
|
// 个人号需要心跳才能被路由视为可用
|
||||||
|
mockMvc.perform(post("/msg-platform/api/v1/channel-account/heartbeat")
|
||||||
|
.contextPath("/msg-platform")
|
||||||
|
.header("Authorization", authToken)
|
||||||
|
.header("X-Tenant-Code", tenantCode)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content(String.format("{\"accountId\":\"%s\",\"riskLevel\":1}", accountCode)))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.code").value(0));
|
||||||
|
|
||||||
|
// 3. 创建外部群会话
|
||||||
String channelConversationId = "room-" + UUID.randomUUID().toString().substring(0, 8);
|
String channelConversationId = "room-" + UUID.randomUUID().toString().substring(0, 8);
|
||||||
String conversationPayload = String.format(
|
String conversationPayload = String.format(
|
||||||
"{\"conversationType\":2,\"channelType\":\"wecom\",\"channelConversationId\":\"%s\",\"conversationName\":\"E2E群\",\"subjectId\":%d}",
|
"{\"conversationType\":2,\"channelType\":\"wechat_personal\",\"conversationScene\":2,\"channelConversationId\":\"%s\",\"conversationName\":\"E2E群\",\"subjectId\":%d}",
|
||||||
channelConversationId, subjectId);
|
channelConversationId, subjectId);
|
||||||
String conversationResponse = mockMvc.perform(post("/msg-platform/api/v1/conversation")
|
String conversationResponse = mockMvc.perform(post("/msg-platform/api/v1/conversation")
|
||||||
.contextPath("/msg-platform")
|
.contextPath("/msg-platform")
|
||||||
@@ -121,7 +132,7 @@ class SendEndToEndTest {
|
|||||||
.andExpect(jsonPath("$.data.length()").value(1))
|
.andExpect(jsonPath("$.data.length()").value(1))
|
||||||
.andExpect(jsonPath("$.data[0].taskId").value(taskId))
|
.andExpect(jsonPath("$.data[0].taskId").value(taskId))
|
||||||
.andExpect(jsonPath("$.data[0].sendStatus").value(2))
|
.andExpect(jsonPath("$.data[0].sendStatus").value(2))
|
||||||
.andExpect(jsonPath("$.data[0].channelType").value("wecom"))
|
.andExpect(jsonPath("$.data[0].channelType").value("wechat_personal"))
|
||||||
.andExpect(jsonPath("$.data[0].conversationId").value(conversationId))
|
.andExpect(jsonPath("$.data[0].conversationId").value(conversationId))
|
||||||
.andExpect(jsonPath("$.data[0].accountId").value(accountId))
|
.andExpect(jsonPath("$.data[0].accountId").value(accountId))
|
||||||
.andExpect(jsonPath("$.data[0].contentType").value("text"))
|
.andExpect(jsonPath("$.data[0].contentType").value("text"))
|
||||||
|
|||||||
@@ -115,9 +115,9 @@ class SendServiceFailoverTest {
|
|||||||
verify(adapter, times(2)).sendMessage(requestCaptor.capture());
|
verify(adapter, times(2)).sendMessage(requestCaptor.capture());
|
||||||
List<SendMessageRequest> requests = requestCaptor.getAllValues();
|
List<SendMessageRequest> requests = requestCaptor.getAllValues();
|
||||||
assertEquals("wxid-primary", requests.get(0).getExtra().get("account_id"));
|
assertEquals("wxid-primary", requests.get(0).getExtra().get("account_id"));
|
||||||
assertEquals(Integer.valueOf(3), requests.get(0).getExtra().get("account_type"));
|
assertEquals(Integer.valueOf(AccountType.WECHAT_PERSONAL.getCode()), requests.get(0).getExtra().get("account_type"));
|
||||||
assertEquals("wxid-backup", requests.get(1).getExtra().get("account_id"));
|
assertEquals("wxid-backup", requests.get(1).getExtra().get("account_id"));
|
||||||
assertEquals(Integer.valueOf(3), requests.get(1).getExtra().get("account_type"));
|
assertEquals(Integer.valueOf(AccountType.WECHAT_PERSONAL.getCode()), requests.get(1).getExtra().get("account_type"));
|
||||||
|
|
||||||
ArgumentCaptor<ChannelAccount> accountCaptor = ArgumentCaptor.forClass(ChannelAccount.class);
|
ArgumentCaptor<ChannelAccount> accountCaptor = ArgumentCaptor.forClass(ChannelAccount.class);
|
||||||
verify(accountMapper, times(1)).updateById(accountCaptor.capture());
|
verify(accountMapper, times(1)).updateById(accountCaptor.capture());
|
||||||
|
|||||||
Reference in New Issue
Block a user