修复下单错误 api
This commit is contained in:
@@ -1,112 +0,0 @@
|
||||
# 桌面通知功能说明
|
||||
|
||||
## 功能概述
|
||||
|
||||
系统已集成浏览器桌面通知功能,当收到新消息时会在 Windows/Mac 系统级别发送通知。
|
||||
|
||||
## 触发条件
|
||||
|
||||
桌面通知会在以下情况触发:
|
||||
1. 收到新消息(非自己发送的)
|
||||
2. 页面不在前台(浏览器最小化或切换到其他标签页)
|
||||
3. 或者正在查看其他会话(不在当前消息的会话页面)
|
||||
|
||||
## 通知内容
|
||||
|
||||
- **标题**:发送者角色 + 昵称(如:"客服 · 张三")
|
||||
- **内容**:消息文本(最多显示100字)
|
||||
- **图片消息**:显示 "[图片消息]"
|
||||
- **点击通知**:自动跳转到对应会话
|
||||
|
||||
## 使用方式
|
||||
|
||||
### 用户端
|
||||
1. 进入 `/messages` 消息列表页面
|
||||
2. 点击页面右上角的铃铛图标
|
||||
3. 浏览器会弹出权限请求,点击"允许"
|
||||
4. 之后收到新消息时会自动发送桌面通知
|
||||
|
||||
### 管理端
|
||||
1. 进入 `/admin/chats` 客服管理页面
|
||||
2. 首次进入会在用户交互后自动请求权限
|
||||
3. 允许权限后即可接收通知
|
||||
|
||||
### 移动端
|
||||
- iOS Safari:不支持桌面通知
|
||||
- Android Chrome:支持桌面通知
|
||||
|
||||
## 权限状态
|
||||
|
||||
- **未开启**:默认状态,首次需要点击允许
|
||||
- **已开启**:绿色铃铛图标,正常接收通知
|
||||
- **已拒绝**:用户点击了拒绝,需要在浏览器设置中手动开启
|
||||
- Chrome: 设置 → 隐私和安全 → 网站设置 → 通知
|
||||
- Safari: 偏好设置 → 网站 → 通知
|
||||
|
||||
## 技术实现
|
||||
|
||||
### 前端文件
|
||||
- `frontend/src/features/chats/composables/useDesktopNotification.ts` - 通知核心逻辑
|
||||
- `frontend/src/features/chats/components/NotificationSettings.vue` - 通知设置组件
|
||||
- `frontend/src/features/chats/views/ChatView.vue` - 用户端聊天页集成
|
||||
- `frontend/src/features/chats/views/MobileChatView.vue` - 移动端聊天页集成
|
||||
- `frontend/src/features/admin/views/AdminChatsView.vue` - 管理端集成
|
||||
|
||||
### 核心 API
|
||||
```typescript
|
||||
const { notify, requestPermission, permission } = useDesktopNotification('user')
|
||||
|
||||
// 发送通知
|
||||
notify(chatEvent, currentConversationId)
|
||||
|
||||
// 请求权限
|
||||
await requestPermission()
|
||||
|
||||
// 权限状态:'default' | 'granted' | 'denied'
|
||||
console.log(permission.value)
|
||||
```
|
||||
|
||||
## 浏览器兼容性
|
||||
|
||||
| 浏览器 | 桌面通知支持 |
|
||||
|--------|-------------|
|
||||
| Chrome | ✅ 完全支持 |
|
||||
| Firefox | ✅ 完全支持 |
|
||||
| Safari (macOS) | ✅ 完全支持 |
|
||||
| Edge | ✅ 完全支持 |
|
||||
| Safari (iOS) | ❌ 不支持 |
|
||||
| 微信内置浏览器 | ❌ 不支持 |
|
||||
|
||||
## 通知特性
|
||||
|
||||
1. **智能去重**:相同会话的通知会自动替换(不会堆积)
|
||||
2. **自动关闭**:通知5秒后自动消失
|
||||
3. **点击跳转**:点击通知会自动跳转到对应会话并聚焦浏览器窗口
|
||||
4. **不干扰当前会话**:如果正在查看该会话,不会发送通知
|
||||
5. **仅限他人消息**:自己发送的消息不会触发通知
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **首次使用需要用户授权**:浏览器安全策略要求用户主动允许
|
||||
2. **需要 HTTPS**:生产环境必须使用 HTTPS(本地开发 localhost 除外)
|
||||
3. **系统勿扰模式**:如果操作系统开启了勿扰模式,通知可能不会显示
|
||||
4. **浏览器设置**:用户可以在浏览器设置中随时关闭网站通知
|
||||
|
||||
## 测试方法
|
||||
|
||||
1. 打开两个浏览器窗口(或使用隐私模式)
|
||||
2. 窗口A:登录用户/客服A,进入某个会话
|
||||
3. 窗口B:登录用户/客服B,进入相同会话
|
||||
4. 在窗口B发送消息
|
||||
5. 将窗口A最小化或切换到其他标签页
|
||||
6. 应该会收到系统通知
|
||||
|
||||
## 排查问题
|
||||
|
||||
如果没有收到通知,检查:
|
||||
1. 浏览器是否支持 Notification API
|
||||
2. 网站通知权限是否被拒绝(检查浏览器地址栏左侧的锁图标)
|
||||
3. 操作系统通知设置是否开启
|
||||
4. 浏览器是否开启了勿扰模式
|
||||
5. 是否在查看当前会话(查看当前会话不会发通知)
|
||||
6. 是否是自己发送的消息(自己发送的不会通知)
|
||||
@@ -185,7 +185,7 @@ export async function cancelOrder(id: number) {
|
||||
}
|
||||
|
||||
export async function submitHandoff(id: number, content: string) {
|
||||
const { data } = await apiClient.post<ApiResponse<HandoffRecord>>(`/orders/${id}/handoffs`, {
|
||||
const { data } = await apiClient.post<ApiResponse<HandoffRecord>>(`/orders/${id}/handoff`, {
|
||||
content,
|
||||
})
|
||||
return data.data
|
||||
@@ -200,22 +200,27 @@ export async function confirmHandoff(orderId: number, type: string, content: str
|
||||
}
|
||||
|
||||
export async function fetchHandoffRecords(id: string | number) {
|
||||
const { data } = await apiClient.get<ApiResponse<HandoffRecord[]>>(`/orders/${id}/handoffs`)
|
||||
return data.data
|
||||
const { data } = await apiClient.get<ApiResponse<{ items: HandoffRecord[] }>>(
|
||||
`/orders/${id}/handoff-records`
|
||||
)
|
||||
return Array.isArray(data.data?.items) ? data.data.items : []
|
||||
}
|
||||
|
||||
export async function confirmReceive(id: number) {
|
||||
const { data } = await apiClient.post<ApiResponse<{ confirmed: boolean }>>(
|
||||
`/orders/${id}/receive`
|
||||
`/orders/${id}/confirm-receive`
|
||||
)
|
||||
return data.data
|
||||
}
|
||||
|
||||
export async function startOrderPayment(orderId: number, req: StartOrderPaymentRequest = {}) {
|
||||
const { data } = await apiClient.post<ApiResponse<PaymentOrder>>(`/orders/${orderId}/pay`, {
|
||||
pay_way: req.pay_way || 'wechat',
|
||||
const { data } = await apiClient.post<ApiResponse<PaymentOrder>>(
|
||||
`/orders/${orderId}/start-payment`,
|
||||
{
|
||||
pay_way: req.pay_way || 'ZFBZF',
|
||||
jspay_flag: req.jspay_flag || '',
|
||||
})
|
||||
}
|
||||
)
|
||||
return data.data
|
||||
}
|
||||
|
||||
@@ -224,7 +229,7 @@ export function startPayment(orderId: number, payWay: string, jsPayFlag?: string
|
||||
}
|
||||
|
||||
export async function queryOrderPayment(orderId: number) {
|
||||
const { data } = await apiClient.post<ApiResponse<PaymentOrder>>(`/orders/${orderId}/pay/query`)
|
||||
const { data } = await apiClient.get<ApiResponse<PaymentOrder>>(`/orders/${orderId}/query-payment`)
|
||||
return data.data
|
||||
}
|
||||
|
||||
@@ -286,8 +291,10 @@ export async function fetchAdminOrder(id: string | number) {
|
||||
}
|
||||
|
||||
export async function fetchAdminHandoffRecords(id: string | number) {
|
||||
const { data } = await apiClient.get<ApiResponse<HandoffRecord[]>>(`/admin/orders/${id}/handoffs`)
|
||||
return data.data
|
||||
const { data } = await apiClient.get<ApiResponse<{ items: HandoffRecord[] }>>(
|
||||
`/admin/orders/${id}/handoff-records`
|
||||
)
|
||||
return Array.isArray(data.data?.items) ? data.data.items : []
|
||||
}
|
||||
|
||||
export async function adminCloseOrder(id: number, reason: string) {
|
||||
@@ -296,7 +303,7 @@ export async function adminCloseOrder(id: number, reason: string) {
|
||||
}
|
||||
|
||||
export async function adminMarkOrderAbnormal(id: number, reason: string) {
|
||||
const { data } = await apiClient.post<ApiResponse<Order>>(`/admin/orders/${id}/abnormal`, {
|
||||
const { data } = await apiClient.post<ApiResponse<Order>>(`/admin/orders/${id}/mark-abnormal`, {
|
||||
reason,
|
||||
})
|
||||
return data.data
|
||||
|
||||
Reference in New Issue
Block a user