diff --git a/BillNote_frontend/src/pages/HomePage/components/MarkdownHeader.tsx b/BillNote_frontend/src/pages/HomePage/components/MarkdownHeader.tsx
index 65e343a..80b66e1 100644
--- a/BillNote_frontend/src/pages/HomePage/components/MarkdownHeader.tsx
+++ b/BillNote_frontend/src/pages/HomePage/components/MarkdownHeader.tsx
@@ -1,167 +1,169 @@
-"use client"
+'use client'
-import { useEffect, useState } from "react"
-import { Copy, Download } from "lucide-react"
-import { Button } from "@/components/ui/button"
-import { Select, SelectContent, SelectItem, SelectTrigger } from "@/components/ui/select"
-import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"
-import { Badge } from "@/components/ui/badge"
+import { useEffect, useState } from 'react'
+import { Copy, Download } from 'lucide-react'
+import { Button } from '@/components/ui/button'
+import { Select, SelectContent, SelectItem, SelectTrigger } from '@/components/ui/select'
+import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
+import { Badge } from '@/components/ui/badge'
interface VersionNote {
- ver_id: string
- model_name?: string
- style?: string
- created_at?: string
+ ver_id: string
+ model_name?: string
+ style?: string
+ created_at?: string
}
interface NoteHeaderProps {
- currentTask?: {
- markdown: VersionNote[] | string
- }
- isMultiVersion: boolean
- currentVerId: string
- setCurrentVerId: (id: string) => void
- modelName: string
- style: string
- noteStyles: { value: string; label: string }[]
- onCopy: () => void
- onDownload: () => void
- createAt?: string | Date
- setShowTranscribe: (show: boolean) => void
+ currentTask?: {
+ markdown: VersionNote[] | string
+ }
+ isMultiVersion: boolean
+ currentVerId: string
+ setCurrentVerId: (id: string) => void
+ modelName: string
+ style: string
+ noteStyles: { value: string; label: string }[]
+ onCopy: () => void
+ onDownload: () => void
+ createAt?: string | Date
+ setShowTranscribe: (show: boolean) => void
}
export function MarkdownHeader({
- currentTask,
- isMultiVersion,
- currentVerId,
- setCurrentVerId,
- modelName,
- style,
- noteStyles,
- onCopy,
- onDownload,
- createAt,
- showTranscribe,
- setShowTranscribe
- }: NoteHeaderProps) {
- const [copied, setCopied] = useState(false)
+ currentTask,
+ isMultiVersion,
+ currentVerId,
+ setCurrentVerId,
+ modelName,
+ style,
+ noteStyles,
+ onCopy,
+ onDownload,
+ createAt,
+ showTranscribe,
+ setShowTranscribe,
+}: NoteHeaderProps) {
+ const [copied, setCopied] = useState(false)
- useEffect(() => {
- let timer: NodeJS.Timeout
- if (copied) {
- timer = setTimeout(() => setCopied(false), 2000)
- }
- return () => clearTimeout(timer)
- }, [copied])
-
- const handleCopy = () => {
- onCopy()
- setCopied(true)
+ useEffect(() => {
+ let timer: NodeJS.Timeout
+ if (copied) {
+ timer = setTimeout(() => setCopied(false), 2000)
}
+ return () => clearTimeout(timer)
+ }, [copied])
- const styleName = noteStyles.find((v) => v.value === style)?.label || style
+ const handleCopy = () => {
+ onCopy()
+ setCopied(true)
+ }
- const reversedMarkdown: VersionNote[] =
- Array.isArray(currentTask?.markdown) ? [...currentTask!.markdown].reverse() : []
+ const styleName = noteStyles.find(v => v.value === style)?.label || style
- const formatDate = (date: string | Date | undefined) => {
- if (!date) return ""
- const d = typeof date === "string" ? new Date(date) : date
- if (isNaN(d.getTime())) return ""
- return d
- .toLocaleString("zh-CN", {
- year: "numeric",
- month: "2-digit",
- day: "2-digit",
- hour: "2-digit",
- minute: "2-digit",
- })
- .replace(/\//g, "-")
- }
+ const reversedMarkdown: VersionNote[] = Array.isArray(currentTask?.markdown)
+ ? [...currentTask!.markdown].reverse()
+ : []
- return (
-
- {/* 左侧区域:版本 + 标签 + 创建时间 */}
-
- {isMultiVersion && (
-
- )}
+ return (
+
+ {/* 左侧区域:版本 + 标签 + 创建时间 */}
+
+ {isMultiVersion && (
+
+ )}
- {createAt && (
-
- 创建时间: {formatDate(createAt)}
-
- )}
-
+
+ {modelName}
+
+
+ {styleName}
+
- {/* 右侧操作按钮 */}
-
-
-
-
-
-
- 复制内容
-
-
+ {createAt && (
+
创建时间: {formatDate(createAt)}
+ )}
+
-
-
-
-
-
- 下载为 Markdown 文件
-
-
-
-
-
-
-
- 原文参照
-
-
-
-
- )
+ {/* 右侧操作按钮 */}
+
+
+
+
+
+
+ 复制内容
+
+
+
+
+
+
+
+
+ 下载为 Markdown 文件
+
+
+
+
+
+
+
+ 原文参照
+
+
+
+
+ )
}
diff --git a/BillNote_frontend/src/pages/HomePage/components/MarkdownViewer.tsx b/BillNote_frontend/src/pages/HomePage/components/MarkdownViewer.tsx
index 91d087f..ecfc303 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 } 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 } from 'lucide-react'
import { toast } from 'react-hot-toast'
import Error from '@/components/Lottie/error.tsx'
import Loading from '@/components/Lottie/Loading.tsx'
@@ -21,7 +21,7 @@ import { ScrollArea } from '@/components/ui/scroll-area.tsx'
import { useTaskStore } from '@/store/taskStore'
import { noteStyles } from '@/constant/note.ts'
import { MarkdownHeader } from '@/pages/HomePage/components/MarkdownHeader.tsx'
-import TranscriptViewer from "@/pages/HomePage/components/transcriptViewer.tsx";
+import TranscriptViewer from '@/pages/HomePage/components/transcriptViewer.tsx'
interface VersionNote {
ver_id: string
@@ -57,10 +57,10 @@ const MarkdownViewer: FC = ({ status }) => {
const taskStatus = currentTask?.status || 'PENDING'
const retryTask = useTaskStore.getState().retryTask
const isMultiVersion = Array.isArray(currentTask?.markdown)
- const [showTranscribe, setShowTranscribe]=useState(false)
+ const [showTranscribe, setShowTranscribe] = useState(false)
// 多版本内容处理
useEffect(() => {
- if (!currentTask) return;
+ if (!currentTask) return
if (!isMultiVersion) {
setCurrentVerId('') // 清空旧版本 ID
@@ -69,12 +69,17 @@ const MarkdownViewer: FC = ({ status }) => {
setCreateTime(currentTask.createdAt)
setSelectedContent(currentTask?.markdown)
} else {
- const latestVerId = currentTask.markdown[currentTask.markdown.length - 1]?.ver_id
- setCurrentVerId(latestVerId) // 重置为最新版本
+ const latestVersion = [...currentTask.markdown].sort(
+ (a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
+ )[0]
+
+ if (latestVersion) {
+ setCurrentVerId(latestVersion.ver_id)
+ }
}
- }, [currentTask?.id,taskStatus])
+ }, [currentTask?.id, taskStatus])
useEffect(() => {
- if (!currentTask || !isMultiVersion) return;
+ if (!currentTask || !isMultiVersion) return
const currentVer = currentTask.markdown.find(v => v.ver_id === currentVerId)
if (currentVer) {
@@ -109,331 +114,324 @@ const MarkdownViewer: FC = ({ status }) => {
if (status === 'loading') {
return (
-
-
-
-
-
正在生成笔记,请稍候…
-
这可能需要几秒钟时间,取决于视频长度
-
+
+
+
+
+
正在生成笔记,请稍候…
+
这可能需要几秒钟时间,取决于视频长度
+
)
}
if (status === 'idle') {
return (
-
-
-
-
输入视频链接并点击“生成笔记”
-
支持哔哩哔哩、YouTube 、抖音等视频平台
-
+
+
+
+
输入视频链接并点击“生成笔记”
+
支持哔哩哔哩、YouTube 、抖音等视频平台
+
)
}
if (status === 'failed' && !isMultiVersion) {
return (
-
-
-
-
笔记生成失败
-
请检查后台或稍后再试
-
-
+
+
+
+
笔记生成失败
+
请检查后台或稍后再试
+
+
)
}
-
return (
-
-
+
+
- {/* 中间内容区域:滚动容器 */}
-
- {selectedContent && selectedContent !== 'loading' && selectedContent !== 'empty' ? (
- <>
-
-
+ {/* 中间内容区域:滚动容器 */}
+
+ {selectedContent && selectedContent !== 'loading' && selectedContent !== 'empty' ? (
+ <>
+
+
+
(
+
+ {children}
+
+ ),
+ h2: ({ children, ...props }) => (
+
+ {children}
+
+ ),
+ h3: ({ children, ...props }) => (
+
+ {children}
+
+ ),
+ h4: ({ children, ...props }) => (
+
+ {children}
+
+ ),
+ // Paragraphs with better line height
+ p: ({ children, ...props }) => (
+
+ {children}
+
+ ),
- (
- {
+ const isOriginLink =
+ typeof children[0] === 'string' &&
+ (children[0] as string).startsWith('原片 @')
+
+ if (isOriginLink) {
+ const timeMatch = (children[0] as string).match(/原片 @ (\d{2}:\d{2})/)
+ const timeText = timeMatch ? timeMatch[1] : '原片'
+
+ return (
+
+
+
+ 原片({timeText})
+
+
+ )
+ }
+
+ // Default link styling with external indicator
+ return (
+
+ {children}
+ {href?.startsWith('http') && (
+
+ )}
+
+ )
+ },
+
+ // Enhanced image with zoom capability
+ img: ({ node, ...props }) => (
+
+
+
+
+
+ ),
+
+ // Better strong/bold text
+ strong: ({ children, ...props }) => (
+
+ {children}
+
+ ),
+
+ // Enhanced list items with support for "fake headings"
+ li: ({ children, ...props }) => {
+ const rawText = String(children)
+ const isFakeHeading = /^(\*\*.+\*\*)$/.test(rawText.trim())
+
+ if (isFakeHeading) {
+ return
{children}
+ }
+
+ return (
+
+ {children}
+
+ )
+ },
+
+ // Enhanced unordered lists
+ ul: ({ children, ...props }) => (
+
+ ),
+
+ // Enhanced ordered lists
+ ol: ({ children, ...props }) => (
+
+ {children}
+
+ ),
+
+ // Enhanced blockquotes
+ blockquote: ({ children, ...props }) => (
+
+ {children}
+
+ ),
+
+ // Enhanced code blocks with syntax highlighting and copy button
+ code: ({ inline, className, children, ...props }) => {
+ const match = /language-(\w+)/.exec(className || '')
+ const codeContent = String(children).replace(/\n$/, '')
+
+ if (!inline && match) {
+ return (
+
+
+
{match[1].toUpperCase()}
+
+
+
+ {codeContent}
+
+
+ )
+ }
- // Paragraphs with better line height
- p: ({ children, ...props }) => (
-
- {children}
-
- ),
+ // Inline code styling
+ return (
+
+ {children}
+
+ )
+ },
- // Enhanced links with special handling for "原片" links
- a: ({ href, children, ...props }) => {
- const isOriginLink = typeof children[0] === 'string' && (children[0] as string).startsWith('原片 @')
+ // Enhanced tables
+ table: ({ children, ...props }) => (
+
+ ),
- if (isOriginLink) {
- const timeMatch = (children[0] as string).match(/原片 @ (\d{2}:\d{2})/)
- const timeText = timeMatch ? timeMatch[1] : '原片'
+ // Table headers
+ th: ({ children, ...props }) => (
+
+ {children}
+ |
+ ),
- return (
-
-
-
- 原片({timeText})
-
-
- )
- }
+ // Table cells
+ td: ({ children, ...props }) => (
+
+ {children}
+ |
+ ),
- // Default link styling with external indicator
- return (
-
- {children}
- {href?.startsWith('http') && }
-
- )
- },
-
- // Enhanced image with zoom capability
- img: ({ node, ...props }) => (
-
-
-
-
-
- ),
-
- // Better strong/bold text
- strong: ({ children, ...props }) => (
-
- {children}
-
- ),
-
- // Enhanced list items with support for "fake headings"
- li: ({ children, ...props }) => {
- const rawText = String(children)
- const isFakeHeading = /^(\*\*.+\*\*)$/.test(rawText.trim())
-
- if (isFakeHeading) {
- return (
-
- {children}
-
- )
- }
-
- return (
-
- {children}
-
- )
- },
-
- // Enhanced unordered lists
- ul: ({ children, ...props }) => (
-
- ),
-
- // Enhanced ordered lists
- ol: ({ children, ...props }) => (
-
- {children}
-
- ),
-
- // Enhanced blockquotes
- blockquote: ({ children, ...props }) => (
-
- {children}
-
- ),
-
- // Enhanced code blocks with syntax highlighting and copy button
- code: ({ inline, className, children, ...props }) => {
- const match = /language-(\w+)/.exec(className || '')
- const codeContent = String(children).replace(/\n$/, '')
-
- if (!inline && match) {
- return (
-
-
-
{match[1].toUpperCase()}
-
-
-
- {codeContent}
-
-
- )
- }
-
- // Inline code styling
- return (
-
- {children}
-
- )
- },
-
- // Enhanced tables
- table: ({ children, ...props }) => (
-
- ),
-
- // Table headers
- th: ({ children, ...props }) => (
-
- {children}
- |
- ),
-
- // Table cells
- td: ({ children, ...props }) => (
-
- {children}
- |
- ),
-
- // Horizontal rule
- hr: ({ ...props }) => (
-
- ),
- }}
- >
- {selectedContent}
-
-
-
-
- {
- showTranscribe && (
-
-
-
-
- )
-
- }
-
- >
- ) : (
-
-
-
-
输入视频链接并点击"生成笔记"按钮
-
支持哔哩哔哩、YouTube等视频网站
-
+ // Horizontal rule
+ hr: ({ ...props }) => (
+
+ ),
+ }}
+ >
+ {selectedContent}
+
- )}
-
+
+ {showTranscribe && (
+
+
+
+ )}
+ >
+ ) : (
+
+
+
+
输入视频链接并点击"生成笔记"按钮
+
支持哔哩哔哩、YouTube等视频网站
+
+
+ )}
+
)
}