Files
accountbook/frontend/.next/cache/webpack/client-production/9.pack
T

6490 lines
342 KiB
Plaintext
Raw Normal View History

2026-03-12 11:24:10 +08:00
wpc@Y§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|]|fallback=[|assert=|/opt/accountbook/frontend/node_modules/next/dist/compiled/assert/assert.js|buffer=|/opt/accountbook/frontend/node_modules/next/dist/compiled/buffer/index.js|constants=|/opt/accountbook/frontend/node_modules/next/dist/compiled/constants-browserify/constants.json|crypto=|/opt/accountbook/frontend/node_modules/next/dist/compiled/crypto-browserify/index.js|domain=|/opt/accountbook/frontend/node_modules/next/dist/compiled/domain-browser/index.js|http=|/opt/accountbook/frontend/node_modules/next/dist/compiled/stream-http/index.js|https=|/opt/accountbook/frontend/node_modules/next/dist/compiled/https-browserify/index.js|os=|/opt/accountbook/frontend/node_modules/next/dist/compiled/os-browserify/browser.js|path=|/opt/accountbook/frontend/node_modules/next/dist/compiled/path-browserify/index.js|punycode=|/opt/accountbook/frontend/node_modules/next/dist/compiled/punycode/punycode.js|process=|/opt/accountbook/frontend/node_modules/next/dist/build/polyfills/process.js|querystring=|/opt/accountbook/frontend/node_modules/next/dist/compiled/querystring-es3/index.js|stream=|/opt/accountbook/frontend/node_modules/next/dist/compiled/stream-browserify/index.js|string_decoder=|/opt/accountbook/frontend/node_modules/next/dist/compiled/string_decoder/string_decoder.js|sys=|/opt/accountbook/frontend/node_modules/next/dist/compiled/util/util.js|timers=|/opt/accountbook/frontend/node_modules/next/dist/compiled/timers-browserify/main.js|tty=|/opt/accountbook/frontend/node_modules/next/dist/compiled/tty-browserify/index.js|util=|/opt/accountbook/frontend/node_modules/next/dist/compiled/util/util.js|vm=|/opt/accountbook/frontend/node_modules/next/dist/compiled/vm-browserify/index.js|zlib=|/opt/accountbook/frontend/node_modules/next/dist/compiled/browserify-zlib/index.js|events=|/opt/accountbook/frontend/node_modules/next/dist/compiled/events/events.js|setImmediate=|/opt/accountbook/frontend/node_modules/next/dist/compiled/setimmediate/setImmediate.js|]|dependencyType=|commonjs|path=|/opt/accountbook/frontend|request=|private-next-pages/categories.jsÀCompilation/modules|/opt/accountbook/frontend/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[7].oneOf[3].use[0]!/opt/accountbook/frontend/pages/categories.jsÈFlagDependencyExportsPlugin|/opt/accountbook/frontend/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[7].oneOf[3].use[0]!/opt/accountbook/frontend/pages/categories.jsÏCompilation/codeGeneration|/opt/accountbook/frontend/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[7].oneOf[3].use[0]!/opt/accountbook/frontend/pages/categories.js|webpackCompilation/assets|chunk161ÆTerserWebpackPlugin|static/chunks/pages/categories-481cd6d9ba9dc4bd.jsÀTerserWebpackPlugin|static/WcdrsmB0Gcf0Ae4THLaKR/_ssgManifest.jsÂTerserWebpackPlugin|static/WcdrsmB0Gcf0Ae4THLaKR/_buildManifest.jsÐRealContentHashPlugin|analyse|static/chunks/pages/categories-481cd6d9ba9dc4bd.jsÊRealContentHashPlugin|analyse|static/WcdrsmB0Gcf0Ae4THLaKR/_ssgManifest.jsÌRealContentHashPlugin|analyse|static/WcdrsmB0Gcf0Ae4THLaKR/_buildManifest.jsÍRealContentHashPlugin|generate|static/WcdrsmB0Gcf0Ae4THLaKR/_buildManifest.js¥webpack/lib/cache/ResolverCachePlugin`_ResolverCachePluginCacheMiss‡context„path‡request…queryˆfragment†module‰directory„fileˆinternalŽfullySpecified“descriptionFilePath“descriptionFileData“descriptionFileRootŒrelativePath__innerRequest_request__innerRequest_relativePathŽ__innerRequest †issuerissuerLayerˆcompiler†client­/opt/accountbook/frontend/pages/categories.js€€ ¦/opt/accountbook/frontend/package.json„name‡version‡private‡scriptsŒdependencies”accountbook-
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import { isLoggedIn, getCategories, createCategory, deleteCategory } from "../lib/api";
import AppShell from "../components/AppShell";
import { Icon } from "../components/icons";
import { useToast } from "../components/ToastProvider";
import { useConfirm } from "../components/ConfirmProvider";
const ICONS = [
"\uD83C\uDF5C",
"\uD83E\uDD58",
"\uD83E\uDD6C",
"\uD83E\uDD69",
"\uD83C\uDF54",
"\uD83C\uDF55",
"☕",
"\uD83C\uDF7A",
"\uD83E\uDDCB",
"\uD83C\uDF4E",
"\uD83C\uDF6A",
"\uD83C\uDF6B",
"\uD83D\uDE97",
"\uD83D\uDE95",
"\uD83D\uDE8C",
"\uD83D\uDE87",
"⛽",
"\uD83D\uDE99",
"\uD83D\uDEF5",
"✈ï¸",
"\uD83D\uDEA2",
"\uD83D\uDED2",
"\uD83D\uDC54",
"\uD83D\uDC55",
"\uD83D\uDC56",
"\uD83D\uDC5F",
"\uD83D\uDC53",
"\uD83E\uDDE2",
"\uD83D\uDC5C",
"\uD83C\uDF92",
"\uD83D\uDC8D",
"\uD83D\uDC84",
"\uD83C\uDFE0",
"\uD83C\uDFE2",
"\uD83C\uDFE6",
"\uD83C\uDFE5",
"\uD83C\uDFE8",
"\uD83C\uDFE9",
"\uD83D\uDD27",
"\uD83D\uDD28",
"\uD83D\uDECBï¸",
"\uD83D\uDCFA",
"\uD83D\uDCBB",
"\uD83D\uDCF1",
"\uD83D\uDCDD",
"\uD83D\uDCB0",
"\uD83C\uDF81",
"\uD83D\uDCC8",
"\uD83E\uDDE7",
"\uD83D\uDCB3",
"\uD83C\uDFAF",
"\uD83D\uDCDA",
"\uD83C\uDFB5",
"\uD83C\uDFAE",
"\uD83C\uDFC3",
"âš½",
"\uD83C\uDFCA",
"\uD83D\uDEB4",
"\uD83C\uDFAD",
"\uD83C\uDFA8",
"\uD83C\uDFAC",
"\uD83D\uDCF7",
"\uD83C\uDFA5",
"\uD83D\uDCFA",
"\uD83E\uDDF8",
"\uD83D\uDC15",
"\uD83D\uDC08",
"\uD83C\uDF38",
"\uD83C\uDF3A"
];
export default function Categories() {
const router = useRouter();
const { showToast } = useToast();
const { confirm } = useConfirm();
const [categories, setCategories] = useState({
expense: [],
income: []
});
const [modalOpen, setModalOpen] = useState(false);
const [categoryType, setCategoryType] = useState("expense");
const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false);
const [formError, setFormError] = useState("");
const [formData, setFormData] = useState({
name: "",
icon: "\uD83D\uDCDD"
});
useEffect(()=>{
if (!isLoggedIn()) {
router.push("/login");
return;
}
loadCategories();
}, [
router
]);
const loadCategories = async ()=>{
setLoading(true);
try {
const data = await getCategories();
setCategories(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const openAddModal = (type)=>{
setCategoryType(type);
setFormData({
name: "",
icon: "\uD83D\uDCDD"
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting) return;
setModalOpen(false);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.name || !formData.icon) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
await createCategory({
type: categoryType,
name: formData.name,
icon: formData.icon
});
closeModal();
showToast("分类已创建", {
tone: "success"
});
await loadCategories();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async (id)=>{
const shouldDelete = await confirm({
title: "删除此分类?",
description: "默认分类ä¸å¯åˆ é™¤ï¼Œè‡ªå®šä¹‰åˆ†ç±»åˆ é™¤åŽå°†æ— æ³•æ¢å¤ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
try {
await deleteCategory(id);
showToast("分类已删除", {
tone: "success"
});
await loadCategories();
} catch (err) {
showToast(err.message, {
tone: "error"
});
}
};
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: "加载中..."
}) : /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("section", {
className: "card category-section category-section--refresh",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "section-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: "支出分类"
}),
/*#__PURE__*/ _jsx("h2", {
children: "支出"
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: ()=>openAddModal("expense"),
children: /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "plus",
size: 16
}),
"添加"
]
})
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "category-list category-list--chips",
children: categories.expense.map((cat)=>/*#__PURE__*/ _jsxs("div", {
className: "category-tag",
children: [
/*#__PURE__*/ _jsx("span", {
className: "cat-icon",
children: cat.icon
}),
/*#__PURE__*/ _jsx("span", {
className: "cat-name",
children: cat.name
}),
!cat.is_default && /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button icon-button--ghost cat-delete",
"aria-label": "删除".concat(cat.name),
onClick: ()=>handleDelete(cat.id),
children: /*#__PURE__*/ _jsx(Icon, {
name: "close",
size: 14
})
})
]
}, cat.id || cat.name))
})
]
}),
/*#__PURE__*/ _jsxs("section", {
className: "card category-section category-section--refresh",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "section-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: "收入分类"
}),
/*#__PURE__*/ _jsx("h2", {
children: "æ”¶å…¥"
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: ()=>openAddModal("income"),
children: /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "plus",
size: 16
}),
"添加"
]
})
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "category-list category-list--chips",
children: categories.income.map((cat)=>/*#__PURE__*/ _jsxs("div", {
className: "category-tag",
children: [
/*#__PURE__*/ _jsx("span", {
className: "cat-icon",
children: cat.icon
}),
/*#__PURE__*/ _jsx("span", {
className: "cat-name",
children: cat.name
}),
!cat.is_default && /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button icon-button--ghost cat-delete",
"aria-label": "删除".concat(cat.name),
onClick: ()=>handleDelete(cat.id),
children: /*#__PURE__*/ _jsx(Icon, {
name: "close",
size: 14
})
})
]
}, cat.id || cat.name))
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "card category-tip category-tip--refresh",
children: /*#__PURE__*/ _jsx("p", {
children: "默认分类无法删除,自定义分类å¯ä»¥åˆ é™¤ã€‚"
})
})
]
}),
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: "新增分类"
}),
/*#__PURE__*/ _jsx("h2", {
children: categoryType === "expense" ? "新建支出分类" : "新建收入分类"
})
]
}),
/*#__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: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
htmlFor: "category-name",
children: "分类åç§°"
}),
/*#__PURE__*/ _jsx("input", {
id: "category-name",
type: "text",
value: formData.name,
onChange: (e)=>setFormData({
...formData,
name: e.target.value
}),
placeholder: "请输入分类åç§°",
required: true,
disabled: submitting
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
children: "选择图标"
}),
/*#__PURE__*/ _jsx("div", {
className: "icon-grid",
style: {
display: "grid",
gridTemplateColumns: "repeat(8, minmax(0, 1fr))",
gap: "8px"
},
children: ICONS.map((icon)=>/*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-btn ".concat(formData.icon === icon ? "active" : ""),
onClick: ()=>setFormData({
...formData,
icon
}),
disabled: submitting,
children: icon
}, icon))
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "modal-actions",
children: /*#__PURE__*/ _jsx("button", {
type: "submit",
className: "btn btn-primary",
disabled: submitting,
children: submitting ? /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
})
})
]
})
]
})
})
]
});
}
exportsTypeŽsideEffectFree‰namespace 
javascript/auto…alias§ˆfallbackŒ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ÿþ
`†assert†buffer‰constants†crypto†domain„http…httpsosˆpunycode‡processquerystring†streamŽstring_decoderƒsys†timersƒtty„utilvm„zlib†eventsŒsetImmediateÊ/opt/accountbook/frontend/node_modules/next/dist/compiled/assert/assert.jsÉ/opt/accountbook/frontend/node_modules/next/dist/compiled/buffer/index.jsÝ/opt/accountbook/frontend/node_modules/next/dist/compiled/constants-browserify/constants.jsonÔ/opt/accountbook/frontend/node_modules/next/dist/compiled/crypto-browserify/index.jsÑ/opt/accountbook/frontend/node_modules/next/dist/compiled/domain-browser/index.jsÎ/opt/accountbook/frontend/node_modules/next/dist/compiled/stream-http/index.jsÓ/opt/accountbook/frontend/node_modules/next/dist/compiled/https-browserify/index.jsÒ/opt/accountbook/frontend/node_modules/next/dist/compiled/os-browserify/browser.jsÒ/opt/accountbook/frontend/node_modules/next/dist/compiled/path-browserify/index.jsÎ/opt/accountbook/frontend/node_modules/next/dist/compiled/punycode/punycode.jsË/opt/accountbook/frontend/node_modules/next/dist/build/polyfills/process.jsÒ/opt/accountbook/frontend/node_modules/next/dist/compiled/querystring-es3/index.jsÔ/opt/accountbook/frontend/node_modules/next/dist/compiled/stream-browserify/index.jsÚ/opt/accountbook/frontend/node_modules/next/dist/compiled/string_decoder/string_decoder.jsÆ/opt/accountbook/frontend/node_modules/next/dist/compiled/util/util.jsÓ/opt/accountbook/frontend/node_modules/next/dist/compiled/timers-browserify/main.jsÑ/opt/accountbook/frontend/node_modules/next/dist/compiled/tty-browserify/index.jsýÐ/opt/accountbook/frontend/node_modules/next/dist/compiled/vm-browserify/index.jsÒ/opt/accountbook/frontend/node_modules/next/dist/compiled/browserify-zlib/index.jsÊ/opt/accountbook/frontend/node_modules/next/dist/compiled/events/events.jsÖ/opt/accountbook/frontend/node_modules/next/dist/compiled/setimmediate/setImmediate.js
Å`‰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ˆ898e1469b695d65e484bfd79 “__webpack_exports__…ICONS‰*default*ŠCategories 0
`ÃÍyB fÿÿÿ
·webpack/lib/dependencies/HarmonyCompatibilityDependency
dÿÿý¨webpack/lib/dependencies/ConstDependency`V
`V`W@ƒ
`,A„¬
`(A­
`WA3
`.A4_
`+A`
`7A˜Ó
`;¶webpack/lib/dependencies/HarmonyExportHeaderDependency A/ L A  L
aP@¿ `Zºwebpack/lib/dependencies/HarmonyImportSideEffectDependencyreact/jsx-runtimeÿ
`V`ÿÿÿ`ÿÿÿ
`,next/routerÿ
`(Š../lib/apiÿ
`W../components/AppShellÿ
`.“../components/iconsÿ
`+../components/ToastProviderÿ
`7../components/ConfirmProviderÿ
`;±webpack/lib/dependencies/PureExpressionDependencya ‡default
aO¹webpack/lib/dependencies/HarmonyExportSpecifierDependencyý
aP@¿¹webpack/lib/dependencies/HarmonyImportSpecifierDependencya
‰useRouterþ
AZc
 øêêý
cQQ
ˆuseToastþ
A
 úííþ
cRR"
ŠuseConfirmþ
¯
 õêêþ
cSS"
ˆuseStateþ
ã
 ð:ÿÿÿ:ÿÿÿþ
cT(T0
ûú
A<D
 ì6ÿÿÿ6ÿÿÿþ
cX&X.
÷ö
Ay
 è2ÿÿÿ2ÿÿÿþ
cY,Y4
óò
¸
 ä.ÿÿÿ.ÿÿÿþ
cZ"Z*
ïî
ð
 à*ÿÿÿ*ÿÿÿþ
c[([0
ëê
A ' 
 Ü&ÿÿÿ&ÿÿÿþ
c\&\.
çæ
AQ Y 
 Ø"ÿÿÿ"ÿÿÿþ
c]$],
‰useEffectþ
A—   
 Óÿÿÿÿÿÿþ
caa

ŠisLoggedInþ
A´ ¾ 
 λ»þ
cb
b
getCategoriesþ
A­
º

 Éþ
cmm,
ŽcreateCategoryþ
A 
 ı±þ
@`@` 
ŽdeleteCategoryþ
A!
 ¿¬¬þ
`` 
ƒjsx„_jsx
A:>
 ¹¡¡þ
`"@µ`&
úû
ô
 µþ
` @º`$
„Iconþ
ù
4°¡¡þ
`%@º`)
„jsxs…_jsxs
A\a
 ªþ
@¿`@¿`
¡ˆAppShell
Abj
4¥þ
@¿`@¿`'
æç
A
 ¡þ
`$@Å`(
ñò
A
 þ
``$
ˆFragment‰_Fragment
A˜¡
4ÿÿÿÿÿÿþ
`%@È`.
çè
è
 {ÿÿÿ{ÿÿÿþ
`"@Ê`'
ãä
Ÿ
 wÿÿÿwÿÿÿþ
`*@Í`/
ßà
ADI
 sÿÿÿsÿÿÿþ
`2@Ð`7
ÌÍ
Å
 oÿÿÿoÿÿÿþ
`:@Ò`>
ÈÉ
Â
 ƒkÿÿÿkÿÿÿþ
`:@Ö`>
ÄÅ
Á
 ÿÿÿgÿÿÿgÿÿÿþ
`2@Û`6
ÏÐ
ì
 {ÿÿÿcÿÿÿcÿÿÿþ
`@@ß`E
¼½
º
 wÿÿÿ_ÿÿÿ_ÿÿÿþ
`>@â`BÃÂ
¿
4tÿÿÿeÿÿÿeÿÿÿþ
`C@â`G
µ
A—
 pÿÿÿXÿÿÿXÿÿÿþ
`*@ì`.
ÀÁ
ALQ
 lÿÿÿTÿÿÿTÿÿÿþ
`V@î`[
­®
A 
 hÿÿÿPÿÿÿPÿÿÿþ
`:@ñ`>
©ª
A
 dÿÿÿLÿÿÿLÿÿÿþ
`:@õ`>
¥¦
A% ) 
 `ÿÿÿHÿÿÿHÿÿÿþ
`M@ù`Q
¡¢
AÎ!Ò!
 \ÿÿÿDÿÿÿDÿÿÿþ
`H@þ`L¨§
AÓ!×!
4YÿÿÿJÿÿÿJÿÿÿþ
`M@þ`Q
©ª
A##
 Uÿÿÿ=ÿÿÿ=ÿÿÿþ
@`"@`'
¥¦
AM$R$
 Qÿÿÿ9ÿÿÿ9ÿÿÿþ
@ `*@ `/
¡¢
A÷$ü$
 Mÿÿÿ5ÿÿÿ5ÿÿÿþ
@`2@`7
Ž
At%x%
 Iÿÿÿ1ÿÿÿ1ÿÿÿþ
@`:@`>
Š
Aq&u&
 Eÿÿÿ-ÿÿÿ-ÿÿÿþ
@`:@`>

Ap't'
 Aÿÿÿ)ÿÿÿ)ÿÿÿþ
@`2@`6

A™(ž(
 =ÿÿÿ%ÿÿÿ%ÿÿÿþ
@`@@`E
~ÿÿÿÿÿÿ
Ah)l)
 9ÿÿÿ!ÿÿÿ!ÿÿÿþ
@ `>@ `B
Am)q)
46ÿÿÿ'ÿÿÿ'ÿÿÿþ
@ `C@ `G
wÿÿÿxÿÿÿ
AI+M+
 2ÿÿÿÿÿÿÿÿÿþ
@*`*@*`.
ƒ
Aý+,
 .ÿÿÿÿÿÿÿÿÿþ
@,`U@,`Z
oÿÿÿpÿÿÿ
A½,Á,
 *ÿÿÿÿÿÿÿÿÿþ
@/`:@/`>
kÿÿÿlÿÿÿ
AÀ-Ä-
 &ÿÿÿÿÿÿÿÿÿþ
@3`:@3`>
gÿÿÿhÿÿÿ
AÖ.Ú.
 "ÿÿÿ
ÿÿÿ
ÿÿÿþ
@7`M@7`Q
cÿÿÿdÿÿÿ
A0ƒ0
 ÿÿÿÿÿÿÿÿÿþ
@<`H@<`Ljÿÿÿiÿÿÿ
A„0ˆ0
4ÿÿÿ ÿÿÿ ÿÿÿþ
@<`M@<`Q
\ÿÿÿ]ÿÿÿ
AG2K2
 ÿÿÿÿþÿÿÿþÿÿþ
