This commit is contained in:
18631081161 2026-03-01 05:01:47 +08:00
commit 8245a67b88
16398 changed files with 2060677 additions and 0 deletions

View File

@ -0,0 +1 @@
{"generationMode": "requirements-first"}

View File

@ -0,0 +1,669 @@
# 设计文档:校园跑腿微信小程序
## 概述
本设计文档描述校园跑腿微信小程序的完整技术架构和实现方案。系统采用三端架构:
- **小程序前端**uni-app (Vue 3),运行于微信小程序环境
- **后台接口**.NET 10 Web API提供 RESTful 接口
- **管理后台**Vue 3 + Element Plus SPA 应用
系统核心流程:用户通过微信手机号登录 → 首页浏览 Banner 和服务入口 → 选择服务类型下单并支付 → 跑腿在订单大厅接单 → 双方通过聊天沟通 → 跑腿完成订单 → 单主确认并评价 → 跑腿提现收益。
## 架构
### 整体架构
```mermaid
graph TB
subgraph 客户端
MP[微信小程序<br/>uni-app Vue 3]
ADMIN[管理后台<br/>Vue 3 + Element Plus]
end
subgraph 后端服务
API[.NET 10 Web API]
AUTH[JWT 认证中间件]
WX[微信开放平台 SDK]
PAY[微信支付 SDK]
end
subgraph 数据层
DB[(MySQL 数据库)]
OSS[对象存储<br/>图片文件]
end
subgraph 第三方服务
WXAPI[微信开放平台]
WXPAY[微信支付]
IM[腾讯 IM]
MAP[地图 API]
end
MP --> API
ADMIN --> API
API --> AUTH
API --> WX
API --> PAY
API --> DB
API --> OSS
WX --> WXAPI
PAY --> WXPAY
MP --> IM
MP --> MAP
```
### 小程序页面结构
```mermaid
graph TD
LOGIN[登录页] --> HOME[首页]
HOME --> PICKUP[代取页]
HOME --> DELIVERY[代送页]
HOME --> HELP[万能帮页]
HOME --> PURCHASE[代购页]
HOME --> FOOD[美食街页]
FOOD --> SHOP_DETAIL[门店详情页]
SHOP_DETAIL --> FOOD_ORDER[美食街订单页]
HOME --> ORDER_HALL[订单大厅页]
ORDER_HALL --> FOOD_ORDER_DETAIL[美食街订单详情页]
HOME --> MSG[消息页]
MSG --> SYS_MSG[系统消息页]
MSG --> ORDER_NOTIFY[订单通知页]
MSG --> CHAT[聊天页]
CHAT --> COMPLETE_ORDER[完成订单确认页]
HOME --> MINE[我的页面]
MINE --> MY_ORDERS[我的订单页]
MINE --> MY_TAKEN[我的接单页]
MINE --> EARNINGS[我的收益页]
MY_ORDERS --> ORDER_DETAIL[订单详情页]
MY_TAKEN --> ORDER_DETAIL
EARNINGS --> EARNINGS_RECORD[收益记录页]
```
## 组件与接口
### API 接口设计
#### 1. 用户认证模块
| 接口 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 手机号登录 | POST | `/api/auth/login` | 接收微信加密手机号数据,解密后登录或注册 |
| 刷新 Token | POST | `/api/auth/refresh` | 刷新过期的 JWT |
#### 2. Banner 模块
| 接口 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 获取 Banner 列表(前端) | GET | `/api/banners` | 返回已启用的 Banner按排序权重排列 |
| 获取 Banner 列表(管理) | GET | `/api/admin/banners` | 返回所有 Banner |
| 创建 Banner | POST | `/api/admin/banners` | 管理员创建 Banner |
| 更新 Banner | PUT | `/api/admin/banners/{id}` | 管理员更新 Banner |
| 删除 Banner | DELETE | `/api/admin/banners/{id}` | 管理员删除 Banner |
#### 3. 服务入口模块
| 接口 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 获取服务入口列表(前端) | GET | `/api/service-entries` | 返回已启用的服务入口 |
| 获取服务入口列表(管理) | GET | `/api/admin/service-entries` | 返回所有服务入口 |
| 更新服务入口 | PUT | `/api/admin/service-entries/{id}` | 管理员更新服务入口配置 |
#### 4. 订单模块
| 接口 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 创建订单 | POST | `/api/orders` | 创建各类型订单(支付成功后调用) |
| 获取订单大厅列表 | GET | `/api/orders/hall` | 获取未接取订单,支持分类和排序 |
| 接取订单 | POST | `/api/orders/{id}/accept` | 跑腿接取订单 |
| 取消订单 | POST | `/api/orders/{id}/cancel` | 单主取消订单 |
| 完成订单 | POST | `/api/orders/{id}/complete` | 跑腿提交完成 |
| 确认订单完成 | POST | `/api/orders/{id}/confirm` | 单主确认完成 |
| 拒绝订单完成 | POST | `/api/orders/{id}/reject` | 单主拒绝完成 |
| 获取我的订单 | GET | `/api/orders/mine` | 单主查看自己的订单 |
| 获取我的接单 | GET | `/api/orders/taken` | 跑腿查看接取的订单 |
| 获取订单详情 | GET | `/api/orders/{id}` | 获取订单完整详情 |
#### 5. 美食街模块
| 接口 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 获取门店列表 | GET | `/api/shops` | 获取门店列表 |
| 获取门店详情 | GET | `/api/shops/{id}` | 获取门店详情含菜品 |
| 管理门店 CRUD | POST/PUT/DELETE | `/api/admin/shops` | 管理员管理门店 |
| 管理菜品 CRUD | POST/PUT/DELETE | `/api/admin/shops/{id}/dishes` | 管理员管理菜品 |
#### 6. 跑腿认证模块
| 接口 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 提交认证申请 | POST | `/api/runner/certification` | 提交跑腿认证 |
| 获取认证状态 | GET | `/api/runner/certification` | 查询认证状态 |
| 审核认证(管理) | PUT | `/api/admin/certifications/{id}` | 管理员审核认证 |
| 获取认证列表(管理) | GET | `/api/admin/certifications` | 管理员查看认证列表 |
#### 7. 评价模块
| 接口 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 提交评价 | POST | `/api/orders/{id}/review` | 单主评价跑腿 |
| 获取评价列表(管理) | GET | `/api/admin/reviews` | 管理员查看评价 |
| 禁用评价(管理) | PUT | `/api/admin/reviews/{id}/disable` | 管理员禁用评价 |
#### 8. 改价模块
| 接口 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 发起改价 | POST | `/api/orders/{id}/price-change` | 发起改价申请 |
| 响应改价 | PUT | `/api/orders/{id}/price-change/{changeId}` | 同意或拒绝改价 |
#### 9. 收益与提现模块
| 接口 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 获取收益概览 | GET | `/api/earnings` | 获取四种金额状态 |
| 获取收益记录 | GET | `/api/earnings/records` | 获取收益明细 |
| 获取提现记录 | GET | `/api/earnings/withdrawals` | 获取提现记录 |
| 申请提现 | POST | `/api/earnings/withdraw` | 申请提现 |
#### 10. 消息与通知模块
| 接口 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 获取未读消息数 | GET | `/api/messages/unread-count` | 获取各类未读数 |
| 获取系统消息列表 | GET | `/api/messages/system` | 获取系统消息 |
| 获取订单通知列表 | GET | `/api/messages/order-notifications` | 获取订单通知 |
| 发布系统通知(管理) | POST | `/api/admin/notifications` | 管理员发布通知 |
#### 11. 佣金分销配置模块
| 接口 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 获取佣金规则 | GET | `/api/admin/commission-rules` | 获取佣金抽成规则 |
| 更新佣金规则 | PUT | `/api/admin/commission-rules` | 更新佣金抽成规则 |
#### 12. 跑腿管理模块
| 接口 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 获取跑腿列表 | GET | `/api/admin/runners` | 管理员查看跑腿列表 |
| 封禁/解封跑腿 | PUT | `/api/admin/runners/{id}/ban` | 管理员封禁跑腿 |
#### 13. 文件上传
| 接口 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 上传图片 | POST | `/api/upload/image` | 上传图片到对象存储 |
#### 14. 配置管理
| 接口 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 获取客服二维码 | GET | `/api/config/qrcode` | 获取客服二维码配置 |
| 获取用户协议 | GET | `/api/config/agreement` | 获取用户协议内容 |
| 获取隐私政策 | GET | `/api/config/privacy` | 获取隐私政策内容 |
| 获取提现说明 | GET | `/api/config/withdrawal-guide` | 获取提现说明 |
| 更新配置(管理) | PUT | `/api/admin/config/{key}` | 管理员更新配置 |
### 认证流程
```mermaid
sequenceDiagram
participant U as 小程序
participant A as API_Server
participant W as 微信开放平台
U->>U: 用户点击"手机号快捷登录"
U->>U: 调用 wx.login() 获取 code
U->>U: 调用 getPhoneNumber 获取加密数据
U->>A: POST /api/auth/login {code, encryptedData, iv}
A->>W: code2Session 获取 session_key
W-->>A: {session_key, openid}
A->>A: 使用 session_key 解密手机号
A->>A: 根据手机号查找或创建用户
A->>A: 生成 JWT (含 userId, role, exp)
A-->>U: {token, userInfo}
U->>U: 存储 token 至本地
U->>U: 跳转至首页
```
### 订单状态流转
```mermaid
stateDiagram-v2
[*] --> 待接单: 支付成功创建订单
待接单 --> 已取消: 单主取消
待接单 --> 进行中: 跑腿接单
进行中 --> 待确认: 跑腿提交完成
待确认 --> 已完成: 单主确认 / 24h超时
待确认 --> 进行中: 单主拒绝
进行中 --> 申诉中: 客服介入
待确认 --> 申诉中: 客服介入
申诉中 --> 已完成: 申诉处理
申诉中 --> 已取消: 申诉处理
已完成 --> [*]
已取消 --> [*]
```
## 数据模型
### 用户表 (Users)
| 字段 | 类型 | 说明 |
|------|------|------|
| Id | int | 主键 |
| OpenId | string | 微信 OpenID |
| Phone | string | 手机号 |
| Nickname | string | 昵称 |
| AvatarUrl | string | 头像 |
| Role | enum | 角色User, Runner, Admin |
| RunnerScore | int | 跑腿评分,默认 80 |
| IsBanned | bool | 是否被封禁 |
| CreatedAt | datetime | 创建时间 |
### 跑腿认证表 (RunnerCertifications)
| 字段 | 类型 | 说明 |
|------|------|------|
| Id | int | 主键 |
| UserId | int | 用户 ID |
| RealName | string | 真实姓名 |
| Phone | string | 手机号 |
| Status | enum | 状态Pending, Approved, Rejected |
| CreatedAt | datetime | 申请时间 |
| ReviewedAt | datetime? | 审核时间 |
### Banner 表 (Banners)
| 字段 | 类型 | 说明 |
|------|------|------|
| Id | int | 主键 |
| ImageUrl | string | 图片地址 |
| LinkType | enum | 链接类型External, Internal |
| LinkUrl | string | 链接地址 |
| SortOrder | int | 排序权重 |
| IsEnabled | bool | 是否启用 |
| CreatedAt | datetime | 创建时间 |
### 服务入口表 (ServiceEntries)
| 字段 | 类型 | 说明 |
|------|------|------|
| Id | int | 主键 |
| Name | string | 服务名称 |
| IconUrl | string | 图标图片地址 |
| PagePath | string | 跳转页面路径 |
| SortOrder | int | 排序权重 |
| IsEnabled | bool | 是否启用 |
### 订单表 (Orders)
| 字段 | 类型 | 说明 |
|------|------|------|
| Id | int | 主键 |
| OrderNo | string | 订单编号 |
| OwnerId | int | 单主用户 ID |
| RunnerId | int? | 跑腿用户 ID |
| OrderType | enum | 类型Pickup, Delivery, Help, Purchase, Food |
| Status | enum | 状态Pending, InProgress, WaitConfirm, Completed, Cancelled, Appealing |
| ItemName | string | 物品名称/要做的事情 |
| PickupLocation | string? | 取货/代取地点 |
| DeliveryLocation | string | 送达地点 |
| Remark | string? | 备注信息 |
| Phone | string | 联系手机号 |
| Commission | decimal | 跑腿佣金 |
| GoodsAmount | decimal? | 商品总金额(万能帮/代购/美食街) |
| TotalAmount | decimal | 支付总金额 |
| CompletionProof | string? | 完成凭证图片 |
| IsReviewed | bool | 是否已评价 |
| CreatedAt | datetime | 下单时间 |
| AcceptedAt | datetime? | 接单时间 |
| CompletedAt | datetime? | 完成时间 |
### 美食街订单详情表 (FoodOrderItems)
| 字段 | 类型 | 说明 |
|------|------|------|
| Id | int | 主键 |
| OrderId | int | 订单 ID |
| ShopId | int | 门店 ID |
| DishId | int | 菜品 ID |
| Quantity | int | 数量 |
| UnitPrice | decimal | 单价 |
### 门店表 (Shops)
| 字段 | 类型 | 说明 |
|------|------|------|
| Id | int | 主键 |
| Name | string | 门店名称 |
| Photo | string | 门店照片 |
| Location | string | 门店位置 |
| Notice | string? | 注意事项 |
| PackingFeeType | enum | 打包费类型Fixed, PerItem |
| PackingFeeAmount | decimal | 打包费金额 |
| IsEnabled | bool | 是否启用 |
### 门店 Banner 表 (ShopBanners)
| 字段 | 类型 | 说明 |
|------|------|------|
| Id | int | 主键 |
| ShopId | int | 门店 ID |
| ImageUrl | string | 图片地址 |
| SortOrder | int | 排序权重 |
### 菜品表 (Dishes)
| 字段 | 类型 | 说明 |
|------|------|------|
| Id | int | 主键 |
| ShopId | int | 门店 ID |
| Name | string | 菜品名称 |
| Photo | string | 菜品照片 |
| Price | decimal | 价格 |
| IsEnabled | bool | 是否启用 |
### 评价表 (Reviews)
| 字段 | 类型 | 说明 |
|------|------|------|
| Id | int | 主键 |
| OrderId | int | 订单 ID |
| RunnerId | int | 跑腿用户 ID |
| Rating | int | 星级 1-5 |
| Content | string? | 评价内容 |
| ScoreChange | int | 分数变化 |
| IsDisabled | bool | 是否被禁用 |
| CreatedAt | datetime | 评价时间 |
### 改价记录表 (PriceChanges)
| 字段 | 类型 | 说明 |
|------|------|------|
| Id | int | 主键 |
| OrderId | int | 订单 ID |
| InitiatorId | int | 发起人 ID |
| ChangeType | enum | 类型Commission, GoodsAmount |
| OriginalPrice | decimal | 原价 |
| NewPrice | decimal | 新价 |
| Status | enum | 状态Pending, Accepted, Rejected |
| CreatedAt | datetime | 发起时间 |
### 申诉记录表 (Appeals)
| 字段 | 类型 | 说明 |
|------|------|------|
| Id | int | 主键 |
| OrderId | int | 订单 ID |
| Result | string | 处理结果 |
| CreatedAt | datetime | 处理时间 |
### 收益表 (Earnings)
| 字段 | 类型 | 说明 |
|------|------|------|
| Id | int | 主键 |
| UserId | int | 用户 ID |
| OrderId | int | 订单 ID |
| GoodsAmount | decimal? | 垫付商品金额 |
| Commission | decimal | 跑腿佣金 |
| PlatformFee | decimal | 平台抽成 |
| NetEarning | decimal | 实得收益 |
| Status | enum | 状态Frozen, Available, Withdrawing, Withdrawn |
| FrozenUntil | datetime | 冻结截止时间 |
| CreatedAt | datetime | 创建时间 |
### 提现记录表 (Withdrawals)
| 字段 | 类型 | 说明 |
|------|------|------|
| Id | int | 主键 |
| UserId | int | 用户 ID |
| Amount | decimal | 提现金额 |
| PaymentMethod | enum | 收款方式WeChat, Alipay |
| QrCodeImage | string | 收款二维码图片 |
| Status | enum | 状态Pending, Processing, Completed |
| CreatedAt | datetime | 申请时间 |
### 佣金规则表 (CommissionRules)
| 字段 | 类型 | 说明 |
|------|------|------|
| Id | int | 主键 |
| MinAmount | decimal | 区间最低金额 |
| MaxAmount | decimal? | 区间最高金额null 表示无上限) |
| RateType | enum | 类型Percentage, Fixed |
| Rate | decimal | 抽成比例或固定金额 |
### 系统消息表 (SystemMessages)
| 字段 | 类型 | 说明 |
|------|------|------|
| Id | int | 主键 |
| Title | string | 标题 |
| Content | string | 正文(富文本) |
| ThumbnailUrl | string? | 缩略图 |
| TargetType | enum | 目标All, OrderUser, RunnerUser, Specific |
| TargetUserIds | string? | 指定用户 ID 列表JSON |
| CreatedAt | datetime | 发布时间 |
### 消息已读表 (MessageReads)
| 字段 | 类型 | 说明 |
|------|------|------|
| Id | int | 主键 |
| UserId | int | 用户 ID |
| MessageType | enum | 消息类型System, OrderNotification |
| MessageId | int | 消息 ID |
| ReadAt | datetime | 已读时间 |
### 系统配置表 (SystemConfigs)
| 字段 | 类型 | 说明 |
|------|------|------|
| Id | int | 主键 |
| Key | string | 配置键 |
| Value | string | 配置值JSON |
| UpdatedAt | datetime | 更新时间 |
## 正确性属性
*正确性属性是一种在系统所有合法执行中都应成立的特征或行为——本质上是关于系统应该做什么的形式化陈述。属性是人类可读规范与机器可验证正确性保证之间的桥梁。*
### Property 1: 登录接口幂等性——手机号查找或创建
*For any* 合法的手机号,调用登录接口时,如果该手机号已存在用户记录则返回该用户的 token如果不存在则创建新用户并返回 token且返回的 JWT 中包含正确的用户 ID 和过期时间。
**Validates: Requirements 1.4**
### Property 2: 跑腿佣金输入校验
*For any* 数值输入,当该值小于 1.0 时,订单创建请求应被拒绝;当该值大于等于 1.0 且小数位不超过 1 位时,订单创建请求应被接受。
**Validates: Requirements 4.2, 4.3**
### Property 3: 订单支付金额计算
*For any* 包含商品总金额和跑腿佣金的订单(万能帮、代购、美食街类型),支付总金额应等于商品总金额加上跑腿佣金。
**Validates: Requirements 6.3, 7.2, 9.8**
### Property 4: 手机号隐藏规则
*For any* 未被接取的订单非单主用户查询订单详情时API 返回的数据中手机号字段应为空或被遮蔽;仅当订单已被接取且查询者为接单跑腿时,手机号才可见。
**Validates: Requirements 4.6**
### Property 5: Banner 列表排序与过滤
*For any* Banner 数据集合,前端获取接口应仅返回 IsEnabled=true 的记录,且按 SortOrder 升序排列。
**Validates: Requirements 2.5**
### Property 6: 服务入口列表排序与过滤
*For any* 服务入口数据集合,前端获取接口应仅返回 IsEnabled=true 的记录,且按 SortOrder 升序排列。
**Validates: Requirements 3.7**
### Property 7: 购物车数量与价格不变量
*For any* 购物车状态,购物车显示的总数量应等于所有菜品数量之和,显示的总价应等于所有菜品的(数量 × 单价)之和。添加菜品使数量加 1减少菜品使数量减 1数量减至 0 时该菜品从购物车中移除。
**Validates: Requirements 9.1, 9.2, 9.3**
### Property 8: 打包费计算
*For any* 美食街订单,当门店配置为总打包费模式时,额外费用等于固定打包费金额;当门店配置为单份打包费模式时,额外费用等于菜品总份数乘以单份打包费金额。
**Validates: Requirements 10.1, 10.2, 10.3**
### Property 9: 订单大厅仅展示未接取订单
*For any* 订单集合,订单大厅接口应仅返回 Status=Pending 的订单。
**Validates: Requirements 11.2**
### Property 10: 订单大厅佣金排序
*For any* 订单列表,当选择佣金优先排序时,返回的订单应按佣金金额从高到低排列。
**Validates: Requirements 11.4**
### Property 11: 接单状态转换
*For any* 处于"待接单"状态的订单,当跑腿接取后,订单状态应变为"进行中",且 RunnerId 应被设置为接单跑腿的用户 ID。
**Validates: Requirements 12.2, 21.5**
### Property 12: 跑腿认证前置检查
*For any* 未通过跑腿认证的用户,尝试接单时应被拒绝。已通过认证的用户应允许接单。
**Validates: Requirements 13.1, 13.2**
### Property 13: 未读消息计数
*For any* 用户的消息集合,未读消息数应等于总消息数减去已读消息数。
**Validates: Requirements 14.2, 14.3, 14.4**
### Property 14: 聊天页手机号显示规则
*For any* 订单的聊天页,当查看者为单主时应展示跑腿认证手机号,当查看者为跑腿时应展示单主下单手机号。
**Validates: Requirements 17.3**
### Property 15: 聊天功能按钮显示规则
*For any* 订单类型和用户角色组合,所有订单显示【发送图片】【更改跑腿价格】,代购和美食街订单额外显示【更改商品价格】,仅跑腿用户可见【完成订单】。
**Validates: Requirements 17.6**
### Property 16: 改价差额计算
*For any* 改价申请,当新价格高于原价时应产生补缴金额(新价 - 原价),当新价格低于原价时应产生退款金额(原价 - 新价)。
**Validates: Requirements 19.1, 19.2**
### Property 17: 跑腿评分计算
*For any* 评价星级1-5分数变化应为1星=-2, 2星=-1, 3星=0, 4星=+1, 5星=+2。跑腿总分应等于初始分 80 加上所有未禁用评价的分数变化之和,且总分范围在 0-100 之间。
**Validates: Requirements 22.1, 22.2**
### Property 18: 评价可见性
*For any* API 请求,当请求者为跑腿用户时,评价内容不应被返回;仅管理员可查看评价内容。
**Validates: Requirements 22.5**
### Property 19: 订单详情按状态显示字段
*For any* 订单,当状态为"待接单"时接单时间、跑腿信息、完成信息应为空;当状态为"进行中"时应显示接单时间和跑腿信息;当状态为"已完成"时应显示所有信息。
**Validates: Requirements 24.4, 24.5, 24.6**
### Property 20: 完成订单状态转换
*For any* 处于"进行中"状态的订单,跑腿提交完成后状态应变为"待确认";单主确认后状态应变为"已完成";单主拒绝后状态应保持"进行中"。
**Validates: Requirements 26.2, 26.5, 26.6**
### Property 21: 收益冻结与解冻
*For any* 已完成的订单,对应的收益记录初始状态应为"冻结中",冻结期满后状态应自动变为"待提现"。
**Validates: Requirements 27.2, 27.3**
### Property 22: 提现金额校验
*For any* 提现申请,提现金额应大于等于 1 元、小于等于可提现余额、且小数位不超过 2 位。不满足条件的申请应被拒绝。
**Validates: Requirements 27.7, 27.8, 27.9**
### Property 23: 佣金分销计算
*For any* 跑腿佣金金额,平台分成应按匹配的佣金区间规则计算:百分比类型按比例计算,固定类型扣除固定金额。跑腿实得 = 原始佣金 - 平台分成。
**Validates: Requirements 28.1, 28.3**
### Property 24: 封禁跑腿接单拒绝
*For any* 被封禁的跑腿用户,接单请求应被拒绝并返回错误信息。
**Validates: Requirements 29.2**
### Property 25: Banner 创建校验
*For any* Banner 创建或更新请求,图片地址不为空、链接类型为合法枚举值、链接地址不为空时应成功;否则应返回校验错误。
**Validates: Requirements 30.6, 30.7**
### Property 26: JWT 认证
*For any* API 请求(除登录接口外),未携带有效 JWT 时应返回 401携带有效 JWT 但非管理员身份访问管理接口时应返回 403。
**Validates: Requirements 32.1, 32.3, 32.4, 32.5**
### Property 27: 数据序列化往返一致性
*For any* 合法的 Banner、服务入口或订单对象JSON 序列化后再反序列化应产生与原始对象等价的结果。
**Validates: Requirements 33.2, 33.3, 33.4**
## 错误处理
### API 错误响应格式
所有 API 错误使用统一的 JSON 响应格式:
```json
{
"code": 400,
"message": "校验失败",
"errors": [
{ "field": "imageUrl", "message": "图片地址不能为空" }
]
}
```
### 错误码定义
| HTTP 状态码 | 场景 |
|-------------|------|
| 400 | 请求参数校验失败 |
| 401 | 未登录或 JWT 过期 |
| 403 | 权限不足(非管理员访问管理接口) |
| 404 | 资源不存在 |
| 409 | 冲突(如订单已被接取) |
| 500 | 服务器内部错误 |
### 小程序端错误处理
- 网络请求失败:展示"网络异常,请重试"提示
- 401 响应:清除本地 token跳转至登录页
- 业务错误:展示 API 返回的 message 字段内容
- 微信 API 调用失败:展示对应的友好提示信息
### 并发控制
- 接单操作使用乐观锁,通过数据库行级锁防止同一订单被多人接取
- 改价操作使用状态检查,同一时间只允许一个待处理的改价申请
## 测试策略
### 测试框架选择
- **后台接口 (.NET 10)**xUnit + FsCheck属性测试库
- **小程序前端 (Vue 3)**Vitest + fast-check属性测试库
- **管理后台 (Vue 3)**Vitest + fast-check
### 单元测试
单元测试聚焦于具体示例和边界情况:
- 登录流程的各种异常场景(授权失败、解密失败、网络错误)
- Banner 和服务入口的 CRUD 操作边界情况
- 订单状态转换的非法操作(如已完成订单再次接单)
- 购物车操作的边界情况(空购物车结算、单品数量为 0
- 提现金额的边界值(最低 1 元、超出余额、小数位数)
### 属性测试
属性测试验证跨所有输入的通用属性,每个属性测试至少运行 100 次迭代:
- 每个属性测试必须引用设计文档中的属性编号
- 标签格式:**Feature: login-and-homepage, Property {number}: {property_text}**
- 每个正确性属性由一个独立的属性测试实现
### 测试覆盖重点
| 模块 | 单元测试 | 属性测试 |
|------|----------|----------|
| 用户认证 | 登录异常场景 | Property 1, 26 |
| Banner/服务入口 | CRUD 边界 | Property 5, 6, 25, 27 |
| 订单创建 | 表单校验 | Property 2, 3, 4 |
| 购物车 | 边界操作 | Property 7, 8 |
| 订单大厅 | 展示逻辑 | Property 9, 10 |
| 接单流程 | 并发场景 | Property 11, 12, 24 |
| 消息通知 | 未读计数 | Property 13 |
| 聊天功能 | 权限控制 | Property 14, 15 |
| 改价 | 金额计算 | Property 16 |
| 评价评分 | 分数计算 | Property 17, 18 |
| 订单详情 | 状态展示 | Property 19, 20 |
| 收益提现 | 金额校验 | Property 21, 22, 23 |

View File

@ -0,0 +1,450 @@
# 需求文档:校园跑腿微信小程序
## 简介
校园跑腿微信小程序是一个面向校园场景的跑腿服务平台,支持代取、代送、万能帮、代购、美食街五大服务类型。用户可以发布跑腿订单,跑腿人员可以接单赚取佣金。平台提供订单管理、即时通讯、评价、收益提现等完整功能。系统包含小程序前端、后台接口、管理后台三端。
## 术语表
- **小程序前端Miniapp_Client**:基于 uni-app (Vue 3) 开发的微信小程序客户端
- **后台接口API_Server**:提供 RESTful API 的 .NET 10 后端服务
- **管理后台Admin_Panel**:基于 Vue 3 + Element Plus 的后台管理 Web 应用
- **Banner**:首页顶部轮播图,包含图片和跳转链接配置
- **服务入口Service_Entry**:首页五大服务按钮,每个入口包含图标图片和跳转目标页面
- **用户User**:使用小程序的终端用户
- **单主Order_Owner**:发布订单的用户
- **跑腿Runner**:接取并执行订单的认证用户
- **管理员Admin**:使用管理后台的运营管理人员
- **订单Order**:用户发布的跑腿任务,包含五种类型:代取、代送、万能帮、代购、美食街
- **佣金Commission**:单主支付给跑腿的服务费用
- **门店Shop**:美食街中的餐饮商家
- **菜品Dish**:门店中的食品项目
- **打包费Packing_Fee**:门店额外收取的打包费用,分为总打包费和单份打包费两种模式
## 需求
### 需求 1微信手机号登录
**用户故事:** 作为用户,我希望通过微信手机号快捷登录小程序,以便快速进入并使用跑腿服务。
#### 验收标准
1. WHEN 用户首次打开小程序且未登录时THE Miniapp_Client SHALL 展示登录页面,引导用户授权手机号登录
2. WHEN 用户点击"手机号快捷登录"按钮时THE Miniapp_Client SHALL 调用微信 `getPhoneNumber` 接口获取加密手机号数据
3. WHEN Miniapp_Client 获取到加密手机号数据后THE Miniapp_Client SHALL 将该数据发送至 API_Server 的登录接口
4. WHEN API_Server 收到登录请求时THE API_Server SHALL 调用微信开放平台接口解密手机号并根据手机号查找或创建用户记录返回登录凭证token
5. WHEN API_Server 成功返回登录凭证时THE Miniapp_Client SHALL 将凭证存储至本地,并跳转至首页
6. IF 微信授权手机号失败或用户拒绝授权THEN THE Miniapp_Client SHALL 展示提示信息"需要授权手机号才能使用服务",并保留在登录页面
7. IF API_Server 登录接口返回错误THEN THE Miniapp_Client SHALL 展示提示信息"登录失败,请重试"
8. WHEN 用户再次打开小程序且本地存在有效登录凭证时THE Miniapp_Client SHALL 自动跳转至首页,无需重复登录
9. IF 本地登录凭证已过期THEN THE Miniapp_Client SHALL 清除过期凭证并引导用户重新登录
### 需求 2首页 Banner 展示
**用户故事:** 作为用户,我希望在首页看到轮播 Banner以便了解平台最新活动和公告信息。
#### 验收标准
1. WHEN 用户进入首页时THE Miniapp_Client SHALL 从 API_Server 获取 Banner 列表并以轮播形式展示
2. WHEN Banner 列表为空时THE Miniapp_Client SHALL 隐藏 Banner 区域,不展示空白占位
3. WHEN 用户点击某个 Banner 且该 Banner 配置了外部链接时THE Miniapp_Client SHALL 通过 web-view 打开该外部链接
4. WHEN 用户点击某个 Banner 且该 Banner 配置了内部页面路径时THE Miniapp_Client SHALL 跳转至对应的小程序内部页面
5. THE API_Server SHALL 提供获取 Banner 列表的接口,返回按排序字段排列的已启用 Banner 数据
6. THE API_Server SHALL 在 Banner 数据中包含以下字段:唯一标识、图片地址、链接类型(外部链接/内部页面)、链接地址、排序权重、启用状态
### 需求 3首页服务入口展示
**用户故事:** 作为用户,我希望在首页看到五大服务入口按钮,以便快速进入对应的下单页面。
#### 验收标准
1. WHEN 用户进入首页时THE Miniapp_Client SHALL 展示下订单入口区域,从 API_Server 获取服务入口配置并展示五大服务按钮(代取、代送、万能帮、代购、美食街)
2. WHEN 用户点击【代取】按钮时THE Miniapp_Client SHALL 跳转至代取页
3. WHEN 用户点击【代送】按钮时THE Miniapp_Client SHALL 跳转至代送页
4. WHEN 用户点击【万能帮】按钮时THE Miniapp_Client SHALL 跳转至万能帮页
5. WHEN 用户点击【代购】按钮时THE Miniapp_Client SHALL 跳转至代购页
6. WHEN 用户点击【美食街】按钮时THE Miniapp_Client SHALL 跳转至美食街页
7. THE API_Server SHALL 提供获取服务入口列表的接口,返回按排序字段排列的服务入口配置数据
8. THE API_Server SHALL 在服务入口数据中包含以下字段:唯一标识、服务名称、图标图片地址、跳转页面路径、排序权重、启用状态
### 需求 4代取页下单
**用户故事:** 作为用户,我希望在代取页填写代取信息并支付,以便发布代取订单。
#### 验收标准
1. WHEN 用户进入代取页时THE Miniapp_Client SHALL 展示包含以下输入项的表单:代取物品、代取地点、送达地点、备注信息、手机号、跑腿佣金
2. WHEN 用户输入的跑腿佣金低于 1.0 元并点击【确定】按钮时THE Miniapp_Client SHALL 弹出系统提示"跑腿佣金不可低于1.0元",不拉起支付
3. THE Miniapp_Client SHALL 限制跑腿佣金输入最低为 1.0 元,支持小数点后 1 位
4. WHEN 用户填写完表单并点击【确定】按钮且佣金合法时THE Miniapp_Client SHALL 拉起微信支付
5. WHEN 微信支付成功后THE API_Server SHALL 创建代取订单并返回订单信息
6. WHILE 订单未被跑腿接取时THE API_Server SHALL 隐藏单主手机号,仅接单跑腿可查看
### 需求 5代送页下单
**用户故事:** 作为用户,我希望在代送页填写代送信息并支付,以便发布代送订单。
#### 验收标准
1. WHEN 用户进入代送页时THE Miniapp_Client SHALL 展示包含以下输入项的表单:代送物品、取货地点、送达地点、备注信息、手机号、跑腿佣金
2. WHEN 用户填写完表单并点击【确定】按钮且佣金合法时THE Miniapp_Client SHALL 拉起微信支付
3. WHEN 微信支付成功后THE API_Server SHALL 创建代送订单并返回订单信息
### 需求 6万能帮页下单
**用户故事:** 作为用户,我希望在万能帮页填写帮忙信息并支付,以便发布万能帮订单。
#### 验收标准
1. WHEN 用户进入万能帮页时THE Miniapp_Client SHALL 展示包含以下输入项的表单:要做的事情、手机号、代购商品总金额、跑腿佣金
2. THE Miniapp_Client SHALL 提示用户代购商品总金额需包含商品总额和包装费等额外费用
3. WHEN 用户填写完表单并点击【确定】按钮时THE Miniapp_Client SHALL 拉起微信支付,支付金额为商品总金额 + 跑腿佣金的总和
4. WHEN 微信支付成功后THE API_Server SHALL 创建万能帮订单并返回订单信息
### 需求 7代购页下单
**用户故事:** 作为用户,我希望在代购页填写代购信息并支付,以便发布代购订单。
#### 验收标准
1. WHEN 用户进入代购页时THE Miniapp_Client SHALL 展示包含以下输入项的表单:代购物品、买货地点、送达地点、备注信息、手机号、代购商品总金额、跑腿佣金
2. WHEN 用户填写完表单并点击【确定】按钮时THE Miniapp_Client SHALL 拉起微信支付,支付金额为商品总金额 + 跑腿佣金的总和
3. WHEN 微信支付成功后THE API_Server SHALL 创建代购订单并返回订单信息
### 需求 8美食街门店与菜品展示
**用户故事:** 作为用户,我希望浏览美食街门店和菜品列表,以便选择想要代购的美食。
#### 验收标准
1. WHEN 用户进入美食街页时THE Miniapp_Client SHALL 展示门店列表,每个门店显示门店照片、门店名、门店位置、店内美食种类数量
2. WHEN 用户点击某个门店时THE Miniapp_Client SHALL 跳转至该门店详情页
3. WHEN 用户进入门店详情页时THE Miniapp_Client SHALL 展示门店 Banner 图(支持多张)、门店注意事项(如打包费说明,可能为空)、美食列表(食品照片、名称、价格)
4. THE API_Server SHALL 提供门店列表和门店详情的查询接口
5. THE Admin_Panel SHALL 支持配置门店信息(照片、名称、位置)、门店 Banner 图、门店注意事项文字、菜品信息(照片、名称、价格)
### 需求 9美食街购物车与下单
**用户故事:** 作为用户,我希望将菜品加入购物车并下单,以便发布美食街代购订单。
#### 验收标准
1. WHEN 用户点击菜品的【+】按钮时THE Miniapp_Client SHALL 将该菜品添加进购物车
2. WHEN 用户点击菜品的【-】按钮时THE Miniapp_Client SHALL 减少购物车中该菜品数量,数量减至 0 时删除该菜品
3. WHEN 购物车中有菜品时THE Miniapp_Client SHALL 在底部购物车栏显示菜品数量和价格总和
4. WHEN 用户点击【购物车】按钮时THE Miniapp_Client SHALL 弹出购物车弹窗,显示菜品照片、门店名、菜品名、价格、数量、额外费用、总价
5. WHEN 用户在购物车弹窗中点击【+】【-】时THE Miniapp_Client SHALL 增减菜品数量,菜品减至 0 时删除该菜品
6. WHEN 用户点击【去结算】按钮时THE Miniapp_Client SHALL 跳转至美食街订单页
7. WHEN 用户进入美食街订单页时THE Miniapp_Client SHALL 展示包含以下输入项的表单:送达地点、备注信息、手机号、跑腿佣金,并自动计算餐品总金额(含打包费等额外费用)
8. WHEN 用户点击【确定】按钮时THE Miniapp_Client SHALL 拉起微信支付,支付金额为商品总金额 + 跑腿佣金的总和
9. WHEN 微信支付成功后THE API_Server SHALL 创建美食街订单并返回订单信息
### 需求 10美食街打包费计算
**用户故事:** 作为用户,我希望系统自动计算打包费,以便在支付前了解准确的总金额。
#### 验收标准
1. THE API_Server SHALL 支持两种打包费模式:总打包费(固定金额,不论菜品数量)和单份打包费(按菜品份数计算)
2. WHEN 门店配置为总打包费模式时THE API_Server SHALL 在订单总额中加上固定打包费金额
3. WHEN 门店配置为单份打包费模式时THE API_Server SHALL 按菜品总份数乘以单份打包费计算额外费用
4. THE Admin_Panel SHALL 支持为每个门店配置打包费模式和金额
### 需求 11订单大厅展示
**用户故事:** 作为跑腿,我希望在订单大厅浏览未被接取的订单,以便选择合适的订单接取。
#### 验收标准
1. WHEN 跑腿进入订单大厅页时THE Miniapp_Client SHALL 按订单分类(代取、代送、万能帮、代购、美食街)展示对应订单列表
2. THE Miniapp_Client SHALL 仅展示未被接取的订单
3. WHEN 进入订单大厅页时THE Miniapp_Client SHALL 向用户申请小程序定位权限
4. THE Miniapp_Client SHALL 支持两种排序方式:佣金优先(按佣金从高到低)和距离优先(按跑腿当前位置到各点位距离之和从近到远),默认佣金优先
5. WHEN 展示代取订单时THE Miniapp_Client SHALL 显示代取物品、取货地点、送达地点、备注信息、跑腿费
6. WHEN 展示代送订单时THE Miniapp_Client SHALL 显示送货物品名、取货地点、送达地点、备注信息、跑腿费
7. WHEN 展示万能帮订单时THE Miniapp_Client SHALL 显示备注信息、跑腿费
8. WHEN 展示代购订单时THE Miniapp_Client SHALL 显示代购物品名、买货地点、送达地点、备注信息、垫付商品金额、跑腿费
9. WHEN 展示美食街订单时THE Miniapp_Client SHALL 显示涉及门店数量、美食菜品数量、送达地点、垫付商品金额、跑腿费
10. WHEN 用户点击刷新按钮时THE Miniapp_Client SHALL 刷新全部列表,刷新后不切换当前标签
### 需求 12接单功能
**用户故事:** 作为跑腿,我希望在订单大厅接取订单,以便开始执行跑腿任务赚取佣金。
#### 验收标准
1. WHEN 跑腿点击非美食街订单的【接单】按钮时THE Miniapp_Client SHALL 弹出接单确认弹窗
2. WHEN 跑腿在确认弹窗中点击【接单】按钮时THE API_Server SHALL 将该订单标记为已接取并关联跑腿用户
3. IF 跑腿接取订单时该订单已被其他跑腿接取THEN THE Miniapp_Client SHALL 弹出系统提示"该订单已被接取"
4. WHEN 展示美食街订单时THE Miniapp_Client SHALL 显示【查看详情】按钮而非【接单】按钮
5. WHEN 跑腿点击美食街订单的【查看详情】按钮时THE Miniapp_Client SHALL 跳转至美食街订单详情页,展示备注信息、送达地点、打包费等额外费用、跑腿佣金、门店名称、菜品照片、菜品名、菜品份数、菜品价格、垫付金额总和
6. WHEN 跑腿在美食街订单详情页点击【接单】按钮时THE Miniapp_Client SHALL 弹出接单确认弹窗
### 需求 13跑腿认证
**用户故事:** 作为用户,我希望通过跑腿认证成为跑腿人员,以便接取订单赚取佣金。
#### 验收标准
1. WHEN 用户尝试接单且未通过跑腿认证时THE Miniapp_Client SHALL 弹出跑腿认证弹窗
2. WHEN 用户已通过跑腿认证时THE Miniapp_Client SHALL 允许正常接单流程
3. WHEN 用户在认证弹窗中输入姓名和手机号并点击【提交】按钮时THE API_Server SHALL 保存认证申请并标记为待审核状态
4. WHILE 用户已提交认证申请但未通过审核时THE Miniapp_Client SHALL 在每次触发认证弹窗时弹出系统提示"平台审核中"
5. THE Admin_Panel SHALL 支持审核跑腿认证申请,可通过或拒绝
### 需求 14消息列表
**用户故事:** 作为用户,我希望查看平台内所有消息,以便及时了解系统通知、订单动态和聊天信息。
#### 验收标准
1. WHEN 用户进入消息页时THE Miniapp_Client SHALL 展示系统消息入口、订单通知入口和聊天记录用户列表
2. WHEN 系统消息有未读时THE Miniapp_Client SHALL 在系统消息入口最右侧显示未读条数
3. WHEN 订单通知有未读时THE Miniapp_Client SHALL 在订单通知入口最右侧显示未读条数
4. WHEN 有任意未读消息时THE Miniapp_Client SHALL 在底部导航栏【消息】按钮右上角显示未读条数
5. WHEN 展示聊天记录用户列表时THE Miniapp_Client SHALL 显示用户头像、昵称、最后一句消息、最后一句时间
6. WHEN 用户点击某个聊天记录时THE Miniapp_Client SHALL 跳转至对应的聊天页
### 需求 15系统消息
**用户故事:** 作为用户,我希望查看平台发布的系统通知,以便了解平台公告和重要信息。
#### 验收标准
1. WHEN 用户进入系统消息页时THE Miniapp_Client SHALL 展示通知列表,每条显示通知标题、正文(最多三行,超出以"…"代替)、图片缩略图、发布时间
2. WHEN 用户点击某条通知时THE Miniapp_Client SHALL 跳转至通知详情页展示完整内容
3. THE Admin_Panel SHALL 支持配置系统通知,正文支持富文本
4. THE Admin_Panel SHALL 支持通知指定用户、全部用户或类型用户(下单用户、跑腿用户)
### 需求 16订单通知
**用户故事:** 作为用户,我希望查看订单相关的通知信息,以便及时了解订单状态变化。
#### 验收标准
1. WHEN 用户进入订单通知页时THE Miniapp_Client SHALL 按分类(全部、被接单、已完成、已取消)展示订单通知
2. THE Miniapp_Client SHALL 在每条通知中显示通知标题、订单编号、订单类型、该订单第一项内容的标题和内容、时间(精确到年月日时分)
3. WHEN 用户点击【查看订单】按钮时THE Miniapp_Client SHALL 跳转至对应的订单详情页
### 需求 17聊天功能
**用户故事:** 作为用户,我希望与订单对方进行即时通讯,以便沟通订单相关事宜。
#### 验收标准
1. WHEN 用户进入聊天页时THE Miniapp_Client SHALL 在顶部展示订单信息,点击【查看详情】跳转至订单详情页
2. THE Miniapp_Client SHALL 展示双方的沟通聊天记录
3. WHEN 用户点击【拨打电话】按钮时THE Miniapp_Client SHALL 弹出电话弹窗,展示对方手机号(单主看到跑腿认证手机号,跑腿看到单主下单手机号)
4. WHEN 用户点击【复制电话】按钮时THE Miniapp_Client SHALL 将手机号复制至剪切板并弹出系统提示"手机号已复制"
5. WHEN 用户点击【联系客服】按钮时THE Miniapp_Client SHALL 跳转至微信小程序自带客服页
6. WHEN 用户点击输入框右侧的【+】按钮时THE Miniapp_Client SHALL 弹出更多功能选项:所有订单显示【发送图片】【更改跑腿价格】,代购和美食街订单额外显示【更改商品价格】,仅跑腿用户可见【完成订单】
7. WHEN 用户点击【发送图片】按钮时THE Miniapp_Client SHALL 支持拍照或相册上传图片
8. WHEN 跑腿用户点击【完成订单】按钮时THE Miniapp_Client SHALL 跳转至完成订单确认页
### 需求 18改价功能
**用户故事:** 作为用户,我希望在聊天中发起改价申请,以便协商调整订单价格。
#### 验收标准
1. WHEN 用户点击【改价】按钮时THE Miniapp_Client SHALL 弹出改价弹窗,支持修改商品总额或跑腿佣金,可输入比原价更小的价格
2. WHEN 用户点击【发起修改申请】按钮后THE API_Server SHALL 在聊天列表中向对方发送改价申请消息
3. WHEN 对方收到改价申请时THE Miniapp_Client SHALL 展示【同意】【拒绝】按钮
4. WHEN 对方点击【同意】或【拒绝】后THE Miniapp_Client SHALL 向双方展示系统提示"您/对方已同意/拒绝商品/跑腿佣金改价"
5. WHILE 改价申请等待对方确认时THE Miniapp_Client SHALL 在改价区域提示"等待对方确认中"
### 需求 19改价补缴与退款
**用户故事:** 作为单主,我希望改价后系统自动处理补缴或退款,以便价格变更后资金正确结算。
#### 验收标准
1. WHEN 单主主动发起改价且修改后价格高于当前价格时THE Miniapp_Client SHALL 在点击【发起申请】时自动计算补缴金额并跳转至微信支付页,支付成功后自动向对方发送改价申请
2. WHEN 单主主动发起改价且修改后价格低于当前价格且对方同意后THE API_Server SHALL 自动退款超出金额至单主微信或平台收益
3. WHEN 退款至微信时THE Miniapp_Client SHALL 在聊天列表弹出系统提示"已退还您xx元请在微信中查看"
4. IF 微信自动退款不可用THEN THE API_Server SHALL 将退还金额退至单主平台收益THE Miniapp_Client SHALL 弹出系统提示"已退还您xx元请在我的收益中查看"
5. WHEN 对方主动发起改价且单主同意后THE API_Server SHALL 按相同逻辑处理补缴或退款
### 需求 20我的页面
**用户故事:** 作为用户,我希望在"我的"页面查看个人信息和常用功能入口,以便管理个人账户和订单。
#### 验收标准
1. WHEN 用户进入"我的"页面时THE Miniapp_Client SHALL 展示下单和接单的订单数、完成数
2. WHEN 用户点击下单或接单区域时THE Miniapp_Client SHALL 跳转至对应的"我的订单页"或"我的接单页"
3. WHEN 用户点击【联系客服】按钮时THE Miniapp_Client SHALL 跳转至小程序自带客服页
4. WHEN 用户点击【客服二维码】按钮时THE Miniapp_Client SHALL 跳转至客服二维码页,展示后台可配置的二维码图片
5. WHEN 用户点击【跑腿认证】按钮时THE Miniapp_Client SHALL 弹出跑腿认证弹窗
6. WHEN 用户点击【我的收益】按钮时THE Miniapp_Client SHALL 跳转至我的收益页
7. WHEN 用户点击【用户协议】或【隐私政策】按钮时THE Miniapp_Client SHALL 跳转至对应页面,内容由后台配置
8. WHEN 用户点击【退出登录】按钮时THE Miniapp_Client SHALL 清除本地登录凭证并跳转至登录页面
### 需求 21我的订单页
**用户故事:** 作为单主,我希望查看和管理自己发布的订单,以便跟踪订单状态和处理订单。
#### 验收标准
1. WHEN 用户进入我的订单页时THE Miniapp_Client SHALL 按订单状态(全部、待接单、进行中、待确认、已完成、已取消、申诉中)和订单类型分类展示
2. WHILE 订单处于"待接单"状态时THE Miniapp_Client SHALL 显示【取消订单】按钮
3. WHEN 用户点击【取消订单】按钮时THE Miniapp_Client SHALL 弹出取消确认弹窗,确认后 THE API_Server SHALL 取消该订单
4. IF 跑腿接取已被取消的订单THEN THE Miniapp_Client SHALL 弹出系统提示"该订单已被取消"
5. WHEN 订单被跑腿接取后THE API_Server SHALL 自动将订单状态改变为"进行中"
6. WHEN "待接单""进行中""已完成"状态的订单时THE Miniapp_Client SHALL 显示【查看详情】按钮,点击跳转至订单详情页
7. WHEN 订单处于"进行中"状态时THE Miniapp_Client SHALL 额外显示【联系跑腿】按钮
8. WHEN 跑腿提交订单完成后THE API_Server SHALL 将订单状态改变为"待确认"
9. WHEN 用户在"待确认"订单中点击【确认处理】按钮并确认完成时THE API_Server SHALL 将订单状态改变为"已完成"
10. WHEN 订单处于"已完成"状态时THE Miniapp_Client SHALL 显示【评价跑腿】【查看详情】【联系跑腿】按钮
11. WHEN 用户点击【评价跑腿】按钮时THE Miniapp_Client SHALL 弹出评价弹窗,支持选择星级和输入评价内容(非必填)
### 需求 22跑腿评分系统
**用户故事:** 作为平台运营者,我希望通过评分系统评估跑腿服务质量,以便维护平台服务水平。
#### 验收标准
1. THE API_Server SHALL 为每名跑腿设置初始分数 80 分,满分 100 分
2. WHEN 单主提交评价时THE API_Server SHALL 按以下规则计算分数变化1星扣2分、2星扣1分、3星不变、4星加1分、5星加2分
3. THE Admin_Panel SHALL 支持查看跑腿的分值变化记录和每次的评价内容
4. THE Admin_Panel SHALL 支持删除或禁用某条评价,操作后不计算该条评价的分数
5. THE API_Server SHALL 确保评价内容仅管理员可查看,跑腿用户无法查看
6. WHEN 用户完成评价后THE Miniapp_Client SHALL 隐藏【评价跑腿】按钮
### 需求 23订单申诉
**用户故事:** 作为用户,我希望对有争议的订单进行申诉,以便通过客服介入解决纠纷。
#### 验收标准
1. WHEN 客服在管理后台将订单状态改变为"申诉中"时THE API_Server SHALL 更新订单状态
2. WHEN 申诉处理结束后THE Admin_Panel SHALL 支持客服将订单状态改变为"已完成"或"已取消"等,并填写申诉处理结果
3. THE Miniapp_Client SHALL 在订单详情页底部展示申诉处理结果和提交时间
4. IF 一条订单有多条申诉处理结果THEN THE Miniapp_Client SHALL 按最新时间排序展示
### 需求 24订单详情页
**用户故事:** 作为用户,我希望查看订单的完整详情,以便了解订单的所有信息和当前状态。
#### 验收标准
1. WHEN 用户进入订单详情页时THE Miniapp_Client SHALL 在页面标题展示"我的xx订单详情"
2. THE Miniapp_Client SHALL 展示订单填写内容、当前状态、订单ID、下单时间精确至年月日时分、接单时间、跑腿昵称、跑腿UID、完成时间、完成凭证
3. WHEN 订单为美食街订单时THE Miniapp_Client SHALL 额外展示打包费等额外费用、每个门店的名称、菜品照片、菜品名、份数、每份价格、总份数、垫付总金额
4. WHILE 订单未被接取时THE Miniapp_Client SHALL 将接单时间、跑腿昵称、跑腿UID、完成时间、完成凭证显示为空页面底部显示【取消订单】按钮
5. WHILE 订单已被接取且未完成时THE Miniapp_Client SHALL 显示接单时间、跑腿昵称、跑腿UID页面底部显示【联系跑腿】按钮
6. WHILE 订单已完成时THE Miniapp_Client SHALL 显示完成时间和完成凭证(若有),页面底部显示【评价跑腿】【联系跑腿】按钮,评价完成后仅显示【联系跑腿】
### 需求 25我的接单页
**用户故事:** 作为跑腿,我希望查看和管理自己接取的订单,以便跟踪接单状态。
#### 验收标准
1. WHEN 跑腿进入我的接单页时THE Miniapp_Client SHALL 按状态(全部、进行中、已完成、已取消)和类型展示订单列表
2. WHEN 订单处于"进行中"状态时THE Miniapp_Client SHALL 显示【完成订单】【查看详情】【联系单主】按钮
3. WHEN 订单处于"已完成"状态时THE Miniapp_Client SHALL 显示【查看详情】【联系单主】按钮
### 需求 26完成订单确认
**用户故事:** 作为跑腿,我希望提交订单完成确认,以便通知单主审核并完成订单。
#### 验收标准
1. WHEN 跑腿进入完成订单确认页时THE Miniapp_Client SHALL 展示订单ID、下单时间、接单时间并支持上传完成凭证图片选填
2. WHEN 跑腿点击【确认】按钮时THE API_Server SHALL 将订单状态改变为"待确认",并根据提交时间自动生成完成时间(精确至年月日时分)
3. WHEN 跑腿提交完成后THE Miniapp_Client SHALL 在聊天页向跑腿显示"您已提交该订单完成,等待单主完成确认"
4. WHEN 跑腿提交完成后THE Miniapp_Client SHALL 在聊天页向单主显示订单确认提示区域,提示需在 24 小时内处理,超时将默认视为完成
5. WHEN 单主点击【确认订单完成】按钮时THE API_Server SHALL 将订单状态改变为"已完成",聊天页双方弹出系统提示
6. WHEN 单主点击【订单未完成】按钮时THE API_Server SHALL 保持订单状态不变,聊天页双方弹出系统提示"单主未通过订单完成,订单继续进行"
### 需求 27我的收益页
**用户故事:** 作为跑腿,我希望查看和管理自己的收益,以便了解收入情况并申请提现。
#### 验收标准
1. WHEN 跑腿进入我的收益页时THE Miniapp_Client SHALL 展示四种金额状态:冻结中、待提现、提现中、已提现
2. THE API_Server SHALL 在订单完成后将佣金计入"冻结中"状态,冻结时间由后台配置(默认 1 日)
3. WHEN 冻结期满后THE API_Server SHALL 自动将佣金从"冻结中"移至"待提现"
4. THE Miniapp_Client SHALL 展示提现记录,显示提现时间和每笔金额
5. WHEN 用户点击【点击查看提现说明】按钮时THE Miniapp_Client SHALL 弹出提现说明弹窗,内容由后台配置
6. WHEN 用户点击【收益记录】按钮时THE Miniapp_Client SHALL 跳转至收益记录页,展示订单号、订单类型、完成时间、垫付商品金额、跑腿佣金
7. WHEN 用户点击【申请提现】按钮时THE Miniapp_Client SHALL 弹出申请提现弹窗,显示可提现金额,支持输入提现金额(最低 1 元,支持小数点两位)
8. IF 用户输入的提现金额超出待提现金额THEN THE Miniapp_Client SHALL 弹出系统提示"超出可提现范围"
9. IF 用户输入的提现金额超出小数范围THEN THE Miniapp_Client SHALL 弹出系统提示"请输入正确的提现金额"
10. WHEN 用户选择收款方式微信或支付宝并上传收款二维码图片后点击【申请提现】按钮时THE API_Server SHALL 保存提现申请
### 需求 28跑腿佣金分销
**用户故事:** 作为平台运营者,我希望按佣金区间抽取平台分成,以便实现平台盈利。
#### 验收标准
1. THE API_Server SHALL 在跑腿佣金结算时按配置的区间规则抽取平台分成
2. THE Admin_Panel SHALL 支持设置跑腿佣金区间范围和对应的抽成比例
3. WHEN 佣金落在某个区间范围内时THE API_Server SHALL 按该区间配置的抽成比例计算平台分成,跑腿实得佣金为原始佣金减去平台分成
### 需求 29跑腿账号管理
**用户故事:** 作为管理员,我希望管理跑腿账号,以便维护平台秩序和服务质量。
#### 验收标准
1. THE Admin_Panel SHALL 支持根据跑腿分数手动封禁跑腿身份
2. IF 被封禁的跑腿点击【接单】按钮THEN THE Miniapp_Client SHALL 弹出系统提示"您的跑腿身份已被封禁,无法接单"
### 需求 30Banner 后台管理
**用户故事:** 作为管理员,我希望在管理后台对首页 Banner 进行增删改查操作,以便灵活配置首页轮播内容。
#### 验收标准
1. WHEN 管理员访问 Banner 管理页面时THE Admin_Panel SHALL 以表格形式展示所有 Banner 记录,包含图片缩略图、链接类型、链接地址、排序权重、启用状态
2. WHEN 管理员点击"新增 Banner"按钮并填写表单后THE Admin_Panel SHALL 调用 API_Server 创建新的 Banner 记录
3. WHEN 管理员编辑某条 Banner 记录并提交后THE Admin_Panel SHALL 调用 API_Server 更新该 Banner 记录
4. WHEN 管理员删除某条 Banner 记录时THE Admin_Panel SHALL 弹出确认对话框,确认后调用 API_Server 删除该记录
5. THE API_Server SHALL 提供 Banner 的创建、查询、更新、删除接口
6. WHEN 创建或更新 Banner 时THE API_Server SHALL 验证图片地址不为空、链接类型为合法枚举值(外部链接或内部页面)、链接地址不为空
7. IF 创建或更新 Banner 的请求数据校验失败THEN THE API_Server SHALL 返回包含具体校验错误信息的错误响应
8. WHEN 管理员上传 Banner 图片时THE Admin_Panel SHALL 支持图片上传功能,并将图片地址回填至表单
### 需求 31服务入口后台管理
**用户故事:** 作为管理员,我希望在管理后台配置首页服务入口的图标图片,以便灵活调整首页服务入口的展示效果。
#### 验收标准
1. WHEN 管理员访问服务入口管理页面时THE Admin_Panel SHALL 以表格或卡片形式展示所有服务入口配置,包含服务名称、图标图片、跳转路径、排序权重、启用状态
2. WHEN 管理员编辑某个服务入口的图标图片并提交后THE Admin_Panel SHALL 调用 API_Server 更新该服务入口配置
3. THE API_Server SHALL 提供服务入口配置的查询和更新接口
4. WHEN 更新服务入口配置时THE API_Server SHALL 验证图标图片地址不为空
5. IF 更新服务入口配置的请求数据校验失败THEN THE API_Server SHALL 返回包含具体校验错误信息的错误响应
### 需求 32用户认证与接口安全
**用户故事:** 作为系统架构师,我希望后台接口具备认证和安全机制,以便保护用户数据和系统安全。
#### 验收标准
1. WHILE 用户未登录时THE API_Server SHALL 拒绝除登录接口外的所有请求,并返回 401 状态码
2. THE API_Server SHALL 使用 JWT 作为登录凭证格式,凭证中包含用户唯一标识和过期时间
3. WHEN API_Server 收到携带 JWT 的请求时THE API_Server SHALL 验证 JWT 的有效性和未过期状态
4. IF JWT 验证失败或已过期THEN THE API_Server SHALL 返回 401 状态码
5. WHILE 请求来源非管理员身份时THE API_Server SHALL 拒绝管理后台相关接口的访问,并返回 403 状态码
### 需求 33数据序列化
**用户故事:** 作为开发者,我希望所有数据在前后端之间以 JSON 格式传输,以便保证数据一致性。
#### 验收标准
1. THE API_Server SHALL 以 JSON 格式序列化和反序列化所有 API 请求和响应数据
2. FOR ALL 合法的 Banner 对象,序列化后再反序列化 SHALL 产生与原始对象等价的结果(往返一致性)
3. FOR ALL 合法的服务入口对象,序列化后再反序列化 SHALL 产生与原始对象等价的结果(往返一致性)
4. FOR ALL 合法的订单对象,序列化后再反序列化 SHALL 产生与原始对象等价的结果(往返一致性)

View File

@ -0,0 +1,408 @@
# 实现计划:校园跑腿微信小程序
## 概述
基于设计文档,将实现分为后台接口(.NET 10、小程序前端uni-app Vue 3、管理后台Vue 3 + Element Plus三端。采用后端优先策略先搭建 API 和数据层,再实现前端页面。
## 任务
- [x] 1. 搭建后台接口项目基础结构
- [x] 1.1 初始化 .NET 10 Web API 项目,配置 MySQL/EF Core、JWT 认证中间件、CORS、Swagger
- 创建 `server/` 目录,使用 `dotnet new webapi` 初始化项目
- 安装 NuGet 包EF Core MySQL、JWT Bearer、Swashbuckle
- 配置 `appsettings.json`数据库连接、JWT 密钥、微信 AppId/Secret
- 编写 JWT 认证中间件和角色授权策略User、Admin
- _Requirements: 32.1, 32.2, 32.3, 32.4, 32.5_
- [x] 1.2 编写 JWT 认证属性测试
- **Property 26: JWT 认证**
- **Validates: Requirements 32.1, 32.3, 32.4, 32.5**
- [x] 1.3 创建数据库实体模型和 DbContext
- 定义所有 18 张表的 Entity 类Users, Banners, ServiceEntries, Orders, FoodOrderItems, Shops, ShopBanners, Dishes, Reviews, PriceChanges, Appeals, Earnings, Withdrawals, CommissionRules, SystemMessages, MessageReads, SystemConfigs, RunnerCertifications
- 配置 EF Core Fluent API 映射(索引、关系、枚举转换)
- 创建初始 Migration
- _Requirements: 全部数据模型_
- [x] 1.4 编写数据序列化往返属性测试
- **Property 27: 数据序列化往返一致性**
- **Validates: Requirements 33.2, 33.3, 33.4**
- [x] 2. 检查点 - 确保所有测试通过
- 确保所有测试通过,如有问题请询问用户。
- [x] 3. 实现用户认证模块
- [x] 3.1 实现微信登录接口 `POST /api/auth/login`
- 接收 code + encryptedData + iv
- 调用微信 code2Session 获取 session_key 和 openid
- 解密手机号,查找或创建用户
- 生成 JWT 返回
- _Requirements: 1.3, 1.4_
- [x] 3.2 编写登录接口属性测试
- **Property 1: 登录接口幂等性——手机号查找或创建**
- **Validates: Requirements 1.4**
- [x] 4. 实现 Banner 和服务入口模块
- [x] 4.1 实现 Banner CRUD 接口
- `GET /api/banners`(前端,仅启用+排序)
- `GET /api/admin/banners`(管理端,全部)
- `POST /api/admin/banners`(创建,含校验)
- `PUT /api/admin/banners/{id}`(更新,含校验)
- `DELETE /api/admin/banners/{id}`(删除)
- _Requirements: 2.5, 2.6, 30.5, 30.6, 30.7_
- [x] 4.2 编写 Banner 列表排序过滤属性测试
- **Property 5: Banner 列表排序与过滤**
- **Validates: Requirements 2.5**
- [x] 4.3 编写 Banner 创建校验属性测试
- **Property 25: Banner 创建校验**
- **Validates: Requirements 30.6, 30.7**
- [x] 4.4 实现服务入口接口
- `GET /api/service-entries`(前端,仅启用+排序)
- `GET /api/admin/service-entries`(管理端)
- `PUT /api/admin/service-entries/{id}`(更新,含校验)
- _Requirements: 3.7, 3.8, 31.3, 31.4, 31.5_
- [x] 4.5 编写服务入口列表排序过滤属性测试
- **Property 6: 服务入口列表排序与过滤**
- **Validates: Requirements 3.7**
- [x] 5. 实现订单创建模块
- [x] 5.1 实现订单创建接口 `POST /api/orders`
- 支持五种订单类型(代取、代送、万能帮、代购、美食街)
- 佣金校验(最低 1.0 元,小数点后 1 位)
- 支付金额计算(佣金类 vs 商品+佣金类)
- 手机号隐藏逻辑(未接单时隐藏)
- _Requirements: 4.1-4.6, 5.1-5.3, 6.1-6.4, 7.1-7.3_
- [x] 5.2 编写佣金校验属性测试
- **Property 2: 跑腿佣金输入校验**
- **Validates: Requirements 4.2, 4.3**
- [x] 5.3 编写支付金额计算属性测试
- **Property 3: 订单支付金额计算**
- **Validates: Requirements 6.3, 7.2, 9.8**
- [x] 5.4 编写手机号隐藏规则属性测试
- **Property 4: 手机号隐藏规则**
- **Validates: Requirements 4.6**
- [x] 6. 实现美食街模块
- [x] 6.1 实现门店和菜品接口
- `GET /api/shops`(门店列表)
- `GET /api/shops/{id}`(门店详情含菜品)
- 管理端 CRUD 接口
- _Requirements: 8.1-8.5_
- [x] 6.2 实现打包费计算逻辑
- 总打包费模式:固定金额
- 单份打包费模式:份数 × 单价
- 集成到美食街订单创建流程
- _Requirements: 10.1, 10.2, 10.3_
- [x] 6.3 编写打包费计算属性测试
- **Property 8: 打包费计算**
- **Validates: Requirements 10.1, 10.2, 10.3**
- [x] 7. 检查点 - 确保所有测试通过
- 确保所有测试通过,如有问题请询问用户。
- [x] 8. 实现订单大厅和接单模块
- [x] 8.1 实现订单大厅接口 `GET /api/orders/hall`
- 仅返回 Status=Pending 的订单
- 支持按分类筛选和排序(佣金优先/距离优先)
- 按订单类型返回对应展示字段
- _Requirements: 11.1-11.10_
- [x] 8.2 编写订单大厅过滤属性测试
- **Property 9: 订单大厅仅展示未接取订单**
- **Validates: Requirements 11.2**
- [x] 8.3 编写订单大厅排序属性测试
- **Property 10: 订单大厅佣金排序**
- **Validates: Requirements 11.4**
- [x] 8.4 实现接单接口 `POST /api/orders/{id}/accept`
- 乐观锁防止并发接单
- 状态转换Pending → InProgress
- 设置 RunnerId 和 AcceptedAt
- _Requirements: 12.1-12.6_
- [x] 8.5 编写接单状态转换属性测试
- **Property 11: 接单状态转换**
- **Validates: Requirements 12.2, 21.5**
- [x] 9. 实现跑腿认证模块
- [x] 9.1 实现跑腿认证接口
- `POST /api/runner/certification`(提交认证)
- `GET /api/runner/certification`(查询状态)
- `GET /api/admin/certifications`(管理端列表)
- `PUT /api/admin/certifications/{id}`(审核)
- 接单前置认证检查逻辑
- _Requirements: 13.1-13.5_
- [x] 9.2 编写跑腿认证前置检查属性测试
- **Property 12: 跑腿认证前置检查**
- **Validates: Requirements 13.1, 13.2**
- [x] 10. 实现订单管理模块
- [x] 10.1 实现订单状态管理接口
- `POST /api/orders/{id}/cancel`(取消订单)
- `POST /api/orders/{id}/complete`(跑腿提交完成)
- `POST /api/orders/{id}/confirm`(单主确认完成)
- `POST /api/orders/{id}/reject`(单主拒绝完成)
- `GET /api/orders/mine`(我的订单)
- `GET /api/orders/taken`(我的接单)
- `GET /api/orders/{id}`(订单详情)
- _Requirements: 21.1-21.11, 24.1-24.6, 25.1-25.3, 26.1-26.6_
- [x] 10.2 编写完成订单状态转换属性测试
- **Property 20: 完成订单状态转换**
- **Validates: Requirements 26.2, 26.5, 26.6**
- [x] 10.3 编写订单详情按状态显示属性测试
- **Property 19: 订单详情按状态显示字段**
- **Validates: Requirements 24.4, 24.5, 24.6**
- [x] 11. 实现评价和改价模块
- [x] 11.1 实现评价接口
- `POST /api/orders/{id}/review`(提交评价,含评分计算)
- `GET /api/admin/reviews`(管理端查看)
- `PUT /api/admin/reviews/{id}/disable`(禁用评价)
- 评分计算逻辑1星=-2, 2星=-1, 3星=0, 4星=+1, 5星=+2
- 评价可见性控制(仅管理员可见)
- _Requirements: 22.1-22.6_
- [x] 11.2 编写跑腿评分计算属性测试
- **Property 17: 跑腿评分计算**
- **Validates: Requirements 22.1, 22.2**
- [x] 11.3 编写评价可见性属性测试
- **Property 18: 评价可见性**
- **Validates: Requirements 22.5**
- [x] 11.4 实现改价接口
- `POST /api/orders/{id}/price-change`(发起改价)
- `PUT /api/orders/{id}/price-change/{changeId}`(响应改价)
- 差额计算逻辑(补缴/退款)
- _Requirements: 18.1-18.5, 19.1-19.5_
- [x] 11.5 编写改价差额计算属性测试
- **Property 16: 改价差额计算**
- **Validates: Requirements 19.1, 19.2**
- [x] 12. 实现收益和提现模块
- [x] 12.1 实现收益和提现接口
- `GET /api/earnings`(收益概览)
- `GET /api/earnings/records`(收益记录)
- `GET /api/earnings/withdrawals`(提现记录)
- `POST /api/earnings/withdraw`(申请提现,含金额校验)
- 佣金分销计算逻辑
- 收益冻结/解冻定时任务
- _Requirements: 27.1-27.10, 28.1-28.3_
- [x] 12.2 编写收益冻结与解冻属性测试
- **Property 21: 收益冻结与解冻**
- **Validates: Requirements 27.2, 27.3**
- [x] 12.3 编写提现金额校验属性测试
- **Property 22: 提现金额校验**
- **Validates: Requirements 27.7, 27.8, 27.9**
- [x] 12.4 编写佣金分销计算属性测试
- **Property 23: 佣金分销计算**
- **Validates: Requirements 28.1, 28.3**
- [x] 13. 实现消息通知和跑腿管理模块
- [x] 13.1 实现消息通知接口
- `GET /api/messages/unread-count`(未读消息数)
- `GET /api/messages/system`(系统消息列表)
- `GET /api/messages/order-notifications`(订单通知列表)
- `POST /api/admin/notifications`(发布系统通知)
- _Requirements: 14.1-14.6, 15.1-15.4, 16.1-16.3_
- [x] 13.2 编写未读消息计数属性测试
- **Property 13: 未读消息计数**
- **Validates: Requirements 14.2, 14.3, 14.4**
- [x] 13.3 实现跑腿管理和申诉接口
- `GET /api/admin/runners`(跑腿列表)
- `PUT /api/admin/runners/{id}/ban`(封禁/解封)
- 订单申诉状态管理
- _Requirements: 29.1-29.2, 23.1-23.4_
- [x] 13.4 编写封禁跑腿接单拒绝属性测试
- **Property 24: 封禁跑腿接单拒绝**
- **Validates: Requirements 29.2**
- [x] 14. 实现配置管理和文件上传接口
- [x] 14.1 实现系统配置和文件上传接口
- `POST /api/upload/image`(图片上传)
- `GET /api/config/qrcode`(客服二维码)
- `GET /api/config/agreement`(用户协议)
- `GET /api/config/privacy`(隐私政策)
- `GET /api/config/withdrawal-guide`(提现说明)
- `PUT /api/admin/config/{key}`(更新配置)
- `GET/PUT /api/admin/commission-rules`(佣金规则)
- _Requirements: 20.4, 20.7, 27.5, 28.2_
- [x] 15. 检查点 - 后台接口完成
- 确保所有后台接口测试通过,如有问题请询问用户。
- [x] 16. 搭建小程序前端基础结构
- [x] 16.1 配置小程序项目基础
- 在 `miniapp/` 目录配置 pages.json所有页面路由和 tabBar
- 配置请求拦截器(自动携带 JWT、401 跳转登录)
- 封装 API 请求工具函数
- 配置全局状态管理Pinia
- _Requirements: 1.8, 1.9, 32.1_
- [x] 17. 实现登录页和首页
- [x] 17.1 实现登录页
- 手机号快捷登录按钮,调用 `getPhoneNumber`
- 调用登录 API存储 token
- 授权失败和登录失败的错误提示
- _Requirements: 1.1-1.9_
- [x] 17.2 实现首页
- Banner 轮播组件(支持外部链接 web-view 和内部页面跳转)
- 五大服务入口按钮(图标从 API 获取,点击跳转对应页面)
- Banner 为空时隐藏区域
- _Requirements: 2.1-2.4, 3.1-3.6_
- [x] 18. 实现下单页面
- [x] 18.1 实现代取页、代送页、万能帮页、代购页
- 各类型订单表单(字段按需求文档)
- 佣金校验(最低 1.0 元,小数点后 1 位)
- 微信支付调用
- _Requirements: 4.1-4.5, 5.1-5.3, 6.1-6.4, 7.1-7.3_
- [x] 18.2 实现美食街页(门店列表 + 门店详情)
- 门店列表展示
- 门店详情页Banner、注意事项、菜品列表
- _Requirements: 8.1-8.3_
- [x] 18.3 实现购物车功能和美食街订单页
- 购物车状态管理Pinia store
- 菜品加减操作
- 底部购物车栏(数量、总价)
- 购物车弹窗
- 美食街订单页(表单 + 自动计算总额)
- _Requirements: 9.1-9.9_
- [x] 18.4 编写购物车数量与价格不变量属性测试
- **Property 7: 购物车数量与价格不变量**
- **Validates: Requirements 9.1, 9.2, 9.3**
- [x] 19. 实现订单大厅和接单页面
- [x] 19.1 实现订单大厅页
- 分类标签切换(代取、代送、万能帮、代购、美食街)
- 排序切换(佣金优先/距离优先)
- 各类型订单卡片展示
- 刷新按钮
- 定位权限申请
- _Requirements: 11.1-11.10_
- [x] 19.2 实现接单功能
- 接单确认弹窗
- 跑腿认证前置检查弹窗
- 美食街订单详情页和接单
- 并发接单提示
- _Requirements: 12.1-12.6, 13.1-13.4_
- [x] 20. 检查点 - 确保所有测试通过
- 确保所有测试通过,如有问题请询问用户。
- [x] 21. 实现消息和聊天页面
- [x] 21.1 实现消息页
- 系统消息入口(含未读数)
- 订单通知入口(含未读数)
- 聊天记录用户列表
- 底部导航栏未读数 badge
- _Requirements: 14.1-14.6_
- [x] 21.2 实现系统消息页和订单通知页
- 系统消息列表(标题、正文截断、缩略图、时间)
- 通知详情页
- 订单通知列表(分类筛选)
- _Requirements: 15.1-15.2, 16.1-16.3_
- [x] 21.3 实现聊天页
- 集成腾讯 IM SDK
- 顶部订单信息栏
- 聊天记录展示
- 电话弹窗(按角色显示对方手机号)
- 更多功能菜单(按订单类型和角色显示按钮)
- 发送图片功能
- _Requirements: 17.1-17.8_
- [x] 21.4 编写聊天页手机号显示规则属性测试
- **Property 14: 聊天页手机号显示规则**
- **Validates: Requirements 17.3**
- [x] 21.5 编写聊天功能按钮显示规则属性测试
- **Property 15: 聊天功能按钮显示规则**
- **Validates: Requirements 17.6**
- [x] 22. 实现改价和订单确认页面
- [x] 22.1 实现改价功能
- 改价弹窗(修改商品总额/跑腿佣金)
- 改价申请消息展示
- 同意/拒绝操作
- 补缴支付和退款提示
- _Requirements: 18.1-18.5, 19.1-19.5_
- [x] 22.2 实现完成订单确认页
- 订单信息展示
- 上传完成凭证
- 单主审核流程(确认/拒绝)
- 聊天页系统提示
- _Requirements: 26.1-26.6_
- [x] 23. 实现"我的"相关页面
- [x] 23.1 实现"我的"页面
- 订单统计(下单数、接单数、完成数)
- 功能入口(联系客服、客服二维码、跑腿认证、我的收益、用户协议、隐私政策、退出登录)
- _Requirements: 20.1-20.8_
- [x] 23.2 实现我的订单页和我的接单页
- 状态和类型筛选
- 按状态显示操作按钮
- 评价跑腿弹窗
- _Requirements: 21.1-21.11, 25.1-25.3_
- [x] 23.3 实现订单详情页
- 按订单状态显示不同字段和按钮
- 美食街订单额外信息
- 申诉处理结果展示
- _Requirements: 24.1-24.6, 23.3-23.4_
- [x] 23.4 实现我的收益页
- 四种金额状态展示
- 提现记录和收益记录
- 申请提现弹窗(金额校验、收款方式选择)
- 提现说明弹窗
- _Requirements: 27.1-27.10_
- [x] 24. 检查点 - 小程序前端完成
- 确保所有测试通过,如有问题请询问用户。
- [x] 25. 搭建管理后台项目
- [x] 25.1 初始化管理后台项目
- 创建 `admin/` 目录,使用 Vite + Vue 3 + Element Plus 初始化
- 配置路由、Axios 请求拦截器JWT、布局组件
- 实现管理员登录页
- _Requirements: 32.5_
- [x] 26. 实现管理后台页面
- [x] 26.1 实现 Banner 管理页面
- Banner 列表表格(图片缩略图、链接类型、链接地址、排序、启用状态)
- 新增/编辑 Banner 表单弹窗(含图片上传)
- 删除确认对话框
- _Requirements: 30.1-30.8_
- [x] 26.2 实现服务入口管理页面
- 服务入口列表(卡片或表格形式)
- 编辑图标图片表单(含图片上传)
- _Requirements: 31.1-31.5_
- [x] 26.3 实现门店和菜品管理页面
- 门店 CRUD照片、名称、位置、注意事项、打包费配置
- 门店 Banner 管理
- 菜品 CRUD照片、名称、价格
- _Requirements: 8.5, 10.4_
- [x] 26.4 实现跑腿认证审核页面
- 认证申请列表
- 审核操作(通过/拒绝)
- _Requirements: 13.5_
- [x] 26.5 实现跑腿管理和评价管理页面
- 跑腿列表(分数、封禁状态)
- 封禁/解封操作
- 评价列表(分值变化记录、评价内容)
- 禁用评价操作
- _Requirements: 29.1, 22.3, 22.4_
- [x] 26.6 实现系统通知和订单管理页面
- 发布系统通知(富文本编辑、目标用户选择)
- 订单列表和申诉管理
- _Requirements: 15.3, 15.4, 23.1, 23.2_
- [x] 26.7 实现配置管理页面
- 佣金规则配置
- 客服二维码配置
- 用户协议/隐私政策配置
- 提现说明配置
- 冻结时间配置
- _Requirements: 28.2, 20.4, 20.7, 27.5_
- [x] 27. 最终检查点 - 确保所有测试通过
- 确保所有测试通过,如有问题请询问用户。
## 备注
- 所有任务(含属性测试)均为必选任务
- 每个任务引用了具体的需求编号以便追溯
- 检查点确保增量验证
- 属性测试验证通用正确性属性
- 单元测试验证具体示例和边界情况
- 聊天功能依赖腾讯 IM SDK需提前申请和配置
- 微信支付功能需要商户号配置
- 距离排序功能依赖地图 API需评估可行性

View File

@ -0,0 +1,9 @@
---
inclusion: always
---
# 语言规则
- 始终使用中文回复用户的问题和对话。
- 代码注释使用中文。
- Git commit message 使用中文。

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"git.ignoreLimitWarning": true
}

View File

@ -0,0 +1 @@
import{_ as A,k as r,w as e,r as d,u as N,o as i,a as t,b as f,c as p,e as n,m as T,h as a,p as V,n as E,s as I,q as L,f as $,t as j,v as q,x as z,y as M,z as R,A as S,B as D,j as F,C as G}from"./index-DdxTGUP0.js";const H={class:"logo-area"},J={key:0},K={key:1},O={class:"header-right"},P={class:"admin-info"},Q={__name:"AdminLayout",setup(U){const c=N(),u=F(!1);function x(_){_==="logout"&&G.confirm("确定退出登录?","提示",{confirmButtonText:"确定",cancelButtonText:"取消",type:"warning"}).then(()=>{localStorage.removeItem("admin_token"),c.push("/login")})}return(_,l)=>{const o=d("el-icon"),s=d("el-menu-item"),v=d("el-menu"),w=d("el-aside"),g=d("el-dropdown-item"),y=d("el-dropdown-menu"),k=d("el-dropdown"),B=d("el-header"),b=d("router-view"),C=d("el-main"),m=d("el-container");return i(),r(m,{class:"layout-container"},{default:e(()=>[t(w,{width:u.value?"64px":"220px",class:"layout-aside"},{default:e(()=>[f("div",H,[u.value?(i(),p("span",K,"跑腿")):(i(),p("span",J,"校园跑腿管理后台"))]),t(v,{"default-active":_.$route.path,collapse:u.value,router:"","background-color":"#304156","text-color":"#bfcbd9","active-text-color":"#409eff"},{default:e(()=>[t(s,{index:"/dashboard"},{title:e(()=>[...l[1]||(l[1]=[a("首页概览",-1)])]),default:e(()=>[t(o,null,{default:e(()=>[t(n(T))]),_:1})]),_:1}),t(s,{index:"/banners"},{title:e(()=>[...l[2]||(l[2]=[a("Banner 管理",-1)])]),default:e(()=>[t(o,null,{default:e(()=>[t(n(V))]),_:1})]),_:1}),t(s,{index:"/service-entries"},{title:e(()=>[...l[3]||(l[3]=[a("服务入口管理",-1)])]),default:e(()=>[t(o,null,{default:e(()=>[t(n(E))]),_:1})]),_:1}),t(s,{index:"/shops"},{title:e(()=>[...l[4]||(l[4]=[a("门店管理",-1)])]),default:e(()=>[t(o,null,{default:e(()=>[t(n(I))]),_:1})]),_:1}),t(s,{index:"/certifications"},{title:e(()=>[...l[5]||(l[5]=[a("跑腿认证审核",-1)])]),default:e(()=>[t(o,null,{default:e(()=>[t(n(L))]),_:1})]),_:1}),t(s,{index:"/runners"},{title:e(()=>[...l[6]||(l[6]=[a("跑腿管理",-1)])]),default:e(()=>[t(o,null,{default:e(()=>[t(n($))]),_:1})]),_:1}),t(s,{index:"/reviews"},{title:e(()=>[...l[7]||(l[7]=[a("评价管理",-1)])]),default:e(()=>[t(o,null,{default:e(()=>[t(n(j))]),_:1})]),_:1}),t(s,{index:"/notifications"},{title:e(()=>[...l[8]||(l[8]=[a("系统通知",-1)])]),default:e(()=>[t(o,null,{default:e(()=>[t(n(q))]),_:1})]),_:1}),t(s,{index:"/orders"},{title:e(()=>[...l[9]||(l[9]=[a("订单管理",-1)])]),default:e(()=>[t(o,null,{default:e(()=>[t(n(z))]),_:1})]),_:1}),t(s,{index:"/config"},{title:e(()=>[...l[10]||(l[10]=[a("配置管理",-1)])]),default:e(()=>[t(o,null,{default:e(()=>[t(n(M))]),_:1})]),_:1})]),_:1},8,["default-active","collapse"])]),_:1},8,["width"]),t(m,null,{default:e(()=>[t(B,{class:"layout-header"},{default:e(()=>[t(o,{class:"collapse-btn",onClick:l[0]||(l[0]=W=>u.value=!u.value)},{default:e(()=>[u.value?(i(),r(n(S),{key:1})):(i(),r(n(R),{key:0}))]),_:1}),f("div",O,[t(k,{onCommand:x},{dropdown:e(()=>[t(y,null,{default:e(()=>[t(g,{command:"logout"},{default:e(()=>[...l[12]||(l[12]=[a("退出登录",-1)])]),_:1})]),_:1})]),default:e(()=>[f("span",P,[l[11]||(l[11]=a(" 管理员 ",-1)),t(o,null,{default:e(()=>[t(n(D))]),_:1})])]),_:1})])]),_:1}),t(C,{class:"layout-main"},{default:e(()=>[t(b)]),_:1})]),_:1})]),_:1})}}},Y=A(Q,[["__scopeId","data-v-70df5590"]]);export{Y as default};

View File

@ -0,0 +1 @@
.layout-container[data-v-70df5590]{height:100vh}.layout-aside[data-v-70df5590]{background-color:#304156;transition:width .3s;overflow:hidden}.logo-area[data-v-70df5590]{height:60px;display:flex;align-items:center;justify-content:center;color:#fff;font-size:16px;font-weight:700;white-space:nowrap;border-bottom:1px solid #3a4a5e}.layout-header[data-v-70df5590]{display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid #e6e6e6;background:#fff}.collapse-btn[data-v-70df5590]{font-size:20px;cursor:pointer}.header-right[data-v-70df5590]{display:flex;align-items:center}.admin-info[data-v-70df5590]{display:flex;align-items:center;cursor:pointer;gap:4px}.layout-main[data-v-70df5590]{background-color:#f0f2f5}

1
admin/dist/assets/Banners-FYTfaTGn.js vendored Normal file
View File

@ -0,0 +1 @@
import{s as f}from"./request-CrM1Jo5H.js";import{D as G,c as L,b as B,a as l,w as a,F as J,k as K,r as i,G as P,j as r,i as Q,o as C,h as s,H as T,C as W,E as v}from"./index-DdxTGUP0.js";const X={style:{display:"flex","justify-content":"space-between","align-items":"center","margin-bottom":"16px"}},le={__name:"Banners",setup(Y){const c=r(!1),g=r(!1),y=r([]),m=r(!1),_=r(!1),k=r(null),U=r(null),O={Authorization:`Bearer ${localStorage.getItem("admin_token")}`},V=()=>({imageUrl:"",linkType:"External",linkUrl:"",sortOrder:0,isEnabled:!0}),n=Q(V()),$={imageUrl:[{required:!0,message:"图片地址不能为空",trigger:"blur"}],linkType:[{required:!0,message:"请选择链接类型",trigger:"change"}],linkUrl:[{required:!0,message:"链接地址不能为空",trigger:"blur"}]};async function b(){c.value=!0;try{y.value=await f.get("/admin/banners")}finally{c.value=!1}}function x(o){_.value=!!o,k.value=(o==null?void 0:o.id)||null,Object.assign(n,o?{imageUrl:o.imageUrl,linkType:o.linkType,linkUrl:o.linkUrl,sortOrder:o.sortOrder,isEnabled:o.isEnabled}:V()),m.value=!0}async function D(){if(await U.value.validate().catch(()=>!1)){g.value=!0;try{_.value?(await f.put(`/admin/banners/${k.value}`,n),v.success("更新成功")):(await f.post("/admin/banners",n),v.success("创建成功")),m.value=!1,b()}finally{g.value=!1}}}async function z(o){await W.confirm("确定删除该 Banner","提示",{type:"warning"}),await f.delete(`/admin/banners/${o.id}`),v.success("删除成功"),b()}return G(b),(o,e)=>{const d=i("el-button"),j=i("el-image"),u=i("el-table-column"),q=i("el-tag"),I=i("el-table"),E=i("el-input"),M=i("el-upload"),p=i("el-form-item"),w=i("el-option"),N=i("el-select"),S=i("el-input-number"),F=i("el-switch"),H=i("el-form"),R=i("el-dialog"),h=P("loading");return C(),L("div",null,[B("div",X,[e[9]||(e[9]=B("h3",{style:{margin:"0"}},"Banner 管理",-1)),l(d,{type:"primary",onClick:e[0]||(e[0]=t=>x())},{default:a(()=>[...e[8]||(e[8]=[s("新增 Banner",-1)])]),_:1})]),J((C(),K(I,{data:y.value,border:""},{default:a(()=>[l(u,{label:"图片",width:"120"},{default:a(({row:t})=>[l(j,{src:t.imageUrl,style:{width:"80px",height:"45px"},fit:"cover"},null,8,["src"])]),_:1}),l(u,{prop:"linkType",label:"链接类型",width:"120"},{default:a(({row:t})=>[s(T(t.linkType==="External"?"外部链接":"内部页面"),1)]),_:1}),l(u,{prop:"linkUrl",label:"链接地址","show-overflow-tooltip":""}),l(u,{prop:"sortOrder",label:"排序",width:"80"}),l(u,{label:"启用状态",width:"100"},{default:a(({row:t})=>[l(q,{type:t.isEnabled?"success":"info"},{default:a(()=>[s(T(t.isEnabled?"启用":"禁用"),1)]),_:2},1032,["type"])]),_:1}),l(u,{label:"操作",width:"160",fixed:"right"},{default:a(({row:t})=>[l(d,{size:"small",onClick:A=>x(t)},{default:a(()=>[...e[10]||(e[10]=[s("编辑",-1)])]),_:1},8,["onClick"]),l(d,{size:"small",type:"danger",onClick:A=>z(t)},{default:a(()=>[...e[11]||(e[11]=[s("删除",-1)])]),_:1},8,["onClick"])]),_:1})]),_:1},8,["data"])),[[h,c.value]]),l(R,{modelValue:m.value,"onUpdate:modelValue":e[7]||(e[7]=t=>m.value=t),title:_.value?"编辑 Banner":"新增 Banner",width:"500px"},{footer:a(()=>[l(d,{onClick:e[6]||(e[6]=t=>m.value=!1)},{default:a(()=>[...e[13]||(e[13]=[s("取消",-1)])]),_:1}),l(d,{type:"primary",loading:g.value,onClick:D},{default:a(()=>[...e[14]||(e[14]=[s("确定",-1)])]),_:1},8,["loading"])]),default:a(()=>[l(H,{ref_key:"formRef",ref:U,model:n,rules:$,"label-width":"90px"},{default:a(()=>[l(p,{label:"图片",prop:"imageUrl"},{default:a(()=>[l(E,{modelValue:n.imageUrl,"onUpdate:modelValue":e[1]||(e[1]=t=>n.imageUrl=t),placeholder:"图片地址"},null,8,["modelValue"]),l(M,{action:"/api/upload/image",headers:O,"show-file-list":!1,"on-success":t=>n.imageUrl=t.url,accept:"image/*",style:{"margin-top":"8px"}},{default:a(()=>[l(d,{size:"small"},{default:a(()=>[...e[12]||(e[12]=[s("上传图片",-1)])]),_:1})]),_:1},8,["on-success"])]),_:1}),l(p,{label:"链接类型",prop:"linkType"},{default:a(()=>[l(N,{modelValue:n.linkType,"onUpdate:modelValue":e[2]||(e[2]=t=>n.linkType=t),style:{width:"100%"}},{default:a(()=>[l(w,{label:"外部链接",value:"External"}),l(w,{label:"内部页面",value:"Internal"})]),_:1},8,["modelValue"])]),_:1}),l(p,{label:"链接地址",prop:"linkUrl"},{default:a(()=>[l(E,{modelValue:n.linkUrl,"onUpdate:modelValue":e[3]||(e[3]=t=>n.linkUrl=t),placeholder:"链接地址"},null,8,["modelValue"])]),_:1}),l(p,{label:"排序权重",prop:"sortOrder"},{default:a(()=>[l(S,{modelValue:n.sortOrder,"onUpdate:modelValue":e[4]||(e[4]=t=>n.sortOrder=t),min:0},null,8,["modelValue"])]),_:1}),l(p,{label:"启用状态"},{default:a(()=>[l(F,{modelValue:n.isEnabled,"onUpdate:modelValue":e[5]||(e[5]=t=>n.isEnabled=t)},null,8,["modelValue"])]),_:1})]),_:1},8,["model"])]),_:1},8,["modelValue","title"])])}}};export{le as default};

View File

@ -0,0 +1 @@
import{s as b}from"./request-CrM1Jo5H.js";import{D as V,c as m,b as y,a as e,w as o,F as B,k as R,j as _,r as i,G as $,o as d,h as r,H as w,J as E,C as P,E as T}from"./index-DdxTGUP0.js";const z={style:{display:"flex","justify-content":"space-between","align-items":"center","margin-bottom":"16px"}},F={key:1,style:{color:"#909399"}},S={__name:"Certifications",setup(I){const p=_(!1),f=_([]),c=_(""),h=t=>({Pending:"待审核",Approved:"已通过",Rejected:"已拒绝"})[t]||t,k=t=>({Pending:"warning",Approved:"success",Rejected:"danger"})[t]||"info",C=t=>t?new Date(t).toLocaleString("zh-CN"):"";async function u(){p.value=!0;try{const t=c.value?{status:c.value}:{};f.value=await b.get("/admin/certifications",{params:t})}finally{p.value=!1}}async function v(t,a){const s=a==="Approved"?"通过":"拒绝";await P.confirm(`确定${s}该认证申请?`,"提示",{type:"warning"}),await b.put(`/admin/certifications/${t.id}`,{status:a}),T.success(`${s}`),u()}return V(u),(t,a)=>{const s=i("el-option"),x=i("el-select"),n=i("el-table-column"),A=i("el-tag"),g=i("el-button"),D=i("el-table"),j=$("loading");return d(),m("div",null,[y("div",z,[a[1]||(a[1]=y("h3",{style:{margin:"0"}},"跑腿认证审核",-1)),e(x,{modelValue:c.value,"onUpdate:modelValue":a[0]||(a[0]=l=>c.value=l),placeholder:"筛选状态",clearable:"",style:{width:"150px"},onChange:u},{default:o(()=>[e(s,{label:"待审核",value:"Pending"}),e(s,{label:"已通过",value:"Approved"}),e(s,{label:"已拒绝",value:"Rejected"})]),_:1},8,["modelValue"])]),B((d(),R(D,{data:f.value,border:""},{default:o(()=>[e(n,{prop:"id",label:"ID",width:"60"}),e(n,{prop:"userId",label:"用户ID",width:"80"}),e(n,{prop:"userNickname",label:"用户昵称",width:"120"}),e(n,{prop:"realName",label:"真实姓名",width:"120"}),e(n,{prop:"phone",label:"手机号",width:"140"}),e(n,{label:"状态",width:"100"},{default:o(({row:l})=>[e(A,{type:k(l.status)},{default:o(()=>[r(w(h(l.status)),1)]),_:2},1032,["type"])]),_:1}),e(n,{prop:"createdAt",label:"申请时间",width:"170"},{default:o(({row:l})=>[r(w(C(l.createdAt)),1)]),_:1}),e(n,{label:"操作",width:"180",fixed:"right"},{default:o(({row:l})=>[l.status==="Pending"?(d(),m(E,{key:0},[e(g,{size:"small",type:"success",onClick:N=>v(l,"Approved")},{default:o(()=>[...a[2]||(a[2]=[r("通过",-1)])]),_:1},8,["onClick"]),e(g,{size:"small",type:"danger",onClick:N=>v(l,"Rejected")},{default:o(()=>[...a[3]||(a[3]=[r("拒绝",-1)])]),_:1},8,["onClick"])],64)):(d(),m("span",F,"已处理"))]),_:1})]),_:1},8,["data"])),[[j,p.value]])])}}};export{S as default};

1
admin/dist/assets/Config-CNY75kZu.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
import{_ as r,c as t,b as o,o as n}from"./index-DdxTGUP0.js";const s={};function a(c,e){return n(),t("div",null,[...e[0]||(e[0]=[o("h2",null,"欢迎使用校园跑腿管理后台",-1),o("p",{style:{color:"#909399","margin-top":"12px"}},"请从左侧菜单选择功能模块",-1)])])}const p=r(s,[["render",a]]);export{p as default};

1
admin/dist/assets/Login-BlVi7L0g.css vendored Normal file
View File

@ -0,0 +1 @@
.login-container[data-v-ed341a76]{height:100vh;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,#667eea,#764ba2)}.login-card[data-v-ed341a76]{width:400px;padding:20px}.login-title[data-v-ed341a76]{text-align:center;margin-bottom:30px;color:#303133}.login-btn[data-v-ed341a76]{width:100%}

1
admin/dist/assets/Login-C6YwVRKJ.js vendored Normal file
View File

@ -0,0 +1 @@
import{_ as x,c as y,a as o,w as a,r as t,u as V,o as b,b as h,d as k,e as p,f as z,g as B,l as C,h as E,E as L,i as N,j as c}from"./index-DdxTGUP0.js";import{s as R}from"./request-CrM1Jo5H.js";const q={class:"login-container"},I={__name:"Login",setup(K){const m=V(),u=c(null),l=c(!1),s=N({username:"",password:""}),f={username:[{required:!0,message:"请输入管理员账号",trigger:"blur"}],password:[{required:!0,message:"请输入密码",trigger:"blur"}]};async function r(){if(await u.value.validate().catch(()=>!1)){l.value=!0;try{const e=await R.post("/admin/auth/login",{username:s.username,password:s.password});localStorage.setItem("admin_token",e.token),L.success("登录成功"),m.push("/")}catch{}finally{l.value=!1}}}return(_,e)=>{const d=t("el-input"),n=t("el-form-item"),g=t("el-button"),w=t("el-form"),v=t("el-card");return b(),y("div",q,[o(v,{class:"login-card"},{default:a(()=>[e[3]||(e[3]=h("h2",{class:"login-title"},"校园跑腿管理后台",-1)),o(w,{ref_key:"formRef",ref:u,model:s,rules:f,"label-width":"0",onSubmit:k(r,["prevent"])},{default:a(()=>[o(n,{prop:"username"},{default:a(()=>[o(d,{modelValue:s.username,"onUpdate:modelValue":e[0]||(e[0]=i=>s.username=i),placeholder:"请输入管理员账号","prefix-icon":p(z),size:"large"},null,8,["modelValue","prefix-icon"])]),_:1}),o(n,{prop:"password"},{default:a(()=>[o(d,{modelValue:s.password,"onUpdate:modelValue":e[1]||(e[1]=i=>s.password=i),type:"password",placeholder:"请输入密码","prefix-icon":p(C),size:"large","show-password":"",onKeyup:B(r,["enter"])},null,8,["modelValue","prefix-icon"])]),_:1}),o(n,null,{default:a(()=>[o(g,{type:"primary",size:"large",class:"login-btn",loading:l.value,onClick:r},{default:a(()=>[...e[2]||(e[2]=[E(" 登录 ",-1)])]),_:1},8,["loading"])]),_:1})]),_:1},8,["model"])]),_:1})])}}},U=x(I,[["__scopeId","data-v-ed341a76"]]);export{U as default};

View File

@ -0,0 +1 @@
import{s as T}from"./request-CrM1Jo5H.js";import{c as k,b as I,a as l,w as o,r as n,o as c,h as g,k as N,L as h,i as B,j as p,E as _}from"./index-DdxTGUP0.js";const A={__name:"Notifications",setup(S){const d=p(!1),m=p(null),u=p(""),b={Authorization:`Bearer ${localStorage.getItem("admin_token")}`},t=B({title:"",content:"",thumbnailUrl:"",targetType:"All"}),v={title:[{required:!0,message:"请输入通知标题",trigger:"blur"}],content:[{required:!0,message:"请输入通知正文",trigger:"blur"}],targetType:[{required:!0,message:"请选择目标用户",trigger:"change"}]};async function y(){if(!await m.value.validate().catch(()=>!1))return;const e={...t};if(e.targetType==="Specific"&&(e.targetUserIds=u.value.split(",").map(r=>parseInt(r.trim())).filter(r=>!isNaN(r)),e.targetUserIds.length===0)){_.warning("请输入有效的用户ID");return}d.value=!0;try{await T.post("/admin/notifications",e),_.success("发布成功"),m.value.resetFields(),u.value=""}finally{d.value=!1}}return(V,e)=>{const r=n("el-input"),s=n("el-form-item"),f=n("el-button"),U=n("el-upload"),i=n("el-option"),x=n("el-select"),w=n("el-form");return c(),k("div",null,[e[7]||(e[7]=I("h3",{style:{margin:"0 0 16px"}},"发布系统通知",-1)),l(w,{ref_key:"formRef",ref:m,model:t,rules:v,"label-width":"100px",style:{"max-width":"700px"}},{default:o(()=>[l(s,{label:"通知标题",prop:"title"},{default:o(()=>[l(r,{modelValue:t.title,"onUpdate:modelValue":e[0]||(e[0]=a=>t.title=a),placeholder:"请输入通知标题"},null,8,["modelValue"])]),_:1}),l(s,{label:"通知正文",prop:"content"},{default:o(()=>[l(r,{modelValue:t.content,"onUpdate:modelValue":e[1]||(e[1]=a=>t.content=a),type:"textarea",rows:8,placeholder:"支持富文本内容"},null,8,["modelValue"])]),_:1}),l(s,{label:"缩略图"},{default:o(()=>[l(r,{modelValue:t.thumbnailUrl,"onUpdate:modelValue":e[2]||(e[2]=a=>t.thumbnailUrl=a),placeholder:"缩略图地址(选填)"},null,8,["modelValue"]),l(U,{action:"/api/upload/image",headers:b,"show-file-list":!1,"on-success":a=>t.thumbnailUrl=a.url,accept:"image/*",style:{"margin-top":"8px"}},{default:o(()=>[l(f,{size:"small"},{default:o(()=>[...e[5]||(e[5]=[g("上传图片",-1)])]),_:1})]),_:1},8,["on-success"])]),_:1}),l(s,{label:"目标用户",prop:"targetType"},{default:o(()=>[l(x,{modelValue:t.targetType,"onUpdate:modelValue":e[3]||(e[3]=a=>t.targetType=a),style:{width:"100%"}},{default:o(()=>[l(i,{label:"全部用户",value:"All"}),l(i,{label:"下单用户",value:"OrderUser"}),l(i,{label:"跑腿用户",value:"RunnerUser"}),l(i,{label:"指定用户",value:"Specific"})]),_:1},8,["modelValue"])]),_:1}),t.targetType==="Specific"?(c(),N(s,{key:0,label:"用户ID列表"},{default:o(()=>[l(r,{modelValue:u.value,"onUpdate:modelValue":e[4]||(e[4]=a=>u.value=a),placeholder:"多个用户ID用逗号分隔1,2,3"},null,8,["modelValue"])]),_:1})):h("",!0),l(s,null,{default:o(()=>[l(f,{type:"primary",loading:d.value,onClick:y},{default:o(()=>[...e[6]||(e[6]=[g("发布通知",-1)])]),_:1},8,["loading"])]),_:1})]),_:1},8,["model"])])}}};export{A as default};

1
admin/dist/assets/Orders-BxsxH1Fv.js vendored Normal file
View File

@ -0,0 +1 @@
import{s as C}from"./request-CrM1Jo5H.js";import{D as j,c as O,b as w,a as e,w as o,F as R,k as V,j as r,r as s,G,o as _,h as d,H as x,L as D,C as q,E as k,i as J}from"./index-DdxTGUP0.js";const K={style:{display:"flex","justify-content":"space-between","align-items":"center","margin-bottom":"16px"}},Q={style:{display:"flex",gap:"8px"}},ee={__name:"Orders",setup(X){const b=r(!1),g=r(!1),P=r([]),c=r(""),v=r(""),p=r(!1),h=r(null),i=J({result:"",newStatus:"Completed"}),N=a=>({Pickup:"代取",Delivery:"代送",Help:"万能帮",Purchase:"代购",Food:"美食街"})[a]||a,T=a=>({Pending:"待接单",InProgress:"进行中",WaitConfirm:"待确认",Completed:"已完成",Cancelled:"已取消",Appealing:"申诉中"})[a]||a,F=a=>({Pending:"info",InProgress:"primary",WaitConfirm:"warning",Completed:"success",Cancelled:"danger",Appealing:""})[a]||"info",S=a=>a?new Date(a).toLocaleString("zh-CN"):"";async function m(){b.value=!0;try{const a={};c.value&&(a.status=c.value),v.value&&(a.orderType=v.value),P.value=await C.get("/admin/orders",{params:a})}finally{b.value=!1}}async function $(a){await q.confirm(`确定将订单 ${a.orderNo} 设为申诉中?`,"提示",{type:"warning"}),await C.post(`/admin/orders/${a.id}/appeal`),k.success("已设为申诉中"),m()}function B(a){h.value=a.id,i.result="",i.newStatus="Completed",p.value=!0}async function I(){if(!i.result.trim()){k.warning("请输入处理结果");return}g.value=!0;try{await C.post(`/admin/orders/${h.value}/appeal/resolve`,i),k.success("申诉处理成功"),p.value=!1,m()}finally{g.value=!1}}return j(m),(a,t)=>{const n=s("el-option"),y=s("el-select"),u=s("el-table-column"),L=s("el-tag"),f=s("el-button"),U=s("el-table"),z=s("el-input"),A=s("el-form-item"),E=s("el-form"),W=s("el-dialog"),H=G("loading");return _(),O("div",null,[w("div",K,[t[6]||(t[6]=w("h3",{style:{margin:"0"}},"订单管理",-1)),w("div",Q,[e(y,{modelValue:c.value,"onUpdate:modelValue":t[0]||(t[0]=l=>c.value=l),placeholder:"订单状态",clearable:"",style:{width:"140px"},onChange:m},{default:o(()=>[e(n,{label:"待接单",value:"Pending"}),e(n,{label:"进行中",value:"InProgress"}),e(n,{label:"待确认",value:"WaitConfirm"}),e(n,{label:"已完成",value:"Completed"}),e(n,{label:"已取消",value:"Cancelled"}),e(n,{label:"申诉中",value:"Appealing"})]),_:1},8,["modelValue"]),e(y,{modelValue:v.value,"onUpdate:modelValue":t[1]||(t[1]=l=>v.value=l),placeholder:"订单类型",clearable:"",style:{width:"140px"},onChange:m},{default:o(()=>[e(n,{label:"代取",value:"Pickup"}),e(n,{label:"代送",value:"Delivery"}),e(n,{label:"万能帮",value:"Help"}),e(n,{label:"代购",value:"Purchase"}),e(n,{label:"美食街",value:"Food"})]),_:1},8,["modelValue"])])]),R((_(),V(U,{data:P.value,border:""},{default:o(()=>[e(u,{prop:"orderNo",label:"订单编号",width:"160"}),e(u,{prop:"orderType",label:"类型",width:"80"},{default:o(({row:l})=>[d(x(N(l.orderType)),1)]),_:1}),e(u,{label:"状态",width:"90"},{default:o(({row:l})=>[e(L,{type:F(l.status),size:"small"},{default:o(()=>[d(x(T(l.status)),1)]),_:2},1032,["type"])]),_:1}),e(u,{prop:"itemName",label:"内容","show-overflow-tooltip":""}),e(u,{prop:"commission",label:"佣金",width:"80"}),e(u,{prop:"totalAmount",label:"总额",width:"80"}),e(u,{prop:"createdAt",label:"下单时间",width:"170"},{default:o(({row:l})=>[d(x(S(l.createdAt)),1)]),_:1}),e(u,{label:"操作",width:"200",fixed:"right"},{default:o(({row:l})=>[l.status==="InProgress"||l.status==="WaitConfirm"?(_(),V(f,{key:0,size:"small",type:"warning",onClick:M=>$(l)},{default:o(()=>[...t[7]||(t[7]=[d("设为申诉",-1)])]),_:1},8,["onClick"])):D("",!0),l.status==="Appealing"?(_(),V(f,{key:1,size:"small",type:"success",onClick:M=>B(l)},{default:o(()=>[...t[8]||(t[8]=[d("处理申诉",-1)])]),_:1},8,["onClick"])):D("",!0)]),_:1})]),_:1},8,["data"])),[[H,b.value]]),e(W,{modelValue:p.value,"onUpdate:modelValue":t[5]||(t[5]=l=>p.value=l),title:"处理申诉",width:"450px"},{footer:o(()=>[e(f,{onClick:t[4]||(t[4]=l=>p.value=!1)},{default:o(()=>[...t[9]||(t[9]=[d("取消",-1)])]),_:1}),e(f,{type:"primary",loading:g.value,onClick:I},{default:o(()=>[...t[10]||(t[10]=[d("确定",-1)])]),_:1},8,["loading"])]),default:o(()=>[e(E,{model:i,"label-width":"90px"},{default:o(()=>[e(A,{label:"处理结果"},{default:o(()=>[e(z,{modelValue:i.result,"onUpdate:modelValue":t[2]||(t[2]=l=>i.result=l),type:"textarea",rows:3,placeholder:"请输入处理结果"},null,8,["modelValue"])]),_:1}),e(A,{label:"目标状态"},{default:o(()=>[e(y,{modelValue:i.newStatus,"onUpdate:modelValue":t[3]||(t[3]=l=>i.newStatus=l),style:{width:"100%"}},{default:o(()=>[e(n,{label:"已完成",value:"Completed"}),e(n,{label:"已取消",value:"Cancelled"})]),_:1},8,["modelValue"])]),_:1})]),_:1},8,["model"])]),_:1},8,["modelValue"])])}}};export{ee as default};

1
admin/dist/assets/Reviews-An_v7U4c.js vendored Normal file
View File

@ -0,0 +1 @@
import{D as I,c as g,b as m,a as t,w as l,g as N,F as V,k as v,j as _,r as i,G as B,o as p,h as r,H as d,K as z,C as E,E as K}from"./index-DdxTGUP0.js";import{s as h}from"./request-CrM1Jo5H.js";const M={style:{display:"flex","justify-content":"space-between","align-items":"center","margin-bottom":"16px"}},S={key:1,style:{color:"#909399"}},T={__name:"Reviews",setup(j){const u=_(!1),f=_([]),c=_(""),y=o=>o?new Date(o).toLocaleString("zh-CN"):"";async function s(){u.value=!0;try{const o=c.value?{runnerId:c.value}:{};f.value=await h.get("/admin/reviews",{params:o})}finally{u.value=!1}}async function w(o){await E.confirm("确定禁用该评价?禁用后将不计算该条评价的分数","提示",{type:"warning"}),await h.put(`/admin/reviews/${o.id}/disable`),K.success("已禁用"),s()}return I(s),(o,n)=>{const b=i("el-button"),C=i("el-input"),a=i("el-table-column"),D=i("el-tag"),k=i("el-table"),x=B("loading");return p(),g("div",null,[m("div",M,[n[2]||(n[2]=m("h3",{style:{margin:"0"}},"评价管理",-1)),t(C,{modelValue:c.value,"onUpdate:modelValue":n[0]||(n[0]=e=>c.value=e),placeholder:"按跑腿ID筛选",clearable:"",style:{width:"200px"},onClear:s,onKeyup:N(s,["enter"])},{append:l(()=>[t(b,{onClick:s},{default:l(()=>[...n[1]||(n[1]=[r("搜索",-1)])]),_:1})]),_:1},8,["modelValue"])]),V((p(),v(k,{data:f.value,border:""},{default:l(()=>[t(a,{prop:"id",label:"ID",width:"60"}),t(a,{prop:"orderNo",label:"订单编号",width:"160"}),t(a,{prop:"runnerId",label:"跑腿ID",width:"80"}),t(a,{prop:"runnerNickname",label:"跑腿昵称",width:"120"}),t(a,{prop:"rating",label:"星级",width:"80"},{default:l(({row:e})=>[r(d(e.rating)+"星",1)]),_:1}),t(a,{prop:"scoreChange",label:"分值变化",width:"100"},{default:l(({row:e})=>[m("span",{style:z({color:e.scoreChange>0?"#67c23a":e.scoreChange<0?"#f56c6c":"#909399"})},d(e.scoreChange>0?"+":"")+d(e.scoreChange),5)]),_:1}),t(a,{prop:"content",label:"评价内容","show-overflow-tooltip":""}),t(a,{label:"状态",width:"80"},{default:l(({row:e})=>[t(D,{type:e.isDisabled?"danger":"success",size:"small"},{default:l(()=>[r(d(e.isDisabled?"已禁用":"正常"),1)]),_:2},1032,["type"])]),_:1}),t(a,{prop:"createdAt",label:"评价时间",width:"170"},{default:l(({row:e})=>[r(d(y(e.createdAt)),1)]),_:1}),t(a,{label:"操作",width:"100",fixed:"right"},{default:l(({row:e})=>[e.isDisabled?(p(),g("span",S,"已禁用")):(p(),v(b,{key:0,size:"small",type:"danger",onClick:A=>w(e)},{default:l(()=>[...n[3]||(n[3]=[r("禁用",-1)])]),_:1},8,["onClick"]))]),_:1})]),_:1},8,["data"])),[[x,u.value]])])}}};export{T as default};

1
admin/dist/assets/Runners-BY9BCgqo.js vendored Normal file
View File

@ -0,0 +1 @@
import{s as f}from"./request-CrM1Jo5H.js";import{D as w,c as h,b as B,F as x,k as c,w as l,G as C,j as b,r as s,o,a,h as d,H as $,C as D,E}from"./index-DdxTGUP0.js";const z={__name:"Runners",setup(M){const i=b(!1),u=b([]);async function p(){i.value=!0;try{u.value=await f.get("/admin/runners")}finally{i.value=!1}}async function _(r,e){const t=e?"封禁":"解封";await D.confirm(`确定${t}跑腿「${r.nickname}」?`,"提示",{type:"warning"}),await f.put(`/admin/runners/${r.id}/ban`,{isBanned:e}),E.success(`${t}`),p()}return w(p),(r,e)=>{const t=s("el-table-column"),g=s("el-tag"),m=s("el-button"),v=s("el-table"),y=C("loading");return o(),h("div",null,[e[2]||(e[2]=B("h3",{style:{margin:"0 0 16px"}},"跑腿管理",-1)),x((o(),c(v,{data:u.value,border:""},{default:l(()=>[a(t,{prop:"id",label:"ID",width:"60"}),a(t,{prop:"nickname",label:"昵称",width:"120"}),a(t,{prop:"phone",label:"手机号",width:"140"}),a(t,{prop:"runnerScore",label:"评分",width:"80"}),a(t,{label:"封禁状态",width:"100"},{default:l(({row:n})=>[a(g,{type:n.isBanned?"danger":"success"},{default:l(()=>[d($(n.isBanned?"已封禁":"正常"),1)]),_:2},1032,["type"])]),_:1}),a(t,{label:"操作",width:"120",fixed:"right"},{default:l(({row:n})=>[n.isBanned?(o(),c(m,{key:1,size:"small",type:"success",onClick:k=>_(n,!1)},{default:l(()=>[...e[1]||(e[1]=[d("解封",-1)])]),_:1},8,["onClick"])):(o(),c(m,{key:0,size:"small",type:"danger",onClick:k=>_(n,!0)},{default:l(()=>[...e[0]||(e[0]=[d("封禁",-1)])]),_:1},8,["onClick"]))]),_:1})]),_:1},8,["data"])),[[y,i.value]])])}}};export{z as default};

View File

@ -0,0 +1 @@
import{s as w}from"./request-CrM1Jo5H.js";import{D as H,c as I,b as M,F as R,k as q,w as a,a as e,G as A,j as i,r as o,o as U,h as u,H as F,i as G,E as L}from"./index-DdxTGUP0.js";const Q={__name:"ServiceEntries",setup(P){const p=i(!1),f=i(!1),_=i([]),d=i(!1),v=i(null),b=i(""),g=i(null),x={Authorization:`Bearer ${localStorage.getItem("admin_token")}`},n=G({iconUrl:"",sortOrder:0,isEnabled:!0}),E={iconUrl:[{required:!0,message:"图标图片地址不能为空",trigger:"blur"}]};async function V(){p.value=!0;try{_.value=await w.get("/admin/service-entries")}finally{p.value=!1}}function k(s){v.value=s.id,b.value=s.name,Object.assign(n,{iconUrl:s.iconUrl,sortOrder:s.sortOrder,isEnabled:s.isEnabled}),d.value=!0}async function h(){if(await g.value.validate().catch(()=>!1)){f.value=!0;try{await w.put(`/admin/service-entries/${v.value}`,n),L.success("更新成功"),d.value=!1,V()}finally{f.value=!1}}}return H(V),(s,l)=>{const r=o("el-table-column"),O=o("el-image"),C=o("el-tag"),m=o("el-button"),B=o("el-table"),y=o("el-input"),c=o("el-form-item"),D=o("el-upload"),N=o("el-input-number"),S=o("el-switch"),$=o("el-form"),z=o("el-dialog"),j=A("loading");return U(),I("div",null,[l[9]||(l[9]=M("h3",{style:{margin:"0 0 16px"}},"服务入口管理",-1)),R((U(),q(B,{data:_.value,border:""},{default:a(()=>[e(r,{prop:"name",label:"服务名称",width:"140"}),e(r,{label:"图标",width:"100"},{default:a(({row:t})=>[e(O,{src:t.iconUrl,style:{width:"40px",height:"40px"},fit:"contain"},null,8,["src"])]),_:1}),e(r,{prop:"pagePath",label:"跳转路径","show-overflow-tooltip":""}),e(r,{prop:"sortOrder",label:"排序",width:"80"}),e(r,{label:"启用状态",width:"100"},{default:a(({row:t})=>[e(C,{type:t.isEnabled?"success":"info"},{default:a(()=>[u(F(t.isEnabled?"启用":"禁用"),1)]),_:2},1032,["type"])]),_:1}),e(r,{label:"操作",width:"100",fixed:"right"},{default:a(({row:t})=>[e(m,{size:"small",onClick:T=>k(t)},{default:a(()=>[...l[5]||(l[5]=[u("编辑",-1)])]),_:1},8,["onClick"])]),_:1})]),_:1},8,["data"])),[[j,p.value]]),e(z,{modelValue:d.value,"onUpdate:modelValue":l[4]||(l[4]=t=>d.value=t),title:"编辑服务入口",width:"500px"},{footer:a(()=>[e(m,{onClick:l[3]||(l[3]=t=>d.value=!1)},{default:a(()=>[...l[7]||(l[7]=[u("取消",-1)])]),_:1}),e(m,{type:"primary",loading:f.value,onClick:h},{default:a(()=>[...l[8]||(l[8]=[u("确定",-1)])]),_:1},8,["loading"])]),default:a(()=>[e($,{ref_key:"formRef",ref:g,model:n,rules:E,"label-width":"90px"},{default:a(()=>[e(c,{label:"服务名称"},{default:a(()=>[e(y,{"model-value":b.value,disabled:""},null,8,["model-value"])]),_:1}),e(c,{label:"图标图片",prop:"iconUrl"},{default:a(()=>[e(y,{modelValue:n.iconUrl,"onUpdate:modelValue":l[0]||(l[0]=t=>n.iconUrl=t),placeholder:"图标图片地址"},null,8,["modelValue"]),e(D,{action:"/api/upload/image",headers:x,"show-file-list":!1,"on-success":t=>n.iconUrl=t.url,accept:"image/*",style:{"margin-top":"8px"}},{default:a(()=>[e(m,{size:"small"},{default:a(()=>[...l[6]||(l[6]=[u("上传图片",-1)])]),_:1})]),_:1},8,["on-success"])]),_:1}),e(c,{label:"排序权重"},{default:a(()=>[e(N,{modelValue:n.sortOrder,"onUpdate:modelValue":l[1]||(l[1]=t=>n.sortOrder=t),min:0},null,8,["modelValue"])]),_:1}),e(c,{label:"启用状态"},{default:a(()=>[e(S,{modelValue:n.isEnabled,"onUpdate:modelValue":l[2]||(l[2]=t=>n.isEnabled=t)},null,8,["modelValue"])]),_:1})]),_:1},8,["model"])]),_:1},8,["modelValue"])])}}};export{Q as default};

View File

@ -0,0 +1 @@
import{D as L,c as O,b as y,a as l,w as a,H as w,e as T,F as J,k as K,I as P,r as n,G as Q,j as d,i as W,o as D,h as i,C as X,E as h}from"./index-DdxTGUP0.js";import{s as c}from"./request-CrM1Jo5H.js";const Y={style:{display:"flex","justify-content":"space-between","align-items":"center","margin-bottom":"16px"}},Z={style:{display:"flex","align-items":"center",gap:"12px"}},ee={style:{margin:"0"}},se={__name:"ShopDishes",setup(le){const p=P().params.id,_=d(!1),g=d(!1),V=d([]),r=d(!1),v=d(!1),k=d(null),x=d(null),B={Authorization:`Bearer ${localStorage.getItem("admin_token")}`},$=()=>({name:"",photo:"",price:0,isEnabled:!0}),s=W($()),z={name:[{required:!0,message:"菜品名称不能为空",trigger:"blur"}],photo:[{required:!0,message:"菜品照片不能为空",trigger:"blur"}]};async function b(){_.value=!0;try{V.value=await c.get(`/admin/shops/${p}/dishes`)}finally{_.value=!1}}function E(o){v.value=!!o,k.value=(o==null?void 0:o.id)||null,Object.assign(s,o?{name:o.name,photo:o.photo,price:o.price,isEnabled:o.isEnabled}:$()),r.value=!0}async function U(){if(await x.value.validate().catch(()=>!1)){g.value=!0;try{v.value?(await c.put(`/admin/shops/${p}/dishes/${k.value}`,s),h.success("更新成功")):(await c.post(`/admin/shops/${p}/dishes`,s),h.success("创建成功")),r.value=!1,b()}finally{g.value=!1}}}async function I(o){await X.confirm(`确定删除菜品「${o.name}」?`,"提示",{type:"warning"}),await c.delete(`/admin/shops/${p}/dishes/${o.id}`),h.success("删除成功"),b()}return L(b),(o,e)=>{const u=n("el-button"),S=n("el-image"),m=n("el-table-column"),j=n("el-tag"),M=n("el-table"),C=n("el-input"),f=n("el-form-item"),N=n("el-upload"),R=n("el-input-number"),q=n("el-switch"),F=n("el-form"),H=n("el-dialog"),A=Q("loading");return D(),O("div",null,[y("div",Y,[y("div",Z,[l(u,{onClick:e[0]||(e[0]=t=>o.$router.push("/shops"))},{default:a(()=>[...e[8]||(e[8]=[i("返回门店列表",-1)])]),_:1}),y("h3",ee,"菜品管理(门店 #"+w(T(p))+"",1)]),l(u,{type:"primary",onClick:e[1]||(e[1]=t=>E())},{default:a(()=>[...e[9]||(e[9]=[i("新增菜品",-1)])]),_:1})]),J((D(),K(M,{data:V.value,border:""},{default:a(()=>[l(m,{label:"照片",width:"100"},{default:a(({row:t})=>[l(S,{src:t.photo,style:{width:"60px",height:"60px"},fit:"cover"},null,8,["src"])]),_:1}),l(m,{prop:"name",label:"菜品名称"}),l(m,{prop:"price",label:"价格(元)",width:"120"}),l(m,{label:"状态",width:"80"},{default:a(({row:t})=>[l(j,{type:t.isEnabled?"success":"info",size:"small"},{default:a(()=>[i(w(t.isEnabled?"启用":"禁用"),1)]),_:2},1032,["type"])]),_:1}),l(m,{label:"操作",width:"160",fixed:"right"},{default:a(({row:t})=>[l(u,{size:"small",onClick:G=>E(t)},{default:a(()=>[...e[10]||(e[10]=[i("编辑",-1)])]),_:1},8,["onClick"]),l(u,{size:"small",type:"danger",onClick:G=>I(t)},{default:a(()=>[...e[11]||(e[11]=[i("删除",-1)])]),_:1},8,["onClick"])]),_:1})]),_:1},8,["data"])),[[A,_.value]]),l(H,{modelValue:r.value,"onUpdate:modelValue":e[7]||(e[7]=t=>r.value=t),title:v.value?"编辑菜品":"新增菜品",width:"500px"},{footer:a(()=>[l(u,{onClick:e[6]||(e[6]=t=>r.value=!1)},{default:a(()=>[...e[13]||(e[13]=[i("取消",-1)])]),_:1}),l(u,{type:"primary",loading:g.value,onClick:U},{default:a(()=>[...e[14]||(e[14]=[i("确定",-1)])]),_:1},8,["loading"])]),default:a(()=>[l(F,{ref_key:"formRef",ref:x,model:s,rules:z,"label-width":"90px"},{default:a(()=>[l(f,{label:"菜品名称",prop:"name"},{default:a(()=>[l(C,{modelValue:s.name,"onUpdate:modelValue":e[2]||(e[2]=t=>s.name=t)},null,8,["modelValue"])]),_:1}),l(f,{label:"菜品照片",prop:"photo"},{default:a(()=>[l(C,{modelValue:s.photo,"onUpdate:modelValue":e[3]||(e[3]=t=>s.photo=t),placeholder:"照片地址"},null,8,["modelValue"]),l(N,{action:"/api/upload/image",headers:B,"show-file-list":!1,"on-success":t=>s.photo=t.url,accept:"image/*",style:{"margin-top":"8px"}},{default:a(()=>[l(u,{size:"small"},{default:a(()=>[...e[12]||(e[12]=[i("上传照片",-1)])]),_:1})]),_:1},8,["on-success"])]),_:1}),l(f,{label:"价格",prop:"price"},{default:a(()=>[l(R,{modelValue:s.price,"onUpdate:modelValue":e[4]||(e[4]=t=>s.price=t),min:0,precision:2,step:1},null,8,["modelValue"])]),_:1}),l(f,{label:"启用状态"},{default:a(()=>[l(q,{modelValue:s.isEnabled,"onUpdate:modelValue":e[5]||(e[5]=t=>s.isEnabled=t)},null,8,["modelValue"])]),_:1})]),_:1},8,["model"])]),_:1},8,["modelValue","title"])])}}};export{se as default};

1
admin/dist/assets/Shops-BNMhRrba.js vendored Normal file

File diff suppressed because one or more lines are too long

66
admin/dist/assets/index-DdxTGUP0.js vendored Normal file

File diff suppressed because one or more lines are too long

1
admin/dist/assets/index-Lpcm-_el.css vendored Normal file

File diff suppressed because one or more lines are too long

6
admin/dist/assets/request-CrM1Jo5H.js vendored Normal file

File diff suppressed because one or more lines are too long

13
admin/dist/index.html vendored Normal file
View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>校园跑腿 - 管理后台</title>
<script type="module" crossorigin src="/assets/index-DdxTGUP0.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Lpcm-_el.css">
</head>
<body>
<div id="app"></div>
</body>
</html>

12
admin/index.html Normal file
View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>校园跑腿 - 管理后台</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

16
admin/node_modules/.bin/esbuild generated vendored Normal file
View File

@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../esbuild/bin/esbuild" "$@"
else
exec node "$basedir/../esbuild/bin/esbuild" "$@"
fi

17
admin/node_modules/.bin/esbuild.cmd generated vendored Normal file
View File

@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\esbuild\bin\esbuild" %*

28
admin/node_modules/.bin/esbuild.ps1 generated vendored Normal file
View File

@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../esbuild/bin/esbuild" $args
} else {
& "$basedir/node$exe" "$basedir/../esbuild/bin/esbuild" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../esbuild/bin/esbuild" $args
} else {
& "node$exe" "$basedir/../esbuild/bin/esbuild" $args
}
$ret=$LASTEXITCODE
}
exit $ret

16
admin/node_modules/.bin/nanoid generated vendored Normal file
View File

@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../nanoid/bin/nanoid.cjs" "$@"
else
exec node "$basedir/../nanoid/bin/nanoid.cjs" "$@"
fi

17
admin/node_modules/.bin/nanoid.cmd generated vendored Normal file
View File

@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\nanoid\bin\nanoid.cjs" %*

28
admin/node_modules/.bin/nanoid.ps1 generated vendored Normal file
View File

@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
} else {
& "$basedir/node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
} else {
& "node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
}
$ret=$LASTEXITCODE
}
exit $ret

