Skip to content

Commit 54ecc9a

Browse files
FinleyGec121914yu
authored andcommitted
feat(publish): Wecom bot (#2343)
* chore: Wecom Config * feat(fe): wecom config fe * feat: wecom fe * chore: uses the newest editmodal * feat: update png; adjust the fe * chore: adjust fe
1 parent d390e83 commit 54ecc9a

File tree

15 files changed

+488
-16
lines changed

15 files changed

+488
-16
lines changed

packages/global/support/outLink/constant.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ export enum PublishChannelEnum {
22
share = 'share',
33
iframe = 'iframe',
44
apikey = 'apikey',
5-
feishu = 'feishu'
5+
feishu = 'feishu',
6+
wecom = 'wecom'
67
}

packages/global/support/outLink/type.d.ts

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { AppSchema } from 'core/app/type';
1+
import { AppSchema } from '../../core/app/type';
22
import { PublishChannelEnum } from './constant';
3+
import { RequireOnlyOne } from '../../common/type/utils';
34

45
// Feishu Config interface
56
export interface FeishuAppType {
@@ -13,12 +14,17 @@ export interface FeishuAppType {
1314
verificationToken?: string;
1415
}
1516

16-
// TODO: Unused
1717
export interface WecomAppType {
18-
SuiteId: string;
18+
AgentId: string;
19+
CorpId: string;
1920
SuiteSecret: string;
21+
CallbackToken: string;
22+
CallbackEncodingAesKey: string;
2023
}
2124

25+
// TODO: unused
26+
export interface WechatAppType {}
27+
2228
export type OutlinkAppType = FeishuAppType | WecomAppType | undefined;
2329

2430
export type OutLinkSchema<T extends OutlinkAppType = undefined> = {
@@ -27,9 +33,6 @@ export type OutLinkSchema<T extends OutlinkAppType = undefined> = {
2733
teamId: string;
2834
tmbId: string;
2935
appId: string;
30-
// teamId: Schema.Types.ObjectId;
31-
// tmbId: Schema.Types.ObjectId;
32-
// appId: Schema.Types.ObjectId;
3336
name: string;
3437
usagePoints: number;
3538
lastTime: Date;

packages/global/support/tmpData/constant.ts

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,30 @@
11
export enum TmpDataEnum {
2-
FeishuAccessToken = 'feishu_access_token'
2+
FeishuAccessToken = 'feishu_access_token',
3+
WecomAccessToken = 'wecom_access_token'
34
}
45

56
type _TmpDataMetadata = {
67
[TmpDataEnum.FeishuAccessToken]: {
78
FeishuAppId: string;
89
};
10+
[TmpDataEnum.WecomAccessToken]: {
11+
CorpId: string;
12+
AgentId: string;
13+
};
914
};
1015

1116
type _TmpDataType = {
1217
[TmpDataEnum.FeishuAccessToken]: {
1318
accessToken: string;
1419
};
20+
[TmpDataEnum.WecomAccessToken]: {
21+
accessToken: string;
22+
};
1523
};
1624

1725
export const TmpDataExpireTime = {
18-
[TmpDataEnum.FeishuAccessToken]: 1000 * 60 * 60 * 1.5 // 1.5 hours
26+
[TmpDataEnum.FeishuAccessToken]: 1000 * 60 * 60 * 1.5, // 1.5 hours
27+
[TmpDataEnum.WecomAccessToken]: 1000 * 60 * 60 * 2 // 2 hours
1928
};
2029

2130
export type TmpDataMetadata<T extends TmpDataEnum> = _TmpDataMetadata[T];

packages/service/common/api/plusRequest.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import axios, { Method, InternalAxiosRequestConfig, AxiosResponse } from 'axios';
1+
import axios, {
2+
Method,
3+
InternalAxiosRequestConfig,
4+
AxiosResponse,
5+
AxiosRequestConfig
6+
} from 'axios';
27
import { FastGPTProUrl } from '../system/constants';
38

49
interface ConfigType {
@@ -118,3 +123,9 @@ export function PUT<T = undefined>(url: string, data = {}, config: ConfigType =
118123
export function DELETE<T = undefined>(url: string, data = {}, config: ConfigType = {}): Promise<T> {
119124
return request(url, data, config, 'DELETE');
120125
}
126+
127+
export const plusRequest = (config: AxiosRequestConfig) =>
128+
instance.request({
129+
...config,
130+
baseURL: FastGPTProUrl
131+
});

packages/web/components/common/Icon/constants.ts

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ export const iconPaths = {
7676
'core/app/logsLight': () => import('./icons/core/app/logsLight.svg'),
7777
'core/app/markLight': () => import('./icons/core/app/markLight.svg'),
7878
'core/app/publish/lark': () => import('./icons/core/app/publish/lark.svg'),
79+
'core/app/publish/wecom': () => import('./icons/core/app/publish/wecom.svg'),
7980
'core/app/questionGuide': () => import('./icons/core/app/questionGuide.svg'),
8081
'core/app/schedulePlan': () => import('./icons/core/app/schedulePlan.svg'),
8182
'core/app/simpleBot': () => import('./icons/core/app/simpleBot.svg'),
Loading

packages/web/components/common/Icon/icons/support/outlink/apikeyFill.svg

+2-2
Loading

packages/web/i18n/zh/publish.json

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
2+
"publish_name": "名称",
23
"create_api_key": "创建新 key",
34
"create_link": "创建链接",
45
"default_response": "默认回复",
@@ -22,5 +23,13 @@
2223
"feishu_api": "飞书接口",
2324
"feishu_bot": "飞书机器人",
2425
"feishu_bot_desc": "通过 API 直接接入飞书机器人",
25-
"copy_link_hint": "将下面链接复制到指定位置"
26+
"copy_link_hint": "将下面链接复制到指定位置",
27+
"wecom": {
28+
"title": "发布到企业微信机器人",
29+
"bot": "企业微信机器人",
30+
"bot_desc": "通过 API 直接接入企业微信机器人",
31+
"edit_modal_title": "编辑企微机器人",
32+
"create_modal_title": "创建企微机器人",
33+
"api": "企微 API"
34+
}
2635
}
Loading

projects/app/src/components/common/MyRadio/index.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@ const MyRadio = ({
7575
{!!item.icon && (
7676
<>
7777
{item.icon.startsWith('/') ? (
78-
<Image src={item.icon} mr={'14px'} w={iconSize} alt={''} />
78+
<Image src={item.icon} mr={'14px'} w={iconSize} alt={''} fill={'primary.600'} />
7979
) : (
80-
<MyIcon mr={'14px'} name={item.icon as any} w={iconSize} />
80+
<MyIcon mr={'14px'} name={item.icon as any} w={iconSize} fill={'primary.600'} />
8181
)}
8282
</>
8383
)}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
2+
import { plusRequest } from '@fastgpt/service/common/api/plusRequest';
3+
4+
export type OutLinkWecomQuery = any;
5+
export type OutLinkWecomBody = any;
6+
export type OutLinkWecomResponse = {};
7+
8+
async function handler(
9+
req: ApiRequestProps<OutLinkWecomBody, OutLinkWecomQuery>,
10+
res: ApiResponseType<any>
11+
): Promise<any> {
12+
const { token, type } = req.query;
13+
const result = await plusRequest({
14+
url: `support/outLink/wecom/${token}`,
15+
params: {
16+
...req.query,
17+
type
18+
},
19+
data: req.body
20+
});
21+
if (result.data?.data?.message) {
22+
// chanllege
23+
res.send(result.data.data.message);
24+
res.end();
25+
}
26+
27+
res.send('success');
28+
res.end();
29+
}
30+
31+
export default handler;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
import React from 'react';
2+
import { Flex, Box, Button, ModalBody, Input, Link } from '@chakra-ui/react';
3+
import MyModal from '@fastgpt/web/components/common/MyModal';
4+
import { PublishChannelEnum } from '@fastgpt/global/support/outLink/constant';
5+
import type { WecomAppType, OutLinkEditType } from '@fastgpt/global/support/outLink/type';
6+
import { useTranslation } from 'next-i18next';
7+
import { useForm } from 'react-hook-form';
8+
import { createShareChat, updateShareChat } from '@/web/support/outLink/api';
9+
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
10+
import BasicInfo from '../components/BasicInfo';
11+
import { getDocPath } from '@/web/common/system/doc';
12+
import { useSystemStore } from '@/web/common/system/useSystemStore';
13+
import MyIcon from '@fastgpt/web/components/common/Icon';
14+
import { useSystem } from '@fastgpt/web/hooks/useSystem';
15+
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
16+
17+
const WecomEditModal = ({
18+
appId,
19+
defaultData,
20+
onClose,
21+
onCreate,
22+
onEdit,
23+
isEdit = false
24+
}: {
25+
appId: string;
26+
defaultData: OutLinkEditType<WecomAppType>;
27+
onClose: () => void;
28+
onCreate: (id: string) => void;
29+
onEdit: () => void;
30+
isEdit?: boolean;
31+
}) => {
32+
const { t } = useTranslation();
33+
const {
34+
register,
35+
setValue,
36+
handleSubmit: submitShareChat
37+
} = useForm({
38+
defaultValues: defaultData
39+
});
40+
41+
const { runAsync: onclickCreate, loading: creating } = useRequest2(
42+
(e) =>
43+
createShareChat({
44+
...e,
45+
appId,
46+
type: PublishChannelEnum.wecom
47+
}),
48+
{
49+
errorToast: t('common:common.Create Failed'),
50+
successToast: t('common:common.Create Success'),
51+
onSuccess: onCreate
52+
}
53+
);
54+
55+
const { runAsync: onclickUpdate, loading: updating } = useRequest2((e) => updateShareChat(e), {
56+
errorToast: t('common:common.Update Failed'),
57+
successToast: t('common:common.Update Success'),
58+
onSuccess: onEdit
59+
});
60+
61+
const { feConfigs } = useSystemStore();
62+
63+
return (
64+
<MyModal
65+
iconSrc="/imgs/modal/shareFill.svg"
66+
title={isEdit ? t('publish:wecom.edit_modal_title') : t('publish:wecom.create_modal_title')}
67+
minW={['auto', '60rem']}
68+
>
69+
<ModalBody display={'grid'} gridTemplateColumns={['1fr', '1fr 1fr']} fontSize={'14px'} p={0}>
70+
<Box p={8} minH={['auto', '400px']} borderRight={'base'}>
71+
<BasicInfo register={register} setValue={setValue} defaultData={defaultData} />
72+
</Box>
73+
<Flex p={8} minH={['auto', '400px']} flexDirection="column" gap={6}>
74+
<Flex alignItems="center">
75+
<Box color="myGray.600">{t('publish:wecom.api')}</Box>
76+
{feConfigs?.docUrl && (
77+
<Link
78+
href={feConfigs.openAPIDocUrl || getDocPath('/docs/use-cases/wecom-bot')}
79+
target={'_blank'}
80+
ml={2}
81+
color={'primary.500'}
82+
fontSize={'sm'}
83+
>
84+
<Flex alignItems={'center'}>
85+
<MyIcon name="book" mr="1" />
86+
{t('common:common.Read document')}
87+
</Flex>
88+
</Link>
89+
)}
90+
</Flex>
91+
<Flex alignItems={'center'}>
92+
<FormLabel flex={'0 0 6.25rem'} required>
93+
Corp ID
94+
</FormLabel>
95+
<Input
96+
placeholder="Corp ID"
97+
{...register('app.CorpId', {
98+
required: true
99+
})}
100+
/>
101+
</Flex>
102+
<Flex alignItems={'center'}>
103+
<FormLabel flex={'0 0 6.25rem'} required>
104+
Agent ID
105+
</FormLabel>
106+
<Input
107+
placeholder="Agent ID"
108+
{...register('app.AgentId', {
109+
required: true
110+
})}
111+
/>
112+
</Flex>
113+
<Flex alignItems={'center'}>
114+
<FormLabel flex={'0 0 6.25rem'} required>
115+
Secret
116+
</FormLabel>
117+
<Input
118+
placeholder="Secret"
119+
{...register('app.SuiteSecret', {
120+
required: true
121+
})}
122+
/>
123+
</Flex>
124+
<Flex alignItems={'center'}>
125+
<FormLabel flex={'0 0 6.25rem'} required>
126+
Token
127+
</FormLabel>
128+
<Input
129+
placeholder="Token"
130+
{...register('app.CallbackToken', {
131+
required: true
132+
})}
133+
/>
134+
</Flex>
135+
<Flex alignItems={'center'}>
136+
<FormLabel flex={'0 0 6.25rem'} required>
137+
AES Key
138+
</FormLabel>
139+
<Input
140+
placeholder="AES Key"
141+
{...register('app.CallbackEncodingAesKey', {
142+
required: true
143+
})}
144+
/>
145+
</Flex>
146+
147+
<Box flex={1}></Box>
148+
149+
<Flex justifyContent={'end'}>
150+
<Button variant={'whiteBase'} mr={3} onClick={onClose}>
151+
{t('common:common.Close')}
152+
</Button>
153+
<Button
154+
isLoading={creating || updating}
155+
onClick={submitShareChat((data) =>
156+
isEdit ? onclickUpdate(data) : onclickCreate(data)
157+
)}
158+
>
159+
{t('common:common.Confirm')}
160+
</Button>
161+
</Flex>
162+
</Flex>
163+
</ModalBody>
164+
</MyModal>
165+
);
166+
};
167+
168+
export default WecomEditModal;

0 commit comments

Comments
 (0)