@F`"@F`&
XÿÿÿYÿÿÿ
AÓ2×2
 ÿÿÿûþÿÿûþÿÿþ
@H`0@H`4
TÿÿÿUÿÿÿ
A3š3
 ÿÿÿ÷þÿÿ÷þÿÿþ
@N`'@N`+
_ÿÿÿ`ÿÿÿ
A4"4
  ÿÿÿóþÿÿóþÿÿþ
@Q`(@Q`-
[ÿÿÿ\ÿÿÿ
AÑ4Ö4
 ÿÿÿïþÿÿïþÿÿþ
@U`&@U`+
WÿÿÿXÿÿÿ
Am5r5
 ÿÿÿëþÿÿëþÿÿþ
@X`.@X`3
DÿÿÿEÿÿÿ
Aâ5æ5
 ÿþÿÿçþÿÿçþÿÿþ
@Z`6@Z`:
@ÿÿÿAÿÿÿ
AÏ6Ó6
 ûþÿÿãþÿÿãþÿÿþ
@^`6@^`:
<ÿÿÿ=ÿÿÿ
Aæ7ê7
 ÷þÿÿßþÿÿßþÿÿþ
@c`.@c`2
8ÿÿÿ9ÿÿÿ
A+9/9
 óþÿÿÛþÿÿÛþÿÿþ
@h`<@h`@?ÿÿÿ>ÿÿÿ
A0949
4ðþÿÿáþÿÿáþÿÿþ
@h`A@h`E
1ÿÿÿ2ÿÿÿ
AW:[:
 ìþÿÿÔþÿÿÔþÿÿþ
@o`3@o`7
<ÿÿÿ=ÿÿÿ
A ;;
 èþÿÿÐþÿÿÐþÿÿþ
@s`&@s`+
8ÿÿÿ9ÿÿÿ
A¥;ª;
 äþÿÿÌþÿÿÌþÿÿþ
@v`.@v`3
%ÿÿÿ&ÿÿÿ
AW<[<
 àþÿÿÈþÿÿÈþÿÿþ
@y`6@y`:
!ÿÿÿ"ÿÿÿ
AL=P=
 ÜþÿÿÄþÿÿÄþÿÿþ
@}`6@}`:
,ÿÿÿ-ÿÿÿ
A„@‰@
 ØþÿÿÀþÿÿÀþÿÿþ
@`.@`3
ÿÿÿÿÿÿ
A6A:A
 Ôþÿÿ¼þÿÿ¼þÿÿþ
`6@Ž`:
ÿÿÿÿÿÿ
AåAéA
 Ðþÿÿ¸þÿÿ¸þÿÿþ
@`6@`:
ÿÿÿÿÿÿ
AÏCÓC
 Ìþÿÿ´þÿÿ´þÿÿþ
@˜`V@˜`Z

ÿÿÿÿÿÿ
AG"G
 Èþÿÿ°þÿÿ°þÿÿþ
`.@¥`2
 ÿÿÿ
ÿÿÿ
A¨G¬G
 Äþÿÿ¬þÿÿ¬þÿÿþ
`<@§`@
ÿÿÿÿÿÿ
AÂHÇH
 Àþÿÿ¨þÿÿ¨þÿÿþ
`M@«`R
ÿÿÿÿÿÿ
AI•I
 ¼þÿÿ¤þÿÿ¤þÿÿþ
`>@®`Bÿÿÿÿÿÿ
AIšI
4¹þÿÿªþÿÿªþÿÿþ
`C@®`G
—webpack/lib/ModuleGraph“RestoreProvidedDataíýÿÿˆprovidedcanMangleProvideterminalBindingexportsInfo¨þÿÿ
‡sources“runtimeRequirements„dataŠjavascript«webpack/lib/util/registerExternalSerializerœwebpack-sources/CachedSource ÑY«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ Categories; }
/* harmony export */ });
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5893);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7294);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1163);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(next_router__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(610);
/* harmony import */ var _components_AppShell__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6248);
/* harmony import */ var _components_icons__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9415);
/* harmony import */ var _components_ToastProvider__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(5546);
/* harmony import */ var _components_ConfirmProvider__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(8846);
«webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource4Mimport { 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, getCategories, createCategory, deleteCategory } from "../lib/api";
import AppShell from "../components/AppShell";
import { Icon } from "../components/icons";
import { useToast } from "../components/ToastProvider";
import { useConfirm } from "../components/ConfirmProvider";
const ICONS = [
"\uD83C\uDF5C",
"\uD83E\uDD58",
"\uD83E\uDD6C",
"\uD83E\uDD69",
"\uD83C\uDF54",
"\uD83C\uDF55",
"☕",
"\uD83C\uDF7A",
"\uD83E\uDDCB",
"\uD83C\uDF4E",
"\uD83C\uDF6A",
"\uD83C\uDF6B",
"\uD83D\uDE97",
"\uD83D\uDE95",
"\uD83D\uDE8C",
"\uD83D\uDE87",
"⛽",
"\uD83D\uDE99",
"\uD83D\uDEF5",
"✈ï¸",
"\uD83D\uDEA2",
"\uD83D\uDED2",
"\uD83D\uDC54",
"\uD83D\uDC55",
"\uD83D\uDC56",
"\uD83D\uDC5F",
"\uD83D\uDC53",
"\uD83E\uDDE2",
"\uD83D\uDC5C",
"\uD83C\uDF92",
"\uD83D\uDC8D",
"\uD83D\uDC84",
"\uD83C\uDFE0",
"\uD83C\uDFE2",
"\uD83C\uDFE6",
"\uD83C\uDFE5",
"\uD83C\uDFE8",
"\uD83C\uDFE9",
"\uD83D\uDD27",
"\uD83D\uDD28",
"\uD83D\uDECBï¸",
"\uD83D\uDCFA",
"\uD83D\uDCBB",
"\uD83D\uDCF1",
"\uD83D\uDCDD",
"\uD83D\uDCB0",
"\uD83C\uDF81",
"\uD83D\uDCC8",
"\uD83E\uDDE7",
"\uD83D\uDCB3",
"\uD83C\uDFAF",
"\uD83D\uDCDA",
"\uD83C\uDFB5",
"\uD83C\uDFAE",
"\uD83C\uDFC3",
"âš½",
"\uD83C\uDFCA",
"\uD83D\uDEB4",
"\uD83C\uDFAD",
"\uD83C\uDFA8",
"\uD83C\uDFAC",
"\uD83D\uDCF7",
"\uD83C\uDFA5",
"\uD83D\uDCFA",
"\uD83E\uDDF8",
"\uD83D\uDC15",
"\uD83D\uDC08",
"\uD83C\uDF38",
"\uD83C\uDF3A"
];
export default function Categories() {
const router = useRouter();
const { showToast } = useToast();
const { confirm } = useConfirm();
const [categories, setCategories] = useState({
expense: [],
income: []
});
const [modalOpen, setModalOpen] = useState(false);
const [categoryType, setCategoryType] = useState("expense");
const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false);
const [formError, setFormError] = useState("");
const [formData, setFormData] = useState({
name: "",
icon: "\uD83D\uDCDD"
});
useEffect(()=>{
if (!isLoggedIn()) {
router.push("/login");
return;
}
loadCategories();
}, [
router
]);
const loadCategories = async ()=>{
setLoading(true);
try {
const data = await getCategories();
setCategories(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const openAddModal = (type)=>{
setCategoryType(type);
setFormData({
name: "",
icon: "\uD83D\uDCDD"
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting) return;
setModalOpen(false);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.name || !formData.icon) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
await createCategory({
type: categoryType,
name: formData.name,
icon: formData.icon
});
closeModal();
showToast("分类已创建", {
tone: "success"
});
await loadCategories();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async (id)=>{
const shouldDelete = await confirm({
title: "删除此分类?",
description: "默认分类ä¸å¯åˆ é™¤ï¼Œè‡ªå®šä¹‰åˆ†ç±»åˆ é™¤åŽå°†æ— æ³•æ¢å¤ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
try {
await deleteCategory(id);
showToast("分类已删除", {
tone: "success"
});
await loadCategories();
} catch (err) {
showToast(err.message, {
tone: "error"
});
}
};
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: "加载中..."
}) : /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("section", {
className: "card category-section category-section--refresh",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "section-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: "支出分类"
}),
/*#__PURE__*/ _jsx("h2", {
children: "支出"
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: ()=>openAddModal("expense"),
children: /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "plus",
size: 16
}),
"添加"
]
})
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "category-list category-list--chips",
children: categories.expense.map((cat)=>/*#__PURE__*/ _jsxs("div", {
className: "category-tag",
children: [
/*#__PURE__*/ _jsx("span", {
className: "cat-icon",
children: cat.icon
}),
/*#__PURE__*/ _jsx("span", {
className: "cat-name",
children: cat.name
}),
!cat.is_default && /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button icon-button--ghost cat-delete",
"aria-label": "删除".concat(cat.name),
onClick: ()=>handleDelete(cat.id),
children: /*#__PURE__*/ _jsx(Icon, {
name: "close",
size: 14
})
})
]
}, cat.id || cat.name))
})
]
}),
/*#__PURE__*/ _jsxs("section", {
className: "card category-section category-section--refresh",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "section-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: "收入分类"
}),
/*#__PURE__*/ _jsx("h2", {
children: "æ”¶å…¥"
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: ()=>openAddModal("income"),
children: /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "plus",
size: 16
}),
"添加"
]
})
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "category-list category-list--chips",
children: categories.income.map((cat)=>/*#__PURE__*/ _jsxs("div", {
className: "category-tag",
children: [
/*#__PURE__*/ _jsx("span", {
className: "cat-icon",
children: cat.icon
}),
/*#__PURE__*/ _jsx("span", {
className: "cat-name",
children: cat.name
}),
!cat.is_default && /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button icon-button--ghost cat-delete",
"aria-label": "删除".concat(cat.name),
onClick: ()=>handleDelete(cat.id),
children: /*#__PURE__*/ _jsx(Icon, {
name: "close",
size: 14
})
})
]
}, cat.id || cat.name))
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "card category-tip category-tip--refresh",
children: /*#__PURE__*/ _jsx("p", {
children: "默认分类无法删除,自定义分类å¯ä»¥åˆ é™¤ã€‚"
})
})
]
}),
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: "新增分类"
}),
/*#__PURE__*/ _jsx("h2", {
children: categoryType === "expense" ? "新建支出分类" : "新建收入分类"
})
]
}),
/*#__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: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
htmlFor: "category-name",
children: "分类åç§°"
}),
/*#__PURE__*/ _jsx("input", {
id: "category-name",
type: "text",
value: formData.name,
onChange: (e)=>setFormData({
...formData,
name: e.target.value
}),
placeholder: "请输入分类åç§°",
required: true,
disabled: submitting
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
children: "选择图标"
}),
/*#__PURE__*/ _jsx("div", {
className: "icon-grid",
style: {
display: "grid",
gridTemplateColumns: "repeat(8, minmax(0, 1fr))",
gap: "8px"
},
children: ICONS.map((icon)=>/*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-btn ".concat(formData.icon === icon ? "active" : ""),
onClick: ()=>setFormData({
...formData,
icon
}),
disabled: submitting,
children: icon
}, icon))
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "modal-actions",
children: /*#__PURE__*/ _jsx("button", {
type: "submit",
className: "btn btn-primary",
disabled: submitting,
children: submitting ? /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
})
})
]
})
]
})
})
]
});
}
cYUW_«­24^`˜Ò .Zbˆ¥®Ûâ<Cy°·èï _& Q X Ÿ ´ ½ ­
¹
 :=ðóõø\`bi˜ ãçšDHÁľÁ½Àçë¹»¾šLP % ( Î!Ñ!Ó!Ö!#š#M$_Q$÷$û$t%w%q&t&p's'™((h)k)m)p)I+L+ý+,½,À,À-Ã-Ö.Ù.00„0‡0G2J2Ó2_Ö23™34!4Ñ4Õ4m5q5â5å5Ï6Ò6æ7é7+9.90939W:Z: ;;¥;©;W<Z<L=O=„@ˆ@6AN9AåAèAÏCÒCG!G¨G«GÂHÆH‘I”I–I™I¶(0,next_router__WEBPACK_IMPORTED_MODULE_2__.useRouter)Ì(0,_components_ToastProvider__WEBPACK_IMPORTED_MODULE_5__/* .useToast */ .p)Ð(0,_components_ConfirmProvider__WEBPACK_IMPORTED_MODULE_6__/* .useConfirm */ .N)¯(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)ÿÿÿÿÿÿ°(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)¾(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .isLoggedIn */ .jl)Á(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .getCategories */ .CP)Â(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .createCategory */ .k4)Â(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .deleteCategory */ .uu)¶(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)ÿ¼_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J·(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)Å_components_AppShell__WEBPACK_IMPORTED_MODULE_3__/* ["default"] */ .Züþ·react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragmentýýýûûûýûüûýûûûûüýýýûûûýûüûýûûûûüûûûýýýûûûûüûýýûûýûûûûûýûü3þÿÿ†source„size„mapsÿýÿÿ___webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ Categories; }
/* harmony export */ });
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5893);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7294);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1163);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(next_router__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(610);
/* harmony import */ var _components_AppShell__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6248);
/* harmony import */ var _components_icons__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9415);
/* harmony import */ var _components_ToastProvider__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(5546);
/* harmony import */ var _components_ConfirmProvider__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(8846);
const ICONS = [
"\uD83C\uDF5C",
"\uD83E\uDD58",
"\uD83E\uDD6C",
"\uD83E\uDD69",
"\uD83C\uDF54",
"\uD83C\uDF55",
"☕",
"\uD83C\uDF7A",
"\uD83E\uDDCB",
"\uD83C\uDF4E",
"\uD83C\uDF6A",
"\uD83C\uDF6B",
"\uD83D\uDE97",
"\uD83D\uDE95",
"\uD83D\uDE8C",
"\uD83D\uDE87",
"⛽",
"\uD83D\uDE99",
"\uD83D\uDEF5",
"✈ï¸",
"\uD83D\uDEA2",
"\uD83D\uDED2",
"\uD83D\uDC54",
"\uD83D\uDC55",
"\uD83D\uDC56",
"\uD83D\uDC5F",
"\uD83D\uDC53",
"\uD83E\uDDE2",
"\uD83D\uDC5C",
"\uD83C\uDF92",
"\uD83D\uDC8D",
"\uD83D\uDC84",
"\uD83C\uDFE0",
"\uD83C\uDFE2",
"\uD83C\uDFE6",
"\uD83C\uDFE5",
"\uD83C\uDFE8",
"\uD83C\uDFE9",
"\uD83D\uDD27",
"\uD83D\uDD28",
"\uD83D\uDECBï¸",
"\uD83D\uDCFA",
"\uD83D\uDCBB",
"\uD83D\uDCF1",
"\uD83D\uDCDD",
"\uD83D\uDCB0",
"\uD83C\uDF81",
"\uD83D\uDCC8",
"\uD83E\uDDE7",
"\uD83D\uDCB3",
"\uD83C\uDFAF",
"\uD83D\uDCDA",
"\uD83C\uDFB5",
"\uD83C\uDFAE",
"\uD83C\uDFC3",
"âš½",
"\uD83C\uDFCA",
"\uD83D\uDEB4",
"\uD83C\uDFAD",
"\uD83C\uDFA8",
"\uD83C\uDFAC",
"\uD83D\uDCF7",
"\uD83C\uDFA5",
"\uD83D\uDCFA",
"\uD83E\uDDF8",
"\uD83D\uDC15",
"\uD83D\uDC08",
"\uD83C\uDF38",
"\uD83C\uDF3A"
];
function Categories() {
const router = (0,next_router__WEBPACK_IMPORTED_MODULE_2__.useRouter)();
const { showToast } = (0,_components_ToastProvider__WEBPACK_IMPORTED_MODULE_5__/* .useToast */ .p)();
const { confirm } = (0,_components_ConfirmProvider__WEBPACK_IMPORTED_MODULE_6__/* .useConfirm */ .N)();
const [categories, setCategories] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)({
expense: [],
income: []
});
const [modalOpen, setModalOpen] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false);
const [categoryType, setCategoryType] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)("expense");
const [loading, setLoading] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(true);
const [submitting, setSubmitting] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false);
const [formError, setFormError] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)("");
const [formData, setFormData] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)({
name: "",
icon: "\uD83D\uDCDD"
});
(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{
if (!(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .isLoggedIn */ .jl)()) {
router.push("/login");
return;
}
loadCategories();
}, [
router
]);
const loadCategories = async ()=>{
setLoading(true);
try {
const data = await (0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .getCategories */ .CP)();
setCategories(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const openAddModal = (type)=>{
setCategoryType(type);
setFormData({
name: "",
icon: "\uD83D\uDCDD"
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting) return;
setModalOpen(false);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.name || !formData.icon) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
await (0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .createCategory */ .k4)({
type: categoryType,
name: formData.name,
icon: formData.icon
});
closeModal();
showToast("分类已创建", {
tone: "success"
});
await loadCategories();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async (id)=>{
const shouldDelete = await confirm({
title: "删除此分类?",
description: "默认分类ä¸å¯åˆ é™¤ï¼Œè‡ªå®šä¹‰åˆ†ç±»åˆ é™¤åŽå°†æ— æ³•æ¢å¤ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
try {
await (0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .deleteCategory */ .uu)(id);
showToast("分类已删除", {
tone: "success"
});
await loadCategories();
} catch (err) {
showToast(err.message, {
tone: "error"
});
}
};
const actions = /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "icon-button",
"aria-label": "设置",
onClick: ()=>router.push("/settings"),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "settings",
size: 18
})
});
return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(_components_AppShell__WEBPACK_IMPORTED_MODULE_3__/* ["default"] */ .Z, {
title: "分类",
subtitle: "æ•´ç†å¸¸ç”¨åˆ†ç±»ä¸Žå›¾æ ‡",
actions: actions,
compactHeader: true,
children: [
loading ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "card loading-state",
children: "加载中..."
}) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, {
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("section", {
className: "card category-section category-section--refresh",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "section-header",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
className: "eyebrow",
children: "支出分类"
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", {
children: "支出"
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: ()=>openAddModal("expense"),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "plus",
size: 16
}),
"添加"
]
})
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "category-list category-list--chips",
children: categories.expense.map((cat)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "category-tag",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
className: "cat-icon",
children: cat.icon
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
className: "cat-name",
children: cat.name
}),
!cat.is_default && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "icon-button icon-button--ghost cat-delete",
"aria-label": "删除".concat(cat.name),
onClick: ()=>handleDelete(cat.id),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "close",
size: 14
})
})
]
}, cat.id || cat.name))
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("section", {
className: "card category-section category-section--refresh",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "section-header",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
className: "eyebrow",
children: "收入分类"
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", {
children: "æ”¶å…¥"
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: ()=>openAddModal("income"),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "plus",
size: 16
}),
"添加"
]
})
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "category-list category-list--chips",
children: categories.income.map((cat)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "category-tag",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
className: "cat-icon",
children: cat.icon
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
className: "cat-name",
children: cat.name
}),
!cat.is_default && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "icon-button icon-button--ghost cat-delete",
"aria-label": "删除".concat(cat.name),
onClick: ()=>handleDelete(cat.id),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "close",
size: 14
})
})
]
}, cat.id || cat.name))
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "card category-tip category-tip--refresh",
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
children: "默认分类无法删除,自定义分类å¯ä»¥åˆ é™¤ã€‚"
})
})
]
}),
modalOpen && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "modal-overlay",
onClick: closeModal,
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "modal-header",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
className: "eyebrow",
children: "新增分类"
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", {
children: categoryType === "expense" ? "新建支出分类" : "新建收入分类"
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "icon-button icon-button--ghost",
"aria-label": "关闭弹窗",
onClick: closeModal,
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "close",
size: 18
})
})
]
}),
formError && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "error-msg",
children: formError
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("form", {
onSubmit: handleSubmit,
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", {
htmlFor: "category-name",
children: "分类åç§°"
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", {
id: "category-name",
type: "text",
value: formData.name,
onChange: (e)=>setFormData({
...formData,
name: e.target.value
}),
placeholder: "请输入分类åç§°",
required: true,
disabled: submitting
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", {
children: "选择图标"
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "icon-grid",
style: {
display: "grid",
gridTemplateColumns: "repeat(8, minmax(0, 1fr))",
gap: "8px"
},
children: ICONS.map((icon)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "icon-btn ".concat(formData.icon === icon ? "active" : ""),
onClick: ()=>setFormData({
...formData,
icon
}),
disabled: submitting,
children: icon
}, icon))
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "modal-actions",
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "submit",
className: "btn btn-primary",
disabled: submitting,
children: submitting ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
})
})
]
})
]
})
})
]
});
}
”{"finalSource":true}ƒmapbufferedMap ConcatSourceRawSource__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ Categories; }
/* harmony export */ });
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5893);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7294);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1163);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(next_router__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(610);
/* harmony import */ var _components_AppShell__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6248);
/* harmony import */ var _components_icons__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9415);
/* harmony import */ var _components_ToastProvider__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(5546);
/* harmony import */ var _components_ConfirmProvider__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(8846);
ReplaceSourceRawSourceþÿÿn085undefined87130undefined132171undefined173259undefined261306undefined308350undefined352406undefined408466undefined18241838undefined18821890(0,next_router__WEBPACK_IMPORTED_MODULE_2__.useRouter)undefined19211928(0,_components_ToastProvider__WEBPACK_IMPORTED_MODULE_5__/* .useToast */ .p)undefined19571966(0,_components_ConfirmProvider__WEBPACK_IMPORTED_MODULE_6__/* .useConfirm */ .N)undefined20112018(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined21082115(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined21692176(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined22242231(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined22802287(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined23352342(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined23852392(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined24552463(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined24842493(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .isLoggedIn */ .jl)undefined27332745(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .getCategories */ .CP)undefined35963609(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .createCategory */ .k4)undefined43714384(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .deleteCategory */ .uu)undefined46664669(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined48484851(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined48534856_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .Jundefined49564960(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined49624969_components_AppShell__WEBPACK_IMPORTED_MODULE_3__/* ["default"] */ .Zundefined51375140(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined52665270(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined52725280react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragmentundefined53475351(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined55305534(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined57005704(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined58255828(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined60786081(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined63336336(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined66316635(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined68386841(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined68436846_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .Jundefined73197322(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined75007504(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined76927695(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined79517954(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined82298232(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined86548657(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined86598662_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .Jundefined91109114(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined92939297(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined94639467(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined95889591(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined98419844(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1009610099(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1039310397(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1060010603(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1060510608_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .Jundefined1108111084(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1126111265(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1145311456(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1171211715(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1199011993(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1241512418(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_
“__webpack_require__•__webpack_require__.n•__webpack_require__.r]þÿÿ•__webpack_require__.d
þÿÿ «webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource`
«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourceW(self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([[161],{
/***/ 5461:
«webpack/lib/util/registerExternalSerializerœwebpack-sources/CachedSource «webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource[/***/ (function(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
«webpack/lib/util/registerExternalSerializerœwebpack-sources/CachedSource «webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource'
(window.__NEXT_P = window.__NEXT_P || []).push([
"/categories",
function () {
return require("private-next-pages/categories.js");
}
]);
if(module.hot) {
module.hot.dispose(function () {
window.__NEXT_P.push(["/categories"])
});
}
bntvD—²»¾#“__webpack_require__„2874…false{}†buffer†source„size„maps„hash¬
(window.__NEXT_P = window.__NEXT_P || []).push([
"/categories",
function () {
return __webpack_require__(2874);
}
]);
if(false) {}
”{"finalSource":true}ƒmapbufferedMap ReplaceSourceRawSource'
(window.__NEXT_P = window.__NEXT_P || []).push([
"/categories",
function () {
return require("private-next-pages/categories.js");
}
]);
if(module.hot) {
module.hot.dispose(function () {
window.__NEXT_P.push(["/categories"])
});
}
Z110116__webpack_require__undefined1181512874undefined178187falseundefined190291{}undefined
/***/ }) †buffer†source„size„maps„hash/***/ (function(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
(window.__NEXT_P = window.__NEXT_P || []).push([
"/categories",
function () {
return __webpack_require__(2874);
}
]);
if(false) {}
/***/ }) ”{"finalSource":true}ƒmapbufferedMap ConcatSourceRawSource[/***/ (function(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
ReplaceSourceRawSource'
(window.__NEXT_P = window.__NEXT_P || []).push([
"/categories",
function () {
return require("private-next-pages/categories.js");
}
]);
if(module.hot) {
module.hot.dispose(function () {
window.__NEXT_P.push(["/categories"])
});
}
Z110116__webpack_require__undefined1181512874undefined178187falseundefined190291{}undefined RawSource
/***/ }),
/***/ 6248:
 F«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourced/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
"use strict";
«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 */ Z: function() { return /* binding */ AppShell; }
/* harmony export */ });
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5893);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7294);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1163);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(next_router__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _icons__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9415);
«webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourceUimport { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useMemo } from "react";
import { useRouter } from "next/router";
import { Icon } from "./icons";
const tabs = [
{
href: "/",
label: "首页",
icon: "home"
},
{
href: "/stats",
label: "统计",
icon: "chart"
},
{
href: "/recurring",
label: "周期",
icon: "repeat"
},
{
href: "/categories",
label: "分类",
icon: "tags"
}
];
export default function AppShell(param) {
let { title, subtitle, actions, headerContent, children, contentClassName = "", hideNav = false, compactHeader = false } = param;
const router = useRouter();
const activeTab = useMemo(()=>{
const matched = tabs.find((tab)=>tab.href === router.pathname);
return (matched === null || matched === void 0 ? void 0 : matched.href) || null;
}, [
router.pathname
]);
const headerNode = headerContent || (title ? /*#__PURE__*/ _jsxs("div", {
className: "app-header__text",
children: [
/*#__PURE__*/ _jsx("h1", {
children: title
}),
subtitle ? /*#__PURE__*/ _jsx("p", {
children: subtitle
}) : null
]
}) : null);
const headerClassName = [
"app-header",
compactHeader ? "app-header--compact" : "",
headerNode ? "app-header--with-content" : "app-header--actions-only",
actions ? "app-header--with-actions" : ""
].filter(Boolean).join(" ");
return /*#__PURE__*/ _jsxs("div", {
className: "app-shell".concat(hideNav ? " app-shell--standalone" : ""),
children: [
/*#__PURE__*/ _jsx("header", {
className: headerClassName,
children: /*#__PURE__*/ _jsxs("div", {
className: "app-shell__container app-header__inner",
children: [
headerNode ? /*#__PURE__*/ _jsx("div", {
className: "app-header__main",
children: headerNode
}) : /*#__PURE__*/ _jsx("div", {
className: "app-header__spacer",
"aria-hidden": "true"
}),
actions ? /*#__PURE__*/ _jsx("div", {
className: "app-header__actions",
children: actions
}) : null
]
})
}),
/*#__PURE__*/ _jsx("main", {
className: "app-content ".concat(contentClassName).trim(),
children: /*#__PURE__*/ _jsx("div", {
className: "app-shell__container app-content__inner",
children: children
})
}),
!hideNav ? /*#__PURE__*/ _jsx("nav", {
className: "bottom-nav",
"aria-label": "主导航",
children: /*#__PURE__*/ _jsx("div", {
className: "app-shell__container bottom-nav__inner",
children: tabs.map((tab)=>{
const isActive = activeTab === tab.href;
return /*#__PURE__*/ _jsxs("button", {
type: "button",
className: "bottom-nav__item".concat(isActive ? " is-active" : ""),
onClick: ()=>router.push(tab.href),
"aria-current": isActive ? "page" : undefined,
children: [
/*#__PURE__*/ _jsx(Icon, {
name: tab.icon,
size: 20
}),
/*#__PURE__*/ _jsx("span", {
children: tab.label
})
]
}, tab.href);
})
})
}) : null
]
});
}
e>@_a_ˆŠ¨þ ÁÉäêûÿ_bÁÄBFÏÒ48ßâM P <
?
¾
Á
þ 
}=@¶(0,next_router__WEBPACK_IMPORTED_MODULE_2__.useRouter)®(0,react__WEBPACK_IMPORTED_MODULE_1__.useMemo)·(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)¶(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)ÿþÿþÿÿÿÿÿÿÿþÿ±_icons__WEBPACK_IMPORTED_MODULE_3__/* .Icon */ .Jþ†buffer†source„size„maps„hashõ/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ Z: function() { return /* binding */ AppShell; }
/* harmony export */ });
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5893);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7294);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1163);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(next_router__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _icons__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9415);
const tabs = [
{
href: "/",
label: "首页",
icon: "home"
},
{
href: "/stats",
label: "统计",
icon: "chart"
},
{
href: "/recurring",
label: "周期",
icon: "repeat"
},
{
href: "/categories",
label: "分类",
icon: "tags"
}
];
function AppShell(param) {
let { title, subtitle, actions, headerContent, children, contentClassName = "", hideNav = false, compactHeader = false } = param;
const router = (0,next_router__WEBPACK_IMPORTED_MODULE_2__.useRouter)();
const activeTab = (0,react__WEBPACK_IMPORTED_MODULE_1__.useMemo)(()=>{
const matched = tabs.find((tab)=>tab.href === router.pathname);
return (matched === null || matched === void 0 ? void 0 : matched.href) || null;
}, [
router.pathname
]);
const headerNode = headerContent || (title ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "app-header__text",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h1", {
children: title
}),
subtitle ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
children: subtitle
}) : null
]
}) : null);
const headerClassName = [
"app-header",
compactHeader ? "app-header--compact" : "",
headerNode ? "app-header--with-content" : "app-header--actions-only",
actions ? "app-header--with-actions" : ""
].filter(Boolean).join(" ");
return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "app-shell".concat(hideNav ? " app-shell--standalone" : ""),
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("header", {
className: headerClassName,
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "app-shell__container app-header__inner",
children: [
headerNode ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "app-header__main",
children: headerNode
}) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "app-header__spacer",
"aria-hidden": "true"
}),
actions ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "app-header__actions",
children: actions
}) : null
]
})
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("main", {
className: "app-content ".concat(contentClassName).trim(),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "app-shell__container app-content__inner",
children: children
})
}),
!hideNav ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("nav", {
className: "bottom-nav",
"aria-label": "主导航",
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "app-shell__container bottom-nav__inner",
children: tabs.map((tab)=>{
const isActive = activeTab === tab.href;
return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", {
type: "button",
className: "bottom-nav__item".concat(isActive ? " is-active" : ""),
onClick: ()=>router.push(tab.href),
"aria-current": isActive ? "page" : undefined,
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_icons__WEBPACK_IMPORTED_MODULE_3__/* .Icon */ .J, {
name: tab.icon,
size: 20
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
children: tab.label
})
]
}, tab.href);
})
})
}) : null
]
});
}
”{"finalSource":true}ƒmapbufferedMap ConcatSourceRawSource´/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ Z: function() { return /* binding */ AppShell; }
/* harmony export */ });
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5893);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7294);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1163);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(next_router__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _icons__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9415);
ReplaceSourceRawSourceUimport { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useMemo } from "react";
import { useRouter } from "next/router";
import { Icon } from "./icons";
const tabs = [
{
href: "/",
label: "首页",
icon: "home"
},
{
href: "/stats",
label: "统计",
icon: "chart"
},
{
href: "/recurring",
label: "周期",
icon: "repeat"
},
{
href: "/categories",
label: "分类",
icon: "tags"
}
];
export default function AppShell(param) {
let { title, subtitle, actions, headerContent, children, contentClassName = "", hideNav = false, compactHeader = false } = param;
const router = useRouter();
const activeTab = useMemo(()=>{
const matched = tabs.find((tab)=>tab.href === router.pathname);
return (matched === null || matched === void 0 ? void 0 : matched.href) || null;
}, [
router.pathname
]);
const headerNode = headerContent || (title ? /*#__PURE__*/ _jsxs("div", {
className: "app-header__text",
children: [
/*#__PURE__*/ _jsx("h1", {
children: title
}),
subtitle ? /*#__PURE__*/ _jsx("p", {
children: subtitle
}) : null
]
}) : null);
const headerClassName = [
"app-header",
compactHeader ? "app-header--compact" : "",
headerNode ? "app-header--with-content" : "app-header--actions-only",
actions ? "app-header--with-actions" : ""
].filter(Boolean).join(" ");
return /*#__PURE__*/ _jsxs("div", {
className: "app-shell".concat(hideNav ? " app-shell--standalone" : ""),
children: [
/*#__PURE__*/ _jsx("header", {
className: headerClassName,
children: /*#__PURE__*/ _jsxs("div", {
className: "app-shell__container app-header__inner",
children: [
headerNode ? /*#__PURE__*/ _jsx("div", {
className: "app-header__main",
children: headerNode
}) : /*#__PURE__*/ _jsx("div", {
className: "app-header__spacer",
"aria-hidden": "true"
}),
actions ? /*#__PURE__*/ _jsx("div", {
className: "app-header__actions",
children: actions
}) : null
]
})
}),
/*#__PURE__*/ _jsx("main", {
className: "app-content ".concat(contentClassName).trim(),
children: /*#__PURE__*/ _jsx("div", {
className: "app-shell__container app-content__inner",
children: children
})
}),
!hideNav ? /*#__PURE__*/ _jsx("nav", {
className: "bottom-nav",
"aria-label": "主导航",
children: /*#__PURE__*/ _jsx("div", {
className: "app-shell__container bottom-nav__inner",
children: tabs.map((tab)=>{
const isActive = activeTab === tab.href;
return /*#__PURE__*/ _jsxs("button", {
type: "button",
className: "bottom-nav__item".concat(isActive ? " is-active" : ""),
onClick: ()=>router.push(tab.href),
"aria-current": isActive ? "page" : undefined,
children: [
/*#__PURE__*/ _jsx(Icon, {
name: tab.icon,
size: 20
}),
/*#__PURE__*/ _jsx("span", {
children: tab.label
})
]
}, tab.href);
})
})
}) : null
]
});
}
}062undefined6495undefined97136undefined138168undefined510524undefined705713(0,next_router__WEBPACK_IMPORTED_MODULE_2__.useRouter)undefined740746(0,react__WEBPACK_IMPORTED_MODULE_1__.useMemo)undefined10191023(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined11191122(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined12171220(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined16021606(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined17431746(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined18441848(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined20152018(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined21802183(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined23812384(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined26202623(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined27502753(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined29492952(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined30813084(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined33263330(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined37093712(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined37143717_icons__WEBPACK_IMPORTED_MODULE_3__/* .Icon */ .Jundefined39013904(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined
/***/ }) ìc/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ Z: function() { return /* binding */ AppShell; }
/* harmony export */ });
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5893);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7294);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1163);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(next_router__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _icons__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9415);
const tabs = [
{
href: "/",
label: "首页",
icon: "home"
},
{
href: "/stats",
label: "统计",
icon: "chart"
},
{
href: "/recurring",
label: "周期",
icon: "repeat"
},
{
href: "/categories",
label: "分类",
icon: "tags"
}
];
function AppShell(param) {
let { title, subtitle, actions, headerContent, children, contentClassName = "", hideNav = false, compactHeader = false } = param;
const router = (0,next_router__WEBPACK_IMPORTED_MODULE_2__.useRouter)();
const activeTab = (0,react__WEBPACK_IMPORTED_MODULE_1__.useMemo)(()=>{
const matched = tabs.find((tab)=>tab.href === router.pathname);
return (matched === null || matched === void 0 ? void 0 : matched.href) || null;
}, [
router.pathname
]);
const headerNode = headerContent || (title ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "app-header__text",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h1", {
children: title
}),
subtitle ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
children: subtitle
}) : null
]
}) : null);
const headerClassName = [
"app-header",
compactHeader ? "app-header--compact" : "",
headerNode ? "app-header--with-content" : "app-header--actions-only",
actions ? "app-header--with-actions" : ""
].filter(Boolean).join(" ");
return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "app-shell".concat(hideNav ? " app-shell--standalone" : ""),
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("header", {
className: headerClassName,
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "app-shell__container app-header__inner",
children: [
headerNode ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "app-header__main",
children: headerNode
}) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "app-header__spacer",
"aria-hidden": "true"
}),
actions ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "app-header__actions",
children: actions
}) : null
]
})
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("main", {
className: "app-content ".concat(contentClassName).trim(),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "app-shell__container app-content__inner",
children: children
})
}),
!hideNav ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("nav", {
className: "bottom-nav",
"aria-label": "主导航",
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "app-shell__container bottom-nav__inner",
children: tabs.map((tab)=>{
const isActive = activeTab === tab.href;
return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", {
type: "button",
className: "bottom-nav__item".concat(isActive ? " is-active" : ""),
onClick: ()=>router.push(tab.href),
"aria-current": isActive ? "page" : undefined,
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_icons__WEBPACK_IMPORTED_MODULE_3__/* .Icon */ .J, {
name: tab.icon,
size: 20
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
children: tab.label
})
]
}, tab.href);
})
})
}) : null
]
});
}
/***/ }) íð  ñd/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
"use strict";
ð´/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ Z: function() { return /* binding */ AppShell; }
/* harmony export */ });
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5893);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7294);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1163);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(next_router__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _icons__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9415);
ñUimport { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useMemo } from "react";
import { useRouter } from "next/router";
import { Icon } from "./icons";
const tabs = [
{
href: "/",
label: "首页",
icon: "home"
},
{
href: "/stats",
label: "统计",
icon: "chart"
},
{
href: "/recurring",
label: "周期",
icon: "repeat"
},
{
href: "/categories",
label: "分类",
icon: "tags"
}
];
export default function AppShell(param) {
let { title, subtitle, actions, headerContent, children, contentClassName = "", hideNav = false, compactHeader = false } = param;
const router = useRouter();
const activeTab = useMemo(()=>{
const matched = tabs.find((tab)=>tab.href === router.pathname);
return (matched === null || matched === void 0 ? void 0 : matched.href) || null;
}, [
router.pathname
]);
const headerNode = headerContent || (title ? /*#__PURE__*/ _jsxs("div", {
className: "app-header__text",
children: [
/*#__PURE__*/ _jsx("h1", {
children: title
}),
subtitle ? /*#__PURE__*/ _jsx("p", {
children: subtitle
}) : null
]
}) : null);
const headerClassName = [
"app-header",
compactHeader ? "app-header--compact" : "",
headerNode ? "app-header--with-content" : "app-header--actions-only",
actions ? "app-header--with-actions" : ""
].filter(Boolean).join(" ");
return /*#__PURE__*/ _jsxs("div", {
className: "app-shell".concat(hideNav ? " app-shell--standalone" : ""),
children: [
/*#__PURE__*/ _jsx("header", {
className: headerClassName,
children: /*#__PURE__*/ _jsxs("div", {
className: "app-shell__container app-header__inner",
children: [
headerNode ? /*#__PURE__*/ _jsx("div", {
className: "app-header__main",
children: headerNode
}) : /*#__PURE__*/ _jsx("div", {
className: "app-header__spacer",
"aria-hidden": "true"
}),
actions ? /*#__PURE__*/ _jsx("div", {
className: "app-header__actions",
children: actions
}) : null
]
})
}),
/*#__PURE__*/ _jsx("main", {
className: "app-content ".concat(contentClassName).trim(),
children: /*#__PURE__*/ _jsx("div", {
className: "app-shell__container app-content__inner",
children: children
})
}),
!hideNav ? /*#__PURE__*/ _jsx("nav", {
className: "bottom-nav",
"aria-label": "主导航",
children: /*#__PURE__*/ _jsx("div", {
className: "app-shell__container bottom-nav__inner",
children: tabs.map((tab)=>{
const isActive = activeTab === tab.href;
return /*#__PURE__*/ _jsxs("button", {
type: "button",
className: "bottom-nav__item".concat(isActive ? " is-active" : ""),
onClick: ()=>router.push(tab.href),
"aria-current": isActive ? "page" : undefined,
children: [
/*#__PURE__*/ _jsx(Icon, {
name: tab.icon,
size: 20
}),
/*#__PURE__*/ _jsx("span", {
children: tab.label
})
]
}, tab.href);
})
})
}) : null
]
});
}
}062undefined6495undefined97136undefined138168undefined510524undefined705713(0,next_router__WEBPACK_IMPORTED_MODULE_2__.useRouter)undefined740746(0,react__WEBPACK_IMPORTED_MODULE_1__.useMemo)undefined10191023(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined11191122(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined12171220(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined16021606(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined17431746(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined18441848(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined20152018(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined21802183(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined23812384(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined26202623(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined27502753(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined29492952(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined30813084(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined33263330(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined37093712(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined37143717_icons__WEBPACK_IMPORTED_MODULE_3__/* .Icon */ .Jundefined39013904(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefinedòó,
/***/ 610:
 O«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourced/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
"use strict";
«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 */ Ap: function() { return /* binding */ getCategoryStats; },
/* harmony export */ CP: function() { return /* binding */ getCategories; },
/* harmony export */ JS: function() { return /* binding */ deleteRecord; },
/* harmony export */ Kp: function() { return /* binding */ searchRecords; },
/* harmony export */ Q6: function() { return /* binding */ getRecords; },
/* harmony export */ TZ: function() { return /* binding */ deleteRecurringBill; },
/* harmony export */ Vn: function() { return /* binding */ getRecurringBills; },
/* harmony export */ Vs: function() { return /* binding */ updateRecord; },
/* harmony export */ Xu: function() { return /* binding */ applyRecurringBill; },
/* harmony export */ ae: function() { return /* binding */ createRecord; },
/* harmony export */ dk: function() { return /* binding */ importData; },
/* harmony export */ fy: function() { return /* binding */ getStats; },
/* harmony export */ gR: function() { return /* binding */ getTrendStats; },
/* harmony export */ jl: function() { return /* binding */ isLoggedIn; },
/* harmony export */ k4: function() { return /* binding */ createCategory; },
/* harmony export */ kS: function() { return /* binding */ logout; },
/* harmony export */ u1: function() { return /* binding */ exportData; },
/* harmony export */ uO: function() { return /* binding */ updateRecurringBill; },
/* harmony export */ uu: function() { return /* binding */ deleteCategory; },
/* harmony export */ x4: function() { return /* binding */ login; },
/* harmony export */ z0: function() { return /* binding */ createRecurringBill; },
/* harmony export */ z2: function() { return /* binding */ register; }
/* harmony export */ });
«webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource²const API_BASE = ""; // ä½¿ç”¨ç›¸å¯¹è·¯å¾„ï¼ŒåŒæºä»£ç
function getAuthHeaders() {
const token = "object" !== "undefined" ? localStorage.getItem("token") : null;
return token ? {
Authorization: "Bearer ".concat(token)
} : {};
}
async function apiCall(url) {
let options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
const res = await fetch("".concat(API_BASE).concat(url), {
...options,
headers: {
"Content-Type": "application/json",
...getAuthHeaders(),
...options.headers
}
});
const data = await res.json();
if (!res.ok) {
throw new Error(data.error || "请求失败");
}
return data;
}
// 认è¯
export async function login(username, password) {
const data = await apiCall("/api/auth/login", {
method: "POST",
body: JSON.stringify({
username,
password
})
});
if ("object" !== "undefined") {
localStorage.setItem("token", data.token);
}
return data;
}
export async function register(username, password) {
const data = await apiCall("/api/auth/register", {
method: "POST",
body: JSON.stringify({
username,
password
})
});
if ("object" !== "undefined") {
localStorage.setItem("token", data.token);
}
return data;
}
export function logout() {
if ("object" !== "undefined") {
localStorage.removeItem("token");
}
}
export function isLoggedIn() {
if ("object" === "undefined") return false;
return !!localStorage.getItem("token");
}
// 账目
export async function getRecords(month) {
let type = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "all";
let url = "/api/records?month=".concat(month);
if (type !== "all") {
url += "&type=".concat(type);
}
return apiCall(url);
}
export async function getStats(month) {
return apiCall("/api/stats?month=".concat(month));
}
export async function createRecord(data) {
return apiCall("/api/records", {
method: "POST",
body: JSON.stringify(data)
});
}
export async function updateRecord(id, data) {
return apiCall("/api/records/".concat(id), {
method: "PUT",
body: JSON.stringify(data)
});
}
export async function deleteRecord(id) {
return apiCall("/api/records/".concat(id), {
method: "DELETE"
});
}
// æœç´¢
export async function searchRecords(keyword) {
return apiCall("/api/records/search?q=".concat(encodeURIComponent(keyword)));
}
// 统计
export async function getTrendStats() {
let period = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : "month", month = arguments.length > 1 ? arguments[1] : void 0;
let url = "/api/stats/trend?period=".concat(period);
if (month) url += "&month=".concat(month);
return apiCall(url);
}
export async function getCategoryStats(month) {
let type = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "all";
let url = "/api/stats/category?type=".concat(type);
if (month) url += "&month=".concat(month);
return apiCall(url);
}
// 周期性账å
export async function getRecurringBills() {
return apiCall("/api/recurring");
}
export async function createRecurringBill(data) {
return apiCall("/api/recurring", {
method: "POST",
body: JSON.stringify(data)
});
}
export async function updateRecurringBill(id, data) {
return apiCall("/api/recurring/".concat(id), {
method: "PUT",
body: JSON.stringify(data)
});
}
export async function deleteRecurringBill(id) {
return apiCall("/api/recurring/".concat(id), {
method: "DELETE"
});
}
export async function applyRecurringBill(id) {
return apiCall("/api/recurring/".concat(id, "/apply"), {
method: "POST"
});
}
// 分类
export async function getCategories() {
return apiCall("/api/categories");
}
export async function createCategory(data) {
return apiCall("/api/categories", {
method: "POST",
body: JSON.stringify(data)
});
}
export async function deleteCategory(id) {
return apiCall("/api/categories/".concat(id), {
method: "DELETE"
});
}
// æ•°æ®å¯¼å…¥å¯¼å‡º
export async function exportData() {
return apiCall("/api/export");
}
export async function importData(data) {
return apiCall("/api/import", {
method: "POST",
body: JSON.stringify(data)
});
}
bRi_ÆÌ©ÀúbhœÓÙú V\kqÌÒag ˆ Ž W

M S _ e ³ ¹ Q
W
þ
ŠhnŽØÞ… true0„trueÿÿ…false‚{}†buffer†source„size„maps„hashÄ/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ Ap: function() { return /* binding */ getCategoryStats; },
/* harmony export */ CP: function() { return /* binding */ getCategories; },
/* harmony export */ JS: function() { return /* binding */ deleteRecord; },
/* harmony export */ Kp: function() { return /* binding */ searchRecords; },
/* harmony export */ Q6: function() { return /* binding */ getRecords; },
/* harmony export */ TZ: function() { return /* binding */ deleteRecurringBill; },
/* harmony export */ Vn: function() { return /* binding */ getRecurringBills; },
/* harmony export */ Vs: function() { return /* binding */ updateRecord; },
/* harmony export */ Xu: function() { return /* binding */ applyRecurringBill; },
/* harmony export */ ae: function() { return /* binding */ createRecord; },
/* harmony export */ dk: function() { return /* binding */ importData; },
/* harmony export */ fy: function() { return /* binding */ getStats; },
/* harmony export */ gR: function() { return /* binding */ getTrendStats; },
/* harmony export */ jl: function() { return /* binding */ isLoggedIn; },
/* harmony export */ k4: function() { return /* binding */ createCategory; },
/* harmony export */ kS: function() { return /* binding */ logout; },
/* harmony export */ u1: function() { return /* binding */ exportData; },
/* harmony export */ uO: function() { return /* binding */ updateRecurringBill; },
/* harmony export */ uu: function() { return /* binding */ deleteCategory; },
/* harmony export */ x4: function() { return /* binding */ login; },
/* harmony export */ z0: function() { return /* binding */ createRecurringBill; },
/* harmony export */ z2: function() { return /* binding */ register; }
/* harmony export */ });
const API_BASE = ""; // ä½¿ç”¨ç›¸å¯¹è·¯å¾„ï¼ŒåŒæºä»£ç
function getAuthHeaders() {
const token = true ? localStorage.getItem("token") : 0;
return token ? {
Authorization: "Bearer ".concat(token)
} : {};
}
async function apiCall(url) {
let options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
const res = await fetch("".concat(API_BASE).concat(url), {
...options,
headers: {
"Content-Type": "application/json",
...getAuthHeaders(),
...options.headers
}
});
const data = await res.json();
if (!res.ok) {
throw new Error(data.error || "请求失败");
}
return data;
}
// 认è¯
async function login(username, password) {
const data = await apiCall("/api/auth/login", {
method: "POST",
body: JSON.stringify({
username,
password
})
});
if (true) {
localStorage.setItem("token", data.token);
}
return data;
}
async function register(username, password) {
const data = await apiCall("/api/auth/register", {
method: "POST",
body: JSON.stringify({
username,
password
})
});
if (true) {
localStorage.setItem("token", data.token);
}
return data;
}
function logout() {
if (true) {
localStorage.removeItem("token");
}
}
function isLoggedIn() {
if (false) {}
return !!localStorage.getItem("token");
}
// 账目
async function getRecords(month) {
let type = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "all";
let url = "/api/records?month=".concat(month);
if (type !== "all") {
url += "&type=".concat(type);
}
return apiCall(url);
}
async function getStats(month) {
return apiCall("/api/stats?month=".concat(month));
}
async function createRecord(data) {
return apiCall("/api/records", {
method: "POST",
body: JSON.stringify(data)
});
}
async function updateRecord(id, data) {
return apiCall("/api/records/".concat(id), {
method: "PUT",
body: JSON.stringify(data)
});
}
async function deleteRecord(id) {
return apiCall("/api/records/".concat(id), {
method: "DELETE"
});
}
// æœç´¢
async function searchRecords(keyword) {
return apiCall("/api/records/search?q=".concat(encodeURIComponent(keyword)));
}
// 统计
async function getTrendStats() {
let period = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : "month", month = arguments.length > 1 ? arguments[1] : void 0;
let url = "/api/stats/trend?period=".concat(period);
if (month) url += "&month=".concat(month);
return apiCall(url);
}
async function getCategoryStats(month) {
let type = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "all";
let url = "/api/stats/category?type=".concat(type);
if (month) url += "&month=".concat(month);
return apiCall(url);
}
// 周期性账å
async function getRecurringBills() {
return apiCall("/api/recurring");
}
async function createRecurringBill(data) {
return apiCall("/api/recurring", {
method: "POST",
body: JSON.stringify(data)
});
}
async function updateRecurringBill(id, data) {
return apiCall("/api/recurring/".concat(id), {
method: "PUT",
body: JSON.stringify(data)
});
}
async function deleteRecurringBill(id) {
return apiCall("/api/recurring/".concat(id), {
method: "DELETE"
});
}
async function applyRecurringBill(id) {
return apiCall("/api/recurring/".concat(id, "/apply"), {
method: "POST"
});
}
// 分类
async function getCategories() {
return apiCall("/api/categories");
}
async function createCategory(data) {
return apiCall("/api/categories", {
method: "POST",
body: JSON.stringify(data)
});
}
async function deleteCategory(id) {
return apiCall("/api/categories/".concat(id), {
method: "DELETE"
});
}
// æ•°æ®å¯¼å…¥å¯¼å‡º
async function exportData() {
return apiCall("/api/export");
}
async function importData(data) {
return apiCall("/api/import", {
method: "POST",
body: JSON.stringify(data)
});
}
”{"finalSource":true}ƒmapbufferedMap ConcatSourceRawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ Ap: function() { return /* binding */ getCategoryStats; },
/* harmony export */ CP: function() { return /* binding */ getCategories; },
/* harmony export */ JS: function() { return /* binding */ deleteRecord; },
/* harmony export */ Kp: function() { return /* binding */ searchRecords; },
/* harmony export */ Q6: function() { return /* binding */ getRecords; },
/* harmony export */ TZ: function() { return /* binding */ deleteRecurringBill; },
/* harmony export */ Vn: function() { return /* binding */ getRecurringBills; },
/* harmony export */ Vs: function() { return /* binding */ updateRecord; },
/* harmony export */ Xu: function() { return /* binding */ applyRecurringBill; },
/* harmony export */ ae: function() { return /* binding */ createRecord; },
/* harmony export */ dk: function() { return /* binding */ importData; },
/* harmony export */ fy: function() { return /* binding */ getStats; },
/* harmony export */ gR: function() { return /* binding */ getTrendStats; },
/* harmony export */ jl: function() { return /* binding */ isLoggedIn; },
/* harmony export */ k4: function() { return /* binding */ createCategory; },
/* harmony export */ kS: function() { return /* binding */ logout; },
/* harmony export */ u1: function() { return /* binding */ exportData; },
/* harmony export */ uO: function() { return /* binding */ updateRecurringBill; },
/* harmony export */ uu: function() { return /* binding */ deleteCategory; },
/* harmony export */ x4: function() { return /* binding */ login; },
/* harmony export */ z0: function() { return /* binding */ createRecurringBill; },
/* harmony export */ z2: function() { return /* binding */ register; }
/* harmony export */ });
ReplaceSourceRawSource²const API_BASE = ""; // ä½¿ç”¨ç›¸å¯¹è·¯å¾„ï¼ŒåŒæºä»£ç
function getAuthHeaders() {
const token = "object" !== "undefined" ? localStorage.getItem("token") : null;
return token ? {
Authorization: "Bearer ".concat(token)
} : {};
}
async function apiCall(url) {
let options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
const res = await fetch("".concat(API_BASE).concat(url), {
...options,
headers: {
"Content-Type": "application/json",
...getAuthHeaders(),
...options.headers
}
});
const data = await res.json();
if (!res.ok) {
throw new Error(data.error || "请求失败");
}
return data;
}
// 认è¯
export async function login(username, password) {
const data = await apiCall("/api/auth/login", {
method: "POST",
body: JSON.stringify({
username,
password
})
});
if ("object" !== "undefined") {
localStorage.setItem("token", data.token);
}
return data;
}
export async function register(username, password) {
const data = await apiCall("/api/auth/register", {
method: "POST",
body: JSON.stringify({
username,
password
})
});
if ("object" !== "undefined") {
localStorage.setItem("token", data.token);
}
return data;
}
export function logout() {
if ("object" !== "undefined") {
localStorage.removeItem("token");
}
}
export function isLoggedIn() {
if ("object" === "undefined") return false;
return !!localStorage.getItem("token");
}
// 账目
export async function getRecords(month) {
let type = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "all";
let url = "/api/records?month=".concat(month);
if (type !== "all") {
url += "&type=".concat(type);
}
return apiCall(url);
}
export async function getStats(month) {
return apiCall("/api/stats?month=".concat(month));
}
export async function createRecord(data) {
return apiCall("/api/records", {
method: "POST",
body: JSON.stringify(data)
});
}
export async function updateRecord(id, data) {
return apiCall("/api/records/".concat(id), {
method: "PUT",
body: JSON.stringify(data)
});
}
export async function deleteRecord(id) {
return apiCall("/api/records/".concat(id), {
method: "DELETE"
});
}
// æœç´¢
export async function searchRecords(keyword) {
return apiCall("/api/records/search?q=".concat(encodeURIComponent(keyword)));
}
// 统计
export async function getTrendStats() {
let period = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : "month", month = arguments.length > 1 ? arguments[1] : void 0;
let url = "/api/stats/trend?period=".concat(period);
if (month) url += "&month=".concat(month);
return apiCall(url);
}
export async function getCategoryStats(month) {
let type = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "all";
let url = "/api/stats/category?type=".concat(type);
if (month) url += "&month=".concat(month);
return apiCall(url);
}
// 周期性账å
export async function getRecurringBills() {
return apiCall("/api/recurring");
}
export async function createRecurringBill(data) {
return apiCall("/api/recurring", {
method: "POST",
body: JSON.stringify(data)
});
}
export async function updateRecurringBill(id, data) {
return apiCall("/api/recurring/".concat(id), {
method: "PUT",
body: JSON.stringify(data)
});
}
export async function deleteRecurringBill(id) {
return apiCall("/api/recurring/".concat(id), {
method: "DELETE"
});
}
export async function applyRecurringBill(id) {
return apiCall("/api/recurring/".concat(id, "/apply"), {
method: "POST"
});
}
// 分类
export async function getCategories() {
return apiCall("/api/categories");
}
export async function createCategory(data) {
return apiCall("/api/categories", {
method: "POST",
body: JSON.stringify(data)
});
}
export async function deleteCategory(id) {
return apiCall("/api/categories/".concat(id), {
method: "DELETE"
});
}
// æ•°æ®å¯¼å…¥å¯¼å‡º
export async function exportData() {
return apiCall("/api/export");
}
export async function importData(data) {
return apiCall("/api/import", {
method: "POST",
body: JSON.stringify(data)
});
}
ý82105 trueundefined1411440undefined710716undefined937960trueundefined10411047undefined12741297trueundefined13781384undefined14131436trueundefined14911497undefined15301553falseundefined15561568{}undefined16221628undefined18991905undefined19962002undefined21452151undefined23092315undefined24402446undefined25772583undefined28932899undefined31673173undefined32513257undefined34093415undefined35823588undefined37163722undefined38633869undefined39443950undefined40984104undefined42384244undefined43124318undefined
/***/ }) à2/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ Ap: function() { return /* binding */ getCategoryStats; },
/* harmony export */ CP: function() { return /* binding */ getCategories; },
/* harmony export */ JS: function() { return /* binding */ deleteRecord; },
/* harmony export */ Kp: function() { return /* binding */ searchRecords; },
/* harmony export */ Q6: function() { return /* binding */ getRecords; },
/* harmony export */ TZ: function() { return /* binding */ deleteRecurringBill; },
/* harmony export */ Vn: function() { return /* binding */ getRecurringBills; },
/* harmony export */ Vs: function() { return /* binding */ updateRecord; },
/* harmony export */ Xu: function() { return /* binding */ applyRecurringBill; },
/* harmony export */ ae: function() { return /* binding */ createRecord; },
/* harmony export */ dk: function() { return /* binding */ importData; },
/* harmony export */ fy: function() { return /* binding */ getStats; },
/* harmony export */ gR: function() { return /* binding */ getTrendStats; },
/* harmony export */ jl: function() { return /* binding */ isLoggedIn; },
/* harmony export */ k4: function() { return /* binding */ createCategory; },
/* harmony export */ kS: function() { return /* binding */ logout; },
/* harmony export */ u1: function() { return /* binding */ exportData; },
/* harmony export */ uO: function() { return /* binding */ updateRecurringBill; },
/* harmony export */ uu: function() { return /* binding */ deleteCategory; },
/* harmony export */ x4: function() { return /* binding */ login; },
/* harmony export */ z0: function() { return /* binding */ createRecurringBill; },
/* harmony export */ z2: function() { return /* binding */ register; }
/* harmony export */ });
const API_BASE = ""; // ä½¿ç”¨ç›¸å¯¹è·¯å¾„ï¼ŒåŒæºä»£ç
function getAuthHeaders() {
const token = true ? localStorage.getItem("token") : 0;
return token ? {
Authorization: "Bearer ".concat(token)
} : {};
}
async function apiCall(url) {
let options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
const res = await fetch("".concat(API_BASE).concat(url), {
...options,
headers: {
"Content-Type": "application/json",
...getAuthHeaders(),
...options.headers
}
});
const data = await res.json();
if (!res.ok) {
throw new Error(data.error || "请求失败");
}
return data;
}
// 认è¯
async function login(username, password) {
const data = await apiCall("/api/auth/login", {
method: "POST",
body: JSON.stringify({
username,
password
})
});
if (true) {
localStorage.setItem("token", data.token);
}
return data;
}
async function register(username, password) {
const data = await apiCall("/api/auth/register", {
method: "POST",
body: JSON.stringify({
username,
password
})
});
if (true) {
localStorage.setItem("token", data.token);
}
return data;
}
function logout() {
if (true) {
localStorage.removeItem("token");
}
}
function isLoggedIn() {
if (false) {}
return !!localStorage.getItem("token");
}
// 账目
async function getRecords(month) {
let type = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "all";
let url = "/api/records?month=".concat(month);
if (type !== "all") {
url += "&type=".concat(type);
}
return apiCall(url);
}
async function getStats(month) {
return apiCall("/api/stats?month=".concat(month));
}
async function createRecord(data) {
return apiCall("/api/records", {
method: "POST",
body: JSON.stringify(data)
});
}
async function updateRecord(id, data) {
return apiCall("/api/records/".concat(id), {
method: "PUT",
body: JSON.stringify(data)
});
}
async function deleteRecord(id) {
return apiCall("/api/records/".concat(id), {
method: "DELETE"
});
}
// æœç´¢
async function searchRecords(keyword) {
return apiCall("/api/records/search?q=".concat(encodeURIComponent(keyword)));
}
// 统计
async function getTrendStats() {
let period = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : "month", month = arguments.length > 1 ? arguments[1] : void 0;
let url = "/api/stats/trend?period=".concat(period);
if (month) url += "&month=".concat(month);
return apiCall(url);
}
async function getCategoryStats(month) {
let type = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "all";
let url = "/api/stats/category?type=".concat(type);
if (month) url += "&month=".concat(month);
return apiCall(url);
}
// 周期性账å
async function getRecurringBills() {
return apiCall("/api/recurring");
}
async function createRecurringBill(data) {
return apiCall("/api/recurring", {
method: "POST",
body: JSON.stringify(data)
});
}
async function updateRecurringBill(id, data) {
return apiCall("/api/recurring/".concat(id), {
method: "PUT",
body: JSON.stringify(data)
});
}
async function deleteRecurringBill(id) {
return apiCall("/api/recurring/".concat(id), {
method: "DELETE"
});
}
async function applyRecurringBill(id) {
return apiCall("/api/recurring/".concat(id, "/apply"), {
method: "POST"
});
}
// 分类
async function getCategories() {
return apiCall("/api/categories");
}
async function createCategory(data) {
return apiCall("/api/categories", {
method: "POST",
body: JSON.stringify(data)
});
}
async function deleteCategory(id) {
return apiCall("/api/categories/".concat(id), {
method: "DELETE"
});
}
// æ•°æ®å¯¼å…¥å¯¼å‡º
async function exportData() {
return apiCall("/api/export");
}
async function importData(data) {
return apiCall("/api/import", {
method: "POST",
body: JSON.stringify(data)
});
}
/***/ }) áä  åôå/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ Ap: function() { return /* binding */ getCategoryStats; },
/* harmony export */ CP: function() { return /* binding */ getCategories; },
/* harmony export */ JS: function() { return /* binding */ deleteRecord; },
/* harmony export */ Kp: function() { return /* binding */ searchRecords; },
/* harmony export */ Q6: function() { return /* binding */ getRecords; },
/* harmony export */ TZ: function() { return /* binding */ deleteRecurringBill; },
/* harmony export */ Vn: function() { return /* binding */ getRecurringBills; },
/* harmony export */ Vs: function() { return /* binding */ updateRecord; },
/* harmony export */ Xu: function() { return /* binding */ applyRecurringBill; },
/* harmony export */ ae: function() { return /* binding */ createRecord; },
/* harmony export */ dk: function() { return /* binding */ importData; },
/* harmony export */ fy: function() { return /* binding */ getStats; },
/* harmony export */ gR: function() { return /* binding */ getTrendStats; },
/* harmony export */ jl: function() { return /* binding */ isLoggedIn; },
/* harmony export */ k4: function() { return /* binding */ createCategory; },
/* harmony export */ kS: function() { return /* binding */ logout; },
/* harmony export */ u1: function() { return /* binding */ exportData; },
/* harmony export */ uO: function() { return /* binding */ updateRecurringBill; },
/* harmony export */ uu: function() { return /* binding */ deleteCategory; },
/* harmony export */ x4: function() { return /* binding */ login; },
/* harmony export */ z0: function() { return /* binding */ createRecurringBill; },
/* harmony export */ z2: function() { return /* binding */ register; }
/* harmony export */ });
æ²const API_BASE = ""; // ä½¿ç”¨ç›¸å¯¹è·¯å¾„ï¼ŒåŒæºä»£ç
function getAuthHeaders() {
const token = "object" !== "undefined" ? localStorage.getItem("token") : null;
return token ? {
Authorization: "Bearer ".concat(token)
} : {};
}
async function apiCall(url) {
let options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
const res = await fetch("".concat(API_BASE).concat(url), {
...options,
headers: {
"Content-Type": "application/json",
...getAuthHeaders(),
...options.headers
}
});
const data = await res.json();
if (!res.ok) {
throw new Error(data.error || "请求失败");
}
return data;
}
// 认è¯
export async function login(username, password) {
const data = await apiCall("/api/auth/login", {
method: "POST",
body: JSON.stringify({
username,
password
})
});
if ("object" !== "undefined") {
localStorage.setItem("token", data.token);
}
return data;
}
export async function register(username, password) {
const data = await apiCall("/api/auth/register", {
method: "POST",
body: JSON.stringify({
username,
password
})
});
if ("object" !== "undefined") {
localStorage.setItem("token", data.token);
}
return data;
}
export function logout() {
if ("object" !== "undefined") {
localStorage.removeItem("token");
}
}
export function isLoggedIn() {
if ("object" === "undefined") return false;
return !!localStorage.getItem("token");
}
// 账目
export async function getRecords(month) {
let type = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "all";
let url = "/api/records?month=".concat(month);
if (type !== "all") {
url += "&type=".concat(type);
}
return apiCall(url);
}
export async function getStats(month) {
return apiCall("/api/stats?month=".concat(month));
}
export async function createRecord(data) {
return apiCall("/api/records", {
method: "POST",
body: JSON.stringify(data)
});
}
export async function updateRecord(id, data) {
return apiCall("/api/records/".concat(id), {
method: "PUT",
body: JSON.stringify(data)
});
}
export async function deleteRecord(id) {
return apiCall("/api/records/".concat(id), {
method: "DELETE"
});
}
// æœç´¢
export async function searchRecords(keyword) {
return apiCall("/api/records/search?q=".concat(encodeURIComponent(keyword)));
}
// 统计
export async function getTrendStats() {
let period = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : "month", month = arguments.length > 1 ? arguments[1] : void 0;
let url = "/api/stats/trend?period=".concat(period);
if (month) url += "&month=".concat(month);
return apiCall(url);
}
export async function getCategoryStats(month) {
let type = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "all";
let url = "/api/stats/category?type=".concat(type);
if (month) url += "&month=".concat(month);
return apiCall(url);
}
// 周期性账å
export async function getRecurringBills() {
return apiCall("/api/recurring");
}
export async function createRecurringBill(data) {
return apiCall("/api/recurring", {
method: "POST",
body: JSON.stringify(data)
});
}
export async function updateRecurringBill(id, data) {
return apiCall("/api/recurring/".concat(id), {
method: "PUT",
body: JSON.stringify(data)
});
}
export async function deleteRecurringBill(id) {
return apiCall("/api/recurring/".concat(id), {
method: "DELETE"
});
}
export async function applyRecurringBill(id) {
return apiCall("/api/recurring/".concat(id, "/apply"), {
method: "POST"
});
}
// 分类
export async function getCategories() {
return apiCall("/api/categories");
}
export async function createCategory(data) {
return apiCall("/api/categories", {
method: "POST",
body: JSON.stringify(data)
});
}
export async function deleteCategory(id) {
return apiCall("/api/categories/".concat(id), {
method: "DELETE"
});
}
// æ•°æ®å¯¼å…¥å¯¼å‡º
export async function exportData() {
return apiCall("/api/export");
}
export async function importData(data) {
return apiCall("/api/import", {
method: "POST",
body: JSON.stringify(data)
});
}
ý82105 trueundefined1411440undefined710716undefined937960trueundefined10411047undefined12741297trueundefined13781384undefined14131436trueundefined14911497undefined15301553falseundefined15561568{}undefined16221628undefined18991905undefined19962002undefined21452151undefined23092315undefined24402446undefined25772583undefined28932899undefined31673173undefined32513257undefined34093415undefined35823588undefined37163722undefined38633869undefined39443950undefined40984104undefined42384244undefined43124318undefinedçè,
/***/ 2874:
 §$«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourced/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
"use strict";
«webpack/lib/util/registerExternalSerializerœwebpack-sources/CachedSource ÑY«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ Categories; }
/* harmony export */ });
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5893);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7294);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1163);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(next_router__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(610);
/* harmony import */ var _components_AppShell__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6248);
/* harmony import */ var _components_icons__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9415);
/* harmony import */ var _components_ToastProvider__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(5546);
/* harmony import */ var _components_ConfirmProvider__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(8846);
«webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource4Mimport { 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, getCategories, createCategory, deleteCategory } from "../lib/api";
import AppShell from "../components/AppShell";
import { Icon } from "../components/icons";
import { useToast } from "../components/ToastProvider";
import { useConfirm } from "../components/ConfirmProvider";
const ICONS = [
"\uD83C\uDF5C",
"\uD83E\uDD58",
"\uD83E\uDD6C",
"\uD83E\uDD69",
"\uD83C\uDF54",
"\uD83C\uDF55",
"☕",
"\uD83C\uDF7A",
"\uD83E\uDDCB",
"\uD83C\uDF4E",
"\uD83C\uDF6A",
"\uD83C\uDF6B",
"\uD83D\uDE97",
"\uD83D\uDE95",
"\uD83D\uDE8C",
"\uD83D\uDE87",
"⛽",
"\uD83D\uDE99",
"\uD83D\uDEF5",
"✈ï¸",
"\uD83D\uDEA2",
"\uD83D\uDED2",
"\uD83D\uDC54",
"\uD83D\uDC55",
"\uD83D\uDC56",
"\uD83D\uDC5F",
"\uD83D\uDC53",
"\uD83E\uDDE2",
"\uD83D\uDC5C",
"\uD83C\uDF92",
"\uD83D\uDC8D",
"\uD83D\uDC84",
"\uD83C\uDFE0",
"\uD83C\uDFE2",
"\uD83C\uDFE6",
"\uD83C\uDFE5",
"\uD83C\uDFE8",
"\uD83C\uDFE9",
"\uD83D\uDD27",
"\uD83D\uDD28",
"\uD83D\uDECBï¸",
"\uD83D\uDCFA",
"\uD83D\uDCBB",
"\uD83D\uDCF1",
"\uD83D\uDCDD",
"\uD83D\uDCB0",
"\uD83C\uDF81",
"\uD83D\uDCC8",
"\uD83E\uDDE7",
"\uD83D\uDCB3",
"\uD83C\uDFAF",
"\uD83D\uDCDA",
"\uD83C\uDFB5",
"\uD83C\uDFAE",
"\uD83C\uDFC3",
"âš½",
"\uD83C\uDFCA",
"\uD83D\uDEB4",
"\uD83C\uDFAD",
"\uD83C\uDFA8",
"\uD83C\uDFAC",
"\uD83D\uDCF7",
"\uD83C\uDFA5",
"\uD83D\uDCFA",
"\uD83E\uDDF8",
"\uD83D\uDC15",
"\uD83D\uDC08",
"\uD83C\uDF38",
"\uD83C\uDF3A"
];
export default function Categories() {
const router = useRouter();
const { showToast } = useToast();
const { confirm } = useConfirm();
const [categories, setCategories] = useState({
expense: [],
income: []
});
const [modalOpen, setModalOpen] = useState(false);
const [categoryType, setCategoryType] = useState("expense");
const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false);
const [formError, setFormError] = useState("");
const [formData, setFormData] = useState({
name: "",
icon: "\uD83D\uDCDD"
});
useEffect(()=>{
if (!isLoggedIn()) {
router.push("/login");
return;
}
loadCategories();
}, [
router
]);
const loadCategories = async ()=>{
setLoading(true);
try {
const data = await getCategories();
setCategories(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const openAddModal = (type)=>{
setCategoryType(type);
setFormData({
name: "",
icon: "\uD83D\uDCDD"
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting) return;
setModalOpen(false);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.name || !formData.icon) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
await createCategory({
type: categoryType,
name: formData.name,
icon: formData.icon
});
closeModal();
showToast("分类已创建", {
tone: "success"
});
await loadCategories();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async (id)=>{
const shouldDelete = await confirm({
title: "删除此分类?",
description: "默认分类ä¸å¯åˆ é™¤ï¼Œè‡ªå®šä¹‰åˆ†ç±»åˆ é™¤åŽå°†æ— æ³•æ¢å¤ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
try {
await deleteCategory(id);
showToast("分类已删除", {
tone: "success"
});
await loadCategories();
} catch (err) {
showToast(err.message, {
tone: "error"
});
}
};
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: "加载中..."
}) : /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("section", {
className: "card category-section category-section--refresh",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "section-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: "支出分类"
}),
/*#__PURE__*/ _jsx("h2", {
children: "支出"
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: ()=>openAddModal("expense"),
children: /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "plus",
size: 16
}),
"添加"
]
})
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "category-list category-list--chips",
children: categories.expense.map((cat)=>/*#__PURE__*/ _jsxs("div", {
className: "category-tag",
children: [
/*#__PURE__*/ _jsx("span", {
className: "cat-icon",
children: cat.icon
}),
/*#__PURE__*/ _jsx("span", {
className: "cat-name",
children: cat.name
}),
!cat.is_default && /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button icon-button--ghost cat-delete",
"aria-label": "删除".concat(cat.name),
onClick: ()=>handleDelete(cat.id),
children: /*#__PURE__*/ _jsx(Icon, {
name: "close",
size: 14
})
})
]
}, cat.id || cat.name))
})
]
}),
/*#__PURE__*/ _jsxs("section", {
className: "card category-section category-section--refresh",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "section-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: "收入分类"
}),
/*#__PURE__*/ _jsx("h2", {
children: "æ”¶å…¥"
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: ()=>openAddModal("income"),
children: /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "plus",
size: 16
}),
"添加"
]
})
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "category-list category-list--chips",
children: categories.income.map((cat)=>/*#__PURE__*/ _jsxs("div", {
className: "category-tag",
children: [
/*#__PURE__*/ _jsx("span", {
className: "cat-icon",
children: cat.icon
}),
/*#__PURE__*/ _jsx("span", {
className: "cat-name",
children: cat.name
}),
!cat.is_default && /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button icon-button--ghost cat-delete",
"aria-label": "删除".concat(cat.name),
onClick: ()=>handleDelete(cat.id),
children: /*#__PURE__*/ _jsx(Icon, {
name: "close",
size: 14
})
})
]
}, cat.id || cat.name))
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "card category-tip category-tip--refresh",
children: /*#__PURE__*/ _jsx("p", {
children: "默认分类无法删除,自定义分类å¯ä»¥åˆ é™¤ã€‚"
})
})
]
}),
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: "新增分类"
}),
/*#__PURE__*/ _jsx("h2", {
children: categoryType === "expense" ? "新建支出分类" : "新建收入分类"
})
]
}),
/*#__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: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
htmlFor: "category-name",
children: "分类åç§°"
}),
/*#__PURE__*/ _jsx("input", {
id: "category-name",
type: "text",
value: formData.name,
onChange: (e)=>setFormData({
...formData,
name: e.target.value
}),
placeholder: "请输入分类åç§°",
required: true,
disabled: submitting
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
children: "选择图标"
}),
/*#__PURE__*/ _jsx("div", {
className: "icon-grid",
style: {
display: "grid",
gridTemplateColumns: "repeat(8, minmax(0, 1fr))",
gap: "8px"
},
children: ICONS.map((icon)=>/*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-btn ".concat(formData.icon === icon ? "active" : ""),
onClick: ()=>setFormData({
...formData,
icon
}),
disabled: submitting,
children: icon
}, icon))
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "modal-actions",
children: /*#__PURE__*/ _jsx("button", {
type: "submit",
className: "btn btn-primary",
disabled: submitting,
children: submitting ? /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
})
})
]
})
]
})
})
]
});
}
cYUW_«­24^`˜Ò .Zbˆ¥®Ûâ<Cy°·èï _& Q X Ÿ ´ ½ ­
¹
 :=ðóõø\`bi˜ ãçšDHÁľÁ½Àçë¹»¾šLP % ( Î!Ñ!Ó!Ö!#š#M$_Q$÷$û$t%w%q&t&p's'™((h)k)m)p)I+L+ý+,½,À,À-Ã-Ö.Ù.00„0‡0G2J2Ó2_Ö23™34!4Ñ4Õ4m5q5â5å5Ï6Ò6æ7é7+9.90939W:Z: ;;¥;©;W<Z<L=O=„@ˆ@6AN9AåAèAÏCÒCG!G¨G«GÂHÆH‘I”I–I™I¶(0,next_router__WEBPACK_IMPORTED_MODULE_2__.useRouter)Ì(0,_components_ToastProvider__WEBPACK_IMPORTED_MODULE_5__/* .useToast */ .p)Ð(0,_components_ConfirmProvider__WEBPACK_IMPORTED_MODULE_6__/* .useConfirm */ .N)¯(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)ÿÿÿÿÿÿ°(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)¾(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .isLoggedIn */ .jl)Á(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .getCategories */ .CP)Â(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .createCategory */ .k4)Â(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .deleteCategory */ .uu)¶(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)ÿ¼_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J·(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)Å_components_AppShell__WEBPACK_IMPORTED_MODULE_3__/* ["default"] */ .Züþ·react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragmentýýýûûûýûüûýûûûûüýýýûûûýûüûýûûûûüûûûýýýûûûûüûýýûûýûûûûûýûü†buffer†source„size„maps„hash___webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ Categories; }
/* harmony export */ });
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5893);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7294);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1163);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(next_router__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(610);
/* harmony import */ var _components_AppShell__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6248);
/* harmony import */ var _components_icons__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9415);
/* harmony import */ var _components_ToastProvider__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(5546);
/* harmony import */ var _components_ConfirmProvider__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(8846);
const ICONS = [
"\uD83C\uDF5C",
"\uD83E\uDD58",
"\uD83E\uDD6C",
"\uD83E\uDD69",
"\uD83C\uDF54",
"\uD83C\uDF55",
"☕",
"\uD83C\uDF7A",
"\uD83E\uDDCB",
"\uD83C\uDF4E",
"\uD83C\uDF6A",
"\uD83C\uDF6B",
"\uD83D\uDE97",
"\uD83D\uDE95",
"\uD83D\uDE8C",
"\uD83D\uDE87",
"⛽",
"\uD83D\uDE99",
"\uD83D\uDEF5",
"✈ï¸",
"\uD83D\uDEA2",
"\uD83D\uDED2",
"\uD83D\uDC54",
"\uD83D\uDC55",
"\uD83D\uDC56",
"\uD83D\uDC5F",
"\uD83D\uDC53",
"\uD83E\uDDE2",
"\uD83D\uDC5C",
"\uD83C\uDF92",
"\uD83D\uDC8D",
"\uD83D\uDC84",
"\uD83C\uDFE0",
"\uD83C\uDFE2",
"\uD83C\uDFE6",
"\uD83C\uDFE5",
"\uD83C\uDFE8",
"\uD83C\uDFE9",
"\uD83D\uDD27",
"\uD83D\uDD28",
"\uD83D\uDECBï¸",
"\uD83D\uDCFA",
"\uD83D\uDCBB",
"\uD83D\uDCF1",
"\uD83D\uDCDD",
"\uD83D\uDCB0",
"\uD83C\uDF81",
"\uD83D\uDCC8",
"\uD83E\uDDE7",
"\uD83D\uDCB3",
"\uD83C\uDFAF",
"\uD83D\uDCDA",
"\uD83C\uDFB5",
"\uD83C\uDFAE",
"\uD83C\uDFC3",
"âš½",
"\uD83C\uDFCA",
"\uD83D\uDEB4",
"\uD83C\uDFAD",
"\uD83C\uDFA8",
"\uD83C\uDFAC",
"\uD83D\uDCF7",
"\uD83C\uDFA5",
"\uD83D\uDCFA",
"\uD83E\uDDF8",
"\uD83D\uDC15",
"\uD83D\uDC08",
"\uD83C\uDF38",
"\uD83C\uDF3A"
];
function Categories() {
const router = (0,next_router__WEBPACK_IMPORTED_MODULE_2__.useRouter)();
const { showToast } = (0,_components_ToastProvider__WEBPACK_IMPORTED_MODULE_5__/* .useToast */ .p)();
const { confirm } = (0,_components_ConfirmProvider__WEBPACK_IMPORTED_MODULE_6__/* .useConfirm */ .N)();
const [categories, setCategories] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)({
expense: [],
income: []
});
const [modalOpen, setModalOpen] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false);
const [categoryType, setCategoryType] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)("expense");
const [loading, setLoading] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(true);
const [submitting, setSubmitting] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false);
const [formError, setFormError] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)("");
const [formData, setFormData] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)({
name: "",
icon: "\uD83D\uDCDD"
});
(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{
if (!(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .isLoggedIn */ .jl)()) {
router.push("/login");
return;
}
loadCategories();
}, [
router
]);
const loadCategories = async ()=>{
setLoading(true);
try {
const data = await (0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .getCategories */ .CP)();
setCategories(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const openAddModal = (type)=>{
setCategoryType(type);
setFormData({
name: "",
icon: "\uD83D\uDCDD"
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting) return;
setModalOpen(false);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.name || !formData.icon) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
await (0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .createCategory */ .k4)({
type: categoryType,
name: formData.name,
icon: formData.icon
});
closeModal();
showToast("分类已创建", {
tone: "success"
});
await loadCategories();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async (id)=>{
const shouldDelete = await confirm({
title: "删除此分类?",
description: "默认分类ä¸å¯åˆ é™¤ï¼Œè‡ªå®šä¹‰åˆ†ç±»åˆ é™¤åŽå°†æ— æ³•æ¢å¤ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
try {
await (0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .deleteCategory */ .uu)(id);
showToast("分类已删除", {
tone: "success"
});
await loadCategories();
} catch (err) {
showToast(err.message, {
tone: "error"
});
}
};
const actions = /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "icon-button",
"aria-label": "设置",
onClick: ()=>router.push("/settings"),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "settings",
size: 18
})
});
return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(_components_AppShell__WEBPACK_IMPORTED_MODULE_3__/* ["default"] */ .Z, {
title: "分类",
subtitle: "æ•´ç†å¸¸ç”¨åˆ†ç±»ä¸Žå›¾æ ‡",
actions: actions,
compactHeader: true,
children: [
loading ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "card loading-state",
children: "加载中..."
}) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, {
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("section", {
className: "card category-section category-section--refresh",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "section-header",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
className: "eyebrow",
children: "支出分类"
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", {
children: "支出"
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: ()=>openAddModal("expense"),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "plus",
size: 16
}),
"添加"
]
})
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "category-list category-list--chips",
children: categories.expense.map((cat)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "category-tag",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
className: "cat-icon",
children: cat.icon
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
className: "cat-name",
children: cat.name
}),
!cat.is_default && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "icon-button icon-button--ghost cat-delete",
"aria-label": "删除".concat(cat.name),
onClick: ()=>handleDelete(cat.id),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "close",
size: 14
})
})
]
}, cat.id || cat.name))
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("section", {
className: "card category-section category-section--refresh",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "section-header",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
className: "eyebrow",
children: "收入分类"
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", {
children: "æ”¶å…¥"
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: ()=>openAddModal("income"),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "plus",
size: 16
}),
"添加"
]
})
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "category-list category-list--chips",
children: categories.income.map((cat)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "category-tag",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
className: "cat-icon",
children: cat.icon
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
className: "cat-name",
children: cat.name
}),
!cat.is_default && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "icon-button icon-button--ghost cat-delete",
"aria-label": "删除".concat(cat.name),
onClick: ()=>handleDelete(cat.id),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "close",
size: 14
})
})
]
}, cat.id || cat.name))
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "card category-tip category-tip--refresh",
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
children: "默认分类无法删除,自定义分类å¯ä»¥åˆ é™¤ã€‚"
})
})
]
}),
modalOpen && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "modal-overlay",
onClick: closeModal,
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "modal-header",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
className: "eyebrow",
children: "新增分类"
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", {
children: categoryType === "expense" ? "新建支出分类" : "新建收入分类"
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "icon-button icon-button--ghost",
"aria-label": "关闭弹窗",
onClick: closeModal,
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "close",
size: 18
})
})
]
}),
formError && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "error-msg",
children: formError
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("form", {
onSubmit: handleSubmit,
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", {
htmlFor: "category-name",
children: "分类åç§°"
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", {
id: "category-name",
type: "text",
value: formData.name,
onChange: (e)=>setFormData({
...formData,
name: e.target.value
}),
placeholder: "请输入分类åç§°",
required: true,
disabled: submitting
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", {
children: "选择图标"
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "icon-grid",
style: {
display: "grid",
gridTemplateColumns: "repeat(8, minmax(0, 1fr))",
gap: "8px"
},
children: ICONS.map((icon)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "icon-btn ".concat(formData.icon === icon ? "active" : ""),
onClick: ()=>setFormData({
...formData,
icon
}),
disabled: submitting,
children: icon
}, icon))
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "modal-actions",
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "submit",
className: "btn btn-primary",
disabled: submitting,
children: submitting ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
})
})
]
})
]
})
})
]
});
}
”{"finalSource":true}ƒmapbufferedMap ConcatSourceRawSource__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ Categories; }
/* harmony export */ });
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5893);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7294);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1163);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(next_router__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(610);
/* harmony import */ var _components_AppShell__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6248);
/* harmony import */ var _components_icons__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9415);
/* harmony import */ var _components_ToastProvider__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(5546);
/* harmony import */ var _components_ConfirmProvider__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(8846);
ReplaceSourceRawSource4Mimport { 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, getCategories, createCategory, deleteCategory } from "../lib/api";
import AppShell from "../components/AppShell";
import { Icon } from "../components/icons";
import { useToast } from "../components/ToastProvider";
import { useConfirm } from "../components/ConfirmProvider";
const ICONS = [
"\uD83C\uDF5C",
"\uD83E\uDD58",
"\uD83E\uDD6C",
"\uD83E\uDD69",
"\uD83C\uDF54",
"\uD83C\uDF55",
"☕",
"\uD83C\uDF7A",
"\uD83E\uDDCB",
"\uD83C\uDF4E",
"\uD83C\uDF6A",
"\uD83C\uDF6B",
"\uD83D\uDE97",
"\uD83D\uDE95",
"\uD83D\uDE8C",
"\uD83D\uDE87",
"⛽",
"\uD83D\uDE99",
"\uD83D\uDEF5",
"✈ï¸",
"\uD83D\uDEA2",
"\uD83D\uDED2",
"\uD83D\uDC54",
"\uD83D\uDC55",
"\uD83D\uDC56",
"\uD83D\uDC5F",
"\uD83D\uDC53",
"\uD83E\uDDE2",
"\uD83D\uDC5C",
"\uD83C\uDF92",
"\uD83D\uDC8D",
"\uD83D\uDC84",
"\uD83C\uDFE0",
"\uD83C\uDFE2",
"\uD83C\uDFE6",
"\uD83C\uDFE5",
"\uD83C\uDFE8",
"\uD83C\uDFE9",
"\uD83D\uDD27",
"\uD83D\uDD28",
"\uD83D\uDECBï¸",
"\uD83D\uDCFA",
"\uD83D\uDCBB",
"\uD83D\uDCF1",
"\uD83D\uDCDD",
"\uD83D\uDCB0",
"\uD83C\uDF81",
"\uD83D\uDCC8",
"\uD83E\uDDE7",
"\uD83D\uDCB3",
"\uD83C\uDFAF",
"\uD83D\uDCDA",
"\uD83C\uDFB5",
"\uD83C\uDFAE",
"\uD83C\uDFC3",
"âš½",
"\uD83C\uDFCA",
"\uD83D\uDEB4",
"\uD83C\uDFAD",
"\uD83C\uDFA8",
"\uD83C\uDFAC",
"\uD83D\uDCF7",
"\uD83C\uDFA5",
"\uD83D\uDCFA",
"\uD83E\uDDF8",
"\uD83D\uDC15",
"\uD83D\uDC08",
"\uD83C\uDF38",
"\uD83C\uDF3A"
];
export default function Categories() {
const router = useRouter();
const { showToast } = useToast();
const { confirm } = useConfirm();
const [categories, setCategories] = useState({
expense: [],
income: []
});
const [modalOpen, setModalOpen] = useState(false);
const [categoryType, setCategoryType] = useState("expense");
const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false);
const [formError, setFormError] = useState("");
const [formData, setFormData] = useState({
name: "",
icon: "\uD83D\uDCDD"
});
useEffect(()=>{
if (!isLoggedIn()) {
router.push("/login");
return;
}
loadCategories();
}, [
router
]);
const loadCategories = async ()=>{
setLoading(true);
try {
const data = await getCategories();
setCategories(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const openAddModal = (type)=>{
setCategoryType(type);
setFormData({
name: "",
icon: "\uD83D\uDCDD"
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting) return;
setModalOpen(false);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.name || !formData.icon) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
await createCategory({
type: categoryType,
name: formData.name,
icon: formData.icon
});
closeModal();
showToast("分类已创建", {
tone: "success"
});
await loadCategories();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async (id)=>{
const shouldDelete = await confirm({
title: "删除此分类?",
description: "默认分类ä¸å¯åˆ é™¤ï¼Œè‡ªå®šä¹‰åˆ†ç±»åˆ é™¤åŽå°†æ— æ³•æ¢å¤ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
try {
await deleteCategory(id);
showToast("分类已删除", {
tone: "success"
});
await loadCategories();
} catch (err) {
showToast(err.message, {
tone: "error"
});
}
};
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: "加载中..."
}) : /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("section", {
className: "card category-section category-section--refresh",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "section-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: "支出分类"
}),
/*#__PURE__*/ _jsx("h2", {
children: "支出"
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: ()=>openAddModal("expense"),
children: /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "plus",
size: 16
}),
"添加"
]
})
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "category-list category-list--chips",
children: categories.expense.map((cat)=>/*#__PURE__*/ _jsxs("div", {
className: "category-tag",
children: [
/*#__PURE__*/ _jsx("span", {
className: "cat-icon",
children: cat.icon
}),
/*#__PURE__*/ _jsx("span", {
className: "cat-name",
children: cat.name
}),
!cat.is_default && /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button icon-button--ghost cat-delete",
"aria-label": "删除".concat(cat.name),
onClick: ()=>handleDelete(cat.id),
children: /*#__PURE__*/ _jsx(Icon, {
name: "close",
size: 14
})
})
]
}, cat.id || cat.name))
})
]
}),
/*#__PURE__*/ _jsxs("section", {
className: "card category-section category-section--refresh",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "section-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: "收入分类"
}),
/*#__PURE__*/ _jsx("h2", {
children: "æ”¶å…¥"
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: ()=>openAddModal("income"),
children: /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "plus",
size: 16
}),
"添加"
]
})
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "category-list category-list--chips",
children: categories.income.map((cat)=>/*#__PURE__*/ _jsxs("div", {
className: "category-tag",
children: [
/*#__PURE__*/ _jsx("span", {
className: "cat-icon",
children: cat.icon
}),
/*#__PURE__*/ _jsx("span", {
className: "cat-name",
children: cat.name
}),
!cat.is_default && /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button icon-button--ghost cat-delete",
"aria-label": "删除".concat(cat.name),
onClick: ()=>handleDelete(cat.id),
children: /*#__PURE__*/ _jsx(Icon, {
name: "close",
size: 14
})
})
]
}, cat.id || cat.name))
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "card category-tip category-tip--refresh",
children: /*#__PURE__*/ _jsx("p", {
children: "默认分类无法删除,自定义分类å¯ä»¥åˆ é™¤ã€‚"
})
})
]
}),
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: "新增分类"
}),
/*#__PURE__*/ _jsx("h2", {
children: categoryType === "expense" ? "新建支出分类" : "新建收入分类"
})
]
}),
/*#__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: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
htmlFor: "category-name",
children: "分类åç§°"
}),
/*#__PURE__*/ _jsx("input", {
id: "category-name",
type: "text",
value: formData.name,
onChange: (e)=>setFormData({
...formData,
name: e.target.value
}),
placeholder: "请输入分类åç§°",
required: true,
disabled: submitting
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
children: "选择图标"
}),
/*#__PURE__*/ _jsx("div", {
className: "icon-grid",
style: {
display: "grid",
gridTemplateColumns: "repeat(8, minmax(0, 1fr))",
gap: "8px"
},
children: ICONS.map((icon)=>/*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-btn ".concat(formData.icon === icon ? "active" : ""),
onClick: ()=>setFormData({
...formData,
icon
}),
disabled: submitting,
children: icon
}, icon))
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "modal-actions",
children: /*#__PURE__*/ _jsx("button", {
type: "submit",
className: "btn btn-primary",
disabled: submitting,
children: submitting ? /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
})
})
]
})
]
})
})
]
});
}
n085undefined87130undefined132171undefined173259undefined261306undefined308350undefined352406undefined408466undefined18241838undefined18821890(0,next_router__WEBPACK_IMPORTED_MODULE_2__.useRouter)undefined19211928(0,_components_ToastProvider__WEBPACK_IMPORTED_MODULE_5__/* .useToast */ .p)undefined19571966(0,_components_ConfirmProvider__WEBPACK_IMPORTED_MODULE_6__/* .useConfirm */ .N)undefined20112018(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined21082115(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined21692176(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined22242231(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined22802287(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined23352342(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined23852392(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined24552463(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined24842493(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .isLoggedIn */ .jl)undefined27332745(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .getCategories */ .CP)undefined35963609(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .createCategory */ .k4)undefined43714384(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .deleteCategory */ .uu)undefined46664669(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined48484851(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined48534856_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .Jundefined49564960(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined49624969_components_AppShell__WEBPACK_IMPORTED_MODULE_3__/* ["default"] */ .Zundefined51375140(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined52665270(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined52725280react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragmentundefined53475351(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined55305534(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined57005704(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined58255828(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined60786081(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined63336336(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined66316635(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined68386841(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined68436846_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .Jundefined73197322(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined75007504(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined76927695(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined79517954(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined82298232(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined86548657(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined86598662_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .Jundefined91109114(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined92939297(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined94639467(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined95889591(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined98419844(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1009610099(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1039310397(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1060010603(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1060510608_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .Jundefined1108111084(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1126111265(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1145311456(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1171211715(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1199011993(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1241512418(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1242012423_comp
/***/ }) Õý_/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ Categories; }
/* harmony export */ });
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5893);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7294);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1163);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(next_router__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(610);
/* harmony import */ var _components_AppShell__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6248);
/* harmony import */ var _components_icons__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9415);
/* harmony import */ var _components_ToastProvider__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(5546);
/* harmony import */ var _components_ConfirmProvider__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(8846);
const ICONS = [
"\uD83C\uDF5C",
"\uD83E\uDD58",
"\uD83E\uDD6C",
"\uD83E\uDD69",
"\uD83C\uDF54",
"\uD83C\uDF55",
"☕",
"\uD83C\uDF7A",
"\uD83E\uDDCB",
"\uD83C\uDF4E",
"\uD83C\uDF6A",
"\uD83C\uDF6B",
"\uD83D\uDE97",
"\uD83D\uDE95",
"\uD83D\uDE8C",
"\uD83D\uDE87",
"⛽",
"\uD83D\uDE99",
"\uD83D\uDEF5",
"✈ï¸",
"\uD83D\uDEA2",
"\uD83D\uDED2",
"\uD83D\uDC54",
"\uD83D\uDC55",
"\uD83D\uDC56",
"\uD83D\uDC5F",
"\uD83D\uDC53",
"\uD83E\uDDE2",
"\uD83D\uDC5C",
"\uD83C\uDF92",
"\uD83D\uDC8D",
"\uD83D\uDC84",
"\uD83C\uDFE0",
"\uD83C\uDFE2",
"\uD83C\uDFE6",
"\uD83C\uDFE5",
"\uD83C\uDFE8",
"\uD83C\uDFE9",
"\uD83D\uDD27",
"\uD83D\uDD28",
"\uD83D\uDECBï¸",
"\uD83D\uDCFA",
"\uD83D\uDCBB",
"\uD83D\uDCF1",
"\uD83D\uDCDD",
"\uD83D\uDCB0",
"\uD83C\uDF81",
"\uD83D\uDCC8",
"\uD83E\uDDE7",
"\uD83D\uDCB3",
"\uD83C\uDFAF",
"\uD83D\uDCDA",
"\uD83C\uDFB5",
"\uD83C\uDFAE",
"\uD83C\uDFC3",
"âš½",
"\uD83C\uDFCA",
"\uD83D\uDEB4",
"\uD83C\uDFAD",
"\uD83C\uDFA8",
"\uD83C\uDFAC",
"\uD83D\uDCF7",
"\uD83C\uDFA5",
"\uD83D\uDCFA",
"\uD83E\uDDF8",
"\uD83D\uDC15",
"\uD83D\uDC08",
"\uD83C\uDF38",
"\uD83C\uDF3A"
];
function Categories() {
const router = (0,next_router__WEBPACK_IMPORTED_MODULE_2__.useRouter)();
const { showToast } = (0,_components_ToastProvider__WEBPACK_IMPORTED_MODULE_5__/* .useToast */ .p)();
const { confirm } = (0,_components_ConfirmProvider__WEBPACK_IMPORTED_MODULE_6__/* .useConfirm */ .N)();
const [categories, setCategories] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)({
expense: [],
income: []
});
const [modalOpen, setModalOpen] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false);
const [categoryType, setCategoryType] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)("expense");
const [loading, setLoading] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(true);
const [submitting, setSubmitting] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false);
const [formError, setFormError] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)("");
const [formData, setFormData] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)({
name: "",
icon: "\uD83D\uDCDD"
});
(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{
if (!(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .isLoggedIn */ .jl)()) {
router.push("/login");
return;
}
loadCategories();
}, [
router
]);
const loadCategories = async ()=>{
setLoading(true);
try {
const data = await (0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .getCategories */ .CP)();
setCategories(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const openAddModal = (type)=>{
setCategoryType(type);
setFormData({
name: "",
icon: "\uD83D\uDCDD"
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting) return;
setModalOpen(false);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.name || !formData.icon) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
await (0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .createCategory */ .k4)({
type: categoryType,
name: formData.name,
icon: formData.icon
});
closeModal();
showToast("分类已创建", {
tone: "success"
});
await loadCategories();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async (id)=>{
const shouldDelete = await confirm({
title: "删除此分类?",
description: "默认分类ä¸å¯åˆ é™¤ï¼Œè‡ªå®šä¹‰åˆ†ç±»åˆ é™¤åŽå°†æ— æ³•æ¢å¤ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
try {
await (0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .deleteCategory */ .uu)(id);
showToast("分类已删除", {
tone: "success"
});
await loadCategories();
} catch (err) {
showToast(err.message, {
tone: "error"
});
}
};
const actions = /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "icon-button",
"aria-label": "设置",
onClick: ()=>router.push("/settings"),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "settings",
size: 18
})
});
return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(_components_AppShell__WEBPACK_IMPORTED_MODULE_3__/* ["default"] */ .Z, {
title: "分类",
subtitle: "æ•´ç†å¸¸ç”¨åˆ†ç±»ä¸Žå›¾æ ‡",
actions: actions,
compactHeader: true,
children: [
loading ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "card loading-state",
children: "加载中..."
}) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, {
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("section", {
className: "card category-section category-section--refresh",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "section-header",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
className: "eyebrow",
children: "支出分类"
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", {
children: "支出"
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: ()=>openAddModal("expense"),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "plus",
size: 16
}),
"添加"
]
})
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "category-list category-list--chips",
children: categories.expense.map((cat)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "category-tag",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
className: "cat-icon",
children: cat.icon
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
className: "cat-name",
children: cat.name
}),
!cat.is_default && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "icon-button icon-button--ghost cat-delete",
"aria-label": "删除".concat(cat.name),
onClick: ()=>handleDelete(cat.id),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "close",
size: 14
})
})
]
}, cat.id || cat.name))
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("section", {
className: "card category-section category-section--refresh",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "section-header",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
className: "eyebrow",
children: "收入分类"
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", {
children: "æ”¶å…¥"
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: ()=>openAddModal("income"),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "plus",
size: 16
}),
"添加"
]
})
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "category-list category-list--chips",
children: categories.income.map((cat)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "category-tag",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
className: "cat-icon",
children: cat.icon
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
className: "cat-name",
children: cat.name
}),
!cat.is_default && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "icon-button icon-button--ghost cat-delete",
"aria-label": "删除".concat(cat.name),
onClick: ()=>handleDelete(cat.id),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "close",
size: 14
})
})
]
}, cat.id || cat.name))
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "card category-tip category-tip--refresh",
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
children: "默认分类无法删除,自定义分类å¯ä»¥åˆ é™¤ã€‚"
})
})
]
}),
modalOpen && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "modal-overlay",
onClick: closeModal,
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "modal-header",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
className: "eyebrow",
children: "新增分类"
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", {
children: categoryType === "expense" ? "新建支出分类" : "新建收入分类"
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "icon-button icon-button--ghost",
"aria-label": "关闭弹窗",
onClick: closeModal,
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "close",
size: 18
})
})
]
}),
formError && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "error-msg",
children: formError
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("form", {
onSubmit: handleSubmit,
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", {
htmlFor: "category-name",
children: "分类åç§°"
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", {
id: "category-name",
type: "text",
value: formData.name,
onChange: (e)=>setFormData({
...formData,
name: e.target.value
}),
placeholder: "请输入分类åç§°",
required: true,
disabled: submitting
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "form-group",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", {
children: "选择图标"
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "icon-grid",
style: {
display: "grid",
gridTemplateColumns: "repeat(8, minmax(0, 1fr))",
gap: "8px"
},
children: ICONS.map((icon)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "icon-btn ".concat(formData.icon === icon ? "active" : ""),
onClick: ()=>setFormData({
...formData,
icon
}),
disabled: submitting,
children: icon
}, icon))
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "modal-actions",
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "submit",
className: "btn btn-primary",
disabled: submitting,
children: submitting ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
})
})
]
})
]
})
})
]
});
}
/***/ }) ÖÙ  ÚéÚ__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ Categories; }
/* harmony export */ });
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5893);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7294);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1163);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(next_router__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(610);
/* harmony import */ var _components_AppShell__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6248);
/* harmony import */ var _components_icons__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9415);
/* harmony import */ var _components_ToastProvider__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(5546);
/* harmony import */ var _components_ConfirmProvider__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(8846);
Û4Mimport { 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, getCategories, createCategory, deleteCategory } from "../lib/api";
import AppShell from "../components/AppShell";
import { Icon } from "../components/icons";
import { useToast } from "../components/ToastProvider";
import { useConfirm } from "../components/ConfirmProvider";
const ICONS = [
"\uD83C\uDF5C",
"\uD83E\uDD58",
"\uD83E\uDD6C",
"\uD83E\uDD69",
"\uD83C\uDF54",
"\uD83C\uDF55",
"☕",
"\uD83C\uDF7A",
"\uD83E\uDDCB",
"\uD83C\uDF4E",
"\uD83C\uDF6A",
"\uD83C\uDF6B",
"\uD83D\uDE97",
"\uD83D\uDE95",
"\uD83D\uDE8C",
"\uD83D\uDE87",
"⛽",
"\uD83D\uDE99",
"\uD83D\uDEF5",
"✈ï¸",
"\uD83D\uDEA2",
"\uD83D\uDED2",
"\uD83D\uDC54",
"\uD83D\uDC55",
"\uD83D\uDC56",
"\uD83D\uDC5F",
"\uD83D\uDC53",
"\uD83E\uDDE2",
"\uD83D\uDC5C",
"\uD83C\uDF92",
"\uD83D\uDC8D",
"\uD83D\uDC84",
"\uD83C\uDFE0",
"\uD83C\uDFE2",
"\uD83C\uDFE6",
"\uD83C\uDFE5",
"\uD83C\uDFE8",
"\uD83C\uDFE9",
"\uD83D\uDD27",
"\uD83D\uDD28",
"\uD83D\uDECBï¸",
"\uD83D\uDCFA",
"\uD83D\uDCBB",
"\uD83D\uDCF1",
"\uD83D\uDCDD",
"\uD83D\uDCB0",
"\uD83C\uDF81",
"\uD83D\uDCC8",
"\uD83E\uDDE7",
"\uD83D\uDCB3",
"\uD83C\uDFAF",
"\uD83D\uDCDA",
"\uD83C\uDFB5",
"\uD83C\uDFAE",
"\uD83C\uDFC3",
"âš½",
"\uD83C\uDFCA",
"\uD83D\uDEB4",
"\uD83C\uDFAD",
"\uD83C\uDFA8",
"\uD83C\uDFAC",
"\uD83D\uDCF7",
"\uD83C\uDFA5",
"\uD83D\uDCFA",
"\uD83E\uDDF8",
"\uD83D\uDC15",
"\uD83D\uDC08",
"\uD83C\uDF38",
"\uD83C\uDF3A"
];
export default function Categories() {
const router = useRouter();
const { showToast } = useToast();
const { confirm } = useConfirm();
const [categories, setCategories] = useState({
expense: [],
income: []
});
const [modalOpen, setModalOpen] = useState(false);
const [categoryType, setCategoryType] = useState("expense");
const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false);
const [formError, setFormError] = useState("");
const [formData, setFormData] = useState({
name: "",
icon: "\uD83D\uDCDD"
});
useEffect(()=>{
if (!isLoggedIn()) {
router.push("/login");
return;
}
loadCategories();
}, [
router
]);
const loadCategories = async ()=>{
setLoading(true);
try {
const data = await getCategories();
setCategories(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const openAddModal = (type)=>{
setCategoryType(type);
setFormData({
name: "",
icon: "\uD83D\uDCDD"
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting) return;
setModalOpen(false);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.name || !formData.icon) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
await createCategory({
type: categoryType,
name: formData.name,
icon: formData.icon
});
closeModal();
showToast("分类已创建", {
tone: "success"
});
await loadCategories();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async (id)=>{
const shouldDelete = await confirm({
title: "删除此分类?",
description: "默认分类ä¸å¯åˆ é™¤ï¼Œè‡ªå®šä¹‰åˆ†ç±»åˆ é™¤åŽå°†æ— æ³•æ¢å¤ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
try {
await deleteCategory(id);
showToast("分类已删除", {
tone: "success"
});
await loadCategories();
} catch (err) {
showToast(err.message, {
tone: "error"
});
}
};
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: "加载中..."
}) : /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("section", {
className: "card category-section category-section--refresh",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "section-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: "支出分类"
}),
/*#__PURE__*/ _jsx("h2", {
children: "支出"
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: ()=>openAddModal("expense"),
children: /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "plus",
size: 16
}),
"添加"
]
})
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "category-list category-list--chips",
children: categories.expense.map((cat)=>/*#__PURE__*/ _jsxs("div", {
className: "category-tag",
children: [
/*#__PURE__*/ _jsx("span", {
className: "cat-icon",
children: cat.icon
}),
/*#__PURE__*/ _jsx("span", {
className: "cat-name",
children: cat.name
}),
!cat.is_default && /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button icon-button--ghost cat-delete",
"aria-label": "删除".concat(cat.name),
onClick: ()=>handleDelete(cat.id),
children: /*#__PURE__*/ _jsx(Icon, {
name: "close",
size: 14
})
})
]
}, cat.id || cat.name))
})
]
}),
/*#__PURE__*/ _jsxs("section", {
className: "card category-section category-section--refresh",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "section-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "eyebrow",
children: "收入分类"
}),
/*#__PURE__*/ _jsx("h2", {
children: "æ”¶å…¥"
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: ()=>openAddModal("income"),
children: /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "plus",
size: 16
}),
"添加"
]
})
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "category-list category-list--chips",
children: categories.income.map((cat)=>/*#__PURE__*/ _jsxs("div", {
className: "category-tag",
children: [
/*#__PURE__*/ _jsx("span", {
className: "cat-icon",
children: cat.icon
}),
/*#__PURE__*/ _jsx("span", {
className: "cat-name",
children: cat.name
}),
!cat.is_default && /*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-button icon-button--ghost cat-delete",
"aria-label": "删除".concat(cat.name),
onClick: ()=>handleDelete(cat.id),
children: /*#__PURE__*/ _jsx(Icon, {
name: "close",
size: 14
})
})
]
}, cat.id || cat.name))
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "card category-tip category-tip--refresh",
children: /*#__PURE__*/ _jsx("p", {
children: "默认分类无法删除,自定义分类å¯ä»¥åˆ é™¤ã€‚"
})
})
]
}),
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: "新增分类"
}),
/*#__PURE__*/ _jsx("h2", {
children: categoryType === "expense" ? "新建支出分类" : "新建收入分类"
})
]
}),
/*#__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: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
htmlFor: "category-name",
children: "分类åç§°"
}),
/*#__PURE__*/ _jsx("input", {
id: "category-name",
type: "text",
value: formData.name,
onChange: (e)=>setFormData({
...formData,
name: e.target.value
}),
placeholder: "请输入分类åç§°",
required: true,
disabled: submitting
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "form-group",
children: [
/*#__PURE__*/ _jsx("label", {
children: "选择图标"
}),
/*#__PURE__*/ _jsx("div", {
className: "icon-grid",
style: {
display: "grid",
gridTemplateColumns: "repeat(8, minmax(0, 1fr))",
gap: "8px"
},
children: ICONS.map((icon)=>/*#__PURE__*/ _jsx("button", {
type: "button",
className: "icon-btn ".concat(formData.icon === icon ? "active" : ""),
onClick: ()=>setFormData({
...formData,
icon
}),
disabled: submitting,
children: icon
}, icon))
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "modal-actions",
children: /*#__PURE__*/ _jsx("button", {
type: "submit",
className: "btn btn-primary",
disabled: submitting,
children: submitting ? /*#__PURE__*/ _jsxs("span", {
className: "button-content",
children: [
/*#__PURE__*/ _jsx(Icon, {
name: "spinner",
size: 16,
className: "is-spinning"
}),
"ä¿å­˜ä¸­..."
]
}) : "ä¿å­˜"
})
})
]
})
]
})
})
]
});
}
n085undefined87130undefined132171undefined173259undefined261306undefined308350undefined352406undefined408466undefined18241838undefined18821890(0,next_router__WEBPACK_IMPORTED_MODULE_2__.useRouter)undefined19211928(0,_components_ToastProvider__WEBPACK_IMPORTED_MODULE_5__/* .useToast */ .p)undefined19571966(0,_components_ConfirmProvider__WEBPACK_IMPORTED_MODULE_6__/* .useConfirm */ .N)undefined20112018(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined21082115(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined21692176(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined22242231(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined22802287(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined23352342(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined23852392(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined24552463(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined24842493(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .isLoggedIn */ .jl)undefined27332745(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .getCategories */ .CP)undefined35963609(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .createCategory */ .k4)undefined43714384(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .deleteCategory */ .uu)undefined46664669(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined48484851(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined48534856_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .Jundefined49564960(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined49624969_components_AppShell__WEBPACK_IMPORTED_MODULE_3__/* ["default"] */ .Zundefined51375140(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined52665270(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined52725280react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragmentundefined53475351(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined55305534(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined57005704(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined58255828(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined60786081(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined63336336(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined66316635(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined68386841(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined68436846_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .Jundefined73197322(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined75007504(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined76927695(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined79517954(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined82298232(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined86548657(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined86598662_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .Jundefined91109114(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined92939297(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined94639467(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined95889591(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined98419844(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1009610099(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1039310397(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1060010603(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1060510608_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .Jundefined1108111084(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1126111265(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1145311456(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1171211715(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1199011993(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1241512418(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1242012423_comp
/***/ 1163:
 g«webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSourceJ/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
«webpack/lib/util/registerExternalSerializerœwebpack-sources/CachedSource ý«webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource1module.exports = require('./dist/client/router')
`/ªmodule.exports = __webpack_require__(3079)†buffer†source„size„maps„hash+module.exports = __webpack_require__(3079)
”{"finalSource":true}ƒmapbufferedMap ReplaceSourceRawSource1module.exports = require('./dist/client/router')
6047module.exports = __webpack_require__(3079)undefined
/***/ }) Ê/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
module.exports = __webpack_require__(3079)
/***/ }) ËÎ ÏJ/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
Ð1module.exports = require('./dist/client/router')
6047module.exports = __webpack_require__(3079)undefinedÑÒ
},
«webpack/lib/util/registerExternalSerializerœwebpack-sources/PrefixSource‰/******/ 9function(__webpack_require__) { // webpackRuntimeModules
÷var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId); }
__webpack_require__.O(0, [888,774,179], function() { return __webpack_exec__(5461); });
var __webpack_exports__ = __webpack_require__.O();
_N_E = __webpack_exports__;
}
]); ê@(self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([[161],{
/***/ 5461:
/***/ (function(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
(window.__NEXT_P = window.__NEXT_P || []).push([
"/categories",
function () {
return __webpack_require__(2874);
}
]);
if(false) {}
/***/ }),
/***/ 6248:
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ Z: function() { return /* binding */ AppShell; }
/* harmony export */ });
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5893);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7294);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1163);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(next_router__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _icons__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9415);
const tabs = [
{
href: "/",
label: "首页",
icon: "home"
},
{
href: "/stats",
label: "统计",
icon: "chart"
},
{
href: "/recurring",
label: "周期",
icon: "repeat"
},
{
href: "/categories",
label: "分类",
icon: "tags"
}
];
function AppShell(param) {
let { title, subtitle, actions, headerContent, children, contentClassName = "", hideNav = false, compactHeader = false } = param;
const router = (0,next_router__WEBPACK_IMPORTED_MODULE_2__.useRouter)();
const activeTab = (0,react__WEBPACK_IMPORTED_MODULE_1__.useMemo)(()=>{
const matched = tabs.find((tab)=>tab.href === router.pathname);
return (matched === null || matched === void 0 ? void 0 : matched.href) || null;
}, [
router.pathname
]);
const headerNode = headerContent || (title ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "app-header__text",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h1", {
children: title
}),
subtitle ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
children: subtitle
}) : null
]
}) : null);
const headerClassName = [
"app-header",
compactHeader ? "app-header--compact" : "",
headerNode ? "app-header--with-content" : "app-header--actions-only",
actions ? "app-header--with-actions" : ""
].filter(Boolean).join(" ");
return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "app-shell".concat(hideNav ? " app-shell--standalone" : ""),
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("header", {
className: headerClassName,
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "app-shell__container app-header__inner",
children: [
headerNode ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "app-header__main",
children: headerNode
}) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "app-header__spacer",
"aria-hidden": "true"
}),
actions ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "app-header__actions",
children: actions
}) : null
]
})
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("main", {
className: "app-content ".concat(contentClassName).trim(),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "app-shell__container app-content__inner",
children: children
})
}),
!hideNav ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("nav", {
className: "bottom-nav",
"aria-label": "主导航",
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "app-shell__container bottom-nav__inner",
children: tabs.map((tab)=>{
const isActive = activeTab === tab.href;
return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", {
type: "button",
className: "bottom-nav__item".concat(isActive ? " is-active" : ""),
onClick: ()=>router.push(tab.href),
"aria-current": isActive ? "page" : undefined,
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_icons__WEBPACK_IMPORTED_MODULE_3__/* .Icon */ .J, {
name: tab.icon,
size: 20
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
children: tab.label
})
]
}, tab.href);
})
})
}) : null
]
});
}
/***/ }),
/***/ 610:
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ Ap: function() { return /* binding */ getCategoryStats; },
/* harmony export */ CP: function() { return /* binding */ getCategories; },
/* harmony export */ JS: function() { return /* binding */ deleteRecord; },
/* harmony export */ Kp: function() { return /* binding */ searchRecords; },
/* harmony export */ Q6: function() { return /* binding */ getRecords; },
/* harmony export */ TZ: function() { return /* binding */ deleteRecurringBill; },
/* harmony export */ Vn: function() { return /* binding */ getRecurringBills; },
/* harmony export */ Vs: function() { return /* binding */ updateRecord; },
/* harmony export */ Xu: function() { return /* binding */ applyRecurringBill; },
/* harmony export */ ae: function() { return /* binding */ createRecord; },
/* harmony export */ dk: function() { return /* binding */ importData; },
/* harmony export */ fy: function() { return /* binding */ getStats; },
/* harmony export */ gR: function() { return /* binding */ getTrendStats; },
/* harmony export */ jl: function() { return /* binding */ isLoggedIn; },
/* harmony export */ k4: function() { return /* binding */ createCategory; },
/* harmony export */ kS: function() { return /* binding */ logout; },
/* harmony export */ u1: function() { return /* binding */ exportData; },
/* harmony export */ uO: function() { return /* binding */ updateRecurringBill; },
/* harmony export */ uu: function() { return /* binding */ deleteCategory; },
/* harmony export */ x4: function() { return /* binding */ login; },
/* harmony export */ z0: function() { return /* binding */ createRecurringBill; },
/* harmony export */ z2: function() { return /* binding */ register; }
/* harmony export */ });
const API_BASE = ""; // ä½¿ç”¨ç›¸å¯¹è·¯å¾„ï¼ŒåŒæºä»£ç
function getAuthHeaders() {
const token = true ? localStorage.getItem("token") : 0;
return token ? {
Authorization: "Bearer ".concat(token)
} : {};
}
async function apiCall(url) {
let options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
const res = await fetch("".concat(API_BASE).concat(url), {
...options,
headers: {
"Content-Type": "application/json",
...getAuthHeaders(),
...options.headers
}
});
const data = await res.json();
if (!res.ok) {
throw new Error(data.error || "请求失败");
}
return data;
}
// 认è¯
async function login(username, password) {
const data = await apiCall("/api/auth/login", {
method: "POST",
body: JSON.stringify({
username,
password
})
});
if (true) {
localStorage.setItem("token", data.token);
}
return data;
}
async function register(username, password) {
const data = await apiCall("/api/auth/register", {
method: "POST",
body: JSON.stringify({
username,
password
})
});
if (true) {
localStorage.setItem("token", data.token);
}
return data;
}
function logout() {
if (true) {
localStorage.removeItem("token");
}
}
function isLoggedIn() {
if (false) {}
return !!localStorage.getItem("token");
}
// 账目
async function getRecords(month) {
let type = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "all";
let url = "/api/records?month=".concat(month);
if (type !== "all") {
url += "&type=".concat(type);
}
return apiCall(url);
}
async function getStats(month) {
return apiCall("/api/stats?month=".concat(month));
}
async function createRecord(data) {
return apiCall("/api/records", {
method: "POST",
body: JSON.stringify(data)
});
}
async function updateRecord(id, data) {
return apiCall("/api/records/".concat(id), {
method: "PUT",
body: JSON.stringify(data)
});
}
async function deleteRecord(id) {
return apiCall("/api/records/".concat(id), {
method: "DELETE"
});
}
// æœç´¢
async function searchRecords(keyword) {
return apiCall("/api/records/search?q=".concat(encodeURIComponent(keyword)));
}
// 统计
async function getTrendStats() {
let period = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : "month", month = arguments.length > 1 ? arguments[1] : void 0;
let url = "/api/stats/trend?period=".concat(period);
if (month) url += "&month=".concat(month);
return apiCall(url);
}
async function getCategoryStats(month) {
let type = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "all";
let url = "/api/stats/category?type=".concat(type);
if (month) url += "&month=".concat(month);
return apiCall(url);
}
// 周期性账å
async function getRecurringBills() {
return apiCall("/api/recurring");
}
async function createRecurringBill(data) {
return apiCall("/api/recurring", {
method: "POST",
body: JSON.stringify(data)
});
}
async function updateRecurringBill(id, data) {
return apiCall("/api/recurring/".concat(id), {
method: "PUT",
body: JSON.stringify(data)
});
}
async function deleteRecurringBill(id) {
return apiCall("/api/recurring/".concat(id), {
method: "DELETE"
});
}
async function applyRecurringBill(id) {
return apiCall("/api/recurring/".concat(id, "/apply"), {
method: "POST"
});
}
// 分类
async function getCategories() {
return apiCall("/api/categories");
}
async function createCategory(data) {
return apiCall("/api/categories", {
method: "POST",
body: JSON.stringify(data)
});
}
async function deleteCategory(id) {
return apiCall("/api/categories/".concat(id), {
method: "DELETE"
});
}
// æ•°æ®å¯¼å…¥å¯¼å‡º
async function exportData() {
return apiCall("/api/export");
}
async function importData(data) {
return apiCall("/api/import", {
method: "POST",
body: JSON.stringify(data)
});
}
/***/ }),
/***/ 2874:
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ Categories; }
/* harmony export */ });
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5893);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7294);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1163);
/* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(next_router__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(610);
/* harmony import */ var _components_AppShell__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6248);
/* harmony import */ var _components_icons__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9415);
/* harmony import */ var _components_ToastProvider__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(5546);
/* harmony import */ var _components_ConfirmProvider__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(8846);
const ICONS = [
"\uD83C\uDF5C",
"\uD83E\uDD58",
"\uD83E\uDD6C",
"\uD83E\uDD69",
"\uD83C\uDF54",
"\uD83C\uDF55",
"☕",
"\uD83C\uDF7A",
"\uD83E\uDDCB",
"\uD83C\uDF4E",
"\uD83C\uDF6A",
"\uD83C\uDF6B",
"\uD83D\uDE97",
"\uD83D\uDE95",
"\uD83D\uDE8C",
"\uD83D\uDE87",
"⛽",
"\uD83D\uDE99",
"\uD83D\uDEF5",
"✈ï¸",
"\uD83D\uDEA2",
"\uD83D\uDED2",
"\uD83D\uDC54",
"\uD83D\uDC55",
"\uD83D\uDC56",
"\uD83D\uDC5F",
"\uD83D\uDC53",
"\uD83E\uDDE2",
"\uD83D\uDC5C",
"\uD83C\uDF92",
"\uD83D\uDC8D",
"\uD83D\uDC84",
"\uD83C\uDFE0",
"\uD83C\uDFE2",
"\uD83C\uDFE6",
"\uD83C\uDFE5",
"\uD83C\uDFE8",
"\uD83C\uDFE9",
"\uD83D\uDD27",
"\uD83D\uDD28",
"\uD83D\uDECBï¸",
"\uD83D\uDCFA",
"\uD83D\uDCBB",
"\uD83D\uDCF1",
"\uD83D\uDCDD",
"\uD83D\uDCB0",
"\uD83C\uDF81",
"\uD83D\uDCC8",
"\uD83E\uDDE7",
"\uD83D\uDCB3",
"\uD83C\uDFAF",
"\uD83D\uDCDA",
"\uD83C\uDFB5",
"\uD83C\uDFAE",
"\uD83C\uDFC3",
"âš½",
"\uD83C\uDFCA",
"\uD83D\uDEB4",
"\uD83C\uDFAD",
"\uD83C\uDFA8",
"\uD83C\uDFAC",
"\uD83D\uDCF7",
"\uD83C\uDFA5",
"\uD83D\uDCFA",
"\uD83E\uDDF8",
"\uD83D\uDC15",
"\uD83D\uDC08",
"\uD83C\uDF38",
"\uD83C\uDF3A"
];
function Categories() {
const router = (0,next_router__WEBPACK_IMPORTED_MODULE_2__.useRouter)();
const { showToast } = (0,_components_ToastProvider__WEBPACK_IMPORTED_MODULE_5__/* .useToast */ .p)();
const { confirm } = (0,_components_ConfirmProvider__WEBPACK_IMPORTED_MODULE_6__/* .useConfirm */ .N)();
const [categories, setCategories] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)({
expense: [],
income: []
});
const [modalOpen, setModalOpen] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false);
const [categoryType, setCategoryType] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)("expense");
const [loading, setLoading] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(true);
const [submitting, setSubmitting] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false);
const [formError, setFormError] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)("");
const [formData, setFormData] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)({
name: "",
icon: "\uD83D\uDCDD"
});
(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{
if (!(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .isLoggedIn */ .jl)()) {
router.push("/login");
return;
}
loadCategories();
}, [
router
]);
const loadCategories = async ()=>{
setLoading(true);
try {
const data = await (0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .getCategories */ .CP)();
setCategories(data);
} catch (err) {
console.error(err);
showToast(err.message, {
tone: "error"
});
} finally{
setLoading(false);
}
};
const openAddModal = (type)=>{
setCategoryType(type);
setFormData({
name: "",
icon: "\uD83D\uDCDD"
});
setFormError("");
setModalOpen(true);
};
const closeModal = ()=>{
if (submitting) return;
setModalOpen(false);
setFormError("");
};
const handleSubmit = async (e)=>{
e.preventDefault();
if (!formData.name || !formData.icon) {
setFormError("请填写完整信æ¯");
return;
}
setSubmitting(true);
setFormError("");
try {
await (0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .createCategory */ .k4)({
type: categoryType,
name: formData.name,
icon: formData.icon
});
closeModal();
showToast("分类已创建", {
tone: "success"
});
await loadCategories();
} catch (err) {
setFormError(err.message);
showToast(err.message, {
tone: "error"
});
} finally{
setSubmitting(false);
}
};
const handleDelete = async (id)=>{
const shouldDelete = await confirm({
title: "删除此分类?",
description: "默认分类ä¸å¯åˆ é™¤ï¼Œè‡ªå®šä¹‰åˆ†ç±»åˆ é™¤åŽå°†æ— æ³•æ¢å¤ã€‚",
confirmText: "删除"
});
if (!shouldDelete) return;
try {
await (0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .deleteCategory */ .uu)(id);
showToast("分类已删除", {
tone: "success"
});
await loadCategories();
} catch (err) {
showToast(err.message, {
tone: "error"
});
}
};
const actions = /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "icon-button",
"aria-label": "设置",
onClick: ()=>router.push("/settings"),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "settings",
size: 18
})
});
return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(_components_AppShell__WEBPACK_IMPORTED_MODULE_3__/* ["default"] */ .Z, {
title: "分类",
subtitle: "æ•´ç†å¸¸ç”¨åˆ†ç±»ä¸Žå›¾æ ‡",
actions: actions,
compactHeader: true,
children: [
loading ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "card loading-state",
children: "加载中..."
}) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, {
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("section", {
className: "card category-section category-section--refresh",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "section-header",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
className: "eyebrow",
children: "支出分类"
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", {
children: "支出"
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: ()=>openAddModal("expense"),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "plus",
size: 16
}),
"添加"
]
})
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "category-list category-list--chips",
children: categories.expense.map((cat)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "category-tag",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
className: "cat-icon",
children: cat.icon
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
className: "cat-name",
children: cat.name
}),
!cat.is_default && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "icon-button icon-button--ghost cat-delete",
"aria-label": "删除".concat(cat.name),
onClick: ()=>handleDelete(cat.id),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "close",
size: 14
})
})
]
}, cat.id || cat.name))
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("section", {
className: "card category-section category-section--refresh",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "section-header",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
className: "eyebrow",
children: "收入分类"
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", {
children: "æ”¶å…¥"
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "btn btn-secondary btn-inline",
onClick: ()=>openAddModal("income"),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", {
className: "button-content",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "plus",
size: 16
}),
"添加"
]
})
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "category-list category-list--chips",
children: categories.income.map((cat)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "category-tag",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
className: "cat-icon",
children: cat.icon
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
className: "cat-name",
children: cat.name
}),
!cat.is_default && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "icon-button icon-button--ghost cat-delete",
"aria-label": "删除".concat(cat.name),
onClick: ()=>handleDelete(cat.id),
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "close",
size: 14
})
})
]
}, cat.id || cat.name))
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "card category-tip category-tip--refresh",
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
children: "默认分类无法删除,自定义分类å¯ä»¥åˆ é™¤ã€‚"
})
})
]
}),
modalOpen && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "modal-overlay",
onClick: closeModal,
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
className: "modal-header",
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
children: [
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
className: "eyebrow",
children: "新增分类"
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", {
children: categoryType === "expense" ? "新建支出分类" : "新建收入分类"
})
]
}),
/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
type: "button",
className: "icon-button icon-button--ghost",
"aria-label": "关闭弹窗",
onClick: closeModal,
children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_icons__WEBPACK_IMPORTED_MODULE_4__/* .Icon */ .J, {
name: "close",
size: 18
})
})
]
}),
formError && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
className: "error-msg",
children: formError
}),