From 82c86fc6a0985f4a98c5a9746f5b6fbeaf13602a Mon Sep 17 00:00:00 2001 From: shinya Date: Wed, 13 Aug 2025 22:07:28 +0800 Subject: [PATCH] feat: admin config subscription --- package.json | 2 + pnpm-lock.yaml | 26 +++ src/app/admin/page.tsx | 219 ++++++------------ src/app/api/admin/config_file/route.ts | 8 +- .../admin/config_subscription/fetch/route.ts | 13 +- src/app/api/config/custom_category/route.ts | 13 -- src/app/api/cron/route.ts | 59 ++++- src/app/douban/page.tsx | 8 +- src/app/layout.tsx | 20 +- src/components/MobileBottomNav.tsx | 29 ++- src/components/Sidebar.tsx | 25 +- src/components/UserMenu.tsx | 40 ++-- src/lib/config.client.ts | 17 -- src/lib/config.ts | 7 +- 14 files changed, 227 insertions(+), 259 deletions(-) delete mode 100644 src/app/api/config/custom_category/route.ts delete mode 100644 src/lib/config.client.ts diff --git a/package.json b/package.json index 874f618..aee6ba1 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@upstash/redis": "^1.25.0", "@vidstack/react": "^1.12.13", "artplayer": "^5.2.5", + "bs58": "^6.0.0", "clsx": "^2.0.0", "framer-motion": "^12.18.1", "he": "^1.2.0", @@ -54,6 +55,7 @@ "@tailwindcss/forms": "^0.5.10", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^15.0.7", + "@types/bs58": "^5.0.0", "@types/he": "^1.2.3", "@types/node": "24.0.3", "@types/react": "^18.3.18", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6a704a8..9cc67e1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,6 +35,9 @@ importers: artplayer: specifier: ^5.2.5 version: 5.2.5 + bs58: + specifier: ^6.0.0 + version: 6.0.0 clsx: specifier: ^2.0.0 version: 2.1.1 @@ -108,6 +111,9 @@ importers: '@testing-library/react': specifier: ^15.0.7 version: 15.0.7(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@types/bs58': + specifier: ^5.0.0 + version: 5.0.0 '@types/he': specifier: ^1.2.3 version: 1.2.3 @@ -1456,6 +1462,10 @@ packages: '@types/babel__traverse@7.20.7': resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==} + '@types/bs58@5.0.0': + resolution: {integrity: sha512-cAw/jKBzo98m6Xz1X5ETqymWfIMbXbu6nK15W4LQYjeHJkVqSmM5PO8Bd9KVHQJ/F4rHcSso9LcjtgCW6TGu2w==} + deprecated: This is a stub types definition. bs58 provides its own type definitions, so you do not need this installed. + '@types/eslint-scope@3.7.7': resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} @@ -2030,6 +2040,9 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + base-x@5.0.1: + resolution: {integrity: sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==} + big.js@5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} @@ -2063,6 +2076,9 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + bs58@6.0.0: + resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==} + bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} @@ -6747,6 +6763,10 @@ snapshots: dependencies: '@babel/types': 7.27.6 + '@types/bs58@5.0.0': + dependencies: + bs58: 6.0.0 + '@types/eslint-scope@3.7.7': dependencies: '@types/eslint': 9.6.1 @@ -7387,6 +7407,8 @@ snapshots: balanced-match@1.0.2: {} + base-x@5.0.1: {} + big.js@5.2.2: {} binary-extensions@2.3.0: {} @@ -7422,6 +7444,10 @@ snapshots: node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.25.2) + bs58@6.0.0: + dependencies: + base-x: 5.0.1 + bser@2.1.1: dependencies: node-int64: 0.4.0 diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 640068a..d75791c 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -149,11 +149,6 @@ const UserConfig = ({ config, role, refreshConfig }: UserConfigProps) => { // 当前登录用户名 const currentUsername = getAuthInfoFromBrowserCookie()?.username || null; - // 检测存储类型是否为 upstash - const isUpstashStorage = - typeof window !== 'undefined' && - (window as any).RUNTIME_CONFIG?.STORAGE_TYPE === 'upstash'; - useEffect(() => { if (config?.UserConfig) { setUserSettings({ @@ -314,26 +309,19 @@ const UserConfig = ({ config, role, refreshConfig }: UserConfigProps) => {
- {category.from !== 'config' && !isUpstashStorage && ( + {category.from !== 'config' && (
- {showAddForm && !isUpstashStorage && ( + {showAddForm && (
{/* 保存排序按钮 */} - {orderChanged && !isUpstashStorage && ( + {orderChanged && (
+ {/* 拉取配置按钮 */} +
+ +
+ {/* 自动更新开关 */}
@@ -1468,27 +1457,6 @@ const ConfigFileComponent = ({ config, refreshConfig }: { config: AdminConfig | />
- - {/* 拉取配置按钮 */} -
- -
@@ -1521,7 +1489,7 @@ const ConfigFileComponent = ({ config, refreshConfig }: { config: AdminConfig | : 'bg-green-600 hover:bg-green-700 text-white' }`} > - {saving ? '保存中…' : '保存配置文件'} + {saving ? '保存中…' : '保存'}
@@ -1530,7 +1498,7 @@ const ConfigFileComponent = ({ config, refreshConfig }: { config: AdminConfig | }; // 新增站点配置组件 -const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => { +const SiteConfigComponent = ({ config, refreshConfig }: { config: AdminConfig | null; refreshConfig: () => Promise }) => { const [siteSettings, setSiteSettings] = useState({ SiteName: '', Announcement: '', @@ -1595,11 +1563,6 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => { } }; - // 检测存储类型是否为 upstash - const isUpstashStorage = - typeof window !== 'undefined' && - (window as any).RUNTIME_CONFIG?.STORAGE_TYPE === 'upstash'; - useEffect(() => { if (config?.SiteConfig) { setSiteSettings({ @@ -1651,22 +1614,18 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => { // 处理豆瓣数据源变化 const handleDoubanDataSourceChange = (value: string) => { - if (!isUpstashStorage) { - setSiteSettings((prev) => ({ - ...prev, - DoubanProxyType: value, - })); - } + setSiteSettings((prev) => ({ + ...prev, + DoubanProxyType: value, + })); }; // 处理豆瓣图片代理变化 const handleDoubanImageProxyChange = (value: string) => { - if (!isUpstashStorage) { - setSiteSettings((prev) => ({ - ...prev, - DoubanImageProxyType: value, - })); - } + setSiteSettings((prev) => ({ + ...prev, + DoubanImageProxyType: value, + })); }; // 保存站点配置 @@ -1685,6 +1644,7 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => { } showSuccess('保存成功, 请刷新页面'); + await refreshConfig(); } catch (err) { showError(err instanceof Error ? err.message : '保存失败'); } finally { @@ -1705,55 +1665,37 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => { {/* 站点名称 */}
- !isUpstashStorage && setSiteSettings((prev) => ({ ...prev, SiteName: e.target.value })) } - disabled={isUpstashStorage} - className={`w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-green-500 focus:border-transparent ${isUpstashStorage ? 'opacity-50 cursor-not-allowed' : '' - }`} + className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-green-500 focus:border-transparent" />
{/* 站点公告 */}