Files
accountbook/frontend/.next/cache/webpack/server-production/2.pack
T

3713 lines
246 KiB
Plaintext
Raw Normal View History

2026-03-12 11:24:10 +08:00
wpcöاwebpack/lib/cache/PackFileCacheStrategyPackContentItems vResolverCachePlugin|normal|default|alias=[|server-only$=|next/dist/compiled/server-only/index|client-only$=|next/dist/compiled/client-only/index|next/dist/compiled/client-only$=|next/dist/compiled/client-only/index|next/dist/compiled/server-only=|next/dist/compiled/server-only/index|]|dependencyType=|esm|path=|/opt/accountbook/frontend|request=|private-next-pages/index.js»Compilation/modules|/opt/accountbook/frontend/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[6].oneOf[3].use[0]!/opt/accountbook/frontend/pages/index.jsÃFlagDependencyExportsPlugin|/opt/accountbook/frontend/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[6].oneOf[3].use[0]!/opt/accountbook/frontend/pages/index.jsrCompilation/codeGeneration|/opt/accountbook/frontend/node_modules/next/dist/build/webpack/loaders/next-route-loader/index.js?kind=PAGES&page=%2F&preferredRegion=&absolutePagePath=private-next-pages%2Findex.js&absoluteAppPath=private-next-pages%2F_app.js&absoluteDocumentPath=next%2Fdist%2Fpages%2F_document&middlewareConfigBase64=e30%3D!|bac29d3a75de88c3|webpack-runtime¥webpack/lib/cache/ResolverCachePlugin`_ResolverCachePluginCacheMiss‡context„path‡request…queryˆfragment†module‰directory„fileˆinternalŽfullySpecified“descriptionFilePath“descriptionFileData“descriptionFileRootŒrelativePath †issuerissuerLayerˆcompiler†server¨/opt/accountbook/frontend/pages/index.js€€ ¦/opt/accountbook/frontend/package.json„name‡version‡private‡scriptsŒdependencies”accountbook-frontend…1.0.0 ƒdev…build…startnext dev -p 3500Šnext buildnext start -p 3500ˆchart.js„next…react‰react-dom†^4.5.1‡^14.0.0‡^18.2.0ÿ™/opt/accountbook/frontend./pages/index.jsšwebpack/lib/FileSystemInfoˆSnapshot@‰ àÄ’¸ÍyBáŸ/opt/accountbook/frontend/pagesˆsafeTime‰timestamp„hash!PN„¸ÍyB@N„¸ÍyBd642cff7a4eb3d3aýË`
Å/opt/accountbook/frontend/opt/accountbook/frontend/pages/package.json¿/opt/accountbook/frontend/opt/accountbook/frontend/package.json¶/opt/accountbook/frontend/opt/accountbook/package.jsonª/opt/accountbook/frontend/opt/package.jsonÁ/opt/accountbook/frontend/opt/accountbook/frontend/pages/index.jsÄ/opt/accountbook/frontend/opt/accountbook/frontend/pages/index.js.jsÅ/opt/accountbook/frontend/opt/accountbook/frontend/pages/index.js.mjsÅ/opt/accountbook/frontend/opt/accountbook/frontend/pages/index.js.tsxÄ/opt/accountbook/frontend/opt/accountbook/frontend/pages/index.js.tsÅ/opt/accountbook/frontend/opt/accountbook/frontend/pages/index.js.jsxÆ/opt/accountbook/frontend/opt/accountbook/frontend/pages/index.js.jsonÆ/opt/accountbook/frontend/opt/accountbook/frontend/pages/index.js.wasm¬/opt/accountbook/frontend/pages/package.json Á’¸ÍyBËæ/opt/accountbook„/opt/ë!@07ØÊyB /7ØÊyBf3b4def2c53d3cadé·èçµæ´˜webpack/lib/NormalModule«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourceimport { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import { isLoggedIn, getRecords, getStats, createRecord, updateRecord, deleteRecord } from "../lib/api";
import { DEFAULT_CATEGORIES } from "../lib/categories";
import AppShell from "../components/AppShell";
import { Icon } from "../components/icons";
import { useToast } from "../components/ToastProvider";
import { useConfirm } from "../components/ConfirmProvider";
export default function Home() {
const router = useRouter();
const { showToast } = useToast();
const { confirm } = useConfirm();
const [currentMonth, setCurrentMonth] = useState(new Date());
const [typeFilter, setTypeFilter] = useState("all");
const [records, setRecords] = useState([]);
const [stats, setStats] = useState({
income: 0,
expense: 0,
balance: 0
});
const [modalOpen, setModalOpen] = useState(false);
const [editingRecord, setEditingRecord] = useState(null);
const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false);
const [deleting, setDeleting] = useState(false);
const [formError, setFormError] = useState("");
const [formData, setFormData] = useState({
type: "expense",
amount: "",
category: "",
date: new Date().toISOString().split("T")[0],
time: new Date().toTimeString().slice(0, 5),
note: ""
});
null;
const getMonthStr = (date)=>`${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}`;
const formatMoney = (num)=>(num || 0).toFixed(2);
const formatMonth = (date)=>`${date.getFullYear()}年${date.getMonth() + 1}月`;
const resetForm = ()=>({
type: "expense",
amount: "",
category: "",
date: new Date().toISOString().split("T")[0],
time: new Date().toTimeString().slice(0, 5),
note: ""
});
const loadData = async ()=>{
setLoading(true);
try {
const [recordsData, statsData] = await Promise.all([
getRecords(getMonthStr(currentMonth), typeFilter),
getStats(getMonthStr(currentMonth))
]);
setRecords(recordsData);
setStats(statsData);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const prevMonth = ()=>{
const newDate = new Date(currentMonth);
newDate.setMonth(newDate.getMonth() - 1);
setCurrentMonth(newDate);
};
const nextMonth = ()=>{
const newDate = new Date(currentMonth);
newDate.setMonth(newDate.getMonth() + 1);
setCurrentMonth(newDate);
};
const handleCardClick = (type)=>{
setTypeFilter(type === typeFilter ? "all" : type);
};
const openAddModal = ()=>{
setEditingRecord(null);
setFormData(resetForm());
setFormError("");
setModalOpen(true);
};
const openEditModal = (record)=>{
const [datePart, timePart] = record.date.split(" ");
setEditingRecord(record);
setFormData({
type: record.type,
amount: record.amount.toString(),
category: record.category,
date: datePart,
time: timePart || "00:00",
note: record.note || ""
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting || deleting) return;
setModalOpen(false);
setEditingRecord(null);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.amount || !formData.category || !formData.date) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
const data = {
type: formData.type,
amount: parseFloat(formData.amount),
category: formData.category,
date: `${formData.date} ${formData.time || "00:00"}`,
note: formData.note
};
if (editingRecord) {
await updateRecord(editingRecord.id, data);
showToast("记录已更新", {
tone: "success"
});
} else {
await createRecord(data);
showToast("记录已添加", {
tone: "success"
});
}
closeModal();
await loadData();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async ()=>{
if (!editingRecord) return;
const shouldDelete = await confirm({
title: "删除这æ¡è®°å½•?",
description: "删除åŽå°†æ— æ³•æ¢å¤ï¼Œè¯·ç¡®è®¤æ˜¯å¦ç»§ç»­ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
setDeleting(true);
try {
await deleteRecord(editingRecord.id);
closeModal();
showToast("记录已删除", {
tone: "success"
});
await loadData();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setDeleting(false);
}
};
const groupedRecords = records.reduce((groups, record)=>{
const date = record.date.split(" ")[0];
if (!groups[date]) groups[date] = [];
groups[date].push(record);
return groups;
}, {});
const sortedDates = Object.keys(groupedRecords).sort((a, b)=>b.localeCompare(a));
const getDayExpense = (date)=>groupedRecords[date].filter((record)=>record.type === "expense").reduce((sum, record)=>sum + record.amount, 0);
const homeHeaderContent = /*#__PURE__*/ _jsxs("div", {
className: "header-center-container",
children: [
/*#__PURE__*/ _jsx("div", {
className: "header-left-actions",
children: /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "æœç´¢è®°å½•",
onClick: ()=>router.push("/search"),
children: /*#__PURE__*/ _jsx(Icon, {
name: "search",
size: 18
})
})
}),
/*#__PURE__*/ _jsxs("div", {
className: "month-switcher-container",
children: [
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "上个月",
onClick: prevMonth,
children: /*#__PURE__*/ _jsx(Icon, {
name: "chevronLeft",
size: 18
})
}),
/*#__PURE__*/ _jsx("span", {
className: "month-switcher__label",
children: formatMonth(currentMonth)
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "下个月",
onClick: nextMonth,
children: /*#__PURE__*/ _jsx(Icon, {
name: "chevronRight",
size: 18
})
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "header-right-actions",
children: /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "设置",
onClick: ()=>router.push("/settings"),
children: /*#__PURE__*/ _jsx(Icon, {
name: "settings",
size: 18
})
})
})
]
});
const modalHeaderContent = /*#__PURE__*/ _jsxs("div", {
className: "header-center-container",
children: [
/*#__PURE__*/ _jsx("div", {
className: "header-left-actions",
children: /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "关闭",
onClick: closeModal,
children: /*#__PURE__*/ _jsx(Icon, {
name: "chevronLeft",
size: 18
})
})
}),
/*#__PURE__*/ _jsx("div", {
className: "modal-title-container",
children: /*#__PURE__*/ _jsx("span", {
className: "modal-title",
children: editingRecord ? "编辑记录" : "新增记录"
})
}),
/*#__PURE__*/ _jsx("div", {
className: "header-right-actions"
})
]
});
return /*#__PURE__*/ _jsxs(AppShell, {
headerContent: modalOpen ? modalHeaderContent : homeHeaderContent,
compactHeader: true,
hideNav: modalOpen,
children: [
/*#__PURE__*/ _jsx("section", {
className: "dashboard-hero card",
children: /*#__PURE__*/ _jsxs("div", {
className: "stats-grid stats-grid--hero",
children: [
/*#__PURE__*/ _jsxs("button", {
type: "button",
className: `stat-card ${typeFilter === "income" ? "active" : ""}`,
onClick: ()=>handleCardClick("income"),
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "æ”¶å…¥"
}),
/*#__PURE__*/ _jsxs("span", {
className: "value income",
children: [
"+",
formatMoney(stats.income)
]
})
]
}),
/*#__PURE__*/ _jsxs("button", {
type: "button",
className: `stat-card ${typeFilter === "expense" ? "active" : ""}`,
onClick: ()=>handleCardClick("expense"),
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "支出"
}),
/*#__PURE__*/ _jsxs("span", {
className: "value expense",
children: [
"-",
formatMoney(stats.expense)
]
})
]
}),
/*#__PURE__*/ _jsxs("button", {
type: "button",
className: "stat-card stat-card--balance",
onClick: ()=>handleCardClick("all"),
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "结余"
}),
/*#__PURE__*/ _jsx("span", {
className: "value",
children: formatMoney(stats.balance)
})
]
})
]
})
}),
/*#__PURE__*/ _jsxs("section", {
className: "card section-card",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "section-heading section-heading--compact",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: "记录列表"
}),
/*#__PURE__*/ _jsx("h2", {
children: typeFilter === "all" ? "全部记录" : typeFilter === "income" ? "仅看收入" : "仅看支出"
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: openAddModal,
children: /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "plus",
size: 16
}),
"新增记录"
]
})
})
]
}),
loading ? /*#__PURE__*/ _jsx("div", {
className: "loading-state",
children: "加载中..."
}) : records.length === 0 ? /*#__PURE__*/ _jsxs("div", {
className: "empty-state empty-state--card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ _jsx(Icon, {
name: "info",
size: 24
})
}),
/*#__PURE__*/ _jsx("p", {
children: "暂无记录,点击上方按钮添加。"
})
]
}) : /*#__PURE__*/ _jsx("div", {
className: "records-list records-list--flush",
children: sortedDates.map((date)=>/*#__PURE__*/ _jsxs("div", {
className: "date-group",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "date-label",
children: [
/*#__PURE__*/ _jsx("span", {
children: new Date(date).toLocaleDateString("zh-CN", {
month: "short",
day: "numeric",
weekday: "short"
})
}),
/*#__PURE__*/ _jsxs("span", {
className: "day-expense",
children: [
"支出 ",
formatMoney(getDayExpense(date))
]
})
]
}),
groupedRecords[date].map((record)=>{
const categories = DEFAULT_CATEGORIES[record.type];
const cat = categories.find((item)=>item.name === record.category) || {
icon: "\uD83D\uDCDD"
};
return /*#__PURE__*/ _jsxs("button", {
type: "button",
className: "record-item",
onClick: ()=>openEditModal(record),
children: [
/*#__PURE__*/ _jsxs("div", {
className: "record-left",
children: [
/*#__PURE__*/ _jsx("div", {
className: "record-icon",
children: cat.icon
}),
/*#__PURE__*/ _jsxs("div", {
className: "record-info",
children: [
/*#__PURE__*/ _jsx("div", {
className: "record-category",
children: record.category
}),
record.note && /*#__PURE__*/ _jsx("div", {
className: "record-note",
children: record.note
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: `record-amount ${record.type}`,
children: [
record.type === "income" ? "+" : "-",
formatMoney(record.amount)
]
})
]
}, record.id);
})
]
}, date))
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "fab",
"aria-label": "新增记录",
onClick: openAddModal,
children: /*#__PURE__*/ _jsx(Icon, {
name: "plus",
size: 24
})
}),
modalOpen && /*#__PURE__*/ _jsx("div", {
className: "modal-overlay modal-overlay--fullscreen",
onClick: closeModal,
children: /*#__PURE__*/ _jsxs("div", {
className: "modal modal--fullscreen",
onClick: (e)=>e.stopPropagation(),
children: [
/*#__PURE__*/ _jsxs("div", {
className: "modal-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: editingRecord ? "编辑记录" : "新增记录"
}),
editingRecord ? /*#__PURE__*/ _jsx("h2", {
children: "更新账目"
}) : null
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button icon-button--ghost",
"aria-label": "关闭弹窗",
onClick: closeModal,
children: /*#__PURE__*/ _jsx(Icon, {
name: "close",
size: 18
})
})
]
}),
formError && /*#__PURE__*/ _jsx("div", {
className: "error-msg",
children: formError
}),
/*#__PURE__*/ _jsxs("form", {
onSubmit: handleSubmit,
children: [
/*#__PURE__*/ _jsxs("div", {
className: "type-switch",
children: [
/*#__PURE__*/ _jsx("button", {
type: "button",
className: `type-btn expense ${formData.type === "expense" ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
type: "expense",
category: ""
}),
disabled: submitting || deleting,
children: "支出"
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: `type-btn income ${formData.type === "income" ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
type: "income",
category: ""
}),
disabled: submitting || deleting,
children: "æ”¶å…¥"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
htmlFor: "record-amount",
children: "金é¢"
}),
/*#__PURE__*/ _jsx("input", {
id: "record-amount",
type: "number",
className: "amount-input",
value: formData.amount,
onChange: (e)=>setFormData({
...formData,
amount: e.target.value
}),
placeholder: "0.00",
step: "0.01",
required: true,
disabled: submitting || deleting
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
children: "分类"
}),
/*#__PURE__*/ _jsx("div", {
className: "category-grid",
children: DEFAULT_CATEGORIES[formData.type].map((cat)=>/*#__PURE__*/ _jsxs("button", {
type: "button",
className: `category-btn ${formData.category === cat.name ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
category: cat.name
}),
disabled: submitting || deleting,
children: [
/*#__PURE__*/ _jsx("span", {
className: "icon",
children: cat.icon
}),
/*#__PURE__*/ _jsx("span", {
children: cat.name
})
]
}, cat.name))
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
children: "日期"
}),
/*#__PURE__*/ _jsxs("div", {
className: "datetime-picker",
children: [
/*#__PURE__*/ _jsx("input", {
type: "date",
value: formData.date,
onChange: (e)=>setFormData({
...formData,
date: e.target.value
}),
required: true,
disabled: submitting || deleting
}),
/*#__PURE__*/ _jsx("input", {
type: "time",
value: formData.time || "00:00",
onChange: (e)=>setFormData({
...formData,
time: e.target.value
}),
disabled: submitting || deleting
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
htmlFor: "record-note",
children: "备注(å¯é€‰ï¼‰"
}),
/*#__PURE__*/ _jsx("input", {
id: "record-note",
type: "text",
value: formData.note,
onChange: (e)=>setFormData({
...formData,
note: e.target.value
}),
placeholder: "添加备注...",
disabled: submitting || deleting
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ _jsx("button", {
type: "submit",
className: "btn btn-primary",
disabled: submitting || deleting,
children: submitting ? /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
}),
editingRecord && /*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-danger",
onClick: handleDelete,
disabled: submitting || deleting,
children: deleting ? "删除中..." : "删除"
})
]
})
]
})
]
})
})
]
});
}
exportsTypeŽsideEffectFree‰namespace 
javascript/auto…alias§Œserver-only$Œclient-only$Ÿnext/dist/compiled/client-only$žnext/dist/compiled/server-only¤next/dist/compiled/server-only/index¤next/dist/compiled/client-only/indexÿþ

ò`‰cacheable†parsedfileDependencies“contextDependencies“missingDependenciesbuildDependenciesvalueDependenciesĆassetsŠassetsInfo†strictexportsArgument”topLevelDeclarationsˆsnapshot ˜webpack/lib/util/LazySetÙ/opt/accountbook/frontend/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js ™webpack/DefinePlugin_hashˆ3b076c4394d7e3cb2ffaeb60 “__webpack_exports__‰*default*„Home ´’¸ÍyB ` ·webpack/lib/dependencies/HarmonyCompatibilityDependency
dÿÿý¨webpack/lib/dependencies/ConstDependency`?
`?a@l
`,`m@•
`(Aþ
`hAÿ6
`7A7e
`.Af
`+AÉ
`7
`;¶webpack/lib/dependencies/HarmonyExportHeaderDependency A2€ A2€
 @ˆºwebpack/lib/dependencies/HarmonyImportSideEffectDependencyreact/jsx-runtimeÿ
`?
`,next/routerÿ
`(Š../lib/apiÿ
`h../lib/categoriesÿ
`7../components/AppShellÿ
`.“../components/iconsÿ
`+../components/ToastProviderÿ
`7 ../components/ConfirmProviderÿ
`;¹webpack/lib/dependencies/HarmonyExportSpecifierDependency`Ó‡default
¹webpack/lib/dependencies/HarmonyImportSpecifierDependencya ‰useRouterþ A:C  
úëëý
c   ˆuseToastþ Aai  úððþ
c  " ŠuseConfirmþ A…  õ ííþ
c

" ˆuseStateþ A¿Ç  ðdÿÿÿdÿÿÿþ
c,4 ûú   ì`ÿÿÿ`ÿÿÿþ
c(0 ÷ö A08  è\ÿÿÿ\ÿÿÿþ
c"* óò A\d  äXÿÿÿXÿÿÿþ
c& ïî ×  àTÿÿÿTÿÿÿþ
c&. ëê A  ÜPÿÿÿPÿÿÿþ
c.6 çæ A@H  ØLÿÿÿLÿÿÿþ
c"* ãâ Ax  ÔHÿÿÿHÿÿÿþ
c(0 ßÞ µ  ÐDÿÿÿDÿÿÿþ
c$, ÛÚ ì  Ì@ÿÿÿ@ÿÿÿþ
c&. ×Ö A  È<ÿÿÿ<ÿÿÿþ
c$, ŠgetRecordsþ A|  ñ±þ
c44 ˆgetStatsþ A¿Ç  ¾¬¬þ
c55 ŒupdateRecordþ A%1  ¹§§þ
czz" ŒcreateRecordþ ß  ´¢¢þ
c" ŒdeleteRecordþ ¸  ¯þ
@™`@™` „jsxs…_jsxs A!&  ©þ
`,@°`1 ƒjsx„_jsx  4£ŒŒþ
``ûü ø 4 þ
`(@µ`,øù ê 4þ
`,@º`0 „Iconþ ï 4˜ŒŒþ
`1@º`5 éê A  }ÿÿÿ}ÿÿÿþ
``ìí A 4zÿÿÿzÿÿÿþ
`"@Ã`&éê A  4Žwÿÿÿwÿÿÿþ
`0@È`4òñ A
 4ÿÿÿÿÿÿþ
`5@È`9ãä Ä 4ˆqÿÿÿqÿÿÿþ
`"@Í`&àá A 4nÿÿÿnÿÿÿþ
`"@Ñ`&ÝÞ Auy 4kÿÿÿkÿÿÿþ
`0@Ö`4æå Az~ 4ÿÿÿsÿÿÿsÿÿÿþ
`5@Ö`9ר AGK 4|ÿÿÿeÿÿÿeÿÿÿþ
``ÔÕ ´ 4yÿÿÿbÿÿÿbÿÿÿþ
`(@ß`,ÑÒ ¦  4vÿÿÿ_ÿÿÿ_ÿÿÿþ
`,@ä`0ÚÙ «  4sÿÿÿgÿÿÿgÿÿÿþ
`1@ä`5 ÄÅ Ar!w!  oÿÿÿXÿÿÿXÿÿÿþ
`-@ì`2ÇÈ AÝ!á! 4lÿÿÿUÿÿÿUÿÿÿþ
``ÄÅ AE"I" 4iÿÿÿRÿÿÿRÿÿÿþ
`(@ñ`,ÁÂ A%#)# 4fÿÿÿOÿÿÿOÿÿÿþ
`,@ö`0ÊÉ A*#.# 4cÿÿÿWÿÿÿWÿÿÿþ
`1@ö`5»¼ AÔ#Ø# 4`ÿÿÿIÿÿÿIÿÿÿþ
``¸¹ A>$B$ 4]ÿÿÿFÿÿÿFÿÿÿþ
`(@þ`,µ Aö$ú$ 4ZÿÿÿCÿÿÿCÿÿÿþ
@`@` «¬ Ap%u%  Vÿÿÿ?ÿÿÿ?ÿÿÿþ
@`@` OÿÿÿˆAppShell Av%~% 4QÿÿÿCÿÿÿCÿÿÿþ
@`@`'©ª A4&8& 4Nÿÿÿ7ÿÿÿ7ÿÿÿþ
@
`@
` Ÿ  A &¥&  Jÿÿÿ3ÿÿÿ3ÿÿÿþ
@`(@`- œ A3'8'  Fÿÿÿ/ÿÿÿ/ÿÿÿþ
@`&@`+žŸ Aj(n( 4Cÿÿÿ,ÿÿÿ,ÿÿÿþ
@`.@`2  A6);)  ?ÿÿÿ(ÿÿÿ(ÿÿÿþ
@`.@`3  AÍ*Ò*  ;ÿÿÿ$ÿÿÿ$ÿÿÿþ
@$`&@$`+ A,
, 48ÿÿÿ!ÿÿÿ!ÿÿÿþ
@)`.@)`2 Š AÒ,×,  4ÿÿÿÿÿÿÿÿÿþ
@-`.@-`3  Ak.p.  0ÿÿÿÿÿÿÿÿÿþ
@6`&@6`+ˆ A‡/‹/ 4-ÿÿÿÿÿÿÿÿÿþ
@;`.@;`2 AS0W0 4*ÿÿÿÿÿÿÿÿÿþ
@?`.@?`2 {ÿÿÿ|ÿÿÿ A’1—1  &ÿÿÿÿÿÿÿÿÿþ
@H`@H` wÿÿÿxÿÿÿ A22  "ÿÿÿ ÿÿÿ ÿÿÿþ
@K`"@K`' sÿÿÿtÿÿÿ A¿2Ä2  ÿÿÿÿÿÿÿÿÿþ
@N`*@N`/vÿÿÿwÿÿÿ A,303 4ÿÿÿÿÿÿÿÿÿþ
@P`2@P`6sÿÿÿtÿÿÿ A 4
4 4ÿÿÿÿÿÿÿÿÿþ
@T`2@T`6pÿÿÿqÿÿÿ A%5)5 4ÿÿÿþþÿÿþþÿÿþ
@Y`*@Y`. fÿÿÿgÿÿÿ A 6%6  ÿÿÿúþÿÿúþÿÿþ
@]`8@]`=iÿÿÿjÿÿÿ A×6Û6 4ÿÿÿ÷þÿÿ÷þÿÿþ
@``6@``:rÿÿÿqÿÿÿ AÜ6à6 4 ÿÿÿÿþÿÿÿþÿÿþ
@``;@``?cÿÿÿdÿÿÿ At8x8 4ÿÿÿñþÿÿñþÿÿþ
@j`,@j`0 YÿÿÿZÿÿÿ A9$9  ÿÿÿíþÿÿíþÿÿþ
@m`>@m`C\ÿÿÿ]ÿÿÿ AÀ9Ä9 4ÿÿÿêþÿÿêþÿÿþ
@p`*@p`.YÿÿÿZÿÿÿ AF:J: 4þþÿÿçþÿÿçþÿÿþ
@r`8@r`<bÿÿÿaÿÿÿ AK:O: 4ûþÿÿïþÿÿïþÿÿþ
@r`=@r`ASÿÿÿTÿÿÿ A;#; 4øþÿÿáþÿÿáþÿÿþ
@w`*@w`.PÿÿÿQÿÿÿ AÆ;Ê; 4õþÿÿÞþÿÿÞþÿÿþ
@{`'@{`+ FÿÿÿGÿÿÿ Ac<h<  ñþÿÿÚþÿÿÚþÿÿþ
@}`H@}`M BÿÿÿCÿÿÿ A ==  íþÿÿÖþÿÿÖþÿÿþ
@€`2@€`7EÿÿÿFÿÿÿ AÇ=Ë= 4êþÿÿÓþÿÿÓþÿÿþ
`:@ƒ`> ;ÿÿÿ<ÿÿÿ A§?¬?  æþÿÿÏþÿÿÏþÿÿþ
`:@Š`? DEFAULT_CATEGORIESþ ABB 4áþÿÿÑþÿÿÑþÿÿþ
@”`;@”`M 2ÿÿÿ3ÿÿÿ A>CCC  ÝþÿÿÆþÿÿÆþÿÿþ
@˜`=@˜`B .ÿÿÿ/ÿÿÿ A˜DD  ÙþÿÿÂþÿÿÂþÿÿþ
@`>@`C1ÿÿÿ2ÿÿÿ A{EE 4Öþÿÿ¿þÿÿ¿þÿÿþ
@ `F@ `J 'ÿÿÿ(ÿÿÿ A°FµF  Òþÿÿ»þÿÿ»þÿÿþ
`F@¤`K*ÿÿÿ+ÿÿÿ A«G¯G 4Ïþÿÿ¸þÿÿ¸þÿÿþ
`N@§`R'ÿÿÿ(ÿÿÿ AII 4Ìþÿÿµþÿÿµþÿÿþ
`]@«`a ÿÿÿÿÿÿ ADKIK  Èþÿÿ±þÿÿ±þÿÿþ
`>@³`C ÿÿÿ!ÿÿÿ A3N7N 4Åþÿÿ®þÿÿ®þÿÿþ
``ÿÿÿÿÿÿ AûNÿN 4Âþÿÿ«þÿÿ«þÿÿþ
`(@Ç`,&ÿÿÿ%ÿÿÿ AOO 4¿þÿÿ³þÿÿ³þÿÿþ
`-@Ç`1ÿÿÿÿÿÿ A‘O•O 4¼þÿÿ¥þÿÿ¥þÿÿþ
`'@Ì`+ 
ÿÿÿÿÿÿ A2P7P  ¸þÿÿ¡þÿÿ¡þÿÿþ
`(@Ï`-  ÿÿÿ
ÿÿÿ AøPýP  ´þÿÿþÿÿþÿÿþ
`&@Ó`+ ÿÿÿÿÿÿ A”Q™Q  °þÿÿ™þÿÿ™þÿÿþ
`.@Ö`3ÿÿÿ ÿÿÿ A R
R 4­þÿÿ–þÿÿ–þÿÿþ
`6@Ø`:ÿÿÿÿÿÿ AS#S 4ªþÿÿ“þÿÿ“þÿÿþ
`F@Ü`Jÿÿÿÿÿÿ ATT 4§þÿÿþÿÿþÿÿþ
`.@á`2ÿþÿÿÿÿÿ AXU\U 4¤þÿÿþÿÿþÿÿþ
`<@æ`@ÿÿÿÿÿÿ A]UaU 4¡þÿÿ•þÿÿ•þÿÿþ
`A@æ`Eùþÿÿúþÿÿ A„VˆV 4žþÿÿ‡þÿÿ‡þÿÿþ
`3@í`7 ïþÿÿðþÿÿ A8W=W  šþÿÿƒþÿÿƒþÿÿþ
`&@ñ`+ ëþÿÿìþÿÿ AÒW×W  –þÿÿþÿÿþÿÿþ
`.@ô`3îþÿÿïþÿÿ A…X‰X 4“þÿÿ|þÿÿ|þÿÿþ
`6@÷`:ëþÿÿìþÿÿ Ay[}[ 4þÿÿyþÿÿyþÿÿþ
@`6@`: áþÿÿâþÿÿ A«^°^  Œþÿÿuþÿÿuþÿÿþ
@`.@`3äþÿÿåþÿÿ A]_a_ 4‰þÿÿrþÿÿrþÿÿþ
@`6@`:áþÿÿâþÿÿ AP`T` 4†þÿÿoþÿÿoþÿÿþ
@`6@`: ×þÿÿØþÿÿ Add  ‚þÿÿkþÿÿkþÿÿþ
@&`.@&`3ÚþÿÿÛþÿÿ AÊdÎd 4þÿÿhþÿÿhþÿÿþ
@)`6@)`:×þÿÿØþÿÿ Awe{e 4|þÿÿeþÿÿeþÿÿþ
@,`6@,`: Aff 4yþÿÿiþÿÿiþÿÿþ
@.`6@.`H ÊþÿÿËþÿÿ A>fCf  uþÿÿ^þÿÿ^þÿÿþ
@.`q@.`vÍþÿÿÎþÿÿ Aii 4rþÿÿ[þÿÿ[þÿÿþ
@7`F@7`JÊþÿÿËþÿÿ ACjGj 4oþÿÿXþÿÿXþÿÿþ
@;`F@;`J ÀþÿÿÁþÿÿ Aókøk  kþÿÿTþÿÿTþÿÿþ
@C`.@C`3ÃþÿÿÄþÿÿ A¥l©l 4hþÿÿQþÿÿQþÿÿþ
@F`6@F`: ¹þÿÿºþÿÿ ARmWm  dþÿÿMþÿÿMþÿÿþ
@I`6@I`;¼þÿÿ½þÿÿ A!n%n 4aþÿÿJþÿÿJþÿÿþ
@L`>@L`B¹þÿÿºþÿÿ Aïpóp 4^þÿÿGþÿÿGþÿÿþ
@V`>@V`B ¯þÿÿ°þÿÿ Att  ZþÿÿCþÿÿCþÿÿþ
@c`.@c`3²þÿÿ³þÿÿ AÈtÌt 4Wþÿÿ@þÿÿ@þÿÿþ
@f`6@f`:¯þÿÿ°þÿÿ A½uÁu 4Tþÿÿ=þÿÿ=þÿÿþ
@j`6@j`: ¥þÿÿ¦þÿÿ AÃxÈx  Pþÿÿ9þÿÿ9þÿÿþ
@w`.@w`3¨þÿÿ©þÿÿ Axy|y 4Mþÿÿ6þÿÿ6þÿÿþ
@z`6@z`: žþÿÿŸþÿÿ A®z³z  Iþÿÿ2þÿÿ2þÿÿþ
@~`Q@~`V¡þÿÿ¢þÿÿ A‰{{ 4Fþÿÿ/þÿÿ/þÿÿþ
@`B@`Fªþÿÿ©þÿÿ AŽ{’{ 4Cþÿÿ7þÿÿ7þÿÿþ
@`G@`K›þÿÿœþÿÿ AÂ}Æ} 4@þÿÿ)þÿÿ)þÿÿþ
`G@Š`K —webpack/lib/ModuleGraph“RestoreProvidedData

žýÿÿˆprovidedcanMangleProvideterminalBindingexportsInfo1þÿÿ

‡sources„data“runtimeRequirementsŠjavascript«webpack/lib/util/registerExternalSerializerœwebpack-sources/CachedSource ð«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourceÃ
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
config: () => (/* binding */ config),
"default": () => (/* binding */ next_route_loaderkind_PAGES_page_2F_preferredRegion_absolutePagePath_private_next_pages_2Findex_js_absoluteAppPath_private_next_pages_2F_app_js_absoluteDocumentPath_next_2Fdist_2Fpages_2F_document_middlewareConfigBase64_e30_3D_),
getServerSideProps: () => (/* binding */ getServerSideProps),
getStaticPaths: () => (/* binding */ getStaticPaths),
getStaticProps: () => (/* binding */ getStaticProps),
reportWebVitals: () => (/* binding */ reportWebVitals),
routeModule: () => (/* binding */ routeModule),
unstable_getServerProps: () => (/* binding */ unstable_getServerProps),
unstable_getServerSideProps: () => (/* binding */ unstable_getServerSideProps),
unstable_getStaticParams: () => (/* binding */ unstable_getStaticParams),
unstable_getStaticPaths: () => (/* binding */ unstable_getStaticPaths),
unstable_getStaticProps: () => (/* binding */ unstable_getStaticProps)
});
// NAMESPACE OBJECT: ./pages/index.js
var pages_namespaceObject = {};
__webpack_require__.r(pages_namespaceObject);
__webpack_require__.d(pages_namespaceObject, {
"default": () => (Home)
});
// EXTERNAL MODULE: ./node_modules/next/dist/server/future/route-modules/pages/module.compiled.js
var module_compiled = __webpack_require__(7093);
// EXTERNAL MODULE: ./node_modules/next/dist/server/future/route-kind.js
var route_kind = __webpack_require__(5244);
// EXTERNAL MODULE: ./node_modules/next/dist/build/templates/helpers.js
var helpers = __webpack_require__(1323);
// EXTERNAL MODULE: ./node_modules/next/dist/pages/_document.js
var _document = __webpack_require__(2899);
var _document_default = /*#__PURE__*/__webpack_require__.n(_document);
// EXTERNAL MODULE: ./pages/_app.js
var _app = __webpack_require__(3414);
// EXTERNAL MODULE: external "react/jsx-runtime"
var jsx_runtime_ = __webpack_require__(997);
// EXTERNAL MODULE: external "react"
var external_react_ = __webpack_require__(6689);
// EXTERNAL MODULE: ./node_modules/next/router.js
var next_router = __webpack_require__(1163);
// EXTERNAL MODULE: ./lib/api.js
var api = __webpack_require__(7751);
// EXTERNAL MODULE: ./lib/categories.js
var lib_categories = __webpack_require__(2204);
// EXTERNAL MODULE: ./components/AppShell.js
var AppShell = __webpack_require__(1712);
// EXTERNAL MODULE: ./components/icons.js
var icons = __webpack_require__(349);
// EXTERNAL MODULE: ./components/ToastProvider.js
var ToastProvider = __webpack_require__(4190);
// EXTERNAL MODULE: ./components/ConfirmProvider.js
var ConfirmProvider = __webpack_require__(4407);
;// CONCATENATED MODULE: ./pages/index.js
«webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource«webpack/lib/util/registerExternalSerializerœwebpack-sources/CachedSource Œ«webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourceimport { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import { isLoggedIn, getRecords, getStats, createRecord, updateRecord, deleteRecord } from "../lib/api";
import { DEFAULT_CATEGORIES } from "../lib/categories";
import AppShell from "../components/AppShell";
import { Icon } from "../components/icons";
import { useToast } from "../components/ToastProvider";
import { useConfirm } from "../components/ConfirmProvider";
export default function Home() {
const router = useRouter();
const { showToast } = useToast();
const { confirm } = useConfirm();
const [currentMonth, setCurrentMonth] = useState(new Date());
const [typeFilter, setTypeFilter] = useState("all");
const [records, setRecords] = useState([]);
const [stats, setStats] = useState({
income: 0,
expense: 0,
balance: 0
});
const [modalOpen, setModalOpen] = useState(false);
const [editingRecord, setEditingRecord] = useState(null);
const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false);
const [deleting, setDeleting] = useState(false);
const [formError, setFormError] = useState("");
const [formData, setFormData] = useState({
type: "expense",
amount: "",
category: "",
date: new Date().toISOString().split("T")[0],
time: new Date().toTimeString().slice(0, 5),
note: ""
});
null;
const getMonthStr = (date)=>`${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}`;
const formatMoney = (num)=>(num || 0).toFixed(2);
const formatMonth = (date)=>`${date.getFullYear()}年${date.getMonth() + 1}月`;
const resetForm = ()=>({
type: "expense",
amount: "",
category: "",
date: new Date().toISOString().split("T")[0],
time: new Date().toTimeString().slice(0, 5),
note: ""
});
const loadData = async ()=>{
setLoading(true);
try {
const [recordsData, statsData] = await Promise.all([
getRecords(getMonthStr(currentMonth), typeFilter),
getStats(getMonthStr(currentMonth))
]);
setRecords(recordsData);
setStats(statsData);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const prevMonth = ()=>{
const newDate = new Date(currentMonth);
newDate.setMonth(newDate.getMonth() - 1);
setCurrentMonth(newDate);
};
const nextMonth = ()=>{
const newDate = new Date(currentMonth);
newDate.setMonth(newDate.getMonth() + 1);
setCurrentMonth(newDate);
};
const handleCardClick = (type)=>{
setTypeFilter(type === typeFilter ? "all" : type);
};
const openAddModal = ()=>{
setEditingRecord(null);
setFormData(resetForm());
setFormError("");
setModalOpen(true);
};
const openEditModal = (record)=>{
const [datePart, timePart] = record.date.split(" ");
setEditingRecord(record);
setFormData({
type: record.type,
amount: record.amount.toString(),
category: record.category,
date: datePart,
time: timePart || "00:00",
note: record.note || ""
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting || deleting) return;
setModalOpen(false);
setEditingRecord(null);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.amount || !formData.category || !formData.date) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
const data = {
type: formData.type,
amount: parseFloat(formData.amount),
category: formData.category,
date: `${formData.date} ${formData.time || "00:00"}`,
note: formData.note
};
if (editingRecord) {
await updateRecord(editingRecord.id, data);
showToast("记录已更新", {
tone: "success"
});
} else {
await createRecord(data);
showToast("记录已添加", {
tone: "success"
});
}
closeModal();
await loadData();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async ()=>{
if (!editingRecord) return;
const shouldDelete = await confirm({
title: "删除这æ¡è®°å½•?",
description: "删除åŽå°†æ— æ³•æ¢å¤ï¼Œè¯·ç¡®è®¤æ˜¯å¦ç»§ç»­ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
setDeleting(true);
try {
await deleteRecord(editingRecord.id);
closeModal();
showToast("记录已删除", {
tone: "success"
});
await loadData();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setDeleting(false);
}
};
const groupedRecords = records.reduce((groups, record)=>{
const date = record.date.split(" ")[0];
if (!groups[date]) groups[date] = [];
groups[date].push(record);
return groups;
}, {});
const sortedDates = Object.keys(groupedRecords).sort((a, b)=>b.localeCompare(a));
const getDayExpense = (date)=>groupedRecords[date].filter((record)=>record.type === "expense").reduce((sum, record)=>sum + record.amount, 0);
const homeHeaderContent = /*#__PURE__*/ _jsxs("div", {
className: "header-center-container",
children: [
/*#__PURE__*/ _jsx("div", {
className: "header-left-actions",
children: /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "æœç´¢è®°å½•",
onClick: ()=>router.push("/search"),
children: /*#__PURE__*/ _jsx(Icon, {
name: "search",
size: 18
})
})
}),
/*#__PURE__*/ _jsxs("div", {
className: "month-switcher-container",
children: [
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "上个月",
onClick: prevMonth,
children: /*#__PURE__*/ _jsx(Icon, {
name: "chevronLeft",
size: 18
})
}),
/*#__PURE__*/ _jsx("span", {
className: "month-switcher__label",
children: formatMonth(currentMonth)
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "下个月",
onClick: nextMonth,
children: /*#__PURE__*/ _jsx(Icon, {
name: "chevronRight",
size: 18
})
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "header-right-actions",
children: /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "设置",
onClick: ()=>router.push("/settings"),
children: /*#__PURE__*/ _jsx(Icon, {
name: "settings",
size: 18
})
})
})
]
});
const modalHeaderContent = /*#__PURE__*/ _jsxs("div", {
className: "header-center-container",
children: [
/*#__PURE__*/ _jsx("div", {
className: "header-left-actions",
children: /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "关闭",
onClick: closeModal,
children: /*#__PURE__*/ _jsx(Icon, {
name: "chevronLeft",
size: 18
})
})
}),
/*#__PURE__*/ _jsx("div", {
className: "modal-title-container",
children: /*#__PURE__*/ _jsx("span", {
className: "modal-title",
children: editingRecord ? "编辑记录" : "新增记录"
})
}),
/*#__PURE__*/ _jsx("div", {
className: "header-right-actions"
})
]
});
return /*#__PURE__*/ _jsxs(AppShell, {
headerContent: modalOpen ? modalHeaderContent : homeHeaderContent,
compactHeader: true,
hideNav: modalOpen,
children: [
/*#__PURE__*/ _jsx("section", {
className: "dashboard-hero card",
children: /*#__PURE__*/ _jsxs("div", {
className: "stats-grid stats-grid--hero",
children: [
/*#__PURE__*/ _jsxs("button", {
type: "button",
className: `stat-card ${typeFilter === "income" ? "active" : ""}`,
onClick: ()=>handleCardClick("income"),
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "æ”¶å…¥"
}),
/*#__PURE__*/ _jsxs("span", {
className: "value income",
children: [
"+",
formatMoney(stats.income)
]
})
]
}),
/*#__PURE__*/ _jsxs("button", {
type: "button",
className: `stat-card ${typeFilter === "expense" ? "active" : ""}`,
onClick: ()=>handleCardClick("expense"),
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "支出"
}),
/*#__PURE__*/ _jsxs("span", {
className: "value expense",
children: [
"-",
formatMoney(stats.expense)
]
})
]
}),
/*#__PURE__*/ _jsxs("button", {
type: "button",
className: "stat-card stat-card--balance",
onClick: ()=>handleCardClick("all"),
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "结余"
}),
/*#__PURE__*/ _jsx("span", {
className: "value",
children: formatMoney(stats.balance)
})
]
})
]
})
}),
/*#__PURE__*/ _jsxs("section", {
className: "card section-card",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "section-heading section-heading--compact",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: "记录列表"
}),
/*#__PURE__*/ _jsx("h2", {
children: typeFilter === "all" ? "全部记录" : typeFilter === "income" ? "仅看收入" : "仅看支出"
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: openAddModal,
children: /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "plus",
size: 16
}),
"新增记录"
]
})
})
]
}),
loading ? /*#__PURE__*/ _jsx("div", {
className: "loading-state",
children: "加载中..."
}) : records.length === 0 ? /*#__PURE__*/ _jsxs("div", {
className: "empty-state empty-state--card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ _jsx(Icon, {
name: "info",
size: 24
})
}),
/*#__PURE__*/ _jsx("p", {
children: "暂无记录,点击上方按钮添加。"
})
]
}) : /*#__PURE__*/ _jsx("div", {
className: "records-list records-list--flush",
children: sortedDates.map((date)=>/*#__PURE__*/ _jsxs("div", {
className: "date-group",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "date-label",
children: [
/*#__PURE__*/ _jsx("span", {
children: new Date(date).toLocaleDateString("zh-CN", {
month: "short",
day: "numeric",
weekday: "short"
})
}),
/*#__PURE__*/ _jsxs("span", {
className: "day-expense",
children: [
"支出 ",
formatMoney(getDayExpense(date))
]
})
]
}),
groupedRecords[date].map((record)=>{
const categories = DEFAULT_CATEGORIES[record.type];
const cat = categories.find((item)=>item.name === record.category) || {
icon: "\uD83D\uDCDD"
};
return /*#__PURE__*/ _jsxs("button", {
type: "button",
className: "record-item",
onClick: ()=>openEditModal(record),
children: [
/*#__PURE__*/ _jsxs("div", {
className: "record-left",
children: [
/*#__PURE__*/ _jsx("div", {
className: "record-icon",
children: cat.icon
}),
/*#__PURE__*/ _jsxs("div", {
className: "record-info",
children: [
/*#__PURE__*/ _jsx("div", {
className: "record-category",
children: record.category
}),
record.note && /*#__PURE__*/ _jsx("div", {
className: "record-note",
children: record.note
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: `record-amount ${record.type}`,
children: [
record.type === "income" ? "+" : "-",
formatMoney(record.amount)
]
})
]
}, record.id);
})
]
}, date))
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "fab",
"aria-label": "新增记录",
onClick: openAddModal,
children: /*#__PURE__*/ _jsx(Icon, {
name: "plus",
size: 24
})
}),
modalOpen && /*#__PURE__*/ _jsx("div", {
className: "modal-overlay modal-overlay--fullscreen",
onClick: closeModal,
children: /*#__PURE__*/ _jsxs("div", {
className: "modal modal--fullscreen",
onClick: (e)=>e.stopPropagation(),
children: [
/*#__PURE__*/ _jsxs("div", {
className: "modal-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: editingRecord ? "编辑记录" : "新增记录"
}),
editingRecord ? /*#__PURE__*/ _jsx("h2", {
children: "更新账目"
}) : null
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button icon-button--ghost",
"aria-label": "关闭弹窗",
onClick: closeModal,
children: /*#__PURE__*/ _jsx(Icon, {
name: "close",
size: 18
})
})
]
}),
formError && /*#__PURE__*/ _jsx("div", {
className: "error-msg",
children: formError
}),
/*#__PURE__*/ _jsxs("form", {
onSubmit: handleSubmit,
children: [
/*#__PURE__*/ _jsxs("div", {
className: "type-switch",
children: [
/*#__PURE__*/ _jsx("button", {
type: "button",
className: `type-btn expense ${formData.type === "expense" ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
type: "expense",
category: ""
}),
disabled: submitting || deleting,
children: "支出"
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: `type-btn income ${formData.type === "income" ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
type: "income",
category: ""
}),
disabled: submitting || deleting,
children: "æ”¶å…¥"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
htmlFor: "record-amount",
children: "金é¢"
}),
/*#__PURE__*/ _jsx("input", {
id: "record-amount",
type: "number",
className: "amount-input",
value: formData.amount,
onChange: (e)=>setFormData({
...formData,
amount: e.target.value
}),
placeholder: "0.00",
step: "0.01",
required: true,
disabled: submitting || deleting
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
children: "分类"
}),
/*#__PURE__*/ _jsx("div", {
className: "category-grid",
children: DEFAULT_CATEGORIES[formData.type].map((cat)=>/*#__PURE__*/ _jsxs("button", {
type: "button",
className: `category-btn ${formData.category === cat.name ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
category: cat.name
}),
disabled: submitting || deleting,
children: [
/*#__PURE__*/ _jsx("span", {
className: "icon",
children: cat.icon
}),
/*#__PURE__*/ _jsx("span", {
children: cat.name
})
]
}, cat.name))
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
children: "日期"
}),
/*#__PURE__*/ _jsxs("div", {
className: "datetime-picker",
children: [
/*#__PURE__*/ _jsx("input", {
type: "date",
value: formData.date,
onChange: (e)=>setFormData({
...formData,
date: e.target.value
}),
required: true,
disabled: submitting || deleting
}),
/*#__PURE__*/ _jsx("input", {
type: "time",
value: formData.time || "00:00",
onChange: (e)=>setFormData({
...formData,
time: e.target.value
}),
disabled: submitting || deleting
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
htmlFor: "record-note",
children: "备注(å¯é€‰ï¼‰"
}),
/*#__PURE__*/ _jsx("input", {
id: "record-note",
type: "text",
value: formData.note,
onChange: (e)=>setFormData({
...formData,
note: e.target.value
}),
placeholder: "添加备注...",
disabled: submitting || deleting
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ _jsx("button", {
type: "submit",
className: "btn btn-primary",
disabled: submitting || deleting,
children: submitting ? /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
}),
editingRecord && /*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-danger",
onClick: handleDelete,
disabled: submitting || deleting,
children: deleting ? "删除中..." : "删除"
})
]
})
]
})
]
})
})
]
});
}
@ˆc>@km_”ýÿ57dfÈÊ:BahŽ¿Æý07\cÏÖ_@Gx­´äë|¿Æ%0ÓÞ¬·!%Œô÷æéëî_” 
ÀÃuxz}GJ°³¢ ¥ § ª r!v!Ý!à!E"H"%#(#*#_-#Ô#×#>$A$ö$ù$p%t%v%}%4&7& &¤&3'7'j(m(6):)Í*Ñ*, ,Ò,Ö,k.o.‡/Š/S0_V01122¿2Ã2,3/3 4 4%5(5 6$6×6Ú6Ü6ß6t8w89#9À9Ã9F:I:K:N:;";Æ;_É;c<g< =
=Ç=Ê=§?«?BB>CBC˜DœD{E~E°F´F«G®GIIDKHK3N6NûNþNOOO_”O2P6PøPüP”Q˜Q R RS"STTXU[U]U`U„V‡V8W<WÒWÖW…XˆXy[|[«^¯^]_`_P`_S`ddÊdÍdwezeff>fBfiiCjFjók÷k¥l¨lRmVm!n$nïpòpttÈtËt½uÀuÃxJÇxxy{y®z²z‰{Œ{Ž{‘{Â}Å}×__WEBPACK_MODULE_REFERENCE__7_5b22757365526f75746572225d_call_directImport_asiSafe1__._Ö__WEBPACK_MODULE_REFERENCE__12_5b22757365546f617374225d_call_directImport_asiSafe1__._Ú__WEBPACK_MODULE_REFERENCE__13_5b22757365436f6e6669726d225d_call_directImport_asiSafe1__._Õ__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._ÿÿÿÿÿÿÿÿÿÿÙ__WEBPACK_MODULE_REFERENCE__8_5b226765745265636f726473225d_call_directImport_asiSafe1__._Õ__WEBPACK_MODULE_REFERENCE__8_5b226765745374617473225d_call_directImport_asiSafe1__._Ý__WEBPACK_MODULE_REFERENCE__8_5b227570646174655265636f7264225d_call_directImport_asiSafe1__._Ý__WEBPACK_MODULE_REFERENCE__8_5b226372656174655265636f7264225d_call_directImport_asiSafe1__._Ý__WEBPACK_MODULE_REFERENCE__8_5b2264656c6574655265636f7264225d_call_directImport_asiSafe1__._Í__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._Æ__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._ÿÿÉ__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._ýþþÿþþþÿþþþÿýþþþÿþþþýÏ__WEBPACK_MODULE_REFERENCE__10_5b2264656661756c74225d_directImport_asiSafe1__._ýüüýüüýüüýýüüüýýýüýþýüýýþýýüüýüä__WEBPACK_MODULE_REFERENCE__9_5b2244454641554c545f43415445474f52494553225d_directImport_asiSafe1__._ûûüûüüûüüýüûûûüüüüýüûûüüûüüûüüÿûüüûüûüüûüüûüûüýü†buffer†source„size„maps„hashê¡
function Home() {
const router = __WEBPACK_MODULE_REFERENCE__7_5b22757365526f75746572225d_call_directImport_asiSafe1__._();
const { showToast } = __WEBPACK_MODULE_REFERENCE__12_5b22757365546f617374225d_call_directImport_asiSafe1__._();
const { confirm } = __WEBPACK_MODULE_REFERENCE__13_5b22757365436f6e6669726d225d_call_directImport_asiSafe1__._();
const [currentMonth, setCurrentMonth] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._(new Date());
const [typeFilter, setTypeFilter] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._("all");
const [records, setRecords] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._([]);
const [stats, setStats] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._({
income: 0,
expense: 0,
balance: 0
});
const [modalOpen, setModalOpen] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._(false);
const [editingRecord, setEditingRecord] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._(null);
const [loading, setLoading] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._(true);
const [submitting, setSubmitting] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._(false);
const [deleting, setDeleting] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._(false);
const [formError, setFormError] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._("");
const [formData, setFormData] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._({
type: "expense",
amount: "",
category: "",
date: new Date().toISOString().split("T")[0],
time: new Date().toTimeString().slice(0, 5),
note: ""
});
null;
const getMonthStr = (date)=>`${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}`;
const formatMoney = (num)=>(num || 0).toFixed(2);
const formatMonth = (date)=>`${date.getFullYear()}年${date.getMonth() + 1}月`;
const resetForm = ()=>({
type: "expense",
amount: "",
category: "",
date: new Date().toISOString().split("T")[0],
time: new Date().toTimeString().slice(0, 5),
note: ""
});
const loadData = async ()=>{
setLoading(true);
try {
const [recordsData, statsData] = await Promise.all([
__WEBPACK_MODULE_REFERENCE__8_5b226765745265636f726473225d_call_directImport_asiSafe1__._(getMonthStr(currentMonth), typeFilter),
__WEBPACK_MODULE_REFERENCE__8_5b226765745374617473225d_call_directImport_asiSafe1__._(getMonthStr(currentMonth))
]);
setRecords(recordsData);
setStats(statsData);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const prevMonth = ()=>{
const newDate = new Date(currentMonth);
newDate.setMonth(newDate.getMonth() - 1);
setCurrentMonth(newDate);
};
const nextMonth = ()=>{
const newDate = new Date(currentMonth);
newDate.setMonth(newDate.getMonth() + 1);
setCurrentMonth(newDate);
};
const handleCardClick = (type)=>{
setTypeFilter(type === typeFilter ? "all" : type);
};
const openAddModal = ()=>{
setEditingRecord(null);
setFormData(resetForm());
setFormError("");
setModalOpen(true);
};
const openEditModal = (record)=>{
const [datePart, timePart] = record.date.split(" ");
setEditingRecord(record);
setFormData({
type: record.type,
amount: record.amount.toString(),
category: record.category,
date: datePart,
time: timePart || "00:00",
note: record.note || ""
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting || deleting) return;
setModalOpen(false);
setEditingRecord(null);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.amount || !formData.category || !formData.date) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
const data = {
type: formData.type,
amount: parseFloat(formData.amount),
category: formData.category,
date: `${formData.date} ${formData.time || "00:00"}`,
note: formData.note
};
if (editingRecord) {
await __WEBPACK_MODULE_REFERENCE__8_5b227570646174655265636f7264225d_call_directImport_asiSafe1__._(editingRecord.id, data);
showToast("记录已更新", {
tone: "success"
});
} else {
await __WEBPACK_MODULE_REFERENCE__8_5b226372656174655265636f7264225d_call_directImport_asiSafe1__._(data);
showToast("记录已添加", {
tone: "success"
});
}
closeModal();
await loadData();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async ()=>{
if (!editingRecord) return;
const shouldDelete = await confirm({
title: "删除这æ¡è®°å½•?",
description: "删除åŽå°†æ— æ³•æ¢å¤ï¼Œè¯·ç¡®è®¤æ˜¯å¦ç»§ç»­ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
setDeleting(true);
try {
await __WEBPACK_MODULE_REFERENCE__8_5b2264656c6574655265636f7264225d_call_directImport_asiSafe1__._(editingRecord.id);
closeModal();
showToast("记录已删除", {
tone: "success"
});
await loadData();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setDeleting(false);
}
};
const groupedRecords = records.reduce((groups, record)=>{
const date = record.date.split(" ")[0];
if (!groups[date]) groups[date] = [];
groups[date].push(record);
return groups;
}, {});
const sortedDates = Object.keys(groupedRecords).sort((a, b)=>b.localeCompare(a));
const getDayExpense = (date)=>groupedRecords[date].filter((record)=>record.type === "expense").reduce((sum, record)=>sum + record.amount, 0);
const homeHeaderContent = /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "header-center-container",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "header-left-actions",
children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("button", {
type: "button",
className: "icon-button",
"aria-label": "æœç´¢è®°å½•",
onClick: ()=>router.push("/search"),
children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._, {
name: "search",
size: 18
})
})
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "month-switcher-container",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("button", {
type: "button",
className: "icon-button",
"aria-label": "上个月",
onClick: prevMonth,
children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._, {
name: "chevronLeft",
size: 18
})
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("span", {
className: "month-switcher__label",
children: formatMonth(currentMonth)
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("button", {
type: "button",
className: "icon-button",
"aria-label": "下个月",
onClick: nextMonth,
children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._, {
name: "chevronRight",
size: 18
})
})
]
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "header-right-actions",
children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("button", {
type: "button",
className: "icon-button",
"aria-label": "设置",
onClick: ()=>router.push("/settings"),
children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._, {
name: "settings",
size: 18
})
})
})
]
});
const modalHeaderContent = /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "header-center-container",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "header-left-actions",
children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("button", {
type: "button",
className: "icon-button",
"aria-label": "关闭",
onClick: closeModal,
children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._, {
name: "chevronLeft",
size: 18
})
})
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "modal-title-container",
children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("span", {
className: "modal-title",
children: editingRecord ? "编辑记录" : "新增记录"
})
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "header-right-actions"
})
]
});
return /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__10_5b2264656661756c74225d_directImport_asiSafe1__._, {
headerContent: modalOpen ? modalHeaderContent : homeHeaderContent,
compactHeader: true,
hideNav: modalOpen,
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("section", {
className: "dashboard-hero card",
children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "stats-grid stats-grid--hero",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("button", {
type: "button",
className: `stat-card ${typeFilter === "income" ? "active" : ""}`,
onClick: ()=>handleCardClick("income"),
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("span", {
className: "label",
children: "æ”¶å…¥"
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("span", {
className: "value income",
children: [
"+",
formatMoney(stats.income)
]
})
]
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("button", {
type: "button",
className: `stat-card ${typeFilter === "expense" ? "active" : ""}`,
onClick: ()=>handleCardClick("expense"),
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("span", {
className: "label",
children: "支出"
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("span", {
className: "value expense",
children: [
"-",
formatMoney(stats.expense)
]
})
]
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("button", {
type: "button",
className: "stat-card stat-card--balance",
onClick: ()=>handleCardClick("all"),
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("span", {
className: "label",
children: "结余"
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("span", {
className: "value",
children: formatMoney(stats.balance)
})
]
})
]
})
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("section", {
className: "card section-card",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "section-heading section-heading--compact",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("p", {
className: "eyebrow",
children: "记录列表"
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("h2", {
children: typeFilter === "all" ? "全部记录" : typeFilter === "income" ? "仅看收入" : "仅看支出"
})
]
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: openAddModal,
children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("span", {
className: "button-content",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._, {
name: "plus",
size: 16
}),
"新增记录"
]
})
})
]
}),
loading ? /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "loading-state",
children: "加载中..."
}) : records.length === 0 ? /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "empty-state empty-state--card",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._, {
name: "info",
size: 24
})
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("p", {
children: "暂无记录,点击上方按钮添加。"
})
]
}) : /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "records-list records-list--flush",
children: sortedDates.map((date)=>/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "date-group",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "date-label",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("span", {
children: new Date(date).toLocaleDateString("zh-CN", {
month: "short",
day: "numeric",
weekday: "short"
})
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("span", {
className: "day-expense",
children: [
"支出 ",
formatMoney(getDayExpense(date))
]
})
]
}),
groupedRecords[date].map((record)=>{
const categories = __WEBPACK_MODULE_REFERENCE__9_5b2244454641554c545f43415445474f52494553225d_directImport_asiSafe1__._[record.type];
const cat = categories.find((item)=>item.name === record.category) || {
icon: "\uD83D\uDCDD"
};
return /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("button", {
type: "button",
className: "record-item",
onClick: ()=>openEditModal(record),
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "record-left",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "record-icon",
children: cat.icon
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "record-info",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "record-category",
children: record.category
}),
record.note && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "record-note",
children: record.note
})
]
})
]
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: `record-amount ${record.type}`,
children: [
record.type === "income" ? "+" : "-",
formatMoney(record.amount)
]
})
]
}, record.id);
})
]
}, date))
})
]
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("button", {
type: "button",
className: "fab",
"aria-label": "新增记录",
onClick: openAddModal,
children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._, {
name: "plus",
size: 24
})
}),
modalOpen && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "modal-overlay modal-overlay--fullscreen",
onClick: closeModal,
children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "modal modal--fullscreen",
onClick: (e)=>e.stopPropagation(),
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "modal-header",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("p", {
className: "eyebrow",
children: editingRecord ? "编辑记录" : "新增记录"
}),
editingRecord ? /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("h2", {
children: "更新账目"
}) : null
]
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("button", {
type: "button",
className: "icon-button icon-button--ghost",
"aria-label": "关闭弹窗",
onClick: closeModal,
children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._, {
name: "close",
size: 18
})
})
]
}),
formError && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "error-msg",
children: formError
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("form", {
onSubmit: handleSubmit,
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "type-switch",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("button", {
type: "button",
className: `type-btn expense ${formData.type === "expense" ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
type: "expense",
category: ""
}),
disabled: submitting || deleting,
children: "支出"
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("button", {
type: "button",
className: `type-btn income ${formData.type === "income" ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
type: "income",
category: ""
}),
disabled: submitting || deleting,
children: "æ”¶å…¥"
})
]
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "form-group",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("label", {
htmlFor: "record-amount",
children: "金é¢"
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("input", {
id: "record-amount",
type: "number",
className: "amount-input",
value: formData.amount,
onChange: (e)=>setFormData({
...formData,
amount: e.target.value
}),
placeholder: "0.00",
step: "0.01",
required: true,
disabled: submitting || deleting
})
]
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "form-group",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("label", {
children: "分类"
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "category-grid",
children: __WEBPACK_MODULE_REFERENCE__9_5b2244454641554c545f43415445474f52494553225d_directImport_asiSafe1__._[formData.type].map((cat)=>/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("button", {
type: "button",
className: `category-btn ${formData.category === cat.name ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
category: cat.name
}),
disabled: submitting || deleting,
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("span", {
className: "icon",
children: cat.icon
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("span", {
children: cat.name
})
]
}, cat.name))
})
]
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "form-group",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("label", {
children: "日期"
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "datetime-picker",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("input", {
type: "date",
value: formData.date,
onChange: (e)=>setFormData({
...formData,
date: e.target.value
}),
required: true,
disabled: submitting || deleting
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("input", {
type: "time",
value: formData.time || "00:00",
onChange: (e)=>setFormData({
...formData,
time: e.target.value
}),
disabled: submitting || deleting
})
]
})
]
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "form-group",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("label", {
htmlFor: "record-note",
children: "备注(å¯é€‰ï¼‰"
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("input", {
id: "record-note",
type: "text",
value: formData.note,
onChange: (e)=>setFormData({
...formData,
note: e.target.value
}),
placeholder: "添加备注...",
disabled: submitting || deleting
})
]
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("button", {
type: "submit",
className: "btn btn-primary",
disabled: submitting || deleting,
children: submitting ? /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("span", {
className: "button-content",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
}),
editingRecord && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("button", {
type: "button",
className: "btn btn-danger",
onClick: handleDelete,
disabled: submitting || deleting,
children: deleting ? "删除中..." : "删除"
})
]
})
]
})
]
})
})
]
});
}
•{"finalSource":false}ƒmapbufferedMap ReplaceSourceRawSourceimport { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import { isLoggedIn, getRecords, getStats, createRecord, updateRecord, deleteRecord } from "../lib/api";
import { DEFAULT_CATEGORIES } from "../lib/categories";
import AppShell from "../components/AppShell";
import { Icon } from "../components/icons";
import { useToast } from "../components/ToastProvider";
import { useConfirm } from "../components/ConfirmProvider";
export default function Home() {
const router = useRouter();
const { showToast } = useToast();
const { confirm } = useConfirm();
const [currentMonth, setCurrentMonth] = useState(new Date());
const [typeFilter, setTypeFilter] = useState("all");
const [records, setRecords] = useState([]);
const [stats, setStats] = useState({
income: 0,
expense: 0,
balance: 0
});
const [modalOpen, setModalOpen] = useState(false);
const [editingRecord, setEditingRecord] = useState(null);
const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false);
const [deleting, setDeleting] = useState(false);
const [formError, setFormError] = useState("");
const [formData, setFormData] = useState({
type: "expense",
amount: "",
category: "",
date: new Date().toISOString().split("T")[0],
time: new Date().toTimeString().slice(0, 5),
note: ""
});
null;
const getMonthStr = (date)=>`${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}`;
const formatMoney = (num)=>(num || 0).toFixed(2);
const formatMonth = (date)=>`${date.getFullYear()}年${date.getMonth() + 1}月`;
const resetForm = ()=>({
type: "expense",
amount: "",
category: "",
date: new Date().toISOString().split("T")[0],
time: new Date().toTimeString().slice(0, 5),
note: ""
});
const loadData = async ()=>{
setLoading(true);
try {
const [recordsData, statsData] = await Promise.all([
getRecords(getMonthStr(currentMonth), typeFilter),
getStats(getMonthStr(currentMonth))
]);
setRecords(recordsData);
setStats(statsData);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const prevMonth = ()=>{
const newDate = new Date(currentMonth);
newDate.setMonth(newDate.getMonth() - 1);
setCurrentMonth(newDate);
};
const nextMonth = ()=>{
const newDate = new Date(currentMonth);
newDate.setMonth(newDate.getMonth() + 1);
setCurrentMonth(newDate);
};
const handleCardClick = (type)=>{
setTypeFilter(type === typeFilter ? "all" : type);
};
const openAddModal = ()=>{
setEditingRecord(null);
setFormData(resetForm());
setFormError("");
setModalOpen(true);
};
const openEditModal = (record)=>{
const [datePart, timePart] = record.date.split(" ");
setEditingRecord(record);
setFormData({
type: record.type,
amount: record.amount.toString(),
category: record.category,
date: datePart,
time: timePart || "00:00",
note: record.note || ""
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting || deleting) return;
setModalOpen(false);
setEditingRecord(null);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.amount || !formData.category || !formData.date) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
const data = {
type: formData.type,
amount: parseFloat(formData.amount),
category: formData.category,
date: `${formData.date} ${formData.time || "00:00"}`,
note: formData.note
};
if (editingRecord) {
await updateRecord(editingRecord.id, data);
showToast("记录已更新", {
tone: "success"
});
} else {
await createRecord(data);
showToast("记录已添加", {
tone: "success"
});
}
closeModal();
await loadData();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async ()=>{
if (!editingRecord) return;
const shouldDelete = await confirm({
title: "删除这æ¡è®°å½•?",
description: "删除åŽå°†æ— æ³•æ¢å¤ï¼Œè¯·ç¡®è®¤æ˜¯å¦ç»§ç»­ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
setDeleting(true);
try {
await deleteRecord(editingRecord.id);
closeModal();
showToast("记录已删除", {
tone: "success"
});
await loadData();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setDeleting(false);
}
};
const groupedRecords = records.reduce((groups, record)=>{
const date = record.date.split(" ")[0];
if (!groups[date]) groups[date] = [];
groups[date].push(record);
return groups;
}, {});
const sortedDates = Object.keys(groupedRecords).sort((a, b)=>b.localeCompare(a));
const getDayExpense = (date)=>groupedRecords[date].filter((record)=>record.type === "expense").reduce((sum, record)=>sum + record.amount, 0);
const homeHeaderContent = /*#__PURE__*/ _jsxs("div", {
className: "header-center-container",
children: [
/*#__PURE__*/ _jsx("div", {
className: "header-left-actions",
children: /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "æœç´¢è®°å½•",
onClick: ()=>router.push("/search"),
children: /*#__PURE__*/ _jsx(Icon, {
name: "search",
size: 18
})
})
}),
/*#__PURE__*/ _jsxs("div", {
className: "month-switcher-container",
children: [
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "上个月",
onClick: prevMonth,
children: /*#__PURE__*/ _jsx(Icon, {
name: "chevronLeft",
size: 18
})
}),
/*#__PURE__*/ _jsx("span", {
className: "month-switcher__label",
children: formatMonth(currentMonth)
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "下个月",
onClick: nextMonth,
children: /*#__PURE__*/ _jsx(Icon, {
name: "chevronRight",
size: 18
})
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "header-right-actions",
children: /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "设置",
onClick: ()=>router.push("/settings"),
children: /*#__PURE__*/ _jsx(Icon, {
name: "settings",
size: 18
})
})
})
]
});
const modalHeaderContent = /*#__PURE__*/ _jsxs("div", {
className: "header-center-container",
children: [
/*#__PURE__*/ _jsx("div", {
className: "header-left-actions",
children: /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "关闭",
onClick: closeModal,
children: /*#__PURE__*/ _jsx(Icon, {
name: "chevronLeft",
size: 18
})
})
}),
/*#__PURE__*/ _jsx("div", {
className: "modal-title-container",
children: /*#__PURE__*/ _jsx("span", {
className: "modal-title",
children: editingRecord ? "编辑记录" : "新增记录"
})
}),
/*#__PURE__*/ _jsx("div", {
className: "header-right-actions"
})
]
});
return /*#__PURE__*/ _jsxs(AppShell, {
headerContent: modalOpen ? modalHeaderContent : homeHeaderContent,
compactHeader: true,
hideNav: modalOpen,
children: [
/*#__PURE__*/ _jsx("section", {
className: "dashboard-hero card",
children: /*#__PURE__*/ _jsxs("div", {
className: "stats-grid stats-grid--hero",
children: [
/*#__PURE__*/ _jsxs("button", {
type: "button",
className: `stat-card ${typeFilter === "income" ? "active" : ""}`,
onClick: ()=>handleCardClick("income"),
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "æ”¶å…¥"
}),
/*#__PURE__*/ _jsxs("span", {
className: "value income",
children: [
"+",
formatMoney(stats.income)
]
})
]
}),
/*#__PURE__*/ _jsxs("button", {
type: "button",
className: `stat-card ${typeFilter === "expense" ? "active" : ""}`,
onClick: ()=>handleCardClick("expense"),
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "支出"
}),
/*#__PURE__*/ _jsxs("span", {
className: "value expense",
children: [
"-",
formatMoney(stats.expense)
]
})
]
}),
/*#__PURE__*/ _jsxs("button", {
type: "button",
className: "stat-card stat-card--balance",
onClick: ()=>handleCardClick("all"),
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "结余"
}),
/*#__PURE__*/ _jsx("span", {
className: "value",
children: formatMoney(stats.balance)
})
]
})
]
})
}),
/*#__PURE__*/ _jsxs("section", {
className: "card section-card",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "section-heading section-heading--compact",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: "记录列表"
}),
/*#__PURE__*/ _jsx("h2", {
children: typeFilter === "all" ? "全部记录" : typeFilter === "income" ? "仅看收入" : "仅看支出"
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: openAddModal,
children: /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "plus",
size: 16
}),
"新增记录"
]
})
})
]
}),
loading ? /*#__PURE__*/ _jsx("div", {
className: "loading-state",
children: "加载中..."
}) : records.length === 0 ? /*#__PURE__*/ _jsxs("div", {
className: "empty-state empty-state--card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ _jsx(Icon, {
name: "info",
size: 24
})
}),
/*#__PURE__*/ _jsx("p", {
children: "暂无记录,点击上方按钮添加。"
})
]
}) : /*#__PURE__*/ _jsx("div", {
className: "records-list records-list--flush",
children: sortedDates.map((date)=>/*#__PURE__*/ _jsxs("div", {
className: "date-group",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "date-label",
children: [
/*#__PURE__*/ _jsx("span", {
children: new Date(date).toLocaleDateString("zh-CN", {
month: "short",
day: "numeric",
weekday: "short"
})
}),
/*#__PURE__*/ _jsxs("span", {
className: "day-expense",
children: [
"支出 ",
formatMoney(getDayExpense(date))
]
})
]
}),
groupedRecords[date].map((record)=>{
const categories = DEFAULT_CATEGORIES[record.type];
const cat = categories.find((item)=>item.name === record.category) || {
icon: "\uD83D\uDCDD"
};
return /*#__PURE__*/ _jsxs("button", {
type: "button",
className: "record-item",
onClick: ()=>openEditModal(record),
children: [
/*#__PURE__*/ _jsxs("div", {
className: "record-left",
children: [
/*#__PURE__*/ _jsx("div", {
className: "record-icon",
children: cat.icon
}),
/*#__PURE__*/ _jsxs("div", {
className: "record-info",
children: [
/*#__PURE__*/ _jsx("div", {
className: "record-category",
children: record.category
}),
record.note && /*#__PURE__*/ _jsx("div", {
className: "record-note",
children: record.note
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: `record-amount ${record.type}`,
children: [
record.type === "income" ? "+" : "-",
formatMoney(record.amount)
]
})
]
}, record.id);
})
]
}, date))
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "fab",
"aria-label": "新增记录",
onClick: openAddModal,
children: /*#__PURE__*/ _jsx(Icon, {
name: "plus",
size: 24
})
}),
modalOpen && /*#__PURE__*/ _jsx("div", {
className: "modal-overlay modal-overlay--fullscreen",
onClick: closeModal,
children: /*#__PURE__*/ _jsxs("div", {
className: "modal modal--fullscreen",
onClick: (e)=>e.stopPropagation(),
children: [
/*#__PURE__*/ _jsxs("div", {
className: "modal-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: editingRecord ? "编辑记录" : "新增记录"
}),
editingRecord ? /*#__PURE__*/ _jsx("h2", {
children: "更新账目"
}) : null
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button icon-button--ghost",
"aria-label": "关闭弹窗",
onClick: closeModal,
children: /*#__PURE__*/ _jsx(Icon, {
name: "close",
size: 18
})
})
]
}),
formError && /*#__PURE__*/ _jsx("div", {
className: "error-msg",
children: formError
}),
/*#__PURE__*/ _jsxs("form", {
onSubmit: handleSubmit,
children: [
/*#__PURE__*/ _jsxs("div", {
className: "type-switch",
children: [
/*#__PURE__*/ _jsx("button", {
type: "button",
className: `type-btn expense ${formData.type === "expense" ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
type: "expense",
category: ""
}),
disabled: submitting || deleting,
children: "支出"
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: `type-btn income ${formData.type === "income" ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
type: "income",
category: ""
}),
disabled: submitting || deleting,
children: "æ”¶å…¥"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
htmlFor: "record-amount",
children: "金é¢"
}),
/*#__PURE__*/ _jsx("input", {
id: "record-amount",
type: "number",
className: "amount-input",
value: formData.amount,
onChange: (e)=>setFormData({
...formData,
amount: e.target.value
}),
placeholder: "0.00",
step: "0.01",
required: true,
disabled: submitting || deleting
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
children: "分类"
}),
/*#__PURE__*/ _jsx("div", {
className: "category-grid",
children: DEFAULT_CATEGORIES[formData.type].map((cat)=>/*#__PURE__*/ _jsxs("button", {
type: "button",
className: `category-btn ${formData.category === cat.name ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
category: cat.name
}),
disabled: submitting || deleting,
children: [
/*#__PURE__*/ _jsx("span", {
className: "icon",
children: cat.icon
}),
/*#__PURE__*/ _jsx("span", {
children: cat.name
})
]
}, cat.name))
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
children: "日期"
}),
/*#__PURE__*/ _jsxs("div", {
className: "datetime-picker",
children: [
/*#__PURE__*/ _jsx("input", {
type: "date",
value: formData.date,
onChange: (e)=>setFormData({
...formData,
date: e.target.value
}),
required: true,
disabled: submitting || deleting
}),
/*#__PURE__*/ _jsx("input", {
type: "time",
value: formData.time || "00:00",
onChange: (e)=>setFormData({
...formData,
time: e.target.value
}),
disabled: submitting || deleting
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
htmlFor: "record-note",
children: "备注(å¯é€‰ï¼‰"
}),
/*#__PURE__*/ _jsx("input", {
id: "record-note",
type: "text",
value: formData.note,
onChange: (e)=>setFormData({
...formData,
note: e.target.value
}),
placeholder: "添加备注...",
disabled: submitting || deleting
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ _jsx("button", {
type: "submit",
className: "btn btn-primary",
disabled: submitting || deleting,
children: submitting ? /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
}),
editingRecord && /*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-danger",
onClick: handleDelete,
disabled: submitting || deleting,
children: deleting ? "删除中..." : "删除"
})
]
})
]
})
]
})
})
]
});
}
‰.062undefined64107undefined109148undefined150253undefined255309undefined311356undefined358400undefined402456undefined458516undefined518532undefined570578__WEBPACK_MODULE_REFERENCE__7_5b22757365526f75746572225d_call_directImport_asiSafe1__._undefined609616__WEBPACK_MODULE_REFERENCE__12_5b22757365546f617374225d_call_directImport_asiSafe1__._undefined645654__WEBPACK_MODULE_REFERENCE__13_5b22757365436f6e6669726d225d_call_directImport_asiSafe1__._undefined703710__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined765772__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined816823__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined860867__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined975982__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined10381045__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined10881095__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11441151__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11971204__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined12521259__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined13021309__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined21722181__WEBPACK_MODULE_REFERENCE__8_5b226765745265636f726473225d_call_directImport_asiSafe1__._undefined22392246__WEBPACK_MODULE_REFERENCE__8_5b226765745374617473225d_call_directImport_asiSafe1__._undefined43894400__WEBPACK_MODULE_REFERENCE__8_5b227570646174655265636f7264225d_call_directImport_asiSafe1__._undefined45634574__WEBPACK_MODULE_REFERENCE__8_5b226372656174655265636f7264225d_call_directImport_asiSafe1__._undefined52925303__WEBPACK_MODULE_REFERENCE__8_5b2264656c6574655265636f7264225d_call_directImport_asiSafe1__._undefined61776181__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined62846287__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined63886391__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined66306633__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined66356638__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined68006804__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined69326935__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined71767179__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined71817184__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined73607363__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined75537556__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined77977800__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined78027805__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined80078010__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined81128115__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined83548357__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined83598362__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined85628566__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined86698672__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined87738776__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined89979000__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined90029005__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined91729175__WEBPACK_MODULE_REFERENCE__
 = ð_LïKuß+×<pµ·ÿ¡ím ² £!è!ê!2"â"'#å#*$%`%b%ª%t&_¹&'d'S(˜(š(â(ª)ö)]*¢*+L+),n,p,¸,_-¤- .P./J/Á/
00]01Y1Â122_é24a4*5v5 7U7Š8Ï8˜9ä9y;Å;Ý<"=ë=0>l?¸?5@@)AuAÞA#BýBBC[D D˜EäE—F_ÜFÞF&G»HI¨IôIJÖJYKžK KèK¹LþL¢MçMNÍNoO»OuPºP—RãR<UŸUÈVWjX¶X•Y_ÚY [X[O\”\^E^l`¸`£cèc­dòdôd<eÊef­fùf»ghŸhëh\i¡i´jùjêk/lqm¶m¸m_n$oiopfpüpHq÷q<r-uru¡xíxyàyÐz{Ú~&ÔÀôj‚<…­†ò†ŸˆZ눙‰Þ‰ˆŠÔŠŸ‹ä‹¯ŽôŽd’W“I”Ž”‘—Ý—Ž˜Ó˜š)›n›p›¸›é™(0,next_router.useRouter)¡(0,ToastProvider/* useToast */.p)¥(0,ConfirmProvider/* useConfirm */.N)œ(0,external_react_.useState)ÿÿÿÿÿÿÿÿÿÿš(0,api/* getRecords */.Q6)˜(0,api/* getStats */.fy)œ(0,api/* updateRecord */.Vs)œ(0,api/* createRecord */.ae)œ(0,api/* deleteRecord */.JS)•(0,jsx_runtime_.jsxs)jsx_runtime_.jsxÿÿicons/* Icon */.Jýþþÿþþþÿþþþÿýþþþÿþþþý—AppShell/* default */.Zýüüýüüýüüýýüüüýýýüýþýüýýþýýüüýü¨lib_categories/* DEFAULT_CATEGORIES */.Sûûüûüüûüüýüûûûüüüüýüûûüüûüüûüüÿûüüûüûüüûüüûüûüýü9
;// CONCATENATED MODULE: ./node_modules/next/dist/build/webpack/loaders/next-route-loader/index.js?kind=PAGES&page=%2F&preferredRegion=&absolutePagePath=private-next-pages%2Findex.js&absoluteAppPath=private-next-pages%2F_app.js&absoluteDocumentPath=next%2Fdist%2Fpages%2F_document&middlewareConfigBase64=e30%3D!
 ˜ «webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourceÛimport { PagesRouteModule } from "next/dist/server/future/route-modules/pages/module.compiled";
import { RouteKind } from "next/dist/server/future/route-kind";
import { hoist } from "next/dist/build/templates/helpers";
// Import the app and document modules.
import Document from "next/dist/pages/_document";
import App from "private-next-pages/_app.js";
// Import the userland code.
import * as userland from "private-next-pages/index.js";
// Re-export the component (should be the default export).
export default hoist(userland, "default");
// Re-export methods.
export const getStaticProps = hoist(userland, "getStaticProps");
export const getStaticPaths = hoist(userland, "getStaticPaths");
export const getServerSideProps = hoist(userland, "getServerSideProps");
export const config = hoist(userland, "config");
export const reportWebVitals = hoist(userland, "reportWebVitals");
// Re-export legacy methods.
export const unstable_getStaticProps = hoist(userland, "unstable_getStaticProps");
export const unstable_getStaticPaths = hoist(userland, "unstable_getStaticPaths");
export const unstable_getStaticParams = hoist(userland, "unstable_getStaticParams");
export const unstable_getServerProps = hoist(userland, "unstable_getServerProps");
export const unstable_getServerSideProps = hoist(userland, "unstable_getServerSideProps");
// Create and export the route module that will be consumed.
export const routeModule = new PagesRouteModule({
definition: {
kind: RouteKind.PAGES,
page: "/index",
pathname: "/",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App,
Document
},
userland
});
//# sourceMappingURL=pages.js.map c/^`Qž Ù35a·ôô  ì€@_5;SWY`v|˜š¡·½ÙÝßæ#17PTV]¼¾Åäê 7=_celŒ³·¹Àßå
w}¥ÑŽ Ÿ´³Á/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Ï__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._®__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._);ýþýþýþýþýþýþýþýþýþýþà__WEBPACK_MODULE_REFERENCE__0_5b225061676573526f7574654d6f64756c65225d_directImport_asiSafe1__._Å__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._Ð: __WEBPACK_MODULE_REFERENCE__4_5b2264656661756c74225d_directImport_asiSafe1__._Ð: __WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._°: __WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._á
// Import the app and document modules.
// Import the userland code.
// Re-export the component (should be the default export).
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._, "default"));
// Re-export methods.
const getStaticProps = __WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._, "getStaticProps");
const getStaticPaths = __WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._, "getStaticPaths");
const getServerSideProps = __WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._, "getServerSideProps");
const config = __WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._, "config");
const reportWebVitals = __WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._, "reportWebVitals");
// Re-export legacy methods.
const unstable_getStaticProps = __WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._, "unstable_getStaticProps");
const unstable_getStaticPaths = __WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._, "unstable_getStaticPaths");
const unstable_getStaticParams = __WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._, "unstable_getStaticParams");
const unstable_getServerProps = __WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._, "unstable_getServerProps");
const unstable_getServerSideProps = __WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._, "unstable_getServerSideProps");
// Create and export the route module that will be consumed.
const routeModule = new __WEBPACK_MODULE_REFERENCE__0_5b225061676573526f7574654d6f64756c65225d_directImport_asiSafe1__._({
definition: {
kind: __WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._.PAGES,
page: "/index",
pathname: "/",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App: __WEBPACK_MODULE_REFERENCE__4_5b2264656661756c74225d_directImport_asiSafe1__._,
Document: __WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._
},
userland: __WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._
});
//# sourceMappingURL=pages.js.map âå æÛimport { PagesRouteModule } from "next/dist/server/future/route-modules/pages/module.compiled";
import { RouteKind } from "next/dist/server/future/route-kind";
import { hoist } from "next/dist/build/templates/helpers";
// Import the app and document modules.
import Document from "next/dist/pages/_document";
import App from "private-next-pages/_app.js";
// Import the userland code.
import * as userland from "private-next-pages/index.js";
// Re-export the component (should be the default export).
export default hoist(userland, "default");
// Re-export methods.
export const getStaticProps = hoist(userland, "getStaticProps");
export const getStaticPaths = hoist(userland, "getStaticPaths");
export const getServerSideProps = hoist(userland, "getServerSideProps");
export const config = hoist(userland, "config");
export const reportWebVitals = hoist(userland, "reportWebVitals");
// Re-export legacy methods.
export const unstable_getStaticProps = hoist(userland, "unstable_getStaticProps");
export const unstable_getStaticPaths = hoist(userland, "unstable_getStaticPaths");
export const unstable_getStaticParams = hoist(userland, "unstable_getStaticParams");
export const unstable_getServerProps = hoist(userland, "unstable_getServerProps");
export const unstable_getServerSideProps = hoist(userland, "unstable_getServerSideProps");
// Create and export the route module that will be consumed.
export const routeModule = new PagesRouteModule({
definition: {
kind: RouteKind.PAGES,
page: "/index",
pathname: "/",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App,
Document
},
userland
});
//# sourceMappingURL=pages.js.mapù 094undefined96158undefined160217undefined259307undefined309353undefined384439undefined500514/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (undefined500514undefined515519__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined521528__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined541541.5);undefined565571undefined595599__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined601608__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined630636undefined660664__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined666673__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined695701undefined729733__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined735742__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined768774undefined790794__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined796803__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined817823undefined848852__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined854861__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined913919undefined952956__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined958965__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined9961002undefined10351039__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined10411048__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined10791085undefined11191123__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined11251132__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined11641170undefined12031207__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined12091216__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined12471253undefined12901294__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined12961303__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined13991405undefined14301445__WEBPACK_MODULE_REFERENCE__0_5b225061676573526f7574654d6f64756c65225d_directImport_asiSafe1__._undefined14811489__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined16781677: __WEBPACK_MODULE_REFERENCE__4_5b2264656661756c74225d_directImport_asiSafe1__._undefined16961695: __WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined17161715: __WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined`ÂÇDÏÑþ+y{¨Ù')VÍÏü"prŸóACp¯ýWÿ,lº¼é)wy¦é79fÞ= a ¥ d
±
Æ
 * W ãnext_route_loaderkind_PAGES_page_2F_preferredRegion_absolutePagePath_private_next_pages_2Findex_js_absoluteAppPath_private_next_pages_2F_app_js_absoluteDocumentPath_next_2Fdist_2Fpages_2F_document_middlewareConfigBase64_e30_3D_˜(0,helpers/* hoist */.l)•pages_namespaceObjectþÿþÿþÿþÿþÿþÿþÿþÿþÿþÿ module_compiled.PagesRouteModuleroute_kind/* RouteKind */.x_app["default"]•(_document_default())û†buffer†source„size„maps­ýÿÿ// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
