提交 3bd89fc5 authored 作者: 陈泽健's avatar 陈泽健

Merge remote-tracking branch 'origin/develop' into develop

# Conflicts:
#	.gitignore
#	AuxiliaryTool/ScriptTool/问题处理/kkfile_https调试脚本/analyze_options.py
#	AuxiliaryTool/ScriptTool/问题处理/kkfile_https调试脚本/build_agent_correct.py
#	AuxiliaryTool/ScriptTool/问题处理/kkfile_https调试脚本/build_agent_in_container.py
#	AuxiliaryTool/ScriptTool/问题处理/kkfile_https调试脚本/build_with_temp_container.py
#	AuxiliaryTool/ScriptTool/问题处理/kkfile_https调试脚本/check_nginx_modules.py
#	AuxiliaryTool/ScriptTool/问题处理/kkfile_https调试脚本/check_nginx_real_config.py
#	AuxiliaryTool/ScriptTool/问题处理/kkfile_https调试脚本/correct_https_test.py
#	AuxiliaryTool/ScriptTool/问题处理/kkfile_https调试脚本/create_jar.py
#	AuxiliaryTool/ScriptTool/问题处理/kkfile_https调试脚本/get_kkfile_nginx.py
#	AuxiliaryTool/ScriptTool/问题处理/kkfile_https调试脚本/implement_agent.py
#	AuxiliaryTool/ScriptTool/问题处理/kkfile_https调试脚本/nginx_url_rewrite_test.py
#	AuxiliaryTool/ScriptTool/问题处理/kkfile_https调试脚本/parse_nginx_single_line.py
#	AuxiliaryTool/ScriptTool/问题处理/kkfile_https调试脚本/plan_agent.py
#	AuxiliaryTool/ScriptTool/问题处理/kkfile_https调试脚本/read_from_host.py
#	AuxiliaryTool/ScriptTool/问题处理/kkfile_https调试脚本/read_nginx_direct.py
#	AuxiliaryTool/ScriptTool/问题处理/kkfile_https调试脚本/real_browser_test.py
#	AuxiliaryTool/ScriptTool/问题处理/kkfile_https调试脚本/rebuild_agent.py
#	AuxiliaryTool/ScriptTool/问题处理/kkfile_https调试脚本/rebuild_clean.py
#	AuxiliaryTool/ScriptTool/问题处理/kkfile_https调试脚本/view_kkfile_block.py
......@@ -387,6 +387,19 @@ def generate_report_main(
print(f" [X] 项目资料上传失败,请查看日志")
else:
print(f" [!] 跳过项目资料上传")
# 询问是否上传到协作文档(创建OnlyOffice在线协作文档)
from src.erp_uploader import ask_cooperation_upload_confirmation_cli, upload_file_to_cooperation
coop_confirmed, coop_project_id, coop_file_name = ask_cooperation_upload_confirmation_cli(report_path)
if coop_confirmed:
print(f"\n正在上传报告到ERP协作文档(项目ID: {coop_project_id})...")
coop_info = upload_file_to_cooperation(report_path, coop_project_id, coop_file_name, logger)
if coop_info:
print(f" [OK] 报告已成功上传到ERP协作文档(协作文档ID: {coop_info.get('id')})")
else:
print(f" [X] 协作文档上传失败,请查看日志")
else:
print(f" [!] 跳过协作文档上传")
else:
print(f" [X] 报告上传失败,请查看日志")
else:
......
......@@ -333,7 +333,8 @@ ERP_MAX_RETRIES = 3
ERP_UPLOAD_IMAGE_URL = "/openclaw/upload/richtext" # 上传图片接口路径
ERP_CREATE_REPORT_URL = "/openclaw/report" # 创建报告接口路径
ERP_STUFF_URL = "/openclaw/stuff" # 获取人员列表接口路径
ERP_UPLOAD_PROJECT_URL = "/openclaw/upload/project" # 项目资料上传接口路径
ERP_UPLOAD_PROJECT_URL = "/openclaw/upload/project" # 项目资料上传接口路径(fileGroup_id=4,仅归档,不创建协作)
ERP_UPLOAD_COOPERATION_URL = "/openclaw/upload/cooperation" # 协作文档上传接口路径(fileGroup_id=1,创建OnlyOffice在线协作文档)
# 请求超时时间(秒)
ERP_REQUEST_TIMEOUT = 30
......
......@@ -29,6 +29,7 @@ from src.config import (
ERP_CREATE_REPORT_URL,
ERP_STUFF_URL,
ERP_UPLOAD_PROJECT_URL,
ERP_UPLOAD_COOPERATION_URL,
ERP_REQUEST_TIMEOUT,
ERP_SAVE_IMAGES_TEMP,
ERP_VALIDATE_IMAGES,
......@@ -669,6 +670,196 @@ def upload_file_to_project(file_path: str, project_id: int, name: str, logger: l
return None
def upload_file_to_cooperation(file_path: str, project_id: int, name: str, logger: logging.Logger = None, group_id: Optional[int] = None) -> Optional[dict]:
"""
上传文件到ERP协作文档(创建OnlyOffice在线协作文档),含重试机制
与项目资料上传不同,协作文档上传会在ERP中创建OnlyOffice在线协作文档,
返回结果中包含 fileKey/filePath/sharePath 等协作信息,支持多人在线协作编辑。
Args:
file_path: 要上传的文件路径(推荐 .docx/.xlsx/.pptx/.pdf)
project_id: 关联的项目ID
name: 文件名称(留空使用原文件名)
logger: 日志记录器(可选,默认创建新的logger)
group_id: 分组ID(可选,可将文件归类到指定分组)
Returns:
上传成功返回协作文档信息字典,失败返回None
文件信息格式: {'id': int, 'file_id': int, 'name': str, 'fileKey': str,
'filePath': str, 'fileType': str, 'fileSize': int,
'sharePath': str, 'project_id': int}
"""
# 如果没有提供logger,创建新的logger
if logger is None:
logger = setup_logger()
url = f'{ERP_BASE_URL}{ERP_UPLOAD_COOPERATION_URL}'
logger.info("=" * 50)
logger.info("协作文档上传流程开始")
logger.info(f"文件路径: {file_path}")
logger.info(f"项目ID: {project_id}")
logger.info(f"文件名称: {name}")
if group_id is not None:
logger.info(f"分组ID: {group_id}")
logger.info("=" * 50)
# 验证文件存在
if not os.path.exists(file_path):
logger.error(f"✗ 文件不存在: {file_path}")
return None
# 获取文件大小
file_size = os.path.getsize(file_path)
logger.info(f"文件大小: {file_size} bytes ({file_size / 1024:.2f} KB)")
for attempt in range(ERP_MAX_RETRIES):
try:
# 准备请求参数(multipart/form-data)
data = {
'project_id': project_id,
'name': name
}
# 分组ID为可选参数,仅在传入时提交
if group_id is not None:
data['group_id'] = group_id
headers = {'X-Api-Key': ERP_API_KEY}
# 打印请求信息
logger.info(f"=== 协作文档上传请求 ===")
logger.info(f"请求URL: {url}")
logger.info(f"请求Headers: X-Api-Key={ERP_API_KEY[:10]}...")
logger.info(f"请求参数:")
logger.info(f" - project_id: {project_id}")
logger.info(f" - name: {name}")
if group_id is not None:
logger.info(f" - group_id: {group_id}")
logger.info(f" - file: {file_path}")
# 读取文件并上传
with open(file_path, 'rb') as f:
files = {'file': (os.path.basename(file_path), f, 'application/octet-stream')}
# 发送请求
resp = requests.post(
url,
headers=headers,
files=files,
data=data,
timeout=ERP_REQUEST_TIMEOUT
)
# 打印响应信息
logger.info(f"响应状态码: {resp.status_code}")
logger.info(f"响应内容: {resp.text}")
result = resp.json()
if result.get('success') == 1:
file_info = result['data']
logger.info(f"✓ 协作文档上传成功!")
logger.info(f" - 协作文档ID: {file_info.get('id')}")
logger.info(f" - 源文件ID: {file_info.get('file_id')}")
logger.info(f" - 文件名称: {file_info.get('name')}")
logger.info(f" - 协作密钥(fileKey): {file_info.get('fileKey')}")
logger.info(f" - 协作路径(filePath): {file_info.get('filePath')}")
logger.info(f" - 文件类型: {file_info.get('fileType')}")
logger.info(f" - 文件大小: {file_info.get('fileSize')} bytes")
logger.info(f" - 分享路径(sharePath): {file_info.get('sharePath')}")
logger.info(f" - 项目ID: {file_info.get('project_id')}")
return file_info
else:
error_code = result.get('error', 0)
# 4xx错误(客户端错误,如权限不足、Key无效)不重试
if 400 <= error_code < 500:
logger.error(f"✗ 协作文档上传失败(客户端错误 {error_code}): {result.get('msg')}")
# 针对权限不足(40000015)给出明确提示
if error_code == 40000015:
logger.error(" → 提示:请确认 API Key 已授权 upload_cooperation 权限")
return None
if attempt < ERP_MAX_RETRIES - 1:
logger.warning(f"协作文档上传失败,{ERP_RETRY_INTERVAL}秒后重试({attempt+1}/{ERP_MAX_RETRIES}): {result.get('msg')}")
time.sleep(ERP_RETRY_INTERVAL)
else:
logger.error(f"✗ 协作文档上传失败(已达最大重试次数): {result.get('msg')}")
except requests.exceptions.Timeout:
logger.warning(f"协作文档上传超时,{ERP_RETRY_INTERVAL}秒后重试({attempt+1}/{ERP_MAX_RETRIES})")
if attempt < ERP_MAX_RETRIES - 1:
time.sleep(ERP_RETRY_INTERVAL)
else:
logger.error(f"✗ 协作文档上传超时(已达最大重试次数)")
except Exception as e:
logger.error(f"✗ 协作文档上传异常: {str(e)}")
break
return None
def ask_cooperation_upload_confirmation_cli(report_path: str) -> Tuple[bool, Optional[int], Optional[str]]:
"""
控制台交互:询问用户是否上传报告到ERP协作文档
Args:
report_path: 报告文件路径
Returns:
元组 (用户选择, 项目ID, 文件名称)
- (True, int, str) 用户确认上传
- (False, None, None) 用户选择不上传
"""
while True:
print(f"\n{'='*50}")
print(f"是否将报告上传到ERP协作文档?(将创建OnlyOffice在线协作文档)")
print(f"{'='*50}")
print(f"报告文件: {report_path}")
choice = input("请输入 Y/N (默认=N): ").strip().upper()
if not choice:
choice = 'N'
if choice == 'Y':
# 输入项目ID
project_id = None
while True:
id_input = input("请输入项目ID: ").strip()
if not id_input:
print("项目ID不能为空,请重新输入")
continue
try:
project_id = int(id_input)
if project_id > 0:
break
else:
print("项目ID必须为正整数,请重新输入")
except ValueError:
print("输入无效,请输入数字")
# 输入文件名称
file_name = None
while True:
name_input = input("请输入文件名称(直接回车使用原文件名): ").strip()
if not name_input:
# 使用原文件名(去掉扩展名)
import os
file_name = os.path.splitext(os.path.basename(report_path))[0]
print(f"使用原文件名: {file_name}")
break
else:
file_name = name_input
break
return True, project_id, file_name
elif choice == 'N':
return False, None, None
else:
print("输入错误,请输入 Y 或 N")
def ask_upload_confirmation_cli(report_path: str) -> Tuple[bool, Optional[int], Optional[list], Optional[int]]:
"""
控制台交互:询问用户是否上传报告到ERP,输入测试单ID、抄送人和创建人
......
#!/usr/bin/env python
import paramiko
def run(ssh, cmd):
stdin, stdout, stderr = ssh.exec_command(cmd)
return stdout.read().decode('utf-8'), stderr.read().decode('utf-8')
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect("192.168.5.70", 22, "root", "Ubains@123", timeout=10)
# 直接读取配置文件并搜索kkfile相关行
out, _ = run(ssh, "docker exec unginx grep -n kkfile /data/middleware/nginx/config/unified443.conf")
print(f"kkfile相关行号:\n{out}")
# 用行号范围读取
print("\n完整配置内容(用grep定位):")
out, _ = run(ssh, "docker exec unginx cat /data/middleware/nginx/config/unified443.conf | grep -A30 'location /kkfile'")
print(out)
ssh.close()
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""实施方案D:Java Agent禁用SSL主机名验证"""
import paramiko, time
def run(ssh, cmd):
stdin, stdout, stderr = ssh.exec_command(cmd)
return stdout.read().decode('utf-8'), stderr.read().decode('utf-8')
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect("192.168.5.70", 22, "root", "Ubains@123", timeout=10)
print("1. 创建Java Agent源代码...")
agent_code = '''
import javax.net.ssl.*;
import java.security.cert.X509Certificate;
import java.lang.instrument.Instrumentation;
public class SSLBypassAgent {
public static void premain(String args, Instrumentation inst) {
try {
// 创建信任所有证书的TrustManager
TrustManager[] trustAll = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() { return null; }
public void checkClientTrusted(X509Certificate[] c, String a) {}
public void checkServerTrusted(X509Certificate[] c, String a) {}
}
};
// 设置SSL上下文
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAll, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// 禁用主机名验证
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
System.out.println("[SSLBypassAgent] SSL hostname verification disabled");
} catch (Exception e) {
e.printStackTrace();
}
}
}
'''
manifest = '''Manifest-Version: 1.0
Premain-Class: SSLBypassAgent
Can-Redefine-Classes: false
'''
# 写入Java源码
run(ssh, f"cat > /tmp/SSLBypassAgent.java << 'JAVAEOF'\n{agent_code}\nJAVAEOF")
print("源码已写入 /tmp/SSLBypassAgent.java")
# 写入MANIFEST
run(ssh, f"mkdir -p /tmp/META-INF && cat > /tmp/META-INF/MANIFEST.MF << 'MFEOF'\n{manifest}\nMFEOF")
print("MANIFEST已创建")
print("\n2. 编译Java Agent...")
# 编译
out, err = run(ssh, "javac /tmp/SSLBypassAgent.java -d /tmp/")
if err and "error" in err.lower():
print(f"编译错误: {err}")
else:
print("编译成功")
print("\n3. 打包成JAR...")
out, err = run(ssh, "cd /tmp && jar cfm ssl-bypass-agent.jar META-INF/MANIFEST.MF SSLBypassAgent.class")
if err:
print(f"打包错误: {err}")
else:
print("打包成功: /tmp/ssl-bypass-agent.jar")
print("\n4. 复制到容器内...")
run(ssh, "docker cp /tmp/ssl-bypass-agent.jar kkfile:/opt/ssl-bypass-agent.jar")
print("已复制到容器: /opt/ssl-bypass-agent.jar")
print("\n5. 修改wrapper启动脚本...")
wrapper = '''#!/bin/bash
rm -rf /tmp/.jodconverter* /tmp/hsperfdata* 2>/dev/null
exec java -javaagent:/opt/ssl-bypass-agent.jar -Dfile.encoding=UTF-8 -Dspring.config.location=/opt/kkFileView-4.1.0/config/application.properties -jar /opt/kkFileView-4.1.0/bin/kkFileView-4.1.0.jar
'''
run(ssh, f"docker exec kkfile bash -c 'cat > /opt/start.sh << \"EOF\"\n{wrapper}\nEOF'")
run(ssh, "docker exec kkfile chmod +x /opt/start.sh")
print("wrapper已更新,添加了 -javaagent 参数")
print("\n6. 提交镜像...")
out, _ = run(ssh, "docker commit kkfile kkfile-with-agent:latest")
print(f"镜像: {out.strip()}")
print("\n7. 重启容器...")
run(ssh, "docker restart kkfile")
print("等待70秒...")
time.sleep(70)
print("\n8. 验证...")
out, _ = run(ssh, "docker logs kkfile 2>&1 | grep -E 'SSLBypassAgent|启动完成' | tail -2")
print(out if out else "检查日志...")
out, _ = run(ssh, "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8012/index")
print(f"HTTP状态: {out}")
ssh.close()
# 报告生成优化需求文档
## 代码路径
- 代码路径:[AuxiliaryTool/FunctionalTestReportGeneration]
## ERP对接文档
- 需求文档路径:[Docs/PRD/自动化生成功能测试报告/ERP对接PRD/PRD_项目资料_上传接口_例子说明.md]
## 功能需求
### 功能目标
**目标:** 对接ERP项目协作文档上传接口,实现创建完成ERP测试报告后,将测试报告文件上传至ERP项目协作文档上传中。
### 需求描述
- 上传项目资料接口:
- 根据[Docs/PRD/自动化生成功能测试报告/ERP对接PRD/PRD_项目资料_上传接口_例子说明.md]### 4.1 协作文档上传章节。
- 接口调用地址:https://office.ubainsyun.com:5082/api/uerp/openclaw/upload/cooperation
- X-Api-Key: 保持原有的key传入就行。
- 请求示例:
```bash
curl -X POST "https://office.ubainsyun.com:5082/uerp/openclaw/upload/cooperation" \
-H "X-Api-Key: your_api_key" \
-F "file=@/path/to/需求文档.pdf" \
-F "project_id=100" \
-F "name=项目需求文档"
```
- project_id和name通过用户输入。
- file就直接采用生产的测试报告word格式即可。
- 新增选项`上传协作文档`
## 规范文档
- 代码规范: `Docs/PRD/01规范文档/_PRD_规范文档_代码规范.md`
- 问题总结: `Docs/PRD/01规范文档/_PRD_问题总结_记录文档.md`
- 方法总结: `Docs/PRD/01规范文档/_PRD_方法总结_记录文档.md`
- 文档规范: `Docs/PRD/01规范文档/_PRD_规范文档_文档规范.md`
- 测试规范: `Docs/PRD/01规范文档/_PRD_规范文档_测试规范.md`
---
\ No newline at end of file
# 主服务端口切换需求文档
## 代码路径
- X86架构:
- 需调用代码路径:[自动化部署脚本/x86架构/新统一平台/auto_check_service_ports.sh]
- 主脚本:[自动化部署脚本/x86架构/新统一平台/new_auto.sh]
- ARM架构:
- 需调用代码路径:[自动化部署脚本/ARM架构/新统一平台/auto_check_service_ports.sh]
- 主脚本:[自动化部署脚本/ARM架构/新统一平台/new_auto.sh]
## 功能需求
### 功能目标
**目标:** middleware脚本
### 需求描述
-
## 规范文档
- 代码规范: `Docs/PRD/01规范文档/_PRD_规范文档_代码规范.md`
- 问题总结: `Docs/PRD/01规范文档/_PRD_问题总结_记录文档.md`
- 方法总结: `Docs/PRD/01规范文档/_PRD_方法总结_记录文档.md`
- 文档规范: `Docs/PRD/01规范文档/_PRD_规范文档_文档规范.md`
- 测试规范: `Docs/PRD/01规范文档/_PRD_规范文档_测试规范.md`
---
\ No newline at end of file
# 服务部署脚本优化
## 代码路径
- deploy服务部署脚本:[自动化部署脚本/x86架构/新统一平台/auto_deploy_services.sh]
- 主脚本:[自动化部署脚本/x86架构/新统一平台/new_auto.sh]
- X86架构:
- deploy服务部署脚本:[自动化部署脚本/x86架构/新统一平台/auto_deploy_services.sh]
- 主脚本:[自动化部署脚本/x86架构/新统一平台/new_auto.sh]
- ARM架构:
- deploy服务部署脚本:[自动化部署脚本/arm架构/新统一平台/arm_auto_deploy_services.sh]
- 主脚本:[自动化部署脚本/arm架构/新统一平台/arm_new_auto.sh]
## 功能需求
### 功能目标
......
......@@ -614,6 +614,159 @@ configure_firewall_for_9990() {
return 0
}
# 配置电子桌牌色彩型号(三色/四色)
# 说明:桌牌的显示参数 color/epd_type 配置在 java-meeting(预定系统)的 sensitive-config.json 中,
# 配置修改即时生效,java-meeting 无需重启即可读取新参数。
# 色彩型号对应关系:
# 三色:color=3, epd_type=1(默认,保持不变)
# 四色:color=4, epd_type=9
# 环境变量 CARDTABLE_COLOR_MODE(由 deploy_services 在 "all" 非交互模式设置):
# 非空时直接采用该值("3" 或 "4"),跳过 whiptail 交互菜单。
# 容错策略:
# - 配置文件缺失 → 仅告警,不中断桌牌容器部署
# - 修改工具采用 jq → python3 → awk 降级链,适配统信 UOS / 欧拉 / 麒麟 等不同操作系统
function configure_tablecard_color() {
local config_file="/data/services/api/java-meeting/java-meeting2.0/config/sensitive-config.json"
log "INFO" "🎨 开始配置电子桌牌色彩型号..."
# 1. 校验配置文件是否存在(缺失仅告警,不中断部署)
if [ ! -f "$config_file" ]; then
log "WARN" "⚠️ 未找到桌牌配置文件: $config_file"
log "WARN" " 请确认已部署预定系统(java-meeting);本次跳过色彩配置,继续部署桌牌容器。"
return 0
fi
# 2. 确定色彩型号:非交互模式用 CARDTABLE_COLOR_MODE / 交互模式弹 whiptail 菜单
local color_choice=""
if [ -n "$CARDTABLE_COLOR_MODE" ]; then
# 非交互模式(all 自动部署),直接采用预设型号(默认三色)
color_choice="$CARDTABLE_COLOR_MODE"
log "INFO" "🤖 非交互模式,桌牌色彩采用预设型号:${color_choice} 色"
else
# 交互模式:弹出色彩选择菜单
color_choice=$(whiptail --title "🎨 电子桌牌色彩型号选择" \
--menu "\n请选择电子桌牌的色彩型号:" \
14 60 2 \
"3" "三色 (color=3, epd_type=1) 默认" \
"4" "四色 (color=4, epd_type=9)" \
3>&1 1>&2 2>&3)
local whiptail_rc=$?
# 用户取消或 ESC:默认三色
if [ "$whiptail_rc" -ne 0 ] || [ -z "$color_choice" ]; then
log "WARN" "⚠️ 用户未选择色彩型号,默认采用三色 (color=3, epd_type=1)"
color_choice="3"
fi
fi
# 3. 映射为目标参数值
local target_color="" target_epd=""
case "$color_choice" in
3)
target_color="3"
target_epd="1"
;;
4)
target_color="4"
target_epd="9"
;;
*)
log "WARN" "⚠️ 未知色彩选项: $color_choice,默认采用三色"
target_color="3"
target_epd="1"
;;
esac
log "INFO" "🎯 目标桌牌参数:color=${target_color}, epd_type=${target_epd}"
# 4. 修改前备份配置文件
local backup_file="${config_file}.bak"
if cp "$config_file" "$backup_file"; then
log "INFO" "💾 已备份配置文件: $backup_file"
else
log "WARN" "⚠️ 配置文件备份失败,将继续修改(建议手动备份)"
fi
# 5. 多工具降级链修改 tableCard.color / tableCard.epd_type(适配不同操作系统)
# 优先级:jq → python3 → awk(节点级/块内精确修改,避免误伤其它 color 字段)
local modify_ok=0
# 优先级 1:jq
if [ "$modify_ok" -eq 0 ] && command -v jq >/dev/null 2>&1; then
local jq_tmp="${config_file}.jq.tmp"
if jq --arg c "$target_color" --arg e "$target_epd" \
'(.tableCard.color)=($c|tonumber) | (.tableCard.epd_type)=($e|tonumber)' \
"$config_file" > "$jq_tmp" 2>/dev/null && [ -s "$jq_tmp" ]; then
mv "$jq_tmp" "$config_file"
modify_ok=1
log "INFO" "✅ 已通过 jq 修改桌牌色彩配置"
else
rm -f "$jq_tmp"
log "WARN" "⚠️ jq 不可用或修改失败,尝试下一工具"
fi
fi
# 优先级 2:python3(标准库 json,ensure_ascii=False 保持中文不转义)
if [ "$modify_ok" -eq 0 ] && command -v python3 >/dev/null 2>&1; then
if python3 - "$config_file" "$target_color" "$target_epd" <<'PYEOF' >/dev/null 2>&1
import json, sys
path, color, epd = sys.argv[1], int(sys.argv[2]), int(sys.argv[3])
with open(path, 'r', encoding='utf-8') as f:
data = json.load(f)
tc = data.get("tableCard")
if not isinstance(tc, dict):
sys.exit(1)
tc["color"] = color
tc["epd_type"] = epd
with open(path, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=4)
PYEOF
then
modify_ok=1
log "INFO" "✅ 已通过 python3 修改桌牌色彩配置"
else
log "WARN" "⚠️ python3 不可用或修改失败,尝试下一工具"
fi
fi
# 优先级 3:awk 作用域替换(仅在 tableCard 块内替换 color/epd_type,所有 Linux 必有)
if [ "$modify_ok" -eq 0 ]; then
local awk_tmp="${config_file}.awk.tmp"
if awk -v tc="$target_color" -v te="$target_epd" '
BEGIN { in_block = 0 }
{
if ($0 ~ /"tableCard"[[:space:]]*:/) { in_block = 1 }
if (in_block == 1) {
if ($0 ~ /^[[:space:]]*"color"[[:space:]]*:/) {
sub(/:[[:space:]]*[0-9]+/, ": " tc)
} else if ($0 ~ /^[[:space:]]*"epd_type"[[:space:]]*:/) {
sub(/:[[:space:]]*[0-9]+/, ": " te)
}
if ($0 ~ /\}/) { in_block = 0 }
}
print
}' "$config_file" > "$awk_tmp" 2>/dev/null && [ -s "$awk_tmp" ]; then
mv "$awk_tmp" "$config_file"
modify_ok=1
log "INFO" "✅ 已通过 awk 修改桌牌色彩配置"
else
rm -f "$awk_tmp"
log "WARN" "⚠️ awk 修改失败"
fi
fi
# 6. 修改结果处理(失败仅告警,不中断桌牌容器部署)
if [ "$modify_ok" -eq 0 ]; then
log "ERROR" "❌ 桌牌色彩配置修改失败(jq/python3/awk 均不可用或失败)"
log "ERROR" " 请手动修改 $config_file:tableCard.color=${target_color}, tableCard.epd_type=${target_epd}"
return 0
fi
log "INFO" "✅ 桌牌色彩配置完成:color=${target_color}, epd_type=${target_epd}(即时生效,无需重启 java-meeting)"
return 0
}
function cardtable_arm() {
local service_name="电子桌牌服务 (cardtable)"
local container_name="cardtable"
......@@ -639,6 +792,10 @@ function cardtable_arm() {
return 1
fi
# 【新增步骤】选择并配置电子桌牌色彩型号(三色/四色)
# 修改的是预定系统 java-meeting 的桌牌显示参数,配置即时生效、无需重启。
configure_tablecard_color
# 1. 检查镜像压缩包是否存在
if [ ! -f "$image_tar" ]; then
log "ERROR" "❌ 镜像文件不存在: $image_tar"
......@@ -800,6 +957,10 @@ function deploy_services() {
log "INFO" "🤖 收到 'all' 参数,自动部署所有系统"
allowed_numbers=(1 2 3 4 5)
# 非交互模式:桌牌色彩采用默认三色(跳过 whiptail 交互菜单)
# 说明:bash 动态作用域下,该 local 变量对 cardtable_arm → configure_tablecard_color 可见
local CARDTABLE_COLOR_MODE="3"
# 直接跳到部署流程,跳过所有交互界面
log "INFO" "=================================================="
log "INFO" "🚀 开始自动部署所有系统"
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论