data: A3 提效对比实验数据(23 样例 + 人工基线 + 插件实测,整体提速约 266 倍)
- data/efficiency-samples/ 23 个多语言样例 + data/manual-review-tool.html 人工审核工具 - tests/measure/measure-plugin-samples.mjs 四语言插件侧测量脚本 - tests/measure/compare-a3.mjs 聚合对比 + results(插件实测/人工基线/comparison) - performance-comparison.md 填实基线对比与结论;README 效果总结由占位改为真实数据
This commit is contained in:
@@ -10,21 +10,25 @@ AI 驱动的代码审查与规范检查一体化 VS Code 插件。集成 ESLint
|
||||
|
||||
## 效果总结(核心指标摘要)
|
||||
|
||||
> 待补充:请填写提效/效果类核心指标摘要(新规项目须提供对比数据证明价值),例如:单文件平均审查耗时、AI 修复准确率、缺陷检出率、规则覆盖率等基线 vs 提效后对比。
|
||||
> 数据来源:A3 提效对比实验(23 个多语言样例,`data/efficiency-samples/`)。「提效后」= 插件静态分析实测(`tests/measure/results/a3-plugin-results.json`,可复现 `node tests/measure/measure-plugin-samples.mjs`);「基线」= 3 名不同经验等级审查人使用人工审核工具逐文件计时记录问题(`tests/measure/results/manual-review-*.json`);聚合对比见 `tests/measure/performance-comparison.md` 与 `tests/measure/results/a3-comparison.json`。
|
||||
|
||||
| 指标 | 基线 | 提效后 | 提升幅度 |
|
||||
|------|------|--------|----------|
|
||||
| (示例)单文件审查耗时 | 待填 | 待填 | 待填 |
|
||||
| (示例)AI 修复采纳率 | — | 待填 | 待填 |
|
||||
| (示例)规则检出覆盖率 | 待填 | 待填 | 待填 |
|
||||
| 指标 | 基线(人工审查,3 人均值) | 提效后(插件静态分析) | 提升幅度 |
|
||||
|------|---------------------------|------------------------|----------|
|
||||
| 全量审查耗时(23 文件) | 38.1 分钟 | 8.6 秒 | **约 266 倍** |
|
||||
| 检出规范问题数(23 文件) | 76 条 | 283 条 | 检出量约 3.7 倍 |
|
||||
| 问题检出率(对照插件全量) | 27%(平均漏检 73%) | 100%(规则全覆盖) | 规则覆盖兜底 |
|
||||
| 单文件审查耗时(JS/CSS) | 约 100 秒 | 约 0.01 秒 | 约 3400–8500 倍 |
|
||||
| 单文件审查耗时(Java/SQL) | 约 100 秒 | 约 1.1 / 0.4 秒(含子进程启动) | 约 94–238 倍 |
|
||||
|
||||
> 结论:插件在秒级完成多语言全量规范审查,较人工审查整体提速约 266 倍;同时内置规则全覆盖、逐字可复现,可弥补人工审查平均约 73% 的规则类漏检。
|
||||
|
||||
## 团队分工
|
||||
|
||||
> 待补充:请如实填写团队成员及分工。
|
||||
|
||||
| 成员 | 分工 |
|
||||
|------|------|
|
||||
| 待填 | 待填 |
|
||||
| 成员 | 分工 |
|
||||
| ------ | ----------------------------------------------------------- |
|
||||
| 范智鹏 | 框架设计与核心技术开发,功能实现落地,测试方案设计与实行 |
|
||||
| 苏洪旭 | 前期调研与可行性分析,插件功能的拓展与优化,进行测试验证 |
|
||||
| 董爱卿 | 需求分析与场景定义,用户体验与UI设计,文档撰写,Gitee库管理 |
|
||||
|
||||
## 规模与技术难度自我评估
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/* header panel styles */
|
||||
.header-card {
|
||||
color: #FFFFFF;
|
||||
background: #FFF1A2B;
|
||||
margin: 0px;
|
||||
padding: 12px 12px;
|
||||
-webkit-border-radius: 6px;
|
||||
border: 1px solid #dddddd;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #333333;
|
||||
color: #444444;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
-webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.10);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/* sidebar panel styles */
|
||||
.sidebar-card {
|
||||
color: #FFFFFF;
|
||||
background: #FFF1A2B;
|
||||
margin: 0px;
|
||||
padding: 12px 12px;
|
||||
-webkit-border-radius: 6px;
|
||||
border: 1px solid #dddddd;
|
||||
}
|
||||
|
||||
.sidebar-title {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #333333;
|
||||
color: #444444;
|
||||
}
|
||||
|
||||
.sidebar-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
-webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.10);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/* footer panel styles */
|
||||
.footer-card {
|
||||
color: #FFFFFF;
|
||||
background: #FFF1A2B;
|
||||
margin: 0px;
|
||||
padding: 12px 12px;
|
||||
-webkit-border-radius: 6px;
|
||||
border: 1px solid #dddddd;
|
||||
}
|
||||
|
||||
.footer-title {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #333333;
|
||||
color: #444444;
|
||||
}
|
||||
|
||||
.footer-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
-webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.10);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/* modal panel styles */
|
||||
.modal-card {
|
||||
color: #FFFFFF;
|
||||
background: #FFF1A2B;
|
||||
margin: 0px;
|
||||
padding: 12px 12px;
|
||||
-webkit-border-radius: 6px;
|
||||
border: 1px solid #dddddd;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #333333;
|
||||
color: #444444;
|
||||
}
|
||||
|
||||
.modal-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
-webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.10);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/* toast panel styles */
|
||||
.toast-card {
|
||||
color: #FFFFFF;
|
||||
background: #FFF1A2B;
|
||||
margin: 0px;
|
||||
padding: 12px 12px;
|
||||
-webkit-border-radius: 6px;
|
||||
border: 1px solid #dddddd;
|
||||
}
|
||||
|
||||
.toast-title {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #333333;
|
||||
color: #444444;
|
||||
}
|
||||
|
||||
.toast-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
-webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.10);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
public class InventoryService {
|
||||
|
||||
private static final String DEFAULT_USER = "guest";
|
||||
|
||||
public void register(String userName) {
|
||||
String password = "admin123";
|
||||
System.out.println("register user: " + userName);
|
||||
try {
|
||||
persist(userName);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
int leftover = computeChecksum(userName);
|
||||
audit(DEFAULT_USER);
|
||||
}
|
||||
|
||||
private int computeChecksum(String value) {
|
||||
String copy = value.toString();
|
||||
return copy.length();
|
||||
}
|
||||
|
||||
private void persist(String userName) {
|
||||
// placeholder persistence
|
||||
}
|
||||
|
||||
private void audit(String actor) {
|
||||
System.out.println("audit by " + actor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
public class NotifyService {
|
||||
|
||||
private static final String DEFAULT_USER = "guest";
|
||||
|
||||
public void register(String userName) {
|
||||
String password = "admin123";
|
||||
System.out.println("register user: " + userName);
|
||||
try {
|
||||
persist(userName);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
int leftover = computeChecksum(userName);
|
||||
audit(DEFAULT_USER);
|
||||
}
|
||||
|
||||
private int computeChecksum(String value) {
|
||||
String copy = value.toString();
|
||||
return copy.length();
|
||||
}
|
||||
|
||||
private void persist(String userName) {
|
||||
// placeholder persistence
|
||||
}
|
||||
|
||||
private void audit(String actor) {
|
||||
System.out.println("audit by " + actor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
public class OrderService {
|
||||
|
||||
private static final String DEFAULT_USER = "guest";
|
||||
|
||||
public void register(String userName) {
|
||||
String password = "admin123";
|
||||
System.out.println("register user: " + userName);
|
||||
try {
|
||||
persist(userName);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
int leftover = computeChecksum(userName);
|
||||
audit(DEFAULT_USER);
|
||||
}
|
||||
|
||||
private int computeChecksum(String value) {
|
||||
String copy = value.toString();
|
||||
return copy.length();
|
||||
}
|
||||
|
||||
private void persist(String userName) {
|
||||
// placeholder persistence
|
||||
}
|
||||
|
||||
private void audit(String actor) {
|
||||
System.out.println("audit by " + actor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
public class PaymentService {
|
||||
|
||||
private static final String DEFAULT_USER = "guest";
|
||||
|
||||
public void register(String userName) {
|
||||
String password = "admin123";
|
||||
System.out.println("register user: " + userName);
|
||||
try {
|
||||
persist(userName);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
int leftover = computeChecksum(userName);
|
||||
audit(DEFAULT_USER);
|
||||
}
|
||||
|
||||
private int computeChecksum(String value) {
|
||||
String copy = value.toString();
|
||||
return copy.length();
|
||||
}
|
||||
|
||||
private void persist(String userName) {
|
||||
// placeholder persistence
|
||||
}
|
||||
|
||||
private void audit(String actor) {
|
||||
System.out.println("audit by " + actor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
public class ReportService {
|
||||
|
||||
private static final String DEFAULT_USER = "guest";
|
||||
|
||||
public void register(String userName) {
|
||||
String password = "admin123";
|
||||
System.out.println("register user: " + userName);
|
||||
try {
|
||||
persist(userName);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
int leftover = computeChecksum(userName);
|
||||
audit(DEFAULT_USER);
|
||||
}
|
||||
|
||||
private int computeChecksum(String value) {
|
||||
String copy = value.toString();
|
||||
return copy.length();
|
||||
}
|
||||
|
||||
private void persist(String userName) {
|
||||
// placeholder persistence
|
||||
}
|
||||
|
||||
private void audit(String actor) {
|
||||
System.out.println("audit by " + actor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
public class UserService {
|
||||
|
||||
private static final String DEFAULT_USER = "guest";
|
||||
|
||||
public void register(String userName) {
|
||||
String password = "admin123";
|
||||
System.out.println("register user: " + userName);
|
||||
try {
|
||||
persist(userName);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
int leftover = computeChecksum(userName);
|
||||
audit(DEFAULT_USER);
|
||||
}
|
||||
|
||||
private int computeChecksum(String value) {
|
||||
String copy = value.toString();
|
||||
return copy.length();
|
||||
}
|
||||
|
||||
private void persist(String userName) {
|
||||
// placeholder persistence
|
||||
}
|
||||
|
||||
private void audit(String actor) {
|
||||
System.out.println("audit by " + actor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// sample-1: order service module
|
||||
var config = { retries: 3 };
|
||||
|
||||
function orderProcess(items) {
|
||||
var total = 0;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
total += items[i].amount;
|
||||
}
|
||||
if (total == 0) {
|
||||
return null;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
function orderValidate(record) {
|
||||
var shadowed = record.id;
|
||||
function inner() {
|
||||
var shadowed = record.alt;
|
||||
return shadowed;
|
||||
}
|
||||
if (record.value === record.value) {
|
||||
inner();
|
||||
}
|
||||
return shadowed;
|
||||
}
|
||||
|
||||
function orderUnsafe(input) {
|
||||
var unused = computeLegacy(input);
|
||||
eval(input.expression);
|
||||
debugger;
|
||||
}
|
||||
|
||||
function computeLegacy(x) {
|
||||
if (x.pending) {}
|
||||
x.count = x.count;
|
||||
return x;
|
||||
}
|
||||
|
||||
module.exports = { orderProcess, orderValidate, orderUnsafe, config };
|
||||
@@ -0,0 +1,39 @@
|
||||
// sample-2: inventory service module
|
||||
var config = { retries: 3 };
|
||||
|
||||
function inventoryProcess(items) {
|
||||
var total = 0;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
total += items[i].amount;
|
||||
}
|
||||
if (total == 0) {
|
||||
return null;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
function inventoryValidate(record) {
|
||||
var shadowed = record.id;
|
||||
function inner() {
|
||||
var shadowed = record.alt;
|
||||
return shadowed;
|
||||
}
|
||||
if (record.value === record.value) {
|
||||
inner();
|
||||
}
|
||||
return shadowed;
|
||||
}
|
||||
|
||||
function inventoryUnsafe(input) {
|
||||
var unused = computeLegacy(input);
|
||||
eval(input.expression);
|
||||
debugger;
|
||||
}
|
||||
|
||||
function computeLegacy(x) {
|
||||
if (x.pending) {}
|
||||
x.count = x.count;
|
||||
return x;
|
||||
}
|
||||
|
||||
module.exports = { inventoryProcess, inventoryValidate, inventoryUnsafe, config };
|
||||
@@ -0,0 +1,39 @@
|
||||
// sample-3: billing service module
|
||||
var config = { retries: 3 };
|
||||
|
||||
function billingProcess(items) {
|
||||
var total = 0;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
total += items[i].amount;
|
||||
}
|
||||
if (total == 0) {
|
||||
return null;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
function billingValidate(record) {
|
||||
var shadowed = record.id;
|
||||
function inner() {
|
||||
var shadowed = record.alt;
|
||||
return shadowed;
|
||||
}
|
||||
if (record.value === record.value) {
|
||||
inner();
|
||||
}
|
||||
return shadowed;
|
||||
}
|
||||
|
||||
function billingUnsafe(input) {
|
||||
var unused = computeLegacy(input);
|
||||
eval(input.expression);
|
||||
debugger;
|
||||
}
|
||||
|
||||
function computeLegacy(x) {
|
||||
if (x.pending) {}
|
||||
x.count = x.count;
|
||||
return x;
|
||||
}
|
||||
|
||||
module.exports = { billingProcess, billingValidate, billingUnsafe, config };
|
||||
@@ -0,0 +1,39 @@
|
||||
// sample-4: customer service module
|
||||
var config = { retries: 3 };
|
||||
|
||||
function customerProcess(items) {
|
||||
var total = 0;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
total += items[i].amount;
|
||||
}
|
||||
if (total == 0) {
|
||||
return null;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
function customerValidate(record) {
|
||||
var shadowed = record.id;
|
||||
function inner() {
|
||||
var shadowed = record.alt;
|
||||
return shadowed;
|
||||
}
|
||||
if (record.value === record.value) {
|
||||
inner();
|
||||
}
|
||||
return shadowed;
|
||||
}
|
||||
|
||||
function customerUnsafe(input) {
|
||||
var unused = computeLegacy(input);
|
||||
eval(input.expression);
|
||||
debugger;
|
||||
}
|
||||
|
||||
function computeLegacy(x) {
|
||||
if (x.pending) {}
|
||||
x.count = x.count;
|
||||
return x;
|
||||
}
|
||||
|
||||
module.exports = { customerProcess, customerValidate, customerUnsafe, config };
|
||||
@@ -0,0 +1,39 @@
|
||||
// sample-5: shipping service module
|
||||
var config = { retries: 3 };
|
||||
|
||||
function shippingProcess(items) {
|
||||
var total = 0;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
total += items[i].amount;
|
||||
}
|
||||
if (total == 0) {
|
||||
return null;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
function shippingValidate(record) {
|
||||
var shadowed = record.id;
|
||||
function inner() {
|
||||
var shadowed = record.alt;
|
||||
return shadowed;
|
||||
}
|
||||
if (record.value === record.value) {
|
||||
inner();
|
||||
}
|
||||
return shadowed;
|
||||
}
|
||||
|
||||
function shippingUnsafe(input) {
|
||||
var unused = computeLegacy(input);
|
||||
eval(input.expression);
|
||||
debugger;
|
||||
}
|
||||
|
||||
function computeLegacy(x) {
|
||||
if (x.pending) {}
|
||||
x.count = x.count;
|
||||
return x;
|
||||
}
|
||||
|
||||
module.exports = { shippingProcess, shippingValidate, shippingUnsafe, config };
|
||||
@@ -0,0 +1,39 @@
|
||||
// sample-6: coupon service module
|
||||
var config = { retries: 3 };
|
||||
|
||||
function couponProcess(items) {
|
||||
var total = 0;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
total += items[i].amount;
|
||||
}
|
||||
if (total == 0) {
|
||||
return null;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
function couponValidate(record) {
|
||||
var shadowed = record.id;
|
||||
function inner() {
|
||||
var shadowed = record.alt;
|
||||
return shadowed;
|
||||
}
|
||||
if (record.value === record.value) {
|
||||
inner();
|
||||
}
|
||||
return shadowed;
|
||||
}
|
||||
|
||||
function couponUnsafe(input) {
|
||||
var unused = computeLegacy(input);
|
||||
eval(input.expression);
|
||||
debugger;
|
||||
}
|
||||
|
||||
function computeLegacy(x) {
|
||||
if (x.pending) {}
|
||||
x.count = x.count;
|
||||
return x;
|
||||
}
|
||||
|
||||
module.exports = { couponProcess, couponValidate, couponUnsafe, config };
|
||||
@@ -0,0 +1,39 @@
|
||||
// sample-7: refund service module
|
||||
var config = { retries: 3 };
|
||||
|
||||
function refundProcess(items) {
|
||||
var total = 0;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
total += items[i].amount;
|
||||
}
|
||||
if (total == 0) {
|
||||
return null;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
function refundValidate(record) {
|
||||
var shadowed = record.id;
|
||||
function inner() {
|
||||
var shadowed = record.alt;
|
||||
return shadowed;
|
||||
}
|
||||
if (record.value === record.value) {
|
||||
inner();
|
||||
}
|
||||
return shadowed;
|
||||
}
|
||||
|
||||
function refundUnsafe(input) {
|
||||
var unused = computeLegacy(input);
|
||||
eval(input.expression);
|
||||
debugger;
|
||||
}
|
||||
|
||||
function computeLegacy(x) {
|
||||
if (x.pending) {}
|
||||
x.count = x.count;
|
||||
return x;
|
||||
}
|
||||
|
||||
module.exports = { refundProcess, refundValidate, refundUnsafe, config };
|
||||
@@ -0,0 +1,39 @@
|
||||
// sample-8: invoice service module
|
||||
var config = { retries: 3 };
|
||||
|
||||
function invoiceProcess(items) {
|
||||
var total = 0;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
total += items[i].amount;
|
||||
}
|
||||
if (total == 0) {
|
||||
return null;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
function invoiceValidate(record) {
|
||||
var shadowed = record.id;
|
||||
function inner() {
|
||||
var shadowed = record.alt;
|
||||
return shadowed;
|
||||
}
|
||||
if (record.value === record.value) {
|
||||
inner();
|
||||
}
|
||||
return shadowed;
|
||||
}
|
||||
|
||||
function invoiceUnsafe(input) {
|
||||
var unused = computeLegacy(input);
|
||||
eval(input.expression);
|
||||
debugger;
|
||||
}
|
||||
|
||||
function computeLegacy(x) {
|
||||
if (x.pending) {}
|
||||
x.count = x.count;
|
||||
return x;
|
||||
}
|
||||
|
||||
module.exports = { invoiceProcess, invoiceValidate, invoiceUnsafe, config };
|
||||
@@ -0,0 +1,8 @@
|
||||
-- daily-orders report query
|
||||
select u.user_id,u.user_name,o.order_id,o.amount
|
||||
from t_user u
|
||||
join t_order o on u.user_id = o.user_id
|
||||
where u.status = 'active'
|
||||
and o.created_at > sysdate - 30
|
||||
and o.amount > 100
|
||||
ORDER BY o.amount desc
|
||||
@@ -0,0 +1,8 @@
|
||||
-- monthly-revenue summary query
|
||||
SELECT d.dept_name, COUNT(*) AS total
|
||||
FROM t_order o
|
||||
JOIN t_user u ON o.user_id = u.user_id
|
||||
JOIN t_dept d ON u.dept_id = d.dept_id
|
||||
WHERE o.status = 'paid'
|
||||
GROUP BY d.dept_name
|
||||
having total > 5
|
||||
@@ -0,0 +1,8 @@
|
||||
-- active-users report query
|
||||
select u.user_id,u.user_name,o.order_id,o.amount
|
||||
from t_user u
|
||||
join t_order o on u.user_id = o.user_id
|
||||
where u.status = 'active'
|
||||
and o.created_at > sysdate - 30
|
||||
and o.amount > 100
|
||||
ORDER BY o.amount desc
|
||||
@@ -0,0 +1,8 @@
|
||||
-- top-departments summary query
|
||||
SELECT d.dept_name, COUNT(*) AS total
|
||||
FROM t_order o
|
||||
JOIN t_user u ON o.user_id = u.user_id
|
||||
JOIN t_dept d ON u.dept_id = d.dept_id
|
||||
WHERE o.status = 'paid'
|
||||
GROUP BY d.dept_name
|
||||
having total > 5
|
||||
@@ -0,0 +1,231 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN"><head>
|
||||
<meta charset="UTF-8">
|
||||
<title>人工审核记录工具 · A3 实验</title>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { font-family: "Segoe UI", "Noto Sans CJK SC", "Microsoft YaHei", sans-serif; background: #1e1e2e; color: #cdd6f4; display: flex; flex-direction: column; height: 100vh; overflow: hidden; }
|
||||
header { padding: 10px 16px; background: #181825; border-bottom: 1px solid #313244; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
|
||||
header h1 { font-size: 15px; color: #89b4fa; margin-right: 8px; }
|
||||
header .field { display: flex; align-items: center; gap: 4px; font-size: 13px; }
|
||||
header input, header select { background: #313244; color: #cdd6f4; border: 1px solid #45475a; border-radius: 4px; padding: 4px 8px; font-size: 13px; }
|
||||
#totalTimer { font-family: Consolas, monospace; font-size: 16px; color: #a6e3a1; margin-left: auto; }
|
||||
.btn { cursor: pointer; border: none; border-radius: 4px; padding: 6px 14px; font-size: 13px; background: #45475a; color: #cdd6f4; }
|
||||
.btn:hover { background: #585b70; }
|
||||
.btn.primary { background: #89b4fa; color: #1e1e2e; font-weight: 600; }
|
||||
.btn.green { background: #a6e3a1; color: #1e1e2e; font-weight: 600; }
|
||||
.btn.red { background: #f38ba8; color: #1e1e2e; }
|
||||
main { display: flex; flex: 1; min-height: 0; }
|
||||
#sidebar { width: 240px; background: #181825; border-right: 1px solid #313244; overflow-y: auto; padding: 8px; }
|
||||
#sidebar .group-title { font-size: 12px; color: #6c7086; text-transform: uppercase; letter-spacing: 1px; margin: 10px 4px 4px; }
|
||||
.file-item { padding: 7px 10px; border-radius: 6px; cursor: pointer; font-size: 13px; display: flex; align-items: center; gap: 6px; margin-bottom: 2px; }
|
||||
.file-item:hover { background: #313244; }
|
||||
.file-item.active { background: #45475a; }
|
||||
.file-item .dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
|
||||
.dot.todo { background: #6c7086; }
|
||||
.dot.doing { background: #f9e2af; box-shadow: 0 0 6px #f9e2af; }
|
||||
.dot.done { background: #a6e3a1; }
|
||||
.file-item .cnt { margin-left: auto; font-size: 11px; color: #a6adc8; background: #313244; border-radius: 8px; padding: 1px 6px; }
|
||||
#content { flex: 1; display: flex; flex-direction: column; min-width: 0; }
|
||||
#codePanel { flex: 1; overflow: auto; background: #11111b; margin: 8px; border-radius: 8px; border: 1px solid #313244; padding: 10px 0; font-family: Consolas, "Courier New", monospace; font-size: 13px; line-height: 1.55; }
|
||||
.code-line { display: flex; white-space: pre; }
|
||||
.code-line:hover { background: #181825; }
|
||||
.code-line .ln { flex: none; width: 48px; text-align: right; padding-right: 12px; color: #585b70; user-select: none; cursor: pointer; }
|
||||
.code-line .ln:hover { color: #89b4fa; text-decoration: underline; }
|
||||
.code-line .ln.marked { color: #f38ba8; font-weight: 700; }
|
||||
.code-line .code { color: #cdd6f4; }
|
||||
#issueBar { background: #181825; border-top: 1px solid #313244; padding: 10px 16px; }
|
||||
#issueBar .row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
|
||||
#issueBar label { font-size: 12px; color: #a6adc8; }
|
||||
#issueBar input, #issueBar select { background: #313244; color: #cdd6f4; border: 1px solid #45475a; border-radius: 4px; padding: 5px 8px; font-size: 13px; }
|
||||
#noteInput { flex: 1; min-width: 240px; }
|
||||
#issueList { margin-top: 8px; display: flex; flex-wrap: wrap; gap: 6px; }
|
||||
.issue-chip { font-size: 12px; background: #313244; border: 1px solid #45475a; border-radius: 12px; padding: 3px 10px; display: inline-flex; gap: 6px; align-items: center; }
|
||||
.issue-chip .sev { font-weight: 700; }
|
||||
.sev.error { color: #f38ba8; } .sev.warning { color: #f9e2af; } .sev.info { color: #89b4fa; }
|
||||
.issue-chip .del { cursor: pointer; color: #6c7086; } .issue-chip .del:hover { color: #f38ba8; }
|
||||
#fileTimer { font-family: Consolas, monospace; color: #f9e2af; font-size: 14px; }
|
||||
.status { font-size: 12px; color: #a6adc8; }
|
||||
#toast { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background: #a6e3a1; color: #1e1e2e; padding: 8px 20px; border-radius: 6px; font-size: 13px; display: none; z-index: 99; }
|
||||
.hint { font-size: 11px; color: #6c7086; margin-top: 6px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>人工审核记录 · A3</h1>
|
||||
<div class="field">受试者 <input id="reviewer" placeholder="编号/昵称" style="width:110px"></div>
|
||||
<div class="field">经验 <select id="level"><option value="junior">初级 (<2年)</option><option value="mid">中级 (2-5年)</option><option value="senior">高级 (>5年)</option></select></div>
|
||||
<button class="btn green" id="exportBtn">导出 JSON</button>
|
||||
<button class="btn red" id="resetBtn">清空全部数据</button>
|
||||
<div id="totalTimer">00:00:00</div>
|
||||
</header>
|
||||
<main>
|
||||
<div id="sidebar"></div>
|
||||
<div id="content">
|
||||
<div id="codePanel"></div>
|
||||
<div id="issueBar">
|
||||
<div class="row">
|
||||
<button class="btn primary" id="startBtn">▶ 开始审查此文件</button>
|
||||
<button class="btn" id="finishBtn" disabled="">⏹ 完成</button>
|
||||
<span id="fileTimer">本文件 00:00</span>
|
||||
<span class="status" id="fileStatus"></span>
|
||||
</div>
|
||||
<div class="row" style="margin-top:8px">
|
||||
<label>行号 <input id="lineInput" type="number" min="1" style="width:70px"></label>
|
||||
<label>严重度 <select id="sevInput"><option value="error">error</option><option value="warning" selected="">warning</option><option value="info">info</option></select></label>
|
||||
<label>问题描述 <input id="noteInput" placeholder="例:使用了 == 应为 ==="></label>
|
||||
<button class="btn" id="addIssueBtn">+ 记录问题</button>
|
||||
</div>
|
||||
<div id="issueList"></div>
|
||||
<div class="hint">提示:点击代码左侧行号可快速填入行号。先点"开始审查"再读代码,读完点"完成"停止计时。中途休息请先点"完成"。</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<div id="toast"></div>
|
||||
<script>
|
||||
const DATA = {"generatedAt":"2026-08-22T04:39:38.089Z","files":[{"rel":"data/efficiency-samples/js/sample-01.js","lang":"JavaScript","languageId":"javascript","code":"// sample-1: order service module\nvar config = { retries: 3 };\n\nfunction orderProcess(items) {\n var total = 0;\n for (var i = 0; i < items.length; i++) {\n total += items[i].amount;\n }\n if (total == 0) {\n return null;\n }\n return total;\n}\n\nfunction orderValidate(record) {\n var shadowed = record.id;\n function inner() {\n var shadowed = record.alt;\n return shadowed;\n }\n if (record.value === record.value) {\n inner();\n }\n return shadowed;\n}\n\nfunction orderUnsafe(input) {\n var unused = computeLegacy(input);\n eval(input.expression);\n debugger;\n}\n\nfunction computeLegacy(x) {\n if (x.pending) {}\n x.count = x.count;\n return x;\n}\n\nmodule.exports = { orderProcess, orderValidate, orderUnsafe, config };\n"},{"rel":"data/efficiency-samples/js/sample-02.js","lang":"JavaScript","languageId":"javascript","code":"// sample-2: inventory service module\nvar config = { retries: 3 };\n\nfunction inventoryProcess(items) {\n var total = 0;\n for (var i = 0; i < items.length; i++) {\n total += items[i].amount;\n }\n if (total == 0) {\n return null;\n }\n return total;\n}\n\nfunction inventoryValidate(record) {\n var shadowed = record.id;\n function inner() {\n var shadowed = record.alt;\n return shadowed;\n }\n if (record.value === record.value) {\n inner();\n }\n return shadowed;\n}\n\nfunction inventoryUnsafe(input) {\n var unused = computeLegacy(input);\n eval(input.expression);\n debugger;\n}\n\nfunction computeLegacy(x) {\n if (x.pending) {}\n x.count = x.count;\n return x;\n}\n\nmodule.exports = { inventoryProcess, inventoryValidate, inventoryUnsafe, config };\n"},{"rel":"data/efficiency-samples/js/sample-03.js","lang":"JavaScript","languageId":"javascript","code":"// sample-3: billing service module\nvar config = { retries: 3 };\n\nfunction billingProcess(items) {\n var total = 0;\n for (var i = 0; i < items.length; i++) {\n total += items[i].amount;\n }\n if (total == 0) {\n return null;\n }\n return total;\n}\n\nfunction billingValidate(record) {\n var shadowed = record.id;\n function inner() {\n var shadowed = record.alt;\n return shadowed;\n }\n if (record.value === record.value) {\n inner();\n }\n return shadowed;\n}\n\nfunction billingUnsafe(input) {\n var unused = computeLegacy(input);\n eval(input.expression);\n debugger;\n}\n\nfunction computeLegacy(x) {\n if (x.pending) {}\n x.count = x.count;\n return x;\n}\n\nmodule.exports = { billingProcess, billingValidate, billingUnsafe, config };\n"},{"rel":"data/efficiency-samples/js/sample-04.js","lang":"JavaScript","languageId":"javascript","code":"// sample-4: customer service module\nvar config = { retries: 3 };\n\nfunction customerProcess(items) {\n var total = 0;\n for (var i = 0; i < items.length; i++) {\n total += items[i].amount;\n }\n if (total == 0) {\n return null;\n }\n return total;\n}\n\nfunction customerValidate(record) {\n var shadowed = record.id;\n function inner() {\n var shadowed = record.alt;\n return shadowed;\n }\n if (record.value === record.value) {\n inner();\n }\n return shadowed;\n}\n\nfunction customerUnsafe(input) {\n var unused = computeLegacy(input);\n eval(input.expression);\n debugger;\n}\n\nfunction computeLegacy(x) {\n if (x.pending) {}\n x.count = x.count;\n return x;\n}\n\nmodule.exports = { customerProcess, customerValidate, customerUnsafe, config };\n"},{"rel":"data/efficiency-samples/js/sample-05.js","lang":"JavaScript","languageId":"javascript","code":"// sample-5: shipping service module\nvar config = { retries: 3 };\n\nfunction shippingProcess(items) {\n var total = 0;\n for (var i = 0; i < items.length; i++) {\n total += items[i].amount;\n }\n if (total == 0) {\n return null;\n }\n return total;\n}\n\nfunction shippingValidate(record) {\n var shadowed = record.id;\n function inner() {\n var shadowed = record.alt;\n return shadowed;\n }\n if (record.value === record.value) {\n inner();\n }\n return shadowed;\n}\n\nfunction shippingUnsafe(input) {\n var unused = computeLegacy(input);\n eval(input.expression);\n debugger;\n}\n\nfunction computeLegacy(x) {\n if (x.pending) {}\n x.count = x.count;\n return x;\n}\n\nmodule.exports = { shippingProcess, shippingValidate, shippingUnsafe, config };\n"},{"rel":"data/efficiency-samples/js/sample-06.js","lang":"JavaScript","languageId":"javascript","code":"// sample-6: coupon service module\nvar config = { retries: 3 };\n\nfunction couponProcess(items) {\n var total = 0;\n for (var i = 0; i < items.length; i++) {\n total += items[i].amount;\n }\n if (total == 0) {\n return null;\n }\n return total;\n}\n\nfunction couponValidate(record) {\n var shadowed = record.id;\n function inner() {\n var shadowed = record.alt;\n return shadowed;\n }\n if (record.value === record.value) {\n inner();\n }\n return shadowed;\n}\n\nfunction couponUnsafe(input) {\n var unused = computeLegacy(input);\n eval(input.expression);\n debugger;\n}\n\nfunction computeLegacy(x) {\n if (x.pending) {}\n x.count = x.count;\n return x;\n}\n\nmodule.exports = { couponProcess, couponValidate, couponUnsafe, config };\n"},{"rel":"data/efficiency-samples/js/sample-07.js","lang":"JavaScript","languageId":"javascript","code":"// sample-7: refund service module\nvar config = { retries: 3 };\n\nfunction refundProcess(items) {\n var total = 0;\n for (var i = 0; i < items.length; i++) {\n total += items[i].amount;\n }\n if (total == 0) {\n return null;\n }\n return total;\n}\n\nfunction refundValidate(record) {\n var shadowed = record.id;\n function inner() {\n var shadowed = record.alt;\n return shadowed;\n }\n if (record.value === record.value) {\n inner();\n }\n return shadowed;\n}\n\nfunction refundUnsafe(input) {\n var unused = computeLegacy(input);\n eval(input.expression);\n debugger;\n}\n\nfunction computeLegacy(x) {\n if (x.pending) {}\n x.count = x.count;\n return x;\n}\n\nmodule.exports = { refundProcess, refundValidate, refundUnsafe, config };\n"},{"rel":"data/efficiency-samples/js/sample-08.js","lang":"JavaScript","languageId":"javascript","code":"// sample-8: invoice service module\nvar config = { retries: 3 };\n\nfunction invoiceProcess(items) {\n var total = 0;\n for (var i = 0; i < items.length; i++) {\n total += items[i].amount;\n }\n if (total == 0) {\n return null;\n }\n return total;\n}\n\nfunction invoiceValidate(record) {\n var shadowed = record.id;\n function inner() {\n var shadowed = record.alt;\n return shadowed;\n }\n if (record.value === record.value) {\n inner();\n }\n return shadowed;\n}\n\nfunction invoiceUnsafe(input) {\n var unused = computeLegacy(input);\n eval(input.expression);\n debugger;\n}\n\nfunction computeLegacy(x) {\n if (x.pending) {}\n x.count = x.count;\n return x;\n}\n\nmodule.exports = { invoiceProcess, invoiceValidate, invoiceUnsafe, config };\n"},{"rel":"data/efficiency-samples/java/InventoryService.java","lang":"Java","languageId":"java","code":"public class InventoryService {\n\n private static final String DEFAULT_USER = \"guest\";\n\n public void register(String userName) {\n String password = \"admin123\";\n System.out.println(\"register user: \" + userName);\n try {\n persist(userName);\n } catch (Exception e) {\n }\n int leftover = computeChecksum(userName);\n audit(DEFAULT_USER);\n }\n\n private int computeChecksum(String value) {\n String copy = value.toString();\n return copy.length();\n }\n\n private void persist(String userName) {\n // placeholder persistence\n }\n\n private void audit(String actor) {\n System.out.println(\"audit by \" + actor);\n }\n}\n"},{"rel":"data/efficiency-samples/java/NotifyService.java","lang":"Java","languageId":"java","code":"public class NotifyService {\n\n private static final String DEFAULT_USER = \"guest\";\n\n public void register(String userName) {\n String password = \"admin123\";\n System.out.println(\"register user: \" + userName);\n try {\n persist(userName);\n } catch (Exception e) {\n }\n int leftover = computeChecksum(userName);\n audit(DEFAULT_USER);\n }\n\n private int computeChecksum(String value) {\n String copy = value.toString();\n return copy.length();\n }\n\n private void persist(String userName) {\n // placeholder persistence\n }\n\n private void audit(String actor) {\n System.out.println(\"audit by \" + actor);\n }\n}\n"},{"rel":"data/efficiency-samples/java/OrderService.java","lang":"Java","languageId":"java","code":"public class OrderService {\n\n private static final String DEFAULT_USER = \"guest\";\n\n public void register(String userName) {\n String password = \"admin123\";\n System.out.println(\"register user: \" + userName);\n try {\n persist(userName);\n } catch (Exception e) {\n }\n int leftover = computeChecksum(userName);\n audit(DEFAULT_USER);\n }\n\n private int computeChecksum(String value) {\n String copy = value.toString();\n return copy.length();\n }\n\n private void persist(String userName) {\n // placeholder persistence\n }\n\n private void audit(String actor) {\n System.out.println(\"audit by \" + actor);\n }\n}\n"},{"rel":"data/efficiency-samples/java/PaymentService.java","lang":"Java","languageId":"java","code":"public class PaymentService {\n\n private static final String DEFAULT_USER = \"guest\";\n\n public void register(String userName) {\n String password = \"admin123\";\n System.out.println(\"register user: \" + userName);\n try {\n persist(userName);\n } catch (Exception e) {\n }\n int leftover = computeChecksum(userName);\n audit(DEFAULT_USER);\n }\n\n private int computeChecksum(String value) {\n String copy = value.toString();\n return copy.length();\n }\n\n private void persist(String userName) {\n // placeholder persistence\n }\n\n private void audit(String actor) {\n System.out.println(\"audit by \" + actor);\n }\n}\n"},{"rel":"data/efficiency-samples/java/ReportService.java","lang":"Java","languageId":"java","code":"public class ReportService {\n\n private static final String DEFAULT_USER = \"guest\";\n\n public void register(String userName) {\n String password = \"admin123\";\n System.out.println(\"register user: \" + userName);\n try {\n persist(userName);\n } catch (Exception e) {\n }\n int leftover = computeChecksum(userName);\n audit(DEFAULT_USER);\n }\n\n private int computeChecksum(String value) {\n String copy = value.toString();\n return copy.length();\n }\n\n private void persist(String userName) {\n // placeholder persistence\n }\n\n private void audit(String actor) {\n System.out.println(\"audit by \" + actor);\n }\n}\n"},{"rel":"data/efficiency-samples/java/UserService.java","lang":"Java","languageId":"java","code":"public class UserService {\n\n private static final String DEFAULT_USER = \"guest\";\n\n public void register(String userName) {\n String password = \"admin123\";\n System.out.println(\"register user: \" + userName);\n try {\n persist(userName);\n } catch (Exception e) {\n }\n int leftover = computeChecksum(userName);\n audit(DEFAULT_USER);\n }\n\n private int computeChecksum(String value) {\n String copy = value.toString();\n return copy.length();\n }\n\n private void persist(String userName) {\n // placeholder persistence\n }\n\n private void audit(String actor) {\n System.out.println(\"audit by \" + actor);\n }\n}\n"},{"rel":"data/efficiency-samples/css/sample-01.css","lang":"CSS","languageId":"css","code":"/* header panel styles */\n.header-card {\n color: #FFFFFF;\n background: #FFF1A2B;\n margin: 0px;\n padding: 12px 12px;\n -webkit-border-radius: 6px;\n border: 1px solid #dddddd;\n}\n\n.header-title {\n font-size: 16px;\n font-weight: 700;\n color: #333333;\n color: #444444;\n}\n\n.header-actions {\n display: flex;\n gap: 8px;\n -webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.10);\n}\n"},{"rel":"data/efficiency-samples/css/sample-02.css","lang":"CSS","languageId":"css","code":"/* sidebar panel styles */\n.sidebar-card {\n color: #FFFFFF;\n background: #FFF1A2B;\n margin: 0px;\n padding: 12px 12px;\n -webkit-border-radius: 6px;\n border: 1px solid #dddddd;\n}\n\n.sidebar-title {\n font-size: 16px;\n font-weight: 700;\n color: #333333;\n color: #444444;\n}\n\n.sidebar-actions {\n display: flex;\n gap: 8px;\n -webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.10);\n}\n"},{"rel":"data/efficiency-samples/css/sample-03.css","lang":"CSS","languageId":"css","code":"/* footer panel styles */\n.footer-card {\n color: #FFFFFF;\n background: #FFF1A2B;\n margin: 0px;\n padding: 12px 12px;\n -webkit-border-radius: 6px;\n border: 1px solid #dddddd;\n}\n\n.footer-title {\n font-size: 16px;\n font-weight: 700;\n color: #333333;\n color: #444444;\n}\n\n.footer-actions {\n display: flex;\n gap: 8px;\n -webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.10);\n}\n"},{"rel":"data/efficiency-samples/css/sample-04.css","lang":"CSS","languageId":"css","code":"/* modal panel styles */\n.modal-card {\n color: #FFFFFF;\n background: #FFF1A2B;\n margin: 0px;\n padding: 12px 12px;\n -webkit-border-radius: 6px;\n border: 1px solid #dddddd;\n}\n\n.modal-title {\n font-size: 16px;\n font-weight: 700;\n color: #333333;\n color: #444444;\n}\n\n.modal-actions {\n display: flex;\n gap: 8px;\n -webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.10);\n}\n"},{"rel":"data/efficiency-samples/css/sample-05.css","lang":"CSS","languageId":"css","code":"/* toast panel styles */\n.toast-card {\n color: #FFFFFF;\n background: #FFF1A2B;\n margin: 0px;\n padding: 12px 12px;\n -webkit-border-radius: 6px;\n border: 1px solid #dddddd;\n}\n\n.toast-title {\n font-size: 16px;\n font-weight: 700;\n color: #333333;\n color: #444444;\n}\n\n.toast-actions {\n display: flex;\n gap: 8px;\n -webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.10);\n}\n"},{"rel":"data/efficiency-samples/sql/sample-01.sql","lang":"SQL","languageId":"sql","code":"-- daily-orders report query\nselect u.user_id,u.user_name,o.order_id,o.amount\nfrom t_user u\njoin t_order o on u.user_id = o.user_id\nwhere u.status = 'active'\n and o.created_at > sysdate - 30\n and o.amount > 100\nORDER BY o.amount desc\n"},{"rel":"data/efficiency-samples/sql/sample-02.sql","lang":"SQL","languageId":"sql","code":"-- monthly-revenue summary query\nSELECT d.dept_name, COUNT(*) AS total\nFROM t_order o\nJOIN t_user u ON o.user_id = u.user_id\nJOIN t_dept d ON u.dept_id = d.dept_id\nWHERE o.status = 'paid'\nGROUP BY d.dept_name\nhaving total > 5\n"},{"rel":"data/efficiency-samples/sql/sample-03.sql","lang":"SQL","languageId":"sql","code":"-- active-users report query\nselect u.user_id,u.user_name,o.order_id,o.amount\nfrom t_user u\njoin t_order o on u.user_id = o.user_id\nwhere u.status = 'active'\n and o.created_at > sysdate - 30\n and o.amount > 100\nORDER BY o.amount desc\n"},{"rel":"data/efficiency-samples/sql/sample-04.sql","lang":"SQL","languageId":"sql","code":"-- top-departments summary query\nSELECT d.dept_name, COUNT(*) AS total\nFROM t_order o\nJOIN t_user u ON o.user_id = u.user_id\nJOIN t_dept d ON u.dept_id = d.dept_id\nWHERE o.status = 'paid'\nGROUP BY d.dept_name\nhaving total > 5\n"}]};
|
||||
const LS_KEY = 'a3-manual-review-v1';
|
||||
const state = load() || { reviewer: '', level: 'mid', files: {} };
|
||||
// state.files[rel] = { elapsedMs, startedAt, done, issues: [{line, severity, note, at}] }
|
||||
const $ = (id) => document.getElementById(id);
|
||||
let current = DATA.files[0]?.rel ?? null;
|
||||
let tickHandle = setInterval(renderTimers, 1000);
|
||||
|
||||
function load() { try { return JSON.parse(localStorage.getItem(LS_KEY)); } catch { return null; } }
|
||||
function save() { localStorage.setItem(LS_KEY, JSON.stringify(state)); }
|
||||
function fstate(rel) { return state.files[rel] ??= { elapsedMs: 0, startedAt: null, done: false, issues: [] }; }
|
||||
function fmtClock(ms) {
|
||||
const s = Math.floor(ms / 1000);
|
||||
const h = String(Math.floor(s / 3600)).padStart(2, '0');
|
||||
return h + ':' + String(Math.floor((s % 3600) / 60)).padStart(2, '0') + ':' + String(s % 60).padStart(2, '0');
|
||||
}
|
||||
function fmtShort(ms) {
|
||||
const s = Math.floor(ms / 1000);
|
||||
return String(Math.floor(s / 60)).padStart(2, '0') + ':' + String(s % 60).padStart(2, '0');
|
||||
}
|
||||
function totalElapsed() {
|
||||
let t = 0;
|
||||
for (const f of Object.values(state.files)) { t += f.elapsedMs + (f.startedAt ? Date.now() - f.startedAt : 0); }
|
||||
return t;
|
||||
}
|
||||
function esc(s) { return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); }
|
||||
|
||||
function renderSidebar() {
|
||||
const el = $('sidebar'); el.innerHTML = '';
|
||||
const groups = {};
|
||||
for (const f of DATA.files) { (groups[f.lang] ??= []).push(f); }
|
||||
for (const [lang, fs] of Object.entries(groups)) {
|
||||
const t = document.createElement('div'); t.className = 'group-title'; t.textContent = lang; el.appendChild(t);
|
||||
for (const f of fs) {
|
||||
const st = fstate(f.rel);
|
||||
const item = document.createElement('div');
|
||||
item.className = 'file-item' + (f.rel === current ? ' active' : '');
|
||||
const dotCls = st.done ? 'done' : (st.startedAt ? 'doing' : (st.elapsedMs > 0 || st.issues.length ? 'doing' : 'todo'));
|
||||
item.innerHTML = '<span class="dot ' + dotCls + '"></span><span>' + f.rel.split('/').pop() + '</span>' +
|
||||
(st.issues.length ? '<span class="cnt">' + st.issues.length + ' 题目</span>' : '');
|
||||
item.onclick = () => switchFile(f.rel);
|
||||
el.appendChild(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function renderCode() {
|
||||
const f = DATA.files.find((x) => x.rel === current);
|
||||
const panel = $('codePanel'); panel.innerHTML = '';
|
||||
if (!f) { panel.textContent = '(无文件)'; return; }
|
||||
const st = fstate(f.rel);
|
||||
const markedLines = new Set(st.issues.map((i) => i.line));
|
||||
const lines = f.code.split('\n');
|
||||
lines.forEach((text, i) => {
|
||||
const row = document.createElement('div'); row.className = 'code-line';
|
||||
const ln = document.createElement('span');
|
||||
ln.className = 'ln' + (markedLines.has(i + 1) ? ' marked' : '');
|
||||
ln.textContent = String(i + 1);
|
||||
ln.onclick = () => { $('lineInput').value = i + 1; $('noteInput').focus(); };
|
||||
const code = document.createElement('span'); code.className = 'code'; code.textContent = text || ' ';
|
||||
row.appendChild(ln); row.appendChild(code); panel.appendChild(row);
|
||||
});
|
||||
panel.scrollTop = 0;
|
||||
}
|
||||
|
||||
function renderIssueBar() {
|
||||
const st = fstate(current);
|
||||
$('startBtn').disabled = !!st.startedAt;
|
||||
$('finishBtn').disabled = !st.startedAt;
|
||||
$('fileStatus').textContent = st.done ? '已完成' : (st.startedAt ? '审查中…' : '未开始');
|
||||
const list = $('issueList'); list.innerHTML = '';
|
||||
for (let idx = 0; idx < st.issues.length; idx++) {
|
||||
const it = st.issues[idx];
|
||||
const chip = document.createElement('span'); chip.className = 'issue-chip';
|
||||
chip.innerHTML = '<span class="sev ' + it.severity + '">' + it.severity + '</span> L' + it.line +
|
||||
' <span>' + esc(it.note || '(未描述)') + '</span> <span class="del" title="删除">✕</span>';
|
||||
chip.querySelector('.del').onclick = () => { st.issues.splice(idx, 1); save(); renderAll(); };
|
||||
list.appendChild(chip);
|
||||
}
|
||||
}
|
||||
|
||||
function renderTimers() {
|
||||
$('totalTimer').textContent = fmtClock(totalElapsed());
|
||||
const st = current && fstate(current);
|
||||
if (st) { $('fileTimer').textContent = '本文件 ' + fmtShort(st.elapsedMs + (st.startedAt ? Date.now() - st.startedAt : 0)); }
|
||||
}
|
||||
|
||||
function renderAll() { renderSidebar(); renderCode(); renderIssueBar(); renderTimers(); }
|
||||
|
||||
function switchFile(rel) {
|
||||
const prev = fstate(current);
|
||||
if (prev.startedAt) { prev.elapsedMs += Date.now() - prev.startedAt; prev.startedAt = null; } // 切换视为暂停
|
||||
current = rel; save(); renderAll();
|
||||
}
|
||||
|
||||
$('startBtn').onclick = () => { const st = fstate(current); if (!st.startedAt) { st.startedAt = Date.now(); st.done = false; save(); renderAll(); } };
|
||||
$('finishBtn').onclick = () => {
|
||||
const st = fstate(current);
|
||||
if (st.startedAt) { st.elapsedMs += Date.now() - st.startedAt; st.startedAt = null; }
|
||||
st.done = true; save(); renderAll();
|
||||
};
|
||||
$('addIssueBtn').onclick = () => {
|
||||
const line = parseInt($('lineInput').value, 10);
|
||||
const note = $('noteInput').value.trim();
|
||||
if (!line || line < 1) { toast('请填写行号(可点击代码行号)'); return; }
|
||||
if (!note) { toast('请填写问题描述'); return; }
|
||||
const st = fstate(current);
|
||||
st.issues.push({ line, severity: $('sevInput').value, note, at: new Date().toISOString() });
|
||||
$('lineInput').value = ''; $('noteInput').value = '';
|
||||
save(); renderAll(); toast('已记录 L' + line);
|
||||
};
|
||||
$('reviewer').oninput = (e) => { state.reviewer = e.target.value; save(); };
|
||||
$('level').onchange = (e) => { state.level = e.target.value; save(); };
|
||||
|
||||
$('exportBtn').onclick = () => {
|
||||
state.reviewer = $('reviewer').value; state.level = $('level').value;
|
||||
for (const st of Object.values(state.files)) {
|
||||
if (st.startedAt) { st.elapsedMs += Date.now() - st.startedAt; st.startedAt = null; }
|
||||
}
|
||||
save();
|
||||
const out = { experiment: 'A3 人工审核 vs 插件审核', exportedAt: new Date().toISOString(), reviewer: state.reviewer, level: state.level, totalElapsedMs: totalElapsed(), files: state.files };
|
||||
const blob = new Blob([JSON.stringify(out, null, 2)], { type: 'application/json' });
|
||||
const a = document.createElement('a');
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = 'manual-review-' + (state.reviewer || 'anon') + '.json';
|
||||
a.click(); URL.revokeObjectURL(a.href);
|
||||
toast('已导出,请交给实验组织者');
|
||||
};
|
||||
$('resetBtn').onclick = () => {
|
||||
if (!confirm('确定清空全部记录?此操作不可恢复。')) return;
|
||||
localStorage.removeItem(LS_KEY); location.reload();
|
||||
};
|
||||
|
||||
function toast(msg) {
|
||||
const t = $('toast'); t.textContent = msg; t.style.display = 'block';
|
||||
setTimeout(() => { t.style.display = 'none'; }, 1600);
|
||||
}
|
||||
|
||||
// 恢复受试者信息
|
||||
if (state.reviewer) { $('reviewer').value = state.reviewer; }
|
||||
if (state.level) { $('level').value = state.level; }
|
||||
renderAll();
|
||||
</script>
|
||||
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,101 @@
|
||||
import { readFileSync, readdirSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
||||
import { join, dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const OUT_DIR = join(__dirname, 'results');
|
||||
|
||||
const LANGS = ['js', 'css', 'java', 'sql'];
|
||||
const LANG_LABEL = { js: 'JS', css: 'CSS', java: 'Java', sql: 'SQL' };
|
||||
|
||||
function loadBaselines() {
|
||||
const files = readdirSync(OUT_DIR).filter(f => /^manual-review-.+\.json$/.test(f)).sort();
|
||||
return files.map(f => JSON.parse(readFileSync(join(OUT_DIR, f), 'utf8')));
|
||||
}
|
||||
|
||||
function langOf(rel) {
|
||||
const parts = rel.split('/');
|
||||
const idx = parts.indexOf('efficiency-samples');
|
||||
return parts[idx + 1];
|
||||
}
|
||||
|
||||
function sum(arr) { return arr.reduce((s, v) => s + v, 0); }
|
||||
function mean(arr) { return arr.length ? sum(arr) / arr.length : 0; }
|
||||
|
||||
function main() {
|
||||
const baselines = loadBaselines();
|
||||
const plugin = JSON.parse(readFileSync(join(OUT_DIR, 'a3-plugin-results.json'), 'utf8'));
|
||||
|
||||
const pluginByLang = {};
|
||||
for (const row of plugin.rows) {
|
||||
pluginByLang[row.lang] = { files: row.files, diagnostics: row.diagnostics, totalMs: row.totalMs };
|
||||
}
|
||||
|
||||
const perReviewer = baselines.map(b => {
|
||||
const agg = {};
|
||||
for (const lang of LANGS) agg[lang] = { issues: 0, elapsedMs: 0, files: 0 };
|
||||
for (const [rel, st] of Object.entries(b.files)) {
|
||||
const lang = langOf(rel);
|
||||
if (!agg[lang]) continue;
|
||||
agg[lang].issues += st.issues.length;
|
||||
agg[lang].elapsedMs += st.elapsedMs;
|
||||
agg[lang].files += 1;
|
||||
}
|
||||
return { reviewer: b.reviewer, level: b.level, totalElapsedMs: b.totalElapsedMs, agg };
|
||||
});
|
||||
|
||||
const comparison = { generatedAt: new Date().toISOString(), reviewers: perReviewer.map(r => ({ reviewer: r.reviewer, level: r.level, totalElapsedMs: r.totalElapsedMs })), rows: [] };
|
||||
|
||||
console.log('===== 每人每语言汇总 =====');
|
||||
for (const r of perReviewer) {
|
||||
console.log(`[${r.reviewer} (${r.level})] 总耗时 ${(r.totalElapsedMs / 60000).toFixed(1)} min`);
|
||||
for (const lang of LANGS) {
|
||||
const a = r.agg[lang];
|
||||
console.log(` ${LANG_LABEL[lang]}: ${a.issues} 条, ${(a.elapsedMs / 1000).toFixed(1)}s / ${a.files} 文件`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n===== 人工基线(3人均值) vs 插件(提效后) =====');
|
||||
console.log('语言 | 人工问题数 | 插件诊断数 | 检出率 | 人工耗时 | 插件耗时 | 提速倍数');
|
||||
for (const lang of LANGS) {
|
||||
const p = pluginByLang[lang];
|
||||
const blFiles = mean(perReviewer.map(r => r.agg[lang].files));
|
||||
const blIssues = mean(perReviewer.map(r => r.agg[lang].issues));
|
||||
const blMs = mean(perReviewer.map(r => r.agg[lang].elapsedMs));
|
||||
const recall = p.diagnostics > 0 ? blIssues / p.diagnostics : 0;
|
||||
const speedup = blMs / (p.totalMs || 1);
|
||||
comparison.rows.push({
|
||||
lang,
|
||||
files: blFiles,
|
||||
baselineIssuesMean: blIssues,
|
||||
baselineIssues: perReviewer.map(r => r.agg[lang].issues),
|
||||
pluginDiagnostics: p.diagnostics,
|
||||
recall: +recall.toFixed(3),
|
||||
baselineMsMean: +blMs.toFixed(1),
|
||||
baselineMs: perReviewer.map(r => r.agg[lang].elapsedMs),
|
||||
pluginMs: +p.totalMs.toFixed(1),
|
||||
speedup: +speedup.toFixed(1),
|
||||
});
|
||||
console.log(`${LANG_LABEL[lang]} | ${blIssues.toFixed(1)} | ${p.diagnostics} | ${(recall * 100).toFixed(0)}% | ${(blMs / 1000).toFixed(1)}s | ${(p.totalMs / 1000).toFixed(1)}s | ${speedup.toFixed(1)}x`);
|
||||
}
|
||||
|
||||
const allBlMs = mean(perReviewer.map(r => r.totalElapsedMs));
|
||||
const allPluginMs = plugin.totalMs;
|
||||
const allRecall = sum(perReviewer.map(r => sum(LANGS.map(l => r.agg[l].issues)))) / perReviewer.length / plugin.totalDiagnostics;
|
||||
const allSpeedup = allBlMs / allPluginMs;
|
||||
comparison.total = {
|
||||
baselineMsMean: +allBlMs.toFixed(1),
|
||||
baselineMs: perReviewer.map(r => r.totalElapsedMs),
|
||||
pluginMs: +allPluginMs.toFixed(1),
|
||||
baselineDiagnosticsMean: +sum(perReviewer.map(r => sum(LANGS.map(l => r.agg[l].issues)))) / perReviewer.length,
|
||||
pluginDiagnostics: plugin.totalDiagnostics,
|
||||
recall: +allRecall.toFixed(3),
|
||||
speedup: +allSpeedup.toFixed(1),
|
||||
};
|
||||
console.log(`\n合计 | ${comparison.total.baselineDiagnosticsMean.toFixed(1)} | ${plugin.totalDiagnostics} | ${(allRecall * 100).toFixed(0)}% | ${(allBlMs / 60000).toFixed(1)}min | ${(allPluginMs / 1000).toFixed(1)}s | ${allSpeedup.toFixed(1)}x`);
|
||||
|
||||
writeFileSync(join(OUT_DIR, 'a3-comparison.json'), JSON.stringify(comparison, null, 2));
|
||||
console.log(`\n结果已写入 ${join(OUT_DIR, 'a3-comparison.json')}`);
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,265 @@
|
||||
import { ESLint } from 'eslint';
|
||||
import js from '@eslint/js';
|
||||
import ts from 'typescript-eslint';
|
||||
import stylelint from 'stylelint';
|
||||
import recommendedConfig from 'stylelint-config-recommended';
|
||||
import { readFileSync, readdirSync, writeFileSync, mkdirSync, existsSync, unlinkSync } from 'fs';
|
||||
import { join, dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { spawnSync } from 'child_process';
|
||||
import os from 'os';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT = join(__dirname, '..', '..');
|
||||
const SAMPLES = join(ROOT, 'data', 'efficiency-samples');
|
||||
const PMD_DIR = join(ROOT, 'jars', 'pmd');
|
||||
const OUT_DIR = join(__dirname, 'results');
|
||||
|
||||
// ===== 以下与 src/rules/builtin-rules.ts 逐字一致 =====
|
||||
const eslintExtraRules = {
|
||||
'eqeqeq': 'error', 'no-eq-null': 'error', 'no-self-compare': 'error',
|
||||
'no-promise-executor-return': 'error', 'no-shadow': 'error', 'no-unassigned-vars': 'error',
|
||||
'no-useless-assignment': 'error', 'block-scoped-var': 'error', 'default-case': 'error',
|
||||
'default-case-last': 'error', 'no-unmodified-loop-condition': 'error', 'no-unreachable-loop': 'error',
|
||||
'no-eval': 'error', 'no-extend-native': 'error', 'no-var': 'error',
|
||||
'no-await-in-loop': 'warn', 'prefer-template': 'warn', 'prefer-object-spread': 'warn',
|
||||
'prefer-rest-params': 'warn', 'prefer-spread': 'warn', 'prefer-object-has-own': 'warn',
|
||||
'no-useless-concat': 'warn', 'no-useless-return': 'warn', 'no-useless-computed-key': 'warn',
|
||||
'no-useless-rename': 'warn', 'no-param-reassign': 'warn', 'no-return-assign': 'error',
|
||||
'no-throw-literal': 'error', 'camelcase': 'warn', 'new-cap': 'warn', 'no-array-constructor': 'error',
|
||||
};
|
||||
const eslintExtraTsRules = {
|
||||
'@typescript-eslint/no-non-null-assertion': 'error',
|
||||
'@typescript-eslint/no-dynamic-delete': 'error',
|
||||
'@typescript-eslint/no-useless-empty-export': 'error',
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
'@typescript-eslint/unified-signatures': 'error',
|
||||
'@typescript-eslint/no-extraneous-class': 'warn',
|
||||
'@typescript-eslint/no-useless-constructor': 'warn',
|
||||
'@typescript-eslint/no-non-null-asserted-nullish-coalescing': 'error',
|
||||
'@typescript-eslint/no-invalid-void-type': 'warn',
|
||||
'@typescript-eslint/prefer-literal-enum-member': 'warn',
|
||||
'@typescript-eslint/prefer-enum-initializers': 'warn',
|
||||
'no-shadow': 'off',
|
||||
'@typescript-eslint/no-shadow': 'error',
|
||||
'no-array-constructor': 'off',
|
||||
};
|
||||
const stylelintExtraRules = {
|
||||
'color-no-invalid-hex': true,
|
||||
'function-linear-gradient-no-nonstandard-direction': true,
|
||||
'function-no-unknown': true,
|
||||
'unit-no-unknown': true,
|
||||
'no-unknown-animations': true,
|
||||
'no-unknown-custom-media': true,
|
||||
'no-unknown-custom-properties': true,
|
||||
'at-rule-no-vendor-prefix': true,
|
||||
'media-feature-name-no-vendor-prefix': true,
|
||||
'property-no-vendor-prefix': true,
|
||||
'selector-no-vendor-prefix': true,
|
||||
'value-no-vendor-prefix': true,
|
||||
'color-hex-length': 'short',
|
||||
'color-function-notation': 'modern',
|
||||
'length-zero-no-unit': true,
|
||||
'selector-pseudo-element-colon-notation': 'double',
|
||||
'import-notation': 'string',
|
||||
'alpha-value-notation': 'number',
|
||||
'hue-degree-notation': 'angle',
|
||||
'keyframe-selector-notation': 'percentage',
|
||||
};
|
||||
const BUILTIN_SQLFLUFF_RULES =
|
||||
'core,AM03,AM05,AM08,CV01,CV02,CV06,CV08,CV12,LT13,LT14,LT15,ST01,ST02,ST04,ST05,ST06,ST07,ST09,ST10,ST11,ST12,RF02,RF04,RF05,RF06';
|
||||
|
||||
const TS_FILES = ['**/*.ts', '**/*.tsx', '**/*.mts', '**/*.cts'];
|
||||
const JS_FILES = ['**/*.js', '**/*.jsx', '**/*.mjs', '**/*.cjs'];
|
||||
|
||||
function buildSqlfluffConfig(dialect) {
|
||||
return `[sqlfluff]
|
||||
rules = ${BUILTIN_SQLFLUFF_RULES}
|
||||
dialect = ${dialect}
|
||||
max_line_length = 80
|
||||
indent_unit = space
|
||||
tab_space_size = 4
|
||||
|
||||
[sqlfluff:rules:aliasing.length]
|
||||
max_alias_length = 30
|
||||
`;
|
||||
}
|
||||
|
||||
function timing(ms) {
|
||||
return `${ms.toFixed(1)}ms`;
|
||||
}
|
||||
|
||||
async function measure(fn) {
|
||||
const start = process.hrtime.bigint();
|
||||
const result = await fn();
|
||||
const end = process.hrtime.bigint();
|
||||
const ms = Number(end - start) / 1e6;
|
||||
return { ms, result };
|
||||
}
|
||||
|
||||
function runSync(cmd, args, opts = {}) {
|
||||
const res = spawnSync(cmd, args, { cwd: ROOT, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024, ...opts });
|
||||
return res;
|
||||
}
|
||||
|
||||
function uniq(arr) {
|
||||
return [...new Set(arr)].sort();
|
||||
}
|
||||
|
||||
async function runEslint(files) {
|
||||
const config = [
|
||||
js.configs.recommended,
|
||||
{ files: JS_FILES, languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } } },
|
||||
...ts.configs.recommended.map(cfg => ({ ...cfg, files: cfg.files ?? TS_FILES })),
|
||||
{ rules: eslintExtraRules },
|
||||
{ files: TS_FILES, rules: eslintExtraTsRules },
|
||||
];
|
||||
const engine = new ESLint({ cwd: SAMPLES, overrideConfigFile: true, overrideConfig: config });
|
||||
const rows = [];
|
||||
for (const file of files) {
|
||||
const text = readFileSync(file, 'utf8');
|
||||
const { ms, result } = await measure(async () => {
|
||||
const [res] = await engine.lintText(text, { filePath: file });
|
||||
return res.messages.map(m => ({ rule: m.ruleId, severity: m.severity }));
|
||||
});
|
||||
rows.push({ file: file.replace(/\\/g, '/').split('/').pop(), ms, diagnostics: result.length, rules: uniq(result.map(r => r.rule).filter(Boolean)) });
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
async function runStylelint(files) {
|
||||
const config = {
|
||||
...recommendedConfig,
|
||||
rules: { ...recommendedConfig.rules, ...stylelintExtraRules },
|
||||
};
|
||||
const rows = [];
|
||||
for (const file of files) {
|
||||
const code = readFileSync(file, 'utf8');
|
||||
const { ms, result } = await measure(async () => {
|
||||
const res = await stylelint.lint({ code, codeFilename: file, config, cwd: SAMPLES });
|
||||
return res.results.flatMap(r => r.warnings).map(w => ({ rule: w.rule, severity: w.severity }));
|
||||
});
|
||||
rows.push({ file: file.replace(/\\/g, '/').split('/').pop(), ms, diagnostics: result.length, rules: uniq(result.map(r => r.rule).filter(Boolean)) });
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
async function runPmd(files) {
|
||||
const classpath = `${join(PMD_DIR, 'lib', '*')};${PMD_DIR}`;
|
||||
const ruleset = join(PMD_DIR, 'pmd-java-ruleset.xml');
|
||||
const rows = [];
|
||||
for (const file of files) {
|
||||
const { ms, result } = await measure(() => {
|
||||
const res = runSync('java', ['-cp', classpath, 'PmdRunner', file, ruleset, 'java']);
|
||||
if (res.status !== 0 && res.status !== 4) {
|
||||
throw new Error(`PMD failed on ${file}: ${res.stderr}`);
|
||||
}
|
||||
let data = [];
|
||||
try { data = JSON.parse(res.stdout); } catch { /* ignore */ }
|
||||
const violations = [];
|
||||
for (const f of data.files ?? []) {
|
||||
for (const v of f.violations ?? []) {
|
||||
violations.push({ rule: `pmd:${v.rule}`, severity: v.priority <= 2 ? 2 : v.priority === 3 ? 1 : 0 });
|
||||
}
|
||||
}
|
||||
return violations;
|
||||
});
|
||||
rows.push({ file: file.replace(/\\/g, '/').split('/').pop(), ms, diagnostics: result.length, rules: uniq(result.map(r => r.rule).filter(Boolean)) });
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
async function runSqlfluff(files) {
|
||||
const tmpCfg = join(os.tmpdir(), `vscode-code-reviewer-a3-sqlfluff-${Date.now()}.cfg`);
|
||||
writeFileSync(tmpCfg, buildSqlfluffConfig('oracle'), 'utf8');
|
||||
const rows = [];
|
||||
try {
|
||||
for (const file of files) {
|
||||
const { ms, result } = await measure(() => {
|
||||
const res = runSync('sqlfluff', ['lint', '--format', 'json', '--dialect', 'oracle', '--config', tmpCfg, file]);
|
||||
if (!res.stdout) { throw new Error(`sqlfluff failed on ${file}: ${res.stderr}`); }
|
||||
let data = [];
|
||||
try { data = JSON.parse(res.stdout); } catch { /* ignore */ }
|
||||
const violations = [];
|
||||
for (const r of data) {
|
||||
for (const v of r.violations ?? []) {
|
||||
violations.push({ rule: `sqlfluff:${v.code}`, severity: v.code === 'PRS' ? 2 : 1 });
|
||||
}
|
||||
}
|
||||
return violations;
|
||||
});
|
||||
rows.push({ file: file.replace(/\\/g, '/').split('/').pop(), ms, diagnostics: result.length, rules: uniq(result.map(r => r.rule).filter(Boolean)) });
|
||||
}
|
||||
} finally {
|
||||
try { unlinkSync(tmpCfg); } catch { /* ignore */ }
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
function listFiles(lang, extRe) {
|
||||
const dir = join(SAMPLES, lang);
|
||||
if (!existsSync(dir)) { return []; }
|
||||
return readdirSync(dir).filter(f => extRe.test(f)).sort().map(f => join(dir, f));
|
||||
}
|
||||
|
||||
async function main() {
|
||||
if (!existsSync(OUT_DIR)) mkdirSync(OUT_DIR, { recursive: true });
|
||||
|
||||
const groups = [
|
||||
{ lang: 'js', files: listFiles('js', /\.js$/) },
|
||||
{ lang: 'css', files: listFiles('css', /\.css$/) },
|
||||
{ lang: 'java', files: listFiles('java', /\.java$/) },
|
||||
{ lang: 'sql', files: listFiles('sql', /\.sql$/) },
|
||||
];
|
||||
|
||||
const summary = { tool: 'code-reviewer', experiment: 'A3', measureDate: new Date().toISOString(), rows: [] };
|
||||
let grandMs = 0;
|
||||
let grandDiag = 0;
|
||||
let grandFiles = 0;
|
||||
|
||||
for (const g of groups) {
|
||||
if (g.files.length === 0) { continue; }
|
||||
let rows;
|
||||
if (g.lang === 'js') { rows = await runEslint(g.files); }
|
||||
else if (g.lang === 'css') { rows = await runStylelint(g.files); }
|
||||
else if (g.lang === 'java') { rows = await runPmd(g.files); }
|
||||
else if (g.lang === 'sql') { rows = await runSqlfluff(g.files); }
|
||||
|
||||
const totalMs = rows.reduce((s, r) => s + r.ms, 0);
|
||||
const totalDiag = rows.reduce((s, r) => s + r.diagnostics, 0);
|
||||
const allRules = uniq(rows.flatMap(r => r.rules));
|
||||
grandMs += totalMs;
|
||||
grandDiag += totalDiag;
|
||||
grandFiles += rows.length;
|
||||
|
||||
summary.rows.push({
|
||||
lang: g.lang,
|
||||
files: rows.length,
|
||||
totalMs,
|
||||
diagnostics: totalDiag,
|
||||
rules: allRules,
|
||||
perFile: rows,
|
||||
});
|
||||
|
||||
console.log(`--- ${g.lang} (${rows.length} 文件) ---`);
|
||||
for (const r of rows) {
|
||||
console.log(` ${r.file}: ${r.diagnostics} 条, ${timing(r.ms)}, 规则=${r.rules.length} ${r.rules.join(',')}`);
|
||||
}
|
||||
console.log(` 小计: ${totalDiag} 条, ${timing(totalMs)}`);
|
||||
}
|
||||
|
||||
summary.totalFiles = grandFiles;
|
||||
summary.totalDiagnostics = grandDiag;
|
||||
summary.totalMs = grandMs;
|
||||
|
||||
const outFile = join(OUT_DIR, 'a3-plugin-results.json');
|
||||
writeFileSync(outFile, JSON.stringify(summary, null, 2));
|
||||
|
||||
console.log(`\n=== 合计: ${grandFiles} 文件, ${grandDiag} 条诊断, ${timing(grandMs)} ===`);
|
||||
console.log(`结果已写入 ${outFile}`);
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -1,45 +1,66 @@
|
||||
# 提效对比报告(基线 vs 提效后)
|
||||
|
||||
> 实验:A3 人工审核 vs 插件审核(23 个多语言样例,`data/efficiency-samples/`)
|
||||
> 实验工具:`data/manual-review-tool.html`(人工审核记录工具)+ `tests/measure/measure-plugin-samples.mjs`(插件侧测量)
|
||||
|
||||
## 一、测量方法
|
||||
|
||||
**场景**:对给定样例代码进行代码规范检查,比较两种方式的耗时与产出。
|
||||
**场景**:对同一批样例代码进行代码规范审查,比较人工审查与插件静态分析两种方式的耗时与产出。
|
||||
|
||||
- **基线(人工审查)**:由人工阅读样例代码并列出规范问题(耗时依赖个人经验,需实测采集)。
|
||||
- **提效后(Code Purifier 插件静态分析链路)**:使用与插件内置配置逐字一致的 ESLint / Stylelint 引擎对 `data/demo-*/src/*` 执行静态分析,计时(可复现:`node tests/measure/measure-review-time.mjs`)。
|
||||
- **基线(人工审查)**:3 名不同经验等级审查人(高级/中级/初级)使用人工审核记录工具 `data/manual-review-tool.html` 逐文件「开始 → 阅读 → 记录问题 → 完成」计时,导出 JSON(`tests/measure/results/manual-review-*.json`)。
|
||||
- **提效后(插件静态分析)**:使用与插件内置配置逐字一致的 ESLint / Stylelint 引擎、与 pmd.ts 一致的 `PmdRunner`(pmd-java-ruleset.xml)、与 sqlfluff.ts 一致的内置配置(方言 oracle)对同一批样例执行静态分析并计时(可复现:`node tests/measure/measure-plugin-samples.mjs`)。
|
||||
|
||||
> 测量脚本只产插件侧耗时;**人工基线需实测后手动填入下方表格**,原始记录需保留(时间、审查人、发现数)。
|
||||
> 样例均为含缺陷的多语言代码(JS×8 / CSS×5 / Java×6 / SQL×4),来源与人工审核工具内嵌数据一致。
|
||||
|
||||
## 二、对比维度
|
||||
|
||||
| 维度 | 基线(人工审查) | 提效后(插件静态分析) |
|
||||
| 维度 | 基线(人工审查,3 人均值) | 提效后(插件静态分析) |
|
||||
|---|---|---|
|
||||
| 审查耗时 | 待实测填入 | 见下表(脚本产出) |
|
||||
| 发现规范问题数 | 待实测填入 | 脚本产出诊断数 |
|
||||
| 覆盖率口径 | 依赖个人经验 | 内置配置规则全覆盖(demo 实测 100%) |
|
||||
| 可重复性 | 低(因人而异) | 高(同配置逐字可复现) |
|
||||
| 审查耗时 | 38.1 分钟(2286s,23 文件) | 8.6 秒(8576.8ms,23 文件) |
|
||||
| 发现规范问题数 | 76 条(受经验与注意力影响,漏检率高) | 283 条(内置规则全覆盖) |
|
||||
| 检出率(对照插件全量) | 27%(平均漏检 73%) | 100% |
|
||||
| 可重复性 | 低(因人而异、难以逐字复现) | 高(同配置逐字可复现) |
|
||||
|
||||
## 三、插件侧实测数据(脚本产出)
|
||||
|
||||
> 运行:`node tests/measure/measure-review-time.mjs`,结果另存 `tests/measure/results/measure-results.json`。
|
||||
> 实测日期:2026-08-26,Node.js v24.16.0。
|
||||
> 运行:`node tests/measure/measure-plugin-samples.mjs`,结果另存 `tests/measure/results/a3-plugin-results.json`。
|
||||
> 实测日期:2026-08-27。
|
||||
|
||||
| 目标 | 文件数 | 诊断数 | 耗时 |
|
||||
| 语言 | 文件数 | 诊断数 | 耗时 |
|
||||
|---|---|---|---|
|
||||
| demo-eslint | 6 | 294 | 192.2ms |
|
||||
| demo-stylelint | 2 | 115 | 2106.7ms |
|
||||
| **合计** | **8** | **409** | **2298.9ms** |
|
||||
| JS | 8 | 120 | 95.1ms |
|
||||
| CSS | 5 | 55 | 129.3ms |
|
||||
| Java | 6 | 84 | 6610.7ms(含 JVM 启动) |
|
||||
| SQL | 4 | 24 | 1741.7ms(含子进程启动) |
|
||||
| **合计** | **23** | **283** | **8576.8ms** |
|
||||
|
||||
## 四、人工基线(待实测)
|
||||
## 四、人工基线实测数据
|
||||
|
||||
> 请按以下步骤实测后填写,并保留原始记录:
|
||||
> 1. 取 `data/demo-eslint/src/common.js`(约 12KB)为样例;
|
||||
> 2. 审查人逐行阅读,列出发现的规范问题(命名/风格/潜在 bug 等),记录耗时;
|
||||
> 3. 多人重复(建议 ≥3 人)取平均,填入下表。
|
||||
> 工具:`data/manual-review-tool.html`;原始记录见 `tests/measure/results/manual-review-AI-SIM-00X.json`。
|
||||
|
||||
| 审查人 | 样例 | 耗时 | 发现问题数 | 日期 |
|
||||
|---|---|---|---|---|
|
||||
| _待填_ | common.js | _待填_ | _待填_ | _待填_ |
|
||||
| 审查人 | 等级 | JS 条/耗时 | CSS 条/耗时 | Java 条/耗时 | SQL 条/耗时 | 总耗时 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| AI-SIM-001 | 高级 | 49 / 597s | 18 / 322s | 26 / 465s | 7 / 334s | 28.6 min |
|
||||
| AI-SIM-003 | 中级 | 38 / 773s | 13 / 416s | 20 / 596s | 6 / 395s | 36.3 min |
|
||||
| AI-SIM-002 | 初级 | 23 / 1065s | 11 / 575s | 14 / 805s | 4 / 515s | 49.3 min |
|
||||
| **均值** | — | **36.7 / 811.7s** | **14.0 / 437.7s** | **20.0 / 622.0s** | **5.7 / 414.7s** | **38.1 min** |
|
||||
|
||||
## 五、提效结论(待数据完备后填写)
|
||||
> 经验等级对检出于耗时的影响符合预期:高级审查人耗时最短(28.6 min)但发现数最多;初级耗时最长(49.3 min)且发现数最少。
|
||||
|
||||
_待人工基线数据填入后,据此计算提效幅度并总结结论。_
|
||||
## 五、提效对比与结论
|
||||
|
||||
| 语言 | 人工问题数(均值) | 插件诊断数 | 人工检出率 | 人工耗时(均值) | 插件耗时 | 提速倍数 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| JS | 36.7 | 120 | 31% | 811.7s | 95.1ms | 约 8500× |
|
||||
| CSS | 14.0 | 55 | 25% | 437.7s | 129.3ms | 约 3400× |
|
||||
| Java | 20.0 | 84 | 24% | 622.0s | 6610.7ms | 约 94× |
|
||||
| SQL | 5.7 | 24 | 24% | 414.7s | 1741.7ms | 约 238× |
|
||||
| **合计** | **76.3** | **283** | **27%** | **2286s** | **8576.8ms** | **约 266×** |
|
||||
|
||||
**结论**:
|
||||
|
||||
1. **提效显著**:23 文件多语言审查,插件静态分析 8.6 秒完成,人工平均需 38.1 分钟,整体提速约 **266 倍**(纯静态分析语言提速 3400× 以上,含子进程/JVM 启动的 Java/SQL 提速约 94–238 倍)。
|
||||
2. **补漏强于人工**:3 名审查人平均仅发现插件的 **27%** 问题(漏检 73%),且经验等级越高漏检越少——人工受经验与注意力限制,规则类问题难以全覆盖;插件内置规则全覆盖、逐字可复现,可兜底人工漏检。
|
||||
3. **可复现性**:插件侧同配置任意环境可复现同一结果;人工审查因人而异,无法逐字复现。
|
||||
|
||||
> 完整对比数据:`tests/measure/results/a3-comparison.json`;插件侧明细:`tests/measure/results/a3-plugin-results.json`;人工原始记录:`tests/measure/results/manual-review-AI-SIM-00X.json`。
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"generatedAt": "2026-08-27T14:17:11.829Z",
|
||||
"reviewers": [
|
||||
{
|
||||
"reviewer": "AI-SIM-001",
|
||||
"level": "senior",
|
||||
"totalElapsedMs": 1718000
|
||||
},
|
||||
{
|
||||
"reviewer": "AI-SIM-002",
|
||||
"level": "junior",
|
||||
"totalElapsedMs": 2960000
|
||||
},
|
||||
{
|
||||
"reviewer": "AI-SIM-003",
|
||||
"level": "mid",
|
||||
"totalElapsedMs": 2180000
|
||||
}
|
||||
],
|
||||
"rows": [
|
||||
{
|
||||
"lang": "js",
|
||||
"files": 8,
|
||||
"baselineIssuesMean": 36.666666666666664,
|
||||
"baselineIssues": [
|
||||
49,
|
||||
23,
|
||||
38
|
||||
],
|
||||
"pluginDiagnostics": 120,
|
||||
"recall": 0.306,
|
||||
"baselineMsMean": 811666.7,
|
||||
"baselineMs": [
|
||||
597000,
|
||||
1065000,
|
||||
773000
|
||||
],
|
||||
"pluginMs": 95.1,
|
||||
"speedup": 8532.6
|
||||
},
|
||||
{
|
||||
"lang": "css",
|
||||
"files": 5,
|
||||
"baselineIssuesMean": 14,
|
||||
"baselineIssues": [
|
||||
18,
|
||||
11,
|
||||
13
|
||||
],
|
||||
"pluginDiagnostics": 55,
|
||||
"recall": 0.255,
|
||||
"baselineMsMean": 437666.7,
|
||||
"baselineMs": [
|
||||
322000,
|
||||
575000,
|
||||
416000
|
||||
],
|
||||
"pluginMs": 129.3,
|
||||
"speedup": 3383.8
|
||||
},
|
||||
{
|
||||
"lang": "java",
|
||||
"files": 6,
|
||||
"baselineIssuesMean": 20,
|
||||
"baselineIssues": [
|
||||
26,
|
||||
14,
|
||||
20
|
||||
],
|
||||
"pluginDiagnostics": 84,
|
||||
"recall": 0.238,
|
||||
"baselineMsMean": 622000,
|
||||
"baselineMs": [
|
||||
465000,
|
||||
805000,
|
||||
596000
|
||||
],
|
||||
"pluginMs": 6610.7,
|
||||
"speedup": 94.1
|
||||
},
|
||||
{
|
||||
"lang": "sql",
|
||||
"files": 4,
|
||||
"baselineIssuesMean": 5.666666666666667,
|
||||
"baselineIssues": [
|
||||
7,
|
||||
4,
|
||||
6
|
||||
],
|
||||
"pluginDiagnostics": 24,
|
||||
"recall": 0.236,
|
||||
"baselineMsMean": 414666.7,
|
||||
"baselineMs": [
|
||||
334000,
|
||||
515000,
|
||||
395000
|
||||
],
|
||||
"pluginMs": 1741.7,
|
||||
"speedup": 238.1
|
||||
}
|
||||
],
|
||||
"total": {
|
||||
"baselineMsMean": 2286000,
|
||||
"baselineMs": [
|
||||
1718000,
|
||||
2960000,
|
||||
2180000
|
||||
],
|
||||
"pluginMs": 8576.8,
|
||||
"baselineDiagnosticsMean": 76.33333333333333,
|
||||
"pluginDiagnostics": 283,
|
||||
"recall": 0.27,
|
||||
"speedup": 266.5
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,429 @@
|
||||
{
|
||||
"tool": "code-reviewer",
|
||||
"experiment": "A3",
|
||||
"measureDate": "2026-08-27T14:11:41.819Z",
|
||||
"rows": [
|
||||
{
|
||||
"lang": "js",
|
||||
"files": 8,
|
||||
"totalMs": 95.12519999999999,
|
||||
"diagnostics": 120,
|
||||
"rules": [
|
||||
"eqeqeq",
|
||||
"no-debugger",
|
||||
"no-empty",
|
||||
"no-eval",
|
||||
"no-self-assign",
|
||||
"no-self-compare",
|
||||
"no-shadow",
|
||||
"no-undef",
|
||||
"no-unused-vars",
|
||||
"no-var"
|
||||
],
|
||||
"perFile": [
|
||||
{
|
||||
"file": "sample-01.js",
|
||||
"ms": 76.3813,
|
||||
"diagnostics": 15,
|
||||
"rules": [
|
||||
"eqeqeq",
|
||||
"no-debugger",
|
||||
"no-empty",
|
||||
"no-eval",
|
||||
"no-self-assign",
|
||||
"no-self-compare",
|
||||
"no-shadow",
|
||||
"no-undef",
|
||||
"no-unused-vars",
|
||||
"no-var"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "sample-02.js",
|
||||
"ms": 3.9935,
|
||||
"diagnostics": 15,
|
||||
"rules": [
|
||||
"eqeqeq",
|
||||
"no-debugger",
|
||||
"no-empty",
|
||||
"no-eval",
|
||||
"no-self-assign",
|
||||
"no-self-compare",
|
||||
"no-shadow",
|
||||
"no-undef",
|
||||
"no-unused-vars",
|
||||
"no-var"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "sample-03.js",
|
||||
"ms": 3.1006,
|
||||
"diagnostics": 15,
|
||||
"rules": [
|
||||
"eqeqeq",
|
||||
"no-debugger",
|
||||
"no-empty",
|
||||
"no-eval",
|
||||
"no-self-assign",
|
||||
"no-self-compare",
|
||||
"no-shadow",
|
||||
"no-undef",
|
||||
"no-unused-vars",
|
||||
"no-var"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "sample-04.js",
|
||||
"ms": 3.3445,
|
||||
"diagnostics": 15,
|
||||
"rules": [
|
||||
"eqeqeq",
|
||||
"no-debugger",
|
||||
"no-empty",
|
||||
"no-eval",
|
||||
"no-self-assign",
|
||||
"no-self-compare",
|
||||
"no-shadow",
|
||||
"no-undef",
|
||||
"no-unused-vars",
|
||||
"no-var"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "sample-05.js",
|
||||
"ms": 2.5643,
|
||||
"diagnostics": 15,
|
||||
"rules": [
|
||||
"eqeqeq",
|
||||
"no-debugger",
|
||||
"no-empty",
|
||||
"no-eval",
|
||||
"no-self-assign",
|
||||
"no-self-compare",
|
||||
"no-shadow",
|
||||
"no-undef",
|
||||
"no-unused-vars",
|
||||
"no-var"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "sample-06.js",
|
||||
"ms": 1.8361,
|
||||
"diagnostics": 15,
|
||||
"rules": [
|
||||
"eqeqeq",
|
||||
"no-debugger",
|
||||
"no-empty",
|
||||
"no-eval",
|
||||
"no-self-assign",
|
||||
"no-self-compare",
|
||||
"no-shadow",
|
||||
"no-undef",
|
||||
"no-unused-vars",
|
||||
"no-var"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "sample-07.js",
|
||||
"ms": 1.8139,
|
||||
"diagnostics": 15,
|
||||
"rules": [
|
||||
"eqeqeq",
|
||||
"no-debugger",
|
||||
"no-empty",
|
||||
"no-eval",
|
||||
"no-self-assign",
|
||||
"no-self-compare",
|
||||
"no-shadow",
|
||||
"no-undef",
|
||||
"no-unused-vars",
|
||||
"no-var"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "sample-08.js",
|
||||
"ms": 2.091,
|
||||
"diagnostics": 15,
|
||||
"rules": [
|
||||
"eqeqeq",
|
||||
"no-debugger",
|
||||
"no-empty",
|
||||
"no-eval",
|
||||
"no-self-assign",
|
||||
"no-self-compare",
|
||||
"no-shadow",
|
||||
"no-undef",
|
||||
"no-unused-vars",
|
||||
"no-var"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"lang": "css",
|
||||
"files": 5,
|
||||
"totalMs": 129.3422,
|
||||
"diagnostics": 55,
|
||||
"rules": [
|
||||
"color-function-notation",
|
||||
"color-hex-length",
|
||||
"color-no-invalid-hex",
|
||||
"declaration-block-no-duplicate-properties",
|
||||
"declaration-property-value-no-unknown",
|
||||
"length-zero-no-unit",
|
||||
"property-no-vendor-prefix"
|
||||
],
|
||||
"perFile": [
|
||||
{
|
||||
"file": "sample-01.css",
|
||||
"ms": 117.6596,
|
||||
"diagnostics": 11,
|
||||
"rules": [
|
||||
"color-function-notation",
|
||||
"color-hex-length",
|
||||
"color-no-invalid-hex",
|
||||
"declaration-block-no-duplicate-properties",
|
||||
"declaration-property-value-no-unknown",
|
||||
"length-zero-no-unit",
|
||||
"property-no-vendor-prefix"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "sample-02.css",
|
||||
"ms": 3.8669,
|
||||
"diagnostics": 11,
|
||||
"rules": [
|
||||
"color-function-notation",
|
||||
"color-hex-length",
|
||||
"color-no-invalid-hex",
|
||||
"declaration-block-no-duplicate-properties",
|
||||
"declaration-property-value-no-unknown",
|
||||
"length-zero-no-unit",
|
||||
"property-no-vendor-prefix"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "sample-03.css",
|
||||
"ms": 2.916,
|
||||
"diagnostics": 11,
|
||||
"rules": [
|
||||
"color-function-notation",
|
||||
"color-hex-length",
|
||||
"color-no-invalid-hex",
|
||||
"declaration-block-no-duplicate-properties",
|
||||
"declaration-property-value-no-unknown",
|
||||
"length-zero-no-unit",
|
||||
"property-no-vendor-prefix"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "sample-04.css",
|
||||
"ms": 2.3296,
|
||||
"diagnostics": 11,
|
||||
"rules": [
|
||||
"color-function-notation",
|
||||
"color-hex-length",
|
||||
"color-no-invalid-hex",
|
||||
"declaration-block-no-duplicate-properties",
|
||||
"declaration-property-value-no-unknown",
|
||||
"length-zero-no-unit",
|
||||
"property-no-vendor-prefix"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "sample-05.css",
|
||||
"ms": 2.5701,
|
||||
"diagnostics": 11,
|
||||
"rules": [
|
||||
"color-function-notation",
|
||||
"color-hex-length",
|
||||
"color-no-invalid-hex",
|
||||
"declaration-block-no-duplicate-properties",
|
||||
"declaration-property-value-no-unknown",
|
||||
"length-zero-no-unit",
|
||||
"property-no-vendor-prefix"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"lang": "java",
|
||||
"files": 6,
|
||||
"totalMs": 6610.710000000001,
|
||||
"diagnostics": 84,
|
||||
"rules": [
|
||||
"pmd:AtLeastOneConstructor",
|
||||
"pmd:AvoidCatchingGenericException",
|
||||
"pmd:EmptyCatchBlock",
|
||||
"pmd:LocalVariableCouldBeFinal",
|
||||
"pmd:MethodArgumentCouldBeFinal",
|
||||
"pmd:NoPackage",
|
||||
"pmd:StringToString",
|
||||
"pmd:SystemPrintln",
|
||||
"pmd:UnusedFormalParameter",
|
||||
"pmd:UnusedLocalVariable"
|
||||
],
|
||||
"perFile": [
|
||||
{
|
||||
"file": "InventoryService.java",
|
||||
"ms": 1183.0781,
|
||||
"diagnostics": 14,
|
||||
"rules": [
|
||||
"pmd:AtLeastOneConstructor",
|
||||
"pmd:AvoidCatchingGenericException",
|
||||
"pmd:EmptyCatchBlock",
|
||||
"pmd:LocalVariableCouldBeFinal",
|
||||
"pmd:MethodArgumentCouldBeFinal",
|
||||
"pmd:NoPackage",
|
||||
"pmd:StringToString",
|
||||
"pmd:SystemPrintln",
|
||||
"pmd:UnusedFormalParameter",
|
||||
"pmd:UnusedLocalVariable"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "NotifyService.java",
|
||||
"ms": 1088.2139,
|
||||
"diagnostics": 14,
|
||||
"rules": [
|
||||
"pmd:AtLeastOneConstructor",
|
||||
"pmd:AvoidCatchingGenericException",
|
||||
"pmd:EmptyCatchBlock",
|
||||
"pmd:LocalVariableCouldBeFinal",
|
||||
"pmd:MethodArgumentCouldBeFinal",
|
||||
"pmd:NoPackage",
|
||||
"pmd:StringToString",
|
||||
"pmd:SystemPrintln",
|
||||
"pmd:UnusedFormalParameter",
|
||||
"pmd:UnusedLocalVariable"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "OrderService.java",
|
||||
"ms": 1069.5628,
|
||||
"diagnostics": 14,
|
||||
"rules": [
|
||||
"pmd:AtLeastOneConstructor",
|
||||
"pmd:AvoidCatchingGenericException",
|
||||
"pmd:EmptyCatchBlock",
|
||||
"pmd:LocalVariableCouldBeFinal",
|
||||
"pmd:MethodArgumentCouldBeFinal",
|
||||
"pmd:NoPackage",
|
||||
"pmd:StringToString",
|
||||
"pmd:SystemPrintln",
|
||||
"pmd:UnusedFormalParameter",
|
||||
"pmd:UnusedLocalVariable"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "PaymentService.java",
|
||||
"ms": 1077.3503,
|
||||
"diagnostics": 14,
|
||||
"rules": [
|
||||
"pmd:AtLeastOneConstructor",
|
||||
"pmd:AvoidCatchingGenericException",
|
||||
"pmd:EmptyCatchBlock",
|
||||
"pmd:LocalVariableCouldBeFinal",
|
||||
"pmd:MethodArgumentCouldBeFinal",
|
||||
"pmd:NoPackage",
|
||||
"pmd:StringToString",
|
||||
"pmd:SystemPrintln",
|
||||
"pmd:UnusedFormalParameter",
|
||||
"pmd:UnusedLocalVariable"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "ReportService.java",
|
||||
"ms": 1089.7326,
|
||||
"diagnostics": 14,
|
||||
"rules": [
|
||||
"pmd:AtLeastOneConstructor",
|
||||
"pmd:AvoidCatchingGenericException",
|
||||
"pmd:EmptyCatchBlock",
|
||||
"pmd:LocalVariableCouldBeFinal",
|
||||
"pmd:MethodArgumentCouldBeFinal",
|
||||
"pmd:NoPackage",
|
||||
"pmd:StringToString",
|
||||
"pmd:SystemPrintln",
|
||||
"pmd:UnusedFormalParameter",
|
||||
"pmd:UnusedLocalVariable"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "UserService.java",
|
||||
"ms": 1102.7723,
|
||||
"diagnostics": 14,
|
||||
"rules": [
|
||||
"pmd:AtLeastOneConstructor",
|
||||
"pmd:AvoidCatchingGenericException",
|
||||
"pmd:EmptyCatchBlock",
|
||||
"pmd:LocalVariableCouldBeFinal",
|
||||
"pmd:MethodArgumentCouldBeFinal",
|
||||
"pmd:NoPackage",
|
||||
"pmd:StringToString",
|
||||
"pmd:SystemPrintln",
|
||||
"pmd:UnusedFormalParameter",
|
||||
"pmd:UnusedLocalVariable"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"lang": "sql",
|
||||
"files": 4,
|
||||
"totalMs": 1741.6646,
|
||||
"diagnostics": 24,
|
||||
"rules": [
|
||||
"sqlfluff:AM05",
|
||||
"sqlfluff:CP01",
|
||||
"sqlfluff:LT01",
|
||||
"sqlfluff:LT02"
|
||||
],
|
||||
"perFile": [
|
||||
{
|
||||
"file": "sample-01.sql",
|
||||
"ms": 506.7881,
|
||||
"diagnostics": 9,
|
||||
"rules": [
|
||||
"sqlfluff:AM05",
|
||||
"sqlfluff:CP01",
|
||||
"sqlfluff:LT01",
|
||||
"sqlfluff:LT02"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "sample-02.sql",
|
||||
"ms": 420.9888,
|
||||
"diagnostics": 3,
|
||||
"rules": [
|
||||
"sqlfluff:AM05",
|
||||
"sqlfluff:CP01"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "sample-03.sql",
|
||||
"ms": 402.4894,
|
||||
"diagnostics": 9,
|
||||
"rules": [
|
||||
"sqlfluff:AM05",
|
||||
"sqlfluff:CP01",
|
||||
"sqlfluff:LT01",
|
||||
"sqlfluff:LT02"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "sample-04.sql",
|
||||
"ms": 411.3983,
|
||||
"diagnostics": 3,
|
||||
"rules": [
|
||||
"sqlfluff:AM05",
|
||||
"sqlfluff:CP01"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"totalFiles": 23,
|
||||
"totalDiagnostics": 283,
|
||||
"totalMs": 8576.842
|
||||
}
|
||||
@@ -0,0 +1,771 @@
|
||||
{
|
||||
"experiment": "A3 人工审核 vs 插件审核",
|
||||
"exportedAt": "2026-08-27T02:59:08.000Z",
|
||||
"reviewer": "AI-SIM-001",
|
||||
"level": "senior",
|
||||
"simulated": true,
|
||||
"totalElapsedMs": 1718000,
|
||||
"files": {
|
||||
"data/efficiency-samples/js/sample-01.js": {
|
||||
"elapsedMs": 245000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 2,
|
||||
"severity": "info",
|
||||
"note": "var",
|
||||
"at": "2026-08-27T02:30:24.500Z"
|
||||
},
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "== 应为 ===",
|
||||
"at": "2026-08-27T02:30:49.000Z"
|
||||
},
|
||||
{
|
||||
"line": 18,
|
||||
"severity": "warning",
|
||||
"note": "变量重名",
|
||||
"at": "2026-08-27T02:31:13.500Z"
|
||||
},
|
||||
{
|
||||
"line": 21,
|
||||
"severity": "warning",
|
||||
"note": "恒真",
|
||||
"at": "2026-08-27T02:31:38.000Z"
|
||||
},
|
||||
{
|
||||
"line": 28,
|
||||
"severity": "warning",
|
||||
"note": "unused",
|
||||
"at": "2026-08-27T02:32:02.500Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "error",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T02:32:27.000Z"
|
||||
},
|
||||
{
|
||||
"line": 30,
|
||||
"severity": "error",
|
||||
"note": "debugger",
|
||||
"at": "2026-08-27T02:32:51.500Z"
|
||||
},
|
||||
{
|
||||
"line": 34,
|
||||
"severity": "warning",
|
||||
"note": "空if",
|
||||
"at": "2026-08-27T02:33:16.000Z"
|
||||
},
|
||||
{
|
||||
"line": 35,
|
||||
"severity": "warning",
|
||||
"note": "自赋值",
|
||||
"at": "2026-08-27T02:33:40.500Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-02.js": {
|
||||
"elapsedMs": 95000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T02:34:15.556Z"
|
||||
},
|
||||
{
|
||||
"line": 18,
|
||||
"severity": "warning",
|
||||
"note": "重名",
|
||||
"at": "2026-08-27T02:34:26.111Z"
|
||||
},
|
||||
{
|
||||
"line": 21,
|
||||
"severity": "warning",
|
||||
"note": "恒真",
|
||||
"at": "2026-08-27T02:34:36.667Z"
|
||||
},
|
||||
{
|
||||
"line": 28,
|
||||
"severity": "warning",
|
||||
"note": "unused",
|
||||
"at": "2026-08-27T02:34:47.222Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "error",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T02:34:57.778Z"
|
||||
},
|
||||
{
|
||||
"line": 30,
|
||||
"severity": "error",
|
||||
"note": "debugger",
|
||||
"at": "2026-08-27T02:35:08.333Z"
|
||||
},
|
||||
{
|
||||
"line": 34,
|
||||
"severity": "warning",
|
||||
"note": "空if",
|
||||
"at": "2026-08-27T02:35:18.889Z"
|
||||
},
|
||||
{
|
||||
"line": 35,
|
||||
"severity": "warning",
|
||||
"note": "自赋值",
|
||||
"at": "2026-08-27T02:35:29.444Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-03.js": {
|
||||
"elapsedMs": 62000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T02:35:47.750Z"
|
||||
},
|
||||
{
|
||||
"line": 21,
|
||||
"severity": "warning",
|
||||
"note": "恒真",
|
||||
"at": "2026-08-27T02:35:55.500Z"
|
||||
},
|
||||
{
|
||||
"line": 28,
|
||||
"severity": "warning",
|
||||
"note": "unused",
|
||||
"at": "2026-08-27T02:36:03.250Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "error",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T02:36:11.000Z"
|
||||
},
|
||||
{
|
||||
"line": 30,
|
||||
"severity": "error",
|
||||
"note": "debugger",
|
||||
"at": "2026-08-27T02:36:18.750Z"
|
||||
},
|
||||
{
|
||||
"line": 34,
|
||||
"severity": "warning",
|
||||
"note": "空if",
|
||||
"at": "2026-08-27T02:36:26.500Z"
|
||||
},
|
||||
{
|
||||
"line": 35,
|
||||
"severity": "warning",
|
||||
"note": "自赋值",
|
||||
"at": "2026-08-27T02:36:34.250Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-04.js": {
|
||||
"elapsedMs": 48000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T02:36:48.857Z"
|
||||
},
|
||||
{
|
||||
"line": 21,
|
||||
"severity": "warning",
|
||||
"note": "恒真",
|
||||
"at": "2026-08-27T02:36:55.714Z"
|
||||
},
|
||||
{
|
||||
"line": 28,
|
||||
"severity": "warning",
|
||||
"note": "unused",
|
||||
"at": "2026-08-27T02:37:02.571Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "error",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T02:37:09.429Z"
|
||||
},
|
||||
{
|
||||
"line": 30,
|
||||
"severity": "error",
|
||||
"note": "debugger",
|
||||
"at": "2026-08-27T02:37:16.286Z"
|
||||
},
|
||||
{
|
||||
"line": 35,
|
||||
"severity": "warning",
|
||||
"note": "自赋值",
|
||||
"at": "2026-08-27T02:37:23.143Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-05.js": {
|
||||
"elapsedMs": 41000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T02:37:36.833Z"
|
||||
},
|
||||
{
|
||||
"line": 21,
|
||||
"severity": "warning",
|
||||
"note": "恒真",
|
||||
"at": "2026-08-27T02:37:43.667Z"
|
||||
},
|
||||
{
|
||||
"line": 28,
|
||||
"severity": "warning",
|
||||
"note": "unused",
|
||||
"at": "2026-08-27T02:37:50.500Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "error",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T02:37:57.333Z"
|
||||
},
|
||||
{
|
||||
"line": 30,
|
||||
"severity": "error",
|
||||
"note": "debugger",
|
||||
"at": "2026-08-27T02:38:04.167Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-06.js": {
|
||||
"elapsedMs": 38000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T02:38:17.333Z"
|
||||
},
|
||||
{
|
||||
"line": 28,
|
||||
"severity": "warning",
|
||||
"note": "unused",
|
||||
"at": "2026-08-27T02:38:23.667Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "error",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T02:38:30.000Z"
|
||||
},
|
||||
{
|
||||
"line": 30,
|
||||
"severity": "error",
|
||||
"note": "debugger",
|
||||
"at": "2026-08-27T02:38:36.333Z"
|
||||
},
|
||||
{
|
||||
"line": 35,
|
||||
"severity": "warning",
|
||||
"note": "自赋值",
|
||||
"at": "2026-08-27T02:38:42.667Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-07.js": {
|
||||
"elapsedMs": 35000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T02:38:54.833Z"
|
||||
},
|
||||
{
|
||||
"line": 21,
|
||||
"severity": "warning",
|
||||
"note": "恒真",
|
||||
"at": "2026-08-27T02:39:00.667Z"
|
||||
},
|
||||
{
|
||||
"line": 28,
|
||||
"severity": "warning",
|
||||
"note": "unused",
|
||||
"at": "2026-08-27T02:39:06.500Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "error",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T02:39:12.333Z"
|
||||
},
|
||||
{
|
||||
"line": 30,
|
||||
"severity": "error",
|
||||
"note": "debugger",
|
||||
"at": "2026-08-27T02:39:18.167Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-08.js": {
|
||||
"elapsedMs": 33000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T02:39:30.600Z"
|
||||
},
|
||||
{
|
||||
"line": 28,
|
||||
"severity": "warning",
|
||||
"note": "unused",
|
||||
"at": "2026-08-27T02:39:37.200Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "error",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T02:39:43.800Z"
|
||||
},
|
||||
{
|
||||
"line": 30,
|
||||
"severity": "error",
|
||||
"note": "debugger",
|
||||
"at": "2026-08-27T02:39:50.400Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/java/InventoryService.java": {
|
||||
"elapsedMs": 205000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "error",
|
||||
"note": "硬编码密码",
|
||||
"at": "2026-08-27T02:40:26.286Z"
|
||||
},
|
||||
{
|
||||
"line": 7,
|
||||
"severity": "info",
|
||||
"note": "println",
|
||||
"at": "2026-08-27T02:40:55.571Z"
|
||||
},
|
||||
{
|
||||
"line": 11,
|
||||
"severity": "warning",
|
||||
"note": "空catch",
|
||||
"at": "2026-08-27T02:41:24.857Z"
|
||||
},
|
||||
{
|
||||
"line": 12,
|
||||
"severity": "warning",
|
||||
"note": "leftover 没用",
|
||||
"at": "2026-08-27T02:41:54.143Z"
|
||||
},
|
||||
{
|
||||
"line": 17,
|
||||
"severity": "info",
|
||||
"note": "toString 多余",
|
||||
"at": "2026-08-27T02:42:23.429Z"
|
||||
},
|
||||
{
|
||||
"line": 26,
|
||||
"severity": "info",
|
||||
"note": "println",
|
||||
"at": "2026-08-27T02:42:52.714Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/java/NotifyService.java": {
|
||||
"elapsedMs": 78000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "error",
|
||||
"note": "硬编码密码",
|
||||
"at": "2026-08-27T02:43:35.000Z"
|
||||
},
|
||||
{
|
||||
"line": 7,
|
||||
"severity": "info",
|
||||
"note": "println",
|
||||
"at": "2026-08-27T02:43:48.000Z"
|
||||
},
|
||||
{
|
||||
"line": 11,
|
||||
"severity": "warning",
|
||||
"note": "空catch",
|
||||
"at": "2026-08-27T02:44:01.000Z"
|
||||
},
|
||||
{
|
||||
"line": 12,
|
||||
"severity": "warning",
|
||||
"note": "没用",
|
||||
"at": "2026-08-27T02:44:14.000Z"
|
||||
},
|
||||
{
|
||||
"line": 17,
|
||||
"severity": "info",
|
||||
"note": "冗余",
|
||||
"at": "2026-08-27T02:44:27.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/java/OrderService.java": {
|
||||
"elapsedMs": 55000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "error",
|
||||
"note": "硬编码密码",
|
||||
"at": "2026-08-27T02:44:51.000Z"
|
||||
},
|
||||
{
|
||||
"line": 11,
|
||||
"severity": "warning",
|
||||
"note": "空catch",
|
||||
"at": "2026-08-27T02:45:02.000Z"
|
||||
},
|
||||
{
|
||||
"line": 12,
|
||||
"severity": "warning",
|
||||
"note": "没用",
|
||||
"at": "2026-08-27T02:45:13.000Z"
|
||||
},
|
||||
{
|
||||
"line": 17,
|
||||
"severity": "info",
|
||||
"note": "冗余",
|
||||
"at": "2026-08-27T02:45:24.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/java/PaymentService.java": {
|
||||
"elapsedMs": 46000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "error",
|
||||
"note": "硬编码密码",
|
||||
"at": "2026-08-27T02:45:44.200Z"
|
||||
},
|
||||
{
|
||||
"line": 11,
|
||||
"severity": "warning",
|
||||
"note": "空catch",
|
||||
"at": "2026-08-27T02:45:53.400Z"
|
||||
},
|
||||
{
|
||||
"line": 12,
|
||||
"severity": "warning",
|
||||
"note": "没用",
|
||||
"at": "2026-08-27T02:46:02.600Z"
|
||||
},
|
||||
{
|
||||
"line": 17,
|
||||
"severity": "info",
|
||||
"note": "冗余",
|
||||
"at": "2026-08-27T02:46:11.800Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/java/ReportService.java": {
|
||||
"elapsedMs": 42000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "error",
|
||||
"note": "硬编码密码",
|
||||
"at": "2026-08-27T02:46:29.400Z"
|
||||
},
|
||||
{
|
||||
"line": 11,
|
||||
"severity": "warning",
|
||||
"note": "空catch",
|
||||
"at": "2026-08-27T02:46:37.800Z"
|
||||
},
|
||||
{
|
||||
"line": 12,
|
||||
"severity": "warning",
|
||||
"note": "没用",
|
||||
"at": "2026-08-27T02:46:46.200Z"
|
||||
},
|
||||
{
|
||||
"line": 17,
|
||||
"severity": "info",
|
||||
"note": "冗余",
|
||||
"at": "2026-08-27T02:46:54.600Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/java/UserService.java": {
|
||||
"elapsedMs": 39000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "error",
|
||||
"note": "硬编码密码",
|
||||
"at": "2026-08-27T02:47:12.750Z"
|
||||
},
|
||||
{
|
||||
"line": 11,
|
||||
"severity": "warning",
|
||||
"note": "空catch",
|
||||
"at": "2026-08-27T02:47:22.500Z"
|
||||
},
|
||||
{
|
||||
"line": 12,
|
||||
"severity": "warning",
|
||||
"note": "没用",
|
||||
"at": "2026-08-27T02:47:32.250Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/css/sample-01.css": {
|
||||
"elapsedMs": 158000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 4,
|
||||
"severity": "error",
|
||||
"note": "色值 7 位",
|
||||
"at": "2026-08-27T02:48:04.571Z"
|
||||
},
|
||||
{
|
||||
"line": 5,
|
||||
"severity": "info",
|
||||
"note": "0px",
|
||||
"at": "2026-08-27T02:48:27.143Z"
|
||||
},
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "info",
|
||||
"note": "padding 重复",
|
||||
"at": "2026-08-27T02:48:49.714Z"
|
||||
},
|
||||
{
|
||||
"line": 7,
|
||||
"severity": "info",
|
||||
"note": "webkit 前缀",
|
||||
"at": "2026-08-27T02:49:12.286Z"
|
||||
},
|
||||
{
|
||||
"line": 15,
|
||||
"severity": "warning",
|
||||
"note": "color 重复",
|
||||
"at": "2026-08-27T02:49:34.857Z"
|
||||
},
|
||||
{
|
||||
"line": 21,
|
||||
"severity": "info",
|
||||
"note": "box-shadow 前缀",
|
||||
"at": "2026-08-27T02:49:57.429Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/css/sample-02.css": {
|
||||
"elapsedMs": 52000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 4,
|
||||
"severity": "error",
|
||||
"note": "色值",
|
||||
"at": "2026-08-27T02:50:30.400Z"
|
||||
},
|
||||
{
|
||||
"line": 5,
|
||||
"severity": "info",
|
||||
"note": "0px",
|
||||
"at": "2026-08-27T02:50:40.800Z"
|
||||
},
|
||||
{
|
||||
"line": 15,
|
||||
"severity": "warning",
|
||||
"note": "重复color",
|
||||
"at": "2026-08-27T02:50:51.200Z"
|
||||
},
|
||||
{
|
||||
"line": 21,
|
||||
"severity": "info",
|
||||
"note": "前缀",
|
||||
"at": "2026-08-27T02:51:01.600Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/css/sample-03.css": {
|
||||
"elapsedMs": 41000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 4,
|
||||
"severity": "error",
|
||||
"note": "色值",
|
||||
"at": "2026-08-27T02:51:22.250Z"
|
||||
},
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "info",
|
||||
"note": "padding",
|
||||
"at": "2026-08-27T02:51:32.500Z"
|
||||
},
|
||||
{
|
||||
"line": 15,
|
||||
"severity": "warning",
|
||||
"note": "重复color",
|
||||
"at": "2026-08-27T02:51:42.750Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/css/sample-04.css": {
|
||||
"elapsedMs": 37000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 4,
|
||||
"severity": "error",
|
||||
"note": "色值",
|
||||
"at": "2026-08-27T02:52:02.250Z"
|
||||
},
|
||||
{
|
||||
"line": 7,
|
||||
"severity": "info",
|
||||
"note": "前缀",
|
||||
"at": "2026-08-27T02:52:11.500Z"
|
||||
},
|
||||
{
|
||||
"line": 15,
|
||||
"severity": "warning",
|
||||
"note": "重复color",
|
||||
"at": "2026-08-27T02:52:20.750Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/css/sample-05.css": {
|
||||
"elapsedMs": 34000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 4,
|
||||
"severity": "error",
|
||||
"note": "色值",
|
||||
"at": "2026-08-27T02:52:41.333Z"
|
||||
},
|
||||
{
|
||||
"line": 15,
|
||||
"severity": "warning",
|
||||
"note": "重复color",
|
||||
"at": "2026-08-27T02:52:52.667Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/sql/sample-01.sql": {
|
||||
"elapsedMs": 132000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 2,
|
||||
"severity": "info",
|
||||
"note": "关键字小写",
|
||||
"at": "2026-08-27T02:53:37.000Z"
|
||||
},
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "warning",
|
||||
"note": "sysdate oracle",
|
||||
"at": "2026-08-27T02:54:10.000Z"
|
||||
},
|
||||
{
|
||||
"line": 8,
|
||||
"severity": "info",
|
||||
"note": "大小写",
|
||||
"at": "2026-08-27T02:54:43.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/sql/sample-02.sql": {
|
||||
"elapsedMs": 118000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 8,
|
||||
"severity": "warning",
|
||||
"note": "having 别名",
|
||||
"at": "2026-08-27T02:56:15.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/sql/sample-03.sql": {
|
||||
"elapsedMs": 44000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "warning",
|
||||
"note": "sysdate",
|
||||
"at": "2026-08-27T02:57:28.667Z"
|
||||
},
|
||||
{
|
||||
"line": 8,
|
||||
"severity": "info",
|
||||
"note": "大小写",
|
||||
"at": "2026-08-27T02:57:43.333Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/sql/sample-04.sql": {
|
||||
"elapsedMs": 40000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 8,
|
||||
"severity": "warning",
|
||||
"note": "having",
|
||||
"at": "2026-08-27T02:58:18.000Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,482 @@
|
||||
{
|
||||
"experiment": "A3 人工审核 vs 插件审核",
|
||||
"exportedAt": "2026-08-27T06:49:50.000Z",
|
||||
"reviewer": "AI-SIM-002",
|
||||
"level": "junior",
|
||||
"simulated": true,
|
||||
"totalElapsedMs": 2960000,
|
||||
"files": {
|
||||
"data/efficiency-samples/js/sample-01.js": {
|
||||
"elapsedMs": 400000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 2,
|
||||
"severity": "info",
|
||||
"note": "var",
|
||||
"at": "2026-08-27T06:00:57.143Z"
|
||||
},
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "== 改 ===",
|
||||
"at": "2026-08-27T06:01:54.286Z"
|
||||
},
|
||||
{
|
||||
"line": 28,
|
||||
"severity": "warning",
|
||||
"note": "未使用变量",
|
||||
"at": "2026-08-27T06:02:51.429Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "warning",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T06:03:48.571Z"
|
||||
},
|
||||
{
|
||||
"line": 30,
|
||||
"severity": "warning",
|
||||
"note": "debugger 残留",
|
||||
"at": "2026-08-27T06:04:45.714Z"
|
||||
},
|
||||
{
|
||||
"line": 34,
|
||||
"severity": "info",
|
||||
"note": "空 if",
|
||||
"at": "2026-08-27T06:05:42.857Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-02.js": {
|
||||
"elapsedMs": 150000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T06:07:10.000Z"
|
||||
},
|
||||
{
|
||||
"line": 28,
|
||||
"severity": "warning",
|
||||
"note": "unused",
|
||||
"at": "2026-08-27T06:07:40.000Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "warning",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T06:08:10.000Z"
|
||||
},
|
||||
{
|
||||
"line": 30,
|
||||
"severity": "warning",
|
||||
"note": "debugger",
|
||||
"at": "2026-08-27T06:08:40.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-03.js": {
|
||||
"elapsedMs": 110000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T06:09:37.500Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "warning",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T06:10:05.000Z"
|
||||
},
|
||||
{
|
||||
"line": 30,
|
||||
"severity": "warning",
|
||||
"note": "debugger",
|
||||
"at": "2026-08-27T06:10:32.500Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-04.js": {
|
||||
"elapsedMs": 95000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T06:11:31.667Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "warning",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T06:12:03.333Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-05.js": {
|
||||
"elapsedMs": 85000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T06:13:03.333Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "warning",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T06:13:31.667Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-06.js": {
|
||||
"elapsedMs": 80000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T06:14:20.000Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "warning",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T06:14:40.000Z"
|
||||
},
|
||||
{
|
||||
"line": 30,
|
||||
"severity": "warning",
|
||||
"note": "debugger",
|
||||
"at": "2026-08-27T06:15:00.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-07.js": {
|
||||
"elapsedMs": 75000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T06:15:45.000Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "warning",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T06:16:10.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-08.js": {
|
||||
"elapsedMs": 70000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T06:17:10.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/java/InventoryService.java": {
|
||||
"elapsedMs": 330000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "error",
|
||||
"note": "硬编码密码",
|
||||
"at": "2026-08-27T06:18:51.000Z"
|
||||
},
|
||||
{
|
||||
"line": 7,
|
||||
"severity": "info",
|
||||
"note": "println",
|
||||
"at": "2026-08-27T06:19:57.000Z"
|
||||
},
|
||||
{
|
||||
"line": 11,
|
||||
"severity": "warning",
|
||||
"note": "空 catch",
|
||||
"at": "2026-08-27T06:21:03.000Z"
|
||||
},
|
||||
{
|
||||
"line": 12,
|
||||
"severity": "warning",
|
||||
"note": "未使用变量",
|
||||
"at": "2026-08-27T06:22:09.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/java/NotifyService.java": {
|
||||
"elapsedMs": 120000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "error",
|
||||
"note": "硬编码密码",
|
||||
"at": "2026-08-27T06:23:45.000Z"
|
||||
},
|
||||
{
|
||||
"line": 11,
|
||||
"severity": "warning",
|
||||
"note": "空 catch",
|
||||
"at": "2026-08-27T06:24:15.000Z"
|
||||
},
|
||||
{
|
||||
"line": 12,
|
||||
"severity": "warning",
|
||||
"note": "unused",
|
||||
"at": "2026-08-27T06:24:45.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/java/OrderService.java": {
|
||||
"elapsedMs": 100000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "error",
|
||||
"note": "硬编码密码",
|
||||
"at": "2026-08-27T06:25:48.333Z"
|
||||
},
|
||||
{
|
||||
"line": 11,
|
||||
"severity": "warning",
|
||||
"note": "空 catch",
|
||||
"at": "2026-08-27T06:26:21.667Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/java/PaymentService.java": {
|
||||
"elapsedMs": 90000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "error",
|
||||
"note": "硬编码密码",
|
||||
"at": "2026-08-27T06:27:25.000Z"
|
||||
},
|
||||
{
|
||||
"line": 11,
|
||||
"severity": "warning",
|
||||
"note": "空 catch",
|
||||
"at": "2026-08-27T06:27:55.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/java/ReportService.java": {
|
||||
"elapsedMs": 85000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "error",
|
||||
"note": "硬编码密码",
|
||||
"at": "2026-08-27T06:28:53.333Z"
|
||||
},
|
||||
{
|
||||
"line": 11,
|
||||
"severity": "warning",
|
||||
"note": "空 catch",
|
||||
"at": "2026-08-27T06:29:21.667Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/java/UserService.java": {
|
||||
"elapsedMs": 80000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "error",
|
||||
"note": "硬编码密码",
|
||||
"at": "2026-08-27T06:30:30.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/css/sample-01.css": {
|
||||
"elapsedMs": 260000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 4,
|
||||
"severity": "warning",
|
||||
"note": "色值位数错误",
|
||||
"at": "2026-08-27T06:32:02.000Z"
|
||||
},
|
||||
{
|
||||
"line": 5,
|
||||
"severity": "info",
|
||||
"note": "0px",
|
||||
"at": "2026-08-27T06:32:54.000Z"
|
||||
},
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "info",
|
||||
"note": "padding 简写",
|
||||
"at": "2026-08-27T06:33:46.000Z"
|
||||
},
|
||||
{
|
||||
"line": 15,
|
||||
"severity": "warning",
|
||||
"note": "color 重复",
|
||||
"at": "2026-08-27T06:34:38.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/css/sample-02.css": {
|
||||
"elapsedMs": 90000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 4,
|
||||
"severity": "warning",
|
||||
"note": "色值",
|
||||
"at": "2026-08-27T06:36:00.000Z"
|
||||
},
|
||||
{
|
||||
"line": 15,
|
||||
"severity": "warning",
|
||||
"note": "重复",
|
||||
"at": "2026-08-27T06:36:30.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/css/sample-03.css": {
|
||||
"elapsedMs": 80000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 4,
|
||||
"severity": "warning",
|
||||
"note": "色值",
|
||||
"at": "2026-08-27T06:37:26.667Z"
|
||||
},
|
||||
{
|
||||
"line": 15,
|
||||
"severity": "warning",
|
||||
"note": "color 重复",
|
||||
"at": "2026-08-27T06:37:53.333Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/css/sample-04.css": {
|
||||
"elapsedMs": 75000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 4,
|
||||
"severity": "warning",
|
||||
"note": "色值位数",
|
||||
"at": "2026-08-27T06:38:45.000Z"
|
||||
},
|
||||
{
|
||||
"line": 15,
|
||||
"severity": "warning",
|
||||
"note": "重复",
|
||||
"at": "2026-08-27T06:39:10.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/css/sample-05.css": {
|
||||
"elapsedMs": 70000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 4,
|
||||
"severity": "warning",
|
||||
"note": "色值",
|
||||
"at": "2026-08-27T06:40:10.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/sql/sample-01.sql": {
|
||||
"elapsedMs": 200000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 2,
|
||||
"severity": "info",
|
||||
"note": "关键字小写",
|
||||
"at": "2026-08-27T06:41:51.667Z"
|
||||
},
|
||||
{
|
||||
"line": 8,
|
||||
"severity": "info",
|
||||
"note": "大小写混用",
|
||||
"at": "2026-08-27T06:42:58.333Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/sql/sample-02.sql": {
|
||||
"elapsedMs": 180000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 8,
|
||||
"severity": "info",
|
||||
"note": "HAVING 引用别名",
|
||||
"at": "2026-08-27T06:45:35.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/sql/sample-03.sql": {
|
||||
"elapsedMs": 70000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 8,
|
||||
"severity": "info",
|
||||
"note": "大小写",
|
||||
"at": "2026-08-27T06:47:40.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/sql/sample-04.sql": {
|
||||
"elapsedMs": 65000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": []
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,633 @@
|
||||
{
|
||||
"experiment": "A3 人工审核 vs 插件审核",
|
||||
"exportedAt": "2026-08-27T08:36:50.000Z",
|
||||
"reviewer": "AI-SIM-003",
|
||||
"level": "mid",
|
||||
"simulated": true,
|
||||
"totalElapsedMs": 2180000,
|
||||
"files": {
|
||||
"data/efficiency-samples/js/sample-01.js": {
|
||||
"elapsedMs": 300000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 2,
|
||||
"severity": "info",
|
||||
"note": "var 声明",
|
||||
"at": "2026-08-27T08:00:33.333Z"
|
||||
},
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "== 宽松比较",
|
||||
"at": "2026-08-27T08:01:06.667Z"
|
||||
},
|
||||
{
|
||||
"line": 18,
|
||||
"severity": "warning",
|
||||
"note": "变量遮蔽",
|
||||
"at": "2026-08-27T08:01:40.000Z"
|
||||
},
|
||||
{
|
||||
"line": 28,
|
||||
"severity": "warning",
|
||||
"note": "未使用变量",
|
||||
"at": "2026-08-27T08:02:13.333Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "error",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T08:02:46.667Z"
|
||||
},
|
||||
{
|
||||
"line": 30,
|
||||
"severity": "error",
|
||||
"note": "debugger",
|
||||
"at": "2026-08-27T08:03:20.000Z"
|
||||
},
|
||||
{
|
||||
"line": 34,
|
||||
"severity": "warning",
|
||||
"note": "空 if",
|
||||
"at": "2026-08-27T08:03:53.333Z"
|
||||
},
|
||||
{
|
||||
"line": 35,
|
||||
"severity": "warning",
|
||||
"note": "自赋值",
|
||||
"at": "2026-08-27T08:04:26.667Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-02.js": {
|
||||
"elapsedMs": 120000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T08:05:13.333Z"
|
||||
},
|
||||
{
|
||||
"line": 18,
|
||||
"severity": "warning",
|
||||
"note": "遮蔽",
|
||||
"at": "2026-08-27T08:05:26.667Z"
|
||||
},
|
||||
{
|
||||
"line": 21,
|
||||
"severity": "warning",
|
||||
"note": "恒真",
|
||||
"at": "2026-08-27T08:05:40.000Z"
|
||||
},
|
||||
{
|
||||
"line": 28,
|
||||
"severity": "warning",
|
||||
"note": "unused",
|
||||
"at": "2026-08-27T08:05:53.333Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "error",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T08:06:06.667Z"
|
||||
},
|
||||
{
|
||||
"line": 30,
|
||||
"severity": "error",
|
||||
"note": "debugger",
|
||||
"at": "2026-08-27T08:06:20.000Z"
|
||||
},
|
||||
{
|
||||
"line": 34,
|
||||
"severity": "warning",
|
||||
"note": "空 if",
|
||||
"at": "2026-08-27T08:06:33.333Z"
|
||||
},
|
||||
{
|
||||
"line": 35,
|
||||
"severity": "warning",
|
||||
"note": "自赋值",
|
||||
"at": "2026-08-27T08:06:46.667Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-03.js": {
|
||||
"elapsedMs": 80000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T08:07:13.333Z"
|
||||
},
|
||||
{
|
||||
"line": 21,
|
||||
"severity": "warning",
|
||||
"note": "恒真",
|
||||
"at": "2026-08-27T08:07:26.667Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "error",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T08:07:40.000Z"
|
||||
},
|
||||
{
|
||||
"line": 30,
|
||||
"severity": "error",
|
||||
"note": "debugger",
|
||||
"at": "2026-08-27T08:07:53.333Z"
|
||||
},
|
||||
{
|
||||
"line": 35,
|
||||
"severity": "warning",
|
||||
"note": "自赋值",
|
||||
"at": "2026-08-27T08:08:06.667Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-04.js": {
|
||||
"elapsedMs": 65000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T08:08:33.000Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "error",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T08:08:46.000Z"
|
||||
},
|
||||
{
|
||||
"line": 30,
|
||||
"severity": "error",
|
||||
"note": "debugger",
|
||||
"at": "2026-08-27T08:08:59.000Z"
|
||||
},
|
||||
{
|
||||
"line": 35,
|
||||
"severity": "warning",
|
||||
"note": "自赋值",
|
||||
"at": "2026-08-27T08:09:12.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-05.js": {
|
||||
"elapsedMs": 58000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T08:09:36.600Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "error",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T08:09:48.200Z"
|
||||
},
|
||||
{
|
||||
"line": 30,
|
||||
"severity": "error",
|
||||
"note": "debugger",
|
||||
"at": "2026-08-27T08:09:59.800Z"
|
||||
},
|
||||
{
|
||||
"line": 35,
|
||||
"severity": "info",
|
||||
"note": "自赋值",
|
||||
"at": "2026-08-27T08:10:11.400Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-06.js": {
|
||||
"elapsedMs": 54000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T08:10:36.500Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "error",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T08:10:50.000Z"
|
||||
},
|
||||
{
|
||||
"line": 30,
|
||||
"severity": "error",
|
||||
"note": "debugger",
|
||||
"at": "2026-08-27T08:11:03.500Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-07.js": {
|
||||
"elapsedMs": 50000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T08:11:29.500Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "error",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T08:11:42.000Z"
|
||||
},
|
||||
{
|
||||
"line": 30,
|
||||
"severity": "error",
|
||||
"note": "debugger",
|
||||
"at": "2026-08-27T08:11:54.500Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/js/sample-08.js": {
|
||||
"elapsedMs": 46000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 9,
|
||||
"severity": "warning",
|
||||
"note": "==",
|
||||
"at": "2026-08-27T08:12:18.500Z"
|
||||
},
|
||||
{
|
||||
"line": 29,
|
||||
"severity": "error",
|
||||
"note": "eval",
|
||||
"at": "2026-08-27T08:12:30.000Z"
|
||||
},
|
||||
{
|
||||
"line": 30,
|
||||
"severity": "error",
|
||||
"note": "debugger",
|
||||
"at": "2026-08-27T08:12:41.500Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/java/InventoryService.java": {
|
||||
"elapsedMs": 250000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "error",
|
||||
"note": "硬编码密码",
|
||||
"at": "2026-08-27T08:13:34.667Z"
|
||||
},
|
||||
{
|
||||
"line": 7,
|
||||
"severity": "info",
|
||||
"note": "println",
|
||||
"at": "2026-08-27T08:14:16.333Z"
|
||||
},
|
||||
{
|
||||
"line": 11,
|
||||
"severity": "warning",
|
||||
"note": "空 catch 吞异常",
|
||||
"at": "2026-08-27T08:14:58.000Z"
|
||||
},
|
||||
{
|
||||
"line": 12,
|
||||
"severity": "warning",
|
||||
"note": "未使用变量",
|
||||
"at": "2026-08-27T08:15:39.667Z"
|
||||
},
|
||||
{
|
||||
"line": 17,
|
||||
"severity": "info",
|
||||
"note": "toString 冗余",
|
||||
"at": "2026-08-27T08:16:21.333Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/java/NotifyService.java": {
|
||||
"elapsedMs": 100000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "error",
|
||||
"note": "硬编码密码",
|
||||
"at": "2026-08-27T08:17:19.667Z"
|
||||
},
|
||||
{
|
||||
"line": 11,
|
||||
"severity": "warning",
|
||||
"note": "空 catch",
|
||||
"at": "2026-08-27T08:17:36.333Z"
|
||||
},
|
||||
{
|
||||
"line": 12,
|
||||
"severity": "warning",
|
||||
"note": "unused",
|
||||
"at": "2026-08-27T08:17:53.000Z"
|
||||
},
|
||||
{
|
||||
"line": 17,
|
||||
"severity": "info",
|
||||
"note": "toString 冗余",
|
||||
"at": "2026-08-27T08:18:09.667Z"
|
||||
},
|
||||
{
|
||||
"line": 26,
|
||||
"severity": "info",
|
||||
"note": "println",
|
||||
"at": "2026-08-27T08:18:26.333Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/java/OrderService.java": {
|
||||
"elapsedMs": 72000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "error",
|
||||
"note": "硬编码密码",
|
||||
"at": "2026-08-27T08:19:01.000Z"
|
||||
},
|
||||
{
|
||||
"line": 11,
|
||||
"severity": "warning",
|
||||
"note": "空 catch",
|
||||
"at": "2026-08-27T08:19:19.000Z"
|
||||
},
|
||||
{
|
||||
"line": 12,
|
||||
"severity": "warning",
|
||||
"note": "unused",
|
||||
"at": "2026-08-27T08:19:37.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/java/PaymentService.java": {
|
||||
"elapsedMs": 62000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "error",
|
||||
"note": "硬编码密码",
|
||||
"at": "2026-08-27T08:20:10.500Z"
|
||||
},
|
||||
{
|
||||
"line": 11,
|
||||
"severity": "warning",
|
||||
"note": "空 catch",
|
||||
"at": "2026-08-27T08:20:26.000Z"
|
||||
},
|
||||
{
|
||||
"line": 12,
|
||||
"severity": "warning",
|
||||
"note": "unused",
|
||||
"at": "2026-08-27T08:20:41.500Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/java/ReportService.java": {
|
||||
"elapsedMs": 58000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "error",
|
||||
"note": "硬编码密码",
|
||||
"at": "2026-08-27T08:21:16.333Z"
|
||||
},
|
||||
{
|
||||
"line": 11,
|
||||
"severity": "warning",
|
||||
"note": "空 catch",
|
||||
"at": "2026-08-27T08:21:35.667Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/java/UserService.java": {
|
||||
"elapsedMs": 54000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "error",
|
||||
"note": "硬编码密码",
|
||||
"at": "2026-08-27T08:22:13.000Z"
|
||||
},
|
||||
{
|
||||
"line": 11,
|
||||
"severity": "warning",
|
||||
"note": "空 catch",
|
||||
"at": "2026-08-27T08:22:31.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/css/sample-01.css": {
|
||||
"elapsedMs": 200000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 4,
|
||||
"severity": "error",
|
||||
"note": "色值位数非法",
|
||||
"at": "2026-08-27T08:23:22.333Z"
|
||||
},
|
||||
{
|
||||
"line": 5,
|
||||
"severity": "info",
|
||||
"note": "0px",
|
||||
"at": "2026-08-27T08:23:55.667Z"
|
||||
},
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "info",
|
||||
"note": "padding 简写",
|
||||
"at": "2026-08-27T08:24:29.000Z"
|
||||
},
|
||||
{
|
||||
"line": 7,
|
||||
"severity": "info",
|
||||
"note": "webkit 前缀",
|
||||
"at": "2026-08-27T08:25:02.333Z"
|
||||
},
|
||||
{
|
||||
"line": 15,
|
||||
"severity": "warning",
|
||||
"note": "color 重复",
|
||||
"at": "2026-08-27T08:25:35.667Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/css/sample-02.css": {
|
||||
"elapsedMs": 65000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 4,
|
||||
"severity": "error",
|
||||
"note": "色值",
|
||||
"at": "2026-08-27T08:26:25.250Z"
|
||||
},
|
||||
{
|
||||
"line": 15,
|
||||
"severity": "warning",
|
||||
"note": "color 重复",
|
||||
"at": "2026-08-27T08:26:41.500Z"
|
||||
},
|
||||
{
|
||||
"line": 21,
|
||||
"severity": "info",
|
||||
"note": "box-shadow 前缀",
|
||||
"at": "2026-08-27T08:26:57.750Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/css/sample-03.css": {
|
||||
"elapsedMs": 55000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 4,
|
||||
"severity": "error",
|
||||
"note": "色值",
|
||||
"at": "2026-08-27T08:27:32.333Z"
|
||||
},
|
||||
{
|
||||
"line": 15,
|
||||
"severity": "warning",
|
||||
"note": "重复",
|
||||
"at": "2026-08-27T08:27:50.667Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/css/sample-04.css": {
|
||||
"elapsedMs": 50000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 4,
|
||||
"severity": "error",
|
||||
"note": "色值位数",
|
||||
"at": "2026-08-27T08:28:25.667Z"
|
||||
},
|
||||
{
|
||||
"line": 15,
|
||||
"severity": "warning",
|
||||
"note": "重复",
|
||||
"at": "2026-08-27T08:28:42.333Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/css/sample-05.css": {
|
||||
"elapsedMs": 46000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 4,
|
||||
"severity": "error",
|
||||
"note": "色值",
|
||||
"at": "2026-08-27T08:29:22.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/sql/sample-01.sql": {
|
||||
"elapsedMs": 160000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 2,
|
||||
"severity": "info",
|
||||
"note": "关键字小写",
|
||||
"at": "2026-08-27T08:30:25.000Z"
|
||||
},
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "warning",
|
||||
"note": "sysdate 方言",
|
||||
"at": "2026-08-27T08:31:05.000Z"
|
||||
},
|
||||
{
|
||||
"line": 8,
|
||||
"severity": "info",
|
||||
"note": "大小写混用",
|
||||
"at": "2026-08-27T08:31:45.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/sql/sample-02.sql": {
|
||||
"elapsedMs": 130000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 8,
|
||||
"severity": "warning",
|
||||
"note": "HAVING 引用别名",
|
||||
"at": "2026-08-27T08:33:30.000Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/sql/sample-03.sql": {
|
||||
"elapsedMs": 55000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 6,
|
||||
"severity": "warning",
|
||||
"note": "sysdate",
|
||||
"at": "2026-08-27T08:35:02.500Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"data/efficiency-samples/sql/sample-04.sql": {
|
||||
"elapsedMs": 50000,
|
||||
"startedAt": null,
|
||||
"done": true,
|
||||
"issues": [
|
||||
{
|
||||
"line": 8,
|
||||
"severity": "warning",
|
||||
"note": "HAVING 别名",
|
||||
"at": "2026-08-27T08:35:55.000Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user