16
admin/node_modules/.bin/parser generated vendored Normal file
View File

@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../@babel/parser/bin/babel-parser.js" "$@"
else
exec node "$basedir/../@babel/parser/bin/babel-parser.js" "$@"
fi

17
admin/node_modules/.bin/parser.cmd generated vendored Normal file
View File

@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\@babel\parser\bin\babel-parser.js" %*

28
admin/node_modules/.bin/parser.ps1 generated vendored Normal file
View File

@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../@babel/parser/bin/babel-parser.js" $args
} else {
& "$basedir/node$exe" "$basedir/../@babel/parser/bin/babel-parser.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../@babel/parser/bin/babel-parser.js" $args
} else {
& "node$exe" "$basedir/../@babel/parser/bin/babel-parser.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret

16
admin/node_modules/.bin/rollup generated vendored Normal file
View File

@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../rollup/dist/bin/rollup" "$@"
else
exec node "$basedir/../rollup/dist/bin/rollup" "$@"
fi

17
admin/node_modules/.bin/rollup.cmd generated vendored Normal file
View File

@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\rollup\dist\bin\rollup" %*

28
admin/node_modules/.bin/rollup.ps1 generated vendored Normal file
View File

@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../rollup/dist/bin/rollup" $args
} else {
& "$basedir/node$exe" "$basedir/../rollup/dist/bin/rollup" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../rollup/dist/bin/rollup" $args
} else {
& "node$exe" "$basedir/../rollup/dist/bin/rollup" $args
}
$ret=$LASTEXITCODE
}
exit $ret

