refactor(ownership): 三张跨产线表定义删除不留副本(第2轮迁归属,已迁入pipeline-core@4b2fd4c)

- models: sd_projects/sd_project_role_models/pipeline_deliverables 3个JSON删除——归属core,双源必乱
- json: sd_project_list/pipeline_deliverables_list CRUD定义删除(迁core)
- wwwroot/api: 15个CRUD页面依赖的dspy删除(随页面迁core,entire_url相对解析跟页面走)
- wwwroot/sd_project_role_models: 手写角色模型页整目录删除(迁core)
- scripts/load_path.py: 已迁页面的RBAC注册条目删除(sd_projects 5条/sd_project_list 1条/role_models 5条/api 4条)
- json/sd_iteration_list+sd_deploy_env_list+sd_features_list: get_project_options.dspy引用改绝对路径/pipeline_core/api/**(留在sdlc的页面消费迁走的api)
- wwwroot/api/cockpit_cards.dspy: 项目管理弹窗URL改/pipeline_core/sd_projects/index.ui
- init/data.json: 4组字典随表迁core(sd_project_status/sd_project_type/deliverable_type/review_status)
- .gitignore: 已迁生成目录条目清理(sd_projects//pipeline_deliverables/)
- 顺带清死双源: wwwroot/json/整目录(build.sh只读模块根json/,wwwroot/json零消费方+内容漂移:subtables还指着改名前的目录)+wwwroot/sd_project_list/index.ui死占位页(零菜单引用)
This commit is contained in:
ymq 2026-09-10 12:33:42 +08:00
parent 31212038d2
commit 0a339a2b19
42 changed files with 335 additions and 1442 deletions

2
.gitignore vendored
View File

@ -6,7 +6,6 @@ __pycache__/
dist/
# CRUD generated directories (auto-generated by xls2ui, NOT in repo)
wwwroot/sd_projects/
wwwroot/sd_iterations/
wwwroot/sd_test_plans/
wwwroot/sd_test_cases/
@ -15,7 +14,6 @@ wwwroot/sd_deploy_envs/
wwwroot/sd_org_settings/
wwwroot/sd_project_repos/
wwwroot/sd_features/
wwwroot/pipeline_deliverables/
# venv
py3/

View File

@ -1,121 +1,332 @@
{
"appcodes": [
{"parentid": "sd_project_status", "parentname": "项目状态", "items": [
{"k": "draft", "v": "草稿"},
{"k": "active", "v": "进行中"},
{"k": "paused", "v": "已暂停"},
{"k": "completed", "v": "已完成"},
{"k": "archived", "v": "已归档"}
]},
{"parentid": "sd_project_type", "parentname": "项目类型", "items": [
{"k": "general", "v": "通用项目"},
{"k": "bidding", "v": "投标项目"},
{"k": "web_app", "v": "Web应用"},
{"k": "api_service", "v": "API服务"},
{"k": "module", "v": "Sage模块"},
{"k": "mobile_app", "v": "移动应用"},
{"k": "cli_tool", "v": "CLI工具"},
{"k": "data_pipeline", "v": "数据管道"}
]},
{"parentid": "sd_iteration_type", "parentname": "迭代类型", "items": [
{"k": "new_feature", "v": "新功能"},
{"k": "bugfix", "v": "Bug修复"},
{"k": "refactor", "v": "重构"},
{"k": "upgrade", "v": "升级"},
{"k": "hotfix", "v": "紧急修复"}
]},
{"parentid": "sd_iteration_status", "parentname": "迭代状态", "items": [
{"k": "planning", "v": "规划中"},
{"k": "in_progress", "v": "进行中"},
{"k": "completed", "v": "已完成"},
{"k": "cancelled", "v": "已取消"}
]},
{"parentid": "sd_test_plan_type", "parentname": "测试方案类型", "items": [
{"k": "functional", "v": "功能测试"},
{"k": "performance", "v": "性能测试"},
{"k": "security", "v": "安全测试"},
{"k": "regression", "v": "回归测试"},
{"k": "integration", "v": "集成测试"}
]},
{"parentid": "sd_test_plan_status", "parentname": "测试方案状态", "items": [
{"k": "draft", "v": "草稿"},
{"k": "approved", "v": "已审批"},
{"k": "executing", "v": "执行中"},
{"k": "completed", "v": "已完成"}
]},
{"parentid": "sd_test_case_type", "parentname": "测试用例类型", "items": [
{"k": "functional", "v": "功能"},
{"k": "performance", "v": "性能"},
{"k": "api", "v": "API"},
{"k": "ui", "v": "UI"},
{"k": "integration", "v": "集成"}
]},
{"parentid": "sd_test_case_status", "parentname": "测试用例状态", "items": [
{"k": "pending", "v": "待执行"},
{"k": "pass", "v": "通过"},
{"k": "fail", "v": "失败"},
{"k": "blocked", "v": "阻塞"},
{"k": "skipped", "v": "跳过"}
]},
{"parentid": "sd_bug_severity", "parentname": "Bug严重程度", "items": [
{"k": "critical", "v": "致命"},
{"k": "major", "v": "严重"},
{"k": "minor", "v": "一般"},
{"k": "trivial", "v": "轻微"}
]},
{"parentid": "sd_bug_status", "parentname": "Bug状态", "items": [
{"k": "open", "v": "新建"},
{"k": "confirmed", "v": "已确认"},
{"k": "fixing", "v": "修复中"},
{"k": "fixed", "v": "已修复"},
{"k": "verified", "v": "已验证"},
{"k": "closed", "v": "已关闭"},
{"k": "rejected", "v": "已驳回"}
]},
{"parentid": "sd_priority", "parentname": "优先级", "items": [
{"k": "P0", "v": "P0-紧急"},
{"k": "P1", "v": "P1-高"},
{"k": "P2", "v": "P2-中"},
{"k": "P3", "v": "P3-低"}
]},
{"parentid": "sd_reporter_type", "parentname": "提交人类型", "items": [
{"k": "agent", "v": "Agent"},
{"k": "human", "v": "人工"}
]},
{"parentid": "sd_env_type", "parentname": "环境类型", "items": [
{"k": "test", "v": "测试环境"},
{"k": "staging", "v": "预发布环境"},
{"k": "production", "v": "生产环境"}
]},
{"parentid": "sd_env_status", "parentname": "环境状态", "items": [
{"k": "configured", "v": "已配置"},
{"k": "verified", "v": "已验证"},
{"k": "failed", "v": "验证失败"}
]},
{"parentid": "sd_feature_type", "parentname": "功能类型", "items": [
{"k": "new_feature", "v": "新功能"},
{"k": "enhancement", "v": "功能增强"},
{"k": "bugfix", "v": "Bug修复"},
{"k": "refactor", "v": "重构"}
]},
{"parentid": "sd_feature_status", "parentname": "功能状态", "items": [
{"k": "proposed", "v": "已提出"},
{"k": "approved", "v": "已批准"},
{"k": "in_progress", "v": "开发中"},
{"k": "delivered", "v": "已交付"},
{"k": "verified", "v": "已验证"},
{"k": "rejected", "v": "已驳回"}
]},
{"parentid": "deliverable_type", "parentname": "交付件类型", "items": [
{"k": "code", "v": "代码"},
{"k": "doc", "v": "文档"},
{"k": "config", "v": "配置"},
{"k": "test-report", "v": "测试报告"}
]},
{"parentid": "review_status", "parentname": "评审状态", "items": [
{"k": "pending", "v": "待评审"},
{"k": "approved", "v": "通过"},
{"k": "rejected", "v": "驳回"}
]}
{
"parentid": "sd_iteration_type",
"parentname": "迭代类型",
"items": [
{
"k": "new_feature",
"v": "新功能"
},
{
"k": "bugfix",
"v": "Bug修复"
},
{
"k": "refactor",
"v": "重构"
},
{
"k": "upgrade",
"v": "升级"
},
{
"k": "hotfix",
"v": "紧急修复"
}
]
},
{
"parentid": "sd_iteration_status",
"parentname": "迭代状态",
"items": [
{
"k": "planning",
"v": "规划中"
},
{
"k": "in_progress",
"v": "进行中"
},
{
"k": "completed",
"v": "已完成"
},
{
"k": "cancelled",
"v": "已取消"
}
]
},
{
"parentid": "sd_test_plan_type",
"parentname": "测试方案类型",
"items": [
{
"k": "functional",
"v": "功能测试"
},
{
"k": "performance",
"v": "性能测试"
},
{
"k": "security",
"v": "安全测试"
},
{
"k": "regression",
"v": "回归测试"
},
{
"k": "integration",
"v": "集成测试"
}
]
},
{
"parentid": "sd_test_plan_status",
"parentname": "测试方案状态",
"items": [
{
"k": "draft",
"v": "草稿"
},
{
"k": "approved",
"v": "已审批"
},
{
"k": "executing",
"v": "执行中"
},
{
"k": "completed",
"v": "已完成"
}
]
},
{
"parentid": "sd_test_case_type",
"parentname": "测试用例类型",
"items": [
{
"k": "functional",
"v": "功能"
},
{
"k": "performance",
"v": "性能"
},
{
"k": "api",
"v": "API"
},
{
"k": "ui",
"v": "UI"
},
{
"k": "integration",
"v": "集成"
}
]
},
{
"parentid": "sd_test_case_status",
"parentname": "测试用例状态",
"items": [
{
"k": "pending",
"v": "待执行"
},
{
"k": "pass",
"v": "通过"
},
{
"k": "fail",
"v": "失败"
},
{
"k": "blocked",
"v": "阻塞"
},
{
"k": "skipped",
"v": "跳过"
}
]
},
{
"parentid": "sd_bug_severity",
"parentname": "Bug严重程度",
"items": [
{
"k": "critical",
"v": "致命"
},
{
"k": "major",
"v": "严重"
},
{
"k": "minor",
"v": "一般"
},
{
"k": "trivial",
"v": "轻微"
}
]
},
{
"parentid": "sd_bug_status",
"parentname": "Bug状态",
"items": [
{
"k": "open",
"v": "新建"
},
{
"k": "confirmed",
"v": "已确认"
},
{
"k": "fixing",
"v": "修复中"
},
{
"k": "fixed",
"v": "已修复"
},
{
"k": "verified",
"v": "已验证"
},
{
"k": "closed",
"v": "已关闭"
},
{
"k": "rejected",
"v": "已驳回"
}
]
},
{
"parentid": "sd_priority",
"parentname": "优先级",
"items": [
{
"k": "P0",
"v": "P0-紧急"
},
{
"k": "P1",
"v": "P1-高"
},
{
"k": "P2",
"v": "P2-中"
},
{
"k": "P3",
"v": "P3-低"
}
]
},
{
"parentid": "sd_reporter_type",
"parentname": "提交人类型",
"items": [
{
"k": "agent",
"v": "Agent"
},
{
"k": "human",
"v": "人工"
}
]
},
{
"parentid": "sd_env_type",
"parentname": "环境类型",
"items": [
{
"k": "test",
"v": "测试环境"
},
{
"k": "staging",
"v": "预发布环境"
},
{
"k": "production",
"v": "生产环境"
}
]
},
{
"parentid": "sd_env_status",
"parentname": "环境状态",
"items": [
{
"k": "configured",
"v": "已配置"
},
{
"k": "verified",
"v": "已验证"
},
{
"k": "failed",
"v": "验证失败"
}
]
},
{
"parentid": "sd_feature_type",
"parentname": "功能类型",
"items": [
{
"k": "new_feature",
"v": "新功能"
},
{
"k": "enhancement",
"v": "功能增强"
},
{
"k": "bugfix",
"v": "Bug修复"
},
{
"k": "refactor",
"v": "重构"
}
]
},
{
"parentid": "sd_feature_status",
"parentname": "功能状态",
"items": [
{
"k": "proposed",
"v": "已提出"
},
{
"k": "approved",
"v": "已批准"
},
{
"k": "in_progress",
"v": "开发中"
},
{
"k": "delivered",
"v": "已交付"
},
{
"k": "verified",
"v": "已验证"
},
{
"k": "rejected",
"v": "已驳回"
}
]
}
]
}

View File

@ -1,67 +0,0 @@
{
"tblname": "pipeline_deliverables",
"title": "交付件管理",
"params": {
"sortby": [
"created_at desc"
],
"confidential_fields": [],
"browserfields": {
"exclouded": [
"content",
"file_path",
"target_path"
],
"alters": {
"project_id": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_project_options.dspy')}}",
"valueField": "value",
"textField": "text"
},
"deliverable_type": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_search_deliverable_type.dspy')}}",
"valueField": "value",
"textField": "text"
},
"review_status": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_search_review_status.dspy')}}",
"valueField": "value",
"textField": "text"
}
}
},
"editexclouded": [
"id",
"created_at",
"reviewed_by",
"created_by"
],
"editable": {
"new_data_url": "{{entire_url('../api/sd_deliverable_create.dspy')}}",
"update_data_url": "{{entire_url('../api/sd_deliverable_update.dspy')}}",
"delete_data_url": "{{entire_url('../api/sd_deliverable_delete.dspy')}}"
},
"data_filter": {
"AND": [
{
"field": "title",
"op": "LIKE",
"var": "title_input"
},
{
"field": "review_status",
"op": "=",
"var": "status_input"
},
{
"field": "deliverable_type",
"op": "=",
"var": "type_input"
}
]
}
}
}

View File

@ -17,7 +17,7 @@
"alters": {
"project_id": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_project_options.dspy')}}",
"dataurl": "{{entire_url('/pipeline_core/api/get_project_options.dspy')}}",
"valueField": "value",
"textField": "text"
},

View File

@ -14,7 +14,7 @@
"alters": {
"project_id": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_project_options.dspy')}}",
"dataurl": "{{entire_url('/pipeline_core/api/get_project_options.dspy')}}",
"valueField": "value",
"textField": "text"
},

View File

@ -13,7 +13,7 @@
"alters": {
"project_id": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_project_options.dspy')}}",
"dataurl": "{{entire_url('/pipeline_core/api/get_project_options.dspy')}}",
"valueField": "value",
"textField": "text"
},

View File

@ -1,80 +0,0 @@
{
"tblname": "sd_projects",
"title": "项目管理",
"params": {
"sortby": [
"created_at desc"
],
"logined_userorgid": "org_id",
"confidential_fields": [],
"browserfields": {
"exclouded": [
"tech_stack"
],
"alters": {
"status": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_search_status.dspy')}}",
"valueField": "value",
"textField": "text"
},
"project_type": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_search_project_type.dspy')}}",
"valueField": "value",
"textField": "text"
},
"pipeline_id": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_pipeline_options.dspy')}}",
"valueField": "value",
"textField": "text"
}
}
},
"editexclouded": [
"id",
"created_at",
"updated_at",
"org_id"
],
"editable": {
"new_data_url": "{{entire_url('../api/sd_project_create.dspy')}}",
"update_data_url": "{{entire_url('../api/sd_project_update.dspy')}}",
"delete_data_url": "{{entire_url('../api/sd_project_delete.dspy')}}"
},
"data_filter": {
"AND": [
{
"field": "name",
"op": "LIKE",
"var": "name_input"
},
{
"field": "status",
"op": "=",
"var": "status_input"
},
{
"field": "project_type",
"op": "=",
"var": "type_input"
}
]
},
"subtables": [
{
"field": "project_id",
"title": "迭代列表",
"url": "{{entire_url('../sd_iterations?project_id=${id}')}}",
"subtable": "sd_iterations"
},
{
"field": "project_id",
"title": "代码仓库",
"url": "{{entire_url('../sd_project_repos?project_id=${id}')}}",
"subtable": "sd_project_repos"
}
]
}
}

View File

@ -1,36 +0,0 @@
{
"summary": [
{
"name": "pipeline_deliverables",
"title": "任务交付件",
"primary": ["id"],
"catelog": "entity"
}
],
"fields": [
{"name": "id", "title": "主键ID", "type": "str", "length": 32, "nullable": "no"},
{"name": "project_id", "title": "项目ID", "type": "str", "length": 32, "nullable": "no"},
{"name": "task_id", "title": "任务ID", "type": "str", "length": 32},
{"name": "title", "title": "交付件标题", "type": "str", "length": 200, "nullable": "no"},
{"name": "deliverable_type", "title": "交付件类型", "type": "str", "length": 32, "nullable": "no", "default": "'code'"},
{"name": "repo_name", "title": "目标仓库别名", "type": "str", "length": 100},
{"name": "target_path", "title": "仓库内相对路径", "type": "str", "length": 500},
{"name": "file_path", "title": "本地存储路径", "type": "str", "length": 500},
{"name": "content", "title": "交付件内容", "type": "longtext"},
{"name": "quality_score", "title": "质量评分(0-100)", "type": "int", "nullable": "no", "default": "80"},
{"name": "review_status", "title": "评审状态", "type": "str", "length": 20, "nullable": "no", "default": "'pending'"},
{"name": "review_comment", "title": "评审意见", "type": "text"},
{"name": "reviewed_by", "title": "评审人", "type": "str", "length": 32},
{"name": "created_by", "title": "创建人", "type": "str", "length": 32, "nullable": "no"},
{"name": "created_at", "title": "创建时间", "type": "timestamp", "nullable": "no"}
],
"indexes": [
{"name": "idx_pd_project", "idxtype": "index", "idxfields": ["project_id"]},
{"name": "idx_pd_task", "idxtype": "index", "idxfields": ["task_id"]},
{"name": "idx_pd_review", "idxtype": "index", "idxfields": ["review_status"]}
],
"codes": [
{"field": "deliverable_type", "table": "appcodes_kv", "valuefield": "k", "textfield": "v", "cond": "parentid='deliverable_type'"},
{"field": "review_status", "table": "appcodes_kv", "valuefield": "k", "textfield": "v", "cond": "parentid='review_status'"}
]
}

View File

@ -1,25 +0,0 @@
{
"summary": [
{
"name": "sd_project_role_models",
"title": "项目角色模型配置",
"primary": ["id"],
"catelog": "entity"
}
],
"fields": [
{"name": "id", "title": "主键ID", "type": "str", "length": 32, "nullable": "no"},
{"name": "project_id", "title": "项目ID", "type": "str", "length": 32, "nullable": "no"},
{"name": "role", "title": "角色名", "type": "str", "length": 64, "nullable": "no"},
{"name": "model_name", "title": "模型名(llm.name,空=用项目缺省模型)", "type": "str", "length": 128},
{"name": "created_at", "title": "创建时间", "type": "timestamp", "nullable": "no"},
{"name": "updated_at", "title": "更新时间", "type": "timestamp"}
],
"indexes": [
{"name": "uk_sd_project_role_models_pr", "idxtype": "unique", "idxfields": ["project_id", "role"]}
],
"codes": [
{"field": "role", "table": "appcodes_kv", "valuefield": "k", "textfield": "v", "cond": "parentid='sd_role'"},
{"field": "model_name", "table": "llm", "valuefield": "name", "textfield": "name", "cond": ""}
]
}

View File

@ -1,35 +0,0 @@
{
"summary": [
{
"name": "sd_projects",
"title": "SDLC项目表",
"primary": ["id"],
"catelog": "entity"
}
],
"fields": [
{"name": "id", "title": "主键ID", "type": "str", "length": 32, "nullable": "no"},
{"name": "name", "title": "项目名称", "type": "str", "length": 200, "nullable": "no"},
{"name": "description", "title": "项目描述", "type": "text"},
{"name": "project_type", "title": "项目类型", "type": "str", "length": 50, "nullable": "no", "default": "'general'"},
{"name": "tech_stack", "title": "技术栈配置(JSON)", "type": "text"},
{"name": "repo_url", "title": "主仓库地址", "type": "str", "length": 500},
{"name": "directory_name", "title": "项目目录名(创建时定死,工作空间解析只读此字段)", "type": "str", "length": 200},
{"name": "workspace_dir", "title": "项目工作目录", "type": "str", "length": 500},
{"name": "default_model", "title": "项目默认模型(llm_model.name,空=走治理链缺省)", "type": "str", "length": 128},
{"name": "pipeline_id", "title": "关联Pipeline定义ID(general=通用项目,不挂产线)", "type": "str", "length": 32, "default": "'general'"},
{"name": "status", "title": "项目状态", "type": "str", "length": 20, "nullable": "no", "default": "'draft'"},
{"name": "org_id", "title": "组织ID", "type": "str", "length": 32, "nullable": "no", "default": "'0'"},
{"name": "created_by", "title": "创建人", "type": "str", "length": 32},
{"name": "created_at", "title": "创建时间", "type": "timestamp", "nullable": "no"},
{"name": "updated_at", "title": "更新时间", "type": "timestamp"}
],
"indexes": [
{"name": "idx_sd_projects_status", "idxtype": "index", "idxfields": ["status"]},
{"name": "idx_sd_projects_org", "idxtype": "index", "idxfields": ["org_id"]}
],
"codes": [
{"field": "status", "table": "appcodes_kv", "valuefield": "k", "textfield": "v", "cond": "parentid='sd_project_status'"},
{"field": "project_type", "table": "appcodes_kv", "valuefield": "k", "textfield": "v", "cond": "parentid='sd_project_type'"}
]
}

View File

@ -18,13 +18,6 @@ PATHS_LOGINED = [
# Dashboard
f"/{MOD}/sd_dashboard/index.ui",
f"/{MOD}/sd_dashboard/dashboard_data.dspy",
# Projects
f"/{MOD}/sd_projects/index.ui",
f"/{MOD}/sd_projects/get_sd_projects.dspy",
f"/{MOD}/sd_projects/add_sd_projects.dspy",
f"/{MOD}/sd_projects/update_sd_projects.dspy",
f"/{MOD}/sd_projects/delete_sd_projects.dspy",
f"/{MOD}/sd_project_list/index.ui",
# Iterations
f"/{MOD}/sd_iterations/index.ui",
f"/{MOD}/sd_iterations/get_sd_iterations.dspy",
@ -60,12 +53,6 @@ PATHS_LOGINED = [
f"/{MOD}/sd_deploy_envs/update_sd_deploy_envs.dspy",
f"/{MOD}/sd_deploy_envs/delete_sd_deploy_envs.dspy",
f"/{MOD}/sd_deploy_env_list/index.ui",
# Project Role Models角色模型配置
f"/{MOD}/sd_project_role_models/index.ui",
f"/{MOD}/sd_project_role_models/get_sd_project_role_models.dspy",
f"/{MOD}/sd_project_role_models/add_sd_project_role_models.dspy",
f"/{MOD}/sd_project_role_models/update_sd_project_role_models.dspy",
f"/{MOD}/sd_project_role_models/delete_sd_project_role_models.dspy",
# Review
f"/{MOD}/sd_review/index.ui",
# API
@ -74,10 +61,6 @@ PATHS_LOGINED = [
f"/{MOD}/api/check_iteration_bugs.dspy",
f"/{MOD}/api/env_verify.dspy",
f"/{MOD}/api/get_iteration_options.dspy",
f"/{MOD}/api/get_project_options.dspy",
f"/{MOD}/api/get_project_select_options.dspy",
f"/{MOD}/api/get_role_options.dspy",
f"/{MOD}/api/get_model_options.dspy",
f"/{MOD}/api/get_test_plan_options.dspy",
f"/{MOD}/api/submit_bug.dspy",
f"/{MOD}/api/sd_bug_create.dspy",
@ -109,10 +92,8 @@ PATHS_LOGINED = [
f"/{MOD}/api/get_search_plan_status.dspy",
f"/{MOD}/api/get_search_plan_type.dspy",
f"/{MOD}/api/get_search_priority.dspy",
f"/{MOD}/api/get_search_project_type.dspy",
f"/{MOD}/api/get_search_reporter_type.dspy",
f"/{MOD}/api/get_search_severity.dspy",
f"/{MOD}/api/get_search_status.dspy",
# Workspace 文件浏览/编辑
f"/{MOD}/api/workspace_tree.dspy",
f"/{MOD}/api/workspace_files.dspy",

View File

@ -16,7 +16,7 @@ async with DBPools().sqlorContext(get_module_dbname('pipeline-sdlc')) as sor:
cards = [
{"title": "活跃项目", "count": pc, "color": "#3b82f6", "icon": "📁",
"popup_url": "/pipeline-sdlc/sd_projects/index.ui", "popup_title": "项目管理"},
"popup_url": "/pipeline_core/sd_projects/index.ui", "popup_title": "项目管理"},
{"title": "进行中迭代", "count": ic, "color": "#10b981", "icon": "🔄",
"popup_url": "/pipeline-sdlc/sd_iterations/index.ui", "popup_title": "迭代管理"},
{"title": "待处理Bug", "count": bc, "color": "#ef4444", "icon": "🐛",

View File

@ -1,16 +0,0 @@
# get_model_options.dspy — 角色模型配置下拉value=模型注册名)
# 2026-09-04 收敛:实现统一在模型治理模块 pipeline_llm.selection.model_options
# 本文件只作 URL 入口。保留历史格式:首项「缺省(用项目默认模型)」+ value/text 两列。
# capabilities='chat':角色模型也是会话/任务 agent 用的对话模型,只列 t2t/i2t/m2t
# 2026-09-06 用户定夺;防把 embedding 等非对话模型配给角色后推理链报能力不匹配)。
rows = [{'value': '', 'text': '缺省(用项目默认模型)'}]
try:
org_id = await get_userorgid()
if org_id:
opts = await llm_model_options(org_id, value_field='name', capabilities='chat')
rows += [{'value': r['value'], 'text': r['text']} for r in opts]
return json.dumps(rows, ensure_ascii=False)
except Exception as e:
debug(f'get_model_options error: {e}')
return json.dumps(rows, ensure_ascii=False)

View File

@ -1,10 +0,0 @@
import json
result = json.dumps([{'value': '', 'text': '请选择'}], ensure_ascii=False)
try:
async with get_sor_context(request._run_ns, 'pipeline') as sor:
rows = await sor.sqlExe("select id as value, name as text from pipelines order by name")
r = [{'value': '', 'text': '请选择'}] + list(rows)
return json.dumps(r, ensure_ascii=False)
except Exception as e:
debug(f'get_pipeline_options error: {e}')
return json.dumps(result, ensure_ascii=False)

View File

@ -1,9 +0,0 @@
result = []
try:
async with get_sor_context(request._run_ns, 'pipeline') as sor:
rows = await sor.sqlExe("select id as project_id, name as project_id_text from sd_projects where pipeline_id='sdlc_general' order by name", {})
result = list(rows)
return json.dumps(result, ensure_ascii=False)
except Exception as e:
debug(f'dropdown error: {e}')
return json.dumps(result, ensure_ascii=False)

View File

@ -1,9 +0,0 @@
import json
try:
async with get_sor_context(request._run_ns, 'pipeline') as sor:
rows = await sor.sqlExe("select id as value, name as text from sd_projects order by created_at desc", {})
r = [{'value': '', 'text': '请选择'}] + list(rows)
return json.dumps(r, ensure_ascii=False)
except Exception as e:
debug(f'get_project_select_options error: {e}')
return json.dumps([{'value': '', 'text': '请选择'}], ensure_ascii=False)

View File

@ -1,12 +0,0 @@
import json
roles = [
{'value': 'agent.pm', 'text': 'PM 项目经理'},
{'value': 'agent.requirement', 'text': '需求分析师'},
{'value': 'agent.design', 'text': '系统设计师'},
{'value': 'agent.develop', 'text': '开发工程师'},
{'value': 'agent.deploy_test', 'text': '测试部署工程师'},
{'value': 'agent.test', 'text': '测试工程师'},
{'value': 'agent.deploy_prod', 'text': '生产部署工程师'},
{'value': 'agent.qc', 'text': 'QC 质量控制'},
]
return json.dumps(roles, ensure_ascii=False)

View File

@ -1,9 +0,0 @@
result = [{'value': '', 'text': '全部'}]
try:
async with get_sor_context(request._run_ns, 'pipeline') as sor:
rows = await sor.sqlExe("select k as value, v as text from appcodes_kv where parentid=${parentid}$ order by v", {'parentid': 'deliverable_type'})
result = [{'value': '', 'text': '全部'}] + list(rows)
return json.dumps(result, ensure_ascii=False)
except Exception as e:
debug(f'search error: {e}')
return json.dumps(result, ensure_ascii=False)

View File

@ -1,9 +0,0 @@
result = [{'value': '', 'text': '全部'}]
try:
async with get_sor_context(request._run_ns, 'pipeline') as sor:
rows = await sor.sqlExe("select k as value, v as text from appcodes_kv where parentid=${parentid}$ order by v", {'parentid': 'sd_project_type'})
result = [{'value': '', 'text': '全部'}] + list(rows)
return json.dumps(result, ensure_ascii=False)
except Exception as e:
debug(f'search error: {e}')
return json.dumps(result, ensure_ascii=False)

View File

@ -1,9 +0,0 @@
result = [{'value': '', 'text': '全部'}]
try:
async with get_sor_context(request._run_ns, 'pipeline') as sor:
rows = await sor.sqlExe("select k as value, v as text from appcodes_kv where parentid=${parentid}$ order by v", {'parentid': 'review_status'})
result = [{'value': '', 'text': '全部'}] + list(rows)
return json.dumps(result, ensure_ascii=False)
except Exception as e:
debug(f'search error: {e}')
return json.dumps(result, ensure_ascii=False)

View File

@ -1,9 +0,0 @@
result = [{'value': '', 'text': '全部'}]
try:
async with get_sor_context(request._run_ns, 'pipeline') as sor:
rows = await sor.sqlExe("select k as value, v as text from appcodes_kv where parentid=${parentid}$ order by v", {'parentid': 'sd_project_status'})
result = [{'value': '', 'text': '全部'}] + list(rows)
return json.dumps(result, ensure_ascii=False)
except Exception as e:
debug(f'search error: {e}')
return json.dumps(result, ensure_ascii=False)

View File

@ -1,26 +0,0 @@
user_id = await get_user()
if not user_id:
return {"widgettype":"Error","options":{"title":"操作失败","message":'未登录',"cwidth":16,"cheight":9,"timeout":3}}
data = {
'id': getID(),
'project_id': params_kw.get('project_id', ''),
'task_id': params_kw.get('task_id', ''),
'title': params_kw.get('title', ''),
'deliverable_type': params_kw.get('deliverable_type', 'code'),
'repo_name': params_kw.get('repo_name', ''),
'target_path': params_kw.get('target_path', ''),
'file_path': params_kw.get('file_path', ''),
'content': params_kw.get('content', ''),
'quality_score': params_kw.get('quality_score', 80),
'review_status': params_kw.get('review_status', 'pending'),
'created_by': user_id,
'created_at': curDateString(),
}
try:
async with get_sor_context(request._run_ns, 'pipeline') as sor:
await sor.C('pipeline_deliverables', data)
return {"widgettype":"Message","options":{"title":"创建成功","message":"ok","cwidth":16,"cheight":9,"timeout":3,"user_data": data}}
except Exception as e:
return {"widgettype":"Error","options":{"title":"操作失败","message":str(e),"cwidth":16,"cheight":9,"timeout":3}}

View File

@ -1,14 +0,0 @@
user_id = await get_user()
if not user_id:
return {"widgettype":"Error","options":{"title":"操作失败","message":'未登录',"cwidth":16,"cheight":9,"timeout":3}}
rec_id = params_kw.get('id', '')
if not rec_id:
return {"widgettype":"Error","options":{"title":"操作失败","message":'缺少id',"cwidth":16,"cheight":9,"timeout":3}}
try:
async with get_sor_context(request._run_ns, 'pipeline') as sor:
await sor.D('pipeline_deliverables', {'id': rec_id})
return {"widgettype":"Message","options":{"title":"操作成功","message":"ok","cwidth":16,"cheight":9,"timeout":3}}
except Exception as e:
return {"widgettype":"Error","options":{"title":"操作失败","message":str(e),"cwidth":16,"cheight":9,"timeout":3}}

View File

@ -1,19 +0,0 @@
user_id = await get_user()
if not user_id:
return {"widgettype":"Error","options":{"title":"操作失败","message":'未登录',"cwidth":16,"cheight":9,"timeout":3}}
rec_id = params_kw.get('id', '')
if not rec_id:
return {"widgettype":"Error","options":{"title":"操作失败","message":'缺少id',"cwidth":16,"cheight":9,"timeout":3}}
data = {'id': rec_id}
for f in ['project_id', 'task_id', 'title', 'deliverable_type', 'repo_name', 'target_path', 'file_path', 'content', 'quality_score', 'review_status', 'review_comment']:
if f in params_kw:
data[f] = params_kw[f]
try:
async with get_sor_context(request._run_ns, 'pipeline') as sor:
await sor.U('pipeline_deliverables', data)
return {"widgettype":"Message","options":{"title":"操作成功","message":"ok","cwidth":16,"cheight":9,"timeout":3}}
except Exception as e:
return {"widgettype":"Error","options":{"title":"操作失败","message":str(e),"cwidth":16,"cheight":9,"timeout":3}}

View File

@ -1,25 +0,0 @@
user_id = await get_user()
if not user_id:
return {"widgettype":"Error","options":{"title":"操作失败","message":'未登录',"cwidth":16,"cheight":9,"timeout":3}}
org_id = (await get_userorgid()) or '0'
data = {
'id': getID(),
'name': params_kw.get('name', ''),
'description': params_kw.get('description', ''),
'project_type': params_kw.get('project_type', ''),
'tech_stack': params_kw.get('tech_stack', ''),
'repo_url': params_kw.get('repo_url', ''),
'pipeline_id': params_kw.get('pipeline_id', '') or 'sdlc_general',
'status': params_kw.get('status', ''),
'org_id': org_id,
'created_by': user_id,
'created_at': curDateString(),
}
try:
async with get_sor_context(request._run_ns, 'pipeline') as sor:
await sor.C('sd_projects', data)
return {"widgettype":"Message","options":{"title":"创建成功","message":"ok","cwidth":16,"cheight":9,"timeout":3},"user_data": data}
except Exception as e:
return {"widgettype":"Error","options":{"title":"操作失败","message":str(e),"cwidth":16,"cheight":9,"timeout":3}}

View File

@ -1,17 +0,0 @@
user_id = await get_user()
if not user_id:
return {"widgettype":"Error","options":{"title":"操作失败","message":'未登录',"cwidth":16,"cheight":9,"timeout":3}}
rec_id = params_kw.get('id', '')
if not rec_id:
return {"widgettype":"Error","options":{"title":"操作失败","message":'缺少id',"cwidth":16,"cheight":9,"timeout":3}}
try:
async with get_sor_context(request._run_ns, 'pipeline') as sor:
ok, emsg = await check_project_owner(rec_id, user_id, sor)
if not ok:
return {"widgettype":"Error","options":{"title":"操作失败","message":emsg,"cwidth":16,"cheight":9,"timeout":3}}
await sor.D('sd_projects', {'id': rec_id})
return {"widgettype":"Message","options":{"title":"操作成功","message":"ok","cwidth":16,"cheight":9,"timeout":3}}
except Exception as e:
return {"widgettype":"Error","options":{"title":"操作失败","message":str(e),"cwidth":16,"cheight":9,"timeout":3}}

View File

@ -1,33 +0,0 @@
user_id = await get_user()
if not user_id:
return {"widgettype":"Error","options":{"title":"操作失败","message":'未登录',"cwidth":16,"cheight":9,"timeout":3}}
rec_id = params_kw.get('id', '')
if not rec_id:
return {"widgettype":"Error","options":{"title":"操作失败","message":'缺少id',"cwidth":16,"cheight":9,"timeout":3}}
data = {'id': rec_id, 'updated_at': curDateString()}
if 'name' in params_kw:
data['name'] = params_kw['name']
if 'description' in params_kw:
data['description'] = params_kw['description']
if 'project_type' in params_kw:
data['project_type'] = params_kw['project_type']
if 'tech_stack' in params_kw:
data['tech_stack'] = params_kw['tech_stack']
if 'repo_url' in params_kw:
data['repo_url'] = params_kw['repo_url']
if 'pipeline_id' in params_kw:
data['pipeline_id'] = params_kw['pipeline_id']
if 'status' in params_kw:
data['status'] = params_kw['status']
try:
async with get_sor_context(request._run_ns, 'pipeline') as sor:
ok, emsg = await check_project_owner(rec_id, user_id, sor)
if not ok:
return {"widgettype":"Error","options":{"title":"操作失败","message":emsg,"cwidth":16,"cheight":9,"timeout":3}}
await sor.U('sd_projects', data)
return {"widgettype":"Message","options":{"title":"操作成功","message":"ok","cwidth":16,"cheight":9,"timeout":3}}
except Exception as e:
return {"widgettype":"Error","options":{"title":"操作失败","message":str(e),"cwidth":16,"cheight":9,"timeout":3}}

View File

@ -1,2 +0,0 @@
#!/bin/bash
~/repos/pipeline-app/py3/bin/xls2ui -m ../models -o ../wwwroot pipeline_sdlc *.json

View File

@ -1,103 +0,0 @@
{
"tblname": "sd_bugs",
"title": "Bug管理",
"params": {
"sortby": [
"created_at desc"
],
"confidential_fields": [],
"browserfields": {
"alters": {
"iteration_id": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_iteration_options.dspy')}}",
"valueField": "value",
"textField": "text"
},
"severity": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_search_severity.dspy')}}",
"valueField": "value",
"textField": "text"
},
"priority": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_search_priority.dspy')}}",
"valueField": "value",
"textField": "text"
},
"status": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_search_bug_status.dspy')}}",
"valueField": "value",
"textField": "text"
},
"reporter_type": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_search_reporter_type.dspy')}}",
"valueField": "value",
"textField": "text"
}
}
},
"editexclouded": [
"id",
"created_at",
"updated_at",
"closed_at",
"verified_by",
"fix_commit"
],
"editable": {
"new_data_url": "{{entire_url('../api/sd_bug_create.dspy')}}",
"update_data_url": "{{entire_url('../api/sd_bug_update.dspy')}}",
"delete_data_url": "{{entire_url('../api/sd_bug_delete.dspy')}}"
},
"data_filter": {
"AND": [
{
"field": "iteration_id",
"op": "=",
"var": "iteration_input"
},
{
"field": "severity",
"op": "=",
"var": "severity_input"
},
{
"field": "status",
"op": "=",
"var": "status_input"
},
{
"field": "title",
"op": "LIKE",
"var": "title_input"
}
]
},
"record_toolbar": [
{
"label": "确认",
"actiontype": "dspy",
"url": "{{entire_url('../api/bug_confirm.dspy')}}",
"options": {
"icon": "check",
"cwidth": 16,
"cheight": 9
}
},
{
"label": "关闭",
"actiontype": "dspy",
"url": "{{entire_url('../api/bug_close.dspy')}}",
"options": {
"icon": "block",
"cwidth": 16,
"cheight": 9
}
}
]
}
}

View File

@ -1,62 +0,0 @@
{
"tblname": "sd_deploy_envs",
"title": "部署环境",
"params": {
"sortby": [
"env_type"
],
"confidential_fields": [
"db_password",
"ssh_key_path"
],
"browserfields": {
"exclouded": [
"db_password",
"ssh_key_path"
],
"alters": {
"project_id": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_project_options.dspy')}}",
"valueField": "value",
"textField": "text"
},
"env_type": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_search_env_type.dspy')}}",
"valueField": "value",
"textField": "text"
},
"status": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_search_env_status.dspy')}}",
"valueField": "value",
"textField": "text"
}
}
},
"editexclouded": [
"id",
"verified_at",
"created_at",
"updated_at"
],
"editable": {
"new_data_url": "{{entire_url('../api/sd_deploy_env_create.dspy')}}",
"update_data_url": "{{entire_url('../api/sd_deploy_env_update.dspy')}}",
"delete_data_url": "{{entire_url('../api/sd_deploy_env_delete.dspy')}}"
},
"record_toolbar": [
{
"label": "验证连接",
"actiontype": "dspy",
"url": "{{entire_url('../api/env_verify.dspy')}}",
"options": {
"icon": "check",
"cwidth": 16,
"cheight": 9
}
}
]
}
}

View File

@ -1,81 +0,0 @@
{
"tblname": "sd_iterations",
"title": "迭代管理",
"params": {
"sortby": [
"created_at desc"
],
"confidential_fields": [],
"browserfields": {
"exclouded": [
"scope"
],
"alters": {
"project_id": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_project_options.dspy')}}",
"valueField": "value",
"textField": "text"
},
"iteration_type": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_search_iteration_type.dspy')}}",
"valueField": "value",
"textField": "text"
},
"status": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_search_iteration_status.dspy')}}",
"valueField": "value",
"textField": "text"
}
}
},
"editexclouded": [
"id",
"task_id",
"started_at",
"completed_at",
"created_at",
"updated_at"
],
"editable": {
"new_data_url": "{{entire_url('../api/sd_iteration_create.dspy')}}",
"update_data_url": "{{entire_url('../api/sd_iteration_update.dspy')}}",
"delete_data_url": "{{entire_url('../api/sd_iteration_delete.dspy')}}"
},
"data_filter": {
"AND": [
{
"field": "project_id",
"op": "=",
"var": "project_input"
},
{
"field": "iteration_name",
"op": "LIKE",
"var": "name_input"
},
{
"field": "status",
"op": "=",
"var": "status_input"
}
]
},
"subtables": [
{
"field": "iteration_id",
"title": "Bug列表",
"url": "{{entire_url('../sd_bug_list?iteration_id=${id}')}}",
"subtable": "sd_bugs"
},
{
"field": "iteration_id",
"title": "测试方案",
"url": "{{entire_url('../sd_test_plan_list?iteration_id=${id}')}}",
"subtable": "sd_test_plans"
}
]
}
}

View File

@ -1,17 +0,0 @@
{
"tblname": "sd_org_settings",
"title": "组织SDLC设置",
"params": {
"sortby": ["created_at desc"],
"logined_userorgid": "org_id",
"browserfields": {
"exclouded": []
},
"editexclouded": ["id", "created_at", "updated_at", "org_id"],
"editable": {
"new_data_url": "{{entire_url('../api/sd_org_setting_create.dspy')}}",
"update_data_url": "{{entire_url('../api/sd_org_setting_update.dspy')}}",
"delete_data_url": "{{entire_url('../api/sd_org_setting_delete.dspy')}}"
}
}
}

View File

@ -1,80 +0,0 @@
{
"tblname": "sd_projects",
"title": "项目管理",
"params": {
"sortby": [
"created_at desc"
],
"logined_userorgid": "org_id",
"confidential_fields": [],
"browserfields": {
"exclouded": [
"tech_stack"
],
"alters": {
"status": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_search_status.dspy')}}",
"valueField": "value",
"textField": "text"
},
"project_type": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_search_project_type.dspy')}}",
"valueField": "value",
"textField": "text"
},
"pipeline_id": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_pipeline_options.dspy')}}",
"valueField": "value",
"textField": "text"
}
}
},
"editexclouded": [
"id",
"created_at",
"updated_at",
"org_id"
],
"editable": {
"new_data_url": "{{entire_url('../api/sd_project_create.dspy')}}",
"update_data_url": "{{entire_url('../api/sd_project_update.dspy')}}",
"delete_data_url": "{{entire_url('../api/sd_project_delete.dspy')}}"
},
"data_filter": {
"AND": [
{
"field": "name",
"op": "LIKE",
"var": "name_input"
},
{
"field": "status",
"op": "=",
"var": "status_input"
},
{
"field": "project_type",
"op": "=",
"var": "type_input"
}
]
},
"subtables": [
{
"field": "project_id",
"title": "迭代列表",
"url": "{{entire_url('../sd_iteration_list?project_id=${id}')}}",
"subtable": "sd_iterations"
},
{
"field": "project_id",
"title": "代码仓库",
"url": "{{entire_url('../sd_project_repo_list?project_id=${id}')}}",
"subtable": "sd_project_repos"
}
]
}
}

View File

@ -1,17 +0,0 @@
{
"tblname": "sd_project_repos",
"title": "代码仓库",
"params": {
"sortby": ["created_at desc"],
"logined_userorgid": "org_id",
"browserfields": {
"exclouded": ["org_id"]
},
"editexclouded": ["id", "created_at", "org_id"],
"editable": {
"new_data_url": "{{entire_url('../api/sd_project_repo_create.dspy')}}",
"update_data_url": "{{entire_url('../api/sd_project_repo_update.dspy')}}",
"delete_data_url": "{{entire_url('../api/sd_project_repo_delete.dspy')}}"
}
}
}

View File

@ -1,76 +0,0 @@
{
"tblname": "sd_test_cases",
"title": "测试用例",
"params": {
"sortby": [
"priority desc",
"created_at desc"
],
"confidential_fields": [],
"browserfields": {
"alters": {
"plan_id": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_test_plan_options.dspy')}}",
"valueField": "value",
"textField": "text"
},
"case_type": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_search_case_type.dspy')}}",
"valueField": "value",
"textField": "text"
},
"status": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_search_case_status.dspy')}}",
"valueField": "value",
"textField": "text"
},
"priority": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_search_priority.dspy')}}",
"valueField": "value",
"textField": "text"
}
}
},
"editexclouded": [
"id",
"actual_result",
"executed_by",
"executed_at",
"duration_ms",
"created_at"
],
"editable": {
"new_data_url": "{{entire_url('../api/sd_test_case_create.dspy')}}",
"update_data_url": "{{entire_url('../api/sd_test_case_update.dspy')}}",
"delete_data_url": "{{entire_url('../api/sd_test_case_delete.dspy')}}"
},
"data_filter": {
"AND": [
{
"field": "plan_id",
"op": "=",
"var": "plan_input"
},
{
"field": "case_type",
"op": "=",
"var": "type_input"
},
{
"field": "status",
"op": "=",
"var": "status_input"
},
{
"field": "priority",
"op": "=",
"var": "priority_input"
}
]
}
}
}

View File

@ -1,50 +0,0 @@
{
"tblname": "sd_test_plans",
"title": "测试方案",
"params": {
"sortby": [
"created_at desc"
],
"confidential_fields": [],
"browserfields": {
"alters": {
"iteration_id": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_iteration_options.dspy')}}",
"valueField": "value",
"textField": "text"
},
"plan_type": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_search_plan_type.dspy')}}",
"valueField": "value",
"textField": "text"
},
"status": {
"uitype": "code",
"dataurl": "{{entire_url('../api/get_search_plan_status.dspy')}}",
"valueField": "value",
"textField": "text"
}
}
},
"editexclouded": [
"id",
"created_at",
"updated_at"
],
"editable": {
"new_data_url": "{{entire_url('../api/sd_test_plan_create.dspy')}}",
"update_data_url": "{{entire_url('../api/sd_test_plan_update.dspy')}}",
"delete_data_url": "{{entire_url('../api/sd_test_plan_delete.dspy')}}"
},
"subtables": [
{
"field": "plan_id",
"title": "测试用例",
"url": "{{entire_url('../sd_test_case_list?plan_id=${id}')}}",
"subtable": "sd_test_cases"
}
]
}
}

View File

@ -1,14 +0,0 @@
{
"widgettype": "VBox",
"options": {"width": "100%", "height": "100%", "padding": "20px", "gap": "16px"},
"subwidgets": [
{
"widgettype": "Text",
"options": {"text": "项目管理 - CRUD List", "cfontsize": 20, "color": "#E0E0E0", "fontWeight": "bold"}
},
{
"widgettype": "Text",
"options": {"text": "Generated by xls2crud - This page will be auto-generated from the sd_project_list table definition", "cfontsize": 14, "color": "#888888"}
}
]
}

View File

@ -1,69 +0,0 @@
ns = params_kw.copy()
for k,v in ns.items():
if v == 'NaN' or v == 'null' or v == '':
ns[k] = None
id = params_kw.id
if not id or len(id) > 32:
id = uuid()
ns['id'] = id
# 会话当前项目强制autoproject_id 用当前项目,忽略前端传值
_uid = await get_user()
if not _uid:
_uid = 'user-01'
_dbname = get_module_dbname('pipeline_sdlc')
async with DBPools().sqlorContext(_dbname) as _sor:
_prec = await _sor.sqlExe("SELECT current_project_id FROM pipeline_agent_settings WHERE user_id=${u}$", {"u": _uid})
await _sor.sqlExe("COMMIT", {})
_cur_pid = getattr(_prec[0], 'current_project_id', '') if _prec else ''
if not _cur_pid:
return {"widgettype":"Error","options":{"title":"错误","timeout":3,"cwidth":20,"cheight":9,"message":"请先在会话中切换项目"}}
ns['project_id'] = _cur_pid
if not ns.get('role'):
return {"widgettype":"Error","options":{"title":"Error","timeout":3,"cwidth":16,"cheight":9,"message":"需要 role"}}
userorgid = await get_userorgid()
if not userorgid:
return {
"widgettype":"Error",
"options":{
"title":"Authorization Error",
"timeout":3,
"cwidth":16,
"cheight":9,
"message":"Please login"
}
}
db = DBPools()
dbname = get_module_dbname('pipeline_sdlc')
async with db.sqlorContext(dbname) as sor:
# 已存在则更新upsert by project_id+role
r = await sor.sqlExe("select id from sd_project_role_models where project_id=${pid}$ and role=${role}$", {"pid": ns['project_id'], "role": ns['role']})
if r:
await sor.sqlExe("update sd_project_role_models set model_name=${m}$ where id=${id}$", {"m": ns.get('model_name'), "id": r[0].id})
else:
await sor.C('sd_project_role_models', ns.copy())
return {
"widgettype":"Message",
"options":{
"cwidth":16,
"cheight":9,
"title":"Add Success",
"timeout":3,
"message":"ok"
}
}
return {
"widgettype":"Error",
"options":{
"title":"Add Error",
"cwidth":16,
"cheight":9,
"timeout":3,
"message":"failed"
}
}

View File

@ -1,44 +0,0 @@
ns = params_kw.copy()
id = params_kw.id
if not id:
return {"widgettype":"Error","options":{"title":"Error","timeout":3,"cwidth":16,"cheight":9,"message":"需要 id"}}
userorgid = await get_userorgid()
if not userorgid:
return {
"widgettype":"Error",
"options":{
"title":"Authorization Error",
"timeout":3,
"cwidth":16,
"cheight":9,
"message":"Please login"
}
}
db = DBPools()
dbname = get_module_dbname('pipeline_sdlc')
async with db.sqlorContext(dbname) as sor:
await sor.D('sd_project_role_models', {'id': id})
return {
"widgettype":"Message",
"options":{
"cwidth":16,
"cheight":9,
"title":"Delete Success",
"timeout":3,
"message":"ok"
}
}
return {
"widgettype":"Error",
"options":{
"title":"Delete Error",
"cwidth":16,
"cheight":9,
"timeout":3,
"message":"failed"
}
}

View File

@ -1,87 +0,0 @@
ns = params_kw.copy()
# 会话当前项目强制过滤auto读 current_project_id无项目报错
_uid = await get_user()
if not _uid:
_uid = 'user-01'
_cur_pid = ''
_dbname = get_module_dbname('pipeline_sdlc')
async with DBPools().sqlorContext(_dbname) as _sor:
_prec = await _sor.sqlExe(
"SELECT current_project_id FROM pipeline_agent_settings WHERE user_id=${u}$",
{"u": _uid})
await _sor.sqlExe("COMMIT", {})
_cur_pid = getattr(_prec[0], 'current_project_id', '') if _prec else ''
if not _cur_pid:
return {"widgettype":"Error","options":{"title":"错误","timeout":3,"cwidth":20,"cheight":9,"message":"请先在会话中切换项目"}}
ns['_cur_pid'] = _cur_pid
userorgid = await get_userorgid()
if not userorgid:
return {
"widgettype":"Error",
"options":{
"title":"Authorization Error",
"timeout":3,
"cwidth":16,
"cheight":9,
"message":"Please login"
}
}
debug(f'get_sd_project_role_models.dspy:{ns=}')
if not ns.get('page'):
ns['page'] = 1
if not ns.get('sort'):
ns['sort'] = ["role asc"]
sql = '''select a.*, b.name as project_name,
case a.role
when 'agent.pm' then 'PM 项目经理'
when 'agent.requirement' then '需求分析师'
when 'agent.design' then '系统设计师'
when 'agent.develop' then '开发工程师'
when 'agent.deploy_test' then '测试部署工程师'
when 'agent.test' then '测试工程师'
when 'agent.deploy_prod' then '生产部署工程师'
when 'agent.qc' then 'QC 质量控制'
else a.role end as role_text
from (select * from sd_project_role_models where project_id = ${_cur_pid}$ [[filterstr]]) a
left join sd_projects b on a.project_id = b.id'''
filterjson = params_kw.get('data_filter')
if filterjson and isinstance(filterjson, str):
try:
filterjson = json.loads(filterjson)
except (json.JSONDecodeError, TypeError):
filterjson = None
if filterjson:
filterdic = ns.copy()
filterdic['filterstr'] = ''
dbf = DBFilter(filterjson)
conds = dbf.gen(ns)
if conds:
ns.update(dbf.consts)
conds = f' and {conds}'
filterdic['filterstr'] = conds
ac = ArgsConvert('[[', ']]')
vars = ac.findAllVariables(sql)
NameSpace = {v:'${' + v + '}$' for v in vars if v != 'filterstr'}
filterdic.update(NameSpace)
sql = ac.convert(sql, filterdic)
else:
ac = ArgsConvert('[[', ']]')
sql = ac.convert(sql, {'filterstr': ''})
debug(f'{sql=}')
db = DBPools()
dbname = get_module_dbname('pipeline_sdlc')
async with db.sqlorContext(dbname) as sor:
r = await sor.sqlPaging(sql, ns)
return r
return {
"total":0,
"rows":[]
}

View File

@ -1,66 +0,0 @@
{
"widgettype":"VBox",
"options":{"cheight":40,"width":"100%"},
"subwidgets":[{
"id":"sd_project_role_models_tbl",
"widgettype":"Tabular",
"options":{
"width":"100%",
"height":"100%",
"title":"项目角色模型配置",
"css":"card",
"editable":{
"new_data_url":"{{entire_url('add_sd_project_role_models.dspy')}}",
"delete_data_url":"{{entire_url('delete_sd_project_role_models.dspy')}}",
"update_data_url":"{{entire_url('update_sd_project_role_models.dspy')}}"
},
"data_url":"{{entire_url('./get_sd_project_role_models.dspy')}}",
"data_method":"GET",
"data_params":{{json.dumps(params_kw, indent=4, ensure_ascii=False)}},
"row_options":{
"browserfields":{
"alters":{
"project_id":{
"uitype":"code",
"dataurl":"{{entire_url('../api/get_project_select_options.dspy')}}",
"valueField":"value",
"textField":"text"
},
"role":{
"uitype":"code",
"dataurl":"{{entire_url('../api/get_role_options.dspy')}}",
"valueField":"value",
"textField":"text"
},
"model_name":{
"uitype":"code",
"dataurl":"{{entire_url('../api/get_model_options.dspy')}}",
"valueField":"value",
"textField":"text"
}
}
},
"editexclouded":["id","created_at","updated_at","project_name","role_text"],
"fields":[
{"name":"id","title":"主键ID","type":"str","length":32,"cwidth":18,"uitype":"str","datatype":"str","label":"主键ID"},
{"name":"project_name","title":"项目","type":"str","length":200,"cwidth":22,"uitype":"str","datatype":"str","label":"项目"},
{"name":"project_id","title":"项目ID","type":"str","length":32,"cwidth":0,"uitype":"code","valueField":"value","textField":"text","dataurl":"{{entire_url('../api/get_project_select_options.dspy')}}","label":"项目ID"},
{"name":"role_text","title":"角色","type":"str","length":64,"cwidth":20,"uitype":"str","datatype":"str","label":"角色"},
{"name":"role","title":"角色名","type":"str","length":64,"cwidth":0,"uitype":"code","valueField":"value","textField":"text","dataurl":"{{entire_url('../api/get_role_options.dspy')}}","label":"角色名"},
{"name":"model_name","title":"模型","type":"str","length":128,"cwidth":20,"uitype":"code","valueField":"value","textField":"text","dataurl":"{{entire_url('../api/get_model_options.dspy')}}","label":"模型(空=缺省)"},
{"name":"created_at","title":"创建时间","type":"timestamp","uitype":"str","datatype":"timestamp","label":"创建时间"},
{"name":"updated_at","title":"更新时间","type":"timestamp","uitype":"str","datatype":"timestamp","label":"更新时间"}
]
},
"data_filter":{
"AND":[
{"field":"role","op":"LIKE","var":"role_input"},
{"field":"project_id","op":"=","var":"project_id_input"}
]
},
"page_rows":100,
"cache_limit":5
}
}]
}

View File

@ -1,60 +0,0 @@
ns = params_kw.copy()
for k,v in ns.items():
if v == 'NaN' or v == 'null' or v == '':
ns[k] = None
id = params_kw.id
if not id:
return {"widgettype":"Error","options":{"title":"Error","timeout":3,"cwidth":16,"cheight":9,"message":"需要 id"}}
# 会话当前项目强制autoproject_id 用当前项目,忽略前端传值
_uid = await get_user()
if not _uid:
_uid = 'user-01'
_dbname = get_module_dbname('pipeline_sdlc')
async with DBPools().sqlorContext(_dbname) as _sor:
_prec = await _sor.sqlExe("SELECT current_project_id FROM pipeline_agent_settings WHERE user_id=${u}$", {"u": _uid})
await _sor.sqlExe("COMMIT", {})
_cur_pid = getattr(_prec[0], 'current_project_id', '') if _prec else ''
if not _cur_pid:
return {"widgettype":"Error","options":{"title":"错误","timeout":3,"cwidth":20,"cheight":9,"message":"请先在会话中切换项目"}}
ns['project_id'] = _cur_pid
userorgid = await get_userorgid()
if not userorgid:
return {
"widgettype":"Error",
"options":{
"title":"Authorization Error",
"timeout":3,
"cwidth":16,
"cheight":9,
"message":"Please login"
}
}
db = DBPools()
dbname = get_module_dbname('pipeline_sdlc')
async with db.sqlorContext(dbname) as sor:
await sor.U('sd_project_role_models', ns.copy())
return {
"widgettype":"Message",
"options":{
"cwidth":16,
"cheight":9,
"title":"Update Success",
"timeout":3,
"message":"ok"
}
}
return {
"widgettype":"Error",
"options":{
"title":"Update Error",
"cwidth":16,
"cheight":9,
"timeout":3,
"message":"failed"
}
}