feat(c2c): 卖单自动获取账户ID和Kava地址,移除手动输入
后端创建卖单时自动从 identity-service 获取卖家 Kava 地址并存入订单, 前端发布页面自动展示 accountSequence(只读),不再需要手动输入1.0系统ID。 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
2b7a30983e
commit
263f1ecf8e
|
|
@ -57,6 +57,8 @@ export class C2cController {
|
||||||
paymentAccount: order.paymentAccount || undefined,
|
paymentAccount: order.paymentAccount || undefined,
|
||||||
paymentQrCode: order.paymentQrCode || undefined,
|
paymentQrCode: order.paymentQrCode || undefined,
|
||||||
paymentRealName: order.paymentRealName || undefined,
|
paymentRealName: order.paymentRealName || undefined,
|
||||||
|
// 卖家 Kava 地址
|
||||||
|
sellerKavaAddress: order.sellerKavaAddress || undefined,
|
||||||
// 超时信息
|
// 超时信息
|
||||||
paymentTimeoutMinutes: order.paymentTimeoutMinutes,
|
paymentTimeoutMinutes: order.paymentTimeoutMinutes,
|
||||||
confirmTimeoutMinutes: order.confirmTimeoutMinutes,
|
confirmTimeoutMinutes: order.confirmTimeoutMinutes,
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,8 @@ export class C2cOrderResponseDto {
|
||||||
paymentAccount?: string;
|
paymentAccount?: string;
|
||||||
paymentQrCode?: string;
|
paymentQrCode?: string;
|
||||||
paymentRealName?: string;
|
paymentRealName?: string;
|
||||||
|
// 卖家 Kava 地址(绿积分转账地址)
|
||||||
|
sellerKavaAddress?: string;
|
||||||
// 超时信息
|
// 超时信息
|
||||||
paymentTimeoutMinutes: number;
|
paymentTimeoutMinutes: number;
|
||||||
confirmTimeoutMinutes: number;
|
confirmTimeoutMinutes: number;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { C2cOrderRepository, C2cOrderEntity } from '../../infrastructure/persist
|
||||||
import { TradingAccountRepository } from '../../infrastructure/persistence/repositories/trading-account.repository';
|
import { TradingAccountRepository } from '../../infrastructure/persistence/repositories/trading-account.repository';
|
||||||
import { RedisService } from '../../infrastructure/redis/redis.service';
|
import { RedisService } from '../../infrastructure/redis/redis.service';
|
||||||
import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service';
|
import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service';
|
||||||
|
import { IdentityClient } from '../../infrastructure/identity/identity.client';
|
||||||
import { Money } from '../../domain/value-objects/money.vo';
|
import { Money } from '../../domain/value-objects/money.vo';
|
||||||
import Decimal from 'decimal.js';
|
import Decimal from 'decimal.js';
|
||||||
|
|
||||||
|
|
@ -57,6 +58,7 @@ export class C2cService {
|
||||||
private readonly tradingAccountRepository: TradingAccountRepository,
|
private readonly tradingAccountRepository: TradingAccountRepository,
|
||||||
private readonly redis: RedisService,
|
private readonly redis: RedisService,
|
||||||
private readonly prisma: PrismaService,
|
private readonly prisma: PrismaService,
|
||||||
|
private readonly identityClient: IdentityClient,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -109,16 +111,12 @@ export class C2cService {
|
||||||
throw new BadRequestException('数量必须大于0');
|
throw new BadRequestException('数量必须大于0');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 卖单必须提供收款信息
|
// 卖单:自动获取卖家 Kava 地址(用于绿积分转账)
|
||||||
|
let sellerKavaAddress: string | null = null;
|
||||||
if (type === C2C_ORDER_TYPE.SELL) {
|
if (type === C2C_ORDER_TYPE.SELL) {
|
||||||
if (!options?.paymentMethod) {
|
sellerKavaAddress = await this.identityClient.getUserKavaAddress(accountSequence);
|
||||||
throw new BadRequestException('卖单必须提供收款方式');
|
if (!sellerKavaAddress) {
|
||||||
}
|
throw new BadRequestException('未找到您的 Kava 钱包地址,请先绑定钱包');
|
||||||
if (!options?.paymentAccount) {
|
|
||||||
throw new BadRequestException('卖单必须提供收款账号');
|
|
||||||
}
|
|
||||||
if (!options?.paymentRealName) {
|
|
||||||
throw new BadRequestException('卖单必须提供收款人实名');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,6 +167,8 @@ export class C2cService {
|
||||||
paymentAccount: options?.paymentAccount,
|
paymentAccount: options?.paymentAccount,
|
||||||
paymentQrCode: options?.paymentQrCode,
|
paymentQrCode: options?.paymentQrCode,
|
||||||
paymentRealName: options?.paymentRealName,
|
paymentRealName: options?.paymentRealName,
|
||||||
|
// 卖家 Kava 地址(卖单时自动获取)
|
||||||
|
sellerKavaAddress,
|
||||||
remark: options?.remark,
|
remark: options?.remark,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,8 @@ export class C2cOrderRepository {
|
||||||
paymentAccount?: string;
|
paymentAccount?: string;
|
||||||
paymentQrCode?: string;
|
paymentQrCode?: string;
|
||||||
paymentRealName?: string;
|
paymentRealName?: string;
|
||||||
|
// 卖家 Kava 地址
|
||||||
|
sellerKavaAddress?: string | null;
|
||||||
remark?: string;
|
remark?: string;
|
||||||
}): Promise<C2cOrderEntity> {
|
}): Promise<C2cOrderEntity> {
|
||||||
const record = await this.prisma.c2cOrder.create({
|
const record = await this.prisma.c2cOrder.create({
|
||||||
|
|
@ -132,6 +134,8 @@ export class C2cOrderRepository {
|
||||||
paymentAccount: data.paymentAccount,
|
paymentAccount: data.paymentAccount,
|
||||||
paymentQrCode: data.paymentQrCode,
|
paymentQrCode: data.paymentQrCode,
|
||||||
paymentRealName: data.paymentRealName,
|
paymentRealName: data.paymentRealName,
|
||||||
|
// 卖家 Kava 地址
|
||||||
|
sellerKavaAddress: data.sellerKavaAddress,
|
||||||
remark: data.remark,
|
remark: data.remark,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,6 @@ abstract class TradingRemoteDataSource {
|
||||||
String? paymentAccount,
|
String? paymentAccount,
|
||||||
String? paymentQrCode,
|
String? paymentQrCode,
|
||||||
String? paymentRealName,
|
String? paymentRealName,
|
||||||
String? systemId, // 1.0系统ID(绿积分支付必填)
|
|
||||||
String? remark,
|
String? remark,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -467,7 +466,6 @@ class TradingRemoteDataSourceImpl implements TradingRemoteDataSource {
|
||||||
String? paymentAccount,
|
String? paymentAccount,
|
||||||
String? paymentQrCode,
|
String? paymentQrCode,
|
||||||
String? paymentRealName,
|
String? paymentRealName,
|
||||||
String? systemId, // 1.0系统ID(绿积分支付必填)
|
|
||||||
String? remark,
|
String? remark,
|
||||||
}) async {
|
}) async {
|
||||||
try {
|
try {
|
||||||
|
|
@ -483,7 +481,6 @@ class TradingRemoteDataSourceImpl implements TradingRemoteDataSource {
|
||||||
if (paymentAccount != null) data['paymentAccount'] = paymentAccount;
|
if (paymentAccount != null) data['paymentAccount'] = paymentAccount;
|
||||||
if (paymentQrCode != null) data['paymentQrCode'] = paymentQrCode;
|
if (paymentQrCode != null) data['paymentQrCode'] = paymentQrCode;
|
||||||
if (paymentRealName != null) data['paymentRealName'] = paymentRealName;
|
if (paymentRealName != null) data['paymentRealName'] = paymentRealName;
|
||||||
if (systemId != null && systemId.isNotEmpty) data['systemId'] = systemId;
|
|
||||||
if (remark != null && remark.isNotEmpty) data['remark'] = remark;
|
if (remark != null && remark.isNotEmpty) data['remark'] = remark;
|
||||||
|
|
||||||
final response = await client.post(
|
final response = await client.post(
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ class _C2cPublishPageState extends ConsumerState<C2cPublishPage> {
|
||||||
Set<String> _selectedPaymentMethods = {'GREEN_POINTS'}; // 绿积分默认选中且不可取消
|
Set<String> _selectedPaymentMethods = {'GREEN_POINTS'}; // 绿积分默认选中且不可取消
|
||||||
final _paymentAccountController = TextEditingController();
|
final _paymentAccountController = TextEditingController();
|
||||||
final _paymentRealNameController = TextEditingController();
|
final _paymentRealNameController = TextEditingController();
|
||||||
final _systemIdController = TextEditingController(); // 1.0系统ID
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
|
@ -41,7 +40,6 @@ class _C2cPublishPageState extends ConsumerState<C2cPublishPage> {
|
||||||
_remarkController.dispose();
|
_remarkController.dispose();
|
||||||
_paymentAccountController.dispose();
|
_paymentAccountController.dispose();
|
||||||
_paymentRealNameController.dispose();
|
_paymentRealNameController.dispose();
|
||||||
_systemIdController.dispose();
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -400,32 +398,27 @@ class _C2cPublishPageState extends ConsumerState<C2cPublishPage> {
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// 1.0系统ID(绿积分必填)
|
// 账户ID(自动读取,只读)
|
||||||
const Text(
|
const Text(
|
||||||
'1.0系统ID',
|
'账户ID',
|
||||||
style: TextStyle(fontSize: 14, color: _grayText),
|
style: TextStyle(fontSize: 14, color: _grayText),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
const Text(
|
const Text(
|
||||||
'买家将通过此ID向您转账绿积分',
|
'买家将通过此账户向您转账绿积分',
|
||||||
style: TextStyle(fontSize: 12, color: _grayText),
|
style: TextStyle(fontSize: 12, color: _grayText),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
TextField(
|
Container(
|
||||||
controller: _systemIdController,
|
width: double.infinity,
|
||||||
decoration: InputDecoration(
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
|
||||||
hintText: '请输入您的1.0系统ID',
|
decoration: BoxDecoration(
|
||||||
hintStyle: const TextStyle(color: _grayText),
|
color: _bgGray,
|
||||||
filled: true,
|
borderRadius: BorderRadius.circular(12),
|
||||||
fillColor: _bgGray,
|
),
|
||||||
border: OutlineInputBorder(
|
child: Text(
|
||||||
borderRadius: BorderRadius.circular(12),
|
ref.watch(userNotifierProvider).accountSequence ?? '',
|
||||||
borderSide: BorderSide.none,
|
style: const TextStyle(fontSize: 15, color: _darkText),
|
||||||
),
|
|
||||||
focusedBorder: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
borderSide: const BorderSide(color: _orange, width: 2),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
@ -675,8 +668,6 @@ class _C2cPublishPageState extends ConsumerState<C2cPublishPage> {
|
||||||
// 验证条件
|
// 验证条件
|
||||||
bool isValid = price > 0 && quantity > 0;
|
bool isValid = price > 0 && quantity > 0;
|
||||||
if (isSell) {
|
if (isSell) {
|
||||||
// 卖单必须填写1.0系统ID(因为绿积分是必选的)
|
|
||||||
isValid = isValid && _systemIdController.text.trim().isNotEmpty;
|
|
||||||
// 如果选择了其他支付方式,还需要填写收款账号和姓名
|
// 如果选择了其他支付方式,还需要填写收款账号和姓名
|
||||||
if (_selectedPaymentMethods.any((m) => m != 'GREEN_POINTS')) {
|
if (_selectedPaymentMethods.any((m) => m != 'GREEN_POINTS')) {
|
||||||
isValid = isValid &&
|
isValid = isValid &&
|
||||||
|
|
@ -774,13 +765,6 @@ class _C2cPublishPageState extends ConsumerState<C2cPublishPage> {
|
||||||
|
|
||||||
// 卖单验证收款信息
|
// 卖单验证收款信息
|
||||||
if (isSell) {
|
if (isSell) {
|
||||||
// 必须填写1.0系统ID(绿积分是必选的)
|
|
||||||
if (_systemIdController.text.trim().isEmpty) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(content: Text('请填写1.0系统ID'), backgroundColor: _red),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 如果选择了其他支付方式,需要填写收款账号和姓名
|
// 如果选择了其他支付方式,需要填写收款账号和姓名
|
||||||
if (_selectedPaymentMethods.any((m) => m != 'GREEN_POINTS')) {
|
if (_selectedPaymentMethods.any((m) => m != 'GREEN_POINTS')) {
|
||||||
if (_paymentAccountController.text.trim().isEmpty) {
|
if (_paymentAccountController.text.trim().isEmpty) {
|
||||||
|
|
@ -832,7 +816,7 @@ class _C2cPublishPageState extends ConsumerState<C2cPublishPage> {
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text('收款方式: $paymentMethodTexts'),
|
Text('收款方式: $paymentMethodTexts'),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text('1.0系统ID: ${_systemIdController.text.trim()}'),
|
Text('账户ID: ${ref.read(userNotifierProvider).accountSequence ?? ''}'),
|
||||||
if (_selectedPaymentMethods.any((m) => m != 'GREEN_POINTS')) ...[
|
if (_selectedPaymentMethods.any((m) => m != 'GREEN_POINTS')) ...[
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text('收款账号: ${_paymentAccountController.text.trim()}'),
|
Text('收款账号: ${_paymentAccountController.text.trim()}'),
|
||||||
|
|
@ -874,7 +858,6 @@ class _C2cPublishPageState extends ConsumerState<C2cPublishPage> {
|
||||||
paymentMethod: isSell ? _selectedPaymentMethods.join(',') : null,
|
paymentMethod: isSell ? _selectedPaymentMethods.join(',') : null,
|
||||||
paymentAccount: isSell ? _paymentAccountController.text.trim() : null,
|
paymentAccount: isSell ? _paymentAccountController.text.trim() : null,
|
||||||
paymentRealName: isSell ? _paymentRealNameController.text.trim() : null,
|
paymentRealName: isSell ? _paymentRealNameController.text.trim() : null,
|
||||||
systemId: isSell ? _systemIdController.text.trim() : null,
|
|
||||||
remark: remark.isEmpty ? null : remark,
|
remark: remark.isEmpty ? null : remark,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,6 @@ class C2cTradingNotifier extends StateNotifier<C2cTradingState> {
|
||||||
String? paymentAccount,
|
String? paymentAccount,
|
||||||
String? paymentQrCode,
|
String? paymentQrCode,
|
||||||
String? paymentRealName,
|
String? paymentRealName,
|
||||||
String? systemId, // 1.0系统ID(绿积分支付必填)
|
|
||||||
String? remark,
|
String? remark,
|
||||||
}) async {
|
}) async {
|
||||||
state = state.copyWith(isLoading: true, clearError: true);
|
state = state.copyWith(isLoading: true, clearError: true);
|
||||||
|
|
@ -102,7 +101,6 @@ class C2cTradingNotifier extends StateNotifier<C2cTradingState> {
|
||||||
paymentAccount: paymentAccount,
|
paymentAccount: paymentAccount,
|
||||||
paymentQrCode: paymentQrCode,
|
paymentQrCode: paymentQrCode,
|
||||||
paymentRealName: paymentRealName,
|
paymentRealName: paymentRealName,
|
||||||
systemId: systemId,
|
|
||||||
remark: remark,
|
remark: remark,
|
||||||
);
|
);
|
||||||
state = state.copyWith(isLoading: false, lastOrder: order);
|
state = state.copyWith(isLoading: false, lastOrder: order);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue