import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../widgets/page_scaffold.dart'; import '../../widgets/data_table_card.dart'; import '../../core/theme/app_theme.dart'; import '../../widgets/form_dialog.dart'; class PartnersScreen extends ConsumerStatefulWidget { const PartnersScreen({super.key}); @override ConsumerState createState() => _PartnersScreenState(); } class _PartnersScreenState extends ConsumerState { int _suppliersPage = 1; int _customersPage = 1; final _searchCtrl = TextEditingController(); final List> _suppliers = [ { 'code': 'GYS001', 'name': '贵州茅台酒股份有限公司', 'type': '白酒厂商', 'contact': '王建国', 'phone': '0851-22886688', 'address': '贵州省仁怀市茅台镇', 'balance': '-86000.00', 'status': '合作中', 'creditDays': 30, }, { 'code': 'GYS002', 'name': '四川五粮液股份有限公司', 'type': '白酒厂商', 'contact': '李明华', 'phone': '0831-12345678', 'address': '四川省宜宾市翠屏区', 'balance': '-42500.00', 'status': '合作中', 'creditDays': 30, }, { 'code': 'GYS003', 'name': '江苏洋河酒厂股份有限公司', 'type': '白酒厂商', 'contact': '张秀英', 'phone': '0527-83999999', 'address': '江苏省宿迁市宿城区', 'balance': '0.00', 'status': '合作中', 'creditDays': 45, }, { 'code': 'GYS004', 'name': '剑南春(集团)有限责任公司', 'type': '白酒厂商', 'contact': '陈志强', 'phone': '0838-88888888', 'address': '四川省德阳市绵竹市', 'balance': '-28600.00', 'status': '合作中', 'creditDays': 30, }, { 'code': 'GYS005', 'name': '泸州老窖股份有限公司', 'type': '白酒厂商', 'contact': '赵丽红', 'phone': '0830-12233456', 'address': '四川省泸州市江阳区', 'balance': '-15200.00', 'status': '合作中', 'creditDays': 30, }, { 'code': 'GYS006', 'name': '法国拉菲集团中国总代理', 'type': '葡萄酒进口商', 'contact': 'Pierre Liu', 'phone': '021-61234567', 'address': '上海市黄浦区外滩18号', 'balance': '-124800.00', 'status': '合作中', 'creditDays': 60, }, { 'code': 'GYS007', 'name': '人头马轩尼诗(中国)有限公司', 'type': '洋酒进口商', 'contact': '刘经理', 'phone': '021-54321678', 'address': '上海市浦东新区', 'balance': '-30240.00', 'status': '合作中', 'creditDays': 60, }, { 'code': 'GYS008', 'name': '山西汾酒集团有限责任公司', 'type': '白酒厂商', 'contact': '周建明', 'phone': '0357-33666888', 'address': '山西省吕梁市汾阳市', 'balance': '0.00', 'status': '暂停合作', 'creditDays': 30, }, ]; final List> _customers = [ { 'code': 'KH001', 'name': '北京国贸大酒店', 'type': '五星级酒店', 'contact': '采购部', 'phone': '010-65051234', 'address': '北京市朝阳区建国门外大街1号', 'balance': '45000.00', 'status': '合作中', }, { 'code': 'KH002', 'name': '上海外滩华尔道夫酒店', 'type': '五星级酒店', 'contact': '采购经理', 'phone': '021-63228888', 'address': '上海市黄浦区中山东一路2号', 'balance': '0.00', 'status': '合作中', }, { 'code': 'KH003', 'name': '广州白云国际会议中心', 'type': '会议中心', 'contact': '餐饮总监', 'phone': '020-86001234', 'address': '广州市白云区云城东路1号', 'balance': '28600.00', 'status': '合作中', }, { 'code': 'KH004', 'name': '深圳湾万象城购物中心', 'type': '商超零售', 'contact': '王采购', 'phone': '0755-82345678', 'address': '深圳市南山区望海路购物公园', 'balance': '12000.00', 'status': '合作中', }, ]; @override void dispose() { _searchCtrl.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return PageScaffold( title: '往来单位', tabs: const [ Tab(text: '供应商'), Tab(text: '客户'), ], tabViews: [ _buildSupplierList(), _buildCustomerList(), ], ); } Widget _buildSupplierList() { final q = _searchCtrl.text.toLowerCase(); final filtered = _suppliers.where((s) { if (q.isEmpty) return true; return (s['name'] as String).toLowerCase().contains(q) || (s['code'] as String).toLowerCase().contains(q); }).toList(); return DataTableCard( totalCount: filtered.length, page: _suppliersPage, onPageChanged: (p) => setState(() => _suppliersPage = p), toolbar: Row( children: [ ElevatedButton.icon( onPressed: () => _showAddPartnerDialog(context, isSupplier: true), icon: const Icon(Icons.add, size: 16), label: const Text('新增供应商'), ), const SizedBox(width: 8), OutlinedButton.icon( onPressed: () {}, icon: const Icon(Icons.file_download_outlined, size: 16), label: const Text('导出'), ), const Spacer(), SizedBox( width: 200, child: TextField( controller: _searchCtrl, decoration: const InputDecoration( hintText: '搜索供应商名称/编码', prefixIcon: Icon(Icons.search, size: 16), hintStyle: TextStyle(fontSize: 13), ), onChanged: (_) => setState(() {}), ), ), ], ), columns: const [ DataColumn(label: Text('供应商编码')), DataColumn(label: Text('供应商名称')), DataColumn(label: Text('类型')), DataColumn(label: Text('联系人')), DataColumn(label: Text('联系电话')), DataColumn(label: Text('账期(天)'), numeric: true), DataColumn(label: Text('应付余额'), numeric: true), DataColumn(label: Text('状态')), DataColumn(label: Text('操作')), ], rows: filtered .map((s) => DataRow(cells: [ DataCell(Text(s['code'] as String, style: const TextStyle( fontFamily: 'monospace', fontSize: 12, color: AppTheme.textSecondary))), DataCell(SizedBox( width: 180, child: Text(s['name'] as String, overflow: TextOverflow.ellipsis, style: const TextStyle(fontWeight: FontWeight.w500)), )), DataCell(Text(s['type'] as String)), DataCell(Text(s['contact'] as String)), DataCell(Text(s['phone'] as String)), DataCell(Text('${s['creditDays']}')), DataCell(Text( '¥${s['balance']}', style: TextStyle( color: (s['balance'] as String).startsWith('-') ? AppTheme.danger : AppTheme.textPrimary, fontWeight: FontWeight.w500, ), )), DataCell(_StatusChip(s['status'] as String)), DataCell(Row( mainAxisSize: MainAxisSize.min, children: [ TextButton( onPressed: () {}, child: const Text('查看', style: TextStyle(fontSize: 12))), TextButton( onPressed: () {}, child: const Text('编辑', style: TextStyle(fontSize: 12))), TextButton( onPressed: () {}, child: const Text('对账', style: TextStyle(fontSize: 12))), ], )), ])) .toList(), ); } Widget _buildCustomerList() { return DataTableCard( totalCount: _customers.length, page: _customersPage, onPageChanged: (p) => setState(() => _customersPage = p), toolbar: Row( children: [ ElevatedButton.icon( onPressed: () => _showAddPartnerDialog(context, isSupplier: false), icon: const Icon(Icons.add, size: 16), label: const Text('新增客户'), ), const SizedBox(width: 8), OutlinedButton.icon( onPressed: () {}, icon: const Icon(Icons.file_download_outlined, size: 16), label: const Text('导出'), ), const Spacer(), SizedBox( width: 200, child: TextField( decoration: const InputDecoration( hintText: '搜索客户名称/编码', prefixIcon: Icon(Icons.search, size: 16), hintStyle: TextStyle(fontSize: 13), ), ), ), ], ), columns: const [ DataColumn(label: Text('客户编码')), DataColumn(label: Text('客户名称')), DataColumn(label: Text('类型')), DataColumn(label: Text('联系人')), DataColumn(label: Text('联系电话')), DataColumn(label: Text('应收余额'), numeric: true), DataColumn(label: Text('状态')), DataColumn(label: Text('操作')), ], rows: _customers .map((c) => DataRow(cells: [ DataCell(Text(c['code'] as String, style: const TextStyle( fontFamily: 'monospace', fontSize: 12, color: AppTheme.textSecondary))), DataCell(SizedBox( width: 180, child: Text(c['name'] as String, overflow: TextOverflow.ellipsis, style: const TextStyle(fontWeight: FontWeight.w500)), )), DataCell(Text(c['type'] as String)), DataCell(Text(c['contact'] as String)), DataCell(Text(c['phone'] as String)), DataCell(Text( '¥${c['balance']}', style: const TextStyle(fontWeight: FontWeight.w500), )), DataCell(_StatusChip(c['status'] as String)), DataCell(Row( mainAxisSize: MainAxisSize.min, children: [ TextButton( onPressed: () {}, child: const Text('查看', style: TextStyle(fontSize: 12))), TextButton( onPressed: () {}, child: const Text('编辑', style: TextStyle(fontSize: 12))), ], )), ])) .toList(), ); } void _showAddPartnerDialog(BuildContext context, {required bool isSupplier}) { final nameCtrl = TextEditingController(); final contactCtrl = TextEditingController(); final phoneCtrl = TextEditingController(); final addressCtrl = TextEditingController(); showDialog( context: context, builder: (ctx) => FormDialog( title: isSupplier ? '新增供应商' : '新增客户', width: 520, onConfirm: () { Navigator.of(ctx).pop(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(isSupplier ? '供应商添加成功' : '客户添加成功'), backgroundColor: AppTheme.success, ), ); }, content: Column( children: [ _DialogField( label: isSupplier ? '供应商名称' : '客户名称', required: true, child: TextFormField( controller: nameCtrl, decoration: InputDecoration( hintText: isSupplier ? '请输入供应商全称' : '请输入客户名称', ), ), ), const SizedBox(height: 12), Row( children: [ Expanded( child: _DialogField( label: '联系人', child: TextFormField( controller: contactCtrl, decoration: const InputDecoration(hintText: '联系人姓名'), ), ), ), const SizedBox(width: 12), Expanded( child: _DialogField( label: '联系电话', child: TextFormField( controller: phoneCtrl, decoration: const InputDecoration(hintText: '手机/座机'), ), ), ), ], ), const SizedBox(height: 12), _DialogField( label: '地址', child: TextFormField( controller: addressCtrl, decoration: const InputDecoration(hintText: '详细地址'), ), ), if (isSupplier) ...[ const SizedBox(height: 12), Row( children: [ Expanded( child: _DialogField( label: '账期(天)', child: TextFormField( initialValue: '30', keyboardType: TextInputType.number, decoration: const InputDecoration(hintText: '结款账期'), ), ), ), const SizedBox(width: 12), Expanded( child: _DialogField( label: '供应商类型', child: DropdownButtonFormField( value: '白酒厂商', items: ['白酒厂商', '葡萄酒进口商', '洋酒进口商', '啤酒厂商', '其他'] .map((s) => DropdownMenuItem( value: s, child: Text(s, style: const TextStyle(fontSize: 13)))) .toList(), onChanged: (_) {}, decoration: const InputDecoration(), ), ), ), ], ), ], ], ), ), ); } } class _DialogField extends StatelessWidget { final String label; final Widget child; final bool required; const _DialogField({ required this.label, required this.child, this.required = false, }); @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ if (required) const Text('* ', style: TextStyle(color: AppTheme.danger, fontSize: 13)), Text(label, style: const TextStyle( fontSize: 13, color: AppTheme.textSecondary)), ], ), const SizedBox(height: 6), child, ], ); } } class _StatusChip extends StatelessWidget { final String status; const _StatusChip(this.status); @override Widget build(BuildContext context) { final bool isActive = status == '合作中'; return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), decoration: BoxDecoration( color: isActive ? const Color(0xFFE8F5E9) : const Color(0xFFF5F5F5), borderRadius: BorderRadius.circular(3), ), child: Text( status, style: TextStyle( color: isActive ? AppTheme.success : AppTheme.textSecondary, fontSize: 12, fontWeight: FontWeight.w500, ), ), ); } }