diff --git a/backend/app/main.py b/backend/app/main.py
index 3aab2b7..0161aee 100644
--- a/backend/app/main.py
+++ b/backend/app/main.py
@@ -64,9 +64,34 @@ from app.modules.opening_balances.lock_router import router as opening_balance_l
app.include_router(opening_balance_lock_router)
from app.routers import journal_entries
+from app.routers import cash
+from app.routers import accounts
+
app.include_router(journal_entries.router)
+app.include_router(cash.router)
+app.include_router(accounts.router)
+
from app.routers import month_locks
app.include_router(month_locks.router)
+from app.routers import year_locks
+app.include_router(year_locks.router)
+
+from app.routers import cash
+app.include_router(cash.router)
+
+
+from fastapi.staticfiles import StaticFiles
+
+app.mount(
+ "/",
+ StaticFiles(directory="app/static", html=True),
+ name="static",
+)
+
+
+
+
+
diff --git a/backend/app/routers/accounts.py b/backend/app/routers/accounts.py
index e69de29..af2698d 100644
--- a/backend/app/routers/accounts.py
+++ b/backend/app/routers/accounts.py
@@ -0,0 +1,23 @@
+from fastapi import APIRouter
+from app.core.database import get_connection
+
+router = APIRouter(prefix="/accounts", tags=["科目"])
+
+@router.get("", summary="科目一覧取得")
+def get_accounts():
+ """
+ 科目マスタ一覧を返す
+ """
+ with get_connection() as conn, conn.cursor() as cur:
+ cur.execute("""
+ SELECT
+ account_id,
+ account_code,
+ account_name,
+ account_type
+ FROM accounts
+ ORDER BY account_code
+ """)
+ rows = cur.fetchall()
+
+ return rows
diff --git a/backend/app/routers/cash.py b/backend/app/routers/cash.py
new file mode 100644
index 0000000..8fbb315
--- /dev/null
+++ b/backend/app/routers/cash.py
@@ -0,0 +1,105 @@
+from fastapi import APIRouter, Query
+from datetime import date
+from app.core.database import get_connection
+
+router = APIRouter(prefix="/cash", tags=["资金"])
+
+
+# ※ 临时方案:资金系科目(现金 / 银行)
+CASH_ACCOUNT_IDS = [101, 102]
+
+
+# -------------------------
+# 资金余额
+# -------------------------
+@router.get("/balance", summary="资金余额取得")
+def get_cash_balance():
+ """
+ 取得当前资金余额(现金・银行)
+ """
+ with get_connection() as conn, conn.cursor() as cur:
+ cur.execute("""
+ SELECT
+ a.account_id,
+ a.account_name,
+ COALESCE(SUM(l.debit), 0) - COALESCE(SUM(l.credit), 0) AS balance
+ FROM accounts a
+ LEFT JOIN journal_lines l
+ ON l.account_id = a.account_id
+ LEFT JOIN journal_entries e
+ ON e.journal_id = l.journal_id
+ AND e.is_deleted = false
+ WHERE a.account_id = ANY(%s)
+ GROUP BY a.account_id, a.account_name
+ ORDER BY a.account_id
+ """, (CASH_ACCOUNT_IDS,))
+
+ rows = cur.fetchall()
+
+ total = sum(r["balance"] for r in rows)
+
+ return {
+ "items": rows,
+ "total_balance": total
+ }
+
+
+# -------------------------
+# 资金流水
+# -------------------------
+@router.get("/transactions", summary="资金流水取得")
+def get_cash_transactions(
+ account_id: int = Query(..., description="资金账户ID"),
+ from_date: date | None = Query(None, alias="from"),
+ to_date: date | None = Query(None, alias="to"),
+):
+ """
+ 指定资金账户的资金流水
+ """
+ with get_connection() as conn, conn.cursor() as cur:
+ sql = """
+ SELECT
+ e.journal_date,
+ e.description,
+ l.debit,
+ l.credit,
+ COALESCE(a2.account_name, '(未指定)') AS counter_account
+ FROM journal_lines l
+ JOIN journal_entries e
+ ON e.journal_id = l.journal_id
+ LEFT JOIN journal_lines l2
+ ON l2.journal_id = l.journal_id
+ AND l2.account_id <> l.account_id
+ LEFT JOIN accounts a2
+ ON a2.account_id = l2.account_id
+ WHERE l.account_id = %s
+ AND e.is_deleted = false
+ """
+
+ params = [account_id]
+
+ if from_date:
+ sql += " AND e.journal_date >= %s"
+ params.append(from_date)
+
+ if to_date:
+ sql += " AND e.journal_date <= %s"
+ params.append(to_date)
+
+ sql += " ORDER BY e.journal_date, e.journal_id"
+
+ cur.execute(sql, params)
+ rows = cur.fetchall()
+
+ result = []
+ for r in rows:
+ amount = r["debit"] - r["credit"]
+ result.append({
+ "journal_date": r["journal_date"],
+ "description": r["description"],
+ "counter_account": r["counter_account"],
+ "amount": amount,
+ "direction": "in" if amount > 0 else "out" if amount < 0 else "none",
+ })
+
+ return result
diff --git a/backend/app/routers/year_locks.py b/backend/app/routers/year_locks.py
new file mode 100644
index 0000000..7477682
--- /dev/null
+++ b/backend/app/routers/year_locks.py
@@ -0,0 +1,49 @@
+from fastapi import APIRouter, HTTPException
+from app.core.database import get_connection
+
+router = APIRouter(prefix="/year-locks", tags=["年度锁定"])
+
+
+@router.get("", summary="年度锁定一覧")
+def get_year_locks():
+ with get_connection() as conn, conn.cursor() as cur:
+ cur.execute("""
+ SELECT fiscal_year, is_locked, locked_at, locked_by
+ FROM year_locks
+ ORDER BY fiscal_year
+ """)
+ return cur.fetchall()
+
+
+@router.post("/lock", summary="年度锁定")
+def lock_year(fiscal_year: int):
+ with get_connection() as conn, conn.cursor() as cur:
+ cur.execute("""
+ INSERT INTO year_locks (fiscal_year, is_locked, locked_at, locked_by)
+ VALUES (%s, true, NOW(), %s)
+ ON CONFLICT (fiscal_year)
+ DO UPDATE
+ SET is_locked = true,
+ locked_at = NOW(),
+ locked_by = EXCLUDED.locked_by
+ """, (fiscal_year, "system"))
+ conn.commit()
+
+ return {"status": "locked", "fiscal_year": fiscal_year}
+
+
+@router.post("/unlock", summary="年度解锁")
+def unlock_year(fiscal_year: int):
+ with get_connection() as conn, conn.cursor() as cur:
+ cur.execute("""
+ UPDATE year_locks
+ SET is_locked = false
+ WHERE fiscal_year = %s
+ """, (fiscal_year,))
+
+ if cur.rowcount == 0:
+ raise HTTPException(status_code=404, detail="指定年度不存在")
+
+ conn.commit()
+
+ return {"status": "unlocked", "fiscal_year": fiscal_year}
diff --git a/backend/app/static/cash-transactions.html b/backend/app/static/cash-transactions.html
new file mode 100644
index 0000000..fe187d4
--- /dev/null
+++ b/backend/app/static/cash-transactions.html
@@ -0,0 +1,96 @@
+
+
+
+
+ 资金流水
+
+
+ 📄 资金流水
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | 日期 |
+ 摘要 |
+ 金额 |
+
+
+
+
+ | 请输入条件后查询 |
+
+
+
+
+
+
+
diff --git a/backend/app/static/cash.html b/backend/app/static/cash.html
new file mode 100644
index 0000000..a3e055e
--- /dev/null
+++ b/backend/app/static/cash.html
@@ -0,0 +1,76 @@
+
+
+
+
+ 资金余额
+
+
+ 💰 当前资金状况
+
+
+
+
+ | 账户 |
+ 余额 |
+
+
+
+
+ | 读取中... |
+
+
+
+
+ | 合计 |
+ - |
+
+
+
+
+
+
+
diff --git a/frontend/index.html b/frontend/index.html
index 8880463..5b78c0b 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -30,7 +30,67 @@
+ 💰 当前资金状况
+
+
+
+
+ | 账户 |
+ 余额 |
+
+
+
+
+ | 读取中... |
+
+
+
+
+ | 合计 |
+ - |
+
+
+
+
+