feat: 添加预约核销功能
This commit is contained in:
+36
-28
@@ -42,16 +42,17 @@ Page({
|
|||||||
'cancelled': '已取消'
|
'cancelled': '已取消'
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkStatus 为字符串:'0' 未核销,'1' 已核销
|
const checkStatusMap = {
|
||||||
const checkStatus = String(result.checkStatus)
|
'1': '已核销',
|
||||||
const checkStatusText = checkStatus === '1' ? '已核销' : '未核销'
|
'0': '未核销'
|
||||||
|
}
|
||||||
|
|
||||||
this.setData({
|
this.setData({
|
||||||
record: {
|
record: {
|
||||||
...formatRecord(result),
|
...formatRecord(result),
|
||||||
statusText: statusMap[result.status] || result.status,
|
statusText: statusMap[result.status] || result.status,
|
||||||
checkStatus: checkStatus,
|
checkStatusText: checkStatusMap[result.checkStatus] || '未核销',
|
||||||
checkStatusText: checkStatusText
|
isChecked: result.checkStatus === '1'
|
||||||
},
|
},
|
||||||
loading: false
|
loading: false
|
||||||
})
|
})
|
||||||
@@ -61,30 +62,37 @@ Page({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async onVerify() {
|
async handleVerify() {
|
||||||
const { record, verifying } = this.data
|
const { record } = this.data
|
||||||
if (verifying || !record || !record.id) return
|
if (!record || record.isChecked || this.data.verifying) return
|
||||||
|
|
||||||
wx.showModal({
|
const confirmed = await new Promise((resolve) => {
|
||||||
title: '确认核销',
|
wx.showModal({
|
||||||
content: '确定要核销该预约记录吗?',
|
title: '确认核销',
|
||||||
confirmColor: '#1890ff',
|
content: '确认通知被访人访客已到达并核销此预约记录?',
|
||||||
success: async (res) => {
|
confirmText: '确认核销',
|
||||||
if (!res.confirm) return
|
confirmColor: '#1890ff',
|
||||||
|
success: (res) => resolve(res.confirm)
|
||||||
this.setData({ verifying: true })
|
})
|
||||||
try {
|
|
||||||
await appointmentDB.notifyHost(record.id)
|
|
||||||
wx.showToast({ title: '核销成功', icon: 'success' })
|
|
||||||
// 刷新详情页
|
|
||||||
this.loadRecordDetail(record.id)
|
|
||||||
} catch (err) {
|
|
||||||
console.error('核销失败', err)
|
|
||||||
wx.showToast({ title: '核销失败,请重试', icon: 'none' })
|
|
||||||
} finally {
|
|
||||||
this.setData({ verifying: false })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (!confirmed) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.setData({ verifying: true })
|
||||||
|
await appointmentDB.notifyHostArrival(record._id)
|
||||||
|
|
||||||
|
this.setData({
|
||||||
|
'record.isChecked': true,
|
||||||
|
'record.checkStatusText': '已核销',
|
||||||
|
verifying: false
|
||||||
|
})
|
||||||
|
|
||||||
|
wx.showToast({ title: '核销成功,已通知被访人', icon: 'success' })
|
||||||
|
} catch (err) {
|
||||||
|
console.error('核销失败', err)
|
||||||
|
this.setData({ verifying: false })
|
||||||
|
wx.showToast({ title: err.message || '核销失败,请稍后重试', icon: 'none' })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -66,16 +66,21 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 核销状态与操作 -->
|
<!-- 核销状态 -->
|
||||||
<view class="detail-section">
|
<view class="check-section">
|
||||||
<view class="detail-row">
|
<view class="detail-row">
|
||||||
<text class="detail-label">核销状态</text>
|
<text class="detail-label">核销状态</text>
|
||||||
<text class="detail-value {{record.checkStatus === '1' ? 'text-success' : 'text-warning'}}">{{record.checkStatusText}}</text>
|
<text class="check-status {{record.isChecked ? 'checked' : 'unchecked'}}">{{record.checkStatusText}}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="verify-btn-wrap" wx:if="{{record.checkStatus === '0'}}">
|
<button
|
||||||
<view class="verify-btn {{verifying ? 'verify-btn-disabled' : ''}}" bindtap="onVerify">
|
wx:if="{{!record.isChecked && record.status === 'approved'}}"
|
||||||
{{verifying ? '核销中...' : '确认核销'}}
|
class="verify-btn"
|
||||||
</view>
|
bindtap="handleVerify"
|
||||||
|
loading="{{verifying}}"
|
||||||
|
disabled="{{verifying}}"
|
||||||
|
>核销到访</button>
|
||||||
|
<view wx:elif="{{record.isChecked}}" class="verified-tip">
|
||||||
|
<text>该预约记录已核销</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 30rpx;
|
padding: 30rpx;
|
||||||
border-bottom: 1rpx solid #f0f0f0;
|
border-bottom: 1rpx solid #f0f0f0;
|
||||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
background: #5b9bd5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail-header .title {
|
.detail-header .title {
|
||||||
@@ -135,34 +135,47 @@
|
|||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 核销状态文字 */
|
/* 核销区块 */
|
||||||
.text-warning {
|
.check-section {
|
||||||
color: #faad14;
|
padding: 30rpx;
|
||||||
font-weight: bold;
|
border-top: 1rpx solid #f0f0f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-success {
|
.check-status {
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 6rpx 16rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-status.checked {
|
||||||
color: #52c41a;
|
color: #52c41a;
|
||||||
font-weight: bold;
|
background-color: #f6ffed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 核销按钮 */
|
.check-status.unchecked {
|
||||||
.verify-btn-wrap {
|
color: #faad14;
|
||||||
padding-top: 20rpx;
|
background-color: #fffbe6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.verify-btn {
|
.verify-btn {
|
||||||
width: 100%;
|
margin-top: 30rpx;
|
||||||
height: 80rpx;
|
background: #5b9bd5;
|
||||||
line-height: 80rpx;
|
|
||||||
text-align: center;
|
|
||||||
background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
|
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 30rpx;
|
|
||||||
font-weight: bold;
|
|
||||||
border-radius: 12rpx;
|
border-radius: 12rpx;
|
||||||
|
font-size: 30rpx;
|
||||||
|
height: 88rpx;
|
||||||
|
line-height: 88rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.verify-btn-disabled {
|
.verify-btn::after {
|
||||||
opacity: 0.6;
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.verified-tip {
|
||||||
|
margin-top: 24rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999;
|
||||||
|
padding: 16rpx 0;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
### 任务目标
|
||||||
|
pages/scan/result/index 页面增加核销功能和显示核销状态功能
|
||||||
|
|
||||||
|
### 详细要求
|
||||||
|
pages/scan/result/index 最下面增加一个核销按钮,显示check_status,未核销时候可以点击按钮
|
||||||
|
调用/visitor/notify-host 进行通知被访人和核销预约记录。分析项目信息,编码必须符合项目架构和风格。
|
||||||
|
同时考虑用户体验与交互优化。
|
||||||
|
### api数据
|
||||||
|
后端接口文件
|
||||||
|
I:\code\xxc\minispringboot\src\main\java\com\example\mini_program\controller\AppointmentController.java
|
||||||
|
I:\code\xxc\minispringboot\src\main\java\com\example\mini_program\controller\VisitorApprovalController.java
|
||||||
|
参考两个文件中的接口信息和项目中的数据结构
|
||||||
|
```
|
||||||
|
@GetMapping("/detail")
|
||||||
|
public Result<VisitApplication> getDetail(@RequestParam String id) {
|
||||||
|
if (id == null || id.trim().isEmpty()) {
|
||||||
|
return Result.error("id不能为空");
|
||||||
|
}
|
||||||
|
return Result.success(appointmentService.getDetail(id));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
和
|
||||||
|
```
|
||||||
|
@GetMapping("/notify-host")
|
||||||
|
public Result<String> notifyHostArrival(@RequestParam String id) {
|
||||||
|
log.info("通知受访者访客已到达, id={}", id);
|
||||||
|
if (id == null || id.trim().isEmpty()) {
|
||||||
|
return Result.error("预约记录ID不能为空");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
visitorApprovalService.notifyHostArrival(id);
|
||||||
|
return Result.success("通知发送成功");
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("通知发送失败, id={}", id, e);
|
||||||
|
return Result.error("通知发送失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
``
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
# 项目目标
|
|
||||||
开发微信小程序,实现一个简单的访客预约系统,用于协能工厂区域的访问管理。
|
|
||||||
预约功能页面可以选择预约时间和预约人,并提交预约信息。
|
|
||||||
预约记录页面可以查看预约记录,和预约进度结果和取消预约。
|
|
||||||
目前不需要进行登录和注册功能,可以直接使用微信小程序的登录和注册功能。
|
|
||||||
# 系统功能需求
|
|
||||||
### 主要页面
|
|
||||||
1. 访客预约操作页面,小程序的首页可以选择跳转预约功能页面和选择跳转进入预约记录页面。
|
|
||||||
2. 预约功能页面,选择预约时间和预约人,并提交预约信息。
|
|
||||||
|
|
||||||
3. 预约记录页面,可以查看预约记录,和预约进度结果和取消预约。
|
|
||||||
|
|
||||||
### 编码原则
|
|
||||||
目前不需要后端信息,使用硬编码模拟数据
|
|
||||||
+5
-7
@@ -200,18 +200,16 @@ const appointmentDB = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 核销通知被访人
|
* 核销预约记录(通知被访人访客已到达)
|
||||||
* @param {string} id - 预约记录 id
|
* @param {string} id - 预约记录 id
|
||||||
* @returns {Promise<boolean>}
|
* @returns {Promise<string>} 操作结果
|
||||||
*/
|
*/
|
||||||
async notifyHost(id) {
|
async notifyHostArrival(id) {
|
||||||
await request({
|
return await request({
|
||||||
url: BASE_URL + API.NOTIFY_HOST,
|
url: BASE_URL + API.NOTIFY_HOST,
|
||||||
method: 'POST',
|
method: 'GET',
|
||||||
header: { 'content-type': 'application/json' },
|
|
||||||
data: { id }
|
data: { id }
|
||||||
})
|
})
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -6,8 +6,8 @@ const ENV_CONFIG = {
|
|||||||
// release: 'https://xcx.yun.588580.xyz',
|
// release: 'https://xcx.yun.588580.xyz',
|
||||||
trial: 'https://qywx.yun.588580.xyz',
|
trial: 'https://qywx.yun.588580.xyz',
|
||||||
// 开发版 & 体验版
|
// 开发版 & 体验版
|
||||||
// develop: 'http://172.16.60.235:8080'
|
develop: 'http://172.16.60.235:8080'
|
||||||
develop: 'http://10.50.13.191:8080'
|
// develop: 'http://10.50.13.191:8080'
|
||||||
}
|
}
|
||||||
|
|
||||||
// 自动判断当前运行环境
|
// 自动判断当前运行环境
|
||||||
|
|||||||
Reference in New Issue
Block a user