This commit is contained in:
houjunxiang
2025-10-09 18:19:55 +08:00
parent f2ffc65094
commit 386f1e7466
1553 changed files with 284685 additions and 32820 deletions

View File

@@ -0,0 +1,284 @@
<template>
<view>
<u-popup :show="showAuncelSelector" closeable @close="close" @open="open" mode="right">
<view class="p10">天平选择</view>
<scroll-view scroll-y="true" class="content">
<u-grid border :col="3" @click="doSelect">
<u-grid-item v-for="(auncel, index) in auncelList" :index="index" :key="index">
<view class="auncel-item">
<view class="auncel-name">
{{ auncel.code }}
<view style="text-align: center">{{ auncel.controlRealName }}</view>
</view>
<view class="weight">
<view
:class="
auncel.weightStable === 0
? 'weight-data-yellow'
: auncel.weightStable === 1
? 'weight-data'
: 'weight-data-warning'
"
>
{{ auncel.weightData }}
</view>
<view class="weight-unit">{{ auncel.weightUnit }}</view>
</view>
</view>
</u-grid-item>
</u-grid>
</scroll-view>
</u-popup>
</view>
</template>
<script setup>
import { ref, computed, onMounted, onUnmounted } from 'vue'
import nx from '@/nx' // 假设你的全局状态/工具挂载在 nx
// Props & Emits
const props = defineProps({
showAuncelSelector: {
type: Boolean,
default: false
},
previousAuncelId: {
type: String,
default: ''
}
})
const emit = defineEmits(['update:showAuncelSelector'])
// 响应式数据
const auncelList = ref([])
// 计算属性:获取用户信息
const userInfo = computed(() => nx.$store('user').userInfo)
// 方法
const open = () => {
getPageData()
listenDeviceData()
}
const close = () => {
console.log('auncel-selector close触发')
auncelList.value = []
uni.$emit('auncelSelector_close')
closeDeviceListener()
emit('update:showAuncelSelector', false)
}
const getPageData = () => {
uni.showLoading({ title: '加载中...' })
nx.$api.laboratory
.getDeviceLaboratoryListBy({
deviceType: 'auncel',
pageNo: 0,
pageSize: -1,
status: '1',
isEnable: '1'
})
.then(res => {
const dataList = res.records.map(item => ({
...item,
weightData: '',
weightUnit: '',
isConnected: 0,
weightStable: 0,
temperature: 0,
humidity: 0,
controlRealName: ''
}))
auncelList.value = dataList
uni.hideLoading()
})
.catch(err => {
console.error('加载天平列表失败:', err)
uni.hideLoading()
})
}
const doSelect = index => {
const currentAuncel = auncelList.value[index]
if (currentAuncel.isConnected !== 1) {
uni.showToast({ title: '天平设备尚未连接!', icon: 'none' })
return
}
if (currentAuncel.controlRealName && currentAuncel.controlRealName !== userInfo.value.realname) {
uni.showToast({
title: `当前天平正被“${currentAuncel.controlRealName}”使用,请选择其他天平!`,
icon: 'none'
})
return
}
let delayFlag = false
if (props.previousAuncelId && props.previousAuncelId !== '' && props.previousAuncelId !== currentAuncel.id) {
releaseDeviceControl(props.previousAuncelId)
delayFlag = true
}
const controlDevice = {
msgId: currentAuncel.id,
cmd: 'controlDevice',
clientType: 'caaClient',
data: {
deviceId: currentAuncel.id,
deviceCode: currentAuncel.code,
deviceName: currentAuncel.name,
isControl: true,
controlRealName: userInfo.value.realname
}
}
const sendControl = () => {
const controlData = JSON.stringify(controlDevice)
nx.$measure.send(controlData)
console.log('controlDevice', controlData)
uni.$emit('auncelSelector_doSelect', controlDevice)
}
if (delayFlag) {
setTimeout(sendControl, 300)
} else {
sendControl()
}
}
const releaseDeviceControl = deviceId => {
if (!deviceId) return
const controlDevice = {
msgId: deviceId,
cmd: 'controlDevice',
clientType: 'caaClient',
data: {
deviceId,
isControl: false,
controlRealName: userInfo.value.realname
}
}
nx.$measure.send(JSON.stringify(controlDevice))
}
const listenDeviceData = () => {
uni.$on('deviceData', handleDeviceData)
uni.$on('deviceStatus', handleDeviceStatus)
uni.$on('connClose', handleConnClose)
}
const handleDeviceData = res => {
if (res.deviceType !== 'auncel') return
auncelList.value.forEach(item => {
if (item.id === res.deviceId) {
item.weightData = res.weightData ?? ''
item.weightUnit = res.weightUnit ?? ''
item.weightStable = res.weightStable ?? 0
item.isConnected = 1
item.controlRealName = res.controlRealName ?? ''
}
})
}
const handleDeviceStatus = res => {
auncelList.value.forEach(item => {
if (item.id === res.deviceId) {
item.isConnected = res.connected ?? 0
if (res.connected === 0) {
item.weightData = '天平断开'
item.weightUnit = ''
item.weightStable = 0
}
}
})
}
const handleConnClose = () => {
auncelList.value.forEach(item => {
item.weightData = ''
item.weightUnit = ''
item.weightStable = 0
item.controlRealName = ''
item.isConnected = 0
})
}
const closeDeviceListener = () => {
uni.$off('deviceData', handleDeviceData)
uni.$off('deviceStatus', handleDeviceStatus)
uni.$off('connClose', handleConnClose)
}
// 生命周期
onMounted(() => {
// 如果组件在 mounted 时已打开,可考虑自动加载(但通常由父组件控制 show
})
onUnmounted(() => {
closeDeviceListener()
})
</script>
<style scoped lang="scss">
.content {
width: 80vw;
height: 90vh;
}
.auncel-item {
height: 180px;
width: 180px;
background-image: url(/static/images/auncel.png);
background-repeat: no-repeat;
background-size: 100%;
display: flex;
flex-direction: column;
}
.auncel-name {
flex: 1;
text-align: center;
padding-top: 20px;
}
.weight {
flex: 1;
display: flex;
flex-direction: row;
font-size: 32px;
letter-spacing: 2px;
padding-top: 10px;
}
.weight-data {
flex: 1;
color: #4cd964;
text-align: right;
font-family: zzjc-lcd;
}
.weight-data-yellow {
flex: 1;
color: #ffff00;
text-align: center;
font-family: zzjc-lcd;
}
.weight-data-warning {
color: #ff3333;
text-align: right;
font-family: zzjc-lcd;
}
.weight-unit {
color: #ffffff;
font-size: 24px;
padding: 0 10px;
}
@media (max-width: 700px) {
.auncel-item {
height: 150px;
width: 150px;
}
.auncel-name {
padding-top: 10px;
}
}
</style>

