From f156371f684afd7ab6fee7be2de235220762a4e9 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期一, 12 十月 2026 19:44:36 +0800
Subject: [PATCH] feat: 新增 JHHG.sh —— 九鸿化工前端部署脚本的 macOS 版

---
 JHHG.sh |  467 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 467 insertions(+), 0 deletions(-)

diff --git a/JHHG.sh b/JHHG.sh
new file mode 100755
index 0000000..d212f9c
--- /dev/null
+++ b/JHHG.sh
@@ -0,0 +1,467 @@
+#!/usr/bin/env bash
+# ============================================================================
+#  Vue 鍓嶇閮ㄧ讲鑴氭湰锛坢acOS / Linux 鐗堬級鈥斺��  閾跺窛涔濋缚鍖栧伐锛圝HHG锛�
+#
+#  鐢卞悓鐩綍鐨� JHHG.bat 杞啓鑰屾潵锛氭楠ゃ�佹彁绀鸿銆佹湇鍔″櫒銆佽处鍙枫�佽繙绔洰褰曘��
+#  瓒呮椂鍙傛暟涓� .bat 瀹屽叏涓�鑷达紝Windows 涓婃�庝箞鐢紝杩欓噷灏辨�庝箞鐢ㄣ��
+#
+#  涓� .bat 鐨勫叏閮ㄥ樊鍒細
+#    1. 涓嶄緷璧� sshpass.exe銆傜郴缁熼噷鏈� sshpass 灏辩敤 sshpass锛屾病鏈夊氨閫�鍥� macOS
+#       鑷甫鐨� /usr/bin/expect 鏉ュ杺瀵嗙爜 鈥斺�� 鎵�浠ヨ繖鍙� Mac 涓嶇敤瑁呬换浣曚笢瑗夸篃鑳借窇銆�
+#    2. 鑴氭湰寮�澶翠細 cd 鍒拌嚜宸辨墍鍦ㄧ洰褰曪紝浠庝换浣曚綅缃皟鐢ㄩ兘鑳芥纭瀯寤哄拰涓婁紶銆�
+#    3. 缁撳熬鐨� pause 鍙湪浜や簰寮忕粓绔噷鐢熸晥锛岃鍏跺畠鑴氭湰/绠¢亾璋冪敤鏃朵笉浼氬崱浣忋��
+#    4. 銆屾瘮杈冩枃浠跺ぇ灏忋�嶈繖涓�姝ユ寜鏍囬鐨勫師鎰忕湡姝e仛浜嗘瘮瀵癸紙.bat 鍙墦鍗颁笉姣斿锛夛紝
+#       澶у皬涓嶄竴鑷寸洿鎺ユ姤閿欙紝閬垮厤鎶婁竴涓笂浼犳畫缂虹殑鍖呰В鍘嬪埌绾夸笂鐩綍銆�
+#
+#  鐢ㄦ硶锛�
+#      ./JHHG.sh                 # 棣栨鍙兘闇�瑕� chmod +x JHHG.sh
+#      bash JHHG.sh
+#
+#  鍙�夌幆澧冨彉閲忥紙涓�鑸敤涓嶅埌锛夛細
+#      JHHG_TRANSPORT=sshpass|expect    寮哄埗鎸囧畾鍠傚瘑鐮佺殑鏂瑰紡
+# ============================================================================
+
+set -uo pipefail
+
+# =========================
+# 閰嶇疆锛堜笌 JHHG.bat 涓�瀛椾笉宸級
+# =========================
+
+readonly COMPANY='JHHG'
+readonly REMOTE_USER='root'
+readonly REMOTE_HOST='42.63.70.90'
+readonly REMOTE_PORT='22'
+# 瀵嗙爜鍚� ! 鍜� #锛氬繀椤荤敤鍗曞紩鍙凤紱涓嶈 source 鍒颁氦浜掑紡 shell 閲岃窇锛堥偅閲屼細鍋� ! 鍘嗗彶灞曞紑锛夛紝
+# 鐢� ./JHHG.sh 鎴� bash JHHG.sh 鎵ц銆�
+# 2026-10-12 瀹炴祴杩囷細鏈嶅姟鍣ㄦ帴鍙楃殑灏辨槸杩欎釜瀹屾暣瀛楃涓诧紙鍘绘帀 !@##@! 鐨� Nxjhhg 浼氳鎷掞級銆�
+readonly PASSWORD='Nxjhhg!@##@!'
+readonly ZIP_FILE='dist.zip'
+readonly REMOTE_DIR='/home/vue/dist'
+readonly SSH_OPTS=(-o StrictHostKeyChecking=no -o ConnectTimeout=10 -o ServerAliveInterval=15 -o ServerAliveCountMax=3)
+
+readonly REMOTE_TARGET="${REMOTE_USER}@${REMOTE_HOST}"
+readonly REMOTE_TMP="${REMOTE_DIR}/.dist.zip.uploading"
+
+# 鑴氭湰鑷韩鎵�鍦ㄧ洰褰� = 椤圭洰鏍圭洰褰�
+cd "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+# =========================
+# 杈撳嚭helper锛堜笌 .bat 鐨勬彁绀烘牸寮忎竴鑷达級
+# =========================
+
+log()   { printf '%s\n' "$*"; }
+ok()    { printf '[OK] %s\n' "$*"; }
+info()  { printf '[INFO] %s\n' "$*"; }
+warn()  { printf '[WARN] %s\n' "$*"; }
+err()   { printf '[ERROR] %s\n' "$*"; }
+
+# 涓� .bat 鐨� :END 涓�鏍凤紝浜や簰寮忕粓绔噷鍋滀竴涓嬪啀閫�鍑�
+pause_if_interactive() {
+    if [[ -t 0 ]]; then
+        printf '\n鎸夊洖杞﹂敭閫�鍑�...'
+        read -r _ || true
+        printf '\n'
+    fi
+}
+
+fail() {
+    log ''
+    log '============================================================'
+    log '                  DEPLOY FAILED'
+    log '============================================================'
+    log ''
+    log 'Please check the error message above.'
+    log ''
+    pause_if_interactive
+    exit 1
+}
+
+# 娌¤鏄惧紡澶勭悊灏卞け璐ョ殑鍛戒护锛屼篃璧板埌 DEPLOY FAILED锛屼笉鐣欏崐鎴緭鍑�
+on_unexpected_error() {
+    err "鍛戒护澶辫触锛堥��鍑虹爜 $1锛岃剼鏈 $2 琛岋級銆�"
+    fail
+}
+
+trap 'on_unexpected_error $? $LINENO' ERR
+
+# =========================
+# 浼犺緭灞傦細鎶婂瘑鐮佸杺缁� ssh/scp
+# =========================
+
+# 浼樺厛 sshpass锛堝拰 .bat 涓�鏍凤級锛屾病鏈夊氨鐢� macOS 鑷甫鐨� expect
+TRANSPORT="${JHHG_TRANSPORT:-}"
+if [[ -z "$TRANSPORT" ]]; then
+    if command -v sshpass >/dev/null 2>&1; then
+        TRANSPORT='sshpass'
+    elif command -v expect >/dev/null 2>&1; then
+        TRANSPORT='expect'
+    fi
+fi
+
+# 鐢ㄥ綋鍓� TRANSPORT 鎵ц涓�鏉� ssh/scp 鍛戒护锛屽弬鏁板師鏍烽�忎紶
+# 瀵嗙爜閫氳繃鐜鍙橀噺浼犻�掞紝涓嶅嚭鐜板湪鍛戒护琛屽弬鏁伴噷锛堜笉浼氳繘 ps 杈撳嚭锛�
+run_remote() {
+    if [[ "$TRANSPORT" == 'sshpass' ]]; then
+        SSHPASS="$PASSWORD" sshpass -e "$@"
+        return $?
+    fi
+    # expect 鍒嗘敮锛氱▼搴忓繀椤诲啓鎴愭枃浠跺啀鐢� -f 璋冪敤锛屽洜涓� `expect -c 鑴氭湰 鍙傛暟...`
+    # 涓嶄細鎶婂弬鏁版斁杩� $argv锛堜細鎶婂畠褰撹剼鏈枃浠跺悕锛夈��
+    local exp_file rc
+    exp_file="$(mktemp "${TMPDIR:-/tmp}/jhhg-deploy.XXXXXX")" || {
+        err 'temp file creation failed.'
+        return 1
+    }
+    cat >"$exp_file" <<'EXPECT_PROGRAM'
+set timeout 300
+log_user 1
+if {[catch {spawn {*}$argv} spawn_err]} {
+    puts stderr "spawn failed: $spawn_err"
+    exit 127
+}
+expect {
+    -re "(?i)are you sure you want to continue connecting" { send "yes\r"; exp_continue }
+    -re "(?i)password:" { send "$env(JHHG_PW)\r"; exp_continue }
+    eof
+}
+# 鎶婂瓙杩涚▼鐨勯��鍑虹爜鍘熸牱甯﹀嚭鍘伙紙瀵嗙爜閿欐椂 ssh 杩斿洖 255锛屽繀椤昏涓婂眰鎰熺煡鍒帮級
+set wait_result {}
+catch wait wait_result
+set rc [lindex $wait_result 3]
+if {![string is integer -strict $rc]} { set rc 1 }
+exit $rc
+EXPECT_PROGRAM
+    JHHG_PW="$PASSWORD" expect -f "$exp_file" "$@"
+    rc=$?
+    rm -f "$exp_file"
+    return $rc
+}
+
+ssh_remote() {                       # ssh_remote "杩滅鍛戒护"
+    run_remote ssh -p "$REMOTE_PORT" "${SSH_OPTS[@]}" "$REMOTE_TARGET" "$1"
+}
+
+scp_up() {                           # scp_up 鏈湴鏂囦欢 杩滅璺緞
+    run_remote scp -P "$REMOTE_PORT" "${SSH_OPTS[@]}" "$1" "${REMOTE_TARGET}:$2"
+}
+
+# =========================
+# 寮�濮�
+# =========================
+
+log ''
+log '============================================================'
+log '             Vue Dist Auto Deploy'
+log '============================================================'
+log ''
+log "Company    : $COMPANY"
+log "Server     : $REMOTE_USER@$REMOTE_HOST"
+log "Port       : $REMOTE_PORT"
+log "Remote Dir : $REMOTE_DIR"
+log "Package    : $ZIP_FILE"
+log ''
+
+# =========================
+# [1/7] 瀵嗙爜宸ュ叿
+# =========================
+
+log '[1/7] Checking password tool...'
+
+if [[ -z "$TRANSPORT" ]]; then
+    err 'sshpass 鍜� expect 閮芥病鏈夛紝鏃犳硶鑷姩杈撳叆瀵嗙爜銆�'
+    info 'macOS 涓�鑸嚜甯� /usr/bin/expect锛屾甯镐笉浼氳蛋鍒拌繖閲岋紱'
+    info '濡傛灉纭疄娌℃湁锛岃 sshpass 鍗冲彲锛堝彲鑳介渶鍏堝姞绗笁鏂� tap锛夛細brew install sshpass'
+    info 'Linux: apt install sshpass  /  yum install sshpass'
+    fail
+fi
+
+if [[ "$TRANSPORT" == 'sshpass' ]]; then
+    ok "sshpass found: $(command -v sshpass)"
+else
+    ok "expect found: $(command -v expect)锛坢acOS 鑷甫锛屾棤闇�瀹夎 sshpass锛�"
+fi
+
+# =========================
+# [2/7] pnpm
+# =========================
+
+log ''
+log '[2/7] Checking pnpm...'
+
+if ! command -v pnpm >/dev/null 2>&1; then
+    err 'pnpm not found.'
+    info 'HINT: npm install -g pnpm'
+    fail
+fi
+
+if ! pnpm --version; then
+    err 'pnpm execution failed.'
+    fail
+fi
+
+# =========================
+# [3/7] node
+# =========================
+
+log ''
+log '[3/7] Checking Node.js...'
+
+if ! command -v node >/dev/null 2>&1; then
+    err 'Node.js not found.'
+    fail
+fi
+
+if ! node --version; then
+    err 'Node.js execution failed.'
+    fail
+fi
+
+# =========================
+# node_modules
+# =========================
+
+if [[ ! -d node_modules ]]; then
+    log ''
+    info 'node_modules not found.'
+    info 'Running pnpm install...'
+    if ! pnpm install; then
+        err 'pnpm install failed.'
+        fail
+    fi
+    ok 'pnpm install completed.'
+else
+    ok 'node_modules exists.'
+fi
+
+# =========================
+# [4/7] 鏋勫缓
+# =========================
+
+log ''
+log '[4/7] Building project...'
+
+SKIP_BUILD=''
+if [[ -f "$ZIP_FILE" ]]; then
+    log ''
+    warn "$ZIP_FILE already exists."
+    printf 'Rebuild? Y/N (default Y): '
+    read -r REBUILD_ANSWER || true
+    case "$(printf '%s' "${REBUILD_ANSWER:-}" | tr '[:lower:]' '[:upper:]')" in
+        N) info 'Skip build.'; SKIP_BUILD='1' ;;
+    esac
+fi
+
+if [[ -z "$SKIP_BUILD" ]]; then
+    info "Company: $COMPANY"
+    info 'Command: pnpm run build'
+    log ''
+    export VITE_COMPANY="$COMPANY"
+    if ! pnpm run build; then
+        log ''
+        err 'Build failed.'
+        fail
+    fi
+    log ''
+    ok 'Build completed.'
+fi
+
+# =========================
+# [5/7] 妫�鏌ュ寘
+# =========================
+
+log ''
+log '[5/7] Checking package...'
+
+if [[ ! -f "$ZIP_FILE" ]]; then
+    err "$ZIP_FILE not found."
+    info 'HINT: Please check whether your build generates dist.zip.'
+    fail
+fi
+
+LOCAL_ZIP_BYTES="$(wc -c < "$ZIP_FILE" | tr -d ' ')"
+LOCAL_ZIP_MB="$(awk -v b="$LOCAL_ZIP_BYTES" 'BEGIN { printf "%.2f", b / 1048576 }')"
+
+ok 'Package found.'
+info "File size: $LOCAL_ZIP_BYTES bytes"
+info "File size: $LOCAL_ZIP_MB MB"
+
+# =========================
+# [6/7] 娴嬭瘯 SSH
+# =========================
+
+log ''
+log '[6/7] Testing SSH connection...'
+
+if ! ssh_remote 'echo SSH_OK'; then
+    err 'SSH connection failed.'
+    fail
+fi
+
+ok 'SSH connection successful.'
+
+# =========================
+# 寤鸿繙绔洰褰�
+# =========================
+
+log ''
+info 'Creating remote directory...'
+
+if ! ssh_remote "mkdir -p '$REMOTE_DIR'"; then
+    err 'Failed to create remote directory.'
+    fail
+fi
+
+ok 'Remote directory ready.'
+
+# =========================
+# 涓婁紶涓存椂鏂囦欢
+# =========================
+
+log ''
+info 'Uploading package...'
+
+ssh_remote "rm -f '$REMOTE_TMP'" || true
+
+# 杩滅璺緞涓嶈兘鍔犲紩鍙凤細ssh 閭f潯鐨勫崟寮曞彿鏄粰杩滅 shell 鍓ョ殑锛岃�� scp 鐨勫弬鏁颁笉缁� shell锛�
+# 鍗曞紩鍙蜂細鍙樻垚鏂囦欢鍚嶇殑鐪熷疄瀛楃锛堣繙绔細鍘诲紑 "'/home/vue/dist/..." 杩欎釜鐩稿璺緞锛�
+if ! scp_up "$ZIP_FILE" "$REMOTE_TMP"; then
+    err 'Upload failed.'
+    fail
+fi
+
+ok 'Upload completed.'
+
+# =========================
+# 鏍¢獙杩滅鏂囦欢
+# =========================
+
+log ''
+info 'Checking remote package...'
+
+if ! ssh_remote "test -f '$REMOTE_TMP'"; then
+    err 'Remote package does not exist.'
+    fail
+fi
+
+ok 'Remote package exists.'
+
+# =========================
+# 姣旇緝鏂囦欢澶у皬
+# =========================
+
+log ''
+info 'Checking package size...'
+log ''
+
+# 澶у皬姣斿鏀惧湪杩滅鍋氥�佸彧鍙栭��鍑虹爜銆�
+# 涓嶈鐢� $(run_remote ...) 鍘绘埅鍙栬繙绔緭鍑猴細expect 浼氭妸鏁存浜や簰鍥炴樉锛坰pawn 鍛戒护琛屻��
+# 瀵嗙爜鎻愮ず锛変竴璧峰啓杩� stdout锛屾埅鍑烘潵鐨勪笉鏄懡浠ょ粨鏋滐紝姣斿蹇呯劧澶辫触銆�
+if ! ssh_remote "test \"\$(stat -c %s '$REMOTE_TMP')\" -eq $LOCAL_ZIP_BYTES"; then
+    # 鍙橀噺涓�寰嬪姞 ${}锛歜ash 3.2 浼氭妸绱ц窡鍏跺悗鐨勫叏瑙掑瓧绗︼紙濡傘�岋紙銆嶏級褰撴垚鍙橀噺鍚嶇殑涓�閮ㄥ垎锛�
+    # 浜庢槸 $ZIP_FILE锛� 浼氳瑙f瀽鎴愬悕涓� "ZIP_FILE锛�" 鐨勫彉閲忥紝閰� set -u 鐩存帴鎶� unbound variable
+    err "鍖呭ぇ灏忎笉涓�鑷达細杩滅 ${REMOTE_TMP} 涓庢湰鍦� ${ZIP_FILE}锛�${LOCAL_ZIP_BYTES} 瀛楄妭锛変笉绗︼紝涓婁紶鍙兘琚埅鏂��"
+    info "杩滅涓存椂鏂囦欢宸蹭繚鐣欍�傚彲鍦ㄦ湇鍔″櫒涓婃墽琛� stat -c %s '${REMOTE_TMP}' 鏍稿锛岀‘璁ゅ悗鍒犻櫎銆�"
+    fail
+fi
+
+ok "鍖呭ぇ灏忎竴鑷达細${LOCAL_ZIP_BYTES} 瀛楄妭銆�"
+
+# =========================
+# 鏀瑰悕鐢熸晥
+# =========================
+
+log ''
+info 'Activating package...'
+
+if ! ssh_remote "mv -f '$REMOTE_TMP' '$REMOTE_DIR/$ZIP_FILE'"; then
+    err 'Failed to activate package.'
+    fail
+fi
+
+ok 'Package activated.'
+
+# =========================
+# 妫�鏌� unzip
+# =========================
+
+log ''
+info 'Checking unzip...'
+
+if ! ssh_remote 'command -v unzip'; then
+    err 'unzip is not installed on server.'
+    log ''
+    log 'CentOS/RHEL:'
+    log 'yum install -y unzip'
+    log ''
+    log 'Ubuntu/Debian:'
+    log 'apt install -y unzip'
+    fail
+fi
+
+ok 'unzip found.'
+
+# =========================
+# 娴嬭瘯 ZIP
+# =========================
+
+log ''
+info 'Testing remote ZIP...'
+
+if ! ssh_remote "cd '$REMOTE_DIR' && unzip -t '$ZIP_FILE'"; then
+    log ''
+    err 'ZIP test failed.'
+    info 'Remote ZIP has been kept.'
+    fail
+fi
+
+ok 'ZIP test passed.'
+
+# =========================
+# 瑙e帇
+# =========================
+
+log ''
+info 'Extracting package...'
+
+if ! ssh_remote "cd '$REMOTE_DIR' && unzip -o '$ZIP_FILE'"; then
+    log ''
+    err 'Remote unzip failed.'
+    info 'Remote ZIP has been kept.'
+    fail
+fi
+
+log ''
+ok 'Extract completed.'
+
+# =========================
+# 鍒犻櫎杩滅 ZIP
+# =========================
+
+log ''
+info 'Removing remote ZIP...'
+
+if ssh_remote "rm -f '$REMOTE_DIR/$ZIP_FILE'"; then
+    ok 'Remote ZIP removed.'
+else
+    warn 'Failed to remove remote ZIP.'
+fi
+
+# =========================
+# [7/7] 瀹屾垚
+# =========================
+
+log ''
+log '============================================================'
+log '                 DEPLOY SUCCESS'
+log '============================================================'
+log ''
+log "Company    : $COMPANY"
+log "Server     : $REMOTE_HOST:$REMOTE_PORT"
+log "Remote Dir : $REMOTE_DIR"
+log "Package    : $ZIP_FILE"
+log "Size       : $LOCAL_ZIP_MB MB"
+log ''
+log 'Deployment completed successfully.'
+log ''
+
+pause_if_interactive

--
Gitblit v1.9.3