diff --git a/napcat.webui/src/components/button/save_buttons.tsx b/napcat.webui/src/components/button/save_buttons.tsx index c9c62c54..f29af52a 100644 --- a/napcat.webui/src/components/button/save_buttons.tsx +++ b/napcat.webui/src/components/button/save_buttons.tsx @@ -5,7 +5,7 @@ import { IoMdRefresh } from 'react-icons/io' export interface SaveButtonsProps { onSubmit: () => void reset: () => void - refresh: () => void + refresh?: () => void isSubmitting: boolean } @@ -27,21 +27,23 @@ const SaveButtons: React.FC = ({ 取消更改 - + {refresh && ( + + )} ) diff --git a/napcat.webui/src/controllers/webui_manager.ts b/napcat.webui/src/controllers/webui_manager.ts index 716ae33f..5a3904c3 100644 --- a/napcat.webui/src/controllers/webui_manager.ts +++ b/napcat.webui/src/controllers/webui_manager.ts @@ -24,12 +24,20 @@ export default class WebUIManager { return data.data.Credential } + public static async changePassword(oldToken: string, newToken: string) { + const { data } = await serverRequest.post>( + '/auth/update_token', + { oldToken, newToken } + ) + return data.data + } + public static async proxy(url = '') { const data = await serverRequest.get>( '/base/proxy?url=' + encodeURIComponent(url) ) data.data.data = JSON.parse(data.data.data) - return data.data as ServerResponse + return data.data as ServerResponse } public static async getPackageInfo() { diff --git a/napcat.webui/src/pages/dashboard/config/change_password.tsx b/napcat.webui/src/pages/dashboard/config/change_password.tsx new file mode 100644 index 00000000..08dc84d0 --- /dev/null +++ b/napcat.webui/src/pages/dashboard/config/change_password.tsx @@ -0,0 +1,81 @@ +import { Input } from '@heroui/input' +import { useLocalStorage } from '@uidotdev/usehooks' +import { Controller, useForm } from 'react-hook-form' +import toast from 'react-hot-toast' +import { useNavigate } from 'react-router-dom' + +import key from '@/const/key' + +import SaveButtons from '@/components/button/save_buttons' + +import WebUIManager from '@/controllers/webui_manager' + +const ChangePasswordCard = () => { + const { + control, + handleSubmit: handleWebuiSubmit, + formState: { isSubmitting }, + reset + } = useForm<{ + oldToken: string + newToken: string + }>({ + defaultValues: { + oldToken: '', + newToken: '' + } + }) + + const navigate = useNavigate() + const [_, setToken] = useLocalStorage(key.token, '') + + const onSubmit = handleWebuiSubmit(async (data) => { + try { + await WebUIManager.changePassword(data.oldToken, data.newToken) + toast.success('修改成功') + setToken('') + localStorage.removeItem(key.token) + navigate('/web_login') + } catch (error) { + const msg = (error as Error).message + toast.error(`修改失败: ${msg}`) + } + }) + + return ( + <> + 修改密码 - NapCat WebUI + ( + + )} + /> + ( + + )} + /> + + + ) +} + +export default ChangePasswordCard diff --git a/napcat.webui/src/pages/dashboard/config/index.tsx b/napcat.webui/src/pages/dashboard/config/index.tsx index d290fb12..54ef7e80 100644 --- a/napcat.webui/src/pages/dashboard/config/index.tsx +++ b/napcat.webui/src/pages/dashboard/config/index.tsx @@ -1,111 +1,27 @@ +import { Card, CardBody } from '@heroui/card' import { Tab, Tabs } from '@heroui/tabs' -import { useLocalStorage } from '@uidotdev/usehooks' -import { useEffect, useState } from 'react' -import { useForm } from 'react-hook-form' -import toast from 'react-hot-toast' import { useMediaQuery } from 'react-responsive' -import key from '@/const/key' - -import PageLoading from '@/components/page_loading' - -import useConfig from '@/hooks/use-config' -import useMusic from '@/hooks/use-music' - +import ChangePasswordCard from './change_password' import OneBotConfigCard from './onebot' import WebUIConfigCard from './webui' -export default function ConfigPage() { - const { config, saveConfigWithoutNetwork, refreshConfig } = useConfig() - const [loading, setLoading] = useState(false) - const { - control: onebotControl, - handleSubmit: handleOnebotSubmit, - formState: { isSubmitting: isOnebotSubmitting }, - setValue: setOnebotValue - } = useForm({ - defaultValues: { - musicSignUrl: '', - enableLocalFile2Url: false, - parseMultMsg: false - } - }) +export interface ConfigPageProps { + children?: React.ReactNode +} - const { - control: webuiControl, - handleSubmit: handleWebuiSubmit, - formState: { isSubmitting: isWebuiSubmitting }, - setValue: setWebuiValue - } = useForm({ - defaultValues: { - background: '', - musicListID: '', - customIcons: {} - } - }) - - const isMediumUp = useMediaQuery({ minWidth: 768 }) - const [b64img, setB64img] = useLocalStorage(key.backgroundImage, '') - const [customIcons, setCustomIcons] = useLocalStorage>( - key.customIcons, - {} +const ConfingPageItem: React.FC = ({ children }) => { + return ( + + +
{children}
+
+
) - const { setListId, listId } = useMusic() - const resetOneBot = () => { - setOnebotValue('musicSignUrl', config.musicSignUrl) - setOnebotValue('enableLocalFile2Url', config.enableLocalFile2Url) - setOnebotValue('parseMultMsg', config.parseMultMsg) - } +} - const resetWebUI = () => { - setWebuiValue('musicListID', listId) - setWebuiValue('customIcons', customIcons) - setWebuiValue('background', b64img) - } - - const onOneBotSubmit = handleOnebotSubmit((data) => { - try { - saveConfigWithoutNetwork(data) - toast.success('保存成功') - } catch (error) { - const msg = (error as Error).message - toast.error(`保存失败: ${msg}`) - } - }) - - const onWebuiSubmit = handleWebuiSubmit((data) => { - try { - setListId(data.musicListID) - setCustomIcons(data.customIcons) - setB64img(data.background) - toast.success('保存成功') - } catch (error) { - const msg = (error as Error).message - toast.error(`保存失败: ${msg}`) - } - }) - - const onRefresh = async (shotTip = true) => { - try { - setLoading(true) - await refreshConfig() - if (shotTip) toast.success('刷新成功') - } catch (error) { - const msg = (error as Error).message - toast.error(`刷新失败: ${msg}`) - } finally { - setLoading(false) - } - } - - useEffect(() => { - resetOneBot() - resetWebUI() - }, [config]) - - useEffect(() => { - onRefresh(false) - }, []) +export default function ConfigPage() { + const isMediumUp = useMediaQuery({ minWidth: 768 }) return (
@@ -122,23 +38,20 @@ export default function ConfigPage() { }} > - - + + + - + + + + + + + + +
diff --git a/napcat.webui/src/pages/dashboard/config/onebot.tsx b/napcat.webui/src/pages/dashboard/config/onebot.tsx index e39eddd1..1155db0e 100644 --- a/napcat.webui/src/pages/dashboard/config/onebot.tsx +++ b/napcat.webui/src/pages/dashboard/config/onebot.tsx @@ -1,68 +1,110 @@ -import { Card, CardBody } from '@heroui/card' import { Input } from '@heroui/input' -import { Controller } from 'react-hook-form' -import type { Control } from 'react-hook-form' +import { useEffect, useState } from 'react' +import { Controller, useForm } from 'react-hook-form' +import toast from 'react-hot-toast' import SaveButtons from '@/components/button/save_buttons' +import PageLoading from '@/components/page_loading' import SwitchCard from '@/components/switch_card' -export interface OneBotConfigCardProps { - control: Control - onSubmit: () => void - reset: () => void - isSubmitting: boolean - onRefresh: () => void -} -const OneBotConfigCard: React.FC = (props) => { - const { control, onSubmit, reset, isSubmitting, onRefresh } = props +import useConfig from '@/hooks/use-config' + +const OneBotConfigCard = () => { + const { config, saveConfigWithoutNetwork, refreshConfig } = useConfig() + const [loading, setLoading] = useState(false) + const { + control, + handleSubmit: handleOnebotSubmit, + formState: { isSubmitting }, + setValue: setOnebotValue + } = useForm({ + defaultValues: { + musicSignUrl: '', + enableLocalFile2Url: false, + parseMultMsg: false + } + }) + const reset = () => { + setOnebotValue('musicSignUrl', config.musicSignUrl) + setOnebotValue('enableLocalFile2Url', config.enableLocalFile2Url) + setOnebotValue('parseMultMsg', config.parseMultMsg) + } + + const onSubmit = handleOnebotSubmit((data) => { + try { + saveConfigWithoutNetwork(data) + toast.success('保存成功') + } catch (error) { + const msg = (error as Error).message + toast.error(`保存失败: ${msg}`) + } + }) + + const onRefresh = async (shotTip = true) => { + try { + setLoading(true) + await refreshConfig() + if (shotTip) toast.success('刷新成功') + } catch (error) { + const msg = (error as Error).message + toast.error(`刷新失败: ${msg}`) + } finally { + setLoading(false) + } + } + + useEffect(() => { + reset() + }, [config]) + + useEffect(() => { + onRefresh(false) + }, []) + + if (loading) return + return ( <> OneBot配置 - NapCat WebUI - - -
- ( - - )} - /> - ( - - )} - /> - ( - - )} - /> - -
-
-
+ ( + + )} + /> + ( + + )} + /> + ( + + )} + /> + ) } diff --git a/napcat.webui/src/pages/dashboard/config/webui.tsx b/napcat.webui/src/pages/dashboard/config/webui.tsx index 82d14760..c4459374 100644 --- a/napcat.webui/src/pages/dashboard/config/webui.tsx +++ b/napcat.webui/src/pages/dashboard/config/webui.tsx @@ -1,69 +1,99 @@ -import { Card, CardBody } from '@heroui/card' import { Input } from '@heroui/input' -import { Controller } from 'react-hook-form' -import type { Control } from 'react-hook-form' +import { useLocalStorage } from '@uidotdev/usehooks' +import { useEffect } from 'react' +import { Controller, useForm } from 'react-hook-form' +import toast from 'react-hot-toast' + +import key from '@/const/key' import SaveButtons from '@/components/button/save_buttons' import ImageInput from '@/components/input/image_input' +import useMusic from '@/hooks/use-music' + import { siteConfig } from '@/config/site' -export interface WebUIConfigCardProps { - control: Control - onSubmit: () => void - reset: () => void - isSubmitting: boolean - onRefresh: () => void -} -const WebUIConfigCard: React.FC = (props) => { - const { control, onSubmit, reset, isSubmitting, onRefresh } = props +const WebUIConfigCard = () => { + const { + control, + handleSubmit: handleWebuiSubmit, + formState: { isSubmitting }, + setValue: setWebuiValue + } = useForm({ + defaultValues: { + background: '', + musicListID: '', + customIcons: {} + } + }) + + const [b64img, setB64img] = useLocalStorage(key.backgroundImage, '') + const [customIcons, setCustomIcons] = useLocalStorage>( + key.customIcons, + {} + ) + const { setListId, listId } = useMusic() + + const reset = () => { + setWebuiValue('musicListID', listId) + setWebuiValue('customIcons', customIcons) + setWebuiValue('background', b64img) + } + + const onSubmit = handleWebuiSubmit((data) => { + try { + setListId(data.musicListID) + setCustomIcons(data.customIcons) + setB64img(data.background) + toast.success('保存成功') + } catch (error) { + const msg = (error as Error).message + toast.error(`保存失败: ${msg}`) + } + }) + + useEffect(() => { + reset() + }, [listId, customIcons, b64img]) + return ( <> WebUI配置 - NapCat WebUI - - -
- ( - - )} - /> -
-
背景图
- } - /> -
-
-
自定义图标
- {siteConfig.navItems.map((item) => ( - ( - - )} - /> - ))} -
- -
-
-
+ ( + + )} + /> +
+
背景图
+ } + /> +
+
+
自定义图标
+ {siteConfig.navItems.map((item) => ( + } + /> + ))} +
+ ) }