| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- import 'package:flutter/material.dart';
- import 'package:tdesign_flutter/tdesign_flutter.dart';
- import '../../../core/i18n/app_localizations.dart';
- import '../../../core/theme/app_colors_extension.dart';
- import '../../../core/utils/amount_utils.dart';
- import '../expense_model.dart';
- /// 查看费用报销明细弹窗(只读)。
- ///
- /// 使用 [TDSlidePopupRoute] 从底部滑出,展示报销明细的所有字段。
- class ExpenseDetailViewDialog extends StatelessWidget {
- final ExpenseDetailModel detail;
- final AppLocalizations l10n;
- const ExpenseDetailViewDialog({
- super.key,
- required this.detail,
- required this.l10n,
- });
- /// 显示弹窗。
- static void show(BuildContext context, ExpenseDetailModel detail) {
- final l10n = AppLocalizations.of(context);
- FocusScope.of(context).unfocus();
- Navigator.push(
- context,
- TDSlidePopupRoute<void>(
- slideTransitionFrom: SlideTransitionFrom.bottom,
- isDismissible: true,
- builder: (_) => ExpenseDetailViewDialog(detail: detail, l10n: l10n),
- ),
- );
- }
- @override
- Widget build(BuildContext context) {
- final colors = Theme.of(context).extension<AppColorsExtension>()!;
- final d = detail;
- final catLabel = d.categoryName.isNotEmpty
- ? '${d.expenseCategory}/${d.categoryName}'
- : d.expenseCategory;
- return ConstrainedBox(
- constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.8),
- child: Container(
- decoration: BoxDecoration(
- color: colors.bgCard,
- borderRadius: const BorderRadius.vertical(top: Radius.circular(16)),
- ),
- child: SafeArea(
- top: false,
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- // 标题栏
- Padding(
- padding: const EdgeInsets.fromLTRB(20, 20, 12, 8),
- child: Row(
- children: [
- const SizedBox(width: 24),
- Expanded(child: Center(child: Text(l10n.get('expenseDetails'), style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600)))),
- GestureDetector(
- onTap: () => Navigator.pop(context),
- child: Icon(Icons.close, color: colors.textSecondary),
- ),
- ],
- ),
- ),
- // 内容
- Flexible(
- child: SingleChildScrollView(
- padding: const EdgeInsets.all(20),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- _row(l10n.get('expenseCategory'), catLabel, colors),
- _row(l10n.get('amountInclTax'), formatAmount(d.totalAmount), colors),
- if (d.approvedAmount > 0)
- _row(l10n.get('approvedAmount'), formatAmount(d.approvedAmount), colors),
- _row(l10n.get('amountExcludingTax'), formatAmount(d.amount), colors),
- if (d.taxAmount > 0)
- _row(l10n.get('taxAmount'), formatAmount(d.taxAmount), colors),
- if (d.taxRate > 0)
- _row(l10n.get('taxRate'), '${d.taxRate.toStringAsFixed(0)}%', colors),
- _row(l10n.get('acctSubject'), d.acctSubjectId.isNotEmpty ? '${d.acctSubjectId}${d.acctSubjectName.isNotEmpty ? '/${d.acctSubjectName}' : ''}' : '-', colors),
- _row(l10n.get('project'), d.projectId.isNotEmpty ? '${d.projectId}${d.projectName.isNotEmpty ? '/${d.projectName}' : ''}' : '-', colors),
- _row(l10n.get('costDept'), d.costDeptId.isNotEmpty ? '${d.costDeptId}${d.costDeptName.isNotEmpty ? '/${d.costDeptName}' : ''}' : '-', colors),
- _row(l10n.get('customerVendor'), d.customerVendorId.isNotEmpty ? '${d.customerVendorId}${d.customerVendorName.isNotEmpty ? '/${d.customerVendorName}' : ''}' : '-', colors),
- _row(l10n.get('expenseApplyNo'), d.aeNo.isNotEmpty ? d.aeNo : '-', colors),
- _row(l10n.get('applyDate'), d.aeDd.isNotEmpty ? _formatDate(d.aeDd) : '-', colors),
- _row(l10n.get('applicant'), d.sqMan.isNotEmpty ? '${d.sqMan}${d.sqManName.isNotEmpty ? '/${d.sqManName}' : ''}' : '-', colors),
- _row(l10n.get('bankName'), d.bankName.isNotEmpty ? d.bankName : '-', colors),
- _row(l10n.get('bankAccountName'), d.bankAccountName.isNotEmpty ? d.bankAccountName : '-', colors),
- _row(l10n.get('bankAccount'), d.bankAccount.isNotEmpty ? d.bankAccount : '-', colors),
- _row(l10n.get('remark'), d.remark.isNotEmpty ? d.remark : '-', colors),
- ],
- ),
- ),
- ),
- ],
- ),
- ),
- ),
- );
- }
- String _formatDate(String raw) {
- final dt = DateTime.tryParse(raw);
- if (dt == null) return raw;
- return '${dt.year}-${dt.month.toString().padLeft(2, '0')}-${dt.day.toString().padLeft(2, '0')}';
- }
- Widget _row(String label, String value, AppColorsExtension colors) {
- return Padding(
- padding: const EdgeInsets.only(bottom: 16),
- child: Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- SizedBox(
- width: 100,
- child: Text(label, style: TextStyle(fontSize: 14, color: colors.textSecondary)),
- ),
- const SizedBox(width: 12),
- Expanded(child: Text(value, style: const TextStyle(fontSize: 14))),
- ],
- ),
- );
- }
- }
|