10 KiB
10 KiB
2026-08-16
新增:线上库同步本地 CLI 工具
- 文件:
deploy/sync-prod-db-to-local.sh(新建,未提交) - 用途:将生产库
dukang_prod(阿里云 RDSrm-bp139andp1aa385i9.mysql.rds.aliyuncs.com:3306,用户dukangadmin)同步到本地 Docker MySQLdukang_haoke(localhost:6016 / 容器内dukang-v1-mysql,root/root)。 - 原理:SSH 隧道借道
dukang-server(-L 6018:rds:3306)→ 本地无 mysql 客户端,故在dukang-v1-mysql容器内跑 mysqldump/mysql,经host.docker.internal:TUNNEL_PORT连隧道;管道直导,不落临时文件。 - 安全:默认先
docker exec mysqldump备份本地到deploy/backups/;需--yes跳过交互确认;--dry-run只读远端 DATABASE_URL 并打印计划。 - 远端凭据从
/opt/dukang/server/dukang-api/.env.production的 DATABASE_URL 运行时解析(密码经MYSQL_PWD环境变量传入,避免命令行暴露)。 - 已知限制:不支持密码含
@;prod DB 名与本地不同(dukang_prod→dukang_haoke)靠 mysqldump 不带--databases实现库名映射。 - 状态:仅跑通
--dry-run,未执行真实同步(待用户确认,因会覆盖本地库并拉取生产数据)。
修复:首次同步失败的根因
- 失败现象:
mysqldump退出码 2,提示本地库可能处于不一致状态(工具自身的失败兜底提示)。 - 真实根因有两条:
- 密码解析错误:生产 DB 密码含
@字符(passHasAt=true)。原 bash 解析用「第一个 @」切分 userinfo/host,把密码里@之后的部分截断,导致 Access denied。 修复:改为在服务端用new URL()解析,base64 回传各字段(user/host/port/db/password),本地base64 -d还原,彻底免疫@/:/$等特殊字符。服务端 auth 测试authTestStatus=0验证密码正确。 - 权限不足:
dukangadmin(应用库用户)无RELOAD/FLUSH_TABLES权限。--single-transaction仍会触发全局FLUSH TABLES→ Access denied。 修复:mysqldump改用--lock-tables=0(不发起 FTWRL)+--set-gtid-purged=OFF(RDS 启用 GTID,否则本地恢复会报 GTID_PURGED 错误),并保留--skip-routines --skip-events --column-statistics=0 --no-tablespaces --add-drop-table --skip-triggers --no-create-db。
- 密码解析错误:生产 DB 密码含
- 验证:结构导出(--no-data)在 4 组 flag 中仅
--lock-tables=0/--skip-lock-tables(不含 --single-transaction)退出 0。 - 现工具已修正并实际执行同步(--yes,先自动备份本地到 deploy/backups/)。
- 注意:
--lock-tables=0无事务一致性快照;生产库在线写入期间导出可能有极小不一致,但恢复时 mysqldump 自带FOREIGN_KEY_CHECKS=0,_dev 库可接受。若需完全一致快照,可给 dukangadmin 授 RELOAD 后用 --single-transaction。
修改:套餐审核导航样式恢复一致
- 文件:
apps/admin-web/src/layouts/AdminLayout.tsx的attachPackageAuditBadge(/store-package-audits项)。 - 诉求演变:用户先要求「文字恒为白色」→ 后改为「不要单独处理,保持与子菜单一致,只是多一个待审徽章图标」。
- 最终实现:label 改为
<span style={{display:'inline-flex',gap:6}}>套餐审核{pendingCount>0 && <Badge count size="small"/>}</span>。文字无强制颜色,随菜单主题继承 normal/hover/selected 颜色;徽章仅 pendingCount>0 时作为图标提示,不参与着色。
发布流水线(本次收尾,含之前未上线的 8+1 文件)
- 背景:此前「联系电话脱敏+套餐多行输入+同步工具」等 9 文件 commit
8de4179已 push dev_jacy/dev/main,但生产发布失败(deploy.env 丢失导致未配置 DEPLOY_HOST)。 - 修复发布:
deploy.env是 gitignore 的本地密钥文件,已丢失不可找回;改用 SSH 别名dukang-server(~/.ssh/config:HostName 47.110.129.57 / User root / IdentityFile pem)覆盖:bash deploy/deploy-prod.sh --host dukang-server -- --skip-db。 - 关键排查:
origin/*本地缓存 ref 多次陈旧(误报 ahead/behind),必须以git ls-remote为准。本次真实远端:dev_jacy=8de4179、dev=c05cd0e、main=bac5c7a,与本地一致,无丢失。 - 本次提交:
bafb342fix(admin) 套餐审核样式 → push dev_jacy → merge dev(0bfc19b) → merge main(029fd69) → push。 - 发布结果:
DEPLOY_EXIT=0,==> 发版完成 (production),健康检查 api:200 / mini-user(h5):200,系统版本记录 commit029fd69。 - 提示:以后若想恢复标准
bash deploy/deploy-prod.sh(不带 --host),需重建deploy/deploy.env(从deploy.env.example复制,填入 DEPLOY_HOST=47.110.129.57 等;该文件 gitignore,勿提交)。
排查:h5-partner 本地 /login 调 /partner/me 报 401
- 现象:
http://localhost:5176/login启动后控制台报GET /api/v1/partner/me 401 (Unauthorized)。 - 结论:不是 bug,是登录页的「过期 token 探测」。链路:Vite 代理
/api→localhost:3010(正常);后端返回{"code":401,"message":"Missing token"}(说明后端在线、代理通)。ensureSession()(api.ts:244)只在 localStorage 有 token 时才打/partner/me;无 token 直接返回未登录。所以 401 来自之前测试残留的失效 token → 前端静默清除并展示登录表单,不崩、不弹错。刷新页面(token 已清)即不再出现。 - 本地登录方式(关键,README 已过期):
MOCK_SMS=true(.env),短信走 mock,不连运营商;固定码MOCK_SMS_FIXED_CODE默认999888(README 写的 123456 已不准)。- README 的测试号
13700000001不在本地同步库;本地partner_account共 9 个,可用真实号如18049821889(Jacy) /13073729990(queen)(均 ACTIVE)。 - 流程:填真实合伙人手机号 → 获取验证码 → 验证码打印在
pnpm dev:api后端终端(Mock SMS → 180****8889 code=XXXXXX)→ 填码登录。 - 注意 h5-partner 默认 5175,本次因 5175 被占自动落到 5176,代理是路径匹配不受影响。
发布:v3.4.17 门店套餐审核快捷入口 上生产
- 提交
1c91e6b(dev_jacy 上,含后端 admin-stores.service.ts + AdminStorePackagesSection/StorePackageAuditsPage/StoresPage 三前端 + 开发计划文档)。 - 流水线:直接快进推送(避免 git checkout 工作树不刷新):
git push origin dev_jacy+dev_jacy:dev+dev_jacy:main,三分支统一到1c91e6b;本地git branch -f dev/main origin/*同步。 - 部署:
bash deploy/deploy-prod.sh --host dukang-server -- --skip-db(后端仅给列表响应加字段,无 schema 变更,故 skip-db)。 - 结果:
DEPLOY_EXIT=0,新 tagv3.4.17,全部应用构建通过,PM2 重启 dukang-api/h5-shop/h5-partner/admin-web(另拉起 h5-user),健康检查 api:200 / mini-user(h5):200,系统版本记录 commit1c91e6b。
发布:v3.4.18 套餐变更对比逐字段列出变动明细
- 需求:套餐变更对比「将变动的地方详细列出来」(之前只给「新增/删除/变更/未变」粗粒度标记,不列具体字段)。
- 改动仅在
apps/admin-web/src/pages/StorePackageAuditsPage.tsx:- 新增
fieldChanges(live, proposed):逐字段比对 价格/套餐名称/菜品内容/可用时间/其他说明/图片,产出label+旧值→新值明细。 diffPackages给「变更」行附changes。PackageDetailCard在「待审核」卡片底部渲染「变更明细」块(旧值删除线 → 新值加粗,橙色块)。- 抽屉顶部加「新增 X · 删除 Y · 变更 Z · 未变 W」汇总条。
- 新增
- 提交
bbd7e52(feat(admin) 套餐变更对比逐字段列出变动明细),快进推送 dev_jacy/dev/main。 - 部署:
bash deploy/deploy-prod.sh --host dukang-server -- --skip-db(无 schema 变更)。 - 结果:构建通过、PM2 重启 admin-web 等、健康检查 api:200 / mini-user(h5):200,系统版本记录 commit
bbd7e52(无精确 tag,记 tag=-,无害)。 - 已知局限:配对按「套餐名称」(空则索引) 位置匹配;若套餐被改名,会误判为「删除旧名+新增新名」而非「变更」,故名称变更不会出现在逐字段明细里。
优化:套餐变更对比·逐字差异 + 文档并入 v3.4.17
- 需求:变动明细要能定位到文本中具体哪些字变了(逐字检查),且把开发计划文档合并到 v3.4.17 文档里(不再单独留 v3.4.18 文档)。
- 代码改动(仍仅
StorePackageAuditsPage.tsx):diffText(a,b):LCS 动态规划 (dp[i][j])+回溯,产出equal/delete/insert段落并合并相邻同类型;O(|a|·|b|),字段长度可控。TextDiff({oldText,newText}):两行渲染——「原:」红删线标被删字、「新:」绿标新增字。FieldChange增加kind: 'text'|'value':价格/图片走旧→新;套餐名称/菜品内容/可用时间/其他说明走TextDiff逐字高亮。杜康好客-v3.4.17-门店套餐审核快捷入口.md新增第 F 节「套餐变更对比·逐字段/逐字明细」,并把原先 v3.4.18 的字段级说明并入,删去独立 v3.4.18 文档计划。
- 提交
ecd9973,快进推送 dev_jacy/dev/main,部署--host dukang-server -- --skip-db。 - 结果:构建通过、健康检查 api:200 / mini-user(h5):200,系统版本记录 commit
ecd9973(tag=-,无害)。 - 验证要点:开任一「变更」套餐的待审核卡片 → 底部「变更明细」→ 菜品/说明等文本以红删+绿增逐字呈现。
优化:h5-partner 门店详情·门店套餐「编辑套餐」按钮
- 需求:按钮缩小、靠最右侧、保持美观。根因:
.partner-btn-outline是整行大按钮(flex:1; height:48px; font-size:16px),放在卡片标题右侧会被拉伸成大块。 - 改动:
apps/h5-partner/src/styles.css新增.partner-btn-outline--compact(flex:none; height:30px; padding:0 14px; font-size:13px; font-weight:500; border-radius:var(--radius-sm); color:var(--color-primary),hover 用color-mix8% 底色);StoreDetailPage.tsx:288的「编辑套餐」按钮加该类(父级space-between已保证贴右)。 - 提交
69e201f,快进推送 dev_jacy/dev/main,部署--host dukang-server -- --skip-db。 - 结果:构建通过、PM2 重启 h5-partner、健康检查 api:200 / mini-user(h5):200,系统版本记录 commit
69e201f(tag=-,无害)。 - 注意:
StoreDetailPage.tsx:311有个历史遗留 TS 错误(status === 'CLOSED'类型无重叠),与本改动无关,未动。