feat(phase-54-58): 前端代码实现 + 测试报告更新
- Phase 54: 自定义字段管理前端实现 - 新增 custom-field 视图组件 - 新增 form-def API 接口 - Phase 55: 报表管理前端实现 - 新增 form-data API 接口 - 新增表单数据视图 - Phase 56-58: 前端组件补全 - 新增表单设计器视图 - 移动端请求工具实现 - 工具: 新增 Phase 完整性检查脚本 - 测试: 更新 Phase 32 测试报告(记录当前状态) - 日志: 闭环执行日志 (20260303T063734Z)
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"phase": "54",
|
||||
"attempt": 1,
|
||||
"generatedAt": "2026-03-03T06:50:14Z",
|
||||
"checks": [],
|
||||
"failed": [],
|
||||
"summary": {
|
||||
"totalChecks": 0,
|
||||
"failedChecks": 0
|
||||
},
|
||||
"errorSummary": []
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"phase": "54",
|
||||
"attempt": 1,
|
||||
"generatedAt": "2026-03-03T06:50:14Z",
|
||||
"input": {
|
||||
"collect": "artifacts/closed-loop/20260303T063734Z/phase-54/local-attempt-1/collect.json"
|
||||
},
|
||||
"summary": {
|
||||
"failedChecks": 0,
|
||||
"categoryCounts": {
|
||||
"A": 0,
|
||||
"B": 0,
|
||||
"C": 0,
|
||||
"D": 0
|
||||
},
|
||||
"repairabilityCounts": {
|
||||
"auto": 0,
|
||||
"suggest": 0,
|
||||
"mitigate": 0,
|
||||
"manual": 0
|
||||
}
|
||||
},
|
||||
"diagnoses": []
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"generatedAt": "2026-03-03T06:50:14Z",
|
||||
"input": {
|
||||
"diagnosis": "artifacts/closed-loop/20260303T063734Z/phase-54/local-attempt-1/diagnosis.json",
|
||||
"recipes": "scripts/ci/repair-recipes.yaml"
|
||||
},
|
||||
"summary": {
|
||||
"planned": 0,
|
||||
"applied": 0,
|
||||
"passed": 0,
|
||||
"failed": 0
|
||||
},
|
||||
"actions": [],
|
||||
"patchPath": null
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"phase": "55",
|
||||
"attempt": 1,
|
||||
"generatedAt": "2026-03-03T07:06:47Z",
|
||||
"checks": [],
|
||||
"failed": [],
|
||||
"summary": {
|
||||
"totalChecks": 0,
|
||||
"failedChecks": 0
|
||||
},
|
||||
"errorSummary": []
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"phase": "55",
|
||||
"attempt": 1,
|
||||
"generatedAt": "2026-03-03T07:06:47Z",
|
||||
"input": {
|
||||
"collect": "artifacts/closed-loop/20260303T063734Z/phase-55/local-attempt-1/collect.json"
|
||||
},
|
||||
"summary": {
|
||||
"failedChecks": 0,
|
||||
"categoryCounts": {
|
||||
"A": 0,
|
||||
"B": 0,
|
||||
"C": 0,
|
||||
"D": 0
|
||||
},
|
||||
"repairabilityCounts": {
|
||||
"auto": 0,
|
||||
"suggest": 0,
|
||||
"mitigate": 0,
|
||||
"manual": 0
|
||||
}
|
||||
},
|
||||
"diagnoses": []
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"generatedAt": "2026-03-03T07:06:47Z",
|
||||
"input": {
|
||||
"diagnosis": "artifacts/closed-loop/20260303T063734Z/phase-55/local-attempt-1/diagnosis.json",
|
||||
"recipes": "scripts/ci/repair-recipes.yaml"
|
||||
},
|
||||
"summary": {
|
||||
"planned": 0,
|
||||
"applied": 0,
|
||||
"passed": 0,
|
||||
"failed": 0
|
||||
},
|
||||
"actions": [],
|
||||
"patchPath": null
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"phase": "56",
|
||||
"attempt": 1,
|
||||
"generatedAt": "2026-03-03T07:24:20Z",
|
||||
"checks": [],
|
||||
"failed": [],
|
||||
"summary": {
|
||||
"totalChecks": 0,
|
||||
"failedChecks": 0
|
||||
},
|
||||
"errorSummary": []
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"phase": "56",
|
||||
"attempt": 1,
|
||||
"generatedAt": "2026-03-03T07:24:20Z",
|
||||
"input": {
|
||||
"collect": "artifacts/closed-loop/20260303T063734Z/phase-56/local-attempt-1/collect.json"
|
||||
},
|
||||
"summary": {
|
||||
"failedChecks": 0,
|
||||
"categoryCounts": {
|
||||
"A": 0,
|
||||
"B": 0,
|
||||
"C": 0,
|
||||
"D": 0
|
||||
},
|
||||
"repairabilityCounts": {
|
||||
"auto": 0,
|
||||
"suggest": 0,
|
||||
"mitigate": 0,
|
||||
"manual": 0
|
||||
}
|
||||
},
|
||||
"diagnoses": []
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"generatedAt": "2026-03-03T07:24:20Z",
|
||||
"input": {
|
||||
"diagnosis": "artifacts/closed-loop/20260303T063734Z/phase-56/local-attempt-1/diagnosis.json",
|
||||
"recipes": "scripts/ci/repair-recipes.yaml"
|
||||
},
|
||||
"summary": {
|
||||
"planned": 0,
|
||||
"applied": 0,
|
||||
"passed": 0,
|
||||
"failed": 0
|
||||
},
|
||||
"actions": [],
|
||||
"patchPath": null
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"phase": "57",
|
||||
"attempt": 1,
|
||||
"generatedAt": "2026-03-03T07:38:47Z",
|
||||
"checks": [],
|
||||
"failed": [],
|
||||
"summary": {
|
||||
"totalChecks": 0,
|
||||
"failedChecks": 0
|
||||
},
|
||||
"errorSummary": []
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"phase": "57",
|
||||
"attempt": 1,
|
||||
"generatedAt": "2026-03-03T07:38:47Z",
|
||||
"input": {
|
||||
"collect": "artifacts/closed-loop/20260303T063734Z/phase-57/local-attempt-1/collect.json"
|
||||
},
|
||||
"summary": {
|
||||
"failedChecks": 0,
|
||||
"categoryCounts": {
|
||||
"A": 0,
|
||||
"B": 0,
|
||||
"C": 0,
|
||||
"D": 0
|
||||
},
|
||||
"repairabilityCounts": {
|
||||
"auto": 0,
|
||||
"suggest": 0,
|
||||
"mitigate": 0,
|
||||
"manual": 0
|
||||
}
|
||||
},
|
||||
"diagnoses": []
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"generatedAt": "2026-03-03T07:38:47Z",
|
||||
"input": {
|
||||
"diagnosis": "artifacts/closed-loop/20260303T063734Z/phase-57/local-attempt-1/diagnosis.json",
|
||||
"recipes": "scripts/ci/repair-recipes.yaml"
|
||||
},
|
||||
"summary": {
|
||||
"planned": 0,
|
||||
"applied": 0,
|
||||
"passed": 0,
|
||||
"failed": 0
|
||||
},
|
||||
"actions": [],
|
||||
"patchPath": null
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"phase": "58",
|
||||
"attempt": 1,
|
||||
"generatedAt": "2026-03-03T07:45:52Z",
|
||||
"checks": [],
|
||||
"failed": [],
|
||||
"summary": {
|
||||
"totalChecks": 0,
|
||||
"failedChecks": 0
|
||||
},
|
||||
"errorSummary": []
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"phase": "58",
|
||||
"attempt": 1,
|
||||
"generatedAt": "2026-03-03T07:45:52Z",
|
||||
"input": {
|
||||
"collect": "artifacts/closed-loop/20260303T063734Z/phase-58/local-attempt-1/collect.json"
|
||||
},
|
||||
"summary": {
|
||||
"failedChecks": 0,
|
||||
"categoryCounts": {
|
||||
"A": 0,
|
||||
"B": 0,
|
||||
"C": 0,
|
||||
"D": 0
|
||||
},
|
||||
"repairabilityCounts": {
|
||||
"auto": 0,
|
||||
"suggest": 0,
|
||||
"mitigate": 0,
|
||||
"manual": 0
|
||||
}
|
||||
},
|
||||
"diagnoses": []
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"generatedAt": "2026-03-03T07:45:52Z",
|
||||
"input": {
|
||||
"diagnosis": "artifacts/closed-loop/20260303T063734Z/phase-58/local-attempt-1/diagnosis.json",
|
||||
"recipes": "scripts/ci/repair-recipes.yaml"
|
||||
},
|
||||
"summary": {
|
||||
"planned": 0,
|
||||
"applied": 0,
|
||||
"passed": 0,
|
||||
"failed": 0
|
||||
},
|
||||
"actions": [],
|
||||
"patchPath": null
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"phase": "32",
|
||||
"status": "PASS",
|
||||
"timestamp": "2026-03-02T23:54:54Z",
|
||||
"status": "FAIL",
|
||||
"timestamp": "2026-03-03T07:45:50Z",
|
||||
"repo": {
|
||||
"owner": "unknown",
|
||||
"name": "unknown",
|
||||
"default_branch": "master"
|
||||
},
|
||||
"git": {
|
||||
"commit": "638a3f1",
|
||||
"branch": "feat-baseline-gate-workflow"
|
||||
"commit": "d4b5a14",
|
||||
"branch": "master"
|
||||
},
|
||||
"ci": {
|
||||
"run_id": null,
|
||||
@@ -26,10 +26,10 @@
|
||||
{
|
||||
"id": "R01",
|
||||
"name": "Compile",
|
||||
"status": "PASS",
|
||||
"critical": 0,
|
||||
"status": "FAIL",
|
||||
"critical": 1,
|
||||
"warnings": 0,
|
||||
"message": "passed"
|
||||
"message": "failed"
|
||||
},
|
||||
{
|
||||
"id": "R02",
|
||||
@@ -42,10 +42,10 @@
|
||||
{
|
||||
"id": "R03",
|
||||
"name": "Rules",
|
||||
"status": "PASS",
|
||||
"critical": 0,
|
||||
"status": "FAIL",
|
||||
"critical": 1,
|
||||
"warnings": 0,
|
||||
"message": "passed"
|
||||
"message": "failed"
|
||||
},
|
||||
{
|
||||
"id": "R04",
|
||||
@@ -58,10 +58,10 @@
|
||||
{
|
||||
"id": "R05",
|
||||
"name": "Integration",
|
||||
"status": "PASS",
|
||||
"critical": 0,
|
||||
"status": "FAIL",
|
||||
"critical": 1,
|
||||
"warnings": 0,
|
||||
"message": "passed"
|
||||
"message": "failed"
|
||||
},
|
||||
{
|
||||
"id": "R06",
|
||||
@@ -114,12 +114,34 @@
|
||||
],
|
||||
"summary": {
|
||||
"total": 11,
|
||||
"pass": 10,
|
||||
"fail": 0,
|
||||
"pass": 7,
|
||||
"fail": 3,
|
||||
"skip": 1,
|
||||
"critical": 0,
|
||||
"critical": 3,
|
||||
"warnings": 0,
|
||||
"pass_rate": 90.91
|
||||
"pass_rate": 63.64
|
||||
},
|
||||
"violations": []
|
||||
"violations": [
|
||||
{
|
||||
"rule": "R01",
|
||||
"severity": "CRITICAL",
|
||||
"file": null,
|
||||
"line": null,
|
||||
"message": "failed"
|
||||
},
|
||||
{
|
||||
"rule": "R03",
|
||||
"severity": "CRITICAL",
|
||||
"file": null,
|
||||
"line": null,
|
||||
"message": "failed"
|
||||
},
|
||||
{
|
||||
"rule": "R05",
|
||||
"severity": "CRITICAL",
|
||||
"file": null,
|
||||
"line": null,
|
||||
"message": "failed"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+229
-1
@@ -1,6 +1,30 @@
|
||||
{
|
||||
"generated_at": "2026-03-03T05:31:09Z",
|
||||
"generated_at": "2026-03-03T07:45:50Z",
|
||||
"matrix": [
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
"endpoint": "/api/v1/ai/chat",
|
||||
"method": "POST",
|
||||
"controller": "ljwx-platform-app/src/main/java/com/ljwx/platform/app/controller/AiChatController.java",
|
||||
"service": null,
|
||||
"test": null,
|
||||
"test_covered": false,
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
"endpoint": "/api/v1/ai/conversations",
|
||||
"method": "GET",
|
||||
"controller": "ljwx-platform-app/src/main/java/com/ljwx/platform/app/controller/AiChatController.java",
|
||||
"service": null,
|
||||
"test": null,
|
||||
"test_covered": false,
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
@@ -49,6 +73,30 @@
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
"endpoint": "/api/v1/billing/usage",
|
||||
"method": "GET",
|
||||
"controller": "ljwx-platform-app/src/main/java/com/ljwx/platform/app/controller/BillingController.java",
|
||||
"service": null,
|
||||
"test": null,
|
||||
"test_covered": false,
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
"endpoint": "/api/v1/billing/summary",
|
||||
"method": "GET",
|
||||
"controller": "ljwx-platform-app/src/main/java/com/ljwx/platform/app/controller/BillingController.java",
|
||||
"service": null,
|
||||
"test": null,
|
||||
"test_covered": false,
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
@@ -73,6 +121,30 @@
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
"endpoint": "/api/v1/custom-fields/{id}",
|
||||
"method": "PUT",
|
||||
"controller": "ljwx-platform-app/src/main/java/com/ljwx/platform/app/controller/CustomFieldDefController.java",
|
||||
"service": null,
|
||||
"test": null,
|
||||
"test_covered": false,
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
"endpoint": "/api/v1/custom-fields/{id}",
|
||||
"method": "DELETE",
|
||||
"controller": "ljwx-platform-app/src/main/java/com/ljwx/platform/app/controller/CustomFieldDefController.java",
|
||||
"service": null,
|
||||
"test": null,
|
||||
"test_covered": false,
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
@@ -181,6 +253,114 @@
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
"endpoint": "/api/v1/form-data/{id}",
|
||||
"method": "GET",
|
||||
"controller": "ljwx-platform-app/src/main/java/com/ljwx/platform/app/controller/FormDataController.java",
|
||||
"service": null,
|
||||
"test": null,
|
||||
"test_covered": false,
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
"endpoint": "/api/v1/form-data/{id}",
|
||||
"method": "PUT",
|
||||
"controller": "ljwx-platform-app/src/main/java/com/ljwx/platform/app/controller/FormDataController.java",
|
||||
"service": null,
|
||||
"test": null,
|
||||
"test_covered": false,
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
"endpoint": "/api/v1/form-defs/{id}",
|
||||
"method": "GET",
|
||||
"controller": "ljwx-platform-app/src/main/java/com/ljwx/platform/app/controller/FormDefController.java",
|
||||
"service": null,
|
||||
"test": null,
|
||||
"test_covered": false,
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
"endpoint": "/api/v1/form-defs/{id}",
|
||||
"method": "PUT",
|
||||
"controller": "ljwx-platform-app/src/main/java/com/ljwx/platform/app/controller/FormDefController.java",
|
||||
"service": null,
|
||||
"test": null,
|
||||
"test_covered": false,
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
"endpoint": "/api/v1/form-defs/{id}",
|
||||
"method": "DELETE",
|
||||
"controller": "ljwx-platform-app/src/main/java/com/ljwx/platform/app/controller/FormDefController.java",
|
||||
"service": null,
|
||||
"test": null,
|
||||
"test_covered": false,
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
"endpoint": "/api/v1/help-docs/{id}",
|
||||
"method": "GET",
|
||||
"controller": "ljwx-platform-app/src/main/java/com/ljwx/platform/app/controller/HelpDocController.java",
|
||||
"service": null,
|
||||
"test": null,
|
||||
"test_covered": false,
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
"endpoint": "/api/v1/help-docs/route",
|
||||
"method": "GET",
|
||||
"controller": "ljwx-platform-app/src/main/java/com/ljwx/platform/app/controller/HelpDocController.java",
|
||||
"service": null,
|
||||
"test": null,
|
||||
"test_covered": false,
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
"endpoint": "/api/v1/help-docs/{id}",
|
||||
"method": "PUT",
|
||||
"controller": "ljwx-platform-app/src/main/java/com/ljwx/platform/app/controller/HelpDocController.java",
|
||||
"service": null,
|
||||
"test": null,
|
||||
"test_covered": false,
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
"endpoint": "/api/v1/help-docs/{id}",
|
||||
"method": "DELETE",
|
||||
"controller": "ljwx-platform-app/src/main/java/com/ljwx/platform/app/controller/HelpDocController.java",
|
||||
"service": null,
|
||||
"test": null,
|
||||
"test_covered": false,
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
@@ -769,6 +949,54 @@
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
"endpoint": "/api/v1/reports/{id}",
|
||||
"method": "GET",
|
||||
"controller": "ljwx-platform-app/src/main/java/com/ljwx/platform/app/controller/RptReportController.java",
|
||||
"service": null,
|
||||
"test": null,
|
||||
"test_covered": false,
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
"endpoint": "/api/v1/reports/{id}",
|
||||
"method": "PUT",
|
||||
"controller": "ljwx-platform-app/src/main/java/com/ljwx/platform/app/controller/RptReportController.java",
|
||||
"service": null,
|
||||
"test": null,
|
||||
"test_covered": false,
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
"endpoint": "/api/v1/reports/{id}",
|
||||
"method": "DELETE",
|
||||
"controller": "ljwx-platform-app/src/main/java/com/ljwx/platform/app/controller/RptReportController.java",
|
||||
"service": null,
|
||||
"test": null,
|
||||
"test_covered": false,
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
"endpoint": "/api/v1/reports/{id}/execute",
|
||||
"method": "POST",
|
||||
"controller": "ljwx-platform-app/src/main/java/com/ljwx/platform/app/controller/RptReportController.java",
|
||||
"service": null,
|
||||
"test": null,
|
||||
"test_covered": false,
|
||||
"spec": null,
|
||||
"gate_status": "PASS"
|
||||
},
|
||||
{
|
||||
"phase": "00",
|
||||
"requirement_id": null,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"generated_at": "2026-03-03T05:31:21Z",
|
||||
"generated_at": "2026-03-03T07:45:51Z",
|
||||
"repo": {
|
||||
"owner": "unknown",
|
||||
"name": "unknown",
|
||||
@@ -7,8 +7,8 @@
|
||||
},
|
||||
"git": {
|
||||
"branch": "master",
|
||||
"commit": "2b50bfe",
|
||||
"short": "2b50bfe"
|
||||
"commit": "d4b5a14",
|
||||
"short": "d4b5a14"
|
||||
},
|
||||
"ci": {
|
||||
"run_id": null,
|
||||
@@ -17,10 +17,10 @@
|
||||
"run_url": null
|
||||
},
|
||||
"totals": {
|
||||
"pass": 33,
|
||||
"fail": 0,
|
||||
"pass": 32,
|
||||
"fail": 1,
|
||||
"pending": 0,
|
||||
"critical": 0,
|
||||
"critical": 3,
|
||||
"warnings": 0
|
||||
},
|
||||
"phases": [
|
||||
@@ -677,19 +677,19 @@
|
||||
},
|
||||
{
|
||||
"phase": "32",
|
||||
"status": "PASS",
|
||||
"pass_rate": 90.91,
|
||||
"critical": 0,
|
||||
"status": "FAIL",
|
||||
"pass_rate": 63.64,
|
||||
"critical": 3,
|
||||
"warnings": 0,
|
||||
"timestamp": "2026-03-02T23:54:54Z",
|
||||
"git_commit": "638a3f1",
|
||||
"timestamp": "2026-03-03T07:45:50Z",
|
||||
"git_commit": "d4b5a14",
|
||||
"r09_status": "PASS",
|
||||
"gate_status": {
|
||||
"R01": "PASS",
|
||||
"R01": "FAIL",
|
||||
"R02": "PASS",
|
||||
"R03": "PASS",
|
||||
"R03": "FAIL",
|
||||
"R04": "PASS",
|
||||
"R05": "PASS",
|
||||
"R05": "FAIL",
|
||||
"R06": "PASS",
|
||||
"R07": "PASS",
|
||||
"R08": "PASS",
|
||||
@@ -700,6 +700,50 @@
|
||||
}
|
||||
],
|
||||
"history": [
|
||||
{
|
||||
"timestamp": "2026-03-03T07:45:50Z",
|
||||
"phase": "32",
|
||||
"status": "FAIL",
|
||||
"pass_rate": 63.64,
|
||||
"git_commit": "d4b5a14",
|
||||
"critical": 3,
|
||||
"warnings": 0,
|
||||
"run_id": null,
|
||||
"run_url": null
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-03-03T07:24:18Z",
|
||||
"phase": "32",
|
||||
"status": "FAIL",
|
||||
"pass_rate": 72.73,
|
||||
"git_commit": "2cafe9b",
|
||||
"critical": 2,
|
||||
"warnings": 0,
|
||||
"run_id": null,
|
||||
"run_url": null
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-03-03T07:06:45Z",
|
||||
"phase": "32",
|
||||
"status": "FAIL",
|
||||
"pass_rate": 72.73,
|
||||
"git_commit": "2e371c0",
|
||||
"critical": 2,
|
||||
"warnings": 0,
|
||||
"run_id": null,
|
||||
"run_url": null
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-03-03T06:50:12Z",
|
||||
"phase": "32",
|
||||
"status": "FAIL",
|
||||
"pass_rate": 72.73,
|
||||
"git_commit": "215cfa7",
|
||||
"critical": 2,
|
||||
"warnings": 0,
|
||||
"run_id": null,
|
||||
"run_url": null
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-03-03T05:31:20Z",
|
||||
"phase": "53",
|
||||
@@ -1205,50 +1249,6 @@
|
||||
"warnings": 0,
|
||||
"run_id": null,
|
||||
"run_url": null
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-03-02T19:45:37Z",
|
||||
"phase": "50",
|
||||
"status": "FAIL",
|
||||
"pass_rate": 63.64,
|
||||
"git_commit": "417be25",
|
||||
"critical": 3,
|
||||
"warnings": 0,
|
||||
"run_id": null,
|
||||
"run_url": null
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-03-02T19:43:38Z",
|
||||
"phase": "32",
|
||||
"status": "FAIL",
|
||||
"pass_rate": 63.64,
|
||||
"git_commit": "417be25",
|
||||
"critical": 3,
|
||||
"warnings": 0,
|
||||
"run_id": null,
|
||||
"run_url": null
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-03-02T19:38:49Z",
|
||||
"phase": "32",
|
||||
"status": "FAIL",
|
||||
"pass_rate": 63.64,
|
||||
"git_commit": "54c9b76",
|
||||
"critical": 3,
|
||||
"warnings": 0,
|
||||
"run_id": null,
|
||||
"run_url": null
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-03-02T19:32:15Z",
|
||||
"phase": "49",
|
||||
"status": "FAIL",
|
||||
"pass_rate": 63.64,
|
||||
"git_commit": "ecf759d",
|
||||
"critical": 3,
|
||||
"warnings": 0,
|
||||
"run_id": null,
|
||||
"run_url": null
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"generated_at": "2026-03-03T05:31:21Z",
|
||||
"generated_at": "2026-03-03T07:45:52Z",
|
||||
"ci": {
|
||||
"run_id": null,
|
||||
"run_attempt": 1,
|
||||
@@ -7,939 +7,10 @@
|
||||
"run_url": null
|
||||
},
|
||||
"summary": {
|
||||
"total": 116,
|
||||
"pass": 116,
|
||||
"total": 0,
|
||||
"pass": 0,
|
||||
"fail": 0,
|
||||
"skip": 0
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[1]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.388,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[2]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[3]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[4]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[5]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[6]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[7]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[8]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[9]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[10]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[11]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[12]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[13]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[14]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[15]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[16]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[17]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[18]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[19]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[20]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.002,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[21]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.002,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[22]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[23]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[24]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.002,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[25]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[26]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[27]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.002,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[28]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.002,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[29]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[30]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[31]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.002,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[32]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[33]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[34]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[35]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.002,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[36]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[37]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[38]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.002,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[39]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.001,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[40]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[41]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[42]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[43]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[44]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[45]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[46]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.001,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[47]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.001,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[48]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[49]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.002,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[50]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[51]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[52]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[53]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.002,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[54]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.002,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[55]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.002,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[56]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.001,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[57]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.001,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[58]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.001,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "protectedEndpointWithoutTokenReturns401(ProtocolEndpoint)[59]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.001,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[1]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.085,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[2]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.01,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[3]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.007,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[4]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.007,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[5]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.008,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[6]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.006,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[7]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[8]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[9]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[10]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[11]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[12]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[13]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[14]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[15]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[16]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.006,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[17]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.006,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[18]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.006,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[19]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[20]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.006,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[21]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.006,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[22]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.007,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[23]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.007,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[24]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.006,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[25]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.007,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[26]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.006,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[27]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.006,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[28]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[29]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[30]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[31]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[32]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.006,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[33]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[34]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[35]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[36]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[37]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.006,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[38]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.006,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[39]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[40]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[41]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[42]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[43]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.006,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[44]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[45]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[46]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[47]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[48]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[49]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[50]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[51]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.003,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[52]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[53]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[54]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[55]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[56]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.005,
|
||||
"message": ""
|
||||
},
|
||||
{
|
||||
"phase": null,
|
||||
"suite": "com.ljwx.platform.contract.protocol.ProtocolContractSecurityTest",
|
||||
"testcase": "authorityEndpointWithNoPermissionTokenReturns403(ProtocolEndpoint)[57]",
|
||||
"status": "PASS",
|
||||
"time_seconds": 0.004,
|
||||
"message": ""
|
||||
}
|
||||
]
|
||||
"tests": []
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import request from '@/api/request'
|
||||
import type { Result } from '@ljwx/shared'
|
||||
|
||||
export interface CustomFieldDefVO {
|
||||
id: number
|
||||
entityType: string
|
||||
fieldKey: string
|
||||
fieldLabel: string
|
||||
fieldType: string
|
||||
required: boolean
|
||||
sortOrder: number
|
||||
options?: unknown[]
|
||||
createdTime: string
|
||||
}
|
||||
|
||||
export interface CustomFieldDefCreateDTO {
|
||||
entityType: string
|
||||
fieldKey: string
|
||||
fieldLabel: string
|
||||
fieldType: string
|
||||
required: boolean
|
||||
sortOrder: number
|
||||
options?: unknown[]
|
||||
}
|
||||
|
||||
export interface CustomFieldDefUpdateDTO {
|
||||
fieldLabel: string
|
||||
required: boolean
|
||||
sortOrder: number
|
||||
options?: unknown[]
|
||||
}
|
||||
|
||||
export function getCustomFieldList(entityType?: string): Promise<Result<CustomFieldDefVO[]>> {
|
||||
return request.get('/api/v1/custom-fields', { params: { entityType } })
|
||||
}
|
||||
|
||||
export function createCustomField(data: CustomFieldDefCreateDTO): Promise<Result<number>> {
|
||||
return request.post('/api/v1/custom-fields', data)
|
||||
}
|
||||
|
||||
export function updateCustomField(id: number, data: CustomFieldDefUpdateDTO): Promise<Result<void>> {
|
||||
return request.put(`/api/v1/custom-fields/${id}`, data)
|
||||
}
|
||||
|
||||
export function deleteCustomField(id: number): Promise<Result<void>> {
|
||||
return request.delete(`/api/v1/custom-fields/${id}`)
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import request from '@/api/request'
|
||||
import type { Result, PageResult } from '@ljwx/shared'
|
||||
|
||||
export interface FormDataVO {
|
||||
id: number
|
||||
formDefId: number
|
||||
fieldValues: Record<string, unknown>
|
||||
creatorId: number
|
||||
createdTime: string
|
||||
updatedTime: string
|
||||
}
|
||||
|
||||
export interface FormDataQueryDTO {
|
||||
formDefId: number
|
||||
creatorId?: number
|
||||
startTime?: string
|
||||
endTime?: string
|
||||
pageNum: number
|
||||
pageSize: number
|
||||
}
|
||||
|
||||
export interface FormDataCreateDTO {
|
||||
formDefId: number
|
||||
fieldValues: Record<string, unknown>
|
||||
}
|
||||
|
||||
export interface FormDataUpdateDTO {
|
||||
fieldValues: Record<string, unknown>
|
||||
}
|
||||
|
||||
export function getFormDataList(params: FormDataQueryDTO): Promise<Result<PageResult<FormDataVO>>> {
|
||||
return request.get('/api/v1/form-data', { params })
|
||||
}
|
||||
|
||||
export function getFormDataById(id: number): Promise<Result<FormDataVO>> {
|
||||
return request.get(`/api/v1/form-data/${id}`)
|
||||
}
|
||||
|
||||
export function createFormData(data: FormDataCreateDTO): Promise<Result<number>> {
|
||||
return request.post('/api/v1/form-data', data)
|
||||
}
|
||||
|
||||
export function updateFormData(id: number, data: FormDataUpdateDTO): Promise<Result<void>> {
|
||||
return request.put(`/api/v1/form-data/${id}`, data)
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import request from '@/api/request'
|
||||
import type { Result, PageResult } from '@ljwx/shared'
|
||||
|
||||
export interface FormDefVO {
|
||||
id: number
|
||||
formName: string
|
||||
formKey: string
|
||||
schema: Record<string, unknown>
|
||||
status: number
|
||||
remark?: string
|
||||
createdTime: string
|
||||
updatedTime: string
|
||||
}
|
||||
|
||||
export interface FormDefQueryDTO {
|
||||
formName?: string
|
||||
formKey?: string
|
||||
status?: number
|
||||
pageNum: number
|
||||
pageSize: number
|
||||
}
|
||||
|
||||
export interface FormDefCreateDTO {
|
||||
formName: string
|
||||
formKey: string
|
||||
schema: Record<string, unknown>
|
||||
remark?: string
|
||||
}
|
||||
|
||||
export interface FormDefUpdateDTO {
|
||||
formName: string
|
||||
schema: Record<string, unknown>
|
||||
status: number
|
||||
remark?: string
|
||||
}
|
||||
|
||||
export function getFormDefList(params: FormDefQueryDTO): Promise<Result<PageResult<FormDefVO>>> {
|
||||
return request.get('/api/v1/form-defs', { params })
|
||||
}
|
||||
|
||||
export function getFormDefById(id: number): Promise<Result<FormDefVO>> {
|
||||
return request.get(`/api/v1/form-defs/${id}`)
|
||||
}
|
||||
|
||||
export function createFormDef(data: FormDefCreateDTO): Promise<Result<number>> {
|
||||
return request.post('/api/v1/form-defs', data)
|
||||
}
|
||||
|
||||
export function updateFormDef(id: number, data: FormDefUpdateDTO): Promise<Result<void>> {
|
||||
return request.put(`/api/v1/form-defs/${id}`, data)
|
||||
}
|
||||
|
||||
export function deleteFormDef(id: number): Promise<Result<void>> {
|
||||
return request.delete(`/api/v1/form-defs/${id}`)
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { View, Edit } from '@element-plus/icons-vue'
|
||||
import {
|
||||
getFormDataList,
|
||||
getFormDataById,
|
||||
updateFormData,
|
||||
type FormDataVO,
|
||||
type FormDataQueryDTO,
|
||||
type FormDataUpdateDTO
|
||||
} from '@/api/form/form-data'
|
||||
import { getFormDefList, type FormDefVO } from '@/api/form/form-def'
|
||||
|
||||
const loading = ref(false)
|
||||
const tableData = ref<FormDataVO[]>([])
|
||||
const total = ref(0)
|
||||
const formDefOptions = ref<FormDefVO[]>([])
|
||||
|
||||
const queryForm = reactive<FormDataQueryDTO>({
|
||||
formDefId: 0,
|
||||
creatorId: undefined,
|
||||
startTime: undefined,
|
||||
endTime: undefined,
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
})
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const dialogTitle = ref('')
|
||||
const currentId = ref<number>()
|
||||
const currentFormData = ref<FormDataVO>()
|
||||
|
||||
async function fetchFormDefs() {
|
||||
try {
|
||||
const res = await getFormDefList({ pageNum: 1, pageSize: 100, status: 1 })
|
||||
formDefOptions.value = res.data.rows
|
||||
} catch (error) {
|
||||
ElMessage.error('获取表单定义失败')
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchList() {
|
||||
if (!queryForm.formDefId) {
|
||||
ElMessage.warning('请先选择表单定义')
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await getFormDataList(queryForm)
|
||||
tableData.value = res.data.rows
|
||||
total.value = res.data.total
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleQuery() {
|
||||
queryForm.pageNum = 1
|
||||
fetchList()
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
queryForm.formDefId = 0
|
||||
queryForm.creatorId = undefined
|
||||
queryForm.startTime = undefined
|
||||
queryForm.endTime = undefined
|
||||
queryForm.pageNum = 1
|
||||
tableData.value = []
|
||||
total.value = 0
|
||||
}
|
||||
|
||||
async function handleView(row: FormDataVO) {
|
||||
dialogTitle.value = '查看表单数据'
|
||||
currentId.value = row.id
|
||||
try {
|
||||
const res = await getFormDataById(row.id)
|
||||
currentFormData.value = res.data
|
||||
dialogVisible.value = true
|
||||
} catch (error) {
|
||||
ElMessage.error('获取详情失败')
|
||||
}
|
||||
}
|
||||
|
||||
function handlePageChange(page: number) {
|
||||
queryForm.pageNum = page
|
||||
fetchList()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchFormDefs()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="form-data-container">
|
||||
<el-card class="search-card">
|
||||
<el-form :model="queryForm" inline>
|
||||
<el-form-item label="表单定义" required>
|
||||
<el-select v-model="queryForm.formDefId" placeholder="请选择表单定义" clearable style="width: 200px">
|
||||
<el-option
|
||||
v-for="form in formDefOptions"
|
||||
:key="form.id"
|
||||
:label="form.formName"
|
||||
:value="form.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="填写人ID">
|
||||
<el-input v-model.number="queryForm.creatorId" placeholder="请输入填写人ID" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker
|
||||
v-model="queryForm.startTime"
|
||||
type="datetime"
|
||||
placeholder="开始时间"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
/>
|
||||
<span style="margin: 0 10px">至</span>
|
||||
<el-date-picker
|
||||
v-model="queryForm.endTime"
|
||||
type="datetime"
|
||||
placeholder="结束时间"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">查询</el-button>
|
||||
<el-button @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card class="table-card">
|
||||
<el-table v-loading="loading" :data="tableData" border>
|
||||
<el-table-column prop="id" label="ID" width="80" />
|
||||
<el-table-column prop="formDefId" label="表单定义ID" width="120" />
|
||||
<el-table-column prop="creatorId" label="填写人ID" width="120" />
|
||||
<el-table-column prop="createdTime" label="创建时间" width="180" />
|
||||
<el-table-column prop="updatedTime" label="更新时间" width="180" />
|
||||
<el-table-column label="操作" width="120" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" :icon="View" link @click="handleView(row)">查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-pagination
|
||||
v-model:current-page="queryForm.pageNum"
|
||||
v-model:page-size="queryForm.pageSize"
|
||||
:total="total"
|
||||
layout="total, prev, pager, next, jumper"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="600px">
|
||||
<el-descriptions v-if="currentFormData" :column="1" border>
|
||||
<el-descriptions-item label="ID">{{ currentFormData.id }}</el-descriptions-item>
|
||||
<el-descriptions-item label="表单定义ID">{{ currentFormData.formDefId }}</el-descriptions-item>
|
||||
<el-descriptions-item label="填写人ID">{{ currentFormData.creatorId }}</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">{{ currentFormData.createdTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="更新时间">{{ currentFormData.updatedTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="表单数据">
|
||||
<pre>{{ JSON.stringify(currentFormData.fieldValues, null, 2) }}</pre>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.form-data-container {
|
||||
padding: 20px;
|
||||
|
||||
.search-card {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.table-card {
|
||||
.el-pagination {
|
||||
margin-top: 20px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #f5f5f5;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
max-height: 400px;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,302 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Plus, Edit, Delete, View } from '@element-plus/icons-vue'
|
||||
import {
|
||||
getFormDefList,
|
||||
createFormDef,
|
||||
updateFormDef,
|
||||
deleteFormDef,
|
||||
type FormDefVO,
|
||||
type FormDefQueryDTO,
|
||||
type FormDefCreateDTO,
|
||||
type FormDefUpdateDTO
|
||||
} from '@/api/form/form-def'
|
||||
|
||||
const loading = ref(false)
|
||||
const tableData = ref<FormDefVO[]>([])
|
||||
const total = ref(0)
|
||||
|
||||
const queryForm = reactive<FormDefQueryDTO>({
|
||||
formName: '',
|
||||
formKey: '',
|
||||
status: undefined,
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
})
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const dialogTitle = ref('')
|
||||
const isEdit = ref(false)
|
||||
const currentId = ref<number>()
|
||||
|
||||
const formData = reactive<FormDefCreateDTO | FormDefUpdateDTO>({
|
||||
formName: '',
|
||||
formKey: '',
|
||||
schema: {},
|
||||
remark: ''
|
||||
})
|
||||
|
||||
interface SchemaField {
|
||||
key: string
|
||||
label: string
|
||||
type: string
|
||||
required: boolean
|
||||
options?: string[]
|
||||
}
|
||||
|
||||
interface FormSchema {
|
||||
fields?: SchemaField[]
|
||||
}
|
||||
|
||||
const schemaFields = ref<SchemaField[]>([])
|
||||
|
||||
const fieldTypes = [
|
||||
{ label: '单行文本', value: 'TEXT' },
|
||||
{ label: '多行文本', value: 'TEXTAREA' },
|
||||
{ label: '数字', value: 'NUMBER' },
|
||||
{ label: '日期', value: 'DATE' },
|
||||
{ label: '下拉选择', value: 'SELECT' },
|
||||
{ label: '复选框', value: 'CHECKBOX' }
|
||||
]
|
||||
|
||||
async function fetchList() {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await getFormDefList(queryForm)
|
||||
tableData.value = res.data.rows
|
||||
total.value = res.data.total
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleQuery() {
|
||||
queryForm.pageNum = 1
|
||||
fetchList()
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
queryForm.formName = ''
|
||||
queryForm.formKey = ''
|
||||
queryForm.status = undefined
|
||||
queryForm.pageNum = 1
|
||||
fetchList()
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
dialogTitle.value = '新增表单定义'
|
||||
isEdit.value = false
|
||||
currentId.value = undefined
|
||||
Object.assign(formData, {
|
||||
formName: '',
|
||||
formKey: '',
|
||||
schema: {},
|
||||
remark: ''
|
||||
})
|
||||
schemaFields.value = []
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
function handleEdit(row: FormDefVO) {
|
||||
dialogTitle.value = '编辑表单定义'
|
||||
isEdit.value = true
|
||||
currentId.value = row.id
|
||||
Object.assign(formData, {
|
||||
formName: row.formName,
|
||||
schema: row.schema,
|
||||
status: row.status,
|
||||
remark: row.remark
|
||||
})
|
||||
|
||||
const schema = row.schema as FormSchema
|
||||
if (schema && Array.isArray(schema.fields)) {
|
||||
schemaFields.value = schema.fields
|
||||
} else {
|
||||
schemaFields.value = []
|
||||
}
|
||||
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
async function handleDelete(row: FormDefVO) {
|
||||
try {
|
||||
await ElMessageBox.confirm('确认删除该表单定义吗?', '提示', {
|
||||
type: 'warning'
|
||||
})
|
||||
await deleteFormDef(row.id)
|
||||
ElMessage.success('删除成功')
|
||||
fetchList()
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
ElMessage.error('删除失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addField() {
|
||||
schemaFields.value.push({
|
||||
key: '',
|
||||
label: '',
|
||||
type: 'TEXT',
|
||||
required: false,
|
||||
options: []
|
||||
})
|
||||
}
|
||||
|
||||
function removeField(index: number) {
|
||||
schemaFields.value.splice(index, 1)
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
formData.schema = {
|
||||
fields: schemaFields.value
|
||||
}
|
||||
|
||||
try {
|
||||
if (isEdit.value && currentId.value) {
|
||||
await updateFormDef(currentId.value, formData as FormDefUpdateDTO)
|
||||
ElMessage.success('更新成功')
|
||||
} else {
|
||||
await createFormDef(formData as FormDefCreateDTO)
|
||||
ElMessage.success('创建成功')
|
||||
}
|
||||
dialogVisible.value = false
|
||||
fetchList()
|
||||
} catch (error) {
|
||||
ElMessage.error(isEdit.value ? '更新失败' : '创建失败')
|
||||
}
|
||||
}
|
||||
|
||||
function handlePageChange(page: number) {
|
||||
queryForm.pageNum = page
|
||||
fetchList()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="form-designer-container">
|
||||
<el-card class="search-card">
|
||||
<el-form :model="queryForm" inline>
|
||||
<el-form-item label="表单名称">
|
||||
<el-input v-model="queryForm.formName" placeholder="请输入表单名称" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="表单标识">
|
||||
<el-input v-model="queryForm.formKey" placeholder="请输入表单标识" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="queryForm.status" placeholder="请选择状态" clearable>
|
||||
<el-option label="启用" :value="1" />
|
||||
<el-option label="停用" :value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">查询</el-button>
|
||||
<el-button @click="handleReset">重置</el-button>
|
||||
<el-button type="primary" :icon="Plus" @click="handleAdd">新增</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card class="table-card">
|
||||
<el-table v-loading="loading" :data="tableData" border>
|
||||
<el-table-column prop="id" label="ID" width="80" />
|
||||
<el-table-column prop="formName" label="表单名称" />
|
||||
<el-table-column prop="formKey" label="表单标识" />
|
||||
<el-table-column prop="status" label="状态" width="80">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.status === 1 ? 'success' : 'danger'">
|
||||
{{ row.status === 1 ? '启用' : '停用' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" show-overflow-tooltip />
|
||||
<el-table-column prop="createdTime" label="创建时间" width="180" />
|
||||
<el-table-column label="操作" width="180" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" :icon="Edit" link @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button type="danger" :icon="Delete" link @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-pagination
|
||||
v-model:current-page="queryForm.pageNum"
|
||||
v-model:page-size="queryForm.pageSize"
|
||||
:total="total"
|
||||
layout="total, prev, pager, next, jumper"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="800px">
|
||||
<el-form :model="formData" label-width="100px">
|
||||
<el-form-item label="表单名称" required>
|
||||
<el-input v-model="formData.formName" placeholder="请输入表单名称" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="!isEdit" label="表单标识" required>
|
||||
<el-input v-model="(formData as FormDefCreateDTO).formKey" placeholder="小写字母+数字+下划线" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="isEdit" label="状态" required>
|
||||
<el-radio-group v-model="(formData as FormDefUpdateDTO).status">
|
||||
<el-radio :value="1">启用</el-radio>
|
||||
<el-radio :value="0">停用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="formData.remark" type="textarea" :rows="2" />
|
||||
</el-form-item>
|
||||
<el-form-item label="表单字段">
|
||||
<div class="field-list">
|
||||
<div v-for="(field, index) in schemaFields" :key="index" class="field-item">
|
||||
<el-input v-model="field.key" placeholder="字段Key" style="width: 150px" />
|
||||
<el-input v-model="field.label" placeholder="字段名称" style="width: 150px" />
|
||||
<el-select v-model="field.type" placeholder="字段类型" style="width: 120px">
|
||||
<el-option v-for="type in fieldTypes" :key="type.value" :label="type.label" :value="type.value" />
|
||||
</el-select>
|
||||
<el-checkbox v-model="field.required">必填</el-checkbox>
|
||||
<el-button type="danger" :icon="Delete" link @click="removeField(index)">删除</el-button>
|
||||
</div>
|
||||
<el-button type="primary" :icon="Plus" @click="addField">添加字段</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.form-designer-container {
|
||||
padding: 20px;
|
||||
|
||||
.search-card {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.table-card {
|
||||
.el-pagination {
|
||||
margin-top: 20px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.field-list {
|
||||
width: 100%;
|
||||
|
||||
.field-item {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,317 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Plus, Edit, Delete } from '@element-plus/icons-vue'
|
||||
import {
|
||||
getCustomFieldList,
|
||||
createCustomField,
|
||||
updateCustomField,
|
||||
deleteCustomField,
|
||||
type CustomFieldDefVO,
|
||||
type CustomFieldDefCreateDTO,
|
||||
type CustomFieldDefUpdateDTO
|
||||
} from '@/api/form/custom-field'
|
||||
|
||||
const loading = ref(false)
|
||||
const tableData = ref<CustomFieldDefVO[]>([])
|
||||
const entityTypeFilter = ref<string>('')
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const dialogTitle = ref('')
|
||||
const isEdit = ref(false)
|
||||
const currentId = ref<number>()
|
||||
|
||||
const formData = reactive<CustomFieldDefCreateDTO | CustomFieldDefUpdateDTO>({
|
||||
entityType: 'USER',
|
||||
fieldKey: '',
|
||||
fieldLabel: '',
|
||||
fieldType: 'TEXT',
|
||||
required: false,
|
||||
sortOrder: 0,
|
||||
options: []
|
||||
})
|
||||
|
||||
const entityTypes = [
|
||||
{ label: '用户', value: 'USER' },
|
||||
{ label: '部门', value: 'DEPT' }
|
||||
]
|
||||
|
||||
const fieldTypes = [
|
||||
{ label: '单行文本', value: 'TEXT' },
|
||||
{ label: '数字', value: 'NUMBER' },
|
||||
{ label: '日期', value: 'DATE' },
|
||||
{ label: '下拉选择', value: 'SELECT' },
|
||||
{ label: '复选框', value: 'CHECKBOX' }
|
||||
]
|
||||
|
||||
const optionInput = ref('')
|
||||
|
||||
async function fetchList() {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await getCustomFieldList(entityTypeFilter.value || undefined)
|
||||
tableData.value = res.data
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleQuery() {
|
||||
fetchList()
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
entityTypeFilter.value = ''
|
||||
fetchList()
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
dialogTitle.value = '新增自定义字段'
|
||||
isEdit.value = false
|
||||
currentId.value = undefined
|
||||
Object.assign(formData, {
|
||||
entityType: 'USER',
|
||||
fieldKey: '',
|
||||
fieldLabel: '',
|
||||
fieldType: 'TEXT',
|
||||
required: false,
|
||||
sortOrder: 0,
|
||||
options: []
|
||||
})
|
||||
optionInput.value = ''
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
function handleEdit(row: CustomFieldDefVO) {
|
||||
dialogTitle.value = '编辑自定义字段'
|
||||
isEdit.value = true
|
||||
currentId.value = row.id
|
||||
Object.assign(formData, {
|
||||
fieldLabel: row.fieldLabel,
|
||||
required: row.required,
|
||||
sortOrder: row.sortOrder,
|
||||
options: row.options || []
|
||||
})
|
||||
optionInput.value = ''
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
async function handleDelete(row: CustomFieldDefVO) {
|
||||
try {
|
||||
await ElMessageBox.confirm('确认删除该自定义字段吗?', '提示', {
|
||||
type: 'warning'
|
||||
})
|
||||
await deleteCustomField(row.id)
|
||||
ElMessage.success('删除成功')
|
||||
fetchList()
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
ElMessage.error('删除失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addOption() {
|
||||
if (!optionInput.value.trim()) {
|
||||
ElMessage.warning('请输入选项内容')
|
||||
return
|
||||
}
|
||||
if (!formData.options) {
|
||||
formData.options = []
|
||||
}
|
||||
formData.options.push(optionInput.value.trim())
|
||||
optionInput.value = ''
|
||||
}
|
||||
|
||||
function removeOption(index: number) {
|
||||
if (formData.options) {
|
||||
formData.options.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
if (isEdit.value && currentId.value) {
|
||||
await updateCustomField(currentId.value, formData as CustomFieldDefUpdateDTO)
|
||||
ElMessage.success('更新成功')
|
||||
} else {
|
||||
await createCustomField(formData as CustomFieldDefCreateDTO)
|
||||
ElMessage.success('创建成功')
|
||||
}
|
||||
dialogVisible.value = false
|
||||
fetchList()
|
||||
} catch (error) {
|
||||
ElMessage.error(isEdit.value ? '更新失败' : '创建失败')
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="custom-field-container">
|
||||
<el-card class="search-card">
|
||||
<el-form inline>
|
||||
<el-form-item label="实体类型">
|
||||
<el-select v-model="entityTypeFilter" placeholder="请选择实体类型" clearable>
|
||||
<el-option
|
||||
v-for="type in entityTypes"
|
||||
:key="type.value"
|
||||
:label="type.label"
|
||||
:value="type.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">查询</el-button>
|
||||
<el-button @click="handleReset">重置</el-button>
|
||||
<el-button type="primary" :icon="Plus" @click="handleAdd">新增</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card class="table-card">
|
||||
<el-table v-loading="loading" :data="tableData" border>
|
||||
<el-table-column prop="id" label="ID" width="80" />
|
||||
<el-table-column prop="entityType" label="实体类型" width="100">
|
||||
<template #default="{ row }">
|
||||
{{ entityTypes.find(t => t.value === row.entityType)?.label }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="fieldKey" label="字段Key" />
|
||||
<el-table-column prop="fieldLabel" label="字段名称" />
|
||||
<el-table-column prop="fieldType" label="字段类型" width="120">
|
||||
<template #default="{ row }">
|
||||
{{ fieldTypes.find(t => t.value === row.fieldType)?.label }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="required" label="是否必填" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.required ? 'danger' : 'info'">
|
||||
{{ row.required ? '必填' : '非必填' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="sortOrder" label="排序" width="80" />
|
||||
<el-table-column prop="createdTime" label="创建时间" width="180" />
|
||||
<el-table-column label="操作" width="180" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" :icon="Edit" link @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button type="danger" :icon="Delete" link @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="600px">
|
||||
<el-form :model="formData" label-width="100px">
|
||||
<el-form-item v-if="!isEdit" label="实体类型" required>
|
||||
<el-select v-model="(formData as CustomFieldDefCreateDTO).entityType" placeholder="请选择实体类型">
|
||||
<el-option
|
||||
v-for="type in entityTypes"
|
||||
:key="type.value"
|
||||
:label="type.label"
|
||||
:value="type.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="!isEdit" label="字段Key" required>
|
||||
<el-input v-model="(formData as CustomFieldDefCreateDTO).fieldKey" placeholder="小写字母+数字+下划线" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="!isEdit" label="字段类型" required>
|
||||
<el-select v-model="(formData as CustomFieldDefCreateDTO).fieldType" placeholder="请选择字段类型">
|
||||
<el-option
|
||||
v-for="type in fieldTypes"
|
||||
:key="type.value"
|
||||
:label="type.label"
|
||||
:value="type.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="字段名称" required>
|
||||
<el-input v-model="formData.fieldLabel" placeholder="请输入字段名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否必填" required>
|
||||
<el-switch v-model="formData.required" />
|
||||
</el-form-item>
|
||||
<el-form-item label="排序">
|
||||
<el-input-number v-model="formData.sortOrder" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="!isEdit && ((formData as CustomFieldDefCreateDTO).fieldType === 'SELECT' || (formData as CustomFieldDefCreateDTO).fieldType === 'CHECKBOX')"
|
||||
label="选项配置"
|
||||
>
|
||||
<div class="options-config">
|
||||
<div class="option-input">
|
||||
<el-input v-model="optionInput" placeholder="输入选项内容" />
|
||||
<el-button type="primary" @click="addOption">添加</el-button>
|
||||
</div>
|
||||
<div class="option-list">
|
||||
<el-tag
|
||||
v-for="(option, index) in formData.options"
|
||||
:key="index"
|
||||
closable
|
||||
@close="removeOption(index)"
|
||||
>
|
||||
{{ option }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="isEdit && formData.options && formData.options.length > 0"
|
||||
label="选项配置"
|
||||
>
|
||||
<div class="options-config">
|
||||
<div class="option-input">
|
||||
<el-input v-model="optionInput" placeholder="输入选项内容" />
|
||||
<el-button type="primary" @click="addOption">添加</el-button>
|
||||
</div>
|
||||
<div class="option-list">
|
||||
<el-tag
|
||||
v-for="(option, index) in formData.options"
|
||||
:key="index"
|
||||
closable
|
||||
@close="removeOption(index)"
|
||||
>
|
||||
{{ option }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.custom-field-container {
|
||||
padding: 20px;
|
||||
|
||||
.search-card {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.options-config {
|
||||
width: 100%;
|
||||
|
||||
.option-input {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.option-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,45 @@
|
||||
interface ApiResult<T = unknown> {
|
||||
code: number
|
||||
message: string
|
||||
data: T
|
||||
}
|
||||
|
||||
const BASE_URL = import.meta.env.VITE_APP_BASE_API || '/api'
|
||||
|
||||
function request<T>(options: UniApp.RequestOptions): Promise<T> {
|
||||
const token = uni.getStorageSync('token')
|
||||
const tenantId = uni.getStorageSync('tenantId')
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.request({
|
||||
...options,
|
||||
url: `${BASE_URL}${options.url}`,
|
||||
header: {
|
||||
Authorization: token ? `Bearer ${token}` : '',
|
||||
'X-Tenant-Id': tenantId || '',
|
||||
'Content-Type': 'application/json',
|
||||
...options.header,
|
||||
},
|
||||
success: (res) => {
|
||||
const data = res.data as ApiResult<T>
|
||||
if (data.code === 200) {
|
||||
resolve(data.data)
|
||||
} else if (data.code === 401) {
|
||||
uni.removeStorageSync('token')
|
||||
uni.removeStorageSync('tenantId')
|
||||
uni.redirectTo({ url: '/pages/login/index' })
|
||||
reject(new Error('UNAUTHORIZED'))
|
||||
} else {
|
||||
uni.showToast({ title: data.message || '请求失败', icon: 'none' })
|
||||
reject(new Error(data.message))
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
uni.showToast({ title: '网络错误', icon: 'none' })
|
||||
reject(err)
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export default request
|
||||
@@ -0,0 +1,224 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Phase 29-53 Implementation Completeness Checker
|
||||
Analyzes phase specifications vs actual implementation
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Set, Tuple
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class PhaseInfo:
|
||||
phase_num: int
|
||||
title: str
|
||||
status: str
|
||||
backend_required: bool
|
||||
frontend_required: bool
|
||||
spec_files: List[str]
|
||||
manifest_files: List[str]
|
||||
missing_files: List[str]
|
||||
extra_files: List[str]
|
||||
|
||||
def parse_phase_spec(spec_path: Path) -> Tuple[bool, bool, List[str]]:
|
||||
"""Parse phase spec file to extract backend/frontend requirements and scope"""
|
||||
with open(spec_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
# Extract YAML frontmatter
|
||||
match = re.search(r'^---\n(.*?)\n---', content, re.DOTALL | re.MULTILINE)
|
||||
if not match:
|
||||
return False, False, []
|
||||
|
||||
try:
|
||||
frontmatter = yaml.safe_load(match.group(1))
|
||||
backend = frontmatter.get('targets', {}).get('backend', False)
|
||||
frontend = frontmatter.get('targets', {}).get('frontend', False)
|
||||
scope = frontmatter.get('scope', [])
|
||||
return backend, frontend, scope
|
||||
except:
|
||||
return False, False, []
|
||||
|
||||
def parse_manifest() -> Dict[int, Tuple[str, str, List[str]]]:
|
||||
"""Parse PHASE_MANIFEST.txt to extract phase info"""
|
||||
manifest_path = Path('/Users/brunogao/work/codes/ljwx/ljwx-platform/PHASE_MANIFEST.txt')
|
||||
phases = {}
|
||||
|
||||
with open(manifest_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
# Split by phase sections
|
||||
phase_sections = re.split(r'\n## PHASE (\d+)\n', content)
|
||||
|
||||
for i in range(1, len(phase_sections), 2):
|
||||
phase_num = int(phase_sections[i])
|
||||
if phase_num < 29 or phase_num > 53:
|
||||
continue
|
||||
|
||||
section = phase_sections[i + 1]
|
||||
|
||||
# Extract title
|
||||
title_match = re.search(r'Title: (.+)', section)
|
||||
title = title_match.group(1) if title_match else "Unknown"
|
||||
|
||||
# Extract status
|
||||
status_match = re.search(r'Status: (\w+)', section)
|
||||
status = status_match.group(1) if status_match else "UNKNOWN"
|
||||
|
||||
# Extract files
|
||||
files = []
|
||||
in_files_section = False
|
||||
for line in section.split('\n'):
|
||||
if line.startswith('Files:'):
|
||||
in_files_section = True
|
||||
continue
|
||||
if in_files_section:
|
||||
if line.startswith('Status:') or line.startswith('Gate:') or line.startswith('##'):
|
||||
break
|
||||
if line.strip().startswith('- '):
|
||||
# Remove quotes and leading dash
|
||||
file_path = line.strip()[2:].strip('"')
|
||||
if file_path and file_path != '--':
|
||||
files.append(file_path)
|
||||
|
||||
phases[phase_num] = (title, status, files)
|
||||
|
||||
return phases
|
||||
|
||||
def check_file_exists(file_path: str, base_dir: Path) -> bool:
|
||||
"""Check if a file exists relative to base directory"""
|
||||
full_path = base_dir / file_path
|
||||
return full_path.exists()
|
||||
|
||||
def analyze_phase(phase_num: int, base_dir: Path) -> PhaseInfo:
|
||||
"""Analyze a single phase for completeness"""
|
||||
spec_path = base_dir / f'spec/phase/phase-{phase_num}.md'
|
||||
|
||||
# Parse spec file
|
||||
if not spec_path.exists():
|
||||
return PhaseInfo(
|
||||
phase_num=phase_num,
|
||||
title="SPEC NOT FOUND",
|
||||
status="NOT_STARTED",
|
||||
backend_required=False,
|
||||
frontend_required=False,
|
||||
spec_files=[],
|
||||
manifest_files=[],
|
||||
missing_files=[],
|
||||
extra_files=[]
|
||||
)
|
||||
|
||||
backend_req, frontend_req, spec_files = parse_phase_spec(spec_path)
|
||||
|
||||
# Parse manifest
|
||||
manifest_data = parse_manifest()
|
||||
if phase_num not in manifest_data:
|
||||
return PhaseInfo(
|
||||
phase_num=phase_num,
|
||||
title="NOT IN MANIFEST",
|
||||
status="NOT_STARTED",
|
||||
backend_required=backend_req,
|
||||
frontend_required=frontend_req,
|
||||
spec_files=spec_files,
|
||||
manifest_files=[],
|
||||
missing_files=spec_files,
|
||||
extra_files=[]
|
||||
)
|
||||
|
||||
title, status, manifest_files = manifest_data[phase_num]
|
||||
|
||||
# Check file existence
|
||||
spec_set = set(spec_files)
|
||||
manifest_set = set(manifest_files)
|
||||
|
||||
missing_files = []
|
||||
for file_path in spec_set:
|
||||
if not check_file_exists(file_path, base_dir):
|
||||
missing_files.append(file_path)
|
||||
|
||||
extra_files = list(manifest_set - spec_set)
|
||||
|
||||
return PhaseInfo(
|
||||
phase_num=phase_num,
|
||||
title=title,
|
||||
status=status,
|
||||
backend_required=backend_req,
|
||||
frontend_required=frontend_req,
|
||||
spec_files=spec_files,
|
||||
manifest_files=manifest_files,
|
||||
missing_files=missing_files,
|
||||
extra_files=extra_files
|
||||
)
|
||||
|
||||
def main():
|
||||
base_dir = Path('/Users/brunogao/work/codes/ljwx/ljwx-platform')
|
||||
|
||||
print("=" * 80)
|
||||
print("Phase 29-53 Implementation Completeness Analysis")
|
||||
print("=" * 80)
|
||||
print()
|
||||
|
||||
complete_count = 0
|
||||
partial_count = 0
|
||||
not_started_count = 0
|
||||
|
||||
for phase_num in range(29, 54):
|
||||
info = analyze_phase(phase_num, base_dir)
|
||||
|
||||
# Determine completeness
|
||||
if info.status == "NOT_STARTED":
|
||||
status_symbol = "❌"
|
||||
completeness = "NOT_STARTED"
|
||||
not_started_count += 1
|
||||
elif len(info.missing_files) == 0:
|
||||
status_symbol = "✅"
|
||||
completeness = "COMPLETE"
|
||||
complete_count += 1
|
||||
else:
|
||||
status_symbol = "⚠️"
|
||||
completeness = "INCOMPLETE"
|
||||
partial_count += 1
|
||||
|
||||
print(f"Phase {phase_num}: {status_symbol} {info.title}")
|
||||
print(f" Status: {info.status}")
|
||||
print(f" Backend: {'required' if info.backend_required else 'not required'}")
|
||||
print(f" Frontend: {'required' if info.frontend_required else 'not required'}")
|
||||
print(f" Files: {len(info.spec_files)} specified, {len(info.manifest_files)} in manifest")
|
||||
|
||||
if info.missing_files:
|
||||
print(f" ⚠️ Missing files ({len(info.missing_files)}):")
|
||||
for f in info.missing_files[:5]: # Show first 5
|
||||
print(f" - {f}")
|
||||
if len(info.missing_files) > 5:
|
||||
print(f" ... and {len(info.missing_files) - 5} more")
|
||||
|
||||
if info.extra_files:
|
||||
print(f" ℹ️ Extra files in manifest ({len(info.extra_files)}):")
|
||||
for f in info.extra_files[:3]:
|
||||
print(f" - {f}")
|
||||
if len(info.extra_files) > 3:
|
||||
print(f" ... and {len(info.extra_files) - 3} more")
|
||||
|
||||
print(f" Completeness: {completeness}")
|
||||
print()
|
||||
|
||||
print("=" * 80)
|
||||
print("Summary")
|
||||
print("=" * 80)
|
||||
print(f"✅ Complete phases: {complete_count}/25")
|
||||
print(f"⚠️ Incomplete phases: {partial_count}/25")
|
||||
print(f"❌ Not started phases: {not_started_count}/25")
|
||||
print()
|
||||
|
||||
if complete_count == 25:
|
||||
print("🎉 All phases 29-53 are fully implemented!")
|
||||
elif partial_count > 0:
|
||||
print(f"⚠️ {partial_count} phases need attention - some files are missing")
|
||||
if not_started_count > 0:
|
||||
print(f"❌ {not_started_count} phases have not been started")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user