feat: 已认种用户分享权益直接进入可结算状态
- 新增 hasPlanted 字段标记用户是否已认种 - 已认种用户的分享权益直接进入可结算余额,无需待领取 - 修正前端权益考核数值(576/288/252/144/108 绿积分) - 修复账本明细筛选栏选择后滚动位置重置问题 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
723d70e4b8
commit
3f5203c142
|
|
@ -0,0 +1,8 @@
|
||||||
|
-- 添加 has_planted 字段,标记用户是否已认种过
|
||||||
|
-- 认种后的用户,分享权益直接进入可结算状态,无需待领取
|
||||||
|
|
||||||
|
ALTER TABLE "wallet_accounts" ADD COLUMN "has_planted" BOOLEAN NOT NULL DEFAULT false;
|
||||||
|
|
||||||
|
-- 为已有认种记录的用户设置 has_planted = true
|
||||||
|
-- 通过检查 settled_total_usdt > 0 来推断(有结算记录说明曾经认种过)
|
||||||
|
UPDATE "wallet_accounts" SET "has_planted" = true WHERE "settled_total_usdt" > 0;
|
||||||
|
|
@ -58,6 +58,9 @@ model WalletAccount {
|
||||||
// 状态
|
// 状态
|
||||||
status String @default("ACTIVE") @map("status") @db.VarChar(20)
|
status String @default("ACTIVE") @map("status") @db.VarChar(20)
|
||||||
|
|
||||||
|
// 是否已认种过(认种后分享权益直接进入可结算)
|
||||||
|
hasPlanted Boolean @default(false) @map("has_planted")
|
||||||
|
|
||||||
// 乐观锁版本号
|
// 乐观锁版本号
|
||||||
version Int @default(0) @map("version")
|
version Int @default(0) @map("version")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import { WalletApplicationService } from '@/application/services';
|
||||||
* 处理认种创建事件
|
* 处理认种创建事件
|
||||||
*
|
*
|
||||||
* 当用户认种一棵树后:
|
* 当用户认种一棵树后:
|
||||||
* 1. 结算该用户所有待领取奖励(从 PENDING 变为 SETTLED)
|
* 1. 标记用户为已认种(后续分享权益直接进入可结算)
|
||||||
* 2. 待领取 → 可结算,算力生效
|
* 2. 结算该用户所有待领取奖励(从 PENDING 变为 SETTLED)
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PlantingCreatedHandler implements OnModuleInit {
|
export class PlantingCreatedHandler implements OnModuleInit {
|
||||||
|
|
@ -29,7 +29,10 @@ export class PlantingCreatedHandler implements OnModuleInit {
|
||||||
this.logger.log(`[PLANTING] User ${accountSequence} planted ${treeCount} tree(s), order: ${orderNo}`);
|
this.logger.log(`[PLANTING] User ${accountSequence} planted ${treeCount} tree(s), order: ${orderNo}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 用户认种后,结算其所有待领取奖励
|
// 1. 标记用户为已认种(后续分享权益直接进入可结算)
|
||||||
|
await this.walletService.markUserAsPlanted(accountSequence);
|
||||||
|
|
||||||
|
// 2. 结算用户所有待领取奖励
|
||||||
const result = await this.walletService.settleUserPendingRewards(accountSequence);
|
const result = await this.walletService.settleUserPendingRewards(accountSequence);
|
||||||
|
|
||||||
if (result.settledCount > 0) {
|
if (result.settledCount > 0) {
|
||||||
|
|
@ -41,7 +44,7 @@ export class PlantingCreatedHandler implements OnModuleInit {
|
||||||
this.logger.debug(`[PLANTING] No pending rewards to settle for ${accountSequence}`);
|
this.logger.debug(`[PLANTING] No pending rewards to settle for ${accountSequence}`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error(`[PLANTING] Failed to settle pending rewards for ${accountSequence}`, error);
|
this.logger.error(`[PLANTING] Failed to process planting for ${accountSequence}`, error);
|
||||||
// 不抛出异常,避免阻塞 Kafka 消费
|
// 不抛出异常,避免阻塞 Kafka 消费
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -956,7 +956,7 @@ export class WalletApplicationService {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分享权益 (SHARE_RIGHT) - 写入 pending_rewards 表待领取
|
// 分享权益 (SHARE_RIGHT)
|
||||||
// targetId 是 accountSequence (用户账户: D2512120001)
|
// targetId 是 accountSequence (用户账户: D2512120001)
|
||||||
const targetId = allocation.targetId;
|
const targetId = allocation.targetId;
|
||||||
|
|
||||||
|
|
@ -967,45 +967,73 @@ export class WalletApplicationService {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加待领取奖励(24小时后过期)- 写入 pending_rewards 表
|
// 根据用户是否已认种,决定分配方式
|
||||||
const expireAt = new Date(Date.now() + 24 * 60 * 60 * 1000);
|
if (wallet.hasPlanted) {
|
||||||
|
// 已认种用户:直接进入可结算余额
|
||||||
|
wallet.addSettleableReward(amount, Hashpower.create(0));
|
||||||
|
await this.walletRepo.save(wallet);
|
||||||
|
|
||||||
const pendingReward = PendingReward.create({
|
// 记录流水 - 直接可结算
|
||||||
accountSequence: wallet.accountSequence,
|
const ledgerEntry = LedgerEntry.create({
|
||||||
userId: wallet.userId,
|
accountSequence: wallet.accountSequence,
|
||||||
usdtAmount: amount,
|
userId: wallet.userId,
|
||||||
hashpowerAmount: Hashpower.create(0),
|
entryType: LedgerEntryType.REWARD_TO_SETTLEABLE,
|
||||||
sourceOrderId: orderId,
|
amount,
|
||||||
allocationType: allocation.allocationType,
|
refOrderId: orderId,
|
||||||
expireAt,
|
memo: `${allocation.allocationType} allocation (direct settleable)`,
|
||||||
});
|
payloadJson: {
|
||||||
await this.pendingRewardRepo.save(pendingReward);
|
allocationType: allocation.allocationType,
|
||||||
|
metadata: allocation.metadata,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await this.ledgerRepo.save(ledgerEntry);
|
||||||
|
|
||||||
// 同步更新 wallet_accounts 表的 pending_usdt 字段
|
await this.walletCacheService.invalidateWallet(wallet.userId.value);
|
||||||
wallet.addPendingReward(amount, Hashpower.create(0), expireAt, orderId);
|
|
||||||
await this.walletRepo.save(wallet);
|
|
||||||
|
|
||||||
// 记录流水
|
this.logger.debug(
|
||||||
const ledgerEntry = LedgerEntry.create({
|
`Allocated ${allocation.amount} USDT to user ${allocation.targetId} for ${allocation.allocationType} (direct settleable)`,
|
||||||
accountSequence: wallet.accountSequence,
|
);
|
||||||
userId: wallet.userId,
|
} else {
|
||||||
entryType: LedgerEntryType.REWARD_PENDING,
|
// 未认种用户:写入 pending_rewards 表待领取
|
||||||
amount,
|
const expireAt = new Date(Date.now() + 24 * 60 * 60 * 1000);
|
||||||
refOrderId: orderId,
|
|
||||||
memo: `${allocation.allocationType} allocation`,
|
const pendingReward = PendingReward.create({
|
||||||
payloadJson: {
|
accountSequence: wallet.accountSequence,
|
||||||
|
userId: wallet.userId,
|
||||||
|
usdtAmount: amount,
|
||||||
|
hashpowerAmount: Hashpower.create(0),
|
||||||
|
sourceOrderId: orderId,
|
||||||
allocationType: allocation.allocationType,
|
allocationType: allocation.allocationType,
|
||||||
expireAt: expireAt.toISOString(),
|
expireAt,
|
||||||
metadata: allocation.metadata,
|
});
|
||||||
},
|
await this.pendingRewardRepo.save(pendingReward);
|
||||||
});
|
|
||||||
await this.ledgerRepo.save(ledgerEntry);
|
|
||||||
|
|
||||||
await this.walletCacheService.invalidateWallet(wallet.userId.value);
|
// 同步更新 wallet_accounts 表的 pending_usdt 字段
|
||||||
|
wallet.addPendingReward(amount, Hashpower.create(0), expireAt, orderId);
|
||||||
|
await this.walletRepo.save(wallet);
|
||||||
|
|
||||||
this.logger.debug(
|
// 记录流水
|
||||||
`Allocated ${allocation.amount} USDT to user ${allocation.targetId} for ${allocation.allocationType} (pending)`,
|
const ledgerEntry = LedgerEntry.create({
|
||||||
);
|
accountSequence: wallet.accountSequence,
|
||||||
|
userId: wallet.userId,
|
||||||
|
entryType: LedgerEntryType.REWARD_PENDING,
|
||||||
|
amount,
|
||||||
|
refOrderId: orderId,
|
||||||
|
memo: `${allocation.allocationType} allocation`,
|
||||||
|
payloadJson: {
|
||||||
|
allocationType: allocation.allocationType,
|
||||||
|
expireAt: expireAt.toISOString(),
|
||||||
|
metadata: allocation.metadata,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await this.ledgerRepo.save(ledgerEntry);
|
||||||
|
|
||||||
|
await this.walletCacheService.invalidateWallet(wallet.userId.value);
|
||||||
|
|
||||||
|
this.logger.debug(
|
||||||
|
`Allocated ${allocation.amount} USDT to user ${allocation.targetId} for ${allocation.allocationType} (pending)`,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1790,6 +1818,29 @@ export class WalletApplicationService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标记用户为已认种
|
||||||
|
* 认种后的用户,分享权益直接进入可结算状态
|
||||||
|
*/
|
||||||
|
async markUserAsPlanted(accountSequence: string): Promise<void> {
|
||||||
|
const wallet = await this.walletRepo.findByAccountSequence(accountSequence);
|
||||||
|
if (!wallet) {
|
||||||
|
this.logger.warn(`[markUserAsPlanted] Wallet not found for ${accountSequence}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wallet.hasPlanted) {
|
||||||
|
this.logger.debug(`[markUserAsPlanted] User ${accountSequence} already marked as planted`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet.markAsPlanted();
|
||||||
|
await this.walletRepo.save(wallet);
|
||||||
|
await this.walletCacheService.invalidateWallet(wallet.userId.value);
|
||||||
|
|
||||||
|
this.logger.log(`[markUserAsPlanted] User ${accountSequence} marked as planted`);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理过期奖励
|
* 处理过期奖励
|
||||||
* 定时任务调用,将已过期的 PENDING 奖励标记为 EXPIRED
|
* 定时任务调用,将已过期的 PENDING 奖励标记为 EXPIRED
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ export class WalletAccount {
|
||||||
private _hashpower: Hashpower;
|
private _hashpower: Hashpower;
|
||||||
private _rewards: WalletRewards;
|
private _rewards: WalletRewards;
|
||||||
private _status: WalletStatus;
|
private _status: WalletStatus;
|
||||||
|
private _hasPlanted: boolean; // 是否已认种过
|
||||||
private readonly _createdAt: Date;
|
private readonly _createdAt: Date;
|
||||||
private _updatedAt: Date;
|
private _updatedAt: Date;
|
||||||
private _domainEvents: DomainEvent[] = [];
|
private _domainEvents: DomainEvent[] = [];
|
||||||
|
|
@ -51,6 +52,7 @@ export class WalletAccount {
|
||||||
hashpower: Hashpower,
|
hashpower: Hashpower,
|
||||||
rewards: WalletRewards,
|
rewards: WalletRewards,
|
||||||
status: WalletStatus,
|
status: WalletStatus,
|
||||||
|
hasPlanted: boolean,
|
||||||
createdAt: Date,
|
createdAt: Date,
|
||||||
updatedAt: Date,
|
updatedAt: Date,
|
||||||
) {
|
) {
|
||||||
|
|
@ -61,6 +63,7 @@ export class WalletAccount {
|
||||||
this._hashpower = hashpower;
|
this._hashpower = hashpower;
|
||||||
this._rewards = rewards;
|
this._rewards = rewards;
|
||||||
this._status = status;
|
this._status = status;
|
||||||
|
this._hasPlanted = hasPlanted;
|
||||||
this._createdAt = createdAt;
|
this._createdAt = createdAt;
|
||||||
this._updatedAt = updatedAt;
|
this._updatedAt = updatedAt;
|
||||||
}
|
}
|
||||||
|
|
@ -75,6 +78,7 @@ export class WalletAccount {
|
||||||
get status(): WalletStatus { return this._status; }
|
get status(): WalletStatus { return this._status; }
|
||||||
get createdAt(): Date { return this._createdAt; }
|
get createdAt(): Date { return this._createdAt; }
|
||||||
get updatedAt(): Date { return this._updatedAt; }
|
get updatedAt(): Date { return this._updatedAt; }
|
||||||
|
get hasPlanted(): boolean { return this._hasPlanted; }
|
||||||
get isActive(): boolean { return this._status === WalletStatus.ACTIVE; }
|
get isActive(): boolean { return this._status === WalletStatus.ACTIVE; }
|
||||||
get domainEvents(): DomainEvent[] { return [...this._domainEvents]; }
|
get domainEvents(): DomainEvent[] { return [...this._domainEvents]; }
|
||||||
|
|
||||||
|
|
@ -104,6 +108,7 @@ export class WalletAccount {
|
||||||
expiredTotalHashpower: Hashpower.zero(),
|
expiredTotalHashpower: Hashpower.zero(),
|
||||||
},
|
},
|
||||||
WalletStatus.ACTIVE,
|
WalletStatus.ACTIVE,
|
||||||
|
false, // hasPlanted
|
||||||
now,
|
now,
|
||||||
now,
|
now,
|
||||||
);
|
);
|
||||||
|
|
@ -134,6 +139,7 @@ export class WalletAccount {
|
||||||
expiredTotalUsdt: Decimal;
|
expiredTotalUsdt: Decimal;
|
||||||
expiredTotalHashpower: Decimal;
|
expiredTotalHashpower: Decimal;
|
||||||
status: string;
|
status: string;
|
||||||
|
hasPlanted: boolean;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}): WalletAccount {
|
}): WalletAccount {
|
||||||
|
|
@ -161,11 +167,18 @@ export class WalletAccount {
|
||||||
expiredTotalHashpower: Hashpower.create(params.expiredTotalHashpower),
|
expiredTotalHashpower: Hashpower.create(params.expiredTotalHashpower),
|
||||||
},
|
},
|
||||||
params.status as WalletStatus,
|
params.status as WalletStatus,
|
||||||
|
params.hasPlanted,
|
||||||
params.createdAt,
|
params.createdAt,
|
||||||
params.updatedAt,
|
params.updatedAt,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 标记为已认种
|
||||||
|
markAsPlanted(): void {
|
||||||
|
this._hasPlanted = true;
|
||||||
|
this._updatedAt = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
// 充值入账
|
// 充值入账
|
||||||
deposit(amount: Money, chainType: string, txHash: string): void {
|
deposit(amount: Money, chainType: string, txHash: string): void {
|
||||||
this.ensureActive();
|
this.ensureActive();
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ export class WalletAccountRepositoryImpl implements IWalletAccountRepository {
|
||||||
expiredTotalUsdt: wallet.rewards.expiredTotalUsdt.toDecimal(),
|
expiredTotalUsdt: wallet.rewards.expiredTotalUsdt.toDecimal(),
|
||||||
expiredTotalHashpower: wallet.rewards.expiredTotalHashpower.decimal,
|
expiredTotalHashpower: wallet.rewards.expiredTotalHashpower.decimal,
|
||||||
status: wallet.status,
|
status: wallet.status,
|
||||||
|
hasPlanted: wallet.hasPlanted,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (wallet.walletId.value === BigInt(0)) {
|
if (wallet.walletId.value === BigInt(0)) {
|
||||||
|
|
@ -118,6 +119,7 @@ export class WalletAccountRepositoryImpl implements IWalletAccountRepository {
|
||||||
expiredTotalUsdt: Decimal;
|
expiredTotalUsdt: Decimal;
|
||||||
expiredTotalHashpower: Decimal;
|
expiredTotalHashpower: Decimal;
|
||||||
status: string;
|
status: string;
|
||||||
|
hasPlanted: boolean;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}): WalletAccount {
|
}): WalletAccount {
|
||||||
|
|
@ -146,6 +148,7 @@ export class WalletAccountRepositoryImpl implements IWalletAccountRepository {
|
||||||
expiredTotalUsdt: new Decimal(record.expiredTotalUsdt.toString()),
|
expiredTotalUsdt: new Decimal(record.expiredTotalUsdt.toString()),
|
||||||
expiredTotalHashpower: new Decimal(record.expiredTotalHashpower.toString()),
|
expiredTotalHashpower: new Decimal(record.expiredTotalHashpower.toString()),
|
||||||
status: record.status,
|
status: record.status,
|
||||||
|
hasPlanted: record.hasPlanted,
|
||||||
createdAt: record.createdAt,
|
createdAt: record.createdAt,
|
||||||
updatedAt: record.updatedAt,
|
updatedAt: record.updatedAt,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1838,7 +1838,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
||||||
initialTarget: _authCityCompanyInitialTarget,
|
initialTarget: _authCityCompanyInitialTarget,
|
||||||
monthlyTarget: _authCityCompanyMonthlyTarget,
|
monthlyTarget: _authCityCompanyMonthlyTarget,
|
||||||
monthIndex: _authCityCompanyMonthIndex,
|
monthIndex: _authCityCompanyMonthIndex,
|
||||||
rewardDescription: '每新增认种 1 棵可获得 40 绿积分',
|
rewardDescription: '每新增认种 1 棵可获得 288 绿积分',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
// 省团队权益考核
|
// 省团队权益考核
|
||||||
|
|
@ -1852,7 +1852,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
||||||
initialTarget: _authProvinceCompanyInitialTarget,
|
initialTarget: _authProvinceCompanyInitialTarget,
|
||||||
monthlyTarget: _authProvinceCompanyMonthlyTarget,
|
monthlyTarget: _authProvinceCompanyMonthlyTarget,
|
||||||
monthIndex: _authProvinceCompanyMonthIndex,
|
monthIndex: _authProvinceCompanyMonthIndex,
|
||||||
rewardDescription: '每新增认种 1 棵可获得 20 绿积分',
|
rewardDescription: '每新增认种 1 棵可获得 144 绿积分',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
// 市区域权益考核
|
// 市区域权益考核
|
||||||
|
|
@ -1866,7 +1866,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
||||||
initialTarget: _cityCompanyInitialTarget,
|
initialTarget: _cityCompanyInitialTarget,
|
||||||
monthlyTarget: _cityCompanyMonthlyTarget,
|
monthlyTarget: _cityCompanyMonthlyTarget,
|
||||||
monthIndex: _cityCompanyMonthIndex,
|
monthIndex: _cityCompanyMonthIndex,
|
||||||
rewardDescription: '每新增认种 1 棵可获得 35 绿积分',
|
rewardDescription: '每新增认种 1 棵可获得 252 绿积分',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
// 省区域权益考核
|
// 省区域权益考核
|
||||||
|
|
@ -1880,7 +1880,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
||||||
initialTarget: _provinceCompanyInitialTarget,
|
initialTarget: _provinceCompanyInitialTarget,
|
||||||
monthlyTarget: _provinceCompanyMonthlyTarget,
|
monthlyTarget: _provinceCompanyMonthlyTarget,
|
||||||
monthIndex: _provinceCompanyMonthIndex,
|
monthIndex: _provinceCompanyMonthIndex,
|
||||||
rewardDescription: '每新增认种 1 棵可获得 15 绿积分',
|
rewardDescription: '每新增认种 1 棵可获得 108 绿积分',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
@ -3537,7 +3537,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
_communityBenefitActive
|
_communityBenefitActive
|
||||||
? '每新增认种 1 棵可获得 80 绿积分'
|
? '每新增认种 1 棵可获得 576 绿积分'
|
||||||
: '需团队认种达到 $_communityInitialTarget 棵激活',
|
: '需团队认种达到 $_communityInitialTarget 棵激活',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,11 @@ class _LedgerDetailPageState extends ConsumerState<LedgerDetailPage>
|
||||||
|
|
||||||
/// 筛选流水类型
|
/// 筛选流水类型
|
||||||
Future<void> _filterByEntryType(String? entryType, int index) async {
|
Future<void> _filterByEntryType(String? entryType, int index) async {
|
||||||
|
// 保存当前滚动位置
|
||||||
|
final scrollOffset = _filterScrollController.hasClients
|
||||||
|
? _filterScrollController.offset
|
||||||
|
: 0.0;
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedEntryType = entryType?.isEmpty == true ? null : entryType;
|
_selectedEntryType = entryType?.isEmpty == true ? null : entryType;
|
||||||
_selectedFilterIndex = index;
|
_selectedFilterIndex = index;
|
||||||
|
|
@ -137,6 +142,13 @@ class _LedgerDetailPageState extends ConsumerState<LedgerDetailPage>
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 恢复滚动位置
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
if (_filterScrollController.hasClients) {
|
||||||
|
_filterScrollController.jumpTo(scrollOffset);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final walletService = ref.read(walletServiceProvider);
|
final walletService = ref.read(walletServiceProvider);
|
||||||
final newLedger = await walletService.getLedger(
|
final newLedger = await walletService.getLedger(
|
||||||
|
|
@ -150,6 +162,13 @@ class _LedgerDetailPageState extends ConsumerState<LedgerDetailPage>
|
||||||
_ledger = newLedger;
|
_ledger = newLedger;
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 数据加载完成后再次确保滚动位置正确
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
if (_filterScrollController.hasClients) {
|
||||||
|
_filterScrollController.jumpTo(scrollOffset);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('[LedgerDetailPage] 筛选失败: $e');
|
debugPrint('[LedgerDetailPage] 筛选失败: $e');
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue