mirror of
https://gitee.com/ulthon/ulthon_information.git
synced 2026-07-09 03:22:52 +08:00
feat(phone-image): 增加翻页预览与无封面图排版样式
- 为手机截图生成器添加翻页功能,支持在生成前预览各页内容 - 增加无封面图时的排版样式,使用装饰线条和居中布局 - 改进图片处理逻辑,清除内联样式并展平嵌套包装元素 - 修复 models.dev 同步接口,支持 GET 请求获取缓存数据 - 优化网络请求,添加直连失败后的本地代理重试机制
This commit is contained in:
@@ -113,6 +113,19 @@ var PhoneImageEngine = (function () {
|
||||
html = html.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '');
|
||||
// 清除空段落
|
||||
html = html.replace(/<p[^>]*>\s*<\/p>/gi, '');
|
||||
|
||||
// 处理图片: 清除内联样式, 强制 max-width:100%
|
||||
html = html.replace(/<img([^>]*?)>/gi, function (match, attrs) {
|
||||
// 移除 style, width, height 内联属性
|
||||
attrs = attrs.replace(/\s*style\s*=\s*"[^"]*"/gi, '');
|
||||
attrs = attrs.replace(/\s*style\s*=\s*'[^']*'/gi, '');
|
||||
attrs = attrs.replace(/\s*width\s*=\s*"[^"]*"/gi, '');
|
||||
attrs = attrs.replace(/\s*width\s*=\s*'[^']*'/gi, '');
|
||||
attrs = attrs.replace(/\s*height\s*=\s*"[^"]*"/gi, '');
|
||||
attrs = attrs.replace(/\s*height\s*=\s*'[^']*'/gi, '');
|
||||
return '<img' + attrs + ' style="max-width:100%;height:auto;display:block;margin:10px 0;">';
|
||||
});
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
@@ -125,6 +138,29 @@ var PhoneImageEngine = (function () {
|
||||
if (!html) return blocks;
|
||||
|
||||
var $temp = $('<div>').html(html);
|
||||
|
||||
// 展平嵌套的包装元素 (div, section, article, main, header, footer)
|
||||
// 将其内部内容提取为直接子元素
|
||||
var wrapperTags = ['div', 'section', 'article', 'main', 'header', 'footer', 'span'];
|
||||
var changed = true;
|
||||
var maxIterations = 10;
|
||||
while (changed && maxIterations > 0) {
|
||||
changed = false;
|
||||
maxIterations--;
|
||||
$temp.children().each(function () {
|
||||
var $el = $(this);
|
||||
var tagName = $el.prop('tagName').toLowerCase();
|
||||
if ($.inArray(tagName, wrapperTags) !== -1) {
|
||||
// 将此包装元素的子内容替换自身
|
||||
var $children = $el.children();
|
||||
if ($children.length > 0) {
|
||||
$el.replaceWith($children);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var children = $temp.children();
|
||||
|
||||
if (children.length === 0) {
|
||||
@@ -161,6 +197,7 @@ var PhoneImageEngine = (function () {
|
||||
case 'h4':
|
||||
case 'h5':
|
||||
case 'h6':
|
||||
block.type = tagName;
|
||||
block.estimatedHeight = estimateHeadingHeight(tagName, $el.text());
|
||||
break;
|
||||
case 'img':
|
||||
@@ -380,34 +417,73 @@ var PhoneImageEngine = (function () {
|
||||
|
||||
// ===== 页面HTML生成 =====
|
||||
|
||||
/**
|
||||
* 检查是否有有效的封面图(排除默认头像占位图)
|
||||
*/
|
||||
function hasValidPoster() {
|
||||
if (!postData.poster) return false;
|
||||
// 排除默认头像占位图
|
||||
var defaultPatterns = ['/static/images/avatar.png', '/static/images/avatar.jpeg', '/static/images/avatar.jpg'];
|
||||
for (var i = 0; i < defaultPatterns.length; i++) {
|
||||
if (postData.poster.indexOf(defaultPatterns[i]) !== -1) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成封面页HTML
|
||||
*/
|
||||
function generateCoverPage(sizeConfig) {
|
||||
var html = '<div class="phone-image-page page-cover" style="width:' +
|
||||
sizeConfig.width + 'px;height:' + sizeConfig.height + 'px;">';
|
||||
var hasCover = hasValidPoster();
|
||||
var html = '<div class="phone-image-page page-cover';
|
||||
if (hasCover) {
|
||||
html += ' has-cover-image';
|
||||
} else {
|
||||
html += ' no-cover-image';
|
||||
}
|
||||
html += '" style="width:' + sizeConfig.width + 'px;height:' + sizeConfig.height + 'px;">';
|
||||
|
||||
if (postData.poster) {
|
||||
if (hasCover) {
|
||||
html += '<img class="cover-image" src="' + postData.poster + '" alt="">';
|
||||
html += '<div class="cover-title">' + escapeHtml(postData.title) + '</div>';
|
||||
if (postData.desc) {
|
||||
html += '<div class="cover-subtitle">' + escapeHtml(postData.desc) + '</div>';
|
||||
}
|
||||
html += '<div class="cover-meta">';
|
||||
if (postData.category_name) {
|
||||
html += escapeHtml(postData.category_name) + ' | ';
|
||||
}
|
||||
if (postData.author_name) {
|
||||
html += escapeHtml(postData.author_name) + ' | ';
|
||||
}
|
||||
if (postData.create_time) {
|
||||
html += postData.create_time;
|
||||
}
|
||||
html += '</div>';
|
||||
} else {
|
||||
// 无封面图: 大标题+摘要+装饰线条排版
|
||||
html += '<div class="cover-decor-line cover-decor-top"></div>';
|
||||
html += '<div class="cover-no-img-content">';
|
||||
html += '<div class="cover-no-img-title">' + escapeHtml(postData.title) + '</div>';
|
||||
html += '<div class="cover-decor-divider"></div>';
|
||||
if (postData.desc) {
|
||||
html += '<div class="cover-no-img-desc">' + escapeHtml(postData.desc) + '</div>';
|
||||
}
|
||||
html += '<div class="cover-no-img-meta">';
|
||||
if (postData.category_name) {
|
||||
html += '<span>' + escapeHtml(postData.category_name) + '</span>';
|
||||
}
|
||||
if (postData.author_name) {
|
||||
html += '<span>' + escapeHtml(postData.author_name) + '</span>';
|
||||
}
|
||||
if (postData.create_time) {
|
||||
html += '<span>' + postData.create_time + '</span>';
|
||||
}
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
html += '<div class="cover-decor-line cover-decor-bottom"></div>';
|
||||
}
|
||||
|
||||
html += '<div class="cover-title">' + escapeHtml(postData.title) + '</div>';
|
||||
|
||||
if (postData.desc) {
|
||||
html += '<div class="cover-subtitle">' + escapeHtml(postData.desc) + '</div>';
|
||||
}
|
||||
|
||||
html += '<div class="cover-meta">';
|
||||
if (postData.category_name) {
|
||||
html += escapeHtml(postData.category_name) + ' | ';
|
||||
}
|
||||
if (postData.author_name) {
|
||||
html += escapeHtml(postData.author_name) + ' | ';
|
||||
}
|
||||
if (postData.create_time) {
|
||||
html += postData.create_time;
|
||||
}
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
return { type: 'cover', html: html };
|
||||
@@ -470,6 +546,9 @@ var PhoneImageEngine = (function () {
|
||||
|
||||
// ===== DOM渲染 =====
|
||||
|
||||
// 当前预览页码 (0-based)
|
||||
var currentPreviewPage = 0;
|
||||
|
||||
/**
|
||||
* 渲染分页结果到DOM
|
||||
*/
|
||||
@@ -493,6 +572,55 @@ var PhoneImageEngine = (function () {
|
||||
for (var i = 0; i < pages.length; i++) {
|
||||
$container.append(pages[i].html);
|
||||
}
|
||||
|
||||
// 确保当前页码有效
|
||||
if (currentPreviewPage >= pages.length) {
|
||||
currentPreviewPage = Math.max(0, pages.length - 1);
|
||||
}
|
||||
|
||||
// 显示当前页, 隐藏其他页
|
||||
showPreviewPage(currentPreviewPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示指定预览页
|
||||
* @param {number} index 页码(0-based)
|
||||
*/
|
||||
function showPreviewPage(index) {
|
||||
if (!$container || !$container.length) return;
|
||||
var $allPages = $container.find('.phone-image-page');
|
||||
$allPages.hide();
|
||||
if (index >= 0 && index < $allPages.length) {
|
||||
$allPages.eq(index).show();
|
||||
currentPreviewPage = index;
|
||||
}
|
||||
// 更新页码显示
|
||||
$container.trigger('pageChange', [currentPreviewPage, pages.length]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下一页
|
||||
*/
|
||||
function nextPage() {
|
||||
if (currentPreviewPage < pages.length - 1) {
|
||||
showPreviewPage(currentPreviewPage + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上一页
|
||||
*/
|
||||
function prevPage() {
|
||||
if (currentPreviewPage > 0) {
|
||||
showPreviewPage(currentPreviewPage - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前预览页码
|
||||
*/
|
||||
function getCurrentPageIndex() {
|
||||
return currentPreviewPage;
|
||||
}
|
||||
|
||||
// ===== 图片生成 =====
|
||||
@@ -512,24 +640,31 @@ var PhoneImageEngine = (function () {
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
// 截图时需要所有页面都显示
|
||||
$pages.show();
|
||||
|
||||
var index = 0;
|
||||
var total = $pages.length;
|
||||
|
||||
function captureNext() {
|
||||
if (index >= total) {
|
||||
if (onProgress) onProgress(total, total, null);
|
||||
// 恢复单页显示
|
||||
showPreviewPage(currentPreviewPage);
|
||||
deferred.resolve(canvases);
|
||||
return;
|
||||
}
|
||||
|
||||
var $page = $($pages[index]);
|
||||
// 隐藏其他页, 只显示当前要截图的页
|
||||
$pages.hide();
|
||||
$pages.eq(index).show();
|
||||
|
||||
html2canvas($page[0], {
|
||||
html2canvas($pages.eq(index)[0], {
|
||||
scale: 2,
|
||||
useCORS: true,
|
||||
backgroundColor: '#ffffff',
|
||||
width: $page.outerWidth(),
|
||||
height: $page.outerHeight(),
|
||||
width: $pages.eq(index).outerWidth(),
|
||||
height: $pages.eq(index).outerHeight(),
|
||||
logging: false
|
||||
}).then(function (canvas) {
|
||||
canvases.push(canvas);
|
||||
@@ -537,6 +672,8 @@ var PhoneImageEngine = (function () {
|
||||
if (onProgress) onProgress(index, total, canvas);
|
||||
captureNext();
|
||||
}).catch(function (err) {
|
||||
// 恢复单页显示
|
||||
showPreviewPage(currentPreviewPage);
|
||||
deferred.reject('截图失败(第' + (index + 1) + '页): ' + err);
|
||||
});
|
||||
}
|
||||
@@ -731,6 +868,10 @@ var PhoneImageEngine = (function () {
|
||||
getPages: getPages,
|
||||
applyAiRecommendation: applyAiRecommendation,
|
||||
applyAiContent: applyAiContent,
|
||||
restoreOriginalContent: restoreOriginalContent
|
||||
restoreOriginalContent: restoreOriginalContent,
|
||||
nextPage: nextPage,
|
||||
prevPage: prevPage,
|
||||
showPreviewPage: showPreviewPage,
|
||||
getCurrentPageIndex: getCurrentPageIndex
|
||||
};
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user