Files
2026-07-09 11:06:20 +08:00

476 lines
15 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="page-container">
<view class="page-body">
<view class="form-section">
<view class="form-group">
<view class="form-item">
<text class="form-label required">危废类型</text>
<picker class="form-value" mode="selector" :range="hwtypeOptions" range-key="alias" @change="onHwTypeChange">
<text>{{ form.hwTypeName || '请选择' }}</text>
<uni-icons type="right" size="14" color="#cccccc"></uni-icons>
</picker>
</view>
<view class="form-item">
<text class="form-label required">产生日期</text>
<view class="form-value">{{ form.productionDate }}</view>
</view>
<view class="form-item">
<text class="form-label required">重量(kg)</text>
<view class="weight-row">
<input class="form-input" type="number" placeholder="请输入重量" v-model="form.weight" />
<view class="form-input-extra" style="margin-left: 8px;">
<button class="btn btn-sm btn-outline" @click="getWeight">获取</button>
</view>
</view>
</view>
<view class="form-item">
<text class="form-label">经办人</text>
<picker class="form-value" mode="selector" :range="handlers" range-key="name" @change="onHandlerChange">
<text>{{ form.handlerName || '请选择' }}</text>
<uni-icons type="right" size="14" color="#cccccc"></uni-icons>
</picker>
</view>
<view class="form-item">
<text class="form-label">去向</text>
<picker class="form-value" mode="selector" :range="destinations" range-key="name" @change="onDestinationChange">
<text>{{ form.destinationName || '请选择' }}</text>
<uni-icons type="right" size="14" color="#cccccc"></uni-icons>
</picker>
</view>
<view class="form-item">
<text class="form-label">提交模式</text>
<radio-group class="radio-group" @change="onSubmitTypeChange">
<label class="radio-item">
<radio value="batch" :checked="form.submit_type === '1'" />
<text>仅产生</text>
</label>
<label class="radio-item">
<radio value="immediate" :checked="form.submit_type === '2'" />
<text>产生入库</text>
</label>
</radio-group>
</view>
</view>
</view>
<view class="tip-bar tip-bar-info">
请确保危废分类准确避免混入其他废弃物
</view>
<view class="btn-area">
<button class="btn btn-primary btn-block" @click="handleSubmit">提交并打印</button>
</view>
</view>
</view>
</template>
<script>
import * as iconv from 'iconv-lite'
import { api } from '@/api'
import { getDateTime, getDate } from '@/utils/common.js'
import { mapGetters } from 'vuex';
import printerService from '@/utils/BluetoothPrinterService.new.js';
import scaleService from '@/utils/BluetoothScaleService.new.js';
export default {
data() {
return {
hwtypeOptions: [
{ id: 1, alias: '活性炭', fwdm: '900-039-49', jldw: '吨', sort_order: 0 },
{ id: 2, alias: '含汞荧光灯管', fwdm: '900-023-29', jldw: '吨', sort_order: 1 }
],
selectedHwType: null,
hwInfo: null,
handlers: [
{ id: 1, name: '李伟' },
{ id: 2, name: '张明' },
{ id: 3, name: '王芳' },
{ id: 4, name: '刘强' }
],
destinations: [
{ id: 1, name: '贮存' },
{ id: 2, name: '转移' },
{ id: 3, name: '自处置' }
],
form: {
hwTypeId: '',
hwTypeName: '',
productionDate: '',
weight: '',
handlerId: '',
handlerName: '',
destinationId: '',
destinationName: '',
submit_type: '1'
},
currentPrintData: null,
// 【蓝牙秤】蓝牙秤连接状态标记,避免重复连接/断开
scaleConnected: false,
// 【打印机】蓝牙打印机连接状态标记(新增)
printerConnected: false
}
},
computed: {
...mapGetters('scale', ['scaleDeviceId', 'scaleServiceId', 'scaleCharacteristicId'])
},
/**
* 页面加载生命周期
* 初始化产生日期为当前时间,并默认选中危废类型、经办人、去向的第一项
*/
onLoad() {
this.$store.dispatch('scale/initScaleConfig'); // 初始化称重配置
this.form.productionDate = getDateTime()
this.initData()
},
onShow() {
// 页面显示时静默连接蓝牙秤(未配置或失败不弹窗)
this.connectScaleSilently()
},
mounted() {
// 注册蓝牙秤实时监听回调
scaleService.onWeightChange(this.handleWeightChange)
scaleService.onConnectionChange(this.handleConnectionChange)
},
beforeDestroy() {
// 注销蓝牙秤监听回调
scaleService.offWeightChange(this.handleWeightChange)
scaleService.offConnectionChange(this.handleConnectionChange)
},
onUnload() {
// 退出页面时断开蓝牙打印机和称重设备连接
this.handleDisconnect()
},
methods: {
async initData() {
await this.gethwType()
await this.gethandler()
this.initOptions()
await this.getHwInfo()
},
// 危废类型
async gethwType() {
try {
const res = await api.hwType()
if (res.code == 1000)
this.hwtypeOptions = res.data
} catch (e) {
console.error('获取危废类型失败:', e)
}
},
// 危废详情
async getHwInfo() {
try {
const res = await api.hwTypeInfo({ tid: this.selectedHwType.id })
console.log('res', res)
if (res.code == 1000)
this.hwInfo = res.data
} catch (e) {
console.error('获取危废详情失败:', e)
}
},
// 产生经办人
async gethandler() {
const res = await api.handler({ type: 1 })
console.log('handler', res)
if (res.code == 1000) {
this.handlers = res.data.map(res => {
return {
id: res.handler_code,
name: res.handler_name
}
})
}
},
initOptions() {
// 默认选中第一项
const hwType = this.hwtypeOptions[0]
this.form.hwTypeId = hwType.id
this.form.hwTypeName = hwType.alias
this.selectedHwType = hwType
const dest = this.destinations[0]
this.form.destinationId = dest.id
this.form.destinationName = dest.name
const handler = this.handlers[0]
this.form.handlerId = handler.id
this.form.handlerName = handler.name
},
/**
* 获取重量(实时监听模式)
* 蓝牙秤连接后会自动推送重量数据,无需发送读取指令。
*
* 流程:
* 1. 检查是否已配置称重设备 → 未配置则引导去设置页
* 2. 检查蓝牙秤连接状态 → 已连接则提示实时称重中
* 3. 未连接则调用 autoConnect() 建立连接
* 4. 连接成功后设备通过 notify 主动推送数据,handleWeightChange 自动填入表单
*/
async getWeight() {
if (!this.scaleDeviceId || !this.scaleServiceId || !this.scaleCharacteristicId) {
uni.showModal({
title: '未配置称重设备',
content: '请先在设置中配置蓝牙称重设备,是否前往设置?',
success: (res) => {
if (res.confirm) {
uni.navigateTo({ url: '/pages/settings/devices/scale' })
}
}
});
return;
}
// 已连接状态:无需重复连接,重量通过 notify 实时推送
if (scaleService.isConnected && this.scaleConnected) {
uni.showToast({ title: '已开启实时称重', icon: 'none' });
return;
}
uni.showToast({ title: '正在连接称重设备...', icon: 'none' });
try {
const success = await scaleService.autoConnect();
this.scaleConnected = success;
uni.showToast({ title: success ? '已连接,实时称重中' : '连接失败', icon: success ? 'success' : 'none' });
} catch (error) {
console.error('【蓝牙秤】连接失败:', error);
this.scaleConnected = false;
uni.showToast({ title: '连接失败', icon: 'none' });
}
},
/**
* 静默连接蓝牙秤(未配置或失败不弹窗)
* 在 onShow 时调用,用于页面切回时自动恢复连接
*/
async connectScaleSilently() {
if (!this.scaleDeviceId || !this.scaleServiceId || !this.scaleCharacteristicId) return;
if (scaleService.isConnected && this.scaleConnected) return;
try {
const success = await scaleService.autoConnect();
this.scaleConnected = success;
} catch (e) {
console.warn('【蓝牙秤】静默连接失败:', e);
}
},
/**
* 蓝牙秤实时重量回调
* 设备通过 notify 主动推送数据时触发,自动填入表单
*/
handleWeightChange(weight) {
if (weight && weight.value !== null && !isNaN(weight.value)) {
this.form.weight = String(weight.value);
}
},
/**
* 蓝牙秤连接状态变更回调
*/
handleConnectionChange(connected) {
this.scaleConnected = connected;
},
/**
* 危废类型选择变更
* @param {Object} e - picker change 事件对象
*/
onHwTypeChange(e) {
const item = this.hwtypeOptions[e.detail.value]
this.form.hwTypeId = item.id
this.form.hwTypeName = item.alias
this.selectedHwType = item
// this.updateDestinationsByHwType(item)
this.getHwInfo()
},
/**
* 经办人选择变更
* @param {Object} e - picker change 事件对象
*/
onHandlerChange(e) {
const item = this.handlers[e.detail.value]
this.form.handlerId = item.id
this.form.handlerName = item.name
},
/**
* 去向选择变更
* @param {Object} e - picker change 事件对象
*/
onDestinationChange(e) {
const item = this.destinations[e.detail.value]
this.form.destinationId = item.id
this.form.destinationName = item.name
},
/**
* 提交模式切换
* @param {Object} e - radio-group change 事件对象
*/
onSubmitTypeChange(e) { this.form.submit_type = e.detail.value },
/**
* 提交登记/打印
*
*/
handleSubmit() {
if (!this.form.hwTypeId) return uni.showToast({ title: '请选择危废类型', icon: 'none' })
if (!this.form.weight) return uni.showToast({ title: '请输入重量', icon: 'none' })
const submitData = {
// ...this.form,
// fwdm: this.selectedHwType?.fwdm || '',
// jldw: this.selectedHwType?.jldw || ''
weight: this.form.weight,
weight_unit: this.selectedHwType.jldw,
direction: this.form.destinationId,
handler_code: this.form.handlerId,
submit_type: this.form.submit_type,
tid: this.form.hwTypeId,
time: getDateTime()
}
if (this.hwInfo.unit == '吨') {
submitData.weight = submitData.weight / 1000
}
console.log('提交数据:', submitData)
api.hwGenerate({ ...submitData }).then(res => {
console.log('hwGenerate res', res)
if (res.code == 1000) {
uni.showToast({ title: '登记成功', icon: 'success' })
// const data = res.data
const hwInfo = this.hwInfo
const result = res.data
const printData = {
'mingcheng': hwInfo.waste_name, // 危废名称
'leibie': hwInfo.waste_category, // 危废类别
'daima': hwInfo.waste_category_code, // 危废代码
'xingtai': hwInfo.waste_form || '-', // 废物形态
'zhuyaochengfen': hwInfo.main_components || '-', // 主要成分
'youhaichengfen': hwInfo.hazardous_components || '-', // 有害成分
'zhuyi': hwInfo.main_properties || '-', // 注意事项
'shibiema': result.digital_id, // 数字识别码
'danwei': hwInfo.unit, // 单位
'lianxi': '', // 联系人
'riqi': getDate(), // 日期
'zhongliang': submitData.weight, // 重量
'beizhu': result.produce_ledger_no || '-', // 备注 台账编号,包装类型
'biaoshi': '', // 标识
'qrcode': result.label_qrcode // 二维码
}
this.currentPrintData = printData
this.doPrint()
}
})
},
async doPrint() {
// const printData = {
// 'mingcheng': '',
// 'leibie': '',
// 'daima': '',
// 'xingtai': '',
// 'zhuyaochengfen': '',
// 'youhaichengfen': '',
// 'zhuyi': '',
// 'shibiema': '',
// 'danwei': '',
// 'lianxi': '',
// 'riqi': '',
// 'zhongliang': '',
// 'beizhu': '-',
// 'biaoshi': ''
// }
if (!this.currentPrintData) {
return false
}
uni.showToast({ title: '打印中...', icon: 'none' })
// 初始化并连接
try {
await printerService.init();
await printerService.autoConnect();
this.printerConnected = true
await printerService.printWasteLabel(this.currentPrintData);
await this.handleDisconnect()
uni.showToast({ title: '打印成功', icon: 'success' })
this.currentPrintData = null
} catch (error) {
console.error('打印失败:', error)
uni.showToast({ title: '打印失败'+ error, icon: 'none' })
}
},
/**
* 断开所有蓝牙连接(打印机 + 称重设备)
*/
async handleDisconnect() {
// 断开蓝牙称重设备
if (this.scaleConnected) {
try {
await scaleService.disconnect();
this.scaleConnected = false;
} catch (err) {
console.warn('【蓝牙秤】断开连接失败:', err);
this.scaleConnected = false;
}
}
// 断开蓝牙打印机
if (this.printerConnected) { // ✅ 修改:this.connected → this.printerConnected
try {
await printerService.disconnect()
this.printerConnected = false // ✅ 修改:this.connected → this.printerConnected
} catch (err) {
console.warn('【蓝牙打印】断开连接失败:', err)
this.printerConnected = false // ✅ 修改:this.connected → this.printerConnected
}
}
}
}
}
</script>
<style lang="scss" scoped>
.weight-row {
display: flex;
align-items: center;
gap: 8px;
flex: 1;
}
.btn-sm {
padding: 0 12px;
font-size: $font-size-base;
height: 32px;
line-height: 32px;
}
.radio-group {
display: flex;
flex: 1;
align-items: center;
justify-content: flex-end;
}
.radio-item {
display: flex;
align-items: center;
margin-right: 16px;
text {
margin-left: 4px;
font-size: $font-size-md;
color: #333;
}
}
.form-input-extra{
margin-left: 8px;
display: flex;
align-items: center;
}
</style>