Add dashboard_for_sage module: menu submenu, sage.py import/load, build.sh module list
This commit is contained in:
parent
c18c9113cc
commit
3cda907ba2
@ -25,6 +25,7 @@ from discount.init import load_discount
|
||||
from harnessed_agent.init import load_harnessed_agent
|
||||
from harnessed_reasoning.init import load_harnessed_reasoning
|
||||
from hermes_web_cli.init import load_hermes_web_cli
|
||||
from dashboard_for_sage.init import load_dashboard_for_sage
|
||||
from global_func import set_globalvariable
|
||||
from unipay.init import load_unipay
|
||||
from platformbiz.init import load_platformbiz
|
||||
@ -56,6 +57,7 @@ def init():
|
||||
load_discount()
|
||||
load_hermes_web_cli()
|
||||
load_smssend()
|
||||
load_dashboard_for_sage()
|
||||
|
||||
if __name__ == '__main__':
|
||||
webapp(init)
|
||||
|
||||
2
build.sh
2
build.sh
@ -26,7 +26,7 @@ do
|
||||
cd $m
|
||||
$cdir/py3/bin/pip install .
|
||||
done
|
||||
for m in appbase rbac accounting llmage platformbiz msp cpcc unipay filemgr dapi uapi rag charge pricing discount harnessed_agent harnessed_reasoning
|
||||
for m in appbase rbac accounting llmage platformbiz msp cpcc unipay filemgr dapi uapi rag charge pricing discount harnessed_agent harnessed_reasoning dashboard_for_sage
|
||||
do
|
||||
echo "install $m module..."
|
||||
cd $cdir/pkgs
|
||||
|
||||
@ -10,6 +10,11 @@
|
||||
"label": "主页",
|
||||
"url": "{{entire_url('public')}}"
|
||||
},
|
||||
{
|
||||
"name": "dashboard",
|
||||
"label": "数据看板",
|
||||
"submenu": "{{entire_url('/dashboard_for_sage/menu.ui')}}"
|
||||
},
|
||||
{
|
||||
"name": "agent",
|
||||
"label": "代理",
|
||||
|
||||
178
xlsx2json_models.py
Normal file
178
xlsx2json_models.py
Normal file
@ -0,0 +1,178 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
将 Sage 相关模块 models/ 目录下的 .xlsx 文件转换为 .json 数据表定义文件。
|
||||
|
||||
用法(在 Sage 虚拟环境中运行):
|
||||
python ~/repos/sage/xlsx2json_models.py # 转换所有模块
|
||||
python ~/repos/sage/xlsx2json_models.py llmage # 只转换 llmage
|
||||
python ~/repos/sage/xlsx2json_models.py --dry-run # 预览
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
import argparse
|
||||
|
||||
# Sage 虚拟环境路径
|
||||
sage_root = os.path.expanduser('~/repos/sage')
|
||||
sys.path.insert(0, sage_root)
|
||||
sys.path.insert(0, os.path.join(sage_root, 'py3/lib/python3.10/site-packages'))
|
||||
|
||||
from appPublic.folderUtils import listFile
|
||||
from xls2ddl.xlsxData import xlsxFactory, CRUDData
|
||||
|
||||
# Sage 相关模块列表
|
||||
SAGE_MODULES = [
|
||||
'appbase', 'rbac', 'accounting', 'llmage', 'platformbiz',
|
||||
'msp', 'cpcc', 'unipay', 'filemgr', 'dapi', 'uapi',
|
||||
'rag', 'charge', 'pricing', 'discount', 'hermes-web-cli',
|
||||
]
|
||||
|
||||
|
||||
def xlsx_to_json_dict(xlsx_path):
|
||||
"""将 xlsx 文件读取并转换为 json 格式的 dict。"""
|
||||
d = xlsxFactory(xlsx_path)
|
||||
if d is None:
|
||||
return None
|
||||
data = d.get_data()
|
||||
|
||||
# 只保留目标字段
|
||||
result = {}
|
||||
|
||||
# summary: 确保 primary 是 list
|
||||
if 'summary' in data:
|
||||
result['summary'] = []
|
||||
for s in data['summary']:
|
||||
entry = {'name': s.get('name'), 'title': s.get('title')}
|
||||
primary = s.get('primary', '')
|
||||
if isinstance(primary, list):
|
||||
entry['primary'] = primary
|
||||
elif primary:
|
||||
entry['primary'] = [p.strip() for p in str(primary).split(',')]
|
||||
else:
|
||||
entry['primary'] = []
|
||||
if s.get('catelog'):
|
||||
entry['catelog'] = s['catelog']
|
||||
result['summary'].append(entry)
|
||||
|
||||
# fields: 清理 None 值
|
||||
if 'fields' in data:
|
||||
result['fields'] = []
|
||||
for f in data['fields']:
|
||||
entry = {'name': f.get('name'), 'title': f.get('title'), 'type': f.get('type')}
|
||||
if f.get('length') is not None:
|
||||
entry['length'] = f['length']
|
||||
if f.get('nullable') is not None:
|
||||
entry['nullable'] = f['nullable']
|
||||
if f.get('default') is not None:
|
||||
entry['default'] = f['default']
|
||||
result['fields'].append(entry)
|
||||
|
||||
# indexes: 从 validation 中的 idx 操作转换,或直接用 indexes sheet
|
||||
if 'indexes' in data and data['indexes']:
|
||||
result['indexes'] = data['indexes']
|
||||
elif 'validation' in data:
|
||||
indexes = []
|
||||
for v in data['validation']:
|
||||
if v.get('oper') == 'idx':
|
||||
idx = {'name': v.get('name'), 'idxtype': 'index'}
|
||||
val = v.get('value', '')
|
||||
parts = val.split(':')
|
||||
if len(parts) >= 2:
|
||||
idx['idxtype'] = parts[0]
|
||||
idx['idxfields'] = [f.strip() for f in parts[1].split(',')]
|
||||
indexes.append(idx)
|
||||
if indexes:
|
||||
result['indexes'] = indexes
|
||||
|
||||
# codes
|
||||
if 'codes' in data and data['codes']:
|
||||
result['codes'] = data['codes']
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def convert_module(module_name, dry_run=False):
|
||||
"""转换单个模块的 models 目录。"""
|
||||
module_dir = os.path.expanduser(f'~/repos/{module_name}')
|
||||
models_dir = os.path.join(module_dir, 'models')
|
||||
|
||||
if not os.path.isdir(models_dir):
|
||||
print(f" [SKIP] {module_name}: models/ directory not found")
|
||||
return 0, 0
|
||||
|
||||
xlsx_files = [f for f in listFile(models_dir) if f.endswith('.xlsx')]
|
||||
if not xlsx_files:
|
||||
print(f" [SKIP] {module_name}: no .xlsx files")
|
||||
return 0, 0
|
||||
|
||||
converted = 0
|
||||
skipped = 0
|
||||
|
||||
for xlsx_path in xlsx_files:
|
||||
table_name = os.path.splitext(os.path.basename(xlsx_path))[0]
|
||||
json_path = os.path.join(models_dir, f'{table_name}.json')
|
||||
|
||||
# 跳过已经是 json 的文件
|
||||
if os.path.exists(json_path):
|
||||
print(f" [EXIST] {table_name}.json already exists")
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
try:
|
||||
result = xlsx_to_json_dict(xlsx_path)
|
||||
if result is None:
|
||||
print(f" [FAIL] {table_name}: could not read xlsx")
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
if dry_run:
|
||||
print(f" [DRY] Would create {table_name}.json ({len(result.get('fields', []))} fields)")
|
||||
converted += 1
|
||||
continue
|
||||
|
||||
with open(json_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(result, f, ensure_ascii=False, indent=4)
|
||||
|
||||
print(f" [OK] {table_name}.json ({len(result.get('fields', []))} fields)")
|
||||
converted += 1
|
||||
|
||||
except Exception as e:
|
||||
print(f" [FAIL] {table_name}: {e}")
|
||||
skipped += 1
|
||||
|
||||
return converted, skipped
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Convert models/*.xlsx to models/*.json')
|
||||
parser.add_argument('modules', nargs='*', help='Module names to convert (default: all)')
|
||||
parser.add_argument('--dry-run', action='store_true', help='Preview without writing files')
|
||||
args = parser.parse_args()
|
||||
|
||||
modules = args.modules if args.modules else SAGE_MODULES
|
||||
dry_run = args.dry_run
|
||||
|
||||
print("=" * 60)
|
||||
print(" Sage Models: xlsx -> json 转换")
|
||||
print("=" * 60)
|
||||
print(f"Modules: {', '.join(modules)}")
|
||||
print(f"Dry run: {dry_run}")
|
||||
print()
|
||||
|
||||
total_converted = 0
|
||||
total_skipped = 0
|
||||
|
||||
for mod in modules:
|
||||
print(f"[{mod}]")
|
||||
c, s = convert_module(mod, dry_run=dry_run)
|
||||
total_converted += c
|
||||
total_skipped += s
|
||||
print()
|
||||
|
||||
print("=" * 60)
|
||||
print(f" 完成: 转换 {total_converted}, 跳过 {total_skipped}")
|
||||
print("=" * 60)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Loading…
x
Reference in New Issue
Block a user