mirror of
https://gitee.com/ulthon/ulthon_information.git
synced 2026-07-01 16:22:49 +08:00
feat(output_view): 导出页面重构 - 长图卡片化展示、缩略图增大、预览优化、纯图片页原图保存
- output_view.html: 长图改为固定高度卡片(70px),Blob URL查看,缩略图minmax(280px,1fr), 竖图预览优先填充视口高度,下载功能完整保留 - phone-image.js: renderPureImageToCanvas()使用naturalWidth/naturalHeight保持原图分辨率, 新增长图生成和保存功能 - Post.php: 新增outputView()方法提供导出页面渲染数据 - PhoneImage.php: 图片数据改为DB存储,新增saveLongImage()方法 - phone_image.html: 添加导出页面入口按钮 - 新增数据库迁移: post_output_file表添加image_data字段
This commit is contained in:
@@ -379,6 +379,7 @@ class Post extends Common
|
||||
View::assign('post', $model_post);
|
||||
View::assign('layoutContentHtml', $layoutContentHtml);
|
||||
View::assign('layoutConfig', $layoutConfig);
|
||||
View::assign('lastOutputId', $postOutput ? $postOutput->id : 0);
|
||||
return View::fetch();
|
||||
}
|
||||
|
||||
@@ -431,6 +432,12 @@ class Post extends Common
|
||||
$phoneImage->savePageImage($output->id, $index + 1, $pageData);
|
||||
}
|
||||
|
||||
// 保存长图(如果有)
|
||||
$longImage = $data['long_image'] ?? '';
|
||||
if (!empty($longImage)) {
|
||||
$phoneImage->saveLongImage($output->id, $longImage);
|
||||
}
|
||||
|
||||
$phoneImage->completeOutput($output->id, count($pages));
|
||||
|
||||
return json(['code' => 0, 'msg' => '保存成功', 'data' => ['output_id' => $output->id]]);
|
||||
@@ -580,6 +587,60 @@ class Post extends Common
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出查看页面
|
||||
*/
|
||||
public function outputView($id)
|
||||
{
|
||||
$output = \app\model\PostOutput::find((int) $id);
|
||||
if (empty($output)) {
|
||||
$this->error('输出记录不存在');
|
||||
}
|
||||
|
||||
$post = ModelPost::find($output->post_id);
|
||||
if (empty($post)) {
|
||||
$this->error('文章不存在');
|
||||
}
|
||||
|
||||
$allFiles = \app\model\PostOutputFile::where('output_id', (int) $id)
|
||||
->order('page', 'asc')
|
||||
->select();
|
||||
|
||||
// 分离长图和分页
|
||||
$longImage = null;
|
||||
$pages = [];
|
||||
foreach ($allFiles as $file) {
|
||||
$item = [
|
||||
'id' => $file->id,
|
||||
'page' => $file->page,
|
||||
'file_url' => $file->file_url,
|
||||
'width' => $file->width,
|
||||
'height' => $file->height,
|
||||
'image_src' => '',
|
||||
];
|
||||
// 优先使用 image_data (data URI)
|
||||
if (!empty($file->image_data)) {
|
||||
$item['image_src'] = 'data:image/jpeg;base64,' . $file->image_data;
|
||||
} elseif (!empty($file->file_url)) {
|
||||
$item['image_src'] = $file->file_url;
|
||||
}
|
||||
|
||||
if ($file->page == 0) {
|
||||
$longImage = $item;
|
||||
} else {
|
||||
$pages[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
View::assign('output', $output);
|
||||
View::assign('post', $post);
|
||||
View::assign('longImage', $longImage);
|
||||
View::assign('pages', $pages);
|
||||
View::assign('downloadZipUrl', url('post/downloadPostOutputZip', ['id' => $id]));
|
||||
|
||||
return View::fetch('post/output_view');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取输出文件列表(AJAX)
|
||||
*/
|
||||
@@ -607,6 +668,7 @@ class Post extends Common
|
||||
'file_size' => $file->file_size,
|
||||
'width' => $file->width,
|
||||
'height' => $file->height,
|
||||
'image_data' => $file->image_data ?: null,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -70,40 +70,69 @@ class PhoneImage implements PostOutputManagerInterface
|
||||
*/
|
||||
public function savePageImage(int $outputId, int $page, string $imageData)
|
||||
{
|
||||
$imageData = str_replace('data:image/jpeg;base64,', '', $imageData);
|
||||
$imageData = str_replace('data:image/png;base64,', '', $imageData);
|
||||
$imageData = str_replace(' ', '+', $imageData);
|
||||
$decoded = base64_decode($imageData);
|
||||
// 保留原始base64用于存储
|
||||
$rawBase64 = str_replace('data:image/jpeg;base64,', '', $imageData);
|
||||
$rawBase64 = str_replace('data:image/png;base64,', '', $rawBase64);
|
||||
$rawBase64 = str_replace(' ', '+', $rawBase64);
|
||||
$decoded = base64_decode($rawBase64);
|
||||
|
||||
if ($decoded === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$dateDir = date('Ymd');
|
||||
$relativeDir = '/upload/post_output/' . $dateDir;
|
||||
$fileName = $outputId . '_' . $page . '.jpg';
|
||||
$relativePath = $relativeDir . '/' . $fileName;
|
||||
$fullDir = App::getRootPath() . '/public' . $relativeDir;
|
||||
$fullPath = $fullDir . '/' . $fileName;
|
||||
|
||||
if (!is_dir($fullDir)) {
|
||||
mkdir($fullDir, 0777, true);
|
||||
}
|
||||
|
||||
file_put_contents($fullPath, $decoded);
|
||||
|
||||
$imageInfo = getimagesize($fullPath);
|
||||
$width = $imageInfo[0] ?? 0;
|
||||
$height = $imageInfo[1] ?? 0;
|
||||
$imageInfo = @getimagesizefromstring($decoded);
|
||||
$width = is_array($imageInfo) ? $imageInfo[0] : 0;
|
||||
$height = is_array($imageInfo) ? $imageInfo[1] : 0;
|
||||
|
||||
$fileRecord = PostOutputFile::create([
|
||||
'output_id' => $outputId,
|
||||
'page' => $page,
|
||||
'file_path' => $relativePath,
|
||||
'file_url' => $relativePath,
|
||||
'file_path' => '',
|
||||
'file_url' => '',
|
||||
'file_size' => strlen($decoded),
|
||||
'width' => $width,
|
||||
'height' => $height,
|
||||
'image_data' => $rawBase64,
|
||||
]);
|
||||
|
||||
return $fileRecord;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存长图
|
||||
* @param int $outputId 输出记录ID
|
||||
* @param string $imageData base64编码的长图数据
|
||||
* @return PostOutputFile|false
|
||||
*/
|
||||
public function saveLongImage(int $outputId, string $imageData)
|
||||
{
|
||||
$rawBase64 = str_replace('data:image/jpeg;base64,', '', $imageData);
|
||||
$rawBase64 = str_replace('data:image/png;base64,', '', $rawBase64);
|
||||
$rawBase64 = str_replace(' ', '+', $rawBase64);
|
||||
$decoded = base64_decode($rawBase64);
|
||||
|
||||
if ($decoded === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$imageInfo = @getimagesizefromstring($decoded);
|
||||
$width = is_array($imageInfo) ? $imageInfo[0] : 0;
|
||||
$height = is_array($imageInfo) ? $imageInfo[1] : 0;
|
||||
|
||||
// 先删除该output_id下已有的长图(page=0)
|
||||
PostOutputFile::where('output_id', $outputId)
|
||||
->where('page', 0)
|
||||
->delete();
|
||||
|
||||
$fileRecord = PostOutputFile::create([
|
||||
'output_id' => $outputId,
|
||||
'page' => 0,
|
||||
'file_path' => '',
|
||||
'file_url' => '',
|
||||
'file_size' => strlen($decoded),
|
||||
'width' => $width,
|
||||
'height' => $height,
|
||||
'image_data' => $rawBase64,
|
||||
]);
|
||||
|
||||
return $fileRecord;
|
||||
@@ -137,22 +166,42 @@ class PhoneImage implements PostOutputManagerInterface
|
||||
|
||||
$zipFileName = 'post_output_' . $outputId . '.zip';
|
||||
$zipPath = $tempDir . '/' . $zipFileName;
|
||||
$tempFiles = [];
|
||||
|
||||
$zip = new \ZipArchive();
|
||||
if ($zip->open($zipPath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) !== true) {
|
||||
throw new \Exception('无法创建ZIP文件');
|
||||
}
|
||||
try {
|
||||
$zip = new \ZipArchive();
|
||||
if ($zip->open($zipPath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) !== true) {
|
||||
throw new \Exception('无法创建ZIP文件');
|
||||
}
|
||||
|
||||
foreach ($files as $file) {
|
||||
$filePath = App::getRootPath() . '/public' . $file->file_path;
|
||||
if (file_exists($filePath)) {
|
||||
foreach ($files as $file) {
|
||||
$pageName = str_pad((string) $file->page, 2, '0', STR_PAD_LEFT) . '.jpg';
|
||||
$zip->addFile($filePath, $pageName);
|
||||
|
||||
if (!empty($file->image_data)) {
|
||||
$decoded = base64_decode($file->image_data);
|
||||
if ($decoded !== false) {
|
||||
$tempFilePath = $tempDir . '/page_' . $file->page . '_' . $outputId . '.jpg';
|
||||
file_put_contents($tempFilePath, $decoded);
|
||||
$tempFiles[] = $tempFilePath;
|
||||
$zip->addFile($tempFilePath, $pageName);
|
||||
}
|
||||
} else {
|
||||
$filePath = App::getRootPath() . '/public' . $file->file_path;
|
||||
if (file_exists($filePath)) {
|
||||
$zip->addFile($filePath, $pageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$zip->close();
|
||||
} finally {
|
||||
foreach ($tempFiles as $tempFile) {
|
||||
if (file_exists($tempFile)) {
|
||||
@unlink($tempFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$zip->close();
|
||||
|
||||
return $zipPath;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user