16
admin/node_modules/.bin/vite generated vendored Normal file
View File

@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../vite/bin/vite.js" "$@"
else
exec node "$basedir/../vite/bin/vite.js" "$@"
fi

17
admin/node_modules/.bin/vite.cmd generated vendored Normal file
View File

@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\vite\bin\vite.js" %*

28
admin/node_modules/.bin/vite.ps1 generated vendored Normal file
View File

@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../vite/bin/vite.js" $args
} else {
& "$basedir/node$exe" "$basedir/../vite/bin/vite.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../vite/bin/vite.js" $args
} else {
& "node$exe" "$basedir/../vite/bin/vite.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret

16
admin/node_modules/.bin/vue-demi-fix generated vendored Normal file
View File

@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../vue-demi/bin/vue-demi-fix.js" "$@"
else
exec node "$basedir/../vue-demi/bin/vue-demi-fix.js" "$@"
fi

17
admin/node_modules/.bin/vue-demi-fix.cmd generated vendored Normal file
View File

@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\vue-demi\bin\vue-demi-fix.js" %*

28
admin/node_modules/.bin/vue-demi-fix.ps1 generated vendored Normal file
View File

@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../vue-demi/bin/vue-demi-fix.js" $args
} else {
& "$basedir/node$exe" "$basedir/../vue-demi/bin/vue-demi-fix.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../vue-demi/bin/vue-demi-fix.js" $args
} else {
& "node$exe" "$basedir/../vue-demi/bin/vue-demi-fix.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret

16
admin/node_modules/.bin/vue-demi-switch generated vendored Normal file
View File

@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../vue-demi/bin/vue-demi-switch.js" "$@"
else
exec node "$basedir/../vue-demi/bin/vue-demi-switch.js" "$@"
fi

17
admin/node_modules/.bin/vue-demi-switch.cmd generated vendored Normal file
View File

@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\vue-demi\bin\vue-demi-switch.js" %*

28
admin/node_modules/.bin/vue-demi-switch.ps1 generated vendored Normal file
View File

@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../vue-demi/bin/vue-demi-switch.js" $args
} else {
& "$basedir/node$exe" "$basedir/../vue-demi/bin/vue-demi-switch.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../vue-demi/bin/vue-demi-switch.js" $args
} else {
& "node$exe" "$basedir/../vue-demi/bin/vue-demi-switch.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret

1088
admin/node_modules/.package-lock.json generated vendored Normal file

File diff suppressed because it is too large Load Diff

22
admin/node_modules/@babel/helper-string-parser/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2014-present Sebastian McKenzie and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,19 @@
# @babel/helper-string-parser
> A utility package to parse strings
See our website [@babel/helper-string-parser](https://babeljs.io/docs/babel-helper-string-parser) for more information.
## Install
Using npm:
```sh
npm install --save @babel/helper-string-parser
```
or using yarn:
```sh
yarn add @babel/helper-string-parser
```

View File

@ -0,0 +1,295 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.readCodePoint = readCodePoint;
exports.readInt = readInt;
exports.readStringContents = readStringContents;
var _isDigit = function isDigit(code) {
return code >= 48 && code <= 57;
};
const forbiddenNumericSeparatorSiblings = {
decBinOct: new Set([46, 66, 69, 79, 95, 98, 101, 111]),
hex: new Set([46, 88, 95, 120])
};
const isAllowedNumericSeparatorSibling = {
bin: ch => ch === 48 || ch === 49,
oct: ch => ch >= 48 && ch <= 55,
dec: ch => ch >= 48 && ch <= 57,
hex: ch => ch >= 48 && ch <= 57 || ch >= 65 && ch <= 70 || ch >= 97 && ch <= 102
};
function readStringContents(type, input, pos, lineStart, curLine, errors) {
const initialPos = pos;
const initialLineStart = lineStart;
const initialCurLine = curLine;
let out = "";
let firstInvalidLoc = null;
let chunkStart = pos;
const {
length
} = input;
for (;;) {
if (pos >= length) {
errors.unterminated(initialPos, initialLineStart, initialCurLine);
out += input.slice(chunkStart, pos);
break;
}
const ch = input.charCodeAt(pos);
if (isStringEnd(type, ch, input, pos)) {
out += input.slice(chunkStart, pos);
break;
}
if (ch === 92) {
out += input.slice(chunkStart, pos);
const res = readEscapedChar(input, pos, lineStart, curLine, type === "template", errors);
if (res.ch === null && !firstInvalidLoc) {
firstInvalidLoc = {
pos,
lineStart,
curLine
};
} else {
out += res.ch;
}
({
pos,
lineStart,
curLine
} = res);
chunkStart = pos;
} else if (ch === 8232 || ch === 8233) {
++pos;
++curLine;
lineStart = pos;
} else if (ch === 10 || ch === 13) {
if (type === "template") {
out += input.slice(chunkStart, pos) + "\n";
++pos;
if (ch === 13 && input.charCodeAt(pos) === 10) {
++pos;
}
++curLine;
chunkStart = lineStart = pos;
} else {
errors.unterminated(initialPos, initialLineStart, initialCurLine);
}
} else {
++pos;
}
}
return {
pos,
str: out,
firstInvalidLoc,
lineStart,
curLine,
containsInvalid: !!firstInvalidLoc
};
}
function isStringEnd(type, ch, input, pos) {
if (type === "template") {
return ch === 96 || ch === 36 && input.charCodeAt(pos + 1) === 123;
}
return ch === (type === "double" ? 34 : 39);
}
function readEscapedChar(input, pos, lineStart, curLine, inTemplate, errors) {
const throwOnInvalid = !inTemplate;
pos++;
const res = ch => ({
pos,
ch,
lineStart,
curLine
});
const ch = input.charCodeAt(pos++);
switch (ch) {
case 110:
return res("\n");
case 114:
return res("\r");
case 120:
{
let code;
({
code,
pos
} = readHexChar(input, pos, lineStart, curLine, 2, false, throwOnInvalid, errors));
return res(code === null ? null : String.fromCharCode(code));
}
case 117:
{
let code;
({
code,
pos
} = readCodePoint(input, pos, lineStart, curLine, throwOnInvalid, errors));
return res(code === null ? null : String.fromCodePoint(code));
}
case 116:
return res("\t");
case 98:
return res("\b");
case 118:
return res("\u000b");
case 102:
return res("\f");
case 13:
if (input.charCodeAt(pos) === 10) {
++pos;
}
case 10:
lineStart = pos;
++curLine;
case 8232:
case 8233:
return res("");
case 56:
case 57:
if (inTemplate) {
return res(null);
} else {
errors.strictNumericEscape(pos - 1, lineStart, curLine);
}
default:
if (ch >= 48 && ch <= 55) {
const startPos = pos - 1;
const match = /^[0-7]+/.exec(input.slice(startPos, pos + 2));
let octalStr = match[0];
let octal = parseInt(octalStr, 8);
if (octal > 255) {
octalStr = octalStr.slice(0, -1);
octal = parseInt(octalStr, 8);
}
pos += octalStr.length - 1;
const next = input.charCodeAt(pos);
if (octalStr !== "0" || next === 56 || next === 57) {
if (inTemplate) {
return res(null);
} else {
errors.strictNumericEscape(startPos, lineStart, curLine);
}
}
return res(String.fromCharCode(octal));
}
return res(String.fromCharCode(ch));
}
}
function readHexChar(input, pos, lineStart, curLine, len, forceLen, throwOnInvalid, errors) {
const initialPos = pos;
let n;
({
n,
pos
} = readInt(input, pos, lineStart, curLine, 16, len, forceLen, false, errors, !throwOnInvalid));
if (n === null) {
if (throwOnInvalid) {
errors.invalidEscapeSequence(initialPos, lineStart, curLine);
} else {
pos = initialPos - 1;
}
}
return {
code: n,
pos
};
}
function readInt(input, pos, lineStart, curLine, radix, len, forceLen, allowNumSeparator, errors, bailOnError) {
const start = pos;
const forbiddenSiblings = radix === 16 ? forbiddenNumericSeparatorSiblings.hex : forbiddenNumericSeparatorSiblings.decBinOct;
const isAllowedSibling = radix === 16 ? isAllowedNumericSeparatorSibling.hex : radix === 10 ? isAllowedNumericSeparatorSibling.dec : radix === 8 ? isAllowedNumericSeparatorSibling.oct : isAllowedNumericSeparatorSibling.bin;
let invalid = false;
let total = 0;
for (let i = 0, e = len == null ? Infinity : len; i < e; ++i) {
const code = input.charCodeAt(pos);
let val;
if (code === 95 && allowNumSeparator !== "bail") {
const prev = input.charCodeAt(pos - 1);
const next = input.charCodeAt(pos + 1);
if (!allowNumSeparator) {
if (bailOnError) return {
n: null,
pos
};
errors.numericSeparatorInEscapeSequence(pos, lineStart, curLine);
} else if (Number.isNaN(next) || !isAllowedSibling(next) || forbiddenSiblings.has(prev) || forbiddenSiblings.has(next)) {
if (bailOnError) return {
n: null,
pos
};
errors.unexpectedNumericSeparator(pos, lineStart, curLine);
}
++pos;
continue;
}
if (code >= 97) {
val = code - 97 + 10;
} else if (code >= 65) {
val = code - 65 + 10;
} else if (_isDigit(code)) {
val = code - 48;
} else {
val = Infinity;
}
if (val >= radix) {
if (val <= 9 && bailOnError) {
return {
n: null,
pos
};
} else if (val <= 9 && errors.invalidDigit(pos, lineStart, curLine, radix)) {
val = 0;
} else if (forceLen) {
val = 0;
invalid = true;
} else {
break;
}
}
++pos;
total = total * radix + val;
}
if (pos === start || len != null && pos - start !== len || invalid) {
return {
n: null,
pos
};
}
return {
n: total,
pos
};
}
function readCodePoint(input, pos, lineStart, curLine, throwOnInvalid, errors) {
const ch = input.charCodeAt(pos);
let code;
if (ch === 123) {
++pos;
({
code,
pos
} = readHexChar(input, pos, lineStart, curLine, input.indexOf("}", pos) - pos, true, throwOnInvalid, errors));
++pos;
if (code !== null && code > 0x10ffff) {
if (throwOnInvalid) {
errors.invalidCodePoint(pos, lineStart, curLine);
} else {
return {
code: null,
pos
};
}
}
} else {
({
code,
pos
} = readHexChar(input, pos, lineStart, curLine, 4, false, throwOnInvalid, errors));
}
return {
code,
pos
};
}
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,31 @@
{
"name": "@babel/helper-string-parser",
"version": "7.27.1",
"description": "A utility package to parse strings",
"repository": {
"type": "git",
"url": "https://github.com/babel/babel.git",
"directory": "packages/babel-helper-string-parser"
},
"homepage": "https://babel.dev/docs/en/next/babel-helper-string-parser",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"main": "./lib/index.js",
"devDependencies": {
"charcodes": "^0.2.0"
},
"engines": {
"node": ">=6.9.0"
},
"author": "The Babel Team (https://babel.dev/team)",
"exports": {
".": {
"types": "./lib/index.d.ts",
"default": "./lib/index.js"
},
"./package.json": "./package.json"
},
"type": "commonjs"
}

View File

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2014-present Sebastian McKenzie and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,19 @@
# @babel/helper-validator-identifier
> Validate identifier/keywords name
See our website [@babel/helper-validator-identifier](https://babeljs.io/docs/babel-helper-validator-identifier) for more information.
## Install
Using npm:
```sh
npm install --save @babel/helper-validator-identifier
```
or using yarn:
```sh
yarn add @babel/helper-validator-identifier
```

View File

@ -0,0 +1,70 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isIdentifierChar = isIdentifierChar;
exports.isIdentifierName = isIdentifierName;
exports.isIdentifierStart = isIdentifierStart;
let nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0560-\u0588\u05d0-\u05ea\u05ef-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u0860-\u086a\u0870-\u0887\u0889-\u088f\u08a0-\u08c9\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u09fc\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c5c\u0c5d\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cdc-\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d04-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d54-\u0d56\u0d5f-\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e86-\u0e8a\u0e8c-\u0ea3\u0ea5\u0ea7-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u1711\u171f-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1878\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4c\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c8a\u1c90-\u1cba\u1cbd-\u1cbf\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u1cfa\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312f\u3131-\u318e\u31a0-\u31bf\u31f0-\u31ff\u3400-\u4dbf\u4e00-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7dc\ua7f1-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\ua8fe\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab69\uab70-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc";
let nonASCIIidentifierChars = "\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u07fd\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u0897-\u089f\u08ca-\u08e1\u08e3-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u09fe\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0afa-\u0aff\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b55-\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c04\u0c3c\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0cf3\u0d00-\u0d03\u0d3b\u0d3c\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d81-\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0ebc\u0ec8-\u0ece\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1715\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u180f-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1abf-\u1add\u1ae0-\u1aeb\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf4\u1cf7-\u1cf9\u1dc0-\u1dff\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\u30fb\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua82c\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua8ff-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f\uff65";
const nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]");
const nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]");
nonASCIIidentifierStartChars = nonASCIIidentifierChars = null;
const astralIdentifierStartCodes = [0, 11, 2, 25, 2, 18, 2, 1, 2, 14, 3, 13, 35, 122, 70, 52, 268, 28, 4, 48, 48, 31, 14, 29, 6, 37, 11, 29, 3, 35, 5, 7, 2, 4, 43, 157, 19, 35, 5, 35, 5, 39, 9, 51, 13, 10, 2, 14, 2, 6, 2, 1, 2, 10, 2, 14, 2, 6, 2, 1, 4, 51, 13, 310, 10, 21, 11, 7, 25, 5, 2, 41, 2, 8, 70, 5, 3, 0, 2, 43, 2, 1, 4, 0, 3, 22, 11, 22, 10, 30, 66, 18, 2, 1, 11, 21, 11, 25, 7, 25, 39, 55, 7, 1, 65, 0, 16, 3, 2, 2, 2, 28, 43, 28, 4, 28, 36, 7, 2, 27, 28, 53, 11, 21, 11, 18, 14, 17, 111, 72, 56, 50, 14, 50, 14, 35, 39, 27, 10, 22, 251, 41, 7, 1, 17, 5, 57, 28, 11, 0, 9, 21, 43, 17, 47, 20, 28, 22, 13, 52, 58, 1, 3, 0, 14, 44, 33, 24, 27, 35, 30, 0, 3, 0, 9, 34, 4, 0, 13, 47, 15, 3, 22, 0, 2, 0, 36, 17, 2, 24, 20, 1, 64, 6, 2, 0, 2, 3, 2, 14, 2, 9, 8, 46, 39, 7, 3, 1, 3, 21, 2, 6, 2, 1, 2, 4, 4, 0, 19, 0, 13, 4, 31, 9, 2, 0, 3, 0, 2, 37, 2, 0, 26, 0, 2, 0, 45, 52, 19, 3, 21, 2, 31, 47, 21, 1, 2, 0, 185, 46, 42, 3, 37, 47, 21, 0, 60, 42, 14, 0, 72, 26, 38, 6, 186, 43, 117, 63, 32, 7, 3, 0, 3, 7, 2, 1, 2, 23, 16, 0, 2, 0, 95, 7, 3, 38, 17, 0, 2, 0, 29, 0, 11, 39, 8, 0, 22, 0, 12, 45, 20, 0, 19, 72, 200, 32, 32, 8, 2, 36, 18, 0, 50, 29, 113, 6, 2, 1, 2, 37, 22, 0, 26, 5, 2, 1, 2, 31, 15, 0, 24, 43, 261, 18, 16, 0, 2, 12, 2, 33, 125, 0, 80, 921, 103, 110, 18, 195, 2637, 96, 16, 1071, 18, 5, 26, 3994, 6, 582, 6842, 29, 1763, 568, 8, 30, 18, 78, 18, 29, 19, 47, 17, 3, 32, 20, 6, 18, 433, 44, 212, 63, 33, 24, 3, 24, 45, 74, 6, 0, 67, 12, 65, 1, 2, 0, 15, 4, 10, 7381, 42, 31, 98, 114, 8702, 3, 2, 6, 2, 1, 2, 290, 16, 0, 30, 2, 3, 0, 15, 3, 9, 395, 2309, 106, 6, 12, 4, 8, 8, 9, 5991, 84, 2, 70, 2, 1, 3, 0, 3, 1, 3, 3, 2, 11, 2, 0, 2, 6, 2, 64, 2, 3, 3, 7, 2, 6, 2, 27, 2, 3, 2, 4, 2, 0, 4, 6, 2, 339, 3, 24, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 7, 1845, 30, 7, 5, 262, 61, 147, 44, 11, 6, 17, 0, 322, 29, 19, 43, 485, 27, 229, 29, 3, 0, 208, 30, 2, 2, 2, 1, 2, 6, 3, 4, 10, 1, 225, 6, 2, 3, 2, 1, 2, 14, 2, 196, 60, 67, 8, 0, 1205, 3, 2, 26, 2, 1, 2, 0, 3, 0, 2, 9, 2, 3, 2, 0, 2, 0, 7, 0, 5, 0, 2, 0, 2, 0, 2, 2, 2, 1, 2, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 3, 3, 2, 6, 2, 3, 2, 3, 2, 0, 2, 9, 2, 16, 6, 2, 2, 4, 2, 16, 4421, 42719, 33, 4381, 3, 5773, 3, 7472, 16, 621, 2467, 541, 1507, 4938, 6, 8489];
const astralIdentifierCodes = [509, 0, 227, 0, 150, 4, 294, 9, 1368, 2, 2, 1, 6, 3, 41, 2, 5, 0, 166, 1, 574, 3, 9, 9, 7, 9, 32, 4, 318, 1, 78, 5, 71, 10, 50, 3, 123, 2, 54, 14, 32, 10, 3, 1, 11, 3, 46, 10, 8, 0, 46, 9, 7, 2, 37, 13, 2, 9, 6, 1, 45, 0, 13, 2, 49, 13, 9, 3, 2, 11, 83, 11, 7, 0, 3, 0, 158, 11, 6, 9, 7, 3, 56, 1, 2, 6, 3, 1, 3, 2, 10, 0, 11, 1, 3, 6, 4, 4, 68, 8, 2, 0, 3, 0, 2, 3, 2, 4, 2, 0, 15, 1, 83, 17, 10, 9, 5, 0, 82, 19, 13, 9, 214, 6, 3, 8, 28, 1, 83, 16, 16, 9, 82, 12, 9, 9, 7, 19, 58, 14, 5, 9, 243, 14, 166, 9, 71, 5, 2, 1, 3, 3, 2, 0, 2, 1, 13, 9, 120, 6, 3, 6, 4, 0, 29, 9, 41, 6, 2, 3, 9, 0, 10, 10, 47, 15, 199, 7, 137, 9, 54, 7, 2, 7, 17, 9, 57, 21, 2, 13, 123, 5, 4, 0, 2, 1, 2, 6, 2, 0, 9, 9, 49, 4, 2, 1, 2, 4, 9, 9, 55, 9, 266, 3, 10, 1, 2, 0, 49, 6, 4, 4, 14, 10, 5350, 0, 7, 14, 11465, 27, 2343, 9, 87, 9, 39, 4, 60, 6, 26, 9, 535, 9, 470, 0, 2, 54, 8, 3, 82, 0, 12, 1, 19628, 1, 4178, 9, 519, 45, 3, 22, 543, 4, 4, 5, 9, 7, 3, 6, 31, 3, 149, 2, 1418, 49, 513, 54, 5, 49, 9, 0, 15, 0, 23, 4, 2, 14, 1361, 6, 2, 16, 3, 6, 2, 1, 2, 4, 101, 0, 161, 6, 10, 9, 357, 0, 62, 13, 499, 13, 245, 1, 2, 9, 233, 0, 3, 0, 8, 1, 6, 0, 475, 6, 110, 6, 6, 9, 4759, 9, 787719, 239];
function isInAstralSet(code, set) {
let pos = 0x10000;
for (let i = 0, length = set.length; i < length; i += 2) {
pos += set[i];
if (pos > code) return false;
pos += set[i + 1];
if (pos >= code) return true;
}
return false;
}
function isIdentifierStart(code) {
if (code < 65) return code === 36;
if (code <= 90) return true;
if (code < 97) return code === 95;
if (code <= 122) return true;
if (code <= 0xffff) {
return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code));
}
return isInAstralSet(code, astralIdentifierStartCodes);
}
function isIdentifierChar(code) {
if (code < 48) return code === 36;
if (code < 58) return true;
if (code < 65) return false;
if (code <= 90) return true;
if (code < 97) return code === 95;
if (code <= 122) return true;
if (code <= 0xffff) {
return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code));
}
return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes);
}
function isIdentifierName(name) {
let isFirst = true;
for (let i = 0; i < name.length; i++) {
let cp = name.charCodeAt(i);
if ((cp & 0xfc00) === 0xd800 && i + 1 < name.length) {
const trail = name.charCodeAt(++i);
if ((trail & 0xfc00) === 0xdc00) {
cp = 0x10000 + ((cp & 0x3ff) << 10) + (trail & 0x3ff);
}
}
if (isFirst) {
isFirst = false;
if (!isIdentifierStart(cp)) {
return false;
}
} else if (!isIdentifierChar(cp)) {
return false;
}
}
return !isFirst;
}
//# sourceMappingURL=identifier.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,57 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "isIdentifierChar", {
enumerable: true,
get: function () {
return _identifier.isIdentifierChar;
}
});
Object.defineProperty(exports, "isIdentifierName", {
enumerable: true,
get: function () {
return _identifier.isIdentifierName;
}
});
Object.defineProperty(exports, "isIdentifierStart", {
enumerable: true,
get: function () {
return _identifier.isIdentifierStart;
}
});
Object.defineProperty(exports, "isKeyword", {
enumerable: true,
get: function () {
return _keyword.isKeyword;
}
});
Object.defineProperty(exports, "isReservedWord", {
enumerable: true,
get: function () {
return _keyword.isReservedWord;
}
});
Object.defineProperty(exports, "isStrictBindOnlyReservedWord", {
enumerable: true,
get: function () {
return _keyword.isStrictBindOnlyReservedWord;
}
});
Object.defineProperty(exports, "isStrictBindReservedWord", {
enumerable: true,
get: function () {
return _keyword.isStrictBindReservedWord;
}
});
Object.defineProperty(exports, "isStrictReservedWord", {
enumerable: true,
get: function () {
return _keyword.isStrictReservedWord;
}
});
var _identifier = require("./identifier.js");
var _keyword = require("./keyword.js");
//# sourceMappingURL=index.js.map

