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