修复(08-28-reimbursement-detail-material-preview-fixes): 收紧撤回展示并校正材料图片尺寸
这个提交包含在:
@@ -689,10 +689,18 @@ reply.header(
|
||||
- PDF originals contribute every original page; JPG/PNG/WebP materials are
|
||||
normalized with `sharp` and embedded one per page. The merged PDF is a
|
||||
derived approval view, never an original or digital-signature fact source.
|
||||
- Image page geometry must use the width and height returned by Sharp's final
|
||||
normalized output (`toBuffer({ resolveWithObject: true }).info`), not input
|
||||
`metadata()`. `rotate()` applies EXIF orientation during output, so input
|
||||
metadata may describe the opposite portrait/landscape shape.
|
||||
- A stable collection hash covers the explicitly ordered material type, ID,
|
||||
file hash, MIME and byte count. The cache key also includes reimbursement ID
|
||||
and merger version. Fix CreationDate, ModificationDate, Creator, Producer and
|
||||
save options so identical input produces byte-identical output.
|
||||
- Any visible merge-algorithm change, including corrected image page geometry,
|
||||
increments the merger version. Byte determinism is required across repeated
|
||||
generation within one version; different versions may intentionally produce
|
||||
different bytes for the same ordered source collection.
|
||||
- The in-memory bundle is bounded to 20 materials, 50 MiB source bytes, 40
|
||||
pages, 40 megapixels per image, 50 MiB output and 100 MiB process cache.
|
||||
Worker execution has a fixed timeout; concurrent requests for one collection
|
||||
@@ -732,6 +740,7 @@ reply.header(
|
||||
### 6. Tests Required
|
||||
|
||||
- Service tests assert deterministic bytes, all-page copy, image embedding,
|
||||
EXIF orientation 6/8 output geometry, ordinary JPG/PNG/WebP geometry,
|
||||
20–30-page worker behavior, concurrent deduplication, expiry and limits.
|
||||
- Route tests assert authorization, reason gate, token binding, cache miss,
|
||||
issue/access audit, audit-failure fail-closed behavior and exact PDF size.
|
||||
@@ -748,6 +757,12 @@ reply.header(
|
||||
const pages = await rasterizeEveryPdfOnThePhone(); // slow, blank-prone and duplicates PDF rendering
|
||||
```
|
||||
|
||||
```js
|
||||
const metadata = await sharp(source).rotate().metadata();
|
||||
// metadata describes the input and can disagree with the rotated output.
|
||||
const page = output.addPage([metadata.width, metadata.height]);
|
||||
```
|
||||
|
||||
#### Correct
|
||||
|
||||
```tsx
|
||||
@@ -755,6 +770,14 @@ const bundle = await fetchReimbursementMaterialPreviewBundle(reimbursementId);
|
||||
await previewFileInWecom({ url: bundle.signedUrl, name: bundle.originalName, size: bundle.fileSize });
|
||||
```
|
||||
|
||||
```js
|
||||
const { data, info } = await sharp(source)
|
||||
.rotate()
|
||||
.jpeg()
|
||||
.toBuffer({ resolveWithObject: true });
|
||||
const page = output.addPage([info.width, info.height]);
|
||||
```
|
||||
|
||||
## Scenario: Lightweight Travel Summary On Reimbursements
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
在新工单中引用
屏蔽一个用户