mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-09-10 22:20:25 +00:00
Implement comprehensive topup billing system with user history viewing and admin management capabilities.
## Features Added
### Frontend
- Add topup history modal with paginated billing records
- Display order details: trade number, payment method, amount, money, status, create time
- Implement empty state with proper illustrations
- Add payment method column with localized display (Stripe, Alipay, WeChat)
- Add admin manual completion feature for pending orders
- Add Coins icon for recharge amount display
- Integrate "Bills" button in RechargeCard header
- Optimize code quality by using shared utility functions (isAdmin)
- Extract constants for status and payment method mappings
- Use React.useMemo for performance optimization
### Backend
- Create GET `/api/user/topup/self` endpoint for user topup history with pagination
- Create POST `/api/user/topup/complete` endpoint for admin manual order completion
- Add `payment_method` field to TopUp model for tracking payment types
- Implement `GetUserTopUps` method with proper pagination and ordering
- Implement `ManualCompleteTopUp` with transaction safety and row-level locking
- Add application-level mutex locks to prevent concurrent order processing
- Record payment method in Epay and Stripe payment flows
- Ensure idempotency and data consistency with proper error handling
### Internationalization
- Add i18n keys for Chinese (zh), English (en), and French (fr)
- Support for billing-related UI text and status messages
## Technical Improvements
- Use database transactions with FOR UPDATE row-level locking
- Implement sync.Map-based mutex for order-level concurrency control
- Proper error handling and user-friendly toast notifications
- Follow existing codebase patterns for empty states and modals
- Maintain code quality with extracted render functions and constants
## Files Changed
- Backend: controller/topup.go, controller/topup_stripe.go, model/topup.go, router/api-router.go
- Frontend: web/src/components/topup/modals/TopupHistoryModal.jsx (new), web/src/components/topup/RechargeCard.jsx, web/src/components/topup/index.jsx
- i18n: web/src/i18n/locales/{zh,en,fr}.json
131 lines
4.3 KiB
React
131 lines
4.3 KiB
React
/*
|
|
Copyright (C) 2025 QuantumNous
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as
|
|
published by the Free Software Foundation, either version 3 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
For commercial licensing, please contact support@quantumnous.com
|
|
*/
|
|
|
|
import React from 'react';
|
|
import { Banner } from '@douyinfe/semi-ui';
|
|
|
|
/**
|
|
* 数据库检查步骤组件
|
|
* 显示当前数据库类型和相关警告信息
|
|
*/
|
|
const DatabaseStep = ({ setupStatus, renderNavigationButtons, t }) => {
|
|
// 检测是否在 Electron 环境中运行
|
|
const isElectron =
|
|
typeof window !== 'undefined' && window.electron?.isElectron;
|
|
|
|
return (
|
|
<>
|
|
{/* 数据库警告 */}
|
|
{setupStatus.database_type === 'sqlite' && (
|
|
<Banner
|
|
type={isElectron ? 'info' : 'warning'}
|
|
closeIcon={null}
|
|
title={isElectron ? t('本地数据存储') : t('数据库警告')}
|
|
description={
|
|
isElectron ? (
|
|
<div>
|
|
<p>
|
|
{t(
|
|
'您的数据将安全地存储在本地计算机上。所有配置、用户信息和使用记录都会自动保存,关闭应用后不会丢失。',
|
|
)}
|
|
</p>
|
|
{window.electron?.dataDir && (
|
|
<p className='mt-2 text-sm opacity-80'>
|
|
<strong>{t('数据存储位置:')}</strong>
|
|
<br />
|
|
<code className='bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded'>
|
|
{window.electron.dataDir}
|
|
</code>
|
|
</p>
|
|
)}
|
|
<p className='mt-2 text-sm opacity-70'>
|
|
💡 {t('提示:如需备份数据,只需复制上述目录即可')}
|
|
</p>
|
|
</div>
|
|
) : (
|
|
<div>
|
|
<p>
|
|
{t(
|
|
'您正在使用 SQLite 数据库。如果您在容器环境中运行,请确保已正确设置数据库文件的持久化映射,否则容器重启后所有数据将丢失!',
|
|
)}
|
|
</p>
|
|
<p className='mt-1'>
|
|
<strong>
|
|
{t(
|
|
'建议在生产环境中使用 MySQL 或 PostgreSQL 数据库,或确保 SQLite 数据库文件已映射到宿主机的持久化存储。',
|
|
)}
|
|
</strong>
|
|
</p>
|
|
</div>
|
|
)
|
|
}
|
|
className='!rounded-lg'
|
|
fullMode={false}
|
|
bordered
|
|
/>
|
|
)}
|
|
|
|
{/* MySQL数据库提示 */}
|
|
{setupStatus.database_type === 'mysql' && (
|
|
<Banner
|
|
type='success'
|
|
closeIcon={null}
|
|
title={t('数据库信息')}
|
|
description={
|
|
<div>
|
|
<p>
|
|
{t(
|
|
'您正在使用 MySQL 数据库。MySQL 是一个可靠的关系型数据库管理系统,适合生产环境使用。',
|
|
)}
|
|
</p>
|
|
</div>
|
|
}
|
|
className='!rounded-lg'
|
|
fullMode={false}
|
|
bordered
|
|
/>
|
|
)}
|
|
|
|
{/* PostgreSQL数据库提示 */}
|
|
{setupStatus.database_type === 'postgres' && (
|
|
<Banner
|
|
type='success'
|
|
closeIcon={null}
|
|
title={t('数据库信息')}
|
|
description={
|
|
<div>
|
|
<p>
|
|
{t(
|
|
'您正在使用 PostgreSQL 数据库。PostgreSQL 是一个功能强大的开源关系型数据库系统,提供了出色的可靠性和数据完整性,适合生产环境使用。',
|
|
)}
|
|
</p>
|
|
</div>
|
|
}
|
|
className='!rounded-lg'
|
|
fullMode={false}
|
|
bordered
|
|
/>
|
|
)}
|
|
{renderNavigationButtons && renderNavigationButtons()}
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default DatabaseStep;
|