mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 13:03:50 +00:00
* New pay (#2484) * remove sub status * feat: new pay mode * fix: ts * limit
This commit is contained in:
29
packages/global/support/wallet/bill/api.d.ts
vendored
29
packages/global/support/wallet/bill/api.d.ts
vendored
@@ -1,16 +1,25 @@
|
|||||||
|
import { StandardSubLevelEnum, SubModeEnum } from '../sub/constants';
|
||||||
import { BillTypeEnum } from './constants';
|
import { BillTypeEnum } from './constants';
|
||||||
|
|
||||||
export type CreateBillProps = {
|
export type CreateStandPlanBill = {
|
||||||
type: BillTypeEnum;
|
type: BillTypeEnum.standSubPlan;
|
||||||
|
level: `${StandardSubLevelEnum}`;
|
||||||
// balance
|
subMode: `${SubModeEnum}`;
|
||||||
balance?: number; // read
|
|
||||||
|
|
||||||
month?: number;
|
|
||||||
// extra dataset size
|
|
||||||
extraDatasetSize?: number; // 1k
|
|
||||||
extraPoints?: number; // 100w
|
|
||||||
};
|
};
|
||||||
|
type CreateExtractPointsBill = {
|
||||||
|
type: BillTypeEnum.extraPoints;
|
||||||
|
extraPoints: number;
|
||||||
|
};
|
||||||
|
type CreateExtractDatasetBill = {
|
||||||
|
type: BillTypeEnum.extraDatasetSub;
|
||||||
|
extraDatasetSize: number;
|
||||||
|
month: number;
|
||||||
|
};
|
||||||
|
export type CreateBillProps =
|
||||||
|
| CreateStandPlanBill
|
||||||
|
| CreateExtractPointsBill
|
||||||
|
| CreateExtractDatasetBill;
|
||||||
|
|
||||||
export type CreateBillResponse = {
|
export type CreateBillResponse = {
|
||||||
billId: string;
|
billId: string;
|
||||||
codeUrl: string;
|
codeUrl: string;
|
||||||
|
@@ -19,7 +19,6 @@ export type BillSchemaType = {
|
|||||||
month?: number;
|
month?: number;
|
||||||
datasetSize?: number;
|
datasetSize?: number;
|
||||||
extraPoints?: number;
|
extraPoints?: number;
|
||||||
invoice: boolean;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
import { i18nT } from '../../../../web/i18n/utils';
|
||||||
|
|
||||||
export enum SubTypeEnum {
|
export enum SubTypeEnum {
|
||||||
standard = 'standard',
|
standard = 'standard',
|
||||||
extraDatasetSize = 'extraDatasetSize',
|
extraDatasetSize = 'extraDatasetSize',
|
||||||
@@ -19,19 +21,6 @@ export const subTypeMap = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum SubStatusEnum {
|
|
||||||
active = 'active',
|
|
||||||
expired = 'expired'
|
|
||||||
}
|
|
||||||
export const subStatusMap = {
|
|
||||||
[SubStatusEnum.active]: {
|
|
||||||
label: 'support.wallet.subscription.status.active'
|
|
||||||
},
|
|
||||||
[SubStatusEnum.expired]: {
|
|
||||||
label: 'support.wallet.subscription.status.canceled'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export enum SubModeEnum {
|
export enum SubModeEnum {
|
||||||
month = 'month',
|
month = 'month',
|
||||||
year = 'year'
|
year = 'year'
|
||||||
@@ -56,23 +45,28 @@ export enum StandardSubLevelEnum {
|
|||||||
}
|
}
|
||||||
export const standardSubLevelMap = {
|
export const standardSubLevelMap = {
|
||||||
[StandardSubLevelEnum.free]: {
|
[StandardSubLevelEnum.free]: {
|
||||||
label: 'support.wallet.subscription.standardSubLevel.free',
|
label: i18nT('common:support.wallet.subscription.standardSubLevel.free'),
|
||||||
desc: 'support.wallet.subscription.standardSubLevel.free desc'
|
desc: i18nT('common:support.wallet.subscription.standardSubLevel.free desc'),
|
||||||
|
weight: 1
|
||||||
},
|
},
|
||||||
[StandardSubLevelEnum.experience]: {
|
[StandardSubLevelEnum.experience]: {
|
||||||
label: 'support.wallet.subscription.standardSubLevel.experience',
|
label: i18nT('common:support.wallet.subscription.standardSubLevel.experience'),
|
||||||
desc: ''
|
desc: '',
|
||||||
|
weight: 2
|
||||||
},
|
},
|
||||||
[StandardSubLevelEnum.team]: {
|
[StandardSubLevelEnum.team]: {
|
||||||
label: 'support.wallet.subscription.standardSubLevel.team',
|
label: i18nT('common:support.wallet.subscription.standardSubLevel.team'),
|
||||||
desc: ''
|
desc: '',
|
||||||
|
weight: 3
|
||||||
},
|
},
|
||||||
[StandardSubLevelEnum.enterprise]: {
|
[StandardSubLevelEnum.enterprise]: {
|
||||||
label: 'support.wallet.subscription.standardSubLevel.enterprise',
|
label: i18nT('common:support.wallet.subscription.standardSubLevel.enterprise'),
|
||||||
desc: ''
|
desc: '',
|
||||||
|
weight: 4
|
||||||
},
|
},
|
||||||
[StandardSubLevelEnum.custom]: {
|
[StandardSubLevelEnum.custom]: {
|
||||||
label: 'support.wallet.subscription.standardSubLevel.custom',
|
label: i18nT('common:support.wallet.subscription.standardSubLevel.custom'),
|
||||||
desc: ''
|
desc: '',
|
||||||
|
weight: 5
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
9
packages/global/support/wallet/sub/type.d.ts
vendored
9
packages/global/support/wallet/sub/type.d.ts
vendored
@@ -1,4 +1,4 @@
|
|||||||
import { StandardSubLevelEnum, SubModeEnum, SubStatusEnum, SubTypeEnum } from './constants';
|
import { StandardSubLevelEnum, SubModeEnum, SubTypeEnum } from './constants';
|
||||||
|
|
||||||
// Content of plan
|
// Content of plan
|
||||||
export type TeamStandardSubPlanItemType = {
|
export type TeamStandardSubPlanItemType = {
|
||||||
@@ -36,17 +36,14 @@ export type TeamSubSchema = {
|
|||||||
_id: string;
|
_id: string;
|
||||||
teamId: string;
|
teamId: string;
|
||||||
type: `${SubTypeEnum}`;
|
type: `${SubTypeEnum}`;
|
||||||
status: `${SubStatusEnum}`;
|
|
||||||
startTime: Date;
|
startTime: Date;
|
||||||
expiredTime: Date;
|
expiredTime: Date;
|
||||||
price: number;
|
|
||||||
|
|
||||||
currentMode: `${SubModeEnum}`;
|
currentMode: `${SubModeEnum}`;
|
||||||
nextMode: `${SubModeEnum}`;
|
nextMode: `${SubModeEnum}`;
|
||||||
currentSubLevel: `${StandardSubLevelEnum}`;
|
currentSubLevel: StandardSubLevelEnum;
|
||||||
nextSubLevel: `${StandardSubLevelEnum}`;
|
nextSubLevel: StandardSubLevelEnum;
|
||||||
|
|
||||||
pointPrice: number;
|
|
||||||
totalPoints: number;
|
totalPoints: number;
|
||||||
surplusPoints: number;
|
surplusPoints: number;
|
||||||
|
|
||||||
|
@@ -7,10 +7,9 @@ import { connectionMongo, getMongoModel } from '../../../common/mongo';
|
|||||||
const { Schema } = connectionMongo;
|
const { Schema } = connectionMongo;
|
||||||
import { TeamCollectionName } from '@fastgpt/global/support/user/team/constant';
|
import { TeamCollectionName } from '@fastgpt/global/support/user/team/constant';
|
||||||
import {
|
import {
|
||||||
standardSubLevelMap,
|
StandardSubLevelEnum,
|
||||||
subModeMap,
|
SubModeEnum,
|
||||||
subStatusMap,
|
SubTypeEnum
|
||||||
subTypeMap
|
|
||||||
} from '@fastgpt/global/support/wallet/sub/constants';
|
} from '@fastgpt/global/support/wallet/sub/constants';
|
||||||
import type { TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type';
|
import type { TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type';
|
||||||
|
|
||||||
@@ -24,12 +23,7 @@ const SubSchema = new Schema({
|
|||||||
},
|
},
|
||||||
type: {
|
type: {
|
||||||
type: String,
|
type: String,
|
||||||
enum: Object.keys(subTypeMap),
|
enum: Object.values(SubTypeEnum),
|
||||||
required: true
|
|
||||||
},
|
|
||||||
status: {
|
|
||||||
type: String,
|
|
||||||
enum: Object.keys(subStatusMap),
|
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
startTime: {
|
startTime: {
|
||||||
@@ -40,38 +34,29 @@ const SubSchema = new Schema({
|
|||||||
type: Date,
|
type: Date,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
price: {
|
|
||||||
// last sub pay price(total price)
|
|
||||||
type: Number,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
|
|
||||||
// standard sub
|
// standard sub
|
||||||
currentMode: {
|
currentMode: {
|
||||||
type: String,
|
type: String,
|
||||||
enum: Object.keys(subModeMap)
|
enum: Object.values(SubModeEnum)
|
||||||
},
|
},
|
||||||
nextMode: {
|
nextMode: {
|
||||||
type: String,
|
type: String,
|
||||||
enum: Object.keys(subModeMap)
|
enum: Object.values(SubModeEnum)
|
||||||
},
|
},
|
||||||
currentSubLevel: {
|
currentSubLevel: {
|
||||||
type: String,
|
type: String,
|
||||||
enum: Object.keys(standardSubLevelMap)
|
enum: Object.values(StandardSubLevelEnum)
|
||||||
},
|
},
|
||||||
nextSubLevel: {
|
nextSubLevel: {
|
||||||
type: String,
|
type: String,
|
||||||
enum: Object.keys(standardSubLevelMap)
|
enum: Object.values(StandardSubLevelEnum)
|
||||||
},
|
},
|
||||||
|
|
||||||
// stand sub and extra points sub. Plan total points
|
// stand sub and extra points sub. Plan total points
|
||||||
totalPoints: {
|
totalPoints: {
|
||||||
type: Number
|
type: Number
|
||||||
},
|
},
|
||||||
pointPrice: {
|
|
||||||
// stand level point total price
|
|
||||||
type: Number
|
|
||||||
},
|
|
||||||
surplusPoints: {
|
surplusPoints: {
|
||||||
// plan surplus points
|
// plan surplus points
|
||||||
type: Number
|
type: Number
|
||||||
|
@@ -1,26 +1,45 @@
|
|||||||
import {
|
import {
|
||||||
StandardSubLevelEnum,
|
StandardSubLevelEnum,
|
||||||
SubModeEnum,
|
SubModeEnum,
|
||||||
SubStatusEnum,
|
SubTypeEnum,
|
||||||
SubTypeEnum
|
standardSubLevelMap
|
||||||
} from '@fastgpt/global/support/wallet/sub/constants';
|
} from '@fastgpt/global/support/wallet/sub/constants';
|
||||||
import { MongoTeamSub } from './schema';
|
import { MongoTeamSub } from './schema';
|
||||||
import { FeTeamPlanStatusType } from '@fastgpt/global/support/wallet/sub/type.d';
|
import { FeTeamPlanStatusType, TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type.d';
|
||||||
import { getVectorCountByTeamId } from '../../../common/vectorStore/controller';
|
import { getVectorCountByTeamId } from '../../../common/vectorStore/controller';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { ClientSession } from '../../../common/mongo';
|
import { ClientSession } from '../../../common/mongo';
|
||||||
import { addMonths } from 'date-fns';
|
import { addMonths } from 'date-fns';
|
||||||
|
import { readFromSecondary } from '../../../common/mongo/utils';
|
||||||
|
|
||||||
export const getStandardPlans = () => {
|
export const getStandardPlansConfig = () => {
|
||||||
return global?.subPlans?.standard;
|
return global?.subPlans?.standard;
|
||||||
};
|
};
|
||||||
export const getStandardPlan = (level: `${StandardSubLevelEnum}`) => {
|
export const getStandardPlanConfig = (level: `${StandardSubLevelEnum}`) => {
|
||||||
return global.subPlans?.standard?.[level];
|
return global.subPlans?.standard?.[level];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const sortStandPlans = (plans: TeamSubSchema[]) => {
|
||||||
|
return plans.sort(
|
||||||
|
(a, b) =>
|
||||||
|
standardSubLevelMap[b.currentSubLevel].weight - standardSubLevelMap[a.currentSubLevel].weight
|
||||||
|
);
|
||||||
|
};
|
||||||
export const getTeamStandPlan = async ({ teamId }: { teamId: string }) => {
|
export const getTeamStandPlan = async ({ teamId }: { teamId: string }) => {
|
||||||
|
const plans = await MongoTeamSub.find(
|
||||||
|
{
|
||||||
|
teamId,
|
||||||
|
type: SubTypeEnum.standard
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
{
|
||||||
|
...readFromSecondary
|
||||||
|
}
|
||||||
|
);
|
||||||
|
sortStandPlans(plans);
|
||||||
|
|
||||||
const standardPlans = global.subPlans?.standard;
|
const standardPlans = global.subPlans?.standard;
|
||||||
const standard = await MongoTeamSub.findOne({ teamId, type: SubTypeEnum.standard }).lean();
|
const standard = plans[0];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
[SubTypeEnum.standard]: standard,
|
[SubTypeEnum.standard]: standard,
|
||||||
@@ -38,12 +57,11 @@ export const initTeamStandardPlan2Free = async ({
|
|||||||
teamId: string;
|
teamId: string;
|
||||||
session?: ClientSession;
|
session?: ClientSession;
|
||||||
}) => {
|
}) => {
|
||||||
const freePoints = global?.subPlans?.standard?.free?.totalPoints || 100;
|
const freePoints = global?.subPlans?.standard?.[StandardSubLevelEnum.free]?.totalPoints || 100;
|
||||||
|
|
||||||
const teamStandardSub = await MongoTeamSub.findOne({ teamId, type: SubTypeEnum.standard });
|
const teamStandardSub = await MongoTeamSub.findOne({ teamId, type: SubTypeEnum.standard });
|
||||||
|
|
||||||
if (teamStandardSub) {
|
if (teamStandardSub) {
|
||||||
teamStandardSub.status = SubStatusEnum.active;
|
|
||||||
teamStandardSub.currentMode = SubModeEnum.month;
|
teamStandardSub.currentMode = SubModeEnum.month;
|
||||||
teamStandardSub.nextMode = SubModeEnum.month;
|
teamStandardSub.nextMode = SubModeEnum.month;
|
||||||
teamStandardSub.startTime = new Date();
|
teamStandardSub.startTime = new Date();
|
||||||
@@ -52,9 +70,6 @@ export const initTeamStandardPlan2Free = async ({
|
|||||||
teamStandardSub.currentSubLevel = StandardSubLevelEnum.free;
|
teamStandardSub.currentSubLevel = StandardSubLevelEnum.free;
|
||||||
teamStandardSub.nextSubLevel = StandardSubLevelEnum.free;
|
teamStandardSub.nextSubLevel = StandardSubLevelEnum.free;
|
||||||
|
|
||||||
teamStandardSub.price = 0;
|
|
||||||
teamStandardSub.pointPrice = 0;
|
|
||||||
|
|
||||||
teamStandardSub.totalPoints = freePoints;
|
teamStandardSub.totalPoints = freePoints;
|
||||||
teamStandardSub.surplusPoints =
|
teamStandardSub.surplusPoints =
|
||||||
teamStandardSub.surplusPoints && teamStandardSub.surplusPoints < 0
|
teamStandardSub.surplusPoints && teamStandardSub.surplusPoints < 0
|
||||||
@@ -68,13 +83,10 @@ export const initTeamStandardPlan2Free = async ({
|
|||||||
{
|
{
|
||||||
teamId,
|
teamId,
|
||||||
type: SubTypeEnum.standard,
|
type: SubTypeEnum.standard,
|
||||||
status: SubStatusEnum.active,
|
|
||||||
currentMode: SubModeEnum.month,
|
currentMode: SubModeEnum.month,
|
||||||
nextMode: SubModeEnum.month,
|
nextMode: SubModeEnum.month,
|
||||||
startTime: new Date(),
|
startTime: new Date(),
|
||||||
expiredTime: addMonths(new Date(), 1),
|
expiredTime: addMonths(new Date(), 1),
|
||||||
price: 0,
|
|
||||||
pointPrice: 0,
|
|
||||||
|
|
||||||
currentSubLevel: StandardSubLevelEnum.free,
|
currentSubLevel: StandardSubLevelEnum.free,
|
||||||
nextSubLevel: StandardSubLevelEnum.free,
|
nextSubLevel: StandardSubLevelEnum.free,
|
||||||
@@ -94,21 +106,27 @@ export const getTeamPlanStatus = async ({
|
|||||||
}): Promise<FeTeamPlanStatusType> => {
|
}): Promise<FeTeamPlanStatusType> => {
|
||||||
const standardPlans = global.subPlans?.standard;
|
const standardPlans = global.subPlans?.standard;
|
||||||
|
|
||||||
|
/* Get all plans and datasetSize */
|
||||||
const [plans, usedDatasetSize] = await Promise.all([
|
const [plans, usedDatasetSize] = await Promise.all([
|
||||||
MongoTeamSub.find({ teamId }).lean(),
|
MongoTeamSub.find({ teamId }).lean(),
|
||||||
getVectorCountByTeamId(teamId)
|
getVectorCountByTeamId(teamId)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const standard = plans.find((plan) => plan.type === SubTypeEnum.standard);
|
/* Get all standardPlans and active standardPlan */
|
||||||
|
const teamStandardPlans = sortStandPlans(
|
||||||
|
plans.filter((plan) => plan.type === SubTypeEnum.standard)
|
||||||
|
);
|
||||||
|
const standardPlan = teamStandardPlans[0];
|
||||||
|
|
||||||
const extraDatasetSize = plans.filter((plan) => plan.type === SubTypeEnum.extraDatasetSize);
|
const extraDatasetSize = plans.filter((plan) => plan.type === SubTypeEnum.extraDatasetSize);
|
||||||
const extraPoints = plans.filter((plan) => plan.type === SubTypeEnum.extraPoints);
|
const extraPoints = plans.filter((plan) => plan.type === SubTypeEnum.extraPoints);
|
||||||
|
|
||||||
// Free user, first login after expiration. The free subscription plan will be reset
|
// Free user, first login after expiration. The free subscription plan will be reset
|
||||||
if (
|
if (
|
||||||
standard &&
|
standardPlan &&
|
||||||
standard.expiredTime &&
|
standardPlan.expiredTime &&
|
||||||
standard.currentSubLevel === StandardSubLevelEnum.free &&
|
standardPlan.currentSubLevel === StandardSubLevelEnum.free &&
|
||||||
dayjs(standard.expiredTime).isBefore(new Date())
|
dayjs(standardPlan.expiredTime).isBefore(new Date())
|
||||||
) {
|
) {
|
||||||
console.log('Init free stand plan', { teamId });
|
console.log('Init free stand plan', { teamId });
|
||||||
await initTeamStandardPlan2Free({ teamId });
|
await initTeamStandardPlan2Free({ teamId });
|
||||||
@@ -116,26 +134,26 @@ export const getTeamPlanStatus = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const totalPoints = standardPlans
|
const totalPoints = standardPlans
|
||||||
? (standard?.totalPoints || 0) +
|
? (standardPlan?.totalPoints || 0) +
|
||||||
extraPoints.reduce((acc, cur) => acc + (cur.totalPoints || 0), 0)
|
extraPoints.reduce((acc, cur) => acc + (cur.totalPoints || 0), 0)
|
||||||
: Infinity;
|
: Infinity;
|
||||||
const surplusPoints =
|
const surplusPoints =
|
||||||
(standard?.surplusPoints || 0) +
|
(standardPlan?.surplusPoints || 0) +
|
||||||
extraPoints.reduce((acc, cur) => acc + (cur.surplusPoints || 0), 0);
|
extraPoints.reduce((acc, cur) => acc + (cur.surplusPoints || 0), 0);
|
||||||
|
|
||||||
const standardMaxDatasetSize =
|
const standardMaxDatasetSize =
|
||||||
standard?.currentSubLevel && standardPlans
|
standardPlan?.currentSubLevel && standardPlans
|
||||||
? standardPlans[standard.currentSubLevel]?.maxDatasetSize || Infinity
|
? standardPlans[standardPlan.currentSubLevel]?.maxDatasetSize || Infinity
|
||||||
: Infinity;
|
: Infinity;
|
||||||
const totalDatasetSize =
|
const totalDatasetSize =
|
||||||
standardMaxDatasetSize +
|
standardMaxDatasetSize +
|
||||||
extraDatasetSize.reduce((acc, cur) => acc + (cur.currentExtraDatasetSize || 0), 0);
|
extraDatasetSize.reduce((acc, cur) => acc + (cur.currentExtraDatasetSize || 0), 0);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
[SubTypeEnum.standard]: standard,
|
[SubTypeEnum.standard]: standardPlan,
|
||||||
standardConstants:
|
standardConstants:
|
||||||
standard?.currentSubLevel && standardPlans
|
standardPlan?.currentSubLevel && standardPlans
|
||||||
? standardPlans[standard.currentSubLevel]
|
? standardPlans[standardPlan.currentSubLevel]
|
||||||
: undefined,
|
: undefined,
|
||||||
|
|
||||||
totalPoints,
|
totalPoints,
|
||||||
|
@@ -1331,7 +1331,7 @@
|
|||||||
"FAQ": "Frequently asked questions",
|
"FAQ": "Frequently asked questions",
|
||||||
"Month amount": "Months",
|
"Month amount": "Months",
|
||||||
"Next plan": "Future plan",
|
"Next plan": "Future plan",
|
||||||
"Nonsupport": "Unable to switch",
|
"Nonsupport": "No purchase required",
|
||||||
"Stand plan level": "Subscription plan",
|
"Stand plan level": "Subscription plan",
|
||||||
"Standard update fail": "Failed to modify subscription plan",
|
"Standard update fail": "Failed to modify subscription plan",
|
||||||
"Standard update success": "Subscription plan change successful!",
|
"Standard update success": "Subscription plan change successful!",
|
||||||
@@ -1360,6 +1360,7 @@
|
|||||||
"point": "integral",
|
"point": "integral",
|
||||||
"rerank": "Rerank",
|
"rerank": "Rerank",
|
||||||
"standardSubLevel": {
|
"standardSubLevel": {
|
||||||
|
"custom": "Customized version",
|
||||||
"enterprise": "Enterprise edition",
|
"enterprise": "Enterprise edition",
|
||||||
"experience": "Experience edition",
|
"experience": "Experience edition",
|
||||||
"free": "Free edition",
|
"free": "Free edition",
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
{
|
{
|
||||||
"bill": {
|
"bill": {
|
||||||
"not_need_invoice": "Balance payment, unable to issue invoice"
|
"buy_standard_plan_success": "Package purchased successfully",
|
||||||
|
"not_need_invoice": "Balance payment, unable to issue invoice",
|
||||||
|
"renew_plan": "Renewal package"
|
||||||
},
|
},
|
||||||
"bind_inform_account_error": "Abnormal binding notification account",
|
"bind_inform_account_error": "Abnormal binding notification account",
|
||||||
"bind_inform_account_success": "Binding notification account successful",
|
"bind_inform_account_success": "Binding notification account successful",
|
||||||
|
@@ -1116,7 +1116,7 @@
|
|||||||
"old_package_price": "旧套餐余额",
|
"old_package_price": "旧套餐余额",
|
||||||
"other": "其他金额,请取整数",
|
"other": "其他金额,请取整数",
|
||||||
"to_recharge": "余额不足,去充值",
|
"to_recharge": "余额不足,去充值",
|
||||||
"wechat": "请微信扫码支付: {{price}}元,请勿关闭页面",
|
"wechat": "请微信扫码支付: {{price}}元\n请勿关闭页面",
|
||||||
"yuan": "{{amount}}元"
|
"yuan": "{{amount}}元"
|
||||||
},
|
},
|
||||||
"permission": {
|
"permission": {
|
||||||
@@ -1331,7 +1331,7 @@
|
|||||||
"FAQ": "常见问题",
|
"FAQ": "常见问题",
|
||||||
"Month amount": "月数",
|
"Month amount": "月数",
|
||||||
"Next plan": "未来套餐",
|
"Next plan": "未来套餐",
|
||||||
"Nonsupport": "无法切换",
|
"Nonsupport": "无需购买",
|
||||||
"Stand plan level": "订阅套餐",
|
"Stand plan level": "订阅套餐",
|
||||||
"Standard update fail": "修改订阅套餐异常",
|
"Standard update fail": "修改订阅套餐异常",
|
||||||
"Standard update success": "变更订阅套餐成功!",
|
"Standard update success": "变更订阅套餐成功!",
|
||||||
@@ -1360,6 +1360,7 @@
|
|||||||
"point": "积分",
|
"point": "积分",
|
||||||
"rerank": "检索结果重排",
|
"rerank": "检索结果重排",
|
||||||
"standardSubLevel": {
|
"standardSubLevel": {
|
||||||
|
"custom": "自定义版",
|
||||||
"enterprise": "企业版",
|
"enterprise": "企业版",
|
||||||
"experience": "体验版",
|
"experience": "体验版",
|
||||||
"free": "免费版",
|
"free": "免费版",
|
||||||
|
@@ -11,7 +11,9 @@
|
|||||||
"use_balance_hint": "由于系统升级,原“自动续费从余额扣款”模式取消,余额充值入口关闭。您的余额可用于购买积分",
|
"use_balance_hint": "由于系统升级,原“自动续费从余额扣款”模式取消,余额充值入口关闭。您的余额可用于购买积分",
|
||||||
"contact_customer_service": "联系客服",
|
"contact_customer_service": "联系客服",
|
||||||
"convert_success": "兑换成功",
|
"convert_success": "兑换成功",
|
||||||
"convert_error": "兑换失败"
|
"convert_error": "兑换失败",
|
||||||
|
"buy_standard_plan_success": "购买套餐成功",
|
||||||
|
"renew_plan": "续费套餐"
|
||||||
},
|
},
|
||||||
"bind_inform_account_error": "绑定通知账号异常",
|
"bind_inform_account_error": "绑定通知账号异常",
|
||||||
"bind_inform_account_success": "绑定通知账号成功",
|
"bind_inform_account_success": "绑定通知账号成功",
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { Box, ModalBody, ModalFooter } from '@chakra-ui/react';
|
import { Box, ModalBody } from '@chakra-ui/react';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { checkBalancePayResult } from '@/web/support/wallet/bill/api';
|
import { checkBalancePayResult } from '@/web/support/wallet/bill/api';
|
||||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
@@ -15,11 +15,12 @@ export type QRPayProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const QRCodePayModal = ({
|
const QRCodePayModal = ({
|
||||||
|
tip,
|
||||||
readPrice,
|
readPrice,
|
||||||
codeUrl,
|
codeUrl,
|
||||||
billId,
|
billId,
|
||||||
onSuccess
|
onSuccess
|
||||||
}: QRPayProps & { onSuccess?: () => any }) => {
|
}: QRPayProps & { tip?: string; onSuccess?: () => any }) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
@@ -72,11 +73,13 @@ const QRCodePayModal = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<MyModal isOpen title={t('common:user.Pay')} iconSrc="/imgs/modal/pay.svg">
|
<MyModal isOpen title={t('common:user.Pay')} iconSrc="/imgs/modal/pay.svg">
|
||||||
<ModalBody textAlign={'center'}>
|
<ModalBody textAlign={'center'} py={6} whiteSpace={'pre'}>
|
||||||
<Box mb={3}>{t('common:pay.wechat', { price: readPrice })}</Box>
|
{tip && <Box mb={3}>{tip}</Box>}
|
||||||
<Box id={'payQRCode'} display={'inline-block'} h={'128px'}></Box>
|
<Box id={'payQRCode'} display={'inline-block'} h={'128px'}></Box>
|
||||||
|
<Box mt={3} textAlign={'center'}>
|
||||||
|
{t('common:pay.wechat', { price: readPrice })}
|
||||||
|
</Box>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter />
|
|
||||||
</MyModal>
|
</MyModal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -1,116 +0,0 @@
|
|||||||
import React, { useState, useCallback, useMemo } from 'react';
|
|
||||||
import { ModalFooter, ModalBody, Button, Input, Box, Grid, Link } from '@chakra-ui/react';
|
|
||||||
import { getWxPayQRCode } from '@/web/support/wallet/bill/api';
|
|
||||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
|
||||||
import { useRouter } from 'next/router';
|
|
||||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
|
||||||
import { useTranslation } from 'next-i18next';
|
|
||||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
|
||||||
import { BillTypeEnum } from '@fastgpt/global/support/wallet/bill/constants';
|
|
||||||
import QRCodePayModal, { type QRPayProps } from '@/components/support/wallet/QRCodePayModal';
|
|
||||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
|
||||||
import { EXTRA_PLAN_CARD_ROUTE } from '@/web/support/wallet/sub/constants';
|
|
||||||
|
|
||||||
const PayModal = ({
|
|
||||||
onClose,
|
|
||||||
defaultValue,
|
|
||||||
onSuccess
|
|
||||||
}: {
|
|
||||||
defaultValue?: number;
|
|
||||||
onClose: () => void;
|
|
||||||
onSuccess?: () => any;
|
|
||||||
}) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { toast } = useToast();
|
|
||||||
const { subPlans } = useSystemStore();
|
|
||||||
const [inputVal, setInputVal] = useState<number | undefined>(defaultValue);
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const [qrPayData, setQRPayData] = useState<QRPayProps>();
|
|
||||||
const handleClickPay = useCallback(async () => {
|
|
||||||
if (!inputVal || inputVal <= 0 || isNaN(+inputVal)) return;
|
|
||||||
setLoading(true);
|
|
||||||
try {
|
|
||||||
// 获取支付二维码
|
|
||||||
const res = await getWxPayQRCode({
|
|
||||||
type: BillTypeEnum.balance,
|
|
||||||
balance: inputVal
|
|
||||||
});
|
|
||||||
setQRPayData({
|
|
||||||
readPrice: res.readPrice,
|
|
||||||
codeUrl: res.codeUrl,
|
|
||||||
billId: res.billId
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
toast({
|
|
||||||
title: getErrText(err),
|
|
||||||
status: 'error'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setLoading(false);
|
|
||||||
}, [inputVal, toast]);
|
|
||||||
|
|
||||||
const payList = useMemo(() => {
|
|
||||||
const list = Object.values(subPlans?.standard || {});
|
|
||||||
const priceList = list.map((item) => item.price);
|
|
||||||
return priceList.concat(priceList.map((item) => item * 10)).filter(Boolean);
|
|
||||||
}, [subPlans?.standard]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MyModal
|
|
||||||
isOpen={true}
|
|
||||||
onClose={onClose}
|
|
||||||
title={t('common:user.Pay')}
|
|
||||||
iconSrc="/imgs/modal/pay.svg"
|
|
||||||
>
|
|
||||||
<ModalBody px={0} display={'flex'} flexDirection={'column'}>
|
|
||||||
<Box px={6} fontSize={'sm'} mb={2} py={2} maxW={'400px'}>
|
|
||||||
该余额仅用于自动续费标准套餐。如需购买额外套餐,可
|
|
||||||
<Link href={EXTRA_PLAN_CARD_ROUTE} color={'primary.600'} textDecoration={'underline'}>
|
|
||||||
直接下单
|
|
||||||
</Link>
|
|
||||||
,无需充值余额。
|
|
||||||
</Box>
|
|
||||||
<Grid gridTemplateColumns={'repeat(3,1fr)'} gridGap={5} mb={4} px={6}>
|
|
||||||
{payList.map((item) => (
|
|
||||||
<Button
|
|
||||||
key={item}
|
|
||||||
variant={item === inputVal ? 'solid' : 'outline'}
|
|
||||||
onClick={() => setInputVal(item)}
|
|
||||||
>
|
|
||||||
{t('common:pay.yuan', { amount: item })}
|
|
||||||
</Button>
|
|
||||||
))}
|
|
||||||
</Grid>
|
|
||||||
<Box px={6}>
|
|
||||||
<Input
|
|
||||||
value={inputVal}
|
|
||||||
type={'number'}
|
|
||||||
step={1}
|
|
||||||
placeholder={t('common:pay.other')}
|
|
||||||
onChange={(e) => {
|
|
||||||
setInputVal(Math.floor(+e.target.value));
|
|
||||||
}}
|
|
||||||
></Input>
|
|
||||||
</Box>
|
|
||||||
</ModalBody>
|
|
||||||
|
|
||||||
<ModalFooter>
|
|
||||||
<Button variant={'whiteBase'} onClick={onClose}>
|
|
||||||
{t('common:common.Close')}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
ml={3}
|
|
||||||
isLoading={loading}
|
|
||||||
isDisabled={!inputVal || inputVal === 0}
|
|
||||||
onClick={handleClickPay}
|
|
||||||
>
|
|
||||||
{t('common:pay.get_pay_QR')}
|
|
||||||
</Button>
|
|
||||||
</ModalFooter>
|
|
||||||
|
|
||||||
{!!qrPayData && <QRCodePayModal {...qrPayData} onSuccess={onSuccess} />}
|
|
||||||
</MyModal>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default PayModal;
|
|
@@ -1,28 +1,17 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
import { jsonRes } from '@fastgpt/service/common/response';
|
|
||||||
import { connectToDatabase } from '@/service/mongo';
|
|
||||||
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||||
import { FeTeamPlanStatusType } from '@fastgpt/global/support/wallet/sub/type';
|
|
||||||
import { getTeamPlanStatus } from '@fastgpt/service/support/wallet/sub/utils';
|
import { getTeamPlanStatus } from '@fastgpt/service/support/wallet/sub/utils';
|
||||||
|
import { NextAPI } from '@/service/middleware/entry';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
const { teamId } = await authCert({
|
||||||
await connectToDatabase();
|
req,
|
||||||
|
authToken: true
|
||||||
|
});
|
||||||
|
|
||||||
const { teamId } = await authCert({
|
return getTeamPlanStatus({
|
||||||
req,
|
teamId
|
||||||
authToken: true
|
});
|
||||||
});
|
|
||||||
|
|
||||||
jsonRes<FeTeamPlanStatusType>(res, {
|
|
||||||
data: await getTeamPlanStatus({
|
|
||||||
teamId
|
|
||||||
})
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
jsonRes(res, {
|
|
||||||
code: 500,
|
|
||||||
error: err
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default NextAPI(handler);
|
||||||
|
@@ -123,6 +123,7 @@ const NodeTemplatesModal = ({ isOpen, onClose }: ModuleTemplateListProps) => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
manual: false,
|
manual: false,
|
||||||
|
throttleWait: 100,
|
||||||
refreshDeps: [basicNodeTemplates, nodeList, hasToolNode, templateType]
|
refreshDeps: [basicNodeTemplates, nodeList, hasToolNode, templateType]
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@@ -1,33 +1,21 @@
|
|||||||
import React, { useMemo, useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
import { Box, Button, Flex, Grid, ModalBody, ModalFooter } from '@chakra-ui/react';
|
import { Box, Button, Flex, Grid } from '@chakra-ui/react';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { StandardSubLevelEnum, SubModeEnum } from '@fastgpt/global/support/wallet/sub/constants';
|
import { StandardSubLevelEnum, SubModeEnum } from '@fastgpt/global/support/wallet/sub/constants';
|
||||||
import { postCheckStandardSub, postUpdateStandardSub } from '@/web/support/wallet/sub/api';
|
|
||||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||||
import { standardSubLevelMap } from '@fastgpt/global/support/wallet/sub/constants';
|
import { standardSubLevelMap } from '@fastgpt/global/support/wallet/sub/constants';
|
||||||
import { StandardSubPlanParams } from '@fastgpt/global/support/wallet/sub/api';
|
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||||
import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
|
||||||
import { StandardSubPlanUpdateResponse } from '@fastgpt/global/support/wallet/sub/api.d';
|
|
||||||
import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/usage/tools';
|
|
||||||
import { TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type';
|
import { TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type';
|
||||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
|
||||||
import QRCodePayModal, { type QRPayProps } from '@/components/support/wallet/QRCodePayModal';
|
import QRCodePayModal, { type QRPayProps } from '@/components/support/wallet/QRCodePayModal';
|
||||||
import { getWxPayQRCode } from '@/web/support/wallet/bill/api';
|
import { getWxPayQRCode } from '@/web/support/wallet/bill/api';
|
||||||
import { BillTypeEnum } from '@fastgpt/global/support/wallet/bill/constants';
|
import { BillTypeEnum } from '@fastgpt/global/support/wallet/bill/constants';
|
||||||
import StandardPlanContentList from '@/components/support/wallet/StandardPlanContentList';
|
import StandardPlanContentList from '@/components/support/wallet/StandardPlanContentList';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
type ConfirmPayModalProps = {
|
|
||||||
teamBalance: number;
|
|
||||||
totalPrice: number;
|
|
||||||
payPrice: number;
|
|
||||||
|
|
||||||
planProps: StandardSubPlanParams;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Standard = ({
|
const Standard = ({
|
||||||
standardPlan,
|
standardPlan: myStandardPlan,
|
||||||
refetchTeamSubPlan
|
refetchTeamSubPlan
|
||||||
}: {
|
}: {
|
||||||
standardPlan?: TeamSubSchema;
|
standardPlan?: TeamSubSchema;
|
||||||
@@ -35,8 +23,9 @@ const Standard = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const { toast } = useToast();
|
||||||
|
|
||||||
const { subPlans, feConfigs } = useSystemStore();
|
const { subPlans, feConfigs } = useSystemStore();
|
||||||
const [confirmPayData, setConfirmPayData] = useState<ConfirmPayModalProps>();
|
|
||||||
const [selectSubMode, setSelectSubMode] = useState<`${SubModeEnum}`>(SubModeEnum.month);
|
const [selectSubMode, setSelectSubMode] = useState<`${SubModeEnum}`>(SubModeEnum.month);
|
||||||
|
|
||||||
const standardSubList = useMemo(() => {
|
const standardSubList = useMemo(() => {
|
||||||
@@ -62,37 +51,17 @@ const Standard = ({
|
|||||||
: [];
|
: [];
|
||||||
}, [subPlans?.standard, selectSubMode]);
|
}, [subPlans?.standard, selectSubMode]);
|
||||||
|
|
||||||
const { runAsync: onclickUpdateStandardPlan, loading: isUpdatingStandardPlan } = useRequest2(
|
// Pay code
|
||||||
postUpdateStandardSub,
|
const [qrPayData, setQRPayData] = useState<QRPayProps>();
|
||||||
{
|
|
||||||
onSuccess() {
|
|
||||||
refetchTeamSubPlan();
|
|
||||||
router.reload();
|
|
||||||
},
|
|
||||||
successToast: t('common:support.wallet.subscription.Standard update success'),
|
|
||||||
errorToast: t('common:support.wallet.subscription.Standard update fail')
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const { mutate: onclickPreCheckStandPlan, isLoading: isCheckingStandardPlan } = useRequest({
|
/* Get pay code */
|
||||||
mutationFn: (data: StandardSubPlanParams) => postCheckStandardSub(data),
|
const { runAsync: onPay, loading: isLoading } = useRequest2(getWxPayQRCode, {
|
||||||
onSuccess(res: StandardSubPlanUpdateResponse) {
|
onSuccess(res) {
|
||||||
if (res.payPrice === undefined) {
|
setQRPayData({
|
||||||
onclickUpdateStandardPlan({
|
readPrice: res.readPrice,
|
||||||
level: res.nextSubLevel,
|
codeUrl: res.codeUrl,
|
||||||
mode: res.nextMode
|
billId: res.billId
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
setConfirmPayData({
|
|
||||||
teamBalance: res.teamBalance,
|
|
||||||
totalPrice: res.planPrice,
|
|
||||||
payPrice: res.payPrice,
|
|
||||||
planProps: {
|
|
||||||
level: res.nextSubLevel,
|
|
||||||
mode: res.nextMode
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -136,9 +105,7 @@ const Standard = ({
|
|||||||
minH={'550px'}
|
minH={'550px'}
|
||||||
>
|
>
|
||||||
{standardSubList.map((item) => {
|
{standardSubList.map((item) => {
|
||||||
const isCurrentPlan =
|
const isCurrentPlan = item.level === myStandardPlan?.currentSubLevel;
|
||||||
item.level === standardPlan?.currentSubLevel &&
|
|
||||||
selectSubMode === standardPlan?.currentMode;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
@@ -158,7 +125,7 @@ const Standard = ({
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Box fontSize={'md'} fontWeight={'500'}>
|
<Box fontSize={'md'} fontWeight={'500'}>
|
||||||
{t(item.label as any)}
|
{t(item.label)}
|
||||||
</Box>
|
</Box>
|
||||||
<Box fontSize={['32px', '42px']} fontWeight={'bold'}>
|
<Box fontSize={['32px', '42px']} fontWeight={'bold'}>
|
||||||
¥{item.price}
|
¥{item.price}
|
||||||
@@ -166,46 +133,44 @@ const Standard = ({
|
|||||||
<Box color={'myGray.500'} h={'40px'} fontSize={'xs'}>
|
<Box color={'myGray.500'} h={'40px'} fontSize={'xs'}>
|
||||||
{t(item.desc as any, { title: feConfigs?.systemTitle })}
|
{t(item.desc as any, { title: feConfigs?.systemTitle })}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
{/* Button */}
|
||||||
{(() => {
|
{(() => {
|
||||||
if (
|
if (item.level === StandardSubLevelEnum.free) {
|
||||||
item.level === StandardSubLevelEnum.free &&
|
|
||||||
selectSubMode === SubModeEnum.year
|
|
||||||
) {
|
|
||||||
return (
|
return (
|
||||||
<Button isDisabled mt={4} mb={6} w={'100%'} variant={'solid'}>
|
<Button isDisabled mt={4} mb={6} w={'100%'} variant={'solid'}>
|
||||||
{t('common:support.wallet.subscription.Nonsupport')}
|
{t('common:support.wallet.subscription.Nonsupport')}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (
|
// feature:
|
||||||
item.level === standardPlan?.nextSubLevel &&
|
// if (
|
||||||
selectSubMode === standardPlan?.nextMode
|
// item.level === myStandardPlan?.nextSubLevel &&
|
||||||
) {
|
// selectSubMode === myStandardPlan?.nextMode
|
||||||
return (
|
// ) {
|
||||||
<Button mt={4} mb={6} w={'100%'} variant={'whiteBase'} isDisabled>
|
// return (
|
||||||
{t('common:support.wallet.subscription.Next plan')}
|
// <Button mt={4} mb={6} w={'100%'} variant={'whiteBase'} isDisabled>
|
||||||
</Button>
|
// {t('common:support.wallet.subscription.Next plan')}
|
||||||
);
|
// </Button>
|
||||||
}
|
// );
|
||||||
|
// }
|
||||||
if (isCurrentPlan) {
|
if (isCurrentPlan) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
mt={4}
|
mt={4}
|
||||||
mb={6}
|
mb={6}
|
||||||
w={'100%'}
|
w={'100%'}
|
||||||
variant={'whiteBase'}
|
variant={'primary'}
|
||||||
isDisabled={
|
isLoading={isLoading}
|
||||||
item.level === standardPlan?.nextSubLevel &&
|
onClick={() => {
|
||||||
selectSubMode === standardPlan?.nextMode
|
onPay({
|
||||||
}
|
type: BillTypeEnum.standSubPlan,
|
||||||
onClick={() =>
|
|
||||||
onclickPreCheckStandPlan({
|
|
||||||
level: item.level,
|
level: item.level,
|
||||||
mode: selectSubMode
|
subMode: selectSubMode
|
||||||
})
|
});
|
||||||
}
|
}}
|
||||||
>
|
>
|
||||||
{t('common:support.wallet.subscription.Current plan')}
|
{t('user:bill.renew_plan')}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -216,11 +181,12 @@ const Standard = ({
|
|||||||
mb={6}
|
mb={6}
|
||||||
w={'100%'}
|
w={'100%'}
|
||||||
variant={'primaryGhost'}
|
variant={'primaryGhost'}
|
||||||
isLoading={isUpdatingStandardPlan || isCheckingStandardPlan}
|
isLoading={isLoading}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
onclickPreCheckStandPlan({
|
onPay({
|
||||||
|
type: BillTypeEnum.standSubPlan,
|
||||||
level: item.level,
|
level: item.level,
|
||||||
mode: selectSubMode
|
subMode: selectSubMode
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -236,13 +202,7 @@ const Standard = ({
|
|||||||
})}
|
})}
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{!!confirmPayData && (
|
{!!qrPayData && <QRCodePayModal tip="您正在购买订阅套餐" {...qrPayData} />}
|
||||||
<ConfirmPayModal
|
|
||||||
{...confirmPayData}
|
|
||||||
onClose={() => setConfirmPayData(undefined)}
|
|
||||||
onConfirmPay={() => onclickUpdateStandardPlan(confirmPayData.planProps)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -301,100 +261,3 @@ const RowTabs = ({
|
|||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const ConfirmPayModal = ({
|
|
||||||
teamBalance,
|
|
||||||
totalPrice,
|
|
||||||
payPrice,
|
|
||||||
onClose,
|
|
||||||
onConfirmPay
|
|
||||||
}: ConfirmPayModalProps & { onClose: () => void; onConfirmPay: () => void }) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const [qrPayData, setQRPayData] = useState<QRPayProps>();
|
|
||||||
|
|
||||||
const formatPayPrice = Math.ceil(formatStorePrice2Read(payPrice));
|
|
||||||
const formatTeamBalance = Math.floor(formatStorePrice2Read(teamBalance));
|
|
||||||
|
|
||||||
const { mutate: handleClickPay, isLoading } = useRequest({
|
|
||||||
mutationFn: async (amount: number) => {
|
|
||||||
// 获取支付二维码
|
|
||||||
return getWxPayQRCode({
|
|
||||||
type: BillTypeEnum.balance,
|
|
||||||
balance: amount
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onSuccess(res) {
|
|
||||||
setQRPayData({
|
|
||||||
readPrice: res.readPrice,
|
|
||||||
codeUrl: res.codeUrl,
|
|
||||||
billId: res.billId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const { runAsync: onPay, loading: onPaying } = useRequest2(async () => onConfirmPay());
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MyModal
|
|
||||||
isOpen
|
|
||||||
iconSrc="modal/confirmPay"
|
|
||||||
title={t('common:support.wallet.Confirm pay')}
|
|
||||||
onClose={onClose}
|
|
||||||
>
|
|
||||||
<ModalBody py={5} px={9}>
|
|
||||||
<Flex>
|
|
||||||
<Box flex={'0 0 100px'}>{t('common:pay.new_package_price')}</Box>
|
|
||||||
<Box>{t('common:pay.yuan', { amount: formatStorePrice2Read(totalPrice) })}</Box>
|
|
||||||
</Flex>
|
|
||||||
<Flex mt={6}>
|
|
||||||
<Box flex={'0 0 100px'}>{t('common:pay.old_package_price')}</Box>
|
|
||||||
<Box>
|
|
||||||
{t('common:pay.yuan', {
|
|
||||||
amount: Math.floor(formatStorePrice2Read(totalPrice - payPrice))
|
|
||||||
})}
|
|
||||||
</Box>
|
|
||||||
</Flex>
|
|
||||||
<Flex mt={6}>
|
|
||||||
<Box flex={'0 0 100px'}>{t('common:pay.need_to_pay')}</Box>
|
|
||||||
<Box>
|
|
||||||
{t('common:pay.yuan', {
|
|
||||||
amount: formatPayPrice
|
|
||||||
})}
|
|
||||||
</Box>
|
|
||||||
</Flex>
|
|
||||||
</ModalBody>
|
|
||||||
<ModalFooter
|
|
||||||
borderTopWidth={'1px'}
|
|
||||||
borderTopColor={'borderColor.base'}
|
|
||||||
mx={9}
|
|
||||||
justifyContent={'flex-start'}
|
|
||||||
px={0}
|
|
||||||
>
|
|
||||||
<Box>{t('common:pay.balance') + ': '}</Box>
|
|
||||||
<Box ml={2} flex={1}>
|
|
||||||
{t('common:pay.yuan', {
|
|
||||||
amount: formatTeamBalance
|
|
||||||
})}
|
|
||||||
</Box>
|
|
||||||
{teamBalance >= payPrice ? (
|
|
||||||
<Button isLoading={onPaying} size={'sm'} onClick={onPay}>
|
|
||||||
{t('common:pay.confirm_pay')}
|
|
||||||
</Button>
|
|
||||||
) : (
|
|
||||||
<Button
|
|
||||||
size={'sm'}
|
|
||||||
isLoading={isLoading}
|
|
||||||
onClick={() => {
|
|
||||||
handleClickPay(Math.ceil(formatStorePrice2Read(payPrice - teamBalance)));
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('common:pay.to_recharge')}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</ModalFooter>
|
|
||||||
|
|
||||||
{!!qrPayData && <QRCodePayModal {...qrPayData} onSuccess={onConfirmPay} />}
|
|
||||||
</MyModal>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { serviceSideProps } from '@/web/common/utils/i18n';
|
import { serviceSideProps } from '@/web/common/utils/i18n';
|
||||||
import { Box, Image } from '@chakra-ui/react';
|
import { Box } from '@chakra-ui/react';
|
||||||
import { useTranslation } from 'next-i18next';
|
|
||||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||||
import { getTeamPlanStatus } from '@/web/support/user/team/api';
|
import { getTeamPlanStatus } from '@/web/support/user/team/api';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
@@ -14,7 +13,6 @@ import { getToken } from '@/web/support/user/auth';
|
|||||||
import Script from 'next/script';
|
import Script from 'next/script';
|
||||||
|
|
||||||
const PriceBox = () => {
|
const PriceBox = () => {
|
||||||
const { t } = useTranslation();
|
|
||||||
const { userInfo } = useUserStore();
|
const { userInfo } = useUserStore();
|
||||||
|
|
||||||
const { data: teamSubPlan, refetch: refetchTeamSubPlan } = useQuery(
|
const { data: teamSubPlan, refetch: refetchTeamSubPlan } = useQuery(
|
||||||
@@ -60,6 +58,6 @@ export default PriceBox;
|
|||||||
|
|
||||||
export async function getServerSideProps(context: any) {
|
export async function getServerSideProps(context: any) {
|
||||||
return {
|
return {
|
||||||
props: { ...(await serviceSideProps(context)) }
|
props: { ...(await serviceSideProps(context, ['user'])) }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,16 +0,0 @@
|
|||||||
import { GET, POST, PUT, DELETE } from '@/web/common/api/request';
|
|
||||||
import {
|
|
||||||
StandardSubPlanParams,
|
|
||||||
StandardSubPlanUpdateResponse
|
|
||||||
} from '@fastgpt/global/support/wallet/sub/api';
|
|
||||||
import { SubStatusEnum, SubTypeEnum } from '@fastgpt/global/support/wallet/sub/constants';
|
|
||||||
|
|
||||||
export const putTeamDatasetSubStatus = (data: {
|
|
||||||
status: `${SubStatusEnum}`;
|
|
||||||
type: `${SubTypeEnum}`;
|
|
||||||
}) => POST('/proApi/support/wallet/sub/updateStatus', data);
|
|
||||||
|
|
||||||
export const postCheckStandardSub = (data: StandardSubPlanParams) =>
|
|
||||||
POST<StandardSubPlanUpdateResponse>('/proApi/support/wallet/sub/standard/preCheck', data);
|
|
||||||
export const postUpdateStandardSub = (data: StandardSubPlanParams) =>
|
|
||||||
POST<StandardSubPlanUpdateResponse>('/proApi/support/wallet/sub/standard/update', data);
|
|
Reference in New Issue
Block a user