78 lines
17 KiB
TypeScript
78 lines
17 KiB
TypeScript
import { ArrowLeft, ArrowRight, Bot, Building2, Check, ChevronRight, CircleCheck, ClipboardList, History, Lightbulb, Link2, MessageSquareText, Paperclip, Save, Search, Send, Sparkles, UserRound } from 'lucide-react'
|
||
|
||
import { Badge } from '@/components/ui/badge'
|
||
import { Button } from '@/components/ui/button'
|
||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
|
||
import { Field, FieldDescription, FieldGroup, FieldLabel, FieldSet } from '@/components/ui/field'
|
||
import { Input } from '@/components/ui/input'
|
||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
|
||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||
import { Textarea } from '@/components/ui/textarea'
|
||
|
||
function go(path: string) { window.location.hash = path }
|
||
|
||
function ScreenNav({ current, otherPath, otherLabel }: { current: string; otherPath: string; otherLabel: string }) {
|
||
return <div className="flex flex-wrap items-center justify-between gap-3 border-b border-border pb-4"><Button variant="ghost" size="sm" onClick={() => go('/concepts')}><ArrowLeft data-icon="inline-start" /> 返回设计入口</Button><div className="flex items-center gap-2"><Badge variant="secondary">{current}</Badge><Button variant="outline" size="sm" onClick={() => go(otherPath)}>{otherLabel}<ArrowRight data-icon="inline-end" /></Button></div></div>
|
||
}
|
||
|
||
function Required() { return <span className="text-destructive">*</span> }
|
||
|
||
export function TicketCreateConcept() {
|
||
return (
|
||
<main className="ticket-screen min-h-screen px-4 py-5 text-foreground sm:px-6 lg:px-8">
|
||
<div className="mx-auto flex max-w-[1380px] flex-col gap-5">
|
||
<ScreenNav current="核心页面 · 工单填写" otherPath="/concept/ticket-detail" otherLabel="查看工单详情" />
|
||
<header className="flex flex-col gap-4 md:flex-row md:items-end md:justify-between"><div><p className="text-xs font-medium text-muted-foreground">客户问题记录</p><h1 className="mt-1 text-3xl font-semibold tracking-[-0.04em]">新建工单</h1><p className="mt-2 text-sm text-muted-foreground">记录客户遇到的问题,信息越完整,后续查询和解决越高效。</p></div><div className="flex items-center gap-2"><Button variant="outline"><Save data-icon="inline-start" /> 保存草稿</Button><Button><Check data-icon="inline-start" /> 创建工单</Button></div></header>
|
||
<div className="grid gap-5 xl:grid-cols-[210px_minmax(0,1fr)_320px]">
|
||
<Card className="h-fit"><CardHeader><CardTitle className="text-sm">填写进度</CardTitle><CardDescription>已完成 2 / 4</CardDescription></CardHeader><CardContent className="flex flex-col gap-1">{[
|
||
{ icon: CircleCheck, label: '问题分类', state: '已完成' }, { icon: CircleCheck, label: '客户与对象', state: '已完成' }, { icon: ClipboardList, label: '问题描述', state: '正在填写' }, { icon: Paperclip, label: '补充信息', state: '可选' },
|
||
].map((step,index)=><div className={index===2?'ticket-step ticket-step-active':'ticket-step'} key={step.label}><span className="ticket-step-icon"><step.icon /></span><span><strong className="block text-xs">{step.label}</strong><span className="text-[11px] text-muted-foreground">{step.state}</span></span></div>)}</CardContent></Card>
|
||
<form className="flex flex-col gap-5">
|
||
<Card><CardHeader><CardTitle className="flex items-center gap-2"><span className="ticket-section-no">01</span> 问题分类</CardTitle><CardDescription>分类会影响工单流程和后续推荐的处理方案。</CardDescription></CardHeader><CardContent><FieldSet><FieldGroup className="grid gap-4 md:grid-cols-2">
|
||
<Field><FieldLabel htmlFor="create-category">问题分类 <Required /></FieldLabel><Select defaultValue="business"><SelectTrigger className="w-full" id="create-category"><SelectValue /></SelectTrigger><SelectContent><SelectGroup><SelectItem value="business">业务问题</SelectItem><SelectItem value="operation">操作问题</SelectItem><SelectItem value="data">数据问题</SelectItem><SelectItem value="technical">技术问题</SelectItem></SelectGroup></SelectContent></Select><FieldDescription>采集进度、业务规则或状态确认</FieldDescription></Field>
|
||
<Field><FieldLabel htmlFor="create-priority">优先级 <Required /></FieldLabel><Select defaultValue="normal"><SelectTrigger className="w-full" id="create-priority"><SelectValue /></SelectTrigger><SelectContent><SelectGroup><SelectItem value="low">低</SelectItem><SelectItem value="normal">普通</SelectItem><SelectItem value="high">高</SelectItem><SelectItem value="urgent">紧急</SelectItem></SelectGroup></SelectContent></Select></Field>
|
||
</FieldGroup></FieldSet></CardContent></Card>
|
||
<Card><CardHeader><CardTitle className="flex items-center gap-2"><span className="ticket-section-no">02</span> 客户与问题对象</CardTitle><CardDescription>明确是哪家客户、哪个任务或账号遇到了问题。</CardDescription></CardHeader><CardContent><FieldSet><FieldGroup>
|
||
<div className="grid gap-4 md:grid-cols-2"><Field><FieldLabel htmlFor="create-org">提出机构 <Required /></FieldLabel><Input id="create-org" defaultValue="深圳海纳科技有限公司" /></Field><Field><FieldLabel htmlFor="create-person">提出人 <Required /></FieldLabel><Input id="create-person" defaultValue="李经理" /></Field></div>
|
||
<div className="grid gap-4 md:grid-cols-2"><Field><FieldLabel htmlFor="create-object">问题对象 <Required /></FieldLabel><Input id="create-object" defaultValue="TASK-8821" /><FieldDescription>客户名称、账号、机构或任务编号</FieldDescription></Field><Field><FieldLabel htmlFor="create-env">环境 <Required /></FieldLabel><Select defaultValue="production"><SelectTrigger className="w-full" id="create-env"><SelectValue /></SelectTrigger><SelectContent><SelectGroup><SelectItem value="production">生产环境</SelectItem><SelectItem value="test">测试环境</SelectItem><SelectItem value="unknown">待确认</SelectItem></SelectGroup></SelectContent></Select></Field></div>
|
||
</FieldGroup></FieldSet></CardContent></Card>
|
||
<Card className="ticket-current-section"><CardHeader><CardTitle className="flex items-center gap-2"><span className="ticket-section-no">03</span> 问题描述</CardTitle><CardDescription>使用客户能理解的语言描述问题表现,不需要先判断技术原因。</CardDescription></CardHeader><CardContent><FieldSet><FieldGroup>
|
||
<Field><FieldLabel htmlFor="create-title">工单标题 <Required /></FieldLabel><Input id="create-title" defaultValue="查询申报数据采集进度" /></Field>
|
||
<Field><FieldLabel htmlFor="create-performance">问题表现 <Required /></FieldLabel><Textarea className="min-h-28" id="create-performance" defaultValue="客户反馈 TASK-8821 从今天早上开始一直显示“采集中”,长时间没有进度变化,希望确认目前处理到哪一步。" /><FieldDescription>建议写明客户看到的状态、发生时间和期望确认的内容。</FieldDescription></Field>
|
||
<Field><FieldLabel htmlFor="create-scope">影响范围</FieldLabel><Input id="create-scope" defaultValue="单个客户,影响本期申报数据获取" /></Field>
|
||
</FieldGroup></FieldSet></CardContent></Card>
|
||
<Card><CardHeader><CardTitle className="flex items-center gap-2"><span className="ticket-section-no">04</span> 补充信息</CardTitle><CardDescription>添加截图、错误信息或客户提供的其他材料。</CardDescription></CardHeader><CardContent><button className="ticket-upload flex min-h-28 w-full flex-col items-center justify-center gap-2 rounded-lg border border-dashed border-border text-sm text-muted-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring" type="button"><Paperclip /><span>拖放附件到这里,或点击选择文件</span><span className="text-xs">支持截图、日志和文档,单个文件不超过 20 MB</span></button></CardContent><CardFooter className="justify-between"><span className="text-xs text-muted-foreground">必填信息已完整,可以创建工单。</span><Button><Check data-icon="inline-start" /> 创建工单</Button></CardFooter></Card>
|
||
</form>
|
||
<div className="grid h-fit gap-4 xl:sticky xl:top-5"><Card className="ticket-summary-card"><CardHeader><CardTitle>工单摘要</CardTitle><CardDescription>创建后将按以下信息进入处理队列</CardDescription></CardHeader><CardContent className="flex flex-col gap-4"><div><Badge>业务问题</Badge><Badge className="ml-2" variant="secondary">普通</Badge></div><div><strong className="text-sm">查询申报数据采集进度</strong><p className="mt-2 text-xs leading-5 text-muted-foreground">深圳海纳科技有限公司 · 李经理</p></div><div className="grid grid-cols-2 gap-3">{[['问题对象','TASK-8821'],['环境','生产环境']].map(([label,value])=><div className="rounded-lg bg-background/80 p-3" key={label}><span className="text-[11px] text-muted-foreground">{label}</span><p className="mt-1 text-xs font-medium">{value}</p></div>)}</div></CardContent></Card><Card><CardHeader><div className="flex items-center gap-2 text-xs font-semibold text-primary"><Sparkles /> AI 建单辅助</div><CardTitle className="text-sm">已识别到任务编号</CardTitle><CardDescription>TASK-8821 可以在创建工单后直接查询采集进度。</CardDescription></CardHeader><CardContent><Button className="w-full" variant="outline"><Search data-icon="inline-start" /> 预先查询任务</Button></CardContent></Card></div>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
)
|
||
}
|
||
|
||
export function TicketDetailConcept() {
|
||
return (
|
||
<main className="ticket-screen min-h-screen px-4 py-5 text-foreground sm:px-6 lg:px-8"><div className="mx-auto flex max-w-[1440px] flex-col gap-5">
|
||
<ScreenNav current="核心页面 · 工单详情" otherPath="/concept/ticket-create" otherLabel="查看工单填写" />
|
||
<header className="grid gap-4 lg:grid-cols-[1fr_auto] lg:items-end"><div><div className="mb-3 flex flex-wrap items-center gap-2"><Badge variant="secondary">业务问题</Badge><Badge variant="destructive">待回复</Badge><span className="text-xs text-muted-foreground">T202607130042 · 创建于 09:52</span></div><h1 className="text-3xl font-semibold tracking-[-0.04em]">查询申报数据采集进度</h1><p className="mt-2 text-sm text-muted-foreground">深圳海纳科技有限公司 · TASK-8821 · 生产环境</p></div><div className="flex flex-wrap gap-2"><Button variant="outline"><Link2 data-icon="inline-start" /> 关联解决方案</Button><Button><Send data-icon="inline-start" /> 回复客户</Button></div></header>
|
||
<section className="ticket-status-strip grid overflow-hidden rounded-xl border border-border bg-card sm:grid-cols-4">{[
|
||
{label:'已创建',time:'09:52',done:true},{label:'处理中',time:'10:02',done:true},{label:'等待回复客户',time:'当前',done:true},{label:'客户确认 / 关闭',time:'待完成',done:false},
|
||
].map((item,index)=><div className="flex items-center gap-3 border-b border-border p-4 last:border-0 sm:border-b-0 sm:border-r" key={item.label}><span className={item.done?'ticket-status-dot ticket-status-done':'ticket-status-dot'}>{item.done?<Check />:index+1}</span><span><strong className="block text-xs">{item.label}</strong><span className="text-[11px] text-muted-foreground">{item.time}</span></span></div>)}</section>
|
||
<div className="grid gap-5 xl:grid-cols-[minmax(0,1fr)_340px]"><div className="grid gap-5">
|
||
<Card><CardHeader><CardTitle>问题概览</CardTitle><CardDescription>客户描述与当前查询结果</CardDescription></CardHeader><CardContent className="grid gap-5"><div className="grid gap-3 sm:grid-cols-3">{[['问题对象','TASK-8821'],['影响范围','单个客户'],['优先级','普通']].map(([label,value])=><div className="rounded-lg bg-muted p-3" key={label}><span className="text-[11px] text-muted-foreground">{label}</span><p className="mt-1 text-sm font-medium">{value}</p></div>)}</div><div><span className="text-xs font-medium">问题表现</span><p className="mt-2 text-sm leading-6">客户反馈任务从今天早上开始一直显示“采集中”,长时间没有进度变化,希望确认目前处理到哪一步。</p></div><div className="ticket-result rounded-xl border border-primary/20 p-4"><div className="flex items-center gap-2 text-xs font-semibold text-primary"><Bot /> 采集任务查询结果 · 10:16</div><p className="mt-3 text-sm leading-6">任务仍在执行,上游税局接口最近一次返回超时;最后有效更新时间为 10:14,当前无需人工重启。</p></div></CardContent></Card>
|
||
<Card><CardHeader><CardTitle>处理过程</CardTitle><CardDescription>客户沟通、内部处理和系统查询按时间记录</CardDescription></CardHeader><CardContent><Tabs defaultValue="timeline"><TabsList variant="line"><TabsTrigger value="timeline">时间线</TabsTrigger><TabsTrigger value="comments">内部评论</TabsTrigger><TabsTrigger value="attachments">附件 2</TabsTrigger></TabsList><TabsContent className="pt-5" value="timeline"><div className="ticket-timeline">{[
|
||
{icon:UserRound,who:'李经理 · 客户',time:'09:52',title:'提交客户问题',text:'TASK-8821 一直显示采集中,麻烦确认一下当前进度。'},
|
||
{icon:Search,who:'王工 · 客服',time:'10:02',title:'开始处理并查询任务',text:'已确认任务编号和生产环境,发起采集进度查询。'},
|
||
{icon:Bot,who:'采集任务查询服务',time:'10:16',title:'返回查询结果',text:'任务运行中,上游接口最近一次返回超时。'},
|
||
{icon:MessageSquareText,who:'系统建议',time:'10:18',title:'生成客户回复草稿',text:'建议说明上游接口状态,并承诺继续关注任务进度。'},
|
||
].map((event)=><div className="ticket-event" key={`${event.time}-${event.title}`}><span className="ticket-event-icon"><event.icon /></span><div><div className="flex flex-wrap items-center gap-2"><strong className="text-sm">{event.title}</strong><span className="text-xs text-muted-foreground">{event.who} · {event.time}</span></div><p className="mt-2 text-sm leading-6 text-muted-foreground">{event.text}</p></div></div>)}</div></TabsContent><TabsContent value="comments"><p className="py-8 text-center text-sm text-muted-foreground">暂无内部评论</p></TabsContent><TabsContent value="attachments"><p className="py-8 text-center text-sm text-muted-foreground">客户截图.png · 任务详情.pdf</p></TabsContent></Tabs></CardContent></Card>
|
||
<Card className="ticket-reply-card"><CardHeader><CardTitle>回复客户</CardTitle><CardDescription>内容会作为处理记录保存,并同步更新客户沟通状态。</CardDescription></CardHeader><CardContent><Textarea className="min-h-28 bg-background" defaultValue="您好,已确认 TASK-8821 仍在采集中。目前上游税局接口响应较慢,我们会继续关注任务进度,恢复后第一时间同步给您。" /></CardContent><CardFooter className="justify-between"><Button variant="ghost"><Sparkles data-icon="inline-start" /> 优化措辞</Button><div className="flex gap-2"><Button variant="outline">仅保存记录</Button><Button><Send data-icon="inline-start" /> 回复并继续跟进</Button></div></CardFooter></Card>
|
||
</div><aside className="grid h-fit gap-4 xl:sticky xl:top-5">
|
||
<Card><CardHeader><CardTitle className="flex items-center gap-2 text-sm"><Building2 /> 客户信息</CardTitle></CardHeader><CardContent className="flex flex-col gap-3"><strong className="text-sm">深圳海纳科技有限公司</strong><div className="flex items-center gap-2 text-xs text-muted-foreground"><UserRound /> 李经理 · 财务负责人</div><Badge className="w-fit" variant="secondary">重点客户</Badge><Button variant="outline" size="sm">查看该客户历史工单</Button></CardContent></Card>
|
||
<Card className="ticket-solution-card"><CardHeader><div className="flex items-center gap-2 text-xs font-semibold text-primary"><Lightbulb /> 推荐解决方案</div><CardTitle className="text-sm">采集任务长时间无进度的排查步骤</CardTitle><CardDescription>匹配度 93% · 已复用 28 次</CardDescription></CardHeader><CardContent><p className="text-xs leading-5 text-muted-foreground">先检查任务状态、上游接口响应和最近一次有效日志,再判断是否需要人工重试。</p></CardContent><CardFooter className="flex-col gap-2"><Button className="w-full"><Link2 data-icon="inline-start" /> 关联到当前工单</Button><Button className="w-full" variant="ghost">查看完整方案 <ChevronRight data-icon="inline-end" /></Button></CardFooter></Card>
|
||
<Card><CardHeader><CardTitle className="flex items-center gap-2 text-sm"><History /> 下一步</CardTitle></CardHeader><CardContent className="flex flex-col gap-2">{['回复客户当前进度','30 分钟后再次查询','任务恢复后填写解决结果'].map((item,index)=><div className="flex items-center gap-3 rounded-lg border border-border p-3 text-xs" key={item}><span className="flex size-5 items-center justify-center rounded bg-secondary">{index+1}</span>{item}</div>)}</CardContent></Card>
|
||
</aside></div>
|
||
</div></main>
|
||
)
|
||
}
|