feat(client): 财务筛选增加往来单位并统一自定义时间组件(两端,原型同步)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-07-14 10:09:22 +08:00
parent 782cf057a3
commit a2aca2e7fc
10 changed files with 314 additions and 35 deletions
@@ -22,6 +22,7 @@ class FinanceListNotifier extends AsyncNotifier<PageResult<FinanceRecord>> {
String _month = '';
String _startDate = '';
String _endDate = '';
int? _partnerId;
@override
Future<PageResult<FinanceRecord>> build() {
@@ -35,6 +36,7 @@ class FinanceListNotifier extends AsyncNotifier<PageResult<FinanceRecord>> {
month: _month.isEmpty ? null : _month,
startDate: _startDate.isEmpty ? null : _startDate,
endDate: _endDate.isEmpty ? null : _endDate,
partnerId: _partnerId,
page: _page,
pageSize: _pageSize,
);
@@ -46,6 +48,13 @@ class FinanceListNotifier extends AsyncNotifier<PageResult<FinanceRecord>> {
reload();
}
/// 往来单位筛选(工具栏 ComboSearchField / 移动端 chip→sheet 共用)。
void setPartner(int? partnerId) {
_partnerId = partnerId;
_page = 1;
reload();
}
void setMonth(String month) {
_month = month;
_startDate = '';
+225 -29
View File
@@ -15,18 +15,24 @@ import '../../core/theme/context_tokens.dart';
import '../../core/utils/clock.dart';
import '../../core/utils/export_util.dart';
import '../../models/finance.dart';
import '../../models/partner.dart';
import '../../providers/finance_provider.dart';
import '../../providers/partner_provider.dart' show allPartnersProvider;
import '../../providers/stock_in_provider.dart';
import '../../providers/stock_out_provider.dart';
import '../../widgets/combo_search_field.dart';
import '../../widgets/searchable_option_field.dart' show OptionItem;
import '../../widgets/ds/ds_atoms.dart';
import '../../widgets/ds/ds_bar_chart.dart';
import '../../widgets/ds/ds_kpi.dart';
import '../../widgets/ds/ds_table.dart';
import '../../widgets/ds/m_kpi_grid.dart';
import '../../widgets/ds/m_sheet.dart';
import '../../widgets/ds/status_icon_map.dart';
import '../../widgets/finance_entry_dialog.dart';
import '../../widgets/finance_partner_drawer.dart';
import '../../widgets/mobile_list_card.dart';
import '../../widgets/wheel_date_picker.dart' show showDateRangeDropdown;
import '../../widgets/write_guard.dart';
import '../../core/theme/app_fonts.dart';
import '../../widgets/ds/ds_toast.dart';
@@ -44,6 +50,10 @@ class _FinanceScreenState extends ConsumerState<FinanceScreen> {
String _rangeLabel = '本月';
// 流水类型筛选(原型 3 chips 扩到 5)
String _flowChip = '全部';
// 往来单位筛选(桌面 toolbar ComboSearchField / 移动端时间行尾 chip→sheet 共用)
int? _partnerId;
// 自定义时间区间(记住上次选择,重开 showDateRangeDropdown 时回显)
DateTimeRange? _customRange;
// 窄屏三分段(原型 m-finance .seg:应收 / 应付 / 流水)
int _mSeg = 0;
@@ -63,11 +73,14 @@ class _FinanceScreenState extends ConsumerState<FinanceScreen> {
super.initState();
// 默认本月(与 KPI 口径一致)
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) _applyRange('本月');
if (mounted) _applyRange('本月', context);
});
}
Future<void> _applyRange(String range) async {
/// [anchorContext] 用于「自定义」分支锚定 showDateRangeDropdown(照 stock_in
/// _dateMenu 写法:传入触发该 chip 的 Builder context,桌面下拉/窄屏 sheet 由
/// 组件内部自适应);本月/本季分支不弹层,传外层 context 即可。
Future<void> _applyRange(String range, BuildContext anchorContext) async {
final now = appNow();
final notifier = ref.read(financeListProvider.notifier);
switch (range) {
@@ -87,23 +100,27 @@ class _FinanceScreenState extends ConsumerState<FinanceScreen> {
_rangeLabel = '本季';
});
case '自定义':
final picked = await showDateRangePicker(
context: context,
firstDate: DateTime(now.year - 3),
lastDate: now,
initialDateRange:
final picked = await showDateRangeDropdown(
anchorContext,
initial: _customRange ??
DateTimeRange(start: DateTime(now.year, now.month, 1), end: now),
);
if (picked == null) return;
notifier.setRange(_ymd.format(picked.start), _ymd.format(picked.end));
setState(() {
_range = range;
_customRange = picked;
_rangeLabel =
'${_ymd.format(picked.start)} ~ ${_ymd.format(picked.end)}';
});
}
}
void _setPartner(int? partnerId) {
setState(() => _partnerId = partnerId);
ref.read(financeListProvider.notifier).setPartner(partnerId);
}
void _reload() {
ref.read(financeListProvider.notifier).reload();
ref.invalidate(financePartnerRowsProvider);
@@ -267,33 +284,93 @@ class _FinanceScreenState extends ConsumerState<FinanceScreen> {
// ── 时间范围 chips(原型 .timerow)──
Widget _timeRow(dynamic t, bool mobile) {
// 移动端时间行尾追加「往来单位」chip(D6:showMSheet 可搜单选,× 清除);
// 桌面往来单位筛选走 _flowTable toolbar 的 ComboSearchField(不在此行)。
final partnerName = mobile
? _partnerNameById(
ref.watch(allPartnersProvider).valueOrNull?.data ?? const [],
_partnerId)
: null;
final children = <Widget>[
Text('时间范围', style: TextStyle(fontSize: AppDims.fsSm, color: t.muted)),
const SizedBox(width: 12),
for (final r in const ['本月', '本季']) ...[
DsChip(
label: r,
selected: _range == r,
caret: false,
onTap: () => _applyRange(r, context)),
const SizedBox(width: 10),
],
Builder(
// anchorCtx = chip 自身位置:自定义范围下拉/sheet 锚定在 chip 下方
// (照 stock_in_list_screen.dart _dateMenu 写法)
builder: (anchorCtx) => DsChip(
label: '自定义',
selected: _range == '自定义',
onTap: () => _applyRange('自定义', anchorCtx)),
),
if (mobile) ...[
const SizedBox(width: 10),
DsChip(
label: '往来单位',
value: partnerName,
onTap: _openPartnerSheet,
onClear: () => _setPartner(null)),
],
];
if (mobile) {
children.addAll([
const SizedBox(width: 10),
WriteGuard(
child: DsButton('登记',
small: true,
icon: LucideIcons.plus,
variant: DsBtnVariant.primary,
onPressed: () => showFinanceEntryDialog(context)),
),
]);
// 窄屏内容(label+4 chip+登记)常超宽:整行横向可滚(照 _flowTable 移动
// 工具栏 chips 横向可滚同款写法),而非把登记钉死右侧裁掉往来单位 chip。
return Padding(
padding: const EdgeInsets.only(bottom: 18),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal, child: Row(children: children)),
);
}
return Padding(
padding: const EdgeInsets.only(bottom: 18),
child: Row(children: [
Text('时间范围', style: TextStyle(fontSize: AppDims.fsSm, color: t.muted)),
const SizedBox(width: 12),
for (final r in const ['本月', '本季', '自定义']) ...[
DsChip(
label: r,
selected: _range == r,
caret: r == '自定义',
onTap: () => _applyRange(r)),
const SizedBox(width: 10),
],
if (mobile) ...[
const Spacer(),
WriteGuard(
child: DsButton('登记',
small: true,
icon: LucideIcons.plus,
variant: DsBtnVariant.primary,
onPressed: () => showFinanceEntryDialog(context)),
),
],
]),
child: Row(children: children),
);
}
String? _partnerNameById(List<Partner> partners, int? id) {
if (id == null) return null;
for (final p in partners) {
if (p.id == id) return p.name;
}
return null;
}
/// 移动端「往来单位」chip → 底部 sheet 可搜索单选(D6,对齐桌面 ComboSearchField)。
Future<void> _openPartnerSheet() async {
final partners = ref.read(allPartnersProvider).valueOrNull?.data ?? const [];
final options = [
for (final p in partners) OptionItem(id: p.id, name: p.name, code: p.code),
];
final sel = await showMSheet<int?>(
context,
title: '往来单位',
builder: (_) => _PartnerSheetBody(options: options, selectedId: _partnerId),
);
if (sel == null || !mounted) return;
// -1 = 清除选择(照 SearchableOptionField 的既有约定)
_setPartner(sel == -1 ? null : sel);
}
// ── KPI 4 卡 ──
Widget _kpis(dynamic t, bool mobile) {
final outSum = ref.watch(stockOutSummaryProvider).valueOrNull;
@@ -547,6 +624,20 @@ class _FinanceScreenState extends ConsumerState<FinanceScreen> {
style: TextStyle(fontSize: AppDims.fsSm, color: t.muted)),
const SizedBox(width: 12),
...chips,
const SizedBox(width: 10),
// 往来单位:可搜索单选下拉(→ financeListProvider.setPartner;照
// stock_out_list_screen.dart 客户 ComboSearchField 写法)。仅桌面
// 工具栏放置,移动端对应筛选在 _timeRow 尾部的「往来单位」chip → sheet。
ComboSearchField(
options: (ref.watch(allPartnersProvider).valueOrNull?.data ??
const [])
.map((p) => OptionItem(id: p.id, name: p.name, code: p.code))
.toList(),
selectedId: _partnerId,
hint: '往来单位',
width: 180,
onChanged: _setPartner,
),
const Spacer(),
Text('$total',
style: TextStyle(
@@ -869,3 +960,108 @@ class _FinanceScreenState extends ConsumerState<FinanceScreen> {
);
}
}
/// 移动端「往来单位」sheet 内容:搜索框 + 全部/逐项列表 + 选中勾(照
/// combo_search_field.dart _ComboPop 的搜索+勾选样式,装进 showMSheet 底部
/// 容器而非锚定弹层)。选中返回 id;点「全部往来单位」返回 -1(清除,约定
/// 同 SearchableOptionField)。
class _PartnerSheetBody extends StatefulWidget {
final List<OptionItem> options;
final int? selectedId;
const _PartnerSheetBody({required this.options, required this.selectedId});
@override
State<_PartnerSheetBody> createState() => _PartnerSheetBodyState();
}
class _PartnerSheetBodyState extends State<_PartnerSheetBody> {
String _kw = '';
@override
Widget build(BuildContext context) {
final t = context.tokens;
final hits = _kw.trim().isEmpty
? widget.options
: widget.options.where((o) => o.matches(_kw)).toList();
Widget optRow({
required String name,
required bool selected,
required VoidCallback onTap,
}) =>
InkWell(
onTap: onTap,
child: Container(
padding: const EdgeInsets.symmetric(vertical: 13, horizontal: 4),
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: t.borderSubtle)),
),
child: Row(children: [
Expanded(
child: Text(name,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: AppDims.fsBody,
fontWeight:
selected ? FontWeight.w600 : FontWeight.w400,
color: selected ? t.primary : t.text)),
),
if (selected) ...[
const SizedBox(width: 8),
Icon(LucideIcons.check, size: 18, color: t.primary),
],
]),
),
);
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 11, vertical: 9),
decoration: BoxDecoration(
color: t.bg,
borderRadius: BorderRadius.circular(AppDims.rMd),
),
child: Row(children: [
Icon(LucideIcons.search, size: 15, color: t.faint),
const SizedBox(width: 8),
Expanded(
child: TextField(
style: TextStyle(fontSize: AppDims.fsBody, color: t.text),
decoration: InputDecoration(
isCollapsed: true,
contentPadding: EdgeInsets.zero,
border: InputBorder.none,
hintText: '搜索往来单位…',
hintStyle:
TextStyle(fontSize: AppDims.fsBody, color: t.faint),
),
onChanged: (v) => setState(() => _kw = v),
),
),
]),
),
const SizedBox(height: 6),
optRow(
name: '全部往来单位',
selected: widget.selectedId == null,
onTap: () => Navigator.of(context).pop(-1),
),
if (hits.isEmpty)
Padding(
padding: const EdgeInsets.all(20),
child: Text('无匹配结果',
style: TextStyle(color: t.muted, fontSize: AppDims.fsSm)),
)
else
for (final o in hits)
optRow(
name: o.name,
selected: o.id == widget.selectedId,
onTap: () => Navigator.of(context).pop(o.id),
),
],
);
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 102 KiB

