提交 912a004e authored 作者: 王鹏飞's avatar 王鹏飞

bug fixes

上级 26a42e11
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -27,7 +27,9 @@ ...@@ -27,7 +27,9 @@
"easy-formula-editor": "^0.0.2-alpha.1", "easy-formula-editor": "^0.0.2-alpha.1",
"echarts": "^5.4.3", "echarts": "^5.4.3",
"evit-gm-crypt": "^1.0.1", "evit-gm-crypt": "^1.0.1",
"file-saver": "^2.0.5",
"highlight.js": "^11.11.1", "highlight.js": "^11.11.1",
"html-docx-js-typescript": "^0.1.5",
"jquery": "^3.7.1", "jquery": "^3.7.1",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"js-md5": "^0.8.3", "js-md5": "^0.8.3",
......
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
overflow: hidden; overflow: hidden;
width: 430px; width: 430px;
border-radius: 30px; border-radius: 30px;
} }
.previee-container { .previee-container {
height: 100%; height: 100%;
...@@ -45,7 +44,7 @@ ...@@ -45,7 +44,7 @@
height: 44px; height: 44px;
line-height: 44px; line-height: 44px;
border-bottom: 1px solid #efefef; border-bottom: 1px solid #efefef;
h2 { h2 {
font-size: 18px; font-size: 18px;
text-align: left; text-align: left;
...@@ -108,19 +107,34 @@ ...@@ -108,19 +107,34 @@
.preview-content-show { .preview-content-show {
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
height: calc(100% - 45px); height: calc(100% - 85px);
}
.preview-page-number {
height: 40px;
line-height: 40px;
text-align: center;
font-size: 14px;
color: #999;
border-top: 1px solid #efefef;
background: #fff;
flex-shrink: 0;
} }
* { * {
line-height: 1.5; line-height: 1.5;
font-family: "黑体"; font-family: '黑体';
} }
.preview-content-html { .preview-content-html {
padding-bottom: 50px; padding-bottom: 50px;
.chapter-practice, .chapter-expand, .chapter-item-section, .chapter-item-header, .chapter-gallery-container { .chapter-practice,
.chapter-expand,
.chapter-item-section,
.chapter-item-header,
.chapter-gallery-container {
margin-top: 15px; margin-top: 15px;
margin-bottom: 15px; margin-bottom: 15px;
&.chapter-expand-inline, &.chapter-gallery-inline { &.chapter-expand-inline,
&.chapter-gallery-inline {
margin-top: 0; margin-top: 0;
margin-bottom: 0; margin-bottom: 0;
margin-top: -3px !important; margin-top: -3px !important;
...@@ -152,7 +166,7 @@ ...@@ -152,7 +166,7 @@
padding: 5px; padding: 5px;
font-size: 18px; font-size: 18px;
} }
div[data-w-e-type=video] { div[data-w-e-type='video'] {
margin: 10px; margin: 10px;
} }
p[data-slate-node]:not(:empty) { p[data-slate-node]:not(:empty) {
...@@ -361,7 +375,6 @@ ...@@ -361,7 +375,6 @@
width: 100%; width: 100%;
} }
p { p {
} }
img { img {
height: auto; height: auto;
...@@ -383,7 +396,10 @@ ...@@ -383,7 +396,10 @@
} }
} }
.chapter-item-tooltip, .chapter-item-link, .chapter-gallery-inline, .chapter-expand-inline { .chapter-item-tooltip,
.chapter-item-link,
.chapter-gallery-inline,
.chapter-expand-inline {
text-indent: 0; text-indent: 0;
svg { svg {
text-indent: 0; text-indent: 0;
...@@ -410,7 +426,7 @@ ...@@ -410,7 +426,7 @@
text-align: center; text-align: center;
padding-top: 40px; padding-top: 40px;
color: #999; color: #999;
font-size: 18px;; font-size: 18px;
} }
.opa { .opa {
position: absolute; position: absolute;
...@@ -485,10 +501,13 @@ ...@@ -485,10 +501,13 @@
width: 100%; width: 100%;
} }
} }
li, dd, dt, blockquote { li,
dd,
dt,
blockquote {
font-size: 18px; font-size: 18px;
font-family: "黑体"; font-family: '黑体';
line-height: 1.5; line-height: 1.5;
margin: 15px 0; margin: 15px 0;
} }
...@@ -656,5 +675,36 @@ ...@@ -656,5 +675,36 @@
height: 100%; height: 100%;
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
.ant-tree .ant-tree-treenode {
position: relative;
// padding-right: 40px;
.ant-tree-node-content-wrapper {
overflow: hidden;
}
}
.tree-node-title {
display: inline-flex;
align-items: center;
width: 100%;
.tree-node-name {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.tree-node-page {
// position: absolute;
// right: 0;
font-size: 12px;
color: #999;
// min-width: 32px;
text-align: right;
background: #f0f0f0;
border-radius: 4px;
padding: 0 6px;
line-height: 20px;
}
}
} }
} }
...@@ -209,7 +209,7 @@ const Examine = () => { ...@@ -209,7 +209,7 @@ const Examine = () => {
}) })
if (data) { if (data) {
if ((data.code && data.code === 3000) || data.code === '3000') { if ((data.code && data.code === 3000) || data.code === '3000') {
navigate('/books/management/list') // navigate('/books/management/list')
return return
} else { } else {
setContentMd5(newMd5) setContentMd5(newMd5)
......
import { asBlob } from 'html-docx-js-typescript'
import { saveAs } from 'file-saver'
import $ from 'jquery'
/**
* 将图片 URL 转为 base64 Data URI
* 优先使用 fetch,失败后尝试 Image + Canvas 方式
*/
async function imgToBase64(src) {
// 方式1:fetch
try {
const res = await fetch(src)
if (res.ok) {
const blob = await res.blob()
return await blobToDataUri(blob)
}
} catch (e) {
console.warn('fetch 图片失败,尝试 canvas 方式:', src, e)
}
// 方式2:Image + Canvas(可绕过部分限制)
try {
return await loadImageAsBase64(src)
} catch (e) {
console.warn('canvas 转换图片失败:', src, e)
}
return null
}
function blobToDataUri(blob) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onloadend = () => resolve(reader.result)
reader.onerror = reject
reader.readAsDataURL(blob)
})
}
function loadImageAsBase64(src) {
return new Promise((resolve, reject) => {
const img = new Image()
img.crossOrigin = 'anonymous'
img.onload = () => {
try {
const canvas = document.createElement('canvas')
canvas.width = img.naturalWidth
canvas.height = img.naturalHeight
const ctx = canvas.getContext('2d')
ctx.drawImage(img, 0, 0)
resolve(canvas.toDataURL('image/png'))
} catch (e) {
reject(e)
}
}
img.onerror = reject
img.src = src
})
}
/**
* 将 DOM 中所有 img 的 src 替换为 base64 Data URI
*/
async function convertImagesToBase64(docEl) {
const imgs = docEl.querySelectorAll('img')
const tasks = Array.from(imgs).map(async (img) => {
const src = img.getAttribute('src')
if (!src || src.startsWith('data:')) return
// 处理相对路径和协议相对路径
let absoluteSrc = src
if (src.startsWith('//')) {
absoluteSrc = window.location.protocol + src
} else if (src.startsWith('/')) {
absoluteSrc = window.location.origin + src
} else if (!src.startsWith('http')) {
absoluteSrc = new URL(src, window.location.href).href
}
const dataUri = await imgToBase64(absoluteSrc)
if (dataUri) {
img.setAttribute('src', dataUri)
} else {
console.warn('图片转 base64 失败,已跳过:', absoluteSrc)
img.remove()
}
})
await Promise.all(tasks)
}
/**
* 使用 html-docx-js-typescript 将 HTML 内容导出为 Word 文档(.docx)
* 图片会自动转为 base64 内嵌到文档中
* @param {string} name - 文件名(不含扩展名)
* @param {string} htmlString - 原始 HTML 字符串
* @param {string[]} removeSelectors - 需要移除的 CSS 选择器列表
*/
export async function exportHtmlToWord(name, htmlString, removeSelectors = []) {
const parser = new DOMParser()
const doc = parser.parseFromString(htmlString, 'text/html')
if (removeSelectors.length) {
$(doc.body).find(removeSelectors.join(', ')).remove()
}
// 将所有图片转为 base64 内嵌
await convertImagesToBase64(doc.body)
// 使用原生 innerHTML 避免 jQuery 序列化可能编码 base64 特殊字符
const htmlContent = doc.body.innerHTML
const fullHtml = `<!DOCTYPE html><html><head><meta charset="utf-8"><style>
@page { size: A4; margin: 2cm; }
body { font-family: SimSun, serif; font-size: 14px; line-height: 1.6; }
table { border-collapse: collapse; width: 100%; }
td, th { border: 1px solid #000; padding: 5px; }
img { max-width: 100%; }
</style></head><body>${htmlContent}</body></html>`
const blob = await asBlob(fullHtml, { orientation: 'portrait' })
saveAs(blob, `${name}.docx`)
}
...@@ -38,7 +38,8 @@ export default defineConfig(() => { ...@@ -38,7 +38,8 @@ export default defineConfig(() => {
// rewrite: (path) => path.replace(/^\/api\/wenku/, '/'), // rewrite: (path) => path.replace(/^\/api\/wenku/, '/'),
// }, // },
'/api': { '/api': {
target: 'https://zijingebook.ezijing.com', // target: 'https://zijingebook.ezijing.com',
target: 'http://localhost:7419',
changeOrigin: true, changeOrigin: true,
secure: false, secure: false,
}, },
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论