config: () => (/* binding */ config),
"default": () => (/* binding */ next_route_loaderkind_PAGES_page_2F_preferredRegion_absolutePagePath_private_next_pages_2Findex_js_absoluteAppPath_private_next_pages_2F_app_js_absoluteDocumentPath_next_2Fdist_2Fpages_2F_document_middlewareConfigBase64_e30_3D_),
getServerSideProps: () => (/* binding */ getServerSideProps),
getStaticPaths: () => (/* binding */ getStaticPaths),
getStaticProps: () => (/* binding */ getStaticProps),
reportWebVitals: () => (/* binding */ reportWebVitals),
routeModule: () => (/* binding */ routeModule),
unstable_getServerProps: () => (/* binding */ unstable_getServerProps),
unstable_getServerSideProps: () => (/* binding */ unstable_getServerSideProps),
unstable_getStaticParams: () => (/* binding */ unstable_getStaticParams),
unstable_getStaticPaths: () => (/* binding */ unstable_getStaticPaths),
unstable_getStaticProps: () => (/* binding */ unstable_getStaticProps)
});
// NAMESPACE OBJECT: ./pages/index.js
var pages_namespaceObject = {};
__webpack_require__.r(pages_namespaceObject);
__webpack_require__.d(pages_namespaceObject, {
"default": () => (Home)
});
// EXTERNAL MODULE: ./node_modules/next/dist/server/future/route-modules/pages/module.compiled.js
var module_compiled = __webpack_require__(7093);
// EXTERNAL MODULE: ./node_modules/next/dist/server/future/route-kind.js
var route_kind = __webpack_require__(5244);
// EXTERNAL MODULE: ./node_modules/next/dist/build/templates/helpers.js
var helpers = __webpack_require__(1323);
// EXTERNAL MODULE: ./node_modules/next/dist/pages/_document.js
var _document = __webpack_require__(2899);
var _document_default = /*#__PURE__*/__webpack_require__.n(_document);
// EXTERNAL MODULE: ./pages/_app.js
var _app = __webpack_require__(3414);
// EXTERNAL MODULE: external "react/jsx-runtime"
var jsx_runtime_ = __webpack_require__(997);
// EXTERNAL MODULE: external "react"
var external_react_ = __webpack_require__(6689);
// EXTERNAL MODULE: ./node_modules/next/router.js
var next_router = __webpack_require__(1163);
// EXTERNAL MODULE: ./lib/api.js
var api = __webpack_require__(7751);
// EXTERNAL MODULE: ./lib/categories.js
var lib_categories = __webpack_require__(2204);
// EXTERNAL MODULE: ./components/AppShell.js
var AppShell = __webpack_require__(1712);
// EXTERNAL MODULE: ./components/icons.js
var icons = __webpack_require__(349);
// EXTERNAL MODULE: ./components/ToastProvider.js
var ToastProvider = __webpack_require__(4190);
// EXTERNAL MODULE: ./components/ConfirmProvider.js
var ConfirmProvider = __webpack_require__(4407);
;// CONCATENATED MODULE: ./pages/index.js
function Home() {
const router = (0,next_router.useRouter)();
const { showToast } = (0,ToastProvider/* useToast */.p)();
const { confirm } = (0,ConfirmProvider/* useConfirm */.N)();
const [currentMonth, setCurrentMonth] = (0,external_react_.useState)(new Date());
const [typeFilter, setTypeFilter] = (0,external_react_.useState)("all");
const [records, setRecords] = (0,external_react_.useState)([]);
const [stats, setStats] = (0,external_react_.useState)({
income: 0,
expense: 0,
balance: 0
});
const [modalOpen, setModalOpen] = (0,external_react_.useState)(false);
const [editingRecord, setEditingRecord] = (0,external_react_.useState)(null);
const [loading, setLoading] = (0,external_react_.useState)(true);
const [submitting, setSubmitting] = (0,external_react_.useState)(false);
const [deleting, setDeleting] = (0,external_react_.useState)(false);
const [formError, setFormError] = (0,external_react_.useState)("");
const [formData, setFormData] = (0,external_react_.useState)({
type: "expense",
amount: "",
category: "",
date: new Date().toISOString().split("T")[0],
time: new Date().toTimeString().slice(0, 5),
note: ""
});
null;
const getMonthStr = (date)=>`${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}`;
const formatMoney = (num)=>(num || 0).toFixed(2);
const formatMonth = (date)=>`${date.getFullYear()}年${date.getMonth() + 1}月`;
const resetForm = ()=>({
type: "expense",
amount: "",
category: "",
date: new Date().toISOString().split("T")[0],
time: new Date().toTimeString().slice(0, 5),
note: ""
});
const loadData = async ()=>{
setLoading(true);
try {
const [recordsData, statsData] = await Promise.all([
(0,api/* getRecords */.Q6)(getMonthStr(currentMonth), typeFilter),
(0,api/* getStats */.fy)(getMonthStr(currentMonth))
]);
setRecords(recordsData);
setStats(statsData);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const prevMonth = ()=>{
const newDate = new Date(currentMonth);
newDate.setMonth(newDate.getMonth() - 1);
setCurrentMonth(newDate);
};
const nextMonth = ()=>{
const newDate = new Date(currentMonth);
newDate.setMonth(newDate.getMonth() + 1);
setCurrentMonth(newDate);
};
const handleCardClick = (type)=>{
setTypeFilter(type === typeFilter ? "all" : type);
};
const openAddModal = ()=>{
setEditingRecord(null);
setFormData(resetForm());
setFormError("");
setModalOpen(true);
};
const openEditModal = (record)=>{
const [datePart, timePart] = record.date.split(" ");
setEditingRecord(record);
setFormData({
type: record.type,
amount: record.amount.toString(),
category: record.category,
date: datePart,
time: timePart || "00:00",
note: record.note || ""
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting || deleting) return;
setModalOpen(false);
setEditingRecord(null);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.amount || !formData.category || !formData.date) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
const data = {
type: formData.type,
amount: parseFloat(formData.amount),
category: formData.category,
date: `${formData.date} ${formData.time || "00:00"}`,
note: formData.note
};
if (editingRecord) {
await (0,api/* updateRecord */.Vs)(editingRecord.id, data);
showToast("记录已更新", {
tone: "success"
});
} else {
await (0,api/* createRecord */.ae)(data);
showToast("记录已添加", {
tone: "success"
});
}
closeModal();
await loadData();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async ()=>{
if (!editingRecord) return;
const shouldDelete = await confirm({
title: "删除这æ¡è®°å½•?",
description: "删除åŽå°†æ— æ³•æ¢å¤ï¼Œè¯·ç¡®è®¤æ˜¯å¦ç»§ç»­ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
setDeleting(true);
try {
await (0,api/* deleteRecord */.JS)(editingRecord.id);
closeModal();
showToast("记录已删除", {
tone: "success"
});
await loadData();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setDeleting(false);
}
};
const groupedRecords = records.reduce((groups, record)=>{
const date = record.date.split(" ")[0];
if (!groups[date]) groups[date] = [];
groups[date].push(record);
return groups;
}, {});
const sortedDates = Object.keys(groupedRecords).sort((a, b)=>b.localeCompare(a));
const getDayExpense = (date)=>groupedRecords[date].filter((record)=>record.type === "expense").reduce((sum, record)=>sum + record.amount, 0);
const homeHeaderContent = /*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "header-center-container",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "header-left-actions",
children: /*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "æœç´¢è®°å½•",
onClick: ()=>router.push("/search"),
children: /*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "search",
size: 18
})
})
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "month-switcher-container",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "上个月",
onClick: prevMonth,
children: /*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "chevronLeft",
size: 18
})
}),
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "month-switcher__label",
children: formatMonth(currentMonth)
}),
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "下个月",
onClick: nextMonth,
children: /*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "chevronRight",
size: 18
})
})
]
}),
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "header-right-actions",
children: /*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "设置",
onClick: ()=>router.push("/settings"),
children: /*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "settings",
size: 18
})
})
})
]
});
const modalHeaderContent = /*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "header-center-container",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "header-left-actions",
children: /*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "关闭",
onClick: closeModal,
children: /*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "chevronLeft",
size: 18
})
})
}),
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "modal-title-container",
children: /*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "modal-title",
children: editingRecord ? "编辑记录" : "新增记录"
})
}),
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "header-right-actions"
})
]
});
return /*#__PURE__*/ (0,jsx_runtime_.jsxs)(AppShell/* default */.Z, {
headerContent: modalOpen ? modalHeaderContent : homeHeaderContent,
compactHeader: true,
hideNav: modalOpen,
children: [
/*#__PURE__*/ jsx_runtime_.jsx("section", {
className: "dashboard-hero card",
children: /*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "stats-grid stats-grid--hero",
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("button", {
type: "button",
className: `stat-card ${typeFilter === "income" ? "active" : ""}`,
onClick: ()=>handleCardClick("income"),
children: [
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "label",
children: "æ”¶å…¥"
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("span", {
className: "value income",
children: [
"+",
formatMoney(stats.income)
]
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("button", {
type: "button",
className: `stat-card ${typeFilter === "expense" ? "active" : ""}`,
onClick: ()=>handleCardClick("expense"),
children: [
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "label",
children: "支出"
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("span", {
className: "value expense",
children: [
"-",
formatMoney(stats.expense)
]
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("button", {
type: "button",
className: "stat-card stat-card--balance",
onClick: ()=>handleCardClick("all"),
children: [
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "label",
children: "结余"
}),
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "value",
children: formatMoney(stats.balance)
})
]
})
]
})
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("section", {
className: "card section-card",
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "section-heading section-heading--compact",
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
children: [
/*#__PURE__*/ jsx_runtime_.jsx("p", {
className: "eyebrow",
children: "记录列表"
}),
/*#__PURE__*/ jsx_runtime_.jsx("h2", {
children: typeFilter === "all" ? "全部记录" : typeFilter === "income" ? "仅看收入" : "仅看支出"
})
]
}),
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: openAddModal,
children: /*#__PURE__*/ (0,jsx_runtime_.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "plus",
size: 16
}),
"新增记录"
]
})
})
]
}),
loading ? /*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "loading-state",
children: "加载中..."
}) : records.length === 0 ? /*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "empty-state empty-state--card",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "info",
size: 24
})
}),
/*#__PURE__*/ jsx_runtime_.jsx("p", {
children: "暂无记录,点击上方按钮添加。"
})
]
}) : /*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "records-list records-list--flush",
children: sortedDates.map((date)=>/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "date-group",
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "date-label",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("span", {
children: new Date(date).toLocaleDateString("zh-CN", {
month: "short",
day: "numeric",
weekday: "short"
})
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("span", {
className: "day-expense",
children: [
"支出 ",
formatMoney(getDayExpense(date))
]
})
]
}),
groupedRecords[date].map((record)=>{
const categories = lib_categories/* DEFAULT_CATEGORIES */.S[record.type];
const cat = categories.find((item)=>item.name === record.category) || {
icon: "\uD83D\uDCDD"
};
return /*#__PURE__*/ (0,jsx_runtime_.jsxs)("button", {
type: "button",
className: "record-item",
onClick: ()=>openEditModal(record),
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "record-left",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "record-icon",
children: cat.icon
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "record-info",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "record-category",
children: record.category
}),
record.note && /*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "record-note",
children: record.note
})
]
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: `record-amount ${record.type}`,
children: [
record.type === "income" ? "+" : "-",
formatMoney(record.amount)
]
})
]
}, record.id);
})
]
}, date))
})
]
}),
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: "fab",
"aria-label": "新增记录",
onClick: openAddModal,
children: /*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "plus",
size: 24
})
}),
modalOpen && /*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "modal-overlay modal-overlay--fullscreen",
onClick: closeModal,
children: /*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "modal modal--fullscreen",
onClick: (e)=>e.stopPropagation(),
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "modal-header",
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
children: [
/*#__PURE__*/ jsx_runtime_.jsx("p", {
className: "eyebrow",
children: editingRecord ? "编辑记录" : "新增记录"
}),
editingRecord ? /*#__PURE__*/ jsx_runtime_.jsx("h2", {
children: "更新账目"
}) : null
]
}),
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: "icon-button icon-button--ghost",
"aria-label": "关闭弹窗",
onClick: closeModal,
children: /*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "close",
size: 18
})
})
]
}),
formError && /*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "error-msg",
children: formError
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("form", {
onSubmit: handleSubmit,