feat: change center-component to components

This commit is contained in:
2025-03-25 15:51:15 +08:00
parent ef50106e5c
commit 45443709af
34 changed files with 504 additions and 88 deletions

91
src/pages/pay/index.tsx Normal file
View File

@@ -0,0 +1,91 @@
import React, { useEffect, useRef, useState } from 'react';
import { X, ChevronRight } from 'lucide-react';
import { usePayStore } from './store/pay';
import { createQrcode } from './modules/create-qrcode';
import Panda from '@/assets/panda.png';
import Button from '@mui/material/Button/Button';
export const App = () => {
const [isAgreed, setIsAgreed] = useState(false);
const qrcodeRef = useRef<HTMLImageElement>(null);
const { getPayUrl, codeUrl, user, init, money, setMoney, subject, setSubject } = usePayStore();
useEffect(() => {
// getPayUrl({ money: money, subject: subject });
init();
}, []);
useEffect(() => {
if (qrcodeRef.current) {
createQrcode(codeUrl, qrcodeRef.current);
}
}, [codeUrl]);
let username = user?.nickname || user?.username || '--';
if (username === 'root') {
username = 'kevisual';
}
const redirectToPay = async () => {
const res = await getPayUrl({ money: money, subject: subject });
if (res.code === 200) {
const newLink = res?.data?.form;
if (newLink) {
// window.location.href = newLink;
window.open(newLink, '_blank');
}
}
};
return (
<div className='min-h-screen bg-gray-50 flex items-center justify-center border-gray-200'>
<div className='w-[600px] h-[400px] bg-white rounded-lg shadow-lg overflow-hidden'>
{/* Header */}
<div className='bg-white p-3 flex justify-between items-center border-b border-gray-200'>
<div className='flex items-center gap-2'>
<img src={user?.avatar ?? Panda} alt='User Avatar' className='w-8 h-8 rounded-full' />
<div>
<h2 className='text-base font-semibold'>{username}</h2>
<span className='text-gray-500 text-xs'></span>
</div>
</div>
<div className='flex items-center gap-3 text-gray-600 text-sm'>
<span></span>
<span></span>
<span></span>
<X className='w-4 h-4' />
</div>
</div>
{/* Main Content */}
<div className='p-4 h-[calc(400px-56px)] overflow-y-auto'>
{/* Membership Type */}
<div className='flex items-center gap-2 mb-6'>
<span className='bg-pink-100 text-pink-500 px-2 py-0.5 rounded text-xs'></span>
<div className='flex-1'></div>
<button className='flex items-center text-gray-600 text-xs'>
<ChevronRight className='w-3 h-3' />
</button>
</div>
{/* Payment QR Code */}
<div className='bg-white border border-gray-200 rounded-lg p-4 text-center min-h-[200px] flex flex-col justify-center items-center'>
<div className='text-2xl font-bold mb-3'>¥ {(money / 100).toFixed(2)}</div>
{/* <QrCode className='w-32 h-32 mx-auto mb-2' /> */}
{/* <img id='qrcode' className='w-32 h-32 mx-auto mb-2' ref={qrcodeRef} /> */}
{/* <p className='text-gray-600 text-xs'>请使用支付宝扫码支付</p> */}
<div className='flex justify-center items-center gap-2'>
<div className='text-center px-4 py-2 cursor-pointer rounded-md shadow-md text-gray-600 text-xs border border-gray-300' onClick={redirectToPay}>
</div>
</div>
</div>
{/* Terms */}
<div className='mt-4 text-xs text-gray-500 text-center flex items-center justify-center gap-1'>
<input type='checkbox' id='terms' checked={isAgreed} onChange={(e) => setIsAgreed(e.target.checked)} className='w-3 h-3 accent-pink-500' />
<label className='text-gray-300 underline' htmlFor='terms'>
</label>
</div>
</div>
</div>
</div>
);
};

View File

@@ -0,0 +1,27 @@
import QRCode from 'qrcode';
export const createQrcode = (url: string, element: HTMLImageElement) => {
if (!url) return;
console.log('pay url', url);
QRCode.toDataURL(
url,
{
errorCorrectionLevel: 'H',
type: 'image/jpeg',
margin: 1,
width: 300,
color: {
dark: '#000000',
light: '#ffffff',
},
},
function (err, url) {
if (err) {
console.log('err', err);
throw err;
}
element.src = url;
},
);
};

View File

@@ -0,0 +1,46 @@
import { create } from 'zustand';
import { query, queryLogin } from '@/modules/query';
import { toast } from 'react-toastify';
interface PayState {
getPayUrl: (data: { money: number; subject: string }) => Promise<any>;
codeUrl: string;
setCodeUrl: (url: string) => void;
user: any;
money: number;
subject: string;
setMoney: (money: number) => void;
setSubject: (subject: string) => void;
init: () => Promise<void>;
}
export const usePayStore = create<PayState>((set) => ({
money: 12800,
setMoney: (money) => set({ money }),
subject: 'kevisual 会员',
setSubject: (subject) => set({ subject }),
getPayUrl: async (data) => {
const res = await query.post({
path: 'alipay',
key: 'pay',
data,
});
if (res.code === 200) {
if (res.data?.form) {
set({ codeUrl: res.data?.form });
}
} else {
toast.error(res.message);
}
return res;
},
codeUrl: '',
setCodeUrl: (url) => set({ codeUrl: url }),
user: null,
init: async () => {
const res = await queryLogin.cacheStore.getCurrentUser();
console.log(res);
if (res) {
set({ user: res });
}
},
}));