追加功能 #486
v4.0: Create excel+pdf library
Added by Xihua Fan 3 months ago.
Updated 19 days ago.
Target version:
IT: Easytryck (Sweden) - v4.0
Description
Background
- 需要使用第三方库实现Excel编辑保存 + PDF保存
Task Details
v4 coding standard:
- Git提交
#xxx(redmine number): xxx(redmine title) - xxx(任意:补充内容)
- 代码规范
2.1: 结构:Public -> Protected -> Private
2.2: 其他代码规范同SBX
- MVCL的v3/v4物理分割
3.1: v3/v4的代码分为两个文件,比如: order.php, order_v3.php
3.2: system也分为两个文件,暂时只有一个user_v3
- Note: front的$this->user在v4中会替换为$this->customer, 即v4中需要清除$this->user
3.3: 代码中,区分v3/v4的调用,比如:new User_V3
- 前台代码
twig, js, css (js, css尽量写在单独的css文件中)
- 后台代码
MVCL (L:en,cn)
- 注释
- 类名:
/**
* xxx
*
* @copyright RedBlue-OTS 2024
* @version v4
*
*/
- 函数名:参数类型 + 返回值类型
/**
* xxx
*
* @param xxx $xxx
* @param xxx $xxx
* @return xxx
*/
Output
Others
Output(2025/09/19) 居家 + Output(2025/09/15 - 2025/09/16) 九亭 + Output(2025/09/12 居家 - 2025/09/13 九亭)
报关资料
- 利用php第三方库作为实现报关资料预览和保存的技术支撑:
- PhpSpreadsheet
- mPDF
- 封装Excel操作类:PhpExcel 提供对外接口
- mPdf 需要一个临时目录,存储图片和字体的缓存文件
- DIR_DOWNLOAD .'custom_declaration/tmp'
- 模板存储路径:
- DIR_DOWNLOAD . custom_declaration/templates/xxxx
- 实体文件存储路径:
- DIR_DOWNLOAD .'custom_declaration/{year}/{20250916 瑞典报关 DHL2504662996}/xxxx
Todo:
如何定位电子章的位置(多页情况下) - 转niko #484
已经在下一次提交中解决,参考以下历史记录
- error.log - 转 niko #484
2025-09-16 11:17:15 - PHP Warning: Undefined array key 5 in D:\Work\Easytryck\06-Development\ots4.0-web\web\system\library\PHPOffice\vendor\mpdf\mpdf\src\Mpdf.php on line 20724
2025-09-16 11:17:15 - PHP Warning: Undefined array key 6 in D:\Work\Easytryck\06-Development\ots4.0-web\web\system\library\PHPOffice\vendor\mpdf\mpdf\src\Mpdf.php on line 20724
不确定具体怎么解决的(好像只发现在local),线上暂时没有发现类似错误
- Status changed from 进行中 to 已关闭
- % Done changed from 40 to 100
- Status changed from 已关闭 to 进行中
- % Done changed from 100 to 80
- Status changed from 进行中 to 已关闭
- % Done changed from 80 to 100
- Status changed from 已关闭 to 进行中
- % Done changed from 100 to 90
Outupt(2025/12/03) 居家 + Outupt(2025/12/01 ~ 2025/12/02) 九亭
- 修复 水印图片位置不准确的bug
- Old:使用excel 动态累计计算单元行的高度,跟A4 297mm 对比,确定图片的位置。
该方案,存在一些统计误差(比如插入行内容超过默认高度,没有动态setHeight),现在已全部废弃
- New: 使用mpdf 最后一页的高度,动态计算图片y轴坐标位置
如果 contentHeight > imageHeight => y轴坐标 = contentHeight + topMargin - imageHeight
如果 contentHeight < imageHeight => y轴坐标 = topMargin
- 解决footer部永远保持在底部。
- 思路:当产生分页时,在footer顶部插入一个空行,空行高度 = 最后一页剩余可用高度
- 遇到一些问题:
- 如何标记footer部分
- 弯路:在excel模板footer部第一个单元格添加注释 - 注释内容在mpdf生成html时,不生成
- 弯路:通过PhpSpreadsheet 针对footer部第一个单元格添加额外的class/属性 - 不能添加html属性,这阶段它还不是html,没有属性这一说,只能进行excel的相关操作
- 弯路:在组装模板数据时,在footer部找一个空白单元格。插入一个tag: {fixed_footer} -(缺点:需要在生成pdf前,将其移除。后面发现添加了tag,影响数据原始高度,高度计算不准,导致再次移除tag后,位置定位有偏差)
- 选用:在phpexcel.php类中维护一个变量:$properties 这里存储各个sheet对应的FixedfooterRow,在渲染pdf时,传递给MpdfWriter类
- 通过标记分割html
- 弯路:寻求AI提供正则。尝试多次才有当前的正确匹配结果。
- 添加空行:
- 弯路:添加多个空行,空行高度 = 可用高度/单独空行的高度。(单独空行的高度 = 单独渲染一个tr模板的高度)
- 选用:添加一个空行,空行高度 = 可用高度
- 可用高度计算不准( 70%时间耗在这里 )
- 弯路:可用高度 = 整页高度 - 内容高度 - 页眉 - 页脚。 这个公式一定没错,毕竟销售合同分毫不差。认定公式没有问题。
- 弯路:同一套代码,Invoice/Pcaking list 有些许偏差,销售合同分毫不差。一直找不到原因 。
- 弯路:发现销售合同缩放100%,尝试将Invoice缩放改为100%,定位分毫不差。 - 发现是scale的原因。
- 弯路:输出打印区域/非打印区域的高度 - 发现页眉/页脚一直不变,中间内容区域高度在变 - 验证scale问题
- 弯路:一直在找*规律*, 既然是scale,就必定有数据进行乘/除。尝试对内容区域进行放大,不够准确,总是差那么一点(要么多一点,要么少一点)。
- 选用:在设置一个*offset*, 通过一些简单的规律,让其接近完美。这里进行多次的数据实验。得到offset = 最后一页内容高度 > 1/2的整体页面内容 ? 可用高度 * 0.1 : 可用高度 * 0.25;
- 整体解决方案
- Excel处理时预先给当前sheet设置一个属性:FixedFooterRow = footer 首行数
- 第一次PDF渲染 > 1页且 存在 FixedFooterRow > 0:否则终止
- 计算最后一页剩余的可用高度 = 可用高度 + 偏移量
- 可用高度 = 页面总高297 - 页眉高度 - 最后一页内容实际高度 - 页脚高度;
- 偏移量 = 最后一页内容高度 > 1/1.18的整体页面内容 ? 可用高度 * 0 : 可用高度 * 0.25;
- 填充指定高度(No.3 计算的最终高度)的空行,插入FixedFooterRow之前,使 footer保持在底部。
- Note: 最多一个sheet需要完成3次渲染
第一次:初次整体渲染 - 计算初始高度,为后面的填充提供数据
第二次:单独渲染footer部分 - 计算footer部分的实际内容高度。针对footer 跨页的情况处理
如footer 一半在第一页,一半在第二页,在插入空行高度时候,需要减去上一页中部分footer 高度
第三次:最终整体渲染 - 插入空行后的渲染
- Due date changed from 09/19/2025 to 12/01/2025
- Status changed from 进行中 to 已关闭
- % Done changed from 90 to 100
Also available in: Atom
PDF