View File

@ -0,0 +1 @@
{"version":3,"names":["_identifier","require","_keyword"],"sources":["../src/index.ts"],"sourcesContent":["export {\n isIdentifierName,\n isIdentifierChar,\n isIdentifierStart,\n} from \"./identifier.ts\";\nexport {\n isReservedWord,\n isStrictBindOnlyReservedWord,\n isStrictBindReservedWord,\n isStrictReservedWord,\n isKeyword,\n} from \"./keyword.ts\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,WAAA,GAAAC,OAAA;AAKA,IAAAC,QAAA,GAAAD,OAAA","ignoreList":[]}

View File

@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isKeyword = isKeyword;
exports.isReservedWord = isReservedWord;
exports.isStrictBindOnlyReservedWord = isStrictBindOnlyReservedWord;
exports.isStrictBindReservedWord = isStrictBindReservedWord;
exports.isStrictReservedWord = isStrictReservedWord;
const reservedWords = {
keyword: ["break", "case", "catch", "continue", "debugger", "default", "do", "else", "finally", "for", "function", "if", "return", "switch", "throw", "try", "var", "const", "while", "with", "new", "this", "super", "class", "extends", "export", "import", "null", "true", "false", "in", "instanceof", "typeof", "void", "delete"],
strict: ["implements", "interface", "let", "package", "private", "protected", "public", "static", "yield"],
strictBind: ["eval", "arguments"]
};
const keywords = new Set(reservedWords.keyword);
const reservedWordsStrictSet = new Set(reservedWords.strict);
const reservedWordsStrictBindSet = new Set(reservedWords.strictBind);
function isReservedWord(word, inModule) {
return inModule && word === "await" || word === "enum";
}
function isStrictReservedWord(word, inModule) {
return isReservedWord(word, inModule) || reservedWordsStrictSet.has(word);
}
function isStrictBindOnlyReservedWord(word) {
return reservedWordsStrictBindSet.has(word);
}
function isStrictBindReservedWord(word, inModule) {
return isStrictReservedWord(word, inModule) || isStrictBindOnlyReservedWord(word);
}
function isKeyword(word) {
return keywords.has(word);
}
//# sourceMappingURL=keyword.js.map

View File

@ -0,0 +1 @@
{"version":3,"names":["reservedWords","keyword","strict","strictBind","keywords","Set","reservedWordsStrictSet","reservedWordsStrictBindSet","isReservedWord","word","inModule","isStrictReservedWord","has","isStrictBindOnlyReservedWord","isStrictBindReservedWord","isKeyword"],"sources":["../src/keyword.ts"],"sourcesContent":["const reservedWords = {\n keyword: [\n \"break\",\n \"case\",\n \"catch\",\n \"continue\",\n \"debugger\",\n \"default\",\n \"do\",\n \"else\",\n \"finally\",\n \"for\",\n \"function\",\n \"if\",\n \"return\",\n \"switch\",\n \"throw\",\n \"try\",\n \"var\",\n \"const\",\n \"while\",\n \"with\",\n \"new\",\n \"this\",\n \"super\",\n \"class\",\n \"extends\",\n \"export\",\n \"import\",\n \"null\",\n \"true\",\n \"false\",\n \"in\",\n \"instanceof\",\n \"typeof\",\n \"void\",\n \"delete\",\n ],\n strict: [\n \"implements\",\n \"interface\",\n \"let\",\n \"package\",\n \"private\",\n \"protected\",\n \"public\",\n \"static\",\n \"yield\",\n ],\n strictBind: [\"eval\", \"arguments\"],\n};\nconst keywords = new Set(reservedWords.keyword);\nconst reservedWordsStrictSet = new Set(reservedWords.strict);\nconst reservedWordsStrictBindSet = new Set(reservedWords.strictBind);\n\n/**\n * Checks if word is a reserved word in non-strict mode\n */\nexport function isReservedWord(word: string, inModule: boolean): boolean {\n return (inModule && word === \"await\") || word === \"enum\";\n}\n\n/**\n * Checks if word is a reserved word in non-binding strict mode\n *\n * Includes non-strict reserved words\n */\nexport function isStrictReservedWord(word: string, inModule: boolean): boolean {\n return isReservedWord(word, inModule) || reservedWordsStrictSet.has(word);\n}\n\n/**\n * Checks if word is a reserved word in binding strict mode, but it is allowed as\n * a normal identifier.\n */\nexport function isStrictBindOnlyReservedWord(word: string): boolean {\n return reservedWordsStrictBindSet.has(word);\n}\n\n/**\n * Checks if word is a reserved word in binding strict mode\n *\n * Includes non-strict reserved words and non-binding strict reserved words\n */\nexport function isStrictBindReservedWord(\n word: string,\n inModule: boolean,\n): boolean {\n return (\n isStrictReservedWord(word, inModule) || isStrictBindOnlyReservedWord(word)\n );\n}\n\nexport function isKeyword(word: string): boolean {\n return keywords.has(word);\n}\n"],"mappings":";;;;;;;;;;AAAA,MAAMA,aAAa,GAAG;EACpBC,OAAO,EAAE,CACP,OAAO,EACP,MAAM,EACN,OAAO,EACP,UAAU,EACV,UAAU,EACV,SAAS,EACT,IAAI,EACJ,MAAM,EACN,SAAS,EACT,KAAK,EACL,UAAU,EACV,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,KAAK,EACL,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,EACN,KAAK,EACL,MAAM,EACN,OAAO,EACP,OAAO,EACP,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,MAAM,EACN,OAAO,EACP,IAAI,EACJ,YAAY,EACZ,QAAQ,EACR,MAAM,EACN,QAAQ,CACT;EACDC,MAAM,EAAE,CACN,YAAY,EACZ,WAAW,EACX,KAAK,EACL,SAAS,EACT,SAAS,EACT,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,OAAO,CACR;EACDC,UAAU,EAAE,CAAC,MAAM,EAAE,WAAW;AAClC,CAAC;AACD,MAAMC,QAAQ,GAAG,IAAIC,GAAG,CAACL,aAAa,CAACC,OAAO,CAAC;AAC/C,MAAMK,sBAAsB,GAAG,IAAID,GAAG,CAACL,aAAa,CAACE,MAAM,CAAC;AAC5D,MAAMK,0BAA0B,GAAG,IAAIF,GAAG,CAACL,aAAa,CAACG,UAAU,CAAC;AAK7D,SAASK,cAAcA,CAACC,IAAY,EAAEC,QAAiB,EAAW;EACvE,OAAQA,QAAQ,IAAID,IAAI,KAAK,OAAO,IAAKA,IAAI,KAAK,MAAM;AAC1D;AAOO,SAASE,oBAAoBA,CAACF,IAAY,EAAEC,QAAiB,EAAW;EAC7E,OAAOF,cAAc,CAACC,IAAI,EAAEC,QAAQ,CAAC,IAAIJ,sBAAsB,CAACM,GAAG,CAACH,IAAI,CAAC;AAC3E;AAMO,SAASI,4BAA4BA,CAACJ,IAAY,EAAW;EAClE,OAAOF,0BAA0B,CAACK,GAAG,CAACH,IAAI,CAAC;AAC7C;AAOO,SAASK,wBAAwBA,CACtCL,IAAY,EACZC,QAAiB,EACR;EACT,OACEC,oBAAoB,CAACF,IAAI,EAAEC,QAAQ,CAAC,IAAIG,4BAA4B,CAACJ,IAAI,CAAC;AAE9E;AAEO,SAASM,SAASA,CAACN,IAAY,EAAW;EAC/C,OAAOL,QAAQ,CAACQ,GAAG,CAACH,IAAI,CAAC;AAC3B","ignoreList":[]}

View File

@ -0,0 +1,31 @@
{
"name": "@babel/helper-validator-identifier",
"version": "7.28.5",
"description": "Validate identifier/keywords name",
"repository": {
"type": "git",
"url": "https://github.com/babel/babel.git",
"directory": "packages/babel-helper-validator-identifier"
},
"license": "MIT",
"publishConfig": {
"access": "public"
},
"main": "./lib/index.js",
"exports": {
".": {
"types": "./lib/index.d.ts",
"default": "./lib/index.js"
},
"./package.json": "./package.json"
},
"devDependencies": {
"@unicode/unicode-17.0.0": "^1.6.10",
"charcodes": "^0.2.0"
},
"engines": {
"node": ">=6.9.0"
},
"author": "The Babel Team (https://babel.dev/team)",
"type": "commonjs"
}

1073
admin/node_modules/@babel/parser/CHANGELOG.md generated vendored Normal file

File diff suppressed because it is too large Load Diff

19
admin/node_modules/@babel/parser/LICENSE generated vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright (C) 2012-2014 by various contributors (see AUTHORS)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

19
admin/node_modules/@babel/parser/README.md generated vendored Normal file
View File

@ -0,0 +1,19 @@
# @babel/parser
> A JavaScript parser
See our website [@babel/parser](https://babeljs.io/docs/babel-parser) for more information or the [issues](https://github.com/babel/babel/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22pkg%3A%20parser%22+is%3Aopen) associated with this package.
## Install
Using npm:
```sh
npm install --save-dev @babel/parser
```
or using yarn:
```sh
yarn add @babel/parser --dev
```

15
admin/node_modules/@babel/parser/bin/babel-parser.js generated vendored Normal file
View File

@ -0,0 +1,15 @@
#!/usr/bin/env node
/* eslint-disable no-var, unicorn/prefer-node-protocol */
var parser = require("..");
var fs = require("fs");
var filename = process.argv[2];
if (!filename) {
console.error("no filename specified");
} else {
var file = fs.readFileSync(filename, "utf8");
var ast = parser.parse(file);
console.log(JSON.stringify(ast, null, " "));
}

14582
admin/node_modules/@babel/parser/lib/index.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

1
admin/node_modules/@babel/parser/lib/index.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

50
admin/node_modules/@babel/parser/package.json generated vendored Normal file
View File

@ -0,0 +1,50 @@
{
"name": "@babel/parser",
"version": "7.29.0",
"description": "A JavaScript parser",
"author": "The Babel Team (https://babel.dev/team)",
"homepage": "https://babel.dev/docs/en/next/babel-parser",
"bugs": "https://github.com/babel/babel/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22pkg%3A+parser+%28babylon%29%22+is%3Aopen",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"keywords": [
"babel",
"javascript",
"parser",
"tc39",
"ecmascript",
"@babel/parser"
],
"repository": {
"type": "git",
"url": "https://github.com/babel/babel.git",
"directory": "packages/babel-parser"
},
"main": "./lib/index.js",
"types": "./typings/babel-parser.d.ts",
"files": [
"bin",
"lib",
"typings/babel-parser.d.ts",
"index.cjs"
],
"engines": {
"node": ">=6.0.0"
},
"# dependencies": "This package doesn't actually have runtime dependencies. @babel/types is only needed for type definitions.",
"dependencies": {
"@babel/types": "^7.29.0"
},
"devDependencies": {
"@babel/code-frame": "^7.29.0",
"@babel/helper-check-duplicate-nodes": "^7.28.6",
"@babel/helper-fixtures": "^7.28.6",
"@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.28.5",
"charcodes": "^0.2.0"
},
"bin": "./bin/babel-parser.js",
"type": "commonjs"
}

View File

@ -0,0 +1,262 @@
// This file is auto-generated! Do not modify it directly.
// Run `yarn gulp bundle-dts` to re-generate it.
/* eslint-disable @typescript-eslint/consistent-type-imports, @typescript-eslint/no-redundant-type-constituents */
import { File, Expression } from '@babel/types';
declare class Position {
line: number;
column: number;
index: number;
constructor(line: number, col: number, index: number);
}
type SyntaxPlugin = "flow" | "typescript" | "jsx" | "pipelineOperator" | "placeholders";
type ParseErrorCode = "BABEL_PARSER_SYNTAX_ERROR" | "BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED";
interface ParseErrorSpecification<ErrorDetails> {
code: ParseErrorCode;
reasonCode: string;
syntaxPlugin?: SyntaxPlugin;
missingPlugin?: string | string[];
loc: Position;
details: ErrorDetails;
pos: number;
}
type ParseError$1<ErrorDetails> = SyntaxError & ParseErrorSpecification<ErrorDetails>;
type BABEL_8_BREAKING = false;
type IF_BABEL_7<V> = false extends BABEL_8_BREAKING ? V : never;
type Plugin$1 =
| "asyncDoExpressions"
| IF_BABEL_7<"asyncGenerators">
| IF_BABEL_7<"bigInt">
| IF_BABEL_7<"classPrivateMethods">
| IF_BABEL_7<"classPrivateProperties">
| IF_BABEL_7<"classProperties">
| IF_BABEL_7<"classStaticBlock">
| IF_BABEL_7<"decimal">
| "decorators-legacy"
| "deferredImportEvaluation"
| "decoratorAutoAccessors"
| "destructuringPrivate"
| IF_BABEL_7<"deprecatedImportAssert">
| "doExpressions"
| IF_BABEL_7<"dynamicImport">
| IF_BABEL_7<"explicitResourceManagement">
| "exportDefaultFrom"
| IF_BABEL_7<"exportNamespaceFrom">
| "flow"
| "flowComments"
| "functionBind"
| "functionSent"
| "importMeta"
| "jsx"
| IF_BABEL_7<"jsonStrings">
| IF_BABEL_7<"logicalAssignment">
| IF_BABEL_7<"importAssertions">
| IF_BABEL_7<"importReflection">
| "moduleBlocks"
| IF_BABEL_7<"moduleStringNames">
| IF_BABEL_7<"nullishCoalescingOperator">
| IF_BABEL_7<"numericSeparator">
| IF_BABEL_7<"objectRestSpread">
| IF_BABEL_7<"optionalCatchBinding">
| IF_BABEL_7<"optionalChaining">
| "partialApplication"
| "placeholders"
| IF_BABEL_7<"privateIn">
| IF_BABEL_7<"regexpUnicodeSets">
| "sourcePhaseImports"
| "throwExpressions"
| IF_BABEL_7<"topLevelAwait">
| "v8intrinsic"
| ParserPluginWithOptions[0];
type ParserPluginWithOptions =
| ["decorators", DecoratorsPluginOptions]
| ["discardBinding", { syntaxType: "void" }]
| ["estree", { classFeatures?: boolean }]
| IF_BABEL_7<["importAttributes", { deprecatedAssertSyntax: boolean }]>
| IF_BABEL_7<["moduleAttributes", { version: "may-2020" }]>
| ["optionalChainingAssign", { version: "2023-07" }]
| ["pipelineOperator", PipelineOperatorPluginOptions]
| ["recordAndTuple", RecordAndTuplePluginOptions]
| ["flow", FlowPluginOptions]
| ["typescript", TypeScriptPluginOptions];
type PluginConfig = Plugin$1 | ParserPluginWithOptions;
interface DecoratorsPluginOptions {
decoratorsBeforeExport?: boolean;
allowCallParenthesized?: boolean;
}
interface PipelineOperatorPluginOptions {
proposal: BABEL_8_BREAKING extends false
? "minimal" | "fsharp" | "hack" | "smart"
: "fsharp" | "hack";
topicToken?: "%" | "#" | "@@" | "^^" | "^";
}
interface RecordAndTuplePluginOptions {
syntaxType: "bar" | "hash";
}
type FlowPluginOptions = BABEL_8_BREAKING extends true
? {
all?: boolean;
enums?: boolean;
}
: {
all?: boolean;
};
interface TypeScriptPluginOptions {
dts?: boolean;
disallowAmbiguousJSXLike?: boolean;
}
type Plugin = PluginConfig;
type SourceType = "script" | "commonjs" | "module" | "unambiguous";
interface Options {
/**
* By default, import and export declarations can only appear at a program's top level.
* Setting this option to true allows them anywhere where a statement is allowed.
*/
allowImportExportEverywhere?: boolean;
/**
* By default, await use is not allowed outside of an async function.
* Set this to true to accept such code.
*/
allowAwaitOutsideFunction?: boolean;
/**
* By default, a return statement at the top level raises an error.
* Set this to true to accept such code.
*/
allowReturnOutsideFunction?: boolean;
/**
* By default, new.target use is not allowed outside of a function or class.
* Set this to true to accept such code.
*/
allowNewTargetOutsideFunction?: boolean;
/**
* By default, super calls are not allowed outside of a method.
* Set this to true to accept such code.
*/
allowSuperOutsideMethod?: boolean;
/**
* By default, exported identifiers must refer to a declared variable.
* Set this to true to allow export statements to reference undeclared variables.
*/
allowUndeclaredExports?: boolean;
/**
* By default, yield use is not allowed outside of a generator function.
* Set this to true to accept such code.
*/
allowYieldOutsideFunction?: boolean;
/**
* By default, Babel parser JavaScript code according to Annex B syntax.
* Set this to `false` to disable such behavior.
*/
annexB?: boolean;
/**
* By default, Babel attaches comments to adjacent AST nodes.
* When this option is set to false, comments are not attached.
* It can provide up to 30% performance improvement when the input code has many comments.
* @babel/eslint-parser will set it for you.
* It is not recommended to use attachComment: false with Babel transform,
* as doing so removes all the comments in output code, and renders annotations such as
* /* istanbul ignore next *\/ nonfunctional.
*/
attachComment?: boolean;
/**
* By default, Babel always throws an error when it finds some invalid code.
* When this option is set to true, it will store the parsing error and
* try to continue parsing the invalid input file.
*/
errorRecovery?: boolean;
/**
* Indicate the mode the code should be parsed in.
* Can be one of "script", "commonjs", "module", or "unambiguous". Defaults to "script".
* "unambiguous" will make @babel/parser attempt to guess, based on the presence
* of ES6 import or export statements.
* Files with ES6 imports and exports are considered "module" and are otherwise "script".
*
* Use "commonjs" to parse code that is intended to be run in a CommonJS environment such as Node.js.
*/
sourceType?: SourceType;
/**
* Correlate output AST nodes with their source filename.
* Useful when generating code and source maps from the ASTs of multiple input files.
*/
sourceFilename?: string;
/**
* By default, all source indexes start from 0.
* You can provide a start index to alternatively start with.
* Useful for integration with other source tools.
*/
startIndex?: number;
/**
* By default, the first line of code parsed is treated as line 1.
* You can provide a line number to alternatively start with.
* Useful for integration with other source tools.
*/
startLine?: number;
/**
* By default, the parsed code is treated as if it starts from line 1, column 0.
* You can provide a column number to alternatively start with.
* Useful for integration with other source tools.
*/
startColumn?: number;
/**
* Array containing the plugins that you want to enable.
*/
plugins?: Plugin[];
/**
* Should the parser work in strict mode.
* Defaults to true if sourceType === 'module'. Otherwise, false.
*/
strictMode?: boolean;
/**
* Adds a ranges property to each node: [node.start, node.end]
*/
ranges?: boolean;
/**
* Adds all parsed tokens to a tokens property on the File node.
*/
tokens?: boolean;
/**
* By default, the parser adds information about parentheses by setting
* `extra.parenthesized` to `true` as needed.
* When this option is `true` the parser creates `ParenthesizedExpression`
* AST nodes instead of using the `extra` property.
*/
createParenthesizedExpressions?: boolean;
/**
* The default is false in Babel 7 and true in Babel 8
* Set this to true to parse it as an `ImportExpression` node.
* Otherwise `import(foo)` is parsed as `CallExpression(Import, [Identifier(foo)])`.
*/
createImportExpressions?: boolean;
}
type ParserOptions = Partial<Options>;
type ParseError = ParseError$1<object>;
type ParseResult<Result extends File | Expression = File> = Result & {
comments: File["comments"];
errors: null | ParseError[];
tokens?: File["tokens"];
};
/**
* Parse the provided code as an entire ECMAScript program.
*/
declare function parse(input: string, options?: ParserOptions): ParseResult<File>;
declare function parseExpression(input: string, options?: ParserOptions): ParseResult<Expression>;
declare const tokTypes: {
// todo(flow->ts) real token type
[name: string]: any;
};
export { DecoratorsPluginOptions, FlowPluginOptions, ParseError, ParseResult, ParserOptions, PluginConfig as ParserPlugin, ParserPluginWithOptions, PipelineOperatorPluginOptions, RecordAndTuplePluginOptions, TypeScriptPluginOptions, parse, parseExpression, tokTypes };

22
admin/node_modules/@babel/types/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2014-present Sebastian McKenzie and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

19
admin/node_modules/@babel/types/README.md generated vendored Normal file
View File

@ -0,0 +1,19 @@
# @babel/types
> Babel Types is a Lodash-esque utility library for AST nodes
See our website [@babel/types](https://babeljs.io/docs/babel-types) for more information or the [issues](https://github.com/babel/babel/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22pkg%3A%20types%22+is%3Aopen) associated with this package.
## Install
Using npm:
```sh
npm install --save-dev @babel/types
```
or using yarn:
```sh
yarn add @babel/types --dev
```

View File

@ -0,0 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = assertNode;
var _isNode = require("../validators/isNode.js");
function assertNode(node) {
if (!(0, _isNode.default)(node)) {
var _node$type;
const type = (_node$type = node == null ? void 0 : node.type) != null ? _node$type : JSON.stringify(node);
throw new TypeError(`Not a valid node of type "${type}"`);
}
}
//# sourceMappingURL=assertNode.js.map

View File

@ -0,0 +1 @@
{"version":3,"names":["_isNode","require","assertNode","node","isNode","_node$type","type","JSON","stringify","TypeError"],"sources":["../../src/asserts/assertNode.ts"],"sourcesContent":["import isNode from \"../validators/isNode.ts\";\nimport type * as t from \"../index.ts\";\n\nexport default function assertNode(node?: any): asserts node is t.Node {\n if (!isNode(node)) {\n const type = node?.type ?? JSON.stringify(node);\n throw new TypeError(`Not a valid node of type \"${type}\"`);\n }\n}\n"],"mappings":";;;;;;AAAA,IAAAA,OAAA,GAAAC,OAAA;AAGe,SAASC,UAAUA,CAACC,IAAU,EAA0B;EACrE,IAAI,CAAC,IAAAC,eAAM,EAACD,IAAI,CAAC,EAAE;IAAA,IAAAE,UAAA;IACjB,MAAMC,IAAI,IAAAD,UAAA,GAAGF,IAAI,oBAAJA,IAAI,CAAEG,IAAI,YAAAD,UAAA,GAAIE,IAAI,CAACC,SAAS,CAACL,IAAI,CAAC;IAC/C,MAAM,IAAIM,SAAS,CAAC,6BAA6BH,IAAI,GAAG,CAAC;EAC3D;AACF","ignoreList":[]}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,3 @@
"use strict";
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = createFlowUnionType;
var _index = require("../generated/index.js");
var _removeTypeDuplicates = require("../../modifications/flow/removeTypeDuplicates.js");
function createFlowUnionType(types) {
const flattened = (0, _removeTypeDuplicates.default)(types);
if (flattened.length === 1) {
return flattened[0];
} else {
return (0, _index.unionTypeAnnotation)(flattened);
}
}
//# sourceMappingURL=createFlowUnionType.js.map

View File

@ -0,0 +1 @@
{"version":3,"names":["_index","require","_removeTypeDuplicates","createFlowUnionType","types","flattened","removeTypeDuplicates","length","unionTypeAnnotation"],"sources":["../../../src/builders/flow/createFlowUnionType.ts"],"sourcesContent":["import { unionTypeAnnotation } from \"../generated/index.ts\";\nimport removeTypeDuplicates from \"../../modifications/flow/removeTypeDuplicates.ts\";\nimport type * as t from \"../../index.ts\";\n\n/**\n * Takes an array of `types` and flattens them, removing duplicates and\n * returns a `UnionTypeAnnotation` node containing them.\n */\nexport default function createFlowUnionType<T extends t.FlowType>(\n types: [T] | T[],\n): T | t.UnionTypeAnnotation {\n const flattened = removeTypeDuplicates(types);\n\n if (flattened.length === 1) {\n return flattened[0] as T;\n } else {\n return unionTypeAnnotation(flattened);\n }\n}\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,qBAAA,GAAAD,OAAA;AAOe,SAASE,mBAAmBA,CACzCC,KAAgB,EACW;EAC3B,MAAMC,SAAS,GAAG,IAAAC,6BAAoB,EAACF,KAAK,CAAC;EAE7C,IAAIC,SAAS,CAACE,MAAM,KAAK,CAAC,EAAE;IAC1B,OAAOF,SAAS,CAAC,CAAC,CAAC;EACrB,CAAC,MAAM;IACL,OAAO,IAAAG,0BAAmB,EAACH,SAAS,CAAC;EACvC;AACF","ignoreList":[]}

View File

@ -0,0 +1,31 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _index = require("../generated/index.js");
var _default = exports.default = createTypeAnnotationBasedOnTypeof;
function createTypeAnnotationBasedOnTypeof(type) {
switch (type) {
case "string":
return (0, _index.stringTypeAnnotation)();
case "number":
return (0, _index.numberTypeAnnotation)();
case "undefined":
return (0, _index.voidTypeAnnotation)();
case "boolean":
return (0, _index.booleanTypeAnnotation)();
case "function":
return (0, _index.genericTypeAnnotation)((0, _index.identifier)("Function"));
case "object":
return (0, _index.genericTypeAnnotation)((0, _index.identifier)("Object"));
case "symbol":
return (0, _index.genericTypeAnnotation)((0, _index.identifier)("Symbol"));
case "bigint":
return (0, _index.anyTypeAnnotation)();
}
throw new Error("Invalid typeof value: " + type);
}
//# sourceMappingURL=createTypeAnnotationBasedOnTypeof.js.map

View File

@ -0,0 +1 @@
{"version":3,"names":["_index","require","_default","exports","default","createTypeAnnotationBasedOnTypeof","type","stringTypeAnnotation","numberTypeAnnotation","voidTypeAnnotation","booleanTypeAnnotation","genericTypeAnnotation","identifier","anyTypeAnnotation","Error"],"sources":["../../../src/builders/flow/createTypeAnnotationBasedOnTypeof.ts"],"sourcesContent":["import {\n anyTypeAnnotation,\n stringTypeAnnotation,\n numberTypeAnnotation,\n voidTypeAnnotation,\n booleanTypeAnnotation,\n genericTypeAnnotation,\n identifier,\n} from \"../generated/index.ts\";\nimport type * as t from \"../../index.ts\";\n\nexport default createTypeAnnotationBasedOnTypeof as {\n (type: \"string\"): t.StringTypeAnnotation;\n (type: \"number\"): t.NumberTypeAnnotation;\n (type: \"undefined\"): t.VoidTypeAnnotation;\n (type: \"boolean\"): t.BooleanTypeAnnotation;\n (type: \"function\"): t.GenericTypeAnnotation;\n (type: \"object\"): t.GenericTypeAnnotation;\n (type: \"symbol\"): t.GenericTypeAnnotation;\n (type: \"bigint\"): t.AnyTypeAnnotation;\n};\n\n/**\n * Create a type annotation based on typeof expression.\n */\nfunction createTypeAnnotationBasedOnTypeof(type: string): t.FlowType {\n switch (type) {\n case \"string\":\n return stringTypeAnnotation();\n case \"number\":\n return numberTypeAnnotation();\n case \"undefined\":\n return voidTypeAnnotation();\n case \"boolean\":\n return booleanTypeAnnotation();\n case \"function\":\n return genericTypeAnnotation(identifier(\"Function\"));\n case \"object\":\n return genericTypeAnnotation(identifier(\"Object\"));\n case \"symbol\":\n return genericTypeAnnotation(identifier(\"Symbol\"));\n case \"bigint\":\n // todo: use BigInt annotation when Flow supports BigInt\n // https://github.com/facebook/flow/issues/6639\n return anyTypeAnnotation();\n }\n throw new Error(\"Invalid typeof value: \" + type);\n}\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAQ+B,IAAAC,QAAA,GAAAC,OAAA,CAAAC,OAAA,GAGhBC,iCAAiC;AAchD,SAASA,iCAAiCA,CAACC,IAAY,EAAc;EACnE,QAAQA,IAAI;IACV,KAAK,QAAQ;MACX,OAAO,IAAAC,2BAAoB,EAAC,CAAC;IAC/B,KAAK,QAAQ;MACX,OAAO,IAAAC,2BAAoB,EAAC,CAAC;IAC/B,KAAK,WAAW;MACd,OAAO,IAAAC,yBAAkB,EAAC,CAAC;IAC7B,KAAK,SAAS;MACZ,OAAO,IAAAC,4BAAqB,EAAC,CAAC;IAChC,KAAK,UAAU;MACb,OAAO,IAAAC,4BAAqB,EAAC,IAAAC,iBAAU,EAAC,UAAU,CAAC,CAAC;IACtD,KAAK,QAAQ;MACX,OAAO,IAAAD,4BAAqB,EAAC,IAAAC,iBAAU,EAAC,QAAQ,CAAC,CAAC;IACpD,KAAK,QAAQ;MACX,OAAO,IAAAD,4BAAqB,EAAC,IAAAC,iBAAU,EAAC,QAAQ,CAAC,CAAC;IACpD,KAAK,QAAQ;MAGX,OAAO,IAAAC,wBAAiB,EAAC,CAAC;EAC9B;EACA,MAAM,IAAIC,KAAK,CAAC,wBAAwB,GAAGR,IAAI,CAAC;AAClD","ignoreList":[]}

View File

@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _lowercase = require("./lowercase.js");
Object.keys(_lowercase).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (key in exports && exports[key] === _lowercase[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _lowercase[key];
}
});
});
var _uppercase = require("./uppercase.js");
Object.keys(_uppercase).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (key in exports && exports[key] === _uppercase[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _uppercase[key];
}
});
});
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,272 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.JSXIdentifier = exports.JSXFragment = exports.JSXExpressionContainer = exports.JSXEmptyExpression = exports.JSXElement = exports.JSXClosingFragment = exports.JSXClosingElement = exports.JSXAttribute = exports.IntersectionTypeAnnotation = exports.InterpreterDirective = exports.InterfaceTypeAnnotation = exports.InterfaceExtends = exports.InterfaceDeclaration = exports.InferredPredicate = exports.IndexedAccessType = exports.ImportSpecifier = exports.ImportNamespaceSpecifier = exports.ImportExpression = exports.ImportDefaultSpecifier = exports.ImportDeclaration = exports.ImportAttribute = exports.Import = exports.IfStatement = exports.Identifier = exports.GenericTypeAnnotation = exports.FunctionTypeParam = exports.FunctionTypeAnnotation = exports.FunctionExpression = exports.FunctionDeclaration = exports.ForStatement = exports.ForOfStatement = exports.ForInStatement = exports.File = exports.ExpressionStatement = exports.ExportSpecifier = exports.ExportNamespaceSpecifier = exports.ExportNamedDeclaration = exports.ExportDefaultSpecifier = exports.ExportDefaultDeclaration = exports.ExportAllDeclaration = exports.ExistsTypeAnnotation = exports.EnumSymbolBody = exports.EnumStringMember = exports.EnumStringBody = exports.EnumNumberMember = exports.EnumNumberBody = exports.EnumDefaultedMember = exports.EnumDeclaration = exports.EnumBooleanMember = exports.EnumBooleanBody = exports.EmptyTypeAnnotation = exports.EmptyStatement = exports.DoWhileStatement = exports.DoExpression = exports.DirectiveLiteral = exports.Directive = exports.Decorator = exports.DeclaredPredicate = exports.DeclareVariable = exports.DeclareTypeAlias = exports.DeclareOpaqueType = exports.DeclareModuleExports = exports.DeclareModule = exports.DeclareInterface = exports.DeclareFunction = exports.DeclareExportDeclaration = exports.DeclareExportAllDeclaration = exports.DeclareClass = exports.DecimalLiteral = exports.DebuggerStatement = exports.ContinueStatement = exports.ConditionalExpression = exports.ClassProperty = exports.ClassPrivateProperty = exports.ClassPrivateMethod = exports.ClassMethod = exports.ClassImplements = exports.ClassExpression = exports.ClassDeclaration = exports.ClassBody = exports.ClassAccessorProperty = exports.CatchClause = exports.CallExpression = exports.BreakStatement = exports.BooleanTypeAnnotation = exports.BooleanLiteralTypeAnnotation = exports.BooleanLiteral = exports.BlockStatement = exports.BindExpression = exports.BinaryExpression = exports.BigIntLiteral = exports.AwaitExpression = exports.AssignmentPattern = exports.AssignmentExpression = exports.ArrowFunctionExpression = exports.ArrayTypeAnnotation = exports.ArrayPattern = exports.ArrayExpression = exports.ArgumentPlaceholder = exports.AnyTypeAnnotation = void 0;
exports.TSNumberKeyword = exports.TSNullKeyword = exports.TSNonNullExpression = exports.TSNeverKeyword = exports.TSNamespaceExportDeclaration = exports.TSNamedTupleMember = exports.TSModuleDeclaration = exports.TSModuleBlock = exports.TSMethodSignature = exports.TSMappedType = exports.TSLiteralType = exports.TSIntrinsicKeyword = exports.TSIntersectionType = exports.TSInterfaceDeclaration = exports.TSInterfaceBody = exports.TSInstantiationExpression = exports.TSInferType = exports.TSIndexedAccessType = exports.TSIndexSignature = exports.TSImportType = exports.TSImportEqualsDeclaration = exports.TSFunctionType = exports.TSExternalModuleReference = exports.TSExpressionWithTypeArguments = exports.TSExportAssignment = exports.TSEnumMember = exports.TSEnumDeclaration = exports.TSEnumBody = exports.TSDeclareMethod = exports.TSDeclareFunction = exports.TSConstructorType = exports.TSConstructSignatureDeclaration = exports.TSConditionalType = exports.TSCallSignatureDeclaration = exports.TSBooleanKeyword = exports.TSBigIntKeyword = exports.TSAsExpression = exports.TSArrayType = exports.TSAnyKeyword = exports.SymbolTypeAnnotation = exports.SwitchStatement = exports.SwitchCase = exports.Super = exports.StringTypeAnnotation = exports.StringLiteralTypeAnnotation = exports.StringLiteral = exports.StaticBlock = exports.SpreadProperty = exports.SpreadElement = exports.SequenceExpression = exports.ReturnStatement = exports.RestProperty = exports.RestElement = exports.RegexLiteral = exports.RegExpLiteral = exports.RecordExpression = exports.QualifiedTypeIdentifier = exports.Program = exports.PrivateName = exports.Placeholder = exports.PipelineTopicExpression = exports.PipelinePrimaryTopicReference = exports.PipelineBareFunction = exports.ParenthesizedExpression = exports.OptionalMemberExpression = exports.OptionalIndexedAccessType = exports.OptionalCallExpression = exports.OpaqueType = exports.ObjectTypeSpreadProperty = exports.ObjectTypeProperty = exports.ObjectTypeInternalSlot = exports.ObjectTypeIndexer = exports.ObjectTypeCallProperty = exports.ObjectTypeAnnotation = exports.ObjectProperty = exports.ObjectPattern = exports.ObjectMethod = exports.ObjectExpression = exports.NumericLiteral = exports.NumberTypeAnnotation = exports.NumberLiteralTypeAnnotation = exports.NumberLiteral = exports.NullableTypeAnnotation = exports.NullLiteralTypeAnnotation = exports.NullLiteral = exports.Noop = exports.NewExpression = exports.ModuleExpression = exports.MixedTypeAnnotation = exports.MetaProperty = exports.MemberExpression = exports.LogicalExpression = exports.LabeledStatement = exports.JSXText = exports.JSXSpreadChild = exports.JSXSpreadAttribute = exports.JSXOpeningFragment = exports.JSXOpeningElement = exports.JSXNamespacedName = exports.JSXMemberExpression = void 0;
exports.YieldExpression = exports.WithStatement = exports.WhileStatement = exports.VoidTypeAnnotation = exports.VoidPattern = exports.Variance = exports.VariableDeclarator = exports.VariableDeclaration = exports.V8IntrinsicIdentifier = exports.UpdateExpression = exports.UnionTypeAnnotation = exports.UnaryExpression = exports.TypeofTypeAnnotation = exports.TypeParameterInstantiation = exports.TypeParameterDeclaration = exports.TypeParameter = exports.TypeCastExpression = exports.TypeAnnotation = exports.TypeAlias = exports.TupleTypeAnnotation = exports.TupleExpression = exports.TryStatement = exports.TopicReference = exports.ThrowStatement = exports.ThisTypeAnnotation = exports.ThisExpression = exports.TemplateLiteral = exports.TemplateElement = exports.TaggedTemplateExpression = exports.TSVoidKeyword = exports.TSUnknownKeyword = exports.TSUnionType = exports.TSUndefinedKeyword = exports.TSTypeReference = exports.TSTypeQuery = exports.TSTypePredicate = exports.TSTypeParameterInstantiation = exports.TSTypeParameterDeclaration = exports.TSTypeParameter = exports.TSTypeOperator = exports.TSTypeLiteral = exports.TSTypeAssertion = exports.TSTypeAnnotation = exports.TSTypeAliasDeclaration = exports.TSTupleType = exports.TSThisType = exports.TSTemplateLiteralType = exports.TSSymbolKeyword = exports.TSStringKeyword = exports.TSSatisfiesExpression = exports.TSRestType = exports.TSQualifiedName = exports.TSPropertySignature = exports.TSParenthesizedType = exports.TSParameterProperty = exports.TSOptionalType = exports.TSObjectKeyword = void 0;
var b = require("./lowercase.js");
var _deprecationWarning = require("../../utils/deprecationWarning.js");
function alias(lowercase) {
return b[lowercase];
}
const ArrayExpression = exports.ArrayExpression = alias("arrayExpression"),
AssignmentExpression = exports.AssignmentExpression = alias("assignmentExpression"),
BinaryExpression = exports.BinaryExpression = alias("binaryExpression"),
InterpreterDirective = exports.InterpreterDirective = alias("interpreterDirective"),
Directive = exports.Directive = alias("directive"),
DirectiveLiteral = exports.DirectiveLiteral = alias("directiveLiteral"),
BlockStatement = exports.BlockStatement = alias("blockStatement"),
BreakStatement = exports.BreakStatement = alias("breakStatement"),
CallExpression = exports.CallExpression = alias("callExpression"),
CatchClause = exports.CatchClause = alias("catchClause"),
ConditionalExpression = exports.ConditionalExpression = alias("conditionalExpression"),
ContinueStatement = exports.ContinueStatement = alias("continueStatement"),
DebuggerStatement = exports.DebuggerStatement = alias("debuggerStatement"),
DoWhileStatement = exports.DoWhileStatement = alias("doWhileStatement"),
EmptyStatement = exports.EmptyStatement = alias("emptyStatement"),
ExpressionStatement = exports.ExpressionStatement = alias("expressionStatement"),
File = exports.File = alias("file"),
ForInStatement = exports.ForInStatement = alias("forInStatement"),
ForStatement = exports.ForStatement = alias("forStatement"),
FunctionDeclaration = exports.FunctionDeclaration = alias("functionDeclaration"),
FunctionExpression = exports.FunctionExpression = alias("functionExpression"),
Identifier = exports.Identifier = alias("identifier"),
IfStatement = exports.IfStatement = alias("ifStatement"),
LabeledStatement = exports.LabeledStatement = alias("labeledStatement"),
StringLiteral = exports.StringLiteral = alias("stringLiteral"),
NumericLiteral = exports.NumericLiteral = alias("numericLiteral"),
NullLiteral = exports.NullLiteral = alias("nullLiteral"),
BooleanLiteral = exports.BooleanLiteral = alias("booleanLiteral"),
RegExpLiteral = exports.RegExpLiteral = alias("regExpLiteral"),
LogicalExpression = exports.LogicalExpression = alias("logicalExpression"),
MemberExpression = exports.MemberExpression = alias("memberExpression"),
NewExpression = exports.NewExpression = alias("newExpression"),
Program = exports.Program = alias("program"),
ObjectExpression = exports.ObjectExpression = alias("objectExpression"),
ObjectMethod = exports.ObjectMethod = alias("objectMethod"),
ObjectProperty = exports.ObjectProperty = alias("objectProperty"),
RestElement = exports.RestElement = alias("restElement"),
ReturnStatement = exports.ReturnStatement = alias("returnStatement"),
SequenceExpression = exports.SequenceExpression = alias("sequenceExpression"),
ParenthesizedExpression = exports.ParenthesizedExpression = alias("parenthesizedExpression"),
SwitchCase = exports.SwitchCase = alias("switchCase"),
SwitchStatement = exports.SwitchStatement = alias("switchStatement"),
ThisExpression = exports.ThisExpression = alias("thisExpression"),
ThrowStatement = exports.ThrowStatement = alias("throwStatement"),
TryStatement = exports.TryStatement = alias("tryStatement"),
UnaryExpression = exports.UnaryExpression = alias("unaryExpression"),
UpdateExpression = exports.UpdateExpression = alias("updateExpression"),
VariableDeclaration = exports.VariableDeclaration = alias("variableDeclaration"),
VariableDeclarator = exports.VariableDeclarator = alias("variableDeclarator"),
WhileStatement = exports.WhileStatement = alias("whileStatement"),
WithStatement = exports.WithStatement = alias("withStatement"),
AssignmentPattern = exports.AssignmentPattern = alias("assignmentPattern"),
ArrayPattern = exports.ArrayPattern = alias("arrayPattern"),
ArrowFunctionExpression = exports.ArrowFunctionExpression = alias("arrowFunctionExpression"),
ClassBody = exports.ClassBody = alias("classBody"),
ClassExpression = exports.ClassExpression = alias("classExpression"),
ClassDeclaration = exports.ClassDeclaration = alias("classDeclaration"),
ExportAllDeclaration = exports.ExportAllDeclaration = alias("exportAllDeclaration"),
ExportDefaultDeclaration = exports.ExportDefaultDeclaration = alias("exportDefaultDeclaration"),
ExportNamedDeclaration = exports.ExportNamedDeclaration = alias("exportNamedDeclaration"),
ExportSpecifier = exports.ExportSpecifier = alias("exportSpecifier"),
ForOfStatement = exports.ForOfStatement = alias("forOfStatement"),
ImportDeclaration = exports.ImportDeclaration = alias("importDeclaration"),
ImportDefaultSpecifier = exports.ImportDefaultSpecifier = alias("importDefaultSpecifier"),
ImportNamespaceSpecifier = exports.ImportNamespaceSpecifier = alias("importNamespaceSpecifier"),
ImportSpecifier = exports.ImportSpecifier = alias("importSpecifier"),
ImportExpression = exports.ImportExpression = alias("importExpression"),
MetaProperty = exports.MetaProperty = alias("metaProperty"),
ClassMethod = exports.ClassMethod = alias("classMethod"),
ObjectPattern = exports.ObjectPattern = alias("objectPattern"),
SpreadElement = exports.SpreadElement = alias("spreadElement"),
Super = exports.Super = alias("super"),
TaggedTemplateExpression = exports.TaggedTemplateExpression = alias("taggedTemplateExpression"),
TemplateElement = exports.TemplateElement = alias("templateElement"),
TemplateLiteral = exports.TemplateLiteral = alias("templateLiteral"),
YieldExpression = exports.YieldExpression = alias("yieldExpression"),
AwaitExpression = exports.AwaitExpression = alias("awaitExpression"),
Import = exports.Import = alias("import"),
BigIntLiteral = exports.BigIntLiteral = alias("bigIntLiteral"),
ExportNamespaceSpecifier = exports.ExportNamespaceSpecifier = alias("exportNamespaceSpecifier"),
OptionalMemberExpression = exports.OptionalMemberExpression = alias("optionalMemberExpression"),
OptionalCallExpression = exports.OptionalCallExpression = alias("optionalCallExpression"),
ClassProperty = exports.ClassProperty = alias("classProperty"),
ClassAccessorProperty = exports.ClassAccessorProperty = alias("classAccessorProperty"),
ClassPrivateProperty = exports.ClassPrivateProperty = alias("classPrivateProperty"),
ClassPrivateMethod = exports.ClassPrivateMethod = alias("classPrivateMethod"),
PrivateName = exports.PrivateName = alias("privateName"),
StaticBlock = exports.StaticBlock = alias("staticBlock"),
ImportAttribute = exports.ImportAttribute = alias("importAttribute"),
AnyTypeAnnotation = exports.AnyTypeAnnotation = alias("anyTypeAnnotation"),
ArrayTypeAnnotation = exports.ArrayTypeAnnotation = alias("arrayTypeAnnotation"),
BooleanTypeAnnotation = exports.BooleanTypeAnnotation = alias("booleanTypeAnnotation"),
BooleanLiteralTypeAnnotation = exports.BooleanLiteralTypeAnnotation = alias("booleanLiteralTypeAnnotation"),
NullLiteralTypeAnnotation = exports.NullLiteralTypeAnnotation = alias("nullLiteralTypeAnnotation"),
ClassImplements = exports.ClassImplements = alias("classImplements"),
DeclareClass = exports.DeclareClass = alias("declareClass"),
DeclareFunction = exports.DeclareFunction = alias("declareFunction"),
DeclareInterface = exports.DeclareInterface = alias("declareInterface"),
DeclareModule = exports.DeclareModule = alias("declareModule"),
DeclareModuleExports = exports.DeclareModuleExports = alias("declareModuleExports"),
DeclareTypeAlias = exports.DeclareTypeAlias = alias("declareTypeAlias"),
DeclareOpaqueType = exports.DeclareOpaqueType = alias("declareOpaqueType"),
DeclareVariable = exports.DeclareVariable = alias("declareVariable"),
DeclareExportDeclaration = exports.DeclareExportDeclaration = alias("declareExportDeclaration"),
DeclareExportAllDeclaration = exports.DeclareExportAllDeclaration = alias("declareExportAllDeclaration"),
DeclaredPredicate = exports.DeclaredPredicate = alias("declaredPredicate"),
ExistsTypeAnnotation = exports.ExistsTypeAnnotation = alias("existsTypeAnnotation"),
FunctionTypeAnnotation = exports.FunctionTypeAnnotation = alias("functionTypeAnnotation"),
FunctionTypeParam = exports.FunctionTypeParam = alias("functionTypeParam"),
GenericTypeAnnotation = exports.GenericTypeAnnotation = alias("genericTypeAnnotation"),
InferredPredicate = exports.InferredPredicate = alias("inferredPredicate"),
InterfaceExtends = exports.InterfaceExtends = alias("interfaceExtends"),
InterfaceDeclaration = exports.InterfaceDeclaration = alias("interfaceDeclaration"),
InterfaceTypeAnnotation = exports.InterfaceTypeAnnotation = alias("interfaceTypeAnnotation"),
IntersectionTypeAnnotation = exports.IntersectionTypeAnnotation = alias("intersectionTypeAnnotation"),
MixedTypeAnnotation = exports.MixedTypeAnnotation = alias("mixedTypeAnnotation"),
EmptyTypeAnnotation = exports.EmptyTypeAnnotation = alias("emptyTypeAnnotation"),
NullableTypeAnnotation = exports.NullableTypeAnnotation = alias("nullableTypeAnnotation"),
NumberLiteralTypeAnnotation = exports.NumberLiteralTypeAnnotation = alias("numberLiteralTypeAnnotation"),
NumberTypeAnnotation = exports.NumberTypeAnnotation = alias("numberTypeAnnotation"),
ObjectTypeAnnotation = exports.ObjectTypeAnnotation = alias("objectTypeAnnotation"),
ObjectTypeInternalSlot = exports.ObjectTypeInternalSlot = alias("objectTypeInternalSlot"),
ObjectTypeCallProperty = exports.ObjectTypeCallProperty = alias("objectTypeCallProperty"),
ObjectTypeIndexer = exports.ObjectTypeIndexer = alias("objectTypeIndexer"),
ObjectTypeProperty = exports.ObjectTypeProperty = alias("objectTypeProperty"),
ObjectTypeSpreadProperty = exports.ObjectTypeSpreadProperty = alias("objectTypeSpreadProperty"),
OpaqueType = exports.OpaqueType = alias("opaqueType"),
QualifiedTypeIdentifier = exports.QualifiedTypeIdentifier = alias("qualifiedTypeIdentifier"),
StringLiteralTypeAnnotation = exports.StringLiteralTypeAnnotation = alias("stringLiteralTypeAnnotation"),
StringTypeAnnotation = exports.StringTypeAnnotation = alias("stringTypeAnnotation"),
SymbolTypeAnnotation = exports.SymbolTypeAnnotation = alias("symbolTypeAnnotation"),
ThisTypeAnnotation = exports.ThisTypeAnnotation = alias("thisTypeAnnotation"),
TupleTypeAnnotation = exports.TupleTypeAnnotation = alias("tupleTypeAnnotation"),
TypeofTypeAnnotation = exports.TypeofTypeAnnotation = alias("typeofTypeAnnotation"),
TypeAlias = exports.TypeAlias = alias("typeAlias"),
TypeAnnotation = exports.TypeAnnotation = alias("typeAnnotation"),
TypeCastExpression = exports.TypeCastExpression = alias("typeCastExpression"),
TypeParameter = exports.TypeParameter = alias("typeParameter"),
TypeParameterDeclaration = exports.TypeParameterDeclaration = alias("typeParameterDeclaration"),
TypeParameterInstantiation = exports.TypeParameterInstantiation = alias("typeParameterInstantiation"),
UnionTypeAnnotation = exports.UnionTypeAnnotation = alias("unionTypeAnnotation"),
Variance = exports.Variance = alias("variance"),
VoidTypeAnnotation = exports.VoidTypeAnnotation = alias("voidTypeAnnotation"),
EnumDeclaration = exports.EnumDeclaration = alias("enumDeclaration"),
EnumBooleanBody = exports.EnumBooleanBody = alias("enumBooleanBody"),
EnumNumberBody = exports.EnumNumberBody = alias("enumNumberBody"),
EnumStringBody = exports.EnumStringBody = alias("enumStringBody"),
EnumSymbolBody = exports.EnumSymbolBody = alias("enumSymbolBody"),
EnumBooleanMember = exports.EnumBooleanMember = alias("enumBooleanMember"),
EnumNumberMember = exports.EnumNumberMember = alias("enumNumberMember"),
EnumStringMember = exports.EnumStringMember = alias("enumStringMember"),
EnumDefaultedMember = exports.EnumDefaultedMember = alias("enumDefaultedMember"),
IndexedAccessType = exports.IndexedAccessType = alias("indexedAccessType"),
OptionalIndexedAccessType = exports.OptionalIndexedAccessType = alias("optionalIndexedAccessType"),
JSXAttribute = exports.JSXAttribute = alias("jsxAttribute"),
JSXClosingElement = exports.JSXClosingElement = alias("jsxClosingElement"),
JSXElement = exports.JSXElement = alias("jsxElement"),
JSXEmptyExpression = exports.JSXEmptyExpression = alias("jsxEmptyExpression"),
JSXExpressionContainer = exports.JSXExpressionContainer = alias("jsxExpressionContainer"),
JSXSpreadChild = exports.JSXSpreadChild = alias("jsxSpreadChild"),
JSXIdentifier = exports.JSXIdentifier = alias("jsxIdentifier"),
JSXMemberExpression = exports.JSXMemberExpression = alias("jsxMemberExpression"),
JSXNamespacedName = exports.JSXNamespacedName = alias("jsxNamespacedName"),
JSXOpeningElement = exports.JSXOpeningElement = alias("jsxOpeningElement"),
JSXSpreadAttribute = exports.JSXSpreadAttribute = alias("jsxSpreadAttribute"),
JSXText = exports.JSXText = alias("jsxText"),
JSXFragment = exports.JSXFragment = alias("jsxFragment"),
JSXOpeningFragment = exports.JSXOpeningFragment = alias("jsxOpeningFragment"),
JSXClosingFragment = exports.JSXClosingFragment = alias("jsxClosingFragment"),
Noop = exports.Noop = alias("noop"),
Placeholder = exports.Placeholder = alias("placeholder"),
V8IntrinsicIdentifier = exports.V8IntrinsicIdentifier = alias("v8IntrinsicIdentifier"),
ArgumentPlaceholder = exports.ArgumentPlaceholder = alias("argumentPlaceholder"),
BindExpression = exports.BindExpression = alias("bindExpression"),
Decorator = exports.Decorator = alias("decorator"),
DoExpression = exports.DoExpression = alias("doExpression"),
ExportDefaultSpecifier = exports.ExportDefaultSpecifier = alias("exportDefaultSpecifier"),
RecordExpression = exports.RecordExpression = alias("recordExpression"),
TupleExpression = exports.TupleExpression = alias("tupleExpression"),
DecimalLiteral = exports.DecimalLiteral = alias("decimalLiteral"),
ModuleExpression = exports.ModuleExpression = alias("moduleExpression"),
TopicReference = exports.TopicReference = alias("topicReference"),
PipelineTopicExpression = exports.PipelineTopicExpression = alias("pipelineTopicExpression"),
PipelineBareFunction = exports.PipelineBareFunction = alias("pipelineBareFunction"),
PipelinePrimaryTopicReference = exports.PipelinePrimaryTopicReference = alias("pipelinePrimaryTopicReference"),
VoidPattern = exports.VoidPattern = alias("voidPattern"),
TSParameterProperty = exports.TSParameterProperty = alias("tsParameterProperty"),
TSDeclareFunction = exports.TSDeclareFunction = alias("tsDeclareFunction"),
TSDeclareMethod = exports.TSDeclareMethod = alias("tsDeclareMethod"),
TSQualifiedName = exports.TSQualifiedName = alias("tsQualifiedName"),
TSCallSignatureDeclaration = exports.TSCallSignatureDeclaration = alias("tsCallSignatureDeclaration"),
TSConstructSignatureDeclaration = exports.TSConstructSignatureDeclaration = alias("tsConstructSignatureDeclaration"),
TSPropertySignature = exports.TSPropertySignature = alias("tsPropertySignature"),
TSMethodSignature = exports.TSMethodSignature = alias("tsMethodSignature"),
TSIndexSignature = exports.TSIndexSignature = alias("tsIndexSignature"),
TSAnyKeyword = exports.TSAnyKeyword = alias("tsAnyKeyword"),
TSBooleanKeyword = exports.TSBooleanKeyword = alias("tsBooleanKeyword"),
TSBigIntKeyword = exports.TSBigIntKeyword = alias("tsBigIntKeyword"),
TSIntrinsicKeyword = exports.TSIntrinsicKeyword = alias("tsIntrinsicKeyword"),
TSNeverKeyword = exports.TSNeverKeyword = alias("tsNeverKeyword"),
TSNullKeyword = exports.TSNullKeyword = alias("tsNullKeyword"),
TSNumberKeyword = exports.TSNumberKeyword = alias("tsNumberKeyword"),
TSObjectKeyword = exports.TSObjectKeyword = alias("tsObjectKeyword"),
TSStringKeyword = exports.TSStringKeyword = alias("tsStringKeyword"),
TSSymbolKeyword = exports.TSSymbolKeyword = alias("tsSymbolKeyword"),
TSUndefinedKeyword = exports.TSUndefinedKeyword = alias("tsUndefinedKeyword"),
TSUnknownKeyword = exports.TSUnknownKeyword = alias("tsUnknownKeyword"),
TSVoidKeyword = exports.TSVoidKeyword = alias("tsVoidKeyword"),
TSThisType = exports.TSThisType = alias("tsThisType"),
TSFunctionType = exports.TSFunctionType = alias("tsFunctionType"),
TSConstructorType = exports.TSConstructorType = alias("tsConstructorType"),
TSTypeReference = exports.TSTypeReference = alias("tsTypeReference"),
TSTypePredicate = exports.TSTypePredicate = alias("tsTypePredicate"),
TSTypeQuery = exports.TSTypeQuery = alias("tsTypeQuery"),
TSTypeLiteral = exports.TSTypeLiteral = alias("tsTypeLiteral"),
TSArrayType = exports.TSArrayType = alias("tsArrayType"),
TSTupleType = exports.TSTupleType = alias("tsTupleType"),
TSOptionalType = exports.TSOptionalType = alias("tsOptionalType"),
TSRestType = exports.TSRestType = alias("tsRestType"),
TSNamedTupleMember = exports.TSNamedTupleMember = alias("tsNamedTupleMember"),
TSUnionType = exports.TSUnionType = alias("tsUnionType"),
TSIntersectionType = exports.TSIntersectionType = alias("tsIntersectionType"),
TSConditionalType = exports.TSConditionalType = alias("tsConditionalType"),
TSInferType = exports.TSInferType = alias("tsInferType"),
TSParenthesizedType = exports.TSParenthesizedType = alias("tsParenthesizedType"),
TSTypeOperator = exports.TSTypeOperator = alias("tsTypeOperator"),
TSIndexedAccessType = exports.TSIndexedAccessType = alias("tsIndexedAccessType"),
TSMappedType = exports.TSMappedType = alias("tsMappedType"),
TSTemplateLiteralType = exports.TSTemplateLiteralType = alias("tsTemplateLiteralType"),
TSLiteralType = exports.TSLiteralType = alias("tsLiteralType"),
TSExpressionWithTypeArguments = exports.TSExpressionWithTypeArguments = alias("tsExpressionWithTypeArguments"),
TSInterfaceDeclaration = exports.TSInterfaceDeclaration = alias("tsInterfaceDeclaration"),
TSInterfaceBody = exports.TSInterfaceBody = alias("tsInterfaceBody"),
TSTypeAliasDeclaration = exports.TSTypeAliasDeclaration = alias("tsTypeAliasDeclaration"),
TSInstantiationExpression = exports.TSInstantiationExpression = alias("tsInstantiationExpression"),
TSAsExpression = exports.TSAsExpression = alias("tsAsExpression"),
TSSatisfiesExpression = exports.TSSatisfiesExpression = alias("tsSatisfiesExpression"),
TSTypeAssertion = exports.TSTypeAssertion = alias("tsTypeAssertion"),
TSEnumBody = exports.TSEnumBody = alias("tsEnumBody"),
TSEnumDeclaration = exports.TSEnumDeclaration = alias("tsEnumDeclaration"),
TSEnumMember = exports.TSEnumMember = alias("tsEnumMember"),
TSModuleDeclaration = exports.TSModuleDeclaration = alias("tsModuleDeclaration"),
TSModuleBlock = exports.TSModuleBlock = alias("tsModuleBlock"),
TSImportType = exports.TSImportType = alias("tsImportType"),
TSImportEqualsDeclaration = exports.TSImportEqualsDeclaration = alias("tsImportEqualsDeclaration"),
TSExternalModuleReference = exports.TSExternalModuleReference = alias("tsExternalModuleReference"),
TSNonNullExpression = exports.TSNonNullExpression = alias("tsNonNullExpression"),
TSExportAssignment = exports.TSExportAssignment = alias("tsExportAssignment"),
TSNamespaceExportDeclaration = exports.TSNamespaceExportDeclaration = alias("tsNamespaceExportDeclaration"),
TSTypeAnnotation = exports.TSTypeAnnotation = alias("tsTypeAnnotation"),
TSTypeParameterInstantiation = exports.TSTypeParameterInstantiation = alias("tsTypeParameterInstantiation"),
TSTypeParameterDeclaration = exports.TSTypeParameterDeclaration = alias("tsTypeParameterDeclaration"),
TSTypeParameter = exports.TSTypeParameter = alias("tsTypeParameter");
const NumberLiteral = exports.NumberLiteral = b.numberLiteral,
RegexLiteral = exports.RegexLiteral = b.regexLiteral,
RestProperty = exports.RestProperty = b.restProperty,
SpreadProperty = exports.SpreadProperty = b.spreadProperty;
//# sourceMappingURL=uppercase.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.buildUndefinedNode = buildUndefinedNode;
var _index = require("./generated/index.js");
function buildUndefinedNode() {
return (0, _index.unaryExpression)("void", (0, _index.numericLiteral)(0), true);
}
//# sourceMappingURL=productions.js.map

