auto-save 2026-04-13 18:59 (+1)
This commit is contained in:
146
web/app/upload/page.tsx
Normal file
146
web/app/upload/page.tsx
Normal file
@@ -0,0 +1,146 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useRef } from 'react'
|
||||
import { UploadCloud, FileAudio, X } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { AppShell } from '@/components/app-shell'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
export default function UploadPage() {
|
||||
const [file, setFile] = useState<File | null>(null)
|
||||
const [title, setTitle] = useState('')
|
||||
const [participants, setParticipants] = useState('')
|
||||
const [dragOver, setDragOver] = useState(false)
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
|
||||
const pickFile = (f: File | null | undefined) => {
|
||||
if (f) setFile(f)
|
||||
}
|
||||
|
||||
const humanSize = (bytes: number) => {
|
||||
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(0) + ' KB'
|
||||
return (bytes / 1024 / 1024).toFixed(1) + ' MB'
|
||||
}
|
||||
|
||||
return (
|
||||
<AppShell>
|
||||
<div className="mx-auto max-w-2xl px-5 py-8 md:px-10 md:py-10">
|
||||
<header className="mb-8">
|
||||
<h1 className="text-[26px] font-semibold tracking-tight">新建会议</h1>
|
||||
<p className="mt-1 text-[14px] text-muted-foreground">
|
||||
把手机录好的音频文件拖进来,云端自动转写并生成总结
|
||||
</p>
|
||||
</header>
|
||||
|
||||
{/* Dropzone */}
|
||||
{!file ? (
|
||||
<div
|
||||
onDragOver={(e) => {
|
||||
e.preventDefault()
|
||||
setDragOver(true)
|
||||
}}
|
||||
onDragLeave={() => setDragOver(false)}
|
||||
onDrop={(e) => {
|
||||
e.preventDefault()
|
||||
setDragOver(false)
|
||||
pickFile(e.dataTransfer.files?.[0])
|
||||
}}
|
||||
onClick={() => inputRef.current?.click()}
|
||||
className={cn(
|
||||
'flex flex-col items-center justify-center rounded-2xl border-2 border-dashed px-6 py-16 transition-all cursor-pointer',
|
||||
dragOver
|
||||
? 'border-primary bg-primary-subtle'
|
||||
: 'border-border bg-surface-elevated hover:border-primary/50 hover:bg-primary-subtle/50',
|
||||
)}
|
||||
>
|
||||
<div className="flex h-14 w-14 items-center justify-center rounded-2xl bg-primary-subtle text-primary">
|
||||
<UploadCloud className="h-7 w-7" />
|
||||
</div>
|
||||
<h3 className="mt-5 text-[17px] font-semibold">拖拽音频文件到这里</h3>
|
||||
<p className="mt-1 text-[13px] text-muted-foreground">或点击选择文件</p>
|
||||
<p className="mt-4 text-[12px] text-muted-foreground">
|
||||
支持 m4a · mp3 · wav · mp4 · opus · 单文件最大 500 MB
|
||||
</p>
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="file"
|
||||
accept="audio/*,video/mp4"
|
||||
className="hidden"
|
||||
onChange={(e) => pickFile(e.target.files?.[0])}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="rounded-2xl border border-border bg-surface-elevated p-5">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="flex h-12 w-12 items-center justify-center rounded-xl bg-primary-subtle text-primary shrink-0">
|
||||
<FileAudio className="h-6 w-6" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<h3 className="text-[15px] font-semibold truncate">{file.name}</h3>
|
||||
<button
|
||||
onClick={() => setFile(null)}
|
||||
className="rounded-lg p-1.5 text-muted-foreground hover:bg-surface-muted"
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
<p className="mt-1 text-[13px] text-muted-foreground">{humanSize(file.size)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Form */}
|
||||
<div className="mt-6 space-y-5">
|
||||
<div>
|
||||
<label className="block text-[13px] font-medium mb-2">会议标题(可选)</label>
|
||||
<input
|
||||
type="text"
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
placeholder="例:与客户对齐定价"
|
||||
className="w-full rounded-xl border border-input bg-surface-elevated px-4 py-3 text-[14px] placeholder:text-muted-foreground/60 focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-[13px] font-medium mb-2">
|
||||
参与人(可选)
|
||||
<span className="ml-2 text-[11px] font-normal text-muted-foreground">
|
||||
填上有助于提升总结质量
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={participants}
|
||||
onChange={(e) => setParticipants(e.target.value)}
|
||||
placeholder="张三, 李四, 客户王总"
|
||||
className="w-full rounded-xl border border-input bg-surface-elevated px-4 py-3 text-[14px] placeholder:text-muted-foreground/60 focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Actions */}
|
||||
<div className="mt-8 flex items-center justify-end gap-3">
|
||||
<Link
|
||||
href="/"
|
||||
className="rounded-full px-5 py-2.5 text-[14px] font-medium text-muted-foreground hover:bg-surface-muted"
|
||||
>
|
||||
取消
|
||||
</Link>
|
||||
<button
|
||||
disabled={!file}
|
||||
className="rounded-full bg-primary px-6 py-2.5 text-[14px] font-medium text-primary-foreground transition-colors hover:bg-primary-light disabled:opacity-40 disabled:cursor-not-allowed"
|
||||
>
|
||||
开始上传 →
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p className="mt-8 text-center text-[12px] text-muted-foreground">
|
||||
上传后 Groq Whisper 转写 · Claude 自动生成要点 / 待办 / 决议
|
||||
</p>
|
||||
</div>
|
||||
</AppShell>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user