+20 -3
View File
@@ -83,7 +83,7 @@
<span class="lbl">时间范围</span>
<div class="chip on" data-range="本月" onclick="setRange('本月')">本月</div>
<div class="chip" data-range="本季" onclick="setRange('本季')">本季</div>
<div class="chip" data-range="自定义" onclick="setRange('自定义')">自定义 <svg viewBox="0 0 24 24"><use href="#i-ic16"/></svg></div>
<div class="chip" data-range="自定义" onclick="openCustomRange(this)">自定义 <svg viewBox="0 0 24 24"><use href="#i-ic16"/></svg></div>
</div>
<!-- 2. KPI 条 -->
@@ -123,6 +123,7 @@
<div class="chip on" data-flt="全部" onclick="setFlowFilter('全部')">全部</div>
<div class="chip" data-flt="收款" onclick="setFlowFilter('收款')">收款</div>
<div class="chip" data-flt="付款" onclick="setFlowFilter('付款')">付款</div>
<div class="chip" id="chipParty" onclick="openPartyFilter(this)">往来单位 <span class="cv" id="partyVal"></span><svg viewBox="0 0 24 24"><use href="#i-chevron-down"/></svg></div>
<div class="sp"></div>
<span class="ref" id="flowCount"></span>
</div>
@@ -141,7 +142,16 @@
<script src="shell.js"></script>
<script>
/* ---- 1. 时间范围 ---- */
function setRange(r){ document.querySelectorAll('.chip[data-range]').forEach(c=>c.classList.toggle('on',c.dataset.range===r)); document.getElementById('finSub').textContent='应收/应付概览 · '+r; if(r==='自定义')toast('自定义区间选择器(原型略)'); }
function setRange(r){ document.querySelectorAll('.chip[data-range]').forEach(c=>c.classList.toggle('on',c.dataset.range===r)); document.getElementById('finSub').textContent='应收/应付概览 · '+r; }
// 自定义区间:起止并排双滚轮锚定 chip 下方(datewheel.js openRange,对齐真实端 showDateRangeDropdown
let customFrom='', customTo='';
function openCustomRange(t){
DateWheel.openRange(t,{from:customFrom,to:customTo,onCommit:(f,to)=>{
customFrom=f; customTo=to;
document.querySelectorAll('.chip[data-range]').forEach(c=>c.classList.toggle('on',c.dataset.range==='自定义'));
document.getElementById('finSub').textContent='应收/应付概览 · '+f+' ~ '+to;
}});
}
/* ---- 3. 趋势图数据(万元) ---- */
const TREND=[
@@ -200,9 +210,13 @@ const FLOWS=[
{date:'2026-06-11',type:'收款',party:'华东酒类批发',amt:55200,ref:'SK-20260611-06',note:'梦之蓝M6'}
];
let flowFilter='全部';
let flowParty='全部';
const PARTIES=['全部',...Array.from(new Set(FLOWS.map(f=>f.party)))];
function setFlowFilter(f){ flowFilter=f; document.querySelectorAll('.chip[data-flt]').forEach(c=>c.classList.toggle('on',c.dataset.flt===f)); renderFlows(); }
// 往来单位:可搜索单选下拉(chip + openSearchMenu,照 stock-out-list.html 客户筛选写法)
function openPartyFilter(t){ openSearchMenu(t,PARTIES.map(v=>({v,label:v,sel:v===flowParty})),v=>{ flowParty=v; closeMenus(); renderFlows(); },{placeholder:'搜索往来单位…'}); }
function renderFlows(){
const rows=FLOWS.filter(f=>flowFilter==='全部'||f.type===flowFilter);
const rows=FLOWS.filter(f=>(flowFilter==='全部'||f.type===flowFilter)&&(flowParty==='全部'||f.party===flowParty));
const tb=document.getElementById('flowBody');
if(rows.length===0){ tb.innerHTML=`<tr><td colspan="6"><div class="empty">没有匹配的流水记录</div></td></tr>`; }
else { tb.innerHTML=rows.map(f=>`<tr>
@@ -215,6 +229,8 @@ function renderFlows(){
</tr>`).join(''); }
document.getElementById('flowCount').textContent=`${rows.length}`;
document.getElementById('flowSub').textContent=`本月 ${FLOWS.length} 笔 · 收 ${FLOWS.filter(f=>f.type==='收款').length} / 付 ${FLOWS.filter(f=>f.type==='付款').length}`;
document.getElementById('partyVal').textContent=flowParty==='全部'?'':flowParty;
document.getElementById('chipParty').classList.toggle('on',flowParty!=='全部');
}
/* ---- 抽屉:某往来单位流水 ---- */
@@ -246,6 +262,7 @@ document.addEventListener('keydown',e=>{ if(e.key==='Escape'){closeMenus();close
buildChart(); buildSummary(); renderFlows();
</script>
<a class="ds-fab" href="../index.html" title="返回设计系统" aria-label="返回设计系统"><svg viewBox="0 0 24 24"><use href="#i-arrow-left"/></svg></a>
<script src="datewheel.js"></script>
<script src="fab.js"></script>
<script src="notify.js"></script>
<script src="statusbar.js"></script>
+60 -3
View File
@@ -7,12 +7,30 @@
<link rel="stylesheet" href="../tokens.css">
<link rel="stylesheet" href="../atoms.css">
<link rel="stylesheet" href="../mobile-atoms.css">
<style>body{margin:0; font-family:var(--font); color:var(--text); background:var(--page); -webkit-font-smoothing:antialiased;}</style>
<style>
body{margin:0; font-family:var(--font); color:var(--text); background:var(--page); -webkit-font-smoothing:antialiased;}
/* 时间范围筛选行(回填真实端已有形态,照桌面 finance.html .timerow):
label+4 chip+登记 常超宽 → 整行横向可滚(照 m-stock-out-list.html 工具栏
chips 横向可滚同款写法),不把登记钉死右侧裁掉往来单位 chip */
.timerow{display:flex; align-items:center; gap:10px; margin:2px 0 14px; overflow-x:auto;}
.timerow::-webkit-scrollbar{display:none;}
.timerow .lbl{font-size:var(--fs-sm); color:var(--muted); margin-right:2px; flex:none; white-space:nowrap;}
.timerow > *{flex:none;}
</style>
</head>
<body>
<div class="m-top" data-m-top data-title="财务管理"></div>
<div class="m-page has-tabs">
<div class="m-scroll">
<!-- 时间范围(真实端 FinanceScreen._timeRow 移动分支:存量漂移回填) -->
<div class="timerow">
<span class="lbl">时间范围</span>
<div class="chip on" data-range="本月" onclick="setRange('本月')">本月</div>
<div class="chip" data-range="本季" onclick="setRange('本季')">本季</div>
<div class="chip" data-range="自定义" onclick="openCustomRange()">自定义 <svg viewBox="0 0 24 24"><use href="#i-ic16"/></svg></div>
<div class="chip" id="chipParty" onclick="openPartnerSheet()">往来单位 <span class="cv" id="partyVal"></span><svg viewBox="0 0 24 24"><use href="#i-chevron-down"/></svg></div>
<div class="btn primary sm" onclick="mToast('登记收支(原型)')"><svg viewBox="0 0 24 24"><use href="#i-plus"/></svg>登记</div>
</div>
<div class="m-kpi">
<div class="k"><div class="kl">本月收入</div><div class="kv">¥86.4万</div><div class="kd up">▲ 8.2% 较上月</div></div>
<div class="k"><div class="kl">本月支出</div><div class="kv">¥52.1万</div><div class="kd down">▲ 3.1% 较上月</div></div>
@@ -29,6 +47,7 @@
<script src="icons.js"></script>
<script src="mobile-shell.js"></script>
<script src="datewheel.js"></script>
<script>
const AR=[
{party:'城东烟酒行',amt:'¥86,200',status:'未结清',date:'账期 06-30'},
@@ -47,13 +66,51 @@ const FLOW=[
let tab='ar';
const FTABS=['ar','ap','flow'];
function setTab(t){ tab=t; const idx=FTABS.indexOf(t); document.querySelectorAll('.seg button').forEach((b,i)=>b.classList.toggle('on',i===idx)); render(); }
/* ---- 时间范围(照桌面 finance.html:仅改文案,不真实过滤 AR/AP/FLOW 展示数据) ---- */
function setRange(r){ document.querySelectorAll('.chip[data-range]').forEach(c=>c.classList.toggle('on',c.dataset.range===r)); }
// 自定义范围:窄屏走底部 sheet 纵排双滚轮(datewheel.js mountRange,对齐真实端
// showDateRangeDropdown 在 isMobile 下走 showMSheet,照 m-stock-in-list.html openAdvDateSheet 写法)
let customFrom='', customTo='';
function openCustomRange(){
openSheet('日期区间','<div id="rangeMount"></div>');
DateWheel.mountRange(document.getElementById('rangeMount'),{from:customFrom,to:customTo,onCommit:(f,to)=>{
customFrom=f; customTo=to;
document.querySelectorAll('.chip[data-range]').forEach(c=>c.classList.toggle('on',c.dataset.range==='自定义'));
closeSheet();
}});
}
/* ---- 往来单位(D6chip → 底部 sheet 可搜索单选,× 清除;仅过滤「流水」分段) ---- */
let flowParty='全部';
const PARTNERS=['全部',...Array.from(new Set([...AR,...AP,...FLOW].map(r=>r.party.split(' · ')[0])))];
function openPartnerSheet(){
openSheet('往来单位',
'<div class="m-search" style="margin-bottom:8px"><svg viewBox="0 0 24 24"><use href="#i-search"/></svg>'
+'<input id="partnerKw" placeholder="搜索往来单位…" oninput="drawPartnerOpts(this.value)"></div>'
+'<div id="partnerOptList"></div>');
drawPartnerOpts('');
}
function drawPartnerOpts(kw){
const q=(kw||'').trim().toLowerCase();
const hits=PARTNERS.filter(v=>v==='全部'||!q||v.toLowerCase().includes(q));
document.getElementById('partnerOptList').innerHTML=hits.length
? hits.map(v=>`<div class="m-opt ${v===flowParty?'sel':''}" onclick="setFlowParty('${v}')">${v}<svg class="ck" viewBox="0 0 24 24"><use href="#i-check"/></svg></div>`).join('')
: '<div style="padding:20px 4px;text-align:center;color:var(--muted);font-size:var(--fs-sm)">无匹配结果</div>';
}
function setFlowParty(v){ flowParty=v; closeSheet(); render(); }
function render(){
const cfg={ar:['应收账款',AR],ap:['应付账款',AP],flow:['资金流水',FLOW]}[tab];
document.getElementById('cnt').textContent=`${cfg[0]} · 共 ${cfg[1].length}`;
document.getElementById('list').innerHTML=cfg[1].map(r=>`<div class="m-card"><div class="m-row">
// 往来单位筛选仅作用于「流水」分段(对应真实端 financeListProvider.setPartner 只过滤流水表)
const rows=tab==='flow'?cfg[1].filter(r=>flowParty==='全部'||r.party.split(' · ')[0]===flowParty):cfg[1];
document.getElementById('cnt').textContent=`${cfg[0]} · 共 ${rows.length}`;
document.getElementById('list').innerHTML=rows.map(r=>`<div class="m-card"><div class="m-row">
<div class="mc-main"><div class="mc-nm">${r.party}</div><div class="mc-sub">${r.date}</div></div>
<div class="mc-right"><span class="badge b-${r.status}">${r.status}</span><span class="mc-amt">${r.amt}</span></div>
</div></div>`).join('');
document.getElementById('partyVal').textContent=flowParty==='全部'?'':flowParty;
document.getElementById('chipParty').classList.toggle('on',flowParty!=='全部');
}
render();
</script>