View File

@ -0,0 +1 @@
{"version":3,"names":["_index","require","buildUndefinedNode","unaryExpression","numericLiteral"],"sources":["../../src/builders/productions.ts"],"sourcesContent":["import { numericLiteral, unaryExpression } from \"./generated/index.ts\";\n\nexport function buildUndefinedNode() {\n return unaryExpression(\"void\", numericLiteral(0), true);\n}\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAEO,SAASC,kBAAkBA,CAAA,EAAG;EACnC,OAAO,IAAAC,sBAAe,EAAC,MAAM,EAAE,IAAAC,qBAAc,EAAC,CAAC,CAAC,EAAE,IAAI,CAAC;AACzD","ignoreList":[]}

View File

@ -0,0 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = buildChildren;
var _index = require("../../validators/generated/index.js");
var _cleanJSXElementLiteralChild = require("../../utils/react/cleanJSXElementLiteralChild.js");
function buildChildren(node) {
const elements = [];
for (let i = 0; i < node.children.length; i++) {
let child = node.children[i];
if ((0, _index.isJSXText)(child)) {
(0, _cleanJSXElementLiteralChild.default)(child, elements);
continue;
}
if ((0, _index.isJSXExpressionContainer)(child)) child = child.expression;
if ((0, _index.isJSXEmptyExpression)(child)) continue;
elements.push(child);
}
return elements;
}
//# sourceMappingURL=buildChildren.js.map

View File

@ -0,0 +1 @@
{"version":3,"names":["_index","require","_cleanJSXElementLiteralChild","buildChildren","node","elements","i","children","length","child","isJSXText","cleanJSXElementLiteralChild","isJSXExpressionContainer","expression","isJSXEmptyExpression","push"],"sources":["../../../src/builders/react/buildChildren.ts"],"sourcesContent":["import {\n isJSXText,\n isJSXExpressionContainer,\n isJSXEmptyExpression,\n} from \"../../validators/generated/index.ts\";\nimport cleanJSXElementLiteralChild from \"../../utils/react/cleanJSXElementLiteralChild.ts\";\nimport type * as t from \"../../index.ts\";\n\ntype ReturnedChild =\n | t.JSXSpreadChild\n | t.JSXElement\n | t.JSXFragment\n | t.Expression;\n\nexport default function buildChildren(\n node: t.JSXElement | t.JSXFragment,\n): ReturnedChild[] {\n const elements = [];\n\n for (let i = 0; i < node.children.length; i++) {\n let child: any = node.children[i];\n\n if (isJSXText(child)) {\n cleanJSXElementLiteralChild(child, elements);\n continue;\n }\n\n if (isJSXExpressionContainer(child)) child = child.expression;\n if (isJSXEmptyExpression(child)) continue;\n\n elements.push(child);\n }\n\n return elements;\n}\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAKA,IAAAC,4BAAA,GAAAD,OAAA;AASe,SAASE,aAAaA,CACnCC,IAAkC,EACjB;EACjB,MAAMC,QAAQ,GAAG,EAAE;EAEnB,KAAK,IAAIC,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGF,IAAI,CAACG,QAAQ,CAACC,MAAM,EAAEF,CAAC,EAAE,EAAE;IAC7C,IAAIG,KAAU,GAAGL,IAAI,CAACG,QAAQ,CAACD,CAAC,CAAC;IAEjC,IAAI,IAAAI,gBAAS,EAACD,KAAK,CAAC,EAAE;MACpB,IAAAE,oCAA2B,EAACF,KAAK,EAAEJ,QAAQ,CAAC;MAC5C;IACF;IAEA,IAAI,IAAAO,+BAAwB,EAACH,KAAK,CAAC,EAAEA,KAAK,GAAGA,KAAK,CAACI,UAAU;IAC7D,IAAI,IAAAC,2BAAoB,EAACL,KAAK,CAAC,EAAE;IAEjCJ,QAAQ,CAACU,IAAI,CAACN,KAAK,CAAC;EACtB;EAEA,OAAOJ,QAAQ;AACjB","ignoreList":[]}

View File

@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = createTSUnionType;
var _index = require("../generated/index.js");
var _removeTypeDuplicates = require("../../modifications/typescript/removeTypeDuplicates.js");
var _index2 = require("../../validators/generated/index.js");
function createTSUnionType(typeAnnotations) {
const types = typeAnnotations.map(type => {
return (0, _index2.isTSTypeAnnotation)(type) ? type.typeAnnotation : type;
});
const flattened = (0, _removeTypeDuplicates.default)(types);
if (flattened.length === 1) {
return flattened[0];
} else {
return (0, _index.tsUnionType)(flattened);
}
}
//# sourceMappingURL=createTSUnionType.js.map

View File

@ -0,0 +1 @@
{"version":3,"names":["_index","require","_removeTypeDuplicates","_index2","createTSUnionType","typeAnnotations","types","map","type","isTSTypeAnnotation","typeAnnotation","flattened","removeTypeDuplicates","length","tsUnionType"],"sources":["../../../src/builders/typescript/createTSUnionType.ts"],"sourcesContent":["import { tsUnionType } from \"../generated/index.ts\";\nimport removeTypeDuplicates from \"../../modifications/typescript/removeTypeDuplicates.ts\";\nimport { isTSTypeAnnotation } from \"../../validators/generated/index.ts\";\nimport type * as t from \"../../index.ts\";\n\n/**\n * Takes an array of `types` and flattens them, removing duplicates and\n * returns a `UnionTypeAnnotation` node containing them.\n */\nexport default function createTSUnionType(\n typeAnnotations: (t.TSTypeAnnotation | t.TSType)[],\n): t.TSType {\n const types = typeAnnotations.map(type => {\n return isTSTypeAnnotation(type) ? type.typeAnnotation : type;\n });\n const flattened = removeTypeDuplicates(types);\n\n if (flattened.length === 1) {\n return flattened[0];\n } else {\n return tsUnionType(flattened);\n }\n}\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,qBAAA,GAAAD,OAAA;AACA,IAAAE,OAAA,GAAAF,OAAA;AAOe,SAASG,iBAAiBA,CACvCC,eAAkD,EACxC;EACV,MAAMC,KAAK,GAAGD,eAAe,CAACE,GAAG,CAACC,IAAI,IAAI;IACxC,OAAO,IAAAC,0BAAkB,EAACD,IAAI,CAAC,GAAGA,IAAI,CAACE,cAAc,GAAGF,IAAI;EAC9D,CAAC,CAAC;EACF,MAAMG,SAAS,GAAG,IAAAC,6BAAoB,EAACN,KAAK,CAAC;EAE7C,IAAIK,SAAS,CAACE,MAAM,KAAK,CAAC,EAAE;IAC1B,OAAOF,SAAS,CAAC,CAAC,CAAC;EACrB,CAAC,MAAM;IACL,OAAO,IAAAG,kBAAW,EAACH,SAAS,CAAC;EAC/B;AACF","ignoreList":[]}

View File

@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = validateNode;
var _validate = require("../validators/validate.js");
var _index = require("../index.js");
function validateNode(node) {
if (node == null || typeof node !== "object") return;
const fields = _index.NODE_FIELDS[node.type];
if (!fields) return;
const keys = _index.BUILDER_KEYS[node.type];
for (const key of keys) {
const field = fields[key];
if (field != null) (0, _validate.validateInternal)(field, node, key, node[key]);
}
return node;
}
//# sourceMappingURL=validateNode.js.map

View File

@ -0,0 +1 @@
{"version":3,"names":["_validate","require","_index","validateNode","node","fields","NODE_FIELDS","type","keys","BUILDER_KEYS","key","field","validateInternal"],"sources":["../../src/builders/validateNode.ts"],"sourcesContent":["import { validateInternal } from \"../validators/validate.ts\";\nimport type * as t from \"../index.ts\";\nimport { BUILDER_KEYS, NODE_FIELDS } from \"../index.ts\";\n\nexport default function validateNode<N extends t.Node>(node: N) {\n if (node == null || typeof node !== \"object\") return;\n const fields = NODE_FIELDS[node.type];\n if (!fields) return;\n\n // todo: because keys not in BUILDER_KEYS are not validated - this actually allows invalid nodes in some cases\n const keys = BUILDER_KEYS[node.type] as (keyof N & string)[];\n for (const key of keys) {\n const field = fields[key];\n if (field != null) validateInternal(field, node, key, node[key]);\n }\n return node;\n}\n"],"mappings":";;;;;;AAAA,IAAAA,SAAA,GAAAC,OAAA;AAEA,IAAAC,MAAA,GAAAD,OAAA;AAEe,SAASE,YAAYA,CAAmBC,IAAO,EAAE;EAC9D,IAAIA,IAAI,IAAI,IAAI,IAAI,OAAOA,IAAI,KAAK,QAAQ,EAAE;EAC9C,MAAMC,MAAM,GAAGC,kBAAW,CAACF,IAAI,CAACG,IAAI,CAAC;EACrC,IAAI,CAACF,MAAM,EAAE;EAGb,MAAMG,IAAI,GAAGC,mBAAY,CAACL,IAAI,CAACG,IAAI,CAAyB;EAC5D,KAAK,MAAMG,GAAG,IAAIF,IAAI,EAAE;IACtB,MAAMG,KAAK,GAAGN,MAAM,CAACK,GAAG,CAAC;IACzB,IAAIC,KAAK,IAAI,IAAI,EAAE,IAAAC,0BAAgB,EAACD,KAAK,EAAEP,IAAI,EAAEM,GAAG,EAAEN,IAAI,CAACM,GAAG,CAAC,CAAC;EAClE;EACA,OAAON,IAAI;AACb","ignoreList":[]}

12
admin/node_modules/@babel/types/lib/clone/clone.js generated vendored Normal file
View File

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = clone;
var _cloneNode = require("./cloneNode.js");
function clone(node) {
return (0, _cloneNode.default)(node, false);
}
//# sourceMappingURL=clone.js.map

View File

@ -0,0 +1 @@
{"version":3,"names":["_cloneNode","require","clone","node","cloneNode"],"sources":["../../src/clone/clone.ts"],"sourcesContent":["import cloneNode from \"./cloneNode.ts\";\nimport type * as t from \"../index.ts\";\n\n/**\n * Create a shallow clone of a `node`, including only\n * properties belonging to the node.\n * @deprecated Use t.cloneNode instead.\n */\nexport default function clone<T extends t.Node>(node: T): T {\n return cloneNode(node, /* deep */ false);\n}\n"],"mappings":";;;;;;AAAA,IAAAA,UAAA,GAAAC,OAAA;AAQe,SAASC,KAAKA,CAAmBC,IAAO,EAAK;EAC1D,OAAO,IAAAC,kBAAS,EAACD,IAAI,EAAa,KAAK,CAAC;AAC1C","ignoreList":[]}

12
admin/node_modules/@babel/types/lib/clone/cloneDeep.js generated vendored Normal file
View File

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = cloneDeep;
var _cloneNode = require("./cloneNode.js");
function cloneDeep(node) {
return (0, _cloneNode.default)(node);
}
//# sourceMappingURL=cloneDeep.js.map

View File

@ -0,0 +1 @@
{"version":3,"names":["_cloneNode","require","cloneDeep","node","cloneNode"],"sources":["../../src/clone/cloneDeep.ts"],"sourcesContent":["import cloneNode from \"./cloneNode.ts\";\nimport type * as t from \"../index.ts\";\n\n/**\n * Create a deep clone of a `node` and all of it's child nodes\n * including only properties belonging to the node.\n * @deprecated Use t.cloneNode instead.\n */\nexport default function cloneDeep<T extends t.Node>(node: T): T {\n return cloneNode(node);\n}\n"],"mappings":";;;;;;AAAA,IAAAA,UAAA,GAAAC,OAAA;AAQe,SAASC,SAASA,CAAmBC,IAAO,EAAK;EAC9D,OAAO,IAAAC,kBAAS,EAACD,IAAI,CAAC;AACxB","ignoreList":[]}

Some files were not shown because too many files have changed in this diff Show More