PageSourceSearch

https://cfadata.com/assets/Cash-CLpKpbaI.js

js cfadata.com collected 2026-10-03 02:31:25 UTC 17,526 bytes, 1 lines download raw bytes

1import{u as Oe,ad as Ve,l as Be,a as qe,k as He,ae as Ue,a4 as y,s as g,ab as ze,af as Ge,g as Ke,ag as We,ac as j,j as e,ah as K,a6 as xe,W as Xe,ai as Qe,a7 as W,B as Je,aj as Ze,v as es,i as ss}from"./index-BgOx-y6Z.js";import{a as l}from"./echarts-DgtDMHXn.js";import{u as ts}from"./useEnterToSubmit-CbWc2UAa.js";import{P as ns}from"./papaparse.min-D_ATfZhF.js";import{C as ls,a as os}from"./ConsoleHeader-CPjrsrnl.js";import{C as as}from"./ConsoleStats-C3UqZ92Z.js";import{C as rs}from"./ConsoleToolbar-BbBdHQtA.js";import{I as cs}from"./IndexList-BnaYICGV.js";import{D as X}from"./DetailPane-Co2tJBoy.js";import{T as fe,C as be}from"./ConsoleBadge-DCgg_VHp.js";import{D as S}from"./DetailRow-gj5uvQBt.js";import{F as he}from"./FormSection-B1sGyorD.js";import{u as is,F as ms}from"./useAutoAdd-BPJdnE0M.js";import{A as us}from"./AttrSwitch-VNlvIg7l.js";import{C as Q,M as ds}from"./IndexChips-Dr5yOrBM.js";import{B as ps,a as ye,b as je,c as xs}from"./buttons-B-td5m2n.js";import{T as L}from"./consoleMotifs-DztxQt8X.js";import{I as fs}from"./consoleSplit-DYESYKMN.js";import{u as bs,C as hs}from"./CommonLocationChips-D6diOlRA.js";import{u as ys}from"./useMoneyFormatter-nQgPhkeI.js";import{A as js}from"./AccountSelector-CWkV2wZd.js";import{c as gs,n as ge}from"./cashStoragePoints-DQmOI55b.js";import{R as vs}from"./DownloadOutlined-9yYWFJzE.js";import{S as ve}from"./index-DrBcIRVV.js";import{E as P}from"./index-CwuBtv0e.js";import{S as Is}from"./index-BTZEaxC7.js";import{T as Ts}from"./index-B22ZqzuR.js";import{P as Ie}from"./index-CgX3Ei35.js";import{R as Te}from"./DeleteOutlined-D2rzDTkW.js";import"./papaparse-DHZrpM8D.js";import"./useIsDark-iZe97-MD.js";import"./ArrowLeftOutlined-C0w1fwDH.js";import"./InfoCircleOutlined-DZC8WRsa.js";import"./DownOutlined-BQJivuOt.js";import"./UpOutlined-BOTXMvQY.js";import"./index-fJz-wRm3.js";import"./index-RbzkweVC.js";const x={physical:{label:"实体现金",...L.cashSource.physical},ewallet:{label:"电子钱包",...L.cashSource.ewallet},bank:{label:"银行活期",...L.cashSource.bank},brokerage:{label:"券商资金",...L.cashSource.brokerage}},J=["physical","ewallet","bank","brokerage"],Cs=[{value:"updated",label:"最近更新"},{value:"amount",label:"按金额"},{value:"name",label:"按名称"},{value:"inventory",label:"按最近盘点"}],ct=()=>{const O=Oe(),M=Ve(),{cash_assets:i,loadLiquidData:Z,addCash:ee,updateCash:se,deleteCash:te,inventoryCash:ne}=Be(),{currencies:Ce,mainCurrency:ke,convertAmount:R}=qe(),{accounts:le,getAccountById:d}=He(),E=Ue(s=>s.members),f=ys(),[a]=y.useForm(),[F,$]=l.useState(null),[oe,A]=l.useState("view"),[b,V]=l.useState(null),[_,Ne]=l.useState(""),[v,we]=l.useState("all"),[C,Se]=l.useState("updated"),[ae,I]=l.useState(!1),r=ke.code,h=l.useCallback(s=>R(s.amount,s.currency,r),[R,r]);l.useEffect(()=>{Z().catch(()=>g.error("现金数据加载失败"))},[Z]);const{total:re,pension:ce}=l.useMemo(()=>ze(i,(s,t)=>R(s,t,r)),[i,R,r]),ie=l.useMemo(()=>gs(i),[i]),Me=Ge(),me=Ke("cash.inventory"),[k,B,q]=We(),H=l.useMemo(()=>i.filter(s=>s.lastInventoryTime?j().diff(j(s.lastInventoryTime),"day")>=me:!0).length,[i,me,Me]),T=l.useMemo(()=>{const s=_.trim().toLowerCase();return[...i.filter(o=>!(v!=="all"&&o.sourceType!==v||s&&!(o.name.toLowerCase().includes(s)||(o.location??"").toLowerCase().includes(s)||(o.notes??"").toLowerCase().includes(s))))].sort((o,m)=>{if(C==="amount")return h(m)-h(o);if(C==="name")return o.name.localeCompare(m.name,"zh-Hans-CN");if(C==="inventory"){const p=o.lastInventoryTime?new Date(o.lastInventoryTime).getTime():0;return(m.lastInventoryTime?new Date(m.lastInventoryTime).getTime():0)-p}return m.updateTime-o.updateTime})},[i,v,_,C,h]),Re=v!=="all"||_.trim().length>0,Ee=l.useMemo(()=>T.reduce((s,t)=>s+h(t),0),[T,h]),n=l.useMemo(()=>i.find(s=>s.id===F)??null,[i,F]),D=l.useMemo(()=>{if(!n)return null;if(!n.lastInventoryTime)return{tone:"warning",value:"长期未盘点"};const s=j().diff(j(n.lastInventoryTime),"day"),t=j(n.lastInventoryTime).format("YYYY-MM-DD");return s>=q?{tone:"danger",value:`${t} · ${s} 天前 · 超 ${q} 天未盘点`}:s>=B?{tone:"warning",value:`${t} · ${s} 天前 · 超 ${B} 天未盘点`}:s>=k?{tone:"warning",value:`${t} · ${s} 天前 · 超 ${k} 天未盘点`}:{tone:"neutral",value:`${t} · ${s} 天前`}},[n,k,B,q]),Fe=l.useMemo(()=>n?n.lastInventoryTime?j().diff(j(n.lastInventoryTime),"day")>=k:!0:!1,[n,k]),U=l.useCallback(()=>{const s=le.find(t=>t.type==="physical");$(null),V(null),a.resetFields(),a.setFieldsValue({currency:r,sourceType:"physical",accountId:s?.id,isForRetirement:!1}),A("form"),I(!0)},[le,r,a]),z=l.useCallback(s=>{$(s.id),V(s),a.resetFields(),a.setFieldsValue(s),A("form"),I(!0)},[a]),N=l.useCallback(()=>{A("view"),V(null),a.resetFields()},[a]);is(()=>U()),l.useEffect(()=>{const s=M.state?.accountId;if(!s)return;const t=d(s);t&&(U(),a.setFieldsValue({accountId:t.id,currency:t.currency,sourceType:t.type==="physical"?"physical":t.type==="ewallet"?"ewallet":t.type==="bank"?"bank":"brokerage"})),O(M.pathname,{replace:!0,state:{}})},[M.state,d,O,M.pathname]);const c=y.useWatch("sourceType",a);l.useEffect(()=>{const s=a.getFieldValue("accountId");if(!s||!c)return;const t=d(s);if(!t)return;const o={physical:"physical",ewallet:"ewallet",bank:"bank",brokerage:"investment"};t.type!==o[c]&&a.setFieldsValue({accountId:void 0})},[c,a,d]),l.useEffect(()=>{c&&c!=="bank"&&a.setFieldsValue({isForRetirement:!1})},[c,a]);const G=l.useCallback(s=>{ne(s).then(()=>g.success("盘点记录已更新")).catch(t=>g.error(t?.message||"盘点失败"))},[ne]),ue=l.useCallback(()=>{a.validateFields().then(async s=>{const t={...s},o=t.accountId?d(t.accountId):null;if(t.memberId=o?.memberId||"self",t.sourceType!=="bank"&&(t.isForRetirement=!1),!t.name)if(t.sourceType==="physical")t.name=`${t.location||"未知位置"}的钱`;else if(t.accountId){const m=d(t.accountId);t.name=m?`${m.name}的资金`:`${x[t.sourceType].label}资产`}else t.name=`${x[t.sourceType].label}资产`;b?(await se(b.id,t),g.success("更新成功")):(await ee(t),g.success("添加成功")),t.location&&bs.getState().addLocation(t.location),N()}).catch(s=>{s?.errorFields||g.error(s?.message||"保存失败")})},[a,b,se,ee,d,N]),de=l.useCallback(s=>{te(s.id).then(()=>{g.success("删除成功"),N(),$(null),I(!1)}).catch(t=>g.error(t?.message||"删除失败"))},[te,N]),$e=l.useCallback(()=>{const s=["名称","来源类型","金额","币种","存放位置","关联账户","归入养老","上次盘点","更新时间"],t=T.map(u=>[u.name,x[u.sourceType].label,u.amount,u.currency,u.location??"",u.accountId?d(u.accountId)?.name??"未关联":"未关联",u.is
1ForRetirement?"是":"",u.lastInventoryTime?j(u.lastInventoryTime).format("YYYY-MM-DD"):"长期未盘点",j(u.updateTime).format("YYYY-MM-DD HH:mm:ss")]),o="\uFEFF"+ns.unparse({fields:s,data:t}),m=new Blob([o],{type:"text/csv;charset=utf-8;"}),p=document.createElement("a"),Y=URL.createObjectURL(m);p.setAttribute("href",Y),p.setAttribute("download",`现金管理_${new Date().toISOString().split("T")[0]}.csv`),p.style.visibility="hidden",document.body.appendChild(p),p.click(),document.body.removeChild(p)},[T,d]),pe=l.useCallback(s=>{const t=x[s.sourceType],o=s.accountId?d(s.accountId):void 0,m=s.memberId||o?.memberId||"self",p=E.find(Pe=>Pe.id===m),Y=s.sourceType==="physical"?ge(s.location)||"未填写位置":s.notes||o?.name||"未关联账户",u=e.jsxs("span",{className:"flex flex-wrap items-center gap-1",children:[e.jsx(Q,{children:Y}),s.isForRetirement?e.jsx(Q,{children:"养老"}):null,s.currency!==r?e.jsxs(Q,{children:["≈ ",f(h(s),r)]}):null,m!=="self"&&p?e.jsx(ds,{ids:[m],members:E}):null]});return{id:s.id,spineColor:t.color,spineRgb:t.rgb,title:s.name,subtitle:u,value:f(s.amount,s.currency),quickActions:[{key:"inventory",icon:e.jsx(K,{}),label:"盘点",onClick:()=>G(s.id)},{key:"edit",icon:e.jsx(xe,{}),label:"编辑",onClick:()=>z(s)}]}},[d,E,r,f,h,G,z]),Ae=l.useMemo(()=>{const s=new Map;return T.forEach(t=>{const o=s.get(t.sourceType);o?o.push(t):s.set(t.sourceType,[t])}),J.filter(t=>s.has(t)).map(t=>{const o=s.get(t);return{key:t,label:x[t].label,count:o.length,summary:f(o.reduce((m,p)=>m+h(p),0),r),rows:o.map(pe)}})},[T,pe,h,r,f]),_e=l.useMemo(()=>[{key:"all",label:"全部",count:i.length,active:v==="all"},...J.map(s=>({key:s,label:x[s].label,count:i.filter(t=>t.sourceType===s).length,active:v===s,dotColor:x[s].color}))],[i,v]),w=!!b,De=w?x[b.sourceType]:null,Ye=n?x[n.sourceType]:null,Le=ts(a,ue);return e.jsxs(ls,{motif:"cash",fill:!0,children:[e.jsx(os,{title:"现金管理",backTo:"/assets/liquid",subtitle:`${ie} 个存放点 · ${i.length} 笔 · 折合 ${f(re,r)}`,icon:e.jsx(Qe,{}),actions:[{key:"export",label:"导出 CSV",icon:e.jsx(vs,{}),onClick:$e},{key:"create",label:"添加现金",icon:e.jsx(Xe,{}),primary:!0,onClick:()=>U()}]}),H>0?e.jsxs("div",{className:"mb-3 flex items-center gap-2 rounded-console border border-console-border bg-console-surface-tint px-3 py-2 text-[13px] text-console-muted",children:[e.jsx(K,{className:"shrink-0",style:{color:"#d97706"}}),e.jsxs("span",{children:["有 ",e.jsx("strong",{className:"tabular-nums text-ink",children:H})," 个存放点已超过一个季度未盘点对账,建议逐一对账。"]})]}):null,e.jsx(as,{items:[{key:"total",label:`现金总额 (${r})`,value:f(re,r),hint:"全量现金按当前汇率折算主币求和,不随上方筛选变化"},...ce>0?[{key:"pension",label:"其中养老锁定",value:f(ce,r),hint:"标记为「归入养老钱包」的银行活期余额(个人养老金资金账户里还没买成产品的钱)。它是你的资产,已包含在左侧「现金总额」内,所以列表之和仍等于总额;但退休前取不出来,在流动钱包页不计入速动资产——两页现金口径的差额就来自这里。盘点照常参与,不受影响。"}]:[],{key:"points",label:"存放点数量",value:ie},{key:"count",label:"现金条目",value:i.length},{key:"never",label:"长期未盘点",value:H}]}),e.jsxs(rs,{search:{value:_,onChange:Ne,placeholder:"搜索名称、位置或说明"},chips:_e,onChip:we,children:[Re?e.jsxs("span",{className:"text-[13px] tabular-nums text-console-muted",children:["筛选出 ",T.length," 笔 · ",f(Ee,r)]}):null,e.jsxs("label",{className:"flex items-center gap-1.5 text-[13px] text-console-muted",children:[e.jsx("span",{children:"排序"}),e.jsx(ve,{size:"small",value:C,onChange:Se,options:Cs,className:"w-24"})]})]}),e.jsxs("div",{className:"flex gap-3 lg:flex-1 lg:min-h-0",children:[e.jsx("aside",{className:`min-w-0 flex-1 rounded-console border border-console-border bg-console-surface transition-opacity ${fs} lg:self-start lg:overflow-y-auto lg:max-h-full ${oe==="form"?"pointer-events-none opacity-60":""} ${ae?"hidden lg:block":""}`,children:e.jsx(cs,{groups:Ae,collapsible:!0,selectedId:F,onSelect:s=>{$(s),A("view"),I(!0)},empty:e.jsx(P,{description:i.length===0?"还没有现金记录,点击右上角「添加现金」":"没有匹配的现金",image:P.PRESENTED_IMAGE_SIMPLE})})}),e.jsx("div",{className:`min-w-0 flex-1 lg:h-full lg:overflow-hidden ${ae?"":"hidden lg:block"}`,children:oe==="form"?e.jsx(X,{accentColor:De?.color??"var(--console-accent)",title:w?`编辑:${b.name}`:"新建现金",subtitle:w?"修改后点击保存生效":"填写后点击保存,金额按币种记录",className:"lg:h-full",actions:e.jsxs(e.Fragment,{children:[e.jsxs("button",{type:"button",onClick:ue,className:ps,children:[e.jsx(es,{}),e.jsx("span",{children:"保存"})]}),e.jsxs("button",{type:"button",onClick:()=>{const s=!!F;N(),s||I(!1)},className:ye,title:"取消","aria-label":"取消",children:[e.jsx(ss,{}),e.jsx("span",{children:"取消"})]}),w?e.jsx("span",{className:"ml-auto",children:e.jsx(Ie,{title:"确定删除这笔现金吗?",onConfirm:()=>b&&de(b),okText:"确定删除",cancelText:"取消",children:e.jsxs("button",{type:"button",className:je,title:"删除","aria-label":"删除",children:[e.jsx(Te,{}),e.jsx("span",{children:"删除"})]})})}):null]}),children:e.jsxs(y,{form:a,layout:"vertical",className:"console-pane-form max-w-2xl mx-auto",initialValues:{amount:0,sourceType:"physical"},onKeyDown:Le,children:[e.jsxs("div",{className:"mb-4 flex flex-wrap items-center justify-between gap-x-5 gap-y-2 rounded-console border border-console-border bg-console-surface-tint px-3 py-2",children:[e.jsx("div",{className:"flex items-center",children:e.jsx(y.Item,{name:"sourceType",noStyle:!0,rules:[{required:!0,message:"请选择来源类型"}],children:e.jsx(Is,{options:J.map(s=>
1({value:s,label:x[s].label}))})})}),c==="bank"?e.jsx(us,{form:a,name:"isForRetirement",label:"归入养老钱包"}):null]}),e.jsxs(he,{title:"基本信息",children:[e.jsx(y.Item,{name:"name",label:"资产名称",tooltip:"若不填,系统将根据存放位置或关联账户自动命名",children:e.jsx(W,{placeholder:"不填则自动命名,如:保险柜的钱"})}),e.jsx(y.Item,{name:"amount",label:"金额",rules:[{required:!0,message:"请输入金额"}],children:e.jsx(Ts,{className:"w-full",precision:2,min:0,controls:!1})}),e.jsx(y.Item,{name:"currency",label:"币种",rules:[{required:!0,message:"请选择币种"}],children:e.jsx(ve,{options:Ce.map(s=>({label:`${s.name} (${s.code})`,value:s.code})),dropdownRender:s=>e.jsxs(e.Fragment,{children:[s,e.jsx("div",{className:"border-t p-2 text-center",children:e.jsx(Je,{type:"link",size:"small",icon:e.jsx(Ze,{}),onClick:()=>O("/management/currencies"),children:"管理币种"})})]})})})]}),e.jsxs(he,{title:"存放与账户",children:[c==="physical"?e.jsx(y.Item,{name:"location",label:"存放位置",rules:[{required:!0,message:"请输入存放位置"}],extra:e.jsx(hs,{form:a}),children:e.jsx(W,{placeholder:"例如: 卧室抽屉、保险柜、钱包"})}):e.jsxs("div",{className:"mb-4 rounded-console-sm bg-console-accent-soft p-3 text-[12px] text-console-accent-strong sm:col-span-2",children:["提示:",x[c]?.label??"该类型","需关联对应的账户以同步余额。"]}),e.jsx(y.Item,{name:"accountId",label:c==="physical"?"关联账户 (可选)":"关联账户",rules:[{required:c!==void 0&&c!=="physical",message:"请选择对应的钱包/银行/券商账户"}],children:e.jsx(js,{allowClear:c==="physical",filterType:c==="physical"?"physical":c==="ewallet"?"ewallet":c==="bank"?"bank":c==="brokerage"?"investment":"physical"})})]}),e.jsxs(ms,{children:[e.jsx(y.Item,{name:"notes",label:"备注",className:"sm:col-span-2",children:e.jsx(W.TextArea,{rows:2,placeholder:"补充说明..."})}),w&&b?.lastInventoryTime?e.jsxs("div",{className:"mb-4 text-[12px] text-console-muted sm:col-span-2",children:["上次盘点:",new Date(b.lastInventoryTime).toLocaleString()]}):null]})]})}):n?e.jsx(X,{accentColor:Ye?.color,title:n.name,subtitle:`${x[n.sourceType].label} · ${n.currency}`,badge:Fe?e.jsx(be,{tone:"warning",title:"已超过 1 个季度未做盘点对账",children:"长期未盘点"}):e.jsx(be,{tone:"success",children:"已盘点"}),className:"lg:sticky lg:top-3",actions:e.jsxs(e.Fragment,{children:[e.jsxs("button",{type:"button",onClick:()=>G(n.id),className:xs,children:[e.jsx(K,{}),e.jsx("span",{children:"盘点"})]}),e.jsxs("button",{type:"button",onClick:()=>z(n),className:ye,children:[e.jsx(xe,{}),e.jsx("span",{children:"编辑"})]}),e.jsx(Ie,{title:"确定删除这笔现金吗?",onConfirm:()=>de(n),okText:"确定删除",cancelText:"取消",children:e.jsxs("button",{type:"button",className:je,children:[e.jsx(Te,{}),e.jsx("span",{children:"删除"})]})})]}),onClose:()=>I(!1),children:e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex flex-col gap-3 sm:flex-row sm:items-stretch",children:[e.jsxs("div",{className:"min-w-0 sm:flex-1",children:[e.jsx("div",{className:"text-[13px] text-console-muted",children:"当前金额"}),e.jsx("div",{className:"text-[22px] font-medium tabular-nums text-console-ink",children:f(n.amount,n.currency)}),n.currency!==r&&e.jsxs("div",{className:"text-[13px] text-console-muted",children:["≈ ",f(h(n),r)]})]}),D?e.jsx("div",{className:"min-w-0 sm:w-[42%] sm:max-w-[300px] sm:flex-none",children:e.jsxs("div",{className:"h-full rounded-console-sm px-3 py-2",style:{backgroundColor:fe[D.tone].bg},children:[e.jsx("div",{className:"text-[13px] text-console-muted",children:"上次盘点"}),e.jsx("div",{className:"text-[18px] font-medium tabular-nums",style:{color:fe[D.tone].fg},children:D.value})]})}):null]}),e.jsxs("div",{className:"grid grid-cols-1 gap-x-6 sm:grid-cols-2",children:[e.jsx(S,{label:"存放位置 / 说明",children:n.sourceType==="physical"?ge(n.location)??"未填写":n.notes??"—"}),e.jsx(S,{label:"关联账户",children:n.accountId?d(n.accountId)?.name??"未关联":"未关联"}),n.isForRetirement?e.jsx(S,{label:"养老归属",children:"已归入养老钱包 · 退休前不可动用,不计入速动资产"}):null,e.jsx(S,{label:"归属成员",children:(n.memberId&&n.memberId!=="self"?E.find(s=>s.id===n.memberId)?.name:void 0)??"本人"}),e.jsx(S,{label:"更新时间",children:j(n.updateTime).format("YYYY-MM-DD HH:mm")}
1)]})]})}):e.jsx(X,{className:"lg:sticky lg:top-3",onClose:()=>I(!1),empty:e.jsxs("div",{className:"px-6 text-center",children:[e.jsx(P,{description:"从左侧选择一笔现金查看详情",image:P.PRESENTED_IMAGE_SIMPLE}),e.jsx("p",{className:"mt-2 text-[12px] leading-5 text-console-muted",children:"支持用趣味化命名保护财务隐私:无论是「深夜食堂基金」还是「神秘金库」, 只要你自己能识别,创意命名就是一道隐私防线。"})]})})})]})]})};export{ct as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.