@@ -15,27 +15,63 @@ import { useActiveDocumentItem } from '@/hooks/useActiveDocumentItem';
1515import { useExplorerTabs } from '@/hooks/useExplorerTabs' ;
1616import { createLogger } from '@/lib/logger' ;
1717import { useTranslations } from 'next-intl' ;
18- import { useState } from 'react' ;
18+ import { useMemo , useState } from 'react' ;
19+
1920const logger = createLogger ( {
2021 type : 'ide:export-menu' ,
2122} , {
22- json : false , // 开启json格式输出
23- pretty : false , // 关闭开发环境美化输出
24- colors : true , // 仅当json:false时启用颜色输出可用
25- includeCaller : false , // 日志不包含调用者
23+ json : false ,
24+ pretty : false ,
25+ colors : true ,
26+ includeCaller : false ,
2627} ) ;
28+
29+ // 定义允许导出的状态列表
30+ // 使用 Set 可以将查询复杂度降低到 O(1),虽然对于短列表来说与 Array 差异不大,但语义更清晰
31+ const EXPORTABLE_STATUSES = new Set ( [
32+ 'MT_REVIEW' ,
33+ 'QA_REVIEW' ,
34+ 'POST_EDIT' ,
35+ 'POST_EDIT_REVIEW' ,
36+ 'SIGN_OFF' ,
37+ 'COMPLETED'
38+ ] ) ;
39+
2740export function ExportMenu ( ) {
2841 const t = useTranslations ( 'IDE.menus.export' ) ;
2942 const { explorerTabs } = useExplorerTabs ( ) ;
3043 const { activeDocumentItem } = useActiveDocumentItem ( ) ;
3144 const [ layout , setLayout ] = useState < 'vertical' | 'horizontal' > ( 'horizontal' ) ;
32- const tabs = explorerTabs ?. documentTabs ?? [ ] ;
33- const aid = ( activeDocumentItem as any ) ?. id ;
34- const currentTab = tabs . find ( ( t : any ) => ( t . items ?? [ ] ) . some ( ( it : any ) => it . id === aid ) ) ;
35- const items : any [ ] = ( currentTab ?. items ?? [ ] ) as any [ ] ;
36- const canExport = items . length > 0 && items . every ( ( it : any ) => it . status === 'COMPLETED' ) ;
37- const docId = ( currentTab as any ) ?. id || '' ;
38- logger . debug ( 'canExport:' + canExport + ',段落个数:' + items . length , 'docId:' + docId ) ;
45+
46+ // 使用 useMemo 优化计算逻辑,避免非相关渲染时的重复计算
47+ const { canExport, docId } = useMemo ( ( ) => {
48+ const tabs = explorerTabs ?. documentTabs ?? [ ] ;
49+ const aid = ( activeDocumentItem as any ) ?. id ;
50+
51+ // 找到当前激活的文档 Tab
52+ const currentTab = tabs . find ( ( t : any ) => ( t . items ?? [ ] ) . some ( ( it : any ) => it . id === aid ) ) ;
53+ const items : any [ ] = ( currentTab ?. items ?? [ ] ) as any [ ] ;
54+ const docId = ( currentTab as any ) ?. id || '' ;
55+
56+ // 核心逻辑修改:检查段落是否非空,且所有段落的状态都在允许列表中
57+ const canExport = items . length > 0 && items . every ( ( it : any ) =>
58+ EXPORTABLE_STATUSES . has ( it . status )
59+ ) ;
60+
61+ logger . debug ( 'canExport:' + canExport + ', 段落个数:' + items . length , 'docId:' + docId ) ;
62+
63+ return { canExport, docId } ;
64+ } , [ explorerTabs , activeDocumentItem ] ) ;
65+
66+ // 生成导出链接的辅助函数
67+ const getExportLink = ( type : 'markdown' | 'word' , mode : 'bilingual' | 'target' ) => {
68+ if ( ! canExport || ! docId ) return '#' ;
69+
70+ const baseUrl = `/api/export/${ type } ?documentId=${ encodeURIComponent ( docId ) } &mode=${ mode } ` ;
71+ // 双语模式需要附加布局参数
72+ return mode === 'bilingual' ? `${ baseUrl } &layout=${ layout } ` : baseUrl ;
73+ } ;
74+
3975 return (
4076 < MenubarMenu >
4177 < MenubarTrigger >
@@ -45,47 +81,23 @@ export function ExportMenu() {
4581 </ MenubarTrigger >
4682 < MenubarContent >
4783 < MenubarItem asChild disabled = { ! canExport } >
48- < a
49- href = {
50- canExport
51- ? `/api/export/markdown?documentId=${ encodeURIComponent ( docId ) } &mode=bilingual&layout=${ layout } `
52- : '#'
53- }
54- >
84+ < a href = { getExportLink ( 'markdown' , 'bilingual' ) } >
5585 { t ( 'bilingualMarkdown' ) }
5686 </ a >
5787 </ MenubarItem >
5888 < MenubarItem asChild disabled = { ! canExport } >
59- < a
60- href = {
61- canExport
62- ? `/api/export/markdown?documentId=${ encodeURIComponent ( docId ) } &mode=target`
63- : '#'
64- }
65- >
89+ < a href = { getExportLink ( 'markdown' , 'target' ) } >
6690 { t ( 'targetOnlyMarkdown' ) }
6791 </ a >
6892 </ MenubarItem >
6993 < MenubarSeparator />
7094 < MenubarItem asChild disabled = { ! canExport } >
71- < a
72- href = {
73- canExport
74- ? `/api/export/word?documentId=${ encodeURIComponent ( docId ) } &mode=bilingual&layout=${ layout } `
75- : '#'
76- }
77- >
95+ < a href = { getExportLink ( 'word' , 'bilingual' ) } >
7896 { t ( 'bilingualWord' ) }
7997 </ a >
8098 </ MenubarItem >
8199 < MenubarItem asChild disabled = { ! canExport } >
82- < a
83- href = {
84- canExport
85- ? `/api/export/word?documentId=${ encodeURIComponent ( docId ) } &mode=target`
86- : '#'
87- }
88- >
100+ < a href = { getExportLink ( 'word' , 'target' ) } >
89101 { t ( 'targetOnlyWord' ) }
90102 </ a >
91103 </ MenubarItem >
@@ -114,4 +126,4 @@ export function ExportMenu() {
114126 ) ;
115127}
116128
117- export default ExportMenu ;
129+ export default ExportMenu ;
0 commit comments