This commit is contained in:
sion
2026-03-25 00:47:37 +08:00
parent 2f612fd899
commit c02eca2999
6 changed files with 74 additions and 75 deletions

View File

@@ -62,13 +62,11 @@ class MyApp extends StatelessWidget {
providers: _buildProviders(), providers: _buildProviders(),
child: Consumer<ThemeProvider>( child: Consumer<ThemeProvider>(
builder: (context, themeProvider, _) { builder: (context, themeProvider, _) {
return AuthNavigator( return ShadApp.custom(
child: ShadApp.custom( themeMode: themeProvider.themeMode,
themeMode: themeProvider.themeMode, theme: createLightShadTheme(),
theme: createLightShadTheme(), darkTheme: createDarkShadTheme(),
darkTheme: createDarkShadTheme(), appBuilder: _buildMaterialApp,
appBuilder: _buildMaterialApp,
),
); );
}, },
), ),
@@ -134,55 +132,3 @@ class MyApp extends StatelessWidget {
); );
} }
} }
/// 认证路由守卫 - 监听认证状态并自动导航
class AuthNavigator extends StatefulWidget {
final Widget child;
const AuthNavigator({super.key, required this.child});
@override
State<AuthNavigator> createState() => _AuthNavigatorState();
}
class _AuthNavigatorState extends State<AuthNavigator> {
bool? _wasLoggedIn;
@override
void didChangeDependencies() {
super.didChangeDependencies();
final isLoggedIn = context.watch<AuthProvider>().isLoggedIn;
if (_wasLoggedIn == null) {
_wasLoggedIn = isLoggedIn;
return;
}
if (_wasLoggedIn != isLoggedIn) {
_wasLoggedIn = isLoggedIn;
_navigateToAuthPage(isLoggedIn);
}
}
void _navigateToAuthPage(bool isLoggedIn) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;
// 退出登录时重置其他 Provider 的状态
if (!isLoggedIn) {
context.read<AssetProvider>().resetLoadState();
context.read<MarketProvider>().resetLoadState();
}
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (_) => isLoggedIn ? const MainPage() : const LoginPage(),
),
(route) => false,
);
});
}
@override
Widget build(BuildContext context) => widget.child;
}

View File

@@ -389,7 +389,7 @@ class _AssetCard extends StatelessWidget {
} }
} }
/// 代币列表 /// 资产列表
class _TokenList extends StatelessWidget { class _TokenList extends StatelessWidget {
final List holdings; final List holdings;
@@ -399,11 +399,22 @@ class _TokenList extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme; final colorScheme = Theme.of(context).colorScheme;
// 对持仓进行排序USDT 放在最上面
final sortedHoldings = List.from(holdings);
sortedHoldings.sort((a, b) {
final codeA = (a.coinCode ?? a['coinCode'] ?? '').toString().toUpperCase();
final codeB = (b.coinCode ?? b['coinCode'] ?? '').toString().toUpperCase();
// USDT 排在最前面
if (codeA == 'USDT') return -1;
if (codeB == 'USDT') return 1;
return 0;
});
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'代币列表', '资产列表',
style: GoogleFonts.spaceGrotesk( style: GoogleFonts.spaceGrotesk(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@@ -411,18 +422,18 @@ class _TokenList extends StatelessWidget {
), ),
), ),
SizedBox(height: AppSpacing.md), SizedBox(height: AppSpacing.md),
if (holdings.isEmpty) if (sortedHoldings.isEmpty)
_EmptyState(icon: LucideIcons.wallet, message: '暂无持仓') _EmptyState(icon: LucideIcons.wallet, message: '暂无持仓')
else else
ListView.separated( ListView.separated(
shrinkWrap: true, shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemCount: holdings.length, itemCount: sortedHoldings.length,
separatorBuilder: (_, __) => Divider( separatorBuilder: (_, __) => Divider(
height: 1, height: 1,
color: colorScheme.outlineVariant.withOpacity(0.2), color: colorScheme.outlineVariant.withOpacity(0.2),
), ),
itemBuilder: (context, index) => _TokenItem(holding: holdings[index]), itemBuilder: (context, index) => _TokenItem(holding: sortedHoldings[index]),
), ),
], ],
); );

View File

