提交 3c0cd0ea authored 作者: 张伊明's avatar 张伊明

feat 更新智能翻译

上级 482124c8
流水线 #544 已通过 于阶段
in 1 分 48 秒
# 智能翻译开发任务拆分(Checklist)
> 目标:按最小可交付顺序完成“智能翻译”功能,并保持结构清晰、便于后续接接口与调整样式。
## 阶段 1:入口与路由
- [x]`moduleHeader` 增加“智能翻译”入口(图标 `tool-item-icon2.png`
- [x] 配置主路由 `intelligentTranslation`
- [x] 配置文档对照页路由(建议 `intelligentTranslationDocument`
- [x] 本地验证:点击入口可进入主页面
## 阶段 2:页面骨架搭建
- [x] 创建目录 `src/views/intelligentTranslation/`
- [x] 创建 `index.vue`(主页面)
- [x] 创建 `documentCompare.vue`(文档对照页)
- [x] 引入左侧通用组件 `src/components/intelligenceLeftTabBar/index.vue`
- [x] 搭建基础布局结构(左侧导航 + 右侧内容区)
## 阶段 3:主页面核心交互(需求 a)
- [x] 实现“文本模式”默认视图
- [x] 原文输入框
- [x] 上传文档按钮
- [x] 翻译按钮(位于右上)
- [x] 右侧翻译内容区
- [x] 实现文本翻译占位逻辑(点击翻译后展示 mock 结果)
- [x] 实现“文件模式”切换逻辑
- [x] 上传后输入区替换为上传文件列表
- [x] 右侧翻译内容区隐藏
- [x] 实现文件模式“翻译”按钮跳转到文档对照页
- [x] 传递上传文件名到对照页
## 阶段 4:上传记录区(需求 a 下半区)
- [x] 在主页面底部实现上传记录区域
- [x] 以占位数据展示:文档名、时间
- [x] 保持结构和类名清晰,便于后续替换为接口
## 阶段 5:文档对照页实现(需求 b)
- [x] 顶部 header 显示文档名称(来自上传文件名)
- [x] 左侧实现文章标题树(mock)
- [x] 右侧实现段落对照(左原文右译文)
- [x] 实现点击树节点后右侧过滤/定位对应段落
## 阶段 6:占位数据与类型管理
- [x] 新建 `mock.js` 统一管理页面 mock 数据
- [x] (可选)不使用 `types.ts`,采用 JS 方案
- [x] 在关键位置加 `TODO: replace with API`
## 阶段 7:样式与可维护性
- [x] 输出简洁样式(不做复杂视觉)
- [x] 统一语义化 class 命名
- [x] 检查结构是否便于后续改样式
## 阶段 8:联调与验收
- [x] 从入口进入主页面流程完整可跑通
- [x] 文本翻译流程可用(占位)
- [x] 文档上传 -> 文件模式 -> 跳转对照页流程可用
- [x] 对照页标题、树、段落对照展示正确
- [x] 检查并修复本次改动引入的 lint 问题
- [x] 左侧导航“智能翻译”支持直接跳转并高亮
# 智能翻译页面实现计划
## 1. 目标概述
- 新增“智能翻译”页面,并接入现有入口与路由。
- 页面包含两个视图:
- a)主页面:文本翻译 / 文档上传翻译 + 上传记录
- b)文档对照页面:文档标题 + 文章导航树 + 原文/译文段落对照
- 当前阶段全部使用前端占位数据,不接真实接口。
---
## 2. 入口与路由接入
### 2.1 moduleHeader 入口
- 文件:`src/components/base/moduleHeader/index.vue`
- 在指定区域(315-326 附近)新增“智能翻译”入口
- 文案:`智能翻译`
- 图标:`@/assets/icons/tool-item-icon2.png`
- 点击跳转到路由名:`intelligentTranslation`
### 2.2 路由
- 新增主路由:
- `name: intelligentTranslation`
- `path: /intelligent-translation`(可按项目现有习惯微调)
- `component: src/views/intelligentTranslation/index.vue`
- 新增文档对照页路由:
- 建议 `name: intelligentTranslationDocument`
- 建议 `path: /intelligent-translation/document`
- `component: src/views/intelligentTranslation/documentCompare.vue`
---
## 3. 目录与文件规划
`src/views/intelligentTranslation/` 下创建:
1. `index.vue`:主页面(需求 a)
2. `documentCompare.vue`:文档对照页面(需求 b)
3. `mock.ts`(可选):占位数据统一管理
4. `types.ts`(可选):类型定义,便于后续接接口
---
## 4. 页面 a(主页面)实现方案
## 4.1 布局结构
- 页面最左侧使用通用组件:`src/components/intelligenceLeftTabBar/index.vue`
- 右侧为主工作区:
- 上方约 2/3:翻译操作区
- 下方约 1/3:文档翻译上传记录
## 4.2 上方翻译区状态
定义两种状态:
### 状态 1:文本模式(默认)
- 左侧:原文输入区(文本输入框)
- 左侧底部:上传文档按钮
- 左侧右上:翻译按钮
- 右侧:翻译内容展示区
- 交互:输入原文并点击翻译,在右侧展示占位翻译结果
### 状态 2:文件模式(上传文件后)
- 上传后左侧输入区切换为“上传文件列表”
- 右侧翻译内容区隐藏
- 左侧右上继续保留翻译按钮
- 点击翻译按钮后跳转到页面 b
## 4.3 上传记录区
- 展示“文档名 + 时间”两列(占位数据)
- 数据来源先用 mock,后续替换为接口
---
## 5. 页面 b(文档对照页)实现方案
## 5.1 页面结构
- 顶部 Header:显示文档名称(来自上传文件名)
- 下方左右两栏:
- 左侧:文章导航树(占位数据模拟接口)
- 右侧:原文/译文按段落一一对照
## 5.2 数据与交互
- 树数据:模拟章节结构(可含 children)
- 段落数据:`[{ sectionId, sourceText, translatedText }]`
- 交互:点击左侧章节,右侧过滤或定位对应段落
---
## 6. 占位数据策略
- 所有“接口返回数据”先统一在 `mock.ts` 管理,避免散落到组件内。
- 页面仅依赖数据结构,后续接真实接口时只替换数据来源。
- 在关键数据位置添加 `TODO: replace with API` 便于后续联调。
---
## 7. 样式与结构约束
- 样式先做简洁版,保证可读与可用。
- 重点保证 HTML 结构和 class 命名清晰,便于后续二次改样式。
- 建议类名示例:
- `intelligent-translation-page`
- `translation-main`
- `source-upload-panel`
- `translation-result-panel`
- `upload-record-list`
- `document-compare-page`
- `article-nav-tree`
- `paragraph-compare-row`
---
## 8. 验收清单
1. moduleHeader 中新增“智能翻译”入口并可跳转
2. 主页面默认文本模式可输入并生成占位翻译结果
3. 上传文档后切换到文件模式(输入区变文件列表,右侧翻译区隐藏)
4. 文件模式点击翻译可进入文档对照页
5. 文档对照页 header 正确显示上传文件名
6. 文档对照页左侧展示文章树,右侧按段落对照展示原文/译文
7. 上传记录区展示占位“文档名+时间”
8. 代码结构清晰,便于后续样式和接口替换
...@@ -39,10 +39,24 @@ export const uploadRecordListMock = [ ...@@ -39,10 +39,24 @@ export const uploadRecordListMock = [
// TODO: replace with API // TODO: replace with API
export const articleTreeMock = [ export const articleTreeMock = [
{ id: 'all', title: '全部章节' }, {
{ id: 'sec-1', title: '一、风险概览' }, id: 'sec-1',
{ id: 'sec-2', title: '二、重点行业观察' }, title: '一、风险概览',
{ id: 'sec-3', title: '三、处置建议' } children: [
{ id: 'sec-1-p1', title: '1.1 全球流动性', sectionId: 'sec-1' },
{ id: 'sec-1-p2', title: '1.2 跨境资本流动', sectionId: 'sec-1' }
]
},
{
id: 'sec-2',
title: '二、重点行业观察',
children: [{ id: 'sec-2-p1', title: '2.1 科技供应链', sectionId: 'sec-2' }]
},
{
id: 'sec-3',
title: '三、处置建议',
children: [{ id: 'sec-3-p1', title: '3.1 预警与演练', sectionId: 'sec-3' }]
}
] ]
// TODO: replace with API // TODO: replace with API
...@@ -76,13 +90,78 @@ export const paragraphRowsMock = [ ...@@ -76,13 +90,78 @@ export const paragraphRowsMock = [
} }
] ]
/**
* 文档对照页显示用的版式识别结果示例 JSON。
* 后续可按 1 PDF -> 1 JSON 的接口返回直接映射。
*/
export const layoutStyleResultMock = {
schema_version: '3.0',
document_meta: {
source_file_name: '测试文档.pdf',
source_file_type: 'pdf',
page_count: 3,
created_at: '2026-04-08T15:00:00Z'
},
pages: [
{
page_idx: 0,
width: 594.96,
height: 841.92,
rotation: null,
node_ids: ['page0_node0', 'page0_node1', 'page0_node2', 'page0_node3', 'page0_node4']
}
],
merged_nodes: [
{
node_id: 'page0_node0',
semantic_type: 'page_header',
page_idx: 0,
content_payload: {
type: 'text',
text: '格式转换测试文件',
html: '<b><span style="color:#333333">格式转换测试文件</span></b>',
heading_level: null,
content_fragments: [{ type: 'text', content: '格式转换测试文件' }],
markdown: null
},
layout: {
bbox: [67, 78, 395, 111],
bbox_norm: [0.069, 0.079, 0.397, 0.112],
angle: 0,
reading_order: 0,
page_idx: 0,
link: null,
z_index: null
},
style_spans: [
{
span_id: 'page0_node0_s0',
start: 0,
end: 8,
text: '格式转换测试文件',
style: {
bold: true,
italic: false,
underline: false,
superscript: false,
subscript: false,
color_hex: '#333333'
}
}
]
}
]
}
/** 文档对照数据(TODO: 替换为真实接口) */ /** 文档对照数据(TODO: 替换为真实接口) */
export function fetchDocumentCompareMock(_fileName, delayMs = 2500) { export function fetchDocumentCompareMock(_fileName, delayMs = 2500) {
return new Promise((resolve) => { return new Promise((resolve) => {
setTimeout(() => { setTimeout(() => {
resolve({ resolve({
articleTree: articleTreeMock, articleTree: articleTreeMock,
paragraphRows: paragraphRowsMock paragraphRows: paragraphRowsMock,
translationProgress: 12,
layoutStyleResult: layoutStyleResultMock
}) })
}, delayMs) }, delayMs)
}) })
......
import { articleTreeMock, paragraphRowsMock } from '../mock'
import { fetchLayoutStyleResult, mapLayoutStyleResult } from './layoutStyleService'
/**
* 对比页接口占位 service
* 后续后端接入时,只需要替换这里的数据获取方式和字段映射逻辑。
*/
export async function fetchDocumentComparePageData(params = {}) {
const { fileName = '' } = params
const response = await fetchDocumentCompareRawData({ fileName })
return mapDocumentComparePageData(response)
}
/**
* 原始接口占位:模拟后端可能返回的结构
* 这里保留为后续分接口时的聚合入口。
*/
export async function fetchDocumentCompareRawData(_params = {}) {
const layoutStyleRaw = await fetchLayoutStyleResult()
return Promise.resolve({
file_info: {
file_name: '测试文档.pdf',
file_type: 'pdf'
},
translation_progress: 12,
article_tree: articleTreeMock,
paragraph_rows: paragraphRowsMock,
layout_style_result: layoutStyleRaw
})
}
/**
* 将后端返回结构映射为页面可直接使用的数据结构。
*/
export function mapDocumentComparePageData(rawData) {
const articleTree = Array.isArray(rawData?.article_tree) ? rawData.article_tree : []
const paragraphRows = Array.isArray(rawData?.paragraph_rows) ? rawData.paragraph_rows : []
const layoutStyleResult = rawData?.layout_style_result
? mapLayoutStyleResult(rawData.layout_style_result)
: null
return {
fileName: rawData?.file_info?.file_name || '',
fileType: rawData?.file_info?.file_type || 'pdf',
translationProgress: Number(rawData?.translation_progress) || 0,
articleTree,
paragraphRows,
layoutStyleResult
}
}
/**
* 版式识别与样式还原结果接口占位 service
* 后续 PDF + JSON 接口接入时,在这里做字段映射。
*/
export async function fetchLayoutStyleResult(_params = {}) {
return Promise.resolve({
schema_version: '3.0',
document_meta: {
source_file_name: '测试文档.pdf',
source_file_type: 'pdf',
page_count: 3,
created_at: '2026-04-08T15:00:00Z'
},
pages: [],
merged_nodes: []
})
}
/**
* 将后端返回的 JSON 结构映射为前端可用结构。
*/
export function mapLayoutStyleResult(rawData) {
return {
schemaVersion: rawData?.schema_version || '',
documentMeta: {
sourceFileName: rawData?.document_meta?.source_file_name || '',
sourceFileType: rawData?.document_meta?.source_file_type || '',
pageCount: Number(rawData?.document_meta?.page_count) || 0,
createdAt: rawData?.document_meta?.created_at || ''
},
pages: Array.isArray(rawData?.pages) ? rawData.pages : [],
mergedNodes: Array.isArray(rawData?.merged_nodes) ? rawData.merged_nodes : []
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论