J

jls-weapp

觉林寺小程序

jls-weapp

觉林寺微信小程序,基于 Taro 4 + Vue 3 + NutUI 搭建

🚀 快速开始

安装依赖

pnpm install

开发模式

# 微信小程序
pnpm dev:weapp

# H5
pnpm dev:h5

# 支付宝小程序
pnpm dev:alipay

生产构建

pnpm build:weapp

📁 项目结构

src/
├── api/                    # API 接口层
│   ├── index.js           # 业务接口定义(需根据业务修改)
│   ├── fn.js              # HTTP 请求封装
│   └── wx/                # 微信相关接口(可选)
├── assets/                 # 静态资源
│   ├── images/            # 图片资源
│   ├── styles/            # 全局样式
│   └── css/               # CSS 文件
├── components/             # 通用组件
│   ├── PosterBuilder/     # 海报生成器(可选)
│   ├── time-picker-data/  # 时间选择器
│   ├── indexNav.vue       # 底部导航
│   └── qrCode.vue         # 二维码组件(可选)
├── composables/            # Composition API hooks
│   ├── useOfflineBookingCache.js        # 离线缓存 hook
│   └── useOfflineBookingCachePolling.js # 轮询刷新 hook
├── hooks/                  # 自定义 hooks
│   └── useGo.js           # 导航辅助 hook
├── pages/                  # 页面组件
│   ├── index/             # 首页(示例页面)
│   └── auth/              # 认证页(必须保留)
├── stores/                 # Pinia 状态管理
│   ├── router.js          # 路由状态(用于认证回跳)
│   ├── main.js            # 主 store
│   ├── host.js            # 配置 store
│   └── counter.js         # 示例 store
├── utils/                  # 工具函数
│   ├── authRedirect.js    # 认证流程核心(必须)
│   ├── request.js         # HTTP 客户端核心(必须)
│   ├── network.js         # 网络状态监测
│   ├── config.js          # 环境配置(⚠️ 需修改)
│   ├── tools.js           # 通用工具
│   ├── uiText.js          # 文案管理
│   ├── wechatPay.js       # 微信支付(可选)
│   ├── mixin.js           # Vue mixin
│   ├── polyfill.js        # 浏览器兼容
│   └── weapp.js           # 小程序工具
├── app.js                  # 应用入口
├── app.config.js           # 页面路由配置
└── app.less                # 全局样式

⚙️ 配置说明

1. 修改服务器配置

环境读取逻辑集中在 src/utils/config.js,实际运行模式由构建配置决定:

export const API_ENVIRONMENTS = {
  production: {
    baseURL: 'https://your-production-domain.com',
    requestDefaultParams: {
      f: 'YOUR_MODULE',
      client_id: 'YOUR_CLIENT_ID',
    },
  },
  mock: {
    baseURL: 'https://your-production-domain.com',
    requestDefaultParams: {
      f: 'YOUR_MODULE',
      client_id: 'YOUR_CLIENT_ID',
    },
    useMock: true,
  },
}

1.1 正式环境 / 本地 Mock 环境

仓库现在内置两套 API 运行模式:

  • production:正式环境,走真实接口
  • mock:本地 Mock 环境,开发态默认启用

核心文件:

  • config/dev.js:本地开发环境开关,默认 API_RUNTIME_ENV = "mock"
  • config/prod.js:生产构建环境开关,默认 API_RUNTIME_ENV = "production"
  • src/utils/config.js:环境定义与当前配置读取
  • src/mock/index.js:统一 Mock 入口
  • src/mock/modules/:按模块拆分的 Mock 处理器
  • src/mock/shared/:请求解析、响应包装、路由匹配等公共能力
  • src/mock/stores/:需要状态的 Mock 数据存储
  • src/mock/fixtures/:纯静态样本和数据工厂
  • src/mock/README.md:新增模块时的目录约定与 handler 示例
  • src/api/message.js:消息列表 / 详情接口示例

当前已经预置了以下 mock:

  • 启动授权:/srv/?a=openid
  • 支付参数:/srv/?a=payfclient_id 由请求层统一补齐)、/srv/?a=icbc_pay_wxamp
  • 分享配置:/srv/?a=wx_share
  • 短信与上传:/srv/?a=sms/srv/?a=upload
  • 消息示例:/srv/?a=message&t=list/srv/?a=message&t=detail

