jeremy 4 月之前
父節點
當前提交
84993e1cdc
共有 1 個文件被更改,包括 96 次插入0 次删除
  1. 96 0
      frontend/src/pages/LeaseDetail.jsx

+ 96 - 0
frontend/src/pages/LeaseDetail.jsx

@@ -341,6 +341,102 @@ export default function LeaseDetail() {
         </div>
       )}
 
+      {/* Récapitulatif annuel */}
+      {payments.length > 0 && (() => {
+        const byYear = {}
+        payments.forEach(p => {
+          const y = p.period_year
+          if (!byYear[y]) byYear[y] = { rent: 0, charges: 0, reg: 0, count: 0 }
+          byYear[y].rent += p.rent_paid
+          byYear[y].charges += p.charges_paid
+          byYear[y].reg += p.charge_regularization || 0
+          byYear[y].count += 1
+        })
+        const years = Object.keys(byYear).sort((a, b) => b - a)
+        return (
+          <div className="card mb-6">
+            <h2 className="text-base font-semibold text-gray-800 mb-3">📊 Récapitulatif annuel</h2>
+            {/* Desktop */}
+            <div className="hidden md:block overflow-x-auto">
+              <table className="w-full text-sm">
+                <thead>
+                  <tr className="border-b text-gray-500 text-left">
+                    <th className="pb-2 pr-6 font-medium">Année</th>
+                    <th className="pb-2 pr-6 font-medium text-right">Loyers encaissés</th>
+                    <th className="pb-2 pr-6 font-medium text-right">Charges encaissées</th>
+                    <th className="pb-2 pr-6 font-medium text-right">Régularisations</th>
+                    <th className="pb-2 font-medium text-right">Total net</th>
+                  </tr>
+                </thead>
+                <tbody className="divide-y divide-gray-50">
+                  {years.map(y => {
+                    const d = byYear[y]
+                    const net = d.rent + d.charges - d.reg
+                    return (
+                      <tr key={y} className="hover:bg-gray-50">
+                        <td className="py-2 pr-6 font-semibold text-gray-800">{y}</td>
+                        <td className="py-2 pr-6 text-right text-gray-700">{fmt(d.rent)}</td>
+                        <td className="py-2 pr-6 text-right text-gray-500">{fmt(d.charges)}</td>
+                        <td className="py-2 pr-6 text-right">
+                          {d.reg !== 0
+                            ? <span className={d.reg > 0 ? 'text-green-600' : 'text-orange-600'}>
+                                {d.reg > 0 ? `−${fmt(d.reg)}` : `+${fmt(Math.abs(d.reg))}`}
+                              </span>
+                            : <span className="text-gray-300">—</span>}
+                        </td>
+                        <td className="py-2 text-right font-bold text-blue-700">{fmt(net)}</td>
+                      </tr>
+                    )
+                  })}
+                </tbody>
+                <tfoot className="border-t-2 border-gray-200">
+                  <tr>
+                    <td className="pt-2 pr-6 font-bold text-gray-900">Total</td>
+                    <td className="pt-2 pr-6 text-right font-bold text-gray-900">
+                      {fmt(years.reduce((s, y) => s + byYear[y].rent, 0))}
+                    </td>
+                    <td className="pt-2 pr-6 text-right font-bold text-gray-900">
+                      {fmt(years.reduce((s, y) => s + byYear[y].charges, 0))}
+                    </td>
+                    <td className="pt-2 pr-6 text-right font-bold text-gray-900">
+                      {fmt(years.reduce((s, y) => s + byYear[y].reg, 0))}
+                    </td>
+                    <td className="pt-2 text-right font-bold text-blue-800 text-base">
+                      {fmt(years.reduce((s, y) => s + byYear[y].rent + byYear[y].charges - byYear[y].reg, 0))}
+                    </td>
+                  </tr>
+                </tfoot>
+              </table>
+            </div>
+            {/* Mobile */}
+            <div className="md:hidden space-y-2">
+              {years.map(y => {
+                const d = byYear[y]
+                const net = d.rent + d.charges - d.reg
+                return (
+                  <div key={y} className="bg-gray-50 rounded-xl px-4 py-3">
+                    <div className="flex justify-between items-center mb-1">
+                      <span className="font-bold text-gray-800">{y}</span>
+                      <span className="font-bold text-blue-700">{fmt(net)}</span>
+                    </div>
+                    <div className="text-xs text-gray-500 space-y-0.5">
+                      <div className="flex justify-between"><span>Loyers</span><span>{fmt(d.rent)}</span></div>
+                      <div className="flex justify-between"><span>Charges</span><span>{fmt(d.charges)}</span></div>
+                      {d.reg !== 0 && (
+                        <div className={`flex justify-between font-medium ${d.reg > 0 ? 'text-green-600' : 'text-orange-600'}`}>
+                          <span>Régularisations</span>
+                          <span>{d.reg > 0 ? `−${fmt(d.reg)}` : `+${fmt(Math.abs(d.reg))}`}</span>
+                        </div>
+                      )}
+                    </div>
+                  </div>
+                )
+              })}
+            </div>
+          </div>
+        )
+      })()}
+
       {/* Paiements */}
       <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 mb-4">
         <h2 className="text-xl font-bold text-gray-900">💰 Historique des paiements</h2>