diff --git a/pages_store/Operator/device_set.vue b/pages_store/Operator/device_set.vue index 2f195a3..9bb1273 100644 --- a/pages_store/Operator/device_set.vue +++ b/pages_store/Operator/device_set.vue @@ -5,48 +5,59 @@ - + 分享二维码,邀请朋友使用车辆 - - 保存 - - + 保存 + - - 车辆编号 - + 车辆编号 + {{ deviceInfos.sn }} + + + 备注 - {{ deviceInfos.sn }} + {{ deviceInfos.remark || '未设置' }} + + + + 满电电压 + + {{ deviceInfos.fullVoltage || '未设置' }} V + + + + 亏电电压 + + {{ deviceInfos.lowVoltage || '未设置' }} V + + + + 满电续航 + + {{ deviceInfos.fullEndurance || '未设置' }} KM - - 车辆型号 - + 车辆型号 - {{ deviceInfos.model }} + {{ deviceInfos.model || '未设置' }} - - - 车牌号 - + + 车牌号 - {{ deviceInfos.vehicleNum }} + {{ deviceInfos.vehicleNum || '未设置' }} - - 车辆解绑 - + 车辆解绑 @@ -56,14 +67,14 @@ - 车牌号 - {{currentEditTitle}} + 取消 - 确认 + 确认 @@ -81,13 +92,15 @@ export default { }, sn: '', deviceInfos: {}, - qrSize: 220, // 338rpx 转换为 px (338/2) + qrSize: 220, logoUrl: 'https://lxnapi.ccttiot.com/bike/img/static/u3giTY4VkWYpnGWRuFHF', - tempFilePath: '', // 保存生成的二维码临时文件路径 + tempFilePath: '', showadd: false, list: [], showPlateModal: false, - tempPlateNumber: '', // 临时存储修改的车牌号 + currentEditField: '', // 当前编辑的字段 + currentEditTitle: '', // 当前编辑项的标题 + tempValue: '', // 临时存储修改的值 } }, onLoad(e) { @@ -98,246 +111,312 @@ export default { this.getModelList(); }, methods: { - confirm(e) { + confirm(e) { + this.showadd = false; + this.putDeviceModel(e[0].value); + }, - this.showadd = false - this.putDeviceModel(e[0].value) + // 打开编辑弹窗 + openPlateModal(field, title) { + this.currentEditField = field; + this.currentEditTitle = title; + this.tempValue = this.deviceInfos[field] || ''; + this.showPlateModal = true; + + // 根据字段类型设置输入框类型 + const numericFields = ['fullVoltage', 'lowVoltage', 'fullEndurance']; + if (numericFields.includes(field)) { + // 找到输入框并设置为数字类型 + // this.$nextTick(() => { + // const input = document.querySelector('.plate-input'); + // if (input) { + // input.type = 'number'; + // input.step = '0.1'; // 允许输入小数 + // } + // }); + } + }, - }, - // 打开车牌号修改弹窗 - openPlateModal() { - this.tempPlateNumber = this.deviceInfos.vehicleNum; // 初始化为当前车牌号 - this.showPlateModal = true; - }, + // 关闭弹窗 + closePlateModal() { + this.showPlateModal = false; + // 重新生成二维码 + this.generateQRCode(); + }, - // 关闭弹窗 - closePlateModal() { - this.showPlateModal = false; - // this.tempPlateNumber = ''; - }, - unBind() { - this.$u.post('/appVerify/untie/' + this.deviceInfos.deviceId).then((res) => { - console.log(res, 'rererer'); - if (res.code === 200) { - uni.redirectTo({ - url: '/pages_store/merchant' - }); - } else { - uni.showToast({ - title: res.msg, - icon: 'none', - duration: 2000 - }); - } - }) - }, - // 确认修改 - confirmPlateNumber() { - if (!this.tempPlateNumber) { - uni.showToast({ - title: '请输入车牌号', - icon: 'none' - }); - return; - } - this.putDeviceVehicleNum(); - this.closePlateModal(); - - }, - putDeviceVehicleNum() { - this.$u.put('/appVerify/device/editVehicleNum?sn=' + this.sn + '&vehicleNum=' + this.tempPlateNumber).then((res) => { - console.log(res, 'rererer'); - if (res.code === 200) { - this.deviceInfo(); - } else { - uni.showToast({ - title: res.msg, - icon: 'none', - duration: 2000 - }); - } - }) - }, - putDeviceModel(modelId) { - this.$u.put('/appVerify/device/editModel?sn=' + this.sn + '&modelId=' + modelId).then((res) => { - console.log(res, 'rererer'); - if (res.code === 200) { - this.deviceInfo(); - } else { - uni.showToast({ - title: res.msg, - icon: 'none', - duration: 2000 - }); - } - }) - }, - changeModel() { - this.showadd = true; - }, - changeVehicleNum() { - uni.navigateTo({ - url: '/pages_store/Operator/change_vehicle_num' - }) - }, - deviceInfo() { - this.$u.get('app/getDeviceBySn?sn=' + this.sn).then((res) => { - console.log(res, 'rererer'); - if (res.code === 200) { - this.deviceInfos = res.data - } else { - uni.showToast({ - title: res.msg, - icon: 'none', - duration: 2000 - }); - } - }) - }, - getModelList() { - this.$u.get('/appVerify/model/getModelByToken').then((res) => { - console.log(res, 'rererer'); - if (res.code === 200) { - // 转换数据格式 - this.list = res.data.map(item => ({ - label: item.model, // 显示的文本 - value: item.modelId // 实际的值 - })); - } else { - uni.showToast({ - title: res.msg, - icon: 'none', - duration: 2000 - }); - } - }) - }, - generateQRCode() { - try { - const qrUrl = `https://testlu.chuangtewl.com?sn=${this.sn}`; - const context = uni.createCanvasContext('qrcode', this); + // 确认编辑 + confirmEdit() { + if (!this.tempValue) { + uni.showToast({ + title: '请输入' + this.currentEditTitle, + icon: 'none' + }); + return; + } - // 先清空画布并填充白色背景 - context.setFillStyle('#ffffff'); - context.fillRect(0, 0, this.qrSize, this.qrSize); - context.draw(true); + // 数字类型字段的验证 + const numericFields = ['fullVoltage', 'lowVoltage', 'fullEndurance']; + if (numericFields.includes(this.currentEditField)) { + const value = parseFloat(this.tempValue); + + // 验证是否为有效数字 + if (isNaN(value)) { + uni.showToast({ + title: '请输入有效的数字', + icon: 'none' + }); + return; + } - // 创建二维码实例 - const qr = new UQRCode(); - qr.data = qrUrl; - qr.size = this.qrSize; - qr.margin = 10; - qr.backgroundColor = '#ffffff'; - qr.foregroundColor = '#000000'; - qr.canvasContext = context; + // 验证范围 + switch (this.currentEditField) { + case 'fullVoltage': + case 'lowVoltage': + if (value < 0 || value > 100) { + uni.showToast({ + title: '电压值应在0-100之间', + icon: 'none' + }); + return; + } + break; + case 'fullEndurance': + if (value < 0 || value > 1000) { + uni.showToast({ + title: '续航里程应在0-1000之间', + icon: 'none' + }); + return; + } + break; + } - // 生成二维码 - qr.make(); - qr.drawCanvas(); + // 转换为数字类型 + this.tempValue = value; + } - // 加载并绘制logo - const logoSize = this.qrSize / 4; // logo大小为二维码的1/4 - const logoX = (this.qrSize - logoSize) / 2; - const logoY = (this.qrSize - logoSize) / 2; + this.updateDeviceField(); + this.closePlateModal(); + }, - uni.getImageInfo({ - src: this.logoUrl, - success: (res) => { - // 绘制白色背景 - context.setFillStyle('#ffffff'); - context.fillRect(logoX - 2, logoY - 2, logoSize + 4, logoSize + 4); - // 绘制logo - context.drawImage(res.path, logoX, logoY, logoSize, logoSize); - context.draw(true); - }, - fail: (err) => { - console.error('Logo加载失败:', err); - } - }); + // 统一的设备字段更新方法 + updateDeviceField() { + const params = { + sn: this.sn, + [this.currentEditField]: this.tempValue + }; - } catch (error) { - console.error('生成二维码失败:', error); - uni.showToast({ - title: '生成二维码失败', - icon: 'none' - }); - } - }, - // 保存二维码到相册 - saveQRCode() { - uni.canvasToTempFilePath({ - canvasId: 'qrcode', - success: (res) => { - this.tempFilePath = res.tempFilePath; - uni.saveImageToPhotosAlbum({ - filePath: res.tempFilePath, - success: () => { - uni.showToast({ - title: '保存成功', - icon: 'success' - }); - }, - fail: (err) => { - if (err.errMsg.indexOf('auth deny') !== -1) { - uni.showModal({ - title: '提示', - content: '需要您授权保存到相册', - success: (res) => { - if (res.confirm) { - uni.openSetting(); - } - } - }); - } else { - uni.showToast({ - title: '保存失败', - icon: 'none' - }); - } - } - }); - }, - fail: (err) => { - console.error('转换失败:', err); - uni.showToast({ - title: '保存失败', - icon: 'none' - }); - } - }, this); - }, - // 分享二维码 - shareQRCode() { - uni.canvasToTempFilePath({ - canvasId: 'qrcode', - success: (res) => { - this.tempFilePath = res.tempFilePath; - console.log('二维码图片已生成:', this.tempFilePath); - }, - fail: (err) => { - console.error('生成分享图片失败:', err); - uni.showToast({ - title: '分享失败', - icon: 'none' - }); - } - }, this); - } - }, + // 对数字类型字段进行特殊处理 + const numericFields = ['fullVoltage', 'lowVoltage', 'fullEndurance']; + if (numericFields.includes(this.currentEditField)) { + params[this.currentEditField] = parseFloat(this.tempValue); + } + + this.$u.put('/appVerify/device/edit', params).then((res) => { + if (res.code === 200) { + this.deviceInfo(); + uni.showToast({ + title: '修改成功', + icon: 'success' + }); + } else { + uni.showToast({ + title: res.msg, + icon: 'none', + duration: 2000 + }); + } + }); + }, + + unBind() { + this.$u.post('/appVerify/untie/' + this.deviceInfos.deviceId).then((res) => { + if (res.code === 200) { + uni.redirectTo({ + url: '/pages_store/merchant' + }); + } else { + uni.showToast({ + title: res.msg, + icon: 'none', + duration: 2000 + }); + } + }) + }, + + putDeviceModel(modelId) { + const params = { + sn: this.sn, + modelId: modelId + }; + + this.$u.put('/appVerify/device/edit', params).then((res) => { + if (res.code === 200) { + this.deviceInfo(); + } else { + uni.showToast({ + title: res.msg, + icon: 'none', + duration: 2000 + }); + } + }) + }, + + changeModel() { + this.showadd = true; + }, + + deviceInfo() { + this.$u.get('app/getDeviceBySn?sn=' + this.sn).then((res) => { + if (res.code === 200) { + this.deviceInfos = res.data + } else { + uni.showToast({ + title: res.msg, + icon: 'none', + duration: 2000 + }); + } + }) + }, + + getModelList() { + this.$u.get('/appVerify/model/getModelByToken').then((res) => { + if (res.code === 200) { + this.list = res.data.map(item => ({ + label: item.model, + value: item.modelId + })); + } else { + uni.showToast({ + title: res.msg, + icon: 'none', + duration: 2000 + }); + } + }) + }, + + generateQRCode() { + try { + const qrUrl = `https://testlu.chuangtewl.com?sn=${this.sn}`; + const context = uni.createCanvasContext('qrcode', this); + + context.setFillStyle('#ffffff'); + context.fillRect(0, 0, this.qrSize, this.qrSize); + context.draw(true); + + const qr = new UQRCode(); + qr.data = qrUrl; + qr.size = this.qrSize; + qr.margin = 10; + qr.backgroundColor = '#ffffff'; + qr.foregroundColor = '#000000'; + qr.canvasContext = context; + + qr.make(); + qr.drawCanvas(); + + const logoSize = this.qrSize / 4; + const logoX = (this.qrSize - logoSize) / 2; + const logoY = (this.qrSize - logoSize) / 2; + + uni.getImageInfo({ + src: this.logoUrl, + success: (res) => { + context.setFillStyle('#ffffff'); + context.fillRect(logoX - 2, logoY - 2, logoSize + 4, logoSize + 4); + context.drawImage(res.path, logoX, logoY, logoSize, logoSize); + context.draw(true); + }, + fail: (err) => { + console.error('Logo加载失败:', err); + } + }); + + } catch (error) { + console.error('生成二维码失败:', error); + uni.showToast({ + title: '生成二维码失败', + icon: 'none' + }); + } + }, + + saveQRCode() { + uni.canvasToTempFilePath({ + canvasId: 'qrcode', + success: (res) => { + this.tempFilePath = res.tempFilePath; + uni.saveImageToPhotosAlbum({ + filePath: res.tempFilePath, + success: () => { + uni.showToast({ + title: '保存成功', + icon: 'success' + }); + }, + fail: (err) => { + if (err.errMsg.indexOf('auth deny') !== -1) { + uni.showModal({ + title: '提示', + content: '需要您授权保存到相册', + success: (res) => { + if (res.confirm) { + uni.openSetting(); + } + } + }); + } else { + uni.showToast({ + title: '保存失败', + icon: 'none' + }); + } + } + }); + }, + fail: (err) => { + console.error('转换失败:', err); + uni.showToast({ + title: '保存失败', + icon: 'none' + }); + } + }, this); + }, + + shareQRCode() { + uni.canvasToTempFilePath({ + canvasId: 'qrcode', + success: (res) => { + this.tempFilePath = res.tempFilePath; + console.log('二维码图片已生成:', this.tempFilePath); + }, + fail: (err) => { + console.error('生成分享图片失败:', err); + uni.showToast({ + title: '分享失败', + icon: 'none' + }); + } + }, this); + } +}, onShareAppMessage() { return { title: '设备分享', imageUrl: 'https://lxnapi.ccttiot.com/bike/img/static/uNRujJOme6J0bIxiN1TF', - path: `/pages/index/index?sn=${this.sn}` // 修改为首页并传递sn参数 + path: `/pages/index/index?sn=${this.sn}` } }, - - // 修改分享到朋友圈的配置 onShareTimeline() { return { title: '设备分享', imageUrl: 'https://lxnapi.ccttiot.com/bike/img/static/uNRujJOme6J0bIxiN1TF', - query: `sn=${this.sn}` // 这里的参数会自动拼接到pages/index/index后面 + query: `sn=${this.sn}` } } } @@ -348,17 +427,13 @@ page { overflow-y: auto; background-image: url('https://lxnapi.ccttiot.com/bike/img/static/uYRs7Cv2Pbp95w3KjGO3'); background-size: cover; - /* 背景图片等比缩放以覆盖整个容器 */ background-position: center; - /* 背景图片居中显示 */ background-repeat: no-repeat; - /* 防止背景图片重复 */ min-height: 100vh; - /* 确保页面至少有 100% 的视窗高度,避免高度不足导致无法滚动 */ - } .page { + padding-bottom: 100rpx; .mask { position: fixed; top: 0; @@ -366,7 +441,7 @@ page { right: 0; bottom: 0; background: rgba(0, 0, 0, 0.6); - z-index: 999; + z-index: 100; } .plate-modal { @@ -378,95 +453,121 @@ page { background: #FFFFFF; border-radius: 24rpx; z-index: 1000; + box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.1); + animation: modalFadeIn 0.3s ease-out; .modal-title { display: flex; flex-direction: column; align-items: center; - padding: 40rpx 0; + padding: 48rpx 0 32rpx; + border-bottom: 2rpx solid #F5F5F5; .logo { - width: 80rpx; - height: 80rpx; + width: 88rpx; + height: 88rpx; border-radius: 50%; - margin-bottom: 20rpx; + margin-bottom: 24rpx; + box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1); } text { - font-size: 32rpx; - font-weight: 500; - color: #333; - } + font-size: 36rpx; + font-weight: 600; + color: #333333; + line-height: 1.4; - .sub-title { - font-size: 24rpx; - color: #999; - margin-top: 8rpx; + &.sub-title { + margin-top: 8rpx; + font-size: 24rpx; + color: #999999; + font-weight: 400; + letter-spacing: 2rpx; + } } } .modal-content { - padding: 0 40rpx; + padding: 32rpx 40rpx; .label { + display: block; font-size: 28rpx; - color: #333; - margin-bottom: 20rpx; + color: #333333; + margin-bottom: 16rpx; + font-weight: 500; } .plate-input { width: 100%; - height: 80rpx; - border: 2rpx dashed #CCCCCC; - border-radius: 8rpx; - padding: 0 20rpx; + height: 88rpx; + background: #F8F8F8; + border-radius: 12rpx; + padding: 0 24rpx; + font-size: 30rpx; + color: #333333; + box-sizing: border-box; + border: 2rpx solid #EEEEEE; + transition: all 0.3s ease; + + &:focus { + border-color: #4297F3; + background: #FFFFFF; + } + } + + .input-placeholder { + color: #999999; font-size: 28rpx; - margin-bottom: 40rpx; } } .modal-footer { display: flex; - border-top: 2rpx solid #EEEEEE; + height: 100rpx; + border-top: 2rpx solid #F5F5F5; .btn { flex: 1; - height: 100rpx; display: flex; align-items: center; justify-content: center; font-size: 32rpx; + font-weight: 500; + transition: all 0.3s ease; &.cancel { - color: #999; - border-right: 2rpx solid #EEEEEE; + color: #666666; + background: #FFFFFF; + border-radius: 0 0 0 24rpx; + + &:active { + background: #F5F5F5; + } } &.confirm { - color: #4297F3; + color: #FFFFFF; + background: #4297F3; + border-radius: 0 0 24rpx 0; + + &:active { + background: darken(#4297F3, 5%); + } } } } } - .input-placeholder { - color: #999999; - } - - .unBind { - margin: 0 auto; - margin-top: 90rpx; - display: flex; - justify-content: center; - align-items: center; - width: 660rpx; - height: 92rpx; - background: #3D3D3D; - box-shadow: 0rpx 2rpx 18rpx 0rpx rgba(0, 0, 0, 0.1); - border-radius: 16rpx 16rpx 16rpx 16rpx; - font-weight: 500; - font-size: 40rpx; - color: #FFFFFF; + @keyframes modalFadeIn { + from { + opacity: 0; + transform: translate(-50%, -48%); + } + to { + opacity: 1; + transform: translate(-50%, -50%); + } } .device_info { @@ -477,44 +578,35 @@ page { padding-bottom: 24rpx; background: #FFFFFF; box-shadow: 0rpx 2rpx 18rpx 0rpx rgba(0, 0, 0, 0.1); - border-radius: 20rpx 20rpx 20rpx 20rpx; + border-radius: 20rpx; .device_info_item { margin-bottom: 20rpx; display: flex; justify-content: space-between; align-items: center; + padding: 24rpx 0; + transition: all 0.3s ease; + border-bottom: 2rpx dashed #dddddd; + &:active { + background: #F8F8F8; + } .device_info_item_title { - font-weight: 400; font-size: 28rpx; - color: #6F6F6F; + color: #666666; } .device_info_item_value { display: flex; - flex-direction: row; align-items: center; - font-weight: 400; font-size: 28rpx; - color: #3D3D3D; - - input { - flex: 1; // 让输入框占据剩余空间 - margin-left: auto; - height: 40rpx; - border: none; - text-align: right; // 文本右对齐 - padding-right: 20rpx; // 右侧添加一些padding,避免文字贴边 - } - - .input-placeholder { - text-align: right; // placeholder也右对齐 - color: #999; // placeholder颜色 - } + color: #333333; .iconfont { - margin-left: 10rpx; // 图标和输入框之间的间距 + margin-left: 8rpx; + color: #999999; + font-size: 24rpx; } } } @@ -540,26 +632,23 @@ page { justify-content: center; align-items: center; padding: 40rpx; - z-index: 1; canvas { - background: #ffffff; + background: #FFFFFF; padding: 20rpx; border-radius: 16rpx; - box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.1); + box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.1); } } .tips { position: absolute; - width: 660rpx; + width: 100%; text-align: center; top: 678rpx; - left: 0; - right: 0; - font-weight: 700; + font-weight: 600; font-size: 32rpx; - color: #3D3D3D; + color: #333333; } .btn_box { @@ -581,7 +670,12 @@ page { border: 2rpx solid #808080; font-weight: 500; font-size: 32rpx; - color: #3D3D3D; + color: #333333; + transition: all 0.3s ease; + + &:active { + background: #F5F5F5; + } } .btn1 { @@ -598,6 +692,11 @@ page { padding: 0; margin: 0; line-height: 82rpx; + transition: all 0.3s ease; + + &:active { + background: darken(#4297F3, 5%); + } &::after { border: none; @@ -605,5 +704,27 @@ page { } } } + + .unBind { + margin: 0 auto; + margin-top: 90rpx; + margin-bottom: 40rpx; + display: flex; + justify-content: center; + align-items: center; + width: 660rpx; + height: 92rpx; + background: #3D3D3D; + box-shadow: 0rpx 2rpx 18rpx 0rpx rgba(0, 0, 0, 0.1); + border-radius: 16rpx; + font-weight: 500; + font-size: 40rpx; + color: #FFFFFF; + transition: all 0.3s ease; + + &:active { + background: darken(#3D3D3D, 5%); + } + } } \ No newline at end of file