Name Last Update
config Loading commit data...
src Loading commit data...
.eslintrc.cjs Loading commit data...
.gitignore Loading commit data...
QUICKSTART.md Loading commit data...
README.md Loading commit data...
babel.config.js Loading commit data...
components.d.ts Loading commit data...
jsconfig.json Loading commit data...
package.json Loading commit data...
pnpm-lock.yaml Loading commit data...
postcss.config.js Loading commit data...
project.config.json Loading commit data...
tailwind.config.js Loading commit data...

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