feat: 迭代

This commit is contained in:
2026-05-22 18:54:30 +08:00
parent ca22542c7a
commit 4c7a1e06a8
20 changed files with 2169 additions and 1087 deletions
+7 -2
View File
@@ -335,9 +335,14 @@ async function handlePhoneLogin() {
setTimeout(() => {
uni.switchTab({ url: '/pages/index/index' });
}, 500);
} catch (e) {
} catch (error: any) {
uni.hideLoading();
console.error(e);
console.error('手机号登录失败', error);
uni.showToast({
title: error.message || '登录失败,请重试',
icon: 'none',
duration: 2000
});
}
}
</script>
+8
View File
@@ -83,6 +83,14 @@ export function request<T = any>(options: RequestOptions): Promise<ApiResponse<T
return;
}
// 检查是否有 token,如果没有 token 说明是登录接口返回的 401,直接返回原始错误消息
const hasToken = useSellerToken ? uni.getStorageSync('sellerToken') : uni.getStorageSync('token');
if (!hasToken) {
// 登录接口的 401 错误,直接返回后端的错误消息
reject(new Error(responseData.message || '认证失败'));
return;
}
// 正常 401 处理,只清除对应账户的 token,不互相干扰
if (useSellerToken) {
// 商家 token 失效,跳转到商家登录页
@@ -5,15 +5,20 @@ import { getFinancialOverview, getPlatformTransactions } from '@/api/finance';
import type { ColumnsType } from 'antd/es/table';
interface FinancialOverview {
systemTotalAmount: number;
totalUserPaid: number;
totalRefund: number;
totalWithdrawn: number;
platformBalance: number;
platformTotalIncome: number;
platformTotalExpense: number;
totalUserBalance: number;
totalMerchantBalance: number;
userCount: number;
merchantCount: number;
todayIncome: number;
todayExpense: number;
monthIncome: number;
monthExpense: number;
pendingWithdrawals: number;
pendingSettlements: number;
todayOrders: number;
}
interface Transaction {
@@ -108,18 +113,21 @@ const FinanceDashboard: React.FC = () => {
{overview && (
<>
{/* 平台总账户额 - 突出显示 */}
{/* 系统总账户额 - 突出显示 */}
<Card style={{ marginBottom: 24, background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' }}>
<Statistic
title={<span style={{ color: '#fff', fontSize: 16 }}></span>}
value={Number(overview.platformBalance || 0) + Number(overview.totalMerchantBalance || 0) + Number(overview.totalUserBalance || 0)}
title={<span style={{ color: '#fff', fontSize: 16 }}></span>}
value={Number(overview.systemTotalAmount || 0)}
prefix={<WalletOutlined style={{ color: '#fff' }} />}
suffix={<span style={{ color: '#fff' }}></span>}
precision={2}
valueStyle={{ color: '#fff', fontSize: 36, fontWeight: 'bold' }}
/>
<div style={{ color: 'rgba(255,255,255,0.8)', fontSize: 12, marginTop: 8 }}>
¥{Number(overview.totalUserPaid || 0).toFixed(2)}- 退¥{Number(overview.totalRefund || 0).toFixed(2)}- ¥{Number(overview.totalWithdrawn || 0).toFixed(2)}
</div>
<div style={{ color: 'rgba(255,255,255,0.6)', fontSize: 11, marginTop: 4 }}>
= ¥{Number(overview.totalMerchantBalance || 0).toFixed(2)}+ ¥{Number(overview.totalUserBalance || 0).toFixed(2)}+ ¥{Number(overview.platformBalance || 0).toFixed(2)}
</div>
</Card>
@@ -127,13 +135,16 @@ const FinanceDashboard: React.FC = () => {
<Col span={6}>
<Card>
<Statistic
title="平台账户余额"
title="平台净收益"
value={overview.platformBalance}
precision={2}
prefix={<WalletOutlined />}
suffix="元"
valueStyle={{ color: '#1890ff' }}
/>
<div style={{ fontSize: 12, color: '#999', marginTop: 8 }}>
-
</div>
</Card>
</Col>
<Col span={6}>
@@ -146,6 +157,9 @@ const FinanceDashboard: React.FC = () => {
suffix="元"
valueStyle={{ color: '#52c41a' }}
/>
<div style={{ fontSize: 12, color: '#999', marginTop: 8 }}>
{overview.userCount}
</div>
</Card>
</Col>
<Col span={6}>
@@ -158,23 +172,25 @@ const FinanceDashboard: React.FC = () => {
suffix="元"
valueStyle={{ color: '#faad14' }}
/>
<div style={{ fontSize: 12, color: '#999', marginTop: 8 }}>
{overview.merchantCount}
</div>
</Card>
</Col>
<Col span={6}>
<Card>
<Statistic
title="待处理提现"
value={overview.pendingWithdrawals}
precision={2}
suffix="元"
valueStyle={{ color: '#ff4d4f' }}
title="今日订单数"
value={overview.todayOrders}
suffix="单"
valueStyle={{ color: '#722ed1' }}
/>
</Card>
</Col>
</Row>
<Row gutter={24} style={{ marginBottom: 24 }}>
<Col span={6}>
<Col span={8}>
<Card>
<Statistic
title="今日收入"
@@ -186,7 +202,7 @@ const FinanceDashboard: React.FC = () => {
/>
</Card>
</Col>
<Col span={6}>
<Col span={8}>
<Card>
<Statistic
title="今日支出"
@@ -198,6 +214,19 @@ const FinanceDashboard: React.FC = () => {
/>
</Card>
</Col>
<Col span={8}>
<Card>
<Statistic
title="今日净收益"
value={Number(overview.todayIncome || 0) - Number(overview.todayExpense || 0)}
precision={2}
suffix="元"
valueStyle={{
color: (Number(overview.todayIncome || 0) - Number(overview.todayExpense || 0)) >= 0 ? '#52c41a' : '#ff4d4f'
}}
/>
</Card>
</Col>
<Col span={6}>
<Card>
<Statistic
@@ -8,21 +8,18 @@ export class PlatformAccount {
@Column({ type: 'varchar', length: 50, comment: '账户名称(如:主账户、备用账户)' })
account_name: string;
@Column({ type: 'decimal', precision: 12, scale: 2, default: 0, comment: '可用余额' })
@Column({ type: 'decimal', precision: 12, scale: 2, default: 0, comment: '可用余额(平台净收益 = total_income - total_expense' })
balance: number;
@Column({ type: 'decimal', precision: 12, scale: 2, default: 0, comment: '冻结余额(提现中)' })
frozen_balance: number;
@Column({ type: 'decimal', precision: 12, scale: 2, default: 0, comment: '累计收入(订单收入)' })
@Column({ type: 'decimal', precision: 12, scale: 2, default: 0, comment: '累计收入(服务费收入)' })
total_income: number;
@Column({ type: 'decimal', precision: 12, scale: 2, default: 0, comment: '累计支出(商家结算+退款' })
@Column({ type: 'decimal', precision: 12, scale: 2, default: 0, comment: '累计支出(邀请返现支出' })
total_expense: number;
@Column({ type: 'decimal', precision: 12, scale: 2, default: 0, comment: '累计服务费收入' })
total_service_fee: number;
@VersionColumn({ comment: '乐观锁版本号' })
version: number;
@@ -0,0 +1,40 @@
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, Index, VersionColumn } from 'typeorm';
@Entity('system_accounts')
export class SystemAccount {
@PrimaryGeneratedColumn({ type: 'bigint', unsigned: true })
id: number;
@Column({ type: 'varchar', length: 50, comment: '账户名称(如:主账户)' })
account_name: string;
@Column({ type: 'decimal', precision: 12, scale: 2, default: 0, comment: '可用余额(total_income - total_refund - total_withdrawn' })
balance: number;
@Column({ type: 'decimal', precision: 12, scale: 2, default: 0, comment: '累计收入(用户实付总额)' })
total_income: number;
@Column({ type: 'decimal', precision: 12, scale: 2, default: 0, comment: '累计退款' })
total_refund: number;
@Column({ type: 'decimal', precision: 12, scale: 2, default: 0, comment: '累计提现(所有提现)' })
total_withdrawn: number;
@VersionColumn({ comment: '乐观锁版本号' })
version: number;
@Column({
type: 'enum',
enum: ['active', 'frozen', 'closed'],
default: 'active',
comment: '状态'
})
@Index()
status: 'active' | 'frozen' | 'closed';
@CreateDateColumn({ comment: '创建时间' })
created_at: Date;
@UpdateDateColumn({ comment: '更新时间' })
updated_at: Date;
}
@@ -0,0 +1,48 @@
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, Index } from 'typeorm';
@Entity('system_transactions')
@Index('uk_transaction_no', ['transactionNo'], { unique: true })
@Index('idx_account_id', ['accountId'])
@Index('idx_transaction_type', ['transactionType'])
@Index('idx_business', ['businessType', 'businessId'])
@Index('idx_created_at', ['createdAt'])
export class SystemTransaction {
@PrimaryGeneratedColumn({ type: 'bigint', unsigned: true, comment: '流水ID' })
id: number;
@Column({ type: 'varchar', length: 32, name: 'transaction_no', comment: '交易流水号(全局唯一)' })
transactionNo: string;
@Column({ type: 'bigint', unsigned: true, name: 'account_id', comment: '系统账户ID' })
accountId: number;
@Column({ type: 'enum', enum: ['income', 'expense'], comment: '方向:income-收入/expense-支出' })
direction: 'income' | 'expense';
@Column({ type: 'decimal', precision: 12, scale: 2, comment: '金额(正数)' })
amount: number;
@Column({ type: 'decimal', precision: 12, scale: 2, name: 'balance_before', comment: '交易前余额' })
balanceBefore: number;
@Column({ type: 'decimal', precision: 12, scale: 2, name: 'balance_after', comment: '交易后余额' })
balanceAfter: number;
@Column({ type: 'varchar', length: 50, name: 'transaction_type', comment: '交易类型' })
transactionType: string;
@Column({ type: 'varchar', length: 50, name: 'business_type', comment: '业务类型:order_payment/refund/withdraw' })
businessType: string;
@Column({ type: 'bigint', unsigned: true, nullable: true, name: 'business_id', comment: '业务ID(订单ID/退款ID/提现ID等)' })
businessId: number;
@Column({ type: 'varchar', length: 32, nullable: true, name: 'business_no', comment: '业务单号' })
businessNo: string;
@Column({ type: 'varchar', length: 500, nullable: true, comment: '备注' })
remark: string;
@CreateDateColumn({ type: 'datetime', name: 'created_at', comment: '创建时间' })
createdAt: Date;
}
@@ -9,6 +9,7 @@ import { MktUserInviteStats } from '@/entities/mkt-user-invite-stats.entity';
import { MktInviteWithdrawal } from '@/entities/mkt-invite-withdrawal.entity';
import { Order } from '@/entities/order.entity';
import { User } from '@/entities/user.entity';
import { FinanceModule } from '@/modules/shared/finance/finance.module';
@Module({
imports: [
@@ -21,6 +22,7 @@ import { User } from '@/entities/user.entity';
Order,
User,
]),
FinanceModule,
],
controllers: [ActivityController],
providers: [ActivityService],
@@ -8,6 +8,8 @@ import { MktUserInviteStats } from '@/entities/mkt-user-invite-stats.entity';
import { MktInviteWithdrawal } from '@/entities/mkt-invite-withdrawal.entity';
import { Order } from '@/entities/order.entity';
import { User } from '@/entities/user.entity';
import { AccountService } from '@/modules/shared/finance/account.service';
import { TransactionService } from '@/modules/shared/finance/transaction.service';
import {
BindInvitationDto,
CreateInviteWithdrawalDto,
@@ -33,6 +35,8 @@ export class ActivityService {
private orderRepo: Repository<Order>,
@InjectRepository(User)
private userRepo: Repository<User>,
private accountService: AccountService,
private transactionService: TransactionService,
private dataSource: DataSource,
) {}
@@ -415,6 +419,30 @@ export class ActivityService {
);
}
// 账户操作:给邀请人用户账户增加返现金额,从平台账户扣减
const transactionNo = this.transactionService.generateTransactionNo();
// 给用户账户增加返现
await this.accountService.addUserBalance(
invitation.inviterId,
amount,
transactionNo,
'invite_cashback',
cashback.id,
order.orderNo,
`邀请返现 - 订单${order.orderNo}${orderIndex}`,
);
// 从平台账户扣减返现支出
await this.accountService.deductPlatformCashback(
amount,
transactionNo,
'invite_cashback',
cashback.id,
order.orderNo,
`邀请返现支出 - 用户${invitation.inviterId}订单${order.orderNo}`,
);
await queryRunner.commitTransaction();
this.logger.log(
`订单 ${order.orderNo} 完成,邀请人 ${invitation.inviterId} 获得第${orderIndex}单返现 ${amount} 元(比例${rate * 100}%`,
@@ -329,11 +329,10 @@ export class OrderService {
paidAt: new Date(),
});
// 记录平台账户收入
// 记录系统总账户收入(用户实付金额)
const transactionNo = `TXN${Date.now()}${Math.floor(Math.random() * 10000)}`;
await this.accountService.addPlatformBalance(
await this.accountService.addSystemIncome(
order.payAmount,
order.serviceFee || 0,
transactionNo,
'order_payment',
order.id,
@@ -378,11 +377,10 @@ export class OrderService {
paidAt: new Date(),
});
// 记录平台账户收入
// 记录系统总账户收入(用户实付金额)
const transactionNo = `TXN${Date.now()}${Math.floor(Math.random() * 10000)}`;
await this.accountService.addPlatformBalance(
await this.accountService.addSystemIncome(
order.payAmount,
order.serviceFee || 0,
transactionNo,
'order_payment',
order.id,
@@ -4,9 +4,11 @@ import { Repository, DataSource, FindOptionsWhere } from 'typeorm';
import { UserAccount } from '@/entities/user-account.entity';
import { MerchantAccount } from '@/entities/merchant-account.entity';
import { PlatformAccount } from '@/entities/platform-account.entity';
import { SystemAccount } from '@/entities/system-account.entity';
import { UserTransaction } from '@/entities/user-transaction.entity';
import { MerchantTransaction } from '@/entities/merchant-transaction.entity';
import { PlatformTransaction } from '@/entities/platform-transaction.entity';
import { SystemTransaction } from '@/entities/system-transaction.entity';
import { QueryUserAccountsDto, QueryMerchantAccountsDto } from './dto/account.dto';
@Injectable()
@@ -18,12 +20,16 @@ export class AccountService {
private merchantAccountRepo: Repository<MerchantAccount>,
@InjectRepository(PlatformAccount)
private platformAccountRepo: Repository<PlatformAccount>,
@InjectRepository(SystemAccount)
private systemAccountRepo: Repository<SystemAccount>,
@InjectRepository(UserTransaction)
private userTransactionRepo: Repository<UserTransaction>,
@InjectRepository(MerchantTransaction)
private merchantTransactionRepo: Repository<MerchantTransaction>,
@InjectRepository(PlatformTransaction)
private platformTransactionRepo: Repository<PlatformTransaction>,
@InjectRepository(SystemTransaction)
private systemTransactionRepo: Repository<SystemTransaction>,
private dataSource: DataSource,
) {}
@@ -429,10 +435,9 @@ export class AccountService {
}
/**
* 平台账户增加余额(订单收入
* 平台账户增加服务费收入
*/
async addPlatformBalance(
amount: number,
async addPlatformServiceFee(
serviceFee: number,
transactionNo: string,
businessType: string,
@@ -454,14 +459,12 @@ export class AccountService {
throw new NotFoundException('平台账户不存在');
}
const balanceBefore = Number(account.balance);
const amountNum = Number(amount);
const serviceFeeNum = Number(serviceFee);
const balanceAfter = parseFloat((balanceBefore + amountNum).toFixed(2));
const balanceBefore = Number(account.balance);
const balanceAfter = parseFloat((balanceBefore + serviceFeeNum).toFixed(2));
account.balance = balanceAfter;
account.total_income = parseFloat((Number(account.total_income) + amountNum).toFixed(2));
account.total_service_fee = parseFloat((Number(account.total_service_fee) + serviceFeeNum).toFixed(2));
account.total_income = parseFloat((Number(account.total_income) + serviceFeeNum).toFixed(2));
account.version += 1;
await queryRunner.manager.save(account);
@@ -470,10 +473,10 @@ export class AccountService {
transaction_no: transactionNo,
account_id: account.id,
direction: 'income',
amount,
amount: serviceFeeNum,
balance_before: balanceBefore,
balance_after: balanceAfter,
transaction_type: '订单收入',
transaction_type: '服务费收入',
business_type: businessType,
business_id: businessId,
business_no: businessNo,
@@ -491,12 +494,11 @@ export class AccountService {
}
/**
* 平台账户扣减余额(结算/返现/提现)
* 平台账户扣减邀请返现支出
*/
async deductPlatformBalance(
amount: number,
async deductPlatformCashback(
cashbackAmount: number,
transactionNo: string,
transactionType: string,
businessType: string,
businessId: number,
businessNo: string,
@@ -516,21 +518,12 @@ export class AccountService {
throw new NotFoundException('平台账户不存在');
}
const cashbackNum = Number(cashbackAmount);
const balanceBefore = Number(account.balance);
if (balanceBefore < amount) {
throw new BadRequestException('平台账户余额不足');
}
const balanceAfter = balanceBefore - amount;
const balanceAfter = parseFloat((balanceBefore - cashbackNum).toFixed(2));
account.balance = balanceAfter;
account.total_expense = Number(account.total_expense) + amount;
if (transactionType === '商家结算') {
} else if (transactionType === '邀请返现') {
} else if (transactionType === '提现') {
}
account.total_expense = parseFloat((Number(account.total_expense) + cashbackNum).toFixed(2));
account.version += 1;
await queryRunner.manager.save(account);
@@ -539,10 +532,73 @@ export class AccountService {
transaction_no: transactionNo,
account_id: account.id,
direction: 'expense',
amount,
amount: cashbackNum,
balance_before: balanceBefore,
balance_after: balanceAfter,
transaction_type: transactionType,
transaction_type: '邀请返现',
business_type: businessType,
business_id: businessId,
business_no: businessNo,
remark,
});
await queryRunner.manager.save(transaction);
await queryRunner.commitTransaction();
} catch (error) {
await queryRunner.rollbackTransaction();
throw error;
} finally {
await queryRunner.release();
}
}
/**
* 平台账户扣减提现
*/
async deductPlatformWithdrawal(
amount: number,
transactionNo: string,
businessType: string,
businessId: number,
businessNo: string,
remark: string,
): Promise<void> {
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
const account = await queryRunner.manager.findOne(PlatformAccount, {
where: { account_name: '主账户' },
lock: { mode: 'pessimistic_write' },
});
if (!account) {
throw new NotFoundException('平台账户不存在');
}
const amountNum = Number(amount);
const balanceBefore = Number(account.balance);
if (balanceBefore < amountNum) {
throw new BadRequestException('平台账户余额不足');
}
const balanceAfter = parseFloat((balanceBefore - amountNum).toFixed(2));
account.balance = balanceAfter;
account.version += 1;
await queryRunner.manager.save(account);
const transaction = this.platformTransactionRepo.create({
transaction_no: transactionNo,
account_id: account.id,
direction: 'expense',
amount: amountNum,
balance_before: balanceBefore,
balance_after: balanceAfter,
transaction_type: '提现',
business_type: businessType,
business_id: businessId,
business_no: businessNo,
@@ -709,4 +765,200 @@ export class AccountService {
totalPendingSettlement: Number(result?.totalPendingSettlement || 0),
};
}
// ============================================================
// 系统总账户操作方法
// ============================================================
/**
* 获取系统总账户
*/
async getSystemAccount(accountName: string = '主账户'): Promise<SystemAccount> {
const account = await this.systemAccountRepo.findOne({ where: { account_name: accountName } });
if (!account) {
throw new NotFoundException(
`系统总账户"${accountName}"不存在,请先执行数据库初始化脚本创建系统总账户`
);
}
return account;
}
/**
* 系统总账户增加收入(用户支付订单)
*/
async addSystemIncome(
amount: number,
transactionNo: string,
businessType: string,
businessId: number,
businessNo: string,
remark: string,
): Promise<void> {
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
const account = await queryRunner.manager.findOne(SystemAccount, {
where: { account_name: '主账户' },
lock: { mode: 'pessimistic_write' },
});
if (!account) {
throw new NotFoundException('系统总账户不存在');
}
const amountNum = Number(amount);
const balanceBefore = Number(account.balance);
const balanceAfter = parseFloat((balanceBefore + amountNum).toFixed(2));
account.balance = balanceAfter;
account.total_income = parseFloat((Number(account.total_income) + amountNum).toFixed(2));
account.version += 1;
await queryRunner.manager.save(account);
const transaction = this.systemTransactionRepo.create({
transactionNo: transactionNo,
accountId: account.id,
direction: 'income',
amount: amountNum,
balanceBefore: balanceBefore,
balanceAfter: balanceAfter,
transactionType: '用户支付',
businessType: businessType,
businessId: businessId,
businessNo: businessNo,
remark,
});
await queryRunner.manager.save(transaction);
await queryRunner.commitTransaction();
} catch (error) {
await queryRunner.rollbackTransaction();
throw error;
} finally {
await queryRunner.release();
}
}
/**
* 系统总账户增加退款支出
*/
async addSystemRefund(
amount: number,
transactionNo: string,
businessType: string,
businessId: number,
businessNo: string,
remark: string,
): Promise<void> {
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
const account = await queryRunner.manager.findOne(SystemAccount, {
where: { account_name: '主账户' },
lock: { mode: 'pessimistic_write' },
});
if (!account) {
throw new NotFoundException('系统总账户不存在');
}
const amountNum = Number(amount);
const balanceBefore = Number(account.balance);
const balanceAfter = parseFloat((balanceBefore - amountNum).toFixed(2));
account.balance = balanceAfter;
account.total_refund = parseFloat((Number(account.total_refund) + amountNum).toFixed(2));
account.version += 1;
await queryRunner.manager.save(account);
const transaction = this.systemTransactionRepo.create({
transactionNo: transactionNo,
accountId: account.id,
direction: 'expense',
amount: amountNum,
balanceBefore: balanceBefore,
balanceAfter: balanceAfter,
transactionType: '退款',
businessType: businessType,
businessId: businessId,
businessNo: businessNo,
remark,
});
await queryRunner.manager.save(transaction);
await queryRunner.commitTransaction();
} catch (error) {
await queryRunner.rollbackTransaction();
throw error;
} finally {
await queryRunner.release();
}
}
/**
* 系统总账户增加提现支出
*/
async addSystemWithdrawal(
amount: number,
transactionNo: string,
businessType: string,
businessId: number,
businessNo: string,
remark: string,
): Promise<void> {
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
const account = await queryRunner.manager.findOne(SystemAccount, {
where: { account_name: '主账户' },
lock: { mode: 'pessimistic_write' },
});
if (!account) {
throw new NotFoundException('系统总账户不存在');
}
const amountNum = Number(amount);
const balanceBefore = Number(account.balance);
const balanceAfter = parseFloat((balanceBefore - amountNum).toFixed(2));
account.balance = balanceAfter;
account.total_withdrawn = parseFloat((Number(account.total_withdrawn) + amountNum).toFixed(2));
account.version += 1;
await queryRunner.manager.save(account);
const transaction = this.systemTransactionRepo.create({
transactionNo: transactionNo,
accountId: account.id,
direction: 'expense',
amount: amountNum,
balanceBefore: balanceBefore,
balanceAfter: balanceAfter,
transactionType: '提现',
businessType: businessType,
businessId: businessId,
businessNo: businessNo,
remark,
});
await queryRunner.manager.save(transaction);
await queryRunner.commitTransaction();
} catch (error) {
await queryRunner.rollbackTransaction();
throw error;
} finally {
await queryRunner.release();
}
}
}
@@ -5,12 +5,15 @@ import { SettlementItem } from '@/entities/settlement-item.entity';
import { UserWithdrawal } from '@/entities/user-withdrawal.entity';
import { MerchantWithdrawal } from '@/entities/merchant-withdrawal.entity';
import { PlatformWithdrawal } from '@/entities/platform-withdrawal.entity';
import { MktInviteWithdrawal } from '@/entities/mkt-invite-withdrawal.entity';
import { UserAccount } from '@/entities/user-account.entity';
import { MerchantAccount } from '@/entities/merchant-account.entity';
import { PlatformAccount } from '@/entities/platform-account.entity';
import { SystemAccount } from '@/entities/system-account.entity';
import { UserTransaction } from '@/entities/user-transaction.entity';
import { MerchantTransaction } from '@/entities/merchant-transaction.entity';
import { PlatformTransaction } from '@/entities/platform-transaction.entity';
import { SystemTransaction } from '@/entities/system-transaction.entity';
import { DailyReconciliation } from '@/entities/daily-reconciliation.entity';
import { PlatformConfig } from '@/entities/platform-config.entity';
import { Merchant } from '@/entities/merchant.entity';
@@ -33,12 +36,15 @@ import { MerchantModule } from '@/modules/merchant/merchant.module';
UserWithdrawal,
MerchantWithdrawal,
PlatformWithdrawal,
MktInviteWithdrawal,
UserAccount,
MerchantAccount,
PlatformAccount,
SystemAccount,
UserTransaction,
MerchantTransaction,
PlatformTransaction,
SystemTransaction,
DailyReconciliation,
PlatformConfig,
Merchant,
@@ -3,8 +3,8 @@ import { InjectRepository } from '@nestjs/typeorm';
import { Repository, DataSource } from 'typeorm';
import { ConfigService } from '@nestjs/config';
import { Order } from '@/entities/order.entity';
import { PlatformAccount } from '@/entities/platform-account.entity';
import { PlatformTransaction } from '@/entities/platform-transaction.entity';
import { AccountService } from './account.service';
import { TransactionService } from './transaction.service';
import Wechatpay = require('wechatpay-node-v3');
@Injectable()
@@ -14,10 +14,8 @@ export class RefundService {
constructor(
@InjectRepository(Order)
private orderRepo: Repository<Order>,
@InjectRepository(PlatformAccount)
private platformAccountRepo: Repository<PlatformAccount>,
@InjectRepository(PlatformTransaction)
private platformTransactionRepo: Repository<PlatformTransaction>,
private accountService: AccountService,
private transactionService: TransactionService,
private dataSource: DataSource,
private configService: ConfigService,
) {
@@ -179,7 +177,7 @@ export class RefundService {
}
/**
* 平台账户记录退款支出(仅用于记账)
* 记录系统总账户退款
* @param order 订单信息
* @param queryRunner 事务查询器
*/
@@ -187,34 +185,17 @@ export class RefundService {
order: Order,
queryRunner: any,
): Promise<void> {
// 获取平台主账户
const platformAccount = await queryRunner.manager.findOne(PlatformAccount, {
where: { accountType: 'main' },
});
const transactionNo = this.transactionService.generateTransactionNo();
if (!platformAccount) {
throw new BadRequestException('平台账户不存在');
}
// 创建退款支出交易记录(仅记账,实际退款通过第三方支付)
const transaction = queryRunner.manager.create(PlatformTransaction, {
accountId: platformAccount.id,
type: 'refund_expense',
amount: order.payAmount,
balance: platformAccount.balance, // 余额不变,仅记录
relatedType: 'order',
relatedId: order.id,
description: `订单退款 - ${order.orderNo}`,
metadata: {
orderId: order.id,
orderNo: order.orderNo,
userId: order.userId,
paymentMethod: order.paymentMethod,
refundAmount: order.payAmount,
},
});
await queryRunner.manager.save(transaction);
// 记录系统总账户退款
await this.accountService.addSystemRefund(
order.payAmount,
transactionNo,
'order_refund',
order.id,
order.orderNo,
`订单退款 - ${order.orderNo}`,
);
}
/**
@@ -1,17 +1,24 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { SystemAccount } from '@/entities/system-account.entity';
import { PlatformAccount } from '@/entities/platform-account.entity';
import { UserAccount } from '@/entities/user-account.entity';
import { MerchantAccount } from '@/entities/merchant-account.entity';
import { PlatformTransaction } from '@/entities/platform-transaction.entity';
import { Order } from '@/entities/order.entity';
import { Settlement } from '@/entities/settlement.entity';
import { MerchantWithdrawal } from '@/entities/merchant-withdrawal.entity';
import { UserWithdrawal } from '@/entities/user-withdrawal.entity';
import { PlatformWithdrawal } from '@/entities/platform-withdrawal.entity';
import { MktInviteWithdrawal } from '@/entities/mkt-invite-withdrawal.entity';
import dayjs from 'dayjs';
@Injectable()
export class ReportService {
constructor(
@InjectRepository(SystemAccount)
private systemAccountRepo: Repository<SystemAccount>,
@InjectRepository(PlatformAccount)
private platformAccountRepo: Repository<PlatformAccount>,
@InjectRepository(UserAccount)
@@ -24,12 +31,26 @@ export class ReportService {
private orderRepo: Repository<Order>,
@InjectRepository(Settlement)
private settlementRepo: Repository<Settlement>,
@InjectRepository(MerchantWithdrawal)
private merchantWithdrawalRepo: Repository<MerchantWithdrawal>,
@InjectRepository(UserWithdrawal)
private userWithdrawalRepo: Repository<UserWithdrawal>,
@InjectRepository(PlatformWithdrawal)
private platformWithdrawalRepo: Repository<PlatformWithdrawal>,
@InjectRepository(MktInviteWithdrawal)
private mktInviteWithdrawalRepo: Repository<MktInviteWithdrawal>,
) {}
/**
* 财务总览
*/
async getOverview() {
// 获取系统总账户
const systemAccount = await this.systemAccountRepo.findOne({
where: { account_name: '系统总账户' },
});
// 获取平台账户
const platformAccount = await this.platformAccountRepo.findOne({
where: { account_name: '主账户' },
});
@@ -68,11 +89,26 @@ export class ReportService {
.getRawOne();
return {
// 系统总账户金额(用户实付 - 退款 - 提现)
systemTotalAmount: Number(systemAccount?.balance || 0),
totalUserPaid: Number(systemAccount?.total_income || 0),
totalRefund: Number(systemAccount?.total_refund || 0),
totalWithdrawn: Number(systemAccount?.total_withdrawn || 0),
// 平台净收益(服务费 - 邀请返现)
platformBalance: Number(platformAccount?.balance || 0),
merchantTotalBalance: Number(merchantStats?.totalBalance || 0),
platformTotalIncome: Number(platformAccount?.total_income || 0),
platformTotalExpense: Number(platformAccount?.total_expense || 0),
// 商家账户统计
totalMerchantBalance: Number(merchantStats?.totalBalance || 0),
merchantCount: Number(merchantStats?.count || 0),
userTotalBalance: Number(userStats?.totalBalance || 0),
// 用户账户统计
totalUserBalance: Number(userStats?.totalBalance || 0),
userCount: Number(userStats?.count || 0),
// 今日统计
todayOrders,
todayIncome: Number(todayIncome?.sum || 0),
todayExpense: Number(todayExpense?.sum || 0),
@@ -167,6 +167,7 @@ export class SettlementService {
const transactionNo = this.transactionService.generateTransactionNo();
// 给商家账户增加余额(订单金额 - 服务费)
await this.accountService.addMerchantBalance(
merchantId,
settlementAmount,
@@ -177,14 +178,14 @@ export class SettlementService {
`商家周结算:${periodStart} ~ ${periodEnd}`
);
await this.accountService.deductPlatformBalance(
settlementAmount,
// 给平台账户增加服务费收入
await this.accountService.addPlatformServiceFee(
serviceFee,
transactionNo,
'商家结算',
'settlement',
settlement.id,
settlementNo,
`商家 ${merchantId} 周结算:${periodStart} ~ ${periodEnd}`
`商家 ${merchantId} 周结算服务费${periodStart} ~ ${periodEnd}`
);
await queryRunner.commitTransaction();
@@ -155,10 +155,10 @@ export class WithdrawalService {
const account = await this.accountService.getPlatformAccount();
// 计算可提现金额 = 累计服务费 - 冻结余额
// 注意:这里使用 total_service_fee 是为了确保只提现平台收入
// 计算可提现金额 = 累计收入 - 冻结余额
// 注意:这里使用 total_income 是为了确保只提现平台收入
// 未来如果有其他收入(广告费、会员费等),需要累加到可提现金额中
const availableAmount = Number(account.total_service_fee) - Number(account.frozen_balance);
const availableAmount = Number(account.total_income) - Number(account.frozen_balance);
if (availableAmount < amount) {
throw new BadRequestException(`可提现金额不足,当前可提现:${availableAmount.toFixed(2)}`);
@@ -294,6 +294,7 @@ export class WithdrawalService {
try {
const transactionNo = this.transactionService.generateTransactionNo();
// 扣减用户账户余额
await this.accountService.deductUserBalance(
withdrawal.userId,
Number(withdrawal.actualAmount),
@@ -304,6 +305,16 @@ export class WithdrawalService {
`用户提现 - ${withdrawal.paymentChannel}`
);
// 记录系统总账户提现
await this.accountService.addSystemWithdrawal(
Number(withdrawal.actualAmount),
transactionNo,
'user_withdraw',
withdrawal.id,
withdrawal.withdrawNo,
`用户 ${withdrawal.userId} 提现 - ${withdrawal.paymentChannel}`,
);
await queryRunner.manager.update(UserWithdrawal, id, {
status: 'paid',
paymentNo,
@@ -415,6 +426,7 @@ export class WithdrawalService {
try {
const transactionNo = this.transactionService.generateTransactionNo();
// 扣减商家账户余额
await this.accountService.deductMerchantBalance(
withdrawal.merchantId,
Number(withdrawal.actualAmount),
@@ -425,6 +437,16 @@ export class WithdrawalService {
`商家提现 - ${withdrawal.bankName}`
);
// 记录系统总账户提现
await this.accountService.addSystemWithdrawal(
Number(withdrawal.actualAmount),
transactionNo,
'merchant_withdraw',
withdrawal.id,
withdrawal.withdrawNo,
`商家 ${withdrawal.merchantId} 提现 - ${withdrawal.bankName}`,
);
await queryRunner.manager.update(MerchantWithdrawal, id, {
status: 'paid',
paymentNo,
@@ -536,10 +558,9 @@ export class WithdrawalService {
try {
const transactionNo = this.transactionService.generateTransactionNo();
await this.accountService.deductPlatformBalance(
await this.accountService.deductPlatformWithdrawal(
Number(withdrawal.actualAmount),
transactionNo,
'提现',
'withdraw',
withdrawal.id,
withdrawal.withdrawNo,