# shop-boot-app **Repository Path**: onionKing/shop-boot-app ## Basic Information - **Project Name**: shop-boot-app - **Description**: C端移动端 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-10 - **Last Updated**: 2026-10-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 青屿生活馆 · 门店预约 门店预约小程序。UI 设计、交互与样式复刻自 `meoo`(Taro + React 版本), 页面组件全部改用本工程自带的 uni-app / uni-ui 组件,未新增任何 UI 依赖。 > 工程脚手架仍由 `pm-app-admin`(uni-app + Vue2 + Vuex + HBuilderX)重建而来, > 技术栈与工程范式对齐 `pm-frontend`;`package.json` 的 name 沿用 `pm-app-admin-v3`。 ## 页面一览 | 页面 | 路径 | 交互要点 | |---|---|---| | 门店首页 | `pages/index` | Banner、门店信息与一键拨号、分类横滚筛选、服务两列网格 | | 预约下单 | `pages/booking/index` | 已选服务卡、未来 7 天日期横滚、30 分钟时段格(已约满/已过时置灰)、指定店员、联系信息校验、底部固定提交栏 | | 我的预约 | `pages/appointments/index` | 四色状态标签、可取消/不可取消两态、二次确认、空状态引导 | | 我的 | `pages/mine/index` | 头像昵称卡、未登录显示游客、功能条目、关于我们页内展开、退出登录 | | 登录 | `pages/login` | 登录/注册切换、图形验证码(后端开启时)、微信一键登录(仅小程序)、跳过登录先逛逛 | ## 技术栈 | 项 | 版本 / 说明 | |---|---| | uni-app | `3.0.0-5020420260813003`(编译器 5.24,Vue3) | | Vue | 3.5.42 | | Pinia | 3.0.4(与 pm-frontend 一致) | | TypeScript | 5.9.3 | | Vite | 5.2.8(由 `@dcloudio/vite-plugin-uni` 精确锁定,**不可升到 7.x**) | | Sass | 1.98.0 | | UI | uni-ui(`uni_modules`,44 个组件) | | 图标 | uni-icons(工程自带,166 个线性图标) | ## 环境要求 - Node.js >= 20.19.0 - npm >= 8.19.0 ## 快速开始 ```bash npm install # H5 开发(默认 http://localhost:9090) npm run dev:h5 # 微信小程序开发(产物 dist/dev/mp-weixin,用微信开发者工具导入) npm run dev:mp-weixin ``` ## 构建 ```bash npm run build:h5 # -> dist/build/h5 npm run build:mp-weixin # -> dist/build/mp-weixin npm run build:app # -> dist/build/app ``` ## 质量检查 ```bash npm run type-check # vue-tsc --noEmit npm run lint:eslint # eslint . npm run lint:eslint:fix # eslint . --fix npm run prettier # prettier --write . ``` ## 目录结构 ``` pm-app-admin-v3/ ├── src/ │ ├── api/ # 接口定义(与 pm-frontend 同构:index + types) │ │ ├── login.ts │ │ ├── types.ts # 统一响应与业务类型 │ │ └── system/user.ts │ ├── components/ # 本地组件(easycom 自动注册,目录名 = 标签名) │ │ ├── date-strip/ # 横向 7 天日历 │ │ ├── section-title/ # 区块标题(左侧色条 + 右侧说明) │ │ ├── service-card/ # 服务项目卡片 │ │ ├── status-tag/ # 预约状态标签(四色) │ │ ├── time-slot-grid/ # 30 分钟一档的时段格 │ │ └── uni-section/ # 第三方组件,不参与规范检查 │ ├── mock/ # 演示数据(门店 / 分类 / 服务 / 店员) │ │ └── booking-data.ts │ ├── types/ # 业务类型声明 │ │ └── booking.ts │ ├── pages/ # 11 个页面 │ │ ├── index.vue # 门店首页(tab) │ │ ├── appointments/ # 我的预约(tab) │ │ ├── mine/ # 我的(tab)+ 个人信息 / 编辑 / 头像 / 改密 │ │ ├── booking/ # 预约下单 │ │ ├── login.vue / register.vue │ │ └── common/textview/ │ ├── plugins/ # 全局插件(挂到 app.config.globalProperties) │ │ ├── auth.ts # $auth 权限校验 │ │ ├── index.ts │ │ ├── modal.ts # $modal 提示/弹窗/loading │ │ └── tab.ts # $tab 路由跳转 │ ├── static/ # 静态资源(ColorUI / iconfont / 图片) │ │ └── scss/ # var(设计 token) / mixin / theme / global │ ├── uni_modules/ # uni-ui 组件(easycom 扫描目录,必须在 src/ 下) │ ├── store/ # Pinia │ │ ├── index.ts │ │ └── modules/ │ │ ├── user.ts # 登录态 / 用户资料 │ │ └── appointment.ts # 预约单(本地落盘) │ ├── utils/ # 工具层 │ │ ├── auth.ts # token 读写 │ │ ├── common.ts # toast / showConfirm / tansParams │ │ ├── config.ts → ../config.ts │ │ ├── crypto.ts # AES │ │ ├── errorCode.ts │ │ ├── jsencrypt.ts # RSA(密钥取自 .env) │ │ ├── request.ts # uni.request 封装 │ │ ├── slot-utils.ts # 日期选项 / 时段可用性 / 手机号校验 │ │ ├── storage.ts │ │ └── upload.ts # uni.uploadFile 封装 │ ├── App.vue │ ├── config.ts # 应用静态配置(环境相关走 .env) │ ├── main.ts # createSSRApp + Pinia │ ├── manifest.json │ ├── pages.json │ └── permission.ts # 路由拦截(uni.addInterceptor) ├── .env.development ├── .env.production ├── eslint.config.ts ├── index.html # H5 模板(Vite 版,非 webpack) ├── tsconfig.json └── vite.config.ts ``` ### 样式规范(复刻 meoo 时建立的约定) 1. **设计 token 单一来源**:`src/static/scss/var.scss`。色值只允许出现在这一个文件里, 组件 SCSS 一律 `@use '@/static/scss/var.scss' as *;` 后引用 `$变量` 或 `var(--变量)`。 2. **运行时变量出口**:`theme.scss` 在 `:root, page` 上把 token 映射成 `--primary` / `--muted-foreground` 等 CSS 变量(`uni-icons` 的 `color` 属性只能接颜色字符串,统一传 `var(--xxx)`)。 新增需要运行时使用的颜色,必须**同时**加到 `var.scss` 的 `$runtime-vars` 映射,否则 `var()` 会静默失效。 3. **组件 SCSS 写在 SFC 内、`scoped`**,并且选择器都落在组件自身根节点 class 上: uni-app 的全局样式不会作用到组件节点内部,**不要**指望在 `global.scss` 里写组件类选择器。 4. **状态修饰类一律显式提升优先级**,如 `&__item.time-slot__item--active { ... }`, 不要只写嵌套的 `&--active`(等价于 `&__item--active`,优先级低于基础类,可能被覆盖)。 5. **正文字号用 `px`,与 meoo 对齐**;仅位置尺寸可以用 `rpx`。`page` 兜底样式在 `theme.scss` 里, 每个页面根节点统一挂 `.ov-page`,通过 `@use '@/static/scss/mixin.scss'` 的 `page()` mixin 拿到底色与安全区。 6. **图标统一用 `uni-icons`**(工程自带,166 个线性图标),不新增图标依赖。 ### 与 meoo 的对应关系 | meoo | shop-boot-app | |---|---| | `components/service-card` | `components/service-card` | | `components/section-title` | `components/section-title` | | `components/status-tag` | `components/status-tag` | | `components/date-strip` | `components/date-strip` | | `components/time-slot-grid` | `components/time-slot-grid` | | `lib/booking-data.ts` | `mock/booking-data.ts` | | `lib/slot-utils.ts` | `utils/slot-utils.ts` | | `store/appointment-store.ts` | `store/modules/appointment.ts` | | `store/auth-store.ts` | `store/modules/user.ts` | | `pages/index` / `appointments` / `profile` / `booking` / `login` | `pages/index.vue` / `pages/appointments/index.vue` / `pages/mine/index.vue` / `pages/booking/index.vue` / `pages/login.vue` | | `app.css` 的 `:root` token | `static/scss/var.scss` + `theme.scss` | > 演示账号:`admin` / `admin123`(本地演示登录,不请求后端)。其余账号走后端 `/auth/login`。 > 首页与预约页可匿名浏览;「我的」页在未登录时显示「游客」,登录后可退出。 > 预约数据存本地 `uni.setStorageSync`,接后端时把 `store/modules/appointment.ts` 的读写换成 `api/` 调用即可。 ## 与 pm-frontend 的对齐程度 | 层面 | 状态 | |---|---| | 目录结构(`src/` + api/store/utils/plugins) | ✅ 对齐 | | TypeScript 配置与 ESLint / Prettier 规范 | ✅ 对齐(printWidth 150) | | Pinia 用法(setup store + `storeToRefs`) | ✅ 对齐,版本同为 3.0.4 | | 环境变量约定(`import.meta.env.VITE_APP_*`) | ✅ 对齐 | | 请求层与鉴权范式(拦截器 + Bearer + clientid) | ✅ 范式对齐(底层为 `uni.request`,非 axios) | | 插件挂载方式(`app.config.globalProperties`) | ✅ 范式对齐 | | 依赖版本 / 构建产物 | ❌ 不可对齐,见下 | ### 为什么 Vite 不能与 pm-frontend 统一 `@dcloudio/vite-plugin-uni` 的 `peerDependencies` 是**精确版本**(当前 `{"vite":"5.2.8"}`), 而 pm-frontend 使用 Vite 7.3.2。二者无法共存,请勿尝试升级本工程的 Vite 大版本。 ### 依赖版本锁定规则(重要) `@dcloudio/*` 的 npm dist-tag 具有误导性: - `@dcloudio/uni-app@latest` → `2.0.2-*`,这是 **Vue2 运行时** - `@dcloudio/vite-plugin-uni@latest` → `3.0.0-alpha-3000020210521001`,**2021 年的 alpha** **必须把所有 `@dcloudio/*` 包锁定到同一个 `3.0.0-` 版本串**(当前 `3.0.0-5020420260813003`)。 整体升版请使用 `npx @dcloudio/uvm@latest`,不要单独升级某个包。 另:`@dcloudio/uni-app` 的 peer 要求 `@dcloudio/types` 为**精确** `3.4.31`,不可写成 `^3.4.8`。 ## 相对原版 pm-app-admin 的修复 重建过程中修复了原工程的实际缺陷: | # | 位置 | 原问题 | 现状 | |---|---|---|---| | 1 | `utils/request` | 使用 HBuilderX Vue2 的 Promise 方言 `then(([err,res])=>...)` | 改为 `uni.request` 标准 `success`/`fail` 回调 | | 2 | `utils/request` | 加密开关判断与调用方层级不一致,AES 加密从未生效 | `isEncrypt` 提升为请求配置顶层开关,已生效 | | 3 | `api/login` | 注册请求 `/register`,后端实际为 `/auth/register` | 已修正 | | 4 | `utils/upload` | 401 后跳转不存在的 `/pages/login/login` | 改为 `/pages/login` | | 5 | `App.vue` + 各页 | `getApp().globalData.config` 在 Vue3 下为 `undefined`,登录页会崩 | 改用 `import.meta.env` + `@/config` | | 6 | `pages/mine/avatar` | 依赖 Vue2 已移除的 `this.$set` | 改用 `reactive` 响应式状态 | | 7 | `utils/permission.js` | 无任何引用的死代码 | 已删除 | | 8 | `manifest.json` | `mp-weixin.setting.es6: false` | 改为 `true`(Vue3 小程序端建议) | | 9 | `config.js` | `baseUrl` / `clientId` 硬编码 | 迁至 `.env.*` | | 10 | `utils/request`、`utils/upload` | 401 并发请求会重复弹窗 | 加入 `reloginShown` 去重 | ## 需要注意的约定 - **`type: module` 不能加**:`@dcloudio/vite-plugin-uni` 是 CJS 包,`package.json` 一旦声明 `"type": "module"`,`vite.config.ts` 中的 ESM 默认导入会解析成模块命名空间对象而非函数, 报 `uni is not a function`。 - **PostCSS 配置位置**:uni-app 的 Vue3 CLI **不读取** `postcss.config.js`, 必须写在 `vite.config.ts` 的 `css.postcss.plugins`。 - **`