From d9a1903d7a4233cc55962f01aef364876f19e08c Mon Sep 17 00:00:00 2001 From: yumoqing Date: Thu, 11 Jun 2026 14:46:43 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20pipeline-app=E7=8B=AC=E7=AB=8B=E4=BA=A7?= =?UTF-8?q?=E7=BA=BF=E5=90=8E=E7=AB=AF=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 3个业务模块: - pipeline_core: 产线定义(pipelines/steps/versions) - pipeline_ops: 运营(定价/供应量/使用记录) - pipeline_dist: 分销(分销商/独立定价/API密钥) - ahserver独立部署(端口9090) - 独立数据库pipeline - 80个文件, 符合module/db-table/crud三规范 --- init/data.json | 24 ++ json/pipeline_steps.json | 27 +++ json/pipeline_versions.json | 27 +++ json/pipelines.json | 21 ++ models/pipeline_steps.json | 110 +++++++++ models/pipeline_versions.json | 85 +++++++ models/pipelines.json | 126 ++++++++++ pipeline_core/__init__.py | 14 ++ pipeline_core/init.py | 279 ++++++++++++++++++++++ pyproject.toml | 8 + scripts/load_path.py | 89 +++++++ wwwroot/api/pipeline_publish.dspy | 5 + wwwroot/api/pipeline_steps_create.dspy | 5 + wwwroot/api/pipeline_steps_delete.dspy | 5 + wwwroot/api/pipeline_steps_update.dspy | 5 + wwwroot/api/pipeline_versions_create.dspy | 5 + wwwroot/api/pipeline_versions_delete.dspy | 5 + wwwroot/api/pipeline_versions_update.dspy | 5 + wwwroot/api/pipelines_create.dspy | 5 + wwwroot/api/pipelines_delete.dspy | 5 + wwwroot/api/pipelines_update.dspy | 5 + wwwroot/index.ui | 201 ++++++++++++++++ 22 files changed, 1061 insertions(+) create mode 100644 init/data.json create mode 100644 json/pipeline_steps.json create mode 100644 json/pipeline_versions.json create mode 100644 json/pipelines.json create mode 100644 models/pipeline_steps.json create mode 100644 models/pipeline_versions.json create mode 100644 models/pipelines.json create mode 100644 pipeline_core/__init__.py create mode 100644 pipeline_core/init.py create mode 100644 pyproject.toml create mode 100644 scripts/load_path.py create mode 100644 wwwroot/api/pipeline_publish.dspy create mode 100644 wwwroot/api/pipeline_steps_create.dspy create mode 100644 wwwroot/api/pipeline_steps_delete.dspy create mode 100644 wwwroot/api/pipeline_steps_update.dspy create mode 100644 wwwroot/api/pipeline_versions_create.dspy create mode 100644 wwwroot/api/pipeline_versions_delete.dspy create mode 100644 wwwroot/api/pipeline_versions_update.dspy create mode 100644 wwwroot/api/pipelines_create.dspy create mode 100644 wwwroot/api/pipelines_delete.dspy create mode 100644 wwwroot/api/pipelines_update.dspy create mode 100644 wwwroot/index.ui diff --git a/init/data.json b/init/data.json new file mode 100644 index 0000000..2f01ed4 --- /dev/null +++ b/init/data.json @@ -0,0 +1,24 @@ +{ + "appcodes": [ + { + "parentid": "pipeline_type", + "parentname": "产线类型", + "items": [ + {"k": "text", "v": "文本"}, + {"k": "audio", "v": "音频"}, + {"k": "video", "v": "视频"}, + {"k": "image", "v": "图片"}, + {"k": "multimodal", "v": "多模态"} + ] + }, + { + "parentid": "pipeline_status", + "parentname": "产线状态", + "items": [ + {"k": "draft", "v": "草稿"}, + {"k": "published", "v": "已发布"}, + {"k": "archived", "v": "已归档"} + ] + } + ] +} diff --git a/json/pipeline_steps.json b/json/pipeline_steps.json new file mode 100644 index 0000000..253b6fa --- /dev/null +++ b/json/pipeline_steps.json @@ -0,0 +1,27 @@ +{ + "tblname": "pipeline_steps", + "title": "产线步骤", + "params": { + "sortby": "step_order", + "browserfields": { + "exclouded": ["id", "step_config", "input_schema", "output_schema"], + "cwidth": {} + }, + "editexclouded": [ + "id", "created_at" + ], + "editable": { + "new_data_url": "{{entire_url('../api/pipeline_steps_create.dspy')}}", + "update_data_url": "{{entire_url('../api/pipeline_steps_update.dspy')}}", + "delete_data_url": "{{entire_url('../api/pipeline_steps_delete.dspy')}}" + }, + "confidential_fields": [], + "subtables": [ + { + "field": "pipeline_id", + "title": "所属产线", + "subtable": "pipelines" + } + ] + } +} diff --git a/json/pipeline_versions.json b/json/pipeline_versions.json new file mode 100644 index 0000000..965d81a --- /dev/null +++ b/json/pipeline_versions.json @@ -0,0 +1,27 @@ +{ + "tblname": "pipeline_versions", + "title": "发布记录", + "params": { + "sortby": "created_at", + "browserfields": { + "exclouded": ["id", "config_snapshot"], + "cwidth": {} + }, + "editexclouded": [ + "id", "created_at" + ], + "editable": { + "new_data_url": "{{entire_url('../api/pipeline_versions_create.dspy')}}", + "update_data_url": "{{entire_url('../api/pipeline_versions_update.dspy')}}", + "delete_data_url": "{{entire_url('../api/pipeline_versions_delete.dspy')}}" + }, + "confidential_fields": [], + "subtables": [ + { + "field": "pipeline_id", + "title": "所属产线", + "subtable": "pipelines" + } + ] + } +} diff --git a/json/pipelines.json b/json/pipelines.json new file mode 100644 index 0000000..7bae2bd --- /dev/null +++ b/json/pipelines.json @@ -0,0 +1,21 @@ +{ + "tblname": "pipelines", + "title": "产线定义", + "params": { + "sortby": "created_at", + "logined_userorgid": "org_id", + "browserfields": { + "exclouded": ["id", "model_api_key", "pipeline_config"], + "cwidth": {} + }, + "editexclouded": [ + "id", "created_at", "updated_at" + ], + "editable": { + "new_data_url": "{{entire_url('../api/pipelines_create.dspy')}}", + "update_data_url": "{{entire_url('../api/pipelines_update.dspy')}}", + "delete_data_url": "{{entire_url('../api/pipelines_delete.dspy')}}" + }, + "confidential_fields": ["model_api_key"] + } +} diff --git a/models/pipeline_steps.json b/models/pipeline_steps.json new file mode 100644 index 0000000..7eb96ea --- /dev/null +++ b/models/pipeline_steps.json @@ -0,0 +1,110 @@ +{ + "summary": [ + { + "name": "pipeline_steps", + "title": "产线步骤表", + "primary": [ + "id" + ] + } + ], + "fields": [ + { + "name": "id", + "title": "id", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "pipeline_id", + "title": "所属产线", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "step_order", + "title": "步骤序号", + "type": "int", + "nullable": "no" + }, + { + "name": "step_name", + "title": "步骤名称", + "type": "str", + "length": 100, + "nullable": "no" + }, + { + "name": "step_type", + "title": "步骤类型", + "type": "str", + "length": 50, + "nullable": "no" + }, + { + "name": "model_name", + "title": "调用模型名称", + "type": "str", + "length": 100 + }, + { + "name": "step_config", + "title": "步骤配置JSON", + "type": "text" + }, + { + "name": "input_schema", + "title": "输入定义JSON", + "type": "text" + }, + { + "name": "output_schema", + "title": "输出定义JSON", + "type": "text" + }, + { + "name": "timeout_seconds", + "title": "超时秒数", + "type": "int", + "default": "300" + }, + { + "name": "retry_count", + "title": "重试次数", + "type": "int", + "default": "0" + }, + { + "name": "created_at", + "title": "创建时间", + "type": "timestamp" + } + ], + "indexes": [ + { + "name": "idx_steps_pipeline", + "idxtype": "index", + "idxfields": [ + "pipeline_id" + ] + }, + { + "name": "idx_steps_order", + "idxtype": "unique", + "idxfields": [ + "pipeline_id", + "step_order" + ] + } + ], + "codes": [ + { + "field": "pipeline_id", + "table": "pipelines", + "valuefield": "id", + "textfield": "name" + } + ] +} diff --git a/models/pipeline_versions.json b/models/pipeline_versions.json new file mode 100644 index 0000000..d524263 --- /dev/null +++ b/models/pipeline_versions.json @@ -0,0 +1,85 @@ +{ + "summary": [ + { + "name": "pipeline_versions", + "title": "产线发布记录表", + "primary": [ + "id" + ] + } + ], + "fields": [ + { + "name": "id", + "title": "id", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "pipeline_id", + "title": "产线ID", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "version", + "title": "版本号", + "type": "str", + "length": 20, + "nullable": "no" + }, + { + "name": "publish_status", + "title": "发布状态", + "type": "str", + "length": 20, + "nullable": "no", + "default": "pending" + }, + { + "name": "published_by", + "title": "发布人", + "type": "str", + "length": 32 + }, + { + "name": "published_at", + "title": "发布时间", + "type": "timestamp" + }, + { + "name": "changelog", + "title": "变更说明", + "type": "text" + }, + { + "name": "config_snapshot", + "title": "配置快照JSON", + "type": "text" + }, + { + "name": "created_at", + "title": "创建时间", + "type": "timestamp" + } + ], + "indexes": [ + { + "name": "idx_versions_pipeline", + "idxtype": "index", + "idxfields": [ + "pipeline_id" + ] + } + ], + "codes": [ + { + "field": "pipeline_id", + "table": "pipelines", + "valuefield": "id", + "textfield": "name" + } + ] +} diff --git a/models/pipelines.json b/models/pipelines.json new file mode 100644 index 0000000..5b6e24b --- /dev/null +++ b/models/pipelines.json @@ -0,0 +1,126 @@ +{ + "summary": [ + { + "name": "pipelines", + "title": "产线定义表", + "primary": [ + "id" + ] + } + ], + "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": "pipeline_type", + "title": "产线类型", + "type": "str", + "length": 50, + "nullable": "no" + }, + { + "name": "version", + "title": "当前版本", + "type": "str", + "length": 20, + "default": "1.0.0" + }, + { + "name": "status", + "title": "状态", + "type": "str", + "length": 20, + "nullable": "no", + "default": "draft" + }, + { + "name": "pipeline_config", + "title": "产线配置JSON", + "type": "text" + }, + { + "name": "model_api_url", + "title": "模型API地址", + "type": "str", + "length": 500 + }, + { + "name": "model_api_key", + "title": "模型API密钥", + "type": "str", + "length": 500 + }, + { + "name": "org_id", + "title": "所属机构ID", + "type": "str", + "length": 32, + "default": "0" + }, + { + "name": "created_by", + "title": "创建人", + "type": "str", + "length": 32 + }, + { + "name": "created_at", + "title": "创建时间", + "type": "timestamp" + }, + { + "name": "updated_at", + "title": "更新时间", + "type": "timestamp" + } + ], + "indexes": [ + { + "name": "idx_pipelines_name", + "idxtype": "index", + "idxfields": [ + "name" + ] + }, + { + "name": "idx_pipelines_status", + "idxtype": "index", + "idxfields": [ + "status" + ] + } + ], + "codes": [ + { + "field": "pipeline_type", + "table": "appcodes_kv", + "valuefield": "k", + "textfield": "v", + "cond": "id='pipeline_type'" + }, + { + "field": "status", + "table": "appcodes_kv", + "valuefield": "k", + "textfield": "v", + "cond": "id='pipeline_status'" + } + ] +} diff --git a/pipeline_core/__init__.py b/pipeline_core/__init__.py new file mode 100644 index 0000000..34a9d89 --- /dev/null +++ b/pipeline_core/__init__.py @@ -0,0 +1,14 @@ +# pipeline_core/__init__.py +from .init import ( + create_pipeline, + update_pipeline, + delete_pipeline, + create_pipeline_step, + update_pipeline_step, + delete_pipeline_step, + create_pipeline_version, + update_pipeline_version, + delete_pipeline_version, + publish_pipeline, + load_pipeline_core, +) diff --git a/pipeline_core/init.py b/pipeline_core/init.py new file mode 100644 index 0000000..3bbfb57 --- /dev/null +++ b/pipeline_core/init.py @@ -0,0 +1,279 @@ +"""pipeline_core 模块 - 产线管理核心模块""" +import json +from appPublic.uniqueID import getID +from sqlor.dbpools import DBPools +from ahserver.serverenv import ServerEnv +from appPublic.log import debug + + +MODULE_NAME = 'pipeline_core' +DBNAME = 'pipeline' + + +def _get_sor(): + """Get database pool and dbname for pipeline_core module.""" + return DBPools(), DBNAME + + +async def create_pipeline(params_kw): + """创建产线记录""" + result = {'success': False, 'message': ''} + try: + db, dbname = _get_sor() + async with db.sqlorContext(dbname) as sor: + data = params_kw.copy() + data.pop('page', None) + data.pop('rows', None) + data.pop('data_filter', None) + data['id'] = getID() + await sor.C('pipelines', data) + result['success'] = True + result['message'] = '创建成功' + result['id'] = data['id'] + except Exception as e: + result['message'] = str(e) + return json.dumps(result, ensure_ascii=False, default=str) + + +async def update_pipeline(params_kw): + """更新产线记录""" + result = {'success': False, 'message': ''} + try: + db, dbname = _get_sor() + async with db.sqlorContext(dbname) as sor: + data = params_kw.copy() + data.pop('page', None) + data.pop('rows', None) + data.pop('data_filter', None) + record_id = data.pop('id', None) + if not record_id: + result['message'] = '缺少id' + else: + await sor.U('pipelines', data, {'id': record_id}) + result['success'] = True + result['message'] = '更新成功' + except Exception as e: + result['message'] = str(e) + return json.dumps(result, ensure_ascii=False, default=str) + + +async def delete_pipeline(params_kw): + """删除产线记录""" + result = {'success': False, 'message': ''} + try: + db, dbname = _get_sor() + async with db.sqlorContext(dbname) as sor: + record_id = params_kw.get('id') + if not record_id: + result['message'] = '缺少id' + else: + await sor.D('pipelines', {'id': record_id}) + result['success'] = True + result['message'] = '删除成功' + except Exception as e: + result['message'] = str(e) + return json.dumps(result, ensure_ascii=False, default=str) + + +async def create_pipeline_step(params_kw): + """创建产线步骤""" + result = {'success': False, 'message': ''} + try: + db, dbname = _get_sor() + async with db.sqlorContext(dbname) as sor: + data = params_kw.copy() + data.pop('page', None) + data.pop('rows', None) + data.pop('data_filter', None) + data['id'] = getID() + await sor.C('pipeline_steps', data) + result['success'] = True + result['message'] = '创建成功' + result['id'] = data['id'] + except Exception as e: + result['message'] = str(e) + return json.dumps(result, ensure_ascii=False, default=str) + + +async def update_pipeline_step(params_kw): + """更新产线步骤""" + result = {'success': False, 'message': ''} + try: + db, dbname = _get_sor() + async with db.sqlorContext(dbname) as sor: + data = params_kw.copy() + data.pop('page', None) + data.pop('rows', None) + data.pop('data_filter', None) + record_id = data.pop('id', None) + if not record_id: + result['message'] = '缺少id' + else: + await sor.U('pipeline_steps', data, {'id': record_id}) + result['success'] = True + result['message'] = '更新成功' + except Exception as e: + result['message'] = str(e) + return json.dumps(result, ensure_ascii=False, default=str) + + +async def delete_pipeline_step(params_kw): + """删除产线步骤""" + result = {'success': False, 'message': ''} + try: + db, dbname = _get_sor() + async with db.sqlorContext(dbname) as sor: + record_id = params_kw.get('id') + if not record_id: + result['message'] = '缺少id' + else: + await sor.D('pipeline_steps', {'id': record_id}) + result['success'] = True + result['message'] = '删除成功' + except Exception as e: + result['message'] = str(e) + return json.dumps(result, ensure_ascii=False, default=str) + + +async def create_pipeline_version(params_kw): + """创建产线发布记录""" + result = {'success': False, 'message': ''} + try: + db, dbname = _get_sor() + async with db.sqlorContext(dbname) as sor: + data = params_kw.copy() + data.pop('page', None) + data.pop('rows', None) + data.pop('data_filter', None) + data['id'] = getID() + await sor.C('pipeline_versions', data) + result['success'] = True + result['message'] = '创建成功' + result['id'] = data['id'] + except Exception as e: + result['message'] = str(e) + return json.dumps(result, ensure_ascii=False, default=str) + + +async def update_pipeline_version(params_kw): + """更新产线发布记录""" + result = {'success': False, 'message': ''} + try: + db, dbname = _get_sor() + async with db.sqlorContext(dbname) as sor: + data = params_kw.copy() + data.pop('page', None) + data.pop('rows', None) + data.pop('data_filter', None) + record_id = data.pop('id', None) + if not record_id: + result['message'] = '缺少id' + else: + await sor.U('pipeline_versions', data, {'id': record_id}) + result['success'] = True + result['message'] = '更新成功' + except Exception as e: + result['message'] = str(e) + return json.dumps(result, ensure_ascii=False, default=str) + + +async def delete_pipeline_version(params_kw): + """删除产线发布记录""" + result = {'success': False, 'message': ''} + try: + db, dbname = _get_sor() + async with db.sqlorContext(dbname) as sor: + record_id = params_kw.get('id') + if not record_id: + result['message'] = '缺少id' + else: + await sor.D('pipeline_versions', {'id': record_id}) + result['success'] = True + result['message'] = '删除成功' + except Exception as e: + result['message'] = str(e) + return json.dumps(result, ensure_ascii=False, default=str) + + +async def publish_pipeline(params_kw): + """发布产线 - 创建发布记录并更新产线状态""" + result = {'success': False, 'message': ''} + try: + pipeline_id = params_kw.get('pipeline_id') + if not pipeline_id: + result['message'] = '缺少pipeline_id' + return json.dumps(result, ensure_ascii=False, default=str) + + changelog = params_kw.get('changelog', '') + published_by = params_kw.get('published_by', '') + + db, dbname = _get_sor() + async with db.sqlorContext(dbname) as sor: + # Get current pipeline + recs = await sor.R('pipelines', {'id': pipeline_id}) + if not recs: + result['message'] = f'产线不存在: {pipeline_id}' + return json.dumps(result, ensure_ascii=False, default=str) + + pipeline = recs[0] + current_version = pipeline.get('version', '1.0.0') if hasattr(pipeline, 'get') else getattr(pipeline, 'version', '1.0.0') + + # Build config snapshot from current pipeline data + config_snapshot = json.dumps({ + 'pipeline_config': getattr(pipeline, 'pipeline_config', None), + 'model_api_url': getattr(pipeline, 'model_api_url', None), + 'version': current_version, + }, ensure_ascii=False, default=str) + + # Create version record + version_id = getID() + version_data = { + 'id': version_id, + 'pipeline_id': pipeline_id, + 'version': current_version, + 'publish_status': 'published', + 'published_by': published_by, + 'changelog': changelog, + 'config_snapshot': config_snapshot, + } + await sor.C('pipeline_versions', version_data) + + # Update pipeline status to published + await sor.U('pipelines', {'status': 'published'}, {'id': pipeline_id}) + + result['success'] = True + result['message'] = '发布成功' + result['version_id'] = version_id + except Exception as e: + result['message'] = str(e) + return json.dumps(result, ensure_ascii=False, default=str) + + +def load_pipeline_core(): + """注册函数到 ServerEnv""" + env = ServerEnv() + # Pipelines + env.create_pipeline = create_pipeline + env.create_pipelines = create_pipeline + env.update_pipeline = update_pipeline + env.update_pipelines = update_pipeline + env.delete_pipeline = delete_pipeline + env.delete_pipelines = delete_pipeline + # Pipeline Steps + env.create_pipeline_step = create_pipeline_step + env.create_pipeline_steps = create_pipeline_step + env.update_pipeline_step = update_pipeline_step + env.update_pipeline_steps = update_pipeline_step + env.delete_pipeline_step = delete_pipeline_step + env.delete_pipeline_steps = delete_pipeline_step + # Pipeline Versions + env.create_pipeline_version = create_pipeline_version + env.create_pipeline_versions = create_pipeline_version + env.update_pipeline_version = update_pipeline_version + env.update_pipeline_versions = update_pipeline_version + env.delete_pipeline_version = delete_pipeline_version + env.delete_pipeline_versions = delete_pipeline_version + # Publish + env.publish_pipeline = publish_pipeline + debug(f'[{MODULE_NAME}] module loaded') + return True diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..8654564 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,8 @@ +[project] +name = "pipeline_core" +version = "0.1.0" +description = "产线管理核心模块 - 产线定义、步骤配置与发布管理" +dependencies = [ + "sqlor", + "bricks_for_python", +] diff --git a/scripts/load_path.py b/scripts/load_path.py new file mode 100644 index 0000000..72aa88c --- /dev/null +++ b/scripts/load_path.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +""" +pipeline_core 模块 RBAC 权限管理脚本 + +使用方法: + cd ~/repos/sage + ./py3/bin/python ~/test/pipeline-app/pipeline_core/scripts/load_path.py +""" + +import subprocess +import os +import sys + + +def find_sage_root(): + candidates = [ + os.path.expanduser("~/repos/sage"), + os.path.expanduser("~/sage"), + ] + for c in candidates: + if os.path.isdir(os.path.join(c, "py3")) and os.path.isdir(os.path.join(c, "wwwroot")): + return c + return None + + +SAGE_ROOT = find_sage_root() +if not SAGE_ROOT: + print("ERROR: Cannot find Sage root directory") + sys.exit(1) + +PYTHON = os.path.join(SAGE_ROOT, "py3", "bin", "python") +SET_PERM_SCRIPT = os.path.join(SAGE_ROOT, "set_role_perm.py") + +MOD = "pipeline_core" + +# ============================================================ +# 权限路径定义 +# ============================================================ + +# operator — 产线管理人员 +PATHS_OPERATOR = [ + f"/{MOD}", + f"/{MOD}/index.ui", + f"/{MOD}/pipelines/", + f"/{MOD}/pipeline_steps/", + f"/{MOD}/pipeline_versions/", + f"/{MOD}/api/pipelines_create.dspy", + f"/{MOD}/api/pipelines_update.dspy", + f"/{MOD}/api/pipelines_delete.dspy", + f"/{MOD}/api/pipeline_steps_create.dspy", + f"/{MOD}/api/pipeline_steps_update.dspy", + f"/{MOD}/api/pipeline_steps_delete.dspy", + f"/{MOD}/api/pipeline_versions_create.dspy", + f"/{MOD}/api/pipeline_versions_update.dspy", + f"/{MOD}/api/pipeline_versions_delete.dspy", + f"/{MOD}/api/pipeline_publish.dspy", +] + +# developer — 开发者(包含所有 operator 路径) +PATHS_DEVELOPER = PATHS_OPERATOR[:] + + +def run_set_perm(role, path): + cmd = [PYTHON, SET_PERM_SCRIPT, role, path] + result = subprocess.run(cmd, capture_output=True, text=True) + return result.returncode == 0 + + +def register_role_paths(role, paths): + count = 0 + for p in paths: + if run_set_perm(role, p): + count += 1 + print(f" {role}: {count}/{len(paths)} paths registered") + return count + + +def main(): + print(f"Sage root: {SAGE_ROOT}") + print("Registering pipeline_core module RBAC permissions...") + total = 0 + total += register_role_paths("operator", PATHS_OPERATOR) + total += register_role_paths("developer", PATHS_DEVELOPER) + print(f"\nDone. Total {total} permission entries registered.") + print("NOTE: Restart Sage after permission changes to reload RBAC cache.") + + +if __name__ == "__main__": + main() diff --git a/wwwroot/api/pipeline_publish.dspy b/wwwroot/api/pipeline_publish.dspy new file mode 100644 index 0000000..7e4afaa --- /dev/null +++ b/wwwroot/api/pipeline_publish.dspy @@ -0,0 +1,5 @@ +func = publish_pipeline +if func is None: + return json.dumps({'status': 'error', 'message': 'function not found'}) +result = await func(params_kw) +return result diff --git a/wwwroot/api/pipeline_steps_create.dspy b/wwwroot/api/pipeline_steps_create.dspy new file mode 100644 index 0000000..851c278 --- /dev/null +++ b/wwwroot/api/pipeline_steps_create.dspy @@ -0,0 +1,5 @@ +func = create_pipeline_step +if func is None: + return json.dumps({'status': 'error', 'message': 'function not found'}) +result = await func(params_kw) +return result diff --git a/wwwroot/api/pipeline_steps_delete.dspy b/wwwroot/api/pipeline_steps_delete.dspy new file mode 100644 index 0000000..d73053c --- /dev/null +++ b/wwwroot/api/pipeline_steps_delete.dspy @@ -0,0 +1,5 @@ +func = delete_pipeline_step +if func is None: + return json.dumps({'status': 'error', 'message': 'function not found'}) +result = await func(params_kw) +return result diff --git a/wwwroot/api/pipeline_steps_update.dspy b/wwwroot/api/pipeline_steps_update.dspy new file mode 100644 index 0000000..998289d --- /dev/null +++ b/wwwroot/api/pipeline_steps_update.dspy @@ -0,0 +1,5 @@ +func = update_pipeline_step +if func is None: + return json.dumps({'status': 'error', 'message': 'function not found'}) +result = await func(params_kw) +return result diff --git a/wwwroot/api/pipeline_versions_create.dspy b/wwwroot/api/pipeline_versions_create.dspy new file mode 100644 index 0000000..3567ff2 --- /dev/null +++ b/wwwroot/api/pipeline_versions_create.dspy @@ -0,0 +1,5 @@ +func = create_pipeline_version +if func is None: + return json.dumps({'status': 'error', 'message': 'function not found'}) +result = await func(params_kw) +return result diff --git a/wwwroot/api/pipeline_versions_delete.dspy b/wwwroot/api/pipeline_versions_delete.dspy new file mode 100644 index 0000000..31e496b --- /dev/null +++ b/wwwroot/api/pipeline_versions_delete.dspy @@ -0,0 +1,5 @@ +func = delete_pipeline_version +if func is None: + return json.dumps({'status': 'error', 'message': 'function not found'}) +result = await func(params_kw) +return result diff --git a/wwwroot/api/pipeline_versions_update.dspy b/wwwroot/api/pipeline_versions_update.dspy new file mode 100644 index 0000000..6618b2e --- /dev/null +++ b/wwwroot/api/pipeline_versions_update.dspy @@ -0,0 +1,5 @@ +func = update_pipeline_version +if func is None: + return json.dumps({'status': 'error', 'message': 'function not found'}) +result = await func(params_kw) +return result diff --git a/wwwroot/api/pipelines_create.dspy b/wwwroot/api/pipelines_create.dspy new file mode 100644 index 0000000..ef6e24b --- /dev/null +++ b/wwwroot/api/pipelines_create.dspy @@ -0,0 +1,5 @@ +func = create_pipeline +if func is None: + return json.dumps({'status': 'error', 'message': 'function not found'}) +result = await func(params_kw) +return result diff --git a/wwwroot/api/pipelines_delete.dspy b/wwwroot/api/pipelines_delete.dspy new file mode 100644 index 0000000..3a07d83 --- /dev/null +++ b/wwwroot/api/pipelines_delete.dspy @@ -0,0 +1,5 @@ +func = delete_pipeline +if func is None: + return json.dumps({'status': 'error', 'message': 'function not found'}) +result = await func(params_kw) +return result diff --git a/wwwroot/api/pipelines_update.dspy b/wwwroot/api/pipelines_update.dspy new file mode 100644 index 0000000..ed3b6c0 --- /dev/null +++ b/wwwroot/api/pipelines_update.dspy @@ -0,0 +1,5 @@ +func = update_pipeline +if func is None: + return json.dumps({'status': 'error', 'message': 'function not found'}) +result = await func(params_kw) +return result diff --git a/wwwroot/index.ui b/wwwroot/index.ui new file mode 100644 index 0000000..378bb9f --- /dev/null +++ b/wwwroot/index.ui @@ -0,0 +1,201 @@ +{ + "widgettype": "VBox", + "options": { + "width": "100%", + "height": "100%", + "padding": "0" + }, + "subwidgets": [ + { + "widgettype": "HBox", + "options": { + "width": "100%", + "alignItems": "center", + "marginBottom": "24px" + }, + "subwidgets": [ + { + "widgettype": "Title2", + "options": { + "text": "产线管理" + } + }, + { + "widgettype": "Filler" + }, + { + "widgettype": "Text", + "options": { + "text": "产线定义、步骤配置与发布管理", + "cfontsize": 1.2 + } + } + ] + }, + { + "widgettype": "VBox", + "options": { + "css": "filler", + "spacing": 16 + }, + "subwidgets": [ + { + "widgettype": "ResponsableBox", + "options": { + "gap": "16px", + "minWidth": "250px" + }, + "subwidgets": [ + { + "widgettype": "VBox", + "options": { + "css": "card", + "cwidth": 23, + "padding": "16px", + "cursor": "pointer", + "borderRadius": "8px" + }, + "binds": [ + { + "wid": "self", + "event": "click", + "actiontype": "urlwidget", + "target": "app.pipeline_core_content", + "options": { + "url": "{{entire_url('pipelines/')}}" + }, + "mode": "replace" + } + ], + "subwidgets": [ + { + "widgettype": "Svg", + "options": { + "svg": "", + "width": "28px", + "height": "28px" + } + }, + { + "widgettype": "Title4", + "options": { + "text": "产线定义", + "marginTop": "8px" + } + }, + { + "widgettype": "Text", + "options": { + "text": "管理产线基本信息与配置", + "cfontsize": 1.2 + } + } + ] + }, + { + "widgettype": "VBox", + "options": { + "css": "card", + "cwidth": 23, + "padding": "16px", + "cursor": "pointer", + "borderRadius": "8px" + }, + "binds": [ + { + "wid": "self", + "event": "click", + "actiontype": "urlwidget", + "target": "app.pipeline_core_content", + "options": { + "url": "{{entire_url('pipeline_steps/')}}" + }, + "mode": "replace" + } + ], + "subwidgets": [ + { + "widgettype": "Svg", + "options": { + "svg": "", + "width": "28px", + "height": "28px" + } + }, + { + "widgettype": "Title4", + "options": { + "text": "产线步骤", + "marginTop": "8px" + } + }, + { + "widgettype": "Text", + "options": { + "text": "配置产线执行步骤与参数", + "cfontsize": 1.2 + } + } + ] + }, + { + "widgettype": "VBox", + "options": { + "css": "card", + "cwidth": 23, + "padding": "16px", + "cursor": "pointer", + "borderRadius": "8px" + }, + "binds": [ + { + "wid": "self", + "event": "click", + "actiontype": "urlwidget", + "target": "app.pipeline_core_content", + "options": { + "url": "{{entire_url('pipeline_versions/')}}" + }, + "mode": "replace" + } + ], + "subwidgets": [ + { + "widgettype": "Svg", + "options": { + "svg": "", + "width": "28px", + "height": "28px" + } + }, + { + "widgettype": "Title4", + "options": { + "text": "发布记录", + "marginTop": "8px" + } + }, + { + "widgettype": "Text", + "options": { + "text": "查看产线版本发布历史", + "cfontsize": 1.2 + } + } + ] + } + ] + }, + { + "widgettype": "VScrollPanel", + "id": "app.pipeline_core_content", + "options": { + "css": "filler", + "width": "100%", + "height": "100%" + } + } + ] + } + ] +}