feat: add WeChat MP channel support and enhance widget configuration
- Updated output path for generated enums to reflect new structure. - Enhanced ChannelController to handle WeChat MP OAuth authorization and callback. - Introduced WechatMPChannelConfig DTO for WeChat MP specific configurations. - Modified WidgetConfigResponse to include channel type and external source. - Added enums for WeChat MP channel type and external source. - Implemented OAuth flow for WeChat MP, including state signing and verification. - Updated frontend forms to accommodate WeChat MP configurations. - Enhanced API interactions to support WeChat MP external ID and source. - Updated generated enums to include WeChat MP external source.
This commit is contained in:
+4
-1
@@ -104,6 +104,8 @@ export type ImAsset = {
|
||||
|
||||
export type ImWidgetConfig = {
|
||||
channelId?: string
|
||||
channelType?: string
|
||||
externalSource?: string
|
||||
title?: string
|
||||
subtitle?: string
|
||||
themeColor?: string
|
||||
@@ -146,6 +148,7 @@ function getRuntimeImConfig() {
|
||||
channelId: widgetConfig.channelId || OPEN_IM_CHANNEL_ID,
|
||||
externalSource:
|
||||
(widgetConfig.externalSource || OPEN_IM_EXTERNAL_SOURCE).trim() || "web_chat",
|
||||
externalId: (widgetConfig.externalId || "").trim(),
|
||||
externalName: (widgetConfig.subject || "").trim(),
|
||||
}
|
||||
}
|
||||
@@ -154,7 +157,7 @@ function createImHeaders() {
|
||||
const config = getRuntimeImConfig()
|
||||
const headers: Record<string, string> = {
|
||||
"X-External-Source": config.externalSource,
|
||||
"X-External-Id": getImVisitorId(),
|
||||
"X-External-Id": config.externalId || getImVisitorId(),
|
||||
"X-Channel-Id": config.channelId,
|
||||
}
|
||||
if (config.externalName) {
|
||||
|
||||
@@ -73,10 +73,12 @@ export const ContactTypeLabels: Record<ContactType, string> = {
|
||||
|
||||
export enum ExternalSource {
|
||||
WebChat = "web_chat",
|
||||
WechatMP = "wechat_mp",
|
||||
WxWorkKF = "wxwork_kf",
|
||||
}
|
||||
export const ExternalSourceLabels: Record<ExternalSource, string> = {
|
||||
[ExternalSource.WebChat]: "网页客服",
|
||||
[ExternalSource.WechatMP]: "微信公众号",
|
||||
[ExternalSource.WxWorkKF]: "企业微信客服",
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@ export function createImRealtimeConnection() {
|
||||
const baseUrl = apiBaseUrl
|
||||
? apiBaseUrl.replace(/^http/, "ws").replace(/\/$/, "")
|
||||
: createWebSocketBaseUrl()
|
||||
const externalId = encodeURIComponent(getImVisitorId())
|
||||
const resolvedExternalId = encodeURIComponent(
|
||||
(config.externalId ?? "").trim() || getImVisitorId()
|
||||
)
|
||||
const externalSource = encodeURIComponent(
|
||||
(config.externalSource ?? "web_chat").trim() || "web_chat"
|
||||
)
|
||||
@@ -30,6 +32,6 @@ export function createImRealtimeConnection() {
|
||||
? `&externalName=${encodeURIComponent(externalName)}`
|
||||
: ""
|
||||
return new WebSocket(
|
||||
`${baseUrl}/api/ws/open?externalId=${externalId}&externalSource=${externalSource}&channelId=${channelId}${nameQuery}`
|
||||
`${baseUrl}/api/ws/open?externalId=${resolvedExternalId}&externalSource=${externalSource}&channelId=${channelId}${nameQuery}`
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ export type KefuWidgetHostConfig = {
|
||||
apiBaseUrl?: string
|
||||
/** 与后端 enums.ExternalSource 一致,默认 web_chat */
|
||||
externalSource?: string
|
||||
/** 外部访客稳定标识;微信公众号 OAuth 场景使用 openid */
|
||||
externalId?: string
|
||||
title?: string
|
||||
subtitle?: string
|
||||
position?: "left" | "right"
|
||||
@@ -48,6 +50,7 @@ export function readKefuWidgetConfig(): KefuWidgetHostConfig {
|
||||
query.get("externalSource") ??
|
||||
process.env.NEXT_PUBLIC_OPEN_IM_EXTERNAL_SOURCE?.trim() ??
|
||||
undefined,
|
||||
externalId: query.get("externalId") ?? undefined,
|
||||
title: query.get("title") ?? undefined,
|
||||
subtitle: query.get("subtitle") ?? undefined,
|
||||
position: (query.get("position") as "left" | "right" | null) ?? undefined,
|
||||
|
||||
@@ -35,6 +35,7 @@ import {
|
||||
import { summarizeIMMessage } from "@/lib/im-message"
|
||||
import { createRealtimeConnectionManager } from "@/lib/realtime-connection"
|
||||
import { generateUUID } from "@/lib/utils"
|
||||
import { readKefuWidgetConfig, setKefuWidgetConfig } from "@/lib/kefu-widget-config"
|
||||
|
||||
type ChatStatus = "connecting" | "connected" | "disconnected"
|
||||
|
||||
@@ -267,6 +268,15 @@ export const useKefuChatStore = create<KefuChatStore>((set, get) => {
|
||||
return
|
||||
}
|
||||
|
||||
if (widgetConfig.channelId || widgetConfig.externalSource) {
|
||||
setKefuWidgetConfig({
|
||||
...readKefuWidgetConfig(),
|
||||
channelId: widgetConfig.channelId || readKefuWidgetConfig().channelId,
|
||||
externalSource:
|
||||
widgetConfig.externalSource || readKefuWidgetConfig().externalSource,
|
||||
})
|
||||
}
|
||||
|
||||
set({
|
||||
title: widgetConfig.title || "在线客服",
|
||||
subtitle: widgetConfig.subtitle || "",
|
||||
|
||||
Reference in New Issue
Block a user