mirror of
https://github.com/labring/FastGPT.git
synced 2025-10-19 18:14:38 +00:00
perf: plus api
This commit is contained in:
@@ -16,7 +16,6 @@
|
|||||||
"qaMaxProcess": 15,
|
"qaMaxProcess": 15,
|
||||||
"pgIvfflatProbe": 20
|
"pgIvfflatProbe": 20
|
||||||
},
|
},
|
||||||
"plugins": {},
|
|
||||||
"ChatModels": [
|
"ChatModels": [
|
||||||
{
|
{
|
||||||
"model": "gpt-3.5-turbo",
|
"model": "gpt-3.5-turbo",
|
||||||
|
@@ -150,7 +150,7 @@
|
|||||||
"Update password failed": "修改密码异常",
|
"Update password failed": "修改密码异常",
|
||||||
"Update password succseful": "修改密码成功",
|
"Update password succseful": "修改密码成功",
|
||||||
"Usage Record": "使用记录",
|
"Usage Record": "使用记录",
|
||||||
"promption": {
|
"promotion": {
|
||||||
"register": "好友注册",
|
"register": "好友注册",
|
||||||
"pay": "好友充值"
|
"pay": "好友充值"
|
||||||
}
|
}
|
||||||
|
3
client/src/api/service/plugins.ts
Normal file
3
client/src/api/service/plugins.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { GET, POST } from './request';
|
||||||
|
|
||||||
|
export const textCensor = (data: { text: string }) => POST('/plugins/censor/text_baidu', data);
|
@@ -1,6 +1,4 @@
|
|||||||
import axios, { Method, InternalAxiosRequestConfig, AxiosResponse } from 'axios';
|
import axios, { Method, InternalAxiosRequestConfig, AxiosResponse } from 'axios';
|
||||||
import { clearToken, getToken } from '@/utils/user';
|
|
||||||
import { TOKEN_ERROR_CODE } from '@/service/errorCode';
|
|
||||||
|
|
||||||
interface ConfigType {
|
interface ConfigType {
|
||||||
headers?: { [key: string]: string };
|
headers?: { [key: string]: string };
|
||||||
@@ -18,7 +16,7 @@ interface ResponseDataType {
|
|||||||
*/
|
*/
|
||||||
function requestStart(config: InternalAxiosRequestConfig): InternalAxiosRequestConfig {
|
function requestStart(config: InternalAxiosRequestConfig): InternalAxiosRequestConfig {
|
||||||
if (config.headers) {
|
if (config.headers) {
|
||||||
// config.headers.token = getToken();
|
config.headers.rootkey = process.env.ROOT_KEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
@@ -53,14 +51,7 @@ function responseError(err: any) {
|
|||||||
if (typeof err === 'string') {
|
if (typeof err === 'string') {
|
||||||
return Promise.reject({ message: err });
|
return Promise.reject({ message: err });
|
||||||
}
|
}
|
||||||
// 有报错响应
|
|
||||||
if (err?.code in TOKEN_ERROR_CODE) {
|
|
||||||
clearToken();
|
|
||||||
window.location.replace(
|
|
||||||
`/login?lastRoute=${encodeURIComponent(location.pathname + location.search)}`
|
|
||||||
);
|
|
||||||
return Promise.reject({ message: 'token过期,重新登录' });
|
|
||||||
}
|
|
||||||
if (err?.response?.data) {
|
if (err?.response?.data) {
|
||||||
return Promise.reject(err?.response?.data);
|
return Promise.reject(err?.response?.data);
|
||||||
}
|
}
|
||||||
@@ -69,6 +60,7 @@ function responseError(err: any) {
|
|||||||
|
|
||||||
/* 创建请求实例 */
|
/* 创建请求实例 */
|
||||||
const instance = axios.create({
|
const instance = axios.create({
|
||||||
|
baseURL: global.systemEnv.pluginBaseUrl,
|
||||||
timeout: 60000, // 超时时间
|
timeout: 60000, // 超时时间
|
||||||
headers: {
|
headers: {
|
||||||
'content-type': 'application/json'
|
'content-type': 'application/json'
|
||||||
@@ -80,7 +72,11 @@ instance.interceptors.request.use(requestStart, (err) => Promise.reject(err));
|
|||||||
/* 响应拦截 */
|
/* 响应拦截 */
|
||||||
instance.interceptors.response.use(responseSuccess, (err) => Promise.reject(err));
|
instance.interceptors.response.use(responseSuccess, (err) => Promise.reject(err));
|
||||||
|
|
||||||
function request(url: string, data: any, config: ConfigType, method: Method): any {
|
export function request(url: string, data: any, config: ConfigType, method: Method): any {
|
||||||
|
if (!global.systemEnv.pluginBaseUrl) {
|
||||||
|
return Promise.reject('请安装商业版插件~');
|
||||||
|
}
|
||||||
|
|
||||||
/* 去空 */
|
/* 去空 */
|
||||||
for (const key in data) {
|
for (const key in data) {
|
||||||
if (data[key] === null || data[key] === undefined) {
|
if (data[key] === null || data[key] === undefined) {
|
||||||
@@ -107,22 +103,18 @@ function request(url: string, data: any, config: ConfigType, method: Method): an
|
|||||||
* @param {Object} config
|
* @param {Object} config
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function GET<T>(url?: string, params = {}, config: ConfigType = {}): Promise<T> {
|
export function GET<T>(url: string, params = {}, config: ConfigType = {}): Promise<T> {
|
||||||
if (!url) return Promise.reject('The Plugin is not installed');
|
|
||||||
return request(url, params, config, 'GET');
|
return request(url, params, config, 'GET');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function POST<T>(url?: string, data = {}, config: ConfigType = {}): Promise<T> {
|
export function POST<T>(url: string, data = {}, config: ConfigType = {}): Promise<T> {
|
||||||
if (!url) return Promise.reject('The Plugin is not installed');
|
|
||||||
return request(url, data, config, 'POST');
|
return request(url, data, config, 'POST');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PUT<T>(url?: string, data = {}, config: ConfigType = {}): Promise<T> {
|
export function PUT<T>(url: string, data = {}, config: ConfigType = {}): Promise<T> {
|
||||||
if (!url) return Promise.reject('The Plugin is not installed');
|
|
||||||
return request(url, data, config, 'PUT');
|
return request(url, data, config, 'PUT');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DELETE<T>(url?: string, data = {}, config: ConfigType = {}): Promise<T> {
|
export function DELETE<T>(url: string, data = {}, config: ConfigType = {}): Promise<T> {
|
||||||
if (!url) return Promise.reject('The Plugin is not installed');
|
|
||||||
return request(url, data, config, 'DELETE');
|
return request(url, data, config, 'DELETE');
|
||||||
}
|
}
|
@@ -10,7 +10,7 @@ export const sendAuthCode = (data: {
|
|||||||
username: string;
|
username: string;
|
||||||
type: `${UserAuthTypeEnum}`;
|
type: `${UserAuthTypeEnum}`;
|
||||||
googleToken: string;
|
googleToken: string;
|
||||||
}) => POST('/user/sendAuthCode', data);
|
}) => POST(`/plusApi/user/account/sendCode`, data);
|
||||||
|
|
||||||
export const getTokenLogin = () => GET<UserType>('/user/account/tokenLogin');
|
export const getTokenLogin = () => GET<UserType>('/user/account/tokenLogin');
|
||||||
export const gitLogin = (params: { code: string; inviterId?: string }) =>
|
export const gitLogin = (params: { code: string; inviterId?: string }) =>
|
||||||
@@ -27,7 +27,7 @@ export const postRegister = ({
|
|||||||
password: string;
|
password: string;
|
||||||
inviterId: string;
|
inviterId: string;
|
||||||
}) =>
|
}) =>
|
||||||
POST<ResLogin>('/user/account/register', {
|
POST<ResLogin>(`/plusApi/user/account/register`, {
|
||||||
username,
|
username,
|
||||||
code,
|
code,
|
||||||
inviterId,
|
inviterId,
|
||||||
@@ -43,7 +43,7 @@ export const postFindPassword = ({
|
|||||||
code: string;
|
code: string;
|
||||||
password: string;
|
password: string;
|
||||||
}) =>
|
}) =>
|
||||||
POST<ResLogin>('/user/account/updatePasswordByCode', {
|
POST<ResLogin>(`/plusApi/user/account/updatePasswordByCode`, {
|
||||||
username,
|
username,
|
||||||
code,
|
code,
|
||||||
password: createHashPassword(password)
|
password: createHashPassword(password)
|
||||||
@@ -74,9 +74,15 @@ export const getPayCode = (amount: number) =>
|
|||||||
GET<{
|
GET<{
|
||||||
codeUrl: string;
|
codeUrl: string;
|
||||||
payId: string;
|
payId: string;
|
||||||
}>(`/user/getPayCode?amount=${amount}`);
|
}>(`/plusApi/user/pay/getPayCode`, { amount });
|
||||||
|
|
||||||
export const checkPayResult = (payId: string) => GET<number>(`/user/checkPayResult?payId=${payId}`);
|
export const checkPayResult = (payId: string) =>
|
||||||
|
GET<number>(`/plusApi/user/pay/checkPayResult`, { payId }).then(() => {
|
||||||
|
try {
|
||||||
|
GET('/user/account/paySuccess');
|
||||||
|
} catch (error) {}
|
||||||
|
return 'success';
|
||||||
|
});
|
||||||
|
|
||||||
export const getInforms = (data: RequestPaging) =>
|
export const getInforms = (data: RequestPaging) =>
|
||||||
POST<PagingData<informSchema>>(`/user/inform/list`, data);
|
POST<PagingData<informSchema>>(`/user/inform/list`, data);
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
import { useState, useMemo, useCallback } from 'react';
|
import { useState, useMemo, useCallback } from 'react';
|
||||||
import { sendAuthCode } from '@/api/user';
|
import { sendAuthCode } from '@/api/user';
|
||||||
import { UserAuthTypeEnum } from '@/constants/common';
|
import { UserAuthTypeEnum } from '@/constants/common';
|
||||||
let timer: any;
|
|
||||||
import { useToast } from './useToast';
|
import { useToast } from './useToast';
|
||||||
import { getClientToken } from '@/utils/plugin/google';
|
|
||||||
import { feConfigs } from '@/store/static';
|
import { feConfigs } from '@/store/static';
|
||||||
|
import { getErrText } from '@/utils/tools';
|
||||||
|
|
||||||
|
let timer: any;
|
||||||
|
|
||||||
export const useSendCode = () => {
|
export const useSendCode = () => {
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
@@ -45,7 +46,7 @@ export const useSendCode = () => {
|
|||||||
});
|
});
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
toast({
|
toast({
|
||||||
title: error.message || '发送验证码异常',
|
title: getErrText(error, '验证码发送异常'),
|
||||||
status: 'error'
|
status: 'error'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -61,3 +62,20 @@ export const useSendCode = () => {
|
|||||||
codeCountDown
|
codeCountDown
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function getClientToken(googleClientVerKey?: string) {
|
||||||
|
if (!googleClientVerKey || typeof window.grecaptcha === 'undefined' || !window.grecaptcha?.ready)
|
||||||
|
return '';
|
||||||
|
return new Promise<string>((resolve, reject) => {
|
||||||
|
window.grecaptcha.ready(async () => {
|
||||||
|
try {
|
||||||
|
const token = await window.grecaptcha.execute(googleClientVerKey, {
|
||||||
|
action: 'submit'
|
||||||
|
});
|
||||||
|
resolve(token);
|
||||||
|
} catch (error) {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@@ -109,7 +109,7 @@ const Promotion = () => {
|
|||||||
<Tr>
|
<Tr>
|
||||||
<Th>时间</Th>
|
<Th>时间</Th>
|
||||||
<Th>类型</Th>
|
<Th>类型</Th>
|
||||||
<Th>金额</Th>
|
<Th>金额(¥)</Th>
|
||||||
</Tr>
|
</Tr>
|
||||||
</Thead>
|
</Thead>
|
||||||
<Tbody fontSize={'sm'}>
|
<Tbody fontSize={'sm'}>
|
||||||
|
44
client/src/pages/api/plusApi/[...path].ts
Normal file
44
client/src/pages/api/plusApi/[...path].ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
import { jsonRes } from '@/service/response';
|
||||||
|
import { request } from '@/api/service/request';
|
||||||
|
import type { Method } from 'axios';
|
||||||
|
import { connectToDatabase } from '@/service/mongo';
|
||||||
|
|
||||||
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
|
try {
|
||||||
|
await connectToDatabase();
|
||||||
|
|
||||||
|
const method = (req.method || 'POST') as Method;
|
||||||
|
const { path = [], ...query } = req.query as any;
|
||||||
|
|
||||||
|
const url = `/${path?.join('/')}`;
|
||||||
|
|
||||||
|
if (!url) {
|
||||||
|
throw new Error('url is empty');
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
...req.body,
|
||||||
|
...query
|
||||||
|
};
|
||||||
|
|
||||||
|
const repose = await request(
|
||||||
|
url,
|
||||||
|
data,
|
||||||
|
{
|
||||||
|
// @ts-ignore
|
||||||
|
headers: req.headers
|
||||||
|
},
|
||||||
|
method
|
||||||
|
);
|
||||||
|
|
||||||
|
jsonRes(res, {
|
||||||
|
data: repose
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
jsonRes(res, {
|
||||||
|
code: 500,
|
||||||
|
error
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -97,7 +97,6 @@ export async function getInitConfig() {
|
|||||||
global.chatModels = res.ChatModels || defaultChatModels;
|
global.chatModels = res.ChatModels || defaultChatModels;
|
||||||
global.qaModels = res.QAModels || defaultQAModels;
|
global.qaModels = res.QAModels || defaultQAModels;
|
||||||
global.vectorModels = res.VectorModels || defaultVectorModels;
|
global.vectorModels = res.VectorModels || defaultVectorModels;
|
||||||
global.systemPlugins = res.plugins || {};
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setDefaultData();
|
setDefaultData();
|
||||||
console.log('get init config error, set default', error);
|
console.log('get init config error, set default', error);
|
||||||
@@ -110,5 +109,4 @@ export function setDefaultData() {
|
|||||||
global.chatModels = defaultChatModels;
|
global.chatModels = defaultChatModels;
|
||||||
global.qaModels = defaultQAModels;
|
global.qaModels = defaultQAModels;
|
||||||
global.vectorModels = defaultVectorModels;
|
global.vectorModels = defaultVectorModels;
|
||||||
global.systemPlugins = {};
|
|
||||||
}
|
}
|
||||||
|
30
client/src/pages/api/user/account/paySuccess.ts
Normal file
30
client/src/pages/api/user/account/paySuccess.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
import { jsonRes } from '@/service/response';
|
||||||
|
import { TrainingData } from '@/service/mongo';
|
||||||
|
import { startQueue } from '@/service/utils/tools';
|
||||||
|
import { authUser } from '@/service/utils/auth';
|
||||||
|
|
||||||
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
|
try {
|
||||||
|
const { userId } = await authUser({ req, authToken: true });
|
||||||
|
await unlockTask(userId);
|
||||||
|
} catch (error) {}
|
||||||
|
jsonRes(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function unlockTask(userId: string) {
|
||||||
|
try {
|
||||||
|
await TrainingData.updateMany(
|
||||||
|
{
|
||||||
|
userId
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lockTime: new Date('2000/1/1')
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
startQueue();
|
||||||
|
} catch (error) {
|
||||||
|
unlockTask(userId);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,64 +0,0 @@
|
|||||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
|
||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
|
||||||
import { jsonRes } from '@/service/response';
|
|
||||||
import { User } from '@/service/models/user';
|
|
||||||
import { connectToDatabase } from '@/service/mongo';
|
|
||||||
import { generateToken, setCookie } from '@/service/utils/tools';
|
|
||||||
import { UserAuthTypeEnum } from '@/constants/common';
|
|
||||||
import { authCode } from '@/service/api/plugins';
|
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
|
||||||
try {
|
|
||||||
const { username, code, password, inviterId } = req.body;
|
|
||||||
|
|
||||||
if (!username || !code || !password) {
|
|
||||||
throw new Error('缺少参数');
|
|
||||||
}
|
|
||||||
|
|
||||||
await connectToDatabase();
|
|
||||||
|
|
||||||
// 验证码校验
|
|
||||||
await authCode({
|
|
||||||
username,
|
|
||||||
type: UserAuthTypeEnum.register,
|
|
||||||
code
|
|
||||||
});
|
|
||||||
|
|
||||||
// 重名校验
|
|
||||||
const authRepeat = await User.findOne({
|
|
||||||
username
|
|
||||||
});
|
|
||||||
|
|
||||||
if (authRepeat) {
|
|
||||||
throw new Error('该用户已被注册');
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await User.create({
|
|
||||||
username,
|
|
||||||
password,
|
|
||||||
inviterId: inviterId ? inviterId : undefined
|
|
||||||
});
|
|
||||||
|
|
||||||
// 根据 id 获取用户信息
|
|
||||||
const user = await User.findById(response._id);
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
throw new Error('获取用户信息异常');
|
|
||||||
}
|
|
||||||
|
|
||||||
const token = generateToken(user._id);
|
|
||||||
setCookie(res, token);
|
|
||||||
|
|
||||||
jsonRes(res, {
|
|
||||||
data: {
|
|
||||||
user,
|
|
||||||
token
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
jsonRes(res, {
|
|
||||||
code: 500,
|
|
||||||
error: err
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,65 +0,0 @@
|
|||||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
|
||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
|
||||||
import { jsonRes } from '@/service/response';
|
|
||||||
import { User } from '@/service/models/user';
|
|
||||||
import { connectToDatabase } from '@/service/mongo';
|
|
||||||
import { UserAuthTypeEnum } from '@/constants/common';
|
|
||||||
import { generateToken, setCookie } from '@/service/utils/tools';
|
|
||||||
import { authCode } from '@/service/api/plugins';
|
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
|
||||||
try {
|
|
||||||
const { username, code, password } = req.body;
|
|
||||||
|
|
||||||
if (!username || !code || !password) {
|
|
||||||
throw new Error('缺少参数');
|
|
||||||
}
|
|
||||||
|
|
||||||
await connectToDatabase();
|
|
||||||
|
|
||||||
// 验证码校验
|
|
||||||
await authCode({
|
|
||||||
username,
|
|
||||||
code,
|
|
||||||
type: UserAuthTypeEnum.findPassword
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!authCode) {
|
|
||||||
throw new Error('验证码错误');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新对应的记录
|
|
||||||
await User.updateOne(
|
|
||||||
{
|
|
||||||
username
|
|
||||||
},
|
|
||||||
{
|
|
||||||
password
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// 根据 username 获取用户信息
|
|
||||||
const user = await User.findOne({
|
|
||||||
username
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
throw new Error('获取用户信息异常');
|
|
||||||
}
|
|
||||||
|
|
||||||
const token = generateToken(user._id);
|
|
||||||
setCookie(res, token);
|
|
||||||
|
|
||||||
jsonRes(res, {
|
|
||||||
data: {
|
|
||||||
user,
|
|
||||||
token
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
jsonRes(res, {
|
|
||||||
code: 500,
|
|
||||||
error: err
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,112 +0,0 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
|
||||||
import { jsonRes } from '@/service/response';
|
|
||||||
import { User, Pay, TrainingData } from '@/service/mongo';
|
|
||||||
import { authUser } from '@/service/utils/auth';
|
|
||||||
import { PaySchema } from '@/types/mongoSchema';
|
|
||||||
import dayjs from 'dayjs';
|
|
||||||
import { startQueue } from '@/service/utils/tools';
|
|
||||||
import { getWxPayQRResult } from '@/service/api/plugins';
|
|
||||||
|
|
||||||
/* 校验支付结果 */
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|
||||||
try {
|
|
||||||
const { payId } = req.query as { payId: string };
|
|
||||||
|
|
||||||
const { userId } = await authUser({ req, authToken: true });
|
|
||||||
|
|
||||||
// 查找订单记录校验
|
|
||||||
const payOrder = await Pay.findById<PaySchema>(payId);
|
|
||||||
|
|
||||||
if (!payOrder) {
|
|
||||||
throw new Error('订单不存在');
|
|
||||||
}
|
|
||||||
if (payOrder.status !== 'NOTPAY') {
|
|
||||||
throw new Error('订单已结算');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取当前用户
|
|
||||||
const user = await User.findById(userId);
|
|
||||||
if (!user) {
|
|
||||||
throw new Error('找不到用户');
|
|
||||||
}
|
|
||||||
|
|
||||||
const payRes = await getWxPayQRResult(payOrder.orderId);
|
|
||||||
|
|
||||||
if (payRes.trade_state === 'SUCCESS') {
|
|
||||||
// 订单已支付
|
|
||||||
try {
|
|
||||||
// 更新订单状态. 如果没有合适的订单,说明订单重复了
|
|
||||||
const updateRes = await Pay.updateOne(
|
|
||||||
{
|
|
||||||
_id: payId,
|
|
||||||
status: 'NOTPAY'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
status: 'SUCCESS'
|
|
||||||
}
|
|
||||||
);
|
|
||||||
if (updateRes.modifiedCount === 1) {
|
|
||||||
// 给用户账号充钱
|
|
||||||
await User.findByIdAndUpdate(userId, {
|
|
||||||
$inc: { balance: payOrder.price }
|
|
||||||
});
|
|
||||||
|
|
||||||
unlockTask(userId);
|
|
||||||
return jsonRes(res, {
|
|
||||||
data: '支付成功'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
// roll back status
|
|
||||||
try {
|
|
||||||
await Pay.findByIdAndUpdate(payId, {
|
|
||||||
status: 'NOTPAY'
|
|
||||||
});
|
|
||||||
} catch (error) {}
|
|
||||||
}
|
|
||||||
return jsonRes(res, {
|
|
||||||
code: 500,
|
|
||||||
data: '更新订单失败,请重试'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 校验下是否超过一天
|
|
||||||
const orderTime = dayjs(payOrder.createTime);
|
|
||||||
const diffInHours = dayjs().diff(orderTime, 'hours');
|
|
||||||
|
|
||||||
if (payRes.trade_state === 'CLOSED' || diffInHours > 24) {
|
|
||||||
// 订单已关闭
|
|
||||||
await Pay.findByIdAndUpdate(payId, {
|
|
||||||
status: 'CLOSED'
|
|
||||||
});
|
|
||||||
return jsonRes(res, {
|
|
||||||
code: 500,
|
|
||||||
data: '订单已过期'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
throw new Error(payRes?.trade_state_desc || '订单无效');
|
|
||||||
} catch (err) {
|
|
||||||
// console.log(err);
|
|
||||||
jsonRes(res, {
|
|
||||||
code: 500,
|
|
||||||
error: err
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function unlockTask(userId: string) {
|
|
||||||
try {
|
|
||||||
await TrainingData.updateMany(
|
|
||||||
{
|
|
||||||
userId
|
|
||||||
},
|
|
||||||
{
|
|
||||||
lockTime: new Date('2000/1/1')
|
|
||||||
}
|
|
||||||
);
|
|
||||||
startQueue();
|
|
||||||
} catch (error) {
|
|
||||||
unlockTask(userId);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,37 +0,0 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
|
||||||
import { jsonRes } from '@/service/response';
|
|
||||||
import { authUser } from '@/service/utils/auth';
|
|
||||||
import { Pay } from '@/service/mongo';
|
|
||||||
import { PRICE_SCALE } from '@/constants/common';
|
|
||||||
import { getWxPayQRUrl } from '@/service/api/plugins';
|
|
||||||
|
|
||||||
/* 获取支付二维码 */
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|
||||||
try {
|
|
||||||
let { amount = 0 } = req.query as { amount: string };
|
|
||||||
amount = +amount;
|
|
||||||
|
|
||||||
const { userId } = await authUser({ req, authToken: true });
|
|
||||||
|
|
||||||
const { code_url, orderId } = await getWxPayQRUrl(amount);
|
|
||||||
|
|
||||||
// add one pay record
|
|
||||||
const payOrder = await Pay.create({
|
|
||||||
userId,
|
|
||||||
price: amount * PRICE_SCALE,
|
|
||||||
orderId
|
|
||||||
});
|
|
||||||
|
|
||||||
jsonRes(res, {
|
|
||||||
data: {
|
|
||||||
payId: payOrder._id,
|
|
||||||
codeUrl: code_url
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
jsonRes(res, {
|
|
||||||
code: 500,
|
|
||||||
error: err
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@@ -39,7 +39,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
jsonRes(res, {
|
jsonRes(res, {
|
||||||
data: {
|
data: {
|
||||||
invitedAmount,
|
invitedAmount,
|
||||||
historyAmount: countHistory[0]?.totalAmount || 0
|
earningsAmount: countHistory[0]?.totalAmount || 0
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@@ -1,47 +0,0 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
|
||||||
import { jsonRes } from '@/service/response';
|
|
||||||
import { UserAuthTypeEnum } from '@/constants/common';
|
|
||||||
import { authGoogleToken } from '@/utils/plugin/google';
|
|
||||||
import requestIp from 'request-ip';
|
|
||||||
import { sendCode } from '@/service/api/plugins';
|
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|
||||||
try {
|
|
||||||
const { username, type, googleToken } = req.body as {
|
|
||||||
username: string;
|
|
||||||
type: `${UserAuthTypeEnum}`;
|
|
||||||
googleToken: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!username || !type) {
|
|
||||||
throw new Error('缺少参数');
|
|
||||||
}
|
|
||||||
|
|
||||||
// google auth
|
|
||||||
global.systemEnv.googleServiceVerKey &&
|
|
||||||
(await authGoogleToken({
|
|
||||||
secret: global.systemEnv.googleServiceVerKey,
|
|
||||||
response: googleToken,
|
|
||||||
remoteip: requestIp.getClientIp(req) || undefined
|
|
||||||
}));
|
|
||||||
|
|
||||||
// register switch
|
|
||||||
if (type === UserAuthTypeEnum.register && !global.feConfigs?.show_register) {
|
|
||||||
throw new Error('Register is closed');
|
|
||||||
}
|
|
||||||
|
|
||||||
await sendCode({
|
|
||||||
username,
|
|
||||||
type
|
|
||||||
});
|
|
||||||
|
|
||||||
jsonRes(res, {
|
|
||||||
message: '发送验证码成功'
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
jsonRes(res, {
|
|
||||||
code: 500,
|
|
||||||
error: err
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
11
client/src/service/api/plugins.d.ts
vendored
11
client/src/service/api/plugins.d.ts
vendored
@@ -1,11 +0,0 @@
|
|||||||
import { UserAuthTypeEnum } from '../../constants/common';
|
|
||||||
|
|
||||||
export type SendCodeBody = {
|
|
||||||
username: string;
|
|
||||||
type: `${UserAuthTypeEnum}`;
|
|
||||||
};
|
|
||||||
export type AuthCodeBody = {
|
|
||||||
username: string;
|
|
||||||
type: `${UserAuthTypeEnum}`;
|
|
||||||
code: string;
|
|
||||||
};
|
|
@@ -1,21 +0,0 @@
|
|||||||
import { GET, POST } from './request';
|
|
||||||
import type { SendCodeBody, AuthCodeBody } from './plugins.d';
|
|
||||||
|
|
||||||
export const sendCode = (data: SendCodeBody) => POST(global.systemPlugins.authCode?.sendUrl, data);
|
|
||||||
export const authCode = (data: AuthCodeBody) => POST(global.systemPlugins.authCode?.authUrl, data);
|
|
||||||
|
|
||||||
export const textCensor = (data: { text: string }) => {
|
|
||||||
if (!global.systemPlugins.censor?.textUrl) return;
|
|
||||||
return POST(global.systemPlugins.censor?.textUrl, data);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getWxPayQRUrl = (amount: number) =>
|
|
||||||
POST<{
|
|
||||||
code_url: string;
|
|
||||||
orderId: string;
|
|
||||||
}>(global.systemPlugins.pay?.getWxQRUrl, { amount });
|
|
||||||
export const getWxPayQRResult = (orderId: string) =>
|
|
||||||
POST<{
|
|
||||||
trade_state: string;
|
|
||||||
trade_state_desc: string;
|
|
||||||
}>(global.systemPlugins.pay?.getWxQRResult, { orderId });
|
|
@@ -19,7 +19,7 @@ const PromotionRecordSchema = new Schema({
|
|||||||
type: {
|
type: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
enum: ['invite', 'register']
|
enum: ['pay', 'register']
|
||||||
},
|
},
|
||||||
amount: {
|
amount: {
|
||||||
type: Number,
|
type: Number,
|
||||||
|
@@ -15,7 +15,7 @@ import { getChatModel } from '@/service/utils/data';
|
|||||||
import { countModelPrice } from '@/service/events/pushBill';
|
import { countModelPrice } from '@/service/events/pushBill';
|
||||||
import { ChatModelItemType } from '@/types/model';
|
import { ChatModelItemType } from '@/types/model';
|
||||||
import { UserModelSchema } from '@/types/mongoSchema';
|
import { UserModelSchema } from '@/types/mongoSchema';
|
||||||
import { textCensor } from '@/service/api/plugins';
|
import { textCensor } from '@/api/service/plugins';
|
||||||
import { ChatCompletionRequestMessageRoleEnum } from 'openai';
|
import { ChatCompletionRequestMessageRoleEnum } from 'openai';
|
||||||
import { AppModuleItemType } from '@/types/app';
|
import { AppModuleItemType } from '@/types/app';
|
||||||
|
|
||||||
|
@@ -54,16 +54,16 @@ export const jsonRes = <T = any>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
addLog.error(msg, {
|
addLog.error(msg, {
|
||||||
message: error.message,
|
message: msg,
|
||||||
stack: error.stack,
|
stack: error?.stack,
|
||||||
...(error.config && {
|
...(error?.config && {
|
||||||
config: {
|
config: {
|
||||||
headers: error.config.headers,
|
headers: error.config.headers,
|
||||||
url: error.config.url,
|
url: error.config.url,
|
||||||
data: error.config.data
|
data: error.config.data
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
...(error.response && {
|
...(error?.response && {
|
||||||
response: {
|
response: {
|
||||||
status: error.response.status,
|
status: error.response.status,
|
||||||
statusText: error.response.statusText
|
statusText: error.response.statusText
|
||||||
@@ -111,16 +111,16 @@ export const sseErrRes = (res: NextApiResponse, error: any) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addLog.error(`sse error: ${msg}`, {
|
addLog.error(`sse error: ${msg}`, {
|
||||||
message: error.message,
|
message: msg,
|
||||||
stack: error.stack,
|
stack: error?.stack,
|
||||||
...(error.config && {
|
...(error?.config && {
|
||||||
config: {
|
config: {
|
||||||
headers: error.config.headers,
|
headers: error.config.headers,
|
||||||
url: error.config.url,
|
url: error.config.url,
|
||||||
data: error.config.data
|
data: error.config.data
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
...(error.response && {
|
...(error?.response && {
|
||||||
response: {
|
response: {
|
||||||
status: error.response.status,
|
status: error.response.status,
|
||||||
statusText: error.response.statusText
|
statusText: error.response.statusText
|
||||||
|
@@ -1,44 +0,0 @@
|
|||||||
// @ts-ignore
|
|
||||||
import Payment from 'wxpay-v3';
|
|
||||||
|
|
||||||
export const getPayment = () => {
|
|
||||||
try {
|
|
||||||
return new Payment({
|
|
||||||
appid: process.env.WX_APPID,
|
|
||||||
mchid: process.env.WX_MCHID,
|
|
||||||
private_key: process.env.WX_PRIVATE_KEY?.replace(/\\n/g, '\n'),
|
|
||||||
serial_no: process.env.WX_SERIAL_NO,
|
|
||||||
apiv3_private_key: process.env.WX_V3_CODE,
|
|
||||||
notify_url: process.env.WX_NOTIFY_URL
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const nativePay = async (amount: number, payId: string) => {
|
|
||||||
try {
|
|
||||||
const res = await getPayment().native({
|
|
||||||
description: 'Fast GPT 余额充值',
|
|
||||||
out_trade_no: payId,
|
|
||||||
amount: {
|
|
||||||
total: amount
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return JSON.parse(res.data).code_url as string;
|
|
||||||
} catch (error) {
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getPayResult = async (payId: string) => {
|
|
||||||
try {
|
|
||||||
const res = await getPayment().getTransactionsByOutTradeNo({
|
|
||||||
out_trade_no: payId
|
|
||||||
});
|
|
||||||
|
|
||||||
return JSON.parse(res.data);
|
|
||||||
} catch (error) {
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
};
|
|
17
client/src/types/index.d.ts
vendored
17
client/src/types/index.d.ts
vendored
@@ -28,27 +28,13 @@ export type FeConfigsType = {
|
|||||||
scripts?: { [key: string]: string }[];
|
scripts?: { [key: string]: string }[];
|
||||||
};
|
};
|
||||||
export type SystemEnvType = {
|
export type SystemEnvType = {
|
||||||
googleServiceVerKey?: string;
|
pluginBaseUrl?: string;
|
||||||
gitLoginSecret?: string;
|
gitLoginSecret?: string;
|
||||||
vectorMaxProcess: number;
|
vectorMaxProcess: number;
|
||||||
qaMaxProcess: number;
|
qaMaxProcess: number;
|
||||||
pgIvfflatProbe: number;
|
pgIvfflatProbe: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PluginType = {
|
|
||||||
authCode?: {
|
|
||||||
sendUrl: string;
|
|
||||||
authUrl: string;
|
|
||||||
};
|
|
||||||
censor?: {
|
|
||||||
textUrl?: string;
|
|
||||||
};
|
|
||||||
pay?: {
|
|
||||||
getWxQRUrl?: string;
|
|
||||||
getWxQRResult?: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
var mongodb: Mongoose | string | null;
|
var mongodb: Mongoose | string | null;
|
||||||
var pgClient: Pool | null;
|
var pgClient: Pool | null;
|
||||||
@@ -64,7 +50,6 @@ declare global {
|
|||||||
|
|
||||||
var feConfigs: FeConfigsType;
|
var feConfigs: FeConfigsType;
|
||||||
var systemEnv: SystemEnvType;
|
var systemEnv: SystemEnvType;
|
||||||
var systemPlugins: PluginType;
|
|
||||||
var chatModels: ChatModelItemType[];
|
var chatModels: ChatModelItemType[];
|
||||||
var qaModels: QAModelItemType[];
|
var qaModels: QAModelItemType[];
|
||||||
var vectorModels: VectorModelItemType[];
|
var vectorModels: VectorModelItemType[];
|
||||||
|
2
client/src/types/mongoSchema.d.ts
vendored
2
client/src/types/mongoSchema.d.ts
vendored
@@ -142,7 +142,7 @@ export interface PromotionRecordSchema {
|
|||||||
_id: string;
|
_id: string;
|
||||||
userId: string; // 收益人
|
userId: string; // 收益人
|
||||||
objUId?: string; // 目标对象(如果是withdraw则为空)
|
objUId?: string; // 目标对象(如果是withdraw则为空)
|
||||||
type: 'invite' | 'shareModel' | 'withdraw';
|
type: 'register' | 'pay';
|
||||||
createTime: Date; // 记录时间
|
createTime: Date; // 记录时间
|
||||||
amount: number;
|
amount: number;
|
||||||
}
|
}
|
||||||
|
@@ -1,37 +0,0 @@
|
|||||||
import axios from 'axios';
|
|
||||||
import { Obj2Query } from '../tools';
|
|
||||||
|
|
||||||
export const getClientToken = (googleClientVerKey?: string) => {
|
|
||||||
if (!googleClientVerKey || typeof window.grecaptcha === 'undefined' || !window.grecaptcha?.ready)
|
|
||||||
return '';
|
|
||||||
return new Promise<string>((resolve, reject) => {
|
|
||||||
window.grecaptcha.ready(async () => {
|
|
||||||
try {
|
|
||||||
const token = await window.grecaptcha.execute(googleClientVerKey, {
|
|
||||||
action: 'submit'
|
|
||||||
});
|
|
||||||
resolve(token);
|
|
||||||
} catch (error) {
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// service run
|
|
||||||
export const authGoogleToken = async (data: {
|
|
||||||
secret: string;
|
|
||||||
response: string;
|
|
||||||
remoteip?: string;
|
|
||||||
}) => {
|
|
||||||
const res = await axios.post<{
|
|
||||||
score?: number;
|
|
||||||
success: boolean;
|
|
||||||
'error-codes': string[];
|
|
||||||
}>(`https://www.recaptcha.net/recaptcha/api/siteverify?${Obj2Query(data)}`);
|
|
||||||
|
|
||||||
if (res.data.success) {
|
|
||||||
return Promise.resolve('');
|
|
||||||
}
|
|
||||||
return Promise.reject(res?.data?.['error-codes']?.[0] || '非法环境');
|
|
||||||
};
|
|
Reference in New Issue
Block a user