hookehuyr

fix(deploy): 修复部署脚本在代理环境下SSH/SCP连接失败的问题

- 在 upload_server 函数中为 SSH/SCP 命令添加 unset http_proxy/https_proxy
- 添加代理处理说明注释,解释各步骤的代理使用策略
- 新增项目文档:CLAUDE.md、CHANGELOG.md
- 新增任务记录:task/2025-03-04.md
- 新增图片资源:三坛大戒相关图片

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# 变更日志
记录项目开发过程中的重要变更和完成任务。
## 2026-03-04
### 13:44:02 - 完成任务
**影响文件**:
- `src/views/MastersDetail.vue`
- `src/views/Splash.vue`
**变更摘要**:
- 无详细描述
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## 项目概述
这是一个基于 Vue 3 + Vite + Vant 4 的移动端 H5 项目(三坛大戒),用于展示佛教戒期相关信息。
## 常用命令
```bash
# 开发(pnpm/npm/yarn)
pnpm dev # 启动开发服务器(默认端口 5173)
pnpm build # 构建生产版本
pnpm lint # ESLint 检查并修复
pnpm serve # 预览构建产物
# 部署(依赖 qshell 和 ssh)
pnpm deploy # 执行完整部署流程:构建 -> 七牛上传 -> 服务器打包上传
bash scripts/deploy.sh # 直接执行部署脚本
```
## 项目架构
### 全局 Loading 机制
项目使用计数器方式管理全局加载状态,优化低网速体验:
- **状态管理**`src/stores/loading.js` - 使用 `pending_count` 记录进行中的请求数
- **拦截器集成**`src/utils/axios.js` - 请求开始 +1,响应成功 -1,错误时重置
- **UI 展示**`src/App.vue` - 全屏蒙版 + van-loading 组件
**特殊 API**:图片流媒体接口 `getImgStreamAPI` 配置了 `{ ignore_loading: true }`,不触发全局 loading。
**路由级加载**`src/router/index.js` 中路由守卫也会控制 loading,避免懒加载白屏。
### 登录态控制
- **Token 存储**:使用 `js-cookie` 存储 `token-stdj`
- **路由守卫**:除 `['/', '/jz_login']` 白名单外,所有页面需登录
- **未登录处理**:重定向到 `/jz_login` 并携带 `redirect` 参数
### API 层设计
- **API 定义**`src/api/index.js` - 统一定义接口路径和 JSDoc
- **请求封装**`src/api/fn.js` - 提供 `fn()` 处理响应、`fetch` 基于 axios
- **默认参数**:所有请求自动携带 `f: 'stdj'``timestamp`(GET)
**API 响应约定**
```javascript
// 成功响应格式(res.code === 1)
{ code: 1, data: {...}, msg: 'success' }
// 错误处理使用 showFailToast
```
### 目录结构
```
src/
├── api/ # API 接口定义
│ ├── index.js # 主接口(首页、文章、登录、用户信息)
│ ├── fn.js # 请求封装与错误处理
│ ├── common.js # 通用接口
│ └── wx/ # 微信相关(支付、配置等)
├── assets/ # 静态资源
├── components/ # 通用组件(VideoPlayer、LoadingSpinner、EmptyState)
├── router/ # Vue Router 配置(含登录守卫)
├── stores/ # Pinia 状态管理(loading store)
├── utils/ # 工具函数
│ ├── axios.js # Axios 拦截器(接入 loading 计数)
│ ├── request.js # Axios 实例导出
│ ├── upload.js # 上传工具
│ └── vconsole.js # 调试控制台
├── views/ # 页面组件
└── main.js # 入口文件
```
## 关键配置
### 移动端适配
- 使用 `postcss-px-to-viewport`,设计稿基准 **375px**
- 选择器添加 `ignore-` 前缀可跳过转换
### 路径别名
```javascript
@ src/
@components src/components/
@utils src/utils/
@api src/api/
@assets src/assets/
@views src/views/
@stores src/stores/
```
### 环境变量
- `.env` - 默认配置
- `.env.development` - 开发环境
- `.env.production` - 生产环境
**关键变量**
- `VITE_BASE` - 资源公共路径
- `VITE_PROXY_TARGET` - 代理目标服务器
- `VITE_PROXY_PREFIX` - 代理前缀(默认 `/srv/`
- `VITE_OUTDIR` - 构建输出目录(默认 `dist`
### 自动导入
- **Vue API**:通过 `unplugin-auto-import` 自动导入(见 `auto-imports.d.ts`
- **Vant 组件**:通过 `unplugin-vue-components` 按需导入(见 `components.d.ts`
## 部署说明
部署脚本 `scripts/deploy.sh` 执行以下流程:
1. **构建项目**`pnpm run build`
2. **上传静态资源到七牛云**`qshell qupload ~/.qshell/stdj_upload.conf`
3. **打包并上传到服务器**`scp -P 12101``zhsy@oa.jcedu.org:/home/www/f`
**依赖**:本机需安装 `qshell` 并配置 `~/.qshell/stdj_upload.conf`
## 开发注意事项
1. **新增 API**:在 `src/api/index.js` 定义接口,使用 `fn(fetch.get/post())` 封装
2. **跳过全局 Loading**:请求配置添加 `{ ignore_loading: true }`
3. **路由配置**:新页面如需登录,无需添加白名单(默认需登录);公开页面添加到 `white_list`
4. **组件命名**:文件名 kebab-case,组件名 PascalCase
......@@ -2,6 +2,10 @@
#
# 部署脚本:构建项目 -> 上传七牛 -> 打包并上传到服务器
# 说明:在 macOS 环境下执行,依赖 npm、qshell、ssh/scp
#
# 代理处理说明:
# - 构建和七牛上传:会使用系统的 http_proxy/https_proxy 环境变量
# - SSH/SCP 连接:临时取消代理环境变量,直连服务器(避免代理干扰)
set -euo pipefail
......@@ -129,13 +133,15 @@ upload_server() {
run_cmd "tar -czvpf '${local_tar:-}' '${local_package_dir:-}'"
log_info "上传到服务器:${server_host:-}:${remote_dir:-}(端口 ${server_port:-})"
run_cmd "scp -P '${server_port:-}' '${local_tar:-}' '${server_host:-}':'${remote_dir:-}'"
# 注意:临时取消代理环境变量,避免 SSH/SCP 受代理影响
run_cmd "unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY && scp -P '${server_port:-}' '${local_tar:-}' '${server_host:-}':'${remote_dir:-}'"
log_info "服务器解压:${remote_dir:-}/${local_tar:-}"
# 说明:构造远端命令,避免变量名意外字符导致的未绑定错误
local remote_cmd
remote_cmd="cd \"${remote_dir:-}\" && tar -xzvf \"${local_tar:-}\" && rm -rf \"${local_tar:-}\""
run_cmd "ssh -p '${server_port:-}' '${server_host:-}' \"$remote_cmd\""
# 注意:临时取消代理环境变量,避免 SSH 受代理影响
run_cmd "unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY && ssh -p '${server_port:-}' '${server_host:-}' \"$remote_cmd\""
log_info "删除本地压缩包"
run_cmd "rm -f '${local_tar:-}'"
......
# 2025-03-04 今日任务
## 需求概述
1. **法会流程跳转修改**:从跳转链接改成读取 `sn` 作为 id,跳转到新闻详情页
2. **新增三坛大戒栏目**:接口需要新增字段返回
3. **viewMore 函数拆分**:拆成 4 个独立的跳转函数
---
## ✅ 任务 1:法会流程跳转修改(已完成)
### 修改内容
- 移除了 `category_link` 判断逻辑
- 使用 `item.parent_sn` 作为路由参数跳转到新闻详情页
### 实现代码
```javascript
// src/views/Home.vue:472-475
const viewMoreCeremony = (item) => {
router.push({ name: 'NewsDetail', params: { id: item.parent_sn || item.id } })
}
```
### 模板更新
```html
<!-- src/views/Home.vue:93 -->
<div class="more-button" @click="viewMoreCeremony(currentStep)">
```
---
## ✅ 任务 3:viewMore 函数拆分(已完成)
### 实现内容
`viewMore` 函数拆分为 4 个独立函数:
1. `viewMoreCeremony` - 法会流程
2. `viewMoreMasters` - 三师七证
3. `viewMoreStudents` - 戒子
4. `viewMoreVolunteers` - 义工
5. `viewMoreByType` - 辅助分发函数(根据 item.name 分发)
### 实现代码
```javascript
// 法会流程 - 使用 parent_sn 跳转到新闻详情页
const viewMoreCeremony = (item) => {
router.push({ name: 'NewsDetail', params: { id: item.parent_sn || item.id } })
}
// 三师七证
const viewMoreMasters = (item) => {
if (item?.category_link) {
location.href = item?.category_link
} else {
router.push(`/masters?pid=${item.id}`)
}
}
// 戒子
const viewMoreStudents = (item) => {
if (item?.category_link) {
location.href = location.origin + location.pathname + '#/' + item?.category_link
} else {
router.push(`/students?i=${item.id}`)
}
}
// 义工
const viewMoreVolunteers = (item) => {
if (item?.category_link) {
location.href = location.origin + location.pathname + '#/' + item?.category_link
} else {
router.push(`/volunteers?i=${item.id}`)
}
}
// 辅助函数:根据 item.name 分发到对应的处理函数
const viewMoreByType = (item) => {
const typeMap = {
'三师七证': viewMoreMasters,
'戒子': viewMoreStudents,
'义工': viewMoreVolunteers,
}
const handler = typeMap[item.name]
if (handler) {
handler(item)
} else {
viewMoreMasters(item) // 默认行为
}
}
```
### 模板更新
```html
<!-- 法会流程:直接调用 viewMoreCeremony -->
<div class="more-button" @click="viewMoreCeremony(currentStep)">
<!-- 其他分类:使用 viewMoreByType 分发 -->
<div class="vertical-more-btn" @click="viewMoreByType(item)">
<div class="more-button" @click="viewMoreByType(item)">
```
---
## ⏳ 任务 2:新增三坛大戒栏目(等待后端接口)
### 当前接口数据结构
```javascript
// 接口返回:/srv/?a=home&f=stdj&timestamp=xxx
{
STDJSSQZ: [...], // 三师七证
STDJFHLC: [...], // 法会流程
STDJXGXW: [...], // 相关新闻
}
```
### 需要新增
- 新增字段 `STDJSTDJ`(三坛大戒)
- 包含栏目信息和文章列表
### 前端需要处理
1. 更新 `src/api/index.js` 的 API 文档注释
2. 添加新的数据展示区块(类似法会流程的展示方式)
3. 添加对应的查看更多跳转函数
### 依赖:后端接口开发
---
## 完成情况
| 任务 | 状态 | 说明 |
|------|------|------|
| 任务 1 | ✅ 已完成 | 法会流程跳转逻辑修改 |
| 任务 3 | ✅ 已完成 | viewMore 函数拆分(代码优化) |
| 任务 2 | ⏳ 等待后端 | 依赖后端接口新增字段 |
---
## 注意事项
1. ✅ 法会流程使用 `parent_sn` 作为路由参数
2. ⏳ 新增三坛大戒栏目需要后端配合开发
3. ✅ 拆分函数后模板调用已更新