11import { type JSONContentZod } from "tentix-server/types" ;
2- import { Loader2Icon , UploadIcon , LibraryBigIcon , XIcon } from "lucide-react" ;
2+ import { Loader2Icon , UploadIcon , LibraryBigIcon , XIcon , FileTextIcon } from "lucide-react" ;
33import React , { useRef , useState , useCallback , useMemo } from "react" ;
44import {
55 SendIcon ,
@@ -14,6 +14,8 @@ import useLocalUser from "@hook/use-local-user.tsx";
1414import { collectFavoritedKnowledge } from "@lib/query" ;
1515import { useTranslation } from "i18n" ;
1616import type { TFunction } from "i18next" ;
17+ import { cn } from "../../../lib/utils" ;
18+ import { ContextOrganizerDialog } from "../../../modal/use-context-organizer-modal" ;
1719
1820// 错误处理工具函数
1921const getErrorMessage = ( error : unknown , t : TFunction ) : string => {
@@ -139,14 +141,18 @@ export function StaffMessageInput({
139141 const [ uploadProgress , setUploadProgress ] = useState < UploadProgress | null > (
140142 null ,
141143 ) ;
144+ const [ isContextOrganizerOpen , setIsContextOrganizerOpen ] = useState ( false ) ;
142145
143146 const editorRef = useRef < EditorRef > ( null ) ;
144147 const { toast } = useToast ( ) ;
145148 const { kbSelectionMode, clearKbSelection, selectedMessageIds } =
146149 useChatStore ( ) ;
147150 const { id : userId } = useLocalUser ( ) ;
151+
152+
153+ const authToken = window . localStorage . getItem ( "token" ) ;
154+ const ticketId = window . location . pathname . split ( '/' ) . pop ( ) ;
148155
149- // 分析消息内容中的文件情况
150156 const analyzeFileContent = useCallback (
151157 ( content : JSONContentZod ) : FileStats => {
152158 let count = 0 ;
@@ -257,6 +263,12 @@ export function StaffMessageInput({
257263 ] ,
258264 ) ;
259265
266+ // 工单整理按钮点击
267+ const handleContextOrganizerClick = useCallback ( ( ) => {
268+ if ( isLoading || uploadProgress ) return ;
269+ setIsContextOrganizerOpen ( true ) ;
270+ } , [ isLoading , uploadProgress ] ) ;
271+
260272 const editorProps = useMemo (
261273 ( ) => ( {
262274 handleKeyDown : ( _ : unknown , event : KeyboardEvent ) => {
@@ -336,6 +348,7 @@ export function StaffMessageInput({
336348 } ;
337349
338350 const isUploading = uploadProgress !== null ;
351+ const isContextOrganizerDisabled = isLoading || isUploading ;
339352
340353 if ( kbSelectionMode ) {
341354 const count = selectedMessageIds . size ;
@@ -410,45 +423,75 @@ export function StaffMessageInput({
410423 }
411424
412425 return (
413- < div className = "border-t relative" >
414- { /* 上传进度指示器 */ }
415- { renderUploadProgress ( ) }
416-
417- { /* 主要内容区域 - 动态调整顶部间距 */ }
418- < form
419- onSubmit = { handleSubmit }
420- style = { {
421- marginTop : progressBarHeight ,
422- transition : "margin-top 0.3s ease-in-out" ,
423- } }
424- >
425- < div className = "flex" >
426- < StaffChatEditor
427- ref = { editorRef }
428- value = { newMessage }
429- onChange = { ( value ) => {
430- onTyping ?.( ) ;
431- setNewMessage ( value as JSONContentZod ) ;
432- } }
433- throttleDelay = { 150 }
434- editorContentClassName = "overflow-auto h-full"
435- editable = { ! isUploading }
436- editorClassName = "focus:outline-none p-4 h-full"
437- className = "border-none"
438- editorProps = { editorProps }
439- />
440- </ div >
441-
442- < Button
443- type = "submit"
444- size = "icon"
445- className = "absolute right-3 bottom-4 flex justify-center items-center rounded-[10px] bg-zinc-900 z-20 h-9 w-9"
446- disabled = { ! canSend }
426+ < >
427+ < div className = "border-t relative" >
428+ { /* 上传进度指示器 */ }
429+ { renderUploadProgress ( ) }
430+
431+ { /* 主要内容区域 - 动态调整顶部间距 */ }
432+ < form
433+ onSubmit = { handleSubmit }
434+ style = { {
435+ marginTop : progressBarHeight ,
436+ transition : "margin-top 0.3s ease-in-out" ,
437+ } }
447438 >
448- { renderSendButtonContent ( ) }
449- < span className = "sr-only" > { t ( "send_message_shortcut" ) } </ span >
450- </ Button >
451- </ form >
452- </ div >
439+ < div className = "flex" >
440+ < StaffChatEditor
441+ ref = { editorRef }
442+ value = { newMessage }
443+ onChange = { ( value ) => {
444+ onTyping ?.( ) ;
445+ setNewMessage ( value as JSONContentZod ) ;
446+ } }
447+ throttleDelay = { 150 }
448+ editorContentClassName = "overflow-auto h-full"
449+ editable = { ! isUploading }
450+ editorClassName = "focus:outline-none p-4 h-full"
451+ ticketId = { ticketId || undefined }
452+ authToken = { authToken || undefined }
453+ className = "border-none"
454+ editorProps = { editorProps }
455+ />
456+ </ div >
457+
458+ { /* 工具栏区域 */ }
459+ < div className = "absolute right-14 bottom-4 flex items-center gap-2 z-20" >
460+ { ticketId && authToken && (
461+ < Button
462+ variant = "ghost"
463+ size = "sm"
464+ onClick = { handleContextOrganizerClick }
465+ disabled = { isContextOrganizerDisabled }
466+ className = { cn (
467+ "h-9 w-9 p-0 hover:bg-gray-100"
468+ ) }
469+ title = { t ( 'organize_ticket_context' ) }
470+ >
471+ < FileTextIcon className = "h-4 w-4" />
472+ </ Button >
473+ ) }
474+ </ div >
475+
476+ < Button
477+ type = "submit"
478+ size = "icon"
479+ className = "absolute right-3 bottom-4 flex justify-center items-center rounded-[10px] bg-zinc-900 z-20 h-9 w-9"
480+ disabled = { ! canSend }
481+ >
482+ { renderSendButtonContent ( ) }
483+ < span className = "sr-only" > { t ( "send_message_shortcut" ) } </ span >
484+ </ Button >
485+ </ form >
486+ </ div >
487+
488+ { /* 工单整理对话框 */ }
489+ < ContextOrganizerDialog
490+ open = { isContextOrganizerOpen }
491+ onOpenChange = { setIsContextOrganizerOpen }
492+ ticketId = { ticketId || "" }
493+ authToken = { authToken || "" }
494+ />
495+ </ >
453496 ) ;
454497}
0 commit comments