Commit b2a8d572 authored by 罗超's avatar 罗超

优化内容

parent a380fcba
...@@ -201,6 +201,7 @@ ...@@ -201,6 +201,7 @@
<!-- 其他页Header --> <!-- 其他页Header -->
<div v-else class="PreviewNotice-header small"> <div v-else class="PreviewNotice-header small">
{{ noticeInfo.tripName }} {{ noticeInfo.tripName }}
<div class="header-line"></div>
</div> </div>
<!-- 渲染当前页的内容块 --> <!-- 渲染当前页的内容块 -->
...@@ -405,7 +406,9 @@ ...@@ -405,7 +406,9 @@
</div> </div>
</template> </template>
<div class="PreviewNotice-footer"></div> <div class="PreviewNotice-footer">
<div class="footer-img"></div>
</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -619,21 +622,13 @@ export default { ...@@ -619,21 +622,13 @@ export default {
try { try {
this.downloadLoading = true; this.downloadLoading = true;
// 等待字体加载
await this.loadFonts();
// 收集所有需要截图的元素 // 收集所有需要截图的元素
const elements = this.collectElements(); const elements = this.collectElements();
console.log('收集到的元素:', elements);
if (elements.length === 0) { if (elements.length === 0) {
this.$message.error('没有找到需要导出的内容'); this.$message.error('没有找到需要导出的内容');
this.downloadLoading = false; this.downloadLoading = false;
return; return;
} }
console.log(`准备截图 ${elements.length} 个页面`);
// 截图所有元素 // 截图所有元素
const images = await this.captureElements(elements); const images = await this.captureElements(elements);
...@@ -657,24 +652,6 @@ export default { ...@@ -657,24 +652,6 @@ export default {
} }
}, },
// 加载字体
async loadFonts() {
try {
await Promise.all([
document.fonts.load('1em SourceHanSerifCN-Regular'),
document.fonts.load('1em SourceHanSerifCN-Bold'),
document.fonts.load('400 1em SourceHanSerifCN-Regular'),
document.fonts.load('700 1em SourceHanSerifCN-Bold'),
document.fonts.load('bold 1em SourceHanSerifCN-Bold')
]);
console.log('字体加载完成');
await new Promise(resolve => setTimeout(resolve, 500));
} catch (error) {
console.warn('字体加载失败:', error);
await new Promise(resolve => setTimeout(resolve, 500));
}
},
// 收集所有需要截图的元素 // 收集所有需要截图的元素
collectElements() { collectElements() {
const elements = []; const elements = [];
...@@ -700,85 +677,6 @@ export default { ...@@ -700,85 +677,6 @@ export default {
return elements; return elements;
}, },
// 将伪元素转换为真实 DOM 元素
convertPseudoElements(element) {
const converted = [];
// 处理所有带有伪元素的节点
const processNode = (node) => {
if (node.nodeType !== 1) return; // 只处理元素节点
const beforeStyle = window.getComputedStyle(node, '::before');
const afterStyle = window.getComputedStyle(node, '::after');
// 处理 ::before
if (beforeStyle && beforeStyle.content && beforeStyle.content !== 'none' && beforeStyle.content !== '""') {
const beforeDiv = document.createElement('div');
beforeDiv.className = '__pseudo-before__';
// 复制样式
this.copyPseudoStyles(beforeStyle, beforeDiv.style);
// 插入到节点开头
node.insertBefore(beforeDiv, node.firstChild);
converted.push({ node, element: beforeDiv, type: 'before' });
}
// 处理 ::after
if (afterStyle && afterStyle.content && afterStyle.content !== 'none' && afterStyle.content !== '""') {
const afterDiv = document.createElement('div');
afterDiv.className = '__pseudo-after__';
// 复制样式
this.copyPseudoStyles(afterStyle, afterDiv.style);
// 插入到节点末尾
node.appendChild(afterDiv);
converted.push({ node, element: afterDiv, type: 'after' });
}
// 递归处理子节点
Array.from(node.children).forEach(child => {
if (!child.className?.includes('__pseudo-')) {
processNode(child);
}
});
};
processNode(element);
return converted;
},
// 复制伪元素样式到真实元素
copyPseudoStyles(computedStyle, targetStyle) {
const importantStyles = [
'width', 'height', 'background', 'backgroundImage', 'backgroundSize',
'backgroundPosition', 'backgroundRepeat', 'position', 'top', 'right',
'bottom', 'left', 'display', 'content', 'transform', 'margin', 'padding'
];
importantStyles.forEach(prop => {
const value = computedStyle.getPropertyValue(prop);
if (value && value !== 'none' && value !== 'auto') {
targetStyle.setProperty(prop, value);
}
});
// 处理 content 属性
if (computedStyle.content && computedStyle.content !== 'none') {
targetStyle.content = computedStyle.content;
}
},
// 移除转换的伪元素
removePseudoElements(converted) {
converted.forEach(({ element }) => {
if (element && element.parentNode) {
element.parentNode.removeChild(element);
}
});
},
// 截图所有元素 // 截图所有元素
async captureElements(elements) { async captureElements(elements) {
const images = []; const images = [];
...@@ -787,10 +685,10 @@ export default { ...@@ -787,10 +685,10 @@ export default {
const { element, name } = elements[i]; const { element, name } = elements[i];
console.log(`正在截图: ${name} (${i + 1}/${elements.length})`); console.log(`正在截图: ${name} (${i + 1}/${elements.length})`);
// 转换伪元素
const convertedPseudos = this.convertPseudoElements(element);
try { try {
// 截图前仅临时禁用可能导致跨域读取错误的第三方样式(如 mapbox)
this.__problemStylesDisabled = this.disableProblematicExternalStyles()
// 临时移除 margin // 临时移除 margin
const originalMargin = element.style.margin; const originalMargin = element.style.margin;
element.style.margin = '0'; element.style.margin = '0';
...@@ -802,69 +700,32 @@ export default { ...@@ -802,69 +700,32 @@ export default {
// 等待一下,确保样式生效 // 等待一下,确保样式生效
await new Promise(resolve => setTimeout(resolve, 50)); await new Promise(resolve => setTimeout(resolve, 50));
const fontEmbedCSS = await htmlToImage.getFontEmbedCSS(element);
// 截图 // 截图
const dataUrl = await htmlToImage.toJpeg(element, { const dataUrl = await htmlToImage.toJpeg(element, {
quality: 0.95, quality: 1,
pixelRatio: 1,
cacheBust: true, cacheBust: true,
skipFonts: false, // 保留字体 // skipFonts: true,
// 过滤掉外部资源,避免 CORS 错误和性能问题 // useCors:true,
filter: (node) => { fontEmbedCSS:fontEmbedCSS
// 排除外部样式表链接
if (node.tagName === 'LINK' && node.rel === 'stylesheet') {
const href = node.href || '';
// 排除所有外部域名的样式表(特别是 mapbox)
if (href.includes('mapbox') ||
(href.startsWith('http') && !href.includes(window.location.hostname))) {
return false;
}
}
// 排除可能引起 CORS 问题的外部资源
if (node.tagName === 'SCRIPT' || node.tagName === 'IFRAME') {
return false;
}
return true;
},
// 忽略 CSS 处理错误,继续生成图片
onclone: (clonedDoc) => {
// 移除可能导致问题的外部样式表
const externalLinks = clonedDoc.querySelectorAll('link[rel="stylesheet"]');
externalLinks.forEach(link => {
const href = link.href || '';
if (href.includes('mapbox') ||
(href.startsWith('http') && !href.includes(window.location.hostname))) {
link.remove();
}
});
}
}); });
// 恢复 margin
element.style.margin = originalMargin; element.style.margin = originalMargin;
// 获取元素尺寸
const rect = element.getBoundingClientRect();
images.push({ images.push({
dataUrl, dataUrl,
width: rect.width, width: 1280,
height: rect.height, height: 1703,
name name
}); });
console.log(`${name} 截图完成 (${rect.width}x${rect.height})`);
// 短暂延迟,避免浏览器卡顿
await new Promise(resolve => setTimeout(resolve, 100)); await new Promise(resolve => setTimeout(resolve, 100));
} catch (error) { } catch (error) {
console.error(`${name} 截图失败:`, error); //throw new Error(`${name} 截图失败`);
throw new Error(`${name} 截图失败`);
} finally { } finally {
// 移除转换的伪元素 // 恢复被禁用的第三方样式
this.removePseudoElements(convertedPseudos); this.restoreProblematicExternalStyles()
} }
} }
...@@ -1504,13 +1365,35 @@ export default { ...@@ -1504,13 +1365,35 @@ export default {
this.$message.error(res.data.message) this.$message.error(res.data.message)
} }
}) })
},
// 仅禁用会触发跨域 cssRules 读取错误的外部样式(如 mapbox)
disableProblematicExternalStyles() {
const disabled = []
const links = Array.from(document.querySelectorAll('link[rel="stylesheet"]'))
links.forEach(link => {
const href = link && link.href ? String(link.href) : ''
// 精确匹配 mapbox 样式来源
const isMapbox = /(^https?:\/\/)?api\.mapbox\.com\/mapbox-gl-js\//.test(href)
if (isMapbox && !link.disabled) {
link.disabled = true
disabled.push(link)
}
})
return disabled
},
restoreProblematicExternalStyles() {
if (!this.__problemStylesDisabled || this.__problemStylesDisabled.length === 0) return
this.__problemStylesDisabled.forEach(link => {
if (link) link.disabled = false
})
this.__problemStylesDisabled = []
} }
} }
} }
</script> </script>
<style> <style>
@font-face { /* @font-face {
font-family: 'SourceHanSerifCN-Regular'; font-family: 'SourceHanSerifCN-Regular';
src: url('https://im.oytour.com/tripfont/SourceHanSerifCN-Regular.otf') format(opentype); src: url('https://im.oytour.com/tripfont/SourceHanSerifCN-Regular.otf') format(opentype);
} }
...@@ -1518,6 +1401,22 @@ export default { ...@@ -1518,6 +1401,22 @@ export default {
@font-face { @font-face {
font-family: 'SourceHanSerifCN-Bold'; font-family: 'SourceHanSerifCN-Bold';
src: url('https://im.oytour.com/tripfont/SourceHanSerifCN-Bold.otf') format(opentype); src: url('https://im.oytour.com/tripfont/SourceHanSerifCN-Bold.otf') format(opentype);
} */
@font-face {
font-family: 'SourceHanSerifCN';
src: url('https://im.oytour.com/tripfont/SourceHanSerifCN-Regular.otf') format(opentype);
font-weight: 400;
font-style: normal;
font-display: swap;
}
/* Bold */
@font-face {
font-family: 'SourceHanSerifCN';
src: url('https://im.oytour.com/tripfont/SourceHanSerifCN-Bold.otf') format(opentype);
font-weight: 700;
font-style: normal;
font-display: swap;
} }
.preview-notice-tools{ .preview-notice-tools{
height: 54px; height: 54px;
...@@ -1540,7 +1439,7 @@ export default { ...@@ -1540,7 +1439,7 @@ export default {
background-size: 100% 100%; background-size: 100% 100%;
height: 1703px; height: 1703px;
position: relative; position: relative;
font-family: 'SourceHanSerifCN-Regular'; font-family: 'SourceHanSerifCN';
/* padding-bottom: 57px; */ /* padding-bottom: 57px; */
overflow: hidden; overflow: hidden;
box-sizing: border-box; box-sizing: border-box;
...@@ -1550,6 +1449,10 @@ export default { ...@@ -1550,6 +1449,10 @@ export default {
.PreviewNotice * { .PreviewNotice * {
line-height: 1; line-height: 1;
} }
.cover-page *,
.PreviewNotice * {
font-family: 'SourceHanSerifCN' !important;
}
.cover-page { .cover-page {
background: url('https://im.oytour.com/tripImg/638957870917977223.jpg') no-repeat 0% 0%; background: url('https://im.oytour.com/tripImg/638957870917977223.jpg') no-repeat 0% 0%;
...@@ -1560,7 +1463,7 @@ export default { ...@@ -1560,7 +1463,7 @@ export default {
font-weight: 800; font-weight: 800;
font-size: 104px; font-size: 104px;
color: #101519; color: #101519;
font-family: 'SourceHanSerifCN-Bold'; /* font-family: 'SourceHanSerifCN-Bold'; */
} }
.cover-page .qr-code { .cover-page .qr-code {
...@@ -1640,7 +1543,8 @@ export default { ...@@ -1640,7 +1543,8 @@ export default {
.PreviewNotice .trip-list .date-td { .PreviewNotice .trip-list .date-td {
color: #0F2350; color: #0F2350;
font-family: 'SourceHanSerifCN-Bold'; font-weight: bold;
/* font-family: 'SourceHanSerifCN-Bold'; */
} }
.PreviewNotice .trip-list .date-td .date-no { .PreviewNotice .trip-list .date-td .date-no {
...@@ -1661,7 +1565,7 @@ export default { ...@@ -1661,7 +1565,7 @@ export default {
font-weight: 400; font-weight: 400;
font-size: 18px; font-size: 18px;
color: #000000; color: #000000;
font-family: 'SourceHanSerifCN-Regular'; /* font-family: 'SourceHanSerifCN-Regular'; */
} }
.PreviewNotice .trip-list td:last-child { .PreviewNotice .trip-list td:last-child {
...@@ -1669,7 +1573,8 @@ export default { ...@@ -1669,7 +1573,8 @@ export default {
} }
.PreviewNotice .title { .PreviewNotice .title {
font-family: 'SourceHanSerifCN-Bold'; /* font-family: 'SourceHanSerifCN-Bold'; */
font-weight: bold;
} }
.PreviewNotice .tc-no { .PreviewNotice .tc-no {
...@@ -1697,7 +1602,8 @@ export default { ...@@ -1697,7 +1602,8 @@ export default {
color: #FFFFFF; color: #FFFFFF;
margin-top: 50px; margin-top: 50px;
text-align: center; text-align: center;
font-family: 'SourceHanSerifCN-Bold'; /* font-family: 'SourceHanSerifCN-Bold'; */
font-weight: bold;
} }
.PreviewNotice .split-line { .PreviewNotice .split-line {
...@@ -1749,7 +1655,7 @@ export default { ...@@ -1749,7 +1655,7 @@ export default {
margin-bottom: 39px; margin-bottom: 39px;
} }
.PreviewNotice-header.small::before { .PreviewNotice-header.small .header-line {
background: url('https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Upload/Goods/638956940819119044.png') no-repeat center center; background: url('https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Upload/Goods/638956940819119044.png') no-repeat center center;
background-size: 100% 100%; background-size: 100% 100%;
position: absolute; position: absolute;
...@@ -1758,7 +1664,6 @@ export default { ...@@ -1758,7 +1664,6 @@ export default {
width: 444px; width: 444px;
height: 12px; height: 12px;
display: inline-block; display: inline-block;
content: ' ';
} }
.PreviewNotice .base-info { .PreviewNotice .base-info {
...@@ -1793,14 +1698,15 @@ export default { ...@@ -1793,14 +1698,15 @@ export default {
.PreviewNotice .base-info .base-info-item .info-content .info-title { .PreviewNotice .base-info .base-info-item .info-content .info-title {
font-size: 28px; font-size: 28px;
color: #0F2350; color: #0F2350;
font-family: 'SourceHanSerifCN-Bold'; /* font-family: 'SourceHanSerifCN-Bold'; */
font-weight: bold;
} }
.PreviewNotice .base-info .base-info-item .info-content .info-content { .PreviewNotice .base-info .base-info-item .info-content .info-content {
font-weight: 400; font-weight: 400;
font-size: 26px; font-size: 26px;
color: #000000; color: #000000;
font-family: 'SourceHanSerifCN-Regular'; /* font-family: 'SourceHanSerifCN-Regular'; */
margin-top: 14px; margin-top: 14px;
} }
...@@ -1856,7 +1762,8 @@ export default { ...@@ -1856,7 +1762,8 @@ export default {
font-weight: 800; font-weight: 800;
font-size: 32px; font-size: 32px;
color: #FFFFFF; color: #FFFFFF;
font-family: 'SourceHanSerifCN-Bold'; /* font-family: 'SourceHanSerifCN-Bold'; */
font-weight: bold;
display: inline-block; display: inline-block;
/* margin-bottom: 20px; */ /* margin-bottom: 20px; */
} }
...@@ -1865,7 +1772,8 @@ export default { ...@@ -1865,7 +1772,8 @@ export default {
font-weight: 800; font-weight: 800;
font-size: 28px; font-size: 28px;
color: #0F2350; color: #0F2350;
font-family: 'SourceHanSerifCN-Bold'; /* font-family: 'SourceHanSerifCN-Bold'; */
font-weight: bold;
padding: 32px 0px 20px 0px; padding: 32px 0px 20px 0px;
} }
...@@ -1875,7 +1783,7 @@ export default { ...@@ -1875,7 +1783,7 @@ export default {
color: #000000; color: #000000;
line-height: 42px; line-height: 42px;
padding-bottom:10px; padding-bottom:10px;
font-family: 'SourceHanSerifCN-Regular'; /* font-family: 'SourceHanSerifCN-Regular'; */
} }
/* 图片容器样式 */ /* 图片容器样式 */
...@@ -1911,9 +1819,7 @@ export default { ...@@ -1911,9 +1819,7 @@ export default {
right: 0; right: 0;
} }
.PreviewNotice-footer::after { .PreviewNotice-footer .footer-img {
content: ' ';
display: block;
width: 612px; width: 612px;
height: 34px; height: 34px;
background: url('https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Upload/Goods/638956342477463092.png') no-repeat center center; background: url('https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Upload/Goods/638956342477463092.png') no-repeat center center;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment