add plan activity config (#6139)
Some checks failed
Build FastGPT images in Personal warehouse / get-vars (push) Has been cancelled
Build FastGPT images in Personal warehouse / build-fastgpt-images (map[arch:amd64 runs-on:ubuntu-24.04]) (push) Has been cancelled
Build FastGPT images in Personal warehouse / build-fastgpt-images (map[arch:arm64 runs-on:ubuntu-24.04-arm]) (push) Has been cancelled
Build FastGPT images in Personal warehouse / release-fastgpt-images (push) Has been cancelled

* activity points

* modal

* ui

* fix

* pref: zod schema

* perf: ad api with zod

* perf: plan year switch

* perf: plan

* i18n

* fix: hook

* fix: activity checker

* fix: i18n

* fix clear token

* fix

* back

* can close modal in pay

* ad token

* rename

* fix

* total points

* eng i18n

---------

Co-authored-by: archer <545436317@qq.com>
This commit is contained in:
heheer 2025-12-24 18:22:25 +08:00 committed by GitHub
parent e53242e8bc
commit 4fbe27f2df
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
52 changed files with 1541 additions and 284 deletions

View File

@ -3,7 +3,8 @@ export enum SystemConfigsTypeEnum {
fastgptPro = 'fastgptPro',
systemMsgModal = 'systemMsgModal',
license = 'license',
operationalAd = 'operationalAd'
operationalAd = 'operationalAd',
activityAd = 'activityAd'
}
export const SystemConfigsTypeMap = {
@ -21,5 +22,8 @@ export const SystemConfigsTypeMap = {
},
[SystemConfigsTypeEnum.operationalAd]: {
label: 'operationalAd'
},
[SystemConfigsTypeEnum.activityAd]: {
label: 'activityAd'
}
};

View File

@ -1,6 +1,7 @@
import { createDocument } from 'zod-openapi';
import { DashboardPath } from './admin/core/dashboard';
import { TagsMap } from './tag';
import { AdminSupportPath } from './admin/support';
export const adminOpenAPIDocument = createDocument({
openapi: '3.1.0',
@ -10,13 +11,18 @@ export const adminOpenAPIDocument = createDocument({
description: 'FastGPT Admin API 文档'
},
paths: {
...DashboardPath
...DashboardPath,
...AdminSupportPath
},
servers: [{ url: '/api' }],
'x-tagGroups': [
{
name: '仪表盘',
tags: [TagsMap.adminDashboard]
},
{
name: '系统配置',
tags: [TagsMap.adminInform]
}
]
});

View File

@ -13,8 +13,6 @@ import {
} from './api';
import { TagsMap } from '../../../tag';
export * from './api';
export const DashboardPath: OpenAPIPath = {
'/admin/core/dashboard/getUserStats': {
get: {

View File

@ -0,0 +1,6 @@
import { AdminUserPath } from './user';
import type { OpenAPIPath } from '../../type';
export const AdminSupportPath: OpenAPIPath = {
...AdminUserPath
};

View File

@ -0,0 +1,6 @@
import { AdminInformPath } from './inform';
import type { OpenAPIPath } from '../../../type';
export const AdminUserPath: OpenAPIPath = {
...AdminInformPath
};

View File

@ -0,0 +1,57 @@
import { z } from 'zod';
import { InformLevelEnum } from '../../../../../support/user/inform/constants';
// Send system inform
export const SendSystemInformBodySchema = z.object({
title: z.string().meta({ description: '通知标题' }),
content: z.string().meta({ description: '通知内容' }),
level: z.enum(InformLevelEnum).meta({ description: '通知等级' })
});
export type SendSystemInformBodyType = z.infer<typeof SendSystemInformBodySchema>;
// Update system modal
export const UpdateSystemModalBodySchema = z.object({
content: z.string().meta({ description: '系统弹窗内容' })
});
export type UpdateSystemModalBodyType = z.infer<typeof UpdateSystemModalBodySchema>;
// Update operational ad
export const UpdateOperationalAdBodySchema = z.object({
operationalAdImage: z.string().meta({ description: '活动图片URL' }),
operationalAdLink: z.string().meta({ description: '活动链接' })
});
export type UpdateOperationalAdBodyType = z.infer<typeof UpdateOperationalAdBodySchema>;
// Update activity ad
export const UpdateActivityAdBodySchema = z.object({
activityAdImage: z.string().meta({ description: '底部广告图片URL' }),
activityAdLink: z.string().meta({ description: '底部广告链接' })
});
export type UpdateActivityAdBodyType = z.infer<typeof UpdateActivityAdBodySchema>;
// Response schemas
export const SystemMsgModalResponseSchema = z
.object({
id: z.string().meta({ description: '弹窗ID' }),
content: z.string().meta({ description: '弹窗内容' })
})
.optional();
export type SystemMsgModalValueType = z.infer<typeof SystemMsgModalResponseSchema>;
export const OperationalAdResponseSchema = z
.object({
id: z.string().meta({ description: '广告ID' }),
operationalAdImage: z.string().meta({ description: '广告图片URL' }),
operationalAdLink: z.string().meta({ description: '广告链接' })
})
.optional();
export type OperationalAdResponseType = z.infer<typeof OperationalAdResponseSchema>;
export const ActivityAdResponseSchema = z
.object({
id: z.string().meta({ description: '广告ID' }),
activityAdImage: z.string().meta({ description: '广告图片URL' }),
activityAdLink: z.string().meta({ description: '广告链接' })
})
.optional();
export type ActivityAdResponseType = z.infer<typeof ActivityAdResponseSchema>;

View File

@ -0,0 +1,161 @@
import type { OpenAPIPath } from '../../../../type';
import {
SendSystemInformBodySchema,
UpdateSystemModalBodySchema,
UpdateOperationalAdBodySchema,
UpdateActivityAdBodySchema,
SystemMsgModalResponseSchema,
OperationalAdResponseSchema,
ActivityAdResponseSchema
} from './api';
import { TagsMap } from '../../../../tag';
export const AdminInformPath: OpenAPIPath = {
'/admin/support/user/inform/sendSystemInform': {
post: {
summary: '发送系统通知给所有用户',
description: '向所有用户发送系统通知消息',
tags: [TagsMap.adminInform],
requestBody: {
content: {
'application/json': {
schema: SendSystemInformBodySchema
}
}
},
responses: {
200: {
description: '成功发送系统通知',
content: {
'application/json': {
schema: {}
}
}
}
}
}
},
'/support/user/inform/getSystemMsgModal': {
get: {
summary: '获取系统弹窗内容',
description: '获取系统消息弹窗的内容',
tags: [TagsMap.adminInform],
responses: {
200: {
description: '成功获取系统弹窗内容',
content: {
'application/json': {
schema: SystemMsgModalResponseSchema
}
}
}
}
}
},
'/admin/support/user/inform/updateSystemModal': {
post: {
summary: '更新系统弹窗内容',
description: '更新系统消息弹窗的内容',
tags: [TagsMap.adminInform],
requestBody: {
content: {
'application/json': {
schema: UpdateSystemModalBodySchema
}
}
},
responses: {
200: {
description: '成功更新系统弹窗',
content: {
'application/json': {
schema: {}
}
}
}
}
}
},
'/support/user/inform/getOperationalAd': {
get: {
summary: '获取运营广告',
description: '获取运营广告的图片和链接',
tags: [TagsMap.adminInform],
responses: {
200: {
description: '成功获取运营广告',
content: {
'application/json': {
schema: OperationalAdResponseSchema
}
}
}
}
}
},
'/admin/support/user/inform/updateOperationalAd': {
post: {
summary: '更新运营广告',
description: '更新运营广告的图片和链接',
tags: [TagsMap.adminInform],
requestBody: {
content: {
'application/json': {
schema: UpdateOperationalAdBodySchema
}
}
},
responses: {
200: {
description: '成功更新运营广告',
content: {
'application/json': {
schema: {}
}
}
}
}
}
},
'/support/user/inform/getActivityAd': {
get: {
summary: '获取活动广告',
description: '获取活动广告的图片和链接',
tags: [TagsMap.adminInform],
responses: {
200: {
description: '成功获取活动广告',
content: {
'application/json': {
schema: ActivityAdResponseSchema
}
}
}
}
}
},
'/admin/support/user/inform/updateActivityAd': {
post: {
summary: '更新活动广告',
description: '更新活动广告的图片和链接',
tags: [TagsMap.adminInform],
requestBody: {
content: {
'application/json': {
schema: UpdateActivityAdBodySchema
}
}
},
responses: {
200: {
description: '成功更新活动广告',
content: {
'application/json': {
schema: {}
}
}
}
}
}
}
};

View File

@ -1,11 +1,9 @@
import { createDocument } from 'zod-openapi';
import { ChatPath } from './core/chat';
import { ApiKeyPath } from './support/openapi';
import { TagsMap } from './tag';
import { PluginPath } from './core/plugin';
import { WalletPath } from './support/wallet';
import { CustomDomainPath } from './support/customDomain';
import { AppPath } from './core/app';
import { SupportPath } from './support';
export const openAPIDocument = createDocument({
openapi: '3.1.0',
@ -17,10 +15,8 @@ export const openAPIDocument = createDocument({
paths: {
...AppPath,
...ChatPath,
...ApiKeyPath,
...PluginPath,
...WalletPath,
...CustomDomainPath
...SupportPath
},
servers: [{ url: '/api' }],
'x-tagGroups': [
@ -37,8 +33,8 @@ export const openAPIDocument = createDocument({
tags: [TagsMap.pluginToolTag, TagsMap.pluginTeam]
},
{
name: '支付系统',
tags: [TagsMap.walletBill, TagsMap.walletDiscountCoupon]
name: '用户体系',
tags: [TagsMap.userInform, TagsMap.walletBill, TagsMap.walletDiscountCoupon]
},
{
name: '通用-辅助功能',

View File

@ -0,0 +1,12 @@
import { UserPath } from './user';
import type { OpenAPIPath } from '../type';
import { WalletPath } from './wallet';
import { ApiKeyPath } from './openapi';
import { CustomDomainPath } from './customDomain';
export const SupportPath: OpenAPIPath = {
...UserPath,
...WalletPath,
...ApiKeyPath,
...CustomDomainPath
};

View File

@ -0,0 +1,6 @@
import { UserInformPath } from './inform';
import type { OpenAPIPath } from '../../type';
export const UserPath: OpenAPIPath = {
...UserInformPath
};

View File

@ -0,0 +1,61 @@
import type { OpenAPIPath } from '../../../type';
import {
SystemMsgModalResponseSchema,
OperationalAdResponseSchema,
ActivityAdResponseSchema
} from '../../../admin/support/user/inform/api';
import { TagsMap } from '../../../tag';
export const UserInformPath: OpenAPIPath = {
'/proApi/support/user/inform/getSystemMsgModal': {
get: {
summary: '获取系统弹窗内容',
description: '获取系统消息弹窗的内容',
tags: [TagsMap.userInform],
responses: {
200: {
description: '成功获取系统弹窗内容',
content: {
'application/json': {
schema: SystemMsgModalResponseSchema
}
}
}
}
}
},
'/proApi/support/user/inform/getOperationalAd': {
get: {
summary: '获取运营广告',
description: '获取运营广告的图片和链接',
tags: [TagsMap.userInform],
responses: {
200: {
description: '成功获取运营广告',
content: {
'application/json': {
schema: OperationalAdResponseSchema
}
}
}
}
}
},
'/proApi/support/user/inform/getActivityAd': {
get: {
summary: '获取活动广告',
description: '获取活动广告的图片和链接',
tags: [TagsMap.userInform],
responses: {
200: {
description: '成功获取活动广告',
content: {
'application/json': {
schema: ActivityAdResponseSchema
}
}
}
}
}
}
};

View File

@ -25,6 +25,32 @@ export const BillListResponseSchema = z.object({
});
export type GetBillListResponseType = z.infer<typeof BillListResponseSchema>;
// Bill detail
export const BillDetailQuerySchema = z.object({
billId: ObjectIdSchema.meta({ description: '订单 ID' })
});
export type BillDetailQueryType = z.infer<typeof BillDetailQuerySchema>;
export const BillDetailResponseSchema = BillSchema.safeExtend({
discountCouponName: z.string().optional(),
couponDetail: z
.object({
key: z.string(),
type: z.enum(CouponTypeEnum),
subscriptions: z.array(
z.object({
type: z.enum(SubTypeEnum),
durationDay: z.number(),
totalPoints: z.number().optional(),
level: z.enum(StandardSubLevelEnum).optional(),
extraDatasetSize: z.number().optional(),
customConfig: z.record(z.string(), z.any()).optional()
})
)
})
.optional()
});
export type BillDetailResponseType = z.infer<typeof BillDetailResponseSchema>;
// Create
export const CreateStandPlanBillSchema = z
.object({
@ -88,30 +114,14 @@ export const CheckPayResultResponseSchema = z.object({
});
export type CheckPayResultResponseType = z.infer<typeof CheckPayResultResponseSchema>;
// Bill detail
export const BillDetailResponseSchema = BillSchema.safeExtend({
discountCouponName: z.string().optional(),
couponDetail: z
.object({
key: z.string(),
type: z.enum(CouponTypeEnum),
subscriptions: z.array(
z.object({
type: z.enum(SubTypeEnum),
durationDay: z.number(),
totalPoints: z.number().optional(),
level: z.enum(StandardSubLevelEnum).optional(),
extraDatasetSize: z.number().optional(),
customConfig: z.record(z.string(), z.any()).optional()
})
)
})
.optional()
});
export type BillDetailResponseType = z.infer<typeof BillDetailResponseSchema>;
// Cancel bill
export const CancelBillPropsSchema = z.object({
billId: ObjectIdSchema.meta({ description: '订单 ID' })
});
export type CancelBillPropsType = z.infer<typeof CancelBillPropsSchema>;
// Check pay result
export const CheckPayResultQuerySchema = z.object({
payId: ObjectIdSchema.meta({ description: '订单 ID' })
});
export type CheckPayResultQueryType = z.infer<typeof CheckPayResultQuerySchema>;

View File

@ -8,7 +8,9 @@ import {
CheckPayResultResponseSchema,
BillDetailResponseSchema,
BillListQuerySchema,
CancelBillPropsSchema
CancelBillPropsSchema,
CheckPayResultQuerySchema,
BillDetailQuerySchema
} from './api';
import { TagsMap } from '../../../tag';
import { ObjectIdSchema } from '../../../../common/type/mongo';
@ -68,11 +70,7 @@ export const BillPath: OpenAPIPath = {
description: '检查订单的支付状态,用于轮询支付结果',
tags: [TagsMap.walletBill],
requestParams: {
query: z.object({
payId: ObjectIdSchema.meta({
description: '订单 ID'
})
})
query: CheckPayResultQuerySchema
},
responses: {
200: {
@ -92,11 +90,7 @@ export const BillPath: OpenAPIPath = {
description: '根据订单 ID 获取订单详细信息,包括优惠券名称等',
tags: [TagsMap.walletBill],
requestParams: {
query: z.object({
billId: ObjectIdSchema.meta({
description: '订单 ID'
})
})
query: BillDetailQuerySchema
},
responses: {
200: {

View File

@ -22,6 +22,8 @@ export const TagsMap = {
walletBill: '订单',
walletDiscountCoupon: '优惠券',
customDomain: '自定义域名',
// User
userInform: '用户通知',
/* Common */
// APIKey
@ -33,5 +35,7 @@ export const TagsMap = {
pluginAdmin: '管理员插件管理',
pluginToolAdmin: '管理员系统工具管理',
// Data
adminDashboard: '管理员仪表盘'
adminDashboard: '管理员仪表盘',
// Inform
adminInform: '管理员通知管理'
};

View File

@ -2,8 +2,7 @@ import type { auditLogMap, adminAuditLogMap } from '../../../../web/support/user
export enum AdminAuditEventEnum {
ADMIN_LOGIN = 'ADMIN_LOGIN',
ADMIN_UPDATE_SYSTEM_MODAL = 'ADMIN_UPDATE_SYSTEM_MODAL',
ADMIN_SEND_SYSTEM_INFORM = 'ADMIN_SEND_SYSTEM_INFORM',
ADMIN_ADD_USER = 'ADMIN_ADD_USER',
ADMIN_UPDATE_USER = 'ADMIN_UPDATE_USER',
ADMIN_UPDATE_TEAM = 'ADMIN_UPDATE_TEAM',
@ -21,7 +20,13 @@ export enum AdminAuditEventEnum {
ADMIN_DELETE_PLUGIN = 'ADMIN_DELETE_PLUGIN',
ADMIN_CREATE_PLUGIN_GROUP = 'ADMIN_CREATE_PLUGIN_GROUP',
ADMIN_UPDATE_PLUGIN_GROUP = 'ADMIN_UPDATE_PLUGIN_GROUP',
ADMIN_DELETE_PLUGIN_GROUP = 'ADMIN_DELETE_PLUGIN_GROUP'
ADMIN_DELETE_PLUGIN_GROUP = 'ADMIN_DELETE_PLUGIN_GROUP',
// Inform
ADMIN_UPDATE_SYSTEM_MODAL = 'ADMIN_UPDATE_SYSTEM_MODAL',
ADMIN_SEND_SYSTEM_INFORM = 'ADMIN_SEND_SYSTEM_INFORM',
ADMIN_UPDATE_ACTIVITY_AD = 'ADMIN_UPDATE_ACTIVITY_AD',
ADMIN_UPDATE_OPERATIONAL_AD = 'ADMIN_UPDATE_OPERATIONAL_AD'
}
export enum AuditEventEnum {

View File

@ -1,5 +1,4 @@
import type { StandardSubLevelEnum, SubModeEnum } from './constants';
import { TeamSubSchema } from './type.d';
export type StandardSubPlanParams = {
level: `${StandardSubLevelEnum}`;

View File

@ -1,103 +0,0 @@
import type { StandardSubLevelEnum, SubModeEnum, SubTypeEnum } from './constants';
// Content of plan
export type TeamStandardSubPlanItemType = {
name?: string;
desc?: string; // Plan description
price: number; // read price / month
pointPrice: number; // read price/ one thousand
totalPoints: number; // n
maxTeamMember: number;
maxAppAmount: number; // max app or plugin amount
maxDatasetAmount: number;
maxDatasetSize: number;
requestsPerMinute?: number;
appRegistrationCount?: number;
chatHistoryStoreDuration: number; // n day
websiteSyncPerDataset?: number;
auditLogStoreDuration?: number;
ticketResponseTime?: number;
customDomain?: number;
// Custom plan specific fields
priceDescription?: string;
customFormUrl?: string;
customDescriptions?: string[];
};
export type StandSubPlanLevelMapType = Record<
`${StandardSubLevelEnum}`,
TeamStandardSubPlanItemType
>;
export type PointsPackageItem = {
points: number;
month: number;
price: number;
};
export type SubPlanType = {
[SubTypeEnum.standard]?: StandSubPlanLevelMapType;
planDescriptionUrl?: string;
appRegistrationUrl?: string;
communitySupportTip?: string;
[SubTypeEnum.extraDatasetSize]: {
price: number;
};
[SubTypeEnum.extraPoints]: {
packages: PointsPackageItem[];
};
};
export type TeamSubSchema = {
_id: string;
teamId: string;
type: `${SubTypeEnum}`;
startTime: Date;
expiredTime: Date;
currentMode: `${SubModeEnum}`;
nextMode: `${SubModeEnum}`;
currentSubLevel: StandardSubLevelEnum;
nextSubLevel: StandardSubLevelEnum;
maxTeamMember?: number;
maxApp?: number;
maxDataset?: number;
// custom level configurations
requestsPerMinute?: number;
chatHistoryStoreDuration?: number;
maxDatasetSize?: number;
websiteSyncPerDataset?: number;
appRegistrationCount?: number;
auditLogStoreDuration?: number;
ticketResponseTime?: number;
customDomain?: number;
totalPoints: number;
surplusPoints: number;
currentExtraDatasetSize: number;
};
export type TeamPlanStatusType = {
[SubTypeEnum.standard]?: TeamSubSchema;
standardConstants?: TeamStandardSubPlanItemType;
totalPoints: number;
usedPoints: number;
// standard + extra
datasetMaxSize: number;
};
export type ClientTeamPlanStatusType = TeamPlanStatusType & {
usedMember: number;
usedAppAmount: number;
usedDatasetSize: number;
usedDatasetIndexSize: number;
usedRegistrationCount: number;
};

View File

@ -0,0 +1,111 @@
import z from 'zod';
import { StandardSubLevelEnum, SubModeEnum, SubTypeEnum } from './constants';
import { ObjectIdSchema } from '../../../common/type/mongo';
// Content of plan
export const TeamStandardSubPlanItemSchema = z.object({
name: z.string().optional(),
desc: z.string().optional(),
price: z.number(),
totalPoints: z.int(), // 总积分
maxTeamMember: z.int(),
maxAppAmount: z.int(),
maxDatasetAmount: z.int(),
maxDatasetSize: z.int(),
requestsPerMinute: z.int().optional(), // QPM
appRegistrationCount: z.int().optional(), // 应用备案数量
chatHistoryStoreDuration: z.int(), // 历史记录保留天数
websiteSyncPerDataset: z.int().optional(), // 站点同步最大页面
auditLogStoreDuration: z.int().optional(), // 审计日志保留天数
ticketResponseTime: z.int().optional(), // 工单支持时间
customDomain: z.int().optional(), // 自定义域名数量
// 定制套餐
priceDescription: z.string().optional(), // 价格描述
customFormUrl: z.string().optional(), // 自定义表单 URL
customDescriptions: z.array(z.string()).optional(), // 自定义描述
// Active
annualBonusPoints: z.int().optional(), // 年度赠送积分
// @deprecated
pointPrice: z.number().optional()
});
export type TeamStandardSubPlanItemType = z.infer<typeof TeamStandardSubPlanItemSchema>;
export const StandSubPlanLevelMapSchema = z.record(
z.enum(StandardSubLevelEnum),
TeamStandardSubPlanItemSchema
);
export type StandSubPlanLevelMapType = z.infer<typeof StandSubPlanLevelMapSchema>;
export const PointsPackageItemSchema = z.object({
points: z.int(),
month: z.int(),
price: z.number(),
activityBonusPoints: z.int().optional() // 活动赠送积分
});
export type PointsPackageItem = z.infer<typeof PointsPackageItemSchema>;
export const SubPlanSchema = z.object({
[SubTypeEnum.standard]: StandSubPlanLevelMapSchema.optional(),
[SubTypeEnum.extraDatasetSize]: z.object({ price: z.number() }).optional(),
[SubTypeEnum.extraPoints]: z.object({ packages: PointsPackageItemSchema.array() }).optional(),
planDescriptionUrl: z.string().optional(),
appRegistrationUrl: z.string().optional(),
communitySupportTip: z.string().optional(),
activityExpirationTime: z.date().optional()
});
export type SubPlanType = z.infer<typeof SubPlanSchema>;
export const TeamSubSchema = z.object({
_id: ObjectIdSchema,
teamId: ObjectIdSchema,
type: z.enum(SubTypeEnum),
startTime: z.date(),
expiredTime: z.date(),
currentMode: z.enum(SubModeEnum),
nextMode: z.enum(SubModeEnum),
currentSubLevel: z.enum(StandardSubLevelEnum),
nextSubLevel: z.enum(StandardSubLevelEnum),
maxTeamMember: z.int().optional(),
maxApp: z.int().optional(),
maxDataset: z.int().optional(),
totalPoints: z.int(),
annualBonusPoints: z.int().optional(),
surplusPoints: z.int(),
currentExtraDatasetSize: z.int(),
// 定制版特有属性
requestsPerMinute: z.int().optional(),
chatHistoryStoreDuration: z.int().optional(),
maxDatasetSize: z.int().optional(),
websiteSyncPerDataset: z.int().optional(),
appRegistrationCount: z.int().optional(),
auditLogStoreDuration: z.int().optional(),
ticketResponseTime: z.int().optional(),
customDomain: z.int().optional()
});
export type TeamSubSchemaType = z.infer<typeof TeamSubSchema>;
export const TeamPlanStatusSchema = z.object({
[SubTypeEnum.standard]: TeamSubSchema.optional(),
standardConstants: TeamStandardSubPlanItemSchema.optional(),
totalPoints: z.int(),
usedPoints: z.int(),
datasetMaxSize: z.int()
});
export type TeamPlanStatusType = z.infer<typeof TeamPlanStatusSchema>;
export const ClientTeamPlanStatusSchema = TeamPlanStatusSchema.extend({
usedMember: z.int(),
usedAppAmount: z.int(),
usedDatasetSize: z.int(),
usedDatasetIndexSize: z.int(),
usedRegistrationCount: z.int()
});
export type ClientTeamPlanStatusType = z.infer<typeof ClientTeamPlanStatusSchema>;

View File

@ -1,4 +0,0 @@
export type SystemMsgModalValueType = {
id: string;
content: string;
};

View File

@ -11,7 +11,7 @@ import {
SubModeEnum,
SubTypeEnum
} from '@fastgpt/global/support/wallet/sub/constants';
import type { TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type';
import type { TeamSubSchemaType } from '@fastgpt/global/support/wallet/sub/type';
export const subCollectionName = 'team_subscriptions';
@ -100,4 +100,4 @@ try {
console.log(error);
}
export const MongoTeamSub = getMongoModel<TeamSubSchema>(subCollectionName, SubSchema);
export const MongoTeamSub = getMongoModel<TeamSubSchemaType>(subCollectionName, SubSchema);

View File

@ -7,8 +7,8 @@ import {
import { MongoTeamSub } from './schema';
import {
type TeamPlanStatusType,
type TeamSubSchema
} from '@fastgpt/global/support/wallet/sub/type.d';
type TeamSubSchemaType
} from '@fastgpt/global/support/wallet/sub/type';
import dayjs from 'dayjs';
import { type ClientSession } from '../../../common/mongo';
import { addMonths } from 'date-fns';
@ -29,7 +29,7 @@ export const getStandardPlanConfig = (level: `${StandardSubLevelEnum}`) => {
return global.subPlans?.standard?.[level];
};
export const sortStandPlans = (plans: TeamSubSchema[]) => {
export const sortStandPlans = (plans: TeamSubSchemaType[]) => {
return plans.sort(
(a, b) =>
standardSubLevelMap[b.currentSubLevel].weight - standardSubLevelMap[a.currentSubLevel].weight

View File

@ -8,7 +8,17 @@ import { imageBaseUrl } from '@fastgpt/global/common/file/image/constants';
export const useUploadAvatar = (
api: (params: { filename: string }) => Promise<CreatePostPresignedUrlResult>,
{ onSuccess }: { onSuccess?: (avatar: string) => void } = {}
{
onSuccess,
maxW = 300,
maxH = 300,
maxSize = 1024 * 500 // 500KB
}: {
onSuccess?: (avatar: string) => void;
maxW?: number;
maxH?: number;
maxSize?: number;
} = {}
) => {
const { toast } = useToast();
const { t } = useTranslation();
@ -32,8 +42,9 @@ export const useUploadAvatar = (
const compressed = base64ToFile(
await compressBase64Img({
base64Img: await fileToBase64(file),
maxW: 300,
maxH: 300
maxW,
maxH,
maxSize
}),
file.name
);

View File

@ -1,5 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path fill-rule="evenodd" clip-rule="evenodd"
d="M12.6262 3.29289C13.0167 2.90237 13.6499 2.90237 14.0404 3.29289C14.4309 3.68342 14.4309 4.31658 14.0404 4.70711L6.70707 12.0404C6.31654 12.431 5.68338 12.431 5.29285 12.0404L1.95952 8.70711C1.56899 8.31658 1.56899 7.68342 1.95952 7.29289C2.35004 6.90237 2.98321 6.90237 3.37373 7.29289L5.99996 9.91912L12.6262 3.29289Z"
fill="#3370FF" />
<svg viewBox="0 0 16 16" fill="none">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.6261 3.29289C13.0166 2.90237 13.6498 2.90237 14.0403 3.29289C14.4308 3.68342 14.4308 4.31658 14.0403 4.70711L6.70694 12.0404C6.31642 12.431 5.68325 12.431 5.29273 12.0404L1.9594 8.70711C1.56887 8.31658 1.56887 7.68342 1.9594 7.29289C2.34992 6.90237 2.98309 6.90237 3.37361 7.29289L5.99984 9.91912L12.6261 3.29289Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 475 B

After

Width:  |  Height:  |  Size: 416 B

View File

@ -19,7 +19,9 @@
"admin_login": "Administrator login",
"admin_save_template_type": "Update template classification",
"admin_send_system_inform": "Send system notifications",
"admin_update_activity_ad": "Bottom advertising configuration",
"admin_update_app_template": "Update templates",
"admin_update_operational_ad": "Full screen ad configuration",
"admin_update_plan": "Editorial Team Package",
"admin_update_plugin": "Plugin Update",
"admin_update_plugin_group": "Plugin group update",
@ -128,7 +130,9 @@
"log_admin_login": "【{{name}}】Logined in the administrator background",
"log_admin_save_template_type": "【{{name}}】Added template classification called [{{typeName}}]",
"log_admin_send_system_inform": "【{{name}}】Sent a system notification titled [{{informTitle}}], with the level of [{{level}}]",
"log_admin_update_activity_ad": "[{{name}}] has configured bottom ads",
"log_admin_update_app_template": "【{{name}}】Updated template information named [{{templateName}}]",
"log_admin_update_operational_ad": "[{{name}}] has configured the event page",
"log_admin_update_plan": "【{{name}}】Edited the package information of the team with the team id [{{teamId}}]",
"log_admin_update_plugin": "【{{name}}】Updated plugin information called [{{pluginName}}]",
"log_admin_update_plugin_group": "【{{name}}】Updated plug-in grouping called [{{groupName}}]",

View File

@ -98,6 +98,10 @@
"Warning": "Warning",
"Website": "Website",
"action_confirm": "Confirm",
"activity_ad.desc": "More points, same annual package price. Get up to 1.66M bonus points.",
"activity_ad.join_now": "Get Started",
"activity_ad.later": "Maybe later",
"activity_ad.title": "Festival Special · Limited Time",
"add_new": "add_new",
"add_new_param": "Add new param",
"add_success": "Added Successfully",
@ -950,7 +954,7 @@
"n_ai_points": "{{amount}} points",
"n_chat_records_retain": "{{amount}} Days of Chat History Retention",
"n_custom_domain_amount": "{{amount}} Custom domains",
"n_custom_domain_amount tip": "The number of custom domain names that the team can configure, which can currently be used to access Wecom intelligent robots",
"n_custom_domain_amount_tip": "The number of custom domain names that the team can configure, which can currently be used to access Wecom intelligent robots",
"n_dataset_amount": "{{amount}} Dataset limit",
"n_dataset_size": "{{amount}} Dataset Indexes",
"n_team_audit_day": "{{amount}} days team operation log records",
@ -1208,6 +1212,7 @@
"support.wallet.subscription.AI points": "AI Points",
"support.wallet.subscription.AI points usage": "AI Points Usage",
"support.wallet.subscription.AI points usage tip": "Each time the AI model is called, a certain amount of AI points will be consumed. For specific calculation standards, please refer to the 'Pricing' above.",
"support.wallet.subscription.Activity expiration time": "Activity ends on {{month}}/{{day}}/{{year}} at {{hour}}:{{minute}}",
"support.wallet.subscription.Ai points": "AI Points Calculation Standards",
"support.wallet.subscription.Current plan": "Current Package",
"support.wallet.subscription.Dataset size": "Knowledge Base Index",
@ -1259,6 +1264,7 @@
"support.wallet.subscription.status.inactive": "Inactive",
"support.wallet.subscription.team_operation_log": "Record team operation logs",
"support.wallet.subscription.token_compute": "Click to View Online Tokens Calculator",
"support.wallet.subscription.total_points": "Total points",
"support.wallet.subscription.type.balance": "Balance Recharge",
"support.wallet.subscription.type.extraDatasetSize": "Dataset Expansion",
"support.wallet.subscription.type.extraPoints": "AI Points Package",

View File

@ -19,7 +19,9 @@
"admin_login": "管理员登录",
"admin_save_template_type": "更新模板分类",
"admin_send_system_inform": "发送系统通知",
"admin_update_activity_ad": "底部广告配置",
"admin_update_app_template": "更新模板",
"admin_update_operational_ad": "全屏广告配置",
"admin_update_plan": "编辑团队套餐",
"admin_update_plugin": "插件更新",
"admin_update_plugin_group": "插件分组更新",
@ -130,7 +132,9 @@
"log_admin_login": "【{{name}}】登录了管理员后台",
"log_admin_save_template_type": "【{{name}}】添加了名为【{{typeName}}】的模板分类",
"log_admin_send_system_inform": "【{{name}}】发送了标题为【{{informTitle}}】的系统通知,等级为【{{level}}】",
"log_admin_update_activity_ad": "【{{name}}】进行了底部广告配置",
"log_admin_update_app_template": "【{{name}}】更新了名为【{{templateName}}】的模板信息",
"log_admin_update_operational_ad": "【{{name}}】进行了活动页配置",
"log_admin_update_plan": "【{{name}}】编辑了团队id为【{{teamId}}】的团队的套餐信息",
"log_admin_update_plugin": "【{{name}}】更新了名为【{{pluginName}}】的插件信息",
"log_admin_update_plugin_group": "【{{name}}】更新了名为【{{groupName}}】的插件分组",

View File

@ -99,6 +99,10 @@
"Warning": "警告",
"Website": "网站",
"action_confirm": "操作确认",
"activity_ad.desc": "充值最高可得额外166万积分年费套餐旧价享新量",
"activity_ad.join_now": "立即参与",
"activity_ad.later": "稍等一会儿",
"activity_ad.title": "双节献礼 · 限时升级",
"add_new": "新增",
"add_new_param": "新增参数",
"add_success": "添加成功",
@ -957,7 +961,7 @@
"n_app_registration_amount": "{{amount}} 个应用备案",
"n_chat_records_retain": "{{amount}} 天对话记录保留",
"n_custom_domain_amount": "{{amount}} 个自定义域名",
"n_custom_domain_amount tip": "团队可以配置的自定义域名数量,目前可用于接入企微智能机器人",
"n_custom_domain_amount_tip": "团队可以配置的自定义域名数量,目前可用于接入企微智能机器人",
"n_dataset_amount": "{{amount}} 个知识库",
"n_dataset_size": "{{amount}} 组知识库索引",
"n_team_audit_day": "{{amount}} 天团队操作日志记录",
@ -1217,6 +1221,7 @@
"support.wallet.subscription.AI points": "AI 积分",
"support.wallet.subscription.AI points usage": "AI 积分使用量",
"support.wallet.subscription.AI points usage tip": "每次调用 AI 模型时,都会消耗一定的 AI 积分。具体的计算标准可参考上方的“计费标准”",
"support.wallet.subscription.Activity expiration time": "活动截至{{year}}年{{month}}月{{day}}日{{hour}}:{{minute}}",
"support.wallet.subscription.Ai points": "AI 积分计算标准",
"support.wallet.subscription.Current plan": "当前套餐",
"support.wallet.subscription.Dataset size": "知识库索引量",
@ -1269,6 +1274,7 @@
"support.wallet.subscription.status.inactive": "待使用",
"support.wallet.subscription.team_operation_log": "记录团队操作日志",
"support.wallet.subscription.token_compute": "点击查看在线 Tokens 计算器",
"support.wallet.subscription.total_points": "总积分",
"support.wallet.subscription.type.balance": "余额充值",
"support.wallet.subscription.type.extraDatasetSize": "知识库扩容",
"support.wallet.subscription.type.extraPoints": "AI 积分套餐",

View File

@ -19,7 +19,9 @@
"admin_login": "管理員登錄",
"admin_save_template_type": "更新模板分類",
"admin_send_system_inform": "發送系統通知",
"admin_update_activity_ad": "底部廣告配置",
"admin_update_app_template": "更新模板",
"admin_update_operational_ad": "全屏廣告配置",
"admin_update_plan": "編輯團隊套餐",
"admin_update_plugin": "插件更新",
"admin_update_plugin_group": "插件分組更新",
@ -128,7 +130,9 @@
"log_admin_login": "【{{name}}】登錄了管理員後台",
"log_admin_save_template_type": "【{{name}}】添加了名為【{{typeName}}】的模板分類",
"log_admin_send_system_inform": "【{{name}}】發送了標題為【{{informTitle}}】的系統通知,等級為【{{level}}】",
"log_admin_update_activity_ad": "【{{name}}】進行了底部廣告配置",
"log_admin_update_app_template": "【{{name}}】更新了名為【{{templateName}}】的模板信息",
"log_admin_update_operational_ad": "【{{name}}】進行了活動頁配置",
"log_admin_update_plan": "【{{name}}】編輯了團隊id為【{{teamId}}】的團隊的套餐信息",
"log_admin_update_plugin": "【{{name}}】更新了名為【{{pluginName}}】的插件信息",
"log_admin_update_plugin_group": "【{{name}}】更新了名為【{{groupName}}】的插件分組",

View File

@ -98,6 +98,10 @@
"Warning": "警告",
"Website": "網站",
"action_confirm": "確認",
"activity_ad.desc": "充值最高可得額外166萬積分年費套餐舊價享新量",
"activity_ad.join_now": "立即參與",
"activity_ad.later": "稍等一會兒",
"activity_ad.title": "雙節獻禮 · 限時升級",
"add_new": "新增",
"add_new_param": "新增參數",
"add_success": "新增成功",
@ -948,7 +952,7 @@
"n_ai_points": "{{amount}} 積分",
"n_chat_records_retain": "{{amount}} 天對話紀錄保留",
"n_custom_domain_amount": "{{amount}} 個自定義域名",
"n_custom_domain_amount tip": "團隊可以配置的自定義域名數量,目前可用於接入企微智能機器人",
"n_custom_domain_amount_tip": "團隊可以配置的自定義域名數量,目前可用於接入企微智能機器人",
"n_dataset_amount": "{{amount}} 個知識庫",
"n_dataset_size": "{{amount}} 組知識庫索引",
"n_team_audit_day": "{{amount}} 天團隊操作日誌記錄",
@ -1205,6 +1209,7 @@
"support.wallet.subscription.AI points": "AI 點數",
"support.wallet.subscription.AI points usage": "AI 點數使用量",
"support.wallet.subscription.AI points usage tip": "每次呼叫 AI 模型時,都會消耗一定的 AI 點數。具體的計算標準可參考上方的「計費標準」",
"support.wallet.subscription.Activity expiration time": "活動截至{{year}}年{{month}}月{{day}}日{{hour}}:{{minute}}",
"support.wallet.subscription.Ai points": "AI 點數計算標準",
"support.wallet.subscription.Current plan": "目前方案",
"support.wallet.subscription.Dataset size": "知識庫索引量",
@ -1256,6 +1261,7 @@
"support.wallet.subscription.status.inactive": "未使用",
"support.wallet.subscription.team_operation_log": "記錄團隊操作日誌",
"support.wallet.subscription.token_compute": "點選檢視線上 Token 計算機",
"support.wallet.subscription.total_points": "總積分",
"support.wallet.subscription.type.balance": "餘額儲值",
"support.wallet.subscription.type.extraDatasetSize": "知識庫擴充容量",
"support.wallet.subscription.type.extraPoints": "AI 點數方案",

View File

@ -7,16 +7,6 @@ export const adminAuditLogMap = {
typeLabel: i18nT('account_team:admin_login'),
params: {} as { name?: string }
},
[AdminAuditEventEnum.ADMIN_UPDATE_SYSTEM_MODAL]: {
content: i18nT('account_team:log_admin_update_system_modal'),
typeLabel: i18nT('account_team:admin_update_system_modal'),
params: {} as { name?: string }
},
[AdminAuditEventEnum.ADMIN_SEND_SYSTEM_INFORM]: {
content: i18nT('account_team:log_admin_send_system_inform'),
typeLabel: i18nT('account_team:admin_send_system_inform'),
params: {} as { name?: string; informTitle?: string; level?: string }
},
[AdminAuditEventEnum.ADMIN_ADD_USER]: {
content: i18nT('account_team:log_admin_add_user'),
typeLabel: i18nT('account_team:admin_add_user'),
@ -108,6 +98,28 @@ export const adminAuditLogMap = {
content: i18nT('account_team:log_admin_delete_plugin_group'),
typeLabel: i18nT('account_team:admin_delete_plugin_group'),
params: {} as { name?: string; groupName: string }
},
// Inform
[AdminAuditEventEnum.ADMIN_UPDATE_SYSTEM_MODAL]: {
content: i18nT('account_team:log_admin_update_system_modal'),
typeLabel: i18nT('account_team:admin_update_system_modal'),
params: {} as { name?: string }
},
[AdminAuditEventEnum.ADMIN_SEND_SYSTEM_INFORM]: {
content: i18nT('account_team:log_admin_send_system_inform'),
typeLabel: i18nT('account_team:admin_send_system_inform'),
params: {} as { name?: string; informTitle?: string; level?: string }
},
[AdminAuditEventEnum.ADMIN_UPDATE_ACTIVITY_AD]: {
content: i18nT('account_team:log_admin_update_activity_ad'),
typeLabel: i18nT('account_team:admin_update_activity_ad'),
params: {}
},
[AdminAuditEventEnum.ADMIN_UPDATE_OPERATIONAL_AD]: {
content: i18nT('account_team:log_admin_update_operational_ad'),
typeLabel: i18nT('account_team:admin_update_operational_ad'),
params: {}
}
};

View File

@ -0,0 +1,61 @@
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40" fill="none">
<g opacity="0.13">
<path d="M19.375 1.1875L18.4375 2.8125V37.1875L19.375 38.8125L20.3125 37.1875V2.8125L19.375 1.1875Z" fill="url(#paint0_linear_30901_98056)"/>
<path d="M19.375 9.375L15.625 6.875V5L19.375 7.5V9.375ZM19.375 13.125L14.375 10V8.125L19.375 11.25V13.125ZM19.375 9.375L23.125 6.875V5L19.375 7.5V9.375ZM19.375 13.125L24.375 10V8.125L19.375 11.25V13.125ZM19.375 30.625L15.625 33.125V35L19.375 32.5V30.625ZM19.375 26.875L14.375 30V31.875L19.375 28.75V26.875ZM19.375 30.625L23.125 33.125V35L19.375 32.5V30.625ZM19.375 26.875L24.375 30V31.875L19.375 28.75V26.875Z" fill="url(#paint1_linear_30901_98056)"/>
<path d="M3.09375 29.4063H4.96875L34.7188 12.2188L35.6562 10.5938H33.7812L4.03125 27.7813L3.09375 29.4063Z" fill="url(#paint2_linear_30901_98056)"/>
<path d="M10.1563 25.3125L9.875 29.8125L8.25 30.75L8.53125 26.25L10.1563 25.3125ZM13.4063 23.4375L13.1875 29.3438L11.5625 30.2813L11.7813 24.375L13.4063 23.4375Z" fill="url(#paint3_linear_30901_98056)"/>
<path d="M10.1563 25.3125L6.125 23.3125L4.5 24.25L8.53125 26.25L10.1563 25.3125ZM13.4063 23.4375L8.1875 20.6875L6.5625 21.625L11.7813 24.375L13.4063 23.4375ZM28.5625 14.6875L32.5938 16.6875L34.2188 15.75L30.1875 13.75L28.5625 14.6875ZM25.3125 16.5625L30.5312 19.3438L32.1562 18.4063L26.9375 15.625L25.3125 16.5625Z" fill="url(#paint4_linear_30901_98056)"/>
<path d="M28.5625 14.6875L28.8438 10.1875L30.4688 9.25L30.1875 13.75L28.5625 14.6875ZM25.3125 16.5625L25.5312 10.6875L27.1562 9.75L26.9375 15.625L25.3125 16.5625Z" fill="url(#paint5_linear_30901_98056)"/>
<path d="M35.6562 29.4063H33.7812L4.03125 12.2188L3.09375 10.5938H4.96875L34.7188 27.7813L35.6562 29.4063Z" fill="url(#paint6_linear_30901_98056)"/>
<path d="M28.5938 25.3125L28.875 29.8125L30.5 30.75L30.2188 26.25L28.5938 25.3125ZM25.3438 23.4375L25.5625 29.3438L27.1875 30.2813L26.9688 24.375L25.3438 23.4375Z" fill="url(#paint7_linear_30901_98056)"/>
<path d="M28.5938 25.3125L32.625 23.3125L34.25 24.25L30.2188 26.25L28.5938 25.3125ZM25.3438 23.4375L30.5625 20.6875L32.1875 21.625L26.9688 24.375L25.3438 23.4375ZM10.1875 14.6875L6.15625 16.6875L4.53125 15.75L8.5625 13.75L10.1875 14.6875ZM13.4375 16.5625L8.21875 19.3438L6.59375 18.4063L11.8125 15.625L13.4375 16.5625ZM10.1875 14.6875L9.90625 10.1875L8.28125 9.25L8.5625 13.75L10.1875 14.6875Z" fill="url(#paint8_linear_30901_98056)"/>
<path d="M13.4375 16.5625L13.2188 10.6875L11.5938 9.75L11.8125 15.625L13.4375 16.5625Z" fill="url(#paint9_linear_30901_98056)"/>
<path d="M19.375 25.9063L14.25 22.9688V17.0625L19.375 14.0938L24.5 17.0313V22.9375L19.375 25.9063ZM15.8125 22.0625L19.375 24.0938L22.9375 22.0313V17.9688L19.375 15.9063L15.8125 17.9688V22.0625Z" fill="url(#paint10_linear_30901_98056)"/>
</g>
<defs>
<linearGradient id="paint0_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint1_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint2_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint3_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint4_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint5_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint6_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint7_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint8_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint9_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint10_linear_30901_98056" x1="36" y1="8" x2="6.5" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -0,0 +1,61 @@
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 25 25" fill="none">
<g opacity="0.24">
<path d="M12.1094 0.742188L11.5234 1.75781V23.2422L12.1094 24.2578L12.6953 23.2422V1.75781L12.1094 0.742188Z" fill="url(#paint0_linear_30901_98201)"/>
<path d="M12.1094 5.85938L9.76562 4.29688V3.125L12.1094 4.6875V5.85938ZM12.1094 8.20313L8.98438 6.25V5.07813L12.1094 7.03125V8.20313ZM12.1094 5.85938L14.4531 4.29688V3.125L12.1094 4.6875V5.85938ZM12.1094 8.20313L15.2344 6.25V5.07813L12.1094 7.03125V8.20313ZM12.1094 19.1406L9.76562 20.7031V21.875L12.1094 20.3125V19.1406ZM12.1094 16.7969L8.98438 18.75V19.9219L12.1094 17.9688V16.7969ZM12.1094 19.1406L14.4531 20.7031V21.875L12.1094 20.3125V19.1406ZM12.1094 16.7969L15.2344 18.75V19.9219L12.1094 17.9688V16.7969Z" fill="url(#paint1_linear_30901_98201)"/>
<path d="M1.93359 18.3789H3.10547L21.6992 7.63672L22.2852 6.6211H21.1133L2.51953 17.3633L1.93359 18.3789Z" fill="url(#paint2_linear_30901_98201)"/>
<path d="M6.34766 15.8203L6.17188 18.6328L5.15625 19.2188L5.33203 16.4063L6.34766 15.8203ZM8.37891 14.6484L8.24219 18.3398L7.22656 18.9258L7.36328 15.2344L8.37891 14.6484Z" fill="url(#paint3_linear_30901_98201)"/>
<path d="M6.34766 15.8203L3.82813 14.5703L2.8125 15.1563L5.33203 16.4063L6.34766 15.8203ZM8.37891 14.6484L5.11719 12.9297L4.10156 13.5156L7.36328 15.2344L8.37891 14.6484ZM17.8516 9.17969L20.3711 10.4297L21.3867 9.84375L18.8672 8.59375L17.8516 9.17969ZM15.8203 10.3516L19.082 12.0898L20.0977 11.5039L16.8359 9.76563L15.8203 10.3516Z" fill="url(#paint4_linear_30901_98201)"/>
<path d="M17.8516 9.17969L18.0273 6.36719L19.043 5.78125L18.8672 8.59375L17.8516 9.17969ZM15.8203 10.3516L15.957 6.67969L16.9727 6.09375L16.8359 9.76563L15.8203 10.3516Z" fill="url(#paint5_linear_30901_98201)"/>
<path d="M22.2852 18.3789H21.1133L2.51953 7.63672L1.93359 6.6211H3.10547L21.6992 17.3633L22.2852 18.3789Z" fill="url(#paint6_linear_30901_98201)"/>
<path d="M17.8711 15.8203L18.0469 18.6328L19.0625 19.2188L18.8867 16.4063L17.8711 15.8203ZM15.8398 14.6484L15.9766 18.3398L16.9922 18.9258L16.8555 15.2344L15.8398 14.6484Z" fill="url(#paint7_linear_30901_98201)"/>
<path d="M17.8711 15.8203L20.3906 14.5703L21.4062 15.1563L18.8867 16.4063L17.8711 15.8203ZM15.8398 14.6484L19.1016 12.9297L20.1172 13.5156L16.8555 15.2344L15.8398 14.6484ZM6.36719 9.17969L3.84766 10.4297L2.83203 9.84375L5.35156 8.59375L6.36719 9.17969ZM8.39844 10.3516L5.13672 12.0898L4.12109 11.5039L7.38281 9.76563L8.39844 10.3516ZM6.36719 9.17969L6.19141 6.36719L5.17578 5.78125L5.35156 8.59375L6.36719 9.17969Z" fill="url(#paint8_linear_30901_98201)"/>
<path d="M8.39844 10.3516L8.26172 6.67969L7.24609 6.09375L7.38281 9.76563L8.39844 10.3516Z" fill="url(#paint9_linear_30901_98201)"/>
<path d="M12.1094 16.1914L8.90625 14.3555V10.6641L12.1094 8.80859L15.3125 10.6445V14.3359L12.1094 16.1914ZM9.88281 13.7891L12.1094 15.0586L14.3359 13.7695V11.2305L12.1094 9.94141L9.88281 11.2305V13.7891Z" fill="url(#paint10_linear_30901_98201)"/>
</g>
<defs>
<linearGradient id="paint0_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint1_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint2_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint3_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint4_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint5_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint6_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint7_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint8_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint9_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint10_linear_30901_98201" x1="4" y1="13" x2="22" y2="11.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -0,0 +1,61 @@
<svg xmlns="http://www.w3.org/2000/svg" width="67" height="67" viewBox="0 0 67 67" fill="none">
<g opacity="0.24">
<path d="M32.4532 1.98901L30.8829 4.71089V62.289L32.4532 65.0109L34.0235 62.289V4.71089L32.4532 1.98901Z" fill="url(#paint0_linear_30901_96540)"/>
<path d="M32.4532 15.7031L26.172 11.5156V8.37495L32.4532 12.5625V15.7031ZM32.4532 21.9843L24.0782 16.75V13.6093L32.4532 18.8437V21.9843ZM32.4532 15.7031L38.7345 11.5156V8.37495L32.4532 12.5625V15.7031ZM32.4532 21.9843L40.8282 16.75V13.6093L32.4532 18.8437V21.9843ZM32.4532 51.2968L26.172 55.4843V58.625L32.4532 54.4375V51.2968ZM32.4532 45.0156L24.0782 50.25V53.3906L32.4532 48.1562V45.0156ZM32.4532 51.2968L38.7345 55.4843V58.625L32.4532 54.4375V51.2968ZM32.4532 45.0156L40.8282 50.25V53.3906L32.4532 48.1562V45.0156Z" fill="url(#paint1_linear_30901_96540)"/>
<path d="M5.18213 49.2554H8.32275L58.154 20.4664L59.7243 17.7445H56.5837L6.75244 46.5336L5.18213 49.2554Z" fill="url(#paint2_linear_30901_96540)"/>
<path d="M17.0118 42.3984L16.5407 49.9359L13.8188 51.5062L14.2899 43.9687L17.0118 42.3984ZM22.4556 39.2578L22.0892 49.1507L19.3673 50.721L19.7337 40.8281L22.4556 39.2578Z" fill="url(#paint3_linear_30901_96540)"/>
<path d="M17.0118 42.3984L10.2595 39.0484L7.5376 40.6187L14.2899 43.9687L17.0118 42.3984ZM22.4556 39.2578L13.7142 34.6515L10.9923 36.2218L19.7337 40.8281L22.4556 39.2578ZM47.8423 24.6015L54.5946 27.9515L57.3165 26.3812L50.5642 23.0312L47.8423 24.6015ZM42.3985 27.7421L51.1399 32.4007L53.8618 30.8304L45.1204 26.1718L42.3985 27.7421Z" fill="url(#paint4_linear_30901_96540)"/>
<path d="M47.8423 24.6015L48.3134 17.064L51.0353 15.4937L50.5642 23.0312L47.8423 24.6015ZM42.3985 27.7421L42.7649 17.9015L45.4868 16.3312L45.1204 26.1718L42.3985 27.7421Z" fill="url(#paint5_linear_30901_96540)"/>
<path d="M59.7243 49.2554H56.5837L6.75244 20.4664L5.18213 17.7445H8.32275L58.154 46.5336L59.7243 49.2554Z" fill="url(#paint6_linear_30901_96540)"/>
<path d="M47.8946 42.3984L48.3657 49.9359L51.0876 51.5062L50.6165 43.9687L47.8946 42.3984ZM42.4509 39.2578L42.8173 49.1507L45.5392 50.721L45.1728 40.8281L42.4509 39.2578Z" fill="url(#paint7_linear_30901_96540)"/>
<path d="M47.8946 42.3984L54.647 39.0484L57.3688 40.6187L50.6165 43.9687L47.8946 42.3984ZM42.4509 39.2578L51.1923 34.6515L53.9142 36.2218L45.1728 40.8281L42.4509 39.2578ZM17.0642 24.6015L10.3118 27.9515L7.58994 26.3812L14.3423 23.0312L17.0642 24.6015ZM22.5079 27.7421L13.7665 32.4007L11.0446 30.8304L19.786 26.1718L22.5079 27.7421ZM17.0642 24.6015L16.5931 17.064L13.8712 15.4937L14.3423 23.0312L17.0642 24.6015Z" fill="url(#paint8_linear_30901_96540)"/>
<path d="M22.5079 27.7421L22.1415 17.9015L19.4196 16.3312L19.786 26.1718L22.5079 27.7421Z" fill="url(#paint9_linear_30901_96540)"/>
<path d="M32.4532 43.3929L23.8688 38.4726V28.5796L32.4532 23.607L41.0376 28.5273V38.4203L32.4532 43.3929ZM26.486 36.9546L32.4532 40.357L38.4204 36.9023V30.0976L32.4532 26.6429L26.486 30.0976V36.9546Z" fill="url(#paint10_linear_30901_96540)"/>
</g>
<defs>
<linearGradient id="paint0_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint1_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint2_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint3_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint4_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint5_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint6_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint7_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint8_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint9_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint10_linear_30901_96540" x1="32.4532" y1="1.98901" x2="32.4532" y2="65.0109" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -0,0 +1,27 @@
<svg width="29" height="12" viewBox="0 0 29 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_di_30901_97735)">
<path d="M23 1.59997L1 1.59998" stroke="url(#paint0_linear_30901_97735)" stroke-width="2" stroke-linecap="round" shape-rendering="crispEdges"/>
</g>
<defs>
<filter id="filter0_di_30901_97735" x="-4.6" y="-2.43187e-05" width="33.2" height="11.2" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2.3"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.500815 0 0 0 0 0.168025 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_30901_97735"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_30901_97735" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.724544 0 0 0 0 0.338905 0 0 0 0.36 0"/>
<feBlend mode="normal" in2="shape" result="effect2_innerShadow_30901_97735"/>
</filter>
<linearGradient id="paint0_linear_30901_97735" x1="1" y1="2.09998" x2="23" y2="2.09997" gradientUnits="userSpaceOnUse">
<stop stop-color="#BB182C"/>
<stop offset="1" stop-color="#BB182C" stop-opacity="0.1"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,30 @@
<svg width="136" height="170" viewBox="0 0 136 170" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_di_30901_97737)">
<path d="M166.6 83.1323L5.6001 83.1323" stroke="url(#paint0_linear_30901_97737)" stroke-width="2" stroke-linecap="round"/>
<path d="M58.6001 94.2076C63.9919 93.5518 77.6171 90.3167 88.9836 82.6225M88.9836 82.6225C86.142 70.1629 70.8409 53.9874 62.3161 62.5125C53.7912 71.0376 63.1904 82.6225 88.9836 82.6225Z" stroke="#BB182C" stroke-width="2"/>
<path d="M119.6 94.3567C114.336 93.698 101.035 90.4488 89.939 82.7209M89.939 82.7209C92.7131 70.2068 107.65 53.9605 115.972 62.5229C124.295 71.0853 115.119 82.7209 89.939 82.7209Z" stroke="#BB182C" stroke-width="2"/>
<path d="M139.6 160.132L39.6001 1.13232" stroke="#BB182C" stroke-width="2"/>
</g>
<defs>
<filter id="filter0_di_30901_97737" x="9.77516e-05" y="-2.43187e-05" width="172.2" height="169.265" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2.3"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.500815 0 0 0 0 0.168025 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_30901_97737"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_30901_97737" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.724544 0 0 0 0 0.338905 0 0 0 0.36 0"/>
<feBlend mode="normal" in2="shape" result="effect2_innerShadow_30901_97737"/>
</filter>
<linearGradient id="paint0_linear_30901_97737" x1="5.6001" y1="83.6323" x2="29.2468" y2="83.1261" gradientUnits="userSpaceOnUse">
<stop stop-color="#BB182C" stop-opacity="0.1"/>
<stop offset="1" stop-color="#BB182C"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,61 @@
<svg width="78" height="81" viewBox="0 0 78 81" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.24">
<path d="M40.203 2.46411L38.2577 5.83599V77.1641L40.203 80.536L42.1483 77.1641V5.83599L40.203 2.46411Z" fill="url(#paint0_linear_30901_97724)"/>
<path d="M40.203 19.4532L32.4218 14.2657V10.375L40.203 15.5625V19.4532ZM40.203 27.2344L29.828 20.75V16.8594L40.203 23.3438V27.2344ZM40.203 19.4532L47.9843 14.2657V10.375L40.203 15.5625V19.4532ZM40.203 27.2344L50.578 20.75V16.8594L40.203 23.3438V27.2344ZM40.203 63.5469L32.4218 68.7344V72.625L40.203 67.4375V63.5469ZM40.203 55.7657L29.828 62.25V66.1407L40.203 59.6563V55.7657ZM40.203 63.5469L47.9843 68.7344V72.625L40.203 67.4375V63.5469ZM40.203 55.7657L50.578 62.25V66.1407L40.203 59.6563V55.7657Z" fill="url(#paint1_linear_30901_97724)"/>
<path d="M6.41943 61.018H10.3101L72.0413 25.354L73.9866 21.9821H70.096L8.36475 57.6461L6.41943 61.018Z" fill="url(#paint2_linear_30901_97724)"/>
<path d="M21.0741 52.5235L20.4905 61.861L17.1187 63.8063L17.7022 54.4688L21.0741 52.5235ZM27.8179 48.6329L27.364 60.8883L23.9921 62.8336L24.446 50.5782L27.8179 48.6329Z" fill="url(#paint3_linear_30901_97724)"/>
<path d="M21.0741 52.5235L12.7093 48.3735L9.3374 50.3188L17.7022 54.4688L21.0741 52.5235ZM27.8179 48.6329L16.989 42.9266L13.6171 44.8719L24.446 50.5782L27.8179 48.6329ZM59.2671 30.4766L67.6319 34.6266L71.0038 32.6813L62.639 28.5313L59.2671 30.4766ZM52.5233 34.3672L63.3522 40.1383L66.7241 38.193L55.8952 32.4219L52.5233 34.3672Z" fill="url(#paint4_linear_30901_97724)"/>
<path d="M59.2671 30.4766L59.8507 21.1391L63.2226 19.1938L62.639 28.5313L59.2671 30.4766ZM52.5233 34.3672L52.9772 22.1766L56.3491 20.2313L55.8952 32.4219L52.5233 34.3672Z" fill="url(#paint5_linear_30901_97724)"/>
<path d="M73.9866 61.018H70.096L8.36475 25.354L6.41943 21.9821H10.3101L72.0413 57.6461L73.9866 61.018Z" fill="url(#paint6_linear_30901_97724)"/>
<path d="M59.3319 52.5235L59.9155 61.861L63.2874 63.8063L62.7038 54.4688L59.3319 52.5235ZM52.5882 48.6329L53.0421 60.8883L56.414 62.8336L55.9601 50.5782L52.5882 48.6329Z" fill="url(#paint7_linear_30901_97724)"/>
<path d="M59.3319 52.5235L67.6968 48.3735L71.0687 50.3188L62.7038 54.4688L59.3319 52.5235ZM52.5882 48.6329L63.4171 42.9266L66.789 44.8719L55.9601 50.5782L52.5882 48.6329ZM21.139 30.4766L12.7741 34.6266L9.40225 32.6813L17.7671 28.5313L21.139 30.4766ZM27.8827 34.3672L17.0538 40.1383L13.6819 38.193L24.5108 32.4219L27.8827 34.3672ZM21.139 30.4766L20.5554 21.1391L17.1835 19.1938L17.7671 28.5313L21.139 30.4766Z" fill="url(#paint8_linear_30901_97724)"/>
<path d="M27.8827 34.3672L27.4288 22.1766L24.0569 20.2313L24.5108 32.4219L27.8827 34.3672Z" fill="url(#paint9_linear_30901_97724)"/>
<path d="M40.203 53.7555L29.5687 47.6602V35.4047L40.203 29.2446L50.8374 35.3399V47.5954L40.203 53.7555ZM32.8108 45.7797L40.203 49.9946L47.5952 45.7149V37.2852L40.203 33.0055L32.8108 37.2852V45.7797Z" fill="url(#paint10_linear_30901_97724)"/>
</g>
<defs>
<linearGradient id="paint0_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint1_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint2_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint3_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint4_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint5_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint6_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint7_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint8_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint9_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
<linearGradient id="paint10_linear_30901_97724" x1="40.203" y1="2.46411" x2="40.203" y2="80.536" gradientUnits="userSpaceOnUse">
<stop stop-color="#3370FF"/>
<stop offset="1" stop-color="#F0F4FF"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -0,0 +1,3 @@
<svg width="27" height="28" viewBox="0 0 27 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.62226 -2.00591C6.23794 -1.79022 5.95648 -1.43496 5.83917 -1.01752L4.96831 1.85934L2.0224 1.00889C1.80798 0.943838 1.58239 0.921415 1.35895 0.942944C1.13551 0.964473 0.91876 1.02952 0.721498 1.13423C0.427919 1.2902 0.188641 1.52812 0.0342524 1.81759C-0.120136 2.10705 -0.182618 2.4349 -0.145207 2.75922C-0.107796 3.08355 0.0278096 3.38961 0.244271 3.63827C0.460734 3.88694 0.748218 4.06691 1.06997 4.15519L4.95928 5.27799L8.02483 10.7845L1.82406 10.5278L-1.60572 7.39941C-1.76707 7.2523 -1.95652 7.13767 -2.16324 7.06205C-2.36996 6.98644 -2.5899 6.95133 -2.81052 6.95873C-3.03114 6.96612 -3.2481 7.01588 -3.44902 7.10516C-3.64995 7.19444 -3.83089 7.3215 -3.98154 7.47907C-4.13218 7.63664 -4.24957 7.82165 -4.32699 8.02352C-4.40442 8.2254 -4.44038 8.44019 -4.4328 8.65563C-4.42523 8.87108 -4.37427 9.08296 -4.28285 9.27917C-4.19143 9.47538 -4.06132 9.65209 -3.89997 9.79921L-1.24539 12.2195L-3.72375 14.8118C-4.02798 15.1301 -4.19031 15.5533 -4.17501 15.9884C-4.15972 16.4235 -3.96805 16.8349 -3.64218 17.132C-3.31631 17.4291 -2.88293 17.5876 -2.43738 17.5727C-1.99183 17.5577 -1.5706 17.3706 -1.26636 17.0523L1.83225 13.8097L8.04926 14.0687L4.89153 19.305L0.420006 20.0815C-0.0189056 20.1578 -0.408794 20.4013 -0.663889 20.7583C-0.790198 20.9351 -0.879614 21.1345 -0.927029 21.345C-0.974445 21.5555 -0.978932 21.7731 -0.940233 21.9854C-0.901536 22.1976 -0.820411 22.4003 -0.701492 22.5819C-0.582571 22.7636 -0.428188 22.9205 -0.24715 23.0439C0.11847 23.293 0.570451 23.3901 1.00936 23.3137L4.5848 22.692L5.22145 26.1837C5.26012 26.3959 5.34122 26.5987 5.46013 26.7803C5.57903 26.962 5.73342 27.119 5.91447 27.2423C6.09551 27.3657 6.29967 27.4531 6.51529 27.4994C6.7309 27.5457 6.95375 27.5501 7.1711 27.5123C7.38845 27.4745 7.59605 27.3953 7.78204 27.2791C7.96803 27.163 8.12877 27.0122 8.25508 26.8353C8.38139 26.6585 8.47079 26.4591 8.51818 26.2486C8.56557 26.038 8.57003 25.8204 8.53129 25.6081L7.70753 21.0961L10.8584 15.8744L13.924 21.3809L12.7742 25.1791C12.7065 25.3871 12.682 25.6062 12.7021 25.8236C12.7222 26.041 12.7865 26.2523 12.8912 26.4451C12.996 26.638 13.1391 26.8084 13.3122 26.9466C13.4852 27.0847 13.6848 27.1877 13.8991 27.2496C14.1135 27.3115 14.3383 27.331 14.5605 27.307C14.7826 27.2829 14.9977 27.2158 15.1929 27.1096C15.3882 27.0034 15.5598 26.8602 15.6977 26.6884C15.8356 26.5167 15.937 26.3197 15.996 26.1092L16.8669 23.2323L19.8128 24.0828C20.0258 24.1489 20.2502 24.1729 20.4728 24.1532C20.6955 24.1336 20.9118 24.0708 21.1093 23.9685C21.3067 23.8662 21.4813 23.7265 21.6227 23.5575C21.7642 23.3884 21.8697 23.1936 21.9331 22.9842C21.9964 22.7749 22.0164 22.5553 21.9918 22.3384C21.9672 22.1214 21.8985 21.9115 21.7897 21.7208C21.6809 21.5301 21.5343 21.3625 21.3584 21.2278C21.1825 21.0931 20.9808 20.9941 20.7652 20.9365L16.8759 19.8137L13.8104 14.3071L20.0112 14.5638L23.4409 17.6922C23.6023 17.8394 23.7917 17.9541 23.9985 18.0298C24.2052 18.1054 24.4252 18.1406 24.6458 18.1332C24.8665 18.1258 25.0835 18.0761 25.2844 17.9868C25.4854 17.8975 25.6664 17.7704 25.817 17.6128C25.9677 17.4553 26.0851 17.2702 26.1625 17.0683C26.2399 16.8664 26.2759 16.6516 26.2683 16.4361C26.2607 16.2206 26.2097 16.0087 26.1182 15.8125C26.0268 15.6163 25.8966 15.4396 25.7352 15.2925L23.0806 12.8722L25.559 10.2798C25.7097 10.1223 25.8271 9.93724 25.9046 9.73535C25.9821 9.53346 26.018 9.31864 26.0105 9.10316C26.0029 8.88769 25.952 8.67577 25.8606 8.47952C25.7691 8.28328 25.639 8.10654 25.4777 7.9594C25.3163 7.81227 25.1268 7.69762 24.92 7.62201C24.7133 7.5464 24.4933 7.5113 24.2727 7.51872C24.052 7.52614 23.835 7.57594 23.6341 7.66527C23.4331 7.7546 23.2522 7.8817 23.1016 8.03933L20.003 11.282L13.786 11.023L16.9437 5.7867L21.4152 5.01018C21.6326 4.97243 21.8402 4.89323 22.0262 4.77711C22.2122 4.66099 22.373 4.51022 22.4993 4.33342C22.6257 4.15662 22.7151 3.95724 22.7626 3.74667C22.81 3.53611 22.8145 3.31848 22.7758 3.10622C22.7371 2.89396 22.6559 2.69122 22.537 2.50959C22.418 2.32795 22.2636 2.17098 22.0826 2.04763C21.9015 1.92429 21.6973 1.83698 21.4817 1.7907C21.266 1.74442 21.0432 1.74008 20.8258 1.77792L17.2504 2.39965L16.6138 -1.09199C16.5356 -1.52062 16.2863 -1.90137 15.9207 -2.15048C15.5551 -2.3996 15.1031 -2.49667 14.6642 -2.42035C14.2253 -2.34403 13.8354 -2.10056 13.5803 -1.74351C13.3252 -1.38646 13.2258 -0.945071 13.3039 -0.516447L14.1277 3.99557L10.9768 9.21726L7.91123 3.71074L9.06098 -0.0874187C9.16328 -0.402515 9.16573 -0.740436 9.06802 -1.05692C8.97031 -1.3734 8.77699 -1.65368 8.51339 -1.86104C8.2498 -2.06841 7.92821 -2.19319 7.59076 -2.21903C7.25331 -2.24488 6.91574 -2.1706 6.62226 -2.00591Z" fill="white" fill-opacity="0.2"/>
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="23" height="24" viewBox="0 0 23 24" fill="none">
<path d="M15.3871 0.000406097C15.0178 0.0095006 14.667 0.170233 14.4109 0.44759L12.6008 2.33317L10.7906 0.44759C10.6602 0.30789 10.5041 0.196845 10.3318 0.121017C10.1594 0.0451883 9.97422 0.00611411 9.78712 0.00610271C9.50861 0.0061789 9.23645 0.0927728 9.00544 0.254814C8.77443 0.416854 8.59506 0.646979 8.49026 0.915768C8.38546 1.18456 8.35999 1.47979 8.41712 1.76374C8.47424 2.04768 8.61136 2.30742 8.81095 2.50976L11.2008 4.99919V10.5705L6.76564 7.79907L5.5297 3.93392C5.47153 3.75213 5.37955 3.58406 5.25902 3.4393C5.1385 3.29454 4.99178 3.17593 4.82724 3.09024C4.66271 3.00454 4.48358 2.95344 4.30009 2.93986C4.1166 2.92627 3.93234 2.95047 3.75782 3.01107C3.58331 3.07166 3.42196 3.16747 3.28299 3.29302C3.14402 3.41857 3.03015 3.5714 2.94789 3.74279C2.86562 3.91418 2.81657 4.10077 2.80353 4.29191C2.79048 4.48304 2.81371 4.67498 2.87189 4.85677L3.82892 7.84749L0.957823 8.8444C0.605375 8.96678 0.314032 9.22999 0.147887 9.57612C-0.0182588 9.92226 -0.0455975 10.323 0.0718851 10.6901C0.189368 11.0572 0.442048 11.3607 0.774339 11.5338C1.10663 11.7069 1.49131 11.7353 1.84376 11.613L5.43399 10.3654L9.88009 13.1453L5.43399 15.9253L1.84376 14.6777C1.49131 14.5554 1.10663 14.5838 0.774339 14.7569C0.609805 14.8426 0.463086 14.9612 0.342559 15.106C0.222032 15.2507 0.130057 15.4188 0.0718851 15.6006C0.0137136 15.7824 -0.00951502 15.9743 0.00352535 16.1654C0.0165657 16.3566 0.0656195 16.5432 0.147886 16.7146C0.314032 17.0607 0.605375 17.3239 0.957823 17.4463L3.82892 18.4432L2.87189 21.4339C2.81368 21.6157 2.79042 21.8077 2.80343 21.9988C2.81645 22.19 2.86549 22.3766 2.94775 22.548C3.03001 22.7194 3.14389 22.8723 3.28287 22.9979C3.42185 23.1234 3.58321 23.2193 3.75774 23.2799C3.93228 23.3405 4.11656 23.3647 4.30008 23.3511C4.48359 23.3375 4.66273 23.2864 4.82728 23.2006C4.99182 23.1149 5.13854 22.9963 5.25907 22.8515C5.37959 22.7067 5.47155 22.5386 5.5297 22.3568L6.76564 18.4916L11.2008 15.7202V21.2915L8.81095 23.7809C8.67658 23.9153 8.56931 24.0763 8.49541 24.2544C8.42151 24.4325 8.38247 24.6241 8.38058 24.8182C8.37868 25.0122 8.41397 25.2046 8.48437 25.3843C8.55478 25.5639 8.65889 25.7271 8.7906 25.8643C8.92231 26.0015 9.07897 26.1099 9.25142 26.1833C9.42387 26.2566 9.60863 26.2934 9.79489 26.2914C9.98115 26.2894 10.1652 26.2488 10.3361 26.1718C10.5071 26.0948 10.6616 25.9831 10.7906 25.8431L12.6008 23.9575L14.4109 25.8431C14.5399 25.9831 14.6945 26.0948 14.8654 26.1718C15.0364 26.2488 15.2204 26.2894 15.4067 26.2914C15.5929 26.2934 15.7777 26.2566 15.9502 26.1833C16.1226 26.1099 16.2793 26.0015 16.411 25.8643C16.5427 25.7271 16.6468 25.5639 16.7172 25.3843C16.7876 25.2046 16.8229 25.0122 16.821 24.8182C16.8191 24.6241 16.7801 24.4325 16.7062 24.2544C16.6323 24.0763 16.525 23.9153 16.3906 23.7809L14.0008 21.2915V15.7202L18.4359 18.4916L19.6719 22.3568C19.73 22.5386 19.822 22.7067 19.9425 22.8515C20.063 22.9963 20.2097 23.115 20.3743 23.2007C20.5388 23.2864 20.718 23.3375 20.9015 23.3511C21.085 23.3647 21.2693 23.3405 21.4439 23.2799C21.6184 23.2193 21.7798 23.1235 21.9188 22.9979C22.0577 22.8724 22.1716 22.7195 22.2539 22.5481C22.3361 22.3766 22.3852 22.19 22.3982 21.9988C22.4112 21.8077 22.3879 21.6157 22.3297 21.4339L21.3727 18.4432L24.2438 17.4463C24.4183 17.3857 24.5797 17.2899 24.7187 17.1644C24.8577 17.0389 24.9716 16.886 25.0539 16.7146C25.1362 16.5432 25.1853 16.3566 25.1984 16.1654C25.2114 15.9743 25.1882 15.7823 25.13 15.6005C25.0718 15.4187 24.9798 15.2506 24.8593 15.1058C24.7387 14.961 24.592 14.8424 24.4274 14.7567C24.2628 14.671 24.0837 14.62 23.9002 14.6064C23.7166 14.5928 23.5323 14.6171 23.3578 14.6777L19.7676 15.9253L15.3215 13.1453L19.7676 10.3654L23.3578 11.613C23.5323 11.6736 23.7166 11.6978 23.9001 11.6843C24.0837 11.6707 24.2628 11.6196 24.4274 11.5339C24.5919 11.4483 24.7387 11.3296 24.8592 11.1849C24.9798 11.0401 25.0718 10.872 25.13 10.6902C25.1881 10.5084 25.2114 10.3164 25.1983 10.1253C25.1853 9.9341 25.1362 9.74749 25.0539 9.57608C24.9716 9.40468 24.8577 9.25184 24.7187 9.1263C24.5797 9.00076 24.4183 8.90497 24.2438 8.8444L21.3727 7.84749L22.3297 4.85677C22.4472 4.48964 22.4198 4.08893 22.2537 3.74279C22.0875 3.39665 21.7962 3.13344 21.4438 3.01107C21.0913 2.88869 20.7066 2.91717 20.3743 3.09023C20.042 3.2633 19.7894 3.56679 19.6719 3.93392L18.4359 7.79907L14.0008 10.5705V4.99919L16.3906 2.50976C16.594 2.30611 16.7335 2.04323 16.7909 1.75556C16.8484 1.4679 16.8211 1.16887 16.7126 0.897634C16.6042 0.626403 16.4196 0.395623 16.1831 0.235524C15.9465 0.0754252 15.6691 -0.00652579 15.3871 0.000406097Z" fill="white" fill-opacity="0.2"/>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -40,6 +40,9 @@ const ManualCopyModal = dynamic(
() => import('@fastgpt/web/hooks/useCopyData').then((mod) => mod.ManualCopyModal),
{ ssr: false }
);
const ActivityAdModal = dynamic(() => import('@/components/support/activity/ActivityAdModal'), {
ssr: false
});
const pcUnShowLayoutRoute: Record<string, boolean> = {
'/': true,
@ -187,6 +190,7 @@ const Layout = ({ children }: { children: JSX.Element }) => {
)}
<ManualCopyModal />
<ActivityAdModal />
<Loading loading={loading} zIndex={999999} />
</>
);

View File

@ -0,0 +1,209 @@
import React, { useCallback, useMemo } from 'react';
import { useDisclosure } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
import { getActivityAd } from '@/web/common/system/api';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import {
Box,
Flex,
Button,
Image,
Modal,
ModalOverlay,
ModalContent,
ModalCloseButton
} from '@chakra-ui/react';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useLocalStorageState } from 'ahooks';
import { useRouter } from 'next/router';
import { useUserStore } from '@/web/support/user/useUserStore';
const CLOSED_AD_KEY = 'logout-activity-ad';
const CLOSED_AD_DURATION = 24 * 60 * 60 * 1000; // 24 hours
const ActivityAdModal = () => {
const { isOpen, onOpen, onClose } = useDisclosure();
const { t } = useTranslation();
const { feConfigs } = useSystemStore();
const router = useRouter();
const { userInfo } = useUserStore();
// Check if ad was recently closed
const [closedData, setClosedData] = useLocalStorageState<string>(CLOSED_AD_KEY, {
listenStorageChange: true
});
const { data } = useRequest2(
async () => {
if (!feConfigs?.isPlus || !userInfo) return;
return getActivityAd();
},
{
manual: false,
onSuccess(res) {
const shouldShowAd = (() => {
if (!res?.id) return false;
if (!closedData) return true;
try {
const { timestamp, adId } = JSON.parse(closedData) as {
timestamp: number;
adId: string;
};
// 不同的广告 id一定展示
if (adId && res.id !== adId) return true;
const now = Date.now();
// Show if 24 hours passed
return now - timestamp > CLOSED_AD_DURATION;
} catch {
return true;
}
})();
if (res?.activityAdImage && shouldShowAd) {
onOpen();
}
},
refreshDeps: [userInfo]
}
);
const handleClose = useCallback(() => {
if (data?.id) {
setClosedData(JSON.stringify({ timestamp: Date.now(), adId: data.id }));
}
onClose();
}, [data?.id, onClose, setClosedData]);
const handleJoin = useCallback(() => {
if (data?.activityAdLink) {
if (data.activityAdLink.startsWith('/')) {
router.push(data.activityAdLink);
handleClose();
} else {
window.open(data.activityAdLink, '_blank');
}
}
}, [data?.activityAdLink, handleClose, router]);
if (!data?.activityAdImage || !userInfo) {
return null;
}
return isOpen ? (
<Modal
isOpen={isOpen}
onClose={handleClose}
isCentered
size="xl"
closeOnOverlayClick={false}
blockScrollOnMount
>
<ModalOverlay bg="blackAlpha.600" />
<ModalContent
maxW="400px"
bg="white"
borderRadius="10px"
overflow="hidden"
position="relative"
p={0}
>
<ModalCloseButton
position="absolute"
top={1}
right={1}
zIndex={10}
bg={'rgba(244, 246, 248, 0.40)'}
borderRadius={'full'}
boxSize={9}
display={'flex'}
alignItems={'center'}
justifyContent="center"
color={'white'}
_hover={{ bg: 'rgba(244, 246, 248, 0.60)' }}
/>
<Flex direction="column">
{/* Activity Image */}
<Box position="relative">
<Image
src={data.activityAdImage}
alt="Activity"
w="100%"
h="auto"
objectFit="cover"
userSelect="none"
draggable={false}
/>
{/* Gradient overlay for smooth transition */}
<Box
position="absolute"
bottom={0}
left={0}
right={0}
h={10}
bg="linear-gradient(180deg, rgba(255, 255, 255, 0.00) 0%, #FFF 100%)"
pointerEvents="none"
/>
</Box>
<Flex
mt={6}
justifyContent={'center'}
color={'black'}
fontSize="20px"
fontWeight={'medium'}
>
{t('common:activity_ad.title')}
</Flex>
<Flex mt={6} color={'black'} justifyContent={'center'} fontSize={'14px'} px={8}>
{t('common:activity_ad.desc')}
</Flex>
<Flex direction="column" align="center" p={8} bg="white">
<Flex direction="column" width="100%" gap={3}>
<Button
width={'100%'}
bg={'#ED372C'}
color={'white'}
borderRadius={'6px'}
h={10}
sx={{
'&::before': {
content: '""',
position: 'absolute',
left: '0',
top: '0',
width: '30px',
height: '30px',
backgroundImage: `url('/imgs/system/snowflakeLeft.svg')`,
backgroundRepeat: 'no-repeat'
},
'&::after': {
content: '""',
position: 'absolute',
right: '0',
bottom: '0',
width: '25px',
height: '25px',
backgroundImage: `url('/imgs/system/snowflakeRight.svg')`
}
}}
_hover={{ bg: '#DE0D00' }}
onClick={handleJoin}
>
{t('common:activity_ad.join_now')}
</Button>
<Button width="100%" variant="whiteBase" h={10} onClick={handleClose}>
{t('common:activity_ad.later')}
</Button>
</Flex>
</Flex>
</Flex>
</ModalContent>
</Modal>
) : null;
};
export default React.memo(ActivityAdModal);

View File

@ -135,7 +135,7 @@ export const RechargeModal = ({
<Box
fontSize={'14px'}
fontWeight={'medium'}
>{`${teamPlanStatus?.usedPoints || 0} / ${teamPlanStatus?.totalPoints ?? t('common:Unlimited')}`}</Box>
>{`${Math.round(teamPlanStatus?.usedPoints || 0)} / ${teamPlanStatus?.totalPoints ?? t('common:Unlimited')}`}</Box>
</Flex>
<Flex h={2} w={'full'} p={0.5} bg={'primary.50'} borderRadius={'md'}>
<Box

View File

@ -47,6 +47,27 @@ const QRCodePayModal = ({
const isWxConfigured = feConfigs.payConfig?.wx;
const isBankConfigured = feConfigs.payConfig?.bank;
const MIN_QR_SIZE = 150;
const [dynamicQRSize, setDynamicQRSize] = useState(QR_CODE_SIZE);
useEffect(() => {
const calculateQRSize = () => {
const windowHeight = window.innerHeight;
const reservedSpace = 470 + (tip ? 60 : 0) + (discountCouponName ? 30 : 0);
const availableHeight = windowHeight - reservedSpace;
const newSize = Math.min(QR_CODE_SIZE, Math.max(MIN_QR_SIZE, availableHeight));
setDynamicQRSize(newSize);
};
window.addEventListener('resize', calculateQRSize);
return () => {
window.removeEventListener('resize', calculateQRSize);
};
}, [tip, discountCouponName]);
const [payWayRenderData, setPayWayRenderData] = useState<{
qrCode?: string;
iframeCode?: string;
@ -99,7 +120,7 @@ const QRCodePayModal = ({
const canvas = document.createElement('canvas');
QRCode.toCanvas(canvas, payWayRenderData.qrCode, {
width: QR_CODE_SIZE,
width: dynamicQRSize,
margin: 0,
color: {
dark: '#000000',
@ -113,7 +134,7 @@ const QRCodePayModal = ({
}
})
.catch(console.error);
}, [payWayRenderData.qrCode]);
}, [payWayRenderData.qrCode, dynamicQRSize]);
useEffect(() => {
drawCode();
}, [drawCode]);
@ -140,15 +161,15 @@ const QRCodePayModal = ({
});
const renderPaymentContent = () => {
if (payWayRenderData.qrCode) {
return <Box ref={canvasRef} display={'inline-block'} h={`${QR_CODE_SIZE}px`} />;
return <Box ref={canvasRef} display={'inline-block'} h={`${dynamicQRSize}px`} />;
}
if (payWayRenderData.iframeCode) {
return (
<iframe
srcDoc={payWayRenderData.iframeCode}
style={{
width: QR_CODE_SIZE + 5,
height: QR_CODE_SIZE + 5,
width: dynamicQRSize + 5,
height: dynamicQRSize + 5,
border: 'none',
display: 'inline-block'
}}
@ -169,6 +190,7 @@ const QRCodePayModal = ({
iconSrc="/imgs/modal/wallet.svg"
w={'600px'}
onClose={onClose}
closeOnOverlayClick={false}
>
<ModalBody textAlign={'center'} padding={['16px 24px', '32px 52px']}>
{tip && <LightTip text={tip} mb={6} textAlign={'left'} />}

View File

@ -3,12 +3,12 @@ import type { StandardSubLevelEnum } from '@fastgpt/global/support/wallet/sub/co
import { SubModeEnum } from '@fastgpt/global/support/wallet/sub/constants';
import React, { useMemo } from 'react';
import { standardSubLevelMap } from '@fastgpt/global/support/wallet/sub/constants';
import { Box, Flex, Grid } from '@chakra-ui/react';
import { Box, Flex, Grid, Text } from '@chakra-ui/react';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useTranslation } from 'next-i18next';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import dynamic from 'next/dynamic';
import type { TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type';
import type { TeamSubSchemaType } from '@fastgpt/global/support/wallet/sub/type';
import Markdown from '@/components/Markdown';
import MyPopover from '@fastgpt/web/components/common/MyPopover';
@ -23,7 +23,7 @@ const StandardPlanContentList = ({
}: {
level: `${StandardSubLevelEnum}`;
mode: `${SubModeEnum}`;
standplan?: TeamSubSchema;
standplan?: TeamSubSchemaType;
}) => {
const { t } = useTranslation();
const { subPlans } = useSystemStore();
@ -38,6 +38,8 @@ const StandardPlanContentList = ({
...standardSubLevelMap[level as `${StandardSubLevelEnum}`],
totalPoints:
standplan?.totalPoints ?? plan.totalPoints * (mode === SubModeEnum.month ? 1 : 12),
annualBonusPoints:
mode === SubModeEnum.month ? 0 : standplan?.annualBonusPoints ?? plan.annualBonusPoints,
requestsPerMinute: standplan?.requestsPerMinute ?? plan.requestsPerMinute,
maxTeamMember: standplan?.maxTeamMember ?? plan.maxTeamMember,
maxAppAmount: standplan?.maxApp ?? plan.maxAppAmount,
@ -56,6 +58,7 @@ const StandardPlanContentList = ({
level,
mode,
standplan?.totalPoints,
standplan?.annualBonusPoints,
standplan?.requestsPerMinute,
standplan?.maxTeamMember,
standplan?.maxApp,
@ -72,13 +75,31 @@ const StandardPlanContentList = ({
return planContent ? (
<Grid gap={4} fontSize={'sm'} fontWeight={500}>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon
name={'price/right'}
w={'16px'}
mr={3}
color={planContent.annualBonusPoints ? '#BB182C' : 'primary.600'}
/>
<Flex alignItems={'center'}>
<Box fontWeight={'bold'} color={'myGray.600'}>
{t('common:n_ai_points', {
amount: planContent.totalPoints
})}
</Box>
{planContent.annualBonusPoints ? (
<>
<Text fontWeight={'bold'} color={'myGray.600'} textDecoration={'line-through'} mr={1}>
{planContent.totalPoints}
</Text>
<Text fontWeight={'bold'} color={'#DF531E'}>
{planContent.totalPoints + planContent.annualBonusPoints}
</Text>
<Text color={'myGray.600'} ml={1}>
{t('common:support.wallet.subscription.point')}
</Text>
</>
) : (
<Box fontWeight={'bold'} color={'myGray.600'} display={'flex'}>
<Text>{planContent.totalPoints}</Text>
<Text ml={1}>{t('common:support.wallet.subscription.point')}</Text>
</Box>
)}
<ModelPriceModal>
{({ onOpen }) => (
<QuestionTip ml={1} label={t('common:aipoint_desc')} onClick={onOpen} />
@ -87,7 +108,7 @@ const StandardPlanContentList = ({
</Flex>
</Flex>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box fontWeight={'bold'} color={'myGray.600'}>
{t('common:n_dataset_size', {
amount: planContent.maxDatasetSize
@ -95,7 +116,7 @@ const StandardPlanContentList = ({
</Box>
</Flex>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>
{t('common:n_team_members', {
amount: planContent.maxTeamMember
@ -103,7 +124,7 @@ const StandardPlanContentList = ({
</Box>
</Flex>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>
{t('common:n_agent_amount', {
amount: planContent.maxAppAmount
@ -111,7 +132,7 @@ const StandardPlanContentList = ({
</Box>
</Flex>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>
{t('common:n_dataset_amount', {
amount: planContent.maxDatasetAmount
@ -119,7 +140,7 @@ const StandardPlanContentList = ({
</Box>
</Flex>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>
{t('common:n_chat_records_retain', {
amount: planContent.chatHistoryStoreDuration
@ -128,7 +149,7 @@ const StandardPlanContentList = ({
</Flex>
{!!planContent.auditLogStoreDuration && (
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>
{t('common:n_team_audit_day', {
amount: planContent.auditLogStoreDuration
@ -137,7 +158,7 @@ const StandardPlanContentList = ({
</Flex>
)}
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>
{t('common:n_team_qpm', {
amount: planContent.requestsPerMinute
@ -147,7 +168,7 @@ const StandardPlanContentList = ({
</Flex>
{!!planContent.websiteSyncPerDataset && (
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box fontWeight={'bold'} color={'myGray.600'}>
{t('common:n_website_sync_max_pages', {
amount: planContent.websiteSyncPerDataset
@ -156,7 +177,7 @@ const StandardPlanContentList = ({
</Flex>
)}
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>
{planContent.ticketResponseTime
? t('common:worker_order_support_time', {
@ -185,7 +206,7 @@ const StandardPlanContentList = ({
</Flex>
{!!planContent.appRegistrationCount && (
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>
{t('common:n_app_registration_amount', {
amount: planContent.appRegistrationCount
@ -195,13 +216,13 @@ const StandardPlanContentList = ({
)}
{planContent.customDomain !== undefined && (
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>
{t('common:n_custom_domain_amount', {
amount: planContent.customDomain
})}
</Box>
<QuestionTip ml={1} label={t('common:n_custom_domain_amount tip')} />
<QuestionTip ml={1} label={t('common:n_custom_domain_amount_tip')} />
</Flex>
)}
</Grid>

View File

@ -24,9 +24,9 @@ const TeamPlanStatusCard = () => {
loadOperationalAd();
}
if (operationalAd?.id) {
const currentKey = `hidden-until-${operationalAd.id}`;
const currentKey = `logout-operational-${operationalAd.id}`;
Object.keys(localStorage).forEach((key) => {
if (key.startsWith('hidden-until-') && key !== currentKey) {
if (key.startsWith('logout-operational-') && key !== currentKey) {
localStorage.removeItem(key);
}
});
@ -34,7 +34,7 @@ const TeamPlanStatusCard = () => {
}, [operationalAd, loadOperationalAd]);
const [hiddenUntil, setHiddenUntil] = useLocalStorageState<number | undefined>(
`hidden-until-${operationalAd?.id}`,
`logout-operational-${operationalAd?.id}`,
{
defaultValue: undefined
}

View File

@ -13,6 +13,7 @@ import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import MySelect from '@fastgpt/web/components/common/MySelect';
import { calculatePrice } from '@fastgpt/global/support/wallet/bill/tools';
import { formatNumberWithUnit } from '@fastgpt/global/common/string/tools';
import { formatActivityExpirationTime } from './utils';
const ExtraPlan = ({ onPaySuccess }: { onPaySuccess?: () => void }) => {
const { t, i18n } = useTranslation();
@ -103,10 +104,16 @@ const ExtraPlan = ({ onPaySuccess }: { onPaySuccess?: () => void }) => {
}
);
// 计算活动时间
const { text: activityExpirationTime } = formatActivityExpirationTime(
subPlans?.activityExpirationTime
);
return (
<VStack>
<Grid gridTemplateColumns={['1fr', '1fr 1fr']} gap={5} w={['100%', 'auto']}>
<Box
position={'relative'}
bg={'white'}
w={'100%'}
px={[4, 8]}
@ -115,18 +122,63 @@ const ExtraPlan = ({ onPaySuccess }: { onPaySuccess?: () => void }) => {
borderWidth={'1px'}
borderColor={'myGray.200'}
boxShadow={'0 1px 2px 0 rgba(19, 51, 107, 0.10), 0 0 1px 0 rgba(19, 51, 107, 0.15)'}
overflow={'hidden'}
>
{subPlans?.activityExpirationTime && (
<>
<Box
position={'absolute'}
top={8}
left={'36%'}
width={'55px'}
height={'64px'}
zIndex={0}
bgImage={'url(/imgs/system/extraSnowflake1.svg)'}
backgroundSize="100% 100%"
backgroundRepeat="no-repeat"
/>
<Box
position={'absolute'}
top={1}
left={'60%'}
width={'25px'}
height={'25px'}
zIndex={0}
bgImage={'url(/imgs/system/extraSnowflake2.svg)'}
backgroundSize="100% 100%"
backgroundRepeat="no-repeat"
/>
<Box
position={'absolute'}
top={1}
right={3}
width={'67px'}
height={'72px'}
zIndex={0}
bgImage={'url(/imgs/system/extraSnowflake3.svg)'}
backgroundSize="100% 100%"
backgroundRepeat="no-repeat"
/>
</>
)}
<Box
position={'relative'}
zIndex={1}
fontSize={'18px'}
fontWeight={'500'}
color={'primary.700'}
pb={6}
pb={subPlans?.activityExpirationTime ? 2 : 6}
borderBottomWidth={'1px'}
borderBottomColor={'myGray.200'}
>
{t('common:support.wallet.subscription.Extra ai points')}
<Box fontSize={'12px'} fontWeight={'normal'} color={'myGray.600'} mt={0.5}>
{activityExpirationTime}
</Box>
</Box>
<Grid
position={'relative'}
zIndex={1}
gridTemplateColumns={['repeat(2, 1fr)', 'repeat(3, 1fr)']}
gap={[2, 3]}
py={[3, 4]}
@ -138,7 +190,8 @@ const ExtraPlan = ({ onPaySuccess }: { onPaySuccess?: () => void }) => {
flexDir={'column'}
alignItems={'center'}
justifyContent={'center'}
p={[3, 4]}
py={extraPointsPackages.length > 6 ? 1 : 2}
px={[3, 4]}
borderRadius={['8px', 'sm']}
borderWidth={'1px'}
borderColor={selectedPackageIndex === index ? '#3E78FF' : 'myGray.200'}
@ -150,10 +203,32 @@ const ExtraPlan = ({ onPaySuccess }: { onPaySuccess?: () => void }) => {
}}
onClick={() => setSelectedPackageIndex(index)}
transition={'all 0.2s'}
position={'relative'}
overflow={'hidden'}
>
{!!pkg.activityBonusPoints && (
<Flex
position={'absolute'}
top={0.5}
right={-8}
minW={24}
py={0.5}
justifyContent={'center'}
fontSize={'10px'}
fontWeight={'bold'}
color={'white'}
bg={'#ED372C'}
transform={'rotate(37deg)'}
whiteSpace={'nowrap'}
>
+{formatNumberWithUnit(pkg.activityBonusPoints, i18n.language)}
</Flex>
)}
<Box fontSize={'24px'} fontWeight={'medium'} color={'myGray.600'}>
{formatNumberWithUnit(pkg.points, i18n.language)}{' '}
{t('common:support.wallet.subscription.point')}
<Box as={'span'} fontSize={'12px'}>
{t('common:support.wallet.subscription.point')}
</Box>
</Box>
<Box
fontSize={['10px', '12px']}
@ -168,7 +243,36 @@ const ExtraPlan = ({ onPaySuccess }: { onPaySuccess?: () => void }) => {
))}
</Grid>
<Flex justifyContent={'space-between'} alignItems={'center'}>
<Flex
position={'relative'}
zIndex={1}
justifyContent={'space-between'}
alignItems={'center'}
>
<Box
fontSize={['13px', '14px']}
color={'myGray.600'}
fontWeight={'medium'}
textAlign={['center', 'left']}
>
{t('common:support.wallet.subscription.total_points')}
</Box>
<Box color={'myGray.600'} fontSize={['18px', '20px']} fontWeight={'medium'}>
{selectedPackageIndex !== undefined && extraPointsPackages[selectedPackageIndex]
? formatNumberWithUnit(
extraPointsPackages[selectedPackageIndex].points +
(extraPointsPackages[selectedPackageIndex]?.activityBonusPoints || 0),
i18n.language
)
: '--'}
</Box>
</Flex>
<Flex
position={'relative'}
zIndex={1}
justifyContent={'space-between'}
alignItems={'center'}
>
<Box
fontSize={['13px', '14px']}
color={'myGray.600'}
@ -187,6 +291,8 @@ const ExtraPlan = ({ onPaySuccess }: { onPaySuccess?: () => void }) => {
</Flex>
<Button
position={'relative'}
zIndex={1}
w={'100%'}
h={['40px', '44px']}
variant={'primaryGhost'}
@ -210,7 +316,7 @@ const ExtraPlan = ({ onPaySuccess }: { onPaySuccess?: () => void }) => {
{t('common:support.wallet.Buy')}
</Button>
<HStack color={'blue.700'} mt={[4, 6]} spacing={[2, 0]}>
<HStack position={'relative'} zIndex={1} color={'blue.700'} mt={[4, 6]} spacing={[2, 0]}>
<MyIcon name={'infoRounded'} w={['16px', '18px']} />
<Box fontSize={['12px', '14px']} fontWeight={'medium'} lineHeight={['1.4', 'normal']}>
{t('common:support.wallet.subscription.Update extra ai points tips')}
@ -349,7 +455,7 @@ const ExtraPlan = ({ onPaySuccess }: { onPaySuccess?: () => void }) => {
</Flex>
</Flex>
<Box mt={['auto', 0]}>
<Box mt={['auto', 4]}>
<Button
w={'100%'}
h={['40px', '44px']}

View File

@ -1,4 +1,4 @@
import React, { useMemo, useState } from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { Box, Button, Flex, Grid } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
@ -6,7 +6,7 @@ import { StandardSubLevelEnum, SubModeEnum } from '@fastgpt/global/support/walle
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { standardSubLevelMap } from '@fastgpt/global/support/wallet/sub/constants';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { type TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type';
import { type TeamSubSchemaType } from '@fastgpt/global/support/wallet/sub/type';
import QRCodePayModal, { type QRPayProps } from '@/components/support/wallet/QRCodePayModal';
import { postCreatePayBill } from '@/web/support/wallet/bill/api';
import { getDiscountCouponList } from '@/web/support/wallet/sub/discountCoupon/api';
@ -17,18 +17,25 @@ import {
DiscountCouponStatusEnum,
DiscountCouponTypeEnum
} from '@fastgpt/global/support/wallet/sub/discountCoupon/constants';
import { formatActivityExpirationTime } from './utils';
export enum PackageChangeStatusEnum {
buy = 'buy',
renewal = 'renewal',
upgrade = 'upgrade'
}
const NEW_PLAN_LEVELS = [
StandardSubLevelEnum.free,
StandardSubLevelEnum.basic,
StandardSubLevelEnum.advanced,
StandardSubLevelEnum.custom
];
const Standard = ({
standardPlan: myStandardPlan,
onPaySuccess
}: {
standardPlan?: TeamSubSchema;
standardPlan?: TeamSubSchemaType;
onPaySuccess?: () => void;
}) => {
const { t } = useTranslation();
@ -42,18 +49,15 @@ const Standard = ({
const [packageChange, setPackageChange] = useState<PackageChangeStatusEnum>();
const { subPlans, feConfigs } = useSystemStore();
const [selectSubMode, setSelectSubMode] = useState<`${SubModeEnum}`>(SubModeEnum.month);
const hasActivityExpiration =
!!subPlans?.activityExpirationTime && selectSubMode === SubModeEnum.year;
const NEW_PLAN_LEVELS = [
StandardSubLevelEnum.free,
StandardSubLevelEnum.basic,
StandardSubLevelEnum.advanced,
StandardSubLevelEnum.custom
];
const {
data: coupons = [],
loading,
runAsync: getCoupons
} = useRequest2(
useEffect(() => {
setSelectSubMode(subPlans?.activityExpirationTime ? SubModeEnum.year : SubModeEnum.month);
}, [subPlans?.activityExpirationTime]);
// 获取优惠券
const { data: coupons = [], runAsync: getCoupons } = useRequest2(
async () => {
if (!myStandardPlan?.teamId) return [];
return getDiscountCouponList(myStandardPlan.teamId);
@ -63,7 +67,7 @@ const Standard = ({
refreshDeps: [myStandardPlan?.teamId]
}
);
// 匹配合适的优惠券
const matchedCoupon = useMemo(() => {
const targetType =
selectSubMode === SubModeEnum.month
@ -99,6 +103,7 @@ const Standard = ({
maxDatasetAmount: myStandardPlan?.maxDataset || value.maxDatasetAmount,
chatHistoryStoreDuration: value.chatHistoryStoreDuration,
maxDatasetSize: value.maxDatasetSize,
annualBonusPoints: selectSubMode === SubModeEnum.month ? 0 : value.annualBonusPoints,
totalPoints: value.totalPoints * (selectSubMode === SubModeEnum.month ? 1 : 12),
// custom plan
@ -108,7 +113,13 @@ const Standard = ({
};
})
: [];
}, [subPlans?.standard, selectSubMode]);
}, [
subPlans?.standard,
selectSubMode,
myStandardPlan?.maxTeamMember,
myStandardPlan?.maxApp,
myStandardPlan?.maxDataset
]);
// Pay code
const [qrPayData, setQRPayData] = useState<QRPayProps>();
@ -120,6 +131,11 @@ const Standard = ({
}
});
// 计算活动时间
const { text: activityExpirationTime } = formatActivityExpirationTime(
subPlans?.activityExpirationTime
);
return (
<>
<Flex flexDirection={'column'} alignItems={'center'} position={'relative'}>
@ -173,6 +189,9 @@ const Standard = ({
>
{standardSubList.map((item) => {
const isCurrentPlan = item.level === myStandardPlan?.currentSubLevel;
const isActivityPlan =
item.level === StandardSubLevelEnum.advanced ||
item.level === StandardSubLevelEnum.basic;
const isHigherLevel =
standardSubLevelMap[item.level].weight >
@ -184,20 +203,87 @@ const Standard = ({
key={item.level}
pos={'relative'}
flex={'1 0 0'}
bg={isCurrentPlan ? 'blue.50' : 'rgba(255, 255, 255, 0.90)'}
bg={'rgba(255, 255, 255, 0.90)'}
p={'28px'}
borderRadius={'xl'}
borderWidth={isCurrentPlan ? '4px' : '1.5px'}
borderWidth={isCurrentPlan ? '2px' : '1.5px'}
boxShadow={'1.5'}
overflow={'hidden'}
{...(isCurrentPlan
? {
borderColor: 'primary.600'
borderColor:
hasActivityExpiration && isActivityPlan ? '#BB182C' : 'primary.600'
}
: {
borderColor: 'myGray.150'
})}
>
{isCurrentPlan && (
{hasActivityExpiration &&
(item.level === StandardSubLevelEnum.basic ||
item.level === StandardSubLevelEnum.advanced) && (
<>
<Box
position={'absolute'}
top={24}
left={0}
w={'29px'}
h={'12px'}
bgImage={"url('/imgs/system/ribbonLeft.svg')"}
bgSize={'contain'}
bgRepeat={'no-repeat'}
zIndex={0}
/>
<Box
position={'absolute'}
top={4}
right={0}
w={'136px'}
h={'170px'}
bgImage={"url('/imgs/system/ribbonRight.svg')"}
bgSize={'contain'}
bgRepeat={'no-repeat'}
zIndex={0}
/>
<Box
position={'absolute'}
bottom={0}
right={0}
w={'78px'}
h={'81px'}
bgImage={"url('/imgs/system/snowflake.svg')"}
bgSize={'contain'}
bgRepeat={'no-repeat'}
zIndex={0}
/>
</>
)}
{hasActivityExpiration &&
(item.level === StandardSubLevelEnum.basic ||
item.level === StandardSubLevelEnum.advanced) && (
<Box
position={'absolute'}
top={0}
left={0}
right={0}
h={'28px'}
bg={'linear-gradient(180deg, #FFE0EB 7.14%, rgba(255, 255, 255, 0.00) 100%)'}
backdropFilter={'blur(0px)'}
zIndex={1}
display={'flex'}
alignItems={'center'}
justifyContent={'center'}
>
<Box
fontSize={'12px'}
fontWeight={'500'}
color={'#E45F5F'}
textAlign={'center'}
>
{activityExpirationTime}
</Box>
</Box>
)}
{isCurrentPlan && !hasActivityExpiration && (
<Box
position={'absolute'}
right={0}
@ -213,10 +299,15 @@ const Standard = ({
{t('common:is_using')}
</Box>
)}
<Box fontSize={'md'} fontWeight={'500'} color={'myGray.900'}>
<Box
fontSize={'md'}
fontWeight={'500'}
color={'myGray.900'}
mt={hasActivityExpiration ? 2 : 0}
>
{t(item.label as any)}
</Box>
<Flex alignItems={'center'} gap={2.5}>
<Flex alignItems={'center'}>
{item.level === StandardSubLevelEnum.custom ? (
<Box
fontSize={['32px', '36px']}
@ -227,26 +318,41 @@ const Standard = ({
{t('common:custom_plan_price')}
</Box>
) : (
<MyBox fontSize={['32px', '42px']} fontWeight={'bold'} color={'myGray.900'}>
{matchedCoupon?.discount && item.price > 0
? (matchedCoupon.discount * item.price).toFixed(1)
: item.price}
</MyBox>
)}
{item.level !== StandardSubLevelEnum.free &&
item.level !== StandardSubLevelEnum.custom &&
matchedCoupon && (
<Box
h={4}
color={'primary.600'}
fontSize={'18px'}
fontWeight={'500'}
whiteSpace={'nowrap'}
<Box
py={1}
borderRadius={20}
display={'inline-block'}
zIndex={10}
pr={8}
bgGradient={'linear(to-r, #fff 90%, transparent)'}
>
<Flex
fontSize={['32px', '42px']}
fontWeight={'bold'}
color={'myGray.900'}
alignItems={'end'}
gap={1}
>
{`${(matchedCoupon.discount * 10).toFixed(0)}`}
</Box>
)}
{matchedCoupon?.discount && item.price > 0
? Number.isInteger(matchedCoupon.discount * item.price)
? matchedCoupon.discount * item.price
: (matchedCoupon.discount * item.price).toFixed(1)
: item.price}
{item.level !== StandardSubLevelEnum.free && matchedCoupon && (
<Box
h={[8, '38px']}
color={'primary.600'}
fontSize={'18px'}
fontWeight={'500'}
whiteSpace={'nowrap'}
>
{`${(matchedCoupon.discount * 10).toFixed(0)}`}
</Box>
)}
</Flex>
</Box>
)}
</Flex>
<Box color={'myGray.500'} minH={'40px'} fontSize={'xs'}>
{t(item.desc as any, { title: feConfigs?.systemTitle })}
@ -254,11 +360,16 @@ const Standard = ({
{/* Button */}
{(() => {
const buttonHeight = 10;
const buttonMarginTop = 4;
const buttonMarginBottom = 6;
if (item.level === StandardSubLevelEnum.free) {
return (
<Button
mt={4}
mb={6}
mt={buttonMarginTop}
mb={buttonMarginBottom}
h={buttonHeight}
_active={{}}
_hover={{}}
boxShadow={'0'}
@ -274,8 +385,9 @@ const Standard = ({
if (item.level === StandardSubLevelEnum.custom) {
return (
<Button
mt={4}
mb={6}
mt={buttonMarginTop}
mb={buttonMarginBottom}
h={buttonHeight}
w={'100%'}
variant={'primaryGhost'}
onClick={() => {
@ -291,11 +403,39 @@ const Standard = ({
if (isCurrentPlan) {
return (
<Button
mt={4}
mb={6}
mt={buttonMarginTop}
mb={buttonMarginBottom}
h={buttonHeight}
w={'100%'}
variant={'primary'}
isLoading={isLoading}
variant={hasActivityExpiration ? 'solid' : 'primary'}
{...(hasActivityExpiration && {
bg: '#ED372C',
color: 'white',
borderRadius: '6px',
_hover: { bg: '#DE0D00' },
sx: {
'&::before': {
content: '""',
position: 'absolute',
left: '0',
top: '0',
width: '30px',
height: '30px',
backgroundImage: `url('/imgs/system/snowflakeLeft.svg')`,
backgroundRepeat: 'no-repeat'
},
'&::after': {
content: '""',
position: 'absolute',
right: '0',
bottom: '0',
width: '25px',
height: '25px',
backgroundImage: `url('/imgs/system/snowflakeRight.svg')`
}
}
})}
onClick={() => {
setPackageChange(PackageChangeStatusEnum.renewal);
onPay({
@ -313,8 +453,9 @@ const Standard = ({
if (isHigherLevel) {
return (
<Button
mt={4}
mb={6}
mt={buttonMarginTop}
mb={buttonMarginBottom}
h={buttonHeight}
w={'100%'}
variant={'primaryGhost'}
isLoading={isLoading}
@ -334,10 +475,20 @@ const Standard = ({
}
return (
<Button
mt={4}
mb={6}
mt={buttonMarginTop}
mb={buttonMarginBottom}
h={buttonHeight}
w={'100%'}
variant={'primaryGhost'}
{...(hasActivityExpiration
? {
variant: 'outline',
borderColor: '#ED372C',
color: '#ED372C',
_hover: { bg: 'rgba(237, 55, 44, 0.1)' }
}
: {
variant: 'primaryGhost'
})}
isLoading={isLoading}
onClick={() => {
setPackageChange(PackageChangeStatusEnum.buy);
@ -358,19 +509,19 @@ const Standard = ({
{item.level === StandardSubLevelEnum.custom ? (
<Grid gap={4} fontSize={'sm'}>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>{t('common:custom_plan_feature_1')}</Box>
</Flex>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>{t('common:custom_plan_feature_2')}</Box>
</Flex>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>{t('common:custom_plan_feature_3')}</Box>
</Flex>
<Flex alignItems={'center'}>
<MyIcon name={'price/right'} w={'16px'} mr={3} />
<MyIcon name={'price/right'} w={'16px'} mr={3} color={'primary.600'} />
<Box color={'myGray.600'}>{t('common:custom_plan_feature_4')}</Box>
</Flex>
</Grid>

View File

@ -0,0 +1,26 @@
import { useTranslation } from 'next-i18next';
export const formatActivityExpirationTime = (date?: Date) => {
const { t } = useTranslation();
if (!date) {
return {
text: ''
};
}
const formatDate = new Date(date);
const year = formatDate.getFullYear();
const month = formatDate.getMonth() + 1;
const day = formatDate.getDate();
const hour = formatDate.getHours().toString().padStart(2, '0');
const minute = formatDate.getMinutes().toString().padStart(2, '0');
return {
text: t('common:support.wallet.subscription.Activity expiration time', {
year,
month,
day,
hour,
minute
})
};
};

View File

@ -57,6 +57,16 @@ const PriceBox = () => {
};
}, [teamSubPlan?.standard?.teamId]);
const handleBack = () => {
// Check if there is history to go back to
if (window.history.length > 1) {
router.back();
} else {
// No history, navigate to home page
router.push('/dashboard/agent');
}
};
const onPaySuccess = () => {
setTimeout(() => {
router.reload();
@ -81,7 +91,7 @@ const PriceBox = () => {
variant={'transparentBase'}
color={'primary.700'}
leftIcon={<MyIcon name={'core/workflow/undo'} w={4} />}
onClick={() => router.back()}
onClick={handleBack}
alignSelf={'flex-start'}
mt={-8}
>
@ -98,7 +108,7 @@ const PriceBox = () => {
w={9}
h={9}
icon={<MyIcon name={'core/workflow/undo'} w={4} />}
onClick={() => router.back()}
onClick={handleBack}
/>
)}

View File

@ -24,7 +24,13 @@ export const updateModelCollaborators = (props: UpdateClbPermissionProps & { mod
export const getMyModels = (props: GetMyModelsQuery) =>
GET<GetMyModelsResponse>('/core/ai/model/getMyModels', props);
/* 活动 banner */
export const getOperationalAd = () =>
GET<{ id: string; operationalAdImage: string; operationalAdLink: string }>(
'/proApi/support/user/inform/getOperationalAd'
);
export const getActivityAd = () =>
GET<{ id: string; activityAdImage: string; activityAdLink: string }>(
'/proApi/support/user/inform/getActivityAd'
);

View File

@ -1,20 +1,35 @@
import { loginOut } from '@/web/support/user/api';
const clearOperationalAdStorage = () => {
const clearAdStorage = () => {
try {
Object.keys(localStorage).forEach((key) => {
if (key.startsWith('hidden-until-')) {
if (key.startsWith('logout-')) {
const oldValue = localStorage.getItem(key);
localStorage.removeItem(key);
// Dispatch ahooks sync event to update useLocalStorageState
if (oldValue !== null) {
window.dispatchEvent(
new CustomEvent('AHOOKS_SYNC_STORAGE_EVENT_NAME', {
detail: {
key,
newValue: null,
oldValue,
storageArea: localStorage
}
})
);
}
}
});
} catch (error) {
console.error('Failed to clear operational ad storage:', error);
console.error('Failed to clear ad storage:', error);
}
};
export const clearToken = () => {
try {
clearOperationalAdStorage();
clearAdStorage();
return loginOut();
} catch (error) {
error;

View File

@ -1,6 +1,6 @@
import { GET, POST } from '@/web/common/api/request';
import type { UserInformType } from '@fastgpt/global/support/user/inform/type';
import type { SystemMsgModalValueType } from '@fastgpt/service/support/user/inform/type';
import type { SystemMsgModalValueType } from '@fastgpt/global/openapi/admin/support/user/inform/api';
import type { PaginationProps, PaginationResponse } from '@fastgpt/web/common/fetch/type';
export const getInforms = (data: PaginationProps) =>

View File

@ -18,7 +18,7 @@ import type {
} from '@fastgpt/global/support/user/team/type.d';
import type {
ClientTeamPlanStatusType,
TeamSubSchema
TeamSubSchemaType
} from '@fastgpt/global/support/wallet/sub/type';
import type { TeamInvoiceHeaderType } from '@fastgpt/global/support/user/team/type';
import type { PaginationProps, PaginationResponse } from '@fastgpt/web/common/fetch/type';
@ -113,7 +113,7 @@ export const checkTeamDatasetSizeLimit = (size: number) =>
export const getTeamPlanStatus = () =>
GET<ClientTeamPlanStatusType>(`/support/user/team/plan/getTeamPlanStatus`, { maxQuantity: 1 });
export const getTeamPlans = () =>
GET<TeamSubSchema[]>(`/proApi/support/user/team/plan/getTeamPlans`);
GET<TeamSubSchemaType[]>(`/proApi/support/user/team/plan/getTeamPlans`);
export const redeemCoupon = (couponCode: string) =>
GET(`/proApi/support/wallet/coupon/redeem`, { key: couponCode });