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

18662 lines
1.1 MiB
Plaintext
Raw Normal View History

2026-03-12 11:24:10 +08:00
wpcs§webpack/lib/cache/PackFileCacheStrategyPackContentItems ` ResolverCachePlugin|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|]|fullySpecified=|false|dependencyType=|commonjs|modules=[|0=|node_modules|]|fallback=|false|exportsFields=[|0=|exports|]|importsFields=[|0=|imports|]|conditionNames=[|0=|node|1=|require|]|descriptionFiles=[|0=|package.json|]|extensions=[|0=|.js|1=|.json|2=|.node|]|enforceExtensions=|false|symlinks=|true|mainFields=[|0=|main|]|mainFiles=[|0=|index|]|roots=[|]|preferRelative=|false|preferAbsolute=|false|restrictions=[|]|path=|/opt/accountbook/frontend/pages|request=|../lib/categoriesˆResolverCachePlugin|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|]|fullySpecified=|false|dependencyType=|esm|path=|/opt/accountbook/frontend/pages|request=|../lib/categories¾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/lib/categories.jsµResolverCachePlugin|normal|default|dependencyType=|esm|fallback=|false|exportsFields=[|0=|exports|]|importsFields=[|0=|imports|]|conditionNames=[|0=|node|1=|import|]|descriptionFiles=[|0=|package.json|]|enforceExtensions=|false|symlinks=|true|mainFields=[|0=|main|]|mainFiles=[|0=|index|]|roots=[|]|preferRelative=|false|preferAbsolute=|false|restrictions=[|]|alias=|false|path=|/opt/accountbook/frontend/pages|request=|../lib/categoriesÆ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/lib/categories.jsÕCompilation/codeGeneration|/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/lib/categories.js|webpack-runtimeCompilation/assets|chunk405Compilation/assets|chunk845Compilation/assets|chunk603¥TerserWebpackPlugin|../pages/index.js©TerserWebpackPlugin|../pages/recurring.js¦TerserWebpackPlugin|../pages/search.js¥webpack/lib/cache/ResolverCachePlugin`_ResolverCachePluginCacheMiss‡context„path‡request…queryˆfragment†module‰directory„fileˆinternalŽfullySpecified“descriptionFilePath“descriptionFileData“descriptionFileRootŒrelativePath  «/opt/accountbook/frontend/lib/categories.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“./lib/categories.jsšwebpack/lib/FileSystemInfoˆSnapshot@‰ £·ÀÍyBá/opt/accountbook/frontend/libˆsafeTime‰timestamp„hash!PݨÀÍyB@ݨÀÍyB6a51e60cacf85ff9ýÐ 0Ÿ·ÀÍyBØó/opt/accountbook„/opt/ø!@07ØÊyB /7ØÊyBf3b4def2c53d3cadöÉõÈôÇóÆ@€¬/opt/accountbook/frontend/pages/package.jsonª/opt/accountbook/frontend/lib/package.json¨/opt/accountbook/frontend/lib/categoriesà †issuerissuerLayerˆcompiler¬/opt/accountbook/frontend/pages/recurring.js†server¾€€ ¿ÙÚÛ@  À£·ÀÍyB½Üâãîó˜webpack/lib/NormalModule«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourceZexport const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
exportsType‰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ˆ3b076c43bf0a79e01a013d70 “__webpack_exports__DEFAULT_CATEGORIES ˜·ÀÍyB µ·webpack/lib/dependencies/HarmonyCompatibilityDependency
dÿÿý¶webpack/lib/dependencies/HarmonyExportHeaderDependency
aj¹webpack/lib/dependencies/HarmonyExportSpecifierDependencyö
aj  
 
 ƒ€€ žŸ @   ª·ÀÍyB ¡§¨³¸—webpack/lib/ModuleGraph“RestoreProvidedData
 
€ˆprovidedcanMangleProvideterminalBindingexportsInfoç
 
‡sources“runtimeRequirements„data
Šjavascript«webpack/lib/util/registerExternalSerializerœwebpack-sources/CachedSource ò «webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourcež/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
«webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourceZexport const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
  †buffer†source„size„mapsñ/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
”{"finalSource":true}  ƒmapbufferedMap  ConcatSourceRawSourcež/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
ReplaceSourceRawSource© 06undefined Ê•__webpack_require__.d§ ya«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource`«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourceu"use strict";
(() => {
var exports = {};
exports.id = 405;
exports.ids = [405,660];
exports.modules = {
/***/ 9601:
«webpack/lib/util/registerExternalSerializerœwebpack-sources/CachedSource «webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourceQ/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
«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„hash// 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,
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "type-switch",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: `type-btn expense ${formData.type === "expense" ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
type: "expense",
category: ""
}),
disabled: submitting || deleting,
children: "支出"
}),
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: `type-btn income ${formData.type === "income" ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
type: "income",
category: ""
}),
disabled: submitting || deleting,
children: "æ”¶å…¥"
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
htmlFor: "record-amount",
children: "金é¢"
}),
/*#__PURE__*/ jsx_runtime_.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__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
children: "分类"
}),
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "category-grid",
children: lib_categories/* DEFAULT_CATEGORIES */.S[formData.type].map((cat)=>/*#__PURE__*/ (0,jsx_runtime_.jsxs)("button", {
type: "button",
className: `category-btn ${formData.category === cat.name ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
category: cat.name
}),
disabled: submitting || deleting,
children: [
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "icon",
children: cat.icon
}),
/*#__PURE__*/ jsx_runtime_.jsx("span", {
children: cat.name
})
]
}, cat.name))
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
children: "日期"
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "datetime-picker",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("input", {
type: "date",
value: formData.date,
onChange: (e)=>setFormData({
...formData,
date: e.target.value
}),
required: true,
disabled: submitting || deleting
}),
/*#__PURE__*/ jsx_runtime_.jsx("input", {
type: "time",
value: formData.time || "00:00",
onChange: (e)=>setFormData({
...formData,
time: e.target.value
}),
disabled: submitting || deleting
})
]
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
htmlFor: "record-note",
children: "备注(å¯é€‰ï¼‰"
}),
/*#__PURE__*/ jsx_runtime_.jsx("input", {
id: "record-note",
type: "text",
value: formData.note,
onChange: (e)=>setFormData({
...formData,
note: e.target.value
}),
placeholder: "添加备注...",
disabled: submitting || deleting
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "submit",
className: "btn btn-primary",
disabled: submitting || deleting,
children: submitting ? /*#__PURE__*/ (0,jsx_runtime_.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
}),
editingRecord && /*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: "btn btn-danger",
onClick: handleDelete,
disabled: submitting || deleting,
children: deleting ? "删除中..." : "删除"
})
]
})
]
})
]
})
})
]
});
}
;// 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!
// Import the app and document modules.
// Import the userland code.
// Re-export the component (should be the default export).
/* harmony default export */ const 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, "default"));
// Re-export methods.
const getStaticProps = (0,helpers/* hoist */.l)(pages_namespaceObject, "getStaticProps");
const getStaticPaths = (0,helpers/* hoist */.l)(pages_namespaceObject, "getStaticPaths");
const getServerSideProps = (0,helpers/* hoist */.l)(pages_namespaceObject, "getServerSideProps");
const config = (0,helpers/* hoist */.l)(pages_namespaceObject, "config");
const reportWebVitals = (0,helpers/* hoist */.l)(pages_namespaceObject, "reportWebVitals");
// Re-export legacy methods.
const unstable_getStaticProps = (0,helpers/* hoist */.l)(pages_namespaceObject, "unstable_getStaticProps");
const unstable_getStaticPaths = (0,helpers/* hoist */.l)(pages_namespaceObject, "unstable_getStaticPaths");
const unstable_getStaticParams = (0,helpers/* hoist */.l)(pages_namespaceObject, "unstable_getStaticParams");
const unstable_getServerProps = (0,helpers/* hoist */.l)(pages_namespaceObject, "unstable_getServerProps");
const unstable_getServerSideProps = (0,helpers/* hoist */.l)(pages_namespaceObject, "unstable_getServerSideProps");
// Create and export the route module that will be consumed.
const routeModule = new module_compiled.PagesRouteModule({
definition: {
kind: route_kind/* RouteKind */.x.PAGES,
page: "/index",
pathname: "/",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App: _app["default"],
Document: (_document_default())
},
userland: pages_namespaceObject
});
//# sourceMappingURL=pages.js.map ”{"finalSource":true}ƒmapbufferedMap `
ConcatSourceRawSourceÃ
// 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

ReplaceSourceReplaceSourceRawSourceimport { 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__
;// 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!
úûÛ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
169194next_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_undefined199277(0,helpers/* hoist */.l)undefined279324pages_namespaceObjectundefined385463(0,helpers/* hoist */.l)undefined465510pages_namespaceObjectundefined555633(0,helpers/* hoist */.l)undefined635680pages_namespaceObjectundefined729807(0,helpers/* hoist */.l)undefined809854pages_namespaceObjectundefined895973(0,helpers/* hoist */.l)undefined9751020pages_namespaceObjectundefined10581136(0,helpers/* hoist */.l)undefined11381183pages_namespaceObjectundefined12671345(0,helpers/* hoist */.l)undefined13471392pages_namespaceObjectundefined14551533(0,helpers/* hoist */.l)undefined15351580pages_namespaceObjectundefined16441722(0,helpers/* hoist */.l)undefined17241769pages_namespaceObjectundefined18331911(0,helpers/* hoist */.l)undefined19131958pages_namespaceObjectundefined20252103(0,helpers/* hoist */.l)undefined21052150pages_namespaceObjectundefined22702365module_compiled.PagesRouteModuleundefined24012469route_kind/* RouteKind */.xundefined26602737_app["default"]undefined27582835(_document_default())undefined28582903pages_namespaceObjectundefined
/***/ }) †buffer†source„size„maps„hashÊš/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
// 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,
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "type-switch",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: `type-btn expense ${formData.type === "expense" ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
type: "expense",
category: ""
}),
disabled: submitting || deleting,
children: "支出"
}),
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: `type-btn income ${formData.type === "income" ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
type: "income",
category: ""
}),
disabled: submitting || deleting,
children: "æ”¶å…¥"
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
htmlFor: "record-amount",
children: "金é¢"
}),
/*#__PURE__*/ jsx_runtime_.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__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
children: "分类"
}),
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "category-grid",
children: lib_categories/* DEFAULT_CATEGORIES */.S[formData.type].map((cat)=>/*#__PURE__*/ (0,jsx_runtime_.jsxs)("button", {
type: "button",
className: `category-btn ${formData.category === cat.name ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
category: cat.name
}),
disabled: submitting || deleting,
children: [
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "icon",
children: cat.icon
}),
/*#__PURE__*/ jsx_runtime_.jsx("span", {
children: cat.name
})
]
}, cat.name))
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
children: "日期"
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "datetime-picker",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("input", {
type: "date",
value: formData.date,
onChange: (e)=>setFormData({
...formData,
date: e.target.value
}),
required: true,
disabled: submitting || deleting
}),
/*#__PURE__*/ jsx_runtime_.jsx("input", {
type: "time",
value: formData.time || "00:00",
onChange: (e)=>setFormData({
...formData,
time: e.target.value
}),
disabled: submitting || deleting
})
]
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
htmlFor: "record-note",
children: "备注(å¯é€‰ï¼‰"
}),
/*#__PURE__*/ jsx_runtime_.jsx("input", {
id: "record-note",
type: "text",
value: formData.note,
onChange: (e)=>setFormData({
...formData,
note: e.target.value
}),
placeholder: "添加备注...",
disabled: submitting || deleting
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "submit",
className: "btn btn-primary",
disabled: submitting || deleting,
children: submitting ? /*#__PURE__*/ (0,jsx_runtime_.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
}),
editingRecord && /*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: "btn btn-danger",
onClick: handleDelete,
disabled: submitting || deleting,
children: deleting ? "删除中..." : "删除"
})
]
})
]
})
]
})
})
]
});
}
;// 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!
// Import the app and document modules.
// Import the userland code.
// Re-export the component (should be the default export).
/* harmony default export */ const 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, "default"));
// Re-export methods.
const getStaticProps = (0,helpers/* hoist */.l)(pages_namespaceObject, "getStaticProps");
const getStaticPaths = (0,helpers/* hoist */.l)(pages_namespaceObject, "getStaticPaths");
const getServerSideProps = (0,helpers/* hoist */.l)(pages_namespaceObject, "getServerSideProps");
const config = (0,helpers/* hoist */.l)(pages_namespaceObject, "config");
const reportWebVitals = (0,helpers/* hoist */.l)(pages_namespaceObject, "reportWebVitals");
// Re-export legacy methods.
const unstable_getStaticProps = (0,helpers/* hoist */.l)(pages_namespaceObject, "unstable_getStaticProps");
const unstable_getStaticPaths = (0,helpers/* hoist */.l)(pages_namespaceObject, "unstable_getStaticPaths");
const unstable_getStaticParams = (0,helpers/* hoist */.l)(pages_namespaceObject, "unstable_getStaticParams");
const unstable_getServerProps = (0,helpers/* hoist */.l)(pages_namespaceObject, "unstable_getServerProps");
const unstable_getServerSideProps = (0,helpers/* hoist */.l)(pages_namespaceObject, "unstable_getServerSideProps");
// Create and export the route module that will be consumed.
const routeModule = new module_compiled.PagesRouteModule({
definition: {
kind: route_kind/* RouteKind */.x.PAGES,
page: "/index",
pathname: "/",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App: _app["default"],
Document: (_document_default())
},
userland: pages_namespaceObject
});
//# sourceMappingURL=pages.js.map
/***/ }) ”{"finalSource":true}ƒmapbufferedMap `ConcatSourceRawSourceQ/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
þÃ
// 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

ReplaceSourceReplaceSourceRawSourceimport { 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__
;// 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!
úûÛ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
169194next_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_undefined199277(0,helpers/* hoist */.l)undefined279324pages_namespaceObjectundefined385463(0,helpers/* hoist */.l)undefined465510pages_namespaceObjectundefined555633(0,helpers/* hoist */.l)undefined635680pages_namespaceObjectundefined729807(0,helpers/* hoist */.l)undefined809854pages_namespaceObjectundefined895973(0,helpers/* hoist */.l)undefined9751020pages_namespaceObjectundefined10581136(0,helpers/* hoist */.l)undefined11381183pages_namespaceObjectundefined12671345(0,helpers/* hoist */.l)undefined13471392pages_namespaceObjectundefined14551533(0,helpers/* hoist */.l)undefined15351580pages_namespaceObjectundefined16441722(0,helpers/* hoist */.l)undefined17241769pages_namespaceObjectundefined18331911(0,helpers/* hoist */.l)undefined19131958pages_namespaceObjectundefined20252103(0,helpers/* hoist */.l)undefined21052150pages_namespaceObjectundefined22702365module_compiled.PagesRouteModuleundefined24012469route_kind/* RouteKind */.xundefined26602737_app["default"]undefined27582835(_document_default())undefined28582903pages_namespaceObjectundefined RawSource
/***/ }),
/***/ 2204:
 ä«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourceQ/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
«webpack/lib/util/registerExternalSerializerœwebpack-sources/CachedSource ò «webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourcež/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
«webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourceZexport const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
†buffer†source„size„maps„hashñ/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
”{"finalSource":true}ƒmapbufferedMap ConcatSourceRawSourcež/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
ReplaceSourceRawSourceZexport const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
 06undefined
/***/ }) åL /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
/***/ }) æé  êëêž/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
íZexport const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
 06undefinedóô,
/***/ 2785:
 "«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
Qmodule.exports = require("next/dist/compiled/next-server/pages.runtime.prod.js"); 
/***/ }) Úq/***/ ((module) => {
module.exports = require("next/dist/compiled/next-server/pages.runtime.prod.js");
/***/ }) ÛÞ ß/***/ ((module) => {
êQmodule.exports = require("next/dist/compiled/next-server/pages.runtime.prod.js");éê,
/***/ 6689:
 ó«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
"module.exports = require("react"); 
/***/ }) ÐB/***/ ((module) => {
module.exports = require("react");
/***/ }) ÑÔ Õöá"module.exports = require("react");àá,
/***/ 6405:
 ÷«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
&module.exports = require("react-dom"); 
/***/ }) ÇF/***/ ((module) => {
module.exports = require("react-dom");
/***/ }) ÈË ÌíØ&module.exports = require("react-dom");ר,
/***/ 997:
 ÿ«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
.module.exports = require("react/jsx-runtime"); 
/***/ }) ¾N/***/ ((module) => {
module.exports = require("react/jsx-runtime");
/***/ }) ¿Â ÃäÏ.module.exports = require("react/jsx-runtime");ÎÏ,
/***/ 2048:
 ð«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
module.exports = require("fs"); 
/***/ }) µ?/***/ ((module) => {
module.exports = require("fs");
/***/ }) ¹ ºÛÆmodule.exports = require("fs");ÅÆ,
/***/ 5315:
 ò«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
!module.exports = require("path"); 
/***/ }) ¬A/***/ ((module) => {
module.exports = require("path");
/***/ }) ­° ±Ò½!module.exports = require("path");¼½,
/***/ 6162:
 ô«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
#module.exports = require("stream"); 
/***/ }) £C/***/ ((module) => {
module.exports = require("stream");
/***/ }) ¤§ ¨É´#module.exports = require("stream");³´,
/***/ 1568:
 ò«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
