Skip to content

Commit 8ba0cc9

Browse files
committed
feat(magic-web): support excel & pdf preview
1 parent c80d4cf commit 8ba0cc9

File tree

57 files changed

+4068
-374
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+4068
-374
lines changed

frontend/magic-web/src/assets/locales/create.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ export function createI18nNext(defaultLang?: string) {
1919
resourcesToBackend(async (lng: string, namespace: string) => {
2020
if (namespace === "magicFlow") {
2121
return import(
22-
`../../../node_modules/@dtyq/magic-flow/dist/common/locales/${normalizeLocale(lng)}/${namespace}.json`
22+
`../../../node_modules/@dtyq/magic-flow/dist/common/locales/${normalizeLocale(
23+
lng,
24+
)}/${namespace}.json`
2325
)
2426
}
2527
return import(`./${normalizeLocale(lng)}/${namespace}.json`)
@@ -30,7 +32,15 @@ export function createI18nNext(defaultLang?: string) {
3032
init: () => {
3133
return instance.init({
3234
defaultNS: ["translation", "common", "interface"],
33-
ns: ["translation", "common", "interface", "message", "flow", "magicFlow"],
35+
ns: [
36+
"translation",
37+
"common",
38+
"interface",
39+
"message",
40+
"flow",
41+
"magicFlow",
42+
"component",
43+
],
3444
// the translations
3545
// (tip move them in a JSON file and import them,
3646
// or even better, manage them via a UI: https://react.i18next.com/guides/multiple-translation-files#manage-your-translations-with-a-management-gui)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"magicPdfRender": {
3+
"toolbar": {
4+
"prevPage": "Previous Page (←)",
5+
"nextPage": "Next Page (→)",
6+
"zoomOut": "Zoom Out (-)",
7+
"zoomIn": "Zoom In (+)",
8+
"rotateLeft": "Rotate Left",
9+
"rotateRight": "Rotate Right",
10+
"reload": "Reload",
11+
"download": "Download",
12+
"fullscreen": "Fullscreen (F11)",
13+
"moreActions": "More Actions"
14+
},
15+
"pageInfo": {
16+
"currentPage": "Page {{current}}",
17+
"totalPages": "of {{total}}",
18+
"pageNumber": "Page",
19+
"scale": "Scale"
20+
},
21+
"status": {
22+
"loading": "Loading...",
23+
"loadingProgress": "Loading Progress",
24+
"noFile": "Please select a PDF file to preview",
25+
"loadFailed": "Failed to load, please try again",
26+
"pageLoadFailed": "Page failed to load",
27+
"downloadUnavailable": "Unable to download this document",
28+
"retry": "Retry"
29+
},
30+
"placeholders": {
31+
"pageNumber": "Page {{number}}",
32+
"scrollToLoad": "Scroll here to load"
33+
},
34+
"dropdown": {
35+
"pageNav": "Page:",
36+
"zoom": "Zoom:",
37+
"zoomOut": "Zoom Out",
38+
"zoomIn": "Zoom In",
39+
"rotateLeft": "Rotate Left",
40+
"rotateRight": "Rotate Right",
41+
"reload": "Reload",
42+
"download": "Download",
43+
"fullscreen": "Fullscreen"
44+
}
45+
}
46+
}

frontend/magic-web/src/assets/locales/en_US/interface.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@
358358
"filePreview": {
359359
"notFoundFile": "The file was not found",
360360
"notSupport": "Preview is not supported yet",
361+
"notSupportFileType": "This file type is not supported yet",
361362
"title": "File preview"
362363
},
363364
"floatButton": {
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"magicPdfRender": {
3+
"toolbar": {
4+
"prevPage": "上一页 (←)",
5+
"nextPage": "下一页 (→)",
6+
"zoomOut": "缩小 (-)",
7+
"zoomIn": "放大 (+)",
8+
"rotateLeft": "逆时针旋转",
9+
"rotateRight": "顺时针旋转",
10+
"reload": "重新加载",
11+
"download": "下载",
12+
"fullscreen": "全屏 (F11)",
13+
"moreActions": "更多操作"
14+
},
15+
"pageInfo": {
16+
"currentPage": "第 {{current}} 页",
17+
"totalPages": "共 {{total}} 页",
18+
"pageNumber": "页码",
19+
"scale": "缩放"
20+
},
21+
"status": {
22+
"loading": "正在加载...",
23+
"loadingProgress": "加载进度",
24+
"noFile": "请选择要预览的 PDF 文件",
25+
"loadFailed": "加载失败,请重试",
26+
"pageLoadFailed": "页面加载失败",
27+
"downloadUnavailable": "无法下载该文档",
28+
"retry": "重试"
29+
},
30+
"placeholders": {
31+
"pageNumber": "页面 {{number}}",
32+
"scrollToLoad": "滚动到此处加载"
33+
},
34+
"dropdown": {
35+
"pageNav": "页面:",
36+
"zoom": "缩放:",
37+
"zoomOut": "缩小",
38+
"zoomIn": "放大",
39+
"rotateLeft": "逆时针旋转",
40+
"rotateRight": "顺时针旋转",
41+
"reload": "重新加载",
42+
"download": "下载",
43+
"fullscreen": "全屏"
44+
}
45+
}
46+
}

frontend/magic-web/src/assets/locales/zh_CN/interface.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@
358358
"filePreview": {
359359
"notFoundFile": "未找到该文件",
360360
"notSupport": "暂不支持预览",
361+
"notSupportFileType": "暂不支持该文件类型",
361362
"title": "文件预览"
362363
},
363364
"floatButton": {

frontend/magic-web/src/const/file.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ export const DRIVE_SPACE_KEY_MAP = {
1616
[DriveSpaceType.Shared]: DriveSpaceKey.Shared,
1717
}
1818

19+
/**
20+
* 可预览文件扩展名
21+
*/
22+
export const PREVIEW_EXTENSIONS = ["pdf", "xls", "xlsx"]
23+
1924
/** 图片扩展名 */
2025
export const IMAGE_EXTENSIONS = ["png", "jpg", "jpeg", "svg", "gif", "webp", "svg", "svg+xml"]
2126
/** 视频扩展名 */

frontend/magic-web/src/opensource/components/base/MagicImagePreview/components/ImageWrapper/index.tsx

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
import { useMessageRenderContext } from "@/opensource/components/business/MessageRenderProvider/hooks"
2-
import { useBoolean, useMemoizedFn } from "ahooks"
2+
import { useBoolean, useMemoizedFn, useUpdateEffect } from "ahooks"
33
import type React from "react"
44
import { useState, memo, useMemo, useRef, useEffect } from "react"
55
import { isString } from "lodash-es"
66
import { useTranslation } from "react-i18next"
7-
import { Skeleton } from "antd"
7+
import { Skeleton, Tooltip } from "antd"
8+
import MessageFilePreviewService from "@/opensource/services/chat/message/MessageImagePreview"
9+
import MessageFilePreviewStore from "@/opensource/stores/chatNew/messagePreview/ImagePreviewStore"
810
import useChatFileUrls from "@/opensource/hooks/chat/useChatFileUrls"
911
import conversationStore from "@/opensource/stores/chatNew/conversation"
1012
import { observer } from "mobx-react-lite"
11-
import type { PreviewFileInfo } from "@/opensource/services/chat/message/MessageFilePreview"
12-
import NetworkErrorContent from "@/opensource/pages/chatNew/components/ChatMessageList/components/MessageFactory/components/NetworkErrorContent"
13+
import type { ImagePreviewInfo } from "@/types/chat/preview"
1314
import useImageSize from "../../hooks/useImageSize"
1415
import { useStyles } from "./styles"
16+
import { IconPhotoX } from "@tabler/icons-react"
17+
import MagicButton from "@/opensource/components/base/MagicButton"
18+
import MagicIcon from "@/opensource/components/base/MagicIcon"
1519

1620
type HTMLImageElementProps = JSX.IntrinsicElements["img"]
1721

@@ -38,6 +42,10 @@ interface ImageWrapperProps extends HTMLImageElementProps {
3842
fileSize?: number
3943
/** 图片加载中的占位符 */
4044
loader?: (cls?: string) => React.ReactNode
45+
/** 是否正在加载 */
46+
isLoading?: boolean
47+
/** 是否 Error */
48+
isError?: boolean
4149
}
4250

4351
const ImageWrapper = observer((props: ImageWrapperProps) => {
@@ -58,13 +66,15 @@ const ImageWrapper = observer((props: ImageWrapperProps) => {
5866
imgExtension,
5967
fileSize,
6068
loader,
69+
isLoading: loading = false,
70+
isError: isError = false,
6171
...rest
6272
} = props
6373
const { t } = useTranslation("interface")
6474
const { styles, cx } = useStyles()
6575
const { hiddenDetail } = useMessageRenderContext()
6676
const imageRef = useRef<HTMLImageElement>(null)
67-
const [fileInfo, setFileInfo] = useState<PreviewFileInfo>()
77+
const [fileInfo, setFileInfo] = useState<ImagePreviewInfo>()
6878
const isLongImage = useImageSize(fileInfo?.url)
6979

7080
const [error, { setTrue, setFalse }] = useBoolean(false)
@@ -134,6 +144,14 @@ const ImageWrapper = observer((props: ImageWrapperProps) => {
134144
useHDImage,
135145
])
136146

147+
useUpdateEffect(() => {
148+
const { previewInfo, open } = MessageFilePreviewStore
149+
// 如果预览弹窗开启状态, 并且旧文件 id 和当前预览文件 id 相同, 并且使用高清图, 重新设置预览信息
150+
if (open && previewInfo?.fileId === fileInfo?.oldFileId && fileInfo?.useHDImage) {
151+
MessageFilePreviewService.setPreviewInfo(fileInfo)
152+
}
153+
}, [fileInfo, MessageFilePreviewStore.previewInfo])
154+
137155
const handleReloadImage = useMemoizedFn(() => {
138156
reload?.()
139157
setFalse()
@@ -163,15 +181,14 @@ const ImageWrapper = observer((props: ImageWrapperProps) => {
163181
>
164182
<div
165183
className={styles.image}
166-
data-file-info={fileInfoBase64}
167184
// eslint-disable-next-line react/no-danger
168185
dangerouslySetInnerHTML={{ __html: fileInfo?.url }}
169186
/>
170187
</button>
171188
)
172189
}
173190

174-
if (isLoading || !fileInfo?.url) {
191+
if (loading || isLoading || !fileInfo?.url) {
175192
return loader ? (
176193
loader?.(className)
177194
) : (
@@ -213,6 +230,7 @@ const ImageWrapper = observer((props: ImageWrapperProps) => {
213230
isLoading,
214231
isLongImage,
215232
loader,
233+
loading,
216234
onError,
217235
onLoad,
218236
rest,
@@ -228,12 +246,19 @@ const ImageWrapper = observer((props: ImageWrapperProps) => {
228246
return t("chat.message.placeholder.image")
229247
}
230248

231-
if (error) {
249+
if (isError || error) {
232250
return (
233-
<NetworkErrorContent
234-
className={cx(styles.networkError, containerClassName)}
235-
onReload={handleReloadImage}
236-
/>
251+
<Tooltip title={t("chat.message.networkError.reload")}>
252+
<div className={styles.imageLoadError} onClick={handleReloadImage}>
253+
<MagicIcon component={IconPhotoX} size={16} />
254+
{t("chat.message.imageLoadFailed")}
255+
<MagicButton
256+
className="reload-button"
257+
size="small"
258+
onClick={handleReloadImage}
259+
/>
260+
</div>
261+
</Tooltip>
237262
)
238263
}
239264

0 commit comments

Comments
 (0)