page2pdf_server 1.0.0

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.
Files changed (79) hide show
  1. package/.babelrc +3 -0
  2. package/.eslintrc +33 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.md +28 -0
  4. package/.github/ISSUE_TEMPLATE/feature_request.md +15 -0
  5. package/.github/ISSUE_TEMPLATE/refactoring.md +15 -0
  6. package/.github/PULL_REQUEST_TEMPLATE.md +18 -0
  7. package/.github/stale.yml +17 -0
  8. package/.github/workflows/cd.yml +75 -0
  9. package/.github/workflows/ci.yml +36 -0
  10. package/.husky/pre-commit +6 -0
  11. package/.husky/pre-push +4 -0
  12. package/.idea/codeStyles/Project.xml +58 -0
  13. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  14. package/.idea/encodings.xml +7 -0
  15. package/.idea/inspectionProfiles/Project_Default.xml +7 -0
  16. package/.idea/modules.xml +8 -0
  17. package/.idea/page2pdf-server.iml +12 -0
  18. package/.idea/tenstack-starter-main.iml +12 -0
  19. package/.idea/vcs.xml +6 -0
  20. package/.prettierrc +8 -0
  21. package/.vscode/settings.json +3 -0
  22. package/LICENSE +18 -0
  23. package/README.md +238 -0
  24. package/__tests__/UrltoPdf/generatePdf.test.ts +207 -0
  25. package/__tests__/UrltoPdf/pdfSplit.test.ts +69 -0
  26. package/__tests__/helpers/index.ts +21 -0
  27. package/__tests__/home.test.ts +77 -0
  28. package/config/default.json +10 -0
  29. package/config/development.json +3 -0
  30. package/config/production.json +3 -0
  31. package/config/test.json +3 -0
  32. package/ecosystem.config.js +41 -0
  33. package/eslintrc.json +14 -0
  34. package/jest.config.js +35 -0
  35. package/nodemon.json +6 -0
  36. package/package.json +105 -0
  37. package/src/CSS/345/205/274/345/256/271/346/200/247.txt +56 -0
  38. package/src/app.ts +41 -0
  39. package/src/components/home/controller.ts +27 -0
  40. package/src/components/home/index.ts +4 -0
  41. package/src/components/home/pdfController.ts +112 -0
  42. package/src/components/home/services.ts +31 -0
  43. package/src/components/home/splitController.ts +124 -0
  44. package/src/components/home/validators.ts +12 -0
  45. package/src/configEnv/index.ts +62 -0
  46. package/src/db/home.ts +14 -0
  47. package/src/helpers/apiResponse.ts +10 -0
  48. package/src/helpers/dataSanitizers.ts +31 -0
  49. package/src/helpers/error/ApiError.ts +25 -0
  50. package/src/helpers/error/ForbiddenError.ts +15 -0
  51. package/src/helpers/error/NotFoundException.ts +15 -0
  52. package/src/helpers/error/TimeOutError.ts +20 -0
  53. package/src/helpers/error/UnauthorizedError.ts +15 -0
  54. package/src/helpers/error/ValidationError.ts +20 -0
  55. package/src/helpers/error/index.ts +15 -0
  56. package/src/helpers/index.ts +2 -0
  57. package/src/helpers/loggers.ts +73 -0
  58. package/src/index.ts +13 -0
  59. package/src/middlewares/errorHandler.ts +52 -0
  60. package/src/new_tab1.mhtml +722 -0
  61. package/src/routes/index.ts +22 -0
  62. package/src/server.ts +30 -0
  63. package/src/testCSS.html +241 -0
  64. package/src/types/global.d.ts +13 -0
  65. package/src/types/request/home.ts +166 -0
  66. package/src/types/request/split.ts +18 -0
  67. package/src/types/response/AppInformation.ts +9 -0
  68. package/src/types/response/index.ts +5 -0
  69. package/src/utils/array.ts +19 -0
  70. package/src/utils/auth.ts +12 -0
  71. package/src/utils/crypt.ts +26 -0
  72. package/src/utils/filter.ts +59 -0
  73. package/src/utils/object.ts +58 -0
  74. package/src/utils/pdfgen.ts +998 -0
  75. package/src/utils/url.ts +54 -0
  76. package/src//346/265/213/350/257/225.txt +241 -0
  77. package/tsconfig.json +41 -0
  78. package/tslint.json +22 -0
  79. package//346/226/207/344/271/246/346/211/223/345/215/260/350/275/254/346/215/242/345/231/250.bat +2 -0