@@ -176,10 +176,8 @@ class _LoginPageState extends State<LoginPage> {
} }
void _navigateToMainPage() { void _navigateToMainPage() {
Navigator.of(context).pushAndRemoveUntil( // 不使用 Navigator,让 main.dart 中的 Consumer<AuthProvider> 自动处理页面切换
MaterialPageRoute(builder: (_) => const MainPage()), // 登录成功后auth.isLoggedIn 会变为 trueConsumer 会自动显示 MainPage
(route) => false,
);
} }
void _navigateToRegister() { void _navigateToRegister() {

View File

@@ -201,6 +201,11 @@ public class AdminController {
String code = (String) params.get("code"); String code = (String) params.get("code");
BigDecimal price = new BigDecimal(params.get("price").toString()); BigDecimal price = new BigDecimal(params.get("price").toString());
// USDT价格固定为1不允许修改
if ("USDT".equalsIgnoreCase(code)) {
return Result.fail("USDT价格固定为1不可修改");
}
Coin coin = coinService.getCoinByCode(code); Coin coin = coinService.getCoinByCode(code);
if (coin == null) { if (coin == null) {
return Result.fail("币种不存在"); return Result.fail("币种不存在");

View File

@@ -153,16 +153,35 @@ public class AssetService {
// 获取交易账户USDT持仓 // 获取交易账户USDT持仓
AccountTrade tradeUsdt = getOrCreateTradeAccount(userId, "USDT"); AccountTrade tradeUsdt = getOrCreateTradeAccount(userId, "USDT");
LocalDateTime now = LocalDateTime.now();
if (direction == 1) { if (direction == 1) {
// 资金账户 -> 交易账户 // 资金账户 -> 交易账户
if (fund.getBalance().compareTo(amount) < 0) { if (fund.getBalance().compareTo(amount) < 0) {
throw new RuntimeException("资金账户余额不足"); throw new RuntimeException("资金账户余额不足");
} }
BigDecimal fundBalanceBefore = fund.getBalance();
BigDecimal tradeBalanceBefore = tradeUsdt.getQuantity();
fund.setBalance(fund.getBalance().subtract(amount)); fund.setBalance(fund.getBalance().subtract(amount));
tradeUsdt.setQuantity(tradeUsdt.getQuantity().add(amount)); tradeUsdt.setQuantity(tradeUsdt.getQuantity().add(amount));
// 使用 LambdaUpdateWrapper 显式更新资金账户
LambdaUpdateWrapper<AccountFund> fundUpdateWrapper = new LambdaUpdateWrapper<>();
fundUpdateWrapper.eq(AccountFund::getId, fund.getId())
.set(AccountFund::getBalance, fund.getBalance())
.set(AccountFund::getUpdateTime, now);
accountFundMapper.update(null, fundUpdateWrapper);
// 使用 LambdaUpdateWrapper 显式更新交易账户
LambdaUpdateWrapper<AccountTrade> tradeUpdateWrapper = new LambdaUpdateWrapper<>();
tradeUpdateWrapper.eq(AccountTrade::getId, tradeUsdt.getId())
.set(AccountTrade::getQuantity, tradeUsdt.getQuantity())
.set(AccountTrade::getUpdateTime, now);
accountTradeMapper.update(null, tradeUpdateWrapper);
// 记录流水 // 记录流水
createFlow(userId, 4, amount.negate(), fund.getBalance().add(amount), createFlow(userId, 4, amount.negate(), fundBalanceBefore,
fund.getBalance(), "USDT", null, "划转至交易账户"); fund.getBalance(), "USDT", null, "划转至交易账户");
} else if (direction == 2) { } else if (direction == 2) {
@@ -170,22 +189,37 @@ public class AssetService {
if (tradeUsdt.getQuantity().compareTo(amount) < 0) { if (tradeUsdt.getQuantity().compareTo(amount) < 0) {
throw new RuntimeException("交易账户USDT余额不足"); throw new RuntimeException("交易账户USDT余额不足");
} }
BigDecimal fundBalanceBefore = fund.getBalance();
BigDecimal tradeBalanceBefore = tradeUsdt.getQuantity();
tradeUsdt.setQuantity(tradeUsdt.getQuantity().subtract(amount)); tradeUsdt.setQuantity(tradeUsdt.getQuantity().subtract(amount));
fund.setBalance(fund.getBalance().add(amount)); fund.setBalance(fund.getBalance().add(amount));
// 使用 LambdaUpdateWrapper 显式更新资金账户
LambdaUpdateWrapper<AccountFund> fundUpdateWrapper = new LambdaUpdateWrapper<>();
fundUpdateWrapper.eq(AccountFund::getId, fund.getId())
.set(AccountFund::getBalance, fund.getBalance())
.set(AccountFund::getUpdateTime, now);
accountFundMapper.update(null, fundUpdateWrapper);
// 使用 LambdaUpdateWrapper 显式更新交易账户
LambdaUpdateWrapper<AccountTrade> tradeUpdateWrapper = new LambdaUpdateWrapper<>();
tradeUpdateWrapper.eq(AccountTrade::getId, tradeUsdt.getId())
.set(AccountTrade::getQuantity, tradeUsdt.getQuantity())
.set(AccountTrade::getUpdateTime, now);
accountTradeMapper.update(null, tradeUpdateWrapper);
// 记录流水 // 记录流水
createFlow(userId, 3, amount, fund.getBalance().subtract(amount), createFlow(userId, 3, amount, fundBalanceBefore,
fund.getBalance(), "USDT", null, "划转至资金账户"); fund.getBalance(), "USDT", null, "划转至资金账户");
} else { } else {
throw new RuntimeException("无效的划转方向"); throw new RuntimeException("无效的划转方向");
} }
fund.setUpdateTime(LocalDateTime.now()); System.out.println("[划转成功] 用户ID=" + userId + ", 方向=" + (direction == 1 ? "资金→交易" : "交易→资金") +
accountFundMapper.updateById(fund); ", 金额=" + amount + " USDT, 资金账户余额=" + fund.getBalance() +
", 交易账户USDT=" + tradeUsdt.getQuantity());
tradeUsdt.setUpdateTime(LocalDateTime.now());
accountTradeMapper.updateById(tradeUsdt);
} }
/** /**

View File

@@ -36,8 +36,13 @@ public class CoinService extends ServiceImpl<CoinMapper, Coin> {
/** /**
* 更新币种价格 * 更新币种价格
* 注意USDT价格固定为1不允许修改
*/ */
public void updatePrice(String code, BigDecimal price) { public void updatePrice(String code, BigDecimal price) {
// USDT价格固定为1不允许修改
if ("USDT".equalsIgnoreCase(code)) {
return;
}
Coin coin = getCoinByCode(code); Coin coin = getCoinByCode(code);
if (coin != null) { if (coin != null) {
coin.setPrice(price); coin.setPrice(price);