!module.exports = require("zlib"); 
/***/ }) šA/***/ ((module) => {
module.exports = require("zlib");
/***/ }) ž ŸÀ«!module.exports = require("zlib");ª«t
};
;
// load runtime
var __webpack_require__ = require("../webpack-runtime.js");
__webpack_require__.C(exports);
Àvar __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId))
var __webpack_exports__ = __webpack_require__.X(0, [899,342,261], () => (__webpack_exec__(9601)));
,module.exports = __webpack_exports__;
})();  í¼¨"use strict";
(() => {
var exports = {};
exports.id = 405;
exports.ids = [405,660];
exports.modules = {
/***/ 9601:
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
// 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,
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "type-switch",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: `type-btn expense ${formData.type === "expense" ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
type: "expense",
category: ""
}),
disabled: submitting || deleting,
children: "支出"
}),
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: `type-btn income ${formData.type === "income" ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
type: "income",
category: ""
}),
disabled: submitting || deleting,
children: "æ”¶å…¥"
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
htmlFor: "record-amount",
children: "金é¢"
}),
/*#__PURE__*/ jsx_runtime_.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__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
children: "分类"
}),
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "category-grid",
children: lib_categories/* DEFAULT_CATEGORIES */.S[formData.type].map((cat)=>/*#__PURE__*/ (0,jsx_runtime_.jsxs)("button", {
type: "button",
className: `category-btn ${formData.category === cat.name ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
category: cat.name
}),
disabled: submitting || deleting,
children: [
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "icon",
children: cat.icon
}),
/*#__PURE__*/ jsx_runtime_.jsx("span", {
children: cat.name
})
]
}, cat.name))
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
children: "日期"
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "datetime-picker",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("input", {
type: "date",
value: formData.date,
onChange: (e)=>setFormData({
...formData,
date: e.target.value
}),
required: true,
disabled: submitting || deleting
}),
/*#__PURE__*/ jsx_runtime_.jsx("input", {
type: "time",
value: formData.time || "00:00",
onChange: (e)=>setFormData({
...formData,
time: e.target.value
}),
disabled: submitting || deleting
})
]
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
htmlFor: "record-note",
children: "备注(å¯é€‰ï¼‰"
}),
/*#__PURE__*/ jsx_runtime_.jsx("input", {
id: "record-note",
type: "text",
value: formData.note,
onChange: (e)=>setFormData({
...formData,
note: e.target.value
}),
placeholder: "添加备注...",
disabled: submitting || deleting
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "submit",
className: "btn btn-primary",
disabled: submitting || deleting,
children: submitting ? /*#__PURE__*/ (0,jsx_runtime_.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
}),
editingRecord && /*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: "btn btn-danger",
onClick: handleDelete,
disabled: submitting || deleting,
children: deleting ? "删除中..." : "删除"
})
]
})
]
})
]
})
})
]
});
}
;// 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!
// Import the app and document modules.
// Import the userland code.
// Re-export the component (should be the default export).
/* harmony default export */ const 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, "default"));
// Re-export methods.
const getStaticProps = (0,helpers/* hoist */.l)(pages_namespaceObject, "getStaticProps");
const getStaticPaths = (0,helpers/* hoist */.l)(pages_namespaceObject, "getStaticPaths");
const getServerSideProps = (0,helpers/* hoist */.l)(pages_namespaceObject, "getServerSideProps");
const config = (0,helpers/* hoist */.l)(pages_namespaceObject, "config");
const reportWebVitals = (0,helpers/* hoist */.l)(pages_namespaceObject, "reportWebVitals");
// Re-export legacy methods.
const unstable_getStaticProps = (0,helpers/* hoist */.l)(pages_namespaceObject, "unstable_getStaticProps");
const unstable_getStaticPaths = (0,helpers/* hoist */.l)(pages_namespaceObject, "unstable_getStaticPaths");
const unstable_getStaticParams = (0,helpers/* hoist */.l)(pages_namespaceObject, "unstable_getStaticParams");
const unstable_getServerProps = (0,helpers/* hoist */.l)(pages_namespaceObject, "unstable_getServerProps");
const unstable_getServerSideProps = (0,helpers/* hoist */.l)(pages_namespaceObject, "unstable_getServerSideProps");
// Create and export the route module that will be consumed.
const routeModule = new module_compiled.PagesRouteModule({
definition: {
kind: route_kind/* RouteKind */.x.PAGES,
page: "/index",
pathname: "/",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App: _app["default"],
Document: (_document_default())
},
userland: pages_namespaceObject
});
//# sourceMappingURL=pages.js.map
/***/ }),
/***/ 2204:
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
/***/ }),
/***/ 2785:
/***/ ((module) => {
module.exports = require("next/dist/compiled/next-server/pages.runtime.prod.js");
/***/ }),
/***/ 6689:
/***/ ((module) => {
module.exports = require("react");
/***/ }),
/***/ 6405:
/***/ ((module) => {
module.exports = require("react-dom");
/***/ }),
/***/ 997:
/***/ ((module) => {
module.exports = require("react/jsx-runtime");
/***/ }),
/***/ 2048:
/***/ ((module) => {
module.exports = require("fs");
/***/ }),
/***/ 5315:
/***/ ((module) => {
module.exports = require("path");
/***/ }),
/***/ 6162:
/***/ ((module) => {
module.exports = require("stream");
/***/ }),
/***/ 1568:
/***/ ((module) => {
module.exports = require("zlib");
/***/ })
};
;
// load runtime
var __webpack_require__ = require("../webpack-runtime.js");
__webpack_require__.C(exports);
var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId))
var __webpack_exports__ = __webpack_require__.X(0, [899,342,261], () => (__webpack_exec__(9601)));
module.exports = __webpack_exports__;
})(); {} ð  `dñu"use strict";
(() => {
var exports = {};
exports.id = 405;
exports.ids = [405,660];
exports.modules = {
/***/ 9601:
ðQ/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
ïÃ
// 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

ReplaceSourceïimport { 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__
;// 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!
ûëÛ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
169194next_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_undefined199277(0,helpers/* hoist */.l)undefined279324pages_namespaceObjectundefined385463(0,helpers/* hoist */.l)undefined465510pages_namespaceObjectundefined555633(0,helpers/* hoist */.l)undefined635680pages_namespaceObjectundefined729807(0,helpers/* hoist */.l)undefined809854pages_namespaceObjectundefined895973(0,helpers/* hoist */.l)undefined9751020pages_namespaceObjectundefined10581136(0,helpers/* hoist */.l)undefined11381183pages_namespaceObjectundefined12671345(0,helpers/* hoist */.l)undefined13471392pages_namespaceObjectundefined14551533(0,helpers/* hoist */.l)undefined15351580pages_namespaceObjectundefined16441722(0,helpers/* hoist */.l)undefined17241769pages_namespaceObjectundefined18331911(0,helpers/* hoist */.l)undefined19131958pages_namespaceObjectundefined20252103(0,helpers/* hoist */.l)undefined21052150pages_namespaceObjectundefined22702365module_compiled.PagesRouteModuleundefined24012469route_kind/* RouteKind */.xundefined26602737_app["default"]undefined27582835(_document_default())undefined28582903pages_namespaceObjectundefined RawSource
/***/ })þ,
/***/ 2204:
ãóãäåæýþý,
/***/ 2785:
â/***/ ((module) => {
ûQmodule.exports = require("next/dist/compiled/next-server/pages.runtime.prod.js");úûú,
/***/ 6689:
ßýù"module.exports = require("react");øùø,
/***/ 6405:
Ýû÷&module.exports = require("react-dom");ö÷ö,
/***/ 997:
Ûùõ.module.exports = require("react/jsx-runtime");ôõô,
/***/ 2048:
Ù÷ómodule.exports = require("fs");òóò,
/***/ 5315:
×õñ!module.exports = require("path");ðñð,
/***/ 6162:
Õóï#module.exports = require("stream");îïî,
/***/ 1568:
Óñí!module.exports = require("zlib");ìíìt
};
;
// load runtime
var __webpack_require__ = require("../webpack-runtime.js");
__webpack_require__.C(exports);
ëÀvar __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId))
var __webpack_exports__ = __webpack_require__.X(0, [899,342,261], () => (__webpack_exec__(9601)));
ê,module.exports = __webpack_exports__;
})(); «webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource`«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourcet"use strict";
(() => {
var exports = {};
exports.id = 845;
exports.ids = [845,660];
exports.modules = {
/***/ 671:
«webpack/lib/util/registerExternalSerializerœwebpack-sources/CachedSource ý «webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourceQ/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
«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_2Frecurring_preferredRegion_absolutePagePath_private_next_pages_2Frecurring_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/recurring.js
var recurring_namespaceObject = {};
__webpack_require__.r(recurring_namespaceObject);
__webpack_require__.d(recurring_namespaceObject, {
"default": () => (Recurring)
});
// 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/recurring.js
«webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource«webpack/lib/util/registerExternalSerializerœwebpack-sources/CachedSource u«webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourcekimport { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import { isLoggedIn, getRecurringBills, createRecurringBill, updateRecurringBill, deleteRecurringBill, applyRecurringBill } 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 Recurring() {
const router = useRouter();
const { showToast } = useToast();
const { confirm } = useConfirm();
const [bills, setBills] = useState([]);
const [modalOpen, setModalOpen] = useState(false);
const [editingBill, setEditingBill] = useState(null);
const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false);
const [deleting, setDeleting] = useState(false);
const [applyingId, setApplyingId] = useState(null);
const [formError, setFormError] = useState("");
const [formData, setFormData] = useState({
type: "expense",
amount: "",
category: "",
day: "1",
note: "",
is_active: true
});
null;
const loadBills = async ()=>{
setLoading(true);
try {
const data = await getRecurringBills();
setBills(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const openAddModal = ()=>{
setEditingBill(null);
setFormData({
type: "expense",
amount: "",
category: "",
day: "1",
note: "",
is_active: true
});
setFormError("");
setModalOpen(true);
};
const openEditModal = (bill)=>{
setEditingBill(bill);
setFormData({
type: bill.type,
amount: bill.amount.toString(),
category: bill.category,
day: bill.day.toString(),
note: bill.note || "",
is_active: !!bill.is_active
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting || deleting) return;
setModalOpen(false);
setEditingBill(null);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.amount || !formData.category || !formData.day) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
const data = {
type: formData.type,
amount: parseFloat(formData.amount),
category: formData.category,
day: parseInt(formData.day),
note: formData.note,
is_active: formData.is_active ? 1 : 0
};
if (editingBill) {
await updateRecurringBill(editingBill.id, data);
showToast("周期账å•已更新", {
tone: "success"
});
} else {
await createRecurringBill(data);
showToast("周期账å•已创建", {
tone: "success"
});
}
closeModal();
await loadBills();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async ()=>{
if (!editingBill) return;
const shouldDelete = await confirm({
title: "删除这æ¡å‘¨æœŸè´¦å•?",
description: "删除åŽå°†æ— æ³•æ¢å¤ï¼Œè¯·ç¡®è®¤æ˜¯å¦ç»§ç»­ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
setDeleting(true);
try {
await deleteRecurringBill(editingBill.id);
closeModal();
showToast("周期账å•已删除", {
tone: "success"
});
await loadBills();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setDeleting(false);
}
};
const handleApply = async (id)=>{
setApplyingId(id);
try {
await applyRecurringBill(id);
showToast("已添加到账目", {
tone: "success"
});
} catch (err) {
showToast(err.message, {
tone: "error"
});
} finally{
setApplyingId(null);
}
};
const handleToggleActive = async (bill, event)=>{
event.stopPropagation();
try {
await updateRecurringBill(bill.id, {
...bill,
is_active: bill.is_active ? 0 : 1
});
showToast(bill.is_active ? "å·²åœç”¨å‘¨æœŸè´¦å•" : "å·²å¯ç”¨å‘¨æœŸè´¦å•", {
tone: "success"
});
await loadBills();
} catch (err) {
showToast(err.message, {
tone: "error"
});
}
};
const days = Array.from({
length: 28
}, (_, index)=>index + 1);
const actions = /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "设置",
onClick: ()=>router.push("/settings"),
children: /*#__PURE__*/ _jsx(Icon, {
name: "settings",
size: 18
})
});
return /*#__PURE__*/ _jsxs(AppShell, {
title: "周期账å•",
subtitle: "管ç†å›ºå®šæ”¶å…¥ä¸Žæ”¯å‡ºèŠ‚å¥",
actions: actions,
compactHeader: true,
children: [
loading ? /*#__PURE__*/ _jsx("div", {
className: "card loading-state",
children: "加载中..."
}) : bills.length === 0 ? /*#__PURE__*/ _jsxs("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ _jsx(Icon, {
name: "repeat",
size: 24
})
}),
/*#__PURE__*/ _jsx("p", {
children: "暂无周期性账å•"
}),
/*#__PURE__*/ _jsx("p", {
className: "sub",
children: "点击å³ä¸‹è§’新增定期收入或支出。"
})
]
}) : /*#__PURE__*/ _jsxs("section", {
className: "card section-card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "section-heading section-heading--compact",
children: /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: "è´¦å•列表"
}),
/*#__PURE__*/ _jsxs("h2", {
children: [
bills.length,
" æ¡å‘¨æœŸè´¦å•"
]
})
]
})
}),
/*#__PURE__*/ _jsx("div", {
className: "bills-list",
children: bills.map((bill)=>{
const categories = DEFAULT_CATEGORIES[bill.type];
const cat = categories.find((item)=>item.name === bill.category) || {
icon: "\uD83D\uDCDD"
};
return /*#__PURE__*/ _jsxs("button", {
type: "button",
className: `bill-item ${bill.is_active ? "" : "inactive"}`,
onClick: ()=>openEditModal(bill),
children: [
/*#__PURE__*/ _jsxs("div", {
className: "bill-left",
children: [
/*#__PURE__*/ _jsx("div", {
className: "bill-icon",
children: cat.icon
}),
/*#__PURE__*/ _jsxs("div", {
className: "bill-info",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "bill-row",
children: [
/*#__PURE__*/ _jsx("div", {
className: "bill-category",
children: bill.category
}),
/*#__PURE__*/ _jsx("span", {
className: `status-chip ${bill.is_active ? "status-chip--success" : ""}`,
children: bill.is_active ? "å¯ç”¨ä¸­" : "å·²åœç”¨"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bill-day",
children: [
"æ¯æœˆ ",
bill.day,
" æ—¥"
]
}),
bill.note && /*#__PURE__*/ _jsx("div", {
className: "bill-note",
children: bill.note
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bill-right",
children: [
/*#__PURE__*/ _jsxs("div", {
className: `bill-amount ${bill.type}`,
children: [
bill.type === "income" ? "+" : "-",
bill.amount.toFixed(2)
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bill-actions",
children: [
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline btn-small",
onClick: (e)=>{
e.stopPropagation();
handleApply(bill.id);
},
disabled: applyingId === bill.id,
children: applyingId === bill.id ? "应用中..." : "应用"
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-ghost btn-inline btn-small",
onClick: (event)=>handleToggleActive(bill, event),
children: bill.is_active ? "åœç”¨" : "å¯ç”¨"
})
]
})
]
})
]
}, bill.id);
})
})
]
}),
/*#__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",
onClick: closeModal,
children: /*#__PURE__*/ _jsxs("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
children: [
/*#__PURE__*/ _jsxs("div", {
className: "modal-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: editingBill ? "编辑账å•" : "新增账å•"
}),
/*#__PURE__*/ _jsx("h2", {
children: editingBill ? "更新周期账å•" : "创建周期账å•"
})
]
}),
/*#__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: "bill-amount",
children: "金é¢"
}),
/*#__PURE__*/ _jsx("input", {
id: "bill-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", {
htmlFor: "bill-day",
children: "æ—¥æœŸï¼ˆæ¯æœˆå‡ å·ï¼‰"
}),
/*#__PURE__*/ _jsx("select", {
id: "bill-day",
value: formData.day,
onChange: (e)=>setFormData({
...formData,
day: e.target.value
}),
disabled: submitting || deleting,
children: days.map((day)=>/*#__PURE__*/ _jsxs("option", {
value: day,
children: [
day,
" æ—¥"
]
}, day))
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
htmlFor: "bill-note",
children: "备注(å¯é€‰ï¼‰"
}),
/*#__PURE__*/ _jsx("input", {
id: "bill-note",
type: "text",
value: formData.note,
onChange: (e)=>setFormData({
...formData,
note: e.target.value
}),
placeholder: "添加备注...",
disabled: submitting || deleting
})
]
}),
editingBill && /*#__PURE__*/ _jsx("div", {
className: "form-group form-group--inline",
children: /*#__PURE__*/ _jsxs("label", {
className: "checkbox-label",
children: [
/*#__PURE__*/ _jsx("input", {
type: "checkbox",
checked: formData.is_active,
onChange: (e)=>setFormData({
...formData,
is_active: e.target.checked
}),
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"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
}),
editingBill && /*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-danger",
onClick: handleDelete,
disabled: submitting || deleting,
children: deleting ? "删除中..." : "删除"
})
]
})
]
})
]
})
})
]
});
}
eh>@km_”#%[]ŠŒ¸îð*,:emŒ°¹ÜãKR}µ¼ê#*Y` f x 
-
þæ÷wnq$'),ILßmpãæèë º¾;>ÈÌ-0úþ[^ÿ C!G!""#_#Ø#Ü#Ä$Ç$&&( (2*5*ø+ü+¶,º,—..o/r/š22È5Ë56“6•6˜6&7)7­7±7a8_e8ý89r9u9v:y:~;;Ã<Æ<È<Ë<ï=ò=£>§>=?A?ð?ó?äBçBFFÈFËF¹G¼GKƒK1L_4LÞLáLjM{M¥M©M{P~PªQ­QZS^S TTUU6W:WTYXYZ ZùZüZ ^^¦^ª^j_m_bJƒb4c7cjdndEeHeJeMe|gg×__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_5b22676574526563757272696e6742696c6c73225d_call_directImport_asiSafe1__._ë__WEBPACK_MODULE_REFERENCE__8_5b22757064617465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._ë__WEBPACK_MODULE_REFERENCE__8_5b22637265617465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._ë__WEBPACK_MODULE_REFERENCE__8_5b2264656c657465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._é__WEBPACK_MODULE_REFERENCE__8_5b226170706c79526563757272696e6742696c6c225d_call_directImport_asiSafe1__._üÆ__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._ÿÉ__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._Í__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._Ï__WEBPACK_MODULE_REFERENCE__10_5b2264656661756c74225d_directImport_asiSafe1__._üþüüýüüþüþüþüä__WEBPACK_MODULE_REFERENCE__9_5b2244454641554c545f43415445474f52494553225d_directImport_asiSafe1__._ýýûýýûûýûýýýûûûûüûýýýûûûûüûýýûûýûûýûûÿýûûýûûýýûûûýûýûýûüû†buffer†source„size„maps„hash…ƒ
function Recurring() {
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 [bills, setBills] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._([]);
const [modalOpen, setModalOpen] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._(false);
const [editingBill, setEditingBill] = __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 [applyingId, setApplyingId] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._(null);
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: "",
day: "1",
note: "",
is_active: true
});
null;
const loadBills = async ()=>{
setLoading(true);
try {
const data = await __WEBPACK_MODULE_REFERENCE__8_5b22676574526563757272696e6742696c6c73225d_call_directImport_asiSafe1__._();
setBills(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const openAddModal = ()=>{
setEditingBill(null);
setFormData({
type: "expense",
amount: "",
category: "",
day: "1",
note: "",
is_active: true
});
setFormError("");
setModalOpen(true);
};
const openEditModal = (bill)=>{
setEditingBill(bill);
setFormData({
type: bill.type,
amount: bill.amount.toString(),
category: bill.category,
day: bill.day.toString(),
note: bill.note || "",
is_active: !!bill.is_active
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting || deleting) return;
setModalOpen(false);
setEditingBill(null);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.amount || !formData.category || !formData.day) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
const data = {
type: formData.type,
amount: parseFloat(formData.amount),
category: formData.category,
day: parseInt(formData.day),
note: formData.note,
is_active: formData.is_active ? 1 : 0
};
if (editingBill) {
await __WEBPACK_MODULE_REFERENCE__8_5b22757064617465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._(editingBill.id, data);
showToast("周期账å•已更新", {
tone: "success"
});
} else {
await __WEBPACK_MODULE_REFERENCE__8_5b22637265617465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._(data);
showToast("周期账å•已创建", {
tone: "success"
});
}
closeModal();
await loadBills();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async ()=>{
if (!editingBill) return;
const shouldDelete = await confirm({
title: "删除这æ¡å‘¨æœŸè´¦å•?",
description: "删除åŽå°†æ— æ³•æ¢å¤ï¼Œè¯·ç¡®è®¤æ˜¯å¦ç»§ç»­ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
setDeleting(true);
try {
await __WEBPACK_MODULE_REFERENCE__8_5b2264656c657465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._(editingBill.id);
closeModal();
showToast("周期账å•已删除", {
tone: "success"
});
await loadBills();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setDeleting(false);
}
};
const handleApply = async (id)=>{
setApplyingId(id);
try {
await __WEBPACK_MODULE_REFERENCE__8_5b226170706c79526563757272696e6742696c6c225d_call_directImport_asiSafe1__._(id);
showToast("已添加到账目", {
tone: "success"
});
} catch (err) {
showToast(err.message, {
tone: "error"
});
} finally{
setApplyingId(null);
}
};
const handleToggleActive = async (bill, event)=>{
event.stopPropagation();
try {
await __WEBPACK_MODULE_REFERENCE__8_5b22757064617465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._(bill.id, {
...bill,
is_active: bill.is_active ? 0 : 1
});
showToast(bill.is_active ? "å·²åœç”¨å‘¨æœŸè´¦å•" : "å·²å¯ç”¨å‘¨æœŸè´¦å•", {
tone: "success"
});
await loadBills();
} catch (err) {
showToast(err.message, {
tone: "error"
});
}
};
const days = Array.from({
length: 28
}, (_, index)=>index + 1);
const actions = /*#__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
})
});
return /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__10_5b2264656661756c74225d_directImport_asiSafe1__._, {
title: "周期账å•",
subtitle: "管ç†å›ºå®šæ”¶å…¥ä¸Žæ”¯å‡ºèŠ‚å¥",
actions: actions,
compactHeader: true,
children: [
loading ? /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "card loading-state",
children: "加载中..."
}) : bills.length === 0 ? /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "card 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: "repeat",
size: 24
})
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("p", {
children: "暂无周期性账å•"
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("p", {
className: "sub",
children: "点击å³ä¸‹è§’新增定期收入或支出。"
})
]
}) : /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("section", {
className: "card section-card",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_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_5b226a737873225d_call_directImport_asiSafe1__._("h2", {
children: [
bills.length,
" æ¡å‘¨æœŸè´¦å•"
]
})
]
})
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "bills-list",
children: bills.map((bill)=>{
const categories = __WEBPACK_MODULE_REFERENCE__9_5b2244454641554c545f43415445474f52494553225d_directImport_asiSafe1__._[bill.type];
const cat = categories.find((item)=>item.name === bill.category) || {
icon: "\uD83D\uDCDD"
};
return /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("button", {
type: "button",
className: `bill-item ${bill.is_active ? "" : "inactive"}`,
onClick: ()=>openEditModal(bill),
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "bill-left",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "bill-icon",
children: cat.icon
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "bill-info",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "bill-row",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "bill-category",
children: bill.category
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("span", {
className: `status-chip ${bill.is_active ? "status-chip--success" : ""}`,
children: bill.is_active ? "å¯ç”¨ä¸­" : "å·²åœç”¨"
})
]
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "bill-day",
children: [
"æ¯æœˆ ",
bill.day,
" æ—¥"
]
}),
bill.note && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "bill-note",
children: bill.note
})
]
})
]
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "bill-right",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: `bill-amount ${bill.type}`,
children: [
bill.type === "income" ? "+" : "-",
bill.amount.toFixed(2)
]
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "bill-actions",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("button", {
type: "button",
className: "btn btn-secondary btn-inline btn-small",
onClick: (e)=>{
e.stopPropagation();
handleApply(bill.id);
},
disabled: applyingId === bill.id,
children: applyingId === bill.id ? "应用中..." : "应用"
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("button", {
type: "button",
className: "btn btn-ghost btn-inline btn-small",
onClick: (event)=>handleToggleActive(bill, event),
children: bill.is_active ? "åœç”¨" : "å¯ç”¨"
})
]
})
]
})
]
}, bill.id);
})
})
]
}),
/*#__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",
onClick: closeModal,
children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "modal",
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: editingBill ? "编辑账å•" : "新增账å•"
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("h2", {
children: editingBill ? "更新周期账å•" : "创建周期账å•"
})
]
}),
/*#__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: "bill-amount",
children: "金é¢"
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("input", {
id: "bill-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", {
htmlFor: "bill-day",
children: "æ—¥æœŸï¼ˆæ¯æœˆå‡ å·ï¼‰"
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("select", {
id: "bill-day",
value: formData.day,
onChange: (e)=>setFormData({
...formData,
day: e.target.value
}),
disabled: submitting || deleting,
children: days.map((day)=>/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("option", {
value: day,
children: [
day,
" æ—¥"
]
}, day))
})
]
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "form-group",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("label", {
htmlFor: "bill-note",
children: "备注(å¯é€‰ï¼‰"
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("input", {
id: "bill-note",
type: "text",
value: formData.note,
onChange: (e)=>setFormData({
...formData,
note: e.target.value
}),
placeholder: "添加备注...",
disabled: submitting || deleting
})
]
}),
editingBill && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "form-group form-group--inline",
children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("label", {
className: "checkbox-label",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("input", {
type: "checkbox",
checked: formData.is_active,
onChange: (e)=>setFormData({
...formData,
is_active: e.target.checked
}),
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"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
}),
editingBill && /*#__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 ReplaceSourceRawSourcekimport { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import { isLoggedIn, getRecurringBills, createRecurringBill, updateRecurringBill, deleteRecurringBill, applyRecurringBill } 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 Recurring() {
const router = useRouter();
const { showToast } = useToast();
const { confirm } = useConfirm();
const [bills, setBills] = useState([]);
const [modalOpen, setModalOpen] = useState(false);
const [editingBill, setEditingBill] = useState(null);
const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false);
const [deleting, setDeleting] = useState(false);
const [applyingId, setApplyingId] = useState(null);
const [formError, setFormError] = useState("");
const [formData, setFormData] = useState({
type: "expense",
amount: "",
category: "",
day: "1",
note: "",
is_active: true
});
null;
const loadBills = async ()=>{
setLoading(true);
try {
const data = await getRecurringBills();
setBills(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const openAddModal = ()=>{
setEditingBill(null);
setFormData({
type: "expense",
amount: "",
category: "",
day: "1",
note: "",
is_active: true
});
setFormError("");
setModalOpen(true);
};
const openEditModal = (bill)=>{
setEditingBill(bill);
setFormData({
type: bill.type,
amount: bill.amount.toString(),
category: bill.category,
day: bill.day.toString(),
note: bill.note || "",
is_active: !!bill.is_active
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting || deleting) return;
setModalOpen(false);
setEditingBill(null);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.amount || !formData.category || !formData.day) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
const data = {
type: formData.type,
amount: parseFloat(formData.amount),
category: formData.category,
day: parseInt(formData.day),
note: formData.note,
is_active: formData.is_active ? 1 : 0
};
if (editingBill) {
await updateRecurringBill(editingBill.id, data);
showToast("周期账å•已更新", {
tone: "success"
});
} else {
await createRecurringBill(data);
showToast("周期账å•已创建", {
tone: "success"
});
}
closeModal();
await loadBills();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async ()=>{
if (!editingBill) return;
const shouldDelete = await confirm({
title: "删除这æ¡å‘¨æœŸè´¦å•?",
description: "删除åŽå°†æ— æ³•æ¢å¤ï¼Œè¯·ç¡®è®¤æ˜¯å¦ç»§ç»­ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
setDeleting(true);
try {
await deleteRecurringBill(editingBill.id);
closeModal();
showToast("周期账å•已删除", {
tone: "success"
});
await loadBills();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setDeleting(false);
}
};
const handleApply = async (id)=>{
setApplyingId(id);
try {
await applyRecurringBill(id);
showToast("已添加到账目", {
tone: "success"
});
} catch (err) {
showToast(err.message, {
tone: "error"
});
} finally{
setApplyingId(null);
}
};
const handleToggleActive = async (bill, event)=>{
event.stopPropagation();
try {
await updateRecurringBill(bill.id, {
...bill,
is_active: bill.is_active ? 0 : 1
});
showToast(bill.is_active ? "å·²åœç”¨å‘¨æœŸè´¦å•" : "å·²å¯ç”¨å‘¨æœŸè´¦å•", {
tone: "success"
});
await loadBills();
} catch (err) {
showToast(err.message, {
tone: "error"
});
}
};
const days = Array.from({
length: 28
}, (_, index)=>index + 1);
const actions = /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "设置",
onClick: ()=>router.push("/settings"),
children: /*#__PURE__*/ _jsx(Icon, {
name: "settings",
size: 18
})
});
return /*#__PURE__*/ _jsxs(AppShell, {
title: "周期账å•",
subtitle: "管ç†å›ºå®šæ”¶å…¥ä¸Žæ”¯å‡ºèŠ‚å¥",
actions: actions,
compactHeader: true,
children: [
loading ? /*#__PURE__*/ _jsx("div", {
className: "card loading-state",
children: "加载中..."
}) : bills.length === 0 ? /*#__PURE__*/ _jsxs("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ _jsx(Icon, {
name: "repeat",
size: 24
})
}),
/*#__PURE__*/ _jsx("p", {
children: "暂无周期性账å•"
}),
/*#__PURE__*/ _jsx("p", {
className: "sub",
children: "点击å³ä¸‹è§’新增定期收入或支出。"
})
]
}) : /*#__PURE__*/ _jsxs("section", {
className: "card section-card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "section-heading section-heading--compact",
children: /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: "è´¦å•列表"
}),
/*#__PURE__*/ _jsxs("h2", {
children: [
bills.length,
" æ¡å‘¨æœŸè´¦å•"
]
})
]
})
}),
/*#__PURE__*/ _jsx("div", {
className: "bills-list",
children: bills.map((bill)=>{
const categories = DEFAULT_CATEGORIES[bill.type];
const cat = categories.find((item)=>item.name === bill.category) || {
icon: "\uD83D\uDCDD"
};
return /*#__PURE__*/ _jsxs("button", {
type: "button",
className: `bill-item ${bill.is_active ? "" : "inactive"}`,
onClick: ()=>openEditModal(bill),
children: [
/*#__PURE__*/ _jsxs("div", {
className: "bill-left",
children: [
/*#__PURE__*/ _jsx("div", {
className: "bill-icon",
children: cat.icon
}),
/*#__PURE__*/ _jsxs("div", {
className: "bill-info",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "bill-row",
children: [
/*#__PURE__*/ _jsx("div", {
className: "bill-category",
children: bill.category
}),
/*#__PURE__*/ _jsx("span", {
className: `status-chip ${bill.is_active ? "status-chip--success" : ""}`,
children: bill.is_active ? "å¯ç”¨ä¸­" : "å·²åœç”¨"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bill-day",
children: [
"æ¯æœˆ ",
bill.day,
" æ—¥"
]
}),
bill.note && /*#__PURE__*/ _jsx("div", {
className: "bill-note",
children: bill.note
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bill-right",
children: [
/*#__PURE__*/ _jsxs("div", {
className: `bill-amount ${bill.type}`,
children: [
bill.type === "income" ? "+" : "-",
bill.amount.toFixed(2)
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bill-actions",
children: [
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline btn-small",
onClick: (e)=>{
e.stopPropagation();
handleApply(bill.id);
},
disabled: applyingId === bill.id,
children: applyingId === bill.id ? "应用中..." : "应用"
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-ghost btn-inline btn-small",
onClick: (event)=>handleToggleActive(bill, event),
children: bill.is_active ? "åœç”¨" : "å¯ç”¨"
})
]
})
]
})
]
}, bill.id);
})
})
]
}),
/*#__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",
onClick: closeModal,
children: /*#__PURE__*/ _jsxs("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
children: [
/*#__PURE__*/ _jsxs("div", {
className: "modal-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: editingBill ? "编辑账å•" : "新增账å•"
}),
/*#__PURE__*/ _jsx("h2", {
children: editingBill ? "更新周期账å•" : "创建周期账å•"
})
]
}),
/*#__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: "bill-amount",
children: "金é¢"
}),
/*#__PURE__*/ _jsx("input", {
id: "bill-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", {
htmlFor: "bill-day",
children: "æ—¥æœŸï¼ˆæ¯æœˆå‡ å·ï¼‰"
}),
/*#__PURE__*/ _jsx("select", {
id: "bill-day",
value: formData.day,
onChange: (e)=>setFormData({
...formData,
day: e.target.value
}),
disabled: submitting || deleting,
children: days.map((day)=>/*#__PURE__*/ _jsxs("option", {
value: day,
children: [
day,
" æ—¥"
]
}, day))
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
htmlFor: "bill-note",
children: "备注(å¯é€‰ï¼‰"
}),
/*#__PURE__*/ _jsx("input", {
id: "bill-note",
type: "text",
value: formData.note,
onChange: (e)=>setFormData({
...formData,
note: e.target.value
}),
placeholder: "添加备注...",
disabled: submitting || deleting
})
]
}),
editingBill && /*#__PURE__*/ _jsx("div", {
className: "form-group form-group--inline",
children: /*#__PURE__*/ _jsxs("label", {
className: "checkbox-label",
children: [
/*#__PURE__*/ _jsx("input", {
type: "checkbox",
checked: formData.is_active,
onChange: (e)=>setFormData({
...formData,
is_active: e.target.checked
}),
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"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
}),
editingBill && /*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-danger",
onClick: handleDelete,
disabled: submitting || deleting,
children: deleting ? "删除中..." : "删除"
})
]
})
]
})
]
})
})
]
});
}
}#062undefined64107undefined109148undefined150291undefined293347undefined349394undefined396438undefined440494undefined496554undefined556570undefined613621__WEBPACK_MODULE_REFERENCE__7_5b22757365526f75746572225d_call_directImport_asiSafe1__._undefined652659__WEBPACK_MODULE_REFERENCE__12_5b22757365546f617374225d_call_directImport_asiSafe1__._undefined688697__WEBPACK_MODULE_REFERENCE__13_5b22757365436f6e6669726d225d_call_directImport_asiSafe1__._undefined732739__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined784791__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined843850__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined893900__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined949956__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined10021009__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined10591066__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11131120__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11631170__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined14241440__WEBPACK_MODULE_REFERENCE__8_5b22676574526563757272696e6742696c6c73225d_call_directImport_asiSafe1__._undefined31743192__WEBPACK_MODULE_REFERENCE__8_5b22757064617465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._undefined33553373__WEBPACK_MODULE_REFERENCE__8_5b22637265617465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._undefined40944112__WEBPACK_MODULE_REFERENCE__8_5b2264656c657465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._undefined45824599__WEBPACK_MODULE_REFERENCE__8_5b226170706c79526563757272696e6742696c6c225d_call_directImport_asiSafe1__._undefined49835001__WEBPACK_MODULE_REFERENCE__8_5b22757064617465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._undefined54865489__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined56685671__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined56735676__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined57765780__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined57825789__WEBPACK_MODULE_REFERENCE__10_5b2264656661756c74225d_directImport_asiSafe1__._undefined59615964__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined61116115__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined62536256__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined63716374__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined63766379__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined65506553__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined66646667__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined68426846__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined69716974__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined71127116__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined72137216__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined74187422__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined77717774__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined79357952__WEBPACK_MODULE_REFERENCE__9_5b2244454641554c545f43415445474f52494553225d_directImport_asiSafe1__._undefined81978201__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined85158519__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined87048707__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asi
;// CONCATENATED MODULE: ./node_modules/next/dist/build/webpack/loaders/next-route-loader/index.js?kind=PAGES&page=%2Frecurring&preferredRegion=&absolutePagePath=private-next-pages%2Frecurring.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/recurring.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: "/recurring",
pathname: "/recurring",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App,
Document
},
userland
});
//# sourceMappingURL=pages.js.map c/^`Qž Ù35a»øø 
! @_9?W[]dz˜œž¥»ÁÝáãê
 '5;TXZaÀÂÉèî;Acgip·»½Äãé{š©ÕŸž±°ÅÄÁ/* 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: "/recurring",
pathname: "/recurring",
// 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/recurring.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: "/recurring",
pathname: "/recurring",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App,
Document
},
userland
});
//# sourceMappingURL=pages.js.mapú 094undefined96158undefined160217undefined259307undefined309353undefined384443undefined504518/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (undefined504518undefined519523__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined525532__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined545545.5);undefined569575undefined599603__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined605612__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined634640undefined664668__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined670677__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined699705undefined733737__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined739746__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined772778undefined794798__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined800807__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined821827undefined852856__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined858865__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined917923undefined956960__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined962969__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined10001006undefined10391043__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined10451052__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined10831089undefined11231127__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined11291136__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined11681174undefined12071211__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined12131220__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined12511257undefined12941298__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined13001307__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined14031409undefined14341449__WEBPACK_MODULE_REFERENCE__0_5b225061676573526f7574654d6f64756c65225d_directImport_asiSafe1__._undefined14851493__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined16951694: __WEBPACK_MODULE_REFERENCE__4_5b2264656661756c74225d_directImport_asiSafe1__._undefined17131712: __WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined17331732: __WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined`ÂÇDÏÑþ+y{¨Ù')VÍÏü"prŸóACp¯ýWÿ,lº¼é)wy¦é79fÞ= a ¥ q
¾
Ó
7 d ðnext_route_loaderkind_PAGES_page_2Frecurring_preferredRegion_absolutePagePath_private_next_pages_2Frecurring_js_absoluteAppPath_private_next_pages_2F_app_js_absoluteDocumentPath_next_2Fdist_2Fpages_2F_document_middlewareConfigBase64_e30_3D_˜(0,helpers/* hoist */.l)™recurring_namespaceObjectþÿþÿþÿþÿþÿþÿþÿþÿþÿþÿ module_compiled.PagesRouteModuleroute_kind/* RouteKind */.x_app["default"]•(_document_default())û†buffer†source„size„maps„hash// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
config: () => (/* binding */ config),
"default": () => (/* binding */ next_route_loaderkind_PAGES_page_2Frecurring_preferredRegion_absolutePagePath_private_next_pages_2Frecurring_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/recurring.js
var recurring_namespaceObject = {};
__webpack_require__.r(recurring_namespaceObject);
__webpack_require__.d(recurring_namespaceObject, {
"default": () => (Recurring)
});
// 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/recurring.js
function Recurring() {
const router = (0,next_router.useRouter)();
const { showToast } = (0,ToastProvider/* useToast */.p)();
const { confirm } = (0,ConfirmProvider/* useConfirm */.N)();
const [bills, setBills] = (0,external_react_.useState)([]);
const [modalOpen, setModalOpen] = (0,external_react_.useState)(false);
const [editingBill, setEditingBill] = (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 [applyingId, setApplyingId] = (0,external_react_.useState)(null);
const [formError, setFormError] = (0,external_react_.useState)("");
const [formData, setFormData] = (0,external_react_.useState)({
type: "expense",
amount: "",
category: "",
day: "1",
note: "",
is_active: true
});
null;
const loadBills = async ()=>{
setLoading(true);
try {
const data = await (0,api/* getRecurringBills */.Vn)();
setBills(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const openAddModal = ()=>{
setEditingBill(null);
setFormData({
type: "expense",
amount: "",
category: "",
day: "1",
note: "",
is_active: true
});
setFormError("");
setModalOpen(true);
};
const openEditModal = (bill)=>{
setEditingBill(bill);
setFormData({
type: bill.type,
amount: bill.amount.toString(),
category: bill.category,
day: bill.day.toString(),
note: bill.note || "",
is_active: !!bill.is_active
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting || deleting) return;
setModalOpen(false);
setEditingBill(null);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.amount || !formData.category || !formData.day) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
const data = {
type: formData.type,
amount: parseFloat(formData.amount),
category: formData.category,
day: parseInt(formData.day),
note: formData.note,
is_active: formData.is_active ? 1 : 0
};
if (editingBill) {
await (0,api/* updateRecurringBill */.uO)(editingBill.id, data);
showToast("周期账å•已更新", {
tone: "success"
});
} else {
await (0,api/* createRecurringBill */.z0)(data);
showToast("周期账å•已创建", {
tone: "success"
});
}
closeModal();
await loadBills();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async ()=>{
if (!editingBill) return;
const shouldDelete = await confirm({
title: "删除这æ¡å‘¨æœŸè´¦å•?",
description: "删除åŽå°†æ— æ³•æ¢å¤ï¼Œè¯·ç¡®è®¤æ˜¯å¦ç»§ç»­ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
setDeleting(true);
try {
await (0,api/* deleteRecurringBill */.TZ)(editingBill.id);
closeModal();
showToast("周期账å•已删除", {
tone: "success"
});
await loadBills();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setDeleting(false);
}
};
const handleApply = async (id)=>{
setApplyingId(id);
try {
await (0,api/* applyRecurringBill */.Xu)(id);
showToast("已添加到账目", {
tone: "success"
});
} catch (err) {
showToast(err.message, {
tone: "error"
});
} finally{
setApplyingId(null);
}
};
const handleToggleActive = async (bill, event)=>{
event.stopPropagation();
try {
await (0,api/* updateRecurringBill */.uO)(bill.id, {
...bill,
is_active: bill.is_active ? 0 : 1
});
showToast(bill.is_active ? "å·²åœç”¨å‘¨æœŸè´¦å•" : "å·²å¯ç”¨å‘¨æœŸè´¦å•", {
tone: "success"
});
await loadBills();
} catch (err) {
showToast(err.message, {
tone: "error"
});
}
};
const days = Array.from({
length: 28
}, (_, index)=>index + 1);
const actions = /*#__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
})
});
return /*#__PURE__*/ (0,jsx_runtime_.jsxs)(AppShell/* default */.Z, {
title: "周期账å•",
subtitle: "管ç†å›ºå®šæ”¶å…¥ä¸Žæ”¯å‡ºèŠ‚å¥",
actions: actions,
compactHeader: true,
children: [
loading ? /*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "card loading-state",
children: "加载中..."
}) : bills.length === 0 ? /*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "repeat",
size: 24
})
}),
/*#__PURE__*/ jsx_runtime_.jsx("p", {
children: "暂无周期性账å•"
}),
/*#__PURE__*/ jsx_runtime_.jsx("p", {
className: "sub",
children: "点击å³ä¸‹è§’新增定期收入或支出。"
})
]
}) : /*#__PURE__*/ (0,jsx_runtime_.jsxs)("section", {
className: "card section-card",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "section-heading section-heading--compact",
children: /*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
children: [
/*#__PURE__*/ jsx_runtime_.jsx("p", {
className: "eyebrow",
children: "è´¦å•列表"
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("h2", {
children: [
bills.length,
" æ¡å‘¨æœŸè´¦å•"
]
})
]
})
}),
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "bills-list",
children: bills.map((bill)=>{
const categories = lib_categories/* DEFAULT_CATEGORIES */.S[bill.type];
const cat = categories.find((item)=>item.name === bill.category) || {
icon: "\uD83D\uDCDD"
};
return /*#__PURE__*/ (0,jsx_runtime_.jsxs)("button", {
type: "button",
className: `bill-item ${bill.is_active ? "" : "inactive"}`,
onClick: ()=>openEditModal(bill),
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "bill-left",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "bill-icon",
children: cat.icon
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "bill-info",
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "bill-row",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "bill-category",
children: bill.category
}),
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: `status-chip ${bill.is_active ? "status-chip--success" : ""}`,
children: bill.is_active ? "å¯ç”¨ä¸­" : "å·²åœç”¨"
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "bill-day",
children: [
"æ¯æœˆ ",
bill.day,
" æ—¥"
]
}),
bill.note && /*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "bill-note",
children: bill.note
})
]
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "bill-right",
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: `bill-amount ${bill.type}`,
children: [
bill.type === "income" ? "+" : "-",
bill.amount.toFixed(2)
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "bill-actions",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline btn-small",
onClick: (e)=>{
e.stopPropagation();
handleApply(bill.id);
},
disabled: applyingId === bill.id,
children: applyingId === bill.id ? "应用中..." : "应用"
}),
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: "btn btn-ghost btn-inline btn-small",
onClick: (event)=>handleToggleActive(bill, event),
children: bill.is_active ? "åœç”¨" : "å¯ç”¨"
})
]
})
]
})
]
}, bill.id);
})
})
]
}),
/*#__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",
onClick: closeModal,
children: /*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "modal",
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: editingBill ? "编辑账å•" : "新增账å•"
}),
/*#__PURE__*/ jsx_runtime_.jsx("h2", {
children: editingBill ? "更新周期账å•" : "创建周期账å•"
})
]
}),
/*#__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,
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "type-switch",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: `type-btn expense ${formData.type === "expense" ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
type: "expense",
category: ""
}),
disabled: submitting || deleting,
children: "支出"
}),
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: `type-btn income ${formData.type === "income" ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
type: "income",
category: ""
}),
disabled: submitting || deleting,
children: "æ”¶å…¥"
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
htmlFor: "bill-amount",
children: "金é¢"
}),
/*#__PURE__*/ jsx_runtime_.jsx("input", {
id: "bill-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__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
children: "分类"
}),
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "category-grid",
children: lib_categories/* DEFAULT_CATEGORIES */.S[formData.type].map((cat)=>/*#__PURE__*/ (0,jsx_runtime_.jsxs)("button", {
type: "button",
className: `category-btn ${formData.category === cat.name ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
category: cat.name
}),
disabled: submitting || deleting,
children: [
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "icon",
children: cat.icon
}),
/*#__PURE__*/ jsx_runtime_.jsx("span", {
children: cat.name
})
]
}, cat.name))
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
htmlFor: "bill-day",
children: "æ—¥æœŸï¼ˆæ¯æœˆå‡ å·ï¼‰"
}),
/*#__PURE__*/ jsx_runtime_.jsx("select", {
id: "bill-day",
value: formData.day,
onChange: (e)=>setFormData({
...formData,
day: e.target.value
}),
disabled: submitting || deleting,
children: days.map((day)=>/*#__PURE__*/ (0,jsx_runtime_.jsxs)("option", {
value: day,
children: [
day,
" æ—¥"
]
}, day))
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
htmlFor: "bill-note",
children: "备注(å¯é€‰ï¼‰"
}),
/*#__PURE__*/ jsx_runtime_.jsx("input", {
id: "bill-note",
type: "text",
value: formData.note,
onChange: (e)=>setFormData({
...formData,
note: e.target.value
}),
placeholder: "添加备注...",
disabled: submitting || deleting
})
]
}),
editingBill && /*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "form-group form-group--inline",
children: /*#__PURE__*/ (0,jsx_runtime_.jsxs)("label", {
className: "checkbox-label",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("input", {
type: "checkbox",
checked: formData.is_active,
onChange: (e)=>setFormData({
...formData,
is_active: e.target.checked
}),
disabled: submitting || deleting
}),
¯ç”¨æ­¤è´¦å•"
]
})
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "submit",
className: "btn btn-primary",
disabled: submitting || deleting,
children: submitting ? /*#__PURE__*/ (0,jsx_runtime_.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
}),
editingBill && /*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: "btn btn-danger",
onClick: handleDelete,
disabled: submitting || deleting,
children: deleting ? "删除中..." : "删除"
})
]
})
]
})
]
})
})
]
});
}
;// CONCATENATED MODULE: ./node_modules/next/dist/build/webpack/loaders/next-route-loader/index.js?kind=PAGES&page=%2Frecurring&preferredRegion=&absolutePagePath=private-next-pages%2Frecurring.js&absoluteAppPath=private-next-pages%2F_app.js&absoluteDocumentPath=next%2Fdist%2Fpages%2F_document&middlewareConfigBase64=e30%3D!
// Import the app and document modules.
// Import the userland code.
// Re-export the component (should be the default export).
/* harmony default export */ const next_route_loaderkind_PAGES_page_2Frecurring_preferredRegion_absolutePagePath_private_next_pages_2Frecurring_js_absoluteAppPath_private_next_pages_2F_app_js_absoluteDocumentPath_next_2Fdist_2Fpages_2F_document_middlewareConfigBase64_e30_3D_ = ((0,helpers/* hoist */.l)(recurring_namespaceObject, "default"));
// Re-export methods.
const getStaticProps = (0,helpers/* hoist */.l)(recurring_namespaceObject, "getStaticProps");
const getStaticPaths = (0,helpers/* hoist */.l)(recurring_namespaceObject, "getStaticPaths");
const getServerSideProps = (0,helpers/* hoist */.l)(recurring_namespaceObject, "getServerSideProps");
const config = (0,helpers/* hoist */.l)(recurring_namespaceObject, "config");
const reportWebVitals = (0,helpers/* hoist */.l)(recurring_namespaceObject, "reportWebVitals");
// Re-export legacy methods.
const unstable_getStaticProps = (0,helpers/* hoist */.l)(recurring_namespaceObject, "unstable_getStaticProps");
const unstable_getStaticPaths = (0,helpers/* hoist */.l)(recurring_namespaceObject, "unstable_getStaticPaths");
const unstable_getStaticParams = (0,helpers/* hoist */.l)(recurring_namespaceObject, "unstable_getStaticParams");
const unstable_getServerProps = (0,helpers/* hoist */.l)(recurring_namespaceObject, "unstable_getServerProps");
const unstable_getServerSideProps = (0,helpers/* hoist */.l)(recurring_namespaceObject, "unstable_getServerSideProps");
// Create and export the route module that will be consumed.
const routeModule = new module_compiled.PagesRouteModule({
definition: {
kind: route_kind/* RouteKind */.x.PAGES,
page: "/recurring",
pathname: "/recurring",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App: _app["default"],
Document: (_document_default())
},
userland: recurring_namespaceObject
});
//# sourceMappingURL=pages.js.map ”{"finalSource":true}ƒmapbufferedMap `
ConcatSourceRawSourceé
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
config: () => (/* binding */ config),
"default": () => (/* binding */ next_route_loaderkind_PAGES_page_2Frecurring_preferredRegion_absolutePagePath_private_next_pages_2Frecurring_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/recurring.js
var recurring_namespaceObject = {};
__webpack_require__.r(recurring_namespaceObject);
__webpack_require__.d(recurring_namespaceObject, {
"default": () => (Recurring)
});
// 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/recurring.js

ReplaceSourceReplaceSourceRawSourcekimport { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import { isLoggedIn, getRecurringBills, createRecurringBill, updateRecurringBill, deleteRecurringBill, applyRecurringBill } 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 Recurring() {
const router = useRouter();
const { showToast } = useToast();
const { confirm } = useConfirm();
const [bills, setBills] = useState([]);
const [modalOpen, setModalOpen] = useState(false);
const [editingBill, setEditingBill] = useState(null);
const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false);
const [deleting, setDeleting] = useState(false);
const [applyingId, setApplyingId] = useState(null);
const [formError, setFormError] = useState("");
const [formData, setFormData] = useState({
type: "expense",
amount: "",
category: "",
day: "1",
note: "",
is_active: true
});
null;
const loadBills = async ()=>{
setLoading(true);
try {
const data = await getRecurringBills();
setBills(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const openAddModal = ()=>{
setEditingBill(null);
setFormData({
type: "expense",
amount: "",
category: "",
day: "1",
note: "",
is_active: true
});
setFormError("");
setModalOpen(true);
};
const openEditModal = (bill)=>{
setEditingBill(bill);
setFormData({
type: bill.type,
amount: bill.amount.toString(),
category: bill.category,
day: bill.day.toString(),
note: bill.note || "",
is_active: !!bill.is_active
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting || deleting) return;
setModalOpen(false);
setEditingBill(null);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.amount || !formData.category || !formData.day) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
const data = {
type: formData.type,
amount: parseFloat(formData.amount),
category: formData.category,
day: parseInt(formData.day),
note: formData.note,
is_active: formData.is_active ? 1 : 0
};
if (editingBill) {
await updateRecurringBill(editingBill.id, data);
showToast("周期账å•已更新", {
tone: "success"
});
} else {
await createRecurringBill(data);
showToast("周期账å•已创建", {
tone: "success"
});
}
closeModal();
await loadBills();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async ()=>{
if (!editingBill) return;
const shouldDelete = await confirm({
title: "删除这æ¡å‘¨æœŸè´¦å•?",
description: "删除åŽå°†æ— æ³•æ¢å¤ï¼Œè¯·ç¡®è®¤æ˜¯å¦ç»§ç»­ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
setDeleting(true);
try {
await deleteRecurringBill(editingBill.id);
closeModal();
showToast("周期账å•已删除", {
tone: "success"
});
await loadBills();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setDeleting(false);
}
};
const handleApply = async (id)=>{
setApplyingId(id);
try {
await applyRecurringBill(id);
showToast("已添加到账目", {
tone: "success"
});
} catch (err) {
showToast(err.message, {
tone: "error"
});
} finally{
setApplyingId(null);
}
};
const handleToggleActive = async (bill, event)=>{
event.stopPropagation();
try {
await updateRecurringBill(bill.id, {
...bill,
is_active: bill.is_active ? 0 : 1
});
showToast(bill.is_active ? "å·²åœç”¨å‘¨æœŸè´¦å•" : "å·²å¯ç”¨å‘¨æœŸè´¦å•", {
tone: "success"
});
await loadBills();
} catch (err) {
showToast(err.message, {
tone: "error"
});
}
};
const days = Array.from({
length: 28
}, (_, index)=>index + 1);
const actions = /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "设置",
onClick: ()=>router.push("/settings"),
children: /*#__PURE__*/ _jsx(Icon, {
name: "settings",
size: 18
})
});
return /*#__PURE__*/ _jsxs(AppShell, {
title: "周期账å•",
subtitle: "管ç†å›ºå®šæ”¶å…¥ä¸Žæ”¯å‡ºèŠ‚å¥",
actions: actions,
compactHeader: true,
children: [
loading ? /*#__PURE__*/ _jsx("div", {
className: "card loading-state",
children: "加载中..."
}) : bills.length === 0 ? /*#__PURE__*/ _jsxs("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ _jsx(Icon, {
name: "repeat",
size: 24
})
}),
/*#__PURE__*/ _jsx("p", {
children: "暂无周期性账å•"
}),
/*#__PURE__*/ _jsx("p", {
className: "sub",
children: "点击å³ä¸‹è§’新增定期收入或支出。"
})
]
}) : /*#__PURE__*/ _jsxs("section", {
className: "card section-card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "section-heading section-heading--compact",
children: /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: "è´¦å•列表"
}),
/*#__PURE__*/ _jsxs("h2", {
children: [
bills.length,
" æ¡å‘¨æœŸè´¦å•"
]
})
]
})
}),
/*#__PURE__*/ _jsx("div", {
className: "bills-list",
children: bills.map((bill)=>{
const categories = DEFAULT_CATEGORIES[bill.type];
const cat = categories.find((item)=>item.name === bill.category) || {
icon: "\uD83D\uDCDD"
};
return /*#__PURE__*/ _jsxs("button", {
type: "button",
className: `bill-item ${bill.is_active ? "" : "inactive"}`,
onClick: ()=>openEditModal(bill),
children: [
/*#__PURE__*/ _jsxs("div", {
className: "bill-left",
children: [
/*#__PURE__*/ _jsx("div", {
className: "bill-icon",
children: cat.icon
}),
/*#__PURE__*/ _jsxs("div", {
className: "bill-info",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "bill-row",
children: [
/*#__PURE__*/ _jsx("div", {
className: "bill-category",
children: bill.category
}),
/*#__PURE__*/ _jsx("span", {
className: `status-chip ${bill.is_active ? "status-chip--success" : ""}`,
children: bill.is_active ? "å¯ç”¨ä¸­" : "å·²åœç”¨"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bill-day",
children: [
"æ¯æœˆ ",
bill.day,
" æ—¥"
]
}),
bill.note && /*#__PURE__*/ _jsx("div", {
className: "bill-note",
children: bill.note
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bill-right",
children: [
/*#__PURE__*/ _jsxs("div", {
className: `bill-amount ${bill.type}`,
children: [
bill.type === "income" ? "+" : "-",
bill.amount.toFixed(2)
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bill-actions",
children: [
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline btn-small",
onClick: (e)=>{
e.stopPropagation();
handleApply(bill.id);
},
disabled: applyingId === bill.id,
children: applyingId === bill.id ? "应用中..." : "应用"
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-ghost btn-inline btn-small",
onClick: (event)=>handleToggleActive(bill, event),
children: bill.is_active ? "åœç”¨" : "å¯ç”¨"
})
]
})
]
})
]
}, bill.id);
})
})
]
}),
/*#__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",
onClick: closeModal,
children: /*#__PURE__*/ _jsxs("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
children: [
/*#__PURE__*/ _jsxs("div", {
className: "modal-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: editingBill ? "编辑账å•" : "新增账å•"
}),
/*#__PURE__*/ _jsx("h2", {
children: editingBill ? "更新周期账å•" : "创建周期账å•"
})
]
}),
/*#__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: "bill-amount",
children: "金é¢"
}),
/*#__PURE__*/ _jsx("input", {
id: "bill-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", {
htmlFor: "bill-day",
children: "æ—¥æœŸï¼ˆæ¯æœˆå‡ å·ï¼‰"
}),
/*#__PURE__*/ _jsx("select", {
id: "bill-day",
value: formData.day,
onChange: (e)=>setFormData({
...formData,
day: e.target.value
}),
disabled: submitting || deleting,
children: days.map((day)=>/*#__PURE__*/ _jsxs("option", {
value: day,
children: [
day,
" æ—¥"
]
}, day))
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
htmlFor: "bill-note",
children: "备注(å¯é€‰ï¼‰"
}),
/*#__PURE__*/ _jsx("input", {
id: "bill-note",
type: "text",
value: formData.note,
onChange: (e)=>setFormData({
...formData,
note: e.target.value
}),
placeholder: "添加备注...",
disabled: submitting || deleting
})
]
}),
editingBill && /*#__PURE__*/ _jsx("div", {
className: "form-group form-group--inline",
children: /*#__PURE__*/ _jsxs("label", {
className: "checkbox-label",
children: [
/*#__PURE__*/ _jsx("input", {
type: "checkbox",
checked: formData.is_active,
onChange: (e)=>setFormData({
...formData,
is_active: e.target.checked
}),
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"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
}),
editingBill && /*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-danger",
onClick: handleDelete,
disabled: submitting || deleting,
children: deleting ? "删除中..." : "删除"
})
]
})
]
})
]
})
})
]
});
}
}#062undefined64107undefined109148undefined150291undefined293347undefined349394undefined396438undefined440494undefined496554undefined556570undefined613621__WEBPACK_MODULE_REFERENCE__7_5b22757365526f75746572225d_call_directImport_asiSafe1__._undefined652659__WEBPACK_MODULE_REFERENCE__12_5b22757365546f617374225d_call_directImport_asiSafe1__._undefined688697__WEBPACK_MODULE_REFERENCE__13_5b22757365436f6e6669726d225d_call_directImport_asiSafe1__._undefined732739__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined784791__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined843850__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined893900__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined949956__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined10021009__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined10591066__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11131120__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11631170__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined14241440__WEBPACK_MODULE_REFERENCE__8_5b22676574526563757272696e6742696c6c73225d_call_directImport_asiSafe1__._undefined31743192__WEBPACK_MODULE_REFERENCE__8_5b22757064617465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._undefined33553373__WEBPACK_MODULE_REFERENCE__8_5b22637265617465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._undefined40944112__WEBPACK_MODULE_REFERENCE__8_5b2264656c657465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._undefined45824599__WEBPACK_MODULE_REFERENCE__8_5b226170706c79526563757272696e6742696c6c225d_call_directImport_asiSafe1__._undefined49835001__WEBPACK_MODULE_REFERENCE__8_5b22757064617465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._undefined54865489__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined56685671__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined56735676__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined57765780__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined57825789__WEBPACK_MODULE_REFERENCE__10_5b2264656661756c74225d_directImport_asiSafe1__._undefined59615964__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined61116115__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined62536256__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined63716374__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined63766379__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined65506553__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined66646667__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined68426846__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined69716974__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined71127116__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined72137216__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined74187422__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined77717774__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined79357952__WEBPACK_MODULE_REFERENCE__9_5b2244454641554c545f43415445474f52494553225d_directImport_asiSafe1__._undefined81978201__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined85158519__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined87048707__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asi
;// CONCATENATED MODULE: ./node_modules/next/dist/build/webpack/loaders/next-route-loader/index.js?kind=PAGES&page=%2Frecurring&preferredRegion=&absolutePagePath=private-next-pages%2Frecurring.js&absoluteAppPath=private-next-pages%2F_app.js&absoluteDocumentPath=next%2Fdist%2Fpages%2F_document&middlewareConfigBase64=e30%3D!
úûì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/recurring.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: "/recurring",
pathname: "/recurring",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App,
Document
},
userland
});
//# sourceMappingURL=pages.js.mapú 094undefined96158undefined160217undefined259307undefined309353undefined384443undefined504518/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (undefined504518undefined519523__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined525532__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined545545.5);undefined569575undefined599603__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined605612__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined634640undefined664668__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined670677__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined699705undefined733737__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined739746__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined772778undefined794798__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined800807__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined821827undefined852856__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined858865__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined917923undefined956960__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined962969__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined10001006undefined10391043__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined10451052__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined10831089undefined11231127__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined11291136__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined11681174undefined12071211__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined12131220__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined12511257undefined12941298__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined13001307__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined14031409undefined14341449__WEBPACK_MODULE_REFERENCE__0_5b225061676573526f7574654d6f64756c65225d_directImport_asiSafe1__._undefined14851493__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined16951694: __WEBPACK_MODULE_REFERENCE__4_5b2264656661756c74225d_directImport_asiSafe1__._undefined17131712: __WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined17331732: __WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefinedJ169194next_route_loaderkind_PAGES_page_2Frecurring_preferredRegion_absolutePagePath_private_next_pages_2Frecurring_js_absoluteAppPath_private_next_pages_2F_app_js_absoluteDocumentPath_next_2Fdist_2Fpages_2F_document_middlewareConfigBase64_e30_3D_undefined199277(0,helpers/* hoist */.l)undefined279324recurring_namespaceObjectundefined385463(0,helpers/* hoist */.l)undefined465510recurring_namespaceObjectundefined555633(0,helpers/* hoist */.l)undefined635680recurring_namespaceObjectundefined729807(0,helpers/* hoist */.l)undefined809854recurring_namespaceObjectundefined895973(0,helpers/* hoist */.l)undefined9751020recurring_namespaceObjectundefined10581136(0,helpers/* hoist */.l)undefined11381183recurring_namespaceObjectundefined12671345(0,helpers/* hoist */.l)undefined13471392recurring_namespaceObjectundefined14551533(0,helpers/* hoist */.l)undefined15351580recurring_namespaceObjectundefined16441722(0,helpers/* hoist */.l)undefined17241769recurring_namespaceObjectundefined18331911(0,helpers/* hoist */.l)undefined19131958recurring_namespaceObjectundefined20252103(0,helpers/* hoist */.l)undefined21052150recurring_namespaceObjectundefined22702365module_compiled.PagesRouteModuleundefined24012469route_kind/* RouteKind */.xundefined26732750_app["default"]undefined27712848(_document_default())undefined28712916recurring_namespaceObjectundefined
/***/ }) †buffer†source„size„maps„hashŠƒ/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
config: () => (/* binding */ config),
"default": () => (/* binding */ next_route_loaderkind_PAGES_page_2Frecurring_preferredRegion_absolutePagePath_private_next_pages_2Frecurring_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/recurring.js
var recurring_namespaceObject = {};
__webpack_require__.r(recurring_namespaceObject);
__webpack_require__.d(recurring_namespaceObject, {
"default": () => (Recurring)
});
// 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/recurring.js
function Recurring() {
const router = (0,next_router.useRouter)();
const { showToast } = (0,ToastProvider/* useToast */.p)();
const { confirm } = (0,ConfirmProvider/* useConfirm */.N)();
const [bills, setBills] = (0,external_react_.useState)([]);
const [modalOpen, setModalOpen] = (0,external_react_.useState)(false);
const [editingBill, setEditingBill] = (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 [applyingId, setApplyingId] = (0,external_react_.useState)(null);
const [formError, setFormError] = (0,external_react_.useState)("");
const [formData, setFormData] = (0,external_react_.useState)({
type: "expense",
amount: "",
category: "",
day: "1",
note: "",
is_active: true
});
null;
const loadBills = async ()=>{
setLoading(true);
try {
const data = await (0,api/* getRecurringBills */.Vn)();
setBills(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const openAddModal = ()=>{
setEditingBill(null);
setFormData({
type: "expense",
amount: "",
category: "",
day: "1",
note: "",
is_active: true
});
setFormError("");
setModalOpen(true);
};
const openEditModal = (bill)=>{
setEditingBill(bill);
setFormData({
type: bill.type,
amount: bill.amount.toString(),
category: bill.category,
day: bill.day.toString(),
note: bill.note || "",
is_active: !!bill.is_active
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting || deleting) return;
setModalOpen(false);
setEditingBill(null);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.amount || !formData.category || !formData.day) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
const data = {
type: formData.type,
amount: parseFloat(formData.amount),
category: formData.category,
day: parseInt(formData.day),
note: formData.note,
is_active: formData.is_active ? 1 : 0
};
if (editingBill) {
await (0,api/* updateRecurringBill */.uO)(editingBill.id, data);
showToast("周期账å•已更新", {
tone: "success"
});
} else {
await (0,api/* createRecurringBill */.z0)(data);
showToast("周期账å•已创建", {
tone: "success"
});
}
closeModal();
await loadBills();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async ()=>{
if (!editingBill) return;
const shouldDelete = await confirm({
title: "删除这æ¡å‘¨æœŸè´¦å•?",
description: "删除åŽå°†æ— æ³•æ¢å¤ï¼Œè¯·ç¡®è®¤æ˜¯å¦ç»§ç»­ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
setDeleting(true);
try {
await (0,api/* deleteRecurringBill */.TZ)(editingBill.id);
closeModal();
showToast("周期账å•已删除", {
tone: "success"
});
await loadBills();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setDeleting(false);
}
};
const handleApply = async (id)=>{
setApplyingId(id);
try {
await (0,api/* applyRecurringBill */.Xu)(id);
showToast("已添加到账目", {
tone: "success"
});
} catch (err) {
showToast(err.message, {
tone: "error"
});
} finally{
setApplyingId(null);
}
};
const handleToggleActive = async (bill, event)=>{
event.stopPropagation();
try {
await (0,api/* updateRecurringBill */.uO)(bill.id, {
...bill,
is_active: bill.is_active ? 0 : 1
});
showToast(bill.is_active ? "å·²åœç”¨å‘¨æœŸè´¦å•" : "å·²å¯ç”¨å‘¨æœŸè´¦å•", {
tone: "success"
});
await loadBills();
} catch (err) {
showToast(err.message, {
tone: "error"
});
}
};
const days = Array.from({
length: 28
}, (_, index)=>index + 1);
const actions = /*#__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
})
});
return /*#__PURE__*/ (0,jsx_runtime_.jsxs)(AppShell/* default */.Z, {
title: "周期账å•",
subtitle: "管ç†å›ºå®šæ”¶å…¥ä¸Žæ”¯å‡ºèŠ‚å¥",
actions: actions,
compactHeader: true,
children: [
loading ? /*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "card loading-state",
children: "加载中..."
}) : bills.length === 0 ? /*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "repeat",
size: 24
})
}),
/*#__PURE__*/ jsx_runtime_.jsx("p", {
children: "暂无周期性账å•"
}),
/*#__PURE__*/ jsx_runtime_.jsx("p", {
className: "sub",
children: "点击å³ä¸‹è§’新增定期收入或支出。"
})
]
}) : /*#__PURE__*/ (0,jsx_runtime_.jsxs)("section", {
className: "card section-card",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "section-heading section-heading--compact",
children: /*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
children: [
/*#__PURE__*/ jsx_runtime_.jsx("p", {
className: "eyebrow",
children: "è´¦å•列表"
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("h2", {
children: [
bills.length,
" æ¡å‘¨æœŸè´¦å•"
]
})
]
})
}),
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "bills-list",
children: bills.map((bill)=>{
const categories = lib_categories/* DEFAULT_CATEGORIES */.S[bill.type];
const cat = categories.find((item)=>item.name === bill.category) || {
icon: "\uD83D\uDCDD"
};
return /*#__PURE__*/ (0,jsx_runtime_.jsxs)("button", {
type: "button",
className: `bill-item ${bill.is_active ? "" : "inactive"}`,
onClick: ()=>openEditModal(bill),
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "bill-left",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "bill-icon",
children: cat.icon
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "bill-info",
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "bill-row",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "bill-category",
children: bill.category
}),
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: `status-chip ${bill.is_active ? "status-chip--success" : ""}`,
children: bill.is_active ? "å¯ç”¨ä¸­" : "å·²åœç”¨"
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "bill-day",
children: [
"æ¯æœˆ ",
bill.day,
" æ—¥"
]
}),
bill.note && /*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "bill-note",
children: bill.note
})
]
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "bill-right",
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: `bill-amount ${bill.type}`,
children: [
bill.type === "income" ? "+" : "-",
bill.amount.toFixed(2)
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "bill-actions",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline btn-small",
onClick: (e)=>{
e.stopPropagation();
handleApply(bill.id);
},
disabled: applyingId === bill.id,
children: applyingId === bill.id ? "应用中..." : "应用"
}),
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: "btn btn-ghost btn-inline btn-small",
onClick: (event)=>handleToggleActive(bill, event),
children: bill.is_active ? "åœç”¨" : "å¯ç”¨"
})
]
})
]
})
]
}, bill.id);
})
})
]
}),
/*#__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",
onClick: closeModal,
children: /*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "modal",
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: editingBill ? "编辑账å•" : "新增账å•"
}),
/*#__PURE__*/ jsx_runtime_.jsx("h2", {
children: editingBill ? "更新周期账å•" : "创建周期账å•"
})
]
}),
/*#__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,
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "type-switch",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: `type-btn expense ${formData.type === "expense" ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
type: "expense",
category: ""
}),
disabled: submitting || deleting,
children: "支出"
}),
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: `type-btn income ${formData.type === "income" ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
type: "income",
category: ""
}),
disabled: submitting || deleting,
children: "æ”¶å…¥"
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
htmlFor: "bill-amount",
children: "金é¢"
}),
/*#__PURE__*/ jsx_runtime_.jsx("input", {
id: "bill-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__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
children: "分类"
}),
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "category-grid",
children: lib_categories/* DEFAULT_CATEGORIES */.S[formData.type].map((cat)=>/*#__PURE__*/ (0,jsx_runtime_.jsxs)("button", {
type: "button",
className: `category-btn ${formData.category === cat.name ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
category: cat.name
}),
disabled: submitting || deleting,
children: [
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "icon",
children: cat.icon
}),
/*#__PURE__*/ jsx_runtime_.jsx("span", {
children: cat.name
})
]
}, cat.name))
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
htmlFor: "bill-day",
children: "æ—¥æœŸï¼ˆæ¯æœˆå‡ å·ï¼‰"
}),
/*#__PURE__*/ jsx_runtime_.jsx("select", {
id: "bill-day",
value: formData.day,
onChange: (e)=>setFormData({
...formData,
day: e.target.value
}),
disabled: submitting || deleting,
children: days.map((day)=>/*#__PURE__*/ (0,jsx_runtime_.jsxs)("option", {
value: day,
children: [
day,
" æ—¥"
]
}, day))
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
htmlFor: "bill-note",
children: "备注(å¯é€‰ï¼‰"
}),
/*#__PURE__*/ jsx_runtime_.jsx("input", {
id: "bill-note",
type: "text",
value: formData.note,
onChange: (e)=>setFormData({
...formData,
note: e.target.value
}),
placeholder: "添加备注...",
disabled: submitting || deleting
})
]
}),
editingBill && /*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "form-group form-group--inline",
children: /*#__PURE__*/ (0,jsx_runtime_.jsxs)("label", {
className: "checkbox-label",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("input", {
type: "checkbox",
checked: formData.is_active,
onChange: (e)=>setFormData({
...formData,
is_active: e.target.checked
}),
disabled: submitting || deleting
}),
¯ç”¨æ­¤è´¦å•"
]
})
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "submit",
className: "btn btn-primary",
disabled: submitting || deleting,
children: submitting ? /*#__PURE__*/ (0,jsx_runtime_.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
}),
editingBill && /*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: "btn btn-danger",
onClick: handleDelete,
disabled: submitting || deleting,
children: deleting ? "删除中..." : "删除"
})
]
})
]
})
]
})
})
]
});
}
;// CONCATENATED MODULE: ./node_modules/next/dist/build/webpack/loaders/next-route-loader/index.js?kind=PAGES&page=%2Frecurring&preferredRegion=&absolutePagePath=private-next-pages%2Frecurring.js&absoluteAppPath=private-next-pages%2F_app.js&absoluteDocumentPath=next%2Fdist%2Fpages%2F_document&middlewareConfigBase64=e30%3D!
// Import the app and document modules.
// Import the userland code.
// Re-export the component (should be the default export).
/* harmony default export */ const next_route_loaderkind_PAGES_page_2Frecurring_preferredRegion_absolutePagePath_private_next_pages_2Frecurring_js_absoluteAppPath_private_next_pages_2F_app_js_absoluteDocumentPath_next_2Fdist_2Fpages_2F_document_middlewareConfigBase64_e30_3D_ = ((0,helpers/* hoist */.l)(recurring_namespaceObject, "default"));
// Re-export methods.
const getStaticProps = (0,helpers/* hoist */.l)(recurring_namespaceObject, "getStaticProps");
const getStaticPaths = (0,helpers/* hoist */.l)(recurring_namespaceObject, "getStaticPaths");
const getServerSideProps = (0,helpers/* hoist */.l)(recurring_namespaceObject, "getServerSideProps");
const config = (0,helpers/* hoist */.l)(recurring_namespaceObject, "config");
const reportWebVitals = (0,helpers/* hoist */.l)(recurring_namespaceObject, "reportWebVitals");
// Re-export legacy methods.
const unstable_getStaticProps = (0,helpers/* hoist */.l)(recurring_namespaceObject, "unstable_getStaticProps");
const unstable_getStaticPaths = (0,helpers/* hoist */.l)(recurring_namespaceObject, "unstable_getStaticPaths");
const unstable_getStaticParams = (0,helpers/* hoist */.l)(recurring_namespaceObject, "unstable_getStaticParams");
const unstable_getServerProps = (0,helpers/* hoist */.l)(recurring_namespaceObject, "unstable_getServerProps");
const unstable_getServerSideProps = (0,helpers/* hoist */.l)(recurring_namespaceObject, "unstable_getServerSideProps");
// Create and export the route module that will be consumed.
const routeModule = new module_compiled.PagesRouteModule({
definition: {
kind: route_kind/* RouteKind */.x.PAGES,
page: "/recurring",
pathname: "/recurring",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App: _app["default"],
Document: (_document_default())
},
userland: recurring_namespaceObject
});
//# sourceMappingURL=pages.js.map
/***/ }) ”{"finalSource":true}ƒmapbufferedMap `ConcatSourceRawSourceQ/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
þé
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
config: () => (/* binding */ config),
"default": () => (/* binding */ next_route_loaderkind_PAGES_page_2Frecurring_preferredRegion_absolutePagePath_private_next_pages_2Frecurring_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/recurring.js
var recurring_namespaceObject = {};
__webpack_require__.r(recurring_namespaceObject);
__webpack_require__.d(recurring_namespaceObject, {
"default": () => (Recurring)
});
// 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/recurring.js

ReplaceSourceReplaceSourceRawSourcekimport { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import { isLoggedIn, getRecurringBills, createRecurringBill, updateRecurringBill, deleteRecurringBill, applyRecurringBill } 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 Recurring() {
const router = useRouter();
const { showToast } = useToast();
const { confirm } = useConfirm();
const [bills, setBills] = useState([]);
const [modalOpen, setModalOpen] = useState(false);
const [editingBill, setEditingBill] = useState(null);
const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false);
const [deleting, setDeleting] = useState(false);
const [applyingId, setApplyingId] = useState(null);
const [formError, setFormError] = useState("");
const [formData, setFormData] = useState({
type: "expense",
amount: "",
category: "",
day: "1",
note: "",
is_active: true
});
null;
const loadBills = async ()=>{
setLoading(true);
try {
const data = await getRecurringBills();
setBills(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const openAddModal = ()=>{
setEditingBill(null);
setFormData({
type: "expense",
amount: "",
category: "",
day: "1",
note: "",
is_active: true
});
setFormError("");
setModalOpen(true);
};
const openEditModal = (bill)=>{
setEditingBill(bill);
setFormData({
type: bill.type,
amount: bill.amount.toString(),
category: bill.category,
day: bill.day.toString(),
note: bill.note || "",
is_active: !!bill.is_active
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting || deleting) return;
setModalOpen(false);
setEditingBill(null);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.amount || !formData.category || !formData.day) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
const data = {
type: formData.type,
amount: parseFloat(formData.amount),
category: formData.category,
day: parseInt(formData.day),
note: formData.note,
is_active: formData.is_active ? 1 : 0
};
if (editingBill) {
await updateRecurringBill(editingBill.id, data);
showToast("周期账å•已更新", {
tone: "success"
});
} else {
await createRecurringBill(data);
showToast("周期账å•已创建", {
tone: "success"
});
}
closeModal();
await loadBills();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async ()=>{
if (!editingBill) return;
const shouldDelete = await confirm({
title: "删除这æ¡å‘¨æœŸè´¦å•?",
description: "删除åŽå°†æ— æ³•æ¢å¤ï¼Œè¯·ç¡®è®¤æ˜¯å¦ç»§ç»­ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
setDeleting(true);
try {
await deleteRecurringBill(editingBill.id);
closeModal();
showToast("周期账å•已删除", {
tone: "success"
});
await loadBills();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setDeleting(false);
}
};
const handleApply = async (id)=>{
setApplyingId(id);
try {
await applyRecurringBill(id);
showToast("已添加到账目", {
tone: "success"
});
} catch (err) {
showToast(err.message, {
tone: "error"
});
} finally{
setApplyingId(null);
}
};
const handleToggleActive = async (bill, event)=>{
event.stopPropagation();
try {
await updateRecurringBill(bill.id, {
...bill,
is_active: bill.is_active ? 0 : 1
});
showToast(bill.is_active ? "å·²åœç”¨å‘¨æœŸè´¦å•" : "å·²å¯ç”¨å‘¨æœŸè´¦å•", {
tone: "success"
});
await loadBills();
} catch (err) {
showToast(err.message, {
tone: "error"
});
}
};
const days = Array.from({
length: 28
}, (_, index)=>index + 1);
const actions = /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "设置",
onClick: ()=>router.push("/settings"),
children: /*#__PURE__*/ _jsx(Icon, {
name: "settings",
size: 18
})
});
return /*#__PURE__*/ _jsxs(AppShell, {
title: "周期账å•",
subtitle: "管ç†å›ºå®šæ”¶å…¥ä¸Žæ”¯å‡ºèŠ‚å¥",
actions: actions,
compactHeader: true,
children: [
loading ? /*#__PURE__*/ _jsx("div", {
className: "card loading-state",
children: "加载中..."
}) : bills.length === 0 ? /*#__PURE__*/ _jsxs("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ _jsx(Icon, {
name: "repeat",
size: 24
})
}),
/*#__PURE__*/ _jsx("p", {
children: "暂无周期性账å•"
}),
/*#__PURE__*/ _jsx("p", {
className: "sub",
children: "点击å³ä¸‹è§’新增定期收入或支出。"
})
]
}) : /*#__PURE__*/ _jsxs("section", {
className: "card section-card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "section-heading section-heading--compact",
children: /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: "è´¦å•列表"
}),
/*#__PURE__*/ _jsxs("h2", {
children: [
bills.length,
" æ¡å‘¨æœŸè´¦å•"
]
})
]
})
}),
/*#__PURE__*/ _jsx("div", {
className: "bills-list",
children: bills.map((bill)=>{
const categories = DEFAULT_CATEGORIES[bill.type];
const cat = categories.find((item)=>item.name === bill.category) || {
icon: "\uD83D\uDCDD"
};
return /*#__PURE__*/ _jsxs("button", {
type: "button",
className: `bill-item ${bill.is_active ? "" : "inactive"}`,
onClick: ()=>openEditModal(bill),
children: [
/*#__PURE__*/ _jsxs("div", {
className: "bill-left",
children: [
/*#__PURE__*/ _jsx("div", {
className: "bill-icon",
children: cat.icon
}),
/*#__PURE__*/ _jsxs("div", {
className: "bill-info",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "bill-row",
children: [
/*#__PURE__*/ _jsx("div", {
className: "bill-category",
children: bill.category
}),
/*#__PURE__*/ _jsx("span", {
className: `status-chip ${bill.is_active ? "status-chip--success" : ""}`,
children: bill.is_active ? "å¯ç”¨ä¸­" : "å·²åœç”¨"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bill-day",
children: [
"æ¯æœˆ ",
bill.day,
" æ—¥"
]
}),
bill.note && /*#__PURE__*/ _jsx("div", {
className: "bill-note",
children: bill.note
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bill-right",
children: [
/*#__PURE__*/ _jsxs("div", {
className: `bill-amount ${bill.type}`,
children: [
bill.type === "income" ? "+" : "-",
bill.amount.toFixed(2)
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bill-actions",
children: [
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline btn-small",
onClick: (e)=>{
e.stopPropagation();
handleApply(bill.id);
},
disabled: applyingId === bill.id,
children: applyingId === bill.id ? "应用中..." : "应用"
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-ghost btn-inline btn-small",
onClick: (event)=>handleToggleActive(bill, event),
children: bill.is_active ? "åœç”¨" : "å¯ç”¨"
})
]
})
]
})
]
}, bill.id);
})
})
]
}),
/*#__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",
onClick: closeModal,
children: /*#__PURE__*/ _jsxs("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
children: [
/*#__PURE__*/ _jsxs("div", {
className: "modal-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: editingBill ? "编辑账å•" : "新增账å•"
}),
/*#__PURE__*/ _jsx("h2", {
children: editingBill ? "更新周期账å•" : "创建周期账å•"
})
]
}),
/*#__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: "bill-amount",
children: "金é¢"
}),
/*#__PURE__*/ _jsx("input", {
id: "bill-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", {
htmlFor: "bill-day",
children: "æ—¥æœŸï¼ˆæ¯æœˆå‡ å·ï¼‰"
}),
/*#__PURE__*/ _jsx("select", {
id: "bill-day",
value: formData.day,
onChange: (e)=>setFormData({
...formData,
day: e.target.value
}),
disabled: submitting || deleting,
children: days.map((day)=>/*#__PURE__*/ _jsxs("option", {
value: day,
children: [
day,
" æ—¥"
]
}, day))
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
htmlFor: "bill-note",
children: "备注(å¯é€‰ï¼‰"
}),
/*#__PURE__*/ _jsx("input", {
id: "bill-note",
type: "text",
value: formData.note,
onChange: (e)=>setFormData({
...formData,
note: e.target.value
}),
placeholder: "添加备注...",
disabled: submitting || deleting
})
]
}),
editingBill && /*#__PURE__*/ _jsx("div", {
className: "form-group form-group--inline",
children: /*#__PURE__*/ _jsxs("label", {
className: "checkbox-label",
children: [
/*#__PURE__*/ _jsx("input", {
type: "checkbox",
checked: formData.is_active,
onChange: (e)=>setFormData({
...formData,
is_active: e.target.checked
}),
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"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
}),
editingBill && /*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-danger",
onClick: handleDelete,
disabled: submitting || deleting,
children: deleting ? "删除中..." : "删除"
})
]
})
]
})
]
})
})
]
});
}
}#062undefined64107undefined109148undefined150291undefined293347undefined349394undefined396438undefined440494undefined496554undefined556570undefined613621__WEBPACK_MODULE_REFERENCE__7_5b22757365526f75746572225d_call_directImport_asiSafe1__._undefined652659__WEBPACK_MODULE_REFERENCE__12_5b22757365546f617374225d_call_directImport_asiSafe1__._undefined688697__WEBPACK_MODULE_REFERENCE__13_5b22757365436f6e6669726d225d_call_directImport_asiSafe1__._undefined732739__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined784791__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined843850__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined893900__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined949956__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined10021009__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined10591066__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11131120__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11631170__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined14241440__WEBPACK_MODULE_REFERENCE__8_5b22676574526563757272696e6742696c6c73225d_call_directImport_asiSafe1__._undefined31743192__WEBPACK_MODULE_REFERENCE__8_5b22757064617465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._undefined33553373__WEBPACK_MODULE_REFERENCE__8_5b22637265617465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._undefined40944112__WEBPACK_MODULE_REFERENCE__8_5b2264656c657465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._undefined45824599__WEBPACK_MODULE_REFERENCE__8_5b226170706c79526563757272696e6742696c6c225d_call_directImport_asiSafe1__._undefined49835001__WEBPACK_MODULE_REFERENCE__8_5b22757064617465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._undefined54865489__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined56685671__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined56735676__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined57765780__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined57825789__WEBPACK_MODULE_REFERENCE__10_5b2264656661756c74225d_directImport_asiSafe1__._undefined59615964__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined61116115__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined62536256__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined63716374__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined63766379__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined65506553__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined66646667__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined68426846__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined69716974__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined71127116__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined72137216__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined74187422__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined77717774__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined79357952__WEBPACK_MODULE_REFERENCE__9_5b2244454641554c545f43415445474f52494553225d_directImport_asiSafe1__._undefined81978201__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined85158519__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined87048707__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asi
;// CONCATENATED MODULE: ./node_modules/next/dist/build/webpack/loaders/next-route-loader/index.js?kind=PAGES&page=%2Frecurring&preferredRegion=&absolutePagePath=private-next-pages%2Frecurring.js&absoluteAppPath=private-next-pages%2F_app.js&absoluteDocumentPath=next%2Fdist%2Fpages%2F_document&middlewareConfigBase64=e30%3D!
úûì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/recurring.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: "/recurring",
pathname: "/recurring",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App,
Document
},
userland
});
//# sourceMappingURL=pages.js.mapú 094undefined96158undefined160217undefined259307undefined309353undefined384443undefined504518/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (undefined504518undefined519523__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined525532__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined545545.5);undefined569575undefined599603__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined605612__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined634640undefined664668__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined670677__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined699705undefined733737__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined739746__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined772778undefined794798__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined800807__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined821827undefined852856__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined858865__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined917923undefined956960__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined962969__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined10001006undefined10391043__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined10451052__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined10831089undefined11231127__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined11291136__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined11681174undefined12071211__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined12131220__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined12511257undefined12941298__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined13001307__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined14031409undefined14341449__WEBPACK_MODULE_REFERENCE__0_5b225061676573526f7574654d6f64756c65225d_directImport_asiSafe1__._undefined14851493__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined16951694: __WEBPACK_MODULE_REFERENCE__4_5b2264656661756c74225d_directImport_asiSafe1__._undefined17131712: __WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined17331732: __WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefinedJ169194next_route_loaderkind_PAGES_page_2Frecurring_preferredRegion_absolutePagePath_private_next_pages_2Frecurring_js_absoluteAppPath_private_next_pages_2F_app_js_absoluteDocumentPath_next_2Fdist_2Fpages_2F_document_middlewareConfigBase64_e30_3D_undefined199277(0,helpers/* hoist */.l)undefined279324recurring_namespaceObjectundefined385463(0,helpers/* hoist */.l)undefined465510recurring_namespaceObjectundefined555633(0,helpers/* hoist */.l)undefined635680recurring_namespaceObjectundefined729807(0,helpers/* hoist */.l)undefined809854recurring_namespaceObjectundefined895973(0,helpers/* hoist */.l)undefined9751020recurring_namespaceObjectundefined10581136(0,helpers/* hoist */.l)undefined11381183recurring_namespaceObjectundefined12671345(0,helpers/* hoist */.l)undefined13471392recurring_namespaceObjectundefined14551533(0,helpers/* hoist */.l)undefined15351580recurring_namespaceObjectundefined16441722(0,helpers/* hoist */.l)undefined17241769recurring_namespaceObjectundefined18331911(0,helpers/* hoist */.l)undefined19131958recurring_namespaceObjectundefined20252103(0,helpers/* hoist */.l)undefined21052150recurring_namespaceObjectundefined22702365module_compiled.PagesRouteModuleundefined24012469route_kind/* RouteKind */.xundefined26732750_app["default"]undefined27712848(_document_default())undefined28712916recurring_namespaceObjectundefined RawSource
/***/ }),
/***/ 2204:
 ä«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourceQ/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
«webpack/lib/util/registerExternalSerializerœwebpack-sources/CachedSource ò «webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourcež/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
«webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourceZexport const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
†buffer†source„size„maps„hashñ/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
”{"finalSource":true}ƒmapbufferedMap ConcatSourceRawSourcež/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
ReplaceSourceRawSourceZexport const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
 06undefined
/***/ }) åL /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
/***/ }) æé  êëêž/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
íZexport const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
 06undefinedóô,
/***/ 2785:
 "«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
Qmodule.exports = require("next/dist/compiled/next-server/pages.runtime.prod.js"); 
/***/ }) Úq/***/ ((module) => {
module.exports = require("next/dist/compiled/next-server/pages.runtime.prod.js");
/***/ }) ÛÞ ß/***/ ((module) => {
êQmodule.exports = require("next/dist/compiled/next-server/pages.runtime.prod.js");éê,
/***/ 6689:
 ó«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
"module.exports = require("react"); 
/***/ }) ÐB/***/ ((module) => {
module.exports = require("react");
/***/ }) ÑÔ Õöá"module.exports = require("react");àá,
/***/ 6405:
 ÷«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
&module.exports = require("react-dom"); 
/***/ }) ÇF/***/ ((module) => {
module.exports = require("react-dom");
/***/ }) ÈË ÌíØ&module.exports = require("react-dom");ר,
/***/ 997:
 ÿ«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
.module.exports = require("react/jsx-runtime"); 
/***/ }) ¾N/***/ ((module) => {
module.exports = require("react/jsx-runtime");
/***/ }) ¿Â ÃäÏ.module.exports = require("react/jsx-runtime");ÎÏ,
/***/ 2048:
 ð«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
module.exports = require("fs"); 
/***/ }) µ?/***/ ((module) => {
module.exports = require("fs");
/***/ }) ¹ ºÛÆmodule.exports = require("fs");ÅÆ,
/***/ 5315:
 ò«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
!module.exports = require("path"); 
/***/ }) ¬A/***/ ((module) => {
module.exports = require("path");
/***/ }) ­° ±Ò½!module.exports = require("path");¼½,
/***/ 6162:
 ô«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
#module.exports = require("stream"); 
/***/ }) £C/***/ ((module) => {
module.exports = require("stream");
/***/ }) ¤§ ¨É´#module.exports = require("stream");³´,
/***/ 1568:
 ò«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
!module.exports = require("zlib"); 
/***/ }) šA/***/ ((module) => {
module.exports = require("zlib");
/***/ }) ž ŸÀ«!module.exports = require("zlib");ª«t
};
;
// load runtime
var __webpack_require__ = require("../webpack-runtime.js");
__webpack_require__.C(exports);
¿var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId))
var __webpack_exports__ = __webpack_require__.X(0, [899,342,261], () => (__webpack_exec__(671)));
,module.exports = __webpack_exports__;
})();  Äz"use strict";
(() => {
var exports = {};
exports.id = 845;
exports.ids = [845,660];
exports.modules = {
/***/ 671:
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
config: () => (/* binding */ config),
"default": () => (/* binding */ next_route_loaderkind_PAGES_page_2Frecurring_preferredRegion_absolutePagePath_private_next_pages_2Frecurring_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/recurring.js
var recurring_namespaceObject = {};
__webpack_require__.r(recurring_namespaceObject);
__webpack_require__.d(recurring_namespaceObject, {
"default": () => (Recurring)
});
// 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/recurring.js
function Recurring() {
const router = (0,next_router.useRouter)();
const { showToast } = (0,ToastProvider/* useToast */.p)();
const { confirm } = (0,ConfirmProvider/* useConfirm */.N)();
const [bills, setBills] = (0,external_react_.useState)([]);
const [modalOpen, setModalOpen] = (0,external_react_.useState)(false);
const [editingBill, setEditingBill] = (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 [applyingId, setApplyingId] = (0,external_react_.useState)(null);
const [formError, setFormError] = (0,external_react_.useState)("");
const [formData, setFormData] = (0,external_react_.useState)({
type: "expense",
amount: "",
category: "",
day: "1",
note: "",
is_active: true
});
null;
const loadBills = async ()=>{
setLoading(true);
try {
const data = await (0,api/* getRecurringBills */.Vn)();
setBills(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const openAddModal = ()=>{
setEditingBill(null);
setFormData({
type: "expense",
amount: "",
category: "",
day: "1",
note: "",
is_active: true
});
setFormError("");
setModalOpen(true);
};
const openEditModal = (bill)=>{
setEditingBill(bill);
setFormData({
type: bill.type,
amount: bill.amount.toString(),
category: bill.category,
day: bill.day.toString(),
note: bill.note || "",
is_active: !!bill.is_active
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting || deleting) return;
setModalOpen(false);
setEditingBill(null);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.amount || !formData.category || !formData.day) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
const data = {
type: formData.type,
amount: parseFloat(formData.amount),
category: formData.category,
day: parseInt(formData.day),
note: formData.note,
is_active: formData.is_active ? 1 : 0
};
if (editingBill) {
await (0,api/* updateRecurringBill */.uO)(editingBill.id, data);
showToast("周期账å•已更新", {
tone: "success"
});
} else {
await (0,api/* createRecurringBill */.z0)(data);
showToast("周期账å•已创建", {
tone: "success"
});
}
closeModal();
await loadBills();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async ()=>{
if (!editingBill) return;
const shouldDelete = await confirm({
title: "删除这æ¡å‘¨æœŸè´¦å•?",
description: "删除åŽå°†æ— æ³•æ¢å¤ï¼Œè¯·ç¡®è®¤æ˜¯å¦ç»§ç»­ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
setDeleting(true);
try {
await (0,api/* deleteRecurringBill */.TZ)(editingBill.id);
closeModal();
showToast("周期账å•已删除", {
tone: "success"
});
await loadBills();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setDeleting(false);
}
};
const handleApply = async (id)=>{
setApplyingId(id);
try {
await (0,api/* applyRecurringBill */.Xu)(id);
showToast("已添加到账目", {
tone: "success"
});
} catch (err) {
showToast(err.message, {
tone: "error"
});
} finally{
setApplyingId(null);
}
};
const handleToggleActive = async (bill, event)=>{
event.stopPropagation();
try {
await (0,api/* updateRecurringBill */.uO)(bill.id, {
...bill,
is_active: bill.is_active ? 0 : 1
});
showToast(bill.is_active ? "å·²åœç”¨å‘¨æœŸè´¦å•" : "å·²å¯ç”¨å‘¨æœŸè´¦å•", {
tone: "success"
});
await loadBills();
} catch (err) {
showToast(err.message, {
tone: "error"
});
}
};
const days = Array.from({
length: 28
}, (_, index)=>index + 1);
const actions = /*#__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
})
});
return /*#__PURE__*/ (0,jsx_runtime_.jsxs)(AppShell/* default */.Z, {
title: "周期账å•",
subtitle: "管ç†å›ºå®šæ”¶å…¥ä¸Žæ”¯å‡ºèŠ‚å¥",
actions: actions,
compactHeader: true,
children: [
loading ? /*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "card loading-state",
children: "加载中..."
}) : bills.length === 0 ? /*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "repeat",
size: 24
})
}),
/*#__PURE__*/ jsx_runtime_.jsx("p", {
children: "暂无周期性账å•"
}),
/*#__PURE__*/ jsx_runtime_.jsx("p", {
className: "sub",
children: "点击å³ä¸‹è§’新增定期收入或支出。"
})
]
}) : /*#__PURE__*/ (0,jsx_runtime_.jsxs)("section", {
className: "card section-card",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "section-heading section-heading--compact",
children: /*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
children: [
/*#__PURE__*/ jsx_runtime_.jsx("p", {
className: "eyebrow",
children: "è´¦å•列表"
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("h2", {
children: [
bills.length,
" æ¡å‘¨æœŸè´¦å•"
]
})
]
})
}),
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "bills-list",
children: bills.map((bill)=>{
const categories = lib_categories/* DEFAULT_CATEGORIES */.S[bill.type];
const cat = categories.find((item)=>item.name === bill.category) || {
icon: "\uD83D\uDCDD"
};
return /*#__PURE__*/ (0,jsx_runtime_.jsxs)("button", {
type: "button",
className: `bill-item ${bill.is_active ? "" : "inactive"}`,
onClick: ()=>openEditModal(bill),
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "bill-left",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "bill-icon",
children: cat.icon
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "bill-info",
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "bill-row",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "bill-category",
children: bill.category
}),
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: `status-chip ${bill.is_active ? "status-chip--success" : ""}`,
children: bill.is_active ? "å¯ç”¨ä¸­" : "å·²åœç”¨"
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "bill-day",
children: [
"æ¯æœˆ ",
bill.day,
" æ—¥"
]
}),
bill.note && /*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "bill-note",
children: bill.note
})
]
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "bill-right",
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: `bill-amount ${bill.type}`,
children: [
bill.type === "income" ? "+" : "-",
bill.amount.toFixed(2)
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "bill-actions",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline btn-small",
onClick: (e)=>{
e.stopPropagation();
handleApply(bill.id);
},
disabled: applyingId === bill.id,
children: applyingId === bill.id ? "应用中..." : "应用"
}),
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: "btn btn-ghost btn-inline btn-small",
onClick: (event)=>handleToggleActive(bill, event),
children: bill.is_active ? "åœç”¨" : "å¯ç”¨"
})
]
})
]
})
]
}, bill.id);
})
})
]
}),
/*#__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",
onClick: closeModal,
children: /*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "modal",
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: editingBill ? "编辑账å•" : "新增账å•"
}),
/*#__PURE__*/ jsx_runtime_.jsx("h2", {
children: editingBill ? "更新周期账å•" : "创建周期账å•"
})
]
}),
/*#__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,
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "type-switch",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: `type-btn expense ${formData.type === "expense" ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
type: "expense",
category: ""
}),
disabled: submitting || deleting,
children: "支出"
}),
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: `type-btn income ${formData.type === "income" ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
type: "income",
category: ""
}),
disabled: submitting || deleting,
children: "æ”¶å…¥"
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
htmlFor: "bill-amount",
children: "金é¢"
}),
/*#__PURE__*/ jsx_runtime_.jsx("input", {
id: "bill-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__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
children: "分类"
}),
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "category-grid",
children: lib_categories/* DEFAULT_CATEGORIES */.S[formData.type].map((cat)=>/*#__PURE__*/ (0,jsx_runtime_.jsxs)("button", {
type: "button",
className: `category-btn ${formData.category === cat.name ? "active" : ""}`,
onClick: ()=>setFormData({
...formData,
category: cat.name
}),
disabled: submitting || deleting,
children: [
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "icon",
children: cat.icon
}),
/*#__PURE__*/ jsx_runtime_.jsx("span", {
children: cat.name
})
]
}, cat.name))
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
htmlFor: "bill-day",
children: "æ—¥æœŸï¼ˆæ¯æœˆå‡ å·ï¼‰"
}),
/*#__PURE__*/ jsx_runtime_.jsx("select", {
id: "bill-day",
value: formData.day,
onChange: (e)=>setFormData({
...formData,
day: e.target.value
}),
disabled: submitting || deleting,
children: days.map((day)=>/*#__PURE__*/ (0,jsx_runtime_.jsxs)("option", {
value: day,
children: [
day,
" æ—¥"
]
}, day))
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("label", {
htmlFor: "bill-note",
children: "备注(å¯é€‰ï¼‰"
}),
/*#__PURE__*/ jsx_runtime_.jsx("input", {
id: "bill-note",
type: "text",
value: formData.note,
onChange: (e)=>setFormData({
...formData,
note: e.target.value
}),
placeholder: "添加备注...",
disabled: submitting || deleting
})
]
}),
editingBill && /*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "form-group form-group--inline",
children: /*#__PURE__*/ (0,jsx_runtime_.jsxs)("label", {
className: "checkbox-label",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("input", {
type: "checkbox",
checked: formData.is_active,
onChange: (e)=>setFormData({
...formData,
is_active: e.target.checked
}),
disabled: submitting || deleting
}),
¯ç”¨æ­¤è´¦å•"
]
})
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "submit",
className: "btn btn-primary",
disabled: submitting || deleting,
children: submitting ? /*#__PURE__*/ (0,jsx_runtime_.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
}),
editingBill && /*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "button",
className: "btn btn-danger",
onClick: handleDelete,
disabled: submitting || deleting,
children: deleting ? "删除中..." : "删除"
})
]
})
]
})
]
})
})
]
});
}
;// CONCATENATED MODULE: ./node_modules/next/dist/build/webpack/loaders/next-route-loader/index.js?kind=PAGES&page=%2Frecurring&preferredRegion=&absolutePagePath=private-next-pages%2Frecurring.js&absoluteAppPath=private-next-pages%2F_app.js&absoluteDocumentPath=next%2Fdist%2Fpages%2F_document&middlewareConfigBase64=e30%3D!
// Import the app and document modules.
// Import the userland code.
// Re-export the component (should be the default export).
/* harmony default export */ const next_route_loaderkind_PAGES_page_2Frecurring_preferredRegion_absolutePagePath_private_next_pages_2Frecurring_js_absoluteAppPath_private_next_pages_2F_app_js_absoluteDocumentPath_next_2Fdist_2Fpages_2F_document_middlewareConfigBase64_e30_3D_ = ((0,helpers/* hoist */.l)(recurring_namespaceObject, "default"));
// Re-export methods.
const getStaticProps = (0,helpers/* hoist */.l)(recurring_namespaceObject, "getStaticProps");
const getStaticPaths = (0,helpers/* hoist */.l)(recurring_namespaceObject, "getStaticPaths");
const getServerSideProps = (0,helpers/* hoist */.l)(recurring_namespaceObject, "getServerSideProps");
const config = (0,helpers/* hoist */.l)(recurring_namespaceObject, "config");
const reportWebVitals = (0,helpers/* hoist */.l)(recurring_namespaceObject, "reportWebVitals");
// Re-export legacy methods.
const unstable_getStaticProps = (0,helpers/* hoist */.l)(recurring_namespaceObject, "unstable_getStaticProps");
const unstable_getStaticPaths = (0,helpers/* hoist */.l)(recurring_namespaceObject, "unstable_getStaticPaths");
const unstable_getStaticParams = (0,helpers/* hoist */.l)(recurring_namespaceObject, "unstable_getStaticParams");
const unstable_getServerProps = (0,helpers/* hoist */.l)(recurring_namespaceObject, "unstable_getServerProps");
const unstable_getServerSideProps = (0,helpers/* hoist */.l)(recurring_namespaceObject, "unstable_getServerSideProps");
// Create and export the route module that will be consumed.
const routeModule = new module_compiled.PagesRouteModule({
definition: {
kind: route_kind/* RouteKind */.x.PAGES,
page: "/recurring",
pathname: "/recurring",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App: _app["default"],
Document: (_document_default())
},
userland: recurring_namespaceObject
});
//# sourceMappingURL=pages.js.map
/***/ }),
/***/ 2204:
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
/***/ }),
/***/ 2785:
/***/ ((module) => {
module.exports = require("next/dist/compiled/next-server/pages.runtime.prod.js");
/***/ }),
/***/ 6689:
/***/ ((module) => {
module.exports = require("react");
/***/ }),
/***/ 6405:
/***/ ((module) => {
module.exports = require("react-dom");
/***/ }),
/***/ 997:
/***/ ((module) => {
module.exports = require("react/jsx-runtime");
/***/ }),
/***/ 2048:
/***/ ((module) => {
module.exports = require("fs");
/***/ }),
/***/ 5315:
/***/ ((module) => {
module.exports = require("path");
/***/ }),
/***/ 6162:
/***/ ((module) => {
module.exports = require("stream");
/***/ }),
/***/ 1568:
/***/ ((module) => {
module.exports = require("zlib");
/***/ })
};
;
// load runtime
var __webpack_require__ = require("../webpack-runtime.js");
__webpack_require__.C(exports);
var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId))
var __webpack_exports__ = __webpack_require__.X(0, [899,342,261], () => (__webpack_exec__(671)));
module.exports = __webpack_exports__;
})(); × È  `dÉt"use strict";
(() => {
var exports = {};
exports.id = 845;
exports.ids = [845,660];
exports.modules = {
/***/ 671:
ÈØÈé
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
config: () => (/* binding */ config),
"default": () => (/* binding */ next_route_loaderkind_PAGES_page_2Frecurring_preferredRegion_absolutePagePath_private_next_pages_2Frecurring_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/recurring.js
var recurring_namespaceObject = {};
__webpack_require__.r(recurring_namespaceObject);
__webpack_require__.d(recurring_namespaceObject, {
"default": () => (Recurring)
});
// 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/recurring.js
ÙÉkimport { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import { isLoggedIn, getRecurringBills, createRecurringBill, updateRecurringBill, deleteRecurringBill, applyRecurringBill } 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 Recurring() {
const router = useRouter();
const { showToast } = useToast();
const { confirm } = useConfirm();
const [bills, setBills] = useState([]);
const [modalOpen, setModalOpen] = useState(false);
const [editingBill, setEditingBill] = useState(null);
const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false);
const [deleting, setDeleting] = useState(false);
const [applyingId, setApplyingId] = useState(null);
const [formError, setFormError] = useState("");
const [formData, setFormData] = useState({
type: "expense",
amount: "",
category: "",
day: "1",
note: "",
is_active: true
});
null;
const loadBills = async ()=>{
setLoading(true);
try {
const data = await getRecurringBills();
setBills(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const openAddModal = ()=>{
setEditingBill(null);
setFormData({
type: "expense",
amount: "",
category: "",
day: "1",
note: "",
is_active: true
});
setFormError("");
setModalOpen(true);
};
const openEditModal = (bill)=>{
setEditingBill(bill);
setFormData({
type: bill.type,
amount: bill.amount.toString(),
category: bill.category,
day: bill.day.toString(),
note: bill.note || "",
is_active: !!bill.is_active
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting || deleting) return;
setModalOpen(false);
setEditingBill(null);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.amount || !formData.category || !formData.day) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
const data = {
type: formData.type,
amount: parseFloat(formData.amount),
category: formData.category,
day: parseInt(formData.day),
note: formData.note,
is_active: formData.is_active ? 1 : 0
};
if (editingBill) {
await updateRecurringBill(editingBill.id, data);
showToast("周期账å•已更新", {
tone: "success"
});
} else {
await createRecurringBill(data);
showToast("周期账å•已创建", {
tone: "success"
});
}
closeModal();
await loadBills();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async ()=>{
if (!editingBill) return;
const shouldDelete = await confirm({
title: "删除这æ¡å‘¨æœŸè´¦å•?",
description: "删除åŽå°†æ— æ³•æ¢å¤ï¼Œè¯·ç¡®è®¤æ˜¯å¦ç»§ç»­ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
setDeleting(true);
try {
await deleteRecurringBill(editingBill.id);
closeModal();
showToast("周期账å•已删除", {
tone: "success"
});
await loadBills();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setDeleting(false);
}
};
const handleApply = async (id)=>{
setApplyingId(id);
try {
await applyRecurringBill(id);
showToast("已添加到账目", {
tone: "success"
});
} catch (err) {
showToast(err.message, {
tone: "error"
});
} finally{
setApplyingId(null);
}
};
const handleToggleActive = async (bill, event)=>{
event.stopPropagation();
try {
await updateRecurringBill(bill.id, {
...bill,
is_active: bill.is_active ? 0 : 1
});
showToast(bill.is_active ? "å·²åœç”¨å‘¨æœŸè´¦å•" : "å·²å¯ç”¨å‘¨æœŸè´¦å•", {
tone: "success"
});
await loadBills();
} catch (err) {
showToast(err.message, {
tone: "error"
});
}
};
const days = Array.from({
length: 28
}, (_, index)=>index + 1);
const actions = /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "设置",
onClick: ()=>router.push("/settings"),
children: /*#__PURE__*/ _jsx(Icon, {
name: "settings",
size: 18
})
});
return /*#__PURE__*/ _jsxs(AppShell, {
title: "周期账å•",
subtitle: "管ç†å›ºå®šæ”¶å…¥ä¸Žæ”¯å‡ºèŠ‚å¥",
actions: actions,
compactHeader: true,
children: [
loading ? /*#__PURE__*/ _jsx("div", {
className: "card loading-state",
children: "加载中..."
}) : bills.length === 0 ? /*#__PURE__*/ _jsxs("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ _jsx(Icon, {
name: "repeat",
size: 24
})
}),
/*#__PURE__*/ _jsx("p", {
children: "暂无周期性账å•"
}),
/*#__PURE__*/ _jsx("p", {
className: "sub",
children: "点击å³ä¸‹è§’新增定期收入或支出。"
})
]
}) : /*#__PURE__*/ _jsxs("section", {
className: "card section-card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "section-heading section-heading--compact",
children: /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: "è´¦å•列表"
}),
/*#__PURE__*/ _jsxs("h2", {
children: [
bills.length,
" æ¡å‘¨æœŸè´¦å•"
]
})
]
})
}),
/*#__PURE__*/ _jsx("div", {
className: "bills-list",
children: bills.map((bill)=>{
const categories = DEFAULT_CATEGORIES[bill.type];
const cat = categories.find((item)=>item.name === bill.category) || {
icon: "\uD83D\uDCDD"
};
return /*#__PURE__*/ _jsxs("button", {
type: "button",
className: `bill-item ${bill.is_active ? "" : "inactive"}`,
onClick: ()=>openEditModal(bill),
children: [
/*#__PURE__*/ _jsxs("div", {
className: "bill-left",
children: [
/*#__PURE__*/ _jsx("div", {
className: "bill-icon",
children: cat.icon
}),
/*#__PURE__*/ _jsxs("div", {
className: "bill-info",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "bill-row",
children: [
/*#__PURE__*/ _jsx("div", {
className: "bill-category",
children: bill.category
}),
/*#__PURE__*/ _jsx("span", {
className: `status-chip ${bill.is_active ? "status-chip--success" : ""}`,
children: bill.is_active ? "å¯ç”¨ä¸­" : "å·²åœç”¨"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bill-day",
children: [
"æ¯æœˆ ",
bill.day,
" æ—¥"
]
}),
bill.note && /*#__PURE__*/ _jsx("div", {
className: "bill-note",
children: bill.note
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bill-right",
children: [
/*#__PURE__*/ _jsxs("div", {
className: `bill-amount ${bill.type}`,
children: [
bill.type === "income" ? "+" : "-",
bill.amount.toFixed(2)
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bill-actions",
children: [
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline btn-small",
onClick: (e)=>{
e.stopPropagation();
handleApply(bill.id);
},
disabled: applyingId === bill.id,
children: applyingId === bill.id ? "应用中..." : "应用"
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-ghost btn-inline btn-small",
onClick: (event)=>handleToggleActive(bill, event),
children: bill.is_active ? "åœç”¨" : "å¯ç”¨"
})
]
})
]
})
]
}, bill.id);
})
})
]
}),
/*#__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",
onClick: closeModal,
children: /*#__PURE__*/ _jsxs("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
children: [
/*#__PURE__*/ _jsxs("div", {
className: "modal-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: editingBill ? "编辑账å•" : "新增账å•"
}),
/*#__PURE__*/ _jsx("h2", {
children: editingBill ? "更新周期账å•" : "创建周期账å•"
})
]
}),
/*#__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: "bill-amount",
children: "金é¢"
}),
/*#__PURE__*/ _jsx("input", {
id: "bill-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", {
htmlFor: "bill-day",
children: "æ—¥æœŸï¼ˆæ¯æœˆå‡ å·ï¼‰"
}),
/*#__PURE__*/ _jsx("select", {
id: "bill-day",
value: formData.day,
onChange: (e)=>setFormData({
...formData,
day: e.target.value
}),
disabled: submitting || deleting,
children: days.map((day)=>/*#__PURE__*/ _jsxs("option", {
value: day,
children: [
day,
" æ—¥"
]
}, day))
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
htmlFor: "bill-note",
children: "备注(å¯é€‰ï¼‰"
}),
/*#__PURE__*/ _jsx("input", {
id: "bill-note",
type: "text",
value: formData.note,
onChange: (e)=>setFormData({
...formData,
note: e.target.value
}),
placeholder: "添加备注...",
disabled: submitting || deleting
})
]
}),
editingBill && /*#__PURE__*/ _jsx("div", {
className: "form-group form-group--inline",
children: /*#__PURE__*/ _jsxs("label", {
className: "checkbox-label",
children: [
/*#__PURE__*/ _jsx("input", {
type: "checkbox",
checked: formData.is_active,
onChange: (e)=>setFormData({
...formData,
is_active: e.target.checked
}),
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"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
}),
editingBill && /*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-danger",
onClick: handleDelete,
disabled: submitting || deleting,
children: deleting ? "删除中..." : "删除"
})
]
})
]
})
]
})
})
]
});
}
}#062undefined64107undefined109148undefined150291undefined293347undefined349394undefined396438undefined440494undefined496554undefined556570undefined613621__WEBPACK_MODULE_REFERENCE__7_5b22757365526f75746572225d_call_directImport_asiSafe1__._undefined652659__WEBPACK_MODULE_REFERENCE__12_5b22757365546f617374225d_call_directImport_asiSafe1__._undefined688697__WEBPACK_MODULE_REFERENCE__13_5b22757365436f6e6669726d225d_call_directImport_asiSafe1__._undefined732739__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined784791__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined843850__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined893900__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined949956__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined10021009__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined10591066__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11131120__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11631170__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined14241440__WEBPACK_MODULE_REFERENCE__8_5b22676574526563757272696e6742696c6c73225d_call_directImport_asiSafe1__._undefined31743192__WEBPACK_MODULE_REFERENCE__8_5b22757064617465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._undefined33553373__WEBPACK_MODULE_REFERENCE__8_5b22637265617465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._undefined40944112__WEBPACK_MODULE_REFERENCE__8_5b2264656c657465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._undefined45824599__WEBPACK_MODULE_REFERENCE__8_5b226170706c79526563757272696e6742696c6c225d_call_directImport_asiSafe1__._undefined49835001__WEBPACK_MODULE_REFERENCE__8_5b22757064617465526563757272696e6742696c6c225d_call_directImport_asiSafe1__._undefined54865489__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined56685671__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined56735676__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined57765780__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined57825789__WEBPACK_MODULE_REFERENCE__10_5b2264656661756c74225d_directImport_asiSafe1__._undefined59615964__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined61116115__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined62536256__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined63716374__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined63766379__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined65506553__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined66646667__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined68426846__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined69716974__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined71127116__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined72137216__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined74187422__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined77717774__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined79357952__WEBPACK_MODULE_REFERENCE__9_5b2244454641554c545f43415445474f52494553225d_directImport_asiSafe1__._undefined81978201__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined85158519__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined87048707__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asi
;// CONCATENATED MODULE: ./node_modules/next/dist/build/webpack/loaders/next-route-loader/index.js?kind=PAGES&page=%2Frecurring&preferredRegion=&absolutePagePath=private-next-pages%2Frecurring.js&absoluteAppPath=private-next-pages%2F_app.js&absoluteDocumentPath=next%2Fdist%2Fpages%2F_document&middlewareConfigBase64=e30%3D!
ÕÅì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/recurring.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: "/recurring",
pathname: "/recurring",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App,
Document
},
userland
});
//# sourceMappingURL=pages.js.mapú 094undefined96158undefined160217undefined259307undefined309353undefined384443undefined504518/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (undefined504518undefined519523__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined525532__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined545545.5);undefined569575undefined599603__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined605612__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined634640undefined664668__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined670677__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined699705undefined733737__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined739746__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined772778undefined794798__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined800807__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined821827undefined852856__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined858865__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined917923undefined956960__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined962969__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined10001006undefined10391043__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined10451052__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined10831089undefined11231127__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined11291136__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined11681174undefined12071211__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined12131220__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined12511257undefined12941298__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined13001307__WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefined14031409undefined14341449__WEBPACK_MODULE_REFERENCE__0_5b225061676573526f7574654d6f64756c65225d_directImport_asiSafe1__._undefined14851493__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined16951694: __WEBPACK_MODULE_REFERENCE__4_5b2264656661756c74225d_directImport_asiSafe1__._undefined17131712: __WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined17331732: __WEBPACK_MODULE_REFERENCE__14_ns_asiSafe1__._undefinedJ169194next_route_loaderkind_PAGES_page_2Frecurring_preferredRegion_absolutePagePath_private_next_pages_2Frecurring_js_absoluteAppPath_private_next_pages_2F_app_js_absoluteDocumentPath_next_2Fdist_2Fpages_2F_document_middlewareConfigBase64_e30_3D_undefined199277(0,helpers/* hoist */.l)undefined279324recurring_namespaceObjectundefined385463(0,helpers/* hoist */.l)undefined465510recurring_namespaceObjectundefined555633(0,helpers/* hoist */.l)undefined635680recurring_namespaceObjectundefined729807(0,helpers/* hoist */.l)undefined809854recurring_namespaceObjectundefined895973(0,helpers/* hoist */.l)undefined9751020recurring_namespaceObjectundefined10581136(0,helpers/* hoist */.l)undefined11381183recurring_namespaceObjectundefined12671345(0,helpers/* hoist */.l)undefined13471392recurring_namespaceObjectundefined14551533(0,helpers/* hoist */.l)undefined15351580recurring_namespaceObjectundefined16441722(0,helpers/* hoist */.l)undefined17241769recurring_namespaceObjectundefined18331911(0,helpers/* hoist */.l)undefined19131958recurring_namespaceObjectundefined20252103(0,helpers/* hoist */.l)undefined21052150recurring_namespaceObjectundefined22702365module_compiled.PagesRouteModuleundefined24012469route_kind/* RouteKind */.xundefined26732750_app["default"]undefined27712848(_document_default())undefined28712916recurring_namespaceObjectundefinedÚÛÚÜÀÐÀÁÂlÿÿÿÃÚÛÚÝÀÞÚßÚÛÚàÀÞÚáÚÛÚâÀÞÚãÚÛÚäÀÞÚåÚÛÚæÀÞÚçÚÛÚèÀÞÚéÚÛÚêÀÞÚëÚÛÚ
var __webpack_exports__ = __webpack_require__.X(0, [899,342,261], () => (__webpack_exec__(671)));
Ùï «webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource`«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourceu"use strict";
(() => {
var exports = {};
exports.id = 603;
exports.ids = [603,660];
exports.modules = {
/***/ 1076:
«webpack/lib/util/registerExternalSerializerœwebpack-sources/CachedSource «webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourceQ/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
«webpack/lib/util/registerExternalSerializerœwebpack-sources/CachedSource I«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourcel
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
config: () => (/* binding */ config),
"default": () => (/* binding */ next_route_loaderkind_PAGES_page_2Fsearch_preferredRegion_absolutePagePath_private_next_pages_2Fsearch_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/search.js
var search_namespaceObject = {};
__webpack_require__.r(search_namespaceObject);
__webpack_require__.d(search_namespaceObject, {
"default": () => (Search)
});
// 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);
;// CONCATENATED MODULE: ./pages/search.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/RawSourceF4import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import { isLoggedIn, searchRecords } from "../lib/api";
import { DEFAULT_CATEGORIES } from "../lib/categories";
import AppShell from "../components/AppShell";
import { Icon } from "../components/icons";
import { useToast } from "../components/ToastProvider";
export default function Search() {
const router = useRouter();
const { showToast } = useToast();
const [keyword, setKeyword] = useState("");
const [results, setResults] = useState([]);
const [loading, setLoading] = useState(false);
null;
const handleSearch = async (e)=>{
e.preventDefault();
if (!keyword.trim()) {
showToast("请输入æœç´¢å…³é”®è¯", {
tone: "info"
});
return;
}
setLoading(true);
try {
const data = await searchRecords(keyword);
setResults(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const formatMoney = (num)=>(num || 0).toFixed(2);
const groupedResults = results.reduce((groups, record)=>{
const date = record.date.split(" ")[0];
if (!groups[date]) groups[date] = [];
groups[date].push(record);
return groups;
}, {});
const sortedDates = Object.keys(groupedResults).sort((a, b)=>b.localeCompare(a));
const totalIncome = results.filter((record)=>record.type === "income").reduce((sum, record)=>sum + record.amount, 0);
const totalExpense = results.filter((record)=>record.type === "expense").reduce((sum, record)=>sum + record.amount, 0);
const totalBalance = totalIncome - totalExpense;
const actions = /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "设置",
onClick: ()=>router.push("/settings"),
children: /*#__PURE__*/ _jsx(Icon, {
name: "settings",
size: 18
})
});
return /*#__PURE__*/ _jsxs(AppShell, {
title: "æœç´¢",
subtitle: "快速查找分类ã€å¤‡æ³¨ä¸Žé‡‘é¢",
actions: actions,
compactHeader: true,
children: [
/*#__PURE__*/ _jsxs("section", {
className: "card section-card section-card--search section-card--search-panel",
children: [
/*#__PURE__*/ _jsxs("form", {
className: "search-form search-form--refresh",
onSubmit: handleSearch,
children: [
/*#__PURE__*/ _jsxs("div", {
className: "search-input-wrap",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "search",
size: 18,
className: "search-input-wrap__icon"
}),
/*#__PURE__*/ _jsx("input", {
type: "text",
value: keyword,
onChange: (e)=>setKeyword(e.target.value),
placeholder: "æœç´¢åˆ†ç±»æˆ–备注...",
autoFocus: true,
disabled: loading
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "submit",
className: "btn btn-primary btn-inline",
disabled: loading,
children: loading ? /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
œç´¢ä¸­..."
]
}) : "æœç´¢"
})
]
}),
results.length > 0 ? /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "search-summary",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "search-stat",
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "æ”¶å…¥"
}),
/*#__PURE__*/ _jsxs("span", {
className: "value income",
children: [
"+",
formatMoney(totalIncome)
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "search-stat",
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "支出"
}),
/*#__PURE__*/ _jsxs("span", {
className: "value expense",
children: [
"-",
formatMoney(totalExpense)
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "search-stat",
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "结余"
}),
/*#__PURE__*/ _jsx("span", {
className: "value",
children: formatMoney(totalBalance)
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "results-count",
children: [
"找到 ",
results.length,
" æ¡è®°å½•"
]
})
]
}) : null
]
}),
loading ? /*#__PURE__*/ _jsx("div", {
className: "card loading-state",
children: "æœç´¢ä¸­..."
}) : results.length > 0 ? /*#__PURE__*/ _jsx("section", {
className: "card section-card",
children: /*#__PURE__*/ _jsx("div", {
className: "records-list records-list--flush",
children: sortedDates.map((date)=>/*#__PURE__*/ _jsxs("div", {
className: "date-group",
children: [
/*#__PURE__*/ _jsx("div", {
className: "date-label",
children: new Date(date).toLocaleDateString("zh-CN", {
month: "short",
day: "numeric",
weekday: "short"
})
}),
groupedResults[date].map((record)=>{
const categories = DEFAULT_CATEGORIES[record.type];
const cat = categories.find((item)=>item.name === record.category) || {
icon: "\uD83D\uDCDD"
};
return /*#__PURE__*/ _jsxs("div", {
className: "record-item record-item--static",
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))
})
}) : keyword ? /*#__PURE__*/ _jsxs("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ _jsx(Icon, {
name: "search",
size: 24
})
}),
/*#__PURE__*/ _jsx("p", {
children: "未找到相关记录"
})
]
}) : /*#__PURE__*/ _jsxs("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ _jsx(Icon, {
name: "search",
size: 24
})
}),
/*#__PURE__*/ _jsx("p", {
children: "输入关键è¯å¼€å§‹æœç´¢"
})
]
})
]
});
}
cBUW_«­ãåJLvx®°¾æî
;Bkr¢ÍÙŒBEG_J®²´»\ `

â
æ
­ ° ÇÊÆÊ}w{}ØÜ_†AD=A?Cþúþþ½À¹¼LP  ¢ ¥ !!¡!¥!;">"Q$b${%_%N&R&%'('J(N(9)<)˜**¢,¦,N/R/Ü/ß/R0U0W0Z011…1‰122‰2Œ2Ž22<3@?3×__WEBPACK_MODULE_REFERENCE__7_5b22757365526f75746572225d_call_directImport_asiSafe1__._Ö__WEBPACK_MODULE_REFERENCE__12_5b22757365546f617374225d_call_directImport_asiSafe1__._Õ__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._ÿÿß__WEBPACK_MODULE_REFERENCE__8_5b227365617263685265636f726473225d_call_directImport_asiSafe1__._Æ__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._ÿÉ__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._Í__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._Ï__WEBPACK_MODULE_REFERENCE__10_5b2264656661756c74225d_directImport_asiSafe1__._þþþüýüüþüýþÐ__WEBPACK_MODULE_REFERENCE__5_5b22467261676d656e74225d_directImport_asiSafe1__._ýýûýýûýýûûýûûûýûä__WEBPACK_MODULE_REFERENCE__9_5b2244454641554c545f43415445474f52494553225d_directImport_asiSafe1__._üüúüúúüüúúûúüúúûú†buffer†source„size„maps„hash+B
function Search() {
const router = __WEBPACK_MODULE_REFERENCE__7_5b22757365526f75746572225d_call_directImport_asiSafe1__._();
const { showToast } = __WEBPACK_MODULE_REFERENCE__12_5b22757365546f617374225d_call_directImport_asiSafe1__._();
const [keyword, setKeyword] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._("");
const [results, setResults] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._([]);
const [loading, setLoading] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._(false);
null;
const handleSearch = async (e)=>{
e.preventDefault();
if (!keyword.trim()) {
showToast("请输入æœç´¢å…³é”®è¯", {
tone: "info"
});
return;
}
setLoading(true);
try {
const data = await __WEBPACK_MODULE_REFERENCE__8_5b227365617263685265636f726473225d_call_directImport_asiSafe1__._(keyword);
setResults(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const formatMoney = (num)=>(num || 0).toFixed(2);
const groupedResults = results.reduce((groups, record)=>{
const date = record.date.split(" ")[0];
if (!groups[date]) groups[date] = [];
groups[date].push(record);
return groups;
}, {});
const sortedDates = Object.keys(groupedResults).sort((a, b)=>b.localeCompare(a));
const totalIncome = results.filter((record)=>record.type === "income").reduce((sum, record)=>sum + record.amount, 0);
const totalExpense = results.filter((record)=>record.type === "expense").reduce((sum, record)=>sum + record.amount, 0);
const totalBalance = totalIncome - totalExpense;
const actions = /*#__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
})
});
return /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__10_5b2264656661756c74225d_directImport_asiSafe1__._, {
title: "æœç´¢",
subtitle: "快速查找分类ã€å¤‡æ³¨ä¸Žé‡‘é¢",
actions: actions,
compactHeader: true,
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("section", {
className: "card section-card section-card--search section-card--search-panel",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("form", {
className: "search-form search-form--refresh",
onSubmit: handleSearch,
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "search-input-wrap",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._, {
name: "search",
size: 18,
className: "search-input-wrap__icon"
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("input", {
type: "text",
value: keyword,
onChange: (e)=>setKeyword(e.target.value),
placeholder: "æœç´¢åˆ†ç±»æˆ–备注...",
autoFocus: true,
disabled: loading
})
]
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("button", {
type: "submit",
className: "btn btn-primary btn-inline",
disabled: loading,
children: loading ? /*#__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"
}),
œç´¢ä¸­..."
]
}) : "æœç´¢"
})
]
}),
results.length > 0 ? /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__5_5b22467261676d656e74225d_directImport_asiSafe1__._, {
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "search-summary",
children: [
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "search-stat",
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(totalIncome)
]
})
]
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "search-stat",
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(totalExpense)
]
})
]
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "search-stat",
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(totalBalance)
})
]
})
]
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "results-count",
children: [
"找到 ",
results.length,
" æ¡è®°å½•"
]
})
]
}) : null
]
}),
loading ? /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "card loading-state",
children: "æœç´¢ä¸­..."
}) : results.length > 0 ? /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("section", {
className: "card section-card",
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_5b226a7378225d_directImport_asiSafe1__._("div", {
className: "date-label",
children: new Date(date).toLocaleDateString("zh-CN", {
month: "short",
day: "numeric",
weekday: "short"
})
}),
groupedResults[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__._("div", {
className: "record-item record-item--static",
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))
})
}) : keyword ? /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "card 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: "search",
size: 24
})
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("p", {
children: "未找到相关记录"
})
]
}) : /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._("div", {
className: "card 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: "search",
size: 24
})
}),
/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._("p", {
children: "输入关键è¯å¼€å§‹æœç´¢"
})
]
})
]
});
}
•{"finalSource":false}ƒmapbufferedMap ReplaceSourceRawSourceF4import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import { isLoggedIn, searchRecords } from "../lib/api";
import { DEFAULT_CATEGORIES } from "../lib/categories";
import AppShell from "../components/AppShell";
import { Icon } from "../components/icons";
import { useToast } from "../components/ToastProvider";
export default function Search() {
const router = useRouter();
const { showToast } = useToast();
const [keyword, setKeyword] = useState("");
const [results, setResults] = useState([]);
const [loading, setLoading] = useState(false);
null;
const handleSearch = async (e)=>{
e.preventDefault();
if (!keyword.trim()) {
showToast("请输入æœç´¢å…³é”®è¯", {
tone: "info"
});
return;
}
setLoading(true);
try {
const data = await searchRecords(keyword);
setResults(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const formatMoney = (num)=>(num || 0).toFixed(2);
const groupedResults = results.reduce((groups, record)=>{
const date = record.date.split(" ")[0];
if (!groups[date]) groups[date] = [];
groups[date].push(record);
return groups;
}, {});
const sortedDates = Object.keys(groupedResults).sort((a, b)=>b.localeCompare(a));
const totalIncome = results.filter((record)=>record.type === "income").reduce((sum, record)=>sum + record.amount, 0);
const totalExpense = results.filter((record)=>record.type === "expense").reduce((sum, record)=>sum + record.amount, 0);
const totalBalance = totalIncome - totalExpense;
const actions = /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "设置",
onClick: ()=>router.push("/settings"),
children: /*#__PURE__*/ _jsx(Icon, {
name: "settings",
size: 18
})
});
return /*#__PURE__*/ _jsxs(AppShell, {
title: "æœç´¢",
subtitle: "快速查找分类ã€å¤‡æ³¨ä¸Žé‡‘é¢",
actions: actions,
compactHeader: true,
children: [
/*#__PURE__*/ _jsxs("section", {
className: "card section-card section-card--search section-card--search-panel",
children: [
/*#__PURE__*/ _jsxs("form", {
className: "search-form search-form--refresh",
onSubmit: handleSearch,
children: [
/*#__PURE__*/ _jsxs("div", {
className: "search-input-wrap",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "search",
size: 18,
className: "search-input-wrap__icon"
}),
/*#__PURE__*/ _jsx("input", {
type: "text",
value: keyword,
onChange: (e)=>setKeyword(e.target.value),
placeholder: "æœç´¢åˆ†ç±»æˆ–备注...",
autoFocus: true,
disabled: loading
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "submit",
className: "btn btn-primary btn-inline",
disabled: loading,
children: loading ? /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
œç´¢ä¸­..."
]
}) : "æœç´¢"
})
]
}),
results.length > 0 ? /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "search-summary",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "search-stat",
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "æ”¶å…¥"
}),
/*#__PURE__*/ _jsxs("span", {
className: "value income",
children: [
"+",
formatMoney(totalIncome)
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "search-stat",
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "支出"
}),
/*#__PURE__*/ _jsxs("span", {
className: "value expense",
children: [
"-",
formatMoney(totalExpense)
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "search-stat",
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "结余"
}),
/*#__PURE__*/ _jsx("span", {
className: "value",
children: formatMoney(totalBalance)
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "results-count",
children: [
"找到 ",
results.length,
" æ¡è®°å½•"
]
})
]
}) : null
]
}),
loading ? /*#__PURE__*/ _jsx("div", {
className: "card loading-state",
children: "æœç´¢ä¸­..."
}) : results.length > 0 ? /*#__PURE__*/ _jsx("section", {
className: "card section-card",
children: /*#__PURE__*/ _jsx("div", {
className: "records-list records-list--flush",
children: sortedDates.map((date)=>/*#__PURE__*/ _jsxs("div", {
className: "date-group",
children: [
/*#__PURE__*/ _jsx("div", {
className: "date-label",
children: new Date(date).toLocaleDateString("zh-CN", {
month: "short",
day: "numeric",
weekday: "short"
})
}),
groupedResults[date].map((record)=>{
const categories = DEFAULT_CATEGORIES[record.type];
const cat = categories.find((item)=>item.name === record.category) || {
icon: "\uD83D\uDCDD"
};
return /*#__PURE__*/ _jsxs("div", {
className: "record-item record-item--static",
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))
})
}) : keyword ? /*#__PURE__*/ _jsxs("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ _jsx(Icon, {
name: "search",
size: 24
})
}),
/*#__PURE__*/ _jsx("p", {
children: "未找到相关记录"
})
]
}) : /*#__PURE__*/ _jsxs("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ _jsx(Icon, {
name: "search",
size: 24
})
}),
/*#__PURE__*/ _jsx("p", {
children: "输入关键è¯å¼€å§‹æœç´¢"
})
]
})
]
});
}
'085undefined87130undefined132171undefined173227undefined229283undefined285330undefined332374undefined376430undefined432446undefined486494__WEBPACK_MODULE_REFERENCE__7_5b22757365526f75746572225d_call_directImport_asiSafe1__._undefined525532__WEBPACK_MODULE_REFERENCE__12_5b22757365546f617374225d_call_directImport_asiSafe1__._undefined571578__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined619626__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined667674__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined973985__WEBPACK_MODULE_REFERENCE__8_5b227365617263685265636f726473225d_call_directImport_asiSafe1__._undefined19321935__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined21142117__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined21192122__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined22222226__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined22282235__WEBPACK_MODULE_REFERENCE__10_5b2264656661756c74225d_directImport_asiSafe1__._undefined23962400__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined25732577__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined27862790__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined29592962__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined29642967__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined32453248__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined37833786__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined40384042__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined42214224__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined42264229__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined47274731__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined47334741__WEBPACK_MODULE_REFERENCE__5_5b22467261676d656e74225d_directImport_asiSafe1__._undefined48244828__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined49944998__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined51855188__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined54375441__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined59515955__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined61426145__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined63946398__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined69106914__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined71017104__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined73537356__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined77567760__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined82048207__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined83548357__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined84608463__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined86098613__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined87638766__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined92979314__WEBPACK_MODULE_REFERENCE__9_5b2244454641554c545f43415445474f52494553225d_directImport_asiSafe1__._undefined95959599__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined98069810__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined1002110024__WEBPACK_MODULE_REFERENCE__5_5b22
Ò
 Ë  è 4
Ý
"$lÞ#kce­Ÿëí<ÛÍˆÍÆ\\U¡¡!í!¨"í"æ#_+$»%&Ã'((à(G)Œ)*j*+E+X-»-Ô. /ï/;01S1u2Á2¬3ñ3M55™7å7:Ù:c;P¨;<`<b<ª<U=š=>c>í>2?¥?ê?ì?4@ß@$A™(0,next_router.useRouter)¡(0,ToastProvider/* useToast */.p)œ(0,external_react_.useState)ÿÿ(0,api/* searchRecords */.Kp)jsx_runtime_.jsxÿicons/* Icon */.J•(0,jsx_runtime_.jsxs)—AppShell/* default */.Zþþþüýüüþüýþ•jsx_runtime_.Fragmentýýûýýûýýûûýûûûýû¨lib_categories/* DEFAULT_CATEGORIES */.Süüúüúúüüúúûúüúúûú@
;// CONCATENATED MODULE: ./node_modules/next/dist/build/webpack/loaders/next-route-loader/index.js?kind=PAGES&page=%2Fsearch&preferredRegion=&absolutePagePath=private-next-pages%2Fsearch.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/search.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: "/search",
pathname: "/search",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App,
Document
},
userland
});
//# sourceMappingURL=pages.js.map c/^`Qž Ù35a¸õõ
 ô€@_6<TXZaw}¢¸¾ÚÞàç$28QUW^˜½¿Æåë 8>`dfm´¸ºÁàæ x~¦Ò¨§¼»Á/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Ï__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._®__WEBPACK_MODULE_REFERENCE__13_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__13_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__13_ns_asiSafe1__._, "default"));
// Re-export methods.
const getStaticProps = __WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._, "getStaticProps");
const getStaticPaths = __WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._, "getStaticPaths");
const getServerSideProps = __WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._, "getServerSideProps");
const config = __WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._, "config");
const reportWebVitals = __WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._, "reportWebVitals");
// Re-export legacy methods.
const unstable_getStaticProps = __WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._, "unstable_getStaticProps");
const unstable_getStaticPaths = __WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._, "unstable_getStaticPaths");
const unstable_getStaticParams = __WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._, "unstable_getStaticParams");
const unstable_getServerProps = __WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._, "unstable_getServerProps");
const unstable_getServerSideProps = __WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__13_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: "/search",
pathname: "/search",
// 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__13_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/search.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: "/search",
pathname: "/search",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App,
Document
},
userland
});
//# sourceMappingURL=pages.js.mapù 094undefined96158undefined160217undefined259307undefined309353undefined384440undefined501515/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (undefined501515undefined516520__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined522529__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined542542.5);undefined566572undefined596600__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined602609__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined631637undefined661665__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined667674__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined696702undefined730734__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined736743__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined769775undefined791795__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined797804__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined818824undefined849853__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined855862__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined914920undefined953957__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined959966__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined9971003undefined10361040__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined10421049__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined10801086undefined11201124__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined11261133__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined11651171undefined12041208__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined12101217__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined12481254undefined12911295__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined12971304__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined14001406undefined14311446__WEBPACK_MODULE_REFERENCE__0_5b225061676573526f7574654d6f64756c65225d_directImport_asiSafe1__._undefined14821490__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined16861685: __WEBPACK_MODULE_REFERENCE__4_5b2264656661756c74225d_directImport_asiSafe1__._undefined17041703: __WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined17241723: __WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined`ÂÇDÏÑþ+y{¨Ù')VÍÏü"prŸóACp¯ýWÿ,lº¼é)wy¦é79fÞ= a ¥ k
¸
Í
 1 ^ ênext_route_loaderkind_PAGES_page_2Fsearch_preferredRegion_absolutePagePath_private_next_pages_2Fsearch_js_absoluteAppPath_private_next_pages_2F_app_js_absoluteDocumentPath_next_2Fdist_2Fpages_2F_document_middlewareConfigBase64_e30_3D_˜(0,helpers/* hoist */.l)search_namespaceObjectþÿþÿþÿþÿþÿþÿþÿþÿþÿþÿ module_compiled.PagesRouteModuleroute_kind/* RouteKind */.x_app["default"]•(_document_default())û†buffer†source„size„maps„hashmI// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
config: () => (/* binding */ config),
"default": () => (/* binding */ next_route_loaderkind_PAGES_page_2Fsearch_preferredRegion_absolutePagePath_private_next_pages_2Fsearch_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/search.js
var search_namespaceObject = {};
__webpack_require__.r(search_namespaceObject);
__webpack_require__.d(search_namespaceObject, {
"default": () => (Search)
});
// 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);
;// CONCATENATED MODULE: ./pages/search.js
function Search() {
const router = (0,next_router.useRouter)();
const { showToast } = (0,ToastProvider/* useToast */.p)();
const [keyword, setKeyword] = (0,external_react_.useState)("");
const [results, setResults] = (0,external_react_.useState)([]);
const [loading, setLoading] = (0,external_react_.useState)(false);
null;
const handleSearch = async (e)=>{
e.preventDefault();
if (!keyword.trim()) {
showToast("请输入æœç´¢å…³é”®è¯", {
tone: "info"
});
return;
}
setLoading(true);
try {
const data = await (0,api/* searchRecords */.Kp)(keyword);
setResults(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const formatMoney = (num)=>(num || 0).toFixed(2);
const groupedResults = results.reduce((groups, record)=>{
const date = record.date.split(" ")[0];
if (!groups[date]) groups[date] = [];
groups[date].push(record);
return groups;
}, {});
const sortedDates = Object.keys(groupedResults).sort((a, b)=>b.localeCompare(a));
const totalIncome = results.filter((record)=>record.type === "income").reduce((sum, record)=>sum + record.amount, 0);
const totalExpense = results.filter((record)=>record.type === "expense").reduce((sum, record)=>sum + record.amount, 0);
const totalBalance = totalIncome - totalExpense;
const actions = /*#__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
})
});
return /*#__PURE__*/ (0,jsx_runtime_.jsxs)(AppShell/* default */.Z, {
title: "æœç´¢",
subtitle: "快速查找分类ã€å¤‡æ³¨ä¸Žé‡‘é¢",
actions: actions,
compactHeader: true,
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("section", {
className: "card section-card section-card--search section-card--search-panel",
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("form", {
className: "search-form search-form--refresh",
onSubmit: handleSearch,
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "search-input-wrap",
children: [
/*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "search",
size: 18,
className: "search-input-wrap__icon"
}),
/*#__PURE__*/ jsx_runtime_.jsx("input", {
type: "text",
value: keyword,
onChange: (e)=>setKeyword(e.target.value),
placeholder: "æœç´¢åˆ†ç±»æˆ–备注...",
autoFocus: true,
disabled: loading
})
]
}),
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "submit",
className: "btn btn-primary btn-inline",
disabled: loading,
children: loading ? /*#__PURE__*/ (0,jsx_runtime_.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
œç´¢ä¸­..."
]
}) : "æœç´¢"
})
]
}),
results.length > 0 ? /*#__PURE__*/ (0,jsx_runtime_.jsxs)(jsx_runtime_.Fragment, {
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "search-summary",
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "search-stat",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "label",
children: "æ”¶å…¥"
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("span", {
className: "value income",
children: [
"+",
formatMoney(totalIncome)
]
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "search-stat",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "label",
children: "支出"
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("span", {
className: "value expense",
children: [
"-",
formatMoney(totalExpense)
]
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "search-stat",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "label",
children: "结余"
}),
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "value",
children: formatMoney(totalBalance)
})
]
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "results-count",
children: [
"找到 ",
results.length,
" æ¡è®°å½•"
]
})
]
}) : null
]
}),
loading ? /*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "card loading-state",
children: "æœç´¢ä¸­..."
}) : results.length > 0 ? /*#__PURE__*/ jsx_runtime_.jsx("section", {
className: "card section-card",
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__*/ jsx_runtime_.jsx("div", {
className: "date-label",
children: new Date(date).toLocaleDateString("zh-CN", {
month: "short",
day: "numeric",
weekday: "short"
})
}),
groupedResults[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)("div", {
className: "record-item record-item--static",
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))
})
}) : keyword ? /*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "search",
size: 24
})
}),
/*#__PURE__*/ jsx_runtime_.jsx("p", {
children: "未找到相关记录"
})
]
}) : /*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "search",
size: 24
})
}),
/*#__PURE__*/ jsx_runtime_.jsx("p", {
children: "输入关键è¯å¼€å§‹æœç´¢"
})
]
})
]
});
}
;// CONCATENATED MODULE: ./node_modules/next/dist/build/webpack/loaders/next-route-loader/index.js?kind=PAGES&page=%2Fsearch&preferredRegion=&absolutePagePath=private-next-pages%2Fsearch.js&absoluteAppPath=private-next-pages%2F_app.js&absoluteDocumentPath=next%2Fdist%2Fpages%2F_document&middlewareConfigBase64=e30%3D!
// Import the app and document modules.
// Import the userland code.
// Re-export the component (should be the default export).
/* harmony default export */ const next_route_loaderkind_PAGES_page_2Fsearch_preferredRegion_absolutePagePath_private_next_pages_2Fsearch_js_absoluteAppPath_private_next_pages_2F_app_js_absoluteDocumentPath_next_2Fdist_2Fpages_2F_document_middlewareConfigBase64_e30_3D_ = ((0,helpers/* hoist */.l)(search_namespaceObject, "default"));
// Re-export methods.
const getStaticProps = (0,helpers/* hoist */.l)(search_namespaceObject, "getStaticProps");
const getStaticPaths = (0,helpers/* hoist */.l)(search_namespaceObject, "getStaticPaths");
const getServerSideProps = (0,helpers/* hoist */.l)(search_namespaceObject, "getServerSideProps");
const config = (0,helpers/* hoist */.l)(search_namespaceObject, "config");
const reportWebVitals = (0,helpers/* hoist */.l)(search_namespaceObject, "reportWebVitals");
// Re-export legacy methods.
const unstable_getStaticProps = (0,helpers/* hoist */.l)(search_namespaceObject, "unstable_getStaticProps");
const unstable_getStaticPaths = (0,helpers/* hoist */.l)(search_namespaceObject, "unstable_getStaticPaths");
const unstable_getStaticParams = (0,helpers/* hoist */.l)(search_namespaceObject, "unstable_getStaticParams");
const unstable_getServerProps = (0,helpers/* hoist */.l)(search_namespaceObject, "unstable_getServerProps");
const unstable_getServerSideProps = (0,helpers/* hoist */.l)(search_namespaceObject, "unstable_getServerSideProps");
// Create and export the route module that will be consumed.
const routeModule = new module_compiled.PagesRouteModule({
definition: {
kind: route_kind/* RouteKind */.x.PAGES,
page: "/search",
pathname: "/search",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App: _app["default"],
Document: (_document_default())
},
userland: search_namespaceObject
});
//# sourceMappingURL=pages.js.map ”{"finalSource":true}ƒmapbufferedMap `
ConcatSourceRawSourcel
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
config: () => (/* binding */ config),
"default": () => (/* binding */ next_route_loaderkind_PAGES_page_2Fsearch_preferredRegion_absolutePagePath_private_next_pages_2Fsearch_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/search.js
var search_namespaceObject = {};
__webpack_require__.r(search_namespaceObject);
__webpack_require__.d(search_namespaceObject, {
"default": () => (Search)
});
// 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);
;// CONCATENATED MODULE: ./pages/search.js

ReplaceSourceReplaceSourceRawSourceF4import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import { isLoggedIn, searchRecords } from "../lib/api";
import { DEFAULT_CATEGORIES } from "../lib/categories";
import AppShell from "../components/AppShell";
import { Icon } from "../components/icons";
import { useToast } from "../components/ToastProvider";
export default function Search() {
const router = useRouter();
const { showToast } = useToast();
const [keyword, setKeyword] = useState("");
const [results, setResults] = useState([]);
const [loading, setLoading] = useState(false);
null;
const handleSearch = async (e)=>{
e.preventDefault();
if (!keyword.trim()) {
showToast("请输入æœç´¢å…³é”®è¯", {
tone: "info"
});
return;
}
setLoading(true);
try {
const data = await searchRecords(keyword);
setResults(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const formatMoney = (num)=>(num || 0).toFixed(2);
const groupedResults = results.reduce((groups, record)=>{
const date = record.date.split(" ")[0];
if (!groups[date]) groups[date] = [];
groups[date].push(record);
return groups;
}, {});
const sortedDates = Object.keys(groupedResults).sort((a, b)=>b.localeCompare(a));
const totalIncome = results.filter((record)=>record.type === "income").reduce((sum, record)=>sum + record.amount, 0);
const totalExpense = results.filter((record)=>record.type === "expense").reduce((sum, record)=>sum + record.amount, 0);
const totalBalance = totalIncome - totalExpense;
const actions = /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "设置",
onClick: ()=>router.push("/settings"),
children: /*#__PURE__*/ _jsx(Icon, {
name: "settings",
size: 18
})
});
return /*#__PURE__*/ _jsxs(AppShell, {
title: "æœç´¢",
subtitle: "快速查找分类ã€å¤‡æ³¨ä¸Žé‡‘é¢",
actions: actions,
compactHeader: true,
children: [
/*#__PURE__*/ _jsxs("section", {
className: "card section-card section-card--search section-card--search-panel",
children: [
/*#__PURE__*/ _jsxs("form", {
className: "search-form search-form--refresh",
onSubmit: handleSearch,
children: [
/*#__PURE__*/ _jsxs("div", {
className: "search-input-wrap",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "search",
size: 18,
className: "search-input-wrap__icon"
}),
/*#__PURE__*/ _jsx("input", {
type: "text",
value: keyword,
onChange: (e)=>setKeyword(e.target.value),
placeholder: "æœç´¢åˆ†ç±»æˆ–备注...",
autoFocus: true,
disabled: loading
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "submit",
className: "btn btn-primary btn-inline",
disabled: loading,
children: loading ? /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
œç´¢ä¸­..."
]
}) : "æœç´¢"
})
]
}),
results.length > 0 ? /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "search-summary",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "search-stat",
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "æ”¶å…¥"
}),
/*#__PURE__*/ _jsxs("span", {
className: "value income",
children: [
"+",
formatMoney(totalIncome)
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "search-stat",
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "支出"
}),
/*#__PURE__*/ _jsxs("span", {
className: "value expense",
children: [
"-",
formatMoney(totalExpense)
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "search-stat",
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "结余"
}),
/*#__PURE__*/ _jsx("span", {
className: "value",
children: formatMoney(totalBalance)
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "results-count",
children: [
"找到 ",
results.length,
" æ¡è®°å½•"
]
})
]
}) : null
]
}),
loading ? /*#__PURE__*/ _jsx("div", {
className: "card loading-state",
children: "æœç´¢ä¸­..."
}) : results.length > 0 ? /*#__PURE__*/ _jsx("section", {
className: "card section-card",
children: /*#__PURE__*/ _jsx("div", {
className: "records-list records-list--flush",
children: sortedDates.map((date)=>/*#__PURE__*/ _jsxs("div", {
className: "date-group",
children: [
/*#__PURE__*/ _jsx("div", {
className: "date-label",
children: new Date(date).toLocaleDateString("zh-CN", {
month: "short",
day: "numeric",
weekday: "short"
})
}),
groupedResults[date].map((record)=>{
const categories = DEFAULT_CATEGORIES[record.type];
const cat = categories.find((item)=>item.name === record.category) || {
icon: "\uD83D\uDCDD"
};
return /*#__PURE__*/ _jsxs("div", {
className: "record-item record-item--static",
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))
})
}) : keyword ? /*#__PURE__*/ _jsxs("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ _jsx(Icon, {
name: "search",
size: 24
})
}),
/*#__PURE__*/ _jsx("p", {
children: "未找到相关记录"
})
]
}) : /*#__PURE__*/ _jsxs("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ _jsx(Icon, {
name: "search",
size: 24
})
}),
/*#__PURE__*/ _jsx("p", {
children: "输入关键è¯å¼€å§‹æœç´¢"
})
]
})
]
});
}
'085undefined87130undefined132171undefined173227undefined229283undefined285330undefined332374undefined376430undefined432446undefined486494__WEBPACK_MODULE_REFERENCE__7_5b22757365526f75746572225d_call_directImport_asiSafe1__._undefined525532__WEBPACK_MODULE_REFERENCE__12_5b22757365546f617374225d_call_directImport_asiSafe1__._undefined571578__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined619626__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined667674__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined973985__WEBPACK_MODULE_REFERENCE__8_5b227365617263685265636f726473225d_call_directImport_asiSafe1__._undefined19321935__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined21142117__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined21192122__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined22222226__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined22282235__WEBPACK_MODULE_REFERENCE__10_5b2264656661756c74225d_directImport_asiSafe1__._undefined23962400__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined25732577__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined27862790__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined29592962__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined29642967__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined32453248__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined37833786__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined40384042__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined42214224__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined42264229__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined47274731__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined47334741__WEBPACK_MODULE_REFERENCE__5_5b22467261676d656e74225d_directImport_asiSafe1__._undefined48244828__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined49944998__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined51855188__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined54375441__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined59515955__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined61426145__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined63946398__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined69106914__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined71017104__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined73537356__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined77567760__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined82048207__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined83548357__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined84608463__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined86098613__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined87638766__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined92979314__WEBPACK_MODULE_REFERENCE__9_5b2244454641554c545f43415445474f52494553225d_directImport_asiSafe1__._undefined95959599__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined98069810__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined1002110024__WEBPACK_MODULE_REFERENCE__5_5b22
;// CONCATENATED MODULE: ./node_modules/next/dist/build/webpack/loaders/next-route-loader/index.js?kind=PAGES&page=%2Fsearch&preferredRegion=&absolutePagePath=private-next-pages%2Fsearch.js&absoluteAppPath=private-next-pages%2F_app.js&absoluteDocumentPath=next%2Fdist%2Fpages%2F_document&middlewareConfigBase64=e30%3D!
úûã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/search.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: "/search",
pathname: "/search",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App,
Document
},
userland
});
//# sourceMappingURL=pages.js.mapù 094undefined96158undefined160217undefined259307undefined309353undefined384440undefined501515/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (undefined501515undefined516520__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined522529__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined542542.5);undefined566572undefined596600__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined602609__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined631637undefined661665__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined667674__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined696702undefined730734__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined736743__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined769775undefined791795__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined797804__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined818824undefined849853__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined855862__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined914920undefined953957__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined959966__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined9971003undefined10361040__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined10421049__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined10801086undefined11201124__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined11261133__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined11651171undefined12041208__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined12101217__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined12481254undefined12911295__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined12971304__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined14001406undefined14311446__WEBPACK_MODULE_REFERENCE__0_5b225061676573526f7574654d6f64756c65225d_directImport_asiSafe1__._undefined14821490__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined16861685: __WEBPACK_MODULE_REFERENCE__4_5b2264656661756c74225d_directImport_asiSafe1__._undefined17041703: __WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined17241723: __WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined 169194next_route_loaderkind_PAGES_page_2Fsearch_preferredRegion_absolutePagePath_private_next_pages_2Fsearch_js_absoluteAppPath_private_next_pages_2F_app_js_absoluteDocumentPath_next_2Fdist_2Fpages_2F_document_middlewareConfigBase64_e30_3D_undefined199277(0,helpers/* hoist */.l)undefined279324search_namespaceObjectundefined385463(0,helpers/* hoist */.l)undefined465510search_namespaceObjectundefined555633(0,helpers/* hoist */.l)undefined635680search_namespaceObjectundefined729807(0,helpers/* hoist */.l)undefined809854search_namespaceObjectundefined895973(0,helpers/* hoist */.l)undefined9751020search_namespaceObjectundefined10581136(0,helpers/* hoist */.l)undefined11381183search_namespaceObjectundefined12671345(0,helpers/* hoist */.l)undefined13471392search_namespaceObjectundefined14551533(0,helpers/* hoist */.l)undefined15351580search_namespaceObjectundefined16441722(0,helpers/* hoist */.l)undefined17241769search_namespaceObjectundefined18331911(0,helpers/* hoist */.l)undefined19131958search_namespaceObjectundefined20252103(0,helpers/* hoist */.l)undefined21052150search_namespaceObjectundefined22702365module_compiled.PagesRouteModuleundefined24012469route_kind/* RouteKind */.xundefined26672744_app["default"]undefined27652842(_document_default())undefined28652910search_namespaceObjectundefined
/***/ }) †buffer†source„size„maps„hashÈI/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
config: () => (/* binding */ config),
"default": () => (/* binding */ next_route_loaderkind_PAGES_page_2Fsearch_preferredRegion_absolutePagePath_private_next_pages_2Fsearch_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/search.js
var search_namespaceObject = {};
__webpack_require__.r(search_namespaceObject);
__webpack_require__.d(search_namespaceObject, {
"default": () => (Search)
});
// 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);
;// CONCATENATED MODULE: ./pages/search.js
function Search() {
const router = (0,next_router.useRouter)();
const { showToast } = (0,ToastProvider/* useToast */.p)();
const [keyword, setKeyword] = (0,external_react_.useState)("");
const [results, setResults] = (0,external_react_.useState)([]);
const [loading, setLoading] = (0,external_react_.useState)(false);
null;
const handleSearch = async (e)=>{
e.preventDefault();
if (!keyword.trim()) {
showToast("请输入æœç´¢å…³é”®è¯", {
tone: "info"
});
return;
}
setLoading(true);
try {
const data = await (0,api/* searchRecords */.Kp)(keyword);
setResults(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const formatMoney = (num)=>(num || 0).toFixed(2);
const groupedResults = results.reduce((groups, record)=>{
const date = record.date.split(" ")[0];
if (!groups[date]) groups[date] = [];
groups[date].push(record);
return groups;
}, {});
const sortedDates = Object.keys(groupedResults).sort((a, b)=>b.localeCompare(a));
const totalIncome = results.filter((record)=>record.type === "income").reduce((sum, record)=>sum + record.amount, 0);
const totalExpense = results.filter((record)=>record.type === "expense").reduce((sum, record)=>sum + record.amount, 0);
const totalBalance = totalIncome - totalExpense;
const actions = /*#__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
})
});
return /*#__PURE__*/ (0,jsx_runtime_.jsxs)(AppShell/* default */.Z, {
title: "æœç´¢",
subtitle: "快速查找分类ã€å¤‡æ³¨ä¸Žé‡‘é¢",
actions: actions,
compactHeader: true,
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("section", {
className: "card section-card section-card--search section-card--search-panel",
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("form", {
className: "search-form search-form--refresh",
onSubmit: handleSearch,
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "search-input-wrap",
children: [
/*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "search",
size: 18,
className: "search-input-wrap__icon"
}),
/*#__PURE__*/ jsx_runtime_.jsx("input", {
type: "text",
value: keyword,
onChange: (e)=>setKeyword(e.target.value),
placeholder: "æœç´¢åˆ†ç±»æˆ–备注...",
autoFocus: true,
disabled: loading
})
]
}),
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "submit",
className: "btn btn-primary btn-inline",
disabled: loading,
children: loading ? /*#__PURE__*/ (0,jsx_runtime_.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
œç´¢ä¸­..."
]
}) : "æœç´¢"
})
]
}),
results.length > 0 ? /*#__PURE__*/ (0,jsx_runtime_.jsxs)(jsx_runtime_.Fragment, {
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "search-summary",
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "search-stat",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "label",
children: "æ”¶å…¥"
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("span", {
className: "value income",
children: [
"+",
formatMoney(totalIncome)
]
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "search-stat",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "label",
children: "支出"
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("span", {
className: "value expense",
children: [
"-",
formatMoney(totalExpense)
]
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "search-stat",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "label",
children: "结余"
}),
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "value",
children: formatMoney(totalBalance)
})
]
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "results-count",
children: [
"找到 ",
results.length,
" æ¡è®°å½•"
]
})
]
}) : null
]
}),
loading ? /*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "card loading-state",
children: "æœç´¢ä¸­..."
}) : results.length > 0 ? /*#__PURE__*/ jsx_runtime_.jsx("section", {
className: "card section-card",
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__*/ jsx_runtime_.jsx("div", {
className: "date-label",
children: new Date(date).toLocaleDateString("zh-CN", {
month: "short",
day: "numeric",
weekday: "short"
})
}),
groupedResults[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)("div", {
className: "record-item record-item--static",
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))
})
}) : keyword ? /*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "search",
size: 24
})
}),
/*#__PURE__*/ jsx_runtime_.jsx("p", {
children: "未找到相关记录"
})
]
}) : /*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "search",
size: 24
})
}),
/*#__PURE__*/ jsx_runtime_.jsx("p", {
children: "输入关键è¯å¼€å§‹æœç´¢"
})
]
})
]
});
}
;// CONCATENATED MODULE: ./node_modules/next/dist/build/webpack/loaders/next-route-loader/index.js?kind=PAGES&page=%2Fsearch&preferredRegion=&absolutePagePath=private-next-pages%2Fsearch.js&absoluteAppPath=private-next-pages%2F_app.js&absoluteDocumentPath=next%2Fdist%2Fpages%2F_document&middlewareConfigBase64=e30%3D!
// Import the app and document modules.
// Import the userland code.
// Re-export the component (should be the default export).
/* harmony default export */ const next_route_loaderkind_PAGES_page_2Fsearch_preferredRegion_absolutePagePath_private_next_pages_2Fsearch_js_absoluteAppPath_private_next_pages_2F_app_js_absoluteDocumentPath_next_2Fdist_2Fpages_2F_document_middlewareConfigBase64_e30_3D_ = ((0,helpers/* hoist */.l)(search_namespaceObject, "default"));
// Re-export methods.
const getStaticProps = (0,helpers/* hoist */.l)(search_namespaceObject, "getStaticProps");
const getStaticPaths = (0,helpers/* hoist */.l)(search_namespaceObject, "getStaticPaths");
const getServerSideProps = (0,helpers/* hoist */.l)(search_namespaceObject, "getServerSideProps");
const config = (0,helpers/* hoist */.l)(search_namespaceObject, "config");
const reportWebVitals = (0,helpers/* hoist */.l)(search_namespaceObject, "reportWebVitals");
// Re-export legacy methods.
const unstable_getStaticProps = (0,helpers/* hoist */.l)(search_namespaceObject, "unstable_getStaticProps");
const unstable_getStaticPaths = (0,helpers/* hoist */.l)(search_namespaceObject, "unstable_getStaticPaths");
const unstable_getStaticParams = (0,helpers/* hoist */.l)(search_namespaceObject, "unstable_getStaticParams");
const unstable_getServerProps = (0,helpers/* hoist */.l)(search_namespaceObject, "unstable_getServerProps");
const unstable_getServerSideProps = (0,helpers/* hoist */.l)(search_namespaceObject, "unstable_getServerSideProps");
// Create and export the route module that will be consumed.
const routeModule = new module_compiled.PagesRouteModule({
definition: {
kind: route_kind/* RouteKind */.x.PAGES,
page: "/search",
pathname: "/search",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App: _app["default"],
Document: (_document_default())
},
userland: search_namespaceObject
});
//# sourceMappingURL=pages.js.map
/***/ }) ”{"finalSource":true}ƒmapbufferedMap `ConcatSourceRawSourceQ/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
þl
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
config: () => (/* binding */ config),
"default": () => (/* binding */ next_route_loaderkind_PAGES_page_2Fsearch_preferredRegion_absolutePagePath_private_next_pages_2Fsearch_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/search.js
var search_namespaceObject = {};
__webpack_require__.r(search_namespaceObject);
__webpack_require__.d(search_namespaceObject, {
"default": () => (Search)
});
// 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);
;// CONCATENATED MODULE: ./pages/search.js

ReplaceSourceReplaceSourceRawSourceF4import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import { isLoggedIn, searchRecords } from "../lib/api";
import { DEFAULT_CATEGORIES } from "../lib/categories";
import AppShell from "../components/AppShell";
import { Icon } from "../components/icons";
import { useToast } from "../components/ToastProvider";
export default function Search() {
const router = useRouter();
const { showToast } = useToast();
const [keyword, setKeyword] = useState("");
const [results, setResults] = useState([]);
const [loading, setLoading] = useState(false);
null;
const handleSearch = async (e)=>{
e.preventDefault();
if (!keyword.trim()) {
showToast("请输入æœç´¢å…³é”®è¯", {
tone: "info"
});
return;
}
setLoading(true);
try {
const data = await searchRecords(keyword);
setResults(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const formatMoney = (num)=>(num || 0).toFixed(2);
const groupedResults = results.reduce((groups, record)=>{
const date = record.date.split(" ")[0];
if (!groups[date]) groups[date] = [];
groups[date].push(record);
return groups;
}, {});
const sortedDates = Object.keys(groupedResults).sort((a, b)=>b.localeCompare(a));
const totalIncome = results.filter((record)=>record.type === "income").reduce((sum, record)=>sum + record.amount, 0);
const totalExpense = results.filter((record)=>record.type === "expense").reduce((sum, record)=>sum + record.amount, 0);
const totalBalance = totalIncome - totalExpense;
const actions = /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "设置",
onClick: ()=>router.push("/settings"),
children: /*#__PURE__*/ _jsx(Icon, {
name: "settings",
size: 18
})
});
return /*#__PURE__*/ _jsxs(AppShell, {
title: "æœç´¢",
subtitle: "快速查找分类ã€å¤‡æ³¨ä¸Žé‡‘é¢",
actions: actions,
compactHeader: true,
children: [
/*#__PURE__*/ _jsxs("section", {
className: "card section-card section-card--search section-card--search-panel",
children: [
/*#__PURE__*/ _jsxs("form", {
className: "search-form search-form--refresh",
onSubmit: handleSearch,
children: [
/*#__PURE__*/ _jsxs("div", {
className: "search-input-wrap",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "search",
size: 18,
className: "search-input-wrap__icon"
}),
/*#__PURE__*/ _jsx("input", {
type: "text",
value: keyword,
onChange: (e)=>setKeyword(e.target.value),
placeholder: "æœç´¢åˆ†ç±»æˆ–备注...",
autoFocus: true,
disabled: loading
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "submit",
className: "btn btn-primary btn-inline",
disabled: loading,
children: loading ? /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
œç´¢ä¸­..."
]
}) : "æœç´¢"
})
]
}),
results.length > 0 ? /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "search-summary",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "search-stat",
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "æ”¶å…¥"
}),
/*#__PURE__*/ _jsxs("span", {
className: "value income",
children: [
"+",
formatMoney(totalIncome)
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "search-stat",
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "支出"
}),
/*#__PURE__*/ _jsxs("span", {
className: "value expense",
children: [
"-",
formatMoney(totalExpense)
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "search-stat",
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "结余"
}),
/*#__PURE__*/ _jsx("span", {
className: "value",
children: formatMoney(totalBalance)
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "results-count",
children: [
"找到 ",
results.length,
" æ¡è®°å½•"
]
})
]
}) : null
]
}),
loading ? /*#__PURE__*/ _jsx("div", {
className: "card loading-state",
children: "æœç´¢ä¸­..."
}) : results.length > 0 ? /*#__PURE__*/ _jsx("section", {
className: "card section-card",
children: /*#__PURE__*/ _jsx("div", {
className: "records-list records-list--flush",
children: sortedDates.map((date)=>/*#__PURE__*/ _jsxs("div", {
className: "date-group",
children: [
/*#__PURE__*/ _jsx("div", {
className: "date-label",
children: new Date(date).toLocaleDateString("zh-CN", {
month: "short",
day: "numeric",
weekday: "short"
})
}),
groupedResults[date].map((record)=>{
const categories = DEFAULT_CATEGORIES[record.type];
const cat = categories.find((item)=>item.name === record.category) || {
icon: "\uD83D\uDCDD"
};
return /*#__PURE__*/ _jsxs("div", {
className: "record-item record-item--static",
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))
})
}) : keyword ? /*#__PURE__*/ _jsxs("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ _jsx(Icon, {
name: "search",
size: 24
})
}),
/*#__PURE__*/ _jsx("p", {
children: "未找到相关记录"
})
]
}) : /*#__PURE__*/ _jsxs("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ _jsx(Icon, {
name: "search",
size: 24
})
}),
/*#__PURE__*/ _jsx("p", {
children: "输入关键è¯å¼€å§‹æœç´¢"
})
]
})
]
});
}
'085undefined87130undefined132171undefined173227undefined229283undefined285330undefined332374undefined376430undefined432446undefined486494__WEBPACK_MODULE_REFERENCE__7_5b22757365526f75746572225d_call_directImport_asiSafe1__._undefined525532__WEBPACK_MODULE_REFERENCE__12_5b22757365546f617374225d_call_directImport_asiSafe1__._undefined571578__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined619626__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined667674__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined973985__WEBPACK_MODULE_REFERENCE__8_5b227365617263685265636f726473225d_call_directImport_asiSafe1__._undefined19321935__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined21142117__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined21192122__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined22222226__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined22282235__WEBPACK_MODULE_REFERENCE__10_5b2264656661756c74225d_directImport_asiSafe1__._undefined23962400__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined25732577__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined27862790__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined29592962__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined29642967__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined32453248__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined37833786__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined40384042__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined42214224__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined42264229__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined47274731__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined47334741__WEBPACK_MODULE_REFERENCE__5_5b22467261676d656e74225d_directImport_asiSafe1__._undefined48244828__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined49944998__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined51855188__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined54375441__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined59515955__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined61426145__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined63946398__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined69106914__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined71017104__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined73537356__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined77567760__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined82048207__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined83548357__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined84608463__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined86098613__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined87638766__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined92979314__WEBPACK_MODULE_REFERENCE__9_5b2244454641554c545f43415445474f52494553225d_directImport_asiSafe1__._undefined95959599__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined98069810__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined1002110024__WEBPACK_MODULE_REFERENCE__5_5b22
;// CONCATENATED MODULE: ./node_modules/next/dist/build/webpack/loaders/next-route-loader/index.js?kind=PAGES&page=%2Fsearch&preferredRegion=&absolutePagePath=private-next-pages%2Fsearch.js&absoluteAppPath=private-next-pages%2F_app.js&absoluteDocumentPath=next%2Fdist%2Fpages%2F_document&middlewareConfigBase64=e30%3D!
úûã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/search.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: "/search",
pathname: "/search",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App,
Document
},
userland
});
//# sourceMappingURL=pages.js.mapù 094undefined96158undefined160217undefined259307undefined309353undefined384440undefined501515/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (undefined501515undefined516520__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined522529__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined542542.5);undefined566572undefined596600__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined602609__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined631637undefined661665__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined667674__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined696702undefined730734__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined736743__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined769775undefined791795__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined797804__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined818824undefined849853__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined855862__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined914920undefined953957__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined959966__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined9971003undefined10361040__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined10421049__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined10801086undefined11201124__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined11261133__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined11651171undefined12041208__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined12101217__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined12481254undefined12911295__WEBPACK_MODULE_REFERENCE__2_5b22686f697374225d_call_directImport_asiSafe1__._undefined12971304__WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined14001406undefined14311446__WEBPACK_MODULE_REFERENCE__0_5b225061676573526f7574654d6f64756c65225d_directImport_asiSafe1__._undefined14821490__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined16861685: __WEBPACK_MODULE_REFERENCE__4_5b2264656661756c74225d_directImport_asiSafe1__._undefined17041703: __WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined17241723: __WEBPACK_MODULE_REFERENCE__13_ns_asiSafe1__._undefined 169194next_route_loaderkind_PAGES_page_2Fsearch_preferredRegion_absolutePagePath_private_next_pages_2Fsearch_js_absoluteAppPath_private_next_pages_2F_app_js_absoluteDocumentPath_next_2Fdist_2Fpages_2F_document_middlewareConfigBase64_e30_3D_undefined199277(0,helpers/* hoist */.l)undefined279324search_namespaceObjectundefined385463(0,helpers/* hoist */.l)undefined465510search_namespaceObjectundefined555633(0,helpers/* hoist */.l)undefined635680search_namespaceObjectundefined729807(0,helpers/* hoist */.l)undefined809854search_namespaceObjectundefined895973(0,helpers/* hoist */.l)undefined9751020search_namespaceObjectundefined10581136(0,helpers/* hoist */.l)undefined11381183search_namespaceObjectundefined12671345(0,helpers/* hoist */.l)undefined13471392search_namespaceObjectundefined14551533(0,helpers/* hoist */.l)undefined15351580search_namespaceObjectundefined16441722(0,helpers/* hoist */.l)undefined17241769search_namespaceObjectundefined18331911(0,helpers/* hoist */.l)undefined19131958search_namespaceObjectundefined20252103(0,helpers/* hoist */.l)undefined21052150search_namespaceObjectundefined22702365module_compiled.PagesRouteModuleundefined24012469route_kind/* RouteKind */.xundefined26672744_app["default"]undefined27652842(_document_default())undefined28652910search_namespaceObjectundefined RawSource
/***/ }),
/***/ 2204:
 ä«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourceQ/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
«webpack/lib/util/registerExternalSerializerœwebpack-sources/CachedSource ò «webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourcež/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
«webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourceZexport const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
†buffer†source„size„maps„hashñ/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
”{"finalSource":true}ƒmapbufferedMap ConcatSourceRawSourcež/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
ReplaceSourceRawSourceZexport const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
 06undefined
/***/ }) åL /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
/***/ }) æé  êëêž/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
íZexport const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
 06undefinedóô,
/***/ 2785:
 "«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
Qmodule.exports = require("next/dist/compiled/next-server/pages.runtime.prod.js"); 
/***/ }) Úq/***/ ((module) => {
module.exports = require("next/dist/compiled/next-server/pages.runtime.prod.js");
/***/ }) ÛÞ ß/***/ ((module) => {
êQmodule.exports = require("next/dist/compiled/next-server/pages.runtime.prod.js");éê,
/***/ 6689:
 ó«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
"module.exports = require("react"); 
/***/ }) ÐB/***/ ((module) => {
module.exports = require("react");
/***/ }) ÑÔ Õöá"module.exports = require("react");àá,
/***/ 6405:
 ÷«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
&module.exports = require("react-dom"); 
/***/ }) ÇF/***/ ((module) => {
module.exports = require("react-dom");
/***/ }) ÈË ÌíØ&module.exports = require("react-dom");ר,
/***/ 997:
 ÿ«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
.module.exports = require("react/jsx-runtime"); 
/***/ }) ¾N/***/ ((module) => {
module.exports = require("react/jsx-runtime");
/***/ }) ¿Â ÃäÏ.module.exports = require("react/jsx-runtime");ÎÏ,
/***/ 2048:
 ð«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
module.exports = require("fs"); 
/***/ }) µ?/***/ ((module) => {
module.exports = require("fs");
/***/ }) ¹ ºÛÆmodule.exports = require("fs");ÅÆ,
/***/ 5315:
 ò«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
!module.exports = require("path"); 
/***/ }) ¬A/***/ ((module) => {
module.exports = require("path");
/***/ }) ­° ±Ò½!module.exports = require("path");¼½,
/***/ 6162:
 ô«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
#module.exports = require("stream"); 
/***/ }) £C/***/ ((module) => {
module.exports = require("stream");
/***/ }) ¤§ ¨É´#module.exports = require("stream");³´,
/***/ 1568:
 ò«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource/***/ ((module) => {
!module.exports = require("zlib"); 
/***/ }) šA/***/ ((module) => {
module.exports = require("zlib");
/***/ }) ž ŸÀ«!module.exports = require("zlib");ª«t
};
;
// load runtime
var __webpack_require__ = require("../webpack-runtime.js");
__webpack_require__.C(exports);
Àvar __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId))
var __webpack_exports__ = __webpack_require__.X(0, [899,342,261], () => (__webpack_exec__(1076)));
,module.exports = __webpack_exports__;
})();  ´ºW"use strict";
(() => {
var exports = {};
exports.id = 603;
exports.ids = [603,660];
exports.modules = {
/***/ 1076:
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
config: () => (/* binding */ config),
"default": () => (/* binding */ next_route_loaderkind_PAGES_page_2Fsearch_preferredRegion_absolutePagePath_private_next_pages_2Fsearch_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/search.js
var search_namespaceObject = {};
__webpack_require__.r(search_namespaceObject);
__webpack_require__.d(search_namespaceObject, {
"default": () => (Search)
});
// 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);
;// CONCATENATED MODULE: ./pages/search.js
function Search() {
const router = (0,next_router.useRouter)();
const { showToast } = (0,ToastProvider/* useToast */.p)();
const [keyword, setKeyword] = (0,external_react_.useState)("");
const [results, setResults] = (0,external_react_.useState)([]);
const [loading, setLoading] = (0,external_react_.useState)(false);
null;
const handleSearch = async (e)=>{
e.preventDefault();
if (!keyword.trim()) {
showToast("请输入æœç´¢å…³é”®è¯", {
tone: "info"
});
return;
}
setLoading(true);
try {
const data = await (0,api/* searchRecords */.Kp)(keyword);
setResults(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const formatMoney = (num)=>(num || 0).toFixed(2);
const groupedResults = results.reduce((groups, record)=>{
const date = record.date.split(" ")[0];
if (!groups[date]) groups[date] = [];
groups[date].push(record);
return groups;
}, {});
const sortedDates = Object.keys(groupedResults).sort((a, b)=>b.localeCompare(a));
const totalIncome = results.filter((record)=>record.type === "income").reduce((sum, record)=>sum + record.amount, 0);
const totalExpense = results.filter((record)=>record.type === "expense").reduce((sum, record)=>sum + record.amount, 0);
const totalBalance = totalIncome - totalExpense;
const actions = /*#__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
})
});
return /*#__PURE__*/ (0,jsx_runtime_.jsxs)(AppShell/* default */.Z, {
title: "æœç´¢",
subtitle: "快速查找分类ã€å¤‡æ³¨ä¸Žé‡‘é¢",
actions: actions,
compactHeader: true,
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("section", {
className: "card section-card section-card--search section-card--search-panel",
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("form", {
className: "search-form search-form--refresh",
onSubmit: handleSearch,
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "search-input-wrap",
children: [
/*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "search",
size: 18,
className: "search-input-wrap__icon"
}),
/*#__PURE__*/ jsx_runtime_.jsx("input", {
type: "text",
value: keyword,
onChange: (e)=>setKeyword(e.target.value),
placeholder: "æœç´¢åˆ†ç±»æˆ–备注...",
autoFocus: true,
disabled: loading
})
]
}),
/*#__PURE__*/ jsx_runtime_.jsx("button", {
type: "submit",
className: "btn btn-primary btn-inline",
disabled: loading,
children: loading ? /*#__PURE__*/ (0,jsx_runtime_.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
œç´¢ä¸­..."
]
}) : "æœç´¢"
})
]
}),
results.length > 0 ? /*#__PURE__*/ (0,jsx_runtime_.jsxs)(jsx_runtime_.Fragment, {
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "search-summary",
children: [
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "search-stat",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "label",
children: "æ”¶å…¥"
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("span", {
className: "value income",
children: [
"+",
formatMoney(totalIncome)
]
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "search-stat",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "label",
children: "支出"
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("span", {
className: "value expense",
children: [
"-",
formatMoney(totalExpense)
]
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "search-stat",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "label",
children: "结余"
}),
/*#__PURE__*/ jsx_runtime_.jsx("span", {
className: "value",
children: formatMoney(totalBalance)
})
]
})
]
}),
/*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "results-count",
children: [
"找到 ",
results.length,
" æ¡è®°å½•"
]
})
]
}) : null
]
}),
loading ? /*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "card loading-state",
children: "æœç´¢ä¸­..."
}) : results.length > 0 ? /*#__PURE__*/ jsx_runtime_.jsx("section", {
className: "card section-card",
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__*/ jsx_runtime_.jsx("div", {
className: "date-label",
children: new Date(date).toLocaleDateString("zh-CN", {
month: "short",
day: "numeric",
weekday: "short"
})
}),
groupedResults[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)("div", {
className: "record-item record-item--static",
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))
})
}) : keyword ? /*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "search",
size: 24
})
}),
/*#__PURE__*/ jsx_runtime_.jsx("p", {
children: "未找到相关记录"
})
]
}) : /*#__PURE__*/ (0,jsx_runtime_.jsxs)("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ jsx_runtime_.jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ jsx_runtime_.jsx(icons/* Icon */.J, {
name: "search",
size: 24
})
}),
/*#__PURE__*/ jsx_runtime_.jsx("p", {
children: "输入关键è¯å¼€å§‹æœç´¢"
})
]
})
]
});
}
;// CONCATENATED MODULE: ./node_modules/next/dist/build/webpack/loaders/next-route-loader/index.js?kind=PAGES&page=%2Fsearch&preferredRegion=&absolutePagePath=private-next-pages%2Fsearch.js&absoluteAppPath=private-next-pages%2F_app.js&absoluteDocumentPath=next%2Fdist%2Fpages%2F_document&middlewareConfigBase64=e30%3D!
// Import the app and document modules.
// Import the userland code.
// Re-export the component (should be the default export).
/* harmony default export */ const next_route_loaderkind_PAGES_page_2Fsearch_preferredRegion_absolutePagePath_private_next_pages_2Fsearch_js_absoluteAppPath_private_next_pages_2F_app_js_absoluteDocumentPath_next_2Fdist_2Fpages_2F_document_middlewareConfigBase64_e30_3D_ = ((0,helpers/* hoist */.l)(search_namespaceObject, "default"));
// Re-export methods.
const getStaticProps = (0,helpers/* hoist */.l)(search_namespaceObject, "getStaticProps");
const getStaticPaths = (0,helpers/* hoist */.l)(search_namespaceObject, "getStaticPaths");
const getServerSideProps = (0,helpers/* hoist */.l)(search_namespaceObject, "getServerSideProps");
const config = (0,helpers/* hoist */.l)(search_namespaceObject, "config");
const reportWebVitals = (0,helpers/* hoist */.l)(search_namespaceObject, "reportWebVitals");
// Re-export legacy methods.
const unstable_getStaticProps = (0,helpers/* hoist */.l)(search_namespaceObject, "unstable_getStaticProps");
const unstable_getStaticPaths = (0,helpers/* hoist */.l)(search_namespaceObject, "unstable_getStaticPaths");
const unstable_getStaticParams = (0,helpers/* hoist */.l)(search_namespaceObject, "unstable_getStaticParams");
const unstable_getServerProps = (0,helpers/* hoist */.l)(search_namespaceObject, "unstable_getServerProps");
const unstable_getServerSideProps = (0,helpers/* hoist */.l)(search_namespaceObject, "unstable_getServerSideProps");
// Create and export the route module that will be consumed.
const routeModule = new module_compiled.PagesRouteModule({
definition: {
kind: route_kind/* RouteKind */.x.PAGES,
page: "/search",
pathname: "/search",
// The following aren't used in production.
bundlePath: "",
filename: ""
},
components: {
App: _app["default"],
Document: (_document_default())
},
userland: search_namespaceObject
});
//# sourceMappingURL=pages.js.map
/***/ }),
/***/ 2204:
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ S: () => (/* binding */ DEFAULT_CATEGORIES)
/* harmony export */ });
const DEFAULT_CATEGORIES = {
expense: [
{
name: "é¤é¥®",
icon: "\uD83C\uDF5C"
},
{
name: "ä¹°èœ",
icon: "\uD83E\uDD6C"
},
{
name: "交通",
icon: "\uD83D\uDE97"
},
{
name: "购物",
icon: "\uD83D\uDED2"
},
{
name: "娱ä¹",
icon: "\uD83C\uDFAE"
},
{
name: "房租",
icon: "\uD83C\uDFE0"
},
{
name: "房贷",
icon: "\uD83C\uDFE6"
},
{
name: "亲情å¡",
icon: "\uD83D\uDCB3"
},
{
name: "水电",
icon: "\uD83D\uDCA7"
},
{
name: "è¡£æœ",
icon: "\uD83D\uDC54"
},
{
name: "通讯",
icon: "\uD83D\uDCF1"
},
{
name: "日用å“",
icon: "\uD83E\uDDF4"
},
{
name: "美妆",
icon: "\uD83D\uDC84"
},
{
name: "医疗",
icon: "\uD83C\uDFE5"
},
{
name: "养娃",
icon: "\uD83D\uDC76"
},
{
name: "家电",
icon: "\uD83D\uDCFA"
},
{
name: "å®¶å…·",
icon: "\uD83D\uDECBï¸"
},
{
name: "装修",
icon: "\uD83D\uDD28"
},
{
name: "宠物",
icon: "\uD83D\uDC15"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
],
income: [
{
name: "工资",
icon: "\uD83D\uDCB0"
},
{
name: "奖金",
icon: "\uD83C\uDF81"
},
{
name: "ç†è´¢",
icon: "\uD83D\uDCC8"
},
{
name: "红包",
icon: "\uD83E\uDDE7"
},
{
name: "å…¶ä»–",
icon: "\uD83D\uDCDD"
}
]
};
/***/ }),
/***/ 2785:
/***/ ((module) => {
module.exports = require("next/dist/compiled/next-server/pages.runtime.prod.js");
/***/ }),
/***/ 6689:
/***/ ((module) => {
module.exports = require("react");
/***/ }),
/***/ 6405:
/***/ ((module) => {
module.exports = require("react-dom");
/***/ }),
/***/ 997:
/***/ ((module) => {
module.exports = require("react/jsx-runtime");
/***/ }),
/***/ 2048:
/***/ ((module) => {
module.exports = require("fs");
/***/ }),
/***/ 5315:
/***/ ((module) => {
module.exports = require("path");
/***/ }),
/***/ 6162:
/***/ ((module) => {
module.exports = require("stream");
/***/ }),
/***/ 1568:
/***/ ((module) => {
module.exports = require("zlib");
/***/ })
};
;
// load runtime
var __webpack_require__ = require("../webpack-runtime.js");
__webpack_require__.C(exports);
var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId))
var __webpack_exports__ = __webpack_require__.X(0, [899,342,261], () => (__webpack_exec__(1076)));
module.exports = __webpack_exports__;
})(); Ç ¸  `d¹u"use strict";
(() => {
var exports = {};
exports.id = 603;
exports.ids = [603,660];
exports.modules = {
/***/ 1076:
¸È¸l
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
config: () => (/* binding */ config),
"default": () => (/* binding */ next_route_loaderkind_PAGES_page_2Fsearch_preferredRegion_absolutePagePath_private_next_pages_2Fsearch_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/search.js
var search_namespaceObject = {};
__webpack_require__.r(search_namespaceObject);
__webpack_require__.d(search_namespaceObject, {
"default": () => (Search)
});
// 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);
;// CONCATENATED MODULE: ./pages/search.js
ɹF4import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import { isLoggedIn, searchRecords } from "../lib/api";
import { DEFAULT_CATEGORIES } from "../lib/categories";
import AppShell from "../components/AppShell";
import { Icon } from "../components/icons";
import { useToast } from "../components/ToastProvider";
export default function Search() {
const router = useRouter();
const { showToast } = useToast();
const [keyword, setKeyword] = useState("");
const [results, setResults] = useState([]);
const [loading, setLoading] = useState(false);
null;
const handleSearch = async (e)=>{
e.preventDefault();
if (!keyword.trim()) {
showToast("请输入æœç´¢å…³é”®è¯", {
tone: "info"
});
return;
}
setLoading(true);
try {
const data = await searchRecords(keyword);
setResults(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const formatMoney = (num)=>(num || 0).toFixed(2);
const groupedResults = results.reduce((groups, record)=>{
const date = record.date.split(" ")[0];
if (!groups[date]) groups[date] = [];
groups[date].push(record);
return groups;
}, {});
const sortedDates = Object.keys(groupedResults).sort((a, b)=>b.localeCompare(a));
const totalIncome = results.filter((record)=>record.type === "income").reduce((sum, record)=>sum + record.amount, 0);
const totalExpense = results.filter((record)=>record.type === "expense").reduce((sum, record)=>sum + record.amount, 0);
const totalBalance = totalIncome - totalExpense;
const actions = /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button",
"aria-label": "设置",
onClick: ()=>router.push("/settings"),
children: /*#__PURE__*/ _jsx(Icon, {
name: "settings",
size: 18
})
});
return /*#__PURE__*/ _jsxs(AppShell, {
title: "æœç´¢",
subtitle: "快速查找分类ã€å¤‡æ³¨ä¸Žé‡‘é¢",
actions: actions,
compactHeader: true,
children: [
/*#__PURE__*/ _jsxs("section", {
className: "card section-card section-card--search section-card--search-panel",
children: [
/*#__PURE__*/ _jsxs("form", {
className: "search-form search-form--refresh",
onSubmit: handleSearch,
children: [
/*#__PURE__*/ _jsxs("div", {
className: "search-input-wrap",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "search",
size: 18,
className: "search-input-wrap__icon"
}),
/*#__PURE__*/ _jsx("input", {
type: "text",
value: keyword,
onChange: (e)=>setKeyword(e.target.value),
placeholder: "æœç´¢åˆ†ç±»æˆ–备注...",
autoFocus: true,
disabled: loading
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "submit",
className: "btn btn-primary btn-inline",
disabled: loading,
children: loading ? /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
œç´¢ä¸­..."
]
}) : "æœç´¢"
})
]
}),
results.length > 0 ? /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "search-summary",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "search-stat",
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "æ”¶å…¥"
}),
/*#__PURE__*/ _jsxs("span", {
className: "value income",
children: [
"+",
formatMoney(totalIncome)
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "search-stat",
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "支出"
}),
/*#__PURE__*/ _jsxs("span", {
className: "value expense",
children: [
"-",
formatMoney(totalExpense)
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "search-stat",
children: [
/*#__PURE__*/ _jsx("span", {
className: "label",
children: "结余"
}),
/*#__PURE__*/ _jsx("span", {
className: "value",
children: formatMoney(totalBalance)
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "results-count",
children: [
"找到 ",
results.length,
" æ¡è®°å½•"
]
})
]
}) : null
]
}),
loading ? /*#__PURE__*/ _jsx("div", {
className: "card loading-state",
children: "æœç´¢ä¸­..."
}) : results.length > 0 ? /*#__PURE__*/ _jsx("section", {
className: "card section-card",
children: /*#__PURE__*/ _jsx("div", {
className: "records-list records-list--flush",
children: sortedDates.map((date)=>/*#__PURE__*/ _jsxs("div", {
className: "date-group",
children: [
/*#__PURE__*/ _jsx("div", {
className: "date-label",
children: new Date(date).toLocaleDateString("zh-CN", {
month: "short",
day: "numeric",
weekday: "short"
})
}),
groupedResults[date].map((record)=>{
const categories = DEFAULT_CATEGORIES[record.type];
const cat = categories.find((item)=>item.name === record.category) || {
icon: "\uD83D\uDCDD"
};
return /*#__PURE__*/ _jsxs("div", {
className: "record-item record-item--static",
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))
})
}) : keyword ? /*#__PURE__*/ _jsxs("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ _jsx(Icon, {
name: "search",
size: 24
})
}),
/*#__PURE__*/ _jsx("p", {
children: "未找到相关记录"
})
]
}) : /*#__PURE__*/ _jsxs("div", {
className: "card empty-state empty-state--card",
children: [
/*#__PURE__*/ _jsx("div", {
className: "empty-state__icon",
children: /*#__PURE__*/ _jsx(Icon, {
name: "search",
size: 24
})
}),
/*#__PURE__*/ _jsx("p", {
children: "输入关键è¯å¼€å§‹æœç´¢"
})
]
})
]
});
}
'085undefined87130undefined132171undefined173227undefined229283undefined285330undefined332374undefined376430undefined432446undefined486494__WEBPACK_MODULE_REFERENCE__7_5b22757365526f75746572225d_call_directImport_asiSafe1__._undefined525532__WEBPACK_MODULE_REFERENCE__12_5b22757365546f617374225d_call_directImport_asiSafe1__._undefined571578__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined619626__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined667674__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined973985__WEBPACK_MODULE_REFERENCE__8_5b227365617263685265636f726473225d_call_directImport_asiSafe1__._undefined19321935__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined21142117__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined21192122__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined22222226__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined22282235__WEBPACK_MODULE_REFERENCE__10_5b2264656661756c74225d_directImport_asiSafe1__._undefined23962400__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined25732577__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined27862790__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined29592962__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined29642967__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined32453248__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined37833786__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined40384042__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined42214224__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined42264229__WEBPACK_MODULE_REFERENCE__11_5b2249636f6e225d_directImport_asiSafe1__._undefined47274731__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined47334741__WEBPACK_MODULE_REFERENCE__5_5b22467261676d656e74225d_directImport_asiSafe1__._undefined48244828__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined49944998__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined51855188__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined54375441__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined59515955__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined61426145__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined63946398__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined69106914__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined71017104__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined73537356__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined77567760__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined82048207__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined83548357__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined84608463__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined86098613__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined87638766__WEBPACK_MODULE_REFERENCE__5_5b226a7378225d_directImport_asiSafe1__._undefined92979314__WEBPACK_MODULE_REFERENCE__9_5b2244454641554c545f43415445474f52494553225d_directImport_asiSafe1__._undefined95959599__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined98069810__WEBPACK_MODULE_REFERENCE__5_5b226a737873225d_call_directImport_asiSafe1__._undefined1002110024__WEBPACK_MODULE_REFERENCE__5_5b22
;// CONCATENATED MODULE: ./node_modules/next/dist/build/webpack/loaders/next-route-loader/index.js?kind=PAGES&page=%2Fsearch&preferredRegion=&absolutePagePath=private-next-pages%2Fsearch.js&absoluteAppPath=private-next-pages%2F_app.js&absoluteDocumentPath=next%2Fdist%2Fpages%2F_document&middlewareConfigBase64=e30%3D!
ŵã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/search.js";
// Re-export the component (should be the default export).
export default hoist(userland, "default");