693 lines
21 KiB
Python
693 lines
21 KiB
Python
"""OA 审批 CRUD(分组、应用、草稿等)"""
|
|
from __future__ import annotations
|
|
|
|
import copy
|
|
import json
|
|
from datetime import datetime
|
|
from typing import Any, Dict, List, Optional, Tuple
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.core.utils import generate_uuid
|
|
from app.models.models import OaApp, OaAppGroup, OaAppVersion
|
|
|
|
DEFAULT_ADVANCED_SETTINGS: Dict[str, Any] = {
|
|
"supervisorFallbackToDeptLeader": True,
|
|
"allowWithdrawRunning": True,
|
|
"approverDedup": False,
|
|
"commentRequired": False,
|
|
"allowAddSign": True,
|
|
"allowReturn": True,
|
|
"autoPassWhenApproverIsInitiator": False,
|
|
}
|
|
|
|
|
|
def _dumps(data: Any) -> Optional[str]:
|
|
if data is None:
|
|
return None
|
|
if isinstance(data, str):
|
|
return data
|
|
return json.dumps(data, ensure_ascii=False)
|
|
|
|
|
|
def _loads(text: Optional[str], default: Any = None) -> Any:
|
|
if text is None or text == "":
|
|
return default
|
|
if not isinstance(text, str):
|
|
return text
|
|
try:
|
|
return json.loads(text)
|
|
except (TypeError, ValueError):
|
|
return default
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 分组 oa_app_group
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def _group_to_dict(g: OaAppGroup) -> Dict[str, Any]:
|
|
return {
|
|
"id": g.id,
|
|
"groupName": g.group_name,
|
|
"tenantNo": g.tenant_no,
|
|
"orderNum": g.order_num if g.order_num is not None else 0,
|
|
"remark": g.remark or "",
|
|
"createTime": g.create_time.strftime("%Y-%m-%d %H:%M:%S") if g.create_time else "",
|
|
"updateTime": g.update_time.strftime("%Y-%m-%d %H:%M:%S") if g.update_time else "",
|
|
}
|
|
|
|
|
|
def list_groups(db: Session, *, tenant_no: str) -> List[Dict[str, Any]]:
|
|
rows = (
|
|
db.query(OaAppGroup)
|
|
.filter(OaAppGroup.tenant_no == tenant_no, OaAppGroup.del_flag == 0)
|
|
.order_by(OaAppGroup.order_num.asc(), OaAppGroup.create_time.asc())
|
|
.all()
|
|
)
|
|
return [_group_to_dict(r) for r in rows]
|
|
|
|
|
|
def get_group(db: Session, group_id: str, tenant_no: str) -> Optional[OaAppGroup]:
|
|
return (
|
|
db.query(OaAppGroup)
|
|
.filter(OaAppGroup.id == group_id, OaAppGroup.tenant_no == tenant_no, OaAppGroup.del_flag == 0)
|
|
.first()
|
|
)
|
|
|
|
|
|
def create_group(
|
|
db: Session,
|
|
*,
|
|
tenant_no: str,
|
|
group_name: str,
|
|
order_num: Optional[int] = None,
|
|
remark: Optional[str] = None,
|
|
user_id: Optional[str] = None,
|
|
) -> OaAppGroup:
|
|
name = (group_name or "").strip()
|
|
if not name:
|
|
raise ValueError("分组名称不能为空")
|
|
now = datetime.now()
|
|
obj = OaAppGroup(
|
|
id=generate_uuid(),
|
|
group_name=name,
|
|
tenant_no=tenant_no,
|
|
order_num=order_num if order_num is not None else 0,
|
|
remark=(remark or "").strip() or None,
|
|
create_by=user_id,
|
|
create_dept_id="",
|
|
create_time=now,
|
|
update_by=user_id,
|
|
update_time=now,
|
|
del_flag=0,
|
|
)
|
|
db.add(obj)
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
|
|
def update_group(
|
|
db: Session,
|
|
group_id: str,
|
|
*,
|
|
tenant_no: str,
|
|
group_name: Optional[str] = None,
|
|
order_num: Optional[int] = None,
|
|
remark: Optional[str] = None,
|
|
user_id: Optional[str] = None,
|
|
) -> OaAppGroup:
|
|
obj = get_group(db, group_id, tenant_no)
|
|
if not obj:
|
|
raise ValueError("分组不存在")
|
|
if group_name is not None:
|
|
name = (group_name or "").strip()
|
|
if not name:
|
|
raise ValueError("分组名称不能为空")
|
|
obj.group_name = name
|
|
if order_num is not None:
|
|
obj.order_num = order_num
|
|
if remark is not None:
|
|
obj.remark = (remark or "").strip() or None
|
|
obj.update_by = user_id
|
|
obj.update_time = datetime.now()
|
|
db.add(obj)
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
|
|
def delete_group(db: Session, group_id: str, *, tenant_no: str, user_id: Optional[str] = None) -> None:
|
|
obj = get_group(db, group_id, tenant_no)
|
|
if not obj:
|
|
raise ValueError("分组不存在")
|
|
used = (
|
|
db.query(OaApp.id)
|
|
.filter(OaApp.group_id == group_id, OaApp.tenant_no == tenant_no, OaApp.del_flag == 0)
|
|
.first()
|
|
)
|
|
if used:
|
|
raise ValueError("分组下仍有应用,无法删除")
|
|
obj.del_flag = 1
|
|
obj.update_by = user_id
|
|
obj.update_time = datetime.now()
|
|
db.add(obj)
|
|
db.commit()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 应用 oa_app / 草稿 oa_app_version
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def _app_to_dict(a: OaApp, *, group_name: str = "", has_draft: bool = False, latest_published: Optional[int] = None) -> Dict[str, Any]:
|
|
return {
|
|
"id": a.id,
|
|
"groupId": a.group_id or "",
|
|
"groupName": group_name or "",
|
|
"appName": a.app_name,
|
|
"iconUrl": a.icon_url or "",
|
|
"description": a.description or "",
|
|
"initiatorScope": a.initiator_scope or "all",
|
|
"initiatorUserIds": _loads(a.initiator_user_ids, []),
|
|
"adminScope": a.admin_scope or "all_oa_admin",
|
|
"adminUserIds": _loads(a.admin_user_ids, []),
|
|
"status": a.status,
|
|
"tenantNo": a.tenant_no,
|
|
"orderNum": a.order_num if a.order_num is not None else 0,
|
|
"remark": a.remark or "",
|
|
"hasDraft": has_draft,
|
|
"latestPublishedVersion": latest_published,
|
|
"createTime": a.create_time.strftime("%Y-%m-%d %H:%M:%S") if a.create_time else "",
|
|
"updateTime": a.update_time.strftime("%Y-%m-%d %H:%M:%S") if a.update_time else "",
|
|
}
|
|
|
|
|
|
def get_app(db: Session, app_id: str, tenant_no: str) -> Optional[OaApp]:
|
|
return (
|
|
db.query(OaApp)
|
|
.filter(OaApp.id == app_id, OaApp.tenant_no == tenant_no, OaApp.del_flag == 0)
|
|
.first()
|
|
)
|
|
|
|
|
|
def list_apps(
|
|
db: Session,
|
|
*,
|
|
tenant_no: str,
|
|
group_id: Optional[str] = None,
|
|
keyword: Optional[str] = None,
|
|
status: Optional[str] = None,
|
|
) -> List[Dict[str, Any]]:
|
|
q = db.query(OaApp).filter(OaApp.tenant_no == tenant_no, OaApp.del_flag == 0)
|
|
if group_id:
|
|
q = q.filter(OaApp.group_id == group_id)
|
|
if status:
|
|
q = q.filter(OaApp.status == status)
|
|
kw = (keyword or "").strip()
|
|
if kw:
|
|
like = f"%{kw}%"
|
|
q = q.filter(OaApp.app_name.like(like))
|
|
rows = q.order_by(OaApp.order_num.asc(), OaApp.create_time.desc()).all()
|
|
if not rows:
|
|
return []
|
|
|
|
group_ids = list({r.group_id for r in rows if r.group_id})
|
|
group_names: Dict[str, str] = {}
|
|
if group_ids:
|
|
for g in (
|
|
db.query(OaAppGroup)
|
|
.filter(OaAppGroup.id.in_(group_ids), OaAppGroup.del_flag == 0)
|
|
.all()
|
|
):
|
|
group_names[g.id] = g.group_name
|
|
|
|
app_ids = [r.id for r in rows]
|
|
# 批量取草稿/最新发布版本号,避免 N+1,且不拉取 form/flow 大 JSON
|
|
draft_app_ids = {
|
|
app_id
|
|
for (app_id,) in (
|
|
db.query(OaAppVersion.app_id)
|
|
.filter(
|
|
OaAppVersion.app_id.in_(app_ids),
|
|
OaAppVersion.tenant_no == tenant_no,
|
|
OaAppVersion.status == "draft",
|
|
OaAppVersion.del_flag == 0,
|
|
)
|
|
.distinct()
|
|
.all()
|
|
)
|
|
}
|
|
latest_published: Dict[str, int] = {
|
|
app_id: version_no
|
|
for app_id, version_no in (
|
|
db.query(OaAppVersion.app_id, OaAppVersion.version_no)
|
|
.filter(
|
|
OaAppVersion.app_id.in_(app_ids),
|
|
OaAppVersion.tenant_no == tenant_no,
|
|
OaAppVersion.is_latest_published == "1",
|
|
OaAppVersion.del_flag == 0,
|
|
)
|
|
.all()
|
|
)
|
|
}
|
|
|
|
return [
|
|
_app_to_dict(
|
|
r,
|
|
group_name=group_names.get(r.group_id or "", ""),
|
|
has_draft=r.id in draft_app_ids,
|
|
latest_published=latest_published.get(r.id),
|
|
)
|
|
for r in rows
|
|
]
|
|
|
|
|
|
def _create_version(
|
|
db: Session,
|
|
*,
|
|
app_id: str,
|
|
tenant_no: str,
|
|
version_no: int,
|
|
status: str,
|
|
form_schema: Any,
|
|
flow_tree: Any,
|
|
advanced: Any,
|
|
user_id: Optional[str],
|
|
is_latest_published: str = "0",
|
|
) -> OaAppVersion:
|
|
now = datetime.now()
|
|
ver = OaAppVersion(
|
|
id=generate_uuid(),
|
|
app_id=app_id,
|
|
version_no=version_no,
|
|
status=status,
|
|
is_latest_published=is_latest_published,
|
|
form_schema_json=_dumps(form_schema if form_schema is not None else {}),
|
|
flow_tree_json=_dumps(flow_tree if flow_tree is not None else {}),
|
|
advanced_settings_json=_dumps(advanced if advanced is not None else DEFAULT_ADVANCED_SETTINGS),
|
|
tenant_no=tenant_no,
|
|
order_num=0,
|
|
remark=None,
|
|
create_by=user_id,
|
|
create_dept_id="",
|
|
create_time=now,
|
|
update_by=user_id,
|
|
update_time=now,
|
|
del_flag=0,
|
|
)
|
|
db.add(ver)
|
|
return ver
|
|
|
|
|
|
def create_app(
|
|
db: Session,
|
|
*,
|
|
tenant_no: str,
|
|
app_name: str,
|
|
group_id: Optional[str] = None,
|
|
icon_url: Optional[str] = None,
|
|
description: Optional[str] = None,
|
|
initiator_scope: str = "all",
|
|
initiator_user_ids: Optional[List[str]] = None,
|
|
admin_scope: str = "all_oa_admin",
|
|
admin_user_ids: Optional[List[str]] = None,
|
|
status: str = "1",
|
|
order_num: Optional[int] = None,
|
|
remark: Optional[str] = None,
|
|
user_id: Optional[str] = None,
|
|
) -> OaApp:
|
|
name = (app_name or "").strip()
|
|
if not name:
|
|
raise ValueError("应用名称不能为空")
|
|
if len(name) > 50:
|
|
raise ValueError("应用名称不能超过50字")
|
|
gid = (group_id or "").strip() or None
|
|
if gid and not get_group(db, gid, tenant_no):
|
|
raise ValueError("分组不存在")
|
|
now = datetime.now()
|
|
obj = OaApp(
|
|
id=generate_uuid(),
|
|
group_id=gid,
|
|
app_name=name,
|
|
icon_url=(icon_url or "").strip() or None,
|
|
description=(description or "").strip() or None,
|
|
initiator_scope=initiator_scope or "all",
|
|
initiator_user_ids=_dumps(initiator_user_ids or []),
|
|
admin_scope=admin_scope or "all_oa_admin",
|
|
admin_user_ids=_dumps(admin_user_ids or []),
|
|
status=status or "1",
|
|
tenant_no=tenant_no,
|
|
order_num=order_num if order_num is not None else 0,
|
|
remark=(remark or "").strip() or None,
|
|
create_by=user_id,
|
|
create_dept_id="",
|
|
create_time=now,
|
|
update_by=user_id,
|
|
update_time=now,
|
|
del_flag=0,
|
|
)
|
|
db.add(obj)
|
|
_create_version(
|
|
db,
|
|
app_id=obj.id,
|
|
tenant_no=tenant_no,
|
|
version_no=1,
|
|
status="draft",
|
|
form_schema={},
|
|
flow_tree={},
|
|
advanced=DEFAULT_ADVANCED_SETTINGS,
|
|
user_id=user_id,
|
|
)
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
|
|
def _copied_app_name(source_name: str) -> str:
|
|
"""原名称 +「复制」;超 50 字时截断前缀并保留后缀。"""
|
|
suffix = "复制"
|
|
base = (source_name or "").strip()
|
|
candidate = f"{base}{suffix}"
|
|
if len(candidate) <= 50:
|
|
return candidate
|
|
max_base = max(0, 50 - len(suffix))
|
|
return f"{base[:max_base]}{suffix}"
|
|
|
|
|
|
def copy_app(
|
|
db: Session,
|
|
source_app_id: str,
|
|
*,
|
|
tenant_no: str,
|
|
user_id: Optional[str] = None,
|
|
) -> OaApp:
|
|
"""复制应用:基础信息 + 草稿/最新发布版的表单·流程·高级设置,结果为未发布草稿。"""
|
|
src = get_app(db, source_app_id, tenant_no)
|
|
if not src:
|
|
raise ValueError("应用不存在")
|
|
|
|
source_ver = _find_draft(db, source_app_id, tenant_no) or _find_latest_published(
|
|
db, source_app_id, tenant_no
|
|
)
|
|
if source_ver:
|
|
form_schema = copy.deepcopy(_loads(source_ver.form_schema_json, {}) or {})
|
|
flow_tree = copy.deepcopy(_loads(source_ver.flow_tree_json, {}) or {})
|
|
advanced = copy.deepcopy(
|
|
_loads(source_ver.advanced_settings_json, DEFAULT_ADVANCED_SETTINGS)
|
|
or DEFAULT_ADVANCED_SETTINGS
|
|
)
|
|
else:
|
|
form_schema = {}
|
|
flow_tree = {}
|
|
advanced = dict(DEFAULT_ADVANCED_SETTINGS)
|
|
|
|
now = datetime.now()
|
|
obj = OaApp(
|
|
id=generate_uuid(),
|
|
group_id=src.group_id,
|
|
app_name=_copied_app_name(src.app_name),
|
|
icon_url=src.icon_url,
|
|
description=src.description,
|
|
initiator_scope=src.initiator_scope or "all",
|
|
initiator_user_ids=src.initiator_user_ids,
|
|
admin_scope=src.admin_scope or "all_oa_admin",
|
|
admin_user_ids=src.admin_user_ids,
|
|
status=src.status or "1",
|
|
tenant_no=tenant_no,
|
|
order_num=src.order_num if src.order_num is not None else 0,
|
|
remark=src.remark,
|
|
create_by=user_id,
|
|
create_dept_id="",
|
|
create_time=now,
|
|
update_by=user_id,
|
|
update_time=now,
|
|
del_flag=0,
|
|
)
|
|
db.add(obj)
|
|
_create_version(
|
|
db,
|
|
app_id=obj.id,
|
|
tenant_no=tenant_no,
|
|
version_no=1,
|
|
status="draft",
|
|
form_schema=form_schema,
|
|
flow_tree=flow_tree,
|
|
advanced=advanced,
|
|
user_id=user_id,
|
|
)
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
|
|
def update_app(
|
|
db: Session,
|
|
app_id: str,
|
|
*,
|
|
tenant_no: str,
|
|
app_name: Optional[str] = None,
|
|
group_id: Optional[str] = None,
|
|
icon_url: Optional[str] = None,
|
|
description: Optional[str] = None,
|
|
initiator_scope: Optional[str] = None,
|
|
initiator_user_ids: Optional[List[str]] = None,
|
|
admin_scope: Optional[str] = None,
|
|
admin_user_ids: Optional[List[str]] = None,
|
|
status: Optional[str] = None,
|
|
order_num: Optional[int] = None,
|
|
remark: Optional[str] = None,
|
|
user_id: Optional[str] = None,
|
|
) -> OaApp:
|
|
obj = get_app(db, app_id, tenant_no)
|
|
if not obj:
|
|
raise ValueError("应用不存在")
|
|
if app_name is not None:
|
|
name = (app_name or "").strip()
|
|
if not name:
|
|
raise ValueError("应用名称不能为空")
|
|
if len(name) > 50:
|
|
raise ValueError("应用名称不能超过50字")
|
|
obj.app_name = name
|
|
if group_id is not None:
|
|
gid = (group_id or "").strip() or None
|
|
if gid and not get_group(db, gid, tenant_no):
|
|
raise ValueError("分组不存在")
|
|
obj.group_id = gid
|
|
if icon_url is not None:
|
|
obj.icon_url = (icon_url or "").strip() or None
|
|
if description is not None:
|
|
desc = (description or "").strip()
|
|
if len(desc) > 100:
|
|
raise ValueError("表单说明不能超过100字")
|
|
obj.description = desc or None
|
|
if initiator_scope is not None:
|
|
obj.initiator_scope = initiator_scope
|
|
if initiator_user_ids is not None:
|
|
obj.initiator_user_ids = _dumps(initiator_user_ids)
|
|
if admin_scope is not None:
|
|
obj.admin_scope = admin_scope
|
|
if admin_user_ids is not None:
|
|
obj.admin_user_ids = _dumps(admin_user_ids)
|
|
if status is not None:
|
|
obj.status = status
|
|
if order_num is not None:
|
|
obj.order_num = order_num
|
|
if remark is not None:
|
|
obj.remark = (remark or "").strip() or None
|
|
obj.update_by = user_id
|
|
obj.update_time = datetime.now()
|
|
db.add(obj)
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
|
|
def delete_app(db: Session, app_id: str, *, tenant_no: str, user_id: Optional[str] = None) -> None:
|
|
obj = get_app(db, app_id, tenant_no)
|
|
if not obj:
|
|
raise ValueError("应用不存在")
|
|
now = datetime.now()
|
|
obj.del_flag = 1
|
|
obj.update_by = user_id
|
|
obj.update_time = now
|
|
db.add(obj)
|
|
for ver in (
|
|
db.query(OaAppVersion)
|
|
.filter(OaAppVersion.app_id == app_id, OaAppVersion.tenant_no == tenant_no, OaAppVersion.del_flag == 0)
|
|
.all()
|
|
):
|
|
ver.del_flag = 1
|
|
ver.update_by = user_id
|
|
ver.update_time = now
|
|
db.add(ver)
|
|
db.commit()
|
|
|
|
|
|
def _find_draft(db: Session, app_id: str, tenant_no: str) -> Optional[OaAppVersion]:
|
|
return (
|
|
db.query(OaAppVersion)
|
|
.filter(
|
|
OaAppVersion.app_id == app_id,
|
|
OaAppVersion.tenant_no == tenant_no,
|
|
OaAppVersion.status == "draft",
|
|
OaAppVersion.del_flag == 0,
|
|
)
|
|
.order_by(OaAppVersion.version_no.desc())
|
|
.first()
|
|
)
|
|
|
|
|
|
def _find_latest_published(db: Session, app_id: str, tenant_no: str) -> Optional[OaAppVersion]:
|
|
return (
|
|
db.query(OaAppVersion)
|
|
.filter(
|
|
OaAppVersion.app_id == app_id,
|
|
OaAppVersion.tenant_no == tenant_no,
|
|
OaAppVersion.is_latest_published == "1",
|
|
OaAppVersion.del_flag == 0,
|
|
)
|
|
.first()
|
|
)
|
|
|
|
|
|
def _version_draft_to_dict(app: OaApp, ver: OaAppVersion) -> Dict[str, Any]:
|
|
advanced = _loads(ver.advanced_settings_json, None)
|
|
if not isinstance(advanced, dict):
|
|
advanced = dict(DEFAULT_ADVANCED_SETTINGS)
|
|
else:
|
|
merged = dict(DEFAULT_ADVANCED_SETTINGS)
|
|
merged.update(advanced)
|
|
advanced = merged
|
|
return {
|
|
"appId": app.id,
|
|
"versionId": ver.id,
|
|
"versionNo": ver.version_no,
|
|
"status": ver.status,
|
|
"basic": {
|
|
"groupId": app.group_id or "",
|
|
"appName": app.app_name,
|
|
"iconUrl": app.icon_url or "",
|
|
"description": app.description or "",
|
|
"initiatorScope": app.initiator_scope or "all",
|
|
"initiatorUserIds": _loads(app.initiator_user_ids, []),
|
|
"adminScope": app.admin_scope or "all_oa_admin",
|
|
"adminUserIds": _loads(app.admin_user_ids, []),
|
|
"status": app.status,
|
|
"orderNum": app.order_num if app.order_num is not None else 0,
|
|
"remark": app.remark or "",
|
|
},
|
|
"formSchemaJson": _loads(ver.form_schema_json, {}),
|
|
"flowTreeJson": _loads(ver.flow_tree_json, {}),
|
|
"advancedSettingsJson": advanced,
|
|
"updateTime": ver.update_time.strftime("%Y-%m-%d %H:%M:%S") if ver.update_time else "",
|
|
}
|
|
|
|
|
|
def get_or_create_draft(
|
|
db: Session, app_id: str, *, tenant_no: str, user_id: Optional[str] = None
|
|
) -> Dict[str, Any]:
|
|
app = get_app(db, app_id, tenant_no)
|
|
if not app:
|
|
raise ValueError("应用不存在")
|
|
draft = _find_draft(db, app_id, tenant_no)
|
|
if draft:
|
|
return _version_draft_to_dict(app, draft)
|
|
published = _find_latest_published(db, app_id, tenant_no)
|
|
if published:
|
|
next_no = (published.version_no or 0) + 1
|
|
draft = _create_version(
|
|
db,
|
|
app_id=app_id,
|
|
tenant_no=tenant_no,
|
|
version_no=next_no,
|
|
status="draft",
|
|
form_schema=_loads(published.form_schema_json, {}),
|
|
flow_tree=_loads(published.flow_tree_json, {}),
|
|
advanced=_loads(published.advanced_settings_json, DEFAULT_ADVANCED_SETTINGS),
|
|
user_id=user_id,
|
|
)
|
|
else:
|
|
max_row = (
|
|
db.query(OaAppVersion)
|
|
.filter(OaAppVersion.app_id == app_id, OaAppVersion.tenant_no == tenant_no, OaAppVersion.del_flag == 0)
|
|
.order_by(OaAppVersion.version_no.desc())
|
|
.first()
|
|
)
|
|
next_no = (max_row.version_no if max_row else 0) + 1
|
|
draft = _create_version(
|
|
db,
|
|
app_id=app_id,
|
|
tenant_no=tenant_no,
|
|
version_no=next_no or 1,
|
|
status="draft",
|
|
form_schema={},
|
|
flow_tree={},
|
|
advanced=DEFAULT_ADVANCED_SETTINGS,
|
|
user_id=user_id,
|
|
)
|
|
db.commit()
|
|
db.refresh(draft)
|
|
return _version_draft_to_dict(app, draft)
|
|
|
|
|
|
def save_draft(
|
|
db: Session,
|
|
app_id: str,
|
|
*,
|
|
tenant_no: str,
|
|
basic: Optional[Dict[str, Any]] = None,
|
|
form_schema_json: Any = None,
|
|
flow_tree_json: Any = None,
|
|
advanced_settings_json: Any = None,
|
|
user_id: Optional[str] = None,
|
|
) -> Dict[str, Any]:
|
|
app = get_app(db, app_id, tenant_no)
|
|
if not app:
|
|
raise ValueError("应用不存在")
|
|
# 确保草稿存在
|
|
get_or_create_draft(db, app_id, tenant_no=tenant_no, user_id=user_id)
|
|
draft = _find_draft(db, app_id, tenant_no)
|
|
if not draft:
|
|
raise ValueError("草稿不存在")
|
|
if basic:
|
|
field_map = {
|
|
"appName": "app_name",
|
|
"groupId": "group_id",
|
|
"iconUrl": "icon_url",
|
|
"description": "description",
|
|
"initiatorScope": "initiator_scope",
|
|
"initiatorUserIds": "initiator_user_ids",
|
|
"adminScope": "admin_scope",
|
|
"adminUserIds": "admin_user_ids",
|
|
"status": "status",
|
|
"orderNum": "order_num",
|
|
"remark": "remark",
|
|
}
|
|
kwargs = {field_map[k]: basic[k] for k in field_map if k in basic}
|
|
if kwargs:
|
|
update_app(db, app_id, tenant_no=tenant_no, user_id=user_id, **kwargs)
|
|
app = get_app(db, app_id, tenant_no)
|
|
draft = _find_draft(db, app_id, tenant_no)
|
|
if not draft:
|
|
raise ValueError("草稿不存在")
|
|
now = datetime.now()
|
|
if form_schema_json is not None:
|
|
draft.form_schema_json = _dumps(form_schema_json)
|
|
if flow_tree_json is not None:
|
|
draft.flow_tree_json = _dumps(flow_tree_json)
|
|
if advanced_settings_json is not None:
|
|
if isinstance(advanced_settings_json, dict):
|
|
merged = dict(DEFAULT_ADVANCED_SETTINGS)
|
|
merged.update(advanced_settings_json)
|
|
draft.advanced_settings_json = _dumps(merged)
|
|
else:
|
|
draft.advanced_settings_json = _dumps(advanced_settings_json)
|
|
draft.update_by = user_id
|
|
draft.update_time = now
|
|
db.add(draft)
|
|
db.commit()
|
|
db.refresh(draft)
|
|
assert app is not None
|
|
return _version_draft_to_dict(app, draft)
|