View File

@@ -0,0 +1,152 @@
<!-- 查看样品详情 -->
<template>
<view>
<u-popup :show="showPopup" @close="close" @open="open" mode="left">
<view class="detail_title">
{{ taskDetail.sampleCode }}
</view>
<view>
<scroll-view scroll-y style="height: 100vh; width: 30vw">
<view style="padding: 10px">
<up-collapse :value="getAllIndexes(fieldGroup)" :accordion="false">
<up-collapse-item
v-for="(fields, groupIndex) in fieldGroup"
:title="fields.title"
:key="groupIndex"
v-if="curParameterKey === '' || curParameterKey === fields.title"
>
<view
class="form-item-my"
v-for="(field, fieldIndex) in fields.fields"
:key="groupIndex + '-' + fieldIndex"
>
<view
class="label-my"
v-html="
field.name +
(typeof field.unit !== 'undefined' && field.unit !== null ? '(' + field.unit + ')' : '')
"
></view>
<view class="content-my">
<view class="content-my-text" v-if="field.type !== 'select'">
<text class="content-my-text-value">{{ field.value }}</text>
</view>
<view class="content-my-text" v-else>
<text class="content-my-text-value">{{ field.valueText }}</text>
</view>
</view>
</view>
</up-collapse-item>
</up-collapse>
</view>
<view class="p30"></view>
</scroll-view>
</view>
</u-popup>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import nx from '@/nx'
// Props
const props = defineProps({
showPopup: {
type: Boolean,
default: false
},
detailPopupParam: {
type: Object,
default: () => ({
taskDetailId: ''
})
}
})
// Data
const curSample = ref({})
const curParameterKey = ref('')
const fieldGroup = ref([])
const taskDetail = ref({})
const optionParameterClassify = ref([])
const conAssayTaskId = ref('')
const busSubCSampleId = ref('')
// Methods
const getAllIndexes = arr => {
return arr.map((_, index) => index)
}
const close = () => {
uni.$emit('sample-detail-popup_close')
}
const getSampleData = () => {
const taskDetailId = props.detailPopupParam.taskDetailId
nx.$api.assayTask.queryFieldsByTaskDetail({ taskDetailId }).then(res => {
fieldGroup.value = res.result
const arr = [{ label: '全部', value: '' }]
for (const g of fieldGroup.value) {
const title = g.title
arr.push({
label: title,
value: title
})
}
optionParameterClassify.value = arr // 字段分类
conAssayTaskId.value = res.additionalProperties.conAssayTaskId
busSubCSampleId.value = res.additionalProperties.busSubCSampleId
taskDetail.value = res.additionalProperties.taskDetail
})
}
const open = () => {
getSampleData()
}
</script>
<style scoped lang="scss">
.form-item-my {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.label-my {
width: 180px; /* 标签宽度 */
display: flex;
align-items: center;
}
.label-my sub {
font-size: 0.6em; /* 调整下标字体大小 */
vertical-align: sub; /* 调整下标垂直对齐 */
}
.content-my {
flex: 1;
padding-left: 7px;
}
.content-my-text {
height: 35px;
display: flex;
align-items: center;
}
.content-my-text-value {
color: rgb(48, 49, 51);
}
.detail_title {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
font-size: 18px;
font-weight: 400;
padding-top: 30px;
padding-bottom: 10px;
background-color: $uni-color-primary;
color: #fff;
}
</style>