mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-21 11:43:56 +00:00
feat(publish): Wechat OffiAccount (#2386)
* feat: OffiAccount fe * feat: offiaccount * fix: wecom requires AES key * fix: OffiAccountEditModal * chore: change wechat svg icon * chore: add offiaccount svg * chore: hide unimplemented wecom entries
This commit is contained in:
@@ -3,5 +3,6 @@ export enum PublishChannelEnum {
|
||||
iframe = 'iframe',
|
||||
apikey = 'apikey',
|
||||
feishu = 'feishu',
|
||||
wecom = 'wecom'
|
||||
wecom = 'wecom',
|
||||
officialAccount = 'official_account'
|
||||
}
|
||||
|
13
packages/global/support/outLink/type.d.ts
vendored
13
packages/global/support/outLink/type.d.ts
vendored
@@ -25,7 +25,18 @@ export interface WecomAppType {
|
||||
// TODO: unused
|
||||
export interface WechatAppType {}
|
||||
|
||||
export type OutlinkAppType = FeishuAppType | WecomAppType | undefined;
|
||||
export interface OffiAccountAppType {
|
||||
appId: string;
|
||||
isVerified?: boolean; // if isVerified, we could use '客服接口' to reply
|
||||
secret: string;
|
||||
CallbackToken: string;
|
||||
CallbackEncodingAesKey?: string;
|
||||
timeoutReply?: string; // if timeout (15s), will reply this content.
|
||||
// timeout reply is optional, but when isVerified is false, the wechat will reply a default message which is `该公众号暂时无法提供服务,请稍后再试`
|
||||
// because we can not reply anything in 15s. Thus, the wechat server will treat this request as a failed request.
|
||||
}
|
||||
|
||||
export type OutlinkAppType = FeishuAppType | WecomAppType | OffiAccountAppType | undefined;
|
||||
|
||||
export type OutLinkSchema<T extends OutlinkAppType = undefined> = {
|
||||
_id: string;
|
||||
|
@@ -1,6 +1,7 @@
|
||||
export enum TmpDataEnum {
|
||||
FeishuAccessToken = 'feishu_access_token',
|
||||
WecomAccessToken = 'wecom_access_token'
|
||||
WecomAccessToken = 'wecom_access_token',
|
||||
OffiAccountAccessToken = 'offiaccount_access_token'
|
||||
}
|
||||
|
||||
type _TmpDataMetadata = {
|
||||
@@ -11,6 +12,9 @@ type _TmpDataMetadata = {
|
||||
CorpId: string;
|
||||
AgentId: string;
|
||||
};
|
||||
[TmpDataEnum.OffiAccountAccessToken]: {
|
||||
AppId: string;
|
||||
};
|
||||
};
|
||||
|
||||
type _TmpDataType = {
|
||||
@@ -20,11 +24,15 @@ type _TmpDataType = {
|
||||
[TmpDataEnum.WecomAccessToken]: {
|
||||
accessToken: string;
|
||||
};
|
||||
[TmpDataEnum.OffiAccountAccessToken]: {
|
||||
accessToken: string;
|
||||
};
|
||||
};
|
||||
|
||||
export const TmpDataExpireTime = {
|
||||
[TmpDataEnum.FeishuAccessToken]: 1000 * 60 * 60 * 1.5, // 1.5 hours
|
||||
[TmpDataEnum.WecomAccessToken]: 1000 * 60 * 60 * 2 // 2 hours
|
||||
[TmpDataEnum.WecomAccessToken]: 1000 * 60 * 60 * 2, // 2 hours
|
||||
[TmpDataEnum.OffiAccountAccessToken]: 1000 * 60 * 60 * 2 // 2 hours
|
||||
};
|
||||
|
||||
export type TmpDataMetadata<T extends TmpDataEnum> = _TmpDataMetadata[T];
|
||||
|
@@ -76,6 +76,8 @@ export const iconPaths = {
|
||||
'core/app/logsLight': () => import('./icons/core/app/logsLight.svg'),
|
||||
'core/app/markLight': () => import('./icons/core/app/markLight.svg'),
|
||||
'core/app/publish/lark': () => import('./icons/core/app/publish/lark.svg'),
|
||||
'core/app/publish/offiaccount': () => import('./icons/core/app/publish/offiaccount.svg'),
|
||||
'core/app/publish/wechat': () => import('./icons/core/app/publish/wechat.svg'),
|
||||
'core/app/publish/wecom': () => import('./icons/core/app/publish/wecom.svg'),
|
||||
'core/app/questionGuide': () => import('./icons/core/app/questionGuide.svg'),
|
||||
'core/app/schedulePlan': () => import('./icons/core/app/schedulePlan.svg'),
|
||||
|
@@ -0,0 +1,22 @@
|
||||
<svg width="22" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="new_bg_logo_primary69a6bf 1" clip-path="url(#clip0_9425_7305)">
|
||||
<g id="Group">
|
||||
<g id="Group_2">
|
||||
<g id="Group_3">
|
||||
<path id="Vector" d="M18.8275 7.82108C17.1159 5.55442 14.1091 4.95306 11.3799 5.92448C11.4724 5.97074 11.5649 5.97074 11.6574 6.017C15.6819 7.3585 17.8098 11.7068 16.4683 15.7313C16.0982 16.7952 15.5431 17.7204 14.8493 18.5068C15.7282 18.2755 16.6071 17.9054 17.3472 17.3503C20.4003 14.9911 21.0016 10.6428 18.8275 7.82108Z" fill="#07C160"/>
|
||||
</g>
|
||||
<g id="Group_4">
|
||||
<path id="Vector_2" d="M8.78947 5.55441C8.97451 5.41564 9.11328 5.32312 9.29832 5.18434C9.29832 5.18434 9.29832 5.18434 9.34458 5.18434C9.52961 5.09183 9.71464 4.99931 9.85342 4.86053C9.85342 4.86053 9.89968 4.86053 9.89968 4.81428C10.2697 4.62924 10.6398 4.49047 11.0099 4.35169C11.0561 4.35169 11.0561 4.35169 11.1024 4.30543C11.2874 4.25917 11.4725 4.16666 11.6575 4.1204H11.7038C11.8888 4.07414 12.0738 4.02788 12.2589 4.02788C12.3051 4.02788 12.3051 4.02788 12.3514 4.02788C12.6289 3.98162 12.814 3.98162 12.999 3.98162C13.0453 3.98162 13.0915 3.98162 13.1378 3.98162C13.3228 3.98162 13.5541 3.93536 13.7391 3.93536C13.9704 3.93536 14.2017 3.93536 14.433 3.98162C14.4793 3.98162 14.4793 3.98162 14.5255 3.98162C14.7568 3.98162 14.9418 4.02788 15.1731 4.07414C15.2194 4.07414 15.2657 4.07414 15.2657 4.07414C15.497 4.1204 15.682 4.16666 15.867 4.21292C15.9133 4.21292 15.9133 4.21292 15.9595 4.25917C16.1908 4.30543 16.4221 4.35169 16.6072 4.44421C16.5146 4.25917 16.4221 4.1204 16.4221 4.1204C15.0806 1.99251 12.8602 0.74353 10.4548 0.74353C9.02077 0.74353 6.80036 1.25237 5.13505 3.24149C4.02485 4.58298 3.65478 6.15577 3.88608 7.72856C4.02485 8.7925 4.62621 10.2265 5.50512 11.1054C5.82893 8.83876 7.03165 6.84965 8.78947 5.55441Z" fill="#07C160"/>
|
||||
</g>
|
||||
<g id="Group_5">
|
||||
<path id="Vector_3" d="M10.4548 15.0375C9.85343 15.0375 9.25207 14.945 8.69697 14.8525C8.65071 14.8525 8.55819 14.8525 8.46568 14.8525C8.28064 14.8525 8.14187 14.8987 8.00309 14.9912L6.15275 16.194C6.1065 16.2402 6.06024 16.2402 5.96772 16.2402C5.82894 16.2402 5.69017 16.1015 5.64391 15.9627C5.64391 15.8702 5.64391 15.8239 5.69017 15.7314C5.69017 15.6851 5.8752 14.8062 6.01398 14.2511C6.01398 14.2049 6.06024 14.1123 6.01398 14.0661C6.01398 13.881 5.92146 13.696 5.73643 13.6035C3.74731 12.262 2.40582 10.1341 2.12827 7.95996C1.61942 8.74635 1.38813 9.34771 1.11058 10.2729C0.139154 13.6498 2.26704 17.6742 5.69017 18.7844C9.6684 20.0797 13.4153 18.6457 14.7106 15.2688C14.8493 14.8525 15.0344 14.1586 15.0806 13.6035C13.7391 14.5749 12.3051 15.0375 10.4548 15.0375Z" fill="#07C160"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_9425_7305">
|
||||
<rect width="21" height="20" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 2.7 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.2306 7.29455C13.9169 7.25216 13.5948 7.22673 13.2641 7.22673C9.66084 7.22673 6.73584 9.67694 6.74432 12.6782C6.74432 13.0343 6.78671 13.3735 6.86301 13.7041C6.30345 13.6278 5.77779 13.4837 5.27758 13.3056L2.93757 14.3146L3.79388 12.5935C2.27627 11.593 1.30127 10.0585 1.30127 8.32042C1.30127 5.31064 4.22627 2.8689 7.82953 2.8689C11.0089 2.8689 13.6541 4.77651 14.2306 7.29455ZM10.3114 5.38107C10.2127 5.34017 10.1069 5.31911 9.99997 5.31911C9.78411 5.31911 9.57708 5.40487 9.42445 5.5575C9.27181 5.71014 9.18606 5.91717 9.18606 6.13303C9.18606 6.34889 9.27181 6.55591 9.42445 6.70855C9.57708 6.86119 9.78411 6.94694 9.99997 6.94694C10.1069 6.94694 10.2127 6.92589 10.3114 6.88499C10.4102 6.84408 10.4999 6.78413 10.5755 6.70855C10.6511 6.63297 10.711 6.54325 10.7519 6.4445C10.7928 6.34575 10.8139 6.23991 10.8139 6.13303C10.8139 6.02614 10.7928 5.92031 10.7519 5.82156C10.711 5.72281 10.6511 5.63308 10.5755 5.5575C10.4999 5.48193 10.4102 5.42197 10.3114 5.38107ZM5.0751 6.71703C5.22773 6.86967 5.43476 6.95542 5.65062 6.95542C5.86648 6.95542 6.0735 6.86967 6.22614 6.71703C6.37878 6.56439 6.46453 6.35737 6.46453 6.14151C6.46453 5.92564 6.37878 5.71862 6.22614 5.56598C6.0735 5.41334 5.86648 5.32759 5.65062 5.32759C5.43476 5.32759 5.22773 5.41334 5.0751 5.56598C4.92246 5.71862 4.83671 5.92564 4.83671 6.14151C4.83671 6.35737 4.92246 6.56439 5.0751 6.71703Z" fill="#2DBC00"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.264 8.3204C16.2653 8.3204 18.6986 10.2704 18.6986 12.6782C18.6986 14.0771 17.8677 15.298 16.596 16.095L17.6134 18.1298L14.6799 16.8665C14.2305 16.9682 13.7557 17.0361 13.264 17.0361C10.2627 17.0361 7.82944 15.0861 7.82944 12.6782C7.82944 10.2704 10.2627 8.3204 13.264 8.3204ZM11.1755 12.2698C11.3094 12.3592 11.4667 12.4069 11.6277 12.4069C12.0771 12.4069 12.4501 12.0424 12.4416 11.593C12.4416 11.432 12.3939 11.2747 12.3044 11.1408C12.215 11.007 12.0879 10.9027 11.9392 10.8411C11.7905 10.7794 11.6268 10.7633 11.4689 10.7947C11.311 10.8261 11.166 10.9037 11.0522 11.0175C10.9384 11.1313 10.8608 11.2763 10.8294 11.4342C10.798 11.5921 10.8141 11.7558 10.8757 11.9045C10.9373 12.0532 11.0417 12.1803 11.1755 12.2698ZM14.3163 12.1685C14.469 12.3212 14.676 12.4069 14.8918 12.4069C15.1077 12.4069 15.3147 12.3212 15.4674 12.1685C15.62 12.0159 15.7057 11.8089 15.7057 11.593C15.7057 11.3771 15.62 11.1701 15.4674 11.0175C15.3147 10.8648 15.1077 10.7791 14.8918 10.7791C14.676 10.7791 14.469 10.8648 14.3163 11.0175C14.1637 11.1701 14.0779 11.3771 14.0779 11.593C14.0779 11.8089 14.1637 12.0159 14.3163 12.1685Z" fill="#2DBC00"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.7 KiB |
@@ -31,5 +31,12 @@
|
||||
"edit_modal_title": "编辑企微机器人",
|
||||
"create_modal_title": "创建企微机器人",
|
||||
"api": "企微 API"
|
||||
},
|
||||
"official_account": {
|
||||
"name": "微信公众号接入",
|
||||
"desc": "通过 API 直接接入微信公众号",
|
||||
"edit_modal_title": "编辑微信公众号接入",
|
||||
"create_modal_title": "创建微信公众号接入",
|
||||
"api": "微信公众号 API"
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 210 KiB |
@@ -0,0 +1,29 @@
|
||||
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
|
||||
import { plusRequest } from '@fastgpt/service/common/api/plusRequest';
|
||||
|
||||
export type OutLinkOffiAccountQuery = any;
|
||||
export type OutLinkOffiAccountBody = any;
|
||||
export type OutLinkOffiAccountResponse = {};
|
||||
|
||||
async function handler(
|
||||
req: ApiRequestProps<OutLinkOffiAccountBody, OutLinkOffiAccountQuery>,
|
||||
res: ApiResponseType<any>
|
||||
): Promise<any> {
|
||||
const { token, type } = req.query;
|
||||
const result = await plusRequest({
|
||||
url: `support/outLink/offiaccount/${token}`,
|
||||
params: {
|
||||
...req.query,
|
||||
type
|
||||
},
|
||||
data: req.body
|
||||
});
|
||||
|
||||
if (result.data?.data?.message) {
|
||||
res.send(result.data.data.message);
|
||||
}
|
||||
|
||||
res.send('');
|
||||
}
|
||||
|
||||
export default handler;
|
@@ -9,6 +9,8 @@ async function handler(
|
||||
req: ApiRequestProps<OutLinkWecomBody, OutLinkWecomQuery>,
|
||||
res: ApiResponseType<any>
|
||||
): Promise<any> {
|
||||
// WARN: it is not supported yet.
|
||||
return {};
|
||||
const { token, type } = req.query;
|
||||
const result = await plusRequest({
|
||||
url: `support/outLink/wecom/${token}`,
|
||||
|
@@ -0,0 +1,153 @@
|
||||
import React from 'react';
|
||||
import { Flex, Box, Button, ModalBody, Input, Link } from '@chakra-ui/react';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { PublishChannelEnum } from '@fastgpt/global/support/outLink/constant';
|
||||
import type { OffiAccountAppType, OutLinkEditType } from '@fastgpt/global/support/outLink/type';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { createShareChat, updateShareChat } from '@/web/support/outLink/api';
|
||||
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import BasicInfo from '../components/BasicInfo';
|
||||
import { getDocPath } from '@/web/common/system/doc';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
|
||||
|
||||
const OffiAccountEditModal = ({
|
||||
appId,
|
||||
defaultData,
|
||||
onClose,
|
||||
onCreate,
|
||||
onEdit,
|
||||
isEdit = false
|
||||
}: {
|
||||
appId: string;
|
||||
defaultData: OutLinkEditType<OffiAccountAppType>;
|
||||
onClose: () => void;
|
||||
onCreate: (id: string) => void;
|
||||
onEdit: () => void;
|
||||
isEdit?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
register,
|
||||
setValue,
|
||||
handleSubmit: submitShareChat
|
||||
} = useForm({
|
||||
defaultValues: defaultData
|
||||
});
|
||||
|
||||
const { runAsync: onclickCreate, loading: creating } = useRequest2(
|
||||
(e) =>
|
||||
createShareChat({
|
||||
...e,
|
||||
appId,
|
||||
type: PublishChannelEnum.officialAccount
|
||||
}),
|
||||
{
|
||||
errorToast: t('common:common.Create Failed'),
|
||||
successToast: t('common:common.Create Success'),
|
||||
onSuccess: onCreate
|
||||
}
|
||||
);
|
||||
|
||||
const { runAsync: onclickUpdate, loading: updating } = useRequest2((e) => updateShareChat(e), {
|
||||
errorToast: t('common:common.Update Failed'),
|
||||
successToast: t('common:common.Update Success'),
|
||||
onSuccess: onEdit
|
||||
});
|
||||
|
||||
const { feConfigs } = useSystemStore();
|
||||
|
||||
return (
|
||||
<MyModal
|
||||
iconSrc="/imgs/modal/shareFill.svg"
|
||||
title={
|
||||
isEdit
|
||||
? t('publish:official_account.edit_modal_title')
|
||||
: t('publish:official_account.create_modal_title')
|
||||
}
|
||||
minW={['auto', '60rem']}
|
||||
>
|
||||
<ModalBody display={'grid'} gridTemplateColumns={['1fr', '1fr 1fr']} fontSize={'14px'} p={0}>
|
||||
<Box p={8} minH={['auto', '400px']} borderRight={'base'}>
|
||||
<BasicInfo register={register} setValue={setValue} defaultData={defaultData} />
|
||||
</Box>
|
||||
<Flex p={8} minH={['auto', '400px']} flexDirection="column" gap={6}>
|
||||
<Flex alignItems="center">
|
||||
<Box color="myGray.600">{t('publish:official_account.api')}</Box>
|
||||
{feConfigs?.docUrl && (
|
||||
<Link
|
||||
href={feConfigs.openAPIDocUrl || getDocPath('/docs/use-cases/official_account')}
|
||||
target={'_blank'}
|
||||
ml={2}
|
||||
color={'primary.500'}
|
||||
fontSize={'sm'}
|
||||
>
|
||||
<Flex alignItems={'center'}>
|
||||
<MyIcon name="book" mr="1" />
|
||||
{t('common:common.Read document')}
|
||||
</Flex>
|
||||
</Link>
|
||||
)}
|
||||
</Flex>
|
||||
<Flex alignItems={'center'}>
|
||||
<FormLabel flex={'0 0 6.25rem'} required>
|
||||
App ID
|
||||
</FormLabel>
|
||||
<Input
|
||||
placeholder="App ID"
|
||||
{...register('app.appId', {
|
||||
required: true
|
||||
})}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex alignItems={'center'}>
|
||||
<FormLabel flex={'0 0 6.25rem'} required>
|
||||
Secret
|
||||
</FormLabel>
|
||||
<Input
|
||||
placeholder="Secret"
|
||||
{...register('app.secret', {
|
||||
required: true
|
||||
})}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex alignItems={'center'}>
|
||||
<FormLabel flex={'0 0 6.25rem'} required>
|
||||
Token
|
||||
</FormLabel>
|
||||
<Input
|
||||
placeholder="Token"
|
||||
{...register('app.CallbackToken', {
|
||||
required: true
|
||||
})}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex alignItems={'center'}>
|
||||
<FormLabel flex={'0 0 6.25rem'}>AES Key</FormLabel>
|
||||
<Input placeholder="AES Key" {...register('app.CallbackEncodingAesKey')} />
|
||||
</Flex>
|
||||
|
||||
<Box flex={1}></Box>
|
||||
|
||||
<Flex justifyContent={'end'}>
|
||||
<Button variant={'whiteBase'} mr={3} onClick={onClose}>
|
||||
{t('common:common.Close')}
|
||||
</Button>
|
||||
<Button
|
||||
isLoading={creating || updating}
|
||||
onClick={submitShareChat((data) =>
|
||||
isEdit ? onclickUpdate(data) : onclickCreate(data)
|
||||
)}
|
||||
>
|
||||
{t('common:common.Confirm')}
|
||||
</Button>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</ModalBody>
|
||||
</MyModal>
|
||||
);
|
||||
};
|
||||
|
||||
export default OffiAccountEditModal;
|
@@ -0,0 +1,227 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import {
|
||||
Flex,
|
||||
Box,
|
||||
Button,
|
||||
TableContainer,
|
||||
Table,
|
||||
Thead,
|
||||
Tr,
|
||||
Th,
|
||||
Td,
|
||||
Tbody,
|
||||
useDisclosure
|
||||
} from '@chakra-ui/react';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useLoading } from '@fastgpt/web/hooks/useLoading';
|
||||
import { getShareChatList, delShareChatById } from '@/web/support/outLink/api';
|
||||
import { formatTimeToChatTime } from '@fastgpt/global/common/string/time';
|
||||
import { defaultOutLinkForm } from '@/web/core/app/constants';
|
||||
import type { OutLinkEditType, OffiAccountAppType } from '@fastgpt/global/support/outLink/type.d';
|
||||
import { PublishChannelEnum } from '@fastgpt/global/support/outLink/constant';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import dayjs from 'dayjs';
|
||||
import dynamic from 'next/dynamic';
|
||||
import MyMenu from '@fastgpt/web/components/common/MyMenu';
|
||||
import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
|
||||
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
|
||||
const OffiAccountEditModal = dynamic(() => import('./OffiAccountEditModal'));
|
||||
const ShowShareLinkModal = dynamic(() => import('../components/showShareLinkModal'));
|
||||
|
||||
const OffiAccount = ({ appId }: { appId: string }) => {
|
||||
const { t } = useTranslation();
|
||||
const { Loading, setIsLoading } = useLoading();
|
||||
const { feConfigs } = useSystemStore();
|
||||
const [editOffiAccountData, setEditOffiAccountData] =
|
||||
useState<OutLinkEditType<OffiAccountAppType>>();
|
||||
const [isEdit, setIsEdit] = useState<boolean>(false);
|
||||
|
||||
const baseUrl = useMemo(
|
||||
() => feConfigs?.customApiDomain || `${location.origin}/api`,
|
||||
[feConfigs?.customApiDomain]
|
||||
);
|
||||
|
||||
const {
|
||||
data: shareChatList = [],
|
||||
loading: isFetching,
|
||||
runAsync: refetchShareChatList
|
||||
} = useRequest2(
|
||||
() => getShareChatList<OffiAccountAppType>({ appId, type: PublishChannelEnum.officialAccount }),
|
||||
{
|
||||
manual: false
|
||||
}
|
||||
);
|
||||
|
||||
const {
|
||||
onOpen: openShowShareLinkModal,
|
||||
isOpen: showShareLinkModalOpen,
|
||||
onClose: closeShowShareLinkModal
|
||||
} = useDisclosure();
|
||||
|
||||
const [showShareLink, setShowShareLink] = useState<string | null>(null);
|
||||
|
||||
return (
|
||||
<Box position={'relative'} pt={3} px={5} minH={'50vh'}>
|
||||
<Flex justifyContent={'space-between'} flexDirection="row">
|
||||
<Box fontWeight={'bold'} fontSize={['md', 'lg']}>
|
||||
{t('publish:official_account.name')}
|
||||
</Box>
|
||||
<Button
|
||||
variant={'primary'}
|
||||
colorScheme={'blue'}
|
||||
size={['sm', 'md']}
|
||||
leftIcon={<MyIcon name={'common/addLight'} w="1.25rem" color="white" />}
|
||||
ml={3}
|
||||
{...(shareChatList.length >= 10
|
||||
? {
|
||||
isDisabled: true,
|
||||
title: t('common:core.app.share.Amount limit tip')
|
||||
}
|
||||
: {})}
|
||||
onClick={() => {
|
||||
setEditOffiAccountData(defaultOutLinkForm as any); // HACK
|
||||
setIsEdit(false);
|
||||
}}
|
||||
>
|
||||
{t('common:add_new')}
|
||||
</Button>
|
||||
</Flex>
|
||||
<TableContainer mt={3}>
|
||||
<Table variant={'simple'} w={'100%'} overflowX={'auto'} fontSize={'sm'}>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>{t('common:common.Name')} </Th>
|
||||
<Th> {t('common:support.outlink.Usage points')} </Th>
|
||||
{feConfigs?.isPlus && (
|
||||
<>
|
||||
<Th>{t('common:core.app.share.Ip limit title')} </Th>
|
||||
<Th> {t('common:common.Expired Time')} </Th>
|
||||
</>
|
||||
)}
|
||||
<Th>{t('common:common.Last use time')} </Th>
|
||||
<Th> </Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{shareChatList.map((item) => (
|
||||
<Tr key={item._id}>
|
||||
<Td>{item.name} </Td>
|
||||
<Td>
|
||||
{Math.round(item.usagePoints)}
|
||||
{feConfigs?.isPlus
|
||||
? `${
|
||||
item.limit?.maxUsagePoints && item.limit.maxUsagePoints > -1
|
||||
? ` / ${item.limit.maxUsagePoints}`
|
||||
: ` / ${t('common:common.Unlimited')}`
|
||||
}`
|
||||
: ''}
|
||||
</Td>
|
||||
{feConfigs?.isPlus && (
|
||||
<>
|
||||
<Td>{item?.limit?.QPM || '-'} </Td>
|
||||
<Td>
|
||||
{item?.limit?.expiredTime
|
||||
? dayjs(item.limit?.expiredTime).format('YYYY/MM/DD\nHH:mm')
|
||||
: '-'}
|
||||
</Td>
|
||||
</>
|
||||
)}
|
||||
<Td>
|
||||
{item.lastTime
|
||||
? t(formatTimeToChatTime(item.lastTime) as any)
|
||||
: t('common:common.Un used')}
|
||||
</Td>
|
||||
<Td display={'flex'} alignItems={'center'}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setShowShareLink(`${baseUrl}/support/outLink/offiaccount/${item.shareId}`);
|
||||
openShowShareLinkModal();
|
||||
}}
|
||||
size={'sm'}
|
||||
mr={3}
|
||||
variant={'whitePrimary'}
|
||||
>
|
||||
{t('publish:request_address')}
|
||||
</Button>
|
||||
<MyMenu
|
||||
Button={
|
||||
<MyIcon
|
||||
name={'more'}
|
||||
_hover={{ bg: 'myGray.100' }}
|
||||
cursor={'pointer'}
|
||||
borderRadius={'md'}
|
||||
w={'14px'}
|
||||
p={2}
|
||||
/>
|
||||
}
|
||||
menuList={[
|
||||
{
|
||||
children: [
|
||||
{
|
||||
label: t('common:common.Edit'),
|
||||
icon: 'edit',
|
||||
onClick: () => {
|
||||
setEditOffiAccountData({
|
||||
_id: item._id,
|
||||
name: item.name,
|
||||
limit: item.limit,
|
||||
app: item.app,
|
||||
responseDetail: item.responseDetail,
|
||||
defaultResponse: item.defaultResponse,
|
||||
immediateResponse: item.immediateResponse
|
||||
});
|
||||
setIsEdit(true);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: t('common:common.Delete'),
|
||||
icon: 'delete',
|
||||
onClick: async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await delShareChatById(item._id);
|
||||
refetchShareChatList();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
{editOffiAccountData && (
|
||||
<OffiAccountEditModal
|
||||
appId={appId}
|
||||
defaultData={editOffiAccountData}
|
||||
onCreate={() => Promise.all([refetchShareChatList(), setEditOffiAccountData(undefined)])}
|
||||
onEdit={() => Promise.all([refetchShareChatList(), setEditOffiAccountData(undefined)])}
|
||||
onClose={() => setEditOffiAccountData(undefined)}
|
||||
isEdit={isEdit}
|
||||
/>
|
||||
)}
|
||||
{shareChatList.length === 0 && !isFetching && (
|
||||
<EmptyTip text={t('common:core.app.share.Not share link')}> </EmptyTip>
|
||||
)}
|
||||
<Loading loading={isFetching} fixed={false} />
|
||||
{showShareLinkModalOpen && (
|
||||
<ShowShareLinkModal
|
||||
shareLink={showShareLink ?? ''}
|
||||
onClose={closeShowShareLinkModal}
|
||||
img="/imgs/outlink/offiaccount-copylink-instruction.png"
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(OffiAccount);
|
@@ -138,9 +138,7 @@ const WecomEditModal = ({
|
||||
</FormLabel>
|
||||
<Input
|
||||
placeholder="AES Key"
|
||||
{...register('app.CallbackEncodingAesKey', {
|
||||
required: true
|
||||
})}
|
||||
{...(register('app.CallbackEncodingAesKey'), { required: true })}
|
||||
/>
|
||||
</Flex>
|
||||
|
||||
|
@@ -16,7 +16,8 @@ import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
const Link = dynamic(() => import('./Link'));
|
||||
const API = dynamic(() => import('./API'));
|
||||
const FeiShu = dynamic(() => import('./FeiShu'));
|
||||
const Wecom = dynamic(() => import('./Wecom'));
|
||||
// const Wecom = dynamic(() => import('./Wecom'));
|
||||
const OffiAccount = dynamic(() => import('./OffiAccount'));
|
||||
|
||||
const OutLink = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -47,11 +48,18 @@ const OutLink = () => {
|
||||
value: PublishChannelEnum.feishu,
|
||||
isProFn: true
|
||||
},
|
||||
// {
|
||||
// icon: 'core/app/publish/wecom',
|
||||
// title: t('publish:wecom.bot'),
|
||||
// desc: t('publish:wecom.bot_desc'),
|
||||
// value: PublishChannelEnum.wecom,
|
||||
// isProFn: true
|
||||
// },
|
||||
{
|
||||
icon: 'core/app/publish/wecom',
|
||||
title: t('publish:wecom.bot'),
|
||||
desc: t('publish:wecom.bot_desc'),
|
||||
value: PublishChannelEnum.wecom,
|
||||
icon: 'core/app/publish/offiaccount',
|
||||
title: t('publish:official_account.name'),
|
||||
desc: t('publish:official_account.desc'),
|
||||
value: PublishChannelEnum.officialAccount,
|
||||
isProFn: true
|
||||
}
|
||||
]);
|
||||
@@ -106,7 +114,8 @@ const OutLink = () => {
|
||||
)}
|
||||
{linkType === PublishChannelEnum.apikey && <API appId={appId} />}
|
||||
{linkType === PublishChannelEnum.feishu && <FeiShu appId={appId} />}
|
||||
{linkType === PublishChannelEnum.wecom && <Wecom appId={appId} />}
|
||||
{/* {linkType === PublishChannelEnum.wecom && <Wecom appId={appId} />} */}
|
||||
{linkType === PublishChannelEnum.officialAccount && <OffiAccount appId={appId} />}
|
||||
</Flex>
|
||||
</Box>
|
||||
);
|
||||
|
Reference in New Issue
Block a user