job51-gitlab-cr-node-skill-prompt-optimize 1.3.6 → 1.3.8
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/.claude/settings.local.json +8 -0
- package/PDF_CONVERSION_README.md +131 -0
- package/convert-report-to-pdf.js +240 -0
- package/mr-review-template.md +9 -9
- package/package.json +1 -1
- package/print-div-pdf.html +167 -0
- package/refactor(ci)_ /346/233/264/346/226/260GitLab CI/351/205/215/347/275/256/345/271/266/344/274/230/345/214/226/347/253/236/344/272/211/345/210/206/346/236/220/346/227/245/345/277/227/346/234/215/345/212/241 (!118) /302/267 Merge requests /302/267 51JobWeb _ dev-boot-test /302/267 GitLab.pdf +0 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# 代码审查报告转PDF工具使用说明
|
|
2
|
+
|
|
3
|
+
## 问题分析
|
|
4
|
+
|
|
5
|
+
您发现当前系统存在以下问题:
|
|
6
|
+
1. `mr-review-template.md` 是一个用于代码审查的提示词模板
|
|
7
|
+
2. 当前目录的PDF文件是从GitLab网页导出的页面快照,不是代码审查报告
|
|
8
|
+
3. 代码审查系统的输出直接发布到GitLab MR中,而不是保存为本地PDF
|
|
9
|
+
|
|
10
|
+
## 解决方案
|
|
11
|
+
|
|
12
|
+
我已创建了一个工具脚本 `convert-report-to-pdf.js` 来解决这个问题:
|
|
13
|
+
|
|
14
|
+
### 功能说明
|
|
15
|
+
|
|
16
|
+
1. **读取审查报告**:从包含 `<REPORT>` 和 `</REPORT>` 标签的文件中提取审查报告内容
|
|
17
|
+
2. **格式转换**:将Markdown格式的报告转换为适合打印的HTML格式
|
|
18
|
+
3. **生成可打印文档**:创建带有适当样式的HTML文档,方便转换为PDF
|
|
19
|
+
|
|
20
|
+
### 使用方法
|
|
21
|
+
|
|
22
|
+
#### 1. 生成代码审查报告
|
|
23
|
+
|
|
24
|
+
首先,确保您有代码审查系统的输出文件。如果您还没有实际的审查报告,可以使用以下示例:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# 创建示例审查报告文件
|
|
28
|
+
echo '<REPORT>
|
|
29
|
+
## 🤖 AI代码审查结果
|
|
30
|
+
|
|
31
|
+
**生成时间**: 2026-03-09 09:30:00
|
|
32
|
+
**审查范围**: 2个文件(仅统计有代码变更的文件)
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
### 审查总览
|
|
37
|
+
|
|
38
|
+
本次审查发现了1个严重问题和2个优化建议,主要涉及安全性、代码可读性和性能方面的问题。
|
|
39
|
+
|
|
40
|
+
### 🔴 严重问题
|
|
41
|
+
|
|
42
|
+
①:在UserService.java文件中,数据库查询缺少输入验证,可能存在SQL注入风险
|
|
43
|
+
**文件及行号**:UserService.java:125-130
|
|
44
|
+
**修改建议**:使用参数化查询替换字符串拼接方式,防止SQL注入攻击
|
|
45
|
+
错误代码:
|
|
46
|
+
```java
|
|
47
|
+
String sql = "SELECT * FROM users WHERE id = " + userId;
|
|
48
|
+
```
|
|
49
|
+
正确示例代码:
|
|
50
|
+
```java
|
|
51
|
+
String sql = "SELECT * FROM users WHERE id = ?";
|
|
52
|
+
PreparedStatement stmt = connection.prepareStatement(sql);
|
|
53
|
+
stmt.setString(1, userId);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 🟢 优化建议
|
|
57
|
+
|
|
58
|
+
**文件及行号**:UserController.java:45-50
|
|
59
|
+
**优化建议**:方法中存在重复代码,建议提取为公共方法提高可维护性
|
|
60
|
+
**示例代码**:
|
|
61
|
+
```java
|
|
62
|
+
// 原代码
|
|
63
|
+
public void updateUser(Long id, String name) {
|
|
64
|
+
validateUser(id);
|
|
65
|
+
validateName(name);
|
|
66
|
+
// ... update logic
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public void createUser(String name) {
|
|
70
|
+
validateUser(null); // 重复的验证逻辑
|
|
71
|
+
validateName(name);
|
|
72
|
+
// ... create logic
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**文件及行号**:ConfigService.java:78-82
|
|
77
|
+
**优化建议**:配置项可以使用枚举类型提高类型安全
|
|
78
|
+
**示例代码**:
|
|
79
|
+
```java
|
|
80
|
+
// 原代码
|
|
81
|
+
public static final String DB_TYPE_MYSQL = "mysql";
|
|
82
|
+
public static final String DB_TYPE_POSTGRES = "postgres";
|
|
83
|
+
|
|
84
|
+
// 建议
|
|
85
|
+
public enum DbType {
|
|
86
|
+
MYSQL("mysql"),
|
|
87
|
+
POSTGRES("postgres");
|
|
88
|
+
|
|
89
|
+
private final String value;
|
|
90
|
+
DbType(String value) { this.value = value; }
|
|
91
|
+
public String getValue() { return value; }
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 🔄 上下文影响分析(需涵盖依赖关系、功能关联性、兼容性风险三个维度)
|
|
96
|
+
|
|
97
|
+
**受影响组件**: 用户管理模块、数据库访问层
|
|
98
|
+
**影响描述**: 如果不修复SQL注入问题,可能导致数据库被恶意查询,造成数据泄露
|
|
99
|
+
**验证建议**: 使用恶意输入测试数据库查询接口,确认是否能阻止非法输入
|
|
100
|
+
|
|
101
|
+
</REPORT>' > sample-review-report.txt
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
#### 2. 转换为PDF可用的HTML格式
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
node convert-report-to-pdf.js sample-review-report.txt review-report.html
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
#### 3. 转换为PDF
|
|
111
|
+
|
|
112
|
+
1. 在浏览器中打开生成的 `review-report.html` 文件
|
|
113
|
+
2. 按 `Ctrl+P` 打开打印对话框
|
|
114
|
+
3. 选择 "另存为PDF" 作为打印机
|
|
115
|
+
4. 设置页面为A4或Letter格式
|
|
116
|
+
5. 点击保存
|
|
117
|
+
|
|
118
|
+
### 注意事项
|
|
119
|
+
|
|
120
|
+
- 转换脚本会保留报告的格式和结构
|
|
121
|
+
- HTML文件包含了自动生成PDF的JavaScript代码(在浏览器中)
|
|
122
|
+
- 如果您的审查报告格式与此不同,可以调整 `convert-report-to-pdf.js` 中的解析逻辑
|
|
123
|
+
|
|
124
|
+
## 完整的工作流程
|
|
125
|
+
|
|
126
|
+
1. 使用 `index.js` 运行代码审查并获得报告输出
|
|
127
|
+
2. 将审查结果保存到文件(包含 `<REPORT>` 标签)
|
|
128
|
+
3. 使用 `convert-report-to-pdf.js` 转换为HTML格式
|
|
129
|
+
4. 在浏览器中打开HTML文件并打印为PDF
|
|
130
|
+
|
|
131
|
+
这样您就可以得到一个格式良好的PDF版本的代码审查报告了。
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 将代码审查报告转换为PDF的HTML模板
|
|
8
|
+
*/
|
|
9
|
+
function createHtmlTemplate(reportContent) {
|
|
10
|
+
return `
|
|
11
|
+
<!DOCTYPE html>
|
|
12
|
+
<html lang="zh-CN">
|
|
13
|
+
<head>
|
|
14
|
+
<meta charset="UTF-8">
|
|
15
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
16
|
+
<title>AI代码审查报告</title>
|
|
17
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
|
18
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
|
19
|
+
<style>
|
|
20
|
+
body {
|
|
21
|
+
font-family: Arial, sans-serif;
|
|
22
|
+
padding: 20px;
|
|
23
|
+
line-height: 1.6;
|
|
24
|
+
}
|
|
25
|
+
.report-container {
|
|
26
|
+
max-width: 800px;
|
|
27
|
+
margin: 0 auto;
|
|
28
|
+
border: 1px solid #ddd;
|
|
29
|
+
padding: 30px;
|
|
30
|
+
background-color: #fff;
|
|
31
|
+
}
|
|
32
|
+
h1, h2, h3 {
|
|
33
|
+
color: #333;
|
|
34
|
+
}
|
|
35
|
+
h1 {
|
|
36
|
+
border-bottom: 2px solid #4CAF50;
|
|
37
|
+
padding-bottom: 10px;
|
|
38
|
+
}
|
|
39
|
+
h2 {
|
|
40
|
+
color: #2196F3;
|
|
41
|
+
border-left: 4px solid #2196F3;
|
|
42
|
+
padding-left: 10px;
|
|
43
|
+
margin-top: 25px;
|
|
44
|
+
}
|
|
45
|
+
.severity-high {
|
|
46
|
+
border-left: 4px solid #f44336;
|
|
47
|
+
background-color: #ffebee;
|
|
48
|
+
padding: 10px;
|
|
49
|
+
margin: 10px 0;
|
|
50
|
+
}
|
|
51
|
+
.severity-medium {
|
|
52
|
+
border-left: 4px solid #ff9800;
|
|
53
|
+
background-color: #fff3e0;
|
|
54
|
+
padding: 10px;
|
|
55
|
+
margin: 10px 0;
|
|
56
|
+
}
|
|
57
|
+
.severity-low {
|
|
58
|
+
border-left: 4px solid #4CAF50;
|
|
59
|
+
background-color: #e8f5e8;
|
|
60
|
+
padding: 10px;
|
|
61
|
+
margin: 10px 0;
|
|
62
|
+
}
|
|
63
|
+
.code-block {
|
|
64
|
+
background-color: #f5f5f5;
|
|
65
|
+
border: 1px solid #ddd;
|
|
66
|
+
border-radius: 4px;
|
|
67
|
+
padding: 10px;
|
|
68
|
+
overflow-x: auto;
|
|
69
|
+
font-family: monospace;
|
|
70
|
+
white-space: pre-wrap;
|
|
71
|
+
}
|
|
72
|
+
.file-info {
|
|
73
|
+
background-color: #e3f2fd;
|
|
74
|
+
padding: 8px;
|
|
75
|
+
border-radius: 4px;
|
|
76
|
+
margin: 5px 0;
|
|
77
|
+
}
|
|
78
|
+
ul {
|
|
79
|
+
padding-left: 20px;
|
|
80
|
+
}
|
|
81
|
+
li {
|
|
82
|
+
margin: 8px 0;
|
|
83
|
+
}
|
|
84
|
+
</style>
|
|
85
|
+
</head>
|
|
86
|
+
<body>
|
|
87
|
+
<div class="report-container">
|
|
88
|
+
${reportContent}
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<script>
|
|
92
|
+
// 页面加载完成后自动转换为PDF(可选)
|
|
93
|
+
function convertToPdf() {
|
|
94
|
+
const { jsPDF } = window.jspdf;
|
|
95
|
+
const element = document.querySelector('.report-container');
|
|
96
|
+
|
|
97
|
+
html2canvas(element, {
|
|
98
|
+
scale: 2,
|
|
99
|
+
useCORS: true,
|
|
100
|
+
backgroundColor: '#ffffff'
|
|
101
|
+
}).then(canvas => {
|
|
102
|
+
const imgData = canvas.toDataURL('image/png');
|
|
103
|
+
const pdf = new jsPDF('p', 'mm', 'a4');
|
|
104
|
+
const imgWidth = 210;
|
|
105
|
+
const pageHeight = 295;
|
|
106
|
+
const imgHeight = canvas.height * imgWidth / canvas.width;
|
|
107
|
+
|
|
108
|
+
let heightLeft = imgHeight;
|
|
109
|
+
let position = 0;
|
|
110
|
+
|
|
111
|
+
pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
|
|
112
|
+
heightLeft -= pageHeight;
|
|
113
|
+
|
|
114
|
+
while (heightLeft >= 0) {
|
|
115
|
+
position = heightLeft - imgHeight;
|
|
116
|
+
pdf.addPage();
|
|
117
|
+
pdf.addImage(imgData, 'PNG', 0, position, imgHeight > pageHeight ? imgWidth : imgWidth, imgHeight > pageHeight ? pageHeight : imgHeight);
|
|
118
|
+
heightLeft -= pageHeight;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
pdf.save('ai-code-review-report.pdf');
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 5秒后自动执行转换,或用户手动调用
|
|
126
|
+
// setTimeout(convertToPdf, 5000);
|
|
127
|
+
</script>
|
|
128
|
+
</body>
|
|
129
|
+
</html>`;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* 将Markdown格式的报告转换为HTML
|
|
134
|
+
*/
|
|
135
|
+
function mdToHtml(mdContent) {
|
|
136
|
+
// 简单的Markdown到HTML转换
|
|
137
|
+
let html = mdContent;
|
|
138
|
+
|
|
139
|
+
// 转义HTML特殊字符
|
|
140
|
+
html = html.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
141
|
+
|
|
142
|
+
// 标题
|
|
143
|
+
html = html.replace(/^###\s+(.*)$/gm, '<h3>$1</h3>');
|
|
144
|
+
html = html.replace(/^##\s+(.*)$/gm, '<h2>$1</h2>');
|
|
145
|
+
html = html.replace(/^#\s+(.*)$/gm, '<h1>$1</h1>');
|
|
146
|
+
|
|
147
|
+
// 段落
|
|
148
|
+
html = html.replace(/^\s*(.+)$/gm, '<p>$1</p>');
|
|
149
|
+
|
|
150
|
+
// 特殊标记(严重问题、警告、优化建议)
|
|
151
|
+
html = html.replace(/🔴\s+严重问题/g, '<h2 class="severity-high-title">🔴 严重问题</h2>');
|
|
152
|
+
html = html.replace(/🟡\s+警告/g, '<h2 class="severity-medium-title">🟡 警告</h2>');
|
|
153
|
+
html = html.replace(/🟢\s+优化建议/g, '<h2 class="severity-low-title">🟢 优化建议</h2>');
|
|
154
|
+
|
|
155
|
+
// 回滚之前的替换,只处理行首的标题
|
|
156
|
+
html = html.replace(/<p>##\s+(.*?)<\/p>/g, '<h2>$1</h2>');
|
|
157
|
+
html = html.replace(/<p>###\s+(.*?)<\/p>/g, '<h3>$1</h3>');
|
|
158
|
+
|
|
159
|
+
// 文件和行号信息
|
|
160
|
+
html = html.replace(/\*\*文件及行号\*\*:([^\n<]+)/g, '<div class="file-info"><strong>文件及行号:</strong>$1</div>');
|
|
161
|
+
|
|
162
|
+
// 修改建议和示例代码
|
|
163
|
+
html = html.replace(/\*\*修改建议\*\*:([\s\S]*?)(?=<div class="file-info"|<h2>|<\/div>|$)/g,
|
|
164
|
+
'<div class="severity-high"><strong>修改建议:</strong><br>$1</div>');
|
|
165
|
+
html = html.replace(/\*\*优化建议\*\*:([\s\S]*?)(?=<div class="file-info"|<h2>|<\/div>|$)/g,
|
|
166
|
+
'<div class="severity-low"><strong>优化建议:</strong><br>$1</div>');
|
|
167
|
+
|
|
168
|
+
// 代码块
|
|
169
|
+
html = html.replace(/```([\s\S]*?)```/g, '<div class="code-block">$1</div>');
|
|
170
|
+
|
|
171
|
+
// 换行处理
|
|
172
|
+
html = html.replace(/\n/g, '<br>');
|
|
173
|
+
|
|
174
|
+
// 恢复一些必要的换行和结构
|
|
175
|
+
html = html.replace(/<br><\/div>/g, '</div>');
|
|
176
|
+
html = html.replace(/<br><\/h2>/g, '</h2>');
|
|
177
|
+
html = html.replace(/<br><\/h3>/g, '</h3>');
|
|
178
|
+
html = html.replace(/<br><\/p>/g, '</p>');
|
|
179
|
+
html = html.replace(/<br><\/strong>/g, '</strong>');
|
|
180
|
+
|
|
181
|
+
return html;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* 从文件读取审查报告并转换为PDF可用的HTML
|
|
186
|
+
*/
|
|
187
|
+
function convertReviewReportToPdfHtml(inputFilePath, outputHtmlPath) {
|
|
188
|
+
try {
|
|
189
|
+
// 读取输入文件
|
|
190
|
+
const content = fs.readFileSync(inputFilePath, 'utf8');
|
|
191
|
+
|
|
192
|
+
// 如果内容被REPORT标签包围,只提取标签内的内容
|
|
193
|
+
const reportMatch = content.match(/<REPORT>([\s\S]*?)<\/REPORT>/);
|
|
194
|
+
const reportContent = reportMatch ? reportMatch[1] : content;
|
|
195
|
+
|
|
196
|
+
// 转换Markdown为HTML
|
|
197
|
+
const htmlContent = mdToHtml(reportContent);
|
|
198
|
+
|
|
199
|
+
// 创建完整的HTML文档
|
|
200
|
+
const fullHtml = createHtmlTemplate(htmlContent);
|
|
201
|
+
|
|
202
|
+
// 写入输出文件
|
|
203
|
+
fs.writeFileSync(outputHtmlPath, fullHtml);
|
|
204
|
+
|
|
205
|
+
console.log(`✅ 已成功将代码审查报告转换为HTML格式: ${outputHtmlPath}`);
|
|
206
|
+
console.log(`💡 要生成PDF,请在浏览器中打开此HTML文件并使用Ctrl+P打印为PDF`);
|
|
207
|
+
|
|
208
|
+
return true;
|
|
209
|
+
} catch (error) {
|
|
210
|
+
console.error('❌ 转换过程中发生错误:', error.message);
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// 如果直接运行此脚本
|
|
216
|
+
if (require.main === module) {
|
|
217
|
+
const args = process.argv.slice(2);
|
|
218
|
+
|
|
219
|
+
if (args.length < 2) {
|
|
220
|
+
console.log('📝 使用方法:');
|
|
221
|
+
console.log(' node convert-report-to-pdf.js <输入报告文件> <输出HTML文件>');
|
|
222
|
+
console.log('');
|
|
223
|
+
console.log('📖 示例:');
|
|
224
|
+
console.log(' node convert-report-to-pdf.js review-output.txt review-report.html');
|
|
225
|
+
console.log('');
|
|
226
|
+
console.log('💡 提示: 生成的HTML文件可以直接在浏览器中打开,然后使用打印功能保存为PDF');
|
|
227
|
+
process.exit(1);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const inputPath = args[0];
|
|
231
|
+
const outputPath = args[1];
|
|
232
|
+
|
|
233
|
+
convertReviewReportToPdfHtml(inputPath, outputPath);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
module.exports = {
|
|
237
|
+
convertReviewReportToPdfHtml,
|
|
238
|
+
createHtmlTemplate,
|
|
239
|
+
mdToHtml
|
|
240
|
+
};
|
package/mr-review-template.md
CHANGED
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
> - 问题行号必须是变更后代码的实际行号,不得引用变更前行号
|
|
66
66
|
> - 若问题涉及多行,行号范围应覆盖完整问题代码块(如 84-93)
|
|
67
67
|
> - **重要**:行号对应的代码必须是变更后保留的代码,不得指向已删除的代码行
|
|
68
|
-
15. `<REPORT
|
|
68
|
+
15. `<REPORT>`标签的每一个标题内都有两个问题块,这里只是进行示例,表示有不止一个问题时应该怎么展示,不是说每一个标题下必须有两个问题,具体问题的数量由review的结果决定,按原始代码块中对应代码的顺序依次展示即可
|
|
69
69
|
16. **输出前必须执行去重检查**:
|
|
70
70
|
> - **第一步:收集所有问题的文件及行号信息**
|
|
71
71
|
> - **第二步:检查是否存在行号重叠**(完全相同或有交集即视为重叠)
|
|
@@ -132,42 +132,42 @@
|
|
|
132
132
|
|
|
133
133
|
### 🔴 严重问题
|
|
134
134
|
|
|
135
|
-
[带圈数字序号,如:①,字体格式和后续问题描述一致]
|
|
135
|
+
[带圈数字序号,如:①,字体格式和后续问题描述一致][具体问题描述]<br/>
|
|
136
136
|
**文件及行号**:[问题所在文件相关代码块开始至结束行号,格式类似:ApplyPushServiceImpl.java:176-180]<br/>
|
|
137
137
|
**修改建议**:[修复建议,展示错误代码及对应修改后的示例代码,注意:错误代码和正确示例代码是必须存在的部分!!!]
|
|
138
138
|
|
|
139
|
-
[带圈数字序号,如:②,字体格式和后续问题描述一致]
|
|
139
|
+
[带圈数字序号,如:②,字体格式和后续问题描述一致][具体问题描述]<br/>
|
|
140
140
|
**文件及行号**:[问题所在文件相关代码块开始至结束行号,格式类似:ApplyPushServiceImpl.java:176-180]<br/>
|
|
141
141
|
**修改建议**:[修复建议,展示错误代码及对应修改后的示例代码,注意:错误代码和正确示例代码是必须存在的部分!!!]
|
|
142
142
|
|
|
143
143
|
### 🟡 警告
|
|
144
144
|
|
|
145
|
-
[带圈数字序号,如:①,字体格式和后续问题描述一致]
|
|
145
|
+
[带圈数字序号,如:①,字体格式和后续问题描述一致][具体问题描述]<br/>
|
|
146
146
|
**文件及行号**:[问题所在文件相关代码块开始至结束行号,格式类似:ApplyPushServiceImpl.java:176-180]<br/>
|
|
147
147
|
**修改建议**:[改进建议,展示相应代码及对应修改后的示例代码]
|
|
148
148
|
|
|
149
|
-
[带圈数字序号,如:②,字体格式和后续问题描述一致]
|
|
149
|
+
[带圈数字序号,如:②,字体格式和后续问题描述一致][具体问题描述]<br/>
|
|
150
150
|
**文件及行号**:[问题所在文件相关代码块开始至结束行号,格式类似:ApplyPushServiceImpl.java:176-180]<br/>
|
|
151
151
|
**修改建议**:[改进建议,展示相应代码及对应修改后的示例代码]
|
|
152
152
|
|
|
153
153
|
### 🟢 优化建议
|
|
154
154
|
|
|
155
|
+
[带圈数字序号,如:①,字体格式和后续优化建议一致][优化建议及可以直接使用的修改提示词]<br/>
|
|
155
156
|
**文件及行号**:[问题所在文件相关代码块开始至结束行号,格式类似:ApplyPushServiceImpl.java:176-180]<br/>
|
|
156
|
-
**优化建议**:[优化建议及可以直接使用的修改提示词]<br/>
|
|
157
157
|
**示例代码**:[展示相应代码及对应修改优化后的示例代码]
|
|
158
158
|
|
|
159
|
+
[带圈数字序号,如:②,字体格式和后续优化建议一致][优化建议及可以直接使用的修改提示词]<br/>
|
|
159
160
|
**文件及行号**:[问题所在文件相关代码块开始至结束行号,格式类似:ApplyPushServiceImpl.java:176-180]<br/>
|
|
160
|
-
**优化建议**:[优化建议及可以直接使用的修改提示词]<br/>
|
|
161
161
|
**示例代码**:[展示相应代码及对应修改优化后的示例代码]
|
|
162
162
|
|
|
163
163
|
### 🔄 上下文影响分析(需涵盖依赖关系、功能关联性、兼容性风险三个维度)
|
|
164
164
|
|
|
165
|
+
[带圈数字序号,如:①,字体格式和影响描述建议一致][影响描述:功能正确性影响、性能影响、兼容性影响(如API变更导致的下游系统影响)]<br/>
|
|
165
166
|
**受影响组件**: [直接依赖的类/方法/模块、间接关联的功能模块]<br/>
|
|
166
|
-
**影响描述**: [功能正确性影响、性能影响、兼容性影响(如API变更导致的下游系统影响)]<br/>
|
|
167
167
|
**验证建议**: [如何验证是否存在此问题]
|
|
168
168
|
|
|
169
|
+
[带圈数字序号,如:②,字体格式和影响描述建议一致][影响描述:功能正确性影响、性能影响、兼容性影响(如API变更导致的下游系统影响)]<br/>
|
|
169
170
|
**受影响组件**: [直接依赖的类/方法/模块、间接关联的功能模块]<br/>
|
|
170
|
-
**影响描述**: [功能正确性影响、性能影响、兼容性影响(如API变更导致的下游系统影响)]<br/>
|
|
171
171
|
**验证建议**: [如何验证是否存在此问题]
|
|
172
172
|
|
|
173
173
|
</REPORT>
|
package/package.json
CHANGED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>打印Div为PDF示例</title>
|
|
7
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
|
8
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
|
9
|
+
<style>
|
|
10
|
+
body {
|
|
11
|
+
font-family: Arial, sans-serif;
|
|
12
|
+
padding: 20px;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
#contentToPrint {
|
|
16
|
+
border: 2px solid #ccc;
|
|
17
|
+
padding: 20px;
|
|
18
|
+
margin: 20px 0;
|
|
19
|
+
background-color: #f9f9f9;
|
|
20
|
+
min-height: 300px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
button {
|
|
24
|
+
background-color: #4CAF50;
|
|
25
|
+
color: white;
|
|
26
|
+
padding: 10px 20px;
|
|
27
|
+
border: none;
|
|
28
|
+
cursor: pointer;
|
|
29
|
+
border-radius: 4px;
|
|
30
|
+
font-size: 16px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
button:hover {
|
|
34
|
+
background-color: #45a049;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
h2 {
|
|
38
|
+
color: #333;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
p {
|
|
42
|
+
line-height: 1.6;
|
|
43
|
+
}
|
|
44
|
+
</style>
|
|
45
|
+
</head>
|
|
46
|
+
<body>
|
|
47
|
+
<h1>打印Div为PDF示例</h1>
|
|
48
|
+
|
|
49
|
+
<button onclick="printDivToPDF()">打印指定区域为PDF</button>
|
|
50
|
+
|
|
51
|
+
<div id="contentToPrint">
|
|
52
|
+
<h2>这是一个要打印到PDF的区域</h2>
|
|
53
|
+
<p>这里是第一段内容。这是一些测试文本,用来展示如何将特定的div区域打印为PDF。</p>
|
|
54
|
+
<p>这里是第二段内容。可以看到我们有丰富的文本内容可以被转换成PDF。</p>
|
|
55
|
+
<ul>
|
|
56
|
+
<li>列表项 1</li>
|
|
57
|
+
<li>列表项 2</li>
|
|
58
|
+
<li>列表项 3</li>
|
|
59
|
+
</ul>
|
|
60
|
+
<p>最后的段落,展示更多内容。</p>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<div>
|
|
64
|
+
<p>这个区域不会被打印到PDF中,因为它不在目标div内。</p>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<script>
|
|
68
|
+
// 获取jsPDF实例
|
|
69
|
+
const { jsPDF } = window.jspdf;
|
|
70
|
+
|
|
71
|
+
function printDivToPDF() {
|
|
72
|
+
// 获取要打印的div元素
|
|
73
|
+
const element = document.getElementById('contentToPrint');
|
|
74
|
+
|
|
75
|
+
// 使用html2canvas将div转换为canvas
|
|
76
|
+
html2canvas(element, {
|
|
77
|
+
scale: 2, // 提高清晰度
|
|
78
|
+
useCORS: true, // 允许跨域图像
|
|
79
|
+
backgroundColor: '#ffffff' // 设置背景色
|
|
80
|
+
}).then(canvas => {
|
|
81
|
+
// 将canvas转换为数据URL
|
|
82
|
+
const imgData = canvas.toDataURL('image/png');
|
|
83
|
+
|
|
84
|
+
// 创建PDF
|
|
85
|
+
const pdf = new jsPDF('p', 'mm', 'a4');
|
|
86
|
+
|
|
87
|
+
// 计算图片在PDF中的尺寸以适应页面宽度
|
|
88
|
+
const imgWidth = 210; // A4页面宽度(mm)
|
|
89
|
+
const pageHeight = 295; // A4页面高度(mm)
|
|
90
|
+
const imgHeight = canvas.height * imgWidth / canvas.width;
|
|
91
|
+
|
|
92
|
+
let heightLeft = imgHeight;
|
|
93
|
+
let position = 0;
|
|
94
|
+
|
|
95
|
+
// 第一页添加图像
|
|
96
|
+
pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
|
|
97
|
+
heightLeft -= pageHeight;
|
|
98
|
+
|
|
99
|
+
// 如果内容超过一页,则添加新页
|
|
100
|
+
while (heightLeft >= 0) {
|
|
101
|
+
position = heightLeft - imgHeight;
|
|
102
|
+
pdf.addPage();
|
|
103
|
+
pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
|
|
104
|
+
heightLeft -= pageHeight;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 保存PDF
|
|
108
|
+
pdf.save('div-content.pdf');
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 纯函数版本:将div转换为PDF的可重用函数
|
|
113
|
+
function divToPDF(divId, filename = 'output.pdf') {
|
|
114
|
+
return new Promise((resolve, reject) => {
|
|
115
|
+
const element = document.getElementById(divId);
|
|
116
|
+
|
|
117
|
+
if (!element) {
|
|
118
|
+
reject(new Error(`Element with id '${divId}' not found`));
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
html2canvas(element, {
|
|
123
|
+
scale: 2,
|
|
124
|
+
useCORS: true,
|
|
125
|
+
backgroundColor: '#ffffff'
|
|
126
|
+
}).then(canvas => {
|
|
127
|
+
const imgData = canvas.toDataURL('image/png');
|
|
128
|
+
|
|
129
|
+
const pdf = new jsPDF('p', 'mm', 'a4');
|
|
130
|
+
const imgWidth = 210;
|
|
131
|
+
const pageHeight = 295;
|
|
132
|
+
const imgHeight = canvas.height * imgWidth / canvas.width;
|
|
133
|
+
|
|
134
|
+
let heightLeft = imgHeight;
|
|
135
|
+
let position = 0;
|
|
136
|
+
|
|
137
|
+
pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
|
|
138
|
+
heightLeft -= pageHeight;
|
|
139
|
+
|
|
140
|
+
while (heightLeft >= 0) {
|
|
141
|
+
position = heightLeft - imgHeight;
|
|
142
|
+
pdf.addPage();
|
|
143
|
+
pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
|
|
144
|
+
heightLeft -= pageHeight;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
pdf.save(filename);
|
|
148
|
+
resolve(pdf);
|
|
149
|
+
}).catch(error => {
|
|
150
|
+
reject(error);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// 示例:使用纯函数版本
|
|
156
|
+
function printWithFunction() {
|
|
157
|
+
divToPDF('contentToPrint', 'my-document.pdf')
|
|
158
|
+
.then(() => {
|
|
159
|
+
console.log('PDF已成功生成');
|
|
160
|
+
})
|
|
161
|
+
.catch(error => {
|
|
162
|
+
console.error('生成PDF时出错:', error);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
</script>
|
|
166
|
+
</body>
|
|
167
|
+
</html>
|