如果你想让本地所有接口都走 Mock,只改一个地方就行:

// config/dev.js
env: {
  NODE_ENV: '"development"',
  API_RUNTIME_ENV: '"mock"',
}

要切回本地真实接口,把它改成:

API_RUNTIME_ENV: '"production"'

这套开关是“全局生效”的:

  • mock:当前构建下所有接口统一走 src/mock/
  • production:当前构建下所有接口统一走真实接口

页面层不要自己再写局部 USE_MOCK_DATA 开关,避免同一个页面和别的页面跑在不同环境里。

建议的接入顺序:

  1. 先在 src/mock/fixtures/ 里按真实字段准备样本数据。
  2. 如果该接口存在状态变化,再在 src/mock/stores/ 里补状态读写。
  3. src/mock/modules/ 里新增对应 handler,并在 src/mock/modules/index.js 注册。
  4. 页面继续只调用正常的 xxxAPI,先对着 mock 跑通交互。
  5. 拿到真实接口后,把 config/dev.js 切回 production,再开始联调真实 API。

1.2 Mock 目录约定

src/mock/ 当前按这几个层次组织:

  • index.js 统一入口,只负责创建请求上下文、匹配 handler、返回 axios / Taro 兼容结果。
  • modules/*.mock.js 按模块定义接口级 handler,一个 handler 对应一个 method + action + type 组合。
  • stores/*.store.js 放有状态的 mock 数据,比如消息已读、列表新增删除、详情回写等。
  • fixtures/*.fixture.js 放纯静态样本和数据工厂,不直接处理状态变化。
  • shared/*.js 放请求解析、响应包装、匹配规则等可复用能力。

详细约定见 src/mock/README.md

1.3 CDN 静态图片缓存更新

如果仓库里的页面直接写死了 https://cdn.ipadbiz.cn/jls_weapp/images/ 下的图片地址,不建议每次换图都改代码重新提审,也不要在每个页面里临时手工拼时间戳。当前项目已经约定用 version.json 统一控制这类本地写死 CDN 图片的缓存版本。

当前固定地址:

  • https://cdn.ipadbiz.cn/jls_weapp/version.json

当前文件结构:

{
  "image_version": "20260515-1"
}

运行方式:

  • 应用启动时会预加载这份 version.json
  • 本地写死的 https://cdn.ipadbiz.cn/jls_weapp/images/xxx.png 会自动变成 https://cdn.ipadbiz.cn/jls_weapp/images/xxx.png?v=<image_version>
  • 这样当 CDN 覆盖同名图片后,只要版本值变化,小程序就会把它当成新资源重新拉取

当前边界:

  • 这套机制只默认作用于“仓库里本地写死的 CDN 图片地址”
  • 接口动态返回的图片 URL 默认不处理,避免把首页/后台内容图也一起卷进缓存策略

开发约定:

  • 新增这类本地写死图片时,优先通过 src/utils/assetUrl.js 里的 getVersionedImageAssetByName('xxx.png') 接入
  • 不要继续在页面里裸写完整 CDN 地址后再各自补 ?v= 或时间戳

当你要替换同名图片时,推荐流程是:

  1. 上传同名图片覆盖 CDN 旧文件
  2. 手动刷新图片 CDN 缓存
  3. 修改 version.json 里的 image_version
  4. 再刷新 version.json 自己的 CDN 缓存

2. 定义 API 接口

编辑 src/api/index.js,添加您的业务接口:

import { buildApiUrl } from '@/utils/tools'

export const yourAPI = (params) => {
    return buildApiUrl('your_action', params)
}

3. 配置页面路由

编辑 src/app.config.js,添加您的页面:

export default {
  pages: [
    'pages/index/index',
    'pages/auth/index',
    'pages/your-page/index',  // 添加您的页面
  ],
  // ...
}

4. 双设计宽度体系

项目采用双设计宽度体系:

  • NutUI 组件:基准宽度 375px
  • 其他所有页面:基准宽度 750px

此配置已在 config/index.js 中设置,请确保遵循此规范。

🧭 动态底部导航与 WebView 承接

当前底部导航不是微信原生 tabBar,而是首页里的自定义 AppTabbar。除 home 外,其余按钮的菜单地址都来自后台 app_menu 配置,但最终仍然统一落到固定承接页 pages/webview-preview/index,再由该页把 url / title 传给 <web-view>

这里有一个很重要的导航约定:

  • home 可以继续用 redirectTo
  • home 的动态菜单必须用 navigateTo

原因不是业务页是否固定,而是页面栈是否保住。只要首页点击动态菜单时用的是 navigateTowebview-preview 就会作为新页面入栈,微信原生左上角返回按钮才能正常出现;如果改成 redirectTo,首页会被替换掉,进入 WebView 后就不会有原生返回按钮。

只有一种场景例外:如果小程序是冷启动后直接打开某个 WebView 页面,那么它天然没有上一页,这时即使用的是同一个承接页,也不会凭空出现原生返回按钮。这类场景需要另外设计“返回首页”兜底,不要误判成 tabbar 跳转逻辑失效。

🔐 认证流程

项目内置完整的微信登录认证系统:

  1. 静默认证:应用启动时自动执行静默认证
  2. 401 自动刷新:当接口返回 401 时,自动刷新会话并重试请求
  3. 授权页回跳:认证完成后自动跳转回原页面

核心文件

  • src/utils/authRedirect.js - 认证流程管理
  • src/utils/request.js - HTTP 请求拦截器

重要:当前授权链路使用的是 /srv/?a=openid。如果后端动作名、cookie 返回方式或公共参数发生变化,需要同时检查真实授权链路和本地 mock 授权链路是否保持一致。

如果你同时修改了动态菜单跳转、webview-preview 或授权回跳逻辑,建议至少手工验证一次这条闭环:

  1. 首页点击底部动态菜单进入 WebView
  2. 如未授权则跳到授权页
  3. 授权成功后回到原来的 WebView 页面
  4. 左上角原生返回按钮仍然可以返回首页

🌐 弱网/离线支持

项目内置弱网和离线支持:

  1. 请求超时处理:自动检测网络超时并降级处理
  2. 离线缓存:支持离线数据缓存和读取
  3. 弱网提示:统一的弱网提示文案

相关文件

  • src/composables/useOfflineBookingCache.js
  • src/composables/useOfflineBookingCachePolling.js
  • src/utils/uiText.js

📦 技术栈

  • 框架:Taro 4.x
  • UI 库:Vue 3 + NutUI 4.x
  • 状态管理:Pinia
  • HTTP:axios-miniprogram
  • 样式:Less + TailwindCSS
  • 构建工具:Webpack 5

🎯 路径别名

已配置的路径别名:

@/utils      -> src/utils
@/components -> src/components
@/images     -> src/assets/images
@/assets     -> src/assets
@/composables-> src/composables
@/api        -> src/api
@/stores     -> src/stores
@/hooks      -> src/hooks

📝 开发规范

组件编写

  • 使用 Vue 3 Composition API
  • 组件统一放在 src/components/ 目录
  • Props 定义清晰,注释详细

API 调用

  • 接口统一放在 src/api/ 下按模块定义
  • 使用 xxxAPI(params) 命名格式
  • 请求方法统一使用 src/api/fn.js 中的封装
  • 页面不要直接判断当前是否 Mock,统一让 src/api/fn.jssrc/mock/ 兜底

状态管理

  • 使用 Pinia 进行状态管理
  • Store 文件统一放在 src/stores/ 目录
  • 复杂逻辑使用 composables 封装

样式编写

  • 通用样式使用 TailwindCSS 工具类
  • 组件样式使用 Less
  • NutUI 组件使用 375px 设计稿,其他使用 750px

🔧 可选功能

以下功能可以根据项目需求选择使用或移除:

  1. 二维码组件src/components/qrCode.vue
  2. 海报生成器src/components/PosterBuilder/
  3. 微信支付src/utils/wechatPay.jssrc/api/wx/
  4. 时间选择器src/components/time-picker-data/
  5. 离线缓存src/composables/useOfflineBookingCache.js

📚 相关文档

⚠️ 注意事项

  1. 小程序启动会自动执行静默认证,确保后端接口正常
  2. 请求超时默认 5 秒,可在 src/utils/request.js 中修改
  3. NutUI 组件已配置自动导入,无需手动引入
  4. TailwindCSS 已禁用 preflight,避免与小程序样式冲突
  5. 认证失败会自动跳转到 /pages/auth/index

📄 License

MIT