diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..29d624e --- /dev/null +++ b/.gitignore @@ -0,0 +1,132 @@ +# =================================== +# 优艺家沙发翻新项目 - 根目录 .gitignore +# Git仓库位于项目根目录 +# =================================== + +# ============ 依赖目录 ============ +node_modules/ +**/node_modules/ +.pnp +.pnp.js + +# ============ 构建输出 ============ +# 后端 +后端/dist/ +后端/build/ + +# 前端 (UniApp) +前端/unpackage/ +前端/dist/ + +# 管理后台 +管理后台/dist/ +管理后台/dist-ssr/ + +# admin(如果使用) +admin/dist/ + +# 通用构建目录 +**/dist/ +**/build/ + + +# ============ 日志文件 ============ +logs/ +*.log +npm-debug.log* +pnpm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +后端/logs/ +后端/*.log + +# ============ 数据库和上传文件 ============ +后端/upload/ +后端/uploads/ +*.db +*.sqlite +*.sqlite3 +*.sql.backup + +# ============ 操作系统文件 ============ +.DS_Store +Thumbs.db +Desktop.ini +$RECYCLE.BIN/ +**/.DS_Store + +# ============ IDE 和编辑器 ============ +# VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# IntelliJ IDEA +.idea/ +*.iml +*.ipr +*.iws + + +# 其他编辑器 +*.swp +*.swo +*~ +.project +.classpath +.settings/ +*.sublime-project +*.sublime-workspace + +# ============ 测试和覆盖率 ============ +coverage/ +.nyc_output/ +*.lcov +**/.nyc_output/ +**/coverage/ + +# ============ 缓存和临时文件 ============ +.cache/ +.vite/ +.parcel-cache/ +.eslintcache +*.tsbuildinfo +.temp/ +.tmp/ +*.tmp +*.temp +*.pid +*.seed +*.pid.lock + +# ============ 包管理器锁文件 ============ +# 取消注释以忽略锁文件(团队开发建议保留) +# package-lock.json +# yarn.lock +# pnpm-lock.yaml + +# ============ 自动生成的类型文件 ============ +# 如果团队需要,可以取消注释 +# 管理后台/auto-imports.d.ts +# 管理后台/components.d.ts + +# ============ 文档相关 ============ +# 保留重要文档,排除临时测试文档 +**/测试*.md +**/*临时*.md +**/*草稿*.md +API格式修复完成.md +API测试脚本.md + + +# ============ 其他 ============ +.history/ +*.bak +*.old +*.orig +*.swp +*.swo diff --git a/前端/api/index.uts b/前端/api/index.uts index c20cbc6..4dbc18c 100644 --- a/前端/api/index.uts +++ b/前端/api/index.uts @@ -39,13 +39,16 @@ export const getBanners = () => { */ export const getCaseList = (params ?: UTSJSONObject) => { // 后端使用page和limit参数,需要转换 - const queryParams = params ? { - page: params['page'] || 1, - limit: params['pageSize'] || params['limit'] || 10, - serviceType: params['category'], // 后端使用serviceType + const queryParams : UTSJSONObject = { + page: params ? (params['page'] || 1) : 1, + limit: params ? (params['pageSize'] || params['limit'] || 10) : 10, status: 'published' // 只获取已发布的案例 - } : {} - return get('/cases', queryParams as UTSJSONObject) + } + // 如果有分类且不是all,则添加serviceType参数 + if (params && params['category'] && params['category'] != 'all') { + queryParams['serviceType'] = params['category'] + } + return get('/cases', queryParams) } /** @@ -77,10 +80,28 @@ export const getActiveServices = () => { } /** - * 获取公司信息 + * 获取公司信息(暂时返回固定数据,后续可对接后端) */ export const getCompanyInfo = () => { - return get('/company/info') + return Promise.resolve({ + code: 0, + message: 'success', + data: { + name: '优艺家沙发翻新', + slogan: '让旧沙发焕发新生', + description: '优艺家专注沙发翻新服务10余年,拥有专业的技术团队和丰富的经验。我们提供各类沙发翻新、维修、清洁服务,让您的旧沙发重新焕发光彩。', + phone: '400-888-8888', + wechat: 'youyijia2024', + address: '北京市朝阳区XX路XX号', + workTime: '周一至周日 9:00-18:00', + features: [ + { title: '专业团队', desc: '10年以上经验的专业师傅' }, + { title: '品质保证', desc: '使用优质材料,质保一年' }, + { title: '免费上门', desc: '免费上门测量和评估' }, + { title: '快速交付', desc: '3-7天完成翻新服务' } + ] + } + }) } /** @@ -90,11 +111,55 @@ export const submitBooking = (data : UTSJSONObject) => { return post('/booking', data) } +/** + * 获取我的预约列表 + */ +export const getMyBookings = (params ?: UTSJSONObject) => { + const queryParams = params ? { + page: params['page'] || 1, + limit: params['limit'] || 10, + status: params['status'] + } : {} + return get('/booking/my', queryParams as UTSJSONObject) +} + +/** + * 获取预约详情 + */ +export const getBookingDetail = (id : string) => { + return get(`/booking/${id}`) +} + +/** + * 取消预约 + */ +export const cancelBooking = (id : string) => { + return post(`/booking/${id}/cancel`, {} as UTSJSONObject) +} + /** * 获取用户信息 */ export const getUserInfo = () => { - return get('/user/info') + return get('/users/profile') +} + +/** + * 微信登录 + */ +export const wechatLogin = (code : string) => { + return post('/auth/wechat/login', { code: code } as UTSJSONObject) +} + +/** + * 微信手机号登录 + */ +export const wechatPhoneLogin = (code : string, encryptedData : string, iv : string) => { + return post('/auth/wechat/phone', { + code: code, + encryptedData: encryptedData, + iv: iv + } as UTSJSONObject) } /** diff --git a/前端/docs/前端功能完善总结.md b/前端/docs/前端功能完善总结.md new file mode 100644 index 0000000..8a799b1 --- /dev/null +++ b/前端/docs/前端功能完善总结.md @@ -0,0 +1,341 @@ +# 前端功能完善总结 + +## 📋 已完成功能清单 + +### 1. 首页 (pages/index/index.uvue) +✅ **已完善功能:** +- 轮播图展示(getBanners API) +- 服务类型展示(从配置读取) +- 公司优势展示 +- 热门案例展示(getHotCases API,已适配后端数据格式) +- 预约入口 +- 所有跳转链接已实现 + +✅ **数据对接:** +- 轮播图数据:固定数据(可扩展对接后端) +- 热门案例:`GET /api/cases?limit=4&status=published` + - 字段映射:`serviceType` → `category`, `afterImages[0]` → `coverImage` + +### 2. 案例列表 (pages/cases/list.uvue) +✅ **已完善功能:** +- 分类筛选(全部/布艺/皮革等) +- 案例列表展示 +- 分页加载 +- 上拉加载更多 +- 空状态提示 +- 加载状态提示 + +✅ **数据对接:** +- API: `GET /api/cases?page={page}&limit={limit}&serviceType={type}&status=published` +- 返回格式:`{ code, message, data: { list, total, page, pageSize } }` +- 字段映射完成 + +### 3. 案例详情 (pages/cases/detail.uvue) +✅ **已完善功能:** +- 案例图片轮播 +- 翻新前后对比 +- 案例详细信息 +- 收藏功能(本地存储) +- 分享功能(提示开发中) +- 在线咨询(拨打电话) +- 立即预约 + +✅ **数据对接:** +- API: `GET /api/cases/:id` +- 返回格式:`{ code, message, data: caseEntity }` +- 字段映射:`serviceType`, `materials`, `estimatedPrice`, `createdAt` 等 +- 自动增加浏览量 + +### 4. 服务介绍 (pages/service/index.uvue) +✅ **已完善功能:** +- 服务类型展示(从后端加载) +- 服务流程展示(固定数据) +- 材质说明 +- 常见问题FAQ(可展开/收起) +- 底部预约按钮 + +✅ **数据对接:** +- API: `GET /api/services/active` +- 返回格式:`{ code, message, data: { list, total } }` +- Emoji映射:fabric→🛋️, leather→💺, cleaning→✨, repair→🔧, custom→💎 + +### 5. 预约页面 (pages/booking/index.uvue) +✅ **已完善功能:** +- 动态加载服务列表 +- 联系人信息输入 +- 预约时间选择(日期选择器) +- 服务地址输入 +- 问题描述输入 +- 图片上传(最多9张) +- 表单验证(必填项、手机号格式) +- 提交预约 + +✅ **数据对接:** +- 加载服务:`GET /api/services/active` +- 提交预约:`POST /api/booking` +- 请求格式: + ```json + { + "serviceId": number, + "contactName": string, + "contactPhone": string, + "address": string, + "appointmentTime": string (ISO 8601), + "requirements": string, + "images": string[] + } + ``` + +### 6. 关于我们 (pages/about/index.uvue) +✅ **已完善功能:** +- 公司Logo和名称 +- 公司简介 +- 我们的优势 +- 联系方式(电话、微信、地址、营业时间) +- 拨打电话功能 +- 复制微信号功能 +- 打开地图功能(提示开发中) + +✅ **数据对接:** +- API: `getCompanyInfo()` - 返回固定数据 +- 可扩展对接后端公司信息管理API + +### 7. 用户中心 (pages/user/index.uvue) +✅ **已完善功能:** +- 用户信息显示 +- 登录/退出功能(微信登录) +- 功能菜单: + - ✅ 我的预约(跳转到预约列表) + - ✅ 我的收藏(跳转到收藏列表) + - ✅ 关于我们 + - ✅ 联系客服(拨打电话) + - 意见反馈(提示开发中) + - 检查更新(提示开发中) + - 清除缓存 +- 退出登录功能 + +### 8. 我的预约列表 (pages/user/booking-list.uvue) **【新增】** +✅ **已完善功能:** +- 状态筛选(全部/待确认/已确认/进行中/已完成/已取消) +- 预约列表展示 +- 分页加载 +- 预约详情查看 +- 取消预约功能 +- 联系客服 +- 空状态提示 + +✅ **数据对接:** +- API: `GET /api/booking/my?page={page}&limit={limit}&status={status}` +- 取消预约:`POST /api/booking/:id/cancel` +- 返回格式:`{ code, message, data: { list, total } }` + +### 9. 我的收藏 (pages/user/favorites.uvue) **【新增】** +✅ **已完善功能:** +- 收藏列表展示 +- 使用case-card组件复用 +- 空状态提示 +- 跳转到案例详情 + +⚠️ **待完善:** +- 需要后端提供收藏API +- 当前使用本地存储 + +## 📊 组件使用情况 + +### 自定义组件 +1. **nav-bar** - 自定义导航栏(首页使用) +2. **section-header** - 区块标题组件(首页、关于我们) +3. **service-card** - 服务卡片组件(首页) +4. **case-card** - 案例卡片组件(首页、案例列表、收藏列表) +5. **before-after** - 前后对比组件(案例详情) + +## 🔗 API对接情况 + +### 已对接的API + +| 功能模块 | API端点 | 方法 | 状态 | +|---------|---------|------|------| +| 轮播图 | - | - | 固定数据 | +| 热门案例 | /api/cases | GET | ✅ | +| 案例列表 | /api/cases | GET | ✅ | +| 案例详情 | /api/cases/:id | GET | ✅ | +| 活跃服务 | /api/services/active | GET | ✅ | +| 提交预约 | /api/booking | POST | ✅ | +| 我的预约 | /api/booking/my | GET | ✅ | +| 取消预约 | /api/booking/:id/cancel | POST | ✅ | +| 公司信息 | - | - | 固定数据 | + +### 待对接的API + +| 功能模块 | 建议API端点 | 方法 | 优先级 | +|---------|------------|------|--------| +| 用户登录 | /api/auth/wechat/login | POST | 高 | +| 用户信息 | /api/users/profile | GET | 高 | +| 收藏操作 | /api/cases/:id/favorite | POST | 中 | +| 收藏列表 | /api/users/favorites | GET | 中 | +| 图片上传 | /api/upload | POST | 中 | +| 轮播图管理 | /api/banners | GET | 低 | +| 公司信息 | /api/company/info | GET | 低 | + +## 📱 页面路由配置 + +```json +{ + "pages": [ + "pages/index/index", // 首页(自定义导航栏) + "pages/cases/list", // 案例列表 + "pages/cases/detail", // 案例详情 + "pages/service/index", // 服务介绍 + "pages/about/index", // 关于我们 + "pages/booking/index", // 预约咨询 + "pages/user/index", // 用户中心 + "pages/user/booking-list", // 我的预约 【新增】 + "pages/user/favorites" // 我的收藏 【新增】 + ], + "tabBar": { + "list": [ + "pages/index/index", // 首页 + "pages/cases/list", // 案例 + "pages/service/index", // 服务 + "pages/user/index" // 我的 + ] + } +} +``` + +## 🎨 UI/UX特性 + +### 已实现的交互 +- ✅ 上拉加载更多 +- ✅ 下拉刷新(部分页面) +- ✅ 图片预览 +- ✅ 加载状态提示 +- ✅ 空状态提示 +- ✅ Toast消息提示 +- ✅ Modal确认对话框 +- ✅ 分类筛选 +- ✅ 状态筛选 +- ✅ FAQ展开/收起 +- ✅ 图片上传预览 +- ✅ 日期选择器 + +### 样式规范 +- 主色调:#D4A574(金棕色) +- 背景色:#f5f5f5 +- 圆角:8rpx, 16rpx, 48rpx +- 间距:24rpx, 32rpx +- 字体大小:24rpx, 28rpx, 32rpx, 36rpx + +## 🔐 权限控制 + +### 需要登录的功能 +- 提交预约 +- 查看我的预约 +- 查看我的收藏 +- 取消预约 + +### 无需登录的功能 +- 浏览首页 +- 查看案例列表 +- 查看案例详情 +- 查看服务介绍 +- 查看关于我们 + +## 📝 本地存储使用 + +```typescript +STORAGE_KEYS = { + TOKEN: 'user_token', // 用户Token + USER_INFO: 'user_info', // 用户信息 + FAVORITES: 'user_favorites', // 收藏列表 + SEARCH_HISTORY: 'search_history' // 搜索历史 +} +``` + +## 🚀 测试建议 + +### 功能测试清单 + +#### 首页 +- [ ] 轮播图滑动 +- [ ] 点击服务类型跳转 +- [ ] 查看热门案例 +- [ ] 点击案例卡片跳转详情 +- [ ] 点击预约按钮跳转预约页 + +#### 案例模块 +- [ ] 切换分类筛选 +- [ ] 上拉加载更多 +- [ ] 查看案例详情 +- [ ] 图片轮播和预览 +- [ ] 收藏功能 +- [ ] 拨打客服电话 +- [ ] 跳转预约页面 + +#### 服务模块 +- [ ] 查看服务列表(从后端加载) +- [ ] 展开/收起FAQ +- [ ] 点击预约按钮 + +#### 预约模块 +- [ ] 选择服务类型(动态加载) +- [ ] 选择预约时间 +- [ ] 上传图片 +- [ ] 表单验证 +- [ ] 提交预约 +- [ ] 查看提交结果 + +#### 用户模块 +- [ ] 微信登录 +- [ ] 查看用户信息 +- [ ] 跳转我的预约 +- [ ] 跳转我的收藏 +- [ ] 拨打客服电话 +- [ ] 清除缓存 +- [ ] 退出登录 + +#### 我的预约 +- [ ] 切换状态筛选 +- [ ] 查看预约列表 +- [ ] 取消预约 +- [ ] 联系客服 + +## ⚠️ 已知问题 + +1. **图片上传**:前端有上传UI,但后端暂无图片上传API +2. **用户收藏**:收藏功能使用本地存储,需要后端API支持 +3. **微信登录**:登录流程模拟实现,需要配置微信小程序AppID +4. **图片资源**:使用placeholder图片,需要替换真实图片 + +## 📈 性能优化建议 + +1. **图片懒加载**:案例列表图片较多,建议使用懒加载 +2. **数据缓存**:服务列表、公司信息等不常变化的数据可以缓存 +3. **分页优化**:案例列表已实现分页,建议设置合理的pageSize +4. **防抖节流**:搜索、筛选等操作建议添加防抖 + +## 🎯 下一步开发计划 + +### 高优先级 +1. 完善用户登录功能(微信登录对接) +2. 实现图片上传功能 +3. 后端提供收藏API +4. 添加搜索功能 + +### 中优先级 +5. 开发后台管理系统 +6. 添加数据统计功能 +7. 优化图片加载性能 +8. 添加消息通知功能 + +### 低优先级 +9. 添加分享功能 +10. 添加评论功能 +11. 添加优惠券功能 +12. 添加积分系统 + +--- + +**文档更新时间:** 2026年1月28日 +**当前版本:** v1.0 +**完成度:** 前端核心功能 95%完成 diff --git a/前端/docs/接口对接完成报告.md b/前端/docs/接口对接完成报告.md new file mode 100644 index 0000000..caca589 --- /dev/null +++ b/前端/docs/接口对接完成报告.md @@ -0,0 +1,368 @@ +# 前后端接口对接完成报告 + +## 一、完成概览 + +本次开发完成了前后端的完整对接,包括: +- ✅ 新增预约(Booking)模块的完整后端实现 +- ✅ 修正所有前端API调用的路径和参数 +- ✅ 统一后端响应数据格式 +- ✅ 完善预约页面功能 +- ✅ 优化案例列表和详情页面的数据适配 + +## 二、后端完成的工作 + +### 1. 新增 Booking 模块 + +#### 文件结构 +``` +后端/src/booking/ +├── booking.controller.ts # 预约控制器 +├── booking.service.ts # 预约服务 +├── booking.module.ts # 预约模块 +└── dto/ + └── booking.dto.ts # 预约DTO +``` + +#### API 接口列表 + +| 方法 | 路径 | 说明 | 权限 | +|------|------|------|------| +| POST | /api/booking | 创建预约 | 登录用户 | +| GET | /api/booking | 获取所有预约 | 管理员/工人 | +| GET | /api/booking/my | 获取我的预约列表 | 登录用户 | +| GET | /api/booking/:id | 获取预约详情 | 登录用户 | +| PATCH | /api/booking/:id | 更新预约信息 | 本人/管理员 | +| POST | /api/booking/:id/cancel | 取消预约 | 本人/管理员 | +| DELETE | /api/booking/:id | 删除预约 | 管理员 | + +#### 预约数据模型 + +```typescript +{ + id: number; + bookingNumber: string; // 预约编号 (自动生成) + serviceId: number; // 服务ID + customerId: number; // 客户ID + contactName: string; // 联系人姓名 + contactPhone: string; // 联系电话 + address: string; // 服务地址 + appointmentTime: Date; // 预约时间 + requirements?: string; // 特殊要求 + images?: string[]; // 沙发现状图片 + status: string; // 状态: pending/confirmed/in_progress/completed/cancelled + quotedPrice?: number; // 报价 + finalPrice?: number; // 最终价格 + notes?: string; // 备注 + assignedWorkerId?: number; // 分配工人ID +} +``` + +### 2. 统一后端响应格式 + +所有API返回格式统一为: + +```typescript +{ + code: 0, // 0表示成功 + message: string, // 响应消息 + data: any // 响应数据 +} +``` + +**修改的服务:** +- `case.service.ts` - 案例服务 + - `findAll()` - 返回格式: `{ code, message, data: { list, total, page, pageSize } }` + - `findOne()` - 返回格式: `{ code, message, data: caseEntity }` + - `getMyCases()` - 返回格式: `{ code, message, data: { list, total, page, pageSize } }` + +- `service.service.ts` - 服务管理 + - `getActiveServices()` - 返回格式: `{ code, message, data: { list, total } }` + +- `booking.service.ts` - 预约管理 + - 所有方法统一返回上述格式 + +## 三、前端完成的工作 + +### 1. 修正 API 调用路径 + +**文件:** `前端/api/index.uts` + +#### 修改的接口: + +1. **用户信息接口** + ```typescript + // 修改前: /user/info + // 修改后: /users/profile + export const getUserInfo = () => { + return get('/users/profile') + } + ``` + +2. **案例列表接口** + ```typescript + export const getCaseList = (params ?: UTSJSONObject) => { + const queryParams : UTSJSONObject = { + page: params ? (params['page'] || 1) : 1, + limit: params ? (params['pageSize'] || params['limit'] || 10) : 10, + status: 'published' + } + // 只在有分类且不为'all'时添加serviceType参数 + if (params && params['category'] && params['category'] != 'all') { + queryParams['serviceType'] = params['category'] + } + return get('/cases', queryParams) + } + ``` + +3. **公司信息接口** + ```typescript + // 改为返回固定数据(临时方案,后续可对接后端) + export const getCompanyInfo = () => { + return Promise.resolve({ + code: 0, + message: 'success', + data: { + name: '优艺家沙发翻新', + slogan: '让旧沙发焕发新生', + // ... 其他信息 + } + }) + } + ``` + +4. **新增预约相关接口** + ```typescript + // 提交预约 + export const submitBooking = (data : UTSJSONObject) => { + return post('/booking', data) + } + + // 获取我的预约列表 + export const getMyBookings = (params ?: UTSJSONObject) => { + return get('/booking/my', queryParams) + } + + // 获取预约详情 + export const getBookingDetail = (id : string) => { + return get(`/booking/${id}`) + } + + // 取消预约 + export const cancelBooking = (id : string) => { + return post(`/booking/${id}/cancel`, {}) + } + ``` + +### 2. 完善预约页面 + +**文件:** `前端/pages/booking/index.uvue` + +#### 主要改进: + +1. **动态加载服务列表** + - 从后端 `/api/services/active` 获取可用服务 + - 用户可选择具体的服务类型 + +2. **添加预约时间选择** + - 使用日期选择器选择预约日期 + - 最小日期为当天 + +3. **完善表单验证** + - 必填项:姓名、电话、地址、服务类型、预约时间 + - 手机号格式验证 + +4. **正确的数据提交格式** + ```typescript + { + serviceId: number, // 服务ID + contactName: string, // 联系人姓名 + contactPhone: string, // 联系电话 + address: string, // 服务地址 + appointmentTime: string, // 预约时间 (ISO 8601格式) + requirements: string, // 特殊要求 + images: string[] // 图片列表 + } + ``` + +### 3. 优化案例列表页面 + +**文件:** `前端/pages/cases/list.uvue` + +#### 数据适配改进: + +```typescript +// 适应后端返回的字段结构 +const newList = list.map((item) : CaseItem => { + return { + id: String(item['id']), + title: item['title'] as string, + category: item['serviceType'] as string, // 后端字段 + categoryName: item['serviceName'] as string, // 服务名称 + coverImage: item['coverImage'] as string, + material: item['material'] as string || '', + duration: item['duration'] as string || '', + price: String(item['estimatedPrice'] || 0), // 估算价格 + views: item['views'] as number || 0, + likes: item['likes'] as number || 0 + } +}) +``` + +### 4. 优化案例详情页面 + +**文件:** `前端/pages/cases/detail.uvue` + +#### 数据映射优化: + +```typescript +caseDetail.value = { + id: String(data['id']), + title: data['title'] as string, + category: data['serviceType'] as string || '', // 后端使用serviceType + categoryName: data['serviceName'] as string || '', + beforeImages: data['beforeImages'] as string[] || [], + afterImages: data['afterImages'] as string[] || [], + description: data['description'] as string, + material: data['material'] as string || '优质材料', + duration: data['duration'] as string || '5-7天', + price: '¥' + (data['estimatedPrice'] || '面议'), + views: data['views'] as number || 0, + likes: data['likes'] as number || 0, + createTime: createdAt.split('T')[0] || '' // 格式化日期 +} +``` + +## 四、配置更新 + +### 环境配置 + +**文件:** `前端/utils/config.uts` + +```typescript +export const ENV = { + development: { + baseUrl: 'http://localhost:3000/api', + imageBaseUrl: 'http://localhost:3000' + }, + production: { + baseUrl: 'https://api.youyijia.com/api', + imageBaseUrl: 'https://api.youyijia.com' + } +} + +// 当前环境 +export const currentEnv = 'development' + +// 关闭Mock数据 +export const useMock = false +``` + +## 五、接口对应关系总结 + +### 1. 认证相关 +| 前端调用 | 后端路径 | 说明 | +|---------|---------|------| +| - | POST /api/auth/register | 用户注册 | +| - | POST /api/auth/login | 用户登录 | +| - | POST /api/auth/wechat/login | 微信登录 | + +### 2. 用户相关 +| 前端调用 | 后端路径 | 说明 | +|---------|---------|------| +| getUserInfo() | GET /api/users/profile | 获取当前用户信息 | + +### 3. 案例相关 +| 前端调用 | 后端路径 | 说明 | +|---------|---------|------| +| getCaseList(params) | GET /api/cases?page&limit&serviceType&status | 获取案例列表 | +| getCaseDetail(id) | GET /api/cases/:id | 获取案例详情 | +| getHotCases() | GET /api/cases?limit=4&status=published | 获取热门案例 | + +### 4. 服务相关 +| 前端调用 | 后端路径 | 说明 | +|---------|---------|------| +| getActiveServices() | GET /api/services/active | 获取有效服务列表 | +| getServiceProcess() | GET /api/services | 获取服务流程 | + +### 5. 预约相关 +| 前端调用 | 后端路径 | 说明 | +|---------|---------|------| +| submitBooking(data) | POST /api/booking | 提交预约 | +| getMyBookings(params) | GET /api/booking/my | 获取我的预约 | +| getBookingDetail(id) | GET /api/booking/:id | 获取预约详情 | +| cancelBooking(id) | POST /api/booking/:id/cancel | 取消预约 | + +## 六、后端服务状态 + +### 服务器信息 +- **地址:** http://localhost:3000 +- **API文档:** http://localhost:3000/docs +- **状态:** ✅ 运行中 + +### 数据库连接 +- **类型:** MySQL +- **数据库:** sffx +- **状态:** ✅ 已连接 + +### 已注册的模块 +- ✅ AppModule +- ✅ AuthModule (认证模块) +- ✅ UserModule (用户模块) +- ✅ CaseModule (案例模块) +- ✅ ServiceModule (服务模块) +- ✅ BookingModule (预约模块) **【新增】** + +## 七、待完成的工作 + +### 1. 前端功能待完善 +- [ ] 用户登录/注册页面 +- [ ] 我的预约列表页面 +- [ ] 收藏功能实现 +- [ ] 图片上传功能 + +### 2. 后端功能待完善 +- [ ] 用户收藏API +- [ ] 图片上传API +- [ ] 公司信息管理API +- [ ] 轮播图管理API + +### 3. 后台管理界面 +- [ ] 后台管理系统开发(等前端功能完善后开始) + - 用户管理 + - 案例管理 + - 服务管理 + - 预约管理 + - 数据统计 + +## 八、测试建议 + +### 1. 接口测试 +访问 http://localhost:3000/docs 查看Swagger API文档,可以在线测试所有接口。 + +### 2. 前端测试流程 +1. 启动后端服务:`cd 后端 && npm run start:dev` +2. 启动前端:使用HBuilderX运行到浏览器或小程序 +3. 测试流程: + - 浏览首页,查看案例列表 + - 点击案例查看详情 + - 进入服务页面查看服务列表 + - 填写预约表单并提交 + +### 3. 需要准备的测试数据 +- 创建管理员账号 +- 添加服务类型(布艺沙发、皮沙发等) +- 添加几个案例数据 +- 测试预约流程 + +## 九、注意事项 + +1. **认证机制**:部分接口需要登录后才能访问,需要在请求头中携带 Bearer Token +2. **数据库同步**:后端配置了 `synchronize: true`,会自动同步数据库结构 +3. **跨域问题**:如需在不同域名访问,需配置CORS +4. **图片存储**:当前图片路径为字符串数组,需要配置文件上传服务 + +--- + +**报告生成时间:** 2026年1月28日 +**完成人员:** GitHub Copilot +**项目状态:** 前后端基础对接完成,可进行功能测试 diff --git a/前端/pages.json b/前端/pages.json index 3616eda..46b2a49 100644 --- a/前端/pages.json +++ b/前端/pages.json @@ -43,6 +43,18 @@ "style": { "navigationBarTitleText": "我的" } + }, + { + "path": "pages/user/booking-list", + "style": { + "navigationBarTitleText": "我的预约" + } + }, + { + "path": "pages/user/favorites", + "style": { + "navigationBarTitleText": "我的收藏" + } } ], "globalStyle": { diff --git a/前端/pages/booking/index.uvue b/前端/pages/booking/index.uvue index ae53833..4c06417 100644 --- a/前端/pages/booking/index.uvue +++ b/前端/pages/booking/index.uvue @@ -55,25 +55,47 @@ /> - + - 沙发类型 + + * + 服务类型 + {{ item.name }} + + + + * + 预约时间 + + + + {{ formData.appointmentDate }} + 请选择预约日期 + + + + 问题描述 @@ -106,7 +128,7 @@ 添加图片 - 最多可上传9张图片 + 提示:当前仅支持预览,图片暂不会上传到服务器 @@ -124,22 +146,25 @@ @@ -347,6 +450,25 @@ color: #C0C4CC; } + /* 日期选择器 */ + .picker-value { + background-color: #f5f5f5; + border-radius: 12rpx; + padding: 24rpx; + height: 40px; + justify-content: center; + } + + .picker-text { + font-size: 28rpx; + color: #303133; + } + + .picker-placeholder { + font-size: 28rpx; + color: #C0C4CC; + } + /* 沙发类型选择 */ .type-grid { flex-direction: row; diff --git a/前端/pages/cases/detail.uvue b/前端/pages/cases/detail.uvue index ee26acf..ac16160 100644 --- a/前端/pages/cases/detail.uvue +++ b/前端/pages/cases/detail.uvue @@ -40,7 +40,7 @@ @@ -102,6 +102,7 @@ diff --git a/前端/pages/user/booking-list.uvue b/前端/pages/user/booking-list.uvue new file mode 100644 index 0000000..8c95465 --- /dev/null +++ b/前端/pages/user/booking-list.uvue @@ -0,0 +1,513 @@ + + + + + + + + {{ item.label }} + + + + + + + + + + + 预约编号:{{ item.bookingNumber }} + + {{ getStatusText(item.status) }} + + + + + + 服务类型 + {{ item.serviceName }} + + + 预约时间 + {{ formatDate(item.appointmentTime) }} + + + 联系电话 + {{ item.contactPhone }} + + + 服务地址 + {{ item.address }} + + + + + 创建时间:{{ formatDate(item.createdAt) }} + + + 取消预约 + + + 联系客服 + + + + + + + + + 加载中... + 没有更多了 + + + + + 📋 + 暂无预约记录 + + 立即预约 + + + + + + + + + + + + diff --git a/前端/pages/user/favorites.uvue b/前端/pages/user/favorites.uvue new file mode 100644 index 0000000..44799b1 --- /dev/null +++ b/前端/pages/user/favorites.uvue @@ -0,0 +1,132 @@ + + + + + + + + + + + ❤️ + 还没有收藏任何案例 + + 去看看案例 + + + + + + + + + + + + diff --git a/前端/pages/user/index.uvue b/前端/pages/user/index.uvue index 057135b..efae8f3 100644 --- a/前端/pages/user/index.uvue +++ b/前端/pages/user/index.uvue @@ -120,6 +120,7 @@ \r\n\r\n","import App from './App.uvue'\r\n\r\nimport { createSSRApp } from 'vue'\r\nexport function createApp() {\r\n\tconst app = createSSRApp(App)\r\n\treturn {\r\n\t\tapp\r\n\t}\r\n}"],"names":["defineComponent","uni","createSSRApp","App"],"mappings":";;;;;;;;;;;;AAIC,MAAA,YAAeA,8BAAA;AAAA,EACd,WAAQ;AACPC,kBAAAA,MAAI,MAAM,OAAM,iBAAgB,YAAY;AAAA,EAC5C;AAAA,EACD,SAAM;AACLA,kBAAAA,MAAI,MAAM,OAAM,kBAAiB,UAAU;AAAA,EAC3C;AAAA,EACD,SAAM;AACLA,kBAAAA,MAAI,MAAM,OAAM,kBAAiB,UAAU;AAAA,EAC3C;AAAA,EAmBD,SAAM;AACLA,kBAAAA,MAAI,MAAM,OAAM,kBAAiB,UAAU;AAAA,EAC3C;CACF;SChCe,YAAS;AACxB,QAAM,MAAMC,2BAAaC,SAAG;AAC5B,SAAO;AAAA,IACN;AAAA;AAEF;AACA,YAAY,IAAI,MAAM,MAAM;;"} \ No newline at end of file +{"version":3,"file":"app.js","sources":["App.uvue","main.uts"],"sourcesContent":["\r\n\r\n","import App from './App.uvue'\r\n\r\nimport { createSSRApp } from 'vue'\r\nexport function createApp() {\r\n\tconst app = createSSRApp(App)\r\n\treturn {\r\n\t\tapp\r\n\t}\r\n}"],"names":["defineComponent","uni","createSSRApp","App"],"mappings":";;;;;;;;;;;;;;AAIC,MAAA,YAAeA,8BAAA;AAAA,EACd,WAAQ;AACPC,kBAAAA,MAAI,MAAM,OAAM,iBAAgB,YAAY;AAAA,EAC5C;AAAA,EACD,SAAM;AACLA,kBAAAA,MAAI,MAAM,OAAM,kBAAiB,UAAU;AAAA,EAC3C;AAAA,EACD,SAAM;AACLA,kBAAAA,MAAI,MAAM,OAAM,kBAAiB,UAAU;AAAA,EAC3C;AAAA,EAmBD,SAAM;AACLA,kBAAAA,MAAI,MAAM,OAAM,kBAAiB,UAAU;AAAA,EAC3C;CACF;SChCe,YAAS;AACxB,QAAM,MAAMC,2BAAaC,SAAG;AAC5B,SAAO;AAAA,IACN;AAAA;AAEF;AACA,YAAY,IAAI,MAAM,MAAM;;"} \ No newline at end of file diff --git a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/common/vendor.js.map b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/common/vendor.js.map index 9977645..3fc7702 100644 --- a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/common/vendor.js.map +++ b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/common/vendor.js.map @@ -1 +1 @@ -{"version":3,"file":"vendor.js","sources":["../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/node_modules/@vue/shared/dist/shared.esm-bundler.js","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/node_modules/@dcloudio/uni-i18n/dist/uni-i18n.es.js","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/node_modules/@dcloudio/uni-shared/dist/uni-shared.es.js","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/node_modules/@dcloudio/uni-mp-vue/dist-x/vue.runtime.esm.js","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/node_modules/@dcloudio/uni-mp-weixin/dist-x/uni.api.esm.js","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/node_modules/@dcloudio/uni-console/dist/mp.esm.js","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/node_modules/@dcloudio/uni-mp-weixin/dist-x/uni.mp.esm.js","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/node_modules/@dcloudio/uni-app/dist-x/uni-app.es.js"],"sourcesContent":["/**\n* @vue/shared v3.4.21\n* (c) 2018-present Yuxi (Evan) You and Vue contributors\n* @license MIT\n**/\nfunction makeMap(str, expectsLowerCase) {\n const set = new Set(str.split(\",\"));\n return expectsLowerCase ? (val) => set.has(val.toLowerCase()) : (val) => set.has(val);\n}\n\nconst EMPTY_OBJ = !!(process.env.NODE_ENV !== \"production\") ? Object.freeze({}) : {};\nconst EMPTY_ARR = !!(process.env.NODE_ENV !== \"production\") ? Object.freeze([]) : [];\nconst NOOP = () => {\n};\nconst NO = () => false;\nconst isOn = (key) => key.charCodeAt(0) === 111 && key.charCodeAt(1) === 110 && // uppercase letter\n(key.charCodeAt(2) > 122 || key.charCodeAt(2) < 97);\nconst isModelListener = (key) => key.startsWith(\"onUpdate:\");\nconst extend = Object.assign;\nconst remove = (arr, el) => {\n const i = arr.indexOf(el);\n if (i > -1) {\n arr.splice(i, 1);\n }\n};\nconst hasOwnProperty = Object.prototype.hasOwnProperty;\nconst hasOwn = (val, key) => hasOwnProperty.call(val, key);\nconst isArray = Array.isArray;\nconst isMap = (val) => toTypeString(val) === \"[object Map]\";\nconst isSet = (val) => toTypeString(val) === \"[object Set]\";\nconst isDate = (val) => toTypeString(val) === \"[object Date]\";\nconst isRegExp = (val) => toTypeString(val) === \"[object RegExp]\";\nconst isFunction = (val) => typeof val === \"function\";\nconst isString = (val) => typeof val === \"string\";\nconst isSymbol = (val) => typeof val === \"symbol\";\nconst isObject = (val) => val !== null && typeof val === \"object\";\nconst isPromise = (val) => {\n return (isObject(val) || isFunction(val)) && isFunction(val.then) && isFunction(val.catch);\n};\nconst objectToString = Object.prototype.toString;\nconst toTypeString = (value) => objectToString.call(value);\nconst toRawType = (value) => {\n return toTypeString(value).slice(8, -1);\n};\nconst isPlainObject = (val) => toTypeString(val) === \"[object Object]\";\nconst isIntegerKey = (key) => isString(key) && key !== \"NaN\" && key[0] !== \"-\" && \"\" + parseInt(key, 10) === key;\nconst isReservedProp = /* @__PURE__ */ makeMap(\n // the leading comma is intentional so empty string \"\" is also included\n \",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted\"\n);\nconst isBuiltInDirective = /* @__PURE__ */ makeMap(\n \"bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text,memo\"\n);\nconst cacheStringFunction = (fn) => {\n const cache = /* @__PURE__ */ Object.create(null);\n return (str) => {\n const hit = cache[str];\n return hit || (cache[str] = fn(str));\n };\n};\nconst camelizeRE = /-(\\w)/g;\nconst camelize = cacheStringFunction((str) => {\n return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : \"\");\n});\nconst hyphenateRE = /\\B([A-Z])/g;\nconst hyphenate = cacheStringFunction(\n (str) => str.replace(hyphenateRE, \"-$1\").toLowerCase()\n);\nconst capitalize = cacheStringFunction((str) => {\n return str.charAt(0).toUpperCase() + str.slice(1);\n});\nconst toHandlerKey = cacheStringFunction((str) => {\n const s = str ? `on${capitalize(str)}` : ``;\n return s;\n});\nconst hasChanged = (value, oldValue) => !Object.is(value, oldValue);\nconst invokeArrayFns = (fns, arg) => {\n for (let i = 0; i < fns.length; i++) {\n fns[i](arg);\n }\n};\nconst def = (obj, key, value) => {\n Object.defineProperty(obj, key, {\n configurable: true,\n enumerable: false,\n value\n });\n};\nconst looseToNumber = (val) => {\n const n = parseFloat(val);\n return isNaN(n) ? val : n;\n};\nconst toNumber = (val) => {\n const n = isString(val) ? Number(val) : NaN;\n return isNaN(n) ? val : n;\n};\nlet _globalThis;\nconst getGlobalThis = () => {\n return _globalThis || (_globalThis = typeof globalThis !== \"undefined\" ? globalThis : typeof self !== \"undefined\" ? self : typeof window !== \"undefined\" ? window : typeof global !== \"undefined\" ? global : {});\n};\nconst identRE = /^[_$a-zA-Z\\xA0-\\uFFFF][_$a-zA-Z0-9\\xA0-\\uFFFF]*$/;\nfunction genPropsAccessExp(name) {\n return identRE.test(name) ? `__props.${name}` : `__props[${JSON.stringify(name)}]`;\n}\n\nconst PatchFlags = {\n \"TEXT\": 1,\n \"1\": \"TEXT\",\n \"CLASS\": 2,\n \"2\": \"CLASS\",\n \"STYLE\": 4,\n \"4\": \"STYLE\",\n \"PROPS\": 8,\n \"8\": \"PROPS\",\n \"FULL_PROPS\": 16,\n \"16\": \"FULL_PROPS\",\n \"NEED_HYDRATION\": 32,\n \"32\": \"NEED_HYDRATION\",\n \"STABLE_FRAGMENT\": 64,\n \"64\": \"STABLE_FRAGMENT\",\n \"KEYED_FRAGMENT\": 128,\n \"128\": \"KEYED_FRAGMENT\",\n \"UNKEYED_FRAGMENT\": 256,\n \"256\": \"UNKEYED_FRAGMENT\",\n \"NEED_PATCH\": 512,\n \"512\": \"NEED_PATCH\",\n \"DYNAMIC_SLOTS\": 1024,\n \"1024\": \"DYNAMIC_SLOTS\",\n \"DEV_ROOT_FRAGMENT\": 2048,\n \"2048\": \"DEV_ROOT_FRAGMENT\",\n \"HOISTED\": -1,\n \"-1\": \"HOISTED\",\n \"BAIL\": -2,\n \"-2\": \"BAIL\"\n};\nconst PatchFlagNames = {\n [1]: `TEXT`,\n [2]: `CLASS`,\n [4]: `STYLE`,\n [8]: `PROPS`,\n [16]: `FULL_PROPS`,\n [32]: `NEED_HYDRATION`,\n [64]: `STABLE_FRAGMENT`,\n [128]: `KEYED_FRAGMENT`,\n [256]: `UNKEYED_FRAGMENT`,\n [512]: `NEED_PATCH`,\n [1024]: `DYNAMIC_SLOTS`,\n [2048]: `DEV_ROOT_FRAGMENT`,\n [-1]: `HOISTED`,\n [-2]: `BAIL`\n};\n\nconst ShapeFlags = {\n \"ELEMENT\": 1,\n \"1\": \"ELEMENT\",\n \"FUNCTIONAL_COMPONENT\": 2,\n \"2\": \"FUNCTIONAL_COMPONENT\",\n \"STATEFUL_COMPONENT\": 4,\n \"4\": \"STATEFUL_COMPONENT\",\n \"TEXT_CHILDREN\": 8,\n \"8\": \"TEXT_CHILDREN\",\n \"ARRAY_CHILDREN\": 16,\n \"16\": \"ARRAY_CHILDREN\",\n \"SLOTS_CHILDREN\": 32,\n \"32\": \"SLOTS_CHILDREN\",\n \"TELEPORT\": 64,\n \"64\": \"TELEPORT\",\n \"SUSPENSE\": 128,\n \"128\": \"SUSPENSE\",\n \"COMPONENT_SHOULD_KEEP_ALIVE\": 256,\n \"256\": \"COMPONENT_SHOULD_KEEP_ALIVE\",\n \"COMPONENT_KEPT_ALIVE\": 512,\n \"512\": \"COMPONENT_KEPT_ALIVE\",\n \"COMPONENT\": 6,\n \"6\": \"COMPONENT\"\n};\n\nconst SlotFlags = {\n \"STABLE\": 1,\n \"1\": \"STABLE\",\n \"DYNAMIC\": 2,\n \"2\": \"DYNAMIC\",\n \"FORWARDED\": 3,\n \"3\": \"FORWARDED\"\n};\nconst slotFlagsText = {\n [1]: \"STABLE\",\n [2]: \"DYNAMIC\",\n [3]: \"FORWARDED\"\n};\n\nconst GLOBALS_ALLOWED = \"Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console,Error\";\nconst isGloballyAllowed = /* @__PURE__ */ makeMap(GLOBALS_ALLOWED);\nconst isGloballyWhitelisted = isGloballyAllowed;\n\nconst range = 2;\nfunction generateCodeFrame(source, start = 0, end = source.length) {\n let lines = source.split(/(\\r?\\n)/);\n const newlineSequences = lines.filter((_, idx) => idx % 2 === 1);\n lines = lines.filter((_, idx) => idx % 2 === 0);\n let count = 0;\n const res = [];\n for (let i = 0; i < lines.length; i++) {\n count += lines[i].length + (newlineSequences[i] && newlineSequences[i].length || 0);\n if (count >= start) {\n for (let j = i - range; j <= i + range || end > count; j++) {\n if (j < 0 || j >= lines.length)\n continue;\n const line = j + 1;\n res.push(\n `${line}${\" \".repeat(Math.max(3 - String(line).length, 0))}| ${lines[j]}`\n );\n const lineLength = lines[j].length;\n const newLineSeqLength = newlineSequences[j] && newlineSequences[j].length || 0;\n if (j === i) {\n const pad = start - (count - (lineLength + newLineSeqLength));\n const length = Math.max(\n 1,\n end > count ? lineLength - pad : end - start\n );\n res.push(` | ` + \" \".repeat(pad) + \"^\".repeat(length));\n } else if (j > i) {\n if (end > count) {\n const length = Math.max(Math.min(end - count, lineLength), 1);\n res.push(` | ` + \"^\".repeat(length));\n }\n count += lineLength + newLineSeqLength;\n }\n }\n break;\n }\n }\n return res.join(\"\\n\");\n}\n\nfunction normalizeStyle(value) {\n if (isArray(value)) {\n const res = {};\n for (let i = 0; i < value.length; i++) {\n const item = value[i];\n const normalized = isString(item) ? parseStringStyle(item) : normalizeStyle(item);\n if (normalized) {\n for (const key in normalized) {\n res[key] = normalized[key];\n }\n }\n }\n return res;\n } else if (isString(value) || isObject(value)) {\n return value;\n }\n}\nconst listDelimiterRE = /;(?![^(]*\\))/g;\nconst propertyDelimiterRE = /:([^]+)/;\nconst styleCommentRE = /\\/\\*[^]*?\\*\\//g;\nfunction parseStringStyle(cssText) {\n const ret = {};\n cssText.replace(styleCommentRE, \"\").split(listDelimiterRE).forEach((item) => {\n if (item) {\n const tmp = item.split(propertyDelimiterRE);\n tmp.length > 1 && (ret[tmp[0].trim()] = tmp[1].trim());\n }\n });\n return ret;\n}\nfunction stringifyStyle(styles) {\n let ret = \"\";\n if (!styles || isString(styles)) {\n return ret;\n }\n for (const key in styles) {\n const value = styles[key];\n const normalizedKey = key.startsWith(`--`) ? key : hyphenate(key);\n if (isString(value) || typeof value === \"number\") {\n ret += `${normalizedKey}:${value};`;\n }\n }\n return ret;\n}\nfunction normalizeClass(value) {\n let res = \"\";\n if (isString(value)) {\n res = value;\n } else if (isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n const normalized = normalizeClass(value[i]);\n if (normalized) {\n res += normalized + \" \";\n }\n }\n } else if (isObject(value)) {\n for (const name in value) {\n if (value[name]) {\n res += name + \" \";\n }\n }\n }\n return res.trim();\n}\nfunction normalizeProps(props) {\n if (!props)\n return null;\n let { class: klass, style } = props;\n if (klass && !isString(klass)) {\n props.class = normalizeClass(klass);\n }\n if (style) {\n props.style = normalizeStyle(style);\n }\n return props;\n}\n\nconst HTML_TAGS = \"html,body,base,head,link,meta,style,title,address,article,aside,footer,header,hgroup,h1,h2,h3,h4,h5,h6,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,summary,template,blockquote,iframe,tfoot\";\nconst SVG_TAGS = \"svg,animate,animateMotion,animateTransform,circle,clipPath,color-profile,defs,desc,discard,ellipse,feBlend,feColorMatrix,feComponentTransfer,feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,feDistantLight,feDropShadow,feFlood,feFuncA,feFuncB,feFuncG,feFuncR,feGaussianBlur,feImage,feMerge,feMergeNode,feMorphology,feOffset,fePointLight,feSpecularLighting,feSpotLight,feTile,feTurbulence,filter,foreignObject,g,hatch,hatchpath,image,line,linearGradient,marker,mask,mesh,meshgradient,meshpatch,meshrow,metadata,mpath,path,pattern,polygon,polyline,radialGradient,rect,set,solidcolor,stop,switch,symbol,text,textPath,title,tspan,unknown,use,view\";\nconst MATH_TAGS = \"annotation,annotation-xml,maction,maligngroup,malignmark,math,menclose,merror,mfenced,mfrac,mfraction,mglyph,mi,mlabeledtr,mlongdiv,mmultiscripts,mn,mo,mover,mpadded,mphantom,mprescripts,mroot,mrow,ms,mscarries,mscarry,msgroup,msline,mspace,msqrt,msrow,mstack,mstyle,msub,msubsup,msup,mtable,mtd,mtext,mtr,munder,munderover,none,semantics\";\nconst VOID_TAGS = \"area,base,br,col,embed,hr,img,input,link,meta,param,source,track,wbr\";\nconst isHTMLTag = /* @__PURE__ */ makeMap(HTML_TAGS);\nconst isSVGTag = /* @__PURE__ */ makeMap(SVG_TAGS);\nconst isMathMLTag = /* @__PURE__ */ makeMap(MATH_TAGS);\nconst isVoidTag = /* @__PURE__ */ makeMap(VOID_TAGS);\n\nconst specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`;\nconst isSpecialBooleanAttr = /* @__PURE__ */ makeMap(specialBooleanAttrs);\nconst isBooleanAttr = /* @__PURE__ */ makeMap(\n specialBooleanAttrs + `,async,autofocus,autoplay,controls,default,defer,disabled,hidden,inert,loop,open,required,reversed,scoped,seamless,checked,muted,multiple,selected`\n);\nfunction includeBooleanAttr(value) {\n return !!value || value === \"\";\n}\nconst unsafeAttrCharRE = /[>/=\"'\\u0009\\u000a\\u000c\\u0020]/;\nconst attrValidationCache = {};\nfunction isSSRSafeAttrName(name) {\n if (attrValidationCache.hasOwnProperty(name)) {\n return attrValidationCache[name];\n }\n const isUnsafe = unsafeAttrCharRE.test(name);\n if (isUnsafe) {\n console.error(`unsafe attribute name: ${name}`);\n }\n return attrValidationCache[name] = !isUnsafe;\n}\nconst propsToAttrMap = {\n acceptCharset: \"accept-charset\",\n className: \"class\",\n htmlFor: \"for\",\n httpEquiv: \"http-equiv\"\n};\nconst isKnownHtmlAttr = /* @__PURE__ */ makeMap(\n `accept,accept-charset,accesskey,action,align,allow,alt,async,autocapitalize,autocomplete,autofocus,autoplay,background,bgcolor,border,buffered,capture,challenge,charset,checked,cite,class,code,codebase,color,cols,colspan,content,contenteditable,contextmenu,controls,coords,crossorigin,csp,data,datetime,decoding,default,defer,dir,dirname,disabled,download,draggable,dropzone,enctype,enterkeyhint,for,form,formaction,formenctype,formmethod,formnovalidate,formtarget,headers,height,hidden,high,href,hreflang,http-equiv,icon,id,importance,inert,integrity,ismap,itemprop,keytype,kind,label,lang,language,loading,list,loop,low,manifest,max,maxlength,minlength,media,min,multiple,muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,preload,radiogroup,readonly,referrerpolicy,rel,required,reversed,rows,rowspan,sandbox,scope,scoped,selected,shape,size,sizes,slot,span,spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,target,title,translate,type,usemap,value,width,wrap`\n);\nconst isKnownSvgAttr = /* @__PURE__ */ makeMap(\n `xmlns,accent-height,accumulate,additive,alignment-baseline,alphabetic,amplitude,arabic-form,ascent,attributeName,attributeType,azimuth,baseFrequency,baseline-shift,baseProfile,bbox,begin,bias,by,calcMode,cap-height,class,clip,clipPathUnits,clip-path,clip-rule,color,color-interpolation,color-interpolation-filters,color-profile,color-rendering,contentScriptType,contentStyleType,crossorigin,cursor,cx,cy,d,decelerate,descent,diffuseConstant,direction,display,divisor,dominant-baseline,dur,dx,dy,edgeMode,elevation,enable-background,end,exponent,fill,fill-opacity,fill-rule,filter,filterRes,filterUnits,flood-color,flood-opacity,font-family,font-size,font-size-adjust,font-stretch,font-style,font-variant,font-weight,format,from,fr,fx,fy,g1,g2,glyph-name,glyph-orientation-horizontal,glyph-orientation-vertical,glyphRef,gradientTransform,gradientUnits,hanging,height,href,hreflang,horiz-adv-x,horiz-origin-x,id,ideographic,image-rendering,in,in2,intercept,k,k1,k2,k3,k4,kernelMatrix,kernelUnitLength,kerning,keyPoints,keySplines,keyTimes,lang,lengthAdjust,letter-spacing,lighting-color,limitingConeAngle,local,marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mask,maskContentUnits,maskUnits,mathematical,max,media,method,min,mode,name,numOctaves,offset,opacity,operator,order,orient,orientation,origin,overflow,overline-position,overline-thickness,panose-1,paint-order,path,pathLength,patternContentUnits,patternTransform,patternUnits,ping,pointer-events,points,pointsAtX,pointsAtY,pointsAtZ,preserveAlpha,preserveAspectRatio,primitiveUnits,r,radius,referrerPolicy,refX,refY,rel,rendering-intent,repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,result,rotate,rx,ry,scale,seed,shape-rendering,slope,spacing,specularConstant,specularExponent,speed,spreadMethod,startOffset,stdDeviation,stemh,stemv,stitchTiles,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,string,stroke,stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-width,style,surfaceScale,systemLanguage,tabindex,tableValues,target,targetX,targetY,text-anchor,text-decoration,text-rendering,textLength,to,transform,transform-origin,type,u1,u2,underline-position,underline-thickness,unicode,unicode-bidi,unicode-range,units-per-em,v-alphabetic,v-hanging,v-ideographic,v-mathematical,values,vector-effect,version,vert-adv-y,vert-origin-x,vert-origin-y,viewBox,viewTarget,visibility,width,widths,word-spacing,writing-mode,x,x-height,x1,x2,xChannelSelector,xlink:actuate,xlink:arcrole,xlink:href,xlink:role,xlink:show,xlink:title,xlink:type,xmlns:xlink,xml:base,xml:lang,xml:space,y,y1,y2,yChannelSelector,z,zoomAndPan`\n);\nfunction isRenderableAttrValue(value) {\n if (value == null) {\n return false;\n }\n const type = typeof value;\n return type === \"string\" || type === \"number\" || type === \"boolean\";\n}\n\nconst escapeRE = /[\"'&<>]/;\nfunction escapeHtml(string) {\n const str = \"\" + string;\n const match = escapeRE.exec(str);\n if (!match) {\n return str;\n }\n let html = \"\";\n let escaped;\n let index;\n let lastIndex = 0;\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34:\n escaped = \""\";\n break;\n case 38:\n escaped = \"&\";\n break;\n case 39:\n escaped = \"'\";\n break;\n case 60:\n escaped = \"<\";\n break;\n case 62:\n escaped = \">\";\n break;\n default:\n continue;\n }\n if (lastIndex !== index) {\n html += str.slice(lastIndex, index);\n }\n lastIndex = index + 1;\n html += escaped;\n }\n return lastIndex !== index ? html + str.slice(lastIndex, index) : html;\n}\nconst commentStripRE = /^-?>||--!>| looseEqual(item, val));\n}\n\nconst toDisplayString = (val) => {\n return isString(val) ? val : val == null ? \"\" : isArray(val) || isObject(val) && (val.toString === objectToString || !isFunction(val.toString)) ? JSON.stringify(val, replacer, 2) : String(val);\n};\nconst replacer = (_key, val) => {\n if (val && val.__v_isRef) {\n return replacer(_key, val.value);\n } else if (isMap(val)) {\n return {\n [`Map(${val.size})`]: [...val.entries()].reduce(\n (entries, [key, val2], i) => {\n entries[stringifySymbol(key, i) + \" =>\"] = val2;\n return entries;\n },\n {}\n )\n };\n } else if (isSet(val)) {\n return {\n [`Set(${val.size})`]: [...val.values()].map((v) => stringifySymbol(v))\n };\n } else if (isSymbol(val)) {\n return stringifySymbol(val);\n } else if (isObject(val) && !isArray(val) && !isPlainObject(val)) {\n return String(val);\n }\n return val;\n};\nconst stringifySymbol = (v, i = \"\") => {\n var _a;\n return isSymbol(v) ? `Symbol(${(_a = v.description) != null ? _a : i})` : v;\n};\n\nexport { EMPTY_ARR, EMPTY_OBJ, NO, NOOP, PatchFlagNames, PatchFlags, ShapeFlags, SlotFlags, camelize, capitalize, def, escapeHtml, escapeHtmlComment, extend, genPropsAccessExp, generateCodeFrame, getGlobalThis, hasChanged, hasOwn, hyphenate, includeBooleanAttr, invokeArrayFns, isArray, isBooleanAttr, isBuiltInDirective, isDate, isFunction, isGloballyAllowed, isGloballyWhitelisted, isHTMLTag, isIntegerKey, isKnownHtmlAttr, isKnownSvgAttr, isMap, isMathMLTag, isModelListener, isObject, isOn, isPlainObject, isPromise, isRegExp, isRenderableAttrValue, isReservedProp, isSSRSafeAttrName, isSVGTag, isSet, isSpecialBooleanAttr, isString, isSymbol, isVoidTag, looseEqual, looseIndexOf, looseToNumber, makeMap, normalizeClass, normalizeProps, normalizeStyle, objectToString, parseStringStyle, propsToAttrMap, remove, slotFlagsText, stringifyStyle, toDisplayString, toHandlerKey, toNumber, toRawType, toTypeString };\n","const isObject = (val) => val !== null && typeof val === 'object';\nconst defaultDelimiters = ['{', '}'];\nclass BaseFormatter {\n constructor() {\n this._caches = Object.create(null);\n }\n interpolate(message, values, delimiters = defaultDelimiters) {\n if (!values) {\n return [message];\n }\n let tokens = this._caches[message];\n if (!tokens) {\n tokens = parse(message, delimiters);\n this._caches[message] = tokens;\n }\n return compile(tokens, values);\n }\n}\nconst RE_TOKEN_LIST_VALUE = /^(?:\\d)+/;\nconst RE_TOKEN_NAMED_VALUE = /^(?:\\w)+/;\nfunction parse(format, [startDelimiter, endDelimiter]) {\n const tokens = [];\n let position = 0;\n let text = '';\n while (position < format.length) {\n let char = format[position++];\n if (char === startDelimiter) {\n if (text) {\n tokens.push({ type: 'text', value: text });\n }\n text = '';\n let sub = '';\n char = format[position++];\n while (char !== undefined && char !== endDelimiter) {\n sub += char;\n char = format[position++];\n }\n const isClosed = char === endDelimiter;\n const type = RE_TOKEN_LIST_VALUE.test(sub)\n ? 'list'\n : isClosed && RE_TOKEN_NAMED_VALUE.test(sub)\n ? 'named'\n : 'unknown';\n tokens.push({ value: sub, type });\n }\n // else if (char === '%') {\n // // when found rails i18n syntax, skip text capture\n // if (format[position] !== '{') {\n // text += char\n // }\n // }\n else {\n text += char;\n }\n }\n text && tokens.push({ type: 'text', value: text });\n return tokens;\n}\nfunction compile(tokens, values) {\n const compiled = [];\n let index = 0;\n const mode = Array.isArray(values)\n ? 'list'\n : isObject(values)\n ? 'named'\n : 'unknown';\n if (mode === 'unknown') {\n return compiled;\n }\n while (index < tokens.length) {\n const token = tokens[index];\n switch (token.type) {\n case 'text':\n compiled.push(token.value);\n break;\n case 'list':\n compiled.push(values[parseInt(token.value, 10)]);\n break;\n case 'named':\n if (mode === 'named') {\n compiled.push(values[token.value]);\n }\n else {\n if (process.env.NODE_ENV !== 'production') {\n console.warn(`Type of token '${token.type}' and format of value '${mode}' don't match!`);\n }\n }\n break;\n case 'unknown':\n if (process.env.NODE_ENV !== 'production') {\n console.warn(`Detect 'unknown' type of token!`);\n }\n break;\n }\n index++;\n }\n return compiled;\n}\n\nconst LOCALE_ZH_HANS = 'zh-Hans';\nconst LOCALE_ZH_HANT = 'zh-Hant';\nconst LOCALE_EN = 'en';\nconst LOCALE_FR = 'fr';\nconst LOCALE_ES = 'es';\nconst hasOwnProperty = Object.prototype.hasOwnProperty;\nconst hasOwn = (val, key) => hasOwnProperty.call(val, key);\nconst defaultFormatter = new BaseFormatter();\nfunction include(str, parts) {\n return !!parts.find((part) => str.indexOf(part) !== -1);\n}\nfunction startsWith(str, parts) {\n return parts.find((part) => str.indexOf(part) === 0);\n}\nfunction normalizeLocale(locale, messages) {\n if (!locale) {\n return;\n }\n locale = locale.trim().replace(/_/g, '-');\n if (messages && messages[locale]) {\n return locale;\n }\n locale = locale.toLowerCase();\n if (locale === 'chinese') {\n // 支付宝\n return LOCALE_ZH_HANS;\n }\n if (locale.indexOf('zh') === 0) {\n if (locale.indexOf('-hans') > -1) {\n return LOCALE_ZH_HANS;\n }\n if (locale.indexOf('-hant') > -1) {\n return LOCALE_ZH_HANT;\n }\n if (include(locale, ['-tw', '-hk', '-mo', '-cht'])) {\n return LOCALE_ZH_HANT;\n }\n return LOCALE_ZH_HANS;\n }\n let locales = [LOCALE_EN, LOCALE_FR, LOCALE_ES];\n if (messages && Object.keys(messages).length > 0) {\n locales = Object.keys(messages);\n }\n const lang = startsWith(locale, locales);\n if (lang) {\n return lang;\n }\n}\nclass I18n {\n constructor({ locale, fallbackLocale, messages, watcher, formater, }) {\n this.locale = LOCALE_EN;\n this.fallbackLocale = LOCALE_EN;\n this.message = {};\n this.messages = {};\n this.watchers = [];\n if (fallbackLocale) {\n this.fallbackLocale = fallbackLocale;\n }\n this.formater = formater || defaultFormatter;\n this.messages = messages || {};\n this.setLocale(locale || LOCALE_EN);\n if (watcher) {\n this.watchLocale(watcher);\n }\n }\n setLocale(locale) {\n const oldLocale = this.locale;\n this.locale = normalizeLocale(locale, this.messages) || this.fallbackLocale;\n if (!this.messages[this.locale]) {\n // 可能初始化时不存在\n this.messages[this.locale] = {};\n }\n this.message = this.messages[this.locale];\n // 仅发生变化时,通知\n if (oldLocale !== this.locale) {\n this.watchers.forEach((watcher) => {\n watcher(this.locale, oldLocale);\n });\n }\n }\n getLocale() {\n return this.locale;\n }\n watchLocale(fn) {\n const index = this.watchers.push(fn) - 1;\n return () => {\n this.watchers.splice(index, 1);\n };\n }\n add(locale, message, override = true) {\n const curMessages = this.messages[locale];\n if (curMessages) {\n if (override) {\n Object.assign(curMessages, message);\n }\n else {\n Object.keys(message).forEach((key) => {\n if (!hasOwn(curMessages, key)) {\n curMessages[key] = message[key];\n }\n });\n }\n }\n else {\n this.messages[locale] = message;\n }\n }\n f(message, values, delimiters) {\n return this.formater.interpolate(message, values, delimiters).join('');\n }\n t(key, locale, values) {\n let message = this.message;\n if (typeof locale === 'string') {\n locale = normalizeLocale(locale, this.messages);\n locale && (message = this.messages[locale]);\n }\n else {\n values = locale;\n }\n if (!hasOwn(message, key)) {\n console.warn(`Cannot translate the value of keypath ${key}. Use the value of keypath as default.`);\n return key;\n }\n return this.formater.interpolate(message[key], values).join('');\n }\n}\n\nfunction watchAppLocale(appVm, i18n) {\n // 需要保证 watch 的触发在组件渲染之前\n if (appVm.$watchLocale) {\n // vue2\n appVm.$watchLocale((newLocale) => {\n i18n.setLocale(newLocale);\n });\n }\n else {\n appVm.$watch(() => appVm.$locale, (newLocale) => {\n i18n.setLocale(newLocale);\n });\n }\n}\nfunction getDefaultLocale() {\n if (typeof uni !== 'undefined' && uni.getLocale) {\n return uni.getLocale();\n }\n // 小程序平台,uni 和 uni-i18n 互相引用,导致访问不到 uni,故在 global 上挂了 getLocale\n if (typeof global !== 'undefined' && global.getLocale) {\n return global.getLocale();\n }\n return LOCALE_EN;\n}\nfunction initVueI18n(locale, messages = {}, fallbackLocale, watcher) {\n // 兼容旧版本入参\n if (typeof locale !== 'string') {\n // ;[locale, messages] = [\n // messages as unknown as string,\n // locale as unknown as LocaleMessages,\n // ]\n // 暂不使用数组解构,uts编译器暂未支持。\n const options = [\n messages,\n locale,\n ];\n locale = options[0];\n messages = options[1];\n }\n if (typeof locale !== 'string') {\n // 因为小程序平台,uni-i18n 和 uni 互相引用,导致此时访问 uni 时,为 undefined\n locale = getDefaultLocale();\n }\n if (typeof fallbackLocale !== 'string') {\n fallbackLocale =\n (typeof __uniConfig !== 'undefined' && __uniConfig.fallbackLocale) ||\n LOCALE_EN;\n }\n const i18n = new I18n({\n locale,\n fallbackLocale,\n messages,\n watcher,\n });\n let t = (key, values) => {\n if (typeof getApp !== 'function') {\n // app view\n /* eslint-disable no-func-assign */\n t = function (key, values) {\n return i18n.t(key, values);\n };\n }\n else {\n let isWatchedAppLocale = false;\n t = function (key, values) {\n const appVm = getApp().$vm;\n // 可能$vm还不存在,比如在支付宝小程序中,组件定义较早,在props的default里使用了t()函数(如uni-goods-nav),此时app还未初始化\n // options: {\n // \ttype: Array,\n // \tdefault () {\n // \t\treturn [{\n // \t\t\ticon: 'shop',\n // \t\t\ttext: t(\"uni-goods-nav.options.shop\"),\n // \t\t}, {\n // \t\t\ticon: 'cart',\n // \t\t\ttext: t(\"uni-goods-nav.options.cart\")\n // \t\t}]\n // \t}\n // },\n if (appVm) {\n // 触发响应式\n appVm.$locale;\n if (!isWatchedAppLocale) {\n isWatchedAppLocale = true;\n watchAppLocale(appVm, i18n);\n }\n }\n return i18n.t(key, values);\n };\n }\n return t(key, values);\n };\n return {\n i18n,\n f(message, values, delimiters) {\n return i18n.f(message, values, delimiters);\n },\n t(key, values) {\n return t(key, values);\n },\n add(locale, message, override = true) {\n return i18n.add(locale, message, override);\n },\n watch(fn) {\n return i18n.watchLocale(fn);\n },\n getLocale() {\n return i18n.getLocale();\n },\n setLocale(newLocale) {\n return i18n.setLocale(newLocale);\n },\n };\n}\n\nconst isString = (val) => typeof val === 'string';\nlet formater;\nfunction hasI18nJson(jsonObj, delimiters) {\n if (!formater) {\n formater = new BaseFormatter();\n }\n return walkJsonObj(jsonObj, (jsonObj, key) => {\n const value = jsonObj[key];\n if (isString(value)) {\n if (isI18nStr(value, delimiters)) {\n return true;\n }\n }\n else {\n return hasI18nJson(value, delimiters);\n }\n });\n}\nfunction parseI18nJson(jsonObj, values, delimiters) {\n if (!formater) {\n formater = new BaseFormatter();\n }\n walkJsonObj(jsonObj, (jsonObj, key) => {\n const value = jsonObj[key];\n if (isString(value)) {\n if (isI18nStr(value, delimiters)) {\n jsonObj[key] = compileStr(value, values, delimiters);\n }\n }\n else {\n parseI18nJson(value, values, delimiters);\n }\n });\n return jsonObj;\n}\nfunction compileI18nJsonStr(jsonStr, { locale, locales, delimiters, }) {\n if (!isI18nStr(jsonStr, delimiters)) {\n return jsonStr;\n }\n if (!formater) {\n formater = new BaseFormatter();\n }\n const localeValues = [];\n Object.keys(locales).forEach((name) => {\n if (name !== locale) {\n localeValues.push({\n locale: name,\n values: locales[name],\n });\n }\n });\n localeValues.unshift({ locale, values: locales[locale] });\n try {\n return JSON.stringify(compileJsonObj(JSON.parse(jsonStr), localeValues, delimiters), null, 2);\n }\n catch (e) { }\n return jsonStr;\n}\nfunction isI18nStr(value, delimiters) {\n return value.indexOf(delimiters[0]) > -1;\n}\nfunction compileStr(value, values, delimiters) {\n return formater.interpolate(value, values, delimiters).join('');\n}\nfunction compileValue(jsonObj, key, localeValues, delimiters) {\n const value = jsonObj[key];\n if (isString(value)) {\n // 存在国际化\n if (isI18nStr(value, delimiters)) {\n jsonObj[key] = compileStr(value, localeValues[0].values, delimiters);\n if (localeValues.length > 1) {\n // 格式化国际化语言\n const valueLocales = (jsonObj[key + 'Locales'] = {});\n localeValues.forEach((localValue) => {\n valueLocales[localValue.locale] = compileStr(value, localValue.values, delimiters);\n });\n }\n }\n }\n else {\n compileJsonObj(value, localeValues, delimiters);\n }\n}\nfunction compileJsonObj(jsonObj, localeValues, delimiters) {\n walkJsonObj(jsonObj, (jsonObj, key) => {\n compileValue(jsonObj, key, localeValues, delimiters);\n });\n return jsonObj;\n}\nfunction walkJsonObj(jsonObj, walk) {\n if (Array.isArray(jsonObj)) {\n for (let i = 0; i < jsonObj.length; i++) {\n if (walk(jsonObj, i)) {\n return true;\n }\n }\n }\n else if (isObject(jsonObj)) {\n for (const key in jsonObj) {\n if (walk(jsonObj, key)) {\n return true;\n }\n }\n }\n return false;\n}\n\nfunction resolveLocale(locales) {\n return (locale) => {\n if (!locale) {\n return locale;\n }\n locale = normalizeLocale(locale) || locale;\n return resolveLocaleChain(locale).find((locale) => locales.indexOf(locale) > -1);\n };\n}\nfunction resolveLocaleChain(locale) {\n const chain = [];\n const tokens = locale.split('-');\n while (tokens.length) {\n chain.push(tokens.join('-'));\n tokens.pop();\n }\n return chain;\n}\n\nexport { BaseFormatter as Formatter, I18n, LOCALE_EN, LOCALE_ES, LOCALE_FR, LOCALE_ZH_HANS, LOCALE_ZH_HANT, compileI18nJsonStr, hasI18nJson, initVueI18n, isI18nStr, isString, normalizeLocale, parseI18nJson, resolveLocale };\n","import { isHTMLTag, isSVGTag, isVoidTag, isString, isFunction, isPlainObject, hyphenate, camelize, normalizeStyle as normalizeStyle$1, parseStringStyle, isArray, normalizeClass as normalizeClass$1, extend, capitalize, makeMap } from '@vue/shared';\n\nconst BUILT_IN_TAG_NAMES = [\n 'ad',\n 'ad-content-page',\n 'ad-draw',\n 'audio',\n 'button',\n 'camera',\n 'canvas',\n 'checkbox',\n 'checkbox-group',\n 'cover-image',\n 'cover-view',\n 'editor',\n 'form',\n 'functional-page-navigator',\n 'icon',\n 'image',\n 'input',\n 'label',\n 'live-player',\n 'live-pusher',\n 'map',\n 'movable-area',\n 'movable-view',\n 'navigator',\n 'official-account',\n 'open-data',\n 'picker',\n 'picker-view',\n 'picker-view-column',\n 'progress',\n 'radio',\n 'radio-group',\n 'rich-text',\n 'scroll-view',\n 'slider',\n 'swiper',\n 'swiper-item',\n 'switch',\n 'text',\n 'textarea',\n 'video',\n 'view',\n 'web-view',\n 'location-picker',\n 'location-view',\n];\nconst BUILT_IN_TAGS = BUILT_IN_TAG_NAMES.map((tag) => 'uni-' + tag);\nconst TAGS = [\n 'app',\n 'layout',\n 'content',\n 'main',\n 'top-window',\n 'left-window',\n 'right-window',\n 'tabbar',\n 'page',\n 'page-head',\n 'page-wrapper',\n 'page-body',\n 'page-refresh',\n 'actionsheet',\n 'modal',\n 'toast',\n 'resize-sensor',\n 'shadow-root',\n].map((tag) => 'uni-' + tag);\nconst NVUE_BUILT_IN_TAGS = [\n 'svg',\n 'view',\n 'a',\n 'div',\n 'img',\n 'image',\n 'text',\n 'span',\n 'input',\n 'textarea',\n 'spinner',\n 'select',\n // slider 被自定义 u-slider 替代\n // 'slider',\n 'slider-neighbor',\n 'indicator',\n 'canvas',\n 'list',\n 'cell',\n 'header',\n 'loading',\n 'loading-indicator',\n 'refresh',\n 'scrollable',\n 'scroller',\n 'video',\n 'web',\n 'embed',\n 'tabbar',\n 'tabheader',\n 'datepicker',\n 'timepicker',\n 'marquee',\n 'countdown',\n 'dc-switch',\n 'waterfall',\n 'richtext',\n 'recycle-list',\n 'u-scalable',\n 'barcode',\n 'gcanvas',\n];\nconst UVUE_BUILT_IN_TAGS = [\n 'ad',\n 'ad-content-page',\n 'ad-draw',\n 'native-view',\n 'loading-indicator',\n 'list-view',\n 'list-item',\n 'swiper',\n 'swiper-item',\n 'rich-text',\n 'sticky-view',\n 'sticky-header',\n 'sticky-section',\n // 自定义\n 'uni-slider',\n // 原生实现\n 'button',\n 'nested-scroll-header',\n 'nested-scroll-body',\n 'waterflow',\n 'flow-item',\n 'share-element',\n 'cover-view',\n 'cover-image',\n // custom element\n 'match-media',\n // 'checkbox',\n // 'checkbox-group',\n // 'form',\n // 'navigator',\n // 'picker-view',\n // 'picker-view-column',\n // 'progress',\n // 'slider',\n // 'switch',\n // 'radio',\n // 'radio-group',\n];\nconst UVUE_WEB_BUILT_IN_TAGS = [\n 'list-view',\n 'list-item',\n 'sticky-section',\n 'sticky-header',\n 'cloud-db-element',\n].map((tag) => 'uni-' + tag);\nconst UVUE_IOS_BUILT_IN_TAGS = [\n 'scroll-view',\n 'web-view',\n 'slider',\n 'form',\n 'switch',\n];\nconst UVUE_HARMONY_BUILT_IN_TAGS = [\n // TODO 列出完整列表\n ...BUILT_IN_TAG_NAMES,\n 'volume-panel',\n];\nconst NVUE_U_BUILT_IN_TAGS = [\n 'u-text',\n 'u-image',\n 'u-input',\n 'u-textarea',\n 'u-video',\n 'u-web-view',\n 'u-slider',\n 'u-ad',\n 'u-ad-draw',\n 'u-rich-text',\n];\nconst UVUE_WEB_BUILT_IN_CUSTOM_ELEMENTS = ['match-media'];\nconst UNI_UI_CONFLICT_TAGS = ['list-item'].map((tag) => 'uni-' + tag);\nfunction isBuiltInComponent(tag) {\n if (UNI_UI_CONFLICT_TAGS.indexOf(tag) !== -1) {\n return false;\n }\n // h5 平台会被转换为 v-uni-\n const realTag = 'uni-' + tag.replace('v-uni-', '');\n // TODO 区分x和非x\n return (BUILT_IN_TAGS.indexOf(realTag) !== -1 ||\n UVUE_WEB_BUILT_IN_TAGS.indexOf(realTag) !== -1);\n}\nfunction isH5CustomElement(tag, isX = false) {\n if (isX && UVUE_WEB_BUILT_IN_TAGS.indexOf(tag) !== -1) {\n return true;\n }\n return TAGS.indexOf(tag) !== -1 || BUILT_IN_TAGS.indexOf(tag) !== -1;\n}\nfunction isUniXElement(name) {\n return /^I?Uni.*Element(?:Impl)?$/.test(name);\n}\nfunction isH5NativeTag(tag) {\n return (tag !== 'head' &&\n (isHTMLTag(tag) || isSVGTag(tag)) &&\n !isBuiltInComponent(tag));\n}\nfunction isAppNativeTag(tag) {\n return isHTMLTag(tag) || isSVGTag(tag) || isBuiltInComponent(tag);\n}\nconst NVUE_CUSTOM_COMPONENTS = [\n 'ad',\n 'ad-draw',\n 'button',\n 'checkbox-group',\n 'checkbox',\n 'form',\n 'icon',\n 'label',\n 'movable-area',\n 'movable-view',\n 'navigator',\n 'picker',\n 'progress',\n 'radio-group',\n 'radio',\n 'rich-text',\n 'swiper-item',\n 'swiper',\n 'switch',\n 'slider',\n 'picker-view',\n 'picker-view-column',\n];\nconst UNI_AD_PLUGINS = ['uniad-plugin', 'uniad-plugin-wx'];\n// 内置的easycom组件\nconst UVUE_BUILT_IN_EASY_COMPONENTS = [\n 'map',\n 'camera',\n 'live-player',\n 'live-pusher',\n];\nfunction isAppUVueBuiltInEasyComponent(tag) {\n return UVUE_BUILT_IN_EASY_COMPONENTS.includes(tag);\n}\n// 主要是指前端实现的组件列表\nconst UVUE_CUSTOM_COMPONENTS = [\n ...NVUE_CUSTOM_COMPONENTS,\n ...UVUE_BUILT_IN_EASY_COMPONENTS,\n];\nfunction isAppUVueNativeTag(tag) {\n // 前端实现的内置组件都会注册一个根组件\n if (tag.startsWith('uni-') && tag.endsWith('-element')) {\n return true;\n }\n if (UVUE_BUILT_IN_TAGS.includes(tag)) {\n return true;\n }\n if (UVUE_CUSTOM_COMPONENTS.includes(tag)) {\n return false;\n }\n if (isBuiltInComponent(tag)) {\n return true;\n }\n // u-text,u-video...\n if (NVUE_U_BUILT_IN_TAGS.includes(tag)) {\n return true;\n }\n return false;\n}\nfunction isAppIOSUVueNativeTag(tag) {\n // 前端实现的内置组件都会注册一个根组件\n if (tag.startsWith('uni-') && tag.endsWith('-element')) {\n return true;\n }\n if (NVUE_BUILT_IN_TAGS.includes(tag)) {\n return true;\n }\n // TODO\n if ([\n 'checkbox',\n 'checkbox-group',\n 'form',\n 'picker-view',\n 'picker-view-column',\n 'progress',\n 'switch',\n 'radio',\n 'radio-group',\n ].includes(tag)) {\n return true;\n }\n if (\n // && tag != 'navigator' && tag != 'slider'\n UVUE_BUILT_IN_TAGS.includes(tag)) {\n return true;\n }\n if (UVUE_IOS_BUILT_IN_TAGS.includes(tag)) {\n return true;\n }\n return false;\n}\nfunction isAppHarmonyUVueNativeTag(tag) {\n // video 目前是easycom实现的\n if (tag === 'video' || tag === 'map') {\n return false;\n }\n // 前端实现的内置组件都会注册一个根组件\n if (tag.startsWith('uni-') && tag.endsWith('-element')) {\n return true;\n }\n if (NVUE_BUILT_IN_TAGS.includes(tag)) {\n return true;\n }\n if (UVUE_BUILT_IN_TAGS.includes(tag)) {\n return true;\n }\n if (UVUE_HARMONY_BUILT_IN_TAGS.includes(tag)) {\n return true;\n }\n return false;\n}\nfunction isAppNVueNativeTag(tag) {\n if (NVUE_BUILT_IN_TAGS.includes(tag)) {\n return true;\n }\n if (NVUE_CUSTOM_COMPONENTS.includes(tag)) {\n return false;\n }\n if (isBuiltInComponent(tag)) {\n return true;\n }\n // u-text,u-video...\n if (NVUE_U_BUILT_IN_TAGS.includes(tag)) {\n return true;\n }\n return false;\n}\nfunction isMiniProgramNativeTag(tag) {\n return isBuiltInComponent(tag);\n}\nfunction isMiniProgramUVueNativeTag(tag) {\n // 小程序平台内置的自定义元素,会被转换为 view\n if (tag.startsWith('uni-') && tag.endsWith('-element')) {\n return true;\n }\n return isBuiltInComponent(tag);\n}\nfunction createIsCustomElement(tags = []) {\n return function isCustomElement(tag) {\n return tags.includes(tag);\n };\n}\nfunction isComponentTag(tag) {\n return tag[0].toLowerCase() + tag.slice(1) === 'component';\n}\nconst COMPONENT_SELECTOR_PREFIX = 'uni-';\nconst COMPONENT_PREFIX = 'v-' + COMPONENT_SELECTOR_PREFIX;\n// TODO 是否还存在其他需要特殊处理的 void 标签?\nconst APP_VOID_TAGS = ['textarea'];\nfunction isAppVoidTag(tag) {\n return APP_VOID_TAGS.includes(tag) || isVoidTag(tag);\n}\n\nconst LINEFEED = '\\n';\nconst NAVBAR_HEIGHT = 44;\nconst TABBAR_HEIGHT = 50;\nconst ON_REACH_BOTTOM_DISTANCE = 50;\nconst RESPONSIVE_MIN_WIDTH = 768;\nconst UNI_STORAGE_LOCALE = 'UNI_LOCALE';\n// quickapp-webview 不能使用 default 作为插槽名称\nconst SLOT_DEFAULT_NAME = 'd';\nconst COMPONENT_NAME_PREFIX = 'VUni';\nconst I18N_JSON_DELIMITERS = ['%', '%'];\nconst PRIMARY_COLOR = '#007aff';\nconst SELECTED_COLOR = '#0062cc'; // 选中的颜色,如选项卡默认的选中颜色\nconst BACKGROUND_COLOR = '#f7f7f7'; // 背景色,如标题栏默认背景色\nconst UNI_SSR = '__uniSSR';\nconst UNI_SSR_TITLE = 'title';\nconst UNI_SSR_STORE = 'store';\nconst UNI_SSR_DATA = 'data';\nconst UNI_SSR_GLOBAL_DATA = 'globalData';\nconst SCHEME_RE = /^([a-z-]+:)?\\/\\//i;\nconst DATA_RE = /^data:.*,.*/;\nconst WEB_INVOKE_APPSERVICE = 'WEB_INVOKE_APPSERVICE';\nconst WXS_PROTOCOL = 'wxs://';\nconst JSON_PROTOCOL = 'json://';\nconst WXS_MODULES = 'wxsModules';\nconst RENDERJS_MODULES = 'renderjsModules';\n// lifecycle\n// App and Page\nconst ON_SHOW = 'onShow';\nconst ON_HIDE = 'onHide';\n//App\nconst ON_LAUNCH = 'onLaunch';\nconst ON_ERROR = 'onError';\nconst ON_THEME_CHANGE = 'onThemeChange';\nconst OFF_THEME_CHANGE = 'offThemeChange';\nconst ON_HOST_THEME_CHANGE = 'onHostThemeChange';\nconst OFF_HOST_THEME_CHANGE = 'offHostThemeChange';\nconst ON_KEYBOARD_HEIGHT_CHANGE = 'onKeyboardHeightChange';\nconst ON_PAGE_NOT_FOUND = 'onPageNotFound';\nconst ON_UNHANDLE_REJECTION = 'onUnhandledRejection';\nconst ON_LAST_PAGE_BACK_PRESS = 'onLastPageBackPress';\nconst ON_EXIT = 'onExit';\n//Page\nconst ON_LOAD = 'onLoad';\nconst ON_READY = 'onReady';\nconst ON_UNLOAD = 'onUnload';\n// 百度特有\nconst ON_INIT = 'onInit';\n// 微信特有\nconst ON_SAVE_EXIT_STATE = 'onSaveExitState';\nconst ON_RESIZE = 'onResize';\nconst ON_BACK_PRESS = 'onBackPress';\nconst ON_PAGE_SCROLL = 'onPageScroll';\nconst ON_TAB_ITEM_TAP = 'onTabItemTap';\nconst ON_REACH_BOTTOM = 'onReachBottom';\nconst ON_PULL_DOWN_REFRESH = 'onPullDownRefresh';\nconst ON_SHARE_TIMELINE = 'onShareTimeline';\nconst ON_SHARE_CHAT = 'onShareChat'; // xhs-share\nconst ON_ADD_TO_FAVORITES = 'onAddToFavorites';\nconst ON_SHARE_APP_MESSAGE = 'onShareAppMessage';\n// navigationBar\nconst ON_NAVIGATION_BAR_BUTTON_TAP = 'onNavigationBarButtonTap';\nconst ON_NAVIGATION_BAR_CHANGE = 'onNavigationBarChange';\nconst ON_NAVIGATION_BAR_SEARCH_INPUT_CLICKED = 'onNavigationBarSearchInputClicked';\nconst ON_NAVIGATION_BAR_SEARCH_INPUT_CHANGED = 'onNavigationBarSearchInputChanged';\nconst ON_NAVIGATION_BAR_SEARCH_INPUT_CONFIRMED = 'onNavigationBarSearchInputConfirmed';\nconst ON_NAVIGATION_BAR_SEARCH_INPUT_FOCUS_CHANGED = 'onNavigationBarSearchInputFocusChanged';\n// framework\nconst ON_APP_ENTER_FOREGROUND = 'onAppEnterForeground';\nconst ON_APP_ENTER_BACKGROUND = 'onAppEnterBackground';\nconst ON_WEB_INVOKE_APP_SERVICE = 'onWebInvokeAppService';\nconst ON_WXS_INVOKE_CALL_METHOD = 'onWxsInvokeCallMethod';\n// mergeVirtualHostAttributes\nconst VIRTUAL_HOST_STYLE = 'virtualHostStyle';\nconst VIRTUAL_HOST_CLASS = 'virtualHostClass';\nconst VIRTUAL_HOST_HIDDEN = 'virtualHostHidden';\nconst VIRTUAL_HOST_ID = 'virtualHostId';\n\nfunction cache(fn) {\n const cache = Object.create(null);\n return (str) => {\n const hit = cache[str];\n return hit || (cache[str] = fn(str));\n };\n}\nfunction cacheStringFunction(fn) {\n return cache(fn);\n}\nfunction getLen(str = '') {\n return ('' + str).replace(/[^\\x00-\\xff]/g, '**').length;\n}\nfunction hasLeadingSlash(str) {\n return str.indexOf('/') === 0;\n}\nfunction addLeadingSlash(str) {\n return hasLeadingSlash(str) ? str : '/' + str;\n}\nfunction removeLeadingSlash(str) {\n return hasLeadingSlash(str) ? str.slice(1) : str;\n}\nconst invokeArrayFns = (fns, arg) => {\n let ret;\n for (let i = 0; i < fns.length; i++) {\n ret = fns[i](arg);\n }\n return ret;\n};\nfunction updateElementStyle(element, styles) {\n for (const attrName in styles) {\n element.style[attrName] = styles[attrName];\n }\n}\nfunction once(fn, ctx = null) {\n let res;\n return ((...args) => {\n if (fn) {\n res = fn.apply(ctx, args);\n fn = null;\n }\n return res;\n });\n}\nconst sanitise = (val) => (val && JSON.parse(JSON.stringify(val))) || val;\nconst _completeValue = (value) => (value > 9 ? value : '0' + value);\nfunction formatDateTime({ date = new Date(), mode = 'date' }) {\n if (mode === 'time') {\n return (_completeValue(date.getHours()) + ':' + _completeValue(date.getMinutes()));\n }\n else {\n return (date.getFullYear() +\n '-' +\n _completeValue(date.getMonth() + 1) +\n '-' +\n _completeValue(date.getDate()));\n }\n}\nfunction callOptions(options, data) {\n options = options || {};\n if (isString(data)) {\n data = {\n errMsg: data,\n };\n }\n if (/:ok$/.test(data.errMsg)) {\n if (isFunction(options.success)) {\n options.success(data);\n }\n }\n else {\n if (isFunction(options.fail)) {\n options.fail(data);\n }\n }\n if (isFunction(options.complete)) {\n options.complete(data);\n }\n}\nfunction getValueByDataPath(obj, path) {\n if (!isString(path)) {\n return;\n }\n path = path.replace(/\\[(\\d+)\\]/g, '.$1');\n const parts = path.split('.');\n let key = parts[0];\n if (!obj) {\n obj = {};\n }\n if (parts.length === 1) {\n return obj[key];\n }\n return getValueByDataPath(obj[key], parts.slice(1).join('.'));\n}\nfunction sortObject(obj) {\n let sortObj = {};\n if (isPlainObject(obj)) {\n Object.keys(obj)\n .sort()\n .forEach((key) => {\n const _key = key;\n sortObj[_key] = obj[_key];\n });\n }\n return !Object.keys(sortObj) ? obj : sortObj;\n}\nfunction getGlobalOnce() {\n if (typeof globalThis !== 'undefined') {\n return globalThis;\n }\n // worker\n if (typeof self !== 'undefined') {\n return self;\n }\n // browser\n if (typeof window !== 'undefined') {\n return window;\n }\n // nodejs\n // if (typeof global !== 'undefined') {\n // return global\n // }\n function g() {\n return this;\n }\n if (typeof g() !== 'undefined') {\n return g();\n }\n return (function () {\n return new Function('return this')();\n })();\n}\nlet g = undefined;\nfunction getGlobal() {\n if (g) {\n return g;\n }\n g = getGlobalOnce();\n return g;\n}\n\nfunction isComponentInternalInstance(vm) {\n return !!vm.appContext;\n}\nfunction resolveComponentInstance(instance) {\n return (instance &&\n (isComponentInternalInstance(instance) ? instance.proxy : instance));\n}\nfunction resolveOwnerVm(vm) {\n if (!vm) {\n return;\n }\n let componentName = vm.type.name;\n while (componentName && isBuiltInComponent(hyphenate(componentName))) {\n // ownerInstance 内置组件需要使用父 vm\n vm = vm.parent;\n componentName = vm.type.name;\n }\n return vm.proxy;\n}\nfunction isElement(el) {\n // Element\n return el.nodeType === 1;\n}\nfunction resolveOwnerEl(instance, multi = false) {\n const { vnode } = instance;\n if (isElement(vnode.el)) {\n return multi ? (vnode.el ? [vnode.el] : []) : vnode.el;\n }\n const { subTree } = instance;\n // ShapeFlags.ARRAY_CHILDREN = 1<<4\n if (subTree.shapeFlag & 16) {\n const elemVNodes = subTree.children.filter((vnode) => vnode.el && isElement(vnode.el));\n if (elemVNodes.length > 0) {\n if (multi) {\n return elemVNodes.map((node) => node.el);\n }\n return elemVNodes[0].el;\n }\n }\n return multi ? (vnode.el ? [vnode.el] : []) : vnode.el;\n}\nfunction dynamicSlotName(name) {\n return name === 'default' ? SLOT_DEFAULT_NAME : name;\n}\nconst customizeRE = /:/g;\nfunction customizeEvent(str) {\n return camelize(str.replace(customizeRE, '-'));\n}\nfunction normalizeStyle(value) {\n const g = getGlobal();\n if (g && g.UTSJSONObject && value instanceof g.UTSJSONObject) {\n const styleObject = {};\n g.UTSJSONObject.keys(value).forEach((key) => {\n styleObject[key] = value[key];\n });\n return normalizeStyle$1(styleObject);\n }\n else if (value instanceof Map) {\n const styleObject = {};\n value.forEach((value, key) => {\n styleObject[key] = value;\n });\n return normalizeStyle$1(styleObject);\n }\n else if (isString(value)) {\n return parseStringStyle(value);\n }\n else if (isArray(value)) {\n const res = {};\n for (let i = 0; i < value.length; i++) {\n const item = value[i];\n const normalized = isString(item)\n ? parseStringStyle(item)\n : normalizeStyle(item);\n if (normalized) {\n for (const key in normalized) {\n res[key] = normalized[key];\n }\n }\n }\n return res;\n }\n else {\n return normalizeStyle$1(value);\n }\n}\nfunction normalizeClass(value) {\n let res = '';\n const g = getGlobal();\n if (g && g.UTSJSONObject && value instanceof g.UTSJSONObject) {\n g.UTSJSONObject.keys(value).forEach((key) => {\n if (value[key]) {\n res += key + ' ';\n }\n });\n }\n else if (value instanceof Map) {\n value.forEach((value, key) => {\n if (value) {\n res += key + ' ';\n }\n });\n }\n else if (isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n const normalized = normalizeClass(value[i]);\n if (normalized) {\n res += normalized + ' ';\n }\n }\n }\n else {\n res = normalizeClass$1(value);\n }\n return res.trim();\n}\nfunction normalizeProps(props) {\n if (!props)\n return null;\n let { class: klass, style } = props;\n if (klass && !isString(klass)) {\n props.class = normalizeClass(klass);\n }\n if (style) {\n props.style = normalizeStyle(style);\n }\n return props;\n}\n\nlet lastLogTime = 0;\nfunction formatLog(module, ...args) {\n const now = Date.now();\n const diff = lastLogTime ? now - lastLogTime : 0;\n lastLogTime = now;\n return `[${now}][${diff}ms][${module}]:${args\n .map((arg) => JSON.stringify(arg))\n .join(' ')}`;\n}\n\nfunction formatKey(key) {\n return camelize(key.substring(5));\n}\n// question/139181,增加副作用,避免 initCustomDataset 在 build 下被 tree-shaking\nconst initCustomDatasetOnce = /*#__PURE__*/ once((isBuiltInElement) => {\n isBuiltInElement =\n isBuiltInElement || ((el) => el.tagName.startsWith('UNI-'));\n const prototype = HTMLElement.prototype;\n const setAttribute = prototype.setAttribute;\n prototype.setAttribute = function (key, value) {\n if (key.startsWith('data-') && isBuiltInElement(this)) {\n const dataset = this.__uniDataset ||\n (this.__uniDataset = {});\n dataset[formatKey(key)] = value;\n }\n setAttribute.call(this, key, value);\n };\n const removeAttribute = prototype.removeAttribute;\n prototype.removeAttribute = function (key) {\n if (this.__uniDataset &&\n key.startsWith('data-') &&\n isBuiltInElement(this)) {\n delete this.__uniDataset[formatKey(key)];\n }\n removeAttribute.call(this, key);\n };\n});\nfunction getCustomDataset(el) {\n return extend({}, el.dataset, el.__uniDataset);\n}\n\nconst unitRE = new RegExp(`\"[^\"]+\"|'[^']+'|url\\\\([^)]+\\\\)|(\\\\d*\\\\.?\\\\d+)[r|u]px`, 'g');\nfunction toFixed(number, precision) {\n const multiplier = Math.pow(10, precision + 1);\n const wholeNumber = Math.floor(number * multiplier);\n return (Math.round(wholeNumber / 10) * 10) / multiplier;\n}\nconst defaultRpx2Unit = {\n unit: 'rem',\n unitRatio: 10 / 320,\n unitPrecision: 5,\n};\nconst defaultMiniProgramRpx2Unit = {\n unit: 'rpx',\n unitRatio: 1,\n unitPrecision: 1,\n};\nconst defaultNVueRpx2Unit = defaultMiniProgramRpx2Unit;\nfunction createRpx2Unit(unit, unitRatio, unitPrecision) {\n // ignore: rpxCalcIncludeWidth\n return (val) => val.replace(unitRE, (m, $1) => {\n if (!$1) {\n return m;\n }\n if (unitRatio === 1) {\n return `${$1}${unit}`;\n }\n const value = toFixed(parseFloat($1) * unitRatio, unitPrecision);\n return value === 0 ? '0' : `${value}${unit}`;\n });\n}\n\nfunction passive(passive) {\n return { passive };\n}\nfunction normalizeDataset(el) {\n // TODO\n return JSON.parse(JSON.stringify(el.dataset || {}));\n}\nfunction normalizeTarget(el) {\n const { id, offsetTop, offsetLeft } = el;\n return {\n id,\n dataset: getCustomDataset(el),\n offsetTop,\n offsetLeft,\n };\n}\nfunction addFont(family, source, desc) {\n const fonts = document.fonts;\n if (fonts) {\n const fontFace = new FontFace(family, source, desc);\n return fontFace.load().then(() => {\n fonts.add && fonts.add(fontFace);\n });\n }\n return new Promise((resolve) => {\n const style = document.createElement('style');\n const values = [];\n if (desc) {\n const { style, weight, stretch, unicodeRange, variant, featureSettings } = desc;\n style && values.push(`font-style:${style}`);\n weight && values.push(`font-weight:${weight}`);\n stretch && values.push(`font-stretch:${stretch}`);\n unicodeRange && values.push(`unicode-range:${unicodeRange}`);\n variant && values.push(`font-variant:${variant}`);\n featureSettings && values.push(`font-feature-settings:${featureSettings}`);\n }\n style.innerText = `@font-face{font-family:\"${family}\";src:${source};${values.join(';')}}`;\n document.head.appendChild(style);\n resolve();\n });\n}\nfunction scrollTo(scrollTop, duration, isH5) {\n if (isString(scrollTop)) {\n const el = document.querySelector(scrollTop);\n if (el) {\n const { top } = el.getBoundingClientRect();\n scrollTop = top + window.pageYOffset;\n // 如果存在,减去 高度\n const pageHeader = document.querySelector('uni-page-head');\n if (pageHeader) {\n scrollTop -= pageHeader.offsetHeight;\n }\n }\n }\n if (scrollTop < 0) {\n scrollTop = 0;\n }\n const documentElement = document.documentElement;\n const { clientHeight, scrollHeight } = documentElement;\n scrollTop = Math.min(scrollTop, scrollHeight - clientHeight);\n if (duration === 0) {\n // 部分浏览器(比如微信)中 scrollTop 的值需要通过 document.body 来控制\n documentElement.scrollTop = document.body.scrollTop = scrollTop;\n return;\n }\n if (window.scrollY === scrollTop) {\n return;\n }\n const scrollTo = (duration) => {\n if (duration <= 0) {\n window.scrollTo(0, scrollTop);\n return;\n }\n const distaince = scrollTop - window.scrollY;\n requestAnimationFrame(function () {\n window.scrollTo(0, window.scrollY + (distaince / duration) * 10);\n scrollTo(duration - 10);\n });\n };\n scrollTo(duration);\n}\n\nconst encode = encodeURIComponent;\nfunction stringifyQuery(obj, encodeStr = encode) {\n const res = obj\n ? Object.keys(obj)\n .map((key) => {\n let val = obj[key];\n if (typeof val === undefined || val === null) {\n val = '';\n }\n else if (isPlainObject(val)) {\n val = JSON.stringify(val);\n }\n return encodeStr(key) + '=' + encodeStr(val);\n })\n .filter((x) => x.length > 0)\n .join('&')\n : null;\n return res ? `?${res}` : '';\n}\n/**\n * Decode text using `decodeURIComponent`. Returns the original text if it\n * fails.\n *\n * @param text - string to decode\n * @returns decoded string\n */\nfunction decode(text) {\n try {\n return decodeURIComponent('' + text);\n }\n catch (err) { }\n return '' + text;\n}\nfunction decodedQuery(query = {}) {\n const decodedQuery = {};\n Object.keys(query).forEach((name) => {\n try {\n decodedQuery[name] = decode(query[name]);\n }\n catch (e) {\n decodedQuery[name] = query[name];\n }\n });\n return decodedQuery;\n}\nconst PLUS_RE = /\\+/g; // %2B\n/**\n * https://github.com/vuejs/vue-router-next/blob/master/src/query.ts\n * @internal\n *\n * @param search - search string to parse\n * @returns a query object\n */\nfunction parseQuery(search) {\n const query = {};\n // avoid creating an object with an empty key and empty value\n // because of split('&')\n if (search === '' || search === '?')\n return query;\n const hasLeadingIM = search[0] === '?';\n const searchParams = (hasLeadingIM ? search.slice(1) : search).split('&');\n for (let i = 0; i < searchParams.length; ++i) {\n // pre decode the + into space\n const searchParam = searchParams[i].replace(PLUS_RE, ' ');\n // allow the = character\n let eqPos = searchParam.indexOf('=');\n let key = decode(eqPos < 0 ? searchParam : searchParam.slice(0, eqPos));\n let value = eqPos < 0 ? null : decode(searchParam.slice(eqPos + 1));\n if (key in query) {\n // an extra variable for ts types\n let currentValue = query[key];\n if (!isArray(currentValue)) {\n currentValue = query[key] = [currentValue];\n }\n currentValue.push(value);\n }\n else {\n query[key] = value;\n }\n }\n return query;\n}\n\nfunction parseUrl(url) {\n const [path, querystring] = url.split('?', 2);\n return {\n path,\n query: parseQuery(querystring || ''),\n };\n}\n\nfunction parseNVueDataset(attr) {\n const dataset = {};\n if (attr) {\n Object.keys(attr).forEach((key) => {\n if (key.indexOf('data-') === 0) {\n dataset[key.replace('data-', '')] = attr[key];\n }\n });\n }\n return dataset;\n}\n\nfunction plusReady(callback) {\n if (!isFunction(callback)) {\n return;\n }\n if (window.plus) {\n return callback();\n }\n document.addEventListener('plusready', callback);\n}\n\nclass DOMException extends Error {\n constructor(message) {\n super(message);\n this.name = 'DOMException';\n }\n}\n\nfunction normalizeEventType(type, options) {\n if (options) {\n if (options.capture) {\n type += 'Capture';\n }\n if (options.once) {\n type += 'Once';\n }\n if (options.passive) {\n type += 'Passive';\n }\n }\n return `on${capitalize(camelize(type))}`;\n}\nclass UniEvent {\n constructor(type, opts) {\n this.defaultPrevented = false;\n this.timeStamp = Date.now();\n this._stop = false;\n this._end = false;\n this.type = type;\n this.bubbles = !!opts.bubbles;\n this.cancelable = !!opts.cancelable;\n }\n preventDefault() {\n this.defaultPrevented = true;\n }\n stopImmediatePropagation() {\n this._end = this._stop = true;\n }\n stopPropagation() {\n this._stop = true;\n }\n}\nfunction createUniEvent(evt) {\n if (evt instanceof UniEvent) {\n return evt;\n }\n const [type] = parseEventName(evt.type);\n const uniEvent = new UniEvent(type, {\n bubbles: false,\n cancelable: false,\n });\n extend(uniEvent, evt);\n return uniEvent;\n}\nclass UniEventTarget {\n constructor() {\n this.listeners = Object.create(null);\n }\n dispatchEvent(evt) {\n const listeners = this.listeners[evt.type];\n if (!listeners) {\n if ((process.env.NODE_ENV !== 'production')) {\n console.error(formatLog('dispatchEvent', this.nodeId), evt.type, 'not found');\n }\n return false;\n }\n // 格式化事件类型\n const event = createUniEvent(evt);\n const len = listeners.length;\n for (let i = 0; i < len; i++) {\n listeners[i].call(this, event);\n if (event._end) {\n break;\n }\n }\n return event.cancelable && event.defaultPrevented;\n }\n addEventListener(type, listener, options) {\n type = normalizeEventType(type, options);\n (this.listeners[type] || (this.listeners[type] = [])).push(listener);\n }\n removeEventListener(type, callback, options) {\n type = normalizeEventType(type, options);\n const listeners = this.listeners[type];\n if (!listeners) {\n return;\n }\n const index = listeners.indexOf(callback);\n if (index > -1) {\n listeners.splice(index, 1);\n }\n }\n}\nconst optionsModifierRE = /(?:Once|Passive|Capture)$/;\nfunction parseEventName(name) {\n let options;\n if (optionsModifierRE.test(name)) {\n options = {};\n let m;\n while ((m = name.match(optionsModifierRE))) {\n name = name.slice(0, name.length - m[0].length);\n options[m[0].toLowerCase()] = true;\n }\n }\n return [hyphenate(name.slice(2)), options];\n}\n\nconst EventModifierFlags = /*#__PURE__*/ (() => {\n return {\n stop: 1,\n prevent: 1 << 1,\n self: 1 << 2,\n };\n})();\nfunction encodeModifier(modifiers) {\n let flag = 0;\n if (modifiers.includes('stop')) {\n flag |= EventModifierFlags.stop;\n }\n if (modifiers.includes('prevent')) {\n flag |= EventModifierFlags.prevent;\n }\n if (modifiers.includes('self')) {\n flag |= EventModifierFlags.self;\n }\n return flag;\n}\n\nconst NODE_TYPE_PAGE = 0;\nconst NODE_TYPE_ELEMENT = 1;\nconst NODE_TYPE_TEXT = 3;\nconst NODE_TYPE_COMMENT = 8;\nfunction sibling(node, type) {\n const { parentNode } = node;\n if (!parentNode) {\n return null;\n }\n const { childNodes } = parentNode;\n return childNodes[childNodes.indexOf(node) + (type === 'n' ? 1 : -1)] || null;\n}\nfunction removeNode(node) {\n const { parentNode } = node;\n if (parentNode) {\n const { childNodes } = parentNode;\n const index = childNodes.indexOf(node);\n if (index > -1) {\n node.parentNode = null;\n childNodes.splice(index, 1);\n }\n }\n}\nfunction checkNodeId(node) {\n if (!node.nodeId && node.pageNode) {\n node.nodeId = node.pageNode.genId();\n }\n}\n// 为优化性能,各平台不使用proxy来实现node的操作拦截,而是直接通过pageNode定制\nclass UniNode extends UniEventTarget {\n constructor(nodeType, nodeName, container) {\n super();\n this.pageNode = null;\n this.parentNode = null;\n this._text = null;\n if (container) {\n const { pageNode } = container;\n if (pageNode) {\n this.pageNode = pageNode;\n this.nodeId = pageNode.genId();\n !pageNode.isUnmounted && pageNode.onCreate(this, nodeName);\n }\n }\n this.nodeType = nodeType;\n this.nodeName = nodeName;\n this.childNodes = [];\n }\n get firstChild() {\n return this.childNodes[0] || null;\n }\n get lastChild() {\n const { childNodes } = this;\n const length = childNodes.length;\n return length ? childNodes[length - 1] : null;\n }\n get nextSibling() {\n return sibling(this, 'n');\n }\n get nodeValue() {\n return null;\n }\n set nodeValue(_val) { }\n get textContent() {\n return this._text || '';\n }\n set textContent(text) {\n this._text = text;\n if (this.pageNode && !this.pageNode.isUnmounted) {\n this.pageNode.onTextContent(this, text);\n }\n }\n get parentElement() {\n const { parentNode } = this;\n if (parentNode && parentNode.nodeType === NODE_TYPE_ELEMENT) {\n return parentNode;\n }\n return null;\n }\n get previousSibling() {\n return sibling(this, 'p');\n }\n appendChild(newChild) {\n return this.insertBefore(newChild, null);\n }\n cloneNode(deep) {\n const cloned = extend(Object.create(Object.getPrototypeOf(this)), this);\n const { attributes } = cloned;\n if (attributes) {\n cloned.attributes = extend({}, attributes);\n }\n if (deep) {\n cloned.childNodes = cloned.childNodes.map((childNode) => childNode.cloneNode(true));\n }\n return cloned;\n }\n insertBefore(newChild, refChild) {\n // 先从现在的父节点移除(注意:不能触发onRemoveChild,否则会生成先remove该 id,再 insert)\n removeNode(newChild);\n newChild.pageNode = this.pageNode;\n newChild.parentNode = this;\n checkNodeId(newChild);\n const { childNodes } = this;\n if (refChild) {\n const index = childNodes.indexOf(refChild);\n if (index === -1) {\n throw new DOMException(`Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.`);\n }\n childNodes.splice(index, 0, newChild);\n }\n else {\n childNodes.push(newChild);\n }\n return this.pageNode && !this.pageNode.isUnmounted\n ? this.pageNode.onInsertBefore(this, newChild, refChild)\n : newChild;\n }\n removeChild(oldChild) {\n const { childNodes } = this;\n const index = childNodes.indexOf(oldChild);\n if (index === -1) {\n throw new DOMException(`Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.`);\n }\n oldChild.parentNode = null;\n childNodes.splice(index, 1);\n return this.pageNode && !this.pageNode.isUnmounted\n ? this.pageNode.onRemoveChild(oldChild)\n : oldChild;\n }\n}\nconst ATTR_CLASS = 'class';\nconst ATTR_STYLE = 'style';\nconst ATTR_INNER_HTML = 'innerHTML';\nconst ATTR_TEXT_CONTENT = 'textContent';\nconst ATTR_V_SHOW = '.vShow';\nconst ATTR_V_OWNER_ID = '.vOwnerId';\nconst ATTR_V_RENDERJS = '.vRenderjs';\nconst ATTR_CHANGE_PREFIX = 'change:';\nclass UniBaseNode extends UniNode {\n constructor(nodeType, nodeName, container) {\n super(nodeType, nodeName, container);\n this.attributes = Object.create(null);\n this.style = null;\n this.vShow = null;\n this._html = null;\n }\n get className() {\n return (this.attributes[ATTR_CLASS] || '');\n }\n set className(val) {\n this.setAttribute(ATTR_CLASS, val);\n }\n get innerHTML() {\n return '';\n }\n set innerHTML(html) {\n this._html = html;\n }\n addEventListener(type, listener, options) {\n super.addEventListener(type, listener, options);\n if (this.pageNode && !this.pageNode.isUnmounted) {\n if (listener.wxsEvent) {\n this.pageNode.onAddWxsEvent(this, normalizeEventType(type, options), listener.wxsEvent, encodeModifier(listener.modifiers || []));\n }\n else {\n this.pageNode.onAddEvent(this, normalizeEventType(type, options), encodeModifier(listener.modifiers || []));\n }\n }\n }\n removeEventListener(type, callback, options) {\n super.removeEventListener(type, callback, options);\n if (this.pageNode && !this.pageNode.isUnmounted) {\n this.pageNode.onRemoveEvent(this, normalizeEventType(type, options));\n }\n }\n getAttribute(qualifiedName) {\n if (qualifiedName === ATTR_STYLE) {\n return this.style;\n }\n return this.attributes[qualifiedName];\n }\n removeAttribute(qualifiedName) {\n if (qualifiedName == ATTR_STYLE) {\n this.style = null;\n }\n else {\n delete this.attributes[qualifiedName];\n }\n if (this.pageNode && !this.pageNode.isUnmounted) {\n this.pageNode.onRemoveAttribute(this, qualifiedName);\n }\n }\n setAttribute(qualifiedName, value) {\n if (qualifiedName === ATTR_STYLE) {\n this.style = value;\n }\n else {\n this.attributes[qualifiedName] = value;\n }\n if (this.pageNode && !this.pageNode.isUnmounted) {\n this.pageNode.onSetAttribute(this, qualifiedName, value);\n }\n }\n toJSON({ attr, normalize, } = {}) {\n const { attributes, style, listeners, _text } = this;\n const res = {};\n if (Object.keys(attributes).length) {\n res.a = normalize ? normalize(attributes) : attributes;\n }\n const events = Object.keys(listeners);\n if (events.length) {\n let w = undefined;\n const e = {};\n events.forEach((name) => {\n const handlers = listeners[name];\n if (handlers.length) {\n // 可能存在多个 handler 且不同 modifiers 吗?\n const { wxsEvent, modifiers } = handlers[0];\n const modifier = encodeModifier(modifiers || []);\n if (!wxsEvent) {\n e[name] = modifier;\n }\n else {\n if (!w) {\n w = {};\n }\n w[name] = [normalize ? normalize(wxsEvent) : wxsEvent, modifier];\n }\n }\n });\n res.e = normalize ? normalize(e, false) : e;\n if (w) {\n res.w = normalize ? normalize(w, false) : w;\n }\n }\n if (style !== null) {\n res.s = normalize ? normalize(style) : style;\n }\n if (!attr) {\n res.i = this.nodeId;\n res.n = this.nodeName;\n }\n if (_text !== null) {\n res.t = normalize ? normalize(_text) : _text;\n }\n return res;\n }\n}\n\nclass UniCommentNode extends UniNode {\n constructor(text, container) {\n super(NODE_TYPE_COMMENT, '#comment', container);\n this._text = (process.env.NODE_ENV !== 'production') ? text : '';\n }\n toJSON(opts = {}) {\n // 暂时不传递 text 到 view 层,没啥意义,节省点数据量\n return opts.attr\n ? {}\n : {\n i: this.nodeId,\n };\n // return opts.attr\n // ? { t: this._text as string }\n // : {\n // i: this.nodeId!,\n // t: this._text as string,\n // }\n }\n}\n\nclass UniElement extends UniBaseNode {\n constructor(nodeName, container) {\n super(NODE_TYPE_ELEMENT, nodeName.toUpperCase(), container);\n this.tagName = this.nodeName;\n }\n}\nclass UniInputElement extends UniElement {\n get value() {\n return this.getAttribute('value');\n }\n set value(val) {\n this.setAttribute('value', val);\n }\n}\nclass UniTextAreaElement extends UniInputElement {\n}\n\nclass UniTextNode extends UniBaseNode {\n constructor(text, container) {\n super(NODE_TYPE_TEXT, '#text', container);\n this._text = text;\n }\n get nodeValue() {\n return this._text || '';\n }\n set nodeValue(text) {\n this._text = text;\n if (this.pageNode && !this.pageNode.isUnmounted) {\n this.pageNode.onNodeValue(this, text);\n }\n }\n}\n\nconst forcePatchProps = {\n AD: ['data'],\n 'AD-DRAW': ['data'],\n 'LIVE-PLAYER': ['picture-in-picture-mode'],\n MAP: [\n 'markers',\n 'polyline',\n 'circles',\n 'controls',\n 'include-points',\n 'polygons',\n ],\n PICKER: ['range', 'value'],\n 'PICKER-VIEW': ['value'],\n 'RICH-TEXT': ['nodes'],\n VIDEO: ['danmu-list', 'header'],\n 'WEB-VIEW': ['webview-styles'],\n};\nconst forcePatchPropKeys = ['animation'];\n\nconst forcePatchProp = (el, key) => {\n if (forcePatchPropKeys.indexOf(key) > -1) {\n return true;\n }\n const keys = forcePatchProps[el.nodeName];\n if (keys && keys.indexOf(key) > -1) {\n return true;\n }\n return false;\n};\n\nconst ACTION_TYPE_PAGE_CREATE = 1;\nconst ACTION_TYPE_PAGE_CREATED = 2;\nconst ACTION_TYPE_CREATE = 3;\nconst ACTION_TYPE_INSERT = 4;\nconst ACTION_TYPE_REMOVE = 5;\nconst ACTION_TYPE_SET_ATTRIBUTE = 6;\nconst ACTION_TYPE_REMOVE_ATTRIBUTE = 7;\nconst ACTION_TYPE_ADD_EVENT = 8;\nconst ACTION_TYPE_REMOVE_EVENT = 9;\nconst ACTION_TYPE_SET_TEXT = 10;\nconst ACTION_TYPE_ADD_WXS_EVENT = 12;\nconst ACTION_TYPE_PAGE_SCROLL = 15;\nconst ACTION_TYPE_EVENT = 20;\n\n/**\n * 需要手动传入 timer,主要是解决 App 平台的定制 timer\n */\nfunction debounce(fn, delay, { clearTimeout, setTimeout }) {\n let timeout;\n const newFn = function () {\n clearTimeout(timeout);\n const timerFn = () => fn.apply(this, arguments);\n timeout = setTimeout(timerFn, delay);\n };\n newFn.cancel = function () {\n clearTimeout(timeout);\n };\n return newFn;\n}\n\nclass EventChannel {\n constructor(id, events) {\n this.id = id;\n this.listener = {};\n this.emitCache = [];\n if (events) {\n Object.keys(events).forEach((name) => {\n this.on(name, events[name]);\n });\n }\n }\n emit(eventName, ...args) {\n const fns = this.listener[eventName];\n if (!fns) {\n return this.emitCache.push({\n eventName,\n args,\n });\n }\n fns.forEach((opt) => {\n opt.fn.apply(opt.fn, args);\n });\n this.listener[eventName] = fns.filter((opt) => opt.type !== 'once');\n }\n on(eventName, fn) {\n this._addListener(eventName, 'on', fn);\n this._clearCache(eventName);\n }\n once(eventName, fn) {\n this._addListener(eventName, 'once', fn);\n this._clearCache(eventName);\n }\n off(eventName, fn) {\n const fns = this.listener[eventName];\n if (!fns) {\n return;\n }\n if (fn) {\n for (let i = 0; i < fns.length;) {\n if (fns[i].fn === fn) {\n fns.splice(i, 1);\n i--;\n }\n i++;\n }\n }\n else {\n delete this.listener[eventName];\n }\n }\n _clearCache(eventName) {\n for (let index = 0; index < this.emitCache.length; index++) {\n const cache = this.emitCache[index];\n const _name = eventName\n ? cache.eventName === eventName\n ? eventName\n : null\n : cache.eventName;\n if (!_name)\n continue;\n const location = this.emit.apply(this, [_name, ...cache.args]);\n if (typeof location === 'number') {\n this.emitCache.pop();\n continue;\n }\n this.emitCache.splice(index, 1);\n index--;\n }\n }\n _addListener(eventName, type, fn) {\n (this.listener[eventName] || (this.listener[eventName] = [])).push({\n fn,\n type,\n });\n }\n}\n\nconst PAGE_HOOKS = [\n ON_INIT,\n ON_LOAD,\n ON_SHOW,\n ON_HIDE,\n ON_UNLOAD,\n ON_BACK_PRESS,\n ON_PAGE_SCROLL,\n ON_TAB_ITEM_TAP,\n ON_REACH_BOTTOM,\n ON_PULL_DOWN_REFRESH,\n ON_SHARE_TIMELINE,\n ON_SHARE_APP_MESSAGE,\n ON_SHARE_CHAT,\n ON_ADD_TO_FAVORITES,\n ON_SAVE_EXIT_STATE,\n ON_NAVIGATION_BAR_BUTTON_TAP,\n ON_NAVIGATION_BAR_SEARCH_INPUT_CLICKED,\n ON_NAVIGATION_BAR_SEARCH_INPUT_CHANGED,\n ON_NAVIGATION_BAR_SEARCH_INPUT_CONFIRMED,\n ON_NAVIGATION_BAR_SEARCH_INPUT_FOCUS_CHANGED,\n];\nfunction isRootImmediateHook(name) {\n const PAGE_SYNC_HOOKS = [ON_LOAD, ON_SHOW];\n return PAGE_SYNC_HOOKS.indexOf(name) > -1;\n}\n// isRootImmediateHookX deprecated\nfunction isRootHook(name) {\n return PAGE_HOOKS.indexOf(name) > -1;\n}\nconst UniLifecycleHooks = [\n ON_SHOW,\n ON_HIDE,\n ON_LAUNCH,\n ON_ERROR,\n ON_THEME_CHANGE,\n ON_PAGE_NOT_FOUND,\n ON_UNHANDLE_REJECTION,\n ON_EXIT,\n ON_INIT,\n ON_LOAD,\n ON_READY,\n ON_UNLOAD,\n ON_RESIZE,\n ON_BACK_PRESS,\n ON_PAGE_SCROLL,\n ON_TAB_ITEM_TAP,\n ON_REACH_BOTTOM,\n ON_PULL_DOWN_REFRESH,\n ON_SHARE_TIMELINE,\n ON_ADD_TO_FAVORITES,\n ON_SHARE_APP_MESSAGE,\n ON_SHARE_CHAT,\n ON_SAVE_EXIT_STATE,\n ON_NAVIGATION_BAR_BUTTON_TAP,\n ON_NAVIGATION_BAR_SEARCH_INPUT_CLICKED,\n ON_NAVIGATION_BAR_SEARCH_INPUT_CHANGED,\n ON_NAVIGATION_BAR_SEARCH_INPUT_CONFIRMED,\n ON_NAVIGATION_BAR_SEARCH_INPUT_FOCUS_CHANGED,\n];\nconst MINI_PROGRAM_PAGE_RUNTIME_HOOKS = /*#__PURE__*/ (() => {\n return {\n onPageScroll: 1,\n onShareAppMessage: 1 << 1,\n onShareTimeline: 1 << 2,\n onShareChat: 1 << 3,\n };\n})();\nfunction isUniLifecycleHook(name, value, checkType = true) {\n // 检查类型\n if (checkType && !isFunction(value)) {\n return false;\n }\n if (UniLifecycleHooks.indexOf(name) > -1) {\n // 已预定义\n return true;\n }\n else if (name.indexOf('on') === 0) {\n // 以 on 开头\n return true;\n }\n return false;\n}\n\nlet vueApp;\nconst createVueAppHooks = [];\n/**\n * 提供 createApp 的回调事件,方便三方插件接收 App 对象,处理挂靠全局 mixin 之类的逻辑\n */\nfunction onCreateVueApp(hook) {\n // TODO 每个 nvue 页面都会触发\n if (vueApp) {\n return hook(vueApp);\n }\n createVueAppHooks.push(hook);\n}\nfunction invokeCreateVueAppHook(app) {\n vueApp = app;\n createVueAppHooks.forEach((hook) => hook(app));\n}\nconst invokeCreateErrorHandler = once((app, createErrorHandler) => {\n // 不再判断开发者是否监听了onError,直接返回 createErrorHandler,内部 errorHandler 会调用开发者自定义的 errorHandler,以及判断开发者是否监听了onError\n return createErrorHandler(app);\n});\n\nconst E = function () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n};\nE.prototype = {\n _id: 1,\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx,\n _id: this._id,\n });\n return this._id++;\n },\n once: function (name, callback, ctx) {\n var self = this;\n function listener() {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n }\n listener._ = callback;\n return this.on(name, listener, ctx);\n },\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n return this;\n },\n off: function (name, event) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n if (evts && event) {\n for (var i = evts.length - 1; i >= 0; i--) {\n if (evts[i].fn === event ||\n evts[i].fn._ === event ||\n evts[i]._id === event) {\n evts.splice(i, 1);\n break;\n }\n }\n liveEvents = evts;\n }\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n liveEvents.length ? (e[name] = liveEvents) : delete e[name];\n return this;\n },\n};\nvar E$1 = E;\n\nconst borderStyles = {\n black: 'rgba(0,0,0,0.4)',\n white: 'rgba(255,255,255,0.4)',\n};\nfunction normalizeTabBarStyles(borderStyle) {\n if (borderStyle && borderStyle in borderStyles) {\n return borderStyles[borderStyle];\n }\n return borderStyle;\n}\nfunction normalizeTitleColor(titleColor) {\n return titleColor === 'black' ? '#000000' : '#ffffff';\n}\nfunction resolveStringStyleItem(modeStyle, styleItem, key) {\n if (isString(styleItem) && styleItem.startsWith('@')) {\n const _key = styleItem.replace('@', '');\n let _styleItem = modeStyle[_key] || styleItem;\n switch (key) {\n case 'titleColor':\n _styleItem = normalizeTitleColor(_styleItem);\n break;\n case 'borderStyle':\n _styleItem = normalizeTabBarStyles(_styleItem);\n break;\n }\n return _styleItem;\n }\n return styleItem;\n}\nfunction normalizeStyles(pageStyle, themeConfig = {}, mode = 'light') {\n const modeStyle = themeConfig[mode];\n const styles = {};\n if (typeof modeStyle === 'undefined' || !pageStyle)\n return pageStyle;\n Object.keys(pageStyle).forEach((key) => {\n const styleItem = pageStyle[key]; // Object Array String\n const parseStyleItem = () => {\n if (isPlainObject(styleItem))\n return normalizeStyles(styleItem, themeConfig, mode);\n if (isArray(styleItem))\n return styleItem.map((item) => {\n if (isPlainObject(item))\n return normalizeStyles(item, themeConfig, mode);\n return resolveStringStyleItem(modeStyle, item);\n });\n return resolveStringStyleItem(modeStyle, styleItem, key);\n };\n styles[key] = parseStyleItem();\n });\n return styles;\n}\n\nfunction getEnvLocale() {\n const { env } = process;\n const lang = env.LC_ALL || env.LC_MESSAGES || env.LANG || env.LANGUAGE;\n return (lang && lang.replace(/[.:].*/, '')) || 'en';\n}\n\nconst isStringIntegerKey = (key) => typeof key === 'string' &&\n key !== 'NaN' &&\n key[0] !== '-' &&\n '' + parseInt(key, 10) === key;\nconst isNumberIntegerKey = (key) => typeof key === 'number' &&\n !isNaN(key) &&\n key >= 0 &&\n parseInt(key + '', 10) === key;\n/**\n * 用于替代@vue/shared的isIntegerKey,原始方法在鸿蒙arkts中会引发bug。根本原因是arkts的数组的key是数字而不是字符串。\n * 目前这个方法使用的地方都和数组有关,切记不能挪作他用。\n * @param key\n * @returns\n */\nconst isIntegerKey = (key) => isNumberIntegerKey(key) || isStringIntegerKey(key);\n\nconst GLOBALS_ALLOWED = 'Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,' +\n 'decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,' +\n 'Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console,Error,' +\n 'uni';\nconst isGloballyAllowed = /*#__PURE__*/ makeMap(GLOBALS_ALLOWED);\n\nexport { ACTION_TYPE_ADD_EVENT, ACTION_TYPE_ADD_WXS_EVENT, ACTION_TYPE_CREATE, ACTION_TYPE_EVENT, ACTION_TYPE_INSERT, ACTION_TYPE_PAGE_CREATE, ACTION_TYPE_PAGE_CREATED, ACTION_TYPE_PAGE_SCROLL, ACTION_TYPE_REMOVE, ACTION_TYPE_REMOVE_ATTRIBUTE, ACTION_TYPE_REMOVE_EVENT, ACTION_TYPE_SET_ATTRIBUTE, ACTION_TYPE_SET_TEXT, ATTR_CHANGE_PREFIX, ATTR_CLASS, ATTR_INNER_HTML, ATTR_STYLE, ATTR_TEXT_CONTENT, ATTR_V_OWNER_ID, ATTR_V_RENDERJS, ATTR_V_SHOW, BACKGROUND_COLOR, BUILT_IN_TAGS, BUILT_IN_TAG_NAMES, COMPONENT_NAME_PREFIX, COMPONENT_PREFIX, COMPONENT_SELECTOR_PREFIX, DATA_RE, E$1 as Emitter, EventChannel, EventModifierFlags, I18N_JSON_DELIMITERS, JSON_PROTOCOL, LINEFEED, MINI_PROGRAM_PAGE_RUNTIME_HOOKS, NAVBAR_HEIGHT, NODE_TYPE_COMMENT, NODE_TYPE_ELEMENT, NODE_TYPE_PAGE, NODE_TYPE_TEXT, NVUE_BUILT_IN_TAGS, NVUE_U_BUILT_IN_TAGS, OFF_HOST_THEME_CHANGE, OFF_THEME_CHANGE, ON_ADD_TO_FAVORITES, ON_APP_ENTER_BACKGROUND, ON_APP_ENTER_FOREGROUND, ON_BACK_PRESS, ON_ERROR, ON_EXIT, ON_HIDE, ON_HOST_THEME_CHANGE, ON_INIT, ON_KEYBOARD_HEIGHT_CHANGE, ON_LAST_PAGE_BACK_PRESS, ON_LAUNCH, ON_LOAD, ON_NAVIGATION_BAR_BUTTON_TAP, ON_NAVIGATION_BAR_CHANGE, ON_NAVIGATION_BAR_SEARCH_INPUT_CHANGED, ON_NAVIGATION_BAR_SEARCH_INPUT_CLICKED, ON_NAVIGATION_BAR_SEARCH_INPUT_CONFIRMED, ON_NAVIGATION_BAR_SEARCH_INPUT_FOCUS_CHANGED, ON_PAGE_NOT_FOUND, ON_PAGE_SCROLL, ON_PULL_DOWN_REFRESH, ON_REACH_BOTTOM, ON_REACH_BOTTOM_DISTANCE, ON_READY, ON_RESIZE, ON_SAVE_EXIT_STATE, ON_SHARE_APP_MESSAGE, ON_SHARE_CHAT, ON_SHARE_TIMELINE, ON_SHOW, ON_TAB_ITEM_TAP, ON_THEME_CHANGE, ON_UNHANDLE_REJECTION, ON_UNLOAD, ON_WEB_INVOKE_APP_SERVICE, ON_WXS_INVOKE_CALL_METHOD, PLUS_RE, PRIMARY_COLOR, RENDERJS_MODULES, RESPONSIVE_MIN_WIDTH, SCHEME_RE, SELECTED_COLOR, SLOT_DEFAULT_NAME, TABBAR_HEIGHT, TAGS, UNI_AD_PLUGINS, UNI_SSR, UNI_SSR_DATA, UNI_SSR_GLOBAL_DATA, UNI_SSR_STORE, UNI_SSR_TITLE, UNI_STORAGE_LOCALE, UNI_UI_CONFLICT_TAGS, UVUE_BUILT_IN_TAGS, UVUE_HARMONY_BUILT_IN_TAGS, UVUE_IOS_BUILT_IN_TAGS, UVUE_WEB_BUILT_IN_CUSTOM_ELEMENTS, UVUE_WEB_BUILT_IN_TAGS, UniBaseNode, UniCommentNode, UniElement, UniEvent, UniInputElement, UniLifecycleHooks, UniNode, UniTextAreaElement, UniTextNode, VIRTUAL_HOST_CLASS, VIRTUAL_HOST_HIDDEN, VIRTUAL_HOST_ID, VIRTUAL_HOST_STYLE, WEB_INVOKE_APPSERVICE, WXS_MODULES, WXS_PROTOCOL, addFont, addLeadingSlash, borderStyles, cache, cacheStringFunction, callOptions, createIsCustomElement, createRpx2Unit, createUniEvent, customizeEvent, debounce, decode, decodedQuery, defaultMiniProgramRpx2Unit, defaultNVueRpx2Unit, defaultRpx2Unit, dynamicSlotName, forcePatchProp, formatDateTime, formatLog, getCustomDataset, getEnvLocale, getGlobal, getLen, getValueByDataPath, initCustomDatasetOnce, invokeArrayFns, invokeCreateErrorHandler, invokeCreateVueAppHook, isAppHarmonyUVueNativeTag, isAppIOSUVueNativeTag, isAppNVueNativeTag, isAppNativeTag, isAppUVueBuiltInEasyComponent, isAppUVueNativeTag, isAppVoidTag, isBuiltInComponent, isComponentInternalInstance, isComponentTag, isGloballyAllowed, isH5CustomElement, isH5NativeTag, isIntegerKey, isMiniProgramNativeTag, isMiniProgramUVueNativeTag, isRootHook, isRootImmediateHook, isUniLifecycleHook, isUniXElement, normalizeClass, normalizeDataset, normalizeEventType, normalizeProps, normalizeStyle, normalizeStyles, normalizeTabBarStyles, normalizeTarget, normalizeTitleColor, onCreateVueApp, once, parseEventName, parseNVueDataset, parseQuery, parseUrl, passive, plusReady, removeLeadingSlash, resolveComponentInstance, resolveOwnerEl, resolveOwnerVm, sanitise, scrollTo, sortObject, stringifyQuery, updateElementStyle };\n","import { isRootHook, getValueByDataPath, isUniLifecycleHook, ON_ERROR, UniLifecycleHooks, invokeCreateErrorHandler, normalizeStyle as normalizeStyle$1, dynamicSlotName, normalizeClass as normalizeClass$1 } from '@dcloudio/uni-shared';\nimport { NOOP, extend, isSymbol, isObject, def, hasChanged, isFunction, isArray, isPromise, camelize, capitalize, EMPTY_OBJ, remove, toHandlerKey, hasOwn, hyphenate, isReservedProp, toRawType, isString, normalizeClass, normalizeStyle, isOn, toTypeString, isMap, isIntegerKey, isSet, isPlainObject, makeMap, invokeArrayFns, isBuiltInDirective, looseToNumber, NO, EMPTY_ARR, isModelListener, toNumber, toDisplayString } from '@vue/shared';\nexport { EMPTY_OBJ, camelize, normalizeClass, normalizeProps, normalizeStyle, toDisplayString, toHandlerKey } from '@vue/shared';\n\n/**\n* @dcloudio/uni-mp-vue v3.4.21\n* (c) 2018-present Yuxi (Evan) You and Vue contributors\n* @license MIT\n**/\n\nfunction warn$2(msg, ...args) {\n console.warn(`[Vue warn] ${msg}`, ...args);\n}\n\nlet activeEffectScope;\nclass EffectScope {\n constructor(detached = false) {\n this.detached = detached;\n /**\n * @internal\n */\n this._active = true;\n /**\n * @internal\n */\n this.effects = [];\n /**\n * @internal\n */\n this.cleanups = [];\n this.parent = activeEffectScope;\n if (!detached && activeEffectScope) {\n this.index = (activeEffectScope.scopes || (activeEffectScope.scopes = [])).push(\n this\n ) - 1;\n }\n }\n get active() {\n return this._active;\n }\n run(fn) {\n if (this._active) {\n const currentEffectScope = activeEffectScope;\n try {\n activeEffectScope = this;\n return fn();\n } finally {\n activeEffectScope = currentEffectScope;\n }\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$2(`cannot run an inactive effect scope.`);\n }\n }\n /**\n * This should only be called on non-detached scopes\n * @internal\n */\n on() {\n activeEffectScope = this;\n }\n /**\n * This should only be called on non-detached scopes\n * @internal\n */\n off() {\n activeEffectScope = this.parent;\n }\n stop(fromParent) {\n if (this._active) {\n let i, l;\n for (i = 0, l = this.effects.length; i < l; i++) {\n this.effects[i].stop();\n }\n for (i = 0, l = this.cleanups.length; i < l; i++) {\n this.cleanups[i]();\n }\n if (this.scopes) {\n for (i = 0, l = this.scopes.length; i < l; i++) {\n this.scopes[i].stop(true);\n }\n }\n if (!this.detached && this.parent && !fromParent) {\n const last = this.parent.scopes.pop();\n if (last && last !== this) {\n this.parent.scopes[this.index] = last;\n last.index = this.index;\n }\n }\n this.parent = void 0;\n this._active = false;\n }\n }\n}\nfunction effectScope(detached) {\n return new EffectScope(detached);\n}\nfunction recordEffectScope(effect, scope = activeEffectScope) {\n if (scope && scope.active) {\n scope.effects.push(effect);\n }\n}\nfunction getCurrentScope() {\n return activeEffectScope;\n}\nfunction onScopeDispose(fn) {\n if (activeEffectScope) {\n activeEffectScope.cleanups.push(fn);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$2(\n `onScopeDispose() is called when there is no active effect scope to be associated with.`\n );\n }\n}\n\nlet activeEffect;\nclass ReactiveEffect {\n constructor(fn, trigger, scheduler, scope) {\n this.fn = fn;\n this.trigger = trigger;\n this.scheduler = scheduler;\n this.active = true;\n this.deps = [];\n /**\n * @internal\n */\n this._dirtyLevel = 4;\n /**\n * @internal\n */\n this._trackId = 0;\n /**\n * @internal\n */\n this._runnings = 0;\n /**\n * @internal\n */\n this._shouldSchedule = false;\n /**\n * @internal\n */\n this._depsLength = 0;\n recordEffectScope(this, scope);\n }\n get dirty() {\n if (this._dirtyLevel === 2 || this._dirtyLevel === 3) {\n this._dirtyLevel = 1;\n pauseTracking();\n for (let i = 0; i < this._depsLength; i++) {\n const dep = this.deps[i];\n if (dep.computed) {\n triggerComputed(dep.computed);\n if (this._dirtyLevel >= 4) {\n break;\n }\n }\n }\n if (this._dirtyLevel === 1) {\n this._dirtyLevel = 0;\n }\n resetTracking();\n }\n return this._dirtyLevel >= 4;\n }\n set dirty(v) {\n this._dirtyLevel = v ? 4 : 0;\n }\n run() {\n this._dirtyLevel = 0;\n if (!this.active) {\n return this.fn();\n }\n let lastShouldTrack = shouldTrack;\n let lastEffect = activeEffect;\n try {\n shouldTrack = true;\n activeEffect = this;\n this._runnings++;\n preCleanupEffect(this);\n return this.fn();\n } finally {\n postCleanupEffect(this);\n this._runnings--;\n activeEffect = lastEffect;\n shouldTrack = lastShouldTrack;\n }\n }\n stop() {\n var _a;\n if (this.active) {\n preCleanupEffect(this);\n postCleanupEffect(this);\n (_a = this.onStop) == null ? void 0 : _a.call(this);\n this.active = false;\n }\n }\n}\nfunction triggerComputed(computed) {\n return computed.value;\n}\nfunction preCleanupEffect(effect2) {\n effect2._trackId++;\n effect2._depsLength = 0;\n}\nfunction postCleanupEffect(effect2) {\n if (effect2.deps.length > effect2._depsLength) {\n for (let i = effect2._depsLength; i < effect2.deps.length; i++) {\n cleanupDepEffect(effect2.deps[i], effect2);\n }\n effect2.deps.length = effect2._depsLength;\n }\n}\nfunction cleanupDepEffect(dep, effect2) {\n const trackId = dep.get(effect2);\n if (trackId !== void 0 && effect2._trackId !== trackId) {\n dep.delete(effect2);\n if (dep.size === 0) {\n dep.cleanup();\n }\n }\n}\nfunction effect(fn, options) {\n if (fn.effect instanceof ReactiveEffect) {\n fn = fn.effect.fn;\n }\n const _effect = new ReactiveEffect(fn, NOOP, () => {\n if (_effect.dirty) {\n _effect.run();\n }\n });\n if (options) {\n extend(_effect, options);\n if (options.scope)\n recordEffectScope(_effect, options.scope);\n }\n if (!options || !options.lazy) {\n _effect.run();\n }\n const runner = _effect.run.bind(_effect);\n runner.effect = _effect;\n return runner;\n}\nfunction stop(runner) {\n runner.effect.stop();\n}\nlet shouldTrack = true;\nlet pauseScheduleStack = 0;\nconst trackStack = [];\nfunction pauseTracking() {\n trackStack.push(shouldTrack);\n shouldTrack = false;\n}\nfunction resetTracking() {\n const last = trackStack.pop();\n shouldTrack = last === void 0 ? true : last;\n}\nfunction pauseScheduling() {\n pauseScheduleStack++;\n}\nfunction resetScheduling() {\n pauseScheduleStack--;\n while (!pauseScheduleStack && queueEffectSchedulers.length) {\n queueEffectSchedulers.shift()();\n }\n}\nfunction trackEffect(effect2, dep, debuggerEventExtraInfo) {\n var _a;\n if (dep.get(effect2) !== effect2._trackId) {\n dep.set(effect2, effect2._trackId);\n const oldDep = effect2.deps[effect2._depsLength];\n if (oldDep !== dep) {\n if (oldDep) {\n cleanupDepEffect(oldDep, effect2);\n }\n effect2.deps[effect2._depsLength++] = dep;\n } else {\n effect2._depsLength++;\n }\n if (!!(process.env.NODE_ENV !== \"production\")) {\n (_a = effect2.onTrack) == null ? void 0 : _a.call(effect2, extend({ effect: effect2 }, debuggerEventExtraInfo));\n }\n }\n}\nconst queueEffectSchedulers = [];\nfunction triggerEffects(dep, dirtyLevel, debuggerEventExtraInfo) {\n var _a;\n pauseScheduling();\n for (const effect2 of dep.keys()) {\n let tracking;\n if (effect2._dirtyLevel < dirtyLevel && (tracking != null ? tracking : tracking = dep.get(effect2) === effect2._trackId)) {\n effect2._shouldSchedule || (effect2._shouldSchedule = effect2._dirtyLevel === 0);\n effect2._dirtyLevel = dirtyLevel;\n }\n if (effect2._shouldSchedule && (tracking != null ? tracking : tracking = dep.get(effect2) === effect2._trackId)) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n (_a = effect2.onTrigger) == null ? void 0 : _a.call(effect2, extend({ effect: effect2 }, debuggerEventExtraInfo));\n }\n effect2.trigger();\n if ((!effect2._runnings || effect2.allowRecurse) && effect2._dirtyLevel !== 2) {\n effect2._shouldSchedule = false;\n if (effect2.scheduler) {\n queueEffectSchedulers.push(effect2.scheduler);\n }\n }\n }\n }\n resetScheduling();\n}\n\nconst createDep = (cleanup, computed) => {\n const dep = /* @__PURE__ */ new Map();\n dep.cleanup = cleanup;\n dep.computed = computed;\n return dep;\n};\n\nconst targetMap = /* @__PURE__ */ new WeakMap();\nconst ITERATE_KEY = Symbol(!!(process.env.NODE_ENV !== \"production\") ? \"iterate\" : \"\");\nconst MAP_KEY_ITERATE_KEY = Symbol(!!(process.env.NODE_ENV !== \"production\") ? \"Map key iterate\" : \"\");\nfunction track(target, type, key) {\n if (shouldTrack && activeEffect) {\n let depsMap = targetMap.get(target);\n if (!depsMap) {\n targetMap.set(target, depsMap = /* @__PURE__ */ new Map());\n }\n let dep = depsMap.get(key);\n if (!dep) {\n depsMap.set(key, dep = createDep(() => depsMap.delete(key)));\n }\n trackEffect(\n activeEffect,\n dep,\n !!(process.env.NODE_ENV !== \"production\") ? {\n target,\n type,\n key\n } : void 0\n );\n }\n}\nfunction trigger(target, type, key, newValue, oldValue, oldTarget) {\n const depsMap = targetMap.get(target);\n if (!depsMap) {\n return;\n }\n let deps = [];\n if (type === \"clear\") {\n deps = [...depsMap.values()];\n } else if (key === \"length\" && isArray(target)) {\n const newLength = Number(newValue);\n depsMap.forEach((dep, key2) => {\n if (key2 === \"length\" || !isSymbol(key2) && key2 >= newLength) {\n deps.push(dep);\n }\n });\n } else {\n if (key !== void 0) {\n deps.push(depsMap.get(key));\n }\n switch (type) {\n case \"add\":\n if (!isArray(target)) {\n deps.push(depsMap.get(ITERATE_KEY));\n if (isMap(target)) {\n deps.push(depsMap.get(MAP_KEY_ITERATE_KEY));\n }\n } else if (isIntegerKey(key)) {\n deps.push(depsMap.get(\"length\"));\n }\n break;\n case \"delete\":\n if (!isArray(target)) {\n deps.push(depsMap.get(ITERATE_KEY));\n if (isMap(target)) {\n deps.push(depsMap.get(MAP_KEY_ITERATE_KEY));\n }\n }\n break;\n case \"set\":\n if (isMap(target)) {\n deps.push(depsMap.get(ITERATE_KEY));\n }\n break;\n }\n }\n pauseScheduling();\n for (const dep of deps) {\n if (dep) {\n triggerEffects(\n dep,\n 4,\n !!(process.env.NODE_ENV !== \"production\") ? {\n target,\n type,\n key,\n newValue,\n oldValue,\n oldTarget\n } : void 0\n );\n }\n }\n resetScheduling();\n}\nfunction getDepFromReactive(object, key) {\n var _a;\n return (_a = targetMap.get(object)) == null ? void 0 : _a.get(key);\n}\n\nconst isNonTrackableKeys = /* @__PURE__ */ makeMap(`__proto__,__v_isRef,__isVue`);\nconst builtInSymbols = new Set(\n /* @__PURE__ */ Object.getOwnPropertyNames(Symbol).filter((key) => key !== \"arguments\" && key !== \"caller\").map((key) => Symbol[key]).filter(isSymbol)\n);\nconst arrayInstrumentations = /* @__PURE__ */ createArrayInstrumentations();\nfunction createArrayInstrumentations() {\n const instrumentations = {};\n [\"includes\", \"indexOf\", \"lastIndexOf\"].forEach((key) => {\n instrumentations[key] = function(...args) {\n const arr = toRaw(this);\n for (let i = 0, l = this.length; i < l; i++) {\n track(arr, \"get\", i + \"\");\n }\n const res = arr[key](...args);\n if (res === -1 || res === false) {\n return arr[key](...args.map(toRaw));\n } else {\n return res;\n }\n };\n });\n [\"push\", \"pop\", \"shift\", \"unshift\", \"splice\"].forEach((key) => {\n instrumentations[key] = function(...args) {\n pauseTracking();\n pauseScheduling();\n const res = toRaw(this)[key].apply(this, args);\n resetScheduling();\n resetTracking();\n return res;\n };\n });\n return instrumentations;\n}\nfunction hasOwnProperty(key) {\n const obj = toRaw(this);\n track(obj, \"has\", key);\n return obj.hasOwnProperty(key);\n}\nclass BaseReactiveHandler {\n constructor(_isReadonly = false, _isShallow = false) {\n this._isReadonly = _isReadonly;\n this._isShallow = _isShallow;\n }\n get(target, key, receiver) {\n const isReadonly2 = this._isReadonly, isShallow2 = this._isShallow;\n if (key === \"__v_isReactive\") {\n return !isReadonly2;\n } else if (key === \"__v_isReadonly\") {\n return isReadonly2;\n } else if (key === \"__v_isShallow\") {\n return isShallow2;\n } else if (key === \"__v_raw\") {\n if (receiver === (isReadonly2 ? isShallow2 ? shallowReadonlyMap : readonlyMap : isShallow2 ? shallowReactiveMap : reactiveMap).get(target) || // receiver is not the reactive proxy, but has the same prototype\n // this means the reciever is a user proxy of the reactive proxy\n Object.getPrototypeOf(target) === Object.getPrototypeOf(receiver)) {\n return target;\n }\n return;\n }\n const targetIsArray = isArray(target);\n if (!isReadonly2) {\n if (targetIsArray && hasOwn(arrayInstrumentations, key)) {\n return Reflect.get(arrayInstrumentations, key, receiver);\n }\n if (key === \"hasOwnProperty\") {\n return hasOwnProperty;\n }\n }\n const res = Reflect.get(target, key, receiver);\n if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) {\n return res;\n }\n if (!isReadonly2) {\n track(target, \"get\", key);\n }\n if (isShallow2) {\n return res;\n }\n if (isRef(res)) {\n return targetIsArray && isIntegerKey(key) ? res : res.value;\n }\n if (isObject(res)) {\n return isReadonly2 ? readonly(res) : reactive(res);\n }\n return res;\n }\n}\nclass MutableReactiveHandler extends BaseReactiveHandler {\n constructor(isShallow2 = false) {\n super(false, isShallow2);\n }\n set(target, key, value, receiver) {\n let oldValue = target[key];\n if (!this._isShallow) {\n const isOldValueReadonly = isReadonly(oldValue);\n if (!isShallow(value) && !isReadonly(value)) {\n oldValue = toRaw(oldValue);\n value = toRaw(value);\n }\n if (!isArray(target) && isRef(oldValue) && !isRef(value)) {\n if (isOldValueReadonly) {\n return false;\n } else {\n oldValue.value = value;\n return true;\n }\n }\n }\n const hadKey = isArray(target) && isIntegerKey(key) ? Number(key) < target.length : hasOwn(target, key);\n const result = Reflect.set(target, key, value, receiver);\n if (target === toRaw(receiver)) {\n if (!hadKey) {\n trigger(target, \"add\", key, value);\n } else if (hasChanged(value, oldValue)) {\n trigger(target, \"set\", key, value, oldValue);\n }\n }\n return result;\n }\n deleteProperty(target, key) {\n const hadKey = hasOwn(target, key);\n const oldValue = target[key];\n const result = Reflect.deleteProperty(target, key);\n if (result && hadKey) {\n trigger(target, \"delete\", key, void 0, oldValue);\n }\n return result;\n }\n has(target, key) {\n const result = Reflect.has(target, key);\n if (!isSymbol(key) || !builtInSymbols.has(key)) {\n track(target, \"has\", key);\n }\n return result;\n }\n ownKeys(target) {\n track(\n target,\n \"iterate\",\n isArray(target) ? \"length\" : ITERATE_KEY\n );\n return Reflect.ownKeys(target);\n }\n}\nclass ReadonlyReactiveHandler extends BaseReactiveHandler {\n constructor(isShallow2 = false) {\n super(true, isShallow2);\n }\n set(target, key) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$2(\n `Set operation on key \"${String(key)}\" failed: target is readonly.`,\n target\n );\n }\n return true;\n }\n deleteProperty(target, key) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$2(\n `Delete operation on key \"${String(key)}\" failed: target is readonly.`,\n target\n );\n }\n return true;\n }\n}\nconst mutableHandlers = /* @__PURE__ */ new MutableReactiveHandler();\nconst readonlyHandlers = /* @__PURE__ */ new ReadonlyReactiveHandler();\nconst shallowReactiveHandlers = /* @__PURE__ */ new MutableReactiveHandler(\n true\n);\nconst shallowReadonlyHandlers = /* @__PURE__ */ new ReadonlyReactiveHandler(true);\n\nconst toShallow = (value) => value;\nconst getProto = (v) => Reflect.getPrototypeOf(v);\nfunction get(target, key, isReadonly = false, isShallow = false) {\n target = target[\"__v_raw\"];\n const rawTarget = toRaw(target);\n const rawKey = toRaw(key);\n if (!isReadonly) {\n if (hasChanged(key, rawKey)) {\n track(rawTarget, \"get\", key);\n }\n track(rawTarget, \"get\", rawKey);\n }\n const { has: has2 } = getProto(rawTarget);\n const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive;\n if (has2.call(rawTarget, key)) {\n return wrap(target.get(key));\n } else if (has2.call(rawTarget, rawKey)) {\n return wrap(target.get(rawKey));\n } else if (target !== rawTarget) {\n target.get(key);\n }\n}\nfunction has(key, isReadonly = false) {\n const target = this[\"__v_raw\"];\n const rawTarget = toRaw(target);\n const rawKey = toRaw(key);\n if (!isReadonly) {\n if (hasChanged(key, rawKey)) {\n track(rawTarget, \"has\", key);\n }\n track(rawTarget, \"has\", rawKey);\n }\n return key === rawKey ? target.has(key) : target.has(key) || target.has(rawKey);\n}\nfunction size(target, isReadonly = false) {\n target = target[\"__v_raw\"];\n !isReadonly && track(toRaw(target), \"iterate\", ITERATE_KEY);\n return Reflect.get(target, \"size\", target);\n}\nfunction add(value) {\n value = toRaw(value);\n const target = toRaw(this);\n const proto = getProto(target);\n const hadKey = proto.has.call(target, value);\n if (!hadKey) {\n target.add(value);\n trigger(target, \"add\", value, value);\n }\n return this;\n}\nfunction set$1(key, value) {\n value = toRaw(value);\n const target = toRaw(this);\n const { has: has2, get: get2 } = getProto(target);\n let hadKey = has2.call(target, key);\n if (!hadKey) {\n key = toRaw(key);\n hadKey = has2.call(target, key);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n checkIdentityKeys(target, has2, key);\n }\n const oldValue = get2.call(target, key);\n target.set(key, value);\n if (!hadKey) {\n trigger(target, \"add\", key, value);\n } else if (hasChanged(value, oldValue)) {\n trigger(target, \"set\", key, value, oldValue);\n }\n return this;\n}\nfunction deleteEntry(key) {\n const target = toRaw(this);\n const { has: has2, get: get2 } = getProto(target);\n let hadKey = has2.call(target, key);\n if (!hadKey) {\n key = toRaw(key);\n hadKey = has2.call(target, key);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n checkIdentityKeys(target, has2, key);\n }\n const oldValue = get2 ? get2.call(target, key) : void 0;\n const result = target.delete(key);\n if (hadKey) {\n trigger(target, \"delete\", key, void 0, oldValue);\n }\n return result;\n}\nfunction clear() {\n const target = toRaw(this);\n const hadItems = target.size !== 0;\n const oldTarget = !!(process.env.NODE_ENV !== \"production\") ? isMap(target) ? new Map(target) : new Set(target) : void 0;\n const result = target.clear();\n if (hadItems) {\n trigger(target, \"clear\", void 0, void 0, oldTarget);\n }\n return result;\n}\nfunction createForEach(isReadonly, isShallow) {\n return function forEach(callback, thisArg) {\n const observed = this;\n const target = observed[\"__v_raw\"];\n const rawTarget = toRaw(target);\n const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive;\n !isReadonly && track(rawTarget, \"iterate\", ITERATE_KEY);\n return target.forEach((value, key) => {\n return callback.call(thisArg, wrap(value), wrap(key), observed);\n });\n };\n}\nfunction createIterableMethod(method, isReadonly, isShallow) {\n return function(...args) {\n const target = this[\"__v_raw\"];\n const rawTarget = toRaw(target);\n const targetIsMap = isMap(rawTarget);\n const isPair = method === \"entries\" || method === Symbol.iterator && targetIsMap;\n const isKeyOnly = method === \"keys\" && targetIsMap;\n const innerIterator = target[method](...args);\n const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive;\n !isReadonly && track(\n rawTarget,\n \"iterate\",\n isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY\n );\n return {\n // iterator protocol\n next() {\n const { value, done } = innerIterator.next();\n return done ? { value, done } : {\n value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value),\n done\n };\n },\n // iterable protocol\n [Symbol.iterator]() {\n return this;\n }\n };\n };\n}\nfunction createReadonlyMethod(type) {\n return function(...args) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n const key = args[0] ? `on key \"${args[0]}\" ` : ``;\n warn$2(\n `${capitalize(type)} operation ${key}failed: target is readonly.`,\n toRaw(this)\n );\n }\n return type === \"delete\" ? false : type === \"clear\" ? void 0 : this;\n };\n}\nfunction createInstrumentations() {\n const mutableInstrumentations2 = {\n get(key) {\n return get(this, key);\n },\n get size() {\n return size(this);\n },\n has,\n add,\n set: set$1,\n delete: deleteEntry,\n clear,\n forEach: createForEach(false, false)\n };\n const shallowInstrumentations2 = {\n get(key) {\n return get(this, key, false, true);\n },\n get size() {\n return size(this);\n },\n has,\n add,\n set: set$1,\n delete: deleteEntry,\n clear,\n forEach: createForEach(false, true)\n };\n const readonlyInstrumentations2 = {\n get(key) {\n return get(this, key, true);\n },\n get size() {\n return size(this, true);\n },\n has(key) {\n return has.call(this, key, true);\n },\n add: createReadonlyMethod(\"add\"),\n set: createReadonlyMethod(\"set\"),\n delete: createReadonlyMethod(\"delete\"),\n clear: createReadonlyMethod(\"clear\"),\n forEach: createForEach(true, false)\n };\n const shallowReadonlyInstrumentations2 = {\n get(key) {\n return get(this, key, true, true);\n },\n get size() {\n return size(this, true);\n },\n has(key) {\n return has.call(this, key, true);\n },\n add: createReadonlyMethod(\"add\"),\n set: createReadonlyMethod(\"set\"),\n delete: createReadonlyMethod(\"delete\"),\n clear: createReadonlyMethod(\"clear\"),\n forEach: createForEach(true, true)\n };\n const iteratorMethods = [\n \"keys\",\n \"values\",\n \"entries\",\n Symbol.iterator\n ];\n iteratorMethods.forEach((method) => {\n mutableInstrumentations2[method] = createIterableMethod(method, false, false);\n readonlyInstrumentations2[method] = createIterableMethod(method, true, false);\n shallowInstrumentations2[method] = createIterableMethod(method, false, true);\n shallowReadonlyInstrumentations2[method] = createIterableMethod(\n method,\n true,\n true\n );\n });\n return [\n mutableInstrumentations2,\n readonlyInstrumentations2,\n shallowInstrumentations2,\n shallowReadonlyInstrumentations2\n ];\n}\nconst [\n mutableInstrumentations,\n readonlyInstrumentations,\n shallowInstrumentations,\n shallowReadonlyInstrumentations\n] = /* @__PURE__ */ createInstrumentations();\nfunction createInstrumentationGetter(isReadonly, shallow) {\n const instrumentations = shallow ? isReadonly ? shallowReadonlyInstrumentations : shallowInstrumentations : isReadonly ? readonlyInstrumentations : mutableInstrumentations;\n return (target, key, receiver) => {\n if (key === \"__v_isReactive\") {\n return !isReadonly;\n } else if (key === \"__v_isReadonly\") {\n return isReadonly;\n } else if (key === \"__v_raw\") {\n return target;\n }\n return Reflect.get(\n hasOwn(instrumentations, key) && key in target ? instrumentations : target,\n key,\n receiver\n );\n };\n}\nconst mutableCollectionHandlers = {\n get: /* @__PURE__ */ createInstrumentationGetter(false, false)\n};\nconst shallowCollectionHandlers = {\n get: /* @__PURE__ */ createInstrumentationGetter(false, true)\n};\nconst readonlyCollectionHandlers = {\n get: /* @__PURE__ */ createInstrumentationGetter(true, false)\n};\nconst shallowReadonlyCollectionHandlers = {\n get: /* @__PURE__ */ createInstrumentationGetter(true, true)\n};\nfunction checkIdentityKeys(target, has2, key) {\n const rawKey = toRaw(key);\n if (rawKey !== key && has2.call(target, rawKey)) {\n const type = toRawType(target);\n warn$2(\n `Reactive ${type} contains both the raw and reactive versions of the same object${type === `Map` ? ` as keys` : ``}, which can lead to inconsistencies. Avoid differentiating between the raw and reactive versions of an object and only use the reactive version if possible.`\n );\n }\n}\n\nconst reactiveMap = /* @__PURE__ */ new WeakMap();\nconst shallowReactiveMap = /* @__PURE__ */ new WeakMap();\nconst readonlyMap = /* @__PURE__ */ new WeakMap();\nconst shallowReadonlyMap = /* @__PURE__ */ new WeakMap();\nfunction targetTypeMap(rawType) {\n switch (rawType) {\n case \"Object\":\n case \"Array\":\n return 1 /* COMMON */;\n case \"Map\":\n case \"Set\":\n case \"WeakMap\":\n case \"WeakSet\":\n return 2 /* COLLECTION */;\n default:\n return 0 /* INVALID */;\n }\n}\nfunction getTargetType(value) {\n return value[\"__v_skip\"] || !Object.isExtensible(value) ? 0 /* INVALID */ : targetTypeMap(toRawType(value));\n}\nfunction reactive(target) {\n if (isReadonly(target)) {\n return target;\n }\n return createReactiveObject(\n target,\n false,\n mutableHandlers,\n mutableCollectionHandlers,\n reactiveMap\n );\n}\nfunction shallowReactive(target) {\n return createReactiveObject(\n target,\n false,\n shallowReactiveHandlers,\n shallowCollectionHandlers,\n shallowReactiveMap\n );\n}\nfunction readonly(target) {\n return createReactiveObject(\n target,\n true,\n readonlyHandlers,\n readonlyCollectionHandlers,\n readonlyMap\n );\n}\nfunction shallowReadonly(target) {\n return createReactiveObject(\n target,\n true,\n shallowReadonlyHandlers,\n shallowReadonlyCollectionHandlers,\n shallowReadonlyMap\n );\n}\nfunction createReactiveObject(target, isReadonly2, baseHandlers, collectionHandlers, proxyMap) {\n if (!isObject(target)) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$2(`value cannot be made reactive: ${String(target)}`);\n }\n return target;\n }\n if (target[\"__v_raw\"] && !(isReadonly2 && target[\"__v_isReactive\"])) {\n return target;\n }\n const existingProxy = proxyMap.get(target);\n if (existingProxy) {\n return existingProxy;\n }\n const targetType = getTargetType(target);\n if (targetType === 0 /* INVALID */) {\n return target;\n }\n const proxy = new Proxy(\n target,\n targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers\n );\n proxyMap.set(target, proxy);\n return proxy;\n}\nfunction isReactive(value) {\n if (isReadonly(value)) {\n return isReactive(value[\"__v_raw\"]);\n }\n return !!(value && value[\"__v_isReactive\"]);\n}\nfunction isReadonly(value) {\n return !!(value && value[\"__v_isReadonly\"]);\n}\nfunction isShallow(value) {\n return !!(value && value[\"__v_isShallow\"]);\n}\nfunction isProxy(value) {\n return isReactive(value) || isReadonly(value);\n}\nfunction toRaw(observed) {\n const raw = observed && observed[\"__v_raw\"];\n return raw ? toRaw(raw) : observed;\n}\nfunction markRaw(value) {\n if (Object.isExtensible(value)) {\n def(value, \"__v_skip\", true);\n }\n return value;\n}\nconst toReactive = (value) => isObject(value) ? reactive(value) : value;\nconst toReadonly = (value) => isObject(value) ? readonly(value) : value;\n\nconst COMPUTED_SIDE_EFFECT_WARN = `Computed is still dirty after getter evaluation, likely because a computed is mutating its own dependency in its getter. State mutations in computed getters should be avoided. Check the docs for more details: https://vuejs.org/guide/essentials/computed.html#getters-should-be-side-effect-free`;\nclass ComputedRefImpl {\n constructor(getter, _setter, isReadonly, isSSR) {\n this.getter = getter;\n this._setter = _setter;\n this.dep = void 0;\n this.__v_isRef = true;\n this[\"__v_isReadonly\"] = false;\n this.effect = new ReactiveEffect(\n () => getter(this._value),\n () => triggerRefValue(\n this,\n this.effect._dirtyLevel === 2 ? 2 : 3\n )\n );\n this.effect.computed = this;\n this.effect.active = this._cacheable = !isSSR;\n this[\"__v_isReadonly\"] = isReadonly;\n }\n get value() {\n const self = toRaw(this);\n if ((!self._cacheable || self.effect.dirty) && hasChanged(self._value, self._value = self.effect.run())) {\n triggerRefValue(self, 4);\n }\n trackRefValue(self);\n if (self.effect._dirtyLevel >= 2) {\n if (!!(process.env.NODE_ENV !== \"production\") && this._warnRecursive) {\n warn$2(COMPUTED_SIDE_EFFECT_WARN, `\n\ngetter: `, this.getter);\n }\n triggerRefValue(self, 2);\n }\n return self._value;\n }\n set value(newValue) {\n this._setter(newValue);\n }\n // #region polyfill _dirty for backward compatibility third party code for Vue <= 3.3.x\n get _dirty() {\n return this.effect.dirty;\n }\n set _dirty(v) {\n this.effect.dirty = v;\n }\n // #endregion\n}\nfunction computed$1(getterOrOptions, debugOptions, isSSR = false) {\n let getter;\n let setter;\n const onlyGetter = isFunction(getterOrOptions);\n if (onlyGetter) {\n getter = getterOrOptions;\n setter = !!(process.env.NODE_ENV !== \"production\") ? () => {\n warn$2(\"Write operation failed: computed value is readonly\");\n } : NOOP;\n } else {\n getter = getterOrOptions.get;\n setter = getterOrOptions.set;\n }\n const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR);\n if (!!(process.env.NODE_ENV !== \"production\") && debugOptions && !isSSR) {\n cRef.effect.onTrack = debugOptions.onTrack;\n cRef.effect.onTrigger = debugOptions.onTrigger;\n }\n return cRef;\n}\n\nfunction trackRefValue(ref2) {\n var _a;\n if (shouldTrack && activeEffect) {\n ref2 = toRaw(ref2);\n trackEffect(\n activeEffect,\n (_a = ref2.dep) != null ? _a : ref2.dep = createDep(\n () => ref2.dep = void 0,\n ref2 instanceof ComputedRefImpl ? ref2 : void 0\n ),\n !!(process.env.NODE_ENV !== \"production\") ? {\n target: ref2,\n type: \"get\",\n key: \"value\"\n } : void 0\n );\n }\n}\nfunction triggerRefValue(ref2, dirtyLevel = 4, newVal) {\n ref2 = toRaw(ref2);\n const dep = ref2.dep;\n if (dep) {\n triggerEffects(\n dep,\n dirtyLevel,\n !!(process.env.NODE_ENV !== \"production\") ? {\n target: ref2,\n type: \"set\",\n key: \"value\",\n newValue: newVal\n } : void 0\n );\n }\n}\nfunction isRef(r) {\n return !!(r && r.__v_isRef === true);\n}\nfunction ref(value) {\n return createRef(value, false);\n}\nfunction shallowRef(value) {\n return createRef(value, true);\n}\nfunction createRef(rawValue, shallow) {\n if (isRef(rawValue)) {\n return rawValue;\n }\n return new RefImpl(rawValue, shallow);\n}\nclass RefImpl {\n constructor(value, __v_isShallow) {\n this.__v_isShallow = __v_isShallow;\n this.dep = void 0;\n this.__v_isRef = true;\n this._rawValue = __v_isShallow ? value : toRaw(value);\n this._value = __v_isShallow ? value : toReactive(value);\n }\n get value() {\n trackRefValue(this);\n return this._value;\n }\n set value(newVal) {\n const useDirectValue = this.__v_isShallow || isShallow(newVal) || isReadonly(newVal);\n newVal = useDirectValue ? newVal : toRaw(newVal);\n if (hasChanged(newVal, this._rawValue)) {\n this._rawValue = newVal;\n this._value = useDirectValue ? newVal : toReactive(newVal);\n triggerRefValue(this, 4, newVal);\n }\n }\n}\nfunction triggerRef(ref2) {\n triggerRefValue(ref2, 4, !!(process.env.NODE_ENV !== \"production\") ? ref2.value : void 0);\n}\nfunction unref(ref2) {\n return isRef(ref2) ? ref2.value : ref2;\n}\nfunction toValue(source) {\n return isFunction(source) ? source() : unref(source);\n}\nconst shallowUnwrapHandlers = {\n get: (target, key, receiver) => unref(Reflect.get(target, key, receiver)),\n set: (target, key, value, receiver) => {\n const oldValue = target[key];\n if (isRef(oldValue) && !isRef(value)) {\n oldValue.value = value;\n return true;\n } else {\n return Reflect.set(target, key, value, receiver);\n }\n }\n};\nfunction proxyRefs(objectWithRefs) {\n return isReactive(objectWithRefs) ? objectWithRefs : new Proxy(objectWithRefs, shallowUnwrapHandlers);\n}\nclass CustomRefImpl {\n constructor(factory) {\n this.dep = void 0;\n this.__v_isRef = true;\n const { get, set } = factory(\n () => trackRefValue(this),\n () => triggerRefValue(this)\n );\n this._get = get;\n this._set = set;\n }\n get value() {\n return this._get();\n }\n set value(newVal) {\n this._set(newVal);\n }\n}\nfunction customRef(factory) {\n return new CustomRefImpl(factory);\n}\nfunction toRefs(object) {\n if (!!(process.env.NODE_ENV !== \"production\") && !isProxy(object)) {\n warn$2(`toRefs() expects a reactive object but received a plain one.`);\n }\n const ret = isArray(object) ? new Array(object.length) : {};\n for (const key in object) {\n ret[key] = propertyToRef(object, key);\n }\n return ret;\n}\nclass ObjectRefImpl {\n constructor(_object, _key, _defaultValue) {\n this._object = _object;\n this._key = _key;\n this._defaultValue = _defaultValue;\n this.__v_isRef = true;\n }\n get value() {\n const val = this._object[this._key];\n return val === void 0 ? this._defaultValue : val;\n }\n set value(newVal) {\n this._object[this._key] = newVal;\n }\n get dep() {\n return getDepFromReactive(toRaw(this._object), this._key);\n }\n}\nclass GetterRefImpl {\n constructor(_getter) {\n this._getter = _getter;\n this.__v_isRef = true;\n this.__v_isReadonly = true;\n }\n get value() {\n return this._getter();\n }\n}\nfunction toRef(source, key, defaultValue) {\n if (isRef(source)) {\n return source;\n } else if (isFunction(source)) {\n return new GetterRefImpl(source);\n } else if (isObject(source) && arguments.length > 1) {\n return propertyToRef(source, key, defaultValue);\n } else {\n return ref(source);\n }\n}\nfunction propertyToRef(source, key, defaultValue) {\n const val = source[key];\n return isRef(val) ? val : new ObjectRefImpl(source, key, defaultValue);\n}\n\nconst stack = [];\nfunction pushWarningContext(vnode) {\n stack.push(vnode);\n}\nfunction popWarningContext() {\n stack.pop();\n}\nfunction warn$1(msg, ...args) {\n pauseTracking();\n const instance = stack.length ? stack[stack.length - 1].component : null;\n const appWarnHandler = instance && instance.appContext.config.warnHandler;\n const trace = getComponentTrace();\n if (appWarnHandler) {\n callWithErrorHandling(\n appWarnHandler,\n instance,\n 11,\n [\n msg + args.map((a) => {\n var _a, _b;\n return (_b = (_a = a.toString) == null ? void 0 : _a.call(a)) != null ? _b : JSON.stringify(a);\n }).join(\"\"),\n instance && instance.proxy,\n trace.map(\n ({ vnode }) => `at <${formatComponentName(instance, vnode.type)}>`\n ).join(\"\\n\"),\n trace\n ]\n );\n } else {\n const warnArgs = [`[Vue warn]: ${msg}`, ...args];\n if (trace.length && // avoid spamming console during tests\n true) {\n warnArgs.push(`\n`, ...formatTrace(trace));\n }\n console.warn(...warnArgs);\n }\n resetTracking();\n}\nfunction getComponentTrace() {\n let currentVNode = stack[stack.length - 1];\n if (!currentVNode) {\n return [];\n }\n const normalizedStack = [];\n while (currentVNode) {\n const last = normalizedStack[0];\n if (last && last.vnode === currentVNode) {\n last.recurseCount++;\n } else {\n normalizedStack.push({\n vnode: currentVNode,\n recurseCount: 0\n });\n }\n const parentInstance = currentVNode.component && currentVNode.component.parent;\n currentVNode = parentInstance && parentInstance.vnode;\n }\n return normalizedStack;\n}\nfunction formatTrace(trace) {\n const logs = [];\n trace.forEach((entry, i) => {\n logs.push(...i === 0 ? [] : [`\n`], ...formatTraceEntry(entry));\n });\n return logs;\n}\nfunction formatTraceEntry({ vnode, recurseCount }) {\n const postfix = recurseCount > 0 ? `... (${recurseCount} recursive calls)` : ``;\n const isRoot = vnode.component ? vnode.component.parent == null : false;\n const open = ` at <${formatComponentName(\n vnode.component,\n vnode.type,\n isRoot\n )}`;\n const close = `>` + postfix;\n return vnode.props ? [open, ...formatProps(vnode.props), close] : [open + close];\n}\nfunction formatProps(props) {\n const res = [];\n const keys = Object.keys(props);\n keys.slice(0, 3).forEach((key) => {\n res.push(...formatProp(key, props[key]));\n });\n if (keys.length > 3) {\n res.push(` ...`);\n }\n return res;\n}\nfunction formatProp(key, value, raw) {\n if (isString(value)) {\n value = JSON.stringify(value);\n return raw ? value : [`${key}=${value}`];\n } else if (typeof value === \"number\" || typeof value === \"boolean\" || value == null) {\n return raw ? value : [`${key}=${value}`];\n } else if (isRef(value)) {\n value = formatProp(key, toRaw(value.value), true);\n return raw ? value : [`${key}=Ref<`, value, `>`];\n } else if (isFunction(value)) {\n return [`${key}=fn${value.name ? `<${value.name}>` : ``}`];\n } else {\n value = toRaw(value);\n return raw ? value : [`${key}=`, value];\n }\n}\n\nconst ErrorTypeStrings = {\n [\"sp\"]: \"serverPrefetch hook\",\n [\"bc\"]: \"beforeCreate hook\",\n [\"c\"]: \"created hook\",\n [\"bm\"]: \"beforeMount hook\",\n [\"m\"]: \"mounted hook\",\n [\"bu\"]: \"beforeUpdate hook\",\n [\"u\"]: \"updated\",\n [\"bum\"]: \"beforeUnmount hook\",\n [\"um\"]: \"unmounted hook\",\n [\"a\"]: \"activated hook\",\n [\"da\"]: \"deactivated hook\",\n [\"ec\"]: \"errorCaptured hook\",\n [\"rtc\"]: \"renderTracked hook\",\n [\"rtg\"]: \"renderTriggered hook\",\n [0]: \"setup function\",\n [1]: \"render function\",\n [2]: \"watcher getter\",\n [3]: \"watcher callback\",\n [4]: \"watcher cleanup function\",\n [5]: \"native event handler\",\n [6]: \"component event handler\",\n [7]: \"vnode hook\",\n [8]: \"directive hook\",\n [9]: \"transition hook\",\n [10]: \"app errorHandler\",\n [11]: \"app warnHandler\",\n [12]: \"ref function\",\n [13]: \"async component loader\",\n [14]: \"scheduler flush. This is likely a Vue internals bug. Please open an issue at https://github.com/vuejs/core .\"\n};\nfunction callWithErrorHandling(fn, instance, type, args) {\n try {\n return args ? fn(...args) : fn();\n } catch (err) {\n handleError(err, instance, type);\n }\n}\nfunction callWithAsyncErrorHandling(fn, instance, type, args) {\n if (isFunction(fn)) {\n const res = callWithErrorHandling(fn, instance, type, args);\n if (res && isPromise(res)) {\n res.catch((err) => {\n handleError(err, instance, type);\n });\n }\n return res;\n }\n const values = [];\n for (let i = 0; i < fn.length; i++) {\n values.push(callWithAsyncErrorHandling(fn[i], instance, type, args));\n }\n return values;\n}\nfunction handleError(err, instance, type, throwInDev = true) {\n const contextVNode = instance ? instance.vnode : null;\n if (instance) {\n let cur = instance.parent;\n const exposedInstance = instance.proxy;\n const errorInfo = !!(process.env.NODE_ENV !== \"production\") ? ErrorTypeStrings[type] || type : `https://vuejs.org/error-reference/#runtime-${type}`;\n while (cur) {\n const errorCapturedHooks = cur.ec;\n if (errorCapturedHooks) {\n for (let i = 0; i < errorCapturedHooks.length; i++) {\n if (errorCapturedHooks[i](err, exposedInstance, errorInfo) === false) {\n return;\n }\n }\n }\n cur = cur.parent;\n }\n const appErrorHandler = instance.appContext.config.errorHandler;\n if (appErrorHandler) {\n callWithErrorHandling(\n appErrorHandler,\n null,\n 10,\n [err, exposedInstance, errorInfo]\n );\n return;\n }\n }\n logError(err, type, contextVNode, throwInDev);\n}\nfunction logError(err, type, contextVNode, throwInDev = true) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n const info = ErrorTypeStrings[type] || type;\n if (contextVNode) {\n pushWarningContext(contextVNode);\n }\n warn$1(`Unhandled error${info ? ` during execution of ${info}` : ``}`);\n if (contextVNode) {\n popWarningContext();\n }\n if (throwInDev) {\n console.error(err);\n } else {\n console.error(err);\n }\n } else {\n console.error(err);\n }\n}\n\nlet isFlushing = false;\nlet isFlushPending = false;\nconst queue = [];\nlet flushIndex = 0;\nconst pendingPostFlushCbs = [];\nlet activePostFlushCbs = null;\nlet postFlushIndex = 0;\nconst resolvedPromise = /* @__PURE__ */ Promise.resolve();\nlet currentFlushPromise = null;\nconst RECURSION_LIMIT = 100;\nfunction nextTick$1(fn) {\n const p = currentFlushPromise || resolvedPromise;\n return fn ? p.then(this ? fn.bind(this) : fn) : p;\n}\nfunction findInsertionIndex(id) {\n let start = flushIndex + 1;\n let end = queue.length;\n while (start < end) {\n const middle = start + end >>> 1;\n const middleJob = queue[middle];\n const middleJobId = getId(middleJob);\n if (middleJobId < id || middleJobId === id && middleJob.pre) {\n start = middle + 1;\n } else {\n end = middle;\n }\n }\n return start;\n}\nfunction queueJob(job) {\n if (!queue.length || !queue.includes(\n job,\n isFlushing && job.allowRecurse ? flushIndex + 1 : flushIndex\n )) {\n if (job.id == null) {\n queue.push(job);\n } else {\n queue.splice(findInsertionIndex(job.id), 0, job);\n }\n queueFlush();\n }\n}\nfunction queueFlush() {\n if (!isFlushing && !isFlushPending) {\n isFlushPending = true;\n currentFlushPromise = resolvedPromise.then(flushJobs);\n }\n}\nfunction hasQueueJob(job) {\n return queue.indexOf(job) > -1;\n}\nfunction invalidateJob(job) {\n const i = queue.indexOf(job);\n if (i > flushIndex) {\n queue.splice(i, 1);\n }\n}\nfunction queuePostFlushCb(cb) {\n if (!isArray(cb)) {\n if (!activePostFlushCbs || !activePostFlushCbs.includes(\n cb,\n cb.allowRecurse ? postFlushIndex + 1 : postFlushIndex\n )) {\n pendingPostFlushCbs.push(cb);\n }\n } else {\n pendingPostFlushCbs.push(...cb);\n }\n queueFlush();\n}\nfunction flushPreFlushCbs(instance, seen, i = isFlushing ? flushIndex + 1 : 0) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n seen = seen || /* @__PURE__ */ new Map();\n }\n for (; i < queue.length; i++) {\n const cb = queue[i];\n if (cb && cb.pre) {\n if (!!(process.env.NODE_ENV !== \"production\") && checkRecursiveUpdates(seen, cb)) {\n continue;\n }\n queue.splice(i, 1);\n i--;\n cb();\n }\n }\n}\nfunction flushPostFlushCbs(seen) {\n if (pendingPostFlushCbs.length) {\n const deduped = [...new Set(pendingPostFlushCbs)].sort(\n (a, b) => getId(a) - getId(b)\n );\n pendingPostFlushCbs.length = 0;\n if (activePostFlushCbs) {\n activePostFlushCbs.push(...deduped);\n return;\n }\n activePostFlushCbs = deduped;\n if (!!(process.env.NODE_ENV !== \"production\")) {\n seen = seen || /* @__PURE__ */ new Map();\n }\n for (postFlushIndex = 0; postFlushIndex < activePostFlushCbs.length; postFlushIndex++) {\n if (!!(process.env.NODE_ENV !== \"production\") && checkRecursiveUpdates(seen, activePostFlushCbs[postFlushIndex])) {\n continue;\n }\n activePostFlushCbs[postFlushIndex]();\n }\n activePostFlushCbs = null;\n postFlushIndex = 0;\n }\n}\nconst getId = (job) => job.id == null ? Infinity : job.id;\nconst comparator = (a, b) => {\n const diff = getId(a) - getId(b);\n if (diff === 0) {\n if (a.pre && !b.pre)\n return -1;\n if (b.pre && !a.pre)\n return 1;\n }\n return diff;\n};\nfunction flushJobs(seen) {\n isFlushPending = false;\n isFlushing = true;\n if (!!(process.env.NODE_ENV !== \"production\")) {\n seen = seen || /* @__PURE__ */ new Map();\n }\n queue.sort(comparator);\n const check = !!(process.env.NODE_ENV !== \"production\") ? (job) => checkRecursiveUpdates(seen, job) : NOOP;\n try {\n for (flushIndex = 0; flushIndex < queue.length; flushIndex++) {\n const job = queue[flushIndex];\n if (job && job.active !== false) {\n if (!!(process.env.NODE_ENV !== \"production\") && check(job)) {\n continue;\n }\n callWithErrorHandling(job, null, 14);\n }\n }\n } finally {\n flushIndex = 0;\n queue.length = 0;\n flushPostFlushCbs(seen);\n isFlushing = false;\n currentFlushPromise = null;\n if (queue.length || pendingPostFlushCbs.length) {\n flushJobs(seen);\n }\n }\n}\nfunction checkRecursiveUpdates(seen, fn) {\n if (!seen.has(fn)) {\n seen.set(fn, 1);\n } else {\n const count = seen.get(fn);\n if (count > RECURSION_LIMIT) {\n const instance = fn.ownerInstance;\n const componentName = instance && getComponentName(instance.type);\n handleError(\n `Maximum recursive updates exceeded${componentName ? ` in component <${componentName}>` : ``}. This means you have a reactive effect that is mutating its own dependencies and thus recursively triggering itself. Possible sources include component template, render function, updated hook or watcher source function.`,\n null,\n 10\n );\n return true;\n } else {\n seen.set(fn, count + 1);\n }\n }\n}\n\nlet devtools;\nlet buffer = [];\nlet devtoolsNotInstalled = false;\nfunction emit$1(event, ...args) {\n if (devtools) {\n devtools.emit(event, ...args);\n } else if (!devtoolsNotInstalled) {\n buffer.push({ event, args });\n }\n}\nfunction setDevtoolsHook(hook, target) {\n var _a, _b;\n devtools = hook;\n if (devtools) {\n devtools.enabled = true;\n buffer.forEach(({ event, args }) => devtools.emit(event, ...args));\n buffer = [];\n } else if (\n // handle late devtools injection - only do this if we are in an actual\n // browser environment to avoid the timer handle stalling test runner exit\n // (#4815)\n typeof window !== \"undefined\" && // some envs mock window but not fully\n window.HTMLElement && // also exclude jsdom\n !((_b = (_a = window.navigator) == null ? void 0 : _a.userAgent) == null ? void 0 : _b.includes(\"jsdom\"))\n ) {\n const replay = target.__VUE_DEVTOOLS_HOOK_REPLAY__ = target.__VUE_DEVTOOLS_HOOK_REPLAY__ || [];\n replay.push((newHook) => {\n setDevtoolsHook(newHook, target);\n });\n setTimeout(() => {\n if (!devtools) {\n target.__VUE_DEVTOOLS_HOOK_REPLAY__ = null;\n devtoolsNotInstalled = true;\n buffer = [];\n }\n }, 3e3);\n } else {\n devtoolsNotInstalled = true;\n buffer = [];\n }\n}\nfunction devtoolsInitApp(app, version) {\n emit$1(\"app:init\" /* APP_INIT */, app, version, {\n Fragment,\n Text,\n Comment,\n Static\n });\n}\nconst devtoolsComponentAdded = /* @__PURE__ */ createDevtoolsComponentHook(\n \"component:added\" /* COMPONENT_ADDED */\n);\nconst devtoolsComponentUpdated = /* @__PURE__ */ createDevtoolsComponentHook(\"component:updated\" /* COMPONENT_UPDATED */);\nconst _devtoolsComponentRemoved = /* @__PURE__ */ createDevtoolsComponentHook(\n \"component:removed\" /* COMPONENT_REMOVED */\n);\nconst devtoolsComponentRemoved = (component) => {\n if (devtools && typeof devtools.cleanupBuffer === \"function\" && // remove the component if it wasn't buffered\n !devtools.cleanupBuffer(component)) {\n _devtoolsComponentRemoved(component);\n }\n};\n/*! #__NO_SIDE_EFFECTS__ */\n// @__NO_SIDE_EFFECTS__\nfunction createDevtoolsComponentHook(hook) {\n return (component) => {\n emit$1(\n hook,\n component.appContext.app,\n component.uid,\n // fixed by xxxxxx\n // 为 0 是 App,无 parent 是 Page 指向 App\n component.uid === 0 ? void 0 : component.parent ? component.parent.uid : 0,\n component\n );\n };\n}\nconst devtoolsPerfStart = /* @__PURE__ */ createDevtoolsPerformanceHook(\n \"perf:start\" /* PERFORMANCE_START */\n);\nconst devtoolsPerfEnd = /* @__PURE__ */ createDevtoolsPerformanceHook(\n \"perf:end\" /* PERFORMANCE_END */\n);\nfunction createDevtoolsPerformanceHook(hook) {\n return (component, type, time) => {\n emit$1(hook, component.appContext.app, component.uid, component, type, time);\n };\n}\nfunction devtoolsComponentEmit(component, event, params) {\n emit$1(\n \"component:emit\" /* COMPONENT_EMIT */,\n component.appContext.app,\n component,\n event,\n params\n );\n}\n\nfunction emit(instance, event, ...rawArgs) {\n if (instance.isUnmounted)\n return;\n const props = instance.vnode.props || EMPTY_OBJ;\n if (!!(process.env.NODE_ENV !== \"production\")) {\n const {\n emitsOptions,\n propsOptions: [propsOptions]\n } = instance;\n if (emitsOptions) {\n if (!(event in emitsOptions) && true) {\n if (!propsOptions || !(toHandlerKey(event) in propsOptions)) {\n warn$1(\n `Component emitted event \"${event}\" but it is neither declared in the emits option nor as an \"${toHandlerKey(event)}\" prop.`\n );\n }\n } else {\n const validator = emitsOptions[event];\n if (isFunction(validator)) {\n const isValid = validator(...rawArgs);\n if (!isValid) {\n warn$1(\n `Invalid event arguments: event validation failed for event \"${event}\".`\n );\n }\n }\n }\n }\n }\n let args = rawArgs;\n const isModelListener = event.startsWith(\"update:\");\n const modelArg = isModelListener && event.slice(7);\n if (modelArg && modelArg in props) {\n const modifiersKey = `${modelArg === \"modelValue\" ? \"model\" : modelArg}Modifiers`;\n const { number, trim } = props[modifiersKey] || EMPTY_OBJ;\n if (trim) {\n args = rawArgs.map((a) => isString(a) ? a.trim() : a);\n }\n if (number) {\n args = rawArgs.map(looseToNumber);\n }\n }\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n devtoolsComponentEmit(instance, event, args);\n }\n if (!!(process.env.NODE_ENV !== \"production\")) {\n const lowerCaseEvent = event.toLowerCase();\n if (lowerCaseEvent !== event && props[toHandlerKey(lowerCaseEvent)]) {\n warn$1(\n `Event \"${lowerCaseEvent}\" is emitted in component ${formatComponentName(\n instance,\n instance.type\n )} but the handler is registered for \"${event}\". Note that HTML attributes are case-insensitive and you cannot use v-on to listen to camelCase events when using in-DOM templates. You should probably use \"${hyphenate(\n event\n )}\" instead of \"${event}\".`\n );\n }\n }\n let handlerName;\n let handler = props[handlerName = toHandlerKey(event)] || // also try camelCase event handler (#2249)\n props[handlerName = toHandlerKey(camelize(event))];\n if (!handler && isModelListener) {\n handler = props[handlerName = toHandlerKey(hyphenate(event))];\n }\n if (handler) {\n callWithAsyncErrorHandling(\n handler,\n instance,\n 6,\n args\n );\n }\n const onceHandler = props[handlerName + `Once`];\n if (onceHandler) {\n if (!instance.emitted) {\n instance.emitted = {};\n } else if (instance.emitted[handlerName]) {\n return;\n }\n instance.emitted[handlerName] = true;\n callWithAsyncErrorHandling(\n onceHandler,\n instance,\n 6,\n args\n );\n }\n}\nfunction normalizeEmitsOptions(comp, appContext, asMixin = false) {\n const cache = appContext.emitsCache;\n const cached = cache.get(comp);\n if (cached !== void 0) {\n return cached;\n }\n const raw = comp.emits;\n let normalized = {};\n let hasExtends = false;\n if (__VUE_OPTIONS_API__ && !isFunction(comp)) {\n const extendEmits = (raw2) => {\n const normalizedFromExtend = normalizeEmitsOptions(raw2, appContext, true);\n if (normalizedFromExtend) {\n hasExtends = true;\n extend(normalized, normalizedFromExtend);\n }\n };\n if (!asMixin && appContext.mixins.length) {\n appContext.mixins.forEach(extendEmits);\n }\n if (comp.extends) {\n extendEmits(comp.extends);\n }\n if (comp.mixins) {\n comp.mixins.forEach(extendEmits);\n }\n }\n if (!raw && !hasExtends) {\n if (isObject(comp)) {\n cache.set(comp, null);\n }\n return null;\n }\n if (isArray(raw)) {\n raw.forEach((key) => normalized[key] = null);\n } else {\n extend(normalized, raw);\n }\n if (isObject(comp)) {\n cache.set(comp, normalized);\n }\n return normalized;\n}\nfunction isEmitListener(options, key) {\n if (!options || !isOn(key)) {\n return false;\n }\n key = key.slice(2).replace(/Once$/, \"\");\n return hasOwn(options, key[0].toLowerCase() + key.slice(1)) || hasOwn(options, hyphenate(key)) || hasOwn(options, key);\n}\n\nlet currentRenderingInstance = null;\nlet currentScopeId = null;\nfunction setCurrentRenderingInstance(instance) {\n const prev = currentRenderingInstance;\n currentRenderingInstance = instance;\n currentScopeId = instance && instance.type.__scopeId || null;\n return prev;\n}\nconst withScopeId = (_id) => withCtx;\nfunction withCtx(fn, ctx = currentRenderingInstance, isNonScopedSlot) {\n if (!ctx)\n return fn;\n if (fn._n) {\n return fn;\n }\n const renderFnWithContext = (...args) => {\n if (renderFnWithContext._d) {\n setBlockTracking(-1);\n }\n const prevInstance = setCurrentRenderingInstance(ctx);\n let res;\n try {\n res = fn(...args);\n } finally {\n setCurrentRenderingInstance(prevInstance);\n if (renderFnWithContext._d) {\n setBlockTracking(1);\n }\n }\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n devtoolsComponentUpdated(ctx);\n }\n return res;\n };\n renderFnWithContext._n = true;\n renderFnWithContext._c = true;\n renderFnWithContext._d = true;\n return renderFnWithContext;\n}\n\nfunction markAttrsAccessed() {\n}\n\nconst COMPONENTS = \"components\";\nconst DIRECTIVES = \"directives\";\nfunction resolveComponent(name, maybeSelfReference) {\n return resolveAsset(COMPONENTS, name, true, maybeSelfReference) || name;\n}\nconst NULL_DYNAMIC_COMPONENT = Symbol.for(\"v-ndc\");\nfunction resolveDirective(name) {\n return resolveAsset(DIRECTIVES, name);\n}\nfunction resolveAsset(type, name, warnMissing = true, maybeSelfReference = false) {\n const instance = currentRenderingInstance || currentInstance;\n if (instance) {\n const Component = instance.type;\n if (type === COMPONENTS) {\n const selfName = getComponentName(\n Component,\n false\n );\n if (selfName && (selfName === name || selfName === camelize(name) || selfName === capitalize(camelize(name)))) {\n return Component;\n }\n }\n const res = (\n // local registration\n // check instance[type] first which is resolved for options API\n resolve(instance[type] || Component[type], name) || // global registration\n resolve(instance.appContext[type], name)\n );\n if (!res && maybeSelfReference) {\n return Component;\n }\n if (!!(process.env.NODE_ENV !== \"production\") && warnMissing && !res) {\n const extra = type === COMPONENTS ? `\nIf this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement.` : ``;\n warn$1(`Failed to resolve ${type.slice(0, -1)}: ${name}${extra}`);\n }\n return res;\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\n `resolve${capitalize(type.slice(0, -1))} can only be used in render() or setup().`\n );\n }\n}\nfunction resolve(registry, name) {\n return registry && (registry[name] || registry[camelize(name)] || registry[capitalize(camelize(name))]);\n}\n\nconst ssrContextKey = Symbol.for(\"v-scx\");\nconst useSSRContext = () => {\n {\n const ctx = inject(ssrContextKey);\n if (!ctx) {\n !!(process.env.NODE_ENV !== \"production\") && warn$1(\n `Server rendering context not provided. Make sure to only call useSSRContext() conditionally in the server build.`\n );\n }\n return ctx;\n }\n};\n\nfunction watchEffect(effect, options) {\n return doWatch(effect, null, options);\n}\nfunction watchPostEffect(effect, options) {\n return doWatch(\n effect,\n null,\n !!(process.env.NODE_ENV !== \"production\") ? extend({}, options, { flush: \"post\" }) : { flush: \"post\" }\n );\n}\nfunction watchSyncEffect(effect, options) {\n return doWatch(\n effect,\n null,\n !!(process.env.NODE_ENV !== \"production\") ? extend({}, options, { flush: \"sync\" }) : { flush: \"sync\" }\n );\n}\nconst INITIAL_WATCHER_VALUE = {};\nfunction watch(source, cb, options) {\n if (!!(process.env.NODE_ENV !== \"production\") && !isFunction(cb)) {\n warn$1(\n `\\`watch(fn, options?)\\` signature has been moved to a separate API. Use \\`watchEffect(fn, options?)\\` instead. \\`watch\\` now only supports \\`watch(source, cb, options?) signature.`\n );\n }\n return doWatch(source, cb, options);\n}\nfunction doWatch(source, cb, {\n immediate,\n deep,\n flush,\n once,\n onTrack,\n onTrigger\n} = EMPTY_OBJ) {\n if (cb && once) {\n const _cb = cb;\n cb = (...args) => {\n _cb(...args);\n unwatch();\n };\n }\n if (!!(process.env.NODE_ENV !== \"production\") && deep !== void 0 && typeof deep === \"number\") {\n warn$1(\n `watch() \"deep\" option with number value will be used as watch depth in future versions. Please use a boolean instead to avoid potential breakage.`\n );\n }\n if (!!(process.env.NODE_ENV !== \"production\") && !cb) {\n if (immediate !== void 0) {\n warn$1(\n `watch() \"immediate\" option is only respected when using the watch(source, callback, options?) signature.`\n );\n }\n if (deep !== void 0) {\n warn$1(\n `watch() \"deep\" option is only respected when using the watch(source, callback, options?) signature.`\n );\n }\n if (once !== void 0) {\n warn$1(\n `watch() \"once\" option is only respected when using the watch(source, callback, options?) signature.`\n );\n }\n }\n const warnInvalidSource = (s) => {\n warn$1(\n `Invalid watch source: `,\n s,\n `A watch source can only be a getter/effect function, a ref, a reactive object, or an array of these types.`\n );\n };\n const instance = currentInstance;\n const reactiveGetter = (source2) => deep === true ? source2 : (\n // for deep: false, only traverse root-level properties\n traverse(source2, deep === false ? 1 : void 0)\n );\n let getter;\n let forceTrigger = false;\n let isMultiSource = false;\n if (isRef(source)) {\n getter = () => source.value;\n forceTrigger = isShallow(source);\n } else if (isReactive(source)) {\n getter = () => reactiveGetter(source);\n forceTrigger = true;\n } else if (isArray(source)) {\n isMultiSource = true;\n forceTrigger = source.some((s) => isReactive(s) || isShallow(s));\n getter = () => source.map((s) => {\n if (isRef(s)) {\n return s.value;\n } else if (isReactive(s)) {\n return reactiveGetter(s);\n } else if (isFunction(s)) {\n return callWithErrorHandling(s, instance, 2);\n } else {\n !!(process.env.NODE_ENV !== \"production\") && warnInvalidSource(s);\n }\n });\n } else if (isFunction(source)) {\n if (cb) {\n getter = () => callWithErrorHandling(source, instance, 2);\n } else {\n getter = () => {\n if (cleanup) {\n cleanup();\n }\n return callWithAsyncErrorHandling(\n source,\n instance,\n 3,\n [onCleanup]\n );\n };\n }\n } else {\n getter = NOOP;\n !!(process.env.NODE_ENV !== \"production\") && warnInvalidSource(source);\n }\n if (cb && deep) {\n const baseGetter = getter;\n getter = () => traverse(baseGetter());\n }\n let cleanup;\n let onCleanup = (fn) => {\n cleanup = effect.onStop = () => {\n callWithErrorHandling(fn, instance, 4);\n cleanup = effect.onStop = void 0;\n };\n };\n let oldValue = isMultiSource ? new Array(source.length).fill(INITIAL_WATCHER_VALUE) : INITIAL_WATCHER_VALUE;\n const job = () => {\n if (!effect.active || !effect.dirty) {\n return;\n }\n if (cb) {\n const newValue = effect.run();\n if (deep || forceTrigger || (isMultiSource ? newValue.some((v, i) => hasChanged(v, oldValue[i])) : hasChanged(newValue, oldValue)) || false) {\n if (cleanup) {\n cleanup();\n }\n callWithAsyncErrorHandling(cb, instance, 3, [\n newValue,\n // pass undefined as the old value when it's changed for the first time\n oldValue === INITIAL_WATCHER_VALUE ? void 0 : isMultiSource && oldValue[0] === INITIAL_WATCHER_VALUE ? [] : oldValue,\n onCleanup\n ]);\n oldValue = newValue;\n }\n } else {\n effect.run();\n }\n };\n job.allowRecurse = !!cb;\n let scheduler;\n if (flush === \"sync\") {\n scheduler = job;\n } else if (flush === \"post\") {\n scheduler = () => queuePostRenderEffect$1(job, instance && instance.suspense);\n } else {\n job.pre = true;\n if (instance)\n job.id = instance.uid;\n scheduler = () => queueJob(job);\n }\n const effect = new ReactiveEffect(getter, NOOP, scheduler);\n const scope = getCurrentScope();\n const unwatch = () => {\n effect.stop();\n if (scope) {\n remove(scope.effects, effect);\n }\n };\n if (!!(process.env.NODE_ENV !== \"production\")) {\n effect.onTrack = onTrack;\n effect.onTrigger = onTrigger;\n }\n if (cb) {\n if (immediate) {\n job();\n } else {\n oldValue = effect.run();\n }\n } else if (flush === \"post\") {\n queuePostRenderEffect$1(\n effect.run.bind(effect),\n instance && instance.suspense\n );\n } else {\n effect.run();\n }\n return unwatch;\n}\nfunction instanceWatch(source, value, options) {\n const publicThis = this.proxy;\n const getter = isString(source) ? source.includes(\".\") ? createPathGetter(publicThis, source) : () => publicThis[source] : source.bind(publicThis, publicThis);\n let cb;\n if (isFunction(value)) {\n cb = value;\n } else {\n cb = value.handler;\n options = value;\n }\n const reset = setCurrentInstance(this);\n const res = doWatch(getter, cb.bind(publicThis), options);\n reset();\n return res;\n}\nfunction createPathGetter(ctx, path) {\n const segments = path.split(\".\");\n return () => {\n let cur = ctx;\n for (let i = 0; i < segments.length && cur; i++) {\n cur = cur[segments[i]];\n }\n return cur;\n };\n}\nfunction traverse(value, depth, currentDepth = 0, seen) {\n if (!isObject(value) || value[\"__v_skip\"]) {\n return value;\n }\n if (depth && depth > 0) {\n if (currentDepth >= depth) {\n return value;\n }\n currentDepth++;\n }\n seen = seen || /* @__PURE__ */ new Set();\n if (seen.has(value)) {\n return value;\n }\n seen.add(value);\n if (isRef(value)) {\n traverse(value.value, depth, currentDepth, seen);\n } else if (isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n traverse(value[i], depth, currentDepth, seen);\n }\n } else if (isSet(value) || isMap(value)) {\n value.forEach((v) => {\n traverse(v, depth, currentDepth, seen);\n });\n } else if (isPlainObject(value)) {\n for (const key in value) {\n traverse(value[key], depth, currentDepth, seen);\n }\n }\n return value;\n}\n\nfunction validateDirectiveName(name) {\n if (isBuiltInDirective(name)) {\n warn$1(\"Do not use built-in directive ids as custom directive id: \" + name);\n }\n}\nfunction withDirectives(vnode, directives) {\n if (currentRenderingInstance === null) {\n !!(process.env.NODE_ENV !== \"production\") && warn$1(`withDirectives can only be used inside render functions.`);\n return vnode;\n }\n const instance = getExposeProxy(currentRenderingInstance) || currentRenderingInstance.proxy;\n const bindings = vnode.dirs || (vnode.dirs = []);\n for (let i = 0; i < directives.length; i++) {\n let [dir, value, arg, modifiers = EMPTY_OBJ] = directives[i];\n if (dir) {\n if (isFunction(dir)) {\n dir = {\n mounted: dir,\n updated: dir\n };\n }\n if (dir.deep) {\n traverse(value);\n }\n bindings.push({\n dir,\n instance,\n value,\n oldValue: void 0,\n arg,\n modifiers\n });\n }\n }\n return vnode;\n}\n\nfunction createAppContext() {\n return {\n app: null,\n config: {\n isNativeTag: NO,\n performance: false,\n globalProperties: {},\n optionMergeStrategies: {},\n errorHandler: void 0,\n warnHandler: void 0,\n compilerOptions: {}\n },\n mixins: [],\n components: {},\n directives: {},\n provides: /* @__PURE__ */ Object.create(null),\n optionsCache: /* @__PURE__ */ new WeakMap(),\n propsCache: /* @__PURE__ */ new WeakMap(),\n emitsCache: /* @__PURE__ */ new WeakMap()\n };\n}\nlet uid$1 = 0;\nfunction createAppAPI(render, hydrate) {\n return function createApp(rootComponent, rootProps = null) {\n if (!isFunction(rootComponent)) {\n rootComponent = extend({}, rootComponent);\n }\n if (rootProps != null && !isObject(rootProps)) {\n !!(process.env.NODE_ENV !== \"production\") && warn$1(`root props passed to app.mount() must be an object.`);\n rootProps = null;\n }\n const context = createAppContext();\n const installedPlugins = /* @__PURE__ */ new WeakSet();\n const app = context.app = {\n _uid: uid$1++,\n _component: rootComponent,\n _props: rootProps,\n _container: null,\n _context: context,\n _instance: null,\n version,\n get config() {\n return context.config;\n },\n set config(v) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\n `app.config cannot be replaced. Modify individual options instead.`\n );\n }\n },\n use(plugin, ...options) {\n if (installedPlugins.has(plugin)) {\n !!(process.env.NODE_ENV !== \"production\") && warn$1(`Plugin has already been applied to target app.`);\n } else if (plugin && isFunction(plugin.install)) {\n installedPlugins.add(plugin);\n plugin.install(app, ...options);\n } else if (isFunction(plugin)) {\n installedPlugins.add(plugin);\n plugin(app, ...options);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\n `A plugin must either be a function or an object with an \"install\" function.`\n );\n }\n return app;\n },\n mixin(mixin) {\n if (__VUE_OPTIONS_API__) {\n if (!context.mixins.includes(mixin)) {\n context.mixins.push(mixin);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\n \"Mixin has already been applied to target app\" + (mixin.name ? `: ${mixin.name}` : \"\")\n );\n }\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\"Mixins are only available in builds supporting Options API\");\n }\n return app;\n },\n component(name, component) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n validateComponentName(name, context.config);\n }\n if (!component) {\n return context.components[name];\n }\n if (!!(process.env.NODE_ENV !== \"production\") && context.components[name]) {\n warn$1(`Component \"${name}\" has already been registered in target app.`);\n }\n context.components[name] = component;\n return app;\n },\n directive(name, directive) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n validateDirectiveName(name);\n }\n if (!directive) {\n return context.directives[name];\n }\n if (!!(process.env.NODE_ENV !== \"production\") && context.directives[name]) {\n warn$1(`Directive \"${name}\" has already been registered in target app.`);\n }\n context.directives[name] = directive;\n return app;\n },\n // fixed by xxxxxx\n mount() {\n },\n // fixed by xxxxxx\n unmount() {\n },\n provide(key, value) {\n if (!!(process.env.NODE_ENV !== \"production\") && key in context.provides) {\n warn$1(\n `App already provides property with key \"${String(key)}\". It will be overwritten with the new value.`\n );\n }\n context.provides[key] = value;\n return app;\n },\n runWithContext(fn) {\n const lastApp = currentApp;\n currentApp = app;\n try {\n return fn();\n } finally {\n currentApp = lastApp;\n }\n }\n };\n return app;\n };\n}\nlet currentApp = null;\n\nfunction provide(key, value) {\n if (!currentInstance) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(`provide() can only be used inside setup().`);\n }\n } else {\n let provides = currentInstance.provides;\n const parentProvides = currentInstance.parent && currentInstance.parent.provides;\n if (parentProvides === provides) {\n provides = currentInstance.provides = Object.create(parentProvides);\n }\n provides[key] = value;\n if (currentInstance.type.mpType === \"app\") {\n currentInstance.appContext.app.provide(key, value);\n }\n }\n}\nfunction inject(key, defaultValue, treatDefaultAsFactory = false) {\n const instance = currentInstance || currentRenderingInstance;\n if (instance || currentApp) {\n const provides = instance ? instance.parent == null ? instance.vnode.appContext && instance.vnode.appContext.provides : instance.parent.provides : currentApp._context.provides;\n if (provides && key in provides) {\n return provides[key];\n } else if (arguments.length > 1) {\n return treatDefaultAsFactory && isFunction(defaultValue) ? defaultValue.call(instance && instance.proxy) : defaultValue;\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(`injection \"${String(key)}\" not found.`);\n }\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(`inject() can only be used inside setup() or functional components.`);\n }\n}\nfunction hasInjectionContext() {\n return !!(currentInstance || currentRenderingInstance || currentApp);\n}\n\n/*! #__NO_SIDE_EFFECTS__ */\n// @__NO_SIDE_EFFECTS__\nfunction defineComponent(options, extraOptions) {\n return isFunction(options) ? (\n // #8326: extend call and options.name access are considered side-effects\n // by Rollup, so we have to wrap it in a pure-annotated IIFE.\n /* @__PURE__ */ (() => extend({ name: options.name }, extraOptions, { setup: options }))()\n ) : options;\n}\n\nconst isKeepAlive = (vnode) => vnode.type.__isKeepAlive;\nfunction onActivated(hook, target) {\n registerKeepAliveHook(hook, \"a\", target);\n}\nfunction onDeactivated(hook, target) {\n registerKeepAliveHook(hook, \"da\", target);\n}\nfunction registerKeepAliveHook(hook, type, target = currentInstance) {\n const wrappedHook = hook.__wdc || (hook.__wdc = () => {\n let current = target;\n while (current) {\n if (current.isDeactivated) {\n return;\n }\n current = current.parent;\n }\n return hook();\n });\n injectHook(type, wrappedHook, target);\n if (target) {\n let current = target.parent;\n while (current && current.parent) {\n if (isKeepAlive(current.parent.vnode)) {\n injectToKeepAliveRoot(wrappedHook, type, target, current);\n }\n current = current.parent;\n }\n }\n}\nfunction injectToKeepAliveRoot(hook, type, target, keepAliveRoot) {\n const injected = injectHook(\n type,\n hook,\n keepAliveRoot,\n true\n /* prepend */\n );\n onUnmounted(() => {\n remove(keepAliveRoot[type], injected);\n }, target);\n}\n\nfunction injectHook(type, hook, target = currentInstance, prepend = false) {\n if (target) {\n if (isRootHook(type)) {\n target = target.root;\n }\n const hooks = target[type] || (target[type] = []);\n const wrappedHook = hook.__weh || (hook.__weh = (...args) => {\n if (target.isUnmounted) {\n return;\n }\n pauseTracking();\n const reset = setCurrentInstance(target);\n const res = callWithAsyncErrorHandling(hook, target, type, args);\n reset();\n resetTracking();\n return res;\n });\n if (prepend) {\n hooks.unshift(wrappedHook);\n } else {\n hooks.push(wrappedHook);\n }\n return wrappedHook;\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n const apiName = toHandlerKey(\n (ErrorTypeStrings[type] || type.replace(/^on/, \"\")).replace(/ hook$/, \"\")\n );\n warn$1(\n `${apiName} is called when there is no active component instance to be associated with. Lifecycle injection APIs can only be used during execution of setup().` + (``)\n );\n }\n}\nconst createHook = (lifecycle) => (hook, target = currentInstance) => (\n // post-create lifecycle registrations are noops during SSR (except for serverPrefetch)\n (!isInSSRComponentSetup || lifecycle === \"sp\") && injectHook(lifecycle, (...args) => hook(...args), target)\n);\nconst onBeforeMount = createHook(\"bm\");\nconst onMounted = createHook(\"m\");\nconst onBeforeUpdate = createHook(\"bu\");\nconst onUpdated = createHook(\"u\");\nconst onBeforeUnmount = createHook(\"bum\");\nconst onUnmounted = createHook(\"um\");\nconst onServerPrefetch = createHook(\"sp\");\nconst onRenderTriggered = createHook(\n \"rtg\"\n);\nconst onRenderTracked = createHook(\n \"rtc\"\n);\nfunction onErrorCaptured(hook, target = currentInstance) {\n injectHook(\"ec\", hook, target);\n}\n\nfunction toHandlers(obj, preserveCaseIfNecessary) {\n const ret = {};\n if (!!(process.env.NODE_ENV !== \"production\") && !isObject(obj)) {\n warn$1(`v-on with no argument expects an object value.`);\n return ret;\n }\n for (const key in obj) {\n ret[preserveCaseIfNecessary && /[A-Z]/.test(key) ? `on:${key}` : toHandlerKey(key)] = obj[key];\n }\n return ret;\n}\n\nconst getPublicInstance = (i) => {\n if (!i)\n return null;\n if (isStatefulComponent(i))\n return getExposeProxy(i) || i.proxy;\n return getPublicInstance(i.parent);\n};\nfunction getComponentInternalInstance(i) {\n return i;\n}\nconst publicPropertiesMap = (\n // Move PURE marker to new line to workaround compiler discarding it\n // due to type annotation\n /* @__PURE__ */ extend(/* @__PURE__ */ Object.create(null), {\n // fixed by xxxxxx\n $: getComponentInternalInstance,\n // fixed by xxxxxx vue-i18n 在 dev 模式,访问了 $el,故模拟一个假的\n // $el: i => i.vnode.el,\n $el: (i) => i.__$el || (i.__$el = {}),\n $data: (i) => i.data,\n $props: (i) => !!(process.env.NODE_ENV !== \"production\") ? shallowReadonly(i.props) : i.props,\n $attrs: (i) => !!(process.env.NODE_ENV !== \"production\") ? shallowReadonly(i.attrs) : i.attrs,\n $slots: (i) => !!(process.env.NODE_ENV !== \"production\") ? shallowReadonly(i.slots) : i.slots,\n $refs: (i) => !!(process.env.NODE_ENV !== \"production\") ? shallowReadonly(i.refs) : i.refs,\n $parent: (i) => getPublicInstance(i.parent),\n $root: (i) => getPublicInstance(i.root),\n $emit: (i) => i.emit,\n $options: (i) => __VUE_OPTIONS_API__ ? resolveMergedOptions(i) : i.type,\n $forceUpdate: (i) => i.f || (i.f = () => {\n i.effect.dirty = true;\n queueJob(i.update);\n }),\n // $nextTick: i => i.n || (i.n = nextTick.bind(i.proxy!)),// fixed by xxxxxx\n $watch: (i) => __VUE_OPTIONS_API__ ? instanceWatch.bind(i) : NOOP\n })\n);\nconst isReservedPrefix = (key) => key === \"_\" || key === \"$\";\nconst hasSetupBinding = (state, key) => state !== EMPTY_OBJ && !state.__isScriptSetup && hasOwn(state, key);\nconst PublicInstanceProxyHandlers = {\n get({ _: instance }, key) {\n const { ctx, setupState, data, props, accessCache, type, appContext } = instance;\n if (!!(process.env.NODE_ENV !== \"production\") && key === \"__isVue\") {\n return true;\n }\n let normalizedProps;\n if (key[0] !== \"$\") {\n const n = accessCache[key];\n if (n !== void 0) {\n switch (n) {\n case 1 /* SETUP */:\n return setupState[key];\n case 2 /* DATA */:\n return data[key];\n case 4 /* CONTEXT */:\n return ctx[key];\n case 3 /* PROPS */:\n return props[key];\n }\n } else if (hasSetupBinding(setupState, key)) {\n accessCache[key] = 1 /* SETUP */;\n return setupState[key];\n } else if (data !== EMPTY_OBJ && hasOwn(data, key)) {\n accessCache[key] = 2 /* DATA */;\n return data[key];\n } else if (\n // only cache other properties when instance has declared (thus stable)\n // props\n (normalizedProps = instance.propsOptions[0]) && hasOwn(normalizedProps, key)\n ) {\n accessCache[key] = 3 /* PROPS */;\n return props[key];\n } else if (ctx !== EMPTY_OBJ && hasOwn(ctx, key)) {\n accessCache[key] = 4 /* CONTEXT */;\n return ctx[key];\n } else if (!__VUE_OPTIONS_API__ || shouldCacheAccess) {\n accessCache[key] = 0 /* OTHER */;\n }\n }\n const publicGetter = publicPropertiesMap[key];\n let cssModule, globalProperties;\n if (publicGetter) {\n if (key === \"$attrs\") {\n track(instance, \"get\", key);\n !!(process.env.NODE_ENV !== \"production\") && markAttrsAccessed();\n } else if (!!(process.env.NODE_ENV !== \"production\") && key === \"$slots\") {\n track(instance, \"get\", key);\n }\n return publicGetter(instance);\n } else if (\n // css module (injected by vue-loader)\n (cssModule = type.__cssModules) && (cssModule = cssModule[key])\n ) {\n return cssModule;\n } else if (ctx !== EMPTY_OBJ && hasOwn(ctx, key)) {\n accessCache[key] = 4 /* CONTEXT */;\n return ctx[key];\n } else if (\n // global properties\n globalProperties = appContext.config.globalProperties, hasOwn(globalProperties, key)\n ) {\n {\n return globalProperties[key];\n }\n } else if (!!(process.env.NODE_ENV !== \"production\") && currentRenderingInstance && (!isString(key) || // #1091 avoid internal isRef/isVNode checks on component instance leading\n // to infinite warning loop\n key.indexOf(\"__v\") !== 0)) {\n if (data !== EMPTY_OBJ && isReservedPrefix(key[0]) && hasOwn(data, key)) {\n warn$1(\n `Property ${JSON.stringify(\n key\n )} must be accessed via $data because it starts with a reserved character (\"$\" or \"_\") and is not proxied on the render context.`\n );\n } else if (instance === currentRenderingInstance) {\n warn$1(\n `Property ${JSON.stringify(key)} was accessed during render but is not defined on instance.`\n );\n }\n }\n },\n set({ _: instance }, key, value) {\n const { data, setupState, ctx } = instance;\n if (hasSetupBinding(setupState, key)) {\n setupState[key] = value;\n return true;\n } else if (!!(process.env.NODE_ENV !== \"production\") && setupState.__isScriptSetup && hasOwn(setupState, key)) {\n warn$1(`Cannot mutate \r\n\r\n\r\n","import Component from 'D:/Project/Self/优艺家沙发翻新/优艺家沙发翻新/components/before-after/before-after.uvue'\nwx.createComponent(Component)"],"names":["uni","Component"],"mappings":";;;;;;;;;;AAwCC,UAAM,QAAQ;AAOd,UAAM,eAAe,CAAC,KAAc,SAAa;AAChD,YAAM,OAAO,QAAQ,WAAW,CAAC,MAAM,WAAW,IAAI,CAAC,MAAM,UAAU;AACvEA,oBAAAA,MAAI,aAAa;AAAA,QAChB,SAAS;AAAA,QACT;AAAA,MACA,CAAA;AAAA,IACF;;;;;;;;;;;;;;;;;;;;ACpDD,GAAG,gBAAgBC,SAAS;"} \ No newline at end of file +{"version":3,"file":"before-after.js","sources":["components/before-after/before-after.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RDovUHJvamVjdC9TZWxmL-S8mOiJuuWutuaymeWPkee_u-aWsC_liY3nq68vY29tcG9uZW50cy9iZWZvcmUtYWZ0ZXIvYmVmb3JlLWFmdGVyLnV2dWU"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\t翻新前后对比\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t翻新前\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t→\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t翻新后\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import Component from 'D:/Project/Self/优艺家沙发翻新/前端/components/before-after/before-after.uvue'\nwx.createComponent(Component)"],"names":["uni","Component"],"mappings":";;;;;;;;;;AAwCC,UAAM,QAAQ;AAOd,UAAM,eAAe,CAAC,KAAc,SAAa;AAChD,YAAM,OAAO,QAAQ,WAAW,CAAC,MAAM,WAAW,IAAI,CAAC,MAAM,UAAU;AACvEA,oBAAAA,MAAI,aAAa;AAAA,QAChB,SAAS;AAAA,QACT;AAAA,MACA,CAAA;AAAA,IACF;;;;;;;;;;;;;;;;;;;;ACpDD,GAAG,gBAAgBC,SAAS;"} \ No newline at end of file diff --git a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/components/case-card/case-card.js.map b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/components/case-card/case-card.js.map index fe924ae..14404ec 100644 --- a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/components/case-card/case-card.js.map +++ b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/components/case-card/case-card.js.map @@ -1 +1 @@ -{"version":3,"file":"case-card.js","sources":["components/case-card/case-card.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RDovUHJvamVjdC9TZWxmL-S8mOiJuuWutuaymeWPkee_u-aWsC_kvJjoibrlrrbmspnlj5Hnv7vmlrAvY29tcG9uZW50cy9jYXNlLWNhcmQvY2FzZS1jYXJkLnV2dWU"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t{{ caseData.categoryName }}\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t{{ caseData.title }}\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t材质:\r\n\t\t\t\t\t{{ caseData.material }}\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t工期:\r\n\t\t\t\t\t{{ caseData.duration }}\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t{{ caseData.price }}\r\n\t\t\t\t\r\n\t\t\t\t\t👁 {{ caseData.views }}\r\n\t\t\t\t\t❤ {{ caseData.likes }}\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import Component from 'D:/Project/Self/优艺家沙发翻新/优艺家沙发翻新/components/case-card/case-card.uvue'\nwx.createComponent(Component)"],"names":["Component"],"mappings":";;MAsCM,iBAAQ,IAAA,QAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAab,UAAM,QAAQ;AAId,UAAM,OAAO;AAIb,UAAM,cAAc,MAAA;AACnB,WAAK,SAAS,MAAM,SAAS,EAAE;AAAA,IAChC;;;;;;;;;;;;;;;;;;;AC5DD,GAAG,gBAAgBA,SAAS;"} \ No newline at end of file +{"version":3,"file":"case-card.js","sources":["components/case-card/case-card.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RDovUHJvamVjdC9TZWxmL-S8mOiJuuWutuaymeWPkee_u-aWsC_liY3nq68vY29tcG9uZW50cy9jYXNlLWNhcmQvY2FzZS1jYXJkLnV2dWU"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t{{ caseData.categoryName }}\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t{{ caseData.title }}\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t材质:\r\n\t\t\t\t\t{{ caseData.material }}\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t工期:\r\n\t\t\t\t\t{{ caseData.duration }}\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t{{ caseData.price }}\r\n\t\t\t\t\r\n\t\t\t\t\t👁 {{ caseData.views }}\r\n\t\t\t\t\t❤ {{ caseData.likes }}\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import Component from 'D:/Project/Self/优艺家沙发翻新/前端/components/case-card/case-card.uvue'\nwx.createComponent(Component)"],"names":["Component"],"mappings":";;MAsCM,iBAAQ,IAAA,QAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAab,UAAM,QAAQ;AAId,UAAM,OAAO;AAIb,UAAM,cAAc,MAAA;AACnB,WAAK,SAAS,MAAM,SAAS,EAAE;AAAA,IAChC;;;;;;;;;;;;;;;;;;;AC5DD,GAAG,gBAAgBA,SAAS;"} \ No newline at end of file diff --git a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/components/nav-bar/nav-bar.js.map b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/components/nav-bar/nav-bar.js.map index 5985f7f..c9fd920 100644 --- a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/components/nav-bar/nav-bar.js.map +++ b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/components/nav-bar/nav-bar.js.map @@ -1 +1 @@ -{"version":3,"file":"nav-bar.js","sources":["components/nav-bar/nav-bar.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RDovUHJvamVjdC9TZWxmL-S8mOiJuuWutuaymeWPkee_u-aWsC_kvJjoibrlrrbmspnlj5Hnv7vmlrAvY29tcG9uZW50cy9uYXYtYmFyL25hdi1iYXIudXZ1ZQ"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t←\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t{{ title }}\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import Component from 'D:/Project/Self/优艺家沙发翻新/优艺家沙发翻新/components/nav-bar/nav-bar.uvue'\nwx.createComponent(Component)"],"names":["ref","onMounted","uni","Component"],"mappings":";;;;;;;;;;;AAkCC,UAAM,kBAAkBA,kBAAI,EAAE;AAE9B,UAAM,eAAeA,kBAAI,EAAE;AAE3BC,kBAAAA,UAAU,MAAA;AACT,YAAM,UAAUC,oBAAI;AACpB,sBAAgB,QAAQ,QAAQ;AAEhC,YAAM,iBAAiBA,oBAAI;AAC3B,mBAAa,SAAS,eAAe,MAAM,QAAQ,mBAAmB,IAAI,eAAe;AAAA,IAE1F,CAAC;AAED,UAAM,aAAa,MAAA;AAClBA,0BAAI,aAAa,IAAA,cAAA;AAAA,QAChB,MAAM,MAAA;AACLA,wBAAAA,MAAI,UAAU;AAAA,YACb,KAAK;AAAA,UACL,CAAA;AAAA,QACF;AAAA,MACA,CAAA,CAAA;AAAA,IACF;;;;;;;;;;;;;;;;;;ACtDD,GAAG,gBAAgBC,SAAS;"} \ No newline at end of file +{"version":3,"file":"nav-bar.js","sources":["components/nav-bar/nav-bar.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RDovUHJvamVjdC9TZWxmL-S8mOiJuuWutuaymeWPkee_u-aWsC_liY3nq68vY29tcG9uZW50cy9uYXYtYmFyL25hdi1iYXIudXZ1ZQ"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t←\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t{{ title }}\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import Component from 'D:/Project/Self/优艺家沙发翻新/前端/components/nav-bar/nav-bar.uvue'\nwx.createComponent(Component)"],"names":["ref","onMounted","uni","Component"],"mappings":";;;;;;;;;;;AAkCC,UAAM,kBAAkBA,kBAAI,EAAE;AAE9B,UAAM,eAAeA,kBAAI,EAAE;AAE3BC,kBAAAA,UAAU,MAAA;AACT,YAAM,UAAUC,oBAAI;AACpB,sBAAgB,QAAQ,QAAQ;AAEhC,YAAM,iBAAiBA,oBAAI;AAC3B,mBAAa,SAAS,eAAe,MAAM,QAAQ,mBAAmB,IAAI,eAAe;AAAA,IAE1F,CAAC;AAED,UAAM,aAAa,MAAA;AAClBA,0BAAI,aAAa,IAAA,cAAA;AAAA,QAChB,MAAM,MAAA;AACLA,wBAAAA,MAAI,UAAU;AAAA,YACb,KAAK;AAAA,UACL,CAAA;AAAA,QACF;AAAA,MACA,CAAA,CAAA;AAAA,IACF;;;;;;;;;;;;;;;;;;ACtDD,GAAG,gBAAgBC,SAAS;"} \ No newline at end of file diff --git a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/components/section-header/section-header.js.map b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/components/section-header/section-header.js.map index a59d553..65a127e 100644 --- a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/components/section-header/section-header.js.map +++ b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/components/section-header/section-header.js.map @@ -1 +1 @@ -{"version":3,"file":"section-header.js","sources":["components/section-header/section-header.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RDovUHJvamVjdC9TZWxmL-S8mOiJuuWutuaymeWPkee_u-aWsC_kvJjoibrlrrbmspnlj5Hnv7vmlrAvY29tcG9uZW50cy9zZWN0aW9uLWhlYWRlci9zZWN0aW9uLWhlYWRlci51dnVl"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t{{ title }}\r\n\t\t\r\n\t\t\r\n\t\t\t查看更多\r\n\t\t\t›\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import Component from 'D:/Project/Self/优艺家沙发翻新/优艺家沙发翻新/components/section-header/section-header.uvue'\nwx.createComponent(Component)"],"names":["Component"],"mappings":";;;;;;;;;;;AAmBC,UAAM,OAAO;AAIb,UAAM,aAAa,MAAA;AAClB,WAAK,MAAM;AAAA,IACZ;;;;;;;;;;;;;;;ACxBD,GAAG,gBAAgBA,SAAS;"} \ No newline at end of file +{"version":3,"file":"section-header.js","sources":["components/section-header/section-header.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RDovUHJvamVjdC9TZWxmL-S8mOiJuuWutuaymeWPkee_u-aWsC_liY3nq68vY29tcG9uZW50cy9zZWN0aW9uLWhlYWRlci9zZWN0aW9uLWhlYWRlci51dnVl"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t{{ title }}\r\n\t\t\r\n\t\t\r\n\t\t\t查看更多\r\n\t\t\t›\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import Component from 'D:/Project/Self/优艺家沙发翻新/前端/components/section-header/section-header.uvue'\nwx.createComponent(Component)"],"names":["Component"],"mappings":";;;;;;;;;;;AAmBC,UAAM,OAAO;AAIb,UAAM,aAAa,MAAA;AAClB,WAAK,MAAM;AAAA,IACZ;;;;;;;;;;;;;;;ACxBD,GAAG,gBAAgBA,SAAS;"} \ No newline at end of file diff --git a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/components/service-card/service-card.js.map b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/components/service-card/service-card.js.map index 5bed8fa..2780b25 100644 --- a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/components/service-card/service-card.js.map +++ b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/components/service-card/service-card.js.map @@ -1 +1 @@ -{"version":3,"file":"service-card.js","sources":["components/service-card/service-card.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RDovUHJvamVjdC9TZWxmL-S8mOiJuuWutuaymeWPkee_u-aWsC_kvJjoibrlrrbmspnlj5Hnv7vmlrAvY29tcG9uZW50cy9zZXJ2aWNlLWNhcmQvc2VydmljZS1jYXJkLnV2dWU"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t{{ name }}\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import Component from 'D:/Project/Self/优艺家沙发翻新/优艺家沙发翻新/components/service-card/service-card.uvue'\nwx.createComponent(Component)"],"names":["Component"],"mappings":";;;;;;;;;;;;AAUC,UAAM,QAAQ;AAMd,UAAM,OAAO;AAIb,UAAM,cAAc,MAAA;AACnB,WAAK,SAAS,MAAM,EAAE;AAAA,IACvB;;;;;;;;;;;;;ACrBD,GAAG,gBAAgBA,SAAS;"} \ No newline at end of file +{"version":3,"file":"service-card.js","sources":["components/service-card/service-card.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RDovUHJvamVjdC9TZWxmL-S8mOiJuuWutuaymeWPkee_u-aWsC_liY3nq68vY29tcG9uZW50cy9zZXJ2aWNlLWNhcmQvc2VydmljZS1jYXJkLnV2dWU"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t{{ name }}\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import Component from 'D:/Project/Self/优艺家沙发翻新/前端/components/service-card/service-card.uvue'\nwx.createComponent(Component)"],"names":["Component"],"mappings":";;;;;;;;;;;;AAUC,UAAM,QAAQ;AAMd,UAAM,OAAO;AAIb,UAAM,cAAc,MAAA;AACnB,WAAK,SAAS,MAAM,EAAE;AAAA,IACvB;;;;;;;;;;;;;ACrBD,GAAG,gBAAgBA,SAAS;"} \ No newline at end of file diff --git a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/about/index.js.map b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/about/index.js.map index ef32c70..80e896e 100644 --- a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/about/index.js.map +++ b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/about/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sources":["pages/about/index.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvYWJvdXQvaW5kZXgudXZ1ZQ"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t优艺家\r\n\t\t\t\t\r\n\t\t\t\t{{ companyInfo.name }}\r\n\t\t\t\t{{ companyInfo.slogan }}\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t{{ companyInfo.description }}\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t✓\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t{{ item.title }}\r\n\t\t\t\t\t\t{{ item.desc }}\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t📞\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t客服电话\r\n\t\t\t\t\t\t\t{{ companyInfo.phone }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t›\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t💬\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t微信号\r\n\t\t\t\t\t\t\t{{ companyInfo.wechat }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t›\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t📍\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t公司地址\r\n\t\t\t\t\t\t\t{{ companyInfo.address }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t›\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t🕐\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t营业时间\r\n\t\t\t\t\t\t\t{{ companyInfo.workTime }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'D:/Project/Self/优艺家沙发翻新/优艺家沙发翻新/pages/about/index.uvue'\nwx.createPage(MiniProgramPage)"],"names":["ref","__awaiter","getCompanyInfo","uni","onLoad","MiniProgramPage"],"mappings":";;;;;;;;;;;MA6FM,oBAAW,IAAA,QAAA;AAAA;;;;;;;;;;;;;;;;;;;;MAMX,oBAAW,IAAA,QAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAYhB,UAAM,cAAcA,kBAAiB,IAAA,YAAA;AAAA,MACpC,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,UAAU;AAAA,MACV,UAAU,CAAE;AAAA,IACZ,CAAA,CAAA;AAGD,UAAM,mBAAmB,MAAA;AAAA,aAAAC,cAAA,UAAA,MAAA,QAAA,QAAA,aAAA;AACxB,YAAI;AACH,gBAAM,MAAM,MAAMC,UAAAA;AAClB,gBAAM,OAAO,IAAI;AAEjB,gBAAM,eAAe,KAAK,UAAU;AACpC,gBAAM,WAAW,aAAa,IAAI,CAAC,SAAI;AACtC,mBAAO,IAAA,YAAA;AAAA,cACN,OAAO,KAAK,OAAO;AAAA,cACnB,MAAM,KAAK,MAAM;AAAA,aACF;AAAA,UACjB,CAAC;AAED,sBAAY,QAAQ,IAAA,YAAA;AAAA,YACnB,MAAM,KAAK,MAAM;AAAA,YACjB,QAAQ,KAAK,QAAQ;AAAA,YACrB,aAAa,KAAK,aAAa;AAAA,YAC/B,OAAO,KAAK,OAAO;AAAA,YACnB,QAAQ,KAAK,QAAQ;AAAA,YACrB,SAAS,KAAK,SAAS;AAAA,YACvB,UAAU,KAAK,UAAU;AAAA,YACzB;AAAA,UACe,CAAA;AAAA,QAChB,SAAQ,GAAG;AACXC,wBAAG,MAAC,MAAM,SAAQ,iCAAgC,YAAY,CAAC;AAAA,QAC/D;AAAA,MACD,CAAA;AAAA;AAGD,UAAM,YAAY,MAAA;AACjBA,oBAAAA,MAAI,cAAc;AAAA,QACjB,aAAa,YAAY,MAAM;AAAA,QAC/B,MAAM,MAAA;AACLA,wBAAAA,MAAI,UAAU;AAAA,YACb,OAAO;AAAA,YACP,MAAM;AAAA,UACN,CAAA;AAAA,QACF;AAAA,MACA,CAAA;AAAA,IACF;AAGA,UAAM,aAAa,MAAA;AAClBA,oBAAAA,MAAI,iBAAiB;AAAA,QACpB,MAAM,YAAY,MAAM;AAAA,QACxB,SAAS,MAAA;AACRA,wBAAAA,MAAI,UAAU;AAAA,YACb,OAAO;AAAA,YACP,MAAM;AAAA,UACN,CAAA;AAAA,QACF;AAAA,MACA,CAAA;AAAA,IACF;AAGA,UAAM,eAAe,MAAA;AACpBA,oBAAAA,MAAI,aAAa;AAAA,QAChB,UAAU;AAAA,QACV,WAAW;AAAA,QACX,MAAM,YAAY,MAAM;AAAA,QACxB,SAAS,YAAY,MAAM;AAAA,QAC3B,MAAM,MAAA;AACLA,wBAAAA,MAAI,UAAU;AAAA,YACb,OAAO;AAAA,YACP,MAAM;AAAA,UACN,CAAA;AAAA,QACF;AAAA,MACA,CAAA;AAAA,IACF;AAEAC,kBAAAA,OAAO,MAAA;AACN;IACD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClMF,GAAG,WAAWC,SAAe;"} \ No newline at end of file +{"version":3,"file":"index.js","sources":["pages/about/index.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvYWJvdXQvaW5kZXgudXZ1ZQ"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t优艺家\r\n\t\t\t\t\r\n\t\t\t\t{{ companyInfo.name }}\r\n\t\t\t\t{{ companyInfo.slogan }}\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t{{ companyInfo.description }}\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t✓\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t{{ item.title }}\r\n\t\t\t\t\t\t{{ item.desc }}\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t📞\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t客服电话\r\n\t\t\t\t\t\t\t{{ companyInfo.phone }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t›\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t💬\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t微信号\r\n\t\t\t\t\t\t\t{{ companyInfo.wechat }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t›\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t📍\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t公司地址\r\n\t\t\t\t\t\t\t{{ companyInfo.address }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t›\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t🕐\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t营业时间\r\n\t\t\t\t\t\t\t{{ companyInfo.workTime }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'D:/Project/Self/优艺家沙发翻新/前端/pages/about/index.uvue'\nwx.createPage(MiniProgramPage)"],"names":["ref","__awaiter","getCompanyInfo","uni","onLoad","MiniProgramPage"],"mappings":";;;;;;;;;;;MA6FM,oBAAW,IAAA,QAAA;AAAA;;;;;;;;;;;;;;;;;;;;MAMX,oBAAW,IAAA,QAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAYhB,UAAM,cAAcA,kBAAiB,IAAA,YAAA;AAAA,MACpC,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,UAAU;AAAA,MACV,UAAU,CAAE;AAAA,IACZ,CAAA,CAAA;AAGD,UAAM,mBAAmB,MAAA;AAAA,aAAAC,cAAA,UAAA,MAAA,QAAA,QAAA,aAAA;AACxB,YAAI;AACH,gBAAM,MAAM,MAAMC,UAAAA;AAClB,gBAAM,OAAO,IAAI;AAEjB,gBAAM,eAAe,KAAK,UAAU;AACpC,gBAAM,WAAW,aAAa,IAAI,CAAC,SAAI;AACtC,mBAAO,IAAA,YAAA;AAAA,cACN,OAAO,KAAK,OAAO;AAAA,cACnB,MAAM,KAAK,MAAM;AAAA,aACF;AAAA,UACjB,CAAC;AAED,sBAAY,QAAQ,IAAA,YAAA;AAAA,YACnB,MAAM,KAAK,MAAM;AAAA,YACjB,QAAQ,KAAK,QAAQ;AAAA,YACrB,aAAa,KAAK,aAAa;AAAA,YAC/B,OAAO,KAAK,OAAO;AAAA,YACnB,QAAQ,KAAK,QAAQ;AAAA,YACrB,SAAS,KAAK,SAAS;AAAA,YACvB,UAAU,KAAK,UAAU;AAAA,YACzB;AAAA,UACe,CAAA;AAAA,QAChB,SAAQ,GAAG;AACXC,wBAAG,MAAC,MAAM,SAAQ,iCAAgC,YAAY,CAAC;AAAA,QAC/D;AAAA,MACD,CAAA;AAAA;AAGD,UAAM,YAAY,MAAA;AACjBA,oBAAAA,MAAI,cAAc;AAAA,QACjB,aAAa,YAAY,MAAM;AAAA,QAC/B,MAAM,MAAA;AACLA,wBAAAA,MAAI,UAAU;AAAA,YACb,OAAO;AAAA,YACP,MAAM;AAAA,UACN,CAAA;AAAA,QACF;AAAA,MACA,CAAA;AAAA,IACF;AAGA,UAAM,aAAa,MAAA;AAClBA,oBAAAA,MAAI,iBAAiB;AAAA,QACpB,MAAM,YAAY,MAAM;AAAA,QACxB,SAAS,MAAA;AACRA,wBAAAA,MAAI,UAAU;AAAA,YACb,OAAO;AAAA,YACP,MAAM;AAAA,UACN,CAAA;AAAA,QACF;AAAA,MACA,CAAA;AAAA,IACF;AAGA,UAAM,eAAe,MAAA;AACpBA,oBAAAA,MAAI,aAAa;AAAA,QAChB,UAAU;AAAA,QACV,WAAW;AAAA,QACX,MAAM,YAAY,MAAM;AAAA,QACxB,SAAS,YAAY,MAAM;AAAA,QAC3B,MAAM,MAAA;AACLA,wBAAAA,MAAI,UAAU;AAAA,YACb,OAAO;AAAA,YACP,MAAM;AAAA,UACN,CAAA;AAAA,QACF;AAAA,MACA,CAAA;AAAA,IACF;AAEAC,kBAAAA,OAAO,MAAA;AACN;IACD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClMF,GAAG,WAAWC,SAAe;"} \ No newline at end of file diff --git a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/booking/index.js.map b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/booking/index.js.map index ff3d2a3..6d7eb5f 100644 --- a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/booking/index.js.map +++ b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/booking/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sources":["pages/booking/index.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvYm9va2luZy9pbmRleC51dnVl"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t预约翻新服务\r\n\t\t\t\t填写以下信息,我们会尽快与您联系\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t*\r\n\t\t\t\t\t\t您的姓名\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t*\r\n\t\t\t\t\t\t联系电话\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t*\r\n\t\t\t\t\t\t您的地址\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t沙发类型\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ item.name }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t问题描述\r\n\t\t\t\t\t\r\n\t\t\t\t\t{{ formData.problem.length }}/500\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t上传图片(可选)\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t×\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t+\r\n\t\t\t\t\t\t\t添加图片\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t最多可上传9张图片\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t提交预约\r\n\t\t\t\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'D:/Project/Self/优艺家沙发翻新/优艺家沙发翻新/pages/booking/index.uvue'\nwx.createPage(MiniProgramPage)"],"names":["ref","SOFA_CATEGORIES","uni","__awaiter","submitBooking","onLoad","MiniProgramPage"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sources":["pages/booking/index.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvYm9va2luZy9pbmRleC51dnVl"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t预约翻新服务\r\n\t\t\t\t填写以下信息,我们会尽快与您联系\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t*\r\n\t\t\t\t\t\t您的姓名\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t*\r\n\t\t\t\t\t\t联系电话\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t*\r\n\t\t\t\t\t\t您的地址\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t*\r\n\t\t\t\t\t\t服务类型\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ item.name }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t*\r\n\t\t\t\t\t\t预约时间\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ formData.appointmentDate }}\r\n\t\t\t\t\t\t\t请选择预约日期\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t问题描述\r\n\t\t\t\t\t\r\n\t\t\t\t\t{{ formData.problem.length }}/500\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t上传图片(可选)\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t×\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t+\r\n\t\t\t\t\t\t\t添加图片\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t提示:当前仅支持预览,图片暂不会上传到服务器\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t提交预约\r\n\t\t\t\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'D:/Project/Self/优艺家沙发翻新/前端/pages/booking/index.uvue'\nwx.createPage(MiniProgramPage)"],"names":["ref","__awaiter","getActiveServices","uni","submitBooking","onLoad","MiniProgramPage"],"mappings":"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"} \ No newline at end of file diff --git a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/cases/detail.js.map b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/cases/detail.js.map index c951aa2..49b4f51 100644 --- a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/cases/detail.js.map +++ b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/cases/detail.js.map @@ -1 +1 @@ -{"version":3,"file":"detail.js","sources":["pages/cases/detail.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvY2FzZXMvZGV0YWlsLnV2dWU"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t{{ caseDetail.categoryName }}\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t{{ caseDetail.title }}\r\n\t\t\t\t\r\n\t\t\t\t\t{{ caseDetail.price }}\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t👁 {{ caseDetail.views }}\r\n\t\t\t\t\t\t❤ {{ caseDetail.likes }}\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t翻新详情\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t使用材质\r\n\t\t\t\t\t\t{{ caseDetail.material }}\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t翻新工期\r\n\t\t\t\t\t\t{{ caseDetail.duration }}\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t完成日期\r\n\t\t\t\t\t\t{{ caseDetail.createTime }}\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t案例描述\r\n\t\t\t\t\t{{ caseDetail.description }}\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t{{ isFavorite ? '❤️' : '🤍' }}\r\n\t\t\t\t\t收藏\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t📤\r\n\t\t\t\t\t分享\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t在线咨询\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t立即预约\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'D:/Project/Self/优艺家沙发翻新/优艺家沙发翻新/pages/cases/detail.uvue'\nwx.createPage(MiniProgramPage)"],"names":["ref","__awaiter","getCaseDetail","uni","onLoad","MiniProgramPage"],"mappings":";;;;;;;;;;;MA0GM,mBAAU,IAAA,QAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiBf,UAAM,SAASA,kBAAI,EAAE;AAGrB,UAAM,aAAaA,kBAAgB,IAAA,WAAA;AAAA,MAClC,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,UAAU;AAAA,MACV,cAAc;AAAA,MACd,cAAc,CAAE;AAAA,MAChB,aAAa,CAAE;AAAA,MACf,aAAa;AAAA,MACb,UAAU;AAAA,MACV,UAAU;AAAA,MACV,OAAO;AAAA,MACP,OAAO;AAAA,MACP,OAAO;AAAA,MACP,YAAY;AAAA,IACZ,CAAA,CAAA;AAGD,UAAM,aAAaA,kBAAI,KAAK;AAG5B,UAAM,kBAAkB,MAAA;AAAA,aAAAC,cAAA,UAAA,MAAA,QAAA,QAAA,aAAA;AACvB,YAAI;AACH,gBAAM,MAAM,MAAMC,UAAAA,cAAc,OAAO,KAAK;AAC5C,gBAAM,OAAO,IAAI;AAEjB,qBAAW,QAAQ,IAAA;AAAA,YAAA;AAAA,cAClB,IAAI,KAAK,IAAI;AAAA,cACb,OAAO,KAAK,OAAO;AAAA,cACnB,UAAU,KAAK,UAAU;AAAA,cACzB,cAAc,KAAK,cAAc;AAAA,cACjC,cAAc,KAAK,cAAc;AAAA,cACjC,aAAa,KAAK,aAAa;AAAA,cAC/B,aAAa,KAAK,aAAa;AAAA,cAC/B,UAAU,KAAK,UAAU;AAAA,cACzB,UAAU,KAAK,UAAU;AAAA,cACzB,OAAO,KAAK,OAAO;AAAA,cACnB,OAAO,KAAK,OAAO;AAAA,cACnB,OAAO,KAAK,OAAO;AAAA,cACnB,YAAY,KAAK,YAAY;AAAA,YACf;AAAA;AAAA;AAGfC,wBAAAA,MAAI,sBAAsB;AAAA,YACzB,OAAO,WAAW,MAAM;AAAA,UACxB,CAAA;AAAA,QACD,SAAQ,GAAG;AACXA,wBAAG,MAAC,MAAM,SAAQ,kCAAiC,YAAY,CAAC;AAAA,QAChE;AAAA,MACD,CAAA;AAAA;AAGD,UAAM,gBAAgB,CAAC,UAAc;AACpCA,oBAAAA,MAAI,aAAa;AAAA,QAChB,SAAS;AAAA,QACT,MAAM,WAAW,MAAM;AAAA,MACvB,CAAA;AAAA,IACF;AAGA,UAAM,iBAAiB,MAAA;AACtB,iBAAW,QAAQ,CAAC,WAAW;AAC/BA,oBAAAA,MAAI,UAAU;AAAA,QACb,OAAO,WAAW,QAAQ,QAAQ;AAAA,QAClC,MAAM;AAAA,MACN,CAAA;AAAA,IACF;AAGA,UAAM,cAAc,MAAA;AAInBA,oBAAAA,MAAI,UAAU;AAAA,QACb,OAAO;AAAA,QACP,MAAM;AAAA,MACN,CAAA;AAAA,IACF;AAGA,UAAM,gBAAgB,MAAA;AACrBA,oBAAAA,MAAI,cAAc;AAAA,QACjB,aAAa;AAAA,QACb,MAAM,MAAA;AACLA,wBAAAA,MAAI,UAAU;AAAA,YACb,OAAO;AAAA,YACP,MAAM;AAAA,UACN,CAAA;AAAA,QACF;AAAA,MACA,CAAA;AAAA,IACF;AAGA,UAAM,cAAc,MAAA;AACnBA,oBAAAA,MAAI,WAAW;AAAA,QACd,KAAK;AAAA,MACL,CAAA;AAAA,IACF;AAEAC,kBAAM,OAAC,CAAC,YAAuB;;AAC9B,aAAO,SAAQ,KAAA,QAAQ,IAAI,OAAK,QAAA,OAAA,SAAA,KAAA;AAChC,UAAI,OAAO,SAAS,IAAI;AACvB;MACA;AAAA,IACF,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpOF,GAAG,WAAWC,SAAe;"} \ No newline at end of file +{"version":3,"file":"detail.js","sources":["pages/cases/detail.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvY2FzZXMvZGV0YWlsLnV2dWU"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t{{ caseDetail.categoryName }}\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t{{ caseDetail.title }}\r\n\t\t\t\t\r\n\t\t\t\t\t{{ caseDetail.price }}\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t👁 {{ caseDetail.views }}\r\n\t\t\t\t\t\t❤ {{ caseDetail.likes }}\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t翻新详情\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t使用材质\r\n\t\t\t\t\t\t{{ caseDetail.material }}\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t翻新工期\r\n\t\t\t\t\t\t{{ caseDetail.duration }}\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t完成日期\r\n\t\t\t\t\t\t{{ caseDetail.createTime }}\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t案例描述\r\n\t\t\t\t\t{{ caseDetail.description }}\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t{{ isFavorite ? '❤️' : '🤍' }}\r\n\t\t\t\t\t收藏\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t📤\r\n\t\t\t\t\t分享\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t在线咨询\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t立即预约\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'D:/Project/Self/优艺家沙发翻新/前端/pages/cases/detail.uvue'\nwx.createPage(MiniProgramPage)"],"names":["ref","__awaiter","getCaseDetail","getServiceTypeName","uni","onLoad","MiniProgramPage"],"mappings":"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"} \ No newline at end of file diff --git a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/cases/list.js.map b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/cases/list.js.map index 807cb46..1dcd2c0 100644 --- a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/cases/list.js.map +++ b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/cases/list.js.map @@ -1 +1 @@ -{"version":3,"file":"list.js","sources":["pages/cases/list.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvY2FzZXMvbGlzdC51dnVl"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t{{ item.name }}\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t加载中...\r\n\t\t\t\t没有更多了\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t📭\r\n\t\t\t\t暂无相关案例\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'D:/Project/Self/优艺家沙发翻新/优艺家沙发翻新/pages/cases/list.uvue'\nwx.createPage(MiniProgramPage)"],"names":["ref","SOFA_CATEGORIES","__awaiter","PAGE_SIZE","getCaseList","uni","onLoad","MiniProgramPage"],"mappings":";;;;;;;;;;;;MA4DM,qBAAY,IAAA,QAAA;AAAA;;;;;;;;;;;;;;;;;;;;MAMZ,iBAAQ,IAAA,QAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAcb,UAAM,aAAaA,kBAAoB,CAAA,CAAE;AAGzC,UAAM,kBAAkBA,kBAAI,KAAK;AAGjC,UAAM,WAAWA,kBAAgB,CAAA,CAAE;AAGnC,UAAM,OAAOA,kBAAI,CAAC;AAClB,UAAM,QAAQA,kBAAI,CAAC;AAGnB,UAAM,UAAUA,kBAAI,KAAK;AACzB,UAAM,SAASA,kBAAI,KAAK;AAGxB,UAAM,iBAAiB,MAAA;AACtB,iBAAW,QAAQC,aAAAA,gBAAgB,IAAI,CAAC,SAAI;AAC3C,eAAO,IAAA,aAAA;AAAA,UACN,IAAI,KAAK;AAAA,UACT,MAAM,KAAK;AAAA,SACK;AAAA,MAClB,CAAC;AAAA,IACF;AAGA,UAAM,iBAAiB,CAAC,OAAW;AAClC,UAAI,gBAAgB,SAAS;AAAI,eAAM;AACvC,sBAAgB,QAAQ;AACxB,WAAK,QAAQ;AACb,eAAS,QAAQ;AACjB,aAAO,QAAQ;AACf;IACD;AAGA,UAAM,gBAAgB,MAAA;AAAA,aAAAC,cAAA,UAAA,MAAA,QAAA,QAAA,aAAA;AACrB,YAAI,QAAQ,SAAS,OAAO;AAAO,iBAAM,QAAA,QAAA,IAAA;AAEzC,gBAAQ,QAAQ;AAChB,YAAI;AACH,gBAAM,SAAS,IAAA,cAAA;AAAA,YACd,UAAU,gBAAgB;AAAA,YAC1B,MAAM,KAAK;AAAA,YACX,UAAUC,aAAS;AAAA,UACF,CAAA;AAElB,gBAAM,MAAM,MAAMC,sBAAY,MAAM;AACpC,gBAAM,OAAO,IAAI;AAEjB,gBAAM,OAAO,KAAK,OAAO,KAAwB,CAAA;AACjD,gBAAM,QAAQ,KAAK,OAAO,KAAe;AAEzC,gBAAM,UAAU,KAAK,IAAI,CAAC,SAAI;AAC7B,mBAAO,IAAA,SAAA;AAAA,cACN,IAAI,KAAK,IAAI;AAAA,cACb,OAAO,KAAK,OAAO;AAAA,cACnB,UAAU,KAAK,UAAU;AAAA,cACzB,cAAc,KAAK,cAAc;AAAA,cACjC,YAAY,KAAK,YAAY;AAAA,cAC7B,UAAU,KAAK,UAAU;AAAA,cACzB,UAAU,KAAK,UAAU;AAAA,cACzB,OAAO,KAAK,OAAO;AAAA,cACnB,OAAO,KAAK,OAAO;AAAA,cACnB,OAAO,KAAK,OAAO;AAAA,aACP;AAAA,UACd,CAAC;AAED,cAAI,KAAK,SAAS,GAAG;AACpB,qBAAS,QAAQ;AAAA,UACjB,OAAM;AACN,qBAAS,QAAQ,CAAC,GAAG,SAAS,OAAO,GAAG,OAAO;AAAA,UAC/C;AAED,cAAI,SAAS,MAAM,UAAU,MAAM,OAAO;AACzC,mBAAO,QAAQ;AAAA,UACf;AAAA,QACD,SAAQ,GAAG;AACXC,wBAAG,MAAC,MAAM,SAAQ,gCAA+B,YAAY,CAAC;AAAA,QAC9D;AACD,gBAAQ,QAAQ;AAAA,MAChB,CAAA;AAAA;AAGD,UAAM,WAAW,MAAA;AAChB,UAAI,CAAC,OAAO,SAAS,CAAC,QAAQ,OAAO;AACpC,aAAK;AACL;MACA;AAAA,IACF;AAGA,UAAM,aAAa,CAAC,OAAW;AAC9BA,oBAAAA,MAAI,WAAW;AAAA,QACd,KAAK,0BAA0B,EAAE;AAAA,MACjC,CAAA;AAAA,IACF;AAEAC,kBAAAA,OAAO,MAAA;AACN;AACA;IACD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrLF,GAAG,WAAWC,SAAe;"} \ No newline at end of file +{"version":3,"file":"list.js","sources":["pages/cases/list.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvY2FzZXMvbGlzdC51dnVl"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t{{ item.name }}\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t加载中...\r\n\t\t\t\t没有更多了\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t📭\r\n\t\t\t\t暂无相关案例\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'D:/Project/Self/优艺家沙发翻新/前端/pages/cases/list.uvue'\nwx.createPage(MiniProgramPage)"],"names":["ref","SOFA_CATEGORIES","uni","__awaiter","PAGE_SIZE","getCaseList","getServiceTypeName","onLoad","MiniProgramPage"],"mappings":"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"} \ No newline at end of file diff --git a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/index.js.map b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/index.js.map index 06aaf35..2862f31 100644 --- a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/index.js.map +++ b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sources":["pages/index/index.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvaW5kZXgvaW5kZXgudXZ1ZQ"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t{{ item.icon }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ item.title }}\r\n\t\t\t\t\t\t\t{{ item.desc }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t免费上门评估\r\n\t\t\t\t\t\t专业师傅免费上门,为您的沙发量身定制翻新方案\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t立即预约\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'D:/Project/Self/优艺家沙发翻新/优艺家沙发翻新/pages/index/index.uvue'\nwx.createPage(MiniProgramPage)"],"names":["ref","SERVICE_TYPES","__awaiter","getBanners","uni","getHotCases","onLoad","MiniProgramPage"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sources":["pages/index/index.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvaW5kZXgvaW5kZXgudXZ1ZQ"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t{{ item.icon }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ item.title }}\r\n\t\t\t\t\t\t\t{{ item.desc }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t免费上门评估\r\n\t\t\t\t\t\t专业师傅免费上门,为您的沙发量身定制翻新方案\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t立即预约\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'D:/Project/Self/优艺家沙发翻新/前端/pages/index/index.uvue'\nwx.createPage(MiniProgramPage)"],"names":["ref","__awaiter","getActiveServices","uni","getBanners","getHotCases","getServiceTypeName","onLoad","MiniProgramPage"],"mappings":"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"} \ No newline at end of file diff --git a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/service/index.js.map b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/service/index.js.map index 91f6c9d..05d26e3 100644 --- a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/service/index.js.map +++ b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/service/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sources":["pages/service/index.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvc2VydmljZS9pbmRleC51dnVl"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t专业沙发翻新服务\r\n\t\t\t\t\t让旧沙发焕发新生\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ item.emoji }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t{{ item.name }}\r\n\t\t\t\t\t\t{{ item.desc }}\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ item.step }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ item.title }}\r\n\t\t\t\t\t\t\t{{ item.description }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ item.name }}\r\n\t\t\t\t\t\t\t{{ item.price }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t{{ item.desc }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ tag }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ item.question }}\r\n\t\t\t\t\t\t\t{{ item.expanded ? '−' : '+' }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ item.answer }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t免费上门评估\r\n\t\t\t\t专业师傅为您量身定制方案\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t立即预约\r\n\t\t\t\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'D:/Project/Self/优艺家沙发翻新/优艺家沙发翻新/pages/service/index.uvue'\nwx.createPage(MiniProgramPage)"],"names":["ref","__awaiter","getServiceProcess","uni","onLoad","MiniProgramPage"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sources":["pages/service/index.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvc2VydmljZS9pbmRleC51dnVl"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t专业沙发翻新服务\r\n\t\t\t\t\t让旧沙发焕发新生\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ item.emoji }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t{{ item.name }}\r\n\t\t\t\t\t\t{{ item.desc }}\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ item.step }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ item.title }}\r\n\t\t\t\t\t\t\t{{ item.description }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ item.name }}\r\n\t\t\t\t\t\t\t{{ item.price }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t{{ item.desc }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ tag }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ item.question }}\r\n\t\t\t\t\t\t\t{{ item.expanded ? '−' : '+' }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ item.answer }}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t免费上门评估\r\n\t\t\t\t专业师傅为您量身定制方案\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t立即预约\r\n\t\t\t\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'D:/Project/Self/优艺家沙发翻新/前端/pages/service/index.uvue'\nwx.createPage(MiniProgramPage)"],"names":["ref","__awaiter","getActiveServices","uni","onLoad","MiniProgramPage"],"mappings":"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"} \ No newline at end of file diff --git a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/user/index.js.map b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/user/index.js.map index 13ffe94..875b1e3 100644 --- a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/user/index.js.map +++ b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/pages/user/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sources":["pages/user/index.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvdXNlci9pbmRleC51dnVl"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t{{ userInfo.nickName || '点击登录' }}\r\n\t\t\t\t\t\t{{ userInfo.phone }}\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t登录\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t📋\r\n\t\t\t\t\t\t\t我的预约\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t 0\">{{ bookingCount }}\r\n\t\t\t\t\t\t\t›\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t❤️\r\n\t\t\t\t\t\t\t我的收藏\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t 0\">{{ favoriteCount }}\r\n\t\t\t\t\t\t\t›\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t🏠\r\n\t\t\t\t\t\t\t关于我们\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t›\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t📞\r\n\t\t\t\t\t\t\t联系客服\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t400-888-8888\r\n\t\t\t\t\t\t\t›\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t💬\r\n\t\t\t\t\t\t\t意见反馈\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t›\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t🔄\r\n\t\t\t\t\t\t\t检查更新\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\tv1.0.0\r\n\t\t\t\t\t\t\t›\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t🧹\r\n\t\t\t\t\t\t\t清除缓存\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ cacheSize }}\r\n\t\t\t\t\t\t\t›\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t退出登录\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'D:/Project/Self/优艺家沙发翻新/优艺家沙发翻新/pages/user/index.uvue'\nwx.createPage(MiniProgramPage)"],"names":["ref","uni","STORAGE_KEYS","onShow","MiniProgramPage"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sources":["pages/user/index.uvue","../../../../Soft/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvdXNlci9pbmRleC51dnVl"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t{{ userInfo.nickName || '点击登录' }}\r\n\t\t\t\t\t\t{{ userInfo.phone }}\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t登录\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t📋\r\n\t\t\t\t\t\t\t我的预约\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t 0\">{{ bookingCount }}\r\n\t\t\t\t\t\t\t›\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t❤️\r\n\t\t\t\t\t\t\t我的收藏\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t 0\">{{ favoriteCount }}\r\n\t\t\t\t\t\t\t›\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t🏠\r\n\t\t\t\t\t\t\t关于我们\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t›\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t📞\r\n\t\t\t\t\t\t\t联系客服\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t400-888-8888\r\n\t\t\t\t\t\t\t›\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t💬\r\n\t\t\t\t\t\t\t意见反馈\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t›\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t🔄\r\n\t\t\t\t\t\t\t检查更新\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\tv1.0.0\r\n\t\t\t\t\t\t\t›\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t🧹\r\n\t\t\t\t\t\t\t清除缓存\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{{ cacheSize }}\r\n\t\t\t\t\t\t\t›\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t退出登录\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'D:/Project/Self/优艺家沙发翻新/前端/pages/user/index.uvue'\nwx.createPage(MiniProgramPage)"],"names":["ref","uni","STORAGE_KEYS","__awaiter","wechatLogin","onShow","MiniProgramPage"],"mappings":"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"} \ No newline at end of file diff --git a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/utils/config.js.map b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/utils/config.js.map index 12885b3..0864f07 100644 --- a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/utils/config.js.map +++ b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/utils/config.js.map @@ -1 +1 @@ -{"version":3,"file":"config.js","sources":["utils/config.uts"],"sourcesContent":["/**\r\n * 项目配置文件\r\n */\r\n\r\n// 环境配置\r\nexport const ENV = {\r\n\t// 开发环境\r\n\tdevelopment: {\r\n\t\tbaseUrl: 'http://localhost:3000/api',\r\n\t\timageBaseUrl: 'http://localhost:3000'\r\n\t},\r\n\t// 生产环境\r\n\tproduction: {\r\n\t\tbaseUrl: 'https://api.youyijia.com/api',\r\n\t\timageBaseUrl: 'https://api.youyijia.com'\r\n\t}\r\n}\r\n\r\n// 当前环境 - 切换为 'production' 上线\r\nexport const currentEnv = 'development'\r\n\r\n// 获取当前环境配置\r\nexport const getEnvConfig = () : UTSJSONObject => {\r\n\tif (currentEnv == 'production') {\r\n\t\treturn {\r\n\t\t\tbaseUrl: ENV.production.baseUrl,\r\n\t\t\timageBaseUrl: ENV.production.imageBaseUrl\r\n\t\t} as UTSJSONObject\r\n\t}\r\n\treturn {\r\n\t\tbaseUrl: ENV.development.baseUrl,\r\n\t\timageBaseUrl: ENV.development.imageBaseUrl\r\n\t} as UTSJSONObject\r\n}\r\n\r\n// 是否使用Mock数据 - 已关闭,对接真实后端\r\nexport const useMock = false\r\n\r\n// 分页配置\r\nexport const PAGE_SIZE = 10\r\n\r\n// 图片上传配置\r\nexport const UPLOAD_CONFIG = {\r\n\tmaxSize: 5 * 1024 * 1024, // 5MB\r\n\tmaxCount: 9,\r\n\taccept: ['image/jpeg', 'image/png', 'image/gif']\r\n}\r\n\r\n// 缓存Key\r\nexport const STORAGE_KEYS = {\r\n\tTOKEN: 'user_token',\r\n\tUSER_INFO: 'user_info',\r\n\tFAVORITES: 'user_favorites',\r\n\tSEARCH_HISTORY: 'search_history'\r\n}\r\n\r\n// 沙发分类\r\nexport const SOFA_CATEGORIES = [\r\n\t{ id: 'all', name: '全部' },\r\n\t{ id: 'leather', name: '皮沙发' },\r\n\t{ id: 'fabric', name: '布艺沙发' },\r\n\t{ id: 'functional', name: '功能沙发' },\r\n\t{ id: 'antique', name: '古典沙发' },\r\n\t{ id: 'office', name: '办公沙发' }\r\n]\r\n\r\n// 翻新服务类型\r\nexport const SERVICE_TYPES = [\r\n\t{ id: 'repair', name: '局部修复', icon: '/static/icons/repair.png' },\r\n\t{ id: 'recolor', name: '改色翻新', icon: '/static/icons/recolor.png' },\r\n\t{ id: 'refurbish', name: '整体翻新', icon: '/static/icons/refurbish.png' },\r\n\t{ id: 'custom', name: '定制换皮', icon: '/static/icons/custom.png' }\r\n]\r\n"],"names":[],"mappings":";AAKO,MAAM,MAAM,IAAA;AAAA,EAAA;AAAA;AAAA,IAElB,aAAa,IAAA,cAAA;AAAA,MACZ,SAAS;AAAA,MACT,cAAc;AAAA,KACd;AAAA;AAAA,IAED,YAAY,IAAA,cAAA;AAAA,MACX,SAAS;AAAA,MACT,cAAc;AAAA,KACd;AAAA,EACD;AAAA;;AAMY,MAAA,eAAe,MAAA;AAO3B,SAAO,IAAA,cAAA;AAAA,IACN,SAAS,IAAI,YAAY;AAAA,IACzB,cAAc,IAAI,YAAY;AAAA,GACb;AACnB;AAMO,MAAM,YAAY;AAGI,IAAA;AAAA,EAAA;AAAA,IAC5B,SAAS,IAAI,OAAO;AAAA,IACpB,UAAU;AAAA,IACV,QAAQ,CAAC,cAAc,aAAa,WAAW;AAAA,EAC/C;AAAA;;AAGY,MAAA,eAAe,IAAA;AAAA,EAAA;AAAA,IAC3B,OAAO;AAAA,IACP,WAAW;AAAA,IACX,WAAW;AAAA,IACX,gBAAgB;AAAA,EAChB;AAAA;;AAGY,MAAA,kBAAkB;AAAA,EAC9B,IAAA,cAAA,EAAE,IAAI,OAAO,MAAM,KAAI,CAAE;AAAA,EACzB,IAAA,cAAA,EAAE,IAAI,WAAW,MAAM,MAAK,CAAE;AAAA,EAC9B,IAAA,cAAA,EAAE,IAAI,UAAU,MAAM,OAAM,CAAE;AAAA,EAC9B,IAAA,cAAA,EAAE,IAAI,cAAc,MAAM,OAAM,CAAE;AAAA,EAClC,IAAA,cAAA,EAAE,IAAI,WAAW,MAAM,OAAM,CAAE;AAAA,EAC/B,IAAA,cAAA,EAAE,IAAI,UAAU,MAAM,OAAM,CAAE;;AAIlB,MAAA,gBAAgB;AAAA,oBAC5B,EAAE,IAAI,UAAU,MAAM,QAAQ,MAAM,4BAA4B;AAAA,oBAChE,EAAE,IAAI,WAAW,MAAM,QAAQ,MAAM,6BAA6B;AAAA,oBAClE,EAAE,IAAI,aAAa,MAAM,QAAQ,MAAM,+BAA+B;AAAA,oBACtE,EAAE,IAAI,UAAU,MAAM,QAAQ,MAAM,4BAA4B;;;;;;;"} \ No newline at end of file +{"version":3,"file":"config.js","sources":["utils/config.uts"],"sourcesContent":["/**\r\n * 项目配置文件\r\n */\r\n\r\n// 环境配置\r\nexport const ENV = {\r\n\t// 开发环境\r\n\tdevelopment: {\r\n\t\tbaseUrl: 'http://192.168.1.43:3000/api',\r\n\t\timageBaseUrl: 'http://192.168.1.43:3000'\r\n\t},\r\n\t// 生产环境\r\n\tproduction: {\r\n\t\tbaseUrl: 'https://api.youyijia.com/api',\r\n\t\timageBaseUrl: 'https://api.youyijia.com'\r\n\t}\r\n}\r\n\r\n// 当前环境 - 切换为 'production' 上线\r\nexport const currentEnv = 'development'\r\n\r\n// 获取当前环境配置\r\nexport const getEnvConfig = () : UTSJSONObject => {\r\n\tif (currentEnv == 'production') {\r\n\t\treturn {\r\n\t\t\tbaseUrl: ENV.production.baseUrl,\r\n\t\t\timageBaseUrl: ENV.production.imageBaseUrl\r\n\t\t} as UTSJSONObject\r\n\t}\r\n\treturn {\r\n\t\tbaseUrl: ENV.development.baseUrl,\r\n\t\timageBaseUrl: ENV.development.imageBaseUrl\r\n\t} as UTSJSONObject\r\n}\r\n\r\n// 是否使用Mock数据 - 已关闭,对接真实后端\r\nexport const useMock = false\r\n\r\n// 分页配置\r\nexport const PAGE_SIZE = 10\r\n\r\n// 图片上传配置\r\nexport const UPLOAD_CONFIG = {\r\n\tmaxSize: 5 * 1024 * 1024, // 5MB\r\n\tmaxCount: 9,\r\n\taccept: ['image/jpeg', 'image/png', 'image/gif']\r\n}\r\n\r\n// 缓存Key\r\nexport const STORAGE_KEYS = {\r\n\tTOKEN: 'user_token',\r\n\tUSER_INFO: 'user_info',\r\n\tFAVORITES: 'user_favorites',\r\n\tSEARCH_HISTORY: 'search_history'\r\n}\r\n\r\n// 沙发分类\r\nexport const SOFA_CATEGORIES = [\r\n\t{ id: 'all', name: '全部' },\r\n\t{ id: 'leather', name: '皮沙发' },\r\n\t{ id: 'fabric', name: '布艺沙发' },\r\n\t{ id: 'functional', name: '功能沙发' },\r\n\t{ id: 'antique', name: '古典沙发' },\r\n\t{ id: 'office', name: '办公沙发' }\r\n]\r\n\r\n// 翻新服务类型\r\nexport const SERVICE_TYPES = [\r\n\t{ id: 'repair', name: '局部修复', icon: '/static/icons/repair.png' },\r\n\t{ id: 'refurbish', name: '整体翻新', icon: '/static/icons/refurbish.png' }\r\n]\r\n\r\n/**\r\n * 获取服务类型名称\r\n */\r\nexport const getServiceTypeName = (type : string) : string => {\r\n\tconst map : Map = new Map([\r\n\t\t['leather', '真皮翻新'],\r\n\t\t['fabric', '布艺翻新'],\r\n\t\t['functional', '功能维修'],\r\n\t\t['antique', '古董修复'],\r\n\t\t['office', '办公沙发'],\r\n\t\t['cleaning', '清洁保养'],\r\n\t\t['repair', '维修改装'],\r\n\t\t['custom', '定制沙发']\r\n\t])\r\n\treturn map.get(type) ?? type\r\n}\r\n"],"names":[],"mappings":";AAKO,MAAM,MAAM,IAAA;AAAA,EAAA;AAAA;AAAA,IAElB,aAAa,IAAA,cAAA;AAAA,MACZ,SAAS;AAAA,MACT,cAAc;AAAA,KACd;AAAA;AAAA,IAED,YAAY,IAAA,cAAA;AAAA,MACX,SAAS;AAAA,MACT,cAAc;AAAA,KACd;AAAA,EACD;AAAA;;AAMY,MAAA,eAAe,MAAA;AAO3B,SAAO,IAAA,cAAA;AAAA,IACN,SAAS,IAAI,YAAY;AAAA,IACzB,cAAc,IAAI,YAAY;AAAA,GACb;AACnB;AAMO,MAAM,YAAY;AAGI,IAAA;AAAA,EAAA;AAAA,IAC5B,SAAS,IAAI,OAAO;AAAA,IACpB,UAAU;AAAA,IACV,QAAQ,CAAC,cAAc,aAAa,WAAW;AAAA,EAC/C;AAAA;;AAGY,MAAA,eAAe,IAAA;AAAA,EAAA;AAAA,IAC3B,OAAO;AAAA,IACP,WAAW;AAAA,IACX,WAAW;AAAA,IACX,gBAAgB;AAAA,EAChB;AAAA;;AAGY,MAAA,kBAAkB;AAAA,EAC9B,IAAA,cAAA,EAAE,IAAI,OAAO,MAAM,KAAI,CAAE;AAAA,EACzB,IAAA,cAAA,EAAE,IAAI,WAAW,MAAM,MAAK,CAAE;AAAA,EAC9B,IAAA,cAAA,EAAE,IAAI,UAAU,MAAM,OAAM,CAAE;AAAA,EAC9B,IAAA,cAAA,EAAE,IAAI,cAAc,MAAM,OAAM,CAAE;AAAA,EAClC,IAAA,cAAA,EAAE,IAAI,WAAW,MAAM,OAAM,CAAE;AAAA,EAC/B,IAAA,cAAA,EAAE,IAAI,UAAU,MAAM,OAAM,CAAE;;AAIF;AAAA,oBAC5B,EAAE,IAAI,UAAU,MAAM,QAAQ,MAAM,4BAA4B;AAAA,oBAChE,EAAE,IAAI,aAAa,MAAM,QAAQ,MAAM,+BAA+B;;AAMhE,MAAM,qBAAqB,CAAC,SAAa;;AAC/C,QAAM,MAA4B,oBAAI,IAAI;AAAA,IACzC,CAAC,WAAW,MAAM;AAAA,IAClB,CAAC,UAAU,MAAM;AAAA,IACjB,CAAC,cAAc,MAAM;AAAA,IACrB,CAAC,WAAW,MAAM;AAAA,IAClB,CAAC,UAAU,MAAM;AAAA,IACjB,CAAC,YAAY,MAAM;AAAA,IACnB,CAAC,UAAU,MAAM;AAAA,IACjB,CAAC,UAAU,MAAM;AAAA,EACjB,CAAA;AACD,0BAAO,KAAQ,IAAI,OAAA,QAAA,OAAA,SAAA,KAAK;AACzB;;;;;;"} \ No newline at end of file diff --git a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/utils/request.js.map b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/utils/request.js.map index 65b1a2c..e11fb13 100644 --- a/前端/unpackage/dist/dev/.sourcemap/mp-weixin/utils/request.js.map +++ b/前端/unpackage/dist/dev/.sourcemap/mp-weixin/utils/request.js.map @@ -1 +1 @@ -{"version":3,"file":"request.js","sources":["utils/request.uts"],"sourcesContent":["/**\r\n * 网络请求封装\r\n * 预留后端接口对接\r\n */\r\nimport { getEnvConfig, useMock, STORAGE_KEYS } from './config.uts'\r\nimport { getMockData } from './mock.uts'\r\n\r\n// 请求配置类型\r\ntype RequestOptions = {\r\n\turl : string\r\n\tmethod ?: 'GET' | 'POST' | 'PUT' | 'DELETE'\r\n\tdata ?: UTSJSONObject | null\r\n\theader ?: UTSJSONObject | null\r\n\tshowLoading ?: boolean\r\n\tloadingText ?: string\r\n}\r\n\r\n// 响应数据类型\r\ntype ResponseData = {\r\n\tcode : number\r\n\tmessage : string\r\n\tdata : any\r\n}\r\n\r\n/**\r\n * 请求拦截器\r\n */\r\nconst requestInterceptor = (options : RequestOptions) : RequestOptions => {\r\n\t// 添加token\r\n\tconst token = uni.getStorageSync(STORAGE_KEYS.TOKEN) as string\r\n\tif (token != '') {\r\n\t\tif (options.header == null) {\r\n\t\t\toptions.header = {} as UTSJSONObject\r\n\t\t}\r\n\t\toptions.header!['Authorization'] = `Bearer ${token}`\r\n\t}\r\n\treturn options\r\n}\r\n\r\n/**\r\n * 响应拦截器\r\n */\r\nconst responseInterceptor = (response : UTSJSONObject) : ResponseData => {\r\n\tconst statusCode = response['statusCode'] as number\r\n\tconst data = response['data'] as UTSJSONObject\r\n\t\r\n\tif (statusCode == 200) {\r\n\t\tconst code = (data['code'] ?? 0) as number\r\n\t\tif (code == 0 || code == 200) {\r\n\t\t\treturn {\r\n\t\t\t\tcode: 0,\r\n\t\t\t\tmessage: 'success',\r\n\t\t\t\tdata: data['data']\r\n\t\t\t} as ResponseData\r\n\t\t} else if (code == 401) {\r\n\t\t\t// token过期,跳转登录\r\n\t\t\tuni.removeStorageSync(STORAGE_KEYS.TOKEN)\r\n\t\t\tuni.showToast({\r\n\t\t\t\ttitle: '请重新登录',\r\n\t\t\t\ticon: 'none'\r\n\t\t\t})\r\n\t\t\treturn {\r\n\t\t\t\tcode: code,\r\n\t\t\t\tmessage: (data['message'] ?? '请重新登录') as string,\r\n\t\t\t\tdata: null\r\n\t\t\t} as ResponseData\r\n\t\t} else {\r\n\t\t\treturn {\r\n\t\t\t\tcode: code,\r\n\t\t\t\tmessage: (data['message'] ?? '请求失败') as string,\r\n\t\t\t\tdata: null\r\n\t\t\t} as ResponseData\r\n\t\t}\r\n\t} else {\r\n\t\treturn {\r\n\t\t\tcode: statusCode,\r\n\t\t\tmessage: '网络请求失败',\r\n\t\t\tdata: null\r\n\t\t} as ResponseData\r\n\t}\r\n}\r\n\r\n/**\r\n * 统一请求方法\r\n */\r\nexport const request = (options : RequestOptions) : Promise => {\r\n\treturn new Promise((resolve, reject) => {\r\n\t\t// 使用Mock数据\r\n\t\tif (useMock) {\r\n\t\t\tconst mockData = getMockData(options.url, options.method ?? 'GET', options.data)\r\n\t\t\tif (mockData != null) {\r\n\t\t\t\tsetTimeout(() => {\r\n\t\t\t\t\tresolve({\r\n\t\t\t\t\t\tcode: 0,\r\n\t\t\t\t\t\tmessage: 'success',\r\n\t\t\t\t\t\tdata: mockData\r\n\t\t\t\t\t} as ResponseData)\r\n\t\t\t\t}, 300) // 模拟网络延迟\r\n\t\t\t\treturn\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\t// 请求拦截\r\n\t\tconst finalOptions = requestInterceptor(options)\r\n\t\t\r\n\t\t// 显示loading\r\n\t\tif (finalOptions.showLoading == true) {\r\n\t\t\tuni.showLoading({\r\n\t\t\t\ttitle: finalOptions.loadingText ?? '加载中...'\r\n\t\t\t})\r\n\t\t}\r\n\t\t\r\n\t\tconst config = getEnvConfig()\r\n\t\tconst baseUrl = config['baseUrl'] as string\r\n\t\t\r\n\t\tuni.request({\r\n\t\t\turl: baseUrl + finalOptions.url,\r\n\t\t\tmethod: finalOptions.method ?? 'GET',\r\n\t\t\tdata: finalOptions.data as UTSJSONObject | null,\r\n\t\t\theader: finalOptions.header as UTSJSONObject | null,\r\n\t\t\tsuccess: (res) => {\r\n\t\t\t\tif (finalOptions.showLoading == true) {\r\n\t\t\t\t\tuni.hideLoading()\r\n\t\t\t\t}\r\n\t\t\t\tconst result = responseInterceptor(res as UTSJSONObject)\r\n\t\t\t\tif (result.code == 0) {\r\n\t\t\t\t\tresolve(result)\r\n\t\t\t\t} else {\r\n\t\t\t\t\tuni.showToast({\r\n\t\t\t\t\t\ttitle: result.message,\r\n\t\t\t\t\t\ticon: 'none'\r\n\t\t\t\t\t})\r\n\t\t\t\t\treject(result)\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t\tfail: (err) => {\r\n\t\t\t\tif (finalOptions.showLoading == true) {\r\n\t\t\t\t\tuni.hideLoading()\r\n\t\t\t\t}\r\n\t\t\t\tuni.showToast({\r\n\t\t\t\t\ttitle: '网络连接失败',\r\n\t\t\t\t\ticon: 'none'\r\n\t\t\t\t})\r\n\t\t\t\treject({\r\n\t\t\t\t\tcode: -1,\r\n\t\t\t\t\tmessage: '网络连接失败',\r\n\t\t\t\t\tdata: null\r\n\t\t\t\t} as ResponseData)\r\n\t\t\t}\r\n\t\t})\r\n\t})\r\n}\r\n\r\n/**\r\n * GET请求\r\n */\r\nexport const get = (url : string, data ?: UTSJSONObject | null) : Promise => {\r\n\treturn request({\r\n\t\turl: url,\r\n\t\tmethod: 'GET',\r\n\t\tdata: data\r\n\t} as RequestOptions)\r\n}\r\n\r\n/**\r\n * POST请求\r\n */\r\nexport const post = (url : string, data ?: UTSJSONObject | null) : Promise => {\r\n\treturn request({\r\n\t\turl: url,\r\n\t\tmethod: 'POST',\r\n\t\tdata: data\r\n\t} as RequestOptions)\r\n}\r\n"],"names":["uni","STORAGE_KEYS","getEnvConfig"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"request.js","sources":["utils/request.uts"],"sourcesContent":["/**\r\n * 网络请求封装\r\n * 预留后端接口对接\r\n */\r\nimport { getEnvConfig, useMock, STORAGE_KEYS } from './config.uts'\r\nimport { getMockData } from './mock.uts'\r\n\r\n// 请求配置类型\r\ntype RequestOptions = {\r\n\turl : string\r\n\tmethod ?: 'GET' | 'POST' | 'PUT' | 'DELETE'\r\n\tdata ?: UTSJSONObject | null\r\n\theader ?: UTSJSONObject | null\r\n\tshowLoading ?: boolean\r\n\tloadingText ?: string\r\n}\r\n\r\n// 响应数据类型\r\ntype ResponseData = {\r\n\tcode : number\r\n\tmessage : string\r\n\tdata : any | null\r\n}\r\n\r\n/**\r\n * 请求拦截器\r\n */\r\nconst requestInterceptor = (options : RequestOptions) : RequestOptions => {\r\n\t// 添加token\r\n\tconst token = uni.getStorageSync(STORAGE_KEYS.TOKEN) as string\r\n\tif (token != '') {\r\n\t\tif (options.header == null) {\r\n\t\t\toptions.header = {} as UTSJSONObject\r\n\t\t}\r\n\t\toptions.header!['Authorization'] = `Bearer ${token}`\r\n\t}\r\n\treturn options\r\n}\r\n\r\n/**\r\n * 响应拦截器\r\n */\r\nconst responseInterceptor = (response : UTSJSONObject) : ResponseData => {\r\n\tconst statusCode = response['statusCode'] as number\r\n\tconst data = response['data'] as UTSJSONObject | null\r\n\t\r\n\tconsole.log('响应拦截器 - statusCode:', statusCode)\r\n\tconsole.log('响应拦截器 - data:', data)\r\n\t\r\n\t// 处理空响应\r\n\tif (data == null) {\r\n\t\treturn {\r\n\t\t\tcode: statusCode,\r\n\t\t\tmessage: '响应数据为空',\r\n\t\t\tdata: null\r\n\t\t} as ResponseData\r\n\t}\r\n\t\r\n\tif (statusCode == 200) {\r\n\t\tconst code = (data['code'] ?? 0) as number\r\n\t\tconsole.log('响应拦截器 - 解析的 code:', code)\r\n\t\tif (code == 0 || code == 200) {\r\n\t\t\tconst result = {\r\n\t\t\t\tcode: 0,\r\n\t\t\t\tmessage: (data['message'] ?? 'success') as string,\r\n\t\t\t\tdata: data['data'] ?? null\r\n\t\t\t} as ResponseData\r\n\t\t\tconsole.log('响应拦截器 - 返回成功结果:', result)\r\n\t\t\treturn result\r\n\t\t} else if (code == 401) {\r\n\t\t\t// token过期,跳转登录\r\n\t\t\tuni.removeStorageSync(STORAGE_KEYS.TOKEN)\r\n\t\t\tuni.showToast({\r\n\t\t\t\ttitle: '请重新登录',\r\n\t\t\t\ticon: 'none'\r\n\t\t\t})\r\n\t\t\treturn {\r\n\t\t\t\tcode: code,\r\n\t\t\t\tmessage: (data['message'] ?? '请重新登录') as string,\r\n\t\t\t\tdata: null\r\n\t\t\t} as ResponseData\r\n\t\t} else {\r\n\t\t\treturn {\r\n\t\t\t\tcode: code,\r\n\t\t\t\tmessage: (data['message'] ?? '请求失败') as string,\r\n\t\t\t\tdata: data['data'] ?? null\r\n\t\t\t} as ResponseData\r\n\t\t}\r\n\t} else {\r\n\t\treturn {\r\n\t\t\tcode: statusCode,\r\n\t\t\tmessage: '网络请求失败',\r\n\t\t\tdata: null\r\n\t\t} as ResponseData\r\n\t}\r\n}\r\n\r\n/**\r\n * 统一请求方法\r\n */\r\nexport const request = (options : RequestOptions) : Promise => {\r\n\treturn new Promise((resolve, reject) => {\r\n\t\t// 使用Mock数据\r\n\t\tif (useMock) {\r\n\t\t\tconst mockData = getMockData(options.url, options.method ?? 'GET', options.data)\r\n\t\t\tif (mockData != null) {\r\n\t\t\t\tsetTimeout(() => {\r\n\t\t\t\t\tresolve({\r\n\t\t\t\t\t\tcode: 0,\r\n\t\t\t\t\t\tmessage: 'success',\r\n\t\t\t\t\t\tdata: mockData\r\n\t\t\t\t\t} as ResponseData)\r\n\t\t\t\t}, 300) // 模拟网络延迟\r\n\t\t\t\treturn\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\t// 请求拦截\r\n\t\tconst finalOptions = requestInterceptor(options)\r\n\t\t\r\n\t\t// 显示loading\r\n\t\tif (finalOptions.showLoading == true) {\r\n\t\t\tuni.showLoading({\r\n\t\t\t\ttitle: finalOptions.loadingText ?? '加载中...'\r\n\t\t\t})\r\n\t\t}\r\n\t\t\r\n\t\tconst config = getEnvConfig()\r\n\t\tconst BASE_URL = 'http://192.168.1.43:3000/api'\r\n\t\tconst baseUrl = config['baseUrl'] as string\r\n\r\n\t\t// 清理 data 中的 undefined 字段,避免被序列化为 'undefined'\r\n\t\tif (finalOptions.data && typeof finalOptions.data === 'object') {\r\n\t\t\tfor (const key in finalOptions.data) {\r\n\t\t\t\tif (finalOptions.data[key] === undefined) {\r\n\t\t\t\t\tdelete finalOptions.data[key]\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tuni.request({\r\n\t\t\turl: baseUrl + finalOptions.url,\r\n\t\t\tmethod: finalOptions.method ?? 'GET',\r\n\t\t\tdata: finalOptions.data as UTSJSONObject | null,\r\n\t\t\theader: finalOptions.header as UTSJSONObject | null,\r\n\t\t\tsuccess: (res) => {\r\n\t\t\t\tif (finalOptions.showLoading == true) {\r\n\t\t\t\t\tuni.hideLoading()\r\n\t\t\t\t}\r\n\t\t\t\tconsole.log('请求成功原始响应:', res)\r\n\t\t\t\tconst result = responseInterceptor(res as UTSJSONObject)\r\n\t\t\t\tconsole.log('拦截器处理后结果:', result)\r\n\t\t\t\tconsole.log('result.code 类型:', typeof result.code, '值:', result.code)\r\n\t\t\t\tif (result.code == 0) {\r\n\t\t\t\t\tconsole.log('判断为成功,resolve')\r\n\t\t\t\t\tresolve(result)\r\n\t\t\t\t} else {\r\n\t\t\t\t\tconsole.log('判断为失败,显示 toast 并 reject')\r\n\t\t\t\t\tuni.showToast({\r\n\t\t\t\t\t\ttitle: result.message,\r\n\t\t\t\t\t\ticon: 'none'\r\n\t\t\t\t\t})\r\n\t\t\t\t\treject(result)\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t\tfail: (err) => {\r\n\t\t\t\tif (finalOptions.showLoading == true) {\r\n\t\t\t\t\tuni.hideLoading()\r\n\t\t\t\t}\r\n\t\t\t\tuni.showToast({\r\n\t\t\t\t\ttitle: '网络连接失败',\r\n\t\t\t\t\ticon: 'none'\r\n\t\t\t\t})\r\n\t\t\t\treject({\r\n\t\t\t\t\tcode: -1,\r\n\t\t\t\t\tmessage: '网络连接失败',\r\n\t\t\t\t\tdata: null\r\n\t\t\t\t} as ResponseData)\r\n\t\t\t}\r\n\t\t})\r\n\t})\r\n}\r\n\r\n/**\r\n * GET请求\r\n */\r\nexport const get = (url : string, data ?: UTSJSONObject | null) : Promise => {\r\n\treturn request({\r\n\t\turl: url,\r\n\t\tmethod: 'GET',\r\n\t\tdata: data\r\n\t} as RequestOptions)\r\n}\r\n\r\n/**\r\n * POST请求\r\n */\r\nexport const post = (url : string, data ?: UTSJSONObject | null) : Promise => {\r\n\treturn request({\r\n\t\turl: url,\r\n\t\tmethod: 'POST',\r\n\t\tdata: data\r\n\t} as RequestOptions)\r\n}\r\n"],"names":["uni","STORAGE_KEYS","getEnvConfig"],"mappings":"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"} \ No newline at end of file diff --git a/前端/unpackage/dist/dev/mp-weixin/api/index.js b/前端/unpackage/dist/dev/mp-weixin/api/index.js index b9212b1..f733e2c 100644 --- a/前端/unpackage/dist/dev/mp-weixin/api/index.js +++ b/前端/unpackage/dist/dev/mp-weixin/api/index.js @@ -27,13 +27,18 @@ const getBanners = () => { })); }; const getCaseList = (params = null) => { - const queryParams = params ? new UTSJSONObject({ - page: params["page"] || 1, - limit: params["pageSize"] || params["limit"] || 10, - serviceType: params["category"], - status: "published" - // 只获取已发布的案例 - }) : new UTSJSONObject({}); + const queryParams = new UTSJSONObject( + { + page: params ? params["page"] || 1 : 1, + limit: params ? params["pageSize"] || params["limit"] || 10 : 10, + status: "published" + // 只获取已发布的案例 + } + // 如果有分类且不是all,则添加serviceType参数 + ); + if (params && params["category"] && params["category"] != "all") { + queryParams["serviceType"] = params["category"]; + } return utils_request.get("/cases", queryParams); }; const getCaseDetail = (id) => { @@ -42,20 +47,55 @@ const getCaseDetail = (id) => { const getHotCases = () => { return utils_request.get("/cases", new UTSJSONObject({ limit: 4, status: "published" })); }; -const getServiceProcess = () => { - return utils_request.get("/services"); +const getActiveServices = () => { + return utils_request.get("/services/active"); }; const getCompanyInfo = () => { - return utils_request.get("/company/info"); + return Promise.resolve(new UTSJSONObject({ + code: 0, + message: "success", + data: new UTSJSONObject({ + name: "优艺家沙发翻新", + slogan: "让旧沙发焕发新生", + description: "优艺家专注沙发翻新服务10余年,拥有专业的技术团队和丰富的经验。我们提供各类沙发翻新、维修、清洁服务,让您的旧沙发重新焕发光彩。", + phone: "400-888-8888", + wechat: "youyijia2024", + address: "北京市朝阳区XX路XX号", + workTime: "周一至周日 9:00-18:00", + features: [ + new UTSJSONObject({ title: "专业团队", desc: "10年以上经验的专业师傅" }), + new UTSJSONObject({ title: "品质保证", desc: "使用优质材料,质保一年" }), + new UTSJSONObject({ title: "免费上门", desc: "免费上门测量和评估" }), + new UTSJSONObject({ title: "快速交付", desc: "3-7天完成翻新服务" }) + ] + }) + })); }; const submitBooking = (data) => { return utils_request.post("/booking", data); }; +const getMyBookings = (params = null) => { + const queryParams = params ? new UTSJSONObject({ + page: params["page"] || 1, + limit: params["limit"] || 10, + status: params["status"] + }) : new UTSJSONObject({}); + return utils_request.get("/booking/my", queryParams); +}; +const cancelBooking = (id) => { + return utils_request.post(`/booking/${id}/cancel`, new UTSJSONObject({})); +}; +const wechatLogin = (code) => { + return utils_request.post("/auth/wechat/login", new UTSJSONObject({ code })); +}; +exports.cancelBooking = cancelBooking; +exports.getActiveServices = getActiveServices; exports.getBanners = getBanners; exports.getCaseDetail = getCaseDetail; exports.getCaseList = getCaseList; exports.getCompanyInfo = getCompanyInfo; exports.getHotCases = getHotCases; -exports.getServiceProcess = getServiceProcess; +exports.getMyBookings = getMyBookings; exports.submitBooking = submitBooking; +exports.wechatLogin = wechatLogin; //# sourceMappingURL=../../.sourcemap/mp-weixin/api/index.js.map diff --git a/前端/unpackage/dist/dev/mp-weixin/app.js b/前端/unpackage/dist/dev/mp-weixin/app.js index f0fc71a..aeb0217 100644 --- a/前端/unpackage/dist/dev/mp-weixin/app.js +++ b/前端/unpackage/dist/dev/mp-weixin/app.js @@ -9,6 +9,8 @@ if (!Math) { "./pages/about/index.js"; "./pages/booking/index.js"; "./pages/user/index.js"; + "./pages/user/booking-list.js"; + "./pages/user/favorites.js"; } const _sfc_main = common_vendor.defineComponent({ onLaunch() { diff --git a/前端/unpackage/dist/dev/mp-weixin/app.json b/前端/unpackage/dist/dev/mp-weixin/app.json index d09e953..7310630 100644 --- a/前端/unpackage/dist/dev/mp-weixin/app.json +++ b/前端/unpackage/dist/dev/mp-weixin/app.json @@ -6,7 +6,9 @@ "pages/service/index", "pages/about/index", "pages/booking/index", - "pages/user/index" + "pages/user/index", + "pages/user/booking-list", + "pages/user/favorites" ], "window": { "navigationBarTextStyle": "black", diff --git a/前端/unpackage/dist/dev/mp-weixin/common/vendor.js b/前端/unpackage/dist/dev/mp-weixin/common/vendor.js index 97f432b..14e89bd 100644 --- a/前端/unpackage/dist/dev/mp-weixin/common/vendor.js +++ b/前端/unpackage/dist/dev/mp-weixin/common/vendor.js @@ -85,8 +85,8 @@ const def = (obj, key, value) => { }); }; const looseToNumber = (val) => { - const n = parseFloat(val); - return isNaN(n) ? val : n; + const n2 = parseFloat(val); + return isNaN(n2) ? val : n2; }; function normalizeStyle$1(value) { if (isArray(value)) { @@ -118,6 +118,26 @@ function parseStringStyle(cssText) { }); return ret; } +function normalizeClass$1(value) { + let res = ""; + if (isString(value)) { + res = value; + } else if (isArray(value)) { + for (let i = 0; i < value.length; i++) { + const normalized = normalizeClass$1(value[i]); + if (normalized) { + res += normalized + " "; + } + } + } else if (isObject(value)) { + for (const name in value) { + if (value[name]) { + res += name + " "; + } + } + } + return res.trim(); +} const toDisplayString = (val) => { return isString(val) ? val : val == null ? "" : isArray(val) || isObject(val) && (val.toString === objectToString || !isFunction(val.toString)) ? JSON.stringify(val, replacer, 2) : String(val); }; @@ -338,6 +358,33 @@ function normalizeStyle(value) { return normalizeStyle$1(value); } } +function normalizeClass(value) { + let res = ""; + const g2 = getGlobal$1(); + if (g2 && g2.UTSJSONObject && value instanceof g2.UTSJSONObject) { + g2.UTSJSONObject.keys(value).forEach((key) => { + if (value[key]) { + res += key + " "; + } + }); + } else if (value instanceof Map) { + value.forEach((value2, key) => { + if (value2) { + res += key + " "; + } + }); + } else if (isArray(value)) { + for (let i = 0; i < value.length; i++) { + const normalized = normalizeClass(value[i]); + if (normalized) { + res += normalized + " "; + } + } + } else { + res = normalizeClass$1(value); + } + return res.trim(); +} const encode = encodeURIComponent; function stringifyQuery(obj, encodeStr = encode) { const res = obj ? Object.keys(obj).map((key) => { @@ -5855,6 +5902,7 @@ function genUniElementId(_ctx, idBinding, genId) { const o = (value, key) => vOn(value, key); const f = (source, renderItem) => vFor(source, renderItem); const e = (target, ...sources) => extend(target, ...sources); +const n = (value) => normalizeClass(value); const t = (val) => toDisplayString(val); const p = (props) => renderProps(props); const sei = setUniElementId; @@ -6529,8 +6577,8 @@ const $once = defineSyncApi(API_ONCE, (name, callback) => { const $off = defineSyncApi(API_OFF, (name, callback) => { if (!isArray(name)) name = name ? [name] : []; - name.forEach((n) => { - eventBus.off(n, callback); + name.forEach((n2) => { + eventBus.off(n2, callback); }); }, OffProtocol); const $emit = defineSyncApi(API_EMIT, (name, ...args) => { @@ -7848,7 +7896,7 @@ function isConsoleWritable() { function initRuntimeSocketService() { const hosts = "192.168.25.30,172.25.240.1,192.168.1.43,127.0.0.1"; const port = "8090"; - const id = "mp-weixin_8xzhU8"; + const id = "mp-weixin_IIWuS0"; const lazy = typeof swan !== "undefined"; let restoreError = lazy ? () => { } : initOnError(); @@ -9550,6 +9598,7 @@ exports.e = e; exports.f = f; exports.gei = gei; exports.index = index; +exports.n = n; exports.o = o; exports.onLoad = onLoad; exports.onMounted = onMounted; diff --git a/前端/unpackage/dist/dev/mp-weixin/pages/about/index.wxml b/前端/unpackage/dist/dev/mp-weixin/pages/about/index.wxml index 50c1a01..953f286 100644 --- a/前端/unpackage/dist/dev/mp-weixin/pages/about/index.wxml +++ b/前端/unpackage/dist/dev/mp-weixin/pages/about/index.wxml @@ -1 +1 @@ -优艺家{{a}}{{b}}{{d}}✓{{item.a}}{{item.b}}📞客服电话{{h}}›💬微信号{{j}}›📍公司地址{{l}}›🕐营业时间{{n}} +优艺家{{a}}{{b}}{{d}}✓{{item.a}}{{item.b}}📞客服电话{{h}}›💬微信号{{j}}›📍公司地址{{l}}›🕐营业时间{{n}} diff --git a/前端/unpackage/dist/dev/mp-weixin/pages/booking/index.js b/前端/unpackage/dist/dev/mp-weixin/pages/booking/index.js index 16630eb..bfbbeb2 100644 --- a/前端/unpackage/dist/dev/mp-weixin/pages/booking/index.js +++ b/前端/unpackage/dist/dev/mp-weixin/pages/booking/index.js @@ -1,7 +1,6 @@ "use strict"; const common_vendor = require("../../common/vendor.js"); const api_index = require("../../api/index.js"); -const utils_config = require("../../utils/config.js"); class FormData extends UTS.UTSType { static get$UTSMetadata$() { return { @@ -11,7 +10,8 @@ class FormData extends UTS.UTSType { userName: { type: String, optional: false }, phone: { type: String, optional: false }, address: { type: String, optional: false }, - sofaType: { type: String, optional: false }, + serviceId: { type: Number, optional: false }, + appointmentDate: { type: String, optional: false }, problem: { type: String, optional: false } }; }, @@ -24,29 +24,36 @@ class FormData extends UTS.UTSType { this.userName = this.__props__.userName; this.phone = this.__props__.phone; this.address = this.__props__.address; - this.sofaType = this.__props__.sofaType; + this.serviceId = this.__props__.serviceId; + this.appointmentDate = this.__props__.appointmentDate; this.problem = this.__props__.problem; delete this.__props__; } } -class SofaType extends UTS.UTSType { +class ServiceItem extends UTS.UTSType { static get$UTSMetadata$() { return { kind: 2, get fields() { return { - id: { type: String, optional: false }, - name: { type: String, optional: false } + id: { type: Number, optional: false }, + name: { type: String, optional: false }, + type: { type: String, optional: false }, + description: { type: String, optional: false }, + price: { type: Number, optional: false } }; }, - name: "SofaType" + name: "ServiceItem" }; } - constructor(options, metadata = SofaType.get$UTSMetadata$(), isJSONParse = false) { + constructor(options, metadata = ServiceItem.get$UTSMetadata$(), isJSONParse = false) { super(); this.__props__ = UTS.UTSType.initProps(options, metadata, isJSONParse); this.id = this.__props__.id; this.name = this.__props__.name; + this.type = this.__props__.type; + this.description = this.__props__.description; + this.price = this.__props__.price; delete this.__props__; } } @@ -57,24 +64,65 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ userName: "", phone: "", address: "", - sofaType: "", + serviceId: 0, + appointmentDate: "", problem: "" })); const imageList = common_vendor.ref([]); - const sofaTypes = common_vendor.ref([]); + const serviceList = common_vendor.ref([]); const submitting = common_vendor.ref(false); - const initSofaTypes = () => { - sofaTypes.value = utils_config.SOFA_CATEGORIES.filter((item) => { - return item.id != "all"; - }).map((item) => { - return new SofaType({ - id: item.id, - name: item.name - }); + const minDate = common_vendor.ref(""); + const loadServices = () => { + return common_vendor.__awaiter(this, void 0, void 0, function* () { + try { + const res = yield api_index.getActiveServices(); + common_vendor.index.__f__("log", "at pages/booking/index.uvue:196", "服务列表响应:", res); + if (res.code == 0 && res.data != null) { + const data = res.data; + let list = []; + if (Array.isArray(data)) { + list = data; + } else { + list = data["list"] || []; + } + common_vendor.index.__f__("log", "at pages/booking/index.uvue:206", "解析的服务列表:", list); + serviceList.value = list.map((item) => { + const basePrice = item["basePrice"] || "0"; + return new ServiceItem({ + id: item["id"], + name: item["name"], + type: item["type"], + description: item["description"], + price: parseFloat(basePrice) + }); + }); + common_vendor.index.__f__("log", "at pages/booking/index.uvue:217", "最终服务列表:", serviceList.value); + } else { + common_vendor.index.__f__("error", "at pages/booking/index.uvue:219", "服务列表响应异常,code:", res.code, "data:", res.data); + } + } catch (e) { + common_vendor.index.__f__("error", "at pages/booking/index.uvue:222", "加载服务列表失败", e); + } }); }; - const selectSofaType = (id) => { - formData.value.sofaType = id; + const initMinDate = () => { + const now = /* @__PURE__ */ new Date(); + const year = now.getFullYear(); + const month = String(now.getMonth() + 1).padStart(2, "0"); + const day = String(now.getDate()).padStart(2, "0"); + minDate.value = `${year}-${month}-${day}`; + const tomorrow = /* @__PURE__ */ new Date(); + tomorrow.setDate(tomorrow.getDate() + 1); + const tYear = tomorrow.getFullYear(); + const tMonth = String(tomorrow.getMonth() + 1).padStart(2, "0"); + const tDay = String(tomorrow.getDate()).padStart(2, "0"); + formData.value.appointmentDate = `${tYear}-${tMonth}-${tDay}`; + }; + const selectService = (id) => { + formData.value.serviceId = id; + }; + const onDateChange = (e = null) => { + formData.value.appointmentDate = e.detail.value; }; const chooseImage = () => { common_vendor.index.chooseImage(new UTSJSONObject({ @@ -119,6 +167,20 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ }); return false; } + if (formData.value.serviceId == 0) { + common_vendor.index.showToast({ + title: "请选择服务类型", + icon: "none" + }); + return false; + } + if (formData.value.appointmentDate == "") { + common_vendor.index.showToast({ + title: "请选择预约时间", + icon: "none" + }); + return false; + } return true; }; const handleSubmit = () => { @@ -129,19 +191,28 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ return Promise.resolve(null); submitting.value = true; try { - const data = new UTSJSONObject({ - userName: formData.value.userName, - phone: formData.value.phone, - address: formData.value.address, - sofaType: formData.value.sofaType, - problem: formData.value.problem, - images: imageList.value + const validImages = imageList.value.filter((url) => { + return url.startsWith("http://") || url.startsWith("https://"); }); + if (imageList.value.length > 0 && validImages.length === 0) { + common_vendor.index.__f__("log", "at pages/booking/index.uvue:340", "警告:图片为微信临时路径,暂不支持上传"); + } + const data = new UTSJSONObject({ + serviceId: formData.value.serviceId, + contactName: formData.value.userName, + contactPhone: formData.value.phone, + address: formData.value.address, + appointmentTime: formData.value.appointmentDate + "T10:00:00.000Z", + requirements: formData.value.problem, + images: validImages + // 只提交有效的URL + }); + common_vendor.index.__f__("log", "at pages/booking/index.uvue:354", "提交预约数据:", data); const res = yield api_index.submitBooking(data); - const result = res.data; + common_vendor.index.__f__("log", "at pages/booking/index.uvue:356", "预约提交结果:", res); common_vendor.index.showModal(new UTSJSONObject({ title: "预约成功", - content: result["message"], + content: "我们会尽快与您联系,请保持电话畅通", showCancel: false, success: () => { common_vendor.index.navigateBack(new UTSJSONObject({ @@ -154,17 +225,14 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ } })); } catch (e) { - common_vendor.index.__f__("error", "at pages/booking/index.uvue:270", "提交预约失败", e); - common_vendor.index.showToast({ - title: "提交失败,请重试", - icon: "none" - }); + common_vendor.index.__f__("error", "at pages/booking/index.uvue:375", "提交预约异常:", e); } submitting.value = false; }); }; common_vendor.onLoad(() => { - initSofaTypes(); + initMinDate(); + loadServices(); }); return (_ctx, _cache) => { "raw js"; @@ -181,23 +249,30 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ f: common_vendor.o(($event) => { return common_vendor.unref(formData).address = $event.detail.value; }), - g: common_vendor.f(common_vendor.unref(sofaTypes), (item, k0, i0) => { + g: common_vendor.f(common_vendor.unref(serviceList), (item, k0, i0) => { return { a: common_vendor.t(item.name), - b: common_vendor.unref(formData).sofaType == item.id ? 1 : "", - c: common_vendor.unref(formData).sofaType == item.id ? 1 : "", + b: common_vendor.unref(formData).serviceId == item.id ? 1 : "", + c: common_vendor.unref(formData).serviceId == item.id ? 1 : "", d: item.id, e: common_vendor.o(($event) => { - return selectSofaType(item.id); + return selectService(item.id); }, item.id) }; }), - h: common_vendor.unref(formData).problem, - i: common_vendor.o(($event) => { + h: common_vendor.unref(formData).appointmentDate + }, common_vendor.unref(formData).appointmentDate ? { + i: common_vendor.t(common_vendor.unref(formData).appointmentDate) + } : {}, { + j: common_vendor.unref(formData).appointmentDate, + k: common_vendor.unref(minDate), + l: common_vendor.o(onDateChange), + m: common_vendor.unref(formData).problem, + n: common_vendor.o(($event) => { return common_vendor.unref(formData).problem = $event.detail.value; }), - j: common_vendor.t(common_vendor.unref(formData).problem.length), - k: common_vendor.f(common_vendor.unref(imageList), (item, index, i0) => { + o: common_vendor.t(common_vendor.unref(formData).problem.length), + p: common_vendor.f(common_vendor.unref(imageList), (item, index, i0) => { return { a: item, b: common_vendor.o(($event) => { @@ -206,12 +281,12 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ c: index }; }), - l: common_vendor.unref(imageList).length < 9 + q: common_vendor.unref(imageList).length < 9 }, common_vendor.unref(imageList).length < 9 ? { - m: common_vendor.o(chooseImage) + r: common_vendor.o(chooseImage) } : {}, { - n: common_vendor.o(handleSubmit), - o: common_vendor.sei(common_vendor.gei(_ctx, ""), "view") + s: common_vendor.o(handleSubmit), + t: common_vendor.sei(common_vendor.gei(_ctx, ""), "view") }); return __returned__; }; diff --git a/前端/unpackage/dist/dev/mp-weixin/pages/booking/index.wxml b/前端/unpackage/dist/dev/mp-weixin/pages/booking/index.wxml index 18cd1c3..cd54c63 100644 --- a/前端/unpackage/dist/dev/mp-weixin/pages/booking/index.wxml +++ b/前端/unpackage/dist/dev/mp-weixin/pages/booking/index.wxml @@ -1 +1 @@ -预约翻新服务填写以下信息,我们会尽快与您联系* 您的姓名 * 联系电话 * 您的地址 沙发类型{{item.a}}问题描述{{j}}/500上传图片(可选)×+添加图片最多可上传9张图片提交预约 +预约翻新服务填写以下信息,我们会尽快与您联系* 您的姓名 * 联系电话 * 您的地址 * 服务类型 {{item.a}}* 预约时间 {{i}}请选择预约日期问题描述{{o}}/500上传图片(可选)×+添加图片提示:当前仅支持预览,图片暂不会上传到服务器提交预约 diff --git a/前端/unpackage/dist/dev/mp-weixin/pages/booking/index.wxss b/前端/unpackage/dist/dev/mp-weixin/pages/booking/index.wxss index 3c748b4..ddb003f 100644 --- a/前端/unpackage/dist/dev/mp-weixin/pages/booking/index.wxss +++ b/前端/unpackage/dist/dev/mp-weixin/pages/booking/index.wxss @@ -80,6 +80,23 @@ color: #C0C4CC; } +/* 日期选择器 */ +.picker-value { + background-color: #f5f5f5; + border-radius: 12rpx; + padding: 24rpx; + height: 40px; + justify-content: center; +} +.picker-text { + font-size: 28rpx; + color: #303133; +} +.picker-placeholder { + font-size: 28rpx; + color: #C0C4CC; +} + /* 沙发类型选择 */ .type-grid { flex-direction: row; diff --git a/前端/unpackage/dist/dev/mp-weixin/pages/cases/detail.js b/前端/unpackage/dist/dev/mp-weixin/pages/cases/detail.js index c18d369..265e60b 100644 --- a/前端/unpackage/dist/dev/mp-weixin/pages/cases/detail.js +++ b/前端/unpackage/dist/dev/mp-weixin/pages/cases/detail.js @@ -1,6 +1,7 @@ "use strict"; const common_vendor = require("../../common/vendor.js"); const api_index = require("../../api/index.js"); +const utils_config = require("../../utils/config.js"); if (!Array) { const _easycom_before_after_1 = common_vendor.resolveComponent("before-after"); _easycom_before_after_1(); @@ -21,6 +22,7 @@ class CaseDetail extends UTS.UTSType { categoryName: { type: String, optional: false }, beforeImages: { type: UTS.UTSType.withGenerics(Array, [String]), optional: false }, afterImages: { type: UTS.UTSType.withGenerics(Array, [String]), optional: false }, + compareAfterImages: { type: UTS.UTSType.withGenerics(Array, [String]), optional: false }, description: { type: String, optional: false }, material: { type: String, optional: false }, duration: { type: String, optional: false }, @@ -42,6 +44,7 @@ class CaseDetail extends UTS.UTSType { this.categoryName = this.__props__.categoryName; this.beforeImages = this.__props__.beforeImages; this.afterImages = this.__props__.afterImages; + this.compareAfterImages = this.__props__.compareAfterImages; this.description = this.__props__.description; this.material = this.__props__.material; this.duration = this.__props__.duration; @@ -63,6 +66,7 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ categoryName: "", beforeImages: [], afterImages: [], + compareAfterImages: [], description: "", material: "", duration: "", @@ -76,37 +80,57 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ return common_vendor.__awaiter(this, void 0, void 0, function* () { try { const res = yield api_index.getCaseDetail(caseId.value); - const data = res.data; - caseDetail.value = new CaseDetail( - { - id: data["id"], - title: data["title"], - category: data["category"], - categoryName: data["categoryName"], - beforeImages: data["beforeImages"], - afterImages: data["afterImages"], - description: data["description"], - material: data["material"], - duration: data["duration"], - price: data["price"], - views: data["views"], - likes: data["likes"], - createTime: data["createTime"] - } - // 更新标题 - ); - common_vendor.index.setNavigationBarTitle({ - title: caseDetail.value.title + if (res.code === 0 && res.data != null) { + const data = res.data; + const images = data["images"] || []; + const beforeImages = data["beforeImages"] || []; + const afterImages = data["afterImages"] || []; + const createdAt = data["createdAt"] || ""; + const displayAfterImages = afterImages.length > 0 ? afterImages : images; + const compareAfterImages = afterImages.length > 0 ? afterImages : []; + caseDetail.value = new CaseDetail( + { + id: String(data["id"]), + title: data["title"], + category: data["serviceType"] || "", + categoryName: utils_config.getServiceTypeName(data["serviceType"]), + beforeImages, + afterImages: displayAfterImages, + compareAfterImages, + description: data["description"], + material: data["materials"] || "优质材料", + duration: (data["duration"] || 0) + "天", + price: data["price"] != null ? "¥" + data["price"] : "面议", + views: data["views"] || 0, + likes: data["likes"] || 0, + createTime: createdAt.split("T")[0] || "" + } + // 更新标题 + ); + common_vendor.index.setNavigationBarTitle({ + title: caseDetail.value.title + }); + } else { + common_vendor.index.showToast({ + title: res.message || "加载失败", + icon: "none" + }); + } + } catch (error) { + common_vendor.index.__f__("error", "at pages/cases/detail.uvue:197", "获取案例详情失败:", error); + common_vendor.index.showToast({ + title: "加载失败", + icon: "none" }); - } catch (e) { - common_vendor.index.__f__("error", "at pages/cases/detail.uvue:173", "获取案例详情失败", e); } }); }; const previewImages = (index) => { + const urls = caseDetail.value.afterImages || []; + const current = urls[index] || urls[0] || ""; common_vendor.index.previewImage({ - current: index, - urls: caseDetail.value.afterImages + current, + urls }); }; const handleFavorite = () => { @@ -164,7 +188,7 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ f: common_vendor.t(common_vendor.unref(caseDetail).likes), g: common_vendor.p({ beforeImage: common_vendor.unref(caseDetail).beforeImages[0] || "", - afterImage: common_vendor.unref(caseDetail).afterImages[0] || "", + afterImage: common_vendor.unref(caseDetail).compareAfterImages[0] || "", showTitle: true }), h: common_vendor.t(common_vendor.unref(caseDetail).material), diff --git a/前端/unpackage/dist/dev/mp-weixin/pages/cases/detail.wxml b/前端/unpackage/dist/dev/mp-weixin/pages/cases/detail.wxml index 08feb64..3d8add7 100644 --- a/前端/unpackage/dist/dev/mp-weixin/pages/cases/detail.wxml +++ b/前端/unpackage/dist/dev/mp-weixin/pages/cases/detail.wxml @@ -1 +1 @@ -{{b}}{{c}}{{d}}👁 {{e}}❤ {{f}}翻新详情使用材质{{h}}翻新工期{{i}}完成日期{{j}}案例描述{{k}}{{l}}收藏📤分享在线咨询立即预约 +{{b}}{{c}}{{d}}👁 {{e}}❤ {{f}}翻新详情使用材质{{h}}翻新工期{{i}}完成日期{{j}}案例描述{{k}}{{l}}收藏📤分享在线咨询立即预约 diff --git a/前端/unpackage/dist/dev/mp-weixin/pages/cases/list.js b/前端/unpackage/dist/dev/mp-weixin/pages/cases/list.js index 0d2cefc..cdacb5c 100644 --- a/前端/unpackage/dist/dev/mp-weixin/pages/cases/list.js +++ b/前端/unpackage/dist/dev/mp-weixin/pages/cases/list.js @@ -93,6 +93,7 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ page.value = 1; caseList.value = []; noMore.value = false; + common_vendor.index.__f__("log", "at pages/cases/list.uvue:114", 111); fetchCaseList(); }; const fetchCaseList = () => { @@ -102,38 +103,49 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ loading.value = true; try { const params = new UTSJSONObject({ - category: currentCategory.value, + serviceType: currentCategory.value != "all" ? currentCategory.value : void 0, page: page.value, - pageSize: utils_config.PAGE_SIZE + limit: utils_config.PAGE_SIZE, + status: "published" }); const res = yield api_index.getCaseList(params); - const data = res.data; - const list = data["items"] || []; - total.value = data["total"] || 0; - const newList = list.map((item) => { - return new CaseItem({ - id: item["id"], - title: item["title"], - category: item["category"], - categoryName: item["categoryName"], - coverImage: item["coverImage"], - material: item["material"], - duration: item["duration"], - price: item["price"], - views: item["views"], - likes: item["likes"] + if (res.code == 0 && res.data != null) { + const data = res.data; + const list = data["list"] || []; + total.value = data["total"] || 0; + const newList = list.map((item) => { + const images = item["images"] || []; + const afterImages = item["afterImages"] || []; + const beforeImages = item["beforeImages"] || []; + const coverImage = images.length > 0 ? images[0] : afterImages.length > 0 ? afterImages[0] : beforeImages.length > 0 ? beforeImages[0] : ""; + return new CaseItem({ + id: String(item["id"]), + title: item["title"], + category: item["serviceType"], + categoryName: utils_config.getServiceTypeName(item["serviceType"]), + coverImage, + material: item["materials"] || "暂无", + duration: (item["duration"] || 0) + "天", + price: item["price"] != null ? "¥" + item["price"] : "面议", + views: item["views"] || 0, + likes: item["likes"] || 0 + }); }); - }); - if (page.value == 1) { - caseList.value = newList; - } else { - caseList.value = [...caseList.value, ...newList]; - } - if (caseList.value.length >= total.value) { - noMore.value = true; + if (page.value == 1) { + caseList.value = newList; + } else { + caseList.value = [...caseList.value, ...newList]; + } + if (caseList.value.length >= total.value) { + noMore.value = true; + } } } catch (e) { - common_vendor.index.__f__("error", "at pages/cases/list.uvue:160", "获取案例列表失败", e); + common_vendor.index.__f__("error", "at pages/cases/list.uvue:170", "获取案例列表失败", e); + common_vendor.index.showToast({ + title: "加载失败", + icon: "none" + }); } loading.value = false; }); @@ -171,7 +183,7 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ return { a: item.id, b: common_vendor.o(goToDetail, item.id), - c: "15d594f8-0-" + i0, + c: "32628196-0-" + i0, d: common_vendor.p({ caseData: item }) diff --git a/前端/unpackage/dist/dev/mp-weixin/pages/index/index.js b/前端/unpackage/dist/dev/mp-weixin/pages/index/index.js index b64db33..af968e0 100644 --- a/前端/unpackage/dist/dev/mp-weixin/pages/index/index.js +++ b/前端/unpackage/dist/dev/mp-weixin/pages/index/index.js @@ -136,30 +136,47 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ new AdvantageItem({ icon: "🚗", title: "上门服务", desc: "免费评估" }), new AdvantageItem({ icon: "💰", title: "价格透明", desc: "无隐形消费" }) ]); - const initServiceTypes = () => { - serviceTypes.value = utils_config.SERVICE_TYPES.map((item) => { - return new ServiceType({ - id: item.id, - name: item.name, - icon: item.icon - }); + const fetchServiceTypes = () => { + return common_vendor.__awaiter(this, void 0, void 0, function* () { + try { + const res = yield api_index.getActiveServices(); + if (res.code === 0 && res.data != null) { + const data = res.data; + const list = data["list"] || []; + serviceTypes.value = list.map((item) => { + return new ServiceType({ + id: String(item["id"]), + name: item["name"], + icon: item["icon"] || "/static/icons/default.png" + }); + }); + } + } catch (e) { + common_vendor.index.__f__("error", "at pages/index/index.uvue:165", "获取服务类型失败", e); + serviceTypes.value = [ + new ServiceType({ id: "repair", name: "局部修复", icon: "/static/icons/repair.png" }), + new ServiceType({ id: "refurbish", name: "整体翻新", icon: "/static/icons/refurbish.png" }) + ]; + } }); }; const fetchBanners = () => { return common_vendor.__awaiter(this, void 0, void 0, function* () { try { const res = yield api_index.getBanners(); - const data = res.data; - bannerList.value = data.map((item) => { - return new BannerItem({ - id: item["id"], - image: item["image"], - title: item["title"], - link: item["link"] + if (res.code === 0 && res.data != null) { + const data = res.data; + bannerList.value = data.map((item) => { + return new BannerItem({ + id: item["id"], + image: item["image"], + title: item["title"], + link: item["link"] + }); }); - }); + } } catch (e) { - common_vendor.index.__f__("error", "at pages/index/index.uvue:174", "获取轮播图失败", e); + common_vendor.index.__f__("error", "at pages/index/index.uvue:190", "获取轮播图失败", e); } }); }; @@ -167,24 +184,30 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ return common_vendor.__awaiter(this, void 0, void 0, function* () { try { const res = yield api_index.getHotCases(); - const data = res.data; - const list = data["items"] || []; - hotCases.value = list.map((item) => { - return new CaseItem({ - id: item["id"], - title: item["title"], - category: item["category"], - categoryName: item["categoryName"], - coverImage: item["coverImage"], - material: item["material"], - duration: item["duration"], - price: item["price"], - views: item["views"], - likes: item["likes"] + if (res.code == 0 && res.data != null) { + const data = res.data; + const list = data["list"] || []; + hotCases.value = list.map((item) => { + const images = item["images"] || []; + const afterImages = item["afterImages"] || []; + const beforeImages = item["beforeImages"] || []; + const coverImage = images.length > 0 ? images[0] : afterImages.length > 0 ? afterImages[0] : beforeImages.length > 0 ? beforeImages[0] : ""; + return new CaseItem({ + id: String(item["id"]), + title: item["title"], + category: item["serviceType"] || "", + categoryName: utils_config.getServiceTypeName(item["serviceType"]), + coverImage, + material: item["materials"] || "暂无", + duration: (item["duration"] || 0) + "天", + price: item["price"] != null ? "¥" + item["price"] : "面议", + views: item["views"] || 0, + likes: item["likes"] || 0 + }); }); - }); + } } catch (e) { - common_vendor.index.__f__("error", "at pages/index/index.uvue:200", "获取热门案例失败", e); + common_vendor.index.__f__("error", "at pages/index/index.uvue:224", "获取热门案例失败", e); } }); }; @@ -221,7 +244,7 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ }); }; common_vendor.onLoad(() => { - initServiceTypes(); + fetchServiceTypes(); fetchBanners(); fetchHotCases(); }); @@ -245,7 +268,7 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ a: item.id, b: item.id, c: common_vendor.o(handleServiceClick, item.id), - d: "767a328a-1-" + i0, + d: "0a3a932a-1-" + i0, e: common_vendor.p({ id: item.id, name: item.name, @@ -270,7 +293,7 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ return { a: item.id, b: common_vendor.o(goToCaseDetail, item.id), - c: "767a328a-3-" + i0, + c: "0a3a932a-3-" + i0, d: common_vendor.p({ caseData: item }) diff --git a/前端/unpackage/dist/dev/mp-weixin/pages/index/index.wxml b/前端/unpackage/dist/dev/mp-weixin/pages/index/index.wxml index 5f3ba5b..45cc1c0 100644 --- a/前端/unpackage/dist/dev/mp-weixin/pages/index/index.wxml +++ b/前端/unpackage/dist/dev/mp-weixin/pages/index/index.wxml @@ -1 +1 @@ -{{item.a}}{{item.b}}{{item.c}}免费上门评估专业师傅免费上门,为您的沙发量身定制翻新方案立即预约 +{{item.a}}{{item.b}}{{item.c}}免费上门评估专业师傅免费上门,为您的沙发量身定制翻新方案立即预约 diff --git a/前端/unpackage/dist/dev/mp-weixin/pages/service/index.js b/前端/unpackage/dist/dev/mp-weixin/pages/service/index.js index 8c7a2e1..7814ad6 100644 --- a/前端/unpackage/dist/dev/mp-weixin/pages/service/index.js +++ b/前端/unpackage/dist/dev/mp-weixin/pages/service/index.js @@ -15,10 +15,12 @@ class ServiceType extends UTS.UTSType { kind: 2, get fields() { return { - id: { type: String, optional: false }, + id: { type: Number, optional: false }, name: { type: String, optional: false }, desc: { type: String, optional: false }, - emoji: { type: String, optional: false } + emoji: { type: String, optional: false }, + type: { type: String, optional: false }, + basePrice: { type: Number, optional: false } }; }, name: "ServiceType" @@ -31,6 +33,8 @@ class ServiceType extends UTS.UTSType { this.name = this.__props__.name; this.desc = this.__props__.desc; this.emoji = this.__props__.emoji; + this.type = this.__props__.type; + this.basePrice = this.__props__.basePrice; delete this.__props__; } } @@ -108,13 +112,14 @@ class FaqItem extends UTS.UTSType { const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ __name: "index", setup(__props) { - const serviceTypes = common_vendor.ref([ - new ServiceType({ id: "repair", name: "局部修复", desc: "破损、划痕修复", emoji: "🔧" }), - new ServiceType({ id: "recolor", name: "改色翻新", desc: "皮面改色换新", emoji: "🎨" }), - new ServiceType({ id: "refurbish", name: "整体翻新", desc: "全面翻新升级", emoji: "✨" }), - new ServiceType({ id: "custom", name: "定制换皮", desc: "个性化定制", emoji: "💎" }) + const serviceTypes = common_vendor.ref([]); + const processList = common_vendor.ref([ + new ProcessItem({ step: 1, title: "在线预约", description: "填写信息,预约上门时间" }), + new ProcessItem({ step: 2, title: "上门评估", description: "专业师傅免费上门勘察" }), + new ProcessItem({ step: 3, title: "确认方案", description: "沟通翻新方案和价格" }), + new ProcessItem({ step: 4, title: "取件翻新", description: "取回沙发进行专业翻新" }), + new ProcessItem({ step: 5, title: "送货验收", description: "送货上门,满意付款" }) ]); - const processList = common_vendor.ref([]); const materials = common_vendor.ref([ new MaterialItem({ name: "头层牛皮", @@ -168,23 +173,41 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ expanded: false }) ]); - const fetchServiceProcess = () => { + const fetchServices = () => { return common_vendor.__awaiter(this, void 0, void 0, function* () { try { - const res = yield api_index.getServiceProcess(); - const data = res.data; - processList.value = data.map((item) => { - return new ProcessItem({ - step: item["step"], - title: item["title"], - description: item["description"] + const res = yield api_index.getActiveServices(); + if (res.code == 0 && res.data != null) { + const data = res.data; + const list = data["list"] || []; + const emojiMap = new UTSJSONObject({ + fabric: "🛋️", + leather: "💺", + cleaning: "✨", + repair: "🔧", + custom: "💎" }); - }); + serviceTypes.value = list.map((item) => { + const type = item["type"]; + return new ServiceType({ + id: item["id"], + name: item["name"], + desc: item["description"], + emoji: emojiMap[type] || "🛋️", + type, + basePrice: item["basePrice"] + }); + }); + } } catch (e) { - common_vendor.index.__f__("error", "at pages/service/index.uvue:217", "获取服务流程失败", e); + common_vendor.index.__f__("error", "at pages/service/index.uvue:237", "获取服务列表失败", e); } }); }; + const fetchServiceProcess = () => { + return common_vendor.__awaiter(this, void 0, void 0, function* () { + }); + }; const toggleFaq = (index) => { faqList.value[index].expanded = !faqList.value[index].expanded; }; @@ -199,6 +222,7 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ }); }; common_vendor.onLoad(() => { + fetchServices(); fetchServiceProcess(); }); return (_ctx, _cache) => { diff --git a/前端/unpackage/dist/dev/mp-weixin/pages/service/index.wxml b/前端/unpackage/dist/dev/mp-weixin/pages/service/index.wxml index f3fb299..9e6a2d2 100644 --- a/前端/unpackage/dist/dev/mp-weixin/pages/service/index.wxml +++ b/前端/unpackage/dist/dev/mp-weixin/pages/service/index.wxml @@ -1 +1 @@ -专业沙发翻新服务让旧沙发焕发新生{{item.a}}{{item.b}}{{item.c}}{{item.a}}{{item.b}}{{item.c}}{{item.a}}{{item.b}}{{item.c}}{{tag.a}}{{item.a}}{{item.b}}{{item.d}}免费上门评估专业师傅为您量身定制方案立即预约 +专业沙发翻新服务让旧沙发焕发新生{{item.a}}{{item.b}}{{item.c}}{{item.a}}{{item.b}}{{item.c}}{{item.a}}{{item.b}}{{item.c}}{{tag.a}}{{item.a}}{{item.b}}{{item.d}}免费上门评估专业师傅为您量身定制方案立即预约 diff --git a/前端/unpackage/dist/dev/mp-weixin/pages/user/index.js b/前端/unpackage/dist/dev/mp-weixin/pages/user/index.js index 7d54183..abc8dde 100644 --- a/前端/unpackage/dist/dev/mp-weixin/pages/user/index.js +++ b/前端/unpackage/dist/dev/mp-weixin/pages/user/index.js @@ -1,6 +1,7 @@ "use strict"; const common_vendor = require("../../common/vendor.js"); const utils_config = require("../../utils/config.js"); +const api_index = require("../../api/index.js"); class UserInfo extends UTS.UTSType { static get$UTSMetadata$() { return { @@ -67,33 +68,69 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ } })); }; + const fetchStats = () => { + bookingCount.value = 0; + const favorites = common_vendor.index.getStorageSync(utils_config.STORAGE_KEYS.FAVORITES); + favoriteCount.value = favorites ? favorites.length : 0; + }; const handleLogin = () => { common_vendor.index.getUserProfile(new UTSJSONObject({ desc: "用于完善用户资料", - success: (res = null) => { - userInfo.value = new UserInfo( - { - id: "", - nickName: res.userInfo.nickName, - avatar: res.userInfo.avatarUrl, - phone: "" + success: (profileRes = null) => { + common_vendor.index.login(new UTSJSONObject({ + provider: "weixin", + success: (loginRes) => { + return common_vendor.__awaiter(this, void 0, void 0, function* () { + var _a; + const code = loginRes.code; + try { + const res = yield api_index.wechatLogin(code); + if (res.code === 0 && res.data != null) { + const data = res.data; + const token = data["access_token"]; + const userDataObj = data["user"]; + common_vendor.index.setStorageSync(utils_config.STORAGE_KEYS.TOKEN, token); + userInfo.value = new UserInfo({ + id: String(userDataObj["id"]), + nickName: profileRes.userInfo.nickName, + avatar: profileRes.userInfo.avatarUrl, + phone: (_a = userDataObj["phone"]) !== null && _a !== void 0 ? _a : "" + }); + common_vendor.index.setStorageSync(utils_config.STORAGE_KEYS.USER_INFO, new UTSJSONObject({ + id: userDataObj["id"], + nickName: profileRes.userInfo.nickName, + avatar: profileRes.userInfo.avatarUrl, + phone: userDataObj["phone"] + })); + isLoggedIn.value = true; + common_vendor.index.showToast({ + title: "登录成功", + icon: "success" + }); + fetchStats(); + } else { + throw new Error(res.message); + } + } catch (error) { + common_vendor.index.__f__("error", "at pages/user/index.uvue:248", "登录失败", error); + common_vendor.index.showToast({ + title: "登录失败,请重试", + icon: "none" + }); + } + }); + }, + fail: () => { + common_vendor.index.showToast({ + title: "登录失败", + icon: "none" + }); } - // 保存用户信息 - ); - common_vendor.index.setStorageSync(utils_config.STORAGE_KEYS.USER_INFO, new UTSJSONObject({ - nickName: res.userInfo.nickName, - avatar: res.userInfo.avatarUrl })); - common_vendor.index.setStorageSync(utils_config.STORAGE_KEYS.TOKEN, "mock_token_" + Date.now().toString()); - isLoggedIn.value = true; - common_vendor.index.showToast({ - title: "登录成功", - icon: "success" - }); }, fail: () => { common_vendor.index.showToast({ - title: "登录失败", + title: "授权失败", icon: "none" }); } @@ -123,15 +160,27 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({ })); }; const goToBookingList = () => { - common_vendor.index.showToast({ - title: "功能开发中", - icon: "none" + if (!isLoggedIn.value) { + common_vendor.index.showToast({ + title: "请先登录", + icon: "none" + }); + return null; + } + common_vendor.index.navigateTo({ + url: "/pages/user/booking-list" }); }; const goToFavorites = () => { - common_vendor.index.showToast({ - title: "功能开发中", - icon: "none" + if (!isLoggedIn.value) { + common_vendor.index.showToast({ + title: "请先登录", + icon: "none" + }); + return null; + } + common_vendor.index.navigateTo({ + url: "/pages/user/favorites" }); }; const goToAbout = () => { diff --git a/前端/unpackage/dist/dev/mp-weixin/utils/config.js b/前端/unpackage/dist/dev/mp-weixin/utils/config.js index 0e02acd..ce4a8cd 100644 --- a/前端/unpackage/dist/dev/mp-weixin/utils/config.js +++ b/前端/unpackage/dist/dev/mp-weixin/utils/config.js @@ -3,8 +3,8 @@ const ENV = new UTSJSONObject( { // 开发环境 development: new UTSJSONObject({ - baseUrl: "http://localhost:3000/api", - imageBaseUrl: "http://localhost:3000" + baseUrl: "http://192.168.1.43:3000/api", + imageBaseUrl: "http://192.168.1.43:3000" }), // 生产环境 production: new UTSJSONObject({ @@ -46,15 +46,27 @@ const SOFA_CATEGORIES = [ new UTSJSONObject({ id: "antique", name: "古典沙发" }), new UTSJSONObject({ id: "office", name: "办公沙发" }) ]; -const SERVICE_TYPES = [ +[ new UTSJSONObject({ id: "repair", name: "局部修复", icon: "/static/icons/repair.png" }), - new UTSJSONObject({ id: "recolor", name: "改色翻新", icon: "/static/icons/recolor.png" }), - new UTSJSONObject({ id: "refurbish", name: "整体翻新", icon: "/static/icons/refurbish.png" }), - new UTSJSONObject({ id: "custom", name: "定制换皮", icon: "/static/icons/custom.png" }) + new UTSJSONObject({ id: "refurbish", name: "整体翻新", icon: "/static/icons/refurbish.png" }) ]; +const getServiceTypeName = (type) => { + var _a; + const map = /* @__PURE__ */ new Map([ + ["leather", "真皮翻新"], + ["fabric", "布艺翻新"], + ["functional", "功能维修"], + ["antique", "古董修复"], + ["office", "办公沙发"], + ["cleaning", "清洁保养"], + ["repair", "维修改装"], + ["custom", "定制沙发"] + ]); + return (_a = UTS.mapGet(map, type)) !== null && _a !== void 0 ? _a : type; +}; exports.PAGE_SIZE = PAGE_SIZE; -exports.SERVICE_TYPES = SERVICE_TYPES; exports.SOFA_CATEGORIES = SOFA_CATEGORIES; exports.STORAGE_KEYS = STORAGE_KEYS; exports.getEnvConfig = getEnvConfig; +exports.getServiceTypeName = getServiceTypeName; //# sourceMappingURL=../../.sourcemap/mp-weixin/utils/config.js.map diff --git a/前端/unpackage/dist/dev/mp-weixin/utils/request.js b/前端/unpackage/dist/dev/mp-weixin/utils/request.js index 2bff3f7..a149d40 100644 --- a/前端/unpackage/dist/dev/mp-weixin/utils/request.js +++ b/前端/unpackage/dist/dev/mp-weixin/utils/request.js @@ -39,7 +39,7 @@ class ResponseData extends UTS.UTSType { return { code: { type: Number, optional: false }, message: { type: String, optional: false }, - data: { type: "Any", optional: false } + data: { type: "Any", optional: true } }; }, name: "ResponseData" @@ -65,17 +65,29 @@ const requestInterceptor = (options) => { return options; }; const responseInterceptor = (response) => { - var _a, _b, _c; + var _a, _b, _c, _d, _e, _f; const statusCode = response["statusCode"]; const data = response["data"]; + common_vendor.index.__f__("log", "at utils/request.uts:47", "响应拦截器 - statusCode:", statusCode); + common_vendor.index.__f__("log", "at utils/request.uts:48", "响应拦截器 - data:", data); + if (data == null) { + return new ResponseData({ + code: statusCode, + message: "响应数据为空", + data: null + }); + } if (statusCode == 200) { const code = (_a = data["code"]) !== null && _a !== void 0 ? _a : 0; + common_vendor.index.__f__("log", "at utils/request.uts:61", "响应拦截器 - 解析的 code:", code); if (code == 0 || code == 200) { - return new ResponseData({ + const result = new ResponseData({ code: 0, - message: "success", - data: data["data"] + message: (_b = data["message"]) !== null && _b !== void 0 ? _b : "success", + data: (_c = data["data"]) !== null && _c !== void 0 ? _c : null }); + common_vendor.index.__f__("log", "at utils/request.uts:68", "响应拦截器 - 返回成功结果:", result); + return result; } else if (code == 401) { common_vendor.index.removeStorageSync(utils_config.STORAGE_KEYS.TOKEN); common_vendor.index.showToast({ @@ -84,14 +96,14 @@ const responseInterceptor = (response) => { }); return new ResponseData({ code, - message: (_b = data["message"]) !== null && _b !== void 0 ? _b : "请重新登录", + message: (_d = data["message"]) !== null && _d !== void 0 ? _d : "请重新登录", data: null }); } else { return new ResponseData({ code, - message: (_c = data["message"]) !== null && _c !== void 0 ? _c : "请求失败", - data: null + message: (_e = data["message"]) !== null && _e !== void 0 ? _e : "请求失败", + data: (_f = data["data"]) !== null && _f !== void 0 ? _f : null }); } } else { @@ -113,6 +125,13 @@ const request = (options) => { } const config = utils_config.getEnvConfig(); const baseUrl = config["baseUrl"]; + if (finalOptions.data && typeof finalOptions.data === "object") { + for (const key in finalOptions.data) { + if (finalOptions.data[key] === void 0) { + delete finalOptions.data[key]; + } + } + } common_vendor.index.request({ url: baseUrl + finalOptions.url, method: (_c = finalOptions.method) !== null && _c !== void 0 ? _c : "GET", @@ -122,10 +141,15 @@ const request = (options) => { if (finalOptions.showLoading == true) { common_vendor.index.hideLoading(); } + common_vendor.index.__f__("log", "at utils/request.uts:150", "请求成功原始响应:", res); const result = responseInterceptor(res); + common_vendor.index.__f__("log", "at utils/request.uts:152", "拦截器处理后结果:", result); + common_vendor.index.__f__("log", "at utils/request.uts:153", "result.code 类型:", typeof result.code, "值:", result.code); if (result.code == 0) { + common_vendor.index.__f__("log", "at utils/request.uts:155", "判断为成功,resolve"); resolve(result); } else { + common_vendor.index.__f__("log", "at utils/request.uts:158", "判断为失败,显示 toast 并 reject"); common_vendor.index.showToast({ title: result.message, icon: "none" diff --git a/前端/utils/config.uts b/前端/utils/config.uts index 4964258..7d48a12 100644 --- a/前端/utils/config.uts +++ b/前端/utils/config.uts @@ -6,8 +6,8 @@ export const ENV = { // 开发环境 development: { - baseUrl: 'http://localhost:3000/api', - imageBaseUrl: 'http://localhost:3000' + baseUrl: 'http://192.168.1.43:3000/api', + imageBaseUrl: 'http://192.168.1.43:3000' }, // 生产环境 production: { @@ -67,7 +67,22 @@ export const SOFA_CATEGORIES = [ // 翻新服务类型 export const SERVICE_TYPES = [ { id: 'repair', name: '局部修复', icon: '/static/icons/repair.png' }, - { id: 'recolor', name: '改色翻新', icon: '/static/icons/recolor.png' }, - { id: 'refurbish', name: '整体翻新', icon: '/static/icons/refurbish.png' }, - { id: 'custom', name: '定制换皮', icon: '/static/icons/custom.png' } + { id: 'refurbish', name: '整体翻新', icon: '/static/icons/refurbish.png' } ] + +/** + * 获取服务类型名称 + */ +export const getServiceTypeName = (type : string) : string => { + const map : Map = new Map([ + ['leather', '真皮翻新'], + ['fabric', '布艺翻新'], + ['functional', '功能维修'], + ['antique', '古董修复'], + ['office', '办公沙发'], + ['cleaning', '清洁保养'], + ['repair', '维修改装'], + ['custom', '定制沙发'] + ]) + return map.get(type) ?? type +} diff --git a/前端/utils/request.uts b/前端/utils/request.uts index 20f5afc..f7789e0 100644 --- a/前端/utils/request.uts +++ b/前端/utils/request.uts @@ -19,7 +19,7 @@ type RequestOptions = { type ResponseData = { code : number message : string - data : any + data : any | null } /** @@ -42,16 +42,31 @@ const requestInterceptor = (options : RequestOptions) : RequestOptions => { */ const responseInterceptor = (response : UTSJSONObject) : ResponseData => { const statusCode = response['statusCode'] as number - const data = response['data'] as UTSJSONObject + const data = response['data'] as UTSJSONObject | null + + console.log('响应拦截器 - statusCode:', statusCode) + console.log('响应拦截器 - data:', data) + + // 处理空响应 + if (data == null) { + return { + code: statusCode, + message: '响应数据为空', + data: null + } as ResponseData + } if (statusCode == 200) { const code = (data['code'] ?? 0) as number + console.log('响应拦截器 - 解析的 code:', code) if (code == 0 || code == 200) { - return { + const result = { code: 0, - message: 'success', - data: data['data'] + message: (data['message'] ?? 'success') as string, + data: data['data'] ?? null } as ResponseData + console.log('响应拦截器 - 返回成功结果:', result) + return result } else if (code == 401) { // token过期,跳转登录 uni.removeStorageSync(STORAGE_KEYS.TOKEN) @@ -68,7 +83,7 @@ const responseInterceptor = (response : UTSJSONObject) : ResponseData => { return { code: code, message: (data['message'] ?? '请求失败') as string, - data: null + data: data['data'] ?? null } as ResponseData } } else { @@ -111,8 +126,18 @@ export const request = (options : RequestOptions) : Promise => { } const config = getEnvConfig() + const BASE_URL = 'http://192.168.1.43:3000/api' const baseUrl = config['baseUrl'] as string - + + // 清理 data 中的 undefined 字段,避免被序列化为 'undefined' + if (finalOptions.data && typeof finalOptions.data === 'object') { + for (const key in finalOptions.data) { + if (finalOptions.data[key] === undefined) { + delete finalOptions.data[key] + } + } + } + uni.request({ url: baseUrl + finalOptions.url, method: finalOptions.method ?? 'GET', @@ -122,10 +147,15 @@ export const request = (options : RequestOptions) : Promise => { if (finalOptions.showLoading == true) { uni.hideLoading() } + console.log('请求成功原始响应:', res) const result = responseInterceptor(res as UTSJSONObject) + console.log('拦截器处理后结果:', result) + console.log('result.code 类型:', typeof result.code, '值:', result.code) if (result.code == 0) { + console.log('判断为成功,resolve') resolve(result) } else { + console.log('判断为失败,显示 toast 并 reject') uni.showToast({ title: result.message, icon: 'none' diff --git a/后端/.env b/后端/.env new file mode 100644 index 0000000..f019367 --- /dev/null +++ b/后端/.env @@ -0,0 +1,36 @@ +# 数据库配置 +DB_HOST=8.130.78.179 +DB_PORT=9986 +DB_USER=sffx +DB_PASS=wF5WKm35Ddm5NDTn +DB_NAME=sffx + +# JWT 配置 +JWT_SECRET=youyijia-sofa-jwt-secret-key-2024 +JWT_EXPIRES_IN=7d +JWT_REFRESH_SECRET=youyijia-sofa-refresh-secret-key-2024 +JWT_REFRESH_EXPIRES_IN=30d + +# 服务器配置 +PORT=3000 +NODE_ENV=development + +# 微信小程序配置 +WECHAT_APPID=wx89f1cd89fbc55f54 +WECHAT_SECRET=cb0697a56ab07147285f77ef555d2750 + +# 服务器配置 +PORT=3000 + +# 文件上传配置 +UPLOAD_DIR=uploads +MAX_FILE_SIZE=5242880 + +# 跨域配置 +CORS_ORIGIN=http://localhost:8080 + +# Redis 配置 (可选) +REDIS_HOST=localhost +REDIS_PORT=6379 +REDIS_PASSWORD= +REDIS_DB=0 \ No newline at end of file diff --git a/后端/.gitignore b/后端/.gitignore deleted file mode 100644 index 4b56acf..0000000 --- a/后端/.gitignore +++ /dev/null @@ -1,56 +0,0 @@ -# compiled output -/dist -/node_modules -/build - -# Logs -logs -*.log -npm-debug.log* -pnpm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* - -# OS -.DS_Store - -# Tests -/coverage -/.nyc_output - -# IDEs and editors -/.idea -.project -.classpath -.c9/ -*.launch -.settings/ -*.sublime-workspace - -# IDE - VSCode -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json - -# dotenv environment variable files -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# temp directory -.temp -.tmp - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json diff --git a/后端/src/app.module.ts b/后端/src/app.module.ts index 76e4742..6bde213 100644 --- a/后端/src/app.module.ts +++ b/后端/src/app.module.ts @@ -13,6 +13,8 @@ import { AuthModule } from './auth/auth.module'; import { UserModule } from './user/user.module'; import { CaseModule } from './case/case.module'; import { ServiceModule } from './service/service.module'; +import { BookingModule } from './booking/booking.module'; +import { DatabaseSeederService } from './database/database-seeder.service'; @Module({ imports: [ @@ -41,12 +43,14 @@ import { ServiceModule } from './service/service.module'; }), inject: [ConfigService], }), + TypeOrmModule.forFeature([User]), AuthModule, UserModule, CaseModule, ServiceModule, + BookingModule, ], controllers: [AppController], - providers: [AppService], + providers: [AppService, DatabaseSeederService], }) export class AppModule {} diff --git a/后端/src/auth/auth.controller.ts b/后端/src/auth/auth.controller.ts index dad4d7c..cfb5c31 100644 --- a/后端/src/auth/auth.controller.ts +++ b/后端/src/auth/auth.controller.ts @@ -12,20 +12,38 @@ export class AuthController { @Public() @Post('register') @ApiOperation({ summary: '用户注册' }) - @ApiResponse({ status: 201, description: '注册成功' }) + @ApiResponse({ status: 200, description: '注册成功' }) @ApiResponse({ status: 409, description: '用户已存在' }) - async register(@Body() registerDto: RegisterDto): Promise { - return this.authService.register(registerDto); + async register(@Body() registerDto: RegisterDto): Promise { + const result = await this.authService.register(registerDto); + return { + code: 0, + message: 'success', + data: result, + }; } @Public() @Post('login') @HttpCode(HttpStatus.OK) @ApiOperation({ summary: '用户登录' }) - @ApiResponse({ status: 200, description: '登录成功' }) - @ApiResponse({ status: 401, description: '用户名或密码错误' }) - async login(@Body() loginDto: LoginDto): Promise { - return this.authService.login(loginDto); + @ApiResponse({ status: 200, description: '登录成功或失败(通过 code 字段区分)' }) + async login(@Body() loginDto: LoginDto): Promise { + try { + const result = await this.authService.login(loginDto); + return { + code: 0, + message: '登录成功', + data: result, + }; + } catch (error) { + // 登录失败返回统一格式,不抛出 HTTP 异常 + return { + code: 401, + message: error.message || '用户名或密码错误', + data: null, + }; + } } @Public() @@ -35,7 +53,12 @@ export class AuthController { @ApiResponse({ status: 200, description: '刷新成功' }) @ApiResponse({ status: 401, description: '刷新令牌无效' }) async refreshToken(@Body('refresh_token') refreshToken: string) { - return this.authService.refreshToken(refreshToken); + const result = await this.authService.refreshToken(refreshToken); + return { + code: 0, + message: 'success', + data: result, + }; } @Public() @@ -44,10 +67,17 @@ export class AuthController { @ApiOperation({ summary: '微信小程序登录' }) @ApiResponse({ status: 200, description: '登录成功' }) @ApiResponse({ status: 400, description: '微信登录失败' }) - async wechatLogin( - @Body() loginData: { wechatLogin: WechatLoginDto; userInfo?: WechatUserInfoDto } - ): Promise { - const { wechatLogin, userInfo } = loginData; - return this.authService.wechatLogin(wechatLogin, userInfo); + async wechatLogin(@Body() body: any): Promise { + // 支持两种格式: + // 1. { wechatLogin: { code, ... }, userInfo: {...} } + // 2. { code, encryptedData, iv, signature } + const wechatLogin: WechatLoginDto = body?.wechatLogin ?? body; + const userInfo: WechatUserInfoDto | undefined = body?.userInfo; + const result = await this.authService.wechatLogin(wechatLogin, userInfo); + return { + code: 0, + message: 'success', + data: result, + }; } } \ No newline at end of file diff --git a/后端/src/booking/booking.controller.ts b/后端/src/booking/booking.controller.ts new file mode 100644 index 0000000..2845403 --- /dev/null +++ b/后端/src/booking/booking.controller.ts @@ -0,0 +1,86 @@ +import { Controller, Get, Post, Body, Patch, Param, Delete, Query, UseGuards, HttpCode } from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth, ApiQuery } from '@nestjs/swagger'; +import { BookingService } from './booking.service'; +import { CreateBookingDto, UpdateBookingDto, QueryBookingDto } from './dto/booking.dto'; +import type { CurrentUserData } from '../auth/decorators/current-user.decorator'; +import { CurrentUser } from '../auth/decorators/current-user.decorator'; +import { Roles } from '../auth/guards/roles.decorator'; +import { Public } from '../auth/guards/public.decorator'; + +@ApiTags('预约管理') +@ApiBearerAuth() +@Controller('booking') +export class BookingController { + constructor(private readonly bookingService: BookingService) {} + + @Post() + @HttpCode(200) // 返回200而不是默认的201 + @Public() // 允许公开访问 + @ApiOperation({ summary: '创建预约' }) + @ApiResponse({ status: 200, description: '预约成功' }) + @ApiResponse({ status: 400, description: '服务不存在或不可用' }) + create(@Body() createBookingDto: CreateBookingDto) { + // 暂时不需要userId,后续可以在小程序登录后传入 + return this.bookingService.create(createBookingDto, null); + } + + @Get() + @Roles('admin', 'worker') + @ApiOperation({ summary: '获取所有预约(管理员/工人)' }) + @ApiQuery({ name: 'status', required: false, enum: ['pending', 'confirmed', 'in_progress', 'completed', 'cancelled'] }) + @ApiQuery({ name: 'page', required: false, type: Number }) + @ApiQuery({ name: 'limit', required: false, type: Number }) + @ApiResponse({ status: 200, description: '获取成功' }) + findAll(@Query() query: QueryBookingDto) { + return this.bookingService.findAll(query); + } + + @Get('my') + @ApiOperation({ summary: '获取我的预约列表' }) + @ApiQuery({ name: 'status', required: false, enum: ['pending', 'confirmed', 'in_progress', 'completed', 'cancelled'] }) + @ApiQuery({ name: 'page', required: false, type: Number }) + @ApiQuery({ name: 'limit', required: false, type: Number }) + @ApiResponse({ status: 200, description: '获取成功' }) + getMyBookings(@Query() query: QueryBookingDto, @CurrentUser() user: CurrentUserData) { + return this.bookingService.getMyBookings(user.userId, query); + } + + @Get(':id') + @ApiOperation({ summary: '根据ID获取预约详情' }) + @ApiResponse({ status: 200, description: '获取成功' }) + @ApiResponse({ status: 404, description: '预约不存在' }) + findOne(@Param('id') id: string) { + return this.bookingService.findOne(+id); + } + + @Patch(':id') + @ApiOperation({ summary: '更新预约信息' }) + @ApiResponse({ status: 200, description: '更新成功' }) + @ApiResponse({ status: 400, description: '无权限或状态不允许' }) + @ApiResponse({ status: 404, description: '预约不存在' }) + update( + @Param('id') id: string, + @Body() updateBookingDto: UpdateBookingDto, + @CurrentUser() user: CurrentUserData + ) { + return this.bookingService.update(+id, updateBookingDto, user.userId, user.role); + } + + @Post(':id/cancel') + @ApiOperation({ summary: '取消预约' }) + @ApiResponse({ status: 200, description: '取消成功' }) + @ApiResponse({ status: 400, description: '无权限或状态不允许' }) + @ApiResponse({ status: 404, description: '预约不存在' }) + cancel(@Param('id') id: string, @CurrentUser() user: CurrentUserData) { + return this.bookingService.cancel(+id, user.userId, user.role); + } + + @Delete(':id') + @Roles('admin') + @ApiOperation({ summary: '删除预约(管理员)' }) + @ApiResponse({ status: 200, description: '删除成功' }) + @ApiResponse({ status: 404, description: '预约不存在' }) + remove(@Param('id') id: string) { + return this.bookingService.remove(+id); + } +} diff --git a/后端/src/booking/booking.module.ts b/后端/src/booking/booking.module.ts new file mode 100644 index 0000000..e18a6c7 --- /dev/null +++ b/后端/src/booking/booking.module.ts @@ -0,0 +1,14 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { BookingController } from './booking.controller'; +import { BookingService } from './booking.service'; +import { Booking } from '../entities/booking.entity'; +import { Service } from '../entities/service.entity'; + +@Module({ + imports: [TypeOrmModule.forFeature([Booking, Service])], + controllers: [BookingController], + providers: [BookingService], + exports: [BookingService], +}) +export class BookingModule {} diff --git a/后端/src/booking/booking.service.ts b/后端/src/booking/booking.service.ts new file mode 100644 index 0000000..777b84a --- /dev/null +++ b/后端/src/booking/booking.service.ts @@ -0,0 +1,210 @@ +import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { Booking } from '../entities/booking.entity'; +import { Service } from '../entities/service.entity'; +import { CreateBookingDto, UpdateBookingDto, QueryBookingDto } from './dto/booking.dto'; + +@Injectable() +export class BookingService { + constructor( + @InjectRepository(Booking) + private bookingRepository: Repository, + @InjectRepository(Service) + private serviceRepository: Repository, + ) {} + + // 生成预约编号 + private generateBookingNumber(): string { + const date = new Date(); + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + const random = Math.random().toString(36).substring(2, 8).toUpperCase(); + return `BK${year}${month}${day}${random}`; + } + + async create(createBookingDto: CreateBookingDto, userId: number | null) { + // 验证服务是否存在 + const service = await this.serviceRepository.findOne({ + where: { id: createBookingDto.serviceId } + }); + + if (!service) { + throw new BadRequestException('服务不存在'); + } + + if (service.status !== 'active') { + throw new BadRequestException('该服务暂不可用'); + } + + const booking = this.bookingRepository.create({ + ...createBookingDto, + customerId: userId ?? undefined, // 将null转为undefined + bookingNumber: this.generateBookingNumber(), + status: 'pending', + }); + + const savedBooking = await this.bookingRepository.save(booking); + + return { + code: 0, + message: '预约成功', + data: savedBooking, + }; + } + + async findAll(query: QueryBookingDto) { + const { status, page = 1, limit = 10 } = query; + + const queryBuilder = this.bookingRepository + .createQueryBuilder('booking') + .leftJoinAndSelect('booking.customer', 'customer') + .leftJoinAndSelect('booking.service', 'service') + .leftJoinAndSelect('booking.assignedWorker', 'worker') + .orderBy('booking.createdAt', 'DESC'); + + if (status) { + queryBuilder.andWhere('booking.status = :status', { status }); + } + + const total = await queryBuilder.getCount(); + const bookings = await queryBuilder + .skip((page - 1) * limit) + .take(limit) + .getMany(); + + return { + code: 0, + message: '获取成功', + data: { + list: bookings, + total, + page, + pageSize: limit, + }, + }; + } + + async getMyBookings(userId: number, query: QueryBookingDto) { + const { status, page = 1, limit = 10 } = query; + + const queryBuilder = this.bookingRepository + .createQueryBuilder('booking') + .leftJoinAndSelect('booking.service', 'service') + .leftJoinAndSelect('booking.assignedWorker', 'worker') + .where('booking.customerId = :userId', { userId }) + .orderBy('booking.createdAt', 'DESC'); + + if (status) { + queryBuilder.andWhere('booking.status = :status', { status }); + } + + const total = await queryBuilder.getCount(); + const bookings = await queryBuilder + .skip((page - 1) * limit) + .take(limit) + .getMany(); + + return { + code: 0, + message: '获取成功', + data: { + list: bookings, + total, + page, + pageSize: limit, + }, + }; + } + + async findOne(id: number) { + const booking = await this.bookingRepository.findOne({ + where: { id }, + relations: ['customer', 'service', 'assignedWorker'], + }); + + if (!booking) { + throw new NotFoundException('预约不存在'); + } + + return { + code: 0, + message: '获取成功', + data: booking, + }; + } + + async update(id: number, updateBookingDto: UpdateBookingDto, userId: number, userRole: string) { + const booking = await this.bookingRepository.findOne({ + where: { id }, + }); + + if (!booking) { + throw new NotFoundException('预约不存在'); + } + + // 普通用户只能更新自己的预约 + if (userRole === 'customer' && booking.customerId !== userId) { + throw new BadRequestException('无权限更新此预约'); + } + + // 客户只能在待确认状态下更新部分信息 + if (userRole === 'customer' && booking.status !== 'pending') { + throw new BadRequestException('预约已确认,无法修改'); + } + + Object.assign(booking, updateBookingDto); + const updatedBooking = await this.bookingRepository.save(booking); + + return { + code: 0, + message: '更新成功', + data: updatedBooking, + }; + } + + async cancel(id: number, userId: number, userRole: string) { + const booking = await this.bookingRepository.findOne({ + where: { id }, + }); + + if (!booking) { + throw new NotFoundException('预约不存在'); + } + + // 普通用户只能取消自己的预约 + if (userRole === 'customer' && booking.customerId !== userId) { + throw new BadRequestException('无权限取消此预约'); + } + + if (booking.status === 'completed' || booking.status === 'cancelled') { + throw new BadRequestException('预约已完成或已取消,无法取消'); + } + + booking.status = 'cancelled'; + await this.bookingRepository.save(booking); + + return { + code: 0, + message: '取消成功', + }; + } + + async remove(id: number) { + const booking = await this.bookingRepository.findOne({ + where: { id }, + }); + + if (!booking) { + throw new NotFoundException('预约不存在'); + } + + await this.bookingRepository.remove(booking); + + return { + code: 0, + message: '删除成功', + }; + } +} diff --git a/后端/src/booking/dto/booking.dto.ts b/后端/src/booking/dto/booking.dto.ts new file mode 100644 index 0000000..5a909e0 --- /dev/null +++ b/后端/src/booking/dto/booking.dto.ts @@ -0,0 +1,117 @@ +import { IsString, IsNotEmpty, IsOptional, IsNumber, IsEnum, IsDateString, IsArray } from 'class-validator'; +import { Type } from 'class-transformer'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; + +export class CreateBookingDto { + @ApiProperty({ description: '服务ID' }) + @IsNumber() + @IsNotEmpty() + serviceId: number; + + @ApiProperty({ description: '联系人姓名' }) + @IsString() + @IsNotEmpty() + contactName: string; + + @ApiProperty({ description: '联系电话' }) + @IsString() + @IsNotEmpty() + contactPhone: string; + + @ApiProperty({ description: '服务地址' }) + @IsString() + @IsNotEmpty() + address: string; + + @ApiProperty({ description: '预约时间' }) + @IsDateString() + @IsNotEmpty() + appointmentTime: string; + + @ApiPropertyOptional({ description: '特殊要求' }) + @IsString() + @IsOptional() + requirements?: string; + + @ApiPropertyOptional({ description: '沙发现状图片', type: [String] }) + @IsArray() + @IsOptional() + images?: string[]; +} + +export class UpdateBookingDto { + @ApiPropertyOptional({ description: '联系人姓名' }) + @IsString() + @IsOptional() + contactName?: string; + + @ApiPropertyOptional({ description: '联系电话' }) + @IsString() + @IsOptional() + contactPhone?: string; + + @ApiPropertyOptional({ description: '服务地址' }) + @IsString() + @IsOptional() + address?: string; + + @ApiPropertyOptional({ description: '预约时间' }) + @IsDateString() + @IsOptional() + appointmentTime?: string; + + @ApiPropertyOptional({ description: '特殊要求' }) + @IsString() + @IsOptional() + requirements?: string; + + @ApiPropertyOptional({ description: '沙发现状图片', type: [String] }) + @IsArray() + @IsOptional() + images?: string[]; + + @ApiPropertyOptional({ description: '状态', enum: ['pending', 'confirmed', 'in_progress', 'completed', 'cancelled'] }) + @IsEnum(['pending', 'confirmed', 'in_progress', 'completed', 'cancelled']) + @IsOptional() + status?: string; + + @ApiPropertyOptional({ description: '报价' }) + @IsNumber() + @IsOptional() + quotedPrice?: number; + + @ApiPropertyOptional({ description: '最终价格' }) + @IsNumber() + @IsOptional() + finalPrice?: number; + + @ApiPropertyOptional({ description: '备注' }) + @IsString() + @IsOptional() + notes?: string; + + @ApiPropertyOptional({ description: '分配工人ID' }) + @IsNumber() + @IsOptional() + assignedWorkerId?: number; +} + +export class QueryBookingDto { + @ApiPropertyOptional({ description: '状态', enum: ['pending', 'confirmed', 'in_progress', 'completed', 'cancelled'] }) + @IsEnum(['pending', 'confirmed', 'in_progress', 'completed', 'cancelled']) + @IsOptional() + status?: string; + + @ApiPropertyOptional({ description: '页码', default: 1 }) + @IsOptional() + @Type(() => Number) + @IsNumber() + page?: number; + + @ApiPropertyOptional({ description: '每页数量', default: 10 }) + @ApiPropertyOptional({ description: '每页数量', default: 10 }) + @IsOptional() + @Type(() => Number) + @IsNumber() + limit?: number; +} diff --git a/后端/src/case/case.controller.ts b/后端/src/case/case.controller.ts index 3f7dd97..d132977 100644 --- a/后端/src/case/case.controller.ts +++ b/后端/src/case/case.controller.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Post, Body, Patch, Param, Delete, Query, UseGuards } from '@nestjs/common'; +import { Controller, Get, Post, Body, Patch, Param, Delete, Query, UseGuards, HttpCode } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth, ApiQuery } from '@nestjs/swagger'; import { CaseService } from './case.service'; import { CreateCaseDto, UpdateCaseDto, QueryCaseDto } from './dto/case.dto'; @@ -14,35 +14,52 @@ export class CaseController { @ApiBearerAuth() @Post() + @HttpCode(200) @Roles('admin', 'worker') @ApiOperation({ summary: '创建案例' }) - @ApiResponse({ status: 201, description: '创建成功' }) - create(@Body() createCaseDto: CreateCaseDto, @CurrentUser() user: CurrentUserData) { - return this.caseService.create(createCaseDto, user.userId); + @ApiResponse({ status: 200, description: '创建成功' }) + async create(@Body() createCaseDto: CreateCaseDto, @CurrentUser() user: CurrentUserData) { + const data = await this.caseService.create(createCaseDto, user.userId); + return { + code: 0, + message: '创建成功', + data, + }; } @Public() @Get() @ApiOperation({ summary: '获取案例列表' }) - @ApiQuery({ name: 'serviceType', required: false, enum: ['fabric', 'leather', 'cleaning', 'repair', 'custom'] }) + @ApiQuery({ name: 'serviceType', required: false, enum: ['leather', 'fabric', 'functional', 'antique', 'office', 'cleaning', 'repair', 'custom'] }) @ApiQuery({ name: 'status', required: false, enum: ['draft', 'published', 'archived'], description: '默认为published' }) @ApiQuery({ name: 'page', required: false, type: Number, description: '页码,默认为1' }) @ApiQuery({ name: 'limit', required: false, type: Number, description: '每页数量,默认为10' }) @ApiResponse({ status: 200, description: '获取成功' }) - findAll(@Query() query: QueryCaseDto) { - return this.caseService.findAll(query); + async findAll(@Query() query: QueryCaseDto) { + const result = await this.caseService.findAll(query); + return { + code: 0, + message: '获取成功', + data: result, + }; } + @ApiBearerAuth() @Get('my') @ApiOperation({ summary: '获取我的案例列表' }) - @ApiQuery({ name: 'serviceType', required: false, enum: ['fabric', 'leather', 'cleaning', 'repair', 'custom'] }) + @ApiQuery({ name: 'serviceType', required: false, enum: ['leather', 'fabric', 'functional', 'antique', 'office', 'cleaning', 'repair', 'custom'] }) @ApiQuery({ name: 'status', required: false, enum: ['draft', 'published', 'archived'] }) @ApiQuery({ name: 'page', required: false, type: Number }) @ApiQuery({ name: 'limit', required: false, type: Number }) @ApiResponse({ status: 200, description: '获取成功' }) - getMyCases(@Query() query: QueryCaseDto, @CurrentUser() user: CurrentUserData) { - return this.caseService.getMyCases(user.userId, query); + async getMyCases(@Query() query: QueryCaseDto, @CurrentUser() user: CurrentUserData) { + const data = await this.caseService.getMyCases(user.userId, query); + return { + code: 0, + message: '获取成功', + data, + }; } @Public() @@ -50,8 +67,13 @@ export class CaseController { @ApiOperation({ summary: '根据ID获取案例详情' }) @ApiResponse({ status: 200, description: '获取成功' }) @ApiResponse({ status: 404, description: '案例不存在' }) - findOne(@Param('id') id: string) { - return this.caseService.findOne(+id); + async findOne(@Param('id') id: string) { + const data = await this.caseService.findOne(+id); + return { + code: 0, + message: '获取成功', + data, + }; } @ApiBearerAuth() @@ -60,12 +82,17 @@ export class CaseController { @ApiResponse({ status: 200, description: '更新成功' }) @ApiResponse({ status: 404, description: '案例不存在' }) @ApiResponse({ status: 403, description: '没有权限' }) - update( + async update( @Param('id') id: string, @Body() updateCaseDto: UpdateCaseDto, @CurrentUser() user: CurrentUserData ) { - return this.caseService.update(+id, updateCaseDto, user.userId, user.role); + const data = await this.caseService.update(+id, updateCaseDto, user.userId, user.role); + return { + code: 0, + message: '更新成功', + data, + }; } @ApiBearerAuth() @@ -74,8 +101,12 @@ export class CaseController { @ApiResponse({ status: 200, description: '删除成功' }) @ApiResponse({ status: 404, description: '案例不存在' }) @ApiResponse({ status: 403, description: '没有权限' }) - remove(@Param('id') id: string, @CurrentUser() user: CurrentUserData) { - return this.caseService.remove(+id, user.userId, user.role); + async remove(@Param('id') id: string, @CurrentUser() user: CurrentUserData) { + await this.caseService.remove(+id, user.userId, user.role); + return { + code: 0, + message: '删除成功', + }; } @Public() @@ -83,7 +114,12 @@ export class CaseController { @ApiOperation({ summary: '点赞案例' }) @ApiResponse({ status: 200, description: '点赞成功' }) @ApiResponse({ status: 404, description: '案例不存在' }) - like(@Param('id') id: string) { - return this.caseService.like(+id); + async like(@Param('id') id: string) { + const data = await this.caseService.like(+id); + return { + code: 0, + message: '点赞成功', + data, + }; } } \ No newline at end of file diff --git a/后端/src/case/case.service.ts b/后端/src/case/case.service.ts index c37a62a..11dc944 100644 --- a/后端/src/case/case.service.ts +++ b/后端/src/case/case.service.ts @@ -29,12 +29,15 @@ export class CaseService { 'case.id', 'case.title', 'case.description', + 'case.images', 'case.beforeImages', 'case.afterImages', 'case.serviceType', + 'case.location', 'case.price', 'case.materials', 'case.duration', + 'case.tags', 'case.status', 'case.views', 'case.likes', @@ -57,18 +60,17 @@ export class CaseService { queryBuilder.skip(skip).take(limit); queryBuilder.orderBy('case.createdAt', 'DESC'); - const [items, total] = await queryBuilder.getManyAndCount(); + const [list, total] = await queryBuilder.getManyAndCount(); return { - items, + list, total, page, - limit, - totalPages: Math.ceil(total / limit), + pageSize: limit, }; } - async findOne(id: number): Promise { + async findOne(id: number): Promise { const caseEntity = await this.caseRepository .createQueryBuilder('case') .leftJoinAndSelect('case.creator', 'creator') @@ -76,12 +78,15 @@ export class CaseService { 'case.id', 'case.title', 'case.description', + 'case.images', 'case.beforeImages', 'case.afterImages', 'case.serviceType', + 'case.location', 'case.price', 'case.materials', 'case.duration', + 'case.tags', 'case.status', 'case.views', 'case.likes', @@ -120,7 +125,16 @@ export class CaseService { } await this.caseRepository.update(id, updateCaseDto); - return this.findOne(id); + const updated = await this.caseRepository.findOne({ + where: { id }, + relations: ['creator'], + }); + + if (!updated) { + throw new NotFoundException('更新后案例不存在'); + } + + return updated; } async remove(id: number, userId: number, userRole: string): Promise { @@ -166,12 +180,15 @@ export class CaseService { 'case.id', 'case.title', 'case.description', + 'case.images', 'case.beforeImages', 'case.afterImages', 'case.serviceType', + 'case.location', 'case.price', 'case.materials', 'case.duration', + 'case.tags', 'case.status', 'case.views', 'case.likes', @@ -194,14 +211,13 @@ export class CaseService { queryBuilder.skip(skip).take(limit); queryBuilder.orderBy('case.createdAt', 'DESC'); - const [items, total] = await queryBuilder.getManyAndCount(); + const [list, total] = await queryBuilder.getManyAndCount(); return { - items, + list, total, page, - limit, - totalPages: Math.ceil(total / limit), + pageSize: limit, }; } } \ No newline at end of file diff --git a/后端/src/case/dto/case.dto.ts b/后端/src/case/dto/case.dto.ts index 637741c..44e9c7d 100644 --- a/后端/src/case/dto/case.dto.ts +++ b/后端/src/case/dto/case.dto.ts @@ -18,9 +18,13 @@ export class CreateCaseDto { @IsArray() afterImages?: string[]; - @IsEnum(['fabric', 'leather', 'cleaning', 'repair', 'custom']) + @IsEnum(['leather', 'fabric', 'functional', 'antique', 'office', 'cleaning', 'repair', 'custom']) serviceType: string; + @IsOptional() + @IsString() + location?: string; + @IsOptional() @Type(() => Number) @IsNumber() @@ -36,6 +40,14 @@ export class CreateCaseDto { @IsNumber() @Min(0) duration?: number; + + @IsOptional() + @IsArray() + images?: string[]; + + @IsOptional() + @IsArray() + tags?: string[]; } export class UpdateCaseDto { @@ -56,9 +68,13 @@ export class UpdateCaseDto { afterImages?: string[]; @IsOptional() - @IsEnum(['fabric', 'leather', 'cleaning', 'repair', 'custom']) + @IsEnum(['leather', 'fabric', 'functional', 'antique', 'office', 'cleaning', 'repair', 'custom']) serviceType?: string; + @IsOptional() + @IsString() + location?: string; + @IsOptional() @Type(() => Number) @IsNumber() @@ -78,11 +94,19 @@ export class UpdateCaseDto { @IsOptional() @IsEnum(['draft', 'published', 'archived']) status?: string; + + @IsOptional() + @IsArray() + images?: string[]; + + @IsOptional() + @IsArray() + tags?: string[]; } export class QueryCaseDto { @IsOptional() - @IsEnum(['fabric', 'leather', 'cleaning', 'repair', 'custom']) + @IsEnum(['leather', 'fabric', 'functional', 'antique', 'office', 'cleaning', 'repair', 'custom']) serviceType?: string; @IsOptional() diff --git a/后端/src/database/database-seeder.service.ts b/后端/src/database/database-seeder.service.ts new file mode 100644 index 0000000..40be1cd --- /dev/null +++ b/后端/src/database/database-seeder.service.ts @@ -0,0 +1,60 @@ +import { Injectable, OnModuleInit, Logger } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { User } from '../entities/user.entity'; +import * as bcrypt from 'bcrypt'; + +@Injectable() +export class DatabaseSeederService implements OnModuleInit { + private readonly logger = new Logger(DatabaseSeederService.name); + + constructor( + @InjectRepository(User) + private userRepository: Repository, + ) {} + + async onModuleInit() { + await this.seedDefaultAdmin(); + } + + private async seedDefaultAdmin() { + try { + // 检查是否已存在管理员账号 + const existingAdmin = await this.userRepository.findOne({ + where: { username: 'admin' }, + }); + + if (existingAdmin) { + // 如果存在但角色不是admin,则更新 + if (existingAdmin.role !== 'admin') { + await this.userRepository.update(existingAdmin.id, { role: 'admin' }); + this.logger.log('✅ 已将 admin 用户角色更新为管理员'); + } else { + this.logger.log('默认管理员账号已存在且角色正确'); + } + return; + } + + // 创建默认管理员账号 + const saltRounds = 10; + const hashedPassword = await bcrypt.hash('admin123', saltRounds); + + const adminUser = this.userRepository.create({ + username: 'admin', + email: 'admin@youyijia.com', + password: hashedPassword, + realName: '系统管理员', + phone: '18888888888', + role: 'admin', + status: 'active', + }); + + await this.userRepository.save(adminUser); + this.logger.log('✅ 默认管理员账号创建成功'); + this.logger.log(' 用户名: admin'); + this.logger.log(' 密码: admin123'); + } catch (error) { + this.logger.error('创建默认管理员账号失败:', error.message); + } + } +} diff --git a/后端/src/entities/booking.entity.ts b/后端/src/entities/booking.entity.ts index 32d4384..8723af7 100644 --- a/后端/src/entities/booking.entity.ts +++ b/后端/src/entities/booking.entity.ts @@ -10,11 +10,11 @@ export class Booking { @Column({ length: 32, unique: true }) bookingNumber: string; // 预约编号 - @ManyToOne(() => User) + @ManyToOne(() => User, { nullable: true }) @JoinColumn({ name: 'customerId' }) customer: User; - @Column() + @Column({ nullable: true }) customerId: number; @ManyToOne(() => Service) diff --git a/后端/src/entities/case.entity.ts b/后端/src/entities/case.entity.ts index 5bbcd9d..fa0a48a 100644 --- a/后端/src/entities/case.entity.ts +++ b/后端/src/entities/case.entity.ts @@ -18,13 +18,19 @@ export class Case { @Column({ type: 'json', nullable: true }) afterImages: string[]; + @Column({ type: 'json', nullable: true }) + images: string[]; + @Column({ type: 'enum', - enum: ['fabric', 'leather', 'cleaning', 'repair', 'custom'], + enum: ['leather', 'fabric', 'functional', 'antique', 'office', 'cleaning', 'repair', 'custom'], default: 'fabric' }) serviceType: string; + @Column({ length: 100, nullable: true }) + location: string; + @Column({ type: 'decimal', precision: 10, scale: 2, nullable: true }) price: number; @@ -34,6 +40,9 @@ export class Case { @Column({ type: 'int', default: 0 }) duration: number; // 工作天数 + @Column({ type: 'json', nullable: true }) + tags: string[]; + @Column({ type: 'enum', enum: ['draft', 'published', 'archived'], diff --git a/后端/src/entities/service.entity.ts b/后端/src/entities/service.entity.ts index 88cbd02..d104cd6 100644 --- a/后端/src/entities/service.entity.ts +++ b/后端/src/entities/service.entity.ts @@ -13,7 +13,7 @@ export class Service { @Column({ type: 'enum', - enum: ['fabric', 'leather', 'cleaning', 'repair', 'custom'], + enum: ['leather', 'fabric', 'functional', 'antique', 'office', 'cleaning', 'repair', 'custom'], unique: true }) type: string; @@ -21,6 +21,9 @@ export class Service { @Column({ type: 'decimal', precision: 10, scale: 2 }) basePrice: number; + @Column({ type: 'text', nullable: true }) + icon: string; // 服务图标URL + @Column({ type: 'json', nullable: true }) images: string[]; diff --git a/后端/src/service/dto/service.dto.ts b/后端/src/service/dto/service.dto.ts index fd9d596..d10234a 100644 --- a/后端/src/service/dto/service.dto.ts +++ b/后端/src/service/dto/service.dto.ts @@ -10,7 +10,7 @@ export class CreateServiceDto { @IsString() description: string; - @IsEnum(['fabric', 'leather', 'cleaning', 'repair', 'custom']) + @IsEnum(['leather', 'fabric', 'functional', 'antique', 'office', 'cleaning', 'repair', 'custom']) type: string; @IsNotEmpty({ message: '基础价格不能为空' }) @@ -19,6 +19,10 @@ export class CreateServiceDto { @Min(0) basePrice: number; + @IsOptional() + @IsString() + icon?: string; + @IsOptional() @IsArray() images?: string[]; @@ -49,7 +53,7 @@ export class UpdateServiceDto { description?: string; @IsOptional() - @IsEnum(['fabric', 'leather', 'cleaning', 'repair', 'custom']) + @IsEnum(['leather', 'fabric', 'functional', 'antique', 'office', 'cleaning', 'repair', 'custom']) type?: string; @IsOptional() @@ -58,6 +62,10 @@ export class UpdateServiceDto { @Min(0) basePrice?: number; + @IsOptional() + @IsString() + icon?: string; + @IsOptional() @IsArray() images?: string[]; @@ -84,10 +92,14 @@ export class UpdateServiceDto { export class QueryServiceDto { @IsOptional() - @IsEnum(['fabric', 'leather', 'cleaning', 'repair', 'custom']) + @IsEnum(['leather', 'fabric', 'functional', 'antique', 'office', 'cleaning', 'repair', 'custom']) type?: string; @IsOptional() @IsEnum(['active', 'inactive']) - status?: string = 'active'; + status?: string; + + @IsOptional() + @IsString() + keyword?: string; } \ No newline at end of file diff --git a/后端/src/service/service.controller.ts b/后端/src/service/service.controller.ts index ca91f88..258d363 100644 --- a/后端/src/service/service.controller.ts +++ b/后端/src/service/service.controller.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Post, Body, Patch, Param, Delete, Query, UseGuards } from '@nestjs/common'; +import { Controller, Get, Post, Body, Patch, Param, Delete, Query, UseGuards, HttpCode } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth, ApiQuery } from '@nestjs/swagger'; import { ServiceService } from './service.service'; import { CreateServiceDto, UpdateServiceDto, QueryServiceDto } from './dto/service.dto'; @@ -12,30 +12,47 @@ export class ServiceController { @ApiBearerAuth() @Post() + @HttpCode(200) @Roles('admin') @ApiOperation({ summary: '创建服务(管理员)' }) - @ApiResponse({ status: 201, description: '创建成功' }) + @ApiResponse({ status: 200, description: '创建成功' }) @ApiResponse({ status: 409, description: '服务类型已存在' }) - create(@Body() createServiceDto: CreateServiceDto) { - return this.serviceService.create(createServiceDto); + async create(@Body() createServiceDto: CreateServiceDto) { + const data = await this.serviceService.create(createServiceDto); + return { + code: 0, + message: '创建成功', + data, + }; } @Public() @Get() @ApiOperation({ summary: '获取服务列表' }) - @ApiQuery({ name: 'type', required: false, enum: ['fabric', 'leather', 'cleaning', 'repair', 'custom'] }) - @ApiQuery({ name: 'status', required: false, enum: ['active', 'inactive'], description: '默认为active' }) + @ApiQuery({ name: 'type', required: false, enum: ['leather', 'fabric', 'functional', 'antique', 'office', 'cleaning', 'repair', 'custom'] }) + @ApiQuery({ name: 'status', required: false, enum: ['active', 'inactive'] }) + @ApiQuery({ name: 'keyword', required: false, description: '搜索关键词' }) @ApiResponse({ status: 200, description: '获取成功' }) - findAll(@Query() query: QueryServiceDto) { - return this.serviceService.findAll(query); + async findAll(@Query() query: QueryServiceDto) { + const data = await this.serviceService.findAll(query); + return { + code: 0, + message: '获取成功', + data, + }; } @Public() @Get('active') @ApiOperation({ summary: '获取所有有效服务' }) @ApiResponse({ status: 200, description: '获取成功' }) - getActiveServices() { - return this.serviceService.getActiveServices(); + async getActiveServices() { + const data = await this.serviceService.getActiveServices(); + return { + code: 0, + message: '获取成功', + data, + }; } @Public() @@ -43,8 +60,13 @@ export class ServiceController { @ApiOperation({ summary: '根据ID获取服务详情' }) @ApiResponse({ status: 200, description: '获取成功' }) @ApiResponse({ status: 404, description: '服务不存在' }) - findOne(@Param('id') id: string) { - return this.serviceService.findOne(+id); + async findOne(@Param('id') id: string) { + const data = await this.serviceService.findOne(+id); + return { + code: 0, + message: '获取成功', + data, + }; } @Public() @@ -52,8 +74,13 @@ export class ServiceController { @ApiOperation({ summary: '根据类型获取服务' }) @ApiResponse({ status: 200, description: '获取成功' }) @ApiResponse({ status: 404, description: '服务类型不存在' }) - findByType(@Param('type') type: string) { - return this.serviceService.findByType(type); + async findByType(@Param('type') type: string) { + const data = await this.serviceService.findByType(type); + return { + code: 0, + message: '获取成功', + data, + }; } @ApiBearerAuth() @@ -63,8 +90,13 @@ export class ServiceController { @ApiResponse({ status: 200, description: '更新成功' }) @ApiResponse({ status: 404, description: '服务不存在' }) @ApiResponse({ status: 409, description: '服务类型已存在' }) - update(@Param('id') id: string, @Body() updateServiceDto: UpdateServiceDto) { - return this.serviceService.update(+id, updateServiceDto); + async update(@Param('id') id: string, @Body() updateServiceDto: UpdateServiceDto) { + const data = await this.serviceService.update(+id, updateServiceDto); + return { + code: 0, + message: '更新成功', + data, + }; } @ApiBearerAuth() @@ -73,8 +105,12 @@ export class ServiceController { @ApiOperation({ summary: '删除服务(管理员)' }) @ApiResponse({ status: 200, description: '删除成功' }) @ApiResponse({ status: 404, description: '服务不存在' }) - remove(@Param('id') id: string) { - return this.serviceService.remove(+id); + async remove(@Param('id') id: string) { + await this.serviceService.remove(+id); + return { + code: 0, + message: '删除成功', + }; } @ApiBearerAuth() @@ -83,8 +119,13 @@ export class ServiceController { @ApiOperation({ summary: '切换服务状态(管理员)' }) @ApiResponse({ status: 200, description: '状态切换成功' }) @ApiResponse({ status: 404, description: '服务不存在' }) - toggleStatus(@Param('id') id: string) { - return this.serviceService.toggleStatus(+id); + async toggleStatus(@Param('id') id: string) { + const data = await this.serviceService.toggleStatus(+id); + return { + code: 0, + message: '状态切换成功', + data, + }; } @ApiBearerAuth() @@ -92,7 +133,11 @@ export class ServiceController { @Roles('admin') @ApiOperation({ summary: '更新服务排序(管理员)' }) @ApiResponse({ status: 200, description: '排序更新成功' }) - updateSortOrder(@Body() serviceOrders: { id: number; sortOrder: number }[]) { - return this.serviceService.updateSortOrder(serviceOrders); + async updateSortOrder(@Body() serviceOrders: { id: number; sortOrder: number }[]) { + await this.serviceService.updateSortOrder(serviceOrders); + return { + code: 0, + message: '排序更新成功', + }; } } \ No newline at end of file diff --git a/后端/src/service/service.service.ts b/后端/src/service/service.service.ts index c6af16b..fdb39dd 100644 --- a/后端/src/service/service.service.ts +++ b/后端/src/service/service.service.ts @@ -29,8 +29,8 @@ export class ServiceService { return this.serviceRepository.save(service); } - async findAll(query: QueryServiceDto): Promise { - const { type, status } = query; + async findAll(query: QueryServiceDto): Promise { + const { type, status, keyword } = query; const queryBuilder = this.serviceRepository.createQueryBuilder('service'); if (type) { @@ -41,10 +41,22 @@ export class ServiceService { queryBuilder.andWhere('service.status = :status', { status }); } + if (keyword) { + queryBuilder.andWhere( + '(service.name LIKE :keyword OR service.description LIKE :keyword)', + { keyword: `%${keyword}%` } + ); + } + queryBuilder.orderBy('service.sortOrder', 'ASC'); queryBuilder.addOrderBy('service.createdAt', 'DESC'); - return queryBuilder.getMany(); + const services = await queryBuilder.getMany(); + + return { + list: services, + total: services.length + }; } async findOne(id: number): Promise { @@ -94,11 +106,16 @@ export class ServiceService { await this.serviceRepository.remove(service); } - async getActiveServices(): Promise { - return this.serviceRepository.find({ + async getActiveServices(): Promise { + const services = await this.serviceRepository.find({ where: { status: 'active' }, order: { sortOrder: 'ASC', createdAt: 'DESC' } }); + + return { + list: services, + total: services.length + }; } async updateSortOrder(serviceOrders: { id: number; sortOrder: number }[]): Promise { diff --git a/后端/src/user/user.controller.ts b/后端/src/user/user.controller.ts index 41eb04d..ae1d57b 100644 --- a/后端/src/user/user.controller.ts +++ b/后端/src/user/user.controller.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Post, Body, Patch, Param, Delete, UseGuards } from '@nestjs/common'; +import { Controller, Get, Post, Body, Patch, Param, Delete, UseGuards, HttpCode } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger'; import { UserService } from './user.service'; import { CreateUserDto, UpdateUserDto } from './dto/user.dto'; @@ -13,26 +13,45 @@ export class UserController { constructor(private readonly userService: UserService) {} @Post() + @HttpCode(200) @Roles('admin') @ApiOperation({ summary: '创建用户(管理员)' }) - @ApiResponse({ status: 201, description: '创建成功' }) - create(@Body() createUserDto: CreateUserDto) { - return this.userService.create(createUserDto); + @ApiResponse({ status: 200, description: '创建成功' }) + async create(@Body() createUserDto: CreateUserDto) { + const data = await this.userService.create(createUserDto); + return { + code: 0, + message: '创建成功', + data, + }; } @Get() @Roles('admin') @ApiOperation({ summary: '获取所有用户(管理员)' }) @ApiResponse({ status: 200, description: '获取成功' }) - findAll() { - return this.userService.findAll(); + async findAll() { + const list = await this.userService.findAll(); + return { + code: 0, + message: '获取成功', + data: { + list, + total: list.length, + }, + }; } @Get('profile') @ApiOperation({ summary: '获取当前用户信息' }) @ApiResponse({ status: 200, description: '获取成功' }) - getProfile(@CurrentUser() user: CurrentUserData) { - return this.userService.getUserProfile(user.userId); + async getProfile(@CurrentUser() user: CurrentUserData) { + const data = await this.userService.getUserProfile(user.userId); + return { + code: 0, + message: '获取成功', + data, + }; } @Get(':id') @@ -40,15 +59,25 @@ export class UserController { @ApiOperation({ summary: '根据ID获取用户(管理员)' }) @ApiResponse({ status: 200, description: '获取成功' }) @ApiResponse({ status: 404, description: '用户不存在' }) - findOne(@Param('id') id: string) { - return this.userService.findById(+id); + async findOne(@Param('id') id: string) { + const data = await this.userService.findById(+id); + return { + code: 0, + message: '获取成功', + data, + }; } @Patch('profile') @ApiOperation({ summary: '更新当前用户信息' }) @ApiResponse({ status: 200, description: '更新成功' }) - updateProfile(@CurrentUser() user: CurrentUserData, @Body() updateUserDto: UpdateUserDto) { - return this.userService.update(user.userId, updateUserDto); + async updateProfile(@CurrentUser() user: CurrentUserData, @Body() updateUserDto: UpdateUserDto) { + const data = await this.userService.update(user.userId, updateUserDto); + return { + code: 0, + message: '更新成功', + data, + }; } @Patch(':id') @@ -56,8 +85,13 @@ export class UserController { @ApiOperation({ summary: '更新用户信息(管理员)' }) @ApiResponse({ status: 200, description: '更新成功' }) @ApiResponse({ status: 404, description: '用户不存在' }) - update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) { - return this.userService.update(+id, updateUserDto); + async update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) { + const data = await this.userService.update(+id, updateUserDto); + return { + code: 0, + message: '更新成功', + data, + }; } @Delete(':id') @@ -65,7 +99,11 @@ export class UserController { @ApiOperation({ summary: '删除用户(管理员)' }) @ApiResponse({ status: 200, description: '删除成功' }) @ApiResponse({ status: 404, description: '用户不存在' }) - remove(@Param('id') id: string) { - return this.userService.remove(+id); + async remove(@Param('id') id: string) { + await this.userService.remove(+id); + return { + code: 0, + message: '删除成功', + }; } } \ No newline at end of file diff --git a/后端/update-admin-role.js b/后端/update-admin-role.js new file mode 100644 index 0000000..604e0c4 --- /dev/null +++ b/后端/update-admin-role.js @@ -0,0 +1,36 @@ +const mysql = require('mysql2/promise'); + +async function updateAdminRole() { + const connection = await mysql.createConnection({ + host: '8.130.78.179', + port: 9986, + user: 'sffx', + password: 'wF5WKm35Ddm5NDTn', + database: 'sffx' + }); + + try { + // 更新 admin 用户角色 + const [result] = await connection.execute( + 'UPDATE users SET role = ? WHERE username = ?', + ['admin', 'admin'] + ); + + console.log('✅ 更新成功!受影响的行数:', result.affectedRows); + + // 查询验证 + const [rows] = await connection.execute( + 'SELECT id, username, email, realName, role, status FROM users WHERE username = ?', + ['admin'] + ); + + console.log('\n当前 admin 用户信息:'); + console.table(rows); + } catch (error) { + console.error('❌ 更新失败:', error.message); + } finally { + await connection.end(); + } +} + +updateAdminRole(); diff --git a/管理后台/README.md b/管理后台/README.md new file mode 100644 index 0000000..cb0e878 --- /dev/null +++ b/管理后台/README.md @@ -0,0 +1,152 @@ +# 优艺家沙发翻新管理后台 + +基于 Vue 3 + Element Plus 的后台管理系统 + +## 技术栈 + +- **框架**: Vue 3.4 + TypeScript 5.3 +- **UI 组件**: Element Plus 2.5 +- **状态管理**: Pinia 2.1 +- **路由**: Vue Router 4.2 +- **HTTP 客户端**: Axios 1.6 +- **构建工具**: Vite 5 +- **日期处理**: Day.js + +## 功能模块 + +### 1. 数据概览 +- 案例、服务、预约、用户总数统计 +- 最新预约列表 +- 快捷操作入口 + +### 2. 案例管理 +- 案例列表查看(分页、搜索、筛选) +- 案例新增/编辑/删除 +- 图片预览 +- 状态管理 + +### 3. 服务管理 +- 服务列表查看 +- 服务新增/编辑/删除 +- 状态开关切换 +- 排序管理 + +### 4. 预约管理 +- 预约列表查看 +- 预约详情查看 +- 状态更新(待确认/已确认/进行中/已完成/已取消) +- 多条件搜索 + +### 5. 用户管理 +- 用户列表查看 +- 用户信息编辑 +- 角色管理(管理员/普通用户) +- 状态管理(启用/禁用) + +## 开发指南 + +### 安装依赖 + +```bash +npm install +``` + +### 启动开发服务器 + +```bash +npm run dev +``` + +访问地址:http://localhost:5173 + +### 构建生产版本 + +```bash +npm run build +``` + +### 预览生产构建 + +```bash +npm run preview +``` + +## 配置说明 + +### API 代理配置 + +开发环境下,所有 `/api` 请求会被代理到后端服务器 `http://localhost:3000` + +配置文件:`vite.config.ts` + +### 环境变量 + +可在项目根目录创建 `.env.development` 和 `.env.production` 文件配置不同环境的变量。 + +## 项目结构 + +``` +管理后台/ +├── src/ +│ ├── api/ # API 接口定义 +│ │ ├── auth.ts # 认证相关 +│ │ ├── case.ts # 案例管理 +│ │ ├── service.ts # 服务管理 +│ │ ├── booking.ts # 预约管理 +│ │ └── user.ts # 用户管理 +│ ├── layout/ # 布局组件 +│ │ └── index.vue # 主布局 +│ ├── router/ # 路由配置 +│ │ └── index.ts +│ ├── stores/ # Pinia 状态管理 +│ │ └── user.ts # 用户状态 +│ ├── styles/ # 全局样式 +│ │ └── index.css +│ ├── utils/ # 工具函数 +│ │ └── request.ts # Axios 封装 +│ ├── views/ # 页面组件 +│ │ ├── dashboard/ # 数据概览 +│ │ ├── case/ # 案例管理 +│ │ ├── service/ # 服务管理 +│ │ ├── booking/ # 预约管理 +│ │ ├── user/ # 用户管理 +│ │ └── login/ # 登录页 +│ ├── App.vue # 根组件 +│ └── main.ts # 入口文件 +├── index.html +├── vite.config.ts # Vite 配置 +├── tsconfig.json # TypeScript 配置 +└── package.json +``` + +## 默认账号 + +``` +用户名:admin +密码:admin123 +``` + +## 注意事项 + +1. **后端服务**: 确保后端服务已启动并运行在 `http://localhost:3000` +2. **认证**: 使用 JWT Token 进行身份认证,token 存储在 localStorage 中(key: `admin_token`) +3. **权限**: 所有管理接口需要 admin 角色权限 +4. **图片上传**: 当前版本使用 URL 输入方式,后续可集成文件上传功能 + +## 界面特色 + +- ✨ 渐变设计,美观大方 +- 🎨 品牌色 #d4a574(金棕色)贯穿全局 +- 📱 响应式布局,适配不同屏幕 +- 🎭 平滑动画过渡 +- 🎯 清晰的操作提示和反馈 +- 🔒 完善的权限控制 + +## 技术亮点 + +- 组合式 API (Composition API) +- TypeScript 类型安全 +- 自动导入 Vue、Pinia、Router API +- Element Plus 按需引入 +- 统一的 HTTP 请求封装和错误处理 +- 路由守卫自动鉴权 diff --git a/管理后台/auto-imports.d.ts b/管理后台/auto-imports.d.ts new file mode 100644 index 0000000..a606bd4 --- /dev/null +++ b/管理后台/auto-imports.d.ts @@ -0,0 +1,87 @@ +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck +// noinspection JSUnusedGlobalSymbols +// Generated by unplugin-auto-import +export {} +declare global { + const EffectScope: typeof import('vue')['EffectScope'] + const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate'] + const computed: typeof import('vue')['computed'] + const createApp: typeof import('vue')['createApp'] + const createPinia: typeof import('pinia')['createPinia'] + const customRef: typeof import('vue')['customRef'] + const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] + const defineComponent: typeof import('vue')['defineComponent'] + const defineStore: typeof import('pinia')['defineStore'] + const effectScope: typeof import('vue')['effectScope'] + const getActivePinia: typeof import('pinia')['getActivePinia'] + const getCurrentInstance: typeof import('vue')['getCurrentInstance'] + const getCurrentScope: typeof import('vue')['getCurrentScope'] + const h: typeof import('vue')['h'] + const inject: typeof import('vue')['inject'] + const isProxy: typeof import('vue')['isProxy'] + const isReactive: typeof import('vue')['isReactive'] + const isReadonly: typeof import('vue')['isReadonly'] + const isRef: typeof import('vue')['isRef'] + const mapActions: typeof import('pinia')['mapActions'] + const mapGetters: typeof import('pinia')['mapGetters'] + const mapState: typeof import('pinia')['mapState'] + const mapStores: typeof import('pinia')['mapStores'] + const mapWritableState: typeof import('pinia')['mapWritableState'] + const markRaw: typeof import('vue')['markRaw'] + const nextTick: typeof import('vue')['nextTick'] + const onActivated: typeof import('vue')['onActivated'] + const onBeforeMount: typeof import('vue')['onBeforeMount'] + const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave'] + const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate'] + const onBeforeUnmount: typeof import('vue')['onBeforeUnmount'] + const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'] + const onDeactivated: typeof import('vue')['onDeactivated'] + const onErrorCaptured: typeof import('vue')['onErrorCaptured'] + const onMounted: typeof import('vue')['onMounted'] + const onRenderTracked: typeof import('vue')['onRenderTracked'] + const onRenderTriggered: typeof import('vue')['onRenderTriggered'] + const onScopeDispose: typeof import('vue')['onScopeDispose'] + const onServerPrefetch: typeof import('vue')['onServerPrefetch'] + const onUnmounted: typeof import('vue')['onUnmounted'] + const onUpdated: typeof import('vue')['onUpdated'] + const onWatcherCleanup: typeof import('vue')['onWatcherCleanup'] + const provide: typeof import('vue')['provide'] + const reactive: typeof import('vue')['reactive'] + const readonly: typeof import('vue')['readonly'] + const ref: typeof import('vue')['ref'] + const resolveComponent: typeof import('vue')['resolveComponent'] + const setActivePinia: typeof import('pinia')['setActivePinia'] + const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix'] + const shallowReactive: typeof import('vue')['shallowReactive'] + const shallowReadonly: typeof import('vue')['shallowReadonly'] + const shallowRef: typeof import('vue')['shallowRef'] + const storeToRefs: typeof import('pinia')['storeToRefs'] + const toRaw: typeof import('vue')['toRaw'] + const toRef: typeof import('vue')['toRef'] + const toRefs: typeof import('vue')['toRefs'] + const toValue: typeof import('vue')['toValue'] + const triggerRef: typeof import('vue')['triggerRef'] + const unref: typeof import('vue')['unref'] + const useAttrs: typeof import('vue')['useAttrs'] + const useCssModule: typeof import('vue')['useCssModule'] + const useCssVars: typeof import('vue')['useCssVars'] + const useId: typeof import('vue')['useId'] + const useLink: typeof import('vue-router')['useLink'] + const useModel: typeof import('vue')['useModel'] + const useRoute: typeof import('vue-router')['useRoute'] + const useRouter: typeof import('vue-router')['useRouter'] + const useSlots: typeof import('vue')['useSlots'] + const useTemplateRef: typeof import('vue')['useTemplateRef'] + const watch: typeof import('vue')['watch'] + const watchEffect: typeof import('vue')['watchEffect'] + const watchPostEffect: typeof import('vue')['watchPostEffect'] + const watchSyncEffect: typeof import('vue')['watchSyncEffect'] +} +// for type re-export +declare global { + // @ts-ignore + export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue' + import('vue') +} diff --git a/管理后台/components.d.ts b/管理后台/components.d.ts new file mode 100644 index 0000000..2b8c778 --- /dev/null +++ b/管理后台/components.d.ts @@ -0,0 +1,51 @@ +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck +// Generated by unplugin-vue-components +// Read more: https://github.com/vuejs/core/pull/3399 +export {} + +declare module 'vue' { + export interface GlobalComponents { + ElAside: typeof import('element-plus/es')['ElAside'] + ElAvatar: typeof import('element-plus/es')['ElAvatar'] + ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb'] + ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] + ElButton: typeof import('element-plus/es')['ElButton'] + ElCard: typeof import('element-plus/es')['ElCard'] + ElCol: typeof import('element-plus/es')['ElCol'] + ElContainer: typeof import('element-plus/es')['ElContainer'] + ElDescriptions: typeof import('element-plus/es')['ElDescriptions'] + ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem'] + ElDialog: typeof import('element-plus/es')['ElDialog'] + ElDropdown: typeof import('element-plus/es')['ElDropdown'] + ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] + ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] + ElForm: typeof import('element-plus/es')['ElForm'] + ElFormItem: typeof import('element-plus/es')['ElFormItem'] + ElHeader: typeof import('element-plus/es')['ElHeader'] + ElIcon: typeof import('element-plus/es')['ElIcon'] + ElImage: typeof import('element-plus/es')['ElImage'] + ElInput: typeof import('element-plus/es')['ElInput'] + ElInputNumber: typeof import('element-plus/es')['ElInputNumber'] + ElMain: typeof import('element-plus/es')['ElMain'] + ElMenu: typeof import('element-plus/es')['ElMenu'] + ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] + ElOption: typeof import('element-plus/es')['ElOption'] + ElPagination: typeof import('element-plus/es')['ElPagination'] + ElRadio: typeof import('element-plus/es')['ElRadio'] + ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] + ElRow: typeof import('element-plus/es')['ElRow'] + ElSelect: typeof import('element-plus/es')['ElSelect'] + ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] + ElSwitch: typeof import('element-plus/es')['ElSwitch'] + ElTable: typeof import('element-plus/es')['ElTable'] + ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] + ElTag: typeof import('element-plus/es')['ElTag'] + RouterLink: typeof import('vue-router')['RouterLink'] + RouterView: typeof import('vue-router')['RouterView'] + } + export interface ComponentCustomProperties { + vLoading: typeof import('element-plus/es')['ElLoadingDirective'] + } +} diff --git a/管理后台/index.html b/管理后台/index.html new file mode 100644 index 0000000..5f5d4af --- /dev/null +++ b/管理后台/index.html @@ -0,0 +1,13 @@ + + + + + + + 优艺家沙发翻新 - 管理后台 + + + + + + diff --git a/管理后台/package-lock.json b/管理后台/package-lock.json new file mode 100644 index 0000000..0ac12f5 --- /dev/null +++ b/管理后台/package-lock.json @@ -0,0 +1,2536 @@ +{ + "name": "sofa-admin", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sofa-admin", + "version": "1.0.0", + "dependencies": { + "@element-plus/icons-vue": "^2.3.1", + "axios": "^1.6.0", + "dayjs": "^1.11.10", + "element-plus": "^2.5.0", + "pinia": "^2.1.7", + "vue": "^3.4.0", + "vue-router": "^4.2.5" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.0.0", + "typescript": "^5.3.0", + "unplugin-auto-import": "^0.17.0", + "unplugin-vue-components": "^0.26.0", + "vite": "^5.0.0", + "vue-tsc": "^1.8.0" + } + }, + "node_modules/@antfu/utils": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz", + "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", + "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", + "dependencies": { + "@babel/types": "^7.28.6" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@element-plus/icons-vue": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz", + "integrity": "sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==", + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.4.tgz", + "integrity": "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.5.tgz", + "integrity": "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==", + "dependencies": { + "@floating-ui/core": "^1.7.4", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==" + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@popperjs/core": { + "name": "@sxzz/popperjs-es", + "version": "2.11.7", + "resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz", + "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.0.tgz", + "integrity": "sha512-tPgXB6cDTndIe1ah7u6amCI1T0SsnlOuKgg10Xh3uizJk4e5M1JGaUMk7J4ciuAUcFpbOiNhm2XIjP9ON0dUqA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.0.tgz", + "integrity": "sha512-sa4LyseLLXr1onr97StkU1Nb7fWcg6niokTwEVNOO7awaKaoRObQ54+V/hrF/BP1noMEaaAW6Fg2d/CfLiq3Mg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.0.tgz", + "integrity": "sha512-/NNIj9A7yLjKdmkx5dC2XQ9DmjIECpGpwHoGmA5E1AhU0fuICSqSWScPhN1yLCkEdkCwJIDu2xIeLPs60MNIVg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.0.tgz", + "integrity": "sha512-xoh8abqgPrPYPr7pTYipqnUi1V3em56JzE/HgDgitTqZBZ3yKCWI+7KUkceM6tNweyUKYru1UMi7FC060RyKwA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.0.tgz", + "integrity": "sha512-PCkMh7fNahWSbA0OTUQ2OpYHpjZZr0hPr8lId8twD7a7SeWrvT3xJVyza+dQwXSSq4yEQTMoXgNOfMCsn8584g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.0.tgz", + "integrity": "sha512-1j3stGx+qbhXql4OCDZhnK7b01s6rBKNybfsX+TNrEe9JNq4DLi1yGiR1xW+nL+FNVvI4D02PUnl6gJ/2y6WJA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.0.tgz", + "integrity": "sha512-eyrr5W08Ms9uM0mLcKfM/Uzx7hjhz2bcjv8P2uynfj0yU8GGPdz8iYrBPhiLOZqahoAMB8ZiolRZPbbU2MAi6Q==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.0.tgz", + "integrity": "sha512-Xds90ITXJCNyX9pDhqf85MKWUI4lqjiPAipJ8OLp8xqI2Ehk+TCVhF9rvOoN8xTbcafow3QOThkNnrM33uCFQA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.0.tgz", + "integrity": "sha512-Xws2KA4CLvZmXjy46SQaXSejuKPhwVdaNinldoYfqruZBaJHqVo6hnRa8SDo9z7PBW5x84SH64+izmldCgbezw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.0.tgz", + "integrity": "sha512-hrKXKbX5FdaRJj7lTMusmvKbhMJSGWJ+w++4KmjiDhpTgNlhYobMvKfDoIWecy4O60K6yA4SnztGuNTQF+Lplw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.0.tgz", + "integrity": "sha512-6A+nccfSDGKsPm00d3xKcrsBcbqzCTAukjwWK6rbuAnB2bHaL3r9720HBVZ/no7+FhZLz/U3GwwZZEh6tOSI8Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.0.tgz", + "integrity": "sha512-4P1VyYUe6XAJtQH1Hh99THxr0GKMMwIXsRNOceLrJnaHTDgk1FTcTimDgneRJPvB3LqDQxUmroBclQ1S0cIJwQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.0.tgz", + "integrity": "sha512-8Vv6pLuIZCMcgXre6c3nOPhE0gjz1+nZP6T+hwWjr7sVH8k0jRkH+XnfjjOTglyMBdSKBPPz54/y1gToSKwrSQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.0.tgz", + "integrity": "sha512-r1te1M0Sm2TBVD/RxBPC6RZVwNqUTwJTA7w+C/IW5v9Ssu6xmxWEi+iJQlpBhtUiT1raJ5b48pI8tBvEjEFnFA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.0.tgz", + "integrity": "sha512-say0uMU/RaPm3CDQLxUUTF2oNWL8ysvHkAjcCzV2znxBr23kFfaxocS9qJm+NdkRhF8wtdEEAJuYcLPhSPbjuQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.0.tgz", + "integrity": "sha512-/MU7/HizQGsnBREtRpcSbSV1zfkoxSTR7wLsRmBPQ8FwUj5sykrP1MyJTvsxP5KBq9SyE6kH8UQQQwa0ASeoQQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.0.tgz", + "integrity": "sha512-Q9eh+gUGILIHEaJf66aF6a414jQbDnn29zeu0eX3dHMuysnhTvsUvZTCAyZ6tJhUjnvzBKE4FtuaYxutxRZpOg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.0.tgz", + "integrity": "sha512-OR5p5yG5OKSxHReWmwvM0P+VTPMwoBS45PXTMYaskKQqybkS3Kmugq1W+YbNWArF8/s7jQScgzXUhArzEQ7x0A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.0.tgz", + "integrity": "sha512-XeatKzo4lHDsVEbm1XDHZlhYZZSQYym6dg2X/Ko0kSFgio+KXLsxwJQprnR48GvdIKDOpqWqssC3iBCjoMcMpw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.0.tgz", + "integrity": "sha512-Lu71y78F5qOfYmubYLHPcJm74GZLU6UJ4THkf/a1K7Tz2ycwC2VUbsqbJAXaR6Bx70SRdlVrt2+n5l7F0agTUw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.0.tgz", + "integrity": "sha512-v5xwKDWcu7qhAEcsUubiav7r+48Uk/ENWdr82MBZZRIm7zThSxCIVDfb3ZeRRq9yqk+oIzMdDo6fCcA5DHfMyA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.0.tgz", + "integrity": "sha512-XnaaaSMGSI6Wk8F4KK3QP7GfuuhjGchElsVerCplUuxRIzdvZ7hRBpLR0omCmw+kI2RFJB80nenhOoGXlJ5TfQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.0.tgz", + "integrity": "sha512-3K1lP+3BXY4t4VihLw5MEg6IZD3ojSYzqzBG571W3kNQe4G4CcFpSUQVgurYgib5d+YaCjeFow8QivWp8vuSvA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.0.tgz", + "integrity": "sha512-MDk610P/vJGc5L5ImE4k5s+GZT3en0KoK1MKPXCRgzmksAMk79j4h3k1IerxTNqwDLxsGxStEZVBqG0gIqZqoA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.0.tgz", + "integrity": "sha512-Zv7v6q6aV+VslnpwzqKAmrk5JdVkLUzok2208ZXGipjb+msxBr/fJPZyeEXiFgH7k62Ak0SLIfxQRZQvTuf7rQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==" + }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", + "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", + "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", + "dev": true, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@volar/language-core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-1.11.1.tgz", + "integrity": "sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==", + "dev": true, + "dependencies": { + "@volar/source-map": "1.11.1" + } + }, + "node_modules/@volar/source-map": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-1.11.1.tgz", + "integrity": "sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==", + "dev": true, + "dependencies": { + "muggle-string": "^0.3.1" + } + }, + "node_modules/@volar/typescript": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-1.11.1.tgz", + "integrity": "sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==", + "dev": true, + "dependencies": { + "@volar/language-core": "1.11.1", + "path-browserify": "^1.0.1" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.27.tgz", + "integrity": "sha512-gnSBQjZA+//qDZen+6a2EdHqJ68Z7uybrMf3SPjEGgG4dicklwDVmMC1AeIHxtLVPT7sn6sH1KOO+tS6gwOUeQ==", + "dependencies": { + "@babel/parser": "^7.28.5", + "@vue/shared": "3.5.27", + "entities": "^7.0.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.27.tgz", + "integrity": "sha512-oAFea8dZgCtVVVTEC7fv3T5CbZW9BxpFzGGxC79xakTr6ooeEqmRuvQydIiDAkglZEAd09LgVf1RoDnL54fu5w==", + "dependencies": { + "@vue/compiler-core": "3.5.27", + "@vue/shared": "3.5.27" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.27.tgz", + "integrity": "sha512-sHZu9QyDPeDmN/MRoshhggVOWE5WlGFStKFwu8G52swATgSny27hJRWteKDSUUzUH+wp+bmeNbhJnEAel/auUQ==", + "dependencies": { + "@babel/parser": "^7.28.5", + "@vue/compiler-core": "3.5.27", + "@vue/compiler-dom": "3.5.27", + "@vue/compiler-ssr": "3.5.27", + "@vue/shared": "3.5.27", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.27.tgz", + "integrity": "sha512-Sj7h+JHt512fV1cTxKlYhg7qxBvack+BGncSpH+8vnN+KN95iPIcqB5rsbblX40XorP+ilO7VIKlkuu3Xq2vjw==", + "dependencies": { + "@vue/compiler-dom": "3.5.27", + "@vue/shared": "3.5.27" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==" + }, + "node_modules/@vue/language-core": { + "version": "1.8.27", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-1.8.27.tgz", + "integrity": "sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==", + "dev": true, + "dependencies": { + "@volar/language-core": "~1.11.1", + "@volar/source-map": "~1.11.1", + "@vue/compiler-dom": "^3.3.0", + "@vue/shared": "^3.3.0", + "computeds": "^0.0.1", + "minimatch": "^9.0.3", + "muggle-string": "^0.3.1", + "path-browserify": "^1.0.1", + "vue-template-compiler": "^2.7.14" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.27.tgz", + "integrity": "sha512-vvorxn2KXfJ0nBEnj4GYshSgsyMNFnIQah/wczXlsNXt+ijhugmW+PpJ2cNPe4V6jpnBcs0MhCODKllWG+nvoQ==", + "dependencies": { + "@vue/shared": "3.5.27" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.27.tgz", + "integrity": "sha512-fxVuX/fzgzeMPn/CLQecWeDIFNt3gQVhxM0rW02Tvp/YmZfXQgcTXlakq7IMutuZ/+Ogbn+K0oct9J3JZfyk3A==", + "dependencies": { + "@vue/reactivity": "3.5.27", + "@vue/shared": "3.5.27" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.27.tgz", + "integrity": "sha512-/QnLslQgYqSJ5aUmb5F0z0caZPGHRB8LEAQ1s81vHFM5CBfnun63rxhvE/scVb/j3TbBuoZwkJyiLCkBluMpeg==", + "dependencies": { + "@vue/reactivity": "3.5.27", + "@vue/runtime-core": "3.5.27", + "@vue/shared": "3.5.27", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.27.tgz", + "integrity": "sha512-qOz/5thjeP1vAFc4+BY3Nr6wxyLhpeQgAE/8dDtKo6a6xdk+L4W46HDZgNmLOBUDEkFXV3G7pRiUqxjX0/2zWA==", + "dependencies": { + "@vue/compiler-ssr": "3.5.27", + "@vue/shared": "3.5.27" + }, + "peerDependencies": { + "vue": "3.5.27" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.27.tgz", + "integrity": "sha512-dXr/3CgqXsJkZ0n9F3I4elY8wM9jMJpP3pvRG52r6m0tu/MsAFIe6JpXVGeNMd/D9F4hQynWT8Rfuj0bdm9kFQ==" + }, + "node_modules/@vueuse/core": { + "version": "10.11.1", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.11.1.tgz", + "integrity": "sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==", + "dependencies": { + "@types/web-bluetooth": "^0.0.20", + "@vueuse/metadata": "10.11.1", + "@vueuse/shared": "10.11.1", + "vue-demi": ">=0.14.8" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/metadata": { + "version": "10.11.1", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.11.1.tgz", + "integrity": "sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "10.11.1", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.11.1.tgz", + "integrity": "sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==", + "dependencies": { + "vue-demi": ">=0.14.8" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.4.tgz", + "integrity": "sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/computeds": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz", + "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==", + "dev": true + }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==" + }, + "node_modules/dayjs": { + "version": "1.11.19", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz", + "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==" + }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/element-plus": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.13.1.tgz", + "integrity": "sha512-eG4BDBGdAsUGN6URH1PixzZb0ngdapLivIk1meghS1uEueLvQ3aljSKrCt5x6sYb6mUk8eGtzTQFgsPmLavQcA==", + "dependencies": { + "@ctrl/tinycolor": "^3.4.1", + "@element-plus/icons-vue": "^2.3.2", + "@floating-ui/dom": "^1.0.1", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", + "@types/lodash": "^4.17.20", + "@types/lodash-es": "^4.17.12", + "@vueuse/core": "^10.11.0", + "async-validator": "^4.2.5", + "dayjs": "^1.11.19", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "lodash-unified": "^1.0.3", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.2.0" + }, + "peerDependencies": { + "vue": "^3.3.0" + } + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true + }, + "node_modules/local-pkg": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.1.tgz", + "integrity": "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==", + "dev": true, + "dependencies": { + "mlly": "^1.7.3", + "pkg-types": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==" + }, + "node_modules/lodash-es": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", + "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==" + }, + "node_modules/lodash-unified": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.3.tgz", + "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==", + "peerDependencies": { + "@types/lodash-es": "*", + "lodash": "*", + "lodash-es": "*" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mlly": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", + "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", + "dev": true, + "dependencies": { + "acorn": "^8.15.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.1" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/muggle-string": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.3.1.tgz", + "integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-wheel-es": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", + "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==" + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pinia": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.3.1.tgz", + "integrity": "sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==", + "dependencies": { + "@vue/devtools-api": "^6.6.3", + "vue-demi": "^0.14.10" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "typescript": ">=4.4.4", + "vue": "^2.7.0 || ^3.5.11" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ] + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.0.tgz", + "integrity": "sha512-e5lPJi/aui4TO1LpAXIRLySmwXSE8k3b9zoGfd42p67wzxog4WHjiZF3M2uheQih4DGyc25QEV4yRBbpueNiUA==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.57.0", + "@rollup/rollup-android-arm64": "4.57.0", + "@rollup/rollup-darwin-arm64": "4.57.0", + "@rollup/rollup-darwin-x64": "4.57.0", + "@rollup/rollup-freebsd-arm64": "4.57.0", + "@rollup/rollup-freebsd-x64": "4.57.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.0", + "@rollup/rollup-linux-arm-musleabihf": "4.57.0", + "@rollup/rollup-linux-arm64-gnu": "4.57.0", + "@rollup/rollup-linux-arm64-musl": "4.57.0", + "@rollup/rollup-linux-loong64-gnu": "4.57.0", + "@rollup/rollup-linux-loong64-musl": "4.57.0", + "@rollup/rollup-linux-ppc64-gnu": "4.57.0", + "@rollup/rollup-linux-ppc64-musl": "4.57.0", + "@rollup/rollup-linux-riscv64-gnu": "4.57.0", + "@rollup/rollup-linux-riscv64-musl": "4.57.0", + "@rollup/rollup-linux-s390x-gnu": "4.57.0", + "@rollup/rollup-linux-x64-gnu": "4.57.0", + "@rollup/rollup-linux-x64-musl": "4.57.0", + "@rollup/rollup-openbsd-x64": "4.57.0", + "@rollup/rollup-openharmony-arm64": "4.57.0", + "@rollup/rollup-win32-arm64-msvc": "4.57.0", + "@rollup/rollup-win32-ia32-msvc": "4.57.0", + "@rollup/rollup-win32-x64-gnu": "4.57.0", + "@rollup/rollup-win32-x64-msvc": "4.57.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scule": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz", + "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", + "dev": true + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-literal": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.1.tgz", + "integrity": "sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==", + "dev": true, + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", + "dev": true + }, + "node_modules/unimport": { + "version": "3.14.6", + "resolved": "https://registry.npmjs.org/unimport/-/unimport-3.14.6.tgz", + "integrity": "sha512-CYvbDaTT04Rh8bmD8jz3WPmHYZRG/NnvYVzwD6V1YAlvvKROlAeNDUBhkBGzNav2RKaeuXvlWYaa1V4Lfi/O0g==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.1.4", + "acorn": "^8.14.0", + "escape-string-regexp": "^5.0.0", + "estree-walker": "^3.0.3", + "fast-glob": "^3.3.3", + "local-pkg": "^1.0.0", + "magic-string": "^0.30.17", + "mlly": "^1.7.4", + "pathe": "^2.0.1", + "picomatch": "^4.0.2", + "pkg-types": "^1.3.0", + "scule": "^1.3.0", + "strip-literal": "^2.1.1", + "unplugin": "^1.16.1" + } + }, + "node_modules/unimport/node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "dev": true + }, + "node_modules/unimport/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/unimport/node_modules/local-pkg": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", + "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", + "dev": true, + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/unimport/node_modules/local-pkg/node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "dev": true, + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, + "node_modules/unplugin": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.16.1.tgz", + "integrity": "sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==", + "dev": true, + "dependencies": { + "acorn": "^8.14.0", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/unplugin-auto-import": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/unplugin-auto-import/-/unplugin-auto-import-0.17.8.tgz", + "integrity": "sha512-CHryj6HzJ+n4ASjzwHruD8arhbdl+UXvhuAIlHDs15Y/IMecG3wrf7FVg4pVH/DIysbq/n0phIjNHAjl7TG7Iw==", + "dev": true, + "dependencies": { + "@antfu/utils": "^0.7.10", + "@rollup/pluginutils": "^5.1.0", + "fast-glob": "^3.3.2", + "local-pkg": "^0.5.0", + "magic-string": "^0.30.10", + "minimatch": "^9.0.4", + "unimport": "^3.7.2", + "unplugin": "^1.11.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@nuxt/kit": "^3.2.2", + "@vueuse/core": "*" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + }, + "@vueuse/core": { + "optional": true + } + } + }, + "node_modules/unplugin-vue-components": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.26.0.tgz", + "integrity": "sha512-s7IdPDlnOvPamjunVxw8kNgKNK8A5KM1YpK5j/p97jEKTjlPNrA0nZBiSfAKKlK1gWZuyWXlKL5dk3EDw874LQ==", + "dev": true, + "dependencies": { + "@antfu/utils": "^0.7.6", + "@rollup/pluginutils": "^5.0.4", + "chokidar": "^3.5.3", + "debug": "^4.3.4", + "fast-glob": "^3.3.1", + "local-pkg": "^0.4.3", + "magic-string": "^0.30.3", + "minimatch": "^9.0.3", + "resolve": "^1.22.4", + "unplugin": "^1.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@babel/parser": "^7.15.8", + "@nuxt/kit": "^3.2.2", + "vue": "2 || 3" + }, + "peerDependenciesMeta": { + "@babel/parser": { + "optional": true + }, + "@nuxt/kit": { + "optional": true + } + } + }, + "node_modules/unplugin-vue-components/node_modules/local-pkg": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", + "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.27.tgz", + "integrity": "sha512-aJ/UtoEyFySPBGarREmN4z6qNKpbEguYHMmXSiOGk69czc+zhs0NF6tEFrY8TZKAl8N/LYAkd4JHVd5E/AsSmw==", + "dependencies": { + "@vue/compiler-dom": "3.5.27", + "@vue/compiler-sfc": "3.5.27", + "@vue/runtime-dom": "3.5.27", + "@vue/server-renderer": "3.5.27", + "@vue/shared": "3.5.27" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/vue-router": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz", + "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/vue-template-compiler": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz", + "integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==", + "dev": true, + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, + "node_modules/vue-tsc": { + "version": "1.8.27", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-1.8.27.tgz", + "integrity": "sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==", + "dev": true, + "dependencies": { + "@volar/typescript": "~1.11.1", + "@vue/language-core": "1.8.27", + "semver": "^7.5.4" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true + } + } +} diff --git a/管理后台/package.json b/管理后台/package.json new file mode 100644 index 0000000..b1b0598 --- /dev/null +++ b/管理后台/package.json @@ -0,0 +1,27 @@ +{ + "name": "sofa-admin", + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vue-tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "vue": "^3.4.0", + "vue-router": "^4.2.5", + "pinia": "^2.1.7", + "axios": "^1.6.0", + "element-plus": "^2.5.0", + "@element-plus/icons-vue": "^2.3.1", + "dayjs": "^1.11.10" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.0.0", + "typescript": "^5.3.0", + "vite": "^5.0.0", + "vue-tsc": "^1.8.0", + "unplugin-auto-import": "^0.17.0", + "unplugin-vue-components": "^0.26.0" + } +} diff --git a/管理后台/src/App.vue b/管理后台/src/App.vue new file mode 100644 index 0000000..f77d050 --- /dev/null +++ b/管理后台/src/App.vue @@ -0,0 +1,13 @@ + + + + + + + diff --git a/管理后台/src/api/auth.ts b/管理后台/src/api/auth.ts new file mode 100644 index 0000000..5f79abf --- /dev/null +++ b/管理后台/src/api/auth.ts @@ -0,0 +1,22 @@ +import request from '@/utils/request' + +export interface LoginParams { + username: string + password: string +} + +export interface LoginResult { + user: any + access_token: string + refresh_token: string +} + +// 登录 +export const login = (data: LoginParams) => { + return request.post('/auth/login', data) +} + +// 刷新 token +export const refreshToken = (refreshToken: string) => { + return request.post('/auth/refresh', { refresh_token: refreshToken }) +} diff --git a/管理后台/src/api/booking.ts b/管理后台/src/api/booking.ts new file mode 100644 index 0000000..ed8878f --- /dev/null +++ b/管理后台/src/api/booking.ts @@ -0,0 +1,54 @@ +import request from '@/utils/request' + +export interface Booking { + id: number + bookingNumber: string + serviceId: number + userId: number + contactName: string + contactPhone: string + address: string + appointmentTime: string + requirements: string + images: string[] + status: string + quotedPrice: number + finalPrice: number + notes: string + assignedWorkerId: number + service: any + user: any + createdAt: string + updatedAt: string +} + +export interface QueryParams { + status?: string + page?: number + limit?: number +} + +// 获取预约列表 +export const getBookingList = (params?: QueryParams) => { + return request.get('/booking', { params }) +} + +// 获取预约详情 +export const getBookingDetail = (id: number) => { + return request.get(`/booking/${id}`) +} + +// 更新预约 +export const updateBooking = (id: number, data: Partial) => { + return request.patch(`/booking/${id}`, data) +} + +// 取消预约 +export const cancelBooking = (id: number) => { + return request.post(`/booking/${id}/cancel`) +} + +// 删除预约 +export const deleteBooking = (id: number) => { + return request.delete(`/booking/${id}`) +} diff --git a/管理后台/src/api/case.ts b/管理后台/src/api/case.ts new file mode 100644 index 0000000..0c3be22 --- /dev/null +++ b/管理后台/src/api/case.ts @@ -0,0 +1,56 @@ +import request from '@/utils/request' + +export interface Case { + id: number + title: string + description: string + beforeImages: string[] + afterImages: string[] + serviceType: string + price: number + materials: string + duration: number + status: string + views: number + likes: number + user: any + createdAt: string + updatedAt: string +} + +export interface QueryParams { + serviceType?: string + status?: string + page?: number + limit?: number +} + +// 获取案例列表 +export const getCaseList = (params?: QueryParams) => { + return request.get('/cases', { params }) +} + +// 获取案例详情 +export const getCaseDetail = (id: number) => { + return request.get(`/cases/${id}`) +} + +// 创建案例 +export const createCase = (data: Partial) => { + return request.post('/cases', data) +} + +// 更新案例 +export const updateCase = (id: number, data: Partial) => { + return request.patch(`/cases/${id}`, data) +} + +// 删除案例 +export const deleteCase = (id: number) => { + return request.delete(`/cases/${id}`) +} + +// 点赞案例 +export const likeCase = (id: number) => { + return request.post(`/cases/${id}/like`) +} diff --git a/管理后台/src/api/service.ts b/管理后台/src/api/service.ts new file mode 100644 index 0000000..d906aa7 --- /dev/null +++ b/管理后台/src/api/service.ts @@ -0,0 +1,66 @@ +import request from '@/utils/request' + +export interface Service { + id: number + name: string + description: string + type: string // 服务类型:leather, fabric, functional等 + category?: string // 别名,与type相同 + basePrice: number // 后端字段 + price?: number // 前端别名 + images: string[] + features: string[] + estimatedDays: number + icon?: string // 图标URL + duration?: string // 时长描述 + status: string + sortOrder: number + createdAt: string + updatedAt: string +} + +export interface QueryParams { + type?: string + status?: string + keyword?: string +} + +// 获取服务列表 +export const getServiceList = (params?: QueryParams) => { + return request.get('/services', { params }) +} + +// 获取服务详情 +export const getServiceDetail = (id: number) => { + return request.get(`/services/${id}`) +} + +// 创建服务 +export const createService = (data: Partial) => { + return request.post('/services', data) +} + +// 更新服务 +export const updateService = (id: number, data: Partial) => { + return request.patch(`/services/${id}`, data) +} + +// 删除服务 +export const deleteService = (id: number) => { + return request.delete(`/services/${id}`) +} + +// 切换服务状态 +export const toggleServiceStatus = (id: number) => { + return request.patch(`/services/${id}/toggle-status`) +} + +// 更新排序 +export const updateSortOrder = (serviceOrders: { id: number; sortOrder: number }[]) => { + return request.patch('/services/sort-order', serviceOrders) +} + +// 获取有效服务列表 +export const getActiveServices = () => { + return request.get('/services/active') +} diff --git a/管理后台/src/api/user.ts b/管理后台/src/api/user.ts new file mode 100644 index 0000000..4162a20 --- /dev/null +++ b/管理后台/src/api/user.ts @@ -0,0 +1,41 @@ +import request from '@/utils/request' + +export interface User { + id: number + username: string + email: string + realName: string + phone: string + avatar: string + role: string + status: string + openid: string + unionid: string + createdAt: string + updatedAt: string +} + +// 获取用户列表 +export const getUserList = () => { + return request.get('/users') +} + +// 获取用户详情 +export const getUserDetail = (id: number) => { + return request.get(`/users/${id}`) +} + +// 更新用户 +export const updateUser = (id: number, data: Partial) => { + return request.patch(`/users/${id}`, data) +} + +// 删除用户 +export const deleteUser = (id: number) => { + return request.delete(`/users/${id}`) +} + +// 获取当前用户信息 +export const getUserProfile = () => { + return request.get('/users/profile') +} diff --git a/管理后台/src/layout/index.vue b/管理后台/src/layout/index.vue new file mode 100644 index 0000000..f84f214 --- /dev/null +++ b/管理后台/src/layout/index.vue @@ -0,0 +1,278 @@ + + + + + + + + 优艺家管理 + + + + + + + + + {{ route.meta?.title }} + + + + + + + + {{ route.meta?.title }} + + + + + + {{ child.meta?.title }} + + + + + + + + + + + + + + + + + {{ item.meta?.title }} + + + + + + + + + + + {{ userStore.userInfo?.realName || userStore.userInfo?.username }} + + + + + + 个人中心 + + + + 退出登录 + + + + + + + + + + + + + + + + + + + + + diff --git a/管理后台/src/main.ts b/管理后台/src/main.ts new file mode 100644 index 0000000..248d2dd --- /dev/null +++ b/管理后台/src/main.ts @@ -0,0 +1,23 @@ +import { createApp } from 'vue' +import { createPinia } from 'pinia' +import ElementPlus from 'element-plus' +import 'element-plus/dist/index.css' +import 'element-plus/theme-chalk/dark/css-vars.css' +import * as ElementPlusIconsVue from '@element-plus/icons-vue' +import zhCn from 'element-plus/dist/locale/zh-cn.mjs' +import router from './router' +import App from './App.vue' +import './styles/index.css' + +const app = createApp(App) + +// 注册所有图标 +for (const [key, component] of Object.entries(ElementPlusIconsVue)) { + app.component(key, component) +} + +app.use(createPinia()) +app.use(router) +app.use(ElementPlus, { locale: zhCn }) + +app.mount('#app') diff --git a/管理后台/src/router/index.ts b/管理后台/src/router/index.ts new file mode 100644 index 0000000..f8bcc0c --- /dev/null +++ b/管理后台/src/router/index.ts @@ -0,0 +1,103 @@ +import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router' +import { useUserStore } from '@/stores/user' +import Layout from '@/layout/index.vue' + +const routes: RouteRecordRaw[] = [ + { + path: '/login', + name: 'Login', + component: () => import('@/views/login/index.vue'), + meta: { title: '登录' } + }, + { + path: '/', + component: Layout, + redirect: '/dashboard', + children: [ + { + path: 'dashboard', + name: 'Dashboard', + component: () => import('@/views/dashboard/index.vue'), + meta: { title: '数据概览', icon: 'DataLine' } + } + ] + }, + { + path: '/case', + component: Layout, + redirect: '/case/list', + meta: { title: '案例管理', icon: 'Picture' }, + children: [ + { + path: 'list', + name: 'CaseList', + component: () => import('@/views/case/list.vue'), + meta: { title: '案例列表', icon: 'List' } + } + ] + }, + { + path: '/service', + component: Layout, + redirect: '/service/list', + meta: { title: '服务管理', icon: 'Setting' }, + children: [ + { + path: 'list', + name: 'ServiceList', + component: () => import('@/views/service/list.vue'), + meta: { title: '服务列表', icon: 'List' } + } + ] + }, + { + path: '/booking', + component: Layout, + redirect: '/booking/list', + meta: { title: '预约管理', icon: 'Calendar' }, + children: [ + { + path: 'list', + name: 'BookingList', + component: () => import('@/views/booking/list.vue'), + meta: { title: '预约列表', icon: 'List' } + } + ] + }, + { + path: '/user', + component: Layout, + redirect: '/user/list', + meta: { title: '用户管理', icon: 'User' }, + children: [ + { + path: 'list', + name: 'UserList', + component: () => import('@/views/user/list.vue'), + meta: { title: '用户列表', icon: 'List' } + } + ] + } +] + +const router = createRouter({ + history: createWebHistory(), + routes +}) + +// 路由守卫 +router.beforeEach((to, from, next) => { + const userStore = useUserStore() + + if (to.path === '/login') { + next() + } else { + if (userStore.token) { + next() + } else { + next('/login') + } + } +}) + +export default router diff --git a/管理后台/src/stores/user.ts b/管理后台/src/stores/user.ts new file mode 100644 index 0000000..9c2d6b4 --- /dev/null +++ b/管理后台/src/stores/user.ts @@ -0,0 +1,53 @@ +import { defineStore } from 'pinia' +import { ref } from 'vue' +import { login as loginApi } from '@/api/auth' + +export interface UserInfo { + id: number + username: string + email: string + realName: string + phone: string + avatar: string + role: string + status: string +} + +export const useUserStore = defineStore('user', () => { + const token = ref(localStorage.getItem('admin_token') || '') + const userInfo = ref(null) + + const setToken = (newToken: string) => { + token.value = newToken + localStorage.setItem('admin_token', newToken) + } + + const setUserInfo = (info: UserInfo) => { + userInfo.value = info + } + + const login = async (username: string, password: string) => { + const res = await loginApi({ username, password }) + if (res.data) { + setToken(res.data.access_token) + setUserInfo(res.data.user) + return true + } + return false + } + + const logout = () => { + token.value = '' + userInfo.value = null + localStorage.removeItem('admin_token') + } + + return { + token, + userInfo, + setToken, + setUserInfo, + login, + logout + } +}) diff --git a/管理后台/src/styles/index.css b/管理后台/src/styles/index.css new file mode 100644 index 0000000..28b3532 --- /dev/null +++ b/管理后台/src/styles/index.css @@ -0,0 +1,51 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html, +body, +#app { + width: 100%; + height: 100%; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, + 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', + 'Noto Color Emoji'; +} + +:root { + --primary-color: #d4a574; + --primary-light: #e8c9a8; + --primary-dark: #b88d5f; +} + +/* 滚动条样式 */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: #f1f1f1; +} + +::-webkit-scrollbar-thumb { + background: #d4a574; + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: #b88d5f; +} + +/* Element Plus 主题色覆盖 */ +:root { + --el-color-primary: #d4a574; + --el-color-primary-light-3: #e8c9a8; + --el-color-primary-light-5: #f3e4d4; + --el-color-primary-light-7: #f9f2ea; + --el-color-primary-light-8: #fcf7f2; + --el-color-primary-light-9: #fdfbf8; + --el-color-primary-dark-2: #b88d5f; +} diff --git a/管理后台/src/utils/request.ts b/管理后台/src/utils/request.ts new file mode 100644 index 0000000..c61d197 --- /dev/null +++ b/管理后台/src/utils/request.ts @@ -0,0 +1,99 @@ +import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios' +import { ElMessage } from 'element-plus' +import { useUserStore } from '@/stores/user' +import router from '@/router' + +interface ResponseData { + code: number + message: string + data: T +} + +const request: AxiosInstance = axios.create({ + baseURL: '/api', + timeout: 30000, + headers: { + 'Content-Type': 'application/json' + } +}) + +// 请求拦截器 +request.interceptors.request.use( + (config) => { + const userStore = useUserStore() + if (userStore.token) { + config.headers.Authorization = `Bearer ${userStore.token}` + } + return config + }, + (error) => { + return Promise.reject(error) + } +) + +// 响应拦截器 +request.interceptors.response.use( + (response: AxiosResponse) => { + const res = response.data + + // 如果返回的状态码不是 0 或 200,则判断为错误 + if (res.code !== 0 && res.code !== 200) { + const isLoginRequest = response.config.url?.includes('/auth/login') + // 登录接口的错误:不显示消息,直接抛出(由登录页面处理) + if (isLoginRequest) { + return Promise.reject(new Error(res.message || '请求失败')) + } + + // 其他接口的错误 + if (res.code === 401) { + // Token 过期或无效 + ElMessage.error('登录已过期,请重新登录') + const userStore = useUserStore() + userStore.logout() + router.push('/login') + } else { + // 其他错误 + ElMessage.error(res.message || '请求失败') + } + + return Promise.reject(new Error(res.message || '请求失败')) + } + + return res + }, + (error) => { + + if (error.response) { + const { status, data } = error.response + console.error('请求错误:', status, data) + + if (status === 401) { + const isLoginRequest = error.response.config.url?.includes('/auth/login') + // 登录接口的错误:不显示消息,直接抛出(由登录页面处理) + if (isLoginRequest) { + return Promise.reject(new Error(data.message || '请求失败')) + } + ElMessage.error('登录已过期,请重新登录') + const userStore = useUserStore() + userStore.logout() + router.push('/login') + } else if (status === 403) { + ElMessage.error('没有权限访问') + } else if (status === 404) { + ElMessage.error('请求的资源不存在') + } else if (status === 500) { + ElMessage.error('服务器错误') + } else { + ElMessage.error(data?.message || '请求失败') + } + } else if (error.request) { + ElMessage.error('网络连接失败') + } else { + ElMessage.error('请求配置错误') + } + + return Promise.reject(error) + } +) + +export default request diff --git a/管理后台/src/views/booking/list.vue b/管理后台/src/views/booking/list.vue new file mode 100644 index 0000000..4839432 --- /dev/null +++ b/管理后台/src/views/booking/list.vue @@ -0,0 +1,239 @@ + + + + + + 预约管理 + + + + + + + + + + + + + + + + + + + + + 搜索 + 重置 + + + + + + + + + + + + {{ formatDate(row.appointmentTime) }} + + + + + {{ getStatusText(row.status) }} + + + + + 查看 + handleStatusCommand(cmd, row)"> + + 更新状态 + + + + 确认 + 进行中 + 完成 + 取消 + + + + + + + + + + + + + {{ currentRow.bookingNumber }} + + {{ getStatusText(currentRow.status) }} + + {{ currentRow.contactName }} + {{ currentRow.contactPhone }} + {{ currentRow.service?.name }} + + {{ formatDate(currentRow.appointmentTime) }} + + {{ currentRow.address }} + + {{ currentRow.description || '无' }} + + + + + + + + {{ formatDate(currentRow.createdAt) }} + + + + 关闭 + + + + + + + + diff --git a/管理后台/src/views/case/list.vue b/管理后台/src/views/case/list.vue new file mode 100644 index 0000000..35d029b --- /dev/null +++ b/管理后台/src/views/case/list.vue @@ -0,0 +1,455 @@ + + + + + + 案例管理 + 新增案例 + + + + + + + + + + + + + + + + + + + + + + + + + + + + 搜索 + 重置 + + + + + + + + + + + + + + {{ getServiceTypeText(row.serviceType) }} + + + + + + + + + {{ row.status === 'published' ? '已发布' : row.status === 'draft' ? '草稿' : '已归档' }} + + + + + + 查看 + 编辑 + 删除 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 示例:https://example.com/1.jpg,https://example.com/2.jpg + + + + + + + + + + + + + + 草稿 + 已发布 + 已归档 + + + + + 取消 + + 确定 + + + + + + + + + diff --git a/管理后台/src/views/dashboard/index.vue b/管理后台/src/views/dashboard/index.vue new file mode 100644 index 0000000..edee658 --- /dev/null +++ b/管理后台/src/views/dashboard/index.vue @@ -0,0 +1,254 @@ + + + + + + + + 总案例数 + {{ stats.totalCases }} + + + + + + + + + + + + + 总服务数 + {{ stats.totalServices }} + + + + + + + + + + + + + 待处理预约 + {{ stats.pendingBookings }} + + + + + + + + + + + + + 总用户数 + {{ stats.totalUsers }} + + + + + + + + + + + + + + + 最新预约 + 查看更多 + + + + + + + + + + {{ formatDate(row.appointmentTime) }} + + + + + {{ getStatusText(row.status) }} + + + + + + + + + + 快捷操作 + + + + 新建案例 + + + 新建服务 + + + 查看预约 + + + 用户管理 + + + + + + + + + + + diff --git a/管理后台/src/views/login/index.vue b/管理后台/src/views/login/index.vue new file mode 100644 index 0000000..0fe67c3 --- /dev/null +++ b/管理后台/src/views/login/index.vue @@ -0,0 +1,249 @@ + + + + + + + + + + 优艺家沙发翻新 + 管理后台系统 + + + + + + + + + + + + + + {{ loading ? '登录中...' : '登录' }} + + + + + + + + + + + + + + + + + + diff --git a/管理后台/src/views/service/list.vue b/管理后台/src/views/service/list.vue new file mode 100644 index 0000000..3ab0b53 --- /dev/null +++ b/管理后台/src/views/service/list.vue @@ -0,0 +1,452 @@ + + + + + + 服务管理 + 新增服务 + + + + + + + + + + + + + + + + + + + + + + + + + + + 搜索 + 重置 + + + + + + + + + + + + + + {{ getCategoryText(row.type) }} + + + + + + ¥{{ row.basePrice }} + + + + + + + + + + + 编辑 + 删除 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 启用 + 禁用 + + + + + 取消 + + 确定 + + + + + + + + + diff --git a/管理后台/src/views/user/list.vue b/管理后台/src/views/user/list.vue new file mode 100644 index 0000000..22fd604 --- /dev/null +++ b/管理后台/src/views/user/list.vue @@ -0,0 +1,358 @@ + + + + + + 用户管理 + + + + + + + + + + + + + + + + + + + + + 搜索 + 重置 + + + + + + + + + + + + + + + + + + {{ row.role === 'admin' ? '管理员' : '用户' }} + + + + + + + + + + + {{ formatDate(row.createdAt) }} + + + + + 查看 + 编辑 + + 删除 + + + + + + + + + + + + + + {{ currentRow.id }} + {{ currentRow.username }} + {{ currentRow.realName || '未设置' }} + {{ currentRow.phone || '未设置' }} + {{ currentRow.email || '未设置' }} + + + {{ currentRow.role === 'admin' ? '管理员' : '用户' }} + + + + + {{ currentRow.status === 'active' ? '启用' : '禁用' }} + + + + {{ currentRow.wechatOpenid || '未绑定' }} + + + {{ formatDate(currentRow.createdAt) }} + + + {{ formatDate(currentRow.updatedAt) }} + + + + 关闭 + + + + + + + + + + + + + + + + + + + + + + + + + + 启用 + 禁用 + + + + + 取消 + + 确定 + + + + + + + + + diff --git a/管理后台/tsconfig.json b/管理后台/tsconfig.json new file mode 100644 index 0000000..63cf416 --- /dev/null +++ b/管理后台/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "preserve", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/管理后台/tsconfig.node.json b/管理后台/tsconfig.node.json new file mode 100644 index 0000000..42872c5 --- /dev/null +++ b/管理后台/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/管理后台/vite.config.ts b/管理后台/vite.config.ts new file mode 100644 index 0000000..7c6b2ff --- /dev/null +++ b/管理后台/vite.config.ts @@ -0,0 +1,33 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import AutoImport from 'unplugin-auto-import/vite' +import Components from 'unplugin-vue-components/vite' +import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' +import { fileURLToPath, URL } from 'node:url' + +export default defineConfig({ + plugins: [ + vue(), + AutoImport({ + resolvers: [ElementPlusResolver()], + imports: ['vue', 'vue-router', 'pinia'] + }), + Components({ + resolvers: [ElementPlusResolver()] + }) + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + }, + server: { + port: 5173, + proxy: { + '/api': { + target: 'http://localhost:3000', + changeOrigin: true + } + } + } +}) diff --git a/管理后台/登录逻辑说明.md b/管理后台/登录逻辑说明.md new file mode 100644 index 0000000..945a5bf --- /dev/null +++ b/管理后台/登录逻辑说明.md @@ -0,0 +1,139 @@ +# 登录接口逻辑说明 + +## 问题描述 +原先的实现中,登录失败时后端会抛出 `UnauthorizedException`(HTTP 401),前端响应拦截器收到 401 后会自动清空 token 并跳转到登录页,这在登录页面本身会造成逻辑混乱。 + +## 解决方案 + +### 1. 后端修改 (`后端/src/auth/auth.controller.ts`) + +**修改前**: +```typescript +async login(@Body() loginDto: LoginDto): Promise { + const result = await this.authService.login(loginDto); + return { code: 0, message: 'success', data: result }; +} +``` +- 如果 auth.service 抛出 `UnauthorizedException`,会直接返回 HTTP 401 状态码 + +**修改后**: +```typescript +async login(@Body() loginDto: LoginDto): Promise { + try { + const result = await this.authService.login(loginDto); + return { + code: 0, + message: '登录成功', + data: result, + }; + } catch (error) { + // 登录失败返回统一格式,不抛出 HTTP 异常 + return { + code: 401, + message: error.message || '用户名或密码错误', + data: null, + }; + } +} +``` + +**关键变化**: +- ✅ HTTP 状态码始终为 200 +- ✅ 通过响应体的 `code` 字段区分成功(0)和失败(401) +- ✅ 错误信息通过 `message` 字段返回 + +### 2. 前端修改 (`管理后台/src/utils/request.ts`) + +**修改前**: +```typescript +if (res.code !== 0 && res.code !== 200) { + ElMessage.error(res.message || '请求失败') + + if (res.code === 401) { + const userStore = useUserStore() + userStore.logout() + router.push('/login') + } + + return Promise.reject(new Error(res.message || '请求失败')) +} +``` +- 所有 401 都会跳转登录页 + +**修改后**: +```typescript +if (res.code !== 0 && res.code !== 200) { + const isLoginRequest = response.config.url?.includes('/auth/login') + + if (res.code === 401 && !isLoginRequest) { + ElMessage.error('登录已过期,请重新登录') + const userStore = useUserStore() + userStore.logout() + router.push('/login') + } else if (!isLoginRequest) { + ElMessage.error(res.message || '请求失败') + } + + return Promise.reject(new Error(res.message || '请求失败')) +} +``` + +**关键变化**: +- ✅ 区分登录请求和其他请求 +- ✅ 登录接口的 401 不会触发自动跳转 +- ✅ 登录接口的错误消息不在拦截器中显示(由登录页面处理) + +### 3. 前端登录页面 (`管理后台/src/views/login/index.vue`) + +保持原有的错误处理逻辑: +```typescript +try { + await userStore.login(loginForm.username, loginForm.password) + ElMessage.success('登录成功') + router.push('/') +} catch (error: any) { + const errorMessage = error.message || '登录失败,请检查用户名和密码' + ElMessage.error(errorMessage) +} +``` + +**关键点**: +- ✅ 登录页面自己处理并显示错误信息 +- ✅ 错误消息来自后端返回的 `message` 字段 + +## 最终效果 + +### 登录成功 +``` +请求: POST /api/auth/login +响应: { code: 0, message: '登录成功', data: { user: {...}, access_token: '...', refresh_token: '...' } } +结果: 显示"登录成功",跳转到首页 +``` + +### 登录失败(用户名或密码错误) +``` +请求: POST /api/auth/login +响应: { code: 401, message: '用户名或密码错误', data: null } +结果: 显示"用户名或密码错误",停留在登录页 +``` + +### 登录失败(账户被禁用) +``` +请求: POST /api/auth/login +响应: { code: 401, message: '账户已被禁用,请联系管理员', data: null } +结果: 显示"账户已被禁用,请联系管理员",停留在登录页 +``` + +### 其他接口 Token 过期 +``` +请求: GET /api/case/list +响应: { code: 401, message: 'Unauthorized', data: null } +结果: 显示"登录已过期,请重新登录",清空 token,跳转到登录页 +``` + +## 总结 + +这个修改确保了: +1. **登录接口**:失败时返回友好的错误信息,不会触发自动跳转 +2. **其他接口**:Token 过期时自动清理状态并跳转到登录页 +3. **用户体验**:错误提示清晰准确,不会出现重复提示或循环跳转
管理后台系统