diff --git a/src/actions/resource.ts b/src/actions/resource.ts index 0ae8575..bd1ef16 100644 --- a/src/actions/resource.ts +++ b/src/actions/resource.ts @@ -21,28 +21,47 @@ async function allResource(){ return callByUser('/api/resource/all') } -async function createResourceByBalance(props: { +type CreateResourceReq = { type: number live: number quota: number expire: number daily_limit: number -}) { +} + +type CreateResourceResp = { + trade_no: string + pay_url: string +} + +async function createResourceByBalance(props: CreateResourceReq) { return await callByUser('/api/resource/create/balance', props) } -async function createResourceByAlipay() { - throw new Error('Not implemented') +async function prepareResourceByAlipay(props: CreateResourceReq) { + return await callByUser('/api/resource/prepare/alipay', props) } -async function createResourceByWechat() { - throw new Error('Not implemented') +async function prepareResourceByWechat(props: CreateResourceReq) { + return await callByUser('/api/resource/prepare/wechat', props) +} + +async function createResourceByAlipay(props: CreateResourceReq) { + return await callByUser('/api/resource/create/alipay', props) +} + +async function createResourceByWechat(props: CreateResourceReq) { + return await callByUser('/api/resource/create/wechat', props) } export { listResourcePss, allResource, + prepareResourceByAlipay, + prepareResourceByWechat, createResourceByBalance, createResourceByAlipay, createResourceByWechat, + type CreateResourceReq, + type CreateResourceResp, } diff --git a/src/actions/trade.ts b/src/actions/trade.ts deleted file mode 100644 index ae49204..0000000 --- a/src/actions/trade.ts +++ /dev/null @@ -1,27 +0,0 @@ -'use server' - -import { callByUser } from "@/actions/base" - -export async function tradeRecharge(props: { - amount: number - method: string -}) { - - let method: number - switch (props.method) { - case 'alipay': - method = 1 - break - case 'wechat': - method = 2 - break - default: - throw new Error(`${props.method} is not a valid method`) - } - - return await callByUser('/api/trade/create', { - subject: '余额充值', - amount: Number(props.amount * 100), - method: method, - }) -} diff --git a/src/app/admin/bills/page.tsx b/src/app/admin/bills/page.tsx index 152949f..a11be52 100644 --- a/src/app/admin/bills/page.tsx +++ b/src/app/admin/bills/page.tsx @@ -247,7 +247,7 @@ export default function BillsPage(props: BillsPageProps) {
{row.original.info} - {row.original.type === 1 && ( + {row.original.type === 1 && row.original.trade.status === 1 && ( diff --git a/src/app/admin/resources/page.tsx b/src/app/admin/resources/page.tsx index 02acbf7..1acf8e8 100644 --- a/src/app/admin/resources/page.tsx +++ b/src/app/admin/resources/page.tsx @@ -270,7 +270,7 @@ export default function ResourcesPage(props: ResourcesPageProps) {
{isAfter(row.original.pss.expire, new Date()) ? 正常 - : 已过期} + : 过期} | 今日限额:{row.original.pss.daily_used} / {row.original.pss.daily_limit} | diff --git a/src/components/composites/purchase/_client/form.tsx b/src/components/composites/purchase/_client/form.tsx index 2d606fc..c163b98 100644 --- a/src/components/composites/purchase/_client/form.tsx +++ b/src/components/composites/purchase/_client/form.tsx @@ -27,6 +27,7 @@ export type Schema = z.infer type PurchaseFormContextType = { form: UseFormReturn + onSubmit?: () => void } export const PurchaseFormContext = createContext(undefined) @@ -35,7 +36,6 @@ export type PurchaseFormProps = {} export default function PurchaseForm(props: PurchaseFormProps) { console.log('PurchaseForm render') - const authCtx = useContext(AuthContext) const form = useForm({ resolver: zodResolver(schema), @@ -49,48 +49,9 @@ export default function PurchaseForm(props: PurchaseFormProps) { }, }) - const router = useRouter() - - const toExtract = () => { - router.push('/admin/extract') - } - - const onSubmit = async (value: Schema) => { - try { - const resp = await createResourceByBalance({ - type: Number(value.type), - live: Number(value.live) * 60, - quota: Number(value.quota), - expire: Number(value.expire) * 24 * 3600, - daily_limit: Number(value.daily_limit), - }) - - if (!resp.success) { - throw new Error(resp.message) - } - - toast.success('购买成功', { - duration: 10 * 1000, - closeButton: true, - action: { - label: `去提取`, - onClick: toExtract, - }, - }) - - await authCtx.refreshProfile() - } - catch (e) { - console.log(e) - toast.error('购买失败', { - description: (e as Error).message, - }) - } - } - return (
-
+
diff --git a/src/components/composites/purchase/_client/pay.tsx b/src/components/composites/purchase/_client/pay.tsx new file mode 100644 index 0000000..1dfacf4 --- /dev/null +++ b/src/components/composites/purchase/_client/pay.tsx @@ -0,0 +1,210 @@ +'use client' +import {Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger} from '@/components/ui/dialog' +import {Button} from '@/components/ui/button' +import alipay from '../_assets/alipay.svg' +import wechat from '../_assets/wechat.svg' +import balance from '../_assets/balance.svg' +import Image from 'next/image' +import {useContext, useState} from 'react' +import {AuthContext} from '@/components/providers/AuthProvider' +import {Alert, AlertDescription} from '@/components/ui/alert' +import { + prepareResourceByAlipay, + prepareResourceByWechat, + CreateResourceReq, + CreateResourceResp, + createResourceByBalance, + createResourceByAlipay, + createResourceByWechat, +} from '@/actions/resource' +import {ApiResponse} from '@/lib/api' +import {toast} from 'sonner' +import {Loader} from 'lucide-react' +import {useRouter} from 'next/navigation' + +export type PayProps = { + method: 'alipay' | 'wechat' | 'balance' + amount: number + resource: CreateResourceReq + +} + +export default function Pay(props: PayProps) { + + const ctx = useContext(AuthContext) + const [open, setOpen] = useState(false) + const [payInfo, setPayInfo] = useState() + + const onOpen = async () => { + setOpen(true) + + if (props.method === 'balance') { + return + } + + let resp: ApiResponse + switch (props.method) { + case 'alipay': + resp = await prepareResourceByAlipay(props.resource) + break + case 'wechat': + resp = await prepareResourceByWechat(props.resource) + break + } + if (!resp.success) { + toast.error(`创建订单失败: ${resp.message}`) + setOpen(false) + return + } + + setPayInfo(resp.data) + } + + const router = useRouter() + const onSubmit = async () => { + let resp: ApiResponse + try { + switch (props.method) { + case 'alipay': + resp = await createResourceByAlipay(props.resource) + break + case 'wechat': + resp = await createResourceByWechat(props.resource) + break + case 'balance': + resp = await createResourceByBalance(props.resource) + break + } + + if (!resp.success) { + throw new Error(resp.message) + } + + toast.success('购买成功', { + duration: 10 * 1000, + closeButton: true, + action: { + label: `去提取`, + onClick: () => router.push('/admin/extract'), + }, + }) + + setOpen(false) + await ctx.refreshProfile() + } + catch (e) { + console.log(e) + toast.error('购买失败', { + description: (e as Error).message, + }) + } + } + + return ( + + + + + + + + {props.method === 'alipay' && (<> + {`支付宝`} + 支付宝 + )} + {props.method === 'wechat' && (<> + {`微信`} + 微信 + )} + {props.method === 'balance' && (<> + {`余额`} + 余额支付 + )} + + + + {props.method === 'balance' ? ( + ctx.profile && ( +
+
+
+ 账户余额 + {ctx.profile.balance}元 +
+
+ 支付金额 + - {props.amount}元 +
+
+
+ 支付后余额 + props.amount ? 'text-done' : `text-fail`}`}> + {ctx.profile.balance - props.amount}元 + +
+
+ + {ctx.profile.balance < props.amount && ( + + + 余额不足,请先充值或选择其他支付方式 + + + )} + + {ctx.profile.balance >= props.amount && ( + + + 检查无误后,点击确认支付按钮完成支付 + + + )} +
+ ) + ) : ( +
+
+
+ {payInfo ? ( +