From 3ff904d0584d7216e6d18c546551c3ba36916091 Mon Sep 17 00:00:00 2001 From: Ananovo Date: Sun, 24 May 2026 02:33:51 +0800 Subject: [PATCH 1/2] =?UTF-8?q?ui(frontend):=20=E9=80=82=E9=85=8D=E7=A7=BB?= =?UTF-8?q?=E5=8A=A8=E7=AB=AF=E5=B8=83=E5=B1=80=E4=B8=8E=E7=AC=94=E8=AE=B0?= =?UTF-8?q?=E9=A2=84=E8=A7=88=E6=8D=A2=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/Form/modelForm/Form.tsx | 89 ++-- .../Form/modelForm/ModelSelector.tsx | 2 +- .../src/components/ui/scroll-area.tsx | 2 +- BillNote_frontend/src/hooks/useMobile.ts | 23 + BillNote_frontend/src/index.css | 40 +- BillNote_frontend/src/layouts/HomeLayout.tsx | 103 +++- .../src/layouts/SettingLayout.tsx | 84 ++- .../pages/HomePage/components/ChatPanel.tsx | 48 +- .../src/pages/HomePage/components/History.tsx | 4 +- .../HomePage/components/MarkdownHeader.tsx | 84 +-- .../HomePage/components/MarkdownViewer.tsx | 138 ++--- .../pages/HomePage/components/NoteForm.tsx | 143 ++--- .../pages/HomePage/components/NoteHistory.tsx | 85 ++- .../src/pages/HomePage/components/StepBar.tsx | 56 +- .../pages/HomePage/components/VideoBanner.tsx | 33 +- .../HomePage/components/transcriptViewer.tsx | 143 +++-- .../src/pages/SettingPage/Downloader.tsx | 10 +- .../src/pages/SettingPage/Model.tsx | 10 +- .../src/pages/SettingPage/Monitor.tsx | 492 ++++++++++-------- .../src/pages/SettingPage/about.tsx | 34 +- .../src/pages/SettingPage/transcriber.tsx | 39 +- .../src/styles/markdown-responsive.css | 57 ++ 22 files changed, 1040 insertions(+), 679 deletions(-) create mode 100644 BillNote_frontend/src/hooks/useMobile.ts create mode 100644 BillNote_frontend/src/styles/markdown-responsive.css diff --git a/BillNote_frontend/src/components/Form/modelForm/Form.tsx b/BillNote_frontend/src/components/Form/modelForm/Form.tsx index 756770f1..d486e8a4 100644 --- a/BillNote_frontend/src/components/Form/modelForm/Form.tsx +++ b/BillNote_frontend/src/components/Form/modelForm/Form.tsx @@ -66,11 +66,11 @@ const ProviderForm = ({ isCreate = false }: { isCreate?: boolean }) => { const [loading, setLoading] = useState(true) const [testing, setTesting] = useState(false) const [isBuiltIn, setIsBuiltIn] = useState(false) - const loadModelsById= useModelStore(state => state.loadModelsById) + const loadModelsById = useModelStore(state => state.loadModelsById) const [modelOptions, setModelOptions] = useState([]) // ⚡新增,保存模型列表 - const [models, setModels]= useState([]) + const [models, setModels] = useState([]) const [modelLoading, setModelLoading] = useState(false) - const randomColor = ()=>{ + const randomColor = () => { return '#' + Math.floor(Math.random() * 16777215).toString(16) } @@ -98,10 +98,8 @@ const ProviderForm = ({ isCreate = false }: { isCreate?: boolean }) => { }) useEffect(() => { - const load = async () => { if (isEditMode) { - const data = await loadProviderById(id!) providerForm.reset(data) setIsBuiltIn(data.type === 'built-in') @@ -115,16 +113,15 @@ const ProviderForm = ({ isCreate = false }: { isCreate?: boolean }) => { setIsBuiltIn(false) } const models = await loadModelsById(id!) - if(models){ + if (models) { console.log('🔧 模型列表:', models) setModels(models) - } setLoading(false) } load() }, [id]) - const handelDelete=async (modelId)=>{ + const handelDelete = async modelId => { if (!window.confirm('确定要删除这个模型吗?')) return try { @@ -132,7 +129,6 @@ const ProviderForm = ({ isCreate = false }: { isCreate?: boolean }) => { console.log('🔧 删除结果:', res) toast.success('删除成功') - } catch (e) { toast.error('删除异常') } @@ -145,19 +141,17 @@ const ProviderForm = ({ isCreate = false }: { isCreate?: boolean }) => { return } try { - if (!id){ + if (!id) { toast.error('请先保存供应商信息') return } setTesting(true) - await testConnection({ - id - }) - - toast.success('测试连通性成功 🎉') + await testConnection({ + id, + }) + toast.success('测试连通性成功 🎉') } catch (error) { - toast.error(`连接失败: ${data.data.msg || '未知错误'}`) // toast.error('测试连通性异常') } finally { @@ -195,12 +189,11 @@ const ProviderForm = ({ isCreate = false }: { isCreate?: boolean }) => { await updateProvider({ ...values, id: id! }) toast.success('更新供应商成功') } else { - id = await addNewProvider({ ...values }) + id = await addNewProvider({ ...values }) toast.success('新增供应商成功') } // 刷新页面 - } // 保存Model信息 @@ -212,12 +205,12 @@ const ProviderForm = ({ isCreate = false }: { isCreate?: boolean }) => { if (loading) return
加载中...
return ( -
+
{/* Provider信息表单 */}
{isEditMode ? '编辑模型供应商' : '新增模型供应商'} @@ -231,10 +224,10 @@ const ProviderForm = ({ isCreate = false }: { isCreate?: boolean }) => { control={providerForm.control} name="name" render={({ field }) => ( - - 名称 + + 名称 - + @@ -244,10 +237,10 @@ const ProviderForm = ({ isCreate = false }: { isCreate?: boolean }) => { control={providerForm.control} name="apiKey" render={({ field }) => ( - - API Key + + API Key - + @@ -257,12 +250,18 @@ const ProviderForm = ({ isCreate = false }: { isCreate?: boolean }) => { control={providerForm.control} name="baseUrl" render={({ field }) => ( - - API地址 + + API地址 - + - @@ -273,10 +272,10 @@ const ProviderForm = ({ isCreate = false }: { isCreate?: boolean }) => { control={providerForm.control} name="type" render={({ field }) => ( - - 类型 + + 类型 - + @@ -291,7 +290,7 @@ const ProviderForm = ({ isCreate = false }: { isCreate?: boolean }) => { {/* 模型信息表单 */} -
+
模型列表
@@ -308,21 +307,25 @@ const ProviderForm = ({ isCreate = false }: { isCreate?: boolean }) => {
已启用模型 -
- { - models && models.map(model => { +
+ {models && + models.map(model => { return ( - + {model.model_name} - - ) - }) - } - + })}
{/**/} diff --git a/BillNote_frontend/src/components/Form/modelForm/ModelSelector.tsx b/BillNote_frontend/src/components/Form/modelForm/ModelSelector.tsx index cd17d119..1798972c 100644 --- a/BillNote_frontend/src/components/Form/modelForm/ModelSelector.tsx +++ b/BillNote_frontend/src/components/Form/modelForm/ModelSelector.tsx @@ -64,7 +64,7 @@ export function ModelSelector({ providerId }: ModelSelectorProps) {
- -
+ +
{(() => { - const idx = currentTask?.markdown.findIndex(v => v.ver_id === currentVerId) + const idx = versions.findIndex(v => v.ver_id === currentVerId) return idx !== -1 ? `版本(${currentVerId.slice(-6)})` : '' })()}
- {(currentTask?.markdown || []).map((v, idx) => { + {versions.map(v => { const shortId = v.ver_id.slice(-6) return ( @@ -114,44 +113,59 @@ export function MarkdownHeader({ )} - - {modelName} - - - {styleName} - + {modelName && ( + + {modelName} + + )} + {styleName && ( + + {styleName} + + )} {createAt && ( -
创建时间: {formatDate(createAt)}
+
+ 创建时间: {formatDate(createAt)} +
)}
- {/* 右侧操作按钮 */} -
+
- 思维导图 + 切换视图 复制内容 @@ -162,8 +176,8 @@ export function MarkdownHeader({ 下载为 Markdown 文件 @@ -176,12 +190,12 @@ export function MarkdownHeader({ onClick={() => { setShowTranscribe(!showTranscribe) }} - variant="ghost" + variant={showTranscribe ? 'default' : 'ghost'} size="sm" className="h-8 px-2" > - {/**/} - 原文参照 + + 原文参照 原文参照 @@ -197,8 +211,8 @@ export function MarkdownHeader({ size="sm" className="h-8 px-2" > - - AI 问答 + + AI 问答 基于笔记内容的 AI 问答 diff --git a/BillNote_frontend/src/pages/HomePage/components/MarkdownViewer.tsx b/BillNote_frontend/src/pages/HomePage/components/MarkdownViewer.tsx index ac95cd3e..b4c892cb 100644 --- a/BillNote_frontend/src/pages/HomePage/components/MarkdownViewer.tsx +++ b/BillNote_frontend/src/pages/HomePage/components/MarkdownViewer.tsx @@ -1,7 +1,7 @@ import { useState, useEffect, useRef, useMemo, memo, FC } from 'react' import ReactMarkdown from 'react-markdown' import { Button } from '@/components/ui/button.tsx' -import { Copy, Download, ArrowRight, Play, ExternalLink } from 'lucide-react' +import { Copy, Download, ArrowRight, Play, ExternalLink, X } from 'lucide-react' import { toast } from 'react-hot-toast' import Error from '@/components/Lottie/error.tsx' import Loading from '@/components/Lottie/Loading.tsx' @@ -16,6 +16,7 @@ import remarkMath from 'remark-math' import rehypeKatex from 'rehype-katex' import 'katex/dist/katex.min.css' import 'github-markdown-css/github-markdown-light.css' +import '@/styles/markdown-responsive.css' import { ScrollArea } from '@/components/ui/scroll-area.tsx' import { useTaskStore } from '@/store/taskStore' import { noteStyles } from '@/constant/note.ts' @@ -57,7 +58,7 @@ function createMarkdownComponents(baseURL: string) { return { h1: ({ children, ...props }: any) => (

{children} @@ -65,7 +66,7 @@ function createMarkdownComponents(baseURL: string) { ), h2: ({ children, ...props }: any) => (

{children} @@ -73,7 +74,7 @@ function createMarkdownComponents(baseURL: string) { ), h3: ({ children, ...props }: any) => (

{children} @@ -81,21 +82,23 @@ function createMarkdownComponents(baseURL: string) { ), h4: ({ children, ...props }: any) => (

{children}

), p: ({ children, ...props }: any) => ( -

+

{children}

), a: ({ href, children, ...props }: any) => { const isOriginLink = - typeof children[0] === 'string' && - (children[0] as string).startsWith('原片 @') + typeof children[0] === 'string' && (children[0] as string).startsWith('原片 @') if (isOriginLink) { const timeMatch = (children[0] as string).match(/原片 @ (\d{2}:\d{2})/) @@ -122,13 +125,11 @@ function createMarkdownComponents(baseURL: string) { href={href} target="_blank" rel="noopener noreferrer" - className="text-primary hover:text-primary/80 inline-flex items-center gap-0.5 font-medium underline underline-offset-4" + className="text-primary hover:text-primary/80 font-medium [overflow-wrap:anywhere] break-words underline underline-offset-4" {...props} > {children} - {href?.startsWith('http') && ( - - )} + {href?.startsWith('http') && } ) }, @@ -161,13 +162,11 @@ function createMarkdownComponents(baseURL: string) { const isFakeHeading = /^(\*\*.+\*\*)$/.test(rawText.trim()) if (isFakeHeading) { - return ( -
{children}
- ) + return
{children}
} return ( -
  • +
  • {children}
  • ) @@ -196,7 +195,7 @@ function createMarkdownComponents(baseURL: string) { if (!inline && match) { return ( -
    +
    {match[1].toUpperCase()}
    +
    +
    + +
    +
    + )} + {/* 侧边问答模式:markdown + ChatPanel 各占一半 */} + {showChat === 'half' && currentTask && ( +
    + +
    + )} + )} ) : ( diff --git a/BillNote_frontend/src/pages/HomePage/components/NoteForm.tsx b/BillNote_frontend/src/pages/HomePage/components/NoteForm.tsx index 9e9cbfa5..d5249aa2 100644 --- a/BillNote_frontend/src/pages/HomePage/components/NoteForm.tsx +++ b/BillNote_frontend/src/pages/HomePage/components/NoteForm.tsx @@ -7,7 +7,7 @@ import { FormLabel, FormMessage, } from '@/components/ui/form.tsx' -import { useEffect,useState } from 'react' +import { useEffect, useState } from 'react' import { useForm, useWatch } from 'react-hook-form' import { zodResolver } from '@hookform/resolvers/zod' import { z } from 'zod' @@ -65,18 +65,14 @@ const formSchema = z if (!video_url) { ctx.addIssue({ code: 'custom', message: '本地视频路径不能为空', path: ['video_url'] }) } - } - else { + } else { if (!video_url) { ctx.addIssue({ code: 'custom', message: '视频链接不能为空', path: ['video_url'] }) - } - else { + } else { try { const url = new URL(video_url) - if (!['http:', 'https:'].includes(url.protocol)) - throw new Error() - } - catch { + if (!['http:', 'https:'].includes(url.protocol)) throw new Error() + } catch { ctx.addIssue({ code: 'custom', message: '请输入正确的视频链接', path: ['video_url'] }) } } @@ -111,7 +107,7 @@ const CheckboxGroup = ({ onChange: (v: string[]) => void disabledMap: Record }) => ( -
    +
    {noteFormats.map(({ label, value: v }) => (