feat: add 40 dspy APIs, 7 UI pages, CSS, pipeline definition SQL
This commit is contained in:
parent
26c092073d
commit
f69870e96a
16
wwwroot/api/bug_close.dspy
Normal file
16
wwwroot/api/bug_close.dspy
Normal file
@ -0,0 +1,16 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
rec_id = params_kw.get('id', '')
|
||||
if not rec_id:
|
||||
return json.dumps({'status': 'error', 'message': '缺少id'}, ensure_ascii=False)
|
||||
|
||||
data = {'id': rec_id, 'status': 'closed', 'closed_at': curDateString(), 'updated_at': curDateString()}
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
await sor.U('sd_bugs', data)
|
||||
return json.dumps({'status': 'ok'}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
16
wwwroot/api/bug_confirm.dspy
Normal file
16
wwwroot/api/bug_confirm.dspy
Normal file
@ -0,0 +1,16 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
rec_id = params_kw.get('id', '')
|
||||
if not rec_id:
|
||||
return json.dumps({'status': 'error', 'message': '缺少id'}, ensure_ascii=False)
|
||||
|
||||
data = {'id': rec_id, 'status': 'confirmed', 'updated_at': curDateString()}
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
await sor.U('sd_bugs', data)
|
||||
return json.dumps({'status': 'ok'}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
22
wwwroot/api/check_iteration_bugs.dspy
Normal file
22
wwwroot/api/check_iteration_bugs.dspy
Normal file
@ -0,0 +1,22 @@
|
||||
iteration_id = params_kw.get('iteration_id', '')
|
||||
if not iteration_id:
|
||||
return json.dumps({'status': 'error', 'message': '缺少iteration_id'}, ensure_ascii=False)
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
total = await sor.sqlExe("select count(*) as cnt from sd_bugs where iteration_id=${iteration_id}$", {'iteration_id': iteration_id})
|
||||
closed = await sor.sqlExe("select count(*) as cnt from sd_bugs where iteration_id=${iteration_id}$ and status=${status}$", {'iteration_id': iteration_id, 'status': 'closed'})
|
||||
|
||||
total_count = total[0]['cnt'] if total else 0
|
||||
closed_count = closed[0]['cnt'] if closed else 0
|
||||
all_closed = total_count > 0 and total_count == closed_count
|
||||
|
||||
return json.dumps({
|
||||
'status': 'ok',
|
||||
'total': total_count,
|
||||
'closed': closed_count,
|
||||
'all_closed': all_closed,
|
||||
'message': f'共{total_count}个bug,已关闭{closed_count}个' + (',全部关闭' if all_closed else ',仍有未关闭')
|
||||
}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
35
wwwroot/api/env_verify.dspy
Normal file
35
wwwroot/api/env_verify.dspy
Normal file
@ -0,0 +1,35 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
rec_id = params_kw.get('id', '')
|
||||
if not rec_id:
|
||||
return json.dumps({'status': 'error', 'message': '缺少id'}, ensure_ascii=False)
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
rows = await sor.sqlExe("select host, port, user, ssh_key_path from sd_deploy_envs where id=${id}$", {'id': rec_id})
|
||||
if not rows:
|
||||
return json.dumps({'status': 'error', 'message': '环境记录不存在'}, ensure_ascii=False)
|
||||
env = rows[0] if isinstance(rows, list) else rows
|
||||
|
||||
host = env.get('host', '')
|
||||
port = env.get('port', '22')
|
||||
ssh_user = env.get('user', '')
|
||||
ssh_key = env.get('ssh_key_path', '')
|
||||
|
||||
import asyncio
|
||||
cmd = f"ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 -p {port}"
|
||||
if ssh_key:
|
||||
cmd += f" -i {ssh_key}"
|
||||
cmd += f" {ssh_user}@{host} echo ok"
|
||||
|
||||
proc = await asyncio.create_subprocess_shell(cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE)
|
||||
stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=15)
|
||||
|
||||
if proc.returncode == 0:
|
||||
return json.dumps({'status': 'ok', 'message': '连接成功'}, ensure_ascii=False)
|
||||
else:
|
||||
return json.dumps({'status': 'error', 'message': f'连接失败: {stderr.decode().strip()}'}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
9
wwwroot/api/get_iteration_options.dspy
Normal file
9
wwwroot/api/get_iteration_options.dspy
Normal file
@ -0,0 +1,9 @@
|
||||
result = []
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
rows = await sor.sqlExe("select id as iteration_id, iteration_name as iteration_id_text from sd_iterations order by iteration_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)
|
||||
9
wwwroot/api/get_project_options.dspy
Normal file
9
wwwroot/api/get_project_options.dspy
Normal file
@ -0,0 +1,9 @@
|
||||
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 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)
|
||||
9
wwwroot/api/get_search_bug_status.dspy
Normal file
9
wwwroot/api/get_search_bug_status.dspy
Normal file
@ -0,0 +1,9 @@
|
||||
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_bug_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)
|
||||
9
wwwroot/api/get_search_case_status.dspy
Normal file
9
wwwroot/api/get_search_case_status.dspy
Normal file
@ -0,0 +1,9 @@
|
||||
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_test_case_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)
|
||||
9
wwwroot/api/get_search_case_type.dspy
Normal file
9
wwwroot/api/get_search_case_type.dspy
Normal file
@ -0,0 +1,9 @@
|
||||
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_test_case_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)
|
||||
9
wwwroot/api/get_search_env_status.dspy
Normal file
9
wwwroot/api/get_search_env_status.dspy
Normal file
@ -0,0 +1,9 @@
|
||||
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_env_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)
|
||||
9
wwwroot/api/get_search_env_type.dspy
Normal file
9
wwwroot/api/get_search_env_type.dspy
Normal file
@ -0,0 +1,9 @@
|
||||
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_env_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)
|
||||
9
wwwroot/api/get_search_iteration_status.dspy
Normal file
9
wwwroot/api/get_search_iteration_status.dspy
Normal file
@ -0,0 +1,9 @@
|
||||
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_iteration_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)
|
||||
9
wwwroot/api/get_search_iteration_type.dspy
Normal file
9
wwwroot/api/get_search_iteration_type.dspy
Normal file
@ -0,0 +1,9 @@
|
||||
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_iteration_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)
|
||||
9
wwwroot/api/get_search_plan_status.dspy
Normal file
9
wwwroot/api/get_search_plan_status.dspy
Normal file
@ -0,0 +1,9 @@
|
||||
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_test_plan_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)
|
||||
9
wwwroot/api/get_search_plan_type.dspy
Normal file
9
wwwroot/api/get_search_plan_type.dspy
Normal file
@ -0,0 +1,9 @@
|
||||
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_test_plan_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)
|
||||
9
wwwroot/api/get_search_priority.dspy
Normal file
9
wwwroot/api/get_search_priority.dspy
Normal file
@ -0,0 +1,9 @@
|
||||
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_priority'})
|
||||
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)
|
||||
9
wwwroot/api/get_search_project_type.dspy
Normal file
9
wwwroot/api/get_search_project_type.dspy
Normal file
@ -0,0 +1,9 @@
|
||||
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)
|
||||
9
wwwroot/api/get_search_reporter_type.dspy
Normal file
9
wwwroot/api/get_search_reporter_type.dspy
Normal file
@ -0,0 +1,9 @@
|
||||
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_reporter_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)
|
||||
9
wwwroot/api/get_search_severity.dspy
Normal file
9
wwwroot/api/get_search_severity.dspy
Normal file
@ -0,0 +1,9 @@
|
||||
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_bug_severity'})
|
||||
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)
|
||||
9
wwwroot/api/get_search_status.dspy
Normal file
9
wwwroot/api/get_search_status.dspy
Normal file
@ -0,0 +1,9 @@
|
||||
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)
|
||||
9
wwwroot/api/get_test_plan_options.dspy
Normal file
9
wwwroot/api/get_test_plan_options.dspy
Normal file
@ -0,0 +1,9 @@
|
||||
result = []
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
rows = await sor.sqlExe("select id as plan_id, plan_name as plan_id_text from sd_test_plans order by plan_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)
|
||||
27
wwwroot/api/sd_bug_create.dspy
Normal file
27
wwwroot/api/sd_bug_create.dspy
Normal file
@ -0,0 +1,27 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
|
||||
data = {
|
||||
'id': getID(),
|
||||
'iteration_id': params_kw.get('iteration_id', ''),
|
||||
'case_id': params_kw.get('case_id', ''),
|
||||
'step_name': params_kw.get('step_name', ''),
|
||||
'title': params_kw.get('title', ''),
|
||||
'description': params_kw.get('description', ''),
|
||||
'severity': params_kw.get('severity', ''),
|
||||
'priority': params_kw.get('priority', ''),
|
||||
'status': params_kw.get('status', ''),
|
||||
'reporter_type': params_kw.get('reporter_type', ''),
|
||||
'reporter_id': params_kw.get('reporter_id', ''),
|
||||
'assignee_id': params_kw.get('assignee_id', ''),
|
||||
'created_at': curDateString(),
|
||||
}
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
await sor.C('sd_bugs', data)
|
||||
return json.dumps({'status': 'ok', 'id': data['id']}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
14
wwwroot/api/sd_bug_delete.dspy
Normal file
14
wwwroot/api/sd_bug_delete.dspy
Normal file
@ -0,0 +1,14 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
rec_id = params_kw.get('id', '')
|
||||
if not rec_id:
|
||||
return json.dumps({'status': 'error', 'message': '缺少id'}, ensure_ascii=False)
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
await sor.D('sd_bugs', {'id': rec_id})
|
||||
return json.dumps({'status': 'ok'}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
38
wwwroot/api/sd_bug_update.dspy
Normal file
38
wwwroot/api/sd_bug_update.dspy
Normal file
@ -0,0 +1,38 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
rec_id = params_kw.get('id', '')
|
||||
if not rec_id:
|
||||
return json.dumps({'status': 'error', 'message': '缺少id'}, ensure_ascii=False)
|
||||
|
||||
data = {'id': rec_id, 'updated_at': curDateString()}
|
||||
if 'iteration_id' in params_kw:
|
||||
data['iteration_id'] = params_kw['iteration_id']
|
||||
if 'case_id' in params_kw:
|
||||
data['case_id'] = params_kw['case_id']
|
||||
if 'step_name' in params_kw:
|
||||
data['step_name'] = params_kw['step_name']
|
||||
if 'title' in params_kw:
|
||||
data['title'] = params_kw['title']
|
||||
if 'description' in params_kw:
|
||||
data['description'] = params_kw['description']
|
||||
if 'severity' in params_kw:
|
||||
data['severity'] = params_kw['severity']
|
||||
if 'priority' in params_kw:
|
||||
data['priority'] = params_kw['priority']
|
||||
if 'status' in params_kw:
|
||||
data['status'] = params_kw['status']
|
||||
if 'reporter_type' in params_kw:
|
||||
data['reporter_type'] = params_kw['reporter_type']
|
||||
if 'reporter_id' in params_kw:
|
||||
data['reporter_id'] = params_kw['reporter_id']
|
||||
if 'assignee_id' in params_kw:
|
||||
data['assignee_id'] = params_kw['assignee_id']
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
await sor.U('sd_bugs', data)
|
||||
return json.dumps({'status': 'ok'}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
23
wwwroot/api/sd_case_create.dspy
Normal file
23
wwwroot/api/sd_case_create.dspy
Normal file
@ -0,0 +1,23 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
|
||||
data = {
|
||||
'id': getID(),
|
||||
'plan_id': params_kw.get('plan_id', ''),
|
||||
'case_name': params_kw.get('case_name', ''),
|
||||
'case_type': params_kw.get('case_type', ''),
|
||||
'priority': params_kw.get('priority', ''),
|
||||
'precondition': params_kw.get('precondition', ''),
|
||||
'steps': params_kw.get('steps', ''),
|
||||
'expected_result': params_kw.get('expected_result', ''),
|
||||
'created_at': curDateString(),
|
||||
}
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
await sor.C('sd_test_cases', data)
|
||||
return json.dumps({'status': 'ok', 'id': data['id']}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
14
wwwroot/api/sd_case_delete.dspy
Normal file
14
wwwroot/api/sd_case_delete.dspy
Normal file
@ -0,0 +1,14 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
rec_id = params_kw.get('id', '')
|
||||
if not rec_id:
|
||||
return json.dumps({'status': 'error', 'message': '缺少id'}, ensure_ascii=False)
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
await sor.D('sd_test_cases', {'id': rec_id})
|
||||
return json.dumps({'status': 'ok'}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
30
wwwroot/api/sd_case_update.dspy
Normal file
30
wwwroot/api/sd_case_update.dspy
Normal file
@ -0,0 +1,30 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
rec_id = params_kw.get('id', '')
|
||||
if not rec_id:
|
||||
return json.dumps({'status': 'error', 'message': '缺少id'}, ensure_ascii=False)
|
||||
|
||||
data = {'id': rec_id, 'updated_at': curDateString()}
|
||||
if 'plan_id' in params_kw:
|
||||
data['plan_id'] = params_kw['plan_id']
|
||||
if 'case_name' in params_kw:
|
||||
data['case_name'] = params_kw['case_name']
|
||||
if 'case_type' in params_kw:
|
||||
data['case_type'] = params_kw['case_type']
|
||||
if 'priority' in params_kw:
|
||||
data['priority'] = params_kw['priority']
|
||||
if 'precondition' in params_kw:
|
||||
data['precondition'] = params_kw['precondition']
|
||||
if 'steps' in params_kw:
|
||||
data['steps'] = params_kw['steps']
|
||||
if 'expected_result' in params_kw:
|
||||
data['expected_result'] = params_kw['expected_result']
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
await sor.U('sd_test_cases', data)
|
||||
return json.dumps({'status': 'ok'}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
30
wwwroot/api/sd_env_create.dspy
Normal file
30
wwwroot/api/sd_env_create.dspy
Normal file
@ -0,0 +1,30 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
|
||||
data = {
|
||||
'id': getID(),
|
||||
'project_id': params_kw.get('project_id', ''),
|
||||
'env_type': params_kw.get('env_type', ''),
|
||||
'host': params_kw.get('host', ''),
|
||||
'port': params_kw.get('port', ''),
|
||||
'user': params_kw.get('user', ''),
|
||||
'ssh_key_path': params_kw.get('ssh_key_path', ''),
|
||||
'sudo_enabled': params_kw.get('sudo_enabled', ''),
|
||||
'deploy_path': params_kw.get('deploy_path', ''),
|
||||
'python_path': params_kw.get('python_path', ''),
|
||||
'db_host': params_kw.get('db_host', ''),
|
||||
'db_port': params_kw.get('db_port', ''),
|
||||
'db_name': params_kw.get('db_name', ''),
|
||||
'db_user': params_kw.get('db_user', ''),
|
||||
'db_password': params_kw.get('db_password', ''),
|
||||
'created_at': curDateString(),
|
||||
}
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
await sor.C('sd_deploy_envs', data)
|
||||
return json.dumps({'status': 'ok', 'id': data['id']}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
14
wwwroot/api/sd_env_delete.dspy
Normal file
14
wwwroot/api/sd_env_delete.dspy
Normal file
@ -0,0 +1,14 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
rec_id = params_kw.get('id', '')
|
||||
if not rec_id:
|
||||
return json.dumps({'status': 'error', 'message': '缺少id'}, ensure_ascii=False)
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
await sor.D('sd_deploy_envs', {'id': rec_id})
|
||||
return json.dumps({'status': 'ok'}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
44
wwwroot/api/sd_env_update.dspy
Normal file
44
wwwroot/api/sd_env_update.dspy
Normal file
@ -0,0 +1,44 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
rec_id = params_kw.get('id', '')
|
||||
if not rec_id:
|
||||
return json.dumps({'status': 'error', 'message': '缺少id'}, ensure_ascii=False)
|
||||
|
||||
data = {'id': rec_id, 'updated_at': curDateString()}
|
||||
if 'project_id' in params_kw:
|
||||
data['project_id'] = params_kw['project_id']
|
||||
if 'env_type' in params_kw:
|
||||
data['env_type'] = params_kw['env_type']
|
||||
if 'host' in params_kw:
|
||||
data['host'] = params_kw['host']
|
||||
if 'port' in params_kw:
|
||||
data['port'] = params_kw['port']
|
||||
if 'user' in params_kw:
|
||||
data['user'] = params_kw['user']
|
||||
if 'ssh_key_path' in params_kw:
|
||||
data['ssh_key_path'] = params_kw['ssh_key_path']
|
||||
if 'sudo_enabled' in params_kw:
|
||||
data['sudo_enabled'] = params_kw['sudo_enabled']
|
||||
if 'deploy_path' in params_kw:
|
||||
data['deploy_path'] = params_kw['deploy_path']
|
||||
if 'python_path' in params_kw:
|
||||
data['python_path'] = params_kw['python_path']
|
||||
if 'db_host' in params_kw:
|
||||
data['db_host'] = params_kw['db_host']
|
||||
if 'db_port' in params_kw:
|
||||
data['db_port'] = params_kw['db_port']
|
||||
if 'db_name' in params_kw:
|
||||
data['db_name'] = params_kw['db_name']
|
||||
if 'db_user' in params_kw:
|
||||
data['db_user'] = params_kw['db_user']
|
||||
if 'db_password' in params_kw:
|
||||
data['db_password'] = params_kw['db_password']
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
await sor.U('sd_deploy_envs', data)
|
||||
return json.dumps({'status': 'ok'}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
21
wwwroot/api/sd_iter_create.dspy
Normal file
21
wwwroot/api/sd_iter_create.dspy
Normal file
@ -0,0 +1,21 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
|
||||
data = {
|
||||
'id': getID(),
|
||||
'project_id': params_kw.get('project_id', ''),
|
||||
'iteration_name': params_kw.get('iteration_name', ''),
|
||||
'iteration_type': params_kw.get('iteration_type', ''),
|
||||
'scope': params_kw.get('scope', ''),
|
||||
'priority': params_kw.get('priority', ''),
|
||||
'created_at': curDateString(),
|
||||
}
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
await sor.C('sd_iterations', data)
|
||||
return json.dumps({'status': 'ok', 'id': data['id']}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
14
wwwroot/api/sd_iter_delete.dspy
Normal file
14
wwwroot/api/sd_iter_delete.dspy
Normal file
@ -0,0 +1,14 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
rec_id = params_kw.get('id', '')
|
||||
if not rec_id:
|
||||
return json.dumps({'status': 'error', 'message': '缺少id'}, ensure_ascii=False)
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
await sor.D('sd_iterations', {'id': rec_id})
|
||||
return json.dumps({'status': 'ok'}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
26
wwwroot/api/sd_iter_update.dspy
Normal file
26
wwwroot/api/sd_iter_update.dspy
Normal file
@ -0,0 +1,26 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
rec_id = params_kw.get('id', '')
|
||||
if not rec_id:
|
||||
return json.dumps({'status': 'error', 'message': '缺少id'}, ensure_ascii=False)
|
||||
|
||||
data = {'id': rec_id, 'updated_at': curDateString()}
|
||||
if 'project_id' in params_kw:
|
||||
data['project_id'] = params_kw['project_id']
|
||||
if 'iteration_name' in params_kw:
|
||||
data['iteration_name'] = params_kw['iteration_name']
|
||||
if 'iteration_type' in params_kw:
|
||||
data['iteration_type'] = params_kw['iteration_type']
|
||||
if 'scope' in params_kw:
|
||||
data['scope'] = params_kw['scope']
|
||||
if 'priority' in params_kw:
|
||||
data['priority'] = params_kw['priority']
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
await sor.U('sd_iterations', data)
|
||||
return json.dumps({'status': 'ok'}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
24
wwwroot/api/sd_plan_create.dspy
Normal file
24
wwwroot/api/sd_plan_create.dspy
Normal file
@ -0,0 +1,24 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
|
||||
data = {
|
||||
'id': getID(),
|
||||
'iteration_id': params_kw.get('iteration_id', ''),
|
||||
'plan_name': params_kw.get('plan_name', ''),
|
||||
'plan_type': params_kw.get('plan_type', ''),
|
||||
'scope': params_kw.get('scope', ''),
|
||||
'environment': params_kw.get('environment', ''),
|
||||
'entry_criteria': params_kw.get('entry_criteria', ''),
|
||||
'exit_criteria': params_kw.get('exit_criteria', ''),
|
||||
'status': params_kw.get('status', ''),
|
||||
'created_at': curDateString(),
|
||||
}
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
await sor.C('sd_test_plans', data)
|
||||
return json.dumps({'status': 'ok', 'id': data['id']}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
14
wwwroot/api/sd_plan_delete.dspy
Normal file
14
wwwroot/api/sd_plan_delete.dspy
Normal file
@ -0,0 +1,14 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
rec_id = params_kw.get('id', '')
|
||||
if not rec_id:
|
||||
return json.dumps({'status': 'error', 'message': '缺少id'}, ensure_ascii=False)
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
await sor.D('sd_test_plans', {'id': rec_id})
|
||||
return json.dumps({'status': 'ok'}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
32
wwwroot/api/sd_plan_update.dspy
Normal file
32
wwwroot/api/sd_plan_update.dspy
Normal file
@ -0,0 +1,32 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
rec_id = params_kw.get('id', '')
|
||||
if not rec_id:
|
||||
return json.dumps({'status': 'error', 'message': '缺少id'}, ensure_ascii=False)
|
||||
|
||||
data = {'id': rec_id, 'updated_at': curDateString()}
|
||||
if 'iteration_id' in params_kw:
|
||||
data['iteration_id'] = params_kw['iteration_id']
|
||||
if 'plan_name' in params_kw:
|
||||
data['plan_name'] = params_kw['plan_name']
|
||||
if 'plan_type' in params_kw:
|
||||
data['plan_type'] = params_kw['plan_type']
|
||||
if 'scope' in params_kw:
|
||||
data['scope'] = params_kw['scope']
|
||||
if 'environment' in params_kw:
|
||||
data['environment'] = params_kw['environment']
|
||||
if 'entry_criteria' in params_kw:
|
||||
data['entry_criteria'] = params_kw['entry_criteria']
|
||||
if 'exit_criteria' in params_kw:
|
||||
data['exit_criteria'] = params_kw['exit_criteria']
|
||||
if 'status' in params_kw:
|
||||
data['status'] = params_kw['status']
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
await sor.U('sd_test_plans', data)
|
||||
return json.dumps({'status': 'ok'}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
24
wwwroot/api/sd_proj_create.dspy
Normal file
24
wwwroot/api/sd_proj_create.dspy
Normal file
@ -0,0 +1,24 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
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', ''),
|
||||
'status': params_kw.get('status', ''),
|
||||
'org_id': org_id,
|
||||
'created_at': curDateString(),
|
||||
}
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
await sor.C('sd_projects', data)
|
||||
return json.dumps({'status': 'ok', 'id': data['id']}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
14
wwwroot/api/sd_proj_delete.dspy
Normal file
14
wwwroot/api/sd_proj_delete.dspy
Normal file
@ -0,0 +1,14 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
rec_id = params_kw.get('id', '')
|
||||
if not rec_id:
|
||||
return json.dumps({'status': 'error', 'message': '缺少id'}, ensure_ascii=False)
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
await sor.D('sd_projects', {'id': rec_id})
|
||||
return json.dumps({'status': 'ok'}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
30
wwwroot/api/sd_proj_update.dspy
Normal file
30
wwwroot/api/sd_proj_update.dspy
Normal file
@ -0,0 +1,30 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
rec_id = params_kw.get('id', '')
|
||||
if not rec_id:
|
||||
return json.dumps({'status': 'error', 'message': '缺少id'}, ensure_ascii=False)
|
||||
|
||||
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:
|
||||
await sor.U('sd_projects', data)
|
||||
return json.dumps({'status': 'ok'}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
30
wwwroot/api/submit_bug.dspy
Normal file
30
wwwroot/api/submit_bug.dspy
Normal file
@ -0,0 +1,30 @@
|
||||
user_id = await get_user()
|
||||
if not user_id:
|
||||
return json.dumps({'status': 'error', 'message': '未登录'}, ensure_ascii=False)
|
||||
|
||||
reporter_type = params_kw.get('reporter_type', '')
|
||||
if not reporter_type:
|
||||
reporter_type = 'agent' if params_kw.get('is_agent', '') else 'human'
|
||||
|
||||
data = {
|
||||
'id': getID(),
|
||||
'iteration_id': params_kw.get('iteration_id', ''),
|
||||
'case_id': params_kw.get('case_id', ''),
|
||||
'step_name': params_kw.get('step_name', ''),
|
||||
'title': params_kw.get('title', ''),
|
||||
'description': params_kw.get('description', ''),
|
||||
'severity': params_kw.get('severity', 'medium'),
|
||||
'priority': params_kw.get('priority', 'medium'),
|
||||
'status': 'new',
|
||||
'reporter_type': reporter_type,
|
||||
'reporter_id': user_id,
|
||||
'assignee_id': params_kw.get('assignee_id', ''),
|
||||
'created_at': curDateString(),
|
||||
}
|
||||
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
await sor.C('sd_bugs', data)
|
||||
return json.dumps({'status': 'ok', 'id': data['id']}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'status': 'error', 'message': str(e)}, ensure_ascii=False)
|
||||
101
wwwroot/index.ui
Normal file
101
wwwroot/index.ui
Normal file
@ -0,0 +1,101 @@
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"width": "100%", "height": "100%", "padding": "20px", "gap": "20px"},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {"text": "SDLC Pipeline", "cfontsize": 28, "color": "#E0E0E0", "fontWeight": "bold"}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {"text": "软件开发生命周期管理", "cfontsize": 14, "color": "#888888"}
|
||||
},
|
||||
{
|
||||
"widgettype": "ResponsableBox",
|
||||
"options": {"gap": "16px", "minWidth": "220px"},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#1E1E2E", "padding": "20px", "borderRadius": "8px", "cursor": "pointer", "cwidth": 25, "gap": "12px", "border": "1px solid #2A2A3E"},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.sdlc_content",
|
||||
"options": {"url": "{{entire_url('pipeline_sdlc/sd_project_list/index.ui')}}"}
|
||||
}
|
||||
],
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "📁", "cfontsize": 32}},
|
||||
{"widgettype": "Text", "options": {"text": "项目管理", "cfontsize": 18, "color": "#FFFFFF", "fontWeight": "bold"}},
|
||||
{"widgettype": "Text", "options": {"text": "Project Management", "cfontsize": 12, "color": "#4A90D9"}},
|
||||
{"widgettype": "Text", "options": {"text": "管理所有软件项目的创建、配置和状态跟踪", "cfontsize": 13, "color": "#888888"}}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#1E1E2E", "padding": "20px", "borderRadius": "8px", "cursor": "pointer", "cwidth": 25, "gap": "12px", "border": "1px solid #2A2A3E"},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.sdlc_content",
|
||||
"options": {"url": "{{entire_url('pipeline_sdlc/sd_iteration/index.ui')}}"}
|
||||
}
|
||||
],
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "🔄", "cfontsize": 32}},
|
||||
{"widgettype": "Text", "options": {"text": "迭代看板", "cfontsize": 18, "color": "#FFFFFF", "fontWeight": "bold"}},
|
||||
{"widgettype": "Text", "options": {"text": "Iteration Board", "cfontsize": 12, "color": "#4A90D9"}},
|
||||
{"widgettype": "Text", "options": {"text": "可视化迭代进度,管理Sprint和任务分配", "cfontsize": 13, "color": "#888888"}}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#1E1E2E", "padding": "20px", "borderRadius": "8px", "cursor": "pointer", "cwidth": 25, "gap": "12px", "border": "1px solid #2A2A3E"},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.sdlc_content",
|
||||
"options": {"url": "{{entire_url('pipeline_sdlc/sd_bug_list/index.ui')}}"}
|
||||
}
|
||||
],
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "🐛", "cfontsize": 32}},
|
||||
{"widgettype": "Text", "options": {"text": "Bug管理", "cfontsize": 18, "color": "#FFFFFF", "fontWeight": "bold"}},
|
||||
{"widgettype": "Text", "options": {"text": "Bug Management", "cfontsize": 12, "color": "#4A90D9"}},
|
||||
{"widgettype": "Text", "options": {"text": "跟踪和管理项目缺陷,分配修复任务", "cfontsize": 13, "color": "#888888"}}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#1E1E2E", "padding": "20px", "borderRadius": "8px", "cursor": "pointer", "cwidth": 25, "gap": "12px", "border": "1px solid #2A2A3E"},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.sdlc_content",
|
||||
"options": {"url": "{{entire_url('pipeline_sdlc/sd_deploy_env_list/index.ui')}}"}
|
||||
}
|
||||
],
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "🚀", "cfontsize": 32}},
|
||||
{"widgettype": "Text", "options": {"text": "部署环境", "cfontsize": 18, "color": "#FFFFFF", "fontWeight": "bold"}},
|
||||
{"widgettype": "Text", "options": {"text": "Deploy Environments", "cfontsize": 12, "color": "#4A90D9"}},
|
||||
{"widgettype": "Text", "options": {"text": "配置和管理开发、测试、生产部署环境", "cfontsize": 13, "color": "#888888"}}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"id": "app.sdlc_content",
|
||||
"options": {"width": "100%", "flex": "1", "minHeight": "200px"}
|
||||
}
|
||||
]
|
||||
}
|
||||
201
wwwroot/pipeline_sdlc.css
Normal file
201
wwwroot/pipeline_sdlc.css
Normal file
@ -0,0 +1,201 @@
|
||||
/* pipeline_sdlc.css - SDLC Pipeline Module Custom Styles */
|
||||
/* Dark theme compatible */
|
||||
|
||||
/* === Base Colors === */
|
||||
:root {
|
||||
--sdlc-bg-primary: #121212;
|
||||
--sdlc-bg-card: #1E1E2E;
|
||||
--sdlc-bg-card-hover: #252540;
|
||||
--sdlc-border: #2A2A3E;
|
||||
--sdlc-border-hover: #3A3A5E;
|
||||
--sdlc-text-primary: #E0E0E0;
|
||||
--sdlc-text-secondary: #888888;
|
||||
--sdlc-text-muted: #666666;
|
||||
--sdlc-accent: #4A90D9;
|
||||
--sdlc-success: #4AD97A;
|
||||
--sdlc-warning: #D9A04A;
|
||||
--sdlc-danger: #D94A4A;
|
||||
--sdlc-purple: #9A4AD9;
|
||||
}
|
||||
|
||||
/* === Card Styles === */
|
||||
.sdlc-card {
|
||||
background-color: var(--sdlc-bg-card);
|
||||
border: 1px solid var(--sdlc-border);
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
transition: background-color 0.2s ease, border-color 0.2s ease, transform 0.1s ease;
|
||||
}
|
||||
|
||||
.sdlc-card:hover {
|
||||
background-color: var(--sdlc-bg-card-hover);
|
||||
border-color: var(--sdlc-border-hover);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
/* === Status Indicators === */
|
||||
.sdlc-status-planning {
|
||||
color: var(--sdlc-accent);
|
||||
}
|
||||
|
||||
.sdlc-status-in-progress {
|
||||
color: var(--sdlc-success);
|
||||
}
|
||||
|
||||
.sdlc-status-completed {
|
||||
color: var(--sdlc-text-secondary);
|
||||
}
|
||||
|
||||
.sdlc-status-blocked {
|
||||
color: var(--sdlc-danger);
|
||||
}
|
||||
|
||||
/* === Priority Indicators === */
|
||||
.sdlc-priority-critical {
|
||||
color: var(--sdlc-danger);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.sdlc-priority-high {
|
||||
color: var(--sdlc-warning);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.sdlc-priority-medium {
|
||||
color: var(--sdlc-accent);
|
||||
}
|
||||
|
||||
.sdlc-priority-low {
|
||||
color: var(--sdlc-text-secondary);
|
||||
}
|
||||
|
||||
/* === Kanban Column Headers === */
|
||||
.sdlc-kanban-header-planning {
|
||||
background-color: #1A3A5C;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.sdlc-kanban-header-progress {
|
||||
background-color: #2A4A1A;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.sdlc-kanban-header-completed {
|
||||
background-color: #3A3A3A;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
/* === Review Queue === */
|
||||
.sdlc-review-task {
|
||||
background-color: var(--sdlc-bg-card);
|
||||
border: 1px solid var(--sdlc-border);
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.sdlc-review-task:hover {
|
||||
background-color: var(--sdlc-bg-card-hover);
|
||||
}
|
||||
|
||||
.sdlc-approval-gate {
|
||||
background-color: var(--sdlc-bg-card);
|
||||
border-left: 3px solid var(--sdlc-purple);
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
/* === Dashboard Stat Cards === */
|
||||
.sdlc-stat-card {
|
||||
background-color: var(--sdlc-bg-card);
|
||||
border: 1px solid var(--sdlc-border);
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.sdlc-stat-number {
|
||||
font-size: 36px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.sdlc-stat-label {
|
||||
font-size: 14px;
|
||||
color: var(--sdlc-text-secondary);
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* === Iteration Cards === */
|
||||
.sdlc-iteration-card {
|
||||
background-color: var(--sdlc-bg-card);
|
||||
border: 1px solid var(--sdlc-border);
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.sdlc-iteration-card:hover {
|
||||
background-color: var(--sdlc-bg-card-hover);
|
||||
border-color: var(--sdlc-accent);
|
||||
}
|
||||
|
||||
.sdlc-iteration-completed {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* === Deployment Status === */
|
||||
.sdlc-deploy-success {
|
||||
color: var(--sdlc-success);
|
||||
}
|
||||
|
||||
.sdlc-deploy-pending {
|
||||
color: var(--sdlc-warning);
|
||||
}
|
||||
|
||||
.sdlc-deploy-failed {
|
||||
color: var(--sdlc-danger);
|
||||
}
|
||||
|
||||
.sdlc-deploy-dev {
|
||||
color: var(--sdlc-accent);
|
||||
}
|
||||
|
||||
/* === Scrollbar Styling (Dark Theme) === */
|
||||
.sdlc-scrollable::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.sdlc-scrollable::-webkit-scrollbar-track {
|
||||
background: var(--sdlc-bg-primary);
|
||||
}
|
||||
|
||||
.sdlc-scrollable::-webkit-scrollbar-thumb {
|
||||
background: var(--sdlc-border);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.sdlc-scrollable::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--sdlc-border-hover);
|
||||
}
|
||||
|
||||
/* === Animation === */
|
||||
@keyframes sdlc-pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
}
|
||||
|
||||
.sdlc-pending-indicator {
|
||||
animation: sdlc-pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* === Responsive Adjustments === */
|
||||
@media (max-width: 768px) {
|
||||
.sdlc-stat-number {
|
||||
font-size: 28px;
|
||||
}
|
||||
}
|
||||
14
wwwroot/sd_bug_list/index.ui
Normal file
14
wwwroot/sd_bug_list/index.ui
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"width": "100%", "height": "100%", "padding": "20px", "gap": "16px"},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {"text": "Bug管理 - CRUD List", "cfontsize": 20, "color": "#E0E0E0", "fontWeight": "bold"}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {"text": "Generated by xls2crud - This page will be auto-generated from the sd_bug_list table definition", "cfontsize": 14, "color": "#888888"}
|
||||
}
|
||||
]
|
||||
}
|
||||
176
wwwroot/sd_dashboard/index.ui
Normal file
176
wwwroot/sd_dashboard/index.ui
Normal file
@ -0,0 +1,176 @@
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"width": "100%", "height": "100%", "padding": "20px", "gap": "20px"},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {"text": "📊 项目概览 Dashboard", "cfontsize": 24, "color": "#E0E0E0", "fontWeight": "bold"}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {"text": "软件开发生命周期全局统计", "cfontsize": 14, "color": "#888888"}
|
||||
},
|
||||
{
|
||||
"widgettype": "ResponsableBox",
|
||||
"options": {"gap": "16px", "minWidth": "180px"},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#1E1E2E", "padding": "20px", "borderRadius": "8px", "gap": "8px", "border": "1px solid #2A2A3E", "cwidth": 25, "alignItems": "center"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "12", "cfontsize": 36, "color": "#4A90D9", "fontWeight": "bold"}},
|
||||
{"widgettype": "Text", "options": {"text": "活跃项目", "cfontsize": 14, "color": "#E0E0E0"}},
|
||||
{"widgettype": "Text", "options": {"text": "Active Projects", "cfontsize": 11, "color": "#888888"}}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#1E1E2E", "padding": "20px", "borderRadius": "8px", "gap": "8px", "border": "1px solid #2A2A3E", "cwidth": 25, "alignItems": "center"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "5", "cfontsize": 36, "color": "#4AD97A", "fontWeight": "bold"}},
|
||||
{"widgettype": "Text", "options": {"text": "进行中迭代", "cfontsize": 14, "color": "#E0E0E0"}},
|
||||
{"widgettype": "Text", "options": {"text": "Active Iterations", "cfontsize": 11, "color": "#888888"}}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#1E1E2E", "padding": "20px", "borderRadius": "8px", "gap": "8px", "border": "1px solid #2A2A3E", "cwidth": 25, "alignItems": "center"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "23", "cfontsize": 36, "color": "#D9A04A", "fontWeight": "bold"}},
|
||||
{"widgettype": "Text", "options": {"text": "待处理Bug", "cfontsize": 14, "color": "#E0E0E0"}},
|
||||
{"widgettype": "Text", "options": {"text": "Open Bugs", "cfontsize": 11, "color": "#888888"}}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#1E1E2E", "padding": "20px", "borderRadius": "8px", "gap": "8px", "border": "1px solid #2A2A3E", "cwidth": 25, "alignItems": "center"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "3", "cfontsize": 36, "color": "#9A4AD9", "fontWeight": "bold"}},
|
||||
{"widgettype": "Text", "options": {"text": "待审批", "cfontsize": 14, "color": "#E0E0E0"}},
|
||||
{"widgettype": "Text", "options": {"text": "Pending Reviews", "cfontsize": 11, "color": "#888888"}}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "ResponsableBox",
|
||||
"options": {"gap": "16px", "minWidth": "350px"},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#1E1E2E", "padding": "20px", "borderRadius": "8px", "gap": "12px", "border": "1px solid #2A2A3E", "cwidth": 50},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "📈 迭代进度", "cfontsize": 16, "color": "#E0E0E0", "fontWeight": "bold"}},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"gap": "8px"},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {"gap": "8px", "alignItems": "center", "justifyContent": "space-between"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "Sprint 23 - API重构", "cfontsize": 13, "color": "#E0E0E0"}},
|
||||
{"widgettype": "Text", "options": {"text": "72%", "cfontsize": 13, "color": "#4AD97A", "fontWeight": "bold"}}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {"gap": "8px", "alignItems": "center", "justifyContent": "space-between"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "Sprint 23b - 测试覆盖", "cfontsize": 13, "color": "#E0E0E0"}},
|
||||
{"widgettype": "Text", "options": {"text": "45%", "cfontsize": 13, "color": "#D9A04A", "fontWeight": "bold"}}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {"gap": "8px", "alignItems": "center", "justifyContent": "space-between"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "Sprint 24 - 功能开发", "cfontsize": 13, "color": "#E0E0E0"}},
|
||||
{"widgettype": "Text", "options": {"text": "规划中", "cfontsize": 13, "color": "#4A90D9", "fontWeight": "bold"}}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#1E1E2E", "padding": "20px", "borderRadius": "8px", "gap": "12px", "border": "1px solid #2A2A3E", "cwidth": 50},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "🐛 Bug趋势", "cfontsize": 16, "color": "#E0E0E0", "fontWeight": "bold"}},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"gap": "8px"},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {"gap": "8px", "alignItems": "center", "justifyContent": "space-between"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "严重 Critical", "cfontsize": 13, "color": "#E0E0E0"}},
|
||||
{"widgettype": "Text", "options": {"text": "3", "cfontsize": 13, "color": "#D94A4A", "fontWeight": "bold"}}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {"gap": "8px", "alignItems": "center", "justifyContent": "space-between"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "高 High", "cfontsize": 13, "color": "#E0E0E0"}},
|
||||
{"widgettype": "Text", "options": {"text": "8", "cfontsize": 13, "color": "#D9A04A", "fontWeight": "bold"}}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {"gap": "8px", "alignItems": "center", "justifyContent": "space-between"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "中 Medium", "cfontsize": 13, "color": "#E0E0E0"}},
|
||||
{"widgettype": "Text", "options": {"text": "12", "cfontsize": 13, "color": "#4A90D9", "fontWeight": "bold"}}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#1E1E2E", "padding": "20px", "borderRadius": "8px", "gap": "12px", "border": "1px solid #2A2A3E"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "🚀 最近部署 Recent Deployments", "cfontsize": 16, "color": "#E0E0E0", "fontWeight": "bold"}},
|
||||
{
|
||||
"widgettype": "ResponsableBox",
|
||||
"options": {"gap": "12px", "minWidth": "250px"},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#121212", "padding": "12px", "borderRadius": "6px", "gap": "4px", "cwidth": 33},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "✅ Production", "cfontsize": 13, "color": "#4AD97A", "fontWeight": "bold"}},
|
||||
{"widgettype": "Text", "options": {"text": "v2.2.5 → v2.2.6", "cfontsize": 12, "color": "#E0E0E0"}},
|
||||
{"widgettype": "Text", "options": {"text": "2026-06-15 18:30", "cfontsize": 11, "color": "#888888"}}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#121212", "padding": "12px", "borderRadius": "6px", "gap": "4px", "cwidth": 33},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "🔄 Staging", "cfontsize": 13, "color": "#D9A04A", "fontWeight": "bold"}},
|
||||
{"widgettype": "Text", "options": {"text": "v2.3.0-rc1", "cfontsize": 12, "color": "#E0E0E0"}},
|
||||
{"widgettype": "Text", "options": {"text": "2026-06-16 10:00", "cfontsize": 11, "color": "#888888"}}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#121212", "padding": "12px", "borderRadius": "6px", "gap": "4px", "cwidth": 33},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "🧪 Dev", "cfontsize": 13, "color": "#4A90D9", "fontWeight": "bold"}},
|
||||
{"widgettype": "Text", "options": {"text": "v2.3.0-dev.47", "cfontsize": 12, "color": "#E0E0E0"}},
|
||||
{"widgettype": "Text", "options": {"text": "2026-06-16 14:22", "cfontsize": 11, "color": "#888888"}}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
14
wwwroot/sd_deploy_env_list/index.ui
Normal file
14
wwwroot/sd_deploy_env_list/index.ui
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"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_deploy_env_list table definition", "cfontsize": 14, "color": "#888888"}
|
||||
}
|
||||
]
|
||||
}
|
||||
14
wwwroot/sd_project_list/index.ui
Normal file
14
wwwroot/sd_project_list/index.ui
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"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"}
|
||||
}
|
||||
]
|
||||
}
|
||||
179
wwwroot/sd_review/index.ui
Normal file
179
wwwroot/sd_review/index.ui
Normal file
@ -0,0 +1,179 @@
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"width": "100%", "height": "100%", "padding": "20px", "gap": "20px"},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {"text": "📝 审核队列 Review Queue", "cfontsize": 24, "color": "#E0E0E0", "fontWeight": "bold"}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {"text": "待处理的人工任务与审批门禁", "cfontsize": 14, "color": "#888888"}
|
||||
},
|
||||
{
|
||||
"widgettype": "ResponsableBox",
|
||||
"options": {"gap": "16px", "minWidth": "400px"},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"cwidth": 50, "gap": "12px"},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#3A2A1A", "padding": "12px", "borderRadius": "6px"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "🔔 人工任务 Human Tasks", "cfontsize": 16, "color": "#D9A04A", "fontWeight": "bold"}}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#1E1E2E", "padding": "16px", "borderRadius": "8px", "gap": "8px", "border": "1px solid #2A2A3E", "cursor": "pointer"},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.sdlc_review_detail",
|
||||
"options": {"url": "{{entire_url('pipeline_sdlc/sd_review/detail.ui')}}?task_id=1"}
|
||||
}
|
||||
],
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {"gap": "8px", "alignItems": "center"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "⏳", "cfontsize": 16}},
|
||||
{"widgettype": "Text", "options": {"text": "代码审查 - API重构PR #42", "cfontsize": 14, "color": "#E0E0E0", "fontWeight": "bold"}}
|
||||
]
|
||||
},
|
||||
{"widgettype": "Text", "options": {"text": "指派: 张三 · 优先级: 高", "cfontsize": 12, "color": "#D9A04A"}},
|
||||
{"widgettype": "Text", "options": {"text": "提交时间: 2026-06-15 14:30 · 等待 1天", "cfontsize": 12, "color": "#888888"}}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#1E1E2E", "padding": "16px", "borderRadius": "8px", "gap": "8px", "border": "1px solid #2A2A3E", "cursor": "pointer"},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.sdlc_review_detail",
|
||||
"options": {"url": "{{entire_url('pipeline_sdlc/sd_review/detail.ui')}}?task_id=2"}
|
||||
}
|
||||
],
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {"gap": "8px", "alignItems": "center"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "⏳", "cfontsize": 16}},
|
||||
{"widgettype": "Text", "options": {"text": "数据库迁移确认 - v2.3.0", "cfontsize": 14, "color": "#E0E0E0", "fontWeight": "bold"}}
|
||||
]
|
||||
},
|
||||
{"widgettype": "Text", "options": {"text": "指派: 李四 · 优先级: 紧急", "cfontsize": 12, "color": "#D94A4A"}},
|
||||
{"widgettype": "Text", "options": {"text": "提交时间: 2026-06-16 09:15 · 等待 2小时", "cfontsize": 12, "color": "#888888"}}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#1E1E2E", "padding": "16px", "borderRadius": "8px", "gap": "8px", "border": "1px solid #2A2A3E", "cursor": "pointer"},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.sdlc_review_detail",
|
||||
"options": {"url": "{{entire_url('pipeline_sdlc/sd_review/detail.ui')}}?task_id=3"}
|
||||
}
|
||||
],
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {"gap": "8px", "alignItems": "center"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "⏳", "cfontsize": 16}},
|
||||
{"widgettype": "Text", "options": {"text": "安全扫描确认 - 依赖更新", "cfontsize": 14, "color": "#E0E0E0", "fontWeight": "bold"}}
|
||||
]
|
||||
},
|
||||
{"widgettype": "Text", "options": {"text": "指派: 王五 · 优先级: 中", "cfontsize": 12, "color": "#4A90D9"}},
|
||||
{"widgettype": "Text", "options": {"text": "提交时间: 2026-06-14 16:00 · 等待 3天", "cfontsize": 12, "color": "#888888"}}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"cwidth": 50, "gap": "12px"},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#2A1A3A", "padding": "12px", "borderRadius": "6px"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "🚧 审批门禁 Approval Gates", "cfontsize": 16, "color": "#9A4AD9", "fontWeight": "bold"}}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#1E1E2E", "padding": "16px", "borderRadius": "8px", "gap": "8px", "border": "1px solid #2A2A3E", "cursor": "pointer"},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.sdlc_review_detail",
|
||||
"options": {"url": "{{entire_url('pipeline_sdlc/sd_review/detail.ui')}}?gate_id=1"}
|
||||
}
|
||||
],
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {"gap": "8px", "alignItems": "center"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "🔒", "cfontsize": 16}},
|
||||
{"widgettype": "Text", "options": {"text": "生产部署审批 - v2.3.0-rc1", "cfontsize": 14, "color": "#E0E0E0", "fontWeight": "bold"}}
|
||||
]
|
||||
},
|
||||
{"widgettype": "Text", "options": {"text": "需要 2/3 审批人通过 · 当前 1/3", "cfontsize": 12, "color": "#9A4AD9"}},
|
||||
{"widgettype": "Text", "options": {"text": "流水线: deploy-production · 阻塞中", "cfontsize": 12, "color": "#D94A4A"}}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"backgroundColor": "#1E1E2E", "padding": "16px", "borderRadius": "8px", "gap": "8px", "border": "1px solid #2A2A3E", "cursor": "pointer"},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.sdlc_review_detail",
|
||||
"options": {"url": "{{entire_url('pipeline_sdlc/sd_review/detail.ui')}}?gate_id=2"}
|
||||
}
|
||||
],
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {"gap": "8px", "alignItems": "center"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "🔒", "cfontsize": 16}},
|
||||
{"widgettype": "Text", "options": {"text": "架构变更审批 - 新增缓存层", "cfontsize": 14, "color": "#E0E0E0", "fontWeight": "bold"}}
|
||||
]
|
||||
},
|
||||
{"widgettype": "Text", "options": {"text": "需要架构委员会审批 · 等待中", "cfontsize": 12, "color": "#9A4AD9"}},
|
||||
{"widgettype": "Text", "options": {"text": "流水线: design-review · 阻塞中", "cfontsize": 12, "color": "#D94A4A"}}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"id": "app.sdlc_review_detail",
|
||||
"options": {"width": "100%", "flex": "1", "minHeight": "100px", "backgroundColor": "#1E1E2E", "borderRadius": "8px", "padding": "16px", "border": "1px solid #2A2A3E"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "点击任务或审批门禁查看详情", "cfontsize": 14, "color": "#666666"}}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user