website-scripts/edit-site-cc.sh

449 lines
14 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# www.tlyq.cc 内容管理脚本
# 兼容 macOS (Bash 3.2+) / Ubuntu / Rocky Linux
# 用法bash edit-site-cc.sh
set -e
# ============================================================
# 配置
# ============================================================
SERVER="tgz"
SRC_DIR="/tmp/project-extract-2/turing-engine"
TRANS="src/lib/translations.ts"
FOOTER="src/components/Footer.tsx"
CONTACT="src/app/contact/page.tsx"
NEWS="src/app/news/page.tsx"
# ANSI 颜色
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
RED='\033[0;31m'
NC='\033[0m'
log() { printf "${GREEN}[✓]${NC} %s\n" "$1"; }
warn() { printf "${YELLOW}[!]${NC} %s\n" "$1"; }
err() { printf "${RED}[✗]${NC} %s\n" "$1"; }
info() { printf "${CYAN}[i]${NC} %s\n" "$1"; }
# 在服务器上执行命令
rsh() { ssh "$SERVER" "$@"; }
# 获取 translations.ts 中指定 marker 的行号
# 用法: get_line "marker" [nth] nth=1 返回第1个匹配nth=2 返回第2个
get_line() {
local marker="$1"
local nth="${2:-1}"
rsh "grep -n \"$marker\" $SRC_DIR/$TRANS | sed -n '${nth}p' | cut -d: -f1"
}
# 在服务器文件中批量插入多行
# 用法: insert_lines <line1> <content1> <line2> <content2> ...
# 行号从大到小排序后依次插入,保证行号准确性
insert_lines() {
local args=("$@")
local pairs=""
local i=0
while [ $i -lt $# ]; do
local ln="${args[$i]}"
local ct="${args[$((i+1))]}"
# 构造 python 元组列表: (line_num, content)
if [ -n "$pairs" ]; then
pairs="$pairs,"
fi
# 转义内容中的反斜杠和引号
pairs="$pairs($ln, \"$(printf '%s' "$ct" | sed 's/\\/\\\\/g; s/"/\\"/g')\")"
i=$((i+2))
done
ssh "$SERVER" python3 - <<PYEOF
pairs = [$pairs]
with open('$SRC_DIR/$TRANS') as f:
lines = f.readlines()
# 按行号从大到小排序,避免插入后行号偏移
pairs.sort(reverse=True)
for line_num, content in pairs:
lines.insert(line_num, content + '\n')
with open('$SRC_DIR/$TRANS', 'w') as f:
f.writelines(lines)
PYEOF
}
# ============================================================
# 主菜单
# ============================================================
show_menu() {
echo ""
printf "${CYAN}=========================================${NC}\n"
printf "${CYAN} www.tlyq.cc 内容管理${NC}\n"
printf "${CYAN}=========================================${NC}\n"
echo ""
echo " 1) 修改联系方式(邮箱/电话/地址)"
echo " 2) 添加企业动态(新闻文章)"
echo " 3) 管理发展历程(时间线)"
echo " 4) 部署到服务器"
echo " 0) 退出"
echo ""
printf "请输入编号 (0-4): "
read choice
echo ""
case "$choice" in
1) edit_contact_info ;;
2) add_news ;;
3) manage_milestones ;;
4) deploy ;;
0) exit 0 ;;
*) warn "无效选择"; show_menu ;;
esac
}
# ============================================================
# 功能 1修改联系方式
# ============================================================
edit_contact_info() {
printf "${CYAN}--- 修改联系方式 ---${NC}\n"
echo ""
# 获取当前值
CUR_EMAIL=$(rsh "grep -m1 'mailto:' $SRC_DIR/$FOOTER | sed 's/.*mailto:\\([^\\\"]*\\).*/\\1/'")
CUR_PHONE=$(rsh "grep -m1 'tel:' $SRC_DIR/$FOOTER | sed 's/.*tel:\\([^\\\"]*\\).*/\\1/'")
CUR_ADDR_ZH=$(rsh "grep 'addrText' $SRC_DIR/$TRANS | head -1 | sed \"s/.*addrText: '\\([^']*\\)'.*/\\1/\"")
CUR_ADDR_EN=$(rsh "grep 'addrText' $SRC_DIR/$TRANS | tail -1 | sed \"s/.*addrText: '\\([^']*\\)'.*/\\1/\"")
info "当前邮箱: $CUR_EMAIL"
info "当前电话: $CUR_PHONE"
info "当前地址(中文): $CUR_ADDR_ZH"
info "当前地址(英文): $CUR_ADDR_EN"
echo ""
printf "新邮箱 (回车跳过): "
read NEW_EMAIL
printf "新电话 (回车跳过): "
read NEW_PHONE
printf "新地址-中文 (回车跳过): "
read NEW_ADDR_ZH
printf "新地址-英文 (回车跳过): "
read NEW_ADDR_EN
if [ -n "$NEW_EMAIL" ]; then
info "替换邮箱: $CUR_EMAIL$NEW_EMAIL"
rsh "sed -i 's/$CUR_EMAIL/$NEW_EMAIL/g' $SRC_DIR/$FOOTER $SRC_DIR/$CONTACT $SRC_DIR/$NEWS"
log "邮箱已更新Footer、联系我们、企业动态 3个文件"
fi
if [ -n "$NEW_PHONE" ]; then
info "替换电话: $CUR_PHONE$NEW_PHONE"
rsh "sed -i 's/$CUR_PHONE/$NEW_PHONE/g' $SRC_DIR/$FOOTER $SRC_DIR/$CONTACT"
log "电话已更新Footer、联系我们 2个文件"
fi
if [ -n "$NEW_ADDR_ZH" ]; then
info "替换地址(中文): $CUR_ADDR_ZH$NEW_ADDR_ZH"
rsh "sed -i \"s/addrText: '$CUR_ADDR_ZH'/addrText: '$NEW_ADDR_ZH'/\" $SRC_DIR/$TRANS"
log "中文地址已更新"
fi
if [ -n "$NEW_ADDR_EN" ]; then
info "替换地址(英文): $CUR_ADDR_EN$NEW_ADDR_EN"
rsh "sed -i \"s/addrText: '$CUR_ADDR_EN'/addrText: '$NEW_ADDR_EN'/\" $SRC_DIR/$TRANS"
log "英文地址已更新"
fi
if [ -z "$NEW_EMAIL" ] && [ -z "$NEW_PHONE" ] && [ -z "$NEW_ADDR_ZH" ] && [ -z "$NEW_ADDR_EN" ]; then
warn "未修改任何内容"
fi
ask_deploy
}
# ============================================================
# 功能 2添加企业动态
# ============================================================
add_news() {
printf "${CYAN}--- 添加企业动态 ---${NC}\n"
echo ""
# 选择分类
echo "选择分类:"
echo " 1) 公司新闻"
echo " 2) 行业资讯"
printf "请选择 (1/2): "
read cat_choice
case "$cat_choice" in
1) ZH_CAT="公司新闻"; EN_CAT="Company News" ;;
2) ZH_CAT="行业资讯"; EN_CAT="Industry News" ;;
*) err "无效选择"; return ;;
esac
echo ""
printf "${YELLOW}--- 中文信息 ---${NC}\n"
printf "日期 (如 2026年4月): "
read ZH_DATE
[ -z "$ZH_DATE" ] && { err "日期不能为空"; return; }
printf "标题: "
read ZH_TITLE
[ -z "$ZH_TITLE" ] && { err "标题不能为空"; return; }
printf "摘要: "
read ZH_DESC
[ -z "$ZH_DESC" ] && { err "摘要不能为空"; return; }
printf "标签 (逗号分隔, 如 AI,产品): "
read ZH_TAGS_INPUT
[ -z "$ZH_TAGS_INPUT" ] && { err "标签不能为空"; return; }
# 构造 tags 数组字符串
ZH_TAGS=$(printf '%s' "$ZH_TAGS_INPUT" | sed "s/ *, */', '/g" | sed "s/^/['/" | sed "s/$/']/")
echo ""
printf "${YELLOW}--- English Info ---${NC}\n"
printf "Date (e.g. April 2026): "
read EN_DATE
[ -z "$EN_DATE" ] && { err "Date is required"; return; }
printf "Title: "
read EN_TITLE
[ -z "$EN_TITLE" ] && { err "Title is required"; return; }
printf "Description: "
read EN_DESC
[ -z "$EN_DESC" ] && { err "Description is required"; return; }
printf "Tags (comma separated, e.g. AI,Product): "
read EN_TAGS_INPUT
[ -z "$EN_TAGS_INPUT" ] && { err "Tags are required"; return; }
EN_TAGS=$(printf '%s' "$EN_TAGS_INPUT" | sed "s/ *, */', '/g" | sed "s/^/['/" | sed "s/$/']/")
# 预览
echo ""
printf "${CYAN}--- 确认信息 ---${NC}\n"
echo "分类: $ZH_CAT / $EN_CAT"
echo "日期: $ZH_DATE / $EN_DATE"
echo "标题: $ZH_TITLE"
echo " $EN_TITLE"
echo "摘要: $ZH_DESC"
echo " $EN_DESC"
echo "标签: $ZH_TAGS"
echo " $EN_TAGS"
echo ""
printf "确认添加? (y/n): "
read confirm
[ "$confirm" != "y" ] && { warn "已取消"; return; }
# 获取 zh 和 en 的 articles: [ 行号
ZH_ART_LINE=$(get_line "articles: \[" 1)
EN_ART_LINE=$(get_line "articles: \[" 2)
# 一次性插入中英文(按行号从大到小排序,保证准确性)
insert_lines \
"$ZH_ART_LINE" " { category: '$ZH_CAT', date: '$ZH_DATE', title: '$ZH_TITLE', desc: '$ZH_DESC', tags: $ZH_TAGS }," \
"$EN_ART_LINE" " { category: '$EN_CAT', date: '$EN_DATE', title: '$EN_TITLE', desc: '$EN_DESC', tags: $EN_TAGS },"
log "企业动态已添加(中英文)"
ask_deploy
}
# ============================================================
# 功能 3管理发展历程
# ============================================================
manage_milestones() {
printf "${CYAN}--- 管理发展历程 ---${NC}\n"
echo ""
echo " 1) 添加新条目"
echo " 2) 修改现有条目"
echo " 0) 返回"
echo ""
printf "请选择 (0-2): "
read ms_choice
case "$ms_choice" in
1) add_milestone ;;
2) edit_milestone ;;
0) show_menu ;;
*) warn "无效选择"; manage_milestones ;;
esac
}
add_milestone() {
echo ""
printf "${YELLOW}--- 中文信息 ---${NC}\n"
printf "日期 (如 2026年4月): "
read ZH_DATE
[ -z "$ZH_DATE" ] && { err "日期不能为空"; return; }
printf "标题: "
read ZH_TITLE
[ -z "$ZH_TITLE" ] && { err "标题不能为空"; return; }
printf "描述: "
read ZH_DESC
[ -z "$ZH_DESC" ] && { err "描述不能为空"; return; }
echo ""
printf "${YELLOW}--- English Info ---${NC}\n"
printf "Date (e.g. Apr 2026): "
read EN_DATE
[ -z "$EN_DATE" ] && { err "Date is required"; return; }
printf "Title: "
read EN_TITLE
[ -z "$EN_TITLE" ] && { err "Title is required"; return; }
printf "Description: "
read EN_DESC
[ -z "$EN_DESC" ] && { err "Description is required"; return; }
echo ""
printf "确认添加? (y/n): "
read confirm
[ "$confirm" != "y" ] && { warn "已取消"; return; }
# 获取 zh 和 en 的 milestones: [ 行号
ZH_MS_LINE=$(get_line "milestones: \[" 1)
EN_MS_LINE=$(get_line "milestones: \[" 2)
# 一次性插入中英文
insert_lines \
"$ZH_MS_LINE" " { date: '$ZH_DATE', title: '$ZH_TITLE', desc: '$ZH_DESC' }," \
"$EN_MS_LINE" " { date: '$EN_DATE', title: '$EN_TITLE', desc: '$EN_DESC' },"
log "发展历程已添加(中英文)"
ask_deploy
}
edit_milestone() {
echo ""
info "当前发展历程 (中文):"
echo ""
# 获取 zh milestones 的起始行
ZH_MS_LINE=$(get_line "milestones: \[" 1)
EN_MS_LINE=$(get_line "milestones: \[" 2)
# 列出所有中文里程碑条目
rsh "awk 'NR>${ZH_MS_LINE} && /date:.*title:/{printf \" %d: %s\\n\", NR, \$0}' $SRC_DIR/$TRANS"
echo ""
printf "请输入要修改的条目行号: "
read LINE_NUM
[ -z "$LINE_NUM" ] && { err "行号不能为空"; return; }
# 验证行号是否有效
VALID=$(rsh "sed -n '${LINE_NUM}p' $SRC_DIR/$TRANS | grep -c 'date:.*title:' || true")
if [ "$VALID" != "1" ]; then
err "该行不是有效的历程条目"
return
fi
# 计算对应的英文行号
OFFSET=$((LINE_NUM - ZH_MS_LINE))
EN_LINE_NUM=$((EN_MS_LINE + OFFSET))
# 显示当前值
info "当前中文内容:"
rsh "sed -n '${LINE_NUM}p' $SRC_DIR/$TRANS"
info "当前英文内容:"
rsh "sed -n '${EN_LINE_NUM}p' $SRC_DIR/$TRANS"
echo ""
printf "${YELLOW}--- 新的中文信息 ---${NC}\n"
printf "日期: "
read ZH_DATE
[ -z "$ZH_DATE" ] && { err "日期不能为空"; return; }
printf "标题: "
read ZH_TITLE
[ -z "$ZH_TITLE" ] && { err "标题不能为空"; return; }
printf "描述: "
read ZH_DESC
[ -z "$ZH_DESC" ] && { err "描述不能为空"; return; }
echo ""
printf "${YELLOW}--- New English Info ---${NC}\n"
printf "Date: "
read EN_DATE
[ -z "$EN_DATE" ] && { err "Date is required"; return; }
printf "Title: "
read EN_TITLE
[ -z "$EN_TITLE" ] && { err "Title is required"; return; }
printf "Description: "
read EN_DESC
[ -z "$EN_DESC" ] && { err "Description is required"; return; }
echo ""
printf "确认修改? (y/n): "
read confirm
[ "$confirm" != "y" ] && { warn "已取消"; return; }
# 替换中文行
ZH_NEW=" { date: '$ZH_DATE', title: '$ZH_TITLE', desc: '$ZH_DESC' },"
# 转义替换内容中的特殊字符
ZH_NEW_ESC=$(printf '%s' "$ZH_NEW" | sed 's/[&/\\]/\\&/g')
rsh "sed -i '${LINE_NUM}s/.*/${ZH_NEW_ESC}/' $SRC_DIR/$TRANS"
# 替换英文行
EN_NEW=" { date: '$EN_DATE', title: '$EN_TITLE', desc: '$EN_DESC' },"
EN_NEW_ESC=$(printf '%s' "$EN_NEW" | sed 's/[&/\\]/\\&/g')
rsh "sed -i '${EN_LINE_NUM}s/.*/${EN_NEW_ESC}/' $SRC_DIR/$TRANS"
log "发展历程已更新(中英文)"
ask_deploy
}
# ============================================================
# 功能 4部署到服务器
# ============================================================
deploy() {
printf "${CYAN}--- 部署 www.tlyq.cc ---${NC}\n"
echo ""
LOCAL_DIR="/Users/niuniu/programs/docker/www-cc/src"
REMOTE_DIR="$SRC_DIR"
DEPLOY_DIR="/root/docker/www-cc/html"
# 从服务器同步最新源码到本地
info "从服务器同步最新源码..."
rsync -az --delete --exclude='node_modules' --exclude='.next' --exclude='out' \
"$SERVER:$REMOTE_DIR/" "$LOCAL_DIR/" 2>/dev/null || {
warn "rsync 不可用,使用 scp..."
rm -rf "$LOCAL_DIR"
mkdir -p "$LOCAL_DIR"
scp -r "$SERVER:$REMOTE_DIR/." "$LOCAL_DIR/" 2>/dev/null
rm -rf "$LOCAL_DIR/node_modules" "$LOCAL_DIR/.next" "$LOCAL_DIR/out"
}
log "打包源码..."
cd "$LOCAL_DIR"
COPYFILE_DISABLE=1 tar czf /tmp/www-src.tar.gz --exclude='node_modules' --exclude='.next' --exclude='out' .
log "上传到服务器..."
scp /tmp/www-src.tar.gz "$SERVER:/tmp/www-src.tar.gz"
log "服务器上构建并部署..."
ssh "$SERVER" "cd $REMOTE_DIR && rm -rf .next out src && tar xzf /tmp/www-src.tar.gz && npm install && rm -rf .next out && npm run build && rm -rf ${DEPLOY_DIR:?}/* && cp -r out/* $DEPLOY_DIR/"
echo ""
log "验证部署..."
URL="https://www.tlyq.cc"
STATUS=$(ssh "$SERVER" "curl -s -o /dev/null -w '%{http_code}' -k '$URL'")
if [ "$STATUS" = "200" ]; then
log "部署成功!访问 $URL"
else
warn "返回状态码: $STATUS,请检查"
fi
echo ""
show_menu
}
# ============================================================
# 通用:询问是否部署
# ============================================================
ask_deploy() {
echo ""
printf "是否立即部署到服务器? (y/n): "
read d
if [ "$d" = "y" ]; then
deploy
else
warn "未部署,修改仅在服务器源码中生效"
info "稍后可选择菜单 4) 部署到服务器"
show_menu
fi
}
# ============================================================
# 启动
# ============================================================
show_menu