@@ -0,0 +1,22 @@
1
+ import { Router } from "express";
2
+ import {
3
+ HomeController,
4
+ appKeyValidator,
5
+ PdfController,
6
+ SplitController,
7
+ } from "@/components/home";
8
+ import { sanitizer } from "@/helpers";
9
+
10
+ const router = Router();
11
+
12
+ router.get("/", sanitizer(appKeyValidator), HomeController.getAppInfo);
13
+ //正常都用一个的 post传输的数据量比get大得多;
14
+ //基本都统一入口:
15
+ router.post("/pdf", sanitizer(appKeyValidator), PdfController.postMakePdf);
16
+
17
+ //为了支持拆分pdf操作:
18
+ router.post("/split", sanitizer(appKeyValidator), SplitController.postSplitPdf);
19
+
20
+ export default router;
21
+
22
+ //厂家的文档: https://pdf-lib.js.org/ https://www.npmjs.com/package/pdf-lib
package/src/server.ts ADDED
@@ -0,0 +1,30 @@
1
+ import { Server, createServer } from "http";
2
+ import e from "express";
3
+ // @ts-ignore
4
+ import config from "config";
5
+ import { exitLog } from "./helpers";
6
+ import CONFIG from "./configEnv";
7
+ //自定义服务端口:
8
+ const server_port = config.get("server_port");
9
+
10
+ export const startServer = (app: e.Application): Server => {
11
+ const httpServer = createServer(app);
12
+
13
+ process
14
+ .on("SIGINT", () => exitLog(null, "SIGINT"))
15
+ .on("SIGQUIT", () => exitLog(null, "SIGQUIT"))
16
+ .on("SIGTERM", () => exitLog(null, "SIGTERM"))
17
+ .on("uncaughtException", (err) => exitLog(err, "uncaughtException"))
18
+ .on("beforeExit", () => exitLog(null, "beforeExit"))
19
+ .on("exit", () => exitLog(null, "exit"));
20
+
21
+ //自定义用server_port替代掉 CONFIG.APP.PORT;
22
+
23
+ return httpServer.listen({ port: server_port }, (): void => {
24
+ process.stdout.write(`⚙️ Application Environment: ${CONFIG.APP.ENV}\n`);
25
+ process.stdout.write(`⏱ Started on: ${Date.now()}\n`);
26
+ process.stdout.write(
27
+ `🚀 文书打印转换器启动好 http://localhost:${server_port}\n`,
28
+ );
29
+ });
30
+ };
@@ -0,0 +1,241 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="robots" content="noindex, nofollow">
6
+ <style>
7
+ body {
8
+ padding: 0;
9
+ margin: 0;
10
+ }
11
+
12
+ svg:not(:root) {
13
+ display: block;
14
+ }
15
+
16
+ .playable-code {
17
+ background-color: #f4f7f8;
18
+ border: none;
19
+ border-left: 6px solid #558abb;
20
+ border-width: medium medium medium 6px;
21
+ color: #4d4e53;
22
+ height: 100px;
23
+ width: 90%;
24
+ padding: 10px 10px 0;
25
+ }
26
+
27
+ .playable-canvas {
28
+ border: 1px solid #4d4e53;
29
+ border-radius: 2px;
30
+ }
31
+
32
+ .playable-buttons {
33
+ text-align: right;
34
+ width: 90%;
35
+ padding: 5px 10px 5px 26px;
36
+ }
37
+ </style>
38
+
39
+ <style>
40
+ fieldset {
41
+ display: flex;
42
+ flex-direction: row;
43
+ justify-content: space-between;
44
+ gap: 1rem;
45
+ width: fit-content;
46
+ }
47
+
48
+ @page toc {
49
+ size: a4 portrait;
50
+ @top-middle {
51
+ content: "Table of contents";
52
+ }
53
+ }
54
+
55
+ @page foreword {
56
+ size: a4 portrait;
57
+ @top-middle {
58
+ content: "Foreword";
59
+ }
60
+ }
61
+
62
+ @page introduction {
63
+ size: a4 portrait;
64
+ @top-middle {
65
+ content: "Introduction";
66
+ }
67
+ }
68
+
69
+ @page conclusion {
70
+ size: a4 portrait;
71
+ @top-middle {
72
+ content: "Conclusion";
73
+ }
74
+ }
75
+
76
+ @page chapter {
77
+ size: a4 landscape;
78
+ @top-middle {
79
+ content: "Chapter";
80
+ }
81
+ }
82
+
83
+ @media print {
84
+ fieldset {
85
+ display: none;
86
+ }
87
+ section {
88
+ font-size: 2rem;
89
+ font-family: Roboto;
90
+ }
91
+ .chapter {
92
+ border: tomato 2px solid;
93
+ }
94
+ [data-print="grouped"] > #toc,
95
+ [data-print="paged"] > #toc {
96
+ page: toc;
97
+ font-family: Courier;
98
+ }
99
+ [data-print="grouped"] > #foreword,
100
+ [data-print="paged"] > #foreword {
101
+ page: foreword;
102
+ font-family: Courier;
103
+ }
104
+ [data-print="grouped"] > #introduction,
105
+ [data-print="paged"] > #introduction {
106
+ page: introduction;
107
+ font-family: Courier;
108
+ }
109
+ [data-print="grouped"] > #conclusion,
110
+ [data-print="paged"] > #conclusion {
111
+ page: conclusion;
112
+ font-family: Courier;
113
+ }
114
+ [data-print="grouped"] > .chapter,
115
+ [data-print="paged"] > .chapter {
116
+ page: chapter;
117
+ }
118
+ [data-print="paged"] > .chapter {
119
+ border: none;
120
+ break-after: page;
121
+ }
122
+ .chapter > ul {
123
+ columns: 2;
124
+ }
125
+ }
126
+
127
+ </style>
128
+
129
+ <title>page - named_page_example - code sample</title>
130
+
131
+ </head>
132
+ <body>
133
+
134
+ <!-- print options 文档看 https://developer.mozilla.org/en-US/docs/Web/CSS/page#named_page_example
135
+ [data-print="paged"] > .chapter { 属性选择符号?
136
+ -->
137
+
138
+ <fieldset id="printStyle">
139
+ <legend>How would you like to print</legend>
140
+ <label for="single"
141
+ ><input type="radio" id="single" name="type" value="single" checked />No
142
+ Pages</label
143
+ >
144
+ <label for="grouped"
145
+ ><input type="radio" id="grouped" name="type" value="grouped" />Pages with
146
+ Grouped Chapters</label
147
+ >
148
+ <label for="paged"
149
+ ><input type="radio" id="paged" name="type" value="paged" />Chapters
150
+ Paged</label
151
+ >
152
+ <button id="print">Print</button>
153
+ </fieldset>
154
+ <!-- Content to be printed -->
155
+ <article id="print-area" data-print="single">
156
+ <section id="toc">
157
+ <h2>Table of contents</h2>
158
+ <ul>
159
+ <li>Foreword</li>
160
+ <li>Introduction</li>
161
+ <li>Chapter One - named pages</li>
162
+ <li>Chapter Two - page orientation</li>
163
+ <li>Chapter Three - page margins</li>
164
+ <li>Conclusion</li>
165
+ </ul>
166
+ </section>
167
+ <section id="foreword">
168
+ <h2>Foreword</h2>
169
+ <p>
170
+ This book is all about how the CSS <code>@page</code> at-rule can help
171
+ with printing HTML books.
172
+ </p>
173
+ </section>
174
+ <section id="introduction">
175
+ <h2>Introduction</h2>
176
+ <p>
177
+ This book is a concept to show how an <em>HTML</em> document can easily be
178
+ printed out in pages.
179
+ </p>
180
+ </section>
181
+ <section id="chapter1" class="chapter">
182
+ <h2>Named pages</h2>
183
+ <p>Lorem ipsum</p>
184
+ </section>
185
+ <section id="chapter2" class="chapter">
186
+ <h2>Page Orientation</h2>
187
+ <p>Lorem ipsum</p>
188
+ </section>
189
+ <section id="chapter3" class="chapter">
190
+ <h2>Page Margins</h2>
191
+ <p>There are 16 page margins that can be set:</p>
192
+ <ul>
193
+ <li>@top-left-corner</li>
194
+ <li>@top-left</li>
195
+ <li>@top-middle</li>
196
+ <li>@top-right</li>
197
+ <li>@top-right-corner</li>
198
+ <li>@left-top</li>
199
+ <li>@left-middle</li>
200
+ <li>@left-bottom</li>
201
+ <li>@right-top</li>
202
+ <li>@right-middle</li>
203
+ <li>@right-bottom</li>
204
+ <li>@bottom-left-corner</li>
205
+ <li>@bottom-left</li>
206
+ <li>@bottom-middle</li>
207
+ <li>@bottom-right</li>
208
+ <li>@bottom-right-corner</li>
209
+ </ul>
210
+ <p>They can be used to show what appears in these parts of the margin</p>
211
+ </section>
212
+ <section id="conclusion">
213
+ <h2>Conclusion</h2>
214
+ <p>Now go ahead and write books.</p>
215
+ </section>
216
+ </article>
217
+
218
+
219
+
220
+ <script>
221
+ const printArea = document.querySelector("#print-area");
222
+ const printButton = document.querySelector("#print");
223
+ const printOption = document.querySelector("#printStyle");
224
+ printOption.addEventListener("change", (event) => {
225
+ //对调paged single: ?? .dataset.print如何变身 data-print="single"属性值的??
226
+ if (event.target.value === "single") {
227
+ printArea.dataset.print = "paged";
228
+ } else if (event.target.value === "grouped") {
229
+ printArea.dataset.print = "grouped";
230
+ } else {
231
+ printArea.dataset.print = "single";
232
+ }
233
+ });
234
+ printButton.addEventListener("click", () => {
235
+ window.print();
236
+ });
237
+
238
+ </script>
239
+
240
+ </body>
241
+ </html>
@@ -0,0 +1,13 @@
1
+ import { Request, Response, NextFunction } from "express";
2
+
3
+ declare global {
4
+ type TodoType = any;
5
+ type Req = Request;
6
+ type Res = Response;
7
+ type NextFn = NextFunction;
8
+ type ResponseData<T> = {
9
+ opcode: number;
10
+ message: string;
11
+ data?: T;
12
+ };
13
+ }
@@ -0,0 +1,166 @@
1
+ import CONFIG from "@/configEnv";
2
+
3
+ export type getAppInfoQuery = `${Lowercase<keyof typeof CONFIG.APP>}`;
4
+
5
+ /**一次作业的模型配置;
6
+ * 若本对象为空{}的话:默认是按照修改时间的顺序简易模式地合并当前工作目录的所有pdf文件。
7
+ * 若某个URL不正常的,很可能无法触发页面加载完成,导致作业一致无法继续下去,大大超出预期执行时间。URL对应网页若不是一次性加载完成还会陆陆续续修改内容的就是这种情况造成死等长时间没结果。
8
+ * */
9
+ export interface ConfigRoot<T> {
10
+ //是否生成合并的pdf:正常情况下, 默认=true进行files输出pdf全部做合并的。 除非files[]也是空的情形。
11
+ //但若需对任一个URL叠加新页眉页脚的,merge就不能=false的。
12
+ merge?: boolean;
13
+ //重定义 合并的pdf文件名, 否则默认名。不需要加 .pdf结尾的
14
+ name: string;
15
+ //双面打印的合并输出pdf, 默认=true, 表示合并输出的pdf考虑到双面打印的页眉页脚的布局差异化情况了。
16
+ doubleSide?: boolean;
17
+ //统一一整份应该用的页眉页脚
18
+ //假如files[]里面有些url自己也定义了lay{localSumNo=false}的页眉页脚输出配置,只能忽略掉它们,页码总数不算他们的,页码连续编号也不算它们的占坑:最好都挪到最后面。
19
+ lay?: HeadFooter;
20
+ //每一个独立的pdf生成:
21
+ files: [T];
22
+
23
+ //共用一个浏览器窗口 默认=true
24
+ singleTab?: boolean;
25
+ //自动关闭浏览器窗口 默认=false
26
+ closeTab?: boolean;
27
+
28
+ //下面这5个参数不是前端配置发送过来的,而是lay{}对象预先进行转换后保存的汇总页眉页脚,只能内部使用,并非外部接口参数!Page.printToPDF需要的。
29
+ headerTemplate?: string;
30
+ footerTemplate?: string;
31
+ headerTemplateL?: string;
32
+ footerTemplateL?: string;
33
+ //第二阶段页眉页脚生成的浏览器执行窗口的targetId,不可配置。
34
+ CDPtab?: string;
35
+ }
36
+
37
+ /**等待输出的每个独立文件:URL,这些文件可能要合并。
38
+ * @前提条件 是:每个url独立文件生成的PDF,它的纸张大小必须保证同一个大小尺寸, size: 必须唯一,但是纸张方向在某些约束条件中可以横屏竖屏混合的。
39
+ * 物理打印机:纸张适配,横竖方向还好能自动调节,size 真实打印纸张尺寸就不好自动处理, 不一样的尺寸?最好拆解pdf。
40
+ * 标准纸张大小的:静态html内CSS定义横竖纸张方向混合的:用reverseRanges参数设置部分纸张反转纸张方向,pageRanges=''的前提下:配置比如'1-5, 8, 11-13'和landscape参数设置相反方向。
41
+ * */
42
+ export interface FileTransform {
43
+ //[必须配置的] 特殊的前缀是 http:// https:// 没有这俩个的都是本地工作目录的文件全名(含文件类型后缀 *.pdf *.*)。
44
+ //任意的本地文件类型,只要可以被Chrome装载并能够支持打印预览的都可以。http打头的网页必须确保已经登录了,也就是遗留cockies token,不能要求交互登录。本地文件不能要求输入口令。
45
+ //不支持*.xls *.doc文件;不支持的格式实际在浏览器拖拽窗口后会蜕变成了下载形式的。被加密的文件必须提前解密,网站登录需提前解决。
46
+ //【特殊问题】若URL网页动态化太离谱,周期性地不间断地更新页面,没法触发加载结束事件的,只能手动在浏览器查看打印另存pdf,然后把手动生成pdf合并进来。Tab切换会主动刷新的也不触发。
47
+ url: string;
48
+ //输出本地工作目录的文件名, 不需要加 .pdf结尾的 【注意】如果out为空表示url是pdf的没必要转换的要直接进入合并步骤。
49
+ //【特别】必须配置唯一性 的本地 工作目录的文件名,同名的被直接覆盖了。
50
+ out: string;
51
+
52
+ //是否汇总合并阶段省略本url,不合并进去,那就是单独独立的pdf输出了。默认=true是合并进去。 和是否打印页眉页脚或页眉统计页数没有绝对关系的。
53
+ merge?: boolean;
54
+
55
+ //默认取值都是=true; 第一阶段不会生成页眉页脚的,汇总第二阶段这个参数才会生效!
56
+ //这里配置displayHeaderFooter优先级最高。
57
+ //页眉页脚如何分开控制是否打印的: 可以把lay{head,foot}其中一个配置串给设置为null,null就代表不输出。例如head=null就不输出页眉,但是页脚照旧打印的。本url的配置优先于汇总pdf配置。
58
+ //若ConfigRoot<T>.merge=false那么必然导致FileTransform.merge强制=false,每个独立pdf页码独立的独立都从1开始编号吗还需要打印吗,页眉页脚需要打印吗?这个情况页眉页脚打印的默认值改成false;
59
+ displayHeaderFooter: boolean;
60
+
61
+ //【特别注意】frNo 可能和 headFrom 配置矛盾。
62
+ //本url打印:从第几页才开始页眉页脚的打印,#页码同样也是在这之后才可能计数和编号!。默认值headFrom=1:就是第一页就开始打印页眉页脚的。
63
+ //书本封面页情况的。这个参数有最高优先级。 【注意】和frNo设置相互影响, 没有页眉页脚就失去页码意义了。若真的违反了可能页码不能连续输出的,被隐藏了页码缘故。
64
+ headFrom?: number;
65
+ //本url打印后,从本URL输出的第几页开始才进行的页码序号的顺序输出的,前面几页不打印页码(但是页眉页脚要打印)。默认值=1全部都打页码。若frNo=0全部不打页码的。
66
+ //假如displayHeaderFooter=false也即页码无法显示出来的情况:请申明frNo=0; 不然默认是连续页码的,不打印的也有占用页码的隐藏的连续数字啊。
67
+ //注意若有配置 headFrom 的要协调好。
68
+ frNo?: number;
69
+
70
+ //是否对页码支持连续编号: Continuous numbering 是跟随汇总合并的页码 基数合计。【注意】本配置单个url范围,单个url不能混合本地页码和全局页面两种!
71
+ //统计页数是否本URL独立自己范围之内进行的汇总计数。比如书本目录有多页的可以独立统计页码序号以及总页数的。默认=false;
72
+ localSumNo?: boolean;
73
+ //本url对应的部分应该用的页眉页脚,覆盖掉合并pdf的相对应设置。页面上只能支持输出一次页眉页脚,不重叠做输出。
74
+ //若lay{localSumNo=false}只能固定支持本url自己内部的页码统计顺序编号,不考虑合并pdf总页数带来的影响的。 还是?预设其它部分的页数统计总数之后?再做偏移页码编写?
75
+ lay: PartHeadFooter;
76
+ //前端声明本url在第一阶段打印输出后,生成的pdf应该有几页。 count没有设置的救不会做异常检查的。不是第二阶段的计数:双面情况可能增加空白页
77
+ count?: number;
78
+ //双面打印的 默认=true, 表示独立分开输出的pdf文件的:考虑到双面打印的页眉页脚的布局差异化情况了。
79
+ //合并输出merge=true的情况:该参数无效,要看汇总配置的哪一个 # ConfigRoot<T>{ doubleSide: }字段。
80
+ doubleSide: boolean;
81
+ //双面打印的情形:必须确保本URL的第一个页是正好右手边(书本翻页的奇数号页码)开始的位置页。正常第一个URL首页面就是双面打印的右手边位置页;默认值=false不必确保.
82
+ rightHand: boolean;
83
+
84
+ //页码是罗马数字;论文目录需要的;默认=false阿拉伯数字。"I","II","III","IV","V","VI","VII","VIII","IX" "X"XI"XII"表盘符号
85
+ //roman只能针对本URL启用;数字转换范围最大支持1到12,超过了便改阿拉伯数字,且只针对pageNumber有效, totalPages不会采用。
86
+ roman?: boolean;
87
+
88
+ //下面这5个参数不是前端配置发送过来的,而是lay{}对象预先进行转换后保存的汇总页眉页脚,只能内部使用,并非外部接口参数!Page.printToPDF需要的。
89
+ headerTemplate?: string;
90
+ footerTemplate?: string;
91
+ headerTemplateL?: string;
92
+ footerTemplateL?: string;
93
+ //第一阶段Url转pdf的浏览器执行窗口的targetId,不可配置。
94
+ CDPtab?: string;
95
+ }
96
+
97
+ /*看 Page.printToPDF()文档说明的: 可以使用的注入参数:
98
+ date: formatted print date
99
+ title: document title
100
+ url: document location
101
+ pageNumber: current page number
102
+ totalPages: total pages in the document
103
+ For example, <span class=title></span> would generate span containing the title.
104
+ */
105
+
106
+ /**页眉页脚声明;前提条件是页眉页脚htm描述里面:不应该把-NOT_DISPLAY- ${pageNumber} ${totalPages}这三个保留字字符串当作普通文字输出的。
107
+ * 前端发送数据包时刻,页眉页脚的脚本需要在 HTML转JSON 工具网站 进行转换处理后的;网站地址 https://uutool.cn/html2json/ 转换htm模板后是数组[string]
108
+ * 实际上也就进行拆分多行字符串拼接数组,还有把html语法中的 ""引号 进行转义 style="position: 变成 style=\\\"position: 处置的。
109
+ * */
110
+ export interface HeadFooter {
111
+ //每一个URL独立设置的 页眉 的 : 若是配置值=null 表示不要打印本页眉: 针对本url。
112
+ //双面打印:右手边位置的,或单面打印使用
113
+ head?: string | string[] | null;
114
+ //每一个页 页脚的
115
+ //每一个URL独立设置的 页脚的 : 若是配置值=null 表示不要打印本页脚的, 针对本url。
116
+ //双面打印:右手边位置的,或单面打印使用
117
+ foot?: string | string[] | null; //实际前端发过来却是[string]的也可以啊。
118
+ /**可注入3个参数"特殊标记字符串"如下: 服务端依据参数来对注入的html进行修改的。
119
+ * ${pageNumber}
120
+ * ${totalPages}
121
+ * -NOT_DISPLAY-
122
+ * 这三个分别代表 页码 总页数 以及页码<div style=""></div>中的可替代占位位置。-NOT_DISPLAY-在后端要直接替代成display:none;的CSS标记字符串!其它2个替换成数字号码。
123
+ * */
124
+ //双面打印:左手边位置的
125
+ headL?: string | string[] | null;
126
+ //双面打印:左手边位置的
127
+ footL?: string | string[] | null;
128
+ }
129
+
130
+ /**实际在第二步骤也即汇总阶段:页眉页脚的生成底下的参数size,landscape,reverseRanges,marginLeft,marginRight几个都不会涉及到了。
131
+ * */
132
+ export interface PartHeadFooter extends HeadFooter {
133
+ //纸张大小: 纸张大小尺寸+布局方向是自定义系列的:
134
+ //a5 a4 a3 b5 b4 jis-b5 jis-b4 letter legal ledger auto 等常见的名字, 默认是 "a4 portrait"
135
+ //中国:默认值改成是 a4 portrait
136
+ size: string;
137
+ //W3C标准纸张大小,横着的吗; 但是非标准尺寸的#自定义的没有这个选择参数的!。 默认是 "portrait"
138
+ landscape: boolean;
139
+ //背景, 默认 =false
140
+ printBackground: boolean;
141
+
142
+ //底下的这四个参数默认都=1cm (~0.4 inches); 若要做配置的必须是英寸为单位的数字, 【单位 注意】
143
+ marginTop?: number;
144
+ marginBottom?: number;
145
+ //就算纸张是横屏的:Chrome生成页眉页脚的位置实际也没牵涉到marginLeft,marginRight;
146
+ marginLeft?: number;
147
+ marginRight?: number;
148
+ //默认全部打印的,#可自定义部分页面输出的。 Paper ranges to print, one based, e.g., '1-5, 8, 11-13'.
149
+ pageRanges?: string;
150
+ }
151
+
152
+ /**配置自定义地非标准纸张尺寸, 横竖纸张要独立配置。
153
+ * */
154
+ export interface MyPaperSize {
155
+ //自定义的尺寸名称 ,前端发送数据包时用这个名字 替换通常的 a4 a5 a3等,纸张横的竖的要定义两个标签。
156
+ name: string;
157
+ //W3C @page size{}语境中配的描述串。 如下:"4in 6in", 前面4英寸宽度的纸张。
158
+ //{"name":"D8", "css": "4in 6in","w": 4,"h": 6},
159
+ css: string;
160
+ //纸张 4 英寸宽度 "w": 4,
161
+ w: number;
162
+ //纸张高度: 英寸单位的,必须和css参数确保一致性。
163
+ h: number;
164
+ }
165
+
166
+ //【CDP文档】 https://chromedevtools.github.io/devtools-protocol/tot/Target/
@@ -0,0 +1,18 @@
1
+ /**拆分大的pdf文件,输出部分页数的小的pdf
2
+ * 支持按pdf纸张页面进行重新排序, 部分提取页数。
3
+ * */
4
+ export interface SplitConfig {
5
+ //等待拆分大的df文件名, 需要加 .pdf结尾的;只能是pdf文档!
6
+ input: string;
7
+ //每一个独立的pdf生成:
8
+ files: [SplitPdfFile];
9
+ }
10
+
11
+ export interface SplitPdfFile {
12
+ //定义部分页面输出的。 Paper ranges to print, one based, e.g., '1-5, 8, 11-13'.
13
+ pageRanges: string;
14
+ //输出本地工作目录的文件名, 不需要加 .pdf结尾的。
15
+ //【特别】必须配置唯一性 的本地 工作目录的文件名,同名的被直接覆盖了。
16
+ //拆分提取的pdf输出页面顺序是依据pageRanges所选定的顺序来输出的,不是原本pdf的顺序。
17
+ out: string;
18
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Application Information response strucuture.
3
+ */
4
+ interface AppInformation {
5
+ NAME: string;
6
+ VERSION: string;
7
+ }
8
+
9
+ export default AppInformation;
@@ -0,0 +1,5 @@
1
+ export interface ApiSuccessResponse<T> {
2
+ status: number;
3
+ message: string;
4
+ data?: T;
5
+ }
@@ -0,0 +1,19 @@
1
+ import { differenceWith, isEqual } from "lodash-es";
2
+
3
+ export interface ArrayDifference {
4
+ added: any[];
5
+ removed: any[];
6
+ }
7
+
8
+ /**
9
+ *
10
+ * @param {any[]} arr1
11
+ * @param {any[]} arr2
12
+ * @returns {ArrayDifference}
13
+ */
14
+ export const diff = (arr1: any[], arr2: any[]): ArrayDifference => {
15
+ const added = differenceWith(arr2, arr1, isEqual);
16
+ const removed = differenceWith(arr1, arr2, isEqual);
17
+
18
+ return { added, removed };
19
+ };
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @description hide password content with '*'
3
+ * @param {object} bodyData
4
+ * @returns bodyData with formatted 'password'
5
+ */
6
+ export const hidePassword = (bodyData: Record<string, any>) => {
7
+ if (bodyData.hasOwnProperty("password")) {
8
+ bodyData.password = "********";
9
+ }
10
+
11
+ return bodyData;
12
+ };
@@ -0,0 +1,26 @@
1
+ import bcrypt from "bcrypt";
2
+ import CONFIG from "@/configEnv";
3
+
4
+ /**
5
+ * @description Create a bcrypt hash for a string.
6
+ * @param {string} value
7
+ * @returns {Promise<any>}
8
+ */
9
+ export const hash = async (value: string): Promise<any> => {
10
+ const saltRounds = parseInt(CONFIG.AUTH.SALT_ROUNDS, 10);
11
+
12
+ return bcrypt.hash(value, saltRounds);
13
+ };
14
+
15
+ /**
16
+ * @description Compare a string with the hash.
17
+ * @param {string} value
18
+ * @param {string} hashedValue
19
+ * @returns {Promise<boolean>}
20
+ */
21
+ export const compare = async (
22
+ value: string,
23
+ hashedValue: string,
24
+ ): Promise<boolean> => {
25
+ return bcrypt.compare(value, hashedValue);
26
+ };
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Converts empty value to null.
3
+ *
4
+ * @param obj
5
+ * @returns {*}
6
+ */
7
+ export const emptyToNull = (obj: any): any => {
8
+ if (isScalarType(obj)) {
9
+ return obj;
10
+ }
11
+
12
+ if (Array.isArray(obj)) {
13
+ return obj.map(emptyToNull);
14
+ }
15
+
16
+ const result: any = {};
17
+
18
+ for (const key of Object.keys(obj)) {
19
+ const value = obj[key];
20
+
21
+ if (typeof value === "object") {
22
+ result[key] = emptyToNull(value);
23
+ } else {
24
+ result[key] = nullIfEmpty(value);
25
+ }
26
+ }
27
+
28
+ return result;
29
+ };
30
+
31
+ /**
32
+ * Returns if scalar type.
33
+ *
34
+ * @param obj
35
+ * @returns {boolean}
36
+ */
37
+ const isScalarType = (obj: any) => {
38
+ return (
39
+ typeof obj !== "object" ||
40
+ obj instanceof String ||
41
+ obj instanceof Number ||
42
+ obj instanceof Boolean ||
43
+ obj === null
44
+ );
45
+ };
46
+
47
+ /**
48
+ * Changes empty value to null.
49
+ *
50
+ * @param value
51
+ * @returns {*}
52
+ */
53
+ const nullIfEmpty = (value: any) => {
54
+ if (typeof value !== "string") {
55
+ return value;
56
+ }
57
+
58
+ return value.trim() === "" ? null : value;
59
+ };