PageSourceSearch

https://shuraba-app.web.app/assets/BudgetVariancePage-BsGO_eIW.js

js shuraba-app.web.app collected 2026-10-03 12:36:59 UTC 15,909 bytes, 2 lines download raw bytes

1const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/exceljs.min-521lG1XK.js","assets/index-DUpygkxg.js","assets/firebase-eOymXQZD.js","assets/index-Sz3rDXYt.css","assets/_commonjs-dynamic-modules-TDtrdbi3.js"])))=>i.map(i=>d[i]);
2import{$ as G,u as K,r as n,bj as O,j as e,G as W,R as X,V as H,T as k,aH as J,h as q}from"./index-DUpygkxg.js";import{E as R}from"./ErrorBanner-Cd4OwWGf.js";import{u as Q}from"./useToast-DyXTsHnJ.js";import{f as d}from"./formatters-QZX43yAa.js";import{c as Z,a as ee,s as te,i as ae}from"./budget-D3Tbvrqo.js";import{A as B}from"./arrow-left-C9DRxuig.js";import{F as se}from"./file-spreadsheet-DFjrbUrD.js";import{C as re}from"./circle-check-rffZ2Dr7.js";import{T as w}from"./trending-down-7nfBUd_6.js";import{R as le,C as ne,X as de,Y as ce,T as ie}from"./CartesianChart-DvcN2kyc.js";import{B as xe,a as P}from"./BarChart-DHwxt_0D.js";import{L as oe}from"./Legend-Cq_Zep5W.js";import{C as me}from"./tooltipContext-Bz8gGe_N.js";import"./firebase-eOymXQZD.js";const $={good:{label:"良好",badge:"bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300",dot:"bg-emerald-500"},warning:{label:"注意",badge:"bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300",dot:"bg-amber-500"},over:{label:"超過/未達",badge:"bg-red-100 text-red-700 dark:bg-red-900/40 dark:text-red-300",dot:"bg-red-500"}};function Ee(){const{id:a}=G(),c=K(),o=Q(),[r,b]=n.useState(null),[i,T]=n.useState([]),[v,_]=n.useState(null),[Y,C]=n.useState(!0),[p,A]=n.useState(null),[E,F]=n.useState(!1),y=n.useCallback(async()=>{if(a){C(!0),A(null);try{const[t,m]=await Promise.all([Z(a),ee(a)]);if(b(t),T(m),t?.grantId){const l=await O(t.grantId);_(l)}}catch(t){A(t instanceof Error?t.message:String(t))}finally{C(!1)}}},[a]);n.useEffect(()=>{y()},[y]);const z=async()=>{F(!0);try{await y(),o.success("最新の実績を再計算しました")}finally{F(!1)}},s=n.useMemo(()=>te(i),[i]),h=n.useMemo(()=>r?ae(r.fiscalYear):0,[r]),S=n.useMemo(()=>i.filter(t=>t.type==="income"),[i]),u=n.useMemo(()=>i.filter(t=>t.type==="expense"),[i]),D=async()=>{if(r)try{const t=await J(()=>import("./exceljs.min-521lG1XK.js").then(x=>x.e),__vite__mapDeps([0,1,2,3,4])),m=new t.Workbook,l=m.addWorksheet("予実管理");l.columns=[{header:"区分",key:"type",width:10},{header:"勘定科目",key:"category",width:20},{header:"予算",key:"budget",width:15},{header:"実績",key:"actual",width:15},{header:"差異",key:"variance",width:15},{header:"差異率(%)",key:"percent",width:12},{header:"ステータス",key:"status",width:12}],l.getRow(1).font={bold:!0},l.getRow(1).fill={type:"pattern",pattern:"solid",fgColor:{argb:"FFF0FDF4"}},i.forEach(x=>{l.addRow({type:x.type==="income"?"収入":"支出",category:x.accountCategory,budget:x.budgetAmount,actual:x.actualAmount,variance:x.variance,percent:x.variancePercent.toFixed(1),status:$[x.status].label})}),l.addRow({}),l.addRow({type:"合計",category:"収入合計",budget:s.totalBudgetIncome,actual:s.totalActualIncome,variance:s.totalActualIncome-s.totalBudgetIncome,percent:s.incomeAchievementPercent.toFixed(1)}),l.addRow({type:"合計",category:"支出合計",budget:s.totalBudgetExpense,actual:s.totalActualExpense,variance:s.totalActualExpense-s.totalBudgetExpense,percent:s.expenseExecutionPercent.toFixed(1)});const U=await m.xlsx.writeBuffer(),M=new Blob([U],{type:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}),I=URL.createObjectURL(M),N=document.createElement("a");N.href=I,N.download=`予実管理_${r.name}_${r.fiscalYear}年度.xlsx`,N.click(),URL.revokeObjectURL(I),o.success("Excelを出力しました")}catch(t){o.error(t instanceof Error?t.message:"Excel出力に失敗しました")}};if(Y)return e.jsx(W,{});if(!r)return e.jsxs("div",{className:"p-6",children:[e.jsxs("button",{onClick:()=>c("/budget"),className:"inline-flex items-center gap-1 text-sm text-emerald-600 hover:underline mb-4",children:[e.jsx(B,{className:"w-4 h-4"})," 予算一覧に戻る"]}),e.jsx(R,{message:p||"予算計画が見つかりません"})]});const g=u.filter(t=>h>=50&&t.budgetAmount>0&&t.actualAmount/t.budgetAmount<.3),f=u.filter(t=>t.status==="over"),j=i.map(t=>({name:t.accountCategory.length>6?t.accountCategory.slice(0,5)+"…":t.accountCategory,fullName:t.accountCategory,予算:t.budgetAmount,実績:t.actualAmount,type:t.type,status:t.status}));return e.jsxs("div",{className:"p-4 sm:p-6 max-w-6xl mx-auto",children:[e.jsxs("button",{onClick:()=>c("/budget"),className:"inline-flex items-center gap-1 text-sm text-emerald-600 hover:underline mb-4",children:[e.jsx(B,{className:"w-4 h-4"})," 予算一覧に戻る"]}),e.jsxs("div",{className:"bg-white dark:bg-gray-900 rounded-xl shadow-sm dark:shadow-black/20 p-5 mb-4",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3 mb-3 flex-wrap",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"text-xl font-bold dark:text-gray-100",children:r.name}),e.jsxs("p",{className:"text-xs text-gray-500 dark:text-gray-400 mt-1",children:[r.fiscalYear,"年度 · ",r.organizationWide?"団体全体":"助成金別",v&&e.jsxs("span",{className:"ml-1",children:["· ",v.name]})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{onClick:z,disabled:E,className:"p-2 text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800",title:"再計算",children:e.jsx(X,{className:`w-4 h-4 ${E?"animate-spin":""}`})}),e.jsxs("button",{onClick:D,className:"inline-flex items-center gap-1 px-3 py-1.5 text-xs font-medium text-green-700 dark:text-green-300 bg-green-50 dark:bg-green-900/30 hover:bg-green-100 dark:hover:bg-green-900/50 rounded-lg transition-colors",children:[e.jsx(se,{className:"w-3.5 h-3.5"})," Excel出力"]}),e.jsxs("button",{onClick:()=>c(`/budget/edit/${r.id}`),className:"inline-flex items-center gap-1 px-3 py-1.5 text-xs font-medium text-blue-700 dark:text-blue-300 bg-blue-50 dark:bg-blue-900/30 hover:bg-blue-100 dar
2k:hover:bg-blue-900/50 rounded-lg transition-colors",children:[e.jsx(H,{className:"w-3.5 h-3.5"})," 編集"]})]})]}),e.jsxs("div",{className:"mt-4",children:[e.jsxs("div",{className:"flex justify-between text-xs text-gray-500 dark:text-gray-400 mb-1",children:[e.jsx("span",{children:"年度経過"}),e.jsxs("span",{className:"font-semibold",children:[h.toFixed(0),"%"]})]}),e.jsx("div",{className:"h-2 bg-gray-100 dark:bg-gray-800 rounded-full overflow-hidden",children:e.jsx("div",{className:"h-full bg-indigo-500 transition-all",style:{width:`${h}%`}})}),e.jsxs("p",{className:"text-xs text-gray-400 mt-1",children:[r.fiscalYear,"/4/1 〜 ",r.fiscalYear+1,"/3/31"]})]})]}),p&&e.jsx(R,{message:p,className:"mb-4"}),e.jsxs("div",{className:"grid grid-cols-2 lg:grid-cols-4 gap-3 mb-4",children:[e.jsx(L,{label:"予算合計",incomeLabel:"収入",expenseLabel:"支出",incomeValue:s.totalBudgetIncome,expenseValue:s.totalBudgetExpense}),e.jsx(L,{label:"実績合計",incomeLabel:"収入",expenseLabel:"支出",incomeValue:s.totalActualIncome,expenseValue:s.totalActualExpense}),e.jsxs("div",{className:"bg-white dark:bg-gray-900 rounded-xl shadow-sm dark:shadow-black/20 p-4",children:[e.jsx("p",{className:"text-xs text-gray-500 dark:text-gray-400 mb-2",children:"執行率"}),e.jsxs("div",{className:"flex items-baseline gap-1",children:[e.jsx("span",{className:"text-2xl font-bold text-blue-600 dark:text-blue-400",children:s.expenseExecutionPercent.toFixed(1)}),e.jsx("span",{className:"text-sm text-gray-400",children:"%"})]}),e.jsx("p",{className:"text-xs text-gray-400 mt-1",children:"支出実績 / 支出予算"}),e.jsxs("p",{className:"text-xs text-gray-500 dark:text-gray-400 mt-2",children:["収入達成率: ",e.jsxs("span",{className:"font-semibold text-emerald-600 dark:text-emerald-400",children:[s.incomeAchievementPercent.toFixed(1),"%"]})]})]}),e.jsxs("div",{className:"bg-white dark:bg-gray-900 rounded-xl shadow-sm dark:shadow-black/20 p-4",children:[e.jsx("p",{className:"text-xs text-gray-500 dark:text-gray-400 mb-2",children:"アラート"}),e.jsxs("div",{className:"space-y-1.5",children:[s.overCount>0?e.jsxs("div",{className:"flex items-center gap-1.5 text-xs text-red-600 dark:text-red-400",children:[e.jsx(k,{className:"w-3.5 h-3.5"}),"超過/未達 ",s.overCount,"件"]}):e.jsxs("div",{className:"flex items-center gap-1.5 text-xs text-emerald-600 dark:text-emerald-400",children:[e.jsx(re,{className:"w-3.5 h-3.5"}),"超過なし"]}),s.warningCount>0&&e.jsxs("div",{className:"flex items-center gap-1.5 text-xs text-amber-600 dark:text-amber-400",children:[e.jsx(k,{className:"w-3.5 h-3.5"}),"注意 ",s.warningCount,"件"]}),g.length>0&&e.jsxs("div",{className:"flex items-center gap-1.5 text-xs text-amber-600 dark:text-amber-400",children:[e.jsx(w,{className:"w-3.5 h-3.5"}),"未執行 ",g.length,"件"]})]})]})]}),(f.length>0||g.length>0)&&e.jsxs("div",{className:"space-y-2 mb-4",children:[f.length>0&&e.jsxs("div",{className:"bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-3 flex items-start gap-2",children:[e.jsx(k,{className:"w-4 h-4 text-red-600 dark:text-red-400 flex-shrink-0 mt-0.5"}),e.jsxs("div",{className:"flex-1 text-xs text-red-700 dark:text-red-300",children:[e.jsx("p",{className:"font-semibold mb-1",children:"予算超過の科目"}),e.jsx("ul",{className:"space-y-0.5",children:f.map(t=>e.jsxs("li",{children:[e.jsx("span",{className:"font-medium",children:t.accountCategory}),": 予算 ",d(t.budgetAmount)," → 実績 ",d(t.actualAmount)," (+",t.variancePercent.toFixed(1),"%)"]},t.lineItemId))})]})]}),g.length>0&&e.jsxs("div",{className:"bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-lg p-3 flex items-start gap-2",children:[e.jsx(w,{className:"w-4 h-4 text-amber-600 dark:text-amber-400 flex-shrink-0 mt-0.5"}),e.jsxs("div",{className:"flex-1 text-xs text-amber-700 dark:text-amber-300",children:[e.jsxs("p",{className:"font-semibold mb-1",children:["大幅未執行の科目(年度 ",h.toFixed(0),"% 経過)"]}),e.jsx("ul",{className:"space-y-0.5",children:g.map(t=>e.jsxs("li",{children:[e.jsx("span",{className:"font-medium",children:t.accountCategory}),": 予算 ",d(t.budgetAmount)," に対し実績 ",d(t.actualAmount)," (",t.budgetAmount>0?(t.actualAmount/t.budgetAmount*100).toFixed(0):"0","%)"]},t.lineItemId))})]})]})]}),j.length>0&&e.jsxs("div",{className:"bg-white dark:bg-gray-900 rounded-xl shadow-sm dark:shadow-black/20 p-4 sm:p-5 mb-4",children:[e.jsx("h3",{className:"text-sm font-bold mb-3 dark:text-gray-100",children:"予算 vs 実績(科目別)"}),e.jsx("div",{className:"h-80",children:e.jsx(le,{width:"100%",height:"100%",children:e.jsxs(xe,{data:j,margin:{top:10,right:10,left:10,bottom:40},children:[e.jsx(ne,{strokeDasharray:"3 3",stroke:"#e5e7eb",opacity:.5}),e.jsx(de,{dataKey:"name",fontSize:11,angle:-30,textAnchor:"end",interval:0,height:60}),e.jsx(ce,{fontSize:11,tickFormatter:t=>t>=1e4?`${Math.round(t/1e4)}万`:String(t)}),e.jsx(ie,{formatter:t=>d(typeof t=="number"?t:Number(t)||0),labelFormatter:(t,m)=>m?.[0]?.payload?.fullName||"",contentStyle:{fontSize:"11px",borderRadius:"8px"}}),e.jsx(oe,{wrapperStyle:{fontSize:"11px"}}),e.jsx(P,{dataKey:"予算",fill:"#a7f3d0",radius:[4,4,0,0]}),e.jsx(P,{dataKey:"実績",radius:[4,4,0,0],children:j.map((t,m)=>{const l=t.status==="over"?"#ef4444":t.status==="warning"?"#f59e0b":"#10b981";return e.jsx(me,{fill:l},m)})})]})})})]}),e.jsxs("div",{className:"bg-white dark:bg-gray-900 rounded-xl shadow-sm dark:shadow-black/20 overflow-hidden mb-4",children:[e.jsx("div",{className:"px-4 sm:px-5 py-3 border-b border-gray-100 dark:border-gray-700",children:e.jsx("h3",{className:"text-sm font-bold dark:text-gray-100",children:"差異明細"})}),i.length===0?e.jsx("p",{className:"p-8 text-center text-sm text-gray-400",children:"明細がありません"}):e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-gray-50 dark:bg-gray-800/50",children:e.jsxs("tr",{className:"text-xs text-gray-500 dark:text-gray-400",children:[e.jsx("th",{className:"px-3 py-2 text-left font-medium",children:"区分"}),e.jsx("th",{className:"px-3 py-2 text-left font-medium",children:"科目"}),e.jsx("th",{className:"px-3 py-2 text-right font-medium",children:"予算"}),e.jsx("th",{className:"px-3 py-2 text-right font-medium",children:"実績"}),e.jsx("th",{className:"px-3 py-2 text-right font-medium",children:"差異"}),e.jsx("th",{className:"px-3 py-2 text-right font-medium",children:"差異率"}),e.jsx("th",{className:"px-3 py-2 text-left font-medium",children:"ステータス"})]})}),e.jsxs("tbody",{children:[S.length>0&&e.jsxs(e.Fragment,{children:[e.jsx("tr",{className:"bg-emerald-50/50 dark:bg-emerald-900/10",children:e.jsx("td",{colSpan:7,className:"px-3 py-1 text-[11px] font-semibold text-emerald-700 dark:text-emerald-400",children:"収入"})}),S.map(t=>e.jsx(V,{variance:t},t.lineItemId))]}),u.length>0&&e.jsxs(e.Fragment,{children:[e.jsx("tr",{className:"bg-blue-50/50 dark:bg-blue-900/10",children:e.jsx("td",{colSpan:7,className:"px-3 py-1 text-[11px] font-semibold text-blue-700 dark:text-blue-400",children:"支出"})}),u.map(t=>e.jsx(V,{variance:t},t.lineItemId))]})]})]})})]}),r.notes&&e.jsxs("div",{className:"bg-white dark:bg-gray-900 rounded-xl shadow-sm dark:shadow-black/20 p-4 sm:p-5 mb-4",children:[e.jsx("h4",{className:"text-xs font-bold mb-2 text-gray-600 dark:text-gray-300",children:"メモ"}),e.jsx("p",{className:"text-sm text-gray-700 dark:text-gray-200 whitespace-pre-wrap",children:r.notes})]})]})}function L({label:a,incomeLabel:c,expenseLabel:o,incomeValue:r,expenseValue:b}){return e.jsxs("div",{className:"bg-white dark:bg-gray-900 rounded-xl shadow-sm dark:shadow-black/20 p-4",children:[e.jsx("p",{className:"text-xs text-gray-500 dark:text-gray-400 mb-2",children:a}),e.jsxs("div",{className:"space-y-1",children:[e.jsxs("div",{className:"flex items-baseline justify-between",children:[e.jsx("span",{className:"text-xs text-emerald-600 dark:text-emerald-400",children:c}),e.jsx("span",{className:"text-sm font-bold text-emerald-700 dark:text-emerald-300",children:d(r)})]}),e.jsxs("div",{className:"flex items-baseline justify-between",children:[e.jsx("span",{className:"text-xs text-blue-600 dar
2k:text-blue-400",children:o}),e.jsx("span",{className:"text-sm font-bold text-blue-700 dark:text-blue-300",children:d(b)})]})]})]})}function V({variance:a}){const c=$[a.status],o=(a.type==="income"?a.variance>=0:a.variance<=0)?"text-emerald-600 dark:text-emerald-400":"text-red-600 dark:text-red-400",r=(a.type==="income"?a.variance>=0:a.variance<=0)?q:w;return e.jsxs("tr",{className:"border-t border-gray-100 dark:border-gray-800 hover:bg-gray-50 dark:hover:bg-gray-800/50",children:[e.jsx("td",{className:"px-3 py-2 text-xs text-gray-500 dark:text-gray-400",children:a.type==="income"?"収入":"支出"}),e.jsx("td",{className:"px-3 py-2 font-medium text-gray-800 dark:text-gray-100",children:a.accountCategory}),e.jsx("td",{className:"px-3 py-2 text-right text-gray-700 dark:text-gray-200 tabular-nums",children:d(a.budgetAmount)}),e.jsx("td",{className:"px-3 py-2 text-right text-gray-700 dark:text-gray-200 tabular-nums",children:d(a.actualAmount)}),e.jsx("td",{className:`px-3 py-2 text-right tabular-nums ${o}`,children:e.jsxs("span",{className:"inline-flex items-center gap-1",children:[e.jsx(r,{className:"w-3 h-3"}),a.variance>=0?"+":"",d(a.variance)]})}),e.jsxs("td",{className:`px-3 py-2 text-right tabular-nums ${o}`,children:[a.variancePercent>=0?"+":"",a.variancePercent.toFixed(1),"%"]}),e.jsx("td",{className:"px-3 py-2",children:e.jsxs("span",{className:`inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium ${c.badge}`,children:[e.jsx("span",{className:`w-1.5 h-1.5 rounded-full ${c.dot}`}),c.label]})})]})}export{Ee 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.