page2pdf_server 1.0.2 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -23
- package/package.json +24 -18
- package/src/CSS/345/205/274/345/256/271/346/200/247.txt +69 -0
- package/src/__tests__/UrltoPdf/generatePdf.test.d.ts +1 -0
- package/{__tests__ → src/__tests__}/UrltoPdf/generatePdf.test.ts +1 -1
- package/src/__tests__/UrltoPdf/pdfSplit.test.d.ts +1 -0
- package/{__tests__ → src/__tests__}/UrltoPdf/pdfSplit.test.ts +1 -1
- package/src/__tests__/helpers/index.d.ts +2 -0
- package/src/__tests__/home.test.d.ts +1 -0
- package/{__tests__ → src/__tests__}/home.test.ts +1 -1
- package/src/app.ts +8 -2
- package/src/components/home/controller.ts +8 -3
- package/src/components/home/pdfController.ts +6 -5
- package/src/components/home/services.ts +3 -3
- package/src/components/home/splitController.ts +6 -5
- package/src/components/home/validators.ts +1 -1
- package/src/db/home.ts +3 -3
- package/src/helpers/apiResponse.ts +1 -1
- package/src/helpers/dataSanitizers.ts +1 -0
- package/src/helpers/error/TimeOutError.ts +1 -1
- package/src/helpers/loggers.ts +5 -3
- package/src/index.ts +6 -1
- package/src/middlewares/errorHandler.ts +1 -1
- package/src/routes/index.ts +2 -2
- package/src/types/request/config.ts +7 -97
- package/src/types/request/home.ts +1 -1
- package/src/types.d.ts +97 -0
- package/src/utils/pdfgen.ts +64 -17
- package/src//346/265/213/350/257/225.txt +26 -2
- package/test//346/211/223/345/215/260/346/234/215/345/212/241.http +17 -0
- package/tsconfig.json +9 -6
- package/.husky/pre-commit +0 -6
- package/.husky/pre-push +0 -4
- package/.idea/codeStyles/Project.xml +0 -58
- package/.idea/codeStyles/codeStyleConfig.xml +0 -5
- package/.idea/encodings.xml +0 -7
- package/.idea/inspectionProfiles/Project_Default.xml +0 -7
- package/.idea/modules.xml +0 -8
- package/.idea/page2pdf-server.iml +0 -12
- package/.idea/tenstack-starter-main.iml +0 -12
- package/.idea/vcs.xml +0 -6
- /package/{__tests__ → src/__tests__}/helpers/index.ts +0 -0
package/README.md
CHANGED
|
@@ -42,12 +42,17 @@ chrome-remote-interface不会为您启动Chrome。本来想用chrome-remote-inte
|
|
|
42
42
|
注意,动态网页在Chrome浏览器直接打印预览的效果应该和本软件转换输出的pdf一致效果,为打印设置的css必须在应用层中自己去添加的。
|
|
43
43
|
纯粹静态html的打印转换pdf,且是标准纸张大小的横竖纸张方向掺杂的这种情况:考虑一次提取一部分pageRanges[]吗,分解多个的files[url,out]独立生成之后做合并。
|
|
44
44
|
|
|
45
|
-
## Prerequisites
|
|
45
|
+
## Prerequisites 必须配置的
|
|
46
46
|
|
|
47
|
-
- [Node.js](https://nodejs.org) (`>=
|
|
47
|
+
- [Node.js](https://nodejs.org) (`>= 20.0.0`)
|
|
48
48
|
- [Yarn](https://yarnpkg.com/en/docs/install) or [NPM](https://docs.npmjs.com/getting-started/installing-node)
|
|
49
|
-
-
|
|
50
|
-
|
|
49
|
+
- 客户电脑必须有Chrome浏览器;
|
|
50
|
+
- 要点击谷歌浏览器的链接,要配置端口号,启动命令设置:目标修改: C:\Users\herzhang\AppData\Local\Google\Chrome\Application\chrome.exe --remote-debugging-port=9872
|
|
51
|
+
比如: "C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9872
|
|
52
|
+
- 之后服务期间,需要首先就该点击该链接开启Chrome浏览器。
|
|
53
|
+
- 特别注意:windows用户若非管理员账户的:桌面上的Chrome快捷方式右键点属性在“兼容性”设置中:必须勾选“管理员身份运行”;
|
|
54
|
+
注意浏览器的管理员和普通身份运行的效果进入显示都不同的。目标URL网站需要登陆处理的,登陆点击后浏览器没有反馈,需直接关闭该TAB页面。
|
|
55
|
+
-报错Error: connect ECONNREFUSED 127.0.0.1:9872 【解决】先在windows任务管理器把chrome.exe的进程全部关闭后重来。
|
|
51
56
|
## Install
|
|
52
57
|
|
|
53
58
|
- Fork or Use [this](https://github.com/filoscoder/tenstack-starter/generate) template repository.
|
|
@@ -57,8 +62,10 @@ chrome-remote-interface不会为您启动Chrome。本来想用chrome-remote-inte
|
|
|
57
62
|
> Make sure you already have [`node.js`](https://github.com/filoscoder/tenstack-starter#prerequisites) and [`npm`](https://github.com/filoscoder/tenstack-starter#prerequisites) or [`yarn`](https://github.com/filoscoder/tenstack-starter#prerequisites) installed in your system.
|
|
58
63
|
|
|
59
64
|
- Set your `git remote add origin` path
|
|
60
|
-
-
|
|
61
|
-
|
|
65
|
+
- 用户电脑也需要做些安装的:
|
|
66
|
+
只需要本工程目录的 /config, /dist, 文书打印转换器.bat,新/pdfs目录, 并且页已经node.js, nodemon;
|
|
67
|
+
还必须要安装工程目录 package-lock.json; /module-alias/的目录全部依赖包的。
|
|
68
|
+
-
|
|
62
69
|
```bash
|
|
63
70
|
git remote add origin ${forked-and-cloned-path}
|
|
64
71
|
```
|
|
@@ -82,7 +89,9 @@ chrome-remote-interface不会为您启动Chrome。本来想用chrome-remote-inte
|
|
|
82
89
|
<br>
|
|
83
90
|
<br>
|
|
84
91
|
|
|
85
|
-
## Alias @
|
|
92
|
+
## Alias 其它,对比 @
|
|
93
|
+
Puppeteer 是一个基于Chrome调试协议CDP 构建的额外高层 API,除其他功能外,它可以启动并使用捆绑版本的 Chromium,而非系统上安装的版本。
|
|
94
|
+
我这个工具目前使用CDP协议构建的,而不是利用Puppeteer做的。
|
|
86
95
|
|
|
87
96
|
To make paths clean and ease to access `@` is setup up for `/src` path
|
|
88
97
|
|
|
@@ -203,25 +212,31 @@ If you have any question or suggestion, don't hesitate to contact me:
|
|
|
203
212
|
|
|
204
213
|
注意,如果发送post请求的body底下的内容实际为空的话,本转换器默认执行:把工作目录的所有pdf文件按照修改时间顺序进行合并,默认输出文件名=配置好的名字。
|
|
205
214
|
假若某个URL不正常的,很可能无法触发页面加载完成,导致作业一致无法继续下去,大大超出预期执行时间。URL对应网页若不是一次性加载完成还会陆陆续续修改内容的就是这种情况造成死等长时间没结果。
|
|
215
|
+
# 调试 "start": "NODE_ENV=development run-s prettify lint & nodemon" 用Debug,异步执行,打断块点有点毛病
|
|
206
216
|
|
|
207
217
|
# 页眉页脚配置html脚本转为json后
|
|
208
218
|
例子,用https://uutool.cn/html2json/ 工具可转换,转换才能通过api/pdf发送命令的。
|
|
209
|
-
"
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
"</div
|
|
215
|
-
]
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
219
|
+
{ name: (original ? "记录" : "报告") + rep?.isp?.no,
|
|
220
|
+
singleTab: true,
|
|
221
|
+
lay: {
|
|
222
|
+
head: [
|
|
223
|
+
'<div style=\\"position: relative; width:100%; text-align:center; border-bottom: 1pt solid #eeeeee; margin: 3.5mm 0px 10px; font-size: 10pt\\">',
|
|
224
|
+
`<div style=\\"position: absolute; width:100%; text-align:left; bottom: 5px; left: 50px;\\">报告No: ${rep?.isp?.no}</div></div>`
|
|
225
|
+
],
|
|
226
|
+
foot: [
|
|
227
|
+
'<div style=\\"position: relative; width: 100%; text-align: left; border-top: 1pt solid #eeeeee; margin: 10px 0px 1.5mm; font-size: 8pt;\\">',
|
|
228
|
+
'<div style=\\"position: absolute; width: 100%; text-align: center; top: 5px;\\">共<span>~pageNumber~</span>页 / 第<span>~totalPages~</span>页</div></div>'
|
|
229
|
+
],
|
|
230
|
+
},
|
|
231
|
+
files: [
|
|
232
|
+
{
|
|
233
|
+
url,
|
|
234
|
+
out: `tmp-${rep?.isp?.no}` + (original ? "-O" : ""),
|
|
235
|
+
headFrom: 3,
|
|
236
|
+
frNo: 3,
|
|
237
|
+
},
|
|
238
|
+
] }
|
|
239
|
+
其中 -NOT_DISPLAY- 指示若没有页码的就不显示相关局部部分。
|
|
225
240
|
# 注意适用性
|
|
226
241
|
本文书打印转换器只能适用单用户在客户本机用,每次执行一个打印指令,不要并行发出指令,本机工作目录也是临时文件,针对当前指令适用的,不能存放无关文件。
|
|
227
242
|
本转换器console命令输出窗口可实时观察到当前打印转换指令的执行过程输出提示,同时目标浏览器也会新开启浏览窗口,这些由本转换器自动开启的浏览窗口实际上
|
|
@@ -237,3 +252,24 @@ If you have any question or suggestion, don't hesitate to contact me:
|
|
|
237
252
|
{"name":"D4", "css": "10.4in 12.6in","w": 10.4,"h": 12.6}
|
|
238
253
|
]
|
|
239
254
|
}
|
|
255
|
+
|
|
256
|
+
# 拒绝连接的
|
|
257
|
+
对Chrome 右键 点选 以管理员身份运行;
|
|
258
|
+
前提需 有npm 就是 node环境的;
|
|
259
|
+
复制目录+ 还需安装 npm ci --only=production
|
|
260
|
+
新版本需无头的 "C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9872 --headless
|
|
261
|
+
|
|
262
|
+
# 动态布局问题
|
|
263
|
+
只用css做动态的组件和用了js脚本做动态布局的组件在打印时刻不同,比如"customize-easy-ui-component"库的LineColumnFlex和LineColumn的差别即使这样,
|
|
264
|
+
前者在打印时刻需要约束浏览器窗口的宽度为纸张输出的宽度差不多的大小,后者可打印页数就可能和内容页数不一致,后者只用css的就不会有这个麻烦。
|
|
265
|
+
就算同一个组件有可能出现:同一次打印出现两种布局状态。比如这样的:<LineColumnFlex 1> {useMediaQuery({query: 'print'}) && <LineColumnFlex 2>}的,
|
|
266
|
+
前面一个是js按照浏览器打印触发之前的div宽度来布局的有5列,然而后面哪一个是按照最终纸张输出宽度来做布局的才2列,完全不一样了!但是后面第二个组件可能输出不完整的,
|
|
267
|
+
因为打印纸张的输出页数实际在useMediaQuery({query: 'print'})逻辑条件成立以前就敲定了可打印纸张数量!!所以有很大问题。js动态代码简单,css动态写代码麻烦。
|
|
268
|
+
就接着这个例子讲:用{useMediaQuery({query: 'print'})&&逻辑嵌套的哪些内容,就算我约束了浏览器宽度为纸张宽度以后,实际上在打印敲定输出页数时间这些逻辑嵌套的
|
|
269
|
+
需要打印内容实际上也并没有计算在立刻敲定输出页数之内的,因此也必然导致打印页数丢失或不够的问题的,这个情况必须用css,除非不打印比打印语境内容占用高度还少的话。
|
|
270
|
+
<div css={{"@media not print": {display: 'none'}}}>
|
|
271
|
+
<LineColumnFlex column={7}>
|
|
272
|
+
</div>
|
|
273
|
+
如上代码会有严重毛病:打印输出实际上只有一次机会render;useMeasure(ref还是空的)div宽度=0导致实际只有输出一列的布局,打印没机会修正了,屏幕情况可以不限次数render,
|
|
274
|
+
可是打印就不行了,上面这情况太特殊了。
|
|
275
|
+
|
package/package.json
CHANGED
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "page2pdf_server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "文书打印转换器",
|
|
5
5
|
"private": false,
|
|
6
6
|
"authors": "herzhang",
|
|
7
7
|
"repository": "https://gitee.com/heerzhang/page2pdf-server",
|
|
8
8
|
"license": "MIT",
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/types.d.ts",
|
|
9
11
|
"scripts": {
|
|
10
12
|
"yarn": "yarn",
|
|
11
13
|
"yarn命令行": "yarn add nodemon -D",
|
|
12
14
|
"注意2": "运行prettify来修复代码,免去到处是标记红色的,太严格了",
|
|
13
|
-
"prettify": "prettier --write \"src/**/*.{ts,js,json}\" \"__tests__/**/*.{ts,js,json}\"",
|
|
15
|
+
"prettify": "prettier --write \"src/**/*.{ts,js,json}\" \"src/__tests__/**/*.{ts,js,json}\"",
|
|
14
16
|
"start": "NODE_ENV=development run-s prettify lint & nodemon",
|
|
15
|
-
"build": "
|
|
16
|
-
"
|
|
17
|
-
"
|
|
17
|
+
"build": "rimraf dist && tsc && rimraf dist/types && ncp src/types.d.ts dist/types",
|
|
18
|
+
"手动管理 .d.ts 文件的完整流程": "确保以下路径存源文件:src/types.d.ts 目标目录:dist/types/",
|
|
19
|
+
"build3": "rimraf dist && tsc --emitDeclarationOnly && dts-bundle --name 'types' --main dist/types/index.d.ts --out 'dist/types.d.ts'",
|
|
20
|
+
"build2": "rimraf dist && tsc --emitDeclarationOnly && ncp src/types.d.ts dist/types",
|
|
21
|
+
"build1": "cross-env NODE_ENV=production run-s prettify clean transpile",
|
|
22
|
+
"lint": "eslint 'src/**/*.{ts,js}' 'src/__tests__/**/*.{ts,js}'",
|
|
23
|
+
"lint:fix": "eslint --fix 'src/**/*.{ts,js}' 'src/__tests__/**/*.{ts,js}' --quiet",
|
|
18
24
|
"有些隐藏错误": "需要运行watch才发现",
|
|
19
25
|
"watch": "tsc --watch",
|
|
20
26
|
"clean": "rimraf dist",
|
|
@@ -30,7 +36,7 @@
|
|
|
30
36
|
"service:delete": "pm2 delete ecosystem.config.js",
|
|
31
37
|
"service:logs": "pm2 logs",
|
|
32
38
|
"hook主动运行": "操作系统缘故,将单引号改成双引号,加转义符,提交代码会自动执行;git提交给它勾掉吧,yarn会自动运行prepare",
|
|
33
|
-
"
|
|
39
|
+
"安装生产依赖在服务器上执行": "工程npm prune --production 然后目标机npm ci --only=production"
|
|
34
40
|
},
|
|
35
41
|
"keywords": [
|
|
36
42
|
"dynamic page pdf generator",
|
|
@@ -43,7 +49,11 @@
|
|
|
43
49
|
"server"
|
|
44
50
|
],
|
|
45
51
|
"dependencies": {
|
|
46
|
-
"
|
|
52
|
+
"@types/bcrypt": "^5.0.0",
|
|
53
|
+
"@types/cors": "^2.8.13",
|
|
54
|
+
"@types/express-pino-logger": "^4.0.3",
|
|
55
|
+
"@types/jsonwebtoken": "^9.0.2",
|
|
56
|
+
"chrome-remote-interface": "^0.33.3",
|
|
47
57
|
"config": "^3.3.9",
|
|
48
58
|
"connect-timeout": "^1.9.0",
|
|
49
59
|
"cors": "^2.8.5",
|
|
@@ -60,26 +70,22 @@
|
|
|
60
70
|
"pdf-lib": "^1.17.1",
|
|
61
71
|
"pino-http": "^8.3.3",
|
|
62
72
|
"pino-pretty": "^10.0.0",
|
|
63
|
-
"rimraf": "^
|
|
73
|
+
"rimraf": "^6.0.1",
|
|
64
74
|
"save-dev": "^0.0.1-security"
|
|
65
75
|
},
|
|
66
76
|
"devDependencies": {
|
|
67
77
|
"@babel/preset-env": "^7.22.5",
|
|
68
78
|
"@babel/preset-typescript": "^7.22.5",
|
|
69
|
-
"@types/bcrypt": "^5.0.0",
|
|
70
79
|
"@types/connect-timeout": "^0.0.37",
|
|
71
|
-
"@types/
|
|
72
|
-
"@types/express": "^4.17.17",
|
|
73
|
-
"@types/express-pino-logger": "^4.0.3",
|
|
80
|
+
"@types/express": "^4.17.22",
|
|
74
81
|
"@types/jest": "^29.5.2",
|
|
75
|
-
"@types/jsonwebtoken": "^9.0.2",
|
|
76
82
|
"@types/lodash-es": "^4.17.7",
|
|
77
|
-
"@types/module-alias": "^2.0.1",
|
|
78
83
|
"@types/morgan": "^1.9.4",
|
|
79
|
-
"@types/node": "^
|
|
84
|
+
"@types/node": "^22.15.21",
|
|
80
85
|
"@types/supertest": "^2.0.12",
|
|
81
86
|
"@typescript-eslint/eslint-plugin": "^5.59.11",
|
|
82
87
|
"@typescript-eslint/parser": "^5.59.11",
|
|
88
|
+
"dts-bundle": "^0.7.3",
|
|
83
89
|
"eslint": "^8.43.0",
|
|
84
90
|
"eslint-config-prettier": "^8.8.0",
|
|
85
91
|
"eslint-plugin-import": "^2.27.5",
|
|
@@ -87,7 +93,7 @@
|
|
|
87
93
|
"husky": "^8.0.3",
|
|
88
94
|
"jest": "^29.5.0",
|
|
89
95
|
"jest-watch-typeahead": "^2.2.2",
|
|
90
|
-
"
|
|
96
|
+
"ncp": "^2.0.0",
|
|
91
97
|
"nodemon": "^3.0.1",
|
|
92
98
|
"npm-run-all": "^4.1.5",
|
|
93
99
|
"pm2": "^5.3.0",
|
|
@@ -96,9 +102,9 @@
|
|
|
96
102
|
"ts-jest": "^29.1.0",
|
|
97
103
|
"ts-node": "^10.9.1",
|
|
98
104
|
"tsconfig-paths": "^4.2.0",
|
|
99
|
-
"typescript": "^5.
|
|
105
|
+
"typescript": "^5.8.3"
|
|
100
106
|
},
|
|
101
107
|
"engines": {
|
|
102
|
-
"node": ">=
|
|
108
|
+
"node": ">= 20.0.0"
|
|
103
109
|
}
|
|
104
110
|
}
|
|
@@ -54,3 +54,72 @@ Chrome浏览器已经 可支持的有这些:
|
|
|
54
54
|
CDP({})前后两次CDP打开新的Page若前面没有close(),那么旧Page.printToPDF也会被后面新Page.navigate所覆盖的,浏览器不支持合并打印的!
|
|
55
55
|
Page.printToPDF({})实际也只能类似Chrome打印预览菜单一致,只能打印当前页面,动态内容页面也是随着鼠标用户操作有可能不一样的打印结果。
|
|
56
56
|
|
|
57
|
+
【精准控制打印位置思路】
|
|
58
|
+
简单直接做法<span position: absolute; bottom: -1200vh;">尾巴</span>但须知道整个文档打印几张纸的,然后在作为参数优化css的计算再来决定做控制,可能会有重叠paint需强制断开页。
|
|
59
|
+
中间区域<div style="position: relative; page-break-before: always;">¥..<span style="position: absolute;top: calc(200vh - 3rem);">尾巴</span>
|
|
60
|
+
必须知道该区域有几张纸;可能会有重叠paint需强制断开页。
|
|
61
|
+
浮动布局<div style="display: flex; flex-direction: column; align-content: flex-end; height: 1300vh;"><div height: 100%;>¥</div><div display: inline-flex;>尾巴</div>必须知道该区域有几张纸,不用担心会有重叠paint。
|
|
62
|
+
后面一定有强制页断开的情景,把紧邻前面的元素定位到纸张的底部位置?【关键】是强制分页能确保独立性。
|
|
63
|
+
<div css={{"@media print": {pageBreakBefore: 'always'}}}><span style="position: absolute;top: -3rem;">尾巴</span><Text>紧跟的新页</Text></div>不需要算区域有几张,不用担心会有重叠paint。
|
|
64
|
+
最后一页情况乱特例<div style="height: 0vh; position: relative; page-break-before: always;"><span style="display: block; position:absolute; bottom:0;">尾巴</span></div>最后多个尾随的空白页!多出一个空白页情况的不打印?
|
|
65
|
+
2023/11/23:验证这下的代码还是无法正常打印页码 位置的。每一个重复div标签计数一次,只显示一次。
|
|
66
|
+
<div css={{"@media print": {pageBreakBefore: 'always'}}}>
|
|
67
|
+
<div
|
|
68
|
+
css={{
|
|
69
|
+
position: 'absolute',
|
|
70
|
+
top: '-2rem',
|
|
71
|
+
"@media print": {
|
|
72
|
+
":after": {
|
|
73
|
+
content: 'counter(page)',
|
|
74
|
+
},
|
|
75
|
+
counterIncrement: 'page',
|
|
76
|
+
// position: 'absolute',
|
|
77
|
+
// bottom: '8rem',
|
|
78
|
+
right: '-1rem',
|
|
79
|
+
fontSize: '12px',
|
|
80
|
+
color: '#777',
|
|
81
|
+
padding: '5px',
|
|
82
|
+
backgroundColor: '#f7f7f7',
|
|
83
|
+
border: '1px solid #ddd',
|
|
84
|
+
borderRadius: '2px',
|
|
85
|
+
// pageBreakAfter: 'always',
|
|
86
|
+
}
|
|
87
|
+
}}
|
|
88
|
+
>
|
|
89
|
+
尾巴
|
|
90
|
+
</div>
|
|
91
|
+
<Text>紧跟的新页</Text>
|
|
92
|
+
</div>
|
|
93
|
+
【动态内容遇到的打印问题】末尾插入方式“只能支持页面启动就明确打印页数的才有效;用副作用中间纯动态变更的就不行了,打印页数早就被限制死了,后面无法再改了。
|
|
94
|
+
const [vtpage, setVtpage] = React.useState(Math.ceil((yBdv0?.top!-yHolw?.bottom!)/yHolw?.width!) || 0);
|
|
95
|
+
React.useEffect(() => {
|
|
96
|
+
if((yBdv0?.top!-yHolw?.bottom!)>0 && (yHolw?.width!)<yBdv0?.width! && (yHolw?.bottom!)>0)
|
|
97
|
+
{
|
|
98
|
+
console.log(`撞见该是却也显示了情形:`, yHolw,"虚拟断开",yBdv0, "系数有=", (yBdv0?.top!-yHolw?.bottom!)/yHolw?.width!);
|
|
99
|
+
//没处理【报错】Too many re-renders. React limits the number of renders to prevent an infinite loop.
|
|
100
|
+
setVtpage(Math.ceil((yBdv0?.top!-yHolw?.bottom!)/yHolw?.width!) || 0);
|
|
101
|
+
}
|
|
102
|
+
}, [yBdv0, yHolw, setVtpage]);
|
|
103
|
+
return <div ref={refBdv0} css={{"@media print": {pageBreakBefore:'always'}}}/>
|
|
104
|
+
{ (new Array(vtpage)).fill(null).map((_, i:number) => {
|
|
105
|
+
console.log(`该是却也显示了情形加虚拟纸张数=`, vtpage,"断页i=",i);
|
|
106
|
+
return <div key={i} css={{"@media print": {pageBreakBefore:'always'}}}/>;
|
|
107
|
+
}) }
|
|
108
|
+
foot: [
|
|
109
|
+
'<div style=\\"position: relative; width: 100%; text-align: left; margin: 10px 0px 1.5mm; font-size: 8pt;\\">',
|
|
110
|
+
'<div style=\\"position: absolute; text-align: left; top: 5px;left: 60px;\\"></div>',
|
|
111
|
+
'<div style=\\"position: absolute; width: 100%; text-align: center; top: 5px;\\"></div>',
|
|
112
|
+
'<div style=\\"-NOT_DISPLAY- position: absolute; text-align: right;top: 5px;right: 20px;\\">共 <span>~totalPages~</span> 页 / 第 <span>~pageNumber~</span> 页</div>',
|
|
113
|
+
"</div>",
|
|
114
|
+
],
|
|
115
|
+
不同版本的Chrome可能对CSS样式、字体渲染或布局引擎存在差异,导致生成的PDF不一致。若网页使用的字体在目标电脑上未安装,Chrome可能自动替换为默认字体,网络延迟资源加载失败,所以用Puppeteer替代浏览器原生打印。
|
|
116
|
+
|
|
117
|
+
失败,Error: 开启窗口尝试2次失败: 【因为】浏览器启动参数要配置特定端口号的。
|
|
118
|
+
|
|
119
|
+
[功能按钮]
|
|
120
|
+
打印预览{非检验员也能用},
|
|
121
|
+
本地转Pdf{非检验员也能用,未盖章,安装node等},
|
|
122
|
+
后端转Pdf{未盖章,立刻下载,用户需排队},
|
|
123
|
+
上传Pdf盖章,
|
|
124
|
+
代理转Pdf{异步的,不能提前获得结果,独立服务器},
|
|
125
|
+
下载盖章后Pdf{假如有存储Pdf};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/src/app.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
1
2
|
import cors from "cors";
|
|
2
3
|
import express from "express";
|
|
3
4
|
import helmet from "helmet";
|
|
@@ -5,8 +6,12 @@ import morgan from "morgan";
|
|
|
5
6
|
import timeout from "connect-timeout";
|
|
6
7
|
import CONFIG from "./configEnv";
|
|
7
8
|
import { expressPinoLogger } from "./helpers";
|
|
8
|
-
import * as errorHandler from "
|
|
9
|
-
import routes from "
|
|
9
|
+
import * as errorHandler from "./middlewares/errorHandler";
|
|
10
|
+
import routes from "./routes";
|
|
11
|
+
|
|
12
|
+
/**打印不全,太多页数情形:
|
|
13
|
+
* */
|
|
14
|
+
EventEmitter.defaultMaxListeners = 100;
|
|
10
15
|
|
|
11
16
|
export const createApp = (): express.Application => {
|
|
12
17
|
const app = express();
|
|
@@ -25,6 +30,7 @@ export const createApp = (): express.Application => {
|
|
|
25
30
|
app.use(expressPinoLogger());
|
|
26
31
|
}
|
|
27
32
|
|
|
33
|
+
// @ts-ignore
|
|
28
34
|
app.use(timeout(CONFIG.SERVER.TIMEOUT));
|
|
29
35
|
|
|
30
36
|
// API Routes
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { OK } from "http-status/lib";
|
|
2
2
|
import { HomeServices } from "./services";
|
|
3
|
-
import { getAppInfoQuery } from "
|
|
4
|
-
import { apiResponse } from "
|
|
3
|
+
import { getAppInfoQuery } from "../../types/request/home";
|
|
4
|
+
import { apiResponse } from "../../helpers/apiResponse";
|
|
5
|
+
import { Request, Response, NextFunction } from "express";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* 为何为了保证单步模式调试运行"test:watchAll": "cross-env NODE_ENV=development jest --watchAll --runInBand --detectOpenHandles",
|
|
@@ -13,7 +14,11 @@ export class HomeController {
|
|
|
13
14
|
* @param {Req} req
|
|
14
15
|
* @param {Res} res
|
|
15
16
|
*/
|
|
16
|
-
static getAppInfo = async (
|
|
17
|
+
static getAppInfo = async (
|
|
18
|
+
req: Request,
|
|
19
|
+
res: Response,
|
|
20
|
+
next: NextFunction,
|
|
21
|
+
) => {
|
|
17
22
|
try {
|
|
18
23
|
const appInfoKey = req.query.key as getAppInfoQuery;
|
|
19
24
|
const homeServices = new HomeServices();
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { OK } from "http-status/lib";
|
|
2
|
-
import {
|
|
3
|
-
import { apiResponse } from "
|
|
4
|
-
import { RenderPDF } from "
|
|
5
|
-
import CONFIG from "
|
|
2
|
+
import { HeadFooter } from "../../types/request/config";
|
|
3
|
+
import { apiResponse } from "../../helpers/apiResponse";
|
|
4
|
+
import { RenderPDF } from "../../utils/pdfgen";
|
|
5
|
+
import CONFIG from "../../configEnv";
|
|
6
|
+
import { ConfigRoot, FileTransform } from "@/types";
|
|
6
7
|
|
|
7
8
|
export class PdfController {
|
|
8
9
|
/** node.js对比前端App 太严格了,一点小毛病页不行啊。
|
|
@@ -14,7 +15,7 @@ export class PdfController {
|
|
|
14
15
|
*/
|
|
15
16
|
static postMakePdf = async (req: Req, res: Res, next: NextFn) => {
|
|
16
17
|
try {
|
|
17
|
-
// const appInfoKey1 = req.query.key as getAppInfoQuery;
|
|
18
|
+
// const appInfoKey1 = req.query.key as getAppInfoQuery; 所有打印都走ConfigRoot配置包=task:可能有多个URL合并输出的。
|
|
18
19
|
const task = req.body as ConfigRoot<FileTransform>;
|
|
19
20
|
task.lay as HeadFooter;
|
|
20
21
|
//预处理汇总输出的pdf页眉页脚, 转换页眉页脚的html存储
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import AppInformation from "
|
|
2
|
-
import { HomeDAO } from "
|
|
3
|
-
import { getAppInfoQuery } from "
|
|
1
|
+
import AppInformation from "../../types/response/AppInformation";
|
|
2
|
+
import { HomeDAO } from "../../db/home";
|
|
3
|
+
import { getAppInfoQuery } from "../../types/request/home";
|
|
4
4
|
|
|
5
5
|
export class HomeServices {
|
|
6
6
|
homeDAO!: HomeDAO;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import { OK } from "http-status/lib";
|
|
3
|
-
import {
|
|
4
|
-
import { apiResponse } from "
|
|
3
|
+
import { HeadFooter } from "../../types/request/config";
|
|
4
|
+
import { apiResponse } from "../../helpers/apiResponse";
|
|
5
5
|
|
|
6
|
-
import { RenderPDF } from "
|
|
7
|
-
import CONFIG from "
|
|
8
|
-
import { SplitConfig, SplitPdfFile } from "
|
|
6
|
+
import { RenderPDF } from "../../utils/pdfgen";
|
|
7
|
+
import CONFIG from "../../configEnv";
|
|
8
|
+
import { SplitConfig, SplitPdfFile } from "../../types/request/split";
|
|
9
|
+
import { ConfigRoot, FileTransform } from "@/types";
|
|
9
10
|
// import CONFIG from "@/configEnv";
|
|
10
11
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
11
12
|
const { PDFDocument } = require("pdf-lib");
|
package/src/db/home.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import AppInformation from "
|
|
2
|
-
import CONFIG from "
|
|
3
|
-
import { getAppInfoQuery } from "
|
|
1
|
+
import AppInformation from "../types/response/AppInformation";
|
|
2
|
+
import CONFIG from "../configEnv";
|
|
3
|
+
import { getAppInfoQuery } from "../types/request/home";
|
|
4
4
|
|
|
5
5
|
export class HomeDAO {
|
|
6
6
|
get = (key?: getAppInfoQuery): Promise<AppInformation | any> => {
|
package/src/helpers/loggers.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import httpStatus from "http-status/lib";
|
|
2
2
|
import expressPino from "express-pino-logger";
|
|
3
|
-
import { hidePassword } from "
|
|
3
|
+
import { hidePassword } from "../utils/auth";
|
|
4
4
|
|
|
5
|
-
const { OK, BAD_REQUEST
|
|
5
|
+
const { OK, BAD_REQUEST } = httpStatus;
|
|
6
6
|
|
|
7
7
|
// More info: https://github.com/pinojs/express-pino-logger
|
|
8
8
|
export const expressPinoLogger = () =>
|
|
@@ -28,10 +28,12 @@ export const expressPinoLogger = () =>
|
|
|
28
28
|
customSuccessMessage(res) {
|
|
29
29
|
const status = res.statusCode!;
|
|
30
30
|
if (status >= 400 && status < 500) {
|
|
31
|
+
// @ts-ignore
|
|
31
32
|
return `${status || BAD_REQUEST} : ${httpStatus[status || 400]}`;
|
|
32
33
|
}
|
|
33
34
|
if (status >= 500) {
|
|
34
|
-
|
|
35
|
+
// @ts-ignore
|
|
36
|
+
return `${status} : ${httpStatus[status || 500]}`;
|
|
35
37
|
}
|
|
36
38
|
return `${OK} : ${httpStatus[200].toUpperCase()}`;
|
|
37
39
|
},
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// ! Don't convert require into import
|
|
2
2
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
3
|
-
|
|
3
|
+
//去掉这个了 离开开发环境无法 独立运行服务端,报错module-alias找不到
|
|
4
|
+
//去掉这个了 require("module-alias").addAlias("@", __dirname);
|
|
5
|
+
//去掉这个了
|
|
4
6
|
|
|
5
7
|
import { createApp } from "./app";
|
|
6
8
|
import { startServer } from "./server";
|
|
@@ -11,3 +13,6 @@ if (process.env.NODE_ENV !== "test") {
|
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
//关键文档Chrome DevTools Protocol资料, https://chromedevtools.github.io/devtools-protocol/tot/Page
|
|
16
|
+
export * from "./types/request/config";
|
|
17
|
+
export { FileTransform } from "@/types";
|
|
18
|
+
export { ConfigRoot } from "@/types";
|
|
@@ -5,7 +5,7 @@ import HttpStatus, {
|
|
|
5
5
|
INTERNAL_SERVER_ERROR,
|
|
6
6
|
REQUEST_TIMEOUT,
|
|
7
7
|
} from "http-status/lib";
|
|
8
|
-
import { TimeOutError } from "
|
|
8
|
+
import { TimeOutError } from "../helpers/error";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @description Error response middleware for 404 not found. This middleware function should be at the very bottom of the stack.
|
package/src/routes/index.ts
CHANGED