提交 78fe6ffc authored 作者: 陈泽健's avatar 陈泽健

```

feat(update): 添加程序更新脚本重启功能和代码规范文档

- 新增 --restart-only 参数支持仅重启服务而不执行更新
- 实现会议预定系统对外后端宿主机启动/重启逻辑
- 添加传统平台服务重启和验证更新成功的完整流程
- 实现运维集控系统和讯飞转录系统后端容器重启功能
- 优化脚本结构支持调试模式下仅运行重启逻辑
- 添加代码规范文档明确注释要求使用中文
- 创建PRD方法总结记录文档用于claude code自动化
- 更新程序更新脚本的需求文档完善部署流程说明
```
上级 1c1e9480
......@@ -26,6 +26,7 @@ PLATFORM=""
SYSTEM=""
UPDATE_TYPE=""
WORKDIR="/home/Update"
RESTART_ONLY=0
while [[ $# -gt 0 ]]; do
case "$1" in
......@@ -33,6 +34,7 @@ while [[ $# -gt 0 ]]; do
--system) SYSTEM="${2:-}"; shift 2;;
--update) UPDATE_TYPE="${2:-}"; shift 2;;
--workdir) WORKDIR="${2:-}"; shift 2;;
--restart-only) RESTART_ONLY=1; shift 1;;
-h|--help) usage; exit 0;;
*) log "Unknown arg: $1"; usage; exit 2;;
esac
......@@ -43,13 +45,16 @@ if [[ -z "$PLATFORM" || -z "$SYSTEM" || -z "$UPDATE_TYPE" ]]; then
exit 2
fi
TS="$(date '+%Y%m%d_%H%M%S')"
BACKUP_ROOT="/home/Backup"
BACKUP_DIR="${BACKUP_ROOT}/Bak${TS}"
BACKUP_TAR="${BACKUP_ROOT}/Bak${TS}.tar.gz"
# 仅在非 RESTART_ONLY 时初始化备份目录(避免 restart-only 还创建备份目录)
if [[ "$RESTART_ONLY" -eq 0 ]]; then
TS="$(date '+%Y%m%d_%H%M%S')"
BACKUP_ROOT="/home/Backup"
BACKUP_DIR="${BACKUP_ROOT}/Bak${TS}"
BACKUP_TAR="${BACKUP_ROOT}/Bak${TS}.tar.gz"
mkdir -p "$BACKUP_DIR"
log "Backup dir: $BACKUP_DIR"
mkdir -p "$BACKUP_DIR"
log "Backup dir: $BACKUP_DIR"
fi
# PRD 指定数据库密码(固定值)
MYSQL_ROOT_PASSWORD='dNrprU&2S'
......@@ -215,8 +220,9 @@ resolve_workdir() {
echo "$base"
}
WORKDIR="$(resolve_workdir "$WORKDIR")"
log "WORKDIR_RESOLVED=$WORKDIR"
if [[ "$RESTART_ONLY" -eq 0 ]]; then
WORKDIR="$(resolve_workdir "$WORKDIR")"
log "WORKDIR_RESOLVED=$WORKDIR"
# 3.3 备份前端/后端(按更新类型)
if [[ "$UPDATE_TYPE" == "前端更新" || "$UPDATE_TYPE" == "全量更新" ]]; then
......@@ -271,6 +277,9 @@ backup_db() {
backup_db "$DB_NAME"
else
log "RESTART_ONLY=1 -> skip WORKDIR resolve/backup/db/update"
fi
# -------------------- 3.4 更新服务(传统平台) --------------------
# 精准覆盖:仅把 sourceDir 中匹配的文件/目录覆盖到 targetDir(不删除 targetDir 里其它内容)
# 用法:sync_overwrite_globs "/src" "/dst" "label" "glob1" "glob2" ...
......@@ -448,6 +457,173 @@ sync_backend_dir_preserve() {
shopt -u dotglob nullglob
}
# 宿主机对外后端启动/重启逻辑(external-meeting-api)
# - 不依赖 run.sh 可执行位(用 sh 解释执行;run.sh 为 #!/bin/sh)
# - 执行后等待最多 30 秒做一次“进程检测”(基于 jar 名关键字)
restart_external_meeting_api_host() {
local app_dir="/var/www/java/external-meeting-api"
local run_sh="${app_dir}/run.sh"
log "Restart external-meeting-api (host):"
log " cd $app_dir"
log " sh ./run.sh"
if [[ ! -d "$app_dir" ]]; then
log "WARN: external app dir not found: $app_dir"
return 0
fi
if [[ ! -f "$run_sh" ]]; then
log "WARN: external run.sh not found: $run_sh"
return 0
fi
(
set +e
cd "$app_dir" || exit 1
sh ./run.sh
ec=$?
log "External sh ./run.sh exitCode=$ec"
exit 0
) || true
# --- verify (best-effort) ---
local i
for i in {1..30}; do
if ps -ef | grep -F 'ubains-meeting-api-1.0-SNAPSHOT.jar' | grep -v grep >/dev/null; then
log "External service process detected."
return 0
fi
sleep 1
done
log "WARN: External service process NOT detected after 30s."
log "WARN: ps snapshot:"
ps -ef | grep -E 'ubains-meeting-api|external-meeting-api|java' | grep -v grep | head -n 20 || true
}
# ========== 3.5 重启服务并验证更新是否成功 ==========
restart_services_traditional() {
case "$SYSTEM" in
"会议预定系统")
if [[ "$UPDATE_TYPE" == "前端更新" ]]; then
log "Skip restart (frontend update only)."
return 0
fi
log "Restart services: 会议预定系统"
# ========== 1) 对外后端:宿主机执行 run.sh ==========
# 对外后端(宿主机)重启
restart_external_meeting_api_host
# ========== 2) 对内后端:优先进入 java 容器内执行 run.sh ==========
log "PRD 3.5 internal (preferred in java container ujava*):"
log " docker exec -it ujavaX bash"
log " cd /var/www/java/api-java-meeting2.0"
log " bash ./run.sh; tail -f logs/ubains-INFO-AND-ERROR.log"
local java_container=""
if command -v docker >/dev/null 2>&1; then
java_container="$(docker ps --format '{{.Names}}' | grep -E '^ujava[0-9]*$' | head -n 1 || true)"
if [[ -z "$java_container" ]]; then
java_container="$(docker ps -a --format '{{.Names}}' | grep -E '^ujava[0-9]*$' | head -n 1 || true)"
fi
if [[ -n "$java_container" ]]; then
log "Detected java container: $java_container"
log "Restart (in container $java_container): /var/www/java/api-java-meeting2.0/run.sh (force bash)"
docker exec "$java_container" bash -lc "cd /var/www/java/api-java-meeting2.0 && bash ./run.sh" || true
log "Verify process (in container $java_container): ps -ef | grep api-java-meeting2.0"
docker exec "$java_container" bash -lc "ps -ef | grep -E 'api-java-meeting2\.0|meeting' | grep -v grep | head -n 5" || true
else
log "WARN: java container (ujava*) not found, fallback to host restart"
if [[ -d "/var/www/java/api-java-meeting2.0" && -f "/var/www/java/api-java-meeting2.0/run.sh" ]]; then
log "Restart (host fallback): /var/www/java/api-java-meeting2.0/run.sh (force bash)"
( cd /var/www/java/api-java-meeting2.0 && bash ./run.sh ) || true
else
log "WARN: api-java-meeting2.0 run.sh not found (host fallback)"
fi
fi
else
log "WARN: docker not found, fallback to host restart"
if [[ -d "/var/www/java/api-java-meeting2.0" && -f "/var/www/java/api-java-meeting2.0/run.sh" ]]; then
log "Restart (host fallback): /var/www/java/api-java-meeting2.0/run.sh (force bash)"
( cd /var/www/java/api-java-meeting2.0 && bash ./run.sh ) || true
else
log "WARN: api-java-meeting2.0 run.sh not found (host fallback)"
fi
fi
# ========== 3) 验证日志 ==========
if [[ -f "/var/www/java/external-meeting-api/logs/ubains-INFO-AND-ERROR.log" ]]; then
log "Verify log (external): tail -n 50 /var/www/java/external-meeting-api/logs/ubains-INFO-AND-ERROR.log"
tail -n 50 /var/www/java/external-meeting-api/logs/ubains-INFO-AND-ERROR.log || true
else
log "WARN: external log file not found: /var/www/java/external-meeting-api/logs/ubains-INFO-AND-ERROR.log"
fi
if [[ -f "/var/www/java/api-java-meeting2.0/logs/ubains-INFO-AND-ERROR.log" ]]; then
log "Verify log (internal): tail -n 50 /var/www/java/api-java-meeting2.0/logs/ubains-INFO-AND-ERROR.log"
tail -n 50 /var/www/java/api-java-meeting2.0/logs/ubains-INFO-AND-ERROR.log || true
else
log "WARN: internal log file not found: /var/www/java/api-java-meeting2.0/logs/ubains-INFO-AND-ERROR.log"
fi
;;
"运维集控系统"|"讯飞转录系统")
# PRD 3.5:后端更新需要重启 upython;前端更新无需重启
if [[ "$UPDATE_TYPE" == "前端更新" ]]; then
log "Skip restart (frontend update only)."
return 0
fi
log "Restart services: $SYSTEM -> docker restart upython"
if command -v docker >/dev/null 2>&1; then
if docker ps -a --format '{{.Names}}' | grep -qx 'upython'; then
docker restart upython
else
log "WARN: container upython not found"
fi
else
log "WARN: docker not found, cannot restart upython"
fi
# 验证日志(仅提示,不阻塞)
if [[ -f "/var/www/html/log/uinfo.log" ]]; then
log "Verify log: tail -n 50 /var/www/html/log/uinfo.log"
tail -n 50 /var/www/html/log/uinfo.log || true
else
log "WARN: log file not found: /var/www/html/log/uinfo.log"
fi
;;
*)
log "WARN: 未配置 $SYSTEM 的重启逻辑,跳过重启。"
;;
esac
}
# 在 update 之后调用 3.5
run_post_update_actions() {
case "$PLATFORM" in
"传统平台")
restart_services_traditional
;;
*)
log "WARN: 平台 $PLATFORM 暂未实现 3.5 重启逻辑"
;;
esac
}
# ====== 调试模式:只跑 3.5(放在函数定义之后)======
if [[ "$RESTART_ONLY" -eq 1 ]]; then
log "RESTART_ONLY=1 -> skip backup/update/tar; only run PRD 3.5 restart"
run_post_update_actions
exit 0
fi
# 依据系统+更新类型执行
do_update_traditional() {
case "$SYSTEM" in
......@@ -527,6 +703,9 @@ case "$PLATFORM" in
log "Start update (传统平台): system=$SYSTEM update=$UPDATE_TYPE workdir=$WORKDIR"
do_update_traditional
log "Update done (传统平台)."
# 3.5 重启并验证
run_post_update_actions
;;
"新统一平台")
log "ERROR: 新统一平台 3.4 更新规则 PRD 未提供(目前仅实现传统平台)。"
......@@ -538,10 +717,12 @@ case "$PLATFORM" in
;;
esac
# 打包备份目录
log "Packing backup to: $BACKUP_TAR"
tar -czvf "$BACKUP_TAR" "$BACKUP_DIR" >/dev/null
# 打包备份目录(仅非 restart-only)
if [[ "$RESTART_ONLY" -eq 0 ]]; then
log "Packing backup to: $BACKUP_TAR"
tar -czvf "$BACKUP_TAR" "$BACKUP_DIR" >/dev/null
log "Backup done."
echo "BACKUP_DIR=$BACKUP_DIR"
echo "BACKUP_TAR=$BACKUP_TAR"
\ No newline at end of file
log "Backup done."
echo "BACKUP_DIR=$BACKUP_DIR"
echo "BACKUP_TAR=$BACKUP_TAR"
fi
\ No newline at end of file
## 方法总结
### 如何使用claude code快速获取弹窗的所有信息元素
在输入框输入:
用chrome浏览器打开这个链接: https://192.168.5.44/#/LoginAdmin。然后,通过chrome devtools mcp完成:输入账号 admin@xty 密码Ubains@4321 验证码csba
完成登录,点击【运维设置】按钮展开运维设置模块,点击【信息模板】进入模块,"获取信息模板模块中点击【新增】按钮后弹出的弹窗里所有表单元素和按钮的XPath,用placeholder或button文本定位",按照这个流程你将信息
告警,转录配置模块下的组织设置编辑、人员设置中的人员添加、区域设置中的区域添加、热词类别的热词添加、集控管理-版本升级模块、会议概览-全景地图模块-搜索框、会议概览-会议指引的新增、会议室指引的新增、授权管理-
会议授权的搜索框、日志管理-操作日志的搜索框、通知日志的搜索框、释放日志的搜索框、联动日志的搜索框、运维日志的搜索框的元素都依次获取一下,获取不到的可以跳过并记录下来,最终输出表格给我吧。用chrome浏览器打开这个链接: https://192.168.5.44/#/LoginAdmin。然后,通过chrome devtools mcp完成:输入账号 admin@xty 密码Ubains@4321 验证码csba
完成登录,点击【运维设置】按钮展开运维设置模块,点击【信息模板】进入模块,"获取信息模板模块中点击【新增】按钮后弹出的弹窗里所有表单元素和按钮的XPath,用placeholder或button文本定位",按照这个流程你将信息
告警,转录配置模块下的组织设置编辑、人员设置中的人员添加、区域设置中的区域添加、热词类别的热词添加、集控管理-版本升级模块、会议概览-全景地图模块-搜索框、会议概览-会议指引的新增、会议室指引的新增、授权管理-
会议授权的搜索框、日志管理-操作日志的搜索框、通知日志的搜索框、释放日志的搜索框、联动日志的搜索框、运维日志的搜索框的元素都依次获取一下,获取不到的可以跳过并记录下来,最终输出表格给我吧。
\ No newline at end of file
......@@ -57,14 +57,14 @@
- 对外后端:✅ 已完成
cd /home/Update/external-meeting-api
mv * /var/www/java/external-meeting-api/(覆盖操作)
2.运维集控系统:
- 前端:✅ 已完成
2.运维集控系统:✅ 已完成
- 前端:
cd /home/Update/web-vue-rms
mv * /var/www/html/web-vue-rms/(覆盖操作)
- 后端:✅ 已完成
- 后端:
cd /home/Update/
mv * /var/www/html/(覆盖操作)
3.讯飞转录系统:
3.讯飞转录系统:✅ 已完成
- 前端:
cd /home/Update/web-vue-rms
mv * /var/www/html/uvoice/web-vue-uvoice/(覆盖操作)
......
# 代码规范:
## 代码注释:
所有代码都需要标注上注释信息,并且以中文体现。
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论