1
This commit is contained in:
257
pages/analysis/auncel/auncel-select.vue
Normal file
257
pages/analysis/auncel/auncel-select.vue
Normal file
@@ -0,0 +1,257 @@
|
||||
<template>
|
||||
<view>
|
||||
<navbar-back title="选择天平"></navbar-back>
|
||||
|
||||
<u-grid :col="3" @click="click">
|
||||
<u-grid-item v-for="(auncel, index) in auncelList" :index="index" :key="index">
|
||||
<view
|
||||
style="
|
||||
height: 180px;
|
||||
width: 180px;
|
||||
background-image: url(../../static/images/auncel.png);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100%;
|
||||
"
|
||||
>
|
||||
<view style="height: 100px">
|
||||
<view style="padding-top: 20px; text-align: center; font-size: 20rpx"
|
||||
><text>{{ auncel.code }}</text></view
|
||||
>
|
||||
<view style="padding-top: 5px; text-align: center"
|
||||
><text>{{ auncel.controlRealName }}</text></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>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
auncelList: [],
|
||||
currentAuncel: '',
|
||||
currentTaskNo: '',
|
||||
currentTaskType: ''
|
||||
}
|
||||
},
|
||||
onLoad(param) {
|
||||
this.currentTaskNo = param.currentTaskNo
|
||||
this.currentTaskType = param.currentTaskType
|
||||
//获取数据
|
||||
this.getPageData()
|
||||
console.log('onLoad')
|
||||
},
|
||||
onShow() {
|
||||
console.log('onShow')
|
||||
// #ifdef H5
|
||||
//注册websocket
|
||||
let regData = {
|
||||
msgId: this.$helper.uuid(),
|
||||
cmd: 'register',
|
||||
clientType: 'caaClient',
|
||||
data: {
|
||||
userId: this.userInfo.user_id,
|
||||
tenantId: this.userInfo.tenant_id,
|
||||
userRealName: this.userInfo.real_name
|
||||
}
|
||||
}
|
||||
this.$measure.setRegData(JSON.stringify(regData))
|
||||
this.$measure.reOpen()
|
||||
// #endif
|
||||
//监听websocket返回来的数据
|
||||
//设备数据
|
||||
uni.$on('deviceData', res => {
|
||||
switch (res.deviceType) {
|
||||
case 'auncel':
|
||||
this.auncelList.forEach((item, index) => {
|
||||
if (item.id === res.deviceId) {
|
||||
item.weightData = res.weightData
|
||||
item.weightUnit = res.weightUnit
|
||||
item.weightStable = res.weightStable
|
||||
item.isConnected = 1
|
||||
item.controlRealName = res.controlRealName
|
||||
}
|
||||
})
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
//设备状态
|
||||
uni.$on('deviceStatus', res => {
|
||||
this.auncelList.forEach((item, index) => {
|
||||
if (item.id === res.deviceId) {
|
||||
item.isConnected = res.connected
|
||||
if (res.connected == 0) {
|
||||
item.weightData = '天平断开'
|
||||
item.weightUnit = ''
|
||||
item.weightStable = 0
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
//连接断开
|
||||
uni.$on('connClose', res => {
|
||||
//重置
|
||||
this.auncelList.forEach(i => {
|
||||
i.weightData = ''
|
||||
i.weightUnit = ''
|
||||
i.weightStable = 0
|
||||
i.controlRealName = ''
|
||||
i.isConnected = 0
|
||||
})
|
||||
})
|
||||
},
|
||||
onHide() {
|
||||
console.log('onHide')
|
||||
//移除监听websocket返回来的数据
|
||||
uni.$off('deviceData')
|
||||
uni.$off('deviceStatus')
|
||||
uni.$off('connClose')
|
||||
},
|
||||
methods: {
|
||||
getPageData() {
|
||||
//显示loading
|
||||
uni.showLoading({
|
||||
title: '加载中...'
|
||||
})
|
||||
//获取计量点数量
|
||||
this.$u.api
|
||||
.getDeviceLaboratoryListBy({
|
||||
deviceType: 'auncel',
|
||||
pageNo: 0,
|
||||
pageSize: -1,
|
||||
status: '1',
|
||||
isEnable: '1'
|
||||
})
|
||||
.then(res => {
|
||||
let dataList = res.result.records
|
||||
dataList.forEach(i => {
|
||||
i.weightData = ''
|
||||
i.weightUnit = ''
|
||||
i.isConnected = 0
|
||||
i.weightStable = 0
|
||||
i.temperature = 0
|
||||
i.humidity = 0
|
||||
i.controlRealName = ''
|
||||
})
|
||||
this.auncelList = dataList
|
||||
uni.hideLoading()
|
||||
})
|
||||
.catch(err => {
|
||||
uni.hideLoading()
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
click(index) {
|
||||
// this.$refs.uToast.show({
|
||||
// title: `点击了第${index + 1}宫格`,
|
||||
// type: 'warning'
|
||||
// });
|
||||
console.log(this.auncelList[index])
|
||||
this.currentAuncel = this.auncelList[index]
|
||||
if (this.currentAuncel.isConnected != 1) {
|
||||
this.$helper.showToast({
|
||||
title: '天平设备尚未连接!'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (this.currentAuncel.controlRealName && this.currentAuncel.controlRealName != this.userInfo.real_name) {
|
||||
this.$helper.showToast({
|
||||
title: '当前天平正被“' + this.currentAuncel.controlRealName + '”使用,请选择其他天平!'
|
||||
})
|
||||
return
|
||||
}
|
||||
//发送控制请求
|
||||
let controlDevice = {
|
||||
msgId: this.currentAuncel.id,
|
||||
cmd: 'controlDevice',
|
||||
clientType: 'caaClient',
|
||||
data: {
|
||||
deviceId: this.currentAuncel.id,
|
||||
isControl: true,
|
||||
controlRealName: this.userInfo.real_name
|
||||
}
|
||||
}
|
||||
//发送控制数据
|
||||
this.$measure.send(JSON.stringify(controlDevice))
|
||||
uni.redirectTo({
|
||||
url:
|
||||
'/pages/auncel/auncel-weigh?currentTaskNo=' +
|
||||
this.currentTaskNo +
|
||||
'¤tTaskType=' +
|
||||
this.currentTaskType +
|
||||
'¤tAuncelId=' +
|
||||
this.currentAuncel.id +
|
||||
'¤tAuncelName=' +
|
||||
this.currentAuncel.name +
|
||||
'¤tAuncelCode=' +
|
||||
this.currentAuncel.code
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.weight {
|
||||
width: 180px;
|
||||
height: 40px;
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.weight-data {
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
color: #4cd964;
|
||||
text-align: right;
|
||||
line-height: 40px;
|
||||
letter-spacing: 2px;
|
||||
font-size: 32px;
|
||||
font-family: zzjc-lcd;
|
||||
}
|
||||
.weight-data-yellow {
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
color: #ffff00;
|
||||
text-align: right;
|
||||
line-height: 40px;
|
||||
letter-spacing: 2px;
|
||||
font-size: 32px;
|
||||
font-family: zzjc-lcd;
|
||||
}
|
||||
.weight-data-warning {
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
color: #ff3333;
|
||||
text-align: right;
|
||||
line-height: 40px;
|
||||
font-size: 32px;
|
||||
font-family: zzjc-lcd;
|
||||
}
|
||||
.weight-unit {
|
||||
color: #ffffff;
|
||||
font-size: 24px;
|
||||
line-height: 40px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
</style>
|
||||
229
pages/analysis/auncel/auncel-status.vue
Normal file
229
pages/analysis/auncel/auncel-status.vue
Normal file
@@ -0,0 +1,229 @@
|
||||
<template>
|
||||
<view>
|
||||
<navbar-back title="天平状态"></navbar-back>
|
||||
<up-grid border :col="3">
|
||||
<up-grid-item v-for="(auncel, index) in auncelList" :index="index" :key="index">
|
||||
<view
|
||||
class="auncel-item"
|
||||
:style="{
|
||||
backgroundImage: `url(${require('@/static/images/auncel.png')})`
|
||||
}"
|
||||
>
|
||||
<view class="auncel-header">
|
||||
<view class="auncel-code">{{ auncel.code }}</view>
|
||||
<view class="auncel-name">{{ auncel.controlRealName }}</view>
|
||||
</view>
|
||||
<view class="weight">
|
||||
<view
|
||||
:class="{
|
||||
'weight-data-yellow': auncel.weightStable === 0,
|
||||
'weight-data': auncel.weightStable === 1,
|
||||
'weight-data-warning': auncel.weightStable === 2
|
||||
}"
|
||||
>
|
||||
{{ auncel.weightData || '' }}
|
||||
</view>
|
||||
<view class="weight-unit">{{ auncel.weightUnit }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</up-grid-item>
|
||||
</up-grid>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { onUnload, onHide } from '@dcloudio/uni-app'
|
||||
import { getTenantId } from '@/defaultBaseUrl'
|
||||
import nx from '@/nx'
|
||||
|
||||
// refs
|
||||
const auncelList = ref([])
|
||||
|
||||
// computed
|
||||
const userInfo = computed(() => nx.$store('user').userInfo)
|
||||
|
||||
// 页面加载
|
||||
onMounted(() => {
|
||||
// getPageData()
|
||||
// #ifdef H5
|
||||
const regData = {
|
||||
msgId: nx.$helper.uuid(),
|
||||
cmd: 'register',
|
||||
clientType: 'caaClient',
|
||||
data: {
|
||||
userId: userInfo.value.id,
|
||||
tenantId: getTenantId(),
|
||||
userRealName: userInfo.value.realname
|
||||
}
|
||||
}
|
||||
nx.$measure.setRegData(JSON.stringify(regData))
|
||||
nx.$measure.reOpen()
|
||||
// #endif
|
||||
|
||||
// 监听 WebSocket 数据
|
||||
uni.$on('deviceData', handleDeviceData)
|
||||
uni.$on('deviceStatus', handleDeviceStatus)
|
||||
uni.$on('connClose', handleConnClose)
|
||||
})
|
||||
onHide(() => {
|
||||
// #ifdef APP-PLUS
|
||||
cleanup()
|
||||
// #endif
|
||||
})
|
||||
onUnmounted(() => {
|
||||
// #ifdef H5
|
||||
cleanup()
|
||||
// #endif
|
||||
})
|
||||
|
||||
function cleanup() {
|
||||
uni.$off('deviceData', handleDeviceData)
|
||||
uni.$off('deviceStatus', handleDeviceStatus)
|
||||
uni.$off('connClose', handleConnClose)
|
||||
}
|
||||
|
||||
// 获取数据
|
||||
function getPageData() {
|
||||
nx.$api.laboratory
|
||||
.getDeviceLaboratoryListBy({
|
||||
deviceType: 'auncel',
|
||||
status: '1',
|
||||
isEnable: '1',
|
||||
pageNo: 0,
|
||||
pageSize: -1
|
||||
})
|
||||
.then(res => {
|
||||
const dataList = res.records || []
|
||||
dataList.forEach(i => {
|
||||
i.weightData = ''
|
||||
i.weightUnit = ''
|
||||
i.isConnected = 0
|
||||
i.weightStable = 0
|
||||
i.temperature = 0
|
||||
i.humidity = 0
|
||||
i.controlRealName = ''
|
||||
})
|
||||
auncelList.value = dataList
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('获取天平列表失败', err)
|
||||
})
|
||||
}
|
||||
|
||||
// WebSocket 事件处理器
|
||||
function handleDeviceData(res) {
|
||||
if (res.deviceType !== 'auncel') return
|
||||
auncelList.value = auncelList.value.map(item => {
|
||||
if (item.id === res.deviceId) {
|
||||
return {
|
||||
...item,
|
||||
weightData: res.weightData,
|
||||
weightUnit: res.weightUnit,
|
||||
weightStable: res.weightStable,
|
||||
isConnected: 1,
|
||||
controlRealName: res.controlRealName
|
||||
}
|
||||
}
|
||||
return item
|
||||
})
|
||||
}
|
||||
|
||||
function handleDeviceStatus(res) {
|
||||
auncelList.value = auncelList.value.map(item => {
|
||||
if (item.id === res.deviceId) {
|
||||
const updated = { ...item, isConnected: res.connected }
|
||||
if (res.connected === 0) {
|
||||
updated.weightData = '天平断开'
|
||||
updated.weightUnit = ''
|
||||
updated.weightStable = 0
|
||||
}
|
||||
return updated
|
||||
}
|
||||
return item
|
||||
})
|
||||
}
|
||||
|
||||
function handleConnClose() {
|
||||
auncelList.value = auncelList.value.map(i => ({
|
||||
...i,
|
||||
weightData: '',
|
||||
weightUnit: '',
|
||||
weightStable: 0,
|
||||
controlRealName: '',
|
||||
isConnected: 0
|
||||
}))
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.auncel-item {
|
||||
height: 180px;
|
||||
width: 180px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.auncel-header {
|
||||
height: 100px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.auncel-code {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.auncel-name {
|
||||
margin-top: 5px;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.weight {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.weight-data,
|
||||
.weight-data-yellow,
|
||||
.weight-data-warning {
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
text-align: right;
|
||||
line-height: 40px;
|
||||
letter-spacing: 2px;
|
||||
font-size: 32px;
|
||||
font-family: zzjc-lcd;
|
||||
}
|
||||
|
||||
.weight-data {
|
||||
color: #4cd964;
|
||||
}
|
||||
|
||||
.weight-data-yellow {
|
||||
color: #ffff00;
|
||||
}
|
||||
|
||||
.weight-data-warning {
|
||||
color: #ff3333;
|
||||
}
|
||||
|
||||
.weight-unit {
|
||||
color: #ffffff;
|
||||
font-size: 24px;
|
||||
line-height: 40px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
</style>
|
||||
839
pages/analysis/auncel/auncel-weigh.vue
Normal file
839
pages/analysis/auncel/auncel-weigh.vue
Normal file
@@ -0,0 +1,839 @@
|
||||
<template>
|
||||
<view>
|
||||
<u-navbar
|
||||
title-color="#fff"
|
||||
title-width="360"
|
||||
back-icon-color="#ffffff"
|
||||
:back-text-style="{ color: '#fff' }"
|
||||
back-text="返回"
|
||||
title="样品称重"
|
||||
:border-bottom="false"
|
||||
:custom-back="customBack"
|
||||
:background="{ 'background-color': '#0055A2' }"
|
||||
></u-navbar>
|
||||
|
||||
<u-row class="content-title" gutter="16">
|
||||
<u-col span="3">
|
||||
<view class="content-title-name">
|
||||
<text>待称重样品</text>
|
||||
</view>
|
||||
<u-gap height="10" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
<u-col span="6">
|
||||
<view class="content-title-name">
|
||||
<text>{{ currentAuncel.code === '' ? '电子天平' : currentAuncel.code }}</text>
|
||||
</view>
|
||||
<u-gap height="10" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
<u-col span="3">
|
||||
<view class="content-title-name">
|
||||
<text>已称重样品</text>
|
||||
</view>
|
||||
<u-gap height="10" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
</u-row>
|
||||
|
||||
<u-row gutter="16" class="content-main-height" align="top">
|
||||
<u-col span="3">
|
||||
<scroll-view scroll-y scroll-with-animation class="content-main-left" :scroll-top="scrollTop">
|
||||
<view
|
||||
v-for="(sample, index) in notWeighSampleList"
|
||||
:key="index"
|
||||
class="u-tab-item"
|
||||
:class="[current == index ? 'u-tab-item-active' : '']"
|
||||
:data-current="index"
|
||||
@tap.stop="swichSample(index)"
|
||||
>
|
||||
<u-row gutter="20" style="width: 100%">
|
||||
<u-col span="3" style="padding: 0rpx">
|
||||
<view>
|
||||
<text>【{{ sample.sort }}】</text>
|
||||
</view>
|
||||
</u-col>
|
||||
<u-col span="9">
|
||||
<view>
|
||||
<text>{{ sample.sampleCode }}</text>
|
||||
</view>
|
||||
<view style="padding-top: 20rpx">
|
||||
<text>{{ sample.dataSourceType | getDataSourceTypeShow }}{{ sample.goodsName }}</text>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="content-main-left-operation">
|
||||
<u-row>
|
||||
<u-col span="2"></u-col>
|
||||
<u-col span="8">
|
||||
<view>
|
||||
<view style="padding: 20rpx; text-align: right">
|
||||
<text style="font-size: 30rpx; height: 50rpx">顺序称重:</text>
|
||||
<u-switch
|
||||
v-model="orderWeighChecked"
|
||||
active-color="#19be6b"
|
||||
inactive-color="#eee"
|
||||
@change="orderWeighChange"
|
||||
></u-switch>
|
||||
</view>
|
||||
</view>
|
||||
</u-col>
|
||||
<u-col span="2"></u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</u-col>
|
||||
<u-col span="6">
|
||||
<view class="content-main-height">
|
||||
<view class="auncel-container">
|
||||
<view class="auncel">
|
||||
<view class="auncel-title">
|
||||
<view style="padding-top: 40rpx; height: 100rpx; width: 100%; text-align: center">
|
||||
<text style="font-size: 44rpx; font-weight: 300"
|
||||
>【{{ currentSample.sort }}】 {{ currentSample.dataSourceType | getDataSourceTypeShow }}</text
|
||||
>
|
||||
</view>
|
||||
|
||||
<view style="padding-top: 30rpx; height: 100rpx; width: 100%; text-align: center">
|
||||
<text style="font-size: 44rpx; font-weight: 300">{{ currentSample.sampleCode }}</text>
|
||||
</view>
|
||||
<view
|
||||
style="
|
||||
padding-top: 20rpx;
|
||||
padding-left: 140rpx;
|
||||
padding-right: 140rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-content: center;
|
||||
"
|
||||
>
|
||||
<block v-if="currentSample.dataSourceType">
|
||||
<u-row v-if="currentSample.dataSourceType == 2 || currentSample.dataSourceType == 3">
|
||||
<u-col span="1"></u-col>
|
||||
<u-col span="3">
|
||||
<u-input
|
||||
style="color: #3b4144; background-color: #ffffff"
|
||||
v-model="currentCupNum"
|
||||
type="number"
|
||||
border="border"
|
||||
:disabled="checkCupNumReadonly"
|
||||
placeholder="杯号"
|
||||
/>
|
||||
</u-col>
|
||||
<u-col span="2">
|
||||
<text style="width: 100%; text-align: left">号杯</text>
|
||||
</u-col>
|
||||
<u-col span="4">
|
||||
<u-input
|
||||
style="color: #3b4144; background-color: #ffffff"
|
||||
v-model="currentSample.remarks"
|
||||
type="number"
|
||||
border="border"
|
||||
placeholder="样重比例"
|
||||
/>
|
||||
</u-col>
|
||||
<u-col span="2">
|
||||
<text style="width: 100%; text-align: left">%</text>
|
||||
</u-col>
|
||||
</u-row>
|
||||
<u-row v-else>
|
||||
<u-col span="2"></u-col>
|
||||
<u-col span="7">
|
||||
<u-input
|
||||
style="color: #3b4144; background-color: #ffffff"
|
||||
v-model="currentCupNum"
|
||||
type="number"
|
||||
border="border"
|
||||
:disabled="checkCupNumReadonly"
|
||||
placeholder="杯号"
|
||||
/>
|
||||
</u-col>
|
||||
<u-col span="3">
|
||||
<text style="width: 100%; text-align: left">号杯</text>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="auncel-weight">
|
||||
<view class="weight">
|
||||
<view
|
||||
:class="
|
||||
currentAuncel.weightStable == 0
|
||||
? 'weight-data-yellow'
|
||||
: currentAuncel.weightStable == 1
|
||||
? 'weight-data'
|
||||
: 'weight-data-warning'
|
||||
"
|
||||
@click="selectAuncel"
|
||||
>
|
||||
{{ currentAuncel.weightData }}
|
||||
</view>
|
||||
<view class="weight-unit">{{ currentAuncel.weightUnit }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<view style="padding: 0rpx 60rpx 10rpx 60rpx">
|
||||
<block v-if="currentAuncel.code !== ''">
|
||||
<u-button
|
||||
style="height: 140rpx; font-size: 80rpx"
|
||||
type="success"
|
||||
:disabled="confirmWeightDisabled"
|
||||
shape="circle"
|
||||
@click="confirm"
|
||||
>确认采集</u-button
|
||||
>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</u-col>
|
||||
<u-col span="3">
|
||||
<view class="content-main-height">
|
||||
<scroll-view scroll-y scroll-with-animation class="content-main-right" :scroll-top="scrollTop">
|
||||
<view
|
||||
v-for="(sample, index) in finishWeighSampleList"
|
||||
:key="index"
|
||||
class="u-tab-item"
|
||||
style="height: 240rpx"
|
||||
>
|
||||
<u-row gutter="20" style="width: 100%">
|
||||
<u-col span="3" style="padding: 0rpx">
|
||||
<view>
|
||||
<text>【{{ sample.sort }}】</text>
|
||||
</view>
|
||||
<view style="padding-top: 20rpx">
|
||||
<text>{{ sample.cupNum }}号杯</text>
|
||||
</view>
|
||||
<view v-if="sample.remarks" style="padding-top: 20rpx">
|
||||
<text>{{ sample.remarks }}</text>
|
||||
</view>
|
||||
</u-col>
|
||||
<u-col span="9">
|
||||
<view>
|
||||
<text>{{ sample.sampleCode }}</text>
|
||||
</view>
|
||||
<view style="padding-top: 20rpx">
|
||||
<text>{{ sample.dataSourceType | getDataSourceTypeShow }}{{ sample.goodsName }}</text>
|
||||
</view>
|
||||
<view style="padding-top: 20rpx">
|
||||
<text style="padding-left: 20rpx">{{ sample.sampleWeight }} g</text>
|
||||
<u-button style="margin-left: 20rpx" size="mini" type="error" @click="weighRevoke(sample.id)"
|
||||
>撤销</u-button
|
||||
>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="content-main-right-operation">
|
||||
<u-row>
|
||||
<u-col span="2"></u-col>
|
||||
<u-col span="8">
|
||||
<u-button
|
||||
:disabled="finishWeighSampleList.length == 0"
|
||||
class="btn-operation"
|
||||
type="success"
|
||||
@click="submit"
|
||||
>立即提交</u-button
|
||||
>
|
||||
</u-col>
|
||||
<u-col span="2"></u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
scrollTop: 0, //tab标题的滚动条位置
|
||||
current: 0, // 预设当前项的值
|
||||
menuHeight: 0, // 左边菜单的高度
|
||||
menuItemHeight: 0, // 左边菜单item的高度
|
||||
orderWeighChecked: true, //顺序称重
|
||||
weightDataIsToZero: false, //重量数据是否归零
|
||||
currentCupNum: '',
|
||||
currentSample: {}, //当前样品
|
||||
currentTaskNo: '', //当前任务样品
|
||||
currentTaskType: '', //当前任务类型
|
||||
currentAuncel: {
|
||||
id: '',
|
||||
name: '',
|
||||
code: '',
|
||||
weightStable: 0,
|
||||
weightData: '请选天平',
|
||||
weightUnit: ''
|
||||
},
|
||||
allWeighSampleCount: 0,
|
||||
notWeighSampleList: [],
|
||||
finishWeighSampleList: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
confirmWeightDisabled() {
|
||||
if (
|
||||
this.currentSample.sampleCode &&
|
||||
this.currentAuncel.weightStable == 1 &&
|
||||
Number(this.currentAuncel.weightData) > 0
|
||||
) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
checkCupNumReadonly() {
|
||||
if (!this.currentAuncel || this.currentAuncel.id == '') return true
|
||||
return false
|
||||
}
|
||||
},
|
||||
onLoad(param) {
|
||||
//console.log(param);
|
||||
if (param.currentTaskNo) {
|
||||
this.currentTaskNo = param.currentTaskNo
|
||||
this.currentTaskType = param.currentTaskType
|
||||
}
|
||||
if (param.currentAuncelId) {
|
||||
this.currentAuncel.id = param.currentAuncelId
|
||||
this.currentAuncel.weightData = ''
|
||||
}
|
||||
if (param.currentAuncelName) {
|
||||
this.currentAuncel.name = param.currentAuncelName
|
||||
}
|
||||
if (param.currentAuncelCode) {
|
||||
this.currentAuncel.code = param.currentAuncelCode
|
||||
}
|
||||
this.getAssayTaskDetail(this.currentTaskNo)
|
||||
},
|
||||
onShow() {
|
||||
console.log('onShow')
|
||||
|
||||
//注册websocket
|
||||
let regData = {
|
||||
msgId: this.$helper.uuid(),
|
||||
cmd: 'register',
|
||||
clientType: 'caaClient',
|
||||
data: {
|
||||
userId: this.userInfo.user_id,
|
||||
tenantId: this.userInfo.tenant_id,
|
||||
userRealName: this.userInfo.real_name
|
||||
}
|
||||
}
|
||||
this.$measure.setRegData(JSON.stringify(regData))
|
||||
this.$measure.reOpen()
|
||||
|
||||
//监听websocket返回来的数据
|
||||
//设备数据
|
||||
uni.$on('deviceData', res => {
|
||||
switch (res.deviceType) {
|
||||
case 'auncel':
|
||||
//console.log(res);
|
||||
if (this.currentAuncel.id === res.deviceId) {
|
||||
this.currentAuncel.weightData = res.weightData
|
||||
this.currentAuncel.weightUnit = res.weightUnit
|
||||
this.currentAuncel.weightStable = res.weightStable
|
||||
this.currentAuncel.isConnected = 1
|
||||
if (Number(res.weightData) == 0) {
|
||||
this.weightDataIsToZero = true
|
||||
}
|
||||
}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
//设备状态
|
||||
uni.$on('deviceStatus', res => {
|
||||
if (this.currentAuncel.id === res.deviceId) {
|
||||
console.log(res)
|
||||
if (res.connected == 0) {
|
||||
this.currentAuncel.weightStable = 0
|
||||
this.currentAuncel.weightData = '天平断开'
|
||||
this.currentAuncel.weightUnit = ''
|
||||
}
|
||||
}
|
||||
this.currentAuncel.isConnected = res.connected
|
||||
})
|
||||
//控制设备状态
|
||||
uni.$on('controlDevice', res => {
|
||||
if (this.currentAuncel.id === res.deviceId) {
|
||||
console.log(res)
|
||||
|
||||
this.currentAuncel.id = ''
|
||||
this.currentAuncel.name = ''
|
||||
this.currentAuncel.code = ''
|
||||
this.currentAuncel.weightStable = 0
|
||||
this.currentAuncel.weightData = '请选天平'
|
||||
this.currentAuncel.weightUnit = ''
|
||||
}
|
||||
})
|
||||
//连接断开
|
||||
uni.$on('connClose', res => {
|
||||
//重置
|
||||
this.currentAuncel.weightData = ''
|
||||
this.currentAuncel.weightUnit = ''
|
||||
this.currentAuncel.weightStable = 0
|
||||
this.currentAuncel.controlUserName = ''
|
||||
this.currentAuncel.isConnected = 0
|
||||
})
|
||||
},
|
||||
onHide() {
|
||||
console.log('onHide')
|
||||
//移除监听websocket返回来的数据
|
||||
uni.$off('deviceData')
|
||||
uni.$off('deviceStatus')
|
||||
uni.$off('controlDevice')
|
||||
uni.$off('connClose')
|
||||
},
|
||||
onUnload() {
|
||||
//取消控制
|
||||
//发送控制请求
|
||||
let controlDevice = {
|
||||
msgId: this.currentAuncel.id,
|
||||
cmd: 'controlDevice',
|
||||
clientType: 'caaClient',
|
||||
data: {
|
||||
deviceId: this.currentAuncel.id,
|
||||
isControl: false,
|
||||
controlRealName: this.userInfo.username
|
||||
}
|
||||
}
|
||||
//发送控制数据
|
||||
this.$measure.send(JSON.stringify(controlDevice))
|
||||
},
|
||||
methods: {
|
||||
//返回上一页
|
||||
customBack() {
|
||||
uni.redirectTo({
|
||||
url: '/pages/sample/sample-weigh'
|
||||
})
|
||||
},
|
||||
//切换样品
|
||||
async swichSample(index) {
|
||||
if (index == this.current) return
|
||||
if (this.orderWeighChecked) return //顺序称重不允许选中
|
||||
this.current = index
|
||||
// 如果为0,意味着尚未初始化
|
||||
if (this.menuHeight == 0 || this.menuItemHeight == 0) {
|
||||
await this.getElRect('menu-scroll-view', 'menuHeight')
|
||||
await this.getElRect('u-tab-item', 'menuItemHeight')
|
||||
}
|
||||
// 将菜单菜单活动item垂直居中
|
||||
this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2
|
||||
this.currentSample = this.notWeighSampleList[index]
|
||||
},
|
||||
// 获取一个目标元素的高度
|
||||
getElRect(elClass, dataVal) {
|
||||
new Promise((resolve, reject) => {
|
||||
const query = uni.createSelectorQuery().in(this)
|
||||
query
|
||||
.select('.' + elClass)
|
||||
.fields({ size: true }, res => {
|
||||
// 如果节点尚未生成,res值为null,循环调用执行
|
||||
if (!res) {
|
||||
setTimeout(() => {
|
||||
this.getElRect(elClass)
|
||||
}, 10)
|
||||
return
|
||||
}
|
||||
this[dataVal] = res.height
|
||||
})
|
||||
.exec()
|
||||
})
|
||||
},
|
||||
confirm() {
|
||||
//保存数据
|
||||
if (!this.weightDataIsToZero) {
|
||||
this.$helper.showToast({
|
||||
title: '天平必须先回零!'
|
||||
})
|
||||
return
|
||||
}
|
||||
//获取当前重量
|
||||
let weight = this.currentAuncel.weightData
|
||||
//获取当前样品
|
||||
let sample = this.notWeighSampleList[this.current]
|
||||
//判断杯号
|
||||
if (this.currentCupNum == null || typeof this.currentCupNum == 'undefined') this.currentCupNum = ''
|
||||
if (this.currentCupNum === '') {
|
||||
this.$helper.showToast({
|
||||
title: '杯号不允许为空!'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (this.current < this.notWeighSampleList.length - 1) {
|
||||
this.currentSample = this.notWeighSampleList[this.current + 1]
|
||||
}
|
||||
//杯号
|
||||
sample.cupNum = this.currentCupNum
|
||||
//删除当前样品
|
||||
this.notWeighSampleList.splice(this.current, 1)
|
||||
//样品重量赋值
|
||||
sample.sampleWeight = weight
|
||||
//天平编号赋值
|
||||
sample.auncelNo = this.currentAuncel.code
|
||||
if (sample.remarks) {
|
||||
sample.remarks = sample.remarks + '%'
|
||||
}
|
||||
this.$u.api
|
||||
.auncelWeigh(sample)
|
||||
.then(res => {
|
||||
//this.finishWeighSampleList.push(sample);
|
||||
//确认采集重量后,归零设为false
|
||||
this.weightDataIsToZero = false
|
||||
this.getAssayTaskDetail(this.currentTaskNo)
|
||||
if (this.orderWeighChecked) {
|
||||
this.current = 0
|
||||
} else {
|
||||
this.current = -1
|
||||
this.currentSample = {}
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
this.showLoading = false
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
submit() {
|
||||
if (this.notWeighSampleList.length != 0) {
|
||||
this.$helper.showToast({
|
||||
title: '当前任务“' + this.currentTaskNo + '”尚未完成称重!'
|
||||
})
|
||||
return
|
||||
}
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确定提交数据?',
|
||||
cancelColor: '#0055A2',
|
||||
confirmColor: '#0055A2',
|
||||
success: res => {
|
||||
if (res.cancel) {
|
||||
console.log('用户点击取消')
|
||||
return
|
||||
}
|
||||
//显示loading
|
||||
uni.showLoading({
|
||||
title: '正在提交...'
|
||||
})
|
||||
this.$u.api
|
||||
.weighBatchSubmitByTaskNo(this.currentTaskNo)
|
||||
.then(res => {
|
||||
this.$helper.showToast({
|
||||
title: '提交成功!'
|
||||
})
|
||||
uni.redirectTo({
|
||||
url: '/pages/sample/sample-weigh'
|
||||
})
|
||||
uni.hideLoading()
|
||||
})
|
||||
.catch(err => {
|
||||
uni.hideLoading()
|
||||
this.$helper.showToast({
|
||||
title: '提交失败!'
|
||||
})
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
})
|
||||
/**
|
||||
if(this.currentTaskType == 4) { //临时样
|
||||
let ids = [];
|
||||
this.finishWeighSampleList.forEach(item => {
|
||||
ids.push(item.id);
|
||||
});
|
||||
|
||||
this.$u.api
|
||||
.weighBatchSubmitByIds(ids.join(","))
|
||||
.then(res => {
|
||||
this.$helper.showToast({
|
||||
title: '提交成功!'
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
this.showLoading = false;
|
||||
console.log(err);
|
||||
});
|
||||
} else {//其他批量秤完提交
|
||||
//if(this.allWeighSampleCount == this.finishWeighSampleList.length) {
|
||||
console.log(this.notWeighSampleList)
|
||||
if(this.notWeighSampleList.length == 0) {
|
||||
this.$u.api
|
||||
.weighBatchSubmitByTaskNo(this.currentTaskNo)
|
||||
.then(res => {
|
||||
this.$helper.showToast({
|
||||
title: '提交成功!'
|
||||
});
|
||||
uni.redirectTo({
|
||||
url: '/pages/sample/sample-weigh'
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
this.showLoading = false;
|
||||
console.log(err);
|
||||
});
|
||||
} else {
|
||||
this.$helper.showToast({
|
||||
title: '当前任务“'+this.currentTaskNo+'”尚未完成称重!'
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
**/
|
||||
},
|
||||
weighRevoke(id) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确定撤销当前数据?',
|
||||
cancelColor: '#0055A2',
|
||||
confirmColor: '#0055A2',
|
||||
success: res => {
|
||||
if (!res.confirm) {
|
||||
console.log('用户点击取消')
|
||||
return
|
||||
}
|
||||
this.$u.api
|
||||
.auncelWeighRevoke(id)
|
||||
.then(res => {
|
||||
this.getAssayTaskDetail(this.currentTaskNo)
|
||||
if (this.orderWeighChecked) {
|
||||
this.current = 0
|
||||
} else {
|
||||
this.current = -1
|
||||
this.currentSample = {}
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
this.showLoading = false
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
//自动生成杯号(仅顺序称重):第一杯:手填,后续杯 = 上一杯 + 1
|
||||
autoGenerateCupNum() {
|
||||
if (!this.orderWeighChecked) return
|
||||
//取上一杯
|
||||
this.currentCupNum = ''
|
||||
let preSample = null
|
||||
if (this.finishWeighSampleList && this.finishWeighSampleList.length > 0) preSample = this.finishWeighSampleList[0]
|
||||
if (preSample == null) {
|
||||
return
|
||||
}
|
||||
const cupNum = preSample.cupNum
|
||||
if (!isNaN(cupNum)) this.currentCupNum = Number(cupNum) + 1
|
||||
},
|
||||
getAssayTaskDetail(taskNo) {
|
||||
this.notWeighSampleList = []
|
||||
this.finishWeighSampleList = []
|
||||
this.$u.api
|
||||
.getAssayTaskDetailListByTaskNo({ taskNo: taskNo })
|
||||
.then(res => {
|
||||
let dataList = res.result
|
||||
this.allWeighSampleCount = dataList.length
|
||||
dataList.forEach((item, index) => {
|
||||
if (item.weightSubmitStatus == 0) {
|
||||
this.notWeighSampleList.push(item)
|
||||
} else if (item.weightSubmitStatus == 1) {
|
||||
this.finishWeighSampleList.unshift(item)
|
||||
//this.finishWeighSampleList.push(item);
|
||||
}
|
||||
})
|
||||
this.showLoading = false
|
||||
//console.log(this.currentSample);
|
||||
if (this.notWeighSampleList[0]) {
|
||||
if (this.orderWeighChecked) {
|
||||
this.current = 0
|
||||
this.currentSample = this.notWeighSampleList[0]
|
||||
} else {
|
||||
this.current = -1
|
||||
this.currentSample = {}
|
||||
}
|
||||
}
|
||||
this.autoGenerateCupNum() //计算生成当前杯号
|
||||
})
|
||||
.catch(err => {
|
||||
this.showLoading = false
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
selectAuncel() {
|
||||
if (this.currentAuncel.weightData === '请选天平') {
|
||||
uni.navigateTo({
|
||||
url:
|
||||
'/pages/auncel/auncel-select?currentTaskNo=' +
|
||||
this.currentTaskNo +
|
||||
'¤tTaskType=' +
|
||||
this.currentTaskType
|
||||
})
|
||||
}
|
||||
},
|
||||
orderWeighChange(e) {
|
||||
if (e && this.notWeighSampleList.length > 0) {
|
||||
//this.current = 0;
|
||||
//this.currentSample = this.notWeighSampleList[0];
|
||||
this.getAssayTaskDetail(this.currentTaskNo)
|
||||
return
|
||||
}
|
||||
this.current = -1
|
||||
this.currentSample = {}
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
getDataSourceTypeShow(val) {
|
||||
if (val == 2) return '【筛上】'
|
||||
if (val == 3) return '【筛下】'
|
||||
return ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.content-title {
|
||||
height: 110rpx;
|
||||
width: 100%;
|
||||
font-size: 46rpx;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.content-title-name {
|
||||
padding: 20rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content-main-height {
|
||||
height: calc(100vh - 250rpx);
|
||||
}
|
||||
|
||||
.content-main-left {
|
||||
height: calc(100vh - 410rpx);
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
|
||||
.u-tab-item {
|
||||
height: 160rpx;
|
||||
background: #f6f6f6;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 36rpx;
|
||||
color: #444;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
border-width: 4rpx;
|
||||
border-bottom: dotted;
|
||||
}
|
||||
|
||||
.u-tab-item-active {
|
||||
position: relative;
|
||||
color: #0055a2;
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.u-tab-item-active::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
|
||||
height: 32rpx;
|
||||
left: 0;
|
||||
top: 39rpx;
|
||||
}
|
||||
|
||||
.content-main-left-operation {
|
||||
height: 160rpx;
|
||||
padding-top: 30rpx;
|
||||
}
|
||||
|
||||
.content-main-right {
|
||||
height: calc(100vh - 410rpx);
|
||||
}
|
||||
|
||||
.content-main-right-operation {
|
||||
height: 160rpx;
|
||||
padding-top: 30rpx;
|
||||
}
|
||||
|
||||
.btn-operation {
|
||||
height: 100rpx;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
|
||||
.auncel-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.auncel {
|
||||
width: 800rpx;
|
||||
height: 800rpx;
|
||||
background-image: url(../../static/images/auncel.png);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.auncel-title {
|
||||
width: 100%;
|
||||
height: 420rpx;
|
||||
}
|
||||
|
||||
.auncel-weight {
|
||||
padding: 40rpx;
|
||||
}
|
||||
|
||||
.weight {
|
||||
width: 100%;
|
||||
min-width: 200px;
|
||||
height: 200rpx;
|
||||
padding: 0 30rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
//background-color: #2c405a;
|
||||
}
|
||||
|
||||
.weight-data {
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
color: #4cd964;
|
||||
text-align: right;
|
||||
line-height: 200rpx;
|
||||
letter-spacing: 4rpx;
|
||||
font-size: 150rpx;
|
||||
font-family: zzjc-lcd;
|
||||
}
|
||||
|
||||
.weight-data-yellow {
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
color: #ffff00;
|
||||
text-align: right;
|
||||
line-height: 200rpx;
|
||||
letter-spacing: 4rpx;
|
||||
font-size: 150rpx;
|
||||
font-family: zzjc-lcd;
|
||||
}
|
||||
|
||||
.weight-data-warning {
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
color: #ff3333;
|
||||
text-align: right;
|
||||
line-height: 200rpx;
|
||||
font-size: 150rpx;
|
||||
font-family: zzjc-lcd;
|
||||
}
|
||||
|
||||
.weight-unit {
|
||||
color: #ffffff;
|
||||
font-size: 130rpx;
|
||||
line-height: 200rpx;
|
||||
padding-left: 20rpx;
|
||||
}
|
||||
</style>
|
||||
105
pages/analysis/index/index.vue
Normal file
105
pages/analysis/index/index.vue
Normal file
@@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<view>
|
||||
<navbar-back title="检斤检化验系统" :autoBack="false" leftIcon="" :leftText="`您好!${userInfo.nickname}`">
|
||||
<u-icon @click="popupShow = true" size="28" color="#FFF" name="account-fill" />
|
||||
</navbar-back>
|
||||
|
||||
<up-grid :col="gridCol" :border="false">
|
||||
<up-grid-item class="mb20 mt20" v-for="item in menuItemList" :key="item.url" @click="goTo(item.url)">
|
||||
<u-icon :name="item.otherConf.icon" color="#0055A2" size="80" />
|
||||
<view class="grid-text">{{ item.name }}</view>
|
||||
</up-grid-item>
|
||||
</up-grid>
|
||||
|
||||
<mePopup :show="popupShow" @update:show="val => (popupShow = val)" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import nx from '@/nx'
|
||||
import { useGridCol } from '@/nx/hooks/useGridCol'
|
||||
import mePopup from '@/pages/index/me-popup.vue'
|
||||
|
||||
// 响应式数据
|
||||
const popupShow = ref(false)
|
||||
const isAllowAgainPrint = ref(false)
|
||||
|
||||
const menuItemList = ref([
|
||||
{ url: '/pages/analysis/sample/sample-receive', otherConf: { icon: 'arrow-downward' }, name: '收样' },
|
||||
{ url: '/pages/analysis/sample/sample-work-list', otherConf: { icon: 'edit-pen-fill' }, name: '样品分析' },
|
||||
{ url: '/pages/analysis/sample/sample-report', otherConf: { icon: 'arrow-upward' }, name: '数据上报' },
|
||||
{ url: '/pages/analysis/sample/sample-report-search', otherConf: { icon: 'search' }, name: '待审数据' },
|
||||
{ url: '/pages/analysis/sample/sample-print', otherConf: { icon: 'file-text-fill' }, name: '单据补打' },
|
||||
{ url: '/pages/analysis/setting/setting', otherConf: { icon: 'setting-fill' }, name: '系统设置' }
|
||||
])
|
||||
|
||||
// 计算属性
|
||||
const userInfo = computed(() => nx.$store('user').userInfo)
|
||||
|
||||
// 方法
|
||||
const goTo = url => {
|
||||
nx.$router.go(url)
|
||||
}
|
||||
|
||||
const checkAllowAgainPrint = () => {
|
||||
const param = {
|
||||
userId: userInfo.value.id,
|
||||
clientId: 'auncel'
|
||||
}
|
||||
nx.$api.user.getAppPermission(param).then(res => {
|
||||
if (!res.success) return
|
||||
const ret = res.result || []
|
||||
if (ret.length === 0) return
|
||||
for (let i = 0; i < ret.length; i++) {
|
||||
if (ret[i].roleValue && ret[i].roleValue === 2) {
|
||||
isAllowAgainPrint.value = true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const openLaboratoryWs = () => {
|
||||
const regData = {
|
||||
msgId: nx.$helper.uuid(),
|
||||
cmd: 'register',
|
||||
clientType: 'caaClient',
|
||||
data: {
|
||||
userId: userInfo.value.id,
|
||||
tenantId: userInfo.value.loginTenantId,
|
||||
userRealName: userInfo.value.realname
|
||||
}
|
||||
}
|
||||
nx.$measure.setRegData(JSON.stringify(regData))
|
||||
nx.$measure.open()
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
// checkAllowAgainPrint()
|
||||
// openLaboratoryWs()
|
||||
})
|
||||
// 动态设置 grid 列数
|
||||
const { gridCol } = useGridCol([400], [2, 3])
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.title_content {
|
||||
text-align: center;
|
||||
padding-top: 75px;
|
||||
letter-spacing: 10px;
|
||||
width: 100%;
|
||||
font-size: 36px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.banner {
|
||||
overflow: hidden;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.grid-text {
|
||||
font-size: 24px;
|
||||
}
|
||||
</style>
|
||||
583
pages/analysis/index/index2.vue
Normal file
583
pages/analysis/index/index2.vue
Normal file
@@ -0,0 +1,583 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<u-navbar
|
||||
title="化学分析天平"
|
||||
:is-back="false"
|
||||
:border-bottom="false"
|
||||
title-color="#fff"
|
||||
:background="{ 'background-image': 'linear-gradient(45deg, rgb(54, 138, 217), rgb(64, 160, 255))' }"
|
||||
></u-navbar>
|
||||
<view style="text-align: center"><u-loading mode="flower" :show="showLoading" size="48"></u-loading></view>
|
||||
<view class="container">
|
||||
<view class="auncel" v-for="(item, index) in deviceLaboratoryList" :key="item.id">
|
||||
<view class="title">
|
||||
<u-row style="width: 100%; padding-bottom: 18rpx" gutter="16">
|
||||
<u-col span="8">
|
||||
<text class="measurePointName"
|
||||
>{{ item.name }} {{ item.controlUserName ? '[' + item.controlUserName + ']远程控制' : '' }}</text
|
||||
>
|
||||
</u-col>
|
||||
<u-col span="4">
|
||||
<!--
|
||||
<view style="width: 100%; display: flex; flex-direction: row; justify-content: flex-end;">
|
||||
<text class="measurePointName" >{{item.isAutoWork ? '自动计量' : '集控接管'}}</text>
|
||||
<u-icon style="padding: 0 20rpx;" name="file-text" label-pos="bottom" color="#2979ff" size="40" @click="goto(item.measurePointId)"></u-icon>
|
||||
<u-icon style="padding: 0 20rpx;" name="setting" label-pos="bottom" label="设置" color="#2979ff" size="40" @click="goto(item.measurePointId)"></u-icon>
|
||||
</view>
|
||||
-->
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
<view :class="item.isConnected == 1 ? 'title-line-green' : 'title-line-gray'"></view>
|
||||
<view class="weight-container">
|
||||
<!-- <view class="infrared-container">
|
||||
<view :class="item.infraredLeft == 0 ? 'infrared-line-gray' : item.infraredLeft == 1 ? 'infrared-line-green':'infrared-line-red'"></view>
|
||||
</view>
|
||||
-->
|
||||
<block v-if="item.deviceType == 'auncel'">
|
||||
<view class="weight">
|
||||
<view
|
||||
:class="
|
||||
item.weightStable == 0
|
||||
? 'weight-data-yellow'
|
||||
: item.weightStable == 1
|
||||
? 'weight-data'
|
||||
: 'weight-data-warning'
|
||||
"
|
||||
>
|
||||
{{ item.weightData }}
|
||||
</view>
|
||||
<view class="weight-unit">{{ item.weightUnit }}</view>
|
||||
</view>
|
||||
</block>
|
||||
<block v-if="item.deviceType == 'temp'">
|
||||
<view class="temp">
|
||||
<view class="charts-box"
|
||||
><qiun-data-charts
|
||||
type="gauge"
|
||||
:opts="temperatureOpts"
|
||||
:chartData="temperatureChartData"
|
||||
background="none"
|
||||
/></view>
|
||||
<view class="charts-box"
|
||||
><qiun-data-charts type="gauge" :opts="humidityOpts" :chartData="humidityChartData" background="none"
|
||||
/></view>
|
||||
</view>
|
||||
</block>
|
||||
<!--
|
||||
<view class="infrared-container">
|
||||
<view :class="item.infraredRight == 0 ? 'infrared-line-gray' : item.infraredRight == 1 ? 'infrared-line-green':'infrared-line-red'"></view>
|
||||
</view>
|
||||
-->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
showLoading: false,
|
||||
runLogMaxLength: 8,
|
||||
deviceLaboratoryList: [],
|
||||
temperatureOpts: {},
|
||||
temperatureChartData: {
|
||||
categories: [
|
||||
{
|
||||
value: 0.2,
|
||||
color: '#1890ff'
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
color: '#2fc25b'
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '温度',
|
||||
data: 0.66
|
||||
}
|
||||
]
|
||||
},
|
||||
humidityOpts: {},
|
||||
humidityChartData: {
|
||||
categories: [
|
||||
{
|
||||
value: 1,
|
||||
color: '#1890ff'
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '湿度',
|
||||
data: 0.66
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
//获取数据
|
||||
this.getPageData()
|
||||
|
||||
//监听websocket返回来的数据
|
||||
//设备数据
|
||||
uni.$on('deviceData', res => {
|
||||
switch (res.deviceType) {
|
||||
case 'weighbridge':
|
||||
this.mearsuPointList.forEach((item, index) => {
|
||||
if (item.measurePointId === res.measurePointId) {
|
||||
//item.weightData = (index + Number(res.deviceValue)).toFixed(2) + " "+ res.deviceUnit;
|
||||
item.weightData = res.deviceValue
|
||||
item.weightUnit = res.deviceUnit
|
||||
item.weightStable = res.deviceStable
|
||||
item.measureIsConnected = 1
|
||||
item.isAutoWork = res.isAutoWork
|
||||
}
|
||||
})
|
||||
break
|
||||
case 'auncel':
|
||||
this.deviceLaboratoryList.forEach((item, index) => {
|
||||
if (item.id === res.deviceId) {
|
||||
//item.weightData = (index + Number(res.deviceValue)).toFixed(2) + " "+ res.deviceUnit;
|
||||
item.weightData = res.weightData
|
||||
item.weightUnit = res.weightUnit
|
||||
item.weightStable = 1
|
||||
item.isConnected = 1
|
||||
}
|
||||
})
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
// this.weight = res.weighbridge;
|
||||
// this.infraredLeft = res.infrared;
|
||||
// this.infraredRight = res.infrared;
|
||||
})
|
||||
|
||||
//设备状态
|
||||
uni.$on('deviceStatus', res => {
|
||||
this.mearsuPointList.forEach((item, index) => {
|
||||
if (item.measurePointId === res.measurePointId) {
|
||||
item.devices.forEach((d, i) => {
|
||||
if (d.id === res.deviceId) {
|
||||
d.isConnected = res.connected
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
//日志数据
|
||||
uni.$on('logData', res => {
|
||||
this.mearsuPointList.forEach((item, index) => {
|
||||
if (item.measurePointId === res.measurePointId) {
|
||||
if (item.runLogs.length >= this.runLogMaxLength) {
|
||||
//删除并返回数组的第一个元素
|
||||
//item.runLogs.shift();
|
||||
//删除并返回数组的最后一个元素
|
||||
item.runLogs.pop()
|
||||
}
|
||||
//向数组的末尾添加
|
||||
//item.runLogs.push(res);
|
||||
//向数组的开头添
|
||||
item.runLogs.unshift(res)
|
||||
|
||||
//滚动
|
||||
// this.$nextTick(function() {
|
||||
// item.scrollTop = 20*item.runLogs.length;
|
||||
// });
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
//监听控制
|
||||
uni.$on('controlMeasurePoint', res => {
|
||||
console.log(res)
|
||||
let data = res.data
|
||||
this.mearsuPointList.forEach(i => {
|
||||
if (i.measurePointId === data.measurePointId) {
|
||||
if (data.success && data.isControl) {
|
||||
i.controlUserName = data.controlUserName
|
||||
} else {
|
||||
i.controlUserName = ''
|
||||
}
|
||||
console.log(i)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
//计量点状态
|
||||
uni.$on('measurePointStatus', res => {
|
||||
//断开
|
||||
this.mearsuPointList.forEach(i => {
|
||||
if (i.measurePointId === res.measurePointId) {
|
||||
if (res.measureIsConnected != 1) {
|
||||
i.weightData = ''
|
||||
i.weightUnit = ''
|
||||
i.weightStable = 0
|
||||
i.infraredLeft = 0
|
||||
i.infraredRight = 0
|
||||
i.measureIsConnected = 0
|
||||
if (i.runLogs.length >= this.runLogMaxLength) {
|
||||
i.runLogs.pop()
|
||||
}
|
||||
i.runLogs.unshift({
|
||||
id: this.$helper.uuid(),
|
||||
content: '计量点连接断开!',
|
||||
measurePointId: i.measurePointId,
|
||||
time: this.$helper.dateFormat(new Date(), 'yy-MM-dd hh:mm:ss')
|
||||
})
|
||||
i.devices.forEach(d => {
|
||||
d.isConnected = 0
|
||||
})
|
||||
} else {
|
||||
i.measureIsConnected = 1
|
||||
/* if(i.runLogs.length >= 8) {
|
||||
i.runLogs.shift();
|
||||
}
|
||||
i.runLogs.push({
|
||||
id: this.$helper.uuid(),
|
||||
content: "计量点连接成功!",
|
||||
measurePointId: i.measurePointId,
|
||||
time: this.$helper.dateFormat(new Date(), "yy-MM-dd hh:mm:ss")
|
||||
}); */
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
//连接断开
|
||||
uni.$on('connClose', res => {
|
||||
//重置
|
||||
this.mearsuPointList.forEach(i => {
|
||||
i.weightData = ''
|
||||
i.weightUnit = ''
|
||||
i.weightStable = 0
|
||||
i.controlUserName = ''
|
||||
i.measureIsConnected = 0
|
||||
if (i.runLogs.length >= this.runLogMaxLength) {
|
||||
i.runLogs.pop()
|
||||
}
|
||||
let lastLog = i.runLogs[i.runLogs.length - 1]
|
||||
if (lastLog && lastLog.content !== '控制中心连接断开!') {
|
||||
i.runLogs.unshift({
|
||||
id: this.$helper.uuid(),
|
||||
content: '控制中心连接断开!',
|
||||
measurePointId: i.measurePointId,
|
||||
time: this.$helper.dateFormat(new Date(), 'yy-MM-dd hh:mm:ss')
|
||||
})
|
||||
}
|
||||
i.devices.forEach(d => {
|
||||
d.isConnected = 0
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
onUnload() {
|
||||
//移除监听websocket返回来的数据
|
||||
uni.$off('deviceData')
|
||||
uni.$off('deviceStatus')
|
||||
uni.$off('logData')
|
||||
uni.$off('controlMeasurePoint')
|
||||
|
||||
uni.$off('measurePointStatus')
|
||||
uni.$off('connClose')
|
||||
},
|
||||
filters: {
|
||||
numFilter(value) {
|
||||
// 截取当前数据到小数点后两位
|
||||
let realVal = value.toFixed(2)
|
||||
return realVal
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
methods: {
|
||||
getPageData() {
|
||||
//显示loading
|
||||
this.showLoading = true
|
||||
//获取计量点数量
|
||||
this.$u.api
|
||||
.getDeviceLaboratoryListBy()
|
||||
.then(res => {
|
||||
let dataList = res.data
|
||||
dataList.forEach(i => {
|
||||
i.weightData = ''
|
||||
i.weightUnit = ''
|
||||
i.isConnected = 0
|
||||
i.weightStable = 0
|
||||
i.temperature = 0
|
||||
i.humidity = 0
|
||||
i.controlUserName = ''
|
||||
})
|
||||
this.deviceLaboratoryList = dataList
|
||||
this.showLoading = false
|
||||
|
||||
//打开websocket
|
||||
this.openLaboratoryWs()
|
||||
|
||||
//发送检查计量点控制情况
|
||||
let checkControl = {
|
||||
msgId: this.$helper.uuid(),
|
||||
cmd: 'checkControl',
|
||||
clientType: 'consoleClient'
|
||||
}
|
||||
if (this.$measure.isOpen) {
|
||||
this.$measure.send(JSON.stringify(checkControl))
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
this.showLoading = false
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
openLaboratoryWs() {
|
||||
//注册websocket
|
||||
let regData = {
|
||||
msgId: this.$helper.uuid(),
|
||||
cmd: 'register',
|
||||
clientType: 'caaClient',
|
||||
data: {
|
||||
userId: this.userInfo.user_id,
|
||||
tenantId: this.userInfo.tenant_id,
|
||||
userRealName: this.userInfo.real_name
|
||||
}
|
||||
}
|
||||
this.$measure.setRegData(JSON.stringify(regData))
|
||||
this.$measure.open()
|
||||
},
|
||||
scroll(e) {
|
||||
// console.log(e);
|
||||
// this.mearsuPointList.forEach((i) => {
|
||||
// if(i.measurepointid === e.currentTarget.dataset.measurepointid) {
|
||||
// i.oldScrollTop = e.detail.scrollTop;
|
||||
// }
|
||||
// });
|
||||
},
|
||||
goto(measurePointId) {
|
||||
uni.reLaunch({
|
||||
url: '/pages/measure/measure?measurePointId=' + measurePointId
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
/* #ifdef H5 */
|
||||
.auncel {
|
||||
width: 31.33%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 20rpx;
|
||||
margin: 1%;
|
||||
border-radius: 24rpx;
|
||||
box-shadow: 1px 1px 10px #909399;
|
||||
}
|
||||
@media only screen and (max-width: 1200px) {
|
||||
.auncel {
|
||||
width: 48%;
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 600px) {
|
||||
.auncel {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
/* #endif */
|
||||
/* #ifndef H5 */
|
||||
.auncel {
|
||||
width: 98%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 20rpx;
|
||||
margin: 1%;
|
||||
border-radius: 24rpx;
|
||||
box-shadow: 1px 1px 10px #909399;
|
||||
}
|
||||
/* #endif */
|
||||
.title-line-gray {
|
||||
width: 100%;
|
||||
height: 6rpx;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: rgb(128, 134, 149);
|
||||
border-radius: 4rpx 4rpx 0 0;
|
||||
}
|
||||
.title-line-green {
|
||||
width: 100%;
|
||||
height: 6rpx;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: rgb(27, 201, 142);
|
||||
border-radius: 4rpx 4rpx 0 0;
|
||||
}
|
||||
.title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
.temp {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
.charts-box {
|
||||
width: 50%;
|
||||
height: 200px;
|
||||
}
|
||||
.measurePointName {
|
||||
font-size: 30rpx;
|
||||
}
|
||||
.weight-container {
|
||||
padding: 10rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.infrared-container {
|
||||
width: 30%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.infrared-line-green {
|
||||
width: 8rpx;
|
||||
height: 90rpx;
|
||||
background-color: #18b566;
|
||||
}
|
||||
.infrared-line-red {
|
||||
width: 8rpx;
|
||||
height: 90rpx;
|
||||
background-color: #ff3333;
|
||||
}
|
||||
.infrared-line-gray {
|
||||
width: 8rpx;
|
||||
height: 90rpx;
|
||||
background-color: #909399;
|
||||
}
|
||||
.infrared-left {
|
||||
width: 8rpx;
|
||||
height: 90rpx;
|
||||
background-color: #18b566;
|
||||
}
|
||||
.infrared-left-warning {
|
||||
width: 8rpx;
|
||||
height: 90rpx;
|
||||
background-color: #ff3333;
|
||||
}
|
||||
.weight {
|
||||
width: 100%;
|
||||
min-width: 200px;
|
||||
height: 90rpx;
|
||||
padding: 0 8rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: #2c405a;
|
||||
}
|
||||
.weight-data {
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
color: #4cd964;
|
||||
text-align: right;
|
||||
line-height: 90rpx;
|
||||
letter-spacing: 4rpx;
|
||||
font-size: 90rpx;
|
||||
font-family: zzjc-lcd;
|
||||
}
|
||||
.weight-data-yellow {
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
color: #ffff00;
|
||||
text-align: right;
|
||||
line-height: 90rpx;
|
||||
letter-spacing: 4rpx;
|
||||
font-size: 90rpx;
|
||||
font-family: zzjc-lcd;
|
||||
}
|
||||
.weight-data-warning {
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
color: #ff3333;
|
||||
text-align: right;
|
||||
line-height: 90rpx;
|
||||
font-size: 90rpx;
|
||||
font-family: zzjc-lcd;
|
||||
}
|
||||
.weight-unit {
|
||||
color: #ffffff;
|
||||
font-size: 60rpx;
|
||||
line-height: 90rpx;
|
||||
padding-left: 20rpx;
|
||||
}
|
||||
.infrared-right {
|
||||
width: 8rpx;
|
||||
height: 90rpx;
|
||||
background-color: #18b566;
|
||||
}
|
||||
.infrared-right-warning {
|
||||
width: 8rpx;
|
||||
height: 90rpx;
|
||||
background-color: #ff3333;
|
||||
}
|
||||
.device-container {
|
||||
padding: 20rpx;
|
||||
width: 100%;
|
||||
height: 200rpx;
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.device {
|
||||
width: 25%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.device-icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
background-color: #ff3333;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.device-icon-green {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
background-color: #18b566;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.device-icon-gray {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
background-color: rgb(128, 134, 149);
|
||||
border-radius: 50%;
|
||||
}
|
||||
.device-icon-red {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
background-color: #ff3333;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.run-log {
|
||||
width: 100%;
|
||||
padding: 10rpx 20rpx;
|
||||
height: 400rpx;
|
||||
background-color: #ecf5ff;
|
||||
border-radius: 24rpx;
|
||||
--box-shadow: 1px 1px 10px #909399;
|
||||
}
|
||||
.log-content {
|
||||
font-size: 28rpx;
|
||||
font-weight: 200;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
</style>
|
||||
143
pages/analysis/sample/pdf-preview.vue
Normal file
143
pages/analysis/sample/pdf-preview.vue
Normal file
@@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<view>
|
||||
<navbar-back title="任务单预览"></navbar-back>
|
||||
<view></view>
|
||||
<!-- #ifdef H5 -->
|
||||
<web-view :src="pdfUrlH5"></web-view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { onLoad, onHide, onUnload } from '@dcloudio/uni-app'
|
||||
import { getBaseUrl } from '@/defaultBaseUrl'
|
||||
import nx from '@/nx'
|
||||
|
||||
// 响应式数据
|
||||
const taskId = ref('')
|
||||
const localFilePath = ref('')
|
||||
const reportKey = ref('')
|
||||
const hideResultFlag = ref('')
|
||||
const viewerUrl = '/hybrid/html/web/viewer.html?file='
|
||||
const pdfUrlH5 = ref('')
|
||||
|
||||
let wv = null // 计划创建的 webview
|
||||
|
||||
// 方法:下载 PDF
|
||||
const downloadPdf = (pdfUrl, retryCount = 0) => {
|
||||
const MAX_RETRY = 3 // 最多重试 3 次
|
||||
return new Promise(resolve => {
|
||||
if (retryCount >= MAX_RETRY) {
|
||||
console.error('PDF 下载失败:超过最大重试次数')
|
||||
return resolve(null)
|
||||
}
|
||||
|
||||
uni.downloadFile({
|
||||
url: pdfUrl,
|
||||
success: res => {
|
||||
if (res.statusCode !== 200) {
|
||||
console.warn(`下载失败,状态码: ${res.statusCode},重试第 ${retryCount + 1} 次`)
|
||||
return resolve(downloadPdf(pdfUrl, retryCount + 1))
|
||||
}
|
||||
|
||||
const tempFilePath = res.tempFilePath
|
||||
uni.getFileInfo({
|
||||
filePath: tempFilePath,
|
||||
success: fileInfo => {
|
||||
if (fileInfo.size > 0) {
|
||||
resolve(tempFilePath)
|
||||
} else {
|
||||
console.warn('文件为空,重试中...')
|
||||
resolve(downloadPdf(pdfUrl, retryCount + 1))
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
console.warn('获取文件信息失败,重试中...')
|
||||
resolve(downloadPdf(pdfUrl, retryCount + 1))
|
||||
}
|
||||
})
|
||||
},
|
||||
fail: () => {
|
||||
console.warn('网络请求失败,重试中...')
|
||||
resolve(downloadPdf(pdfUrl, retryCount + 1))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 方法:Android 加载 PDF
|
||||
const loadPdfOnAndroid = async pdfUrl => {
|
||||
const tempFilePath = await downloadPdf(pdfUrl)
|
||||
if (!tempFilePath) return
|
||||
const localPath = plus.io.convertLocalFileSystemURL(tempFilePath)
|
||||
localFilePath.value = localPath
|
||||
const allUrl = viewerUrl + encodeURIComponent(localPath)
|
||||
// 创建并加载 webview
|
||||
wv = plus.webview.create('', 'custom-webview', {
|
||||
top: uni.getSystemInfoSync().statusBarHeight + 44,
|
||||
bottom: 0
|
||||
})
|
||||
wv.loadURL(allUrl)
|
||||
const currentWebview = getCurrentPages().pop().$getAppWebview()
|
||||
currentWebview.append(wv)
|
||||
}
|
||||
|
||||
// 获取 PDF 预览 URL
|
||||
const getPdf = async () => {
|
||||
const printBaseUrl = getBaseUrl()
|
||||
const baseUrl = getBaseUrl()
|
||||
let dataUrl = `${baseUrl}/qms/bus/qmsBusAssayTask/getAssayTaskDataWithDetailData?taskId=${taskId.value}`
|
||||
dataUrl += `&hideResultFlag=${hideResultFlag.value}`
|
||||
const token = nx.$store('user').token
|
||||
let url = `${printBaseUrl}/report/gridpp/report/previewDocs`
|
||||
url += `?token=${token}`
|
||||
url += `&type=PDF`
|
||||
url += `&reportKey=${reportKey.value}`
|
||||
url += `&dataUrl=${encodeURIComponent(dataUrl)}`
|
||||
|
||||
// #ifdef H5
|
||||
pdfUrlH5.value = viewerUrl + encodeURIComponent(url)
|
||||
// #endif
|
||||
|
||||
// #ifndef H5
|
||||
await loadPdfOnAndroid(url)
|
||||
// #endif
|
||||
}
|
||||
|
||||
// 删除临时文件
|
||||
const deleteTmpFile = () => {
|
||||
if (!localFilePath.value) return
|
||||
const dir = localFilePath.value.substring(0, localFilePath.value.lastIndexOf('/'))
|
||||
plus.io.resolveLocalFileSystemURL(
|
||||
dir,
|
||||
entry => {
|
||||
entry.removeRecursively(
|
||||
() => console.log('删除成功'),
|
||||
e => console.log('删除失败:' + e.message)
|
||||
)
|
||||
},
|
||||
e => console.log('目录不存在:' + e.message)
|
||||
)
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
onLoad(param => {
|
||||
if (param.taskId) {
|
||||
taskId.value = param.taskId
|
||||
reportKey.value = param.reportKey
|
||||
hideResultFlag.value = param.hideResultFlag
|
||||
}
|
||||
getPdf()
|
||||
})
|
||||
|
||||
onHide(() => {
|
||||
deleteTmpFile()
|
||||
})
|
||||
|
||||
onUnload(() => {
|
||||
deleteTmpFile()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
237
pages/analysis/sample/sample-look.vue
Normal file
237
pages/analysis/sample/sample-look.vue
Normal file
@@ -0,0 +1,237 @@
|
||||
<template>
|
||||
<view>
|
||||
<navbar-back :autoBack="false" title="任 务 单" @leftClick="customBack"></navbar-back>
|
||||
<u-row class="content-title" gutter="16">
|
||||
<u-col span="4">
|
||||
<view class="content-title-name">
|
||||
<text>任务列表</text>
|
||||
</view>
|
||||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
<u-col span="8">
|
||||
<view class="content-title-name">
|
||||
<text>样品列表</text>
|
||||
</view>
|
||||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
</u-row>
|
||||
<u-row class="content-main-height" gutter="16" align="top">
|
||||
<u-col span="4">
|
||||
<scroll-view
|
||||
scroll-y
|
||||
scroll-with-animation
|
||||
class="content-main-height content-main-left"
|
||||
:scroll-top="scrollTop"
|
||||
>
|
||||
<view
|
||||
v-for="(task, index) in taskList"
|
||||
:key="index"
|
||||
class="u-tab-item"
|
||||
:class="[current == index ? 'u-tab-item-active' : '']"
|
||||
:data-current="index"
|
||||
@tap.stop="swichTask(index)"
|
||||
>
|
||||
<u-row style="width: 100%">
|
||||
<u-col span="2" style="text-align: center">
|
||||
<u-icon name="tags-fill" size="34"></u-icon>
|
||||
</u-col>
|
||||
<u-col span="10">
|
||||
<view>
|
||||
<text style="font-size: 42rpx">{{ task.taskNo }}</text>
|
||||
</view>
|
||||
<view style="margin-top: 20rpx">
|
||||
<text>{{ task.taskName }}</text>
|
||||
</view>
|
||||
<view class="x-f" style="margin-top: 20rpx">
|
||||
<u-icon color="" name="clock"></u-icon>
|
||||
<text style="margin-left: 10rpx">{{ task.taskOperTime }}</text>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</u-col>
|
||||
<u-col span="8">
|
||||
<view class="content-main-height">
|
||||
<scroll-view scroll-y scroll-with-animation class="content-main-height">
|
||||
<block v-for="(sample, index) in sampleList" :key="index">
|
||||
<view
|
||||
v-if="index == 0 || (index > 0 && sampleList[index].sort != sampleList[index - 1].sort)"
|
||||
style="padding: 10rpx; font-size: 36rpx"
|
||||
>
|
||||
<u-row>
|
||||
<u-col span="2" style="text-align: center">
|
||||
<view>
|
||||
<text>【{{ sample.sort }}】</text>
|
||||
</view>
|
||||
</u-col>
|
||||
<u-col span="10">
|
||||
<view>
|
||||
<text style="padding-left: 20rpx">{{ sample.sampleCode }}</text>
|
||||
</view>
|
||||
<view>
|
||||
<text style="padding-left: 20rpx">{{ sample.sampleName }}</text>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
<u-line style="padding: 10rpx" color="#bbb" />
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
scrollTop: 0, //tab标题的滚动条位置
|
||||
current: 0, // 预设当前项的值
|
||||
menuHeight: 0, // 左边菜单的高度
|
||||
menuItemHeight: 0, // 左边菜单item的高度
|
||||
taskList: [],
|
||||
sampleList: []
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
//获取任务列表
|
||||
this.getAssayTask()
|
||||
},
|
||||
methods: {
|
||||
//返回首页
|
||||
customBack() {
|
||||
uni.reLaunch({
|
||||
url: '/pages/analysis/index/index'
|
||||
})
|
||||
},
|
||||
//切换任务
|
||||
async swichTask(index) {
|
||||
if (index == this.current) return
|
||||
this.current = index
|
||||
// 如果为0,意味着尚未初始化
|
||||
if (this.menuHeight == 0 || this.menuItemHeight == 0) {
|
||||
await this.getElRect('menu-scroll-view', 'menuHeight')
|
||||
await this.getElRect('u-tab-item', 'menuItemHeight')
|
||||
}
|
||||
// 将菜单菜单活动item垂直居中
|
||||
this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2
|
||||
|
||||
//获取任务详情
|
||||
this.getAssayTaskDetail(this.taskList[index].taskNo)
|
||||
},
|
||||
// 获取一个目标元素的高度
|
||||
getElRect(elClass, dataVal) {
|
||||
new Promise((resolve, reject) => {
|
||||
const query = uni.createSelectorQuery().in(this)
|
||||
query
|
||||
.select('.' + elClass)
|
||||
.fields({ size: true }, res => {
|
||||
// 如果节点尚未生成,res值为null,循环调用执行
|
||||
if (!res) {
|
||||
setTimeout(() => {
|
||||
this.getElRect(elClass)
|
||||
}, 10)
|
||||
return
|
||||
}
|
||||
this[dataVal] = res.height
|
||||
})
|
||||
.exec()
|
||||
})
|
||||
},
|
||||
getAssayTask() {
|
||||
//显示loading
|
||||
uni.showLoading({
|
||||
title: '加载中...'
|
||||
})
|
||||
const param = {
|
||||
assayOper: this.userInfo.realname,
|
||||
operateType: 'task'
|
||||
}
|
||||
this.$u.api
|
||||
.getAssayTaskList(param)
|
||||
.then(res => {
|
||||
this.taskList = res.result
|
||||
if (this.taskList && this.taskList.length > 0) {
|
||||
this.getAssayTaskDetail(this.taskList[0].taskNo)
|
||||
} else {
|
||||
uni.hideLoading()
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
uni.hideLoading()
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
getAssayTaskDetail(taskNo) {
|
||||
this.$u.api
|
||||
.getAssayTaskDetailListByTaskNo({ taskNo: taskNo })
|
||||
.then(res => {
|
||||
this.sampleList = res.result
|
||||
uni.hideLoading()
|
||||
})
|
||||
.catch(err => {
|
||||
uni.hideLoading()
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content-title {
|
||||
height: 110rpx;
|
||||
width: 100%;
|
||||
font-size: 46rpx;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.content-title-name {
|
||||
padding: 20rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content-main-height {
|
||||
height: calc(100vh - 250rpx);
|
||||
}
|
||||
|
||||
.content-main-left {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
|
||||
.u-tab-item {
|
||||
padding: 10rpx;
|
||||
height: 200rpx;
|
||||
background: #f6f6f6;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 36rpx;
|
||||
color: #444;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
border-width: 4rpx;
|
||||
border-bottom: dotted;
|
||||
}
|
||||
|
||||
.u-tab-item-active {
|
||||
position: relative;
|
||||
color: #0055a2;
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.u-tab-item-active::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
|
||||
height: 32rpx;
|
||||
left: 0;
|
||||
top: 39rpx;
|
||||
}
|
||||
</style>
|
||||
318
pages/analysis/sample/sample-print.vue
Normal file
318
pages/analysis/sample/sample-print.vue
Normal file
@@ -0,0 +1,318 @@
|
||||
<template>
|
||||
<view>
|
||||
<navbar-back :autoBack="false" title="单据补打" @leftClick="customBack"></navbar-back>
|
||||
|
||||
<u-row class="content-title" gutter="16">
|
||||
<u-col span="4">
|
||||
<view class="content-title-name">
|
||||
<text>任务列表</text>
|
||||
</view>
|
||||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
<u-col span="8">
|
||||
<view class="content-title-name">
|
||||
<text>样品列表</text>
|
||||
</view>
|
||||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
</u-row>
|
||||
|
||||
<u-row class="content-main-height" gutter="16" align="top">
|
||||
<!-- 左侧任务列表 -->
|
||||
<u-col span="4">
|
||||
<scroll-view
|
||||
scroll-y
|
||||
scroll-with-animation
|
||||
class="content-main-height content-main-left"
|
||||
:scroll-top="scrollTop"
|
||||
ref="menuScrollView"
|
||||
>
|
||||
<view
|
||||
v-for="(task, index) in taskList"
|
||||
:key="index"
|
||||
class="u-tab-item"
|
||||
:class="{ 'u-tab-item-active': current === index }"
|
||||
@tap.stop="switchTask(index)"
|
||||
>
|
||||
<u-row style="width: 100%">
|
||||
<u-col span="2" style="text-align: center">
|
||||
<u-icon :color="taskStyle(task)" name="tags-fill" size="34"></u-icon>
|
||||
</u-col>
|
||||
<u-col span="10">
|
||||
<view>
|
||||
<text style="font-size: 18px">{{ task.taskNo }}</text>
|
||||
</view>
|
||||
<view style="margin-top: 10px">
|
||||
<text>{{ task.taskName }} {{ task.assayOper }}</text>
|
||||
</view>
|
||||
<view class="x-f" style="margin-top: 10px">
|
||||
<u-icon name="clock"></u-icon>
|
||||
<text style="margin-left: 5px">{{ task.taskOperTime }}</text>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</u-col>
|
||||
|
||||
<!-- 右侧样品列表 -->
|
||||
<u-col span="8">
|
||||
<view class="content-main-height">
|
||||
<scroll-view scroll-y scroll-with-animation class="content-main-right">
|
||||
<block v-for="(sample, index) in sampleList" :key="index">
|
||||
<view style="padding: 5px; font-size: 16px">
|
||||
<u-row>
|
||||
<u-col span="2" style="text-align: center">
|
||||
<view>
|
||||
<text>【{{ sample.sort }}】</text>
|
||||
</view>
|
||||
</u-col>
|
||||
<u-col span="5">
|
||||
<view>
|
||||
<text style="padding-left: 10px">{{ sample.sampleCode }}</text>
|
||||
</view>
|
||||
<view>
|
||||
<text style="padding-left: 10px">{{ sample.sampleName }}</text>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
<u-line style="padding: 10rpx" color="#bbb" />
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<view class="content-main-right-operation">
|
||||
<u-row>
|
||||
<u-col span="6"></u-col>
|
||||
<u-col span="3">
|
||||
<u-button class="btn-operation" type="primary" @click="previewPDF" v-if="currentTaskId">
|
||||
预览任务单
|
||||
</u-button>
|
||||
</u-col>
|
||||
<u-col span="3">
|
||||
<u-button class="btn-operation" :disabled="taskList.length <= 0" type="success" @click="printTask">
|
||||
打印任务单
|
||||
</u-button>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import nx from '@/nx'
|
||||
|
||||
// refs
|
||||
const scrollTop = ref(0)
|
||||
const current = ref(0)
|
||||
const menuHeight = ref(0)
|
||||
const menuItemHeight = ref(0)
|
||||
const currentTask = ref({})
|
||||
const currentTaskId = ref('')
|
||||
const currentTaskNo = ref('')
|
||||
const conAssayTask = ref(null)
|
||||
const taskList = ref([])
|
||||
const sampleList = ref([])
|
||||
const menuScrollView = ref(null)
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
getAssayTask()
|
||||
})
|
||||
|
||||
checkPrintConfig()
|
||||
|
||||
// 方法
|
||||
function customBack() {
|
||||
uni.reLaunch({
|
||||
url: '/pages/analysis/index/index'
|
||||
})
|
||||
}
|
||||
|
||||
function taskStyle(task) {
|
||||
return task.weightTaskStatus === 3 ? 'green' : ''
|
||||
}
|
||||
|
||||
// 切换任务
|
||||
async function switchTask(index) {
|
||||
if (index === current.value) return
|
||||
current.value = index
|
||||
|
||||
// 初始化高度
|
||||
if (menuHeight.value === 0 || menuItemHeight.value === 0) {
|
||||
await getElRect('menu-scroll-view', 'menuHeight')
|
||||
await getElRect('.u-tab-item', 'menuItemHeight')
|
||||
}
|
||||
|
||||
// 滚动居中
|
||||
scrollTop.value = index * menuItemHeight.value + menuItemHeight.value / 2 - menuHeight.value / 2
|
||||
|
||||
// 更新当前任务
|
||||
const task = taskList.value[index]
|
||||
currentTask.value = task
|
||||
currentTaskNo.value = task.taskNo
|
||||
currentTaskId.value = task.id
|
||||
getAssayTaskDetail(currentTaskNo.value)
|
||||
}
|
||||
|
||||
// 获取元素尺寸
|
||||
function getElRect(selector, targetRef) {
|
||||
return new Promise(resolve => {
|
||||
const query = uni.createSelectorQuery().in(getCurrentInstance().proxy)
|
||||
query
|
||||
.select(selector)
|
||||
.fields({ size: true }, res => {
|
||||
if (!res) {
|
||||
// 如果未获取到,稍后重试(可选)
|
||||
setTimeout(() => resolve(getElRect(selector, targetRef)), 10)
|
||||
return
|
||||
}
|
||||
if (targetRef === 'menuHeight') {
|
||||
menuHeight.value = res.height
|
||||
} else if (targetRef === 'menuItemHeight') {
|
||||
menuItemHeight.value = res.height
|
||||
}
|
||||
resolve(res)
|
||||
})
|
||||
.exec()
|
||||
})
|
||||
}
|
||||
|
||||
// 获取任务列表
|
||||
function getAssayTask() {
|
||||
const param = {
|
||||
operateType: 'print',
|
||||
finishStatus: 'submited,finished'
|
||||
}
|
||||
|
||||
nx.$api.auncel.getAssayTaskList(param).then(res => {
|
||||
taskList.value = res || []
|
||||
if (taskList.value.length > 0) {
|
||||
const first = taskList.value[0]
|
||||
currentTask.value = first
|
||||
currentTaskNo.value = first.taskNo
|
||||
currentTaskId.value = first.id
|
||||
getAssayTaskDetail(currentTaskNo.value)
|
||||
} else {
|
||||
currentTask.value = {}
|
||||
currentTaskNo.value = ''
|
||||
currentTaskId.value = ''
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 获取任务详情
|
||||
function getAssayTaskDetail(taskNo) {
|
||||
if (!taskNo) return
|
||||
nx.$api.assayTask.getAssayTaskDetailListByTaskNo({ taskNo }).then(res => {
|
||||
sampleList.value = res.result || []
|
||||
if (res.additionalProperties?.conAssayTask) {
|
||||
conAssayTask.value = res.additionalProperties.conAssayTask
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 打印任务
|
||||
function printTask() {
|
||||
const task = currentTask.value
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: `确定补打“${task.taskNo}的原始记录单”?`,
|
||||
cancelColor: '#0055A2',
|
||||
confirmColor: '#0055A2',
|
||||
success: res => {
|
||||
if (res.confirm) {
|
||||
nx.$print.getPrintTemplateAndPrint(currentTask.value)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 预览 PDF
|
||||
function previewPDF() {
|
||||
const url = `/pages/analysis/sample/pdf-preview?taskId=${currentTaskId.value}&reportKey=${conAssayTask.value?.assayTaskTemplateKey}&hideResultFlag=true`
|
||||
uni.navigateTo({ url })
|
||||
}
|
||||
|
||||
// 检查打印服务配置(模拟 onShow)
|
||||
function checkPrintConfig() {
|
||||
const printList = uni.getStorageSync('KEY_PRINT_LIST')
|
||||
if (!printList || printList.length <= 0) {
|
||||
uni.showToast({
|
||||
title: '打印服务未配置,请在系统设置中配置打印服务!',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content-title {
|
||||
height: 50px;
|
||||
width: 100%;
|
||||
font-size: 20px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.content-title-name {
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content-main-height {
|
||||
height: calc(100vh - 125px);
|
||||
}
|
||||
|
||||
.content-main-left {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
|
||||
.u-tab-item {
|
||||
padding: 5px;
|
||||
height: 100px;
|
||||
background: #f6f6f6;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
color: #444;
|
||||
line-height: 1;
|
||||
border-width: 2px;
|
||||
border-bottom: dotted;
|
||||
}
|
||||
|
||||
.u-tab-item-active {
|
||||
position: relative;
|
||||
color: #0055a2;
|
||||
font-weight: 600;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.u-tab-item-active::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
height: 16px;
|
||||
left: 0;
|
||||
top: 20px;
|
||||
}
|
||||
|
||||
.content-main-right {
|
||||
height: calc(100vh - 205px);
|
||||
}
|
||||
|
||||
.content-main-right-operation {
|
||||
height: 80px;
|
||||
padding-top: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.btn-operation {
|
||||
width: 95%;
|
||||
}
|
||||
</style>
|
||||
339
pages/analysis/sample/sample-receive.vue
Normal file
339
pages/analysis/sample/sample-receive.vue
Normal file
@@ -0,0 +1,339 @@
|
||||
<template>
|
||||
<view>
|
||||
<navbar-back :autoBack="false" title="样品分析-收样" @leftClick="customBack"></navbar-back>
|
||||
|
||||
<u-row class="content-title" gutter="16">
|
||||
<u-col span="4">
|
||||
<view class="content-title-name">
|
||||
<text>任务列表</text>
|
||||
</view>
|
||||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
<u-col span="8">
|
||||
<view class="content-title-name">
|
||||
<text>样品列表</text>
|
||||
</view>
|
||||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
</u-row>
|
||||
|
||||
<u-row class="content-main-height" gutter="16" align="top">
|
||||
<!-- 任务列表 -->
|
||||
<u-col span="4">
|
||||
<scroll-view
|
||||
scroll-y
|
||||
scroll-with-animation
|
||||
class="content-main-height content-main-left"
|
||||
:scroll-top="scrollTop"
|
||||
>
|
||||
<view
|
||||
v-for="(task, index) in taskList"
|
||||
:key="index"
|
||||
class="u-tab-item"
|
||||
:class="[current === index ? 'u-tab-item-active' : '']"
|
||||
@tap.stop="switchTask(index)"
|
||||
>
|
||||
<u-row style="width: 100%">
|
||||
<u-col span="2" style="text-align: center">
|
||||
<u-icon :color="taskStyle(task)" name="tags-fill" size="34"></u-icon>
|
||||
</u-col>
|
||||
<u-col span="10">
|
||||
<view class="fs18">{{ task.taskNo }}</view>
|
||||
<view style="margin-top: 10px">{{ task.taskName }}</view>
|
||||
<view class="x-f" style="margin-top: 10px">
|
||||
<u-icon name="clock"></u-icon>
|
||||
<text style="margin-left: 5px">{{ task.taskOperTime }}</text>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</u-col>
|
||||
|
||||
<!-- 样品列表 -->
|
||||
<u-col span="8">
|
||||
<view class="content-main-height">
|
||||
<scroll-view scroll-y scroll-with-animation class="content-main-right">
|
||||
<block v-for="(sample, index) in sampleList" :key="index">
|
||||
<view style="padding: 5px; font-size: 16px">
|
||||
<u-row>
|
||||
<u-col span="3" style="text-align: center">
|
||||
<u-row>
|
||||
<u-col span="6" style="text-align: center">
|
||||
<u-checkbox
|
||||
v-model="sample.checked"
|
||||
v-if="sample.sampleProcessNo === currentNode"
|
||||
@change="selectSample(sample)"
|
||||
></u-checkbox>
|
||||
</u-col>
|
||||
<u-col span="6" style="text-align: center">
|
||||
<text>【{{ sample.sort }}】</text>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</u-col>
|
||||
<u-col span="9" class="sample_desc">
|
||||
<view>
|
||||
<view
|
||||
><text style="padding-left: 10px">{{ sample.sampleCode }}</text></view
|
||||
>
|
||||
<view>
|
||||
<text style="padding-left: 10px">
|
||||
{{ getDataSourceTypeShow(sample.dataSourceType) }}{{ sample.sampleName }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="sample_desc_warn" v-if="sample.sampleProcessNo !== currentNode">
|
||||
当前节点:{{ getProcessNameShow(sample.sampleProcessNo) }}
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
<u-line style="padding: 5px" color="#bbb" />
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
|
||||
<view class="content-main-right-operation">
|
||||
<u-row>
|
||||
<u-col span="8"></u-col>
|
||||
<u-col span="4">
|
||||
<u-button class="btn-operation" :disabled="taskList.length <= 0" type="success" @click="confirmReceipt">
|
||||
确认收样
|
||||
</u-button>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import nx from '@/nx'
|
||||
import { onLoad, onBackPress } from '@dcloudio/uni-app'
|
||||
|
||||
// 响应式数据
|
||||
const currentNode = ref('F30')
|
||||
const scrollTop = ref(0)
|
||||
const current = ref(0)
|
||||
const taskList = ref([])
|
||||
const sampleList = ref([])
|
||||
const dicSampleProcessCodeList = ref([])
|
||||
|
||||
// 计算属性
|
||||
const userInfo = computed(() => nx.$store('user').userInfo)
|
||||
|
||||
// 方法
|
||||
const customBack = () => {
|
||||
uni.reLaunch({ url: '/pages/analysis/index/index' })
|
||||
}
|
||||
|
||||
const selectSample = sample => {
|
||||
sample.checked = !sample.checked
|
||||
}
|
||||
|
||||
const taskStyle = task => {
|
||||
if ((task.weightTaskStatus === 0 || task.weightTaskStatus === 1) && task.reviewCount > 0) {
|
||||
return 'red'
|
||||
}
|
||||
if (task.weightTaskStatus === 2 && task.reviewCount > 0) {
|
||||
return 'green'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
const confirmReceipt = () => {
|
||||
const errNodeList = sampleList.value.filter(item => item.sampleProcessNo !== currentNode.value)
|
||||
if (errNodeList.length > 0) {
|
||||
uni.showToast({
|
||||
title: '存在异常节点,联系管理员处理!',
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const checkedSampleList = sampleList.value.filter(item => item.checked)
|
||||
if (checkedSampleList.length !== sampleList.value.length) {
|
||||
uni.showToast({ title: '样品未全部勾选,请检查!', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确认收样?',
|
||||
cancelColor: '#0055A2',
|
||||
confirmColor: '#0055A2',
|
||||
success: res => {
|
||||
if (res.cancel) return
|
||||
|
||||
const sampleIdList = checkedSampleList.map(item => item.busSubCsampleId)
|
||||
const data = {
|
||||
busAssayTaskId: taskList.value[current.value]?.id,
|
||||
sampleSourceType: 2,
|
||||
sampleProcessNo: currentNode.value,
|
||||
isGenSampleHandover: false,
|
||||
sampleIdList
|
||||
}
|
||||
|
||||
nx.$api.assayTask
|
||||
.execReceiveSample(data)
|
||||
.then(() => {
|
||||
getAssayTask()
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('收样失败:', err)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const switchTask = index => {
|
||||
if (index === current.value) return
|
||||
current.value = index
|
||||
|
||||
const task = taskList.value[index]
|
||||
if (!task) return
|
||||
|
||||
getAssayTaskDetail(task.taskNo)
|
||||
}
|
||||
|
||||
const getAssayTask = () => {
|
||||
const param = {
|
||||
finishStatus: 'waiting_receive',
|
||||
assayOper: userInfo.value.nickname
|
||||
}
|
||||
|
||||
nx.$api.auncel
|
||||
.getAssayTaskList(param)
|
||||
.then(res => {
|
||||
taskList.value = res || []
|
||||
if (taskList.value.length > 0) {
|
||||
current.value = 0
|
||||
getAssayTaskDetail(taskList.value[0].taskNo)
|
||||
} else {
|
||||
sampleList.value = []
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('获取任务列表失败:', err)
|
||||
sampleList.value = []
|
||||
})
|
||||
}
|
||||
|
||||
const getAssayTaskDetail = taskNo => {
|
||||
const param = {
|
||||
taskNo,
|
||||
waiting_receive: '1'
|
||||
}
|
||||
|
||||
nx.$api.assayTask
|
||||
.getAssayTaskDetailListByTaskNo(param)
|
||||
.then(res => {
|
||||
sampleList.value = (res.result || []).map(item => ({ ...item, checked: false }))
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('获取任务详情失败:', err)
|
||||
sampleList.value = []
|
||||
})
|
||||
}
|
||||
|
||||
const getDicSampleProcessCodeList = () => {
|
||||
nx.$api.assayTask.queryQmsDicSampleProcessCodeList().then(res => {
|
||||
dicSampleProcessCodeList.value = res.records || []
|
||||
})
|
||||
}
|
||||
|
||||
const getProcessNameShow = val => {
|
||||
const item = dicSampleProcessCodeList.value.find(i => i.processCode === val)
|
||||
return item ? item.processName : val
|
||||
}
|
||||
|
||||
const getDataSourceTypeShow = val => {
|
||||
if (val === 2) return '【筛上】'
|
||||
if (val === 3) return '【筛下】'
|
||||
return ''
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
onLoad(() => {
|
||||
getDicSampleProcessCodeList()
|
||||
getAssayTask()
|
||||
})
|
||||
|
||||
onBackPress(() => {
|
||||
customBack()
|
||||
return true
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content-title {
|
||||
height: 50px;
|
||||
width: 100%;
|
||||
font-size: 20px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.content-title-name {
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content-main-height {
|
||||
height: calc(100vh - 125px);
|
||||
}
|
||||
|
||||
.content-main-left {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
|
||||
.u-tab-item {
|
||||
padding: 5px;
|
||||
height: 100px;
|
||||
background: #f6f6f6;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
color: #444;
|
||||
line-height: 1;
|
||||
border-bottom: 2px dotted;
|
||||
}
|
||||
|
||||
.u-tab-item-active {
|
||||
position: relative;
|
||||
color: #0055a2;
|
||||
font-weight: 600;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.content-main-right {
|
||||
height: calc(100vh - 205px);
|
||||
}
|
||||
|
||||
.content-main-right-operation {
|
||||
height: 80px;
|
||||
padding-top: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.btn-operation {
|
||||
height: 50px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.sample_desc {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-between !important;
|
||||
padding-right: 15px !important;
|
||||
}
|
||||
|
||||
.sample_desc_warn {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
299
pages/analysis/sample/sample-report-search.vue
Normal file
299
pages/analysis/sample/sample-report-search.vue
Normal file
@@ -0,0 +1,299 @@
|
||||
<template>
|
||||
<view>
|
||||
<navbar-back :autoBack="false" title="审核查询" @leftClick="customBack"></navbar-back>
|
||||
<u-row class="content-title" gutter="16">
|
||||
<u-col span="4">
|
||||
<view class="content-title-name">
|
||||
<text>任务列表</text>
|
||||
</view>
|
||||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
<u-col span="8">
|
||||
<view class="content-title-name">
|
||||
<text>样品列表</text>
|
||||
</view>
|
||||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
</u-row>
|
||||
<u-row class="content-main-height" gutter="16" align="top">
|
||||
<u-col span="4">
|
||||
<scroll-view
|
||||
scroll-y
|
||||
scroll-with-animation
|
||||
class="content-main-height content-main-left"
|
||||
:scroll-top="scrollTop"
|
||||
>
|
||||
<view
|
||||
v-for="(task, index) in taskList"
|
||||
:key="index"
|
||||
class="u-tab-item"
|
||||
:class="[current.value === index ? 'u-tab-item-active' : '']"
|
||||
@tap.stop="swichTask(index)"
|
||||
>
|
||||
<u-row style="width: 100%">
|
||||
<u-col span="2" style="text-align: center">
|
||||
<u-icon :color="taskStyle(task)" name="tags-fill" size="34"></u-icon>
|
||||
</u-col>
|
||||
<u-col span="10">
|
||||
<view>
|
||||
<text style="font-size: 18px">{{ task.taskNo }}</text>
|
||||
</view>
|
||||
<view style="margin-top: 10px">
|
||||
<text>{{ task.taskName }} {{ task.assayOper }}</text>
|
||||
</view>
|
||||
<view class="x-f" style="margin-top: 10px">
|
||||
<u-icon color="" name="clock"></u-icon>
|
||||
<text style="margin-left: 5px">{{ task.reportTime }}</text>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</u-col>
|
||||
<u-col span="8">
|
||||
<view class="content-main-height">
|
||||
<scroll-view scroll-y scroll-with-animation class="content-main-right">
|
||||
<block v-for="(sample, index) in sampleList" :key="index">
|
||||
<view style="padding: 5px; font-size: 16px">
|
||||
<u-row
|
||||
@click="showSampleDetail(sample.id, index)"
|
||||
:class="selectedIndex.value === index ? 'selected_Sample' : ''"
|
||||
>
|
||||
<u-col span="2" style="text-align: center" :style="sampleStyle(sample)">
|
||||
<view>
|
||||
<text>【{{ sample.sort }}】</text>
|
||||
</view>
|
||||
</u-col>
|
||||
<u-col span="5">
|
||||
<view>
|
||||
<text style="padding-left: 10px">{{ sample.sampleCode }}</text>
|
||||
</view>
|
||||
<view>
|
||||
<text style="padding-left: 10px">
|
||||
{{ getDataSourceTypeShow(sample.dataSourceType) }}{{ sample.sampleName }}
|
||||
</text>
|
||||
</view>
|
||||
<view v-if="sample.sampleWeight">
|
||||
<text style="padding-left: 10px">{{ sample.sampleWeight }} g</text>
|
||||
</view>
|
||||
</u-col>
|
||||
<u-col span="5">
|
||||
<view>
|
||||
<text style="padding-left: 10px">{{ sample.remarks }}</text>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
<u-line style="padding: 5px" color="#bbb" />
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
<view class="content-main-right-operation">
|
||||
<u-row>
|
||||
<u-col span="3"></u-col>
|
||||
<u-col span="6">
|
||||
<u-button class="btn-operation" type="primary" @click="previewPDF" v-if="currentTaskId.value">
|
||||
任务单预览
|
||||
</u-button>
|
||||
</u-col>
|
||||
<u-col span="3"> </u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
|
||||
<sample-detail-popup
|
||||
ref="sampleDetailPopup"
|
||||
:showPopup="showDetailPopup"
|
||||
:detailPopupParam="detailPopupParam"
|
||||
></sample-detail-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { onLoad, onBackPress } from '@dcloudio/uni-app'
|
||||
import SampleDetailPopup from '@/components/sample/sample-detail-popup.vue'
|
||||
import nx from '@/nx'
|
||||
|
||||
// 响应式数据
|
||||
const scrollTop = ref(0)
|
||||
const current = ref(0)
|
||||
const currentTask = ref({})
|
||||
const currentTaskId = ref('')
|
||||
const currentTaskNo = ref('')
|
||||
const conAssayTask = ref('')
|
||||
const reviewNum = ref(0)
|
||||
const selectedIndex = ref(-1)
|
||||
const taskList = ref([])
|
||||
const sampleList = ref([])
|
||||
const showDetailPopup = ref(false)
|
||||
const detailPopupParam = ref({ taskDetailId: '' })
|
||||
|
||||
// 计算属性
|
||||
const userInfo = computed(() => nx.$store('user').userInfo)
|
||||
|
||||
// 方法
|
||||
const customBack = () => {
|
||||
uni.reLaunch({ url: '/pages/analysis/index/index' })
|
||||
}
|
||||
|
||||
const taskStyle = task => {
|
||||
if ((task.weightTaskStatus === 0 || task.weightTaskStatus === 1) && task.reviewCount > 0) return 'red'
|
||||
if (task.weightTaskStatus === 2 && task.reviewCount > 0) return 'green'
|
||||
return ''
|
||||
}
|
||||
|
||||
const sampleStyle = sample => {
|
||||
if ((sample.weightSubmitStatus === 0 || sample.weightSubmitStatus === 1) && sample.reviewCount > 0) {
|
||||
return 'color: red'
|
||||
}
|
||||
if (sample.weightSubmitStatus === 2 && sample.reviewCount > 0) {
|
||||
return 'color: green'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
const swichTask = async index => {
|
||||
if (index === current.value) return
|
||||
current.value = index
|
||||
selectedIndex.value = -1
|
||||
const task = taskList.value[index]
|
||||
currentTask.value = task
|
||||
currentTaskNo.value = task.taskNo
|
||||
currentTaskId.value = task.id
|
||||
getAssayTaskDetail(task.taskNo)
|
||||
}
|
||||
|
||||
const showSampleDetail = (detailId, index) => {
|
||||
selectedIndex.value = index
|
||||
console.log('detailId', detailId)
|
||||
detailPopupParam.value = { taskDetailId: detailId }
|
||||
showDetailPopup.value = true
|
||||
}
|
||||
|
||||
const getAssayTask = () => {
|
||||
taskList.value = []
|
||||
sampleList.value = []
|
||||
const param = {
|
||||
finishStatus: 'finished',
|
||||
wfStatus: 'running',
|
||||
assayOper: userInfo.value.realname
|
||||
}
|
||||
nx.$api.auncel.getAssayTaskList(param).then(res => {
|
||||
taskList.value = res
|
||||
if (taskList.value.length > 0) {
|
||||
current.value = 0
|
||||
currentTask.value = taskList.value[0]
|
||||
currentTaskNo.value = taskList.value[0].taskNo
|
||||
currentTaskId.value = taskList.value[0].id
|
||||
getAssayTaskDetail(currentTaskNo.value)
|
||||
} else {
|
||||
current.value = 0
|
||||
currentTask.value = {}
|
||||
currentTaskNo.value = ''
|
||||
currentTaskId.value = ''
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getAssayTaskDetail = taskNo => {
|
||||
reviewNum.value = 0
|
||||
nx.$api.assayTaskTemplateKey
|
||||
.getAssayTaskDetailListByTaskNo({ taskNo })
|
||||
.then(res => {
|
||||
sampleList.value = res.result || []
|
||||
if (res.additionalProperties?.conAssayTask) {
|
||||
conAssayTask.value = res.additionalProperties.conAssayTask
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
|
||||
const previewPDF = () => {
|
||||
const url = `/pages/analysis/sample/pdf-preview?taskId=${currentTaskId.value}&reportKey=${conAssayTask.value.assayTaskTemplateKey}`
|
||||
uni.navigateTo({ url })
|
||||
}
|
||||
|
||||
const getDataSourceTypeShow = val => {
|
||||
if (val === 2) return '【筛上】'
|
||||
if (val === 3) return '【筛下】'
|
||||
return ''
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
getAssayTask()
|
||||
uni.$on('sample-detail-popup_close', () => {
|
||||
showDetailPopup.value = false
|
||||
})
|
||||
})
|
||||
|
||||
onBackPress(() => {
|
||||
customBack()
|
||||
return true
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* 样式部分保持不变 */
|
||||
.content-title {
|
||||
height: 50px;
|
||||
width: 100%;
|
||||
font-size: 20px;
|
||||
font-weight: 300;
|
||||
}
|
||||
.content-title-name {
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
.content-main-height {
|
||||
height: calc(100vh - 125px);
|
||||
}
|
||||
.content-main-left {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
.u-tab-item {
|
||||
padding: 5px;
|
||||
height: 100px;
|
||||
background: #f6f6f6;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
color: #444;
|
||||
line-height: 1;
|
||||
border-width: 2px;
|
||||
border-bottom: dotted;
|
||||
}
|
||||
.u-tab-item-active {
|
||||
position: relative;
|
||||
color: #0055a2;
|
||||
font-weight: 600;
|
||||
background: #fff;
|
||||
}
|
||||
.u-tab-item-active::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
height: 16px;
|
||||
left: 0;
|
||||
top: 20px;
|
||||
}
|
||||
.content-main-right {
|
||||
height: calc(100vh - 205px);
|
||||
}
|
||||
.content-main-right-operation {
|
||||
height: 80px;
|
||||
padding-top: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
.btn-operation {
|
||||
width: 95%;
|
||||
}
|
||||
.selected_Sample {
|
||||
background-color: #d7e9fa;
|
||||
}
|
||||
</style>
|
||||
413
pages/analysis/sample/sample-report.vue
Normal file
413
pages/analysis/sample/sample-report.vue
Normal file
@@ -0,0 +1,413 @@
|
||||
<template>
|
||||
<view>
|
||||
<navbar-back :autoBack="false" title="数据上报" @leftClick="customBack"></navbar-back>
|
||||
<u-row class="content-title" gutter="16">
|
||||
<u-col span="4">
|
||||
<view class="content-title-name">
|
||||
<text>任务列表</text>
|
||||
</view>
|
||||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
<u-col span="8">
|
||||
<view class="content-title-name">
|
||||
<text>样品列表</text>
|
||||
</view>
|
||||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
</u-row>
|
||||
<u-row class="content-main-height" gutter="16" align="top">
|
||||
<u-col span="4">
|
||||
<scroll-view
|
||||
scroll-y
|
||||
scroll-with-animation
|
||||
class="content-main-height content-main-left"
|
||||
:scroll-top="scrollTop"
|
||||
>
|
||||
<view
|
||||
v-for="(task, index) in taskList"
|
||||
:key="index"
|
||||
class="u-tab-item"
|
||||
:class="current === index ? 'u-tab-item-active' : ''"
|
||||
@tap.stop="swichTask(index)"
|
||||
>
|
||||
<u-row style="width: 100%">
|
||||
<u-col span="2" style="text-align: center">
|
||||
<u-icon :color="taskStyle(task)" name="tags-fill" size="34"></u-icon>
|
||||
</u-col>
|
||||
<u-col span="10">
|
||||
<view>
|
||||
<text style="font-size: 18px">{{ task.taskNo }}</text>
|
||||
</view>
|
||||
<view style="margin-top: 10px">
|
||||
<text>{{ task.taskName }} {{ task.assayOper }}</text>
|
||||
</view>
|
||||
<view class="x-f" style="margin-top: 10px">
|
||||
<u-icon color="" name="clock"></u-icon>
|
||||
<text style="margin-left: 5px">{{ task.taskOperTime }}</text>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</u-col>
|
||||
<u-col span="8">
|
||||
<view class="content-main-height">
|
||||
<scroll-view scroll-y scroll-with-animation class="content-main-right">
|
||||
<block v-for="(sample, index) in sampleList" :key="index">
|
||||
<view style="padding: 5px; font-size: 16px">
|
||||
<u-row
|
||||
@click="showSampleDetail(sample.id, index)"
|
||||
:class="selectedIndex === index ? 'selected_Sample' : ''"
|
||||
>
|
||||
<u-col span="2" style="text-align: center" :style="sampleStyle(sample)">
|
||||
<view>
|
||||
<text>【{{ sample.sort }}】</text>
|
||||
</view>
|
||||
</u-col>
|
||||
<u-col span="5">
|
||||
<view>
|
||||
<text style="padding-left: 10px">{{ sample.sampleCode }}</text>
|
||||
</view>
|
||||
<view>
|
||||
<text style="padding-left: 10px"
|
||||
>{{ getDataSourceTypeShow(sample.dataSourceType) }}{{ sample.sampleName }}</text
|
||||
>
|
||||
</view>
|
||||
</u-col>
|
||||
<u-col span="5">
|
||||
<view class="sample_desc_warn" v-if="sample.sampleProcessNo !== currentNode">
|
||||
当前节点:{{ getProcessNameShow(sample.sampleProcessNo) }}
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
<u-line style="padding: 5px" color="#bbb" />
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
<view class="content-main-right-operation">
|
||||
<u-row>
|
||||
<u-col span="3"></u-col>
|
||||
<u-col span="3">
|
||||
<u-button class="btn-operation" type="primary" @click="previewPDF" v-if="currentTaskId">
|
||||
任务单预览
|
||||
</u-button>
|
||||
</u-col>
|
||||
<u-col span="3">
|
||||
<u-button
|
||||
class="btn-operation"
|
||||
v-if="currentTaskId"
|
||||
type="warning"
|
||||
:disabled="taskReviewDisabled"
|
||||
@click="taskReview"
|
||||
>
|
||||
撤回任务单
|
||||
</u-button>
|
||||
</u-col>
|
||||
<u-col span="3">
|
||||
<u-button class="btn-operation" :disabled="dataReportDisabled" type="success" @click="dataReport">
|
||||
数据上报
|
||||
</u-button>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
|
||||
<!-- 样品详情 -->
|
||||
<sample-detail-popup
|
||||
ref="sampleDetailPopup"
|
||||
:showPopup="showDetailPopup"
|
||||
:detailPopupParam="detailPopupParam"
|
||||
></sample-detail-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { onLoad, onBackPress } from '@dcloudio/uni-app'
|
||||
import SampleDetailPopup from '@/components/sample/sample-detail-popup.vue'
|
||||
import nx from '@/nx'
|
||||
|
||||
// 响应式数据
|
||||
const scrollTop = ref(0)
|
||||
const current = ref(0)
|
||||
const currentTask = ref({})
|
||||
const currentTaskId = ref('')
|
||||
const currentTaskNo = ref('')
|
||||
const conAssayTask = ref('')
|
||||
const reviewNum = ref(0)
|
||||
const selectedIndex = ref(-1)
|
||||
const taskList = ref([])
|
||||
const sampleList = ref([])
|
||||
const showDetailPopup = ref(false)
|
||||
const detailPopupParam = ref({ taskDetailId: '' })
|
||||
const currentNode = ref('F31')
|
||||
const dicSampleProcessCodeList = ref([])
|
||||
|
||||
// 计算属性
|
||||
const taskReviewDisabled = computed(() => currentTask.value.finishStatus !== 'finished')
|
||||
const dataReportDisabled = computed(() => currentTask.value.finishStatus !== 'finished')
|
||||
const userInfo = computed(() => nx.$store('user').userInfo)
|
||||
|
||||
// 方法
|
||||
const customBack = () => {
|
||||
uni.reLaunch({ url: '/pages/analysis/index/index' })
|
||||
}
|
||||
|
||||
const taskStyle = task => {
|
||||
if ((task.weightTaskStatus === 0 || task.weightTaskStatus === 1) && task.reviewCount > 0) return 'red'
|
||||
if (task.weightTaskStatus === 2 && task.reviewCount > 0) return 'green'
|
||||
return ''
|
||||
}
|
||||
|
||||
const sampleStyle = sample => {
|
||||
if ((sample.weightSubmitStatus === 0 || sample.weightSubmitStatus === 1) && sample.reviewCount > 0) {
|
||||
return 'color: red'
|
||||
}
|
||||
if (sample.weightSubmitStatus === 2 && sample.reviewCount > 0) {
|
||||
return 'color: green'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
const swichTask = async index => {
|
||||
if (index === current.value) return
|
||||
current.value = index
|
||||
const task = taskList.value[index]
|
||||
currentTask.value = task
|
||||
currentTaskNo.value = task.taskNo
|
||||
currentTaskId.value = task.id
|
||||
getAssayTaskDetail(task.taskNo)
|
||||
}
|
||||
|
||||
const showSampleDetail = (detailId, index) => {
|
||||
selectedIndex.value = index
|
||||
detailPopupParam.value = { taskDetailId: detailId }
|
||||
showDetailPopup.value = true
|
||||
}
|
||||
|
||||
const getAssayTask = () => {
|
||||
taskList.value = []
|
||||
sampleList.value = []
|
||||
const param = {
|
||||
finishStatus: 'finished',
|
||||
wfStatus: '0,revoke',
|
||||
assayOper: userInfo.value.nickname
|
||||
}
|
||||
nx.$api.auncel
|
||||
.getAssayTaskList(param)
|
||||
.then(res => {
|
||||
taskList.value = res
|
||||
if (taskList.value.length > 0) {
|
||||
current.value = 0
|
||||
currentTask.value = taskList.value[0]
|
||||
currentTaskNo.value = taskList.value[0].taskNo
|
||||
currentTaskId.value = taskList.value[0].id
|
||||
getAssayTaskDetail(currentTaskNo.value)
|
||||
} else {
|
||||
current.value = 0
|
||||
currentTask.value = {}
|
||||
currentTaskNo.value = ''
|
||||
currentTaskId.value = ''
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
|
||||
const getAssayTaskDetail = taskNo => {
|
||||
reviewNum.value = 0
|
||||
$u.api
|
||||
.getAssayTaskDetailListByTaskNo({ taskNo })
|
||||
.then(res => {
|
||||
sampleList.value = res.result || []
|
||||
if (res.additionalProperties?.conAssayTask) {
|
||||
conAssayTask.value = res.additionalProperties.conAssayTask
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
|
||||
const previewPDF = () => {
|
||||
const url = `/pages/analysis/sample/pdf-preview?taskId=${currentTaskId.value}&reportKey=${conAssayTask.value.assayTaskTemplateKey}&hideResultFlag=true`
|
||||
uni.navigateTo({ url })
|
||||
}
|
||||
|
||||
const taskReview = () => {
|
||||
const errNodeList = sampleList.value.filter(item => item.sampleProcessNo !== currentNode.value)
|
||||
if (errNodeList.length > 0) {
|
||||
uni.showToast({ title: '存在异常节点,联系管理员处理!', icon: 'none', duration: 3000 })
|
||||
return
|
||||
}
|
||||
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '撤回当前任务指派单,是否继续?',
|
||||
cancelColor: '#0055A2',
|
||||
confirmColor: '#0055A2',
|
||||
success: res => {
|
||||
if (res.confirm) {
|
||||
nx.$api.assayTask.rollbackAssayTask(currentTaskId.value).then(() => {
|
||||
currentTaskId.value = ''
|
||||
currentTask.value = {}
|
||||
uni.showToast({ title: '撤回成功!' })
|
||||
uni.navigateTo({ url: '/pages/analysis/sample/sample-work-list' })
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const dataReport = () => {
|
||||
const errNodeList = sampleList.value.filter(item => item.sampleProcessNo !== currentNode.value)
|
||||
if (errNodeList.length > 0) {
|
||||
uni.showToast({ title: '存在异常节点,联系管理员处理!', icon: 'none', duration: 3000 })
|
||||
return
|
||||
}
|
||||
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确定上报数据?',
|
||||
cancelColor: '#0055A2',
|
||||
confirmColor: '#0055A2',
|
||||
success: res => {
|
||||
if (res.confirm) {
|
||||
nx.$api.assayTask.reportAssayTask(currentTaskId.value).then(res => {
|
||||
currentTaskId.value = ''
|
||||
currentTask.value = {}
|
||||
if (res.additionalProperties?.conAssayTask?.isPrint === 1) {
|
||||
printTask()
|
||||
}
|
||||
getAssayTask()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getDicSampleProcessCodeList = () => {
|
||||
nx.$api.assayTask.queryQmsDicSampleProcessCodeList().then(res => {
|
||||
dicSampleProcessCodeList.value = res.records
|
||||
})
|
||||
}
|
||||
|
||||
const getProcessNameShow = val => {
|
||||
const item = dicSampleProcessCodeList.value.find(i => i.processCode === val)
|
||||
return item ? item.processName : val
|
||||
}
|
||||
|
||||
const getDataSourceTypeShow = val => {
|
||||
if (val === 2) return '【筛上】'
|
||||
if (val === 3) return '【筛下】'
|
||||
return ''
|
||||
}
|
||||
|
||||
const printTask = () => {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '数据上报成功!是否打印“原始记录单”?',
|
||||
cancelColor: '#0055A2',
|
||||
confirmColor: '#0055A2',
|
||||
success: res => {
|
||||
if (res.confirm) {
|
||||
nx.$print.getPrintTemplateAndPrint(currentTask.value)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
getDicSampleProcessCodeList()
|
||||
getAssayTask()
|
||||
|
||||
// 监听 popup 关闭
|
||||
uni.$on('sample-detail-popup_close', () => {
|
||||
showDetailPopup.value = false
|
||||
})
|
||||
})
|
||||
|
||||
onBackPress(() => {
|
||||
customBack()
|
||||
return true
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* 样式保持不变 */
|
||||
.content-title {
|
||||
height: 50px;
|
||||
width: 100%;
|
||||
font-size: 20px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.content-title-name {
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content-main-height {
|
||||
height: calc(100vh - 125px);
|
||||
}
|
||||
|
||||
.content-main-left {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
|
||||
.u-tab-item {
|
||||
padding: 5px;
|
||||
height: 100px;
|
||||
background: #f6f6f6;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
color: #444;
|
||||
line-height: 1;
|
||||
border-width: 2px;
|
||||
border-bottom: dotted;
|
||||
}
|
||||
|
||||
.u-tab-item-active {
|
||||
position: relative;
|
||||
color: #0055a2;
|
||||
font-weight: 600;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.u-tab-item-active::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
height: 16px;
|
||||
left: 0;
|
||||
top: 20px;
|
||||
}
|
||||
|
||||
.content-main-right {
|
||||
height: calc(100vh - 205px);
|
||||
}
|
||||
|
||||
.content-main-right-operation {
|
||||
height: 80px;
|
||||
padding-top: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.btn-operation {
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
.selected_Sample {
|
||||
background-color: #d7e9fa;
|
||||
}
|
||||
.sample_desc_warn {
|
||||
color: red;
|
||||
padding-right: 10px;
|
||||
}
|
||||
</style>
|
||||
423
pages/analysis/sample/sample-review.vue
Normal file
423
pages/analysis/sample/sample-review.vue
Normal file
@@ -0,0 +1,423 @@
|
||||
<template>
|
||||
<view>
|
||||
<navbar-back :autoBack="false" title="样重复核" @leftClick="customBack"></navbar-back>
|
||||
<u-row class="content-title" gutter="16">
|
||||
<u-col span="4">
|
||||
<view class="content-title-name">
|
||||
<text>任务列表</text>
|
||||
</view>
|
||||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
<u-col span="8">
|
||||
<view class="content-title-name">
|
||||
<text>样品列表</text>
|
||||
</view>
|
||||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
</u-row>
|
||||
<u-row class="content-main-height" gutter="16" align="top">
|
||||
<u-col span="4">
|
||||
<scroll-view
|
||||
scroll-y
|
||||
scroll-with-animation
|
||||
class="content-main-height content-main-left"
|
||||
:scroll-top="scrollTop"
|
||||
>
|
||||
<view
|
||||
v-for="(task, index) in taskList"
|
||||
:key="index"
|
||||
class="u-tab-item"
|
||||
:class="[current == index ? 'u-tab-item-active' : '']"
|
||||
:data-current="index"
|
||||
@tap.stop="swichTask(index)"
|
||||
>
|
||||
<u-row style="width: 100%">
|
||||
<u-col span="2" style="text-align: center">
|
||||
<u-icon name="tags-fill" size="34"></u-icon>
|
||||
</u-col>
|
||||
<u-col span="10">
|
||||
<view>
|
||||
<text style="font-size: 42rpx">{{ task.taskNo }}</text>
|
||||
</view>
|
||||
<view style="margin-top: 20rpx">
|
||||
<text>{{ task.taskName }}</text>
|
||||
</view>
|
||||
<view class="x-f" style="margin-top: 20rpx">
|
||||
<u-icon name="clock"></u-icon>
|
||||
<text style="margin-left: 10rpx">{{ task.taskOperTime }}</text>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</u-col>
|
||||
<u-col span="8">
|
||||
<view class="content-main-height">
|
||||
<scroll-view scroll-y scroll-with-animation class="content-main-right">
|
||||
<u-checkbox-group @change="checkboxGroupChange" style="width: 100%">
|
||||
<block v-for="(sample, index) in sampleList" :key="index">
|
||||
<view style="width: 100%; padding: 10rpx; font-size: 36rpx">
|
||||
<u-row>
|
||||
<u-col span="2" style="text-align: center">
|
||||
<view>
|
||||
<text>【{{ sample.sort }}】</text>
|
||||
</view>
|
||||
</u-col>
|
||||
<u-col span="4">
|
||||
<view>
|
||||
<text style="padding-left: 20rpx">{{ sample.sampleCode }}</text>
|
||||
</view>
|
||||
<view>
|
||||
<text style="padding-left: 20rpx"
|
||||
>{{ sample.dataSourceType | getDataSourceTypeShow }}{{ sample.sampleName }}</text
|
||||
>
|
||||
</view>
|
||||
<view>
|
||||
<text v-if="sample.sampleWeight" style="padding-left: 20rpx">{{ sample.sampleWeight }} g</text>
|
||||
</view>
|
||||
</u-col>
|
||||
<u-col span="4">
|
||||
<view>
|
||||
<text style="padding-left: 20rpx">{{ sample.cupNum }}号杯</text>
|
||||
</view>
|
||||
<view>
|
||||
<text style="padding-left: 20rpx">{{ sample.remarks }}</text>
|
||||
</view>
|
||||
<view>
|
||||
<text style="padding-left: 20rpx">{{ sample.measureTime | getWeightTimeShow }}</text>
|
||||
</view>
|
||||
</u-col>
|
||||
<u-col span="2">
|
||||
<view>
|
||||
<u-checkbox
|
||||
@change="checkboxChange"
|
||||
v-model="sample.checked"
|
||||
:label="sample.id"
|
||||
:name="sample.id"
|
||||
>
|
||||
</u-checkbox>
|
||||
<!-- <block v-if="sample.reviewCount > 0 && sample.weightSubmitStatus == 0">
|
||||
<u-button
|
||||
type="warning"
|
||||
@click="recovery(sample.id)"
|
||||
>恢复</u-button>
|
||||
</block>
|
||||
<block v-else>
|
||||
<u-button
|
||||
type="default"
|
||||
@click="review(sample.id)"
|
||||
>复核</u-button>
|
||||
</block> -->
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
<u-line style="padding: 10rpx" color="#bbb" />
|
||||
</view>
|
||||
</block>
|
||||
</u-checkbox-group>
|
||||
</scroll-view>
|
||||
<view class="content-main-right-operation">
|
||||
<u-row>
|
||||
<u-col span="4"><!-- <u-button class="btn-operation" type="primary">原始记录单打印</u-button> --></u-col>
|
||||
<u-col span="4"
|
||||
><!-- <u-button class="btn-operation" :disabled="reviewNum > 0" type="success" >数据上报</u-button> --></u-col
|
||||
>
|
||||
<u-col span="4">
|
||||
<!-- <u-button class="btn-operation" :disabled="reviewNum == 0" type="warning" @click="taskReview">任务单退回复核</u-button> -->
|
||||
<u-button class="btn-operation" :disabled="reviewList.length <= 0" type="warning" @click="taskReviewAll"
|
||||
>任务单退回复核</u-button
|
||||
>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
scrollTop: 0, //tab标题的滚动条位置
|
||||
current: 0, // 预设当前项的值
|
||||
menuHeight: 0, // 左边菜单的高度
|
||||
menuItemHeight: 0, // 左边菜单item的高度
|
||||
currentTaskId: '', //当前选择的任务单id
|
||||
currentTaskNo: '', //当前选中的任务编号
|
||||
reviewNum: 0, //复核数
|
||||
reviewList: [],
|
||||
taskList: [],
|
||||
sampleList: []
|
||||
}
|
||||
},
|
||||
onLoad(param) {
|
||||
if (param.currentTaskNo) {
|
||||
this.currentTaskNo = param.currentTaskNo
|
||||
}
|
||||
//获取任务列表
|
||||
this.getAssayTask()
|
||||
},
|
||||
methods: {
|
||||
//返回上一页
|
||||
customBack() {
|
||||
uni.redirectTo({
|
||||
url: '/pages/analysis/sample/sample-report'
|
||||
})
|
||||
},
|
||||
//开始秤样
|
||||
startWeighSample() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/auncel/auncel-weigh'
|
||||
})
|
||||
},
|
||||
//切换任务
|
||||
async swichTask(index) {
|
||||
if (index == this.current) return
|
||||
this.current = index
|
||||
// 如果为0,意味着尚未初始化
|
||||
if (this.menuHeight == 0 || this.menuItemHeight == 0) {
|
||||
await this.getElRect('menu-scroll-view', 'menuHeight')
|
||||
await this.getElRect('u-tab-item', 'menuItemHeight')
|
||||
}
|
||||
// 将菜单菜单活动item垂直居中
|
||||
this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2
|
||||
|
||||
//获取任务详情
|
||||
this.currentTaskNo = this.taskList[index].taskNo
|
||||
this.currentTaskId = this.taskList[index].id
|
||||
this.getAssayTaskDetail(this.currentTaskNo)
|
||||
},
|
||||
// 获取一个目标元素的高度
|
||||
getElRect(elClass, dataVal) {
|
||||
new Promise((resolve, reject) => {
|
||||
const query = uni.createSelectorQuery().in(this)
|
||||
query
|
||||
.select('.' + elClass)
|
||||
.fields({ size: true }, res => {
|
||||
// 如果节点尚未生成,res值为null,循环调用执行
|
||||
if (!res) {
|
||||
setTimeout(() => {
|
||||
this.getElRect(elClass)
|
||||
}, 10)
|
||||
return
|
||||
}
|
||||
this[dataVal] = res.height
|
||||
})
|
||||
.exec()
|
||||
})
|
||||
},
|
||||
getAssayTask() {
|
||||
//显示loading
|
||||
uni.showLoading({
|
||||
title: '加载中...'
|
||||
})
|
||||
// this.$u.api
|
||||
// .getAssayTaskListBy({taskStatus:2})
|
||||
const param = {
|
||||
operateType: 'review',
|
||||
taskNo: this.currentTaskNo
|
||||
}
|
||||
this.$u.api
|
||||
.getAssayTaskList(param)
|
||||
.then(res => {
|
||||
this.taskList = res.result
|
||||
this.currentTaskNo = this.taskList[0].taskNo
|
||||
this.currentTaskId = this.taskList[0].id
|
||||
this.getAssayTaskDetail(this.currentTaskNo)
|
||||
uni.hideLoading()
|
||||
})
|
||||
.catch(err => {
|
||||
uni.hideLoading()
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
getAssayTaskDetail(taskNo) {
|
||||
this.reviewNum = 0
|
||||
this.$u.api
|
||||
.getAssayTaskDetailListByTaskNo({ taskNo: taskNo })
|
||||
.then(res => {
|
||||
this.sampleList = res.result
|
||||
this.showLoading = false
|
||||
|
||||
//统计需要复核的数量
|
||||
this.sampleList.forEach(item => {
|
||||
if (item.reviewCount > 0 && item.weightSubmitStatus == 0) {
|
||||
item.checked = true
|
||||
this.reviewNum += 1
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
this.showLoading = false
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
review(id) {
|
||||
this.$u.api
|
||||
.assayTaskDetailReview(id)
|
||||
.then(res => {
|
||||
this.getAssayTaskDetail(this.currentTaskNo)
|
||||
this.showLoading = false
|
||||
})
|
||||
.catch(err => {
|
||||
this.showLoading = false
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
recovery(id) {
|
||||
this.$u.api
|
||||
.assayTaskDetailRecovery(id)
|
||||
.then(res => {
|
||||
this.getAssayTaskDetail(this.currentTaskNo)
|
||||
this.showLoading = false
|
||||
})
|
||||
.catch(err => {
|
||||
this.showLoading = false
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
//任务单退回复核
|
||||
taskReview() {
|
||||
this.$u.api
|
||||
.assayTaskReview(this.currentTaskId)
|
||||
.then(res => {
|
||||
this.showLoading = false
|
||||
|
||||
uni.redirectTo({
|
||||
url: '/pages/sample/sample-report'
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
this.showLoading = false
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
//任务单及样品退回复核
|
||||
taskReviewAll() {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确定复核当前选中的样品?',
|
||||
cancelColor: '#0055A2',
|
||||
confirmColor: '#0055A2',
|
||||
success: res => {
|
||||
if (res.cancel) {
|
||||
console.log('用户点击取消')
|
||||
return
|
||||
}
|
||||
console.log('确定。。。')
|
||||
//显示loading
|
||||
uni.showLoading({
|
||||
title: '退回中...'
|
||||
})
|
||||
this.$u.api
|
||||
.reviewWeightTaskByTaskIdAndSampleIds(this.currentTaskId, this.reviewList.join(','))
|
||||
.then(res => {
|
||||
uni.hideLoading()
|
||||
uni.redirectTo({
|
||||
url: '/pages/sample/sample-report'
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
uni.hideLoading()
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
checkboxGroupChange(v) {
|
||||
this.reviewList = v
|
||||
this.reviewNum = v.length
|
||||
//console.log('group change', v);
|
||||
},
|
||||
checkboxChange(e) {
|
||||
/* if(e.value) {
|
||||
this.review(e.name);
|
||||
} else {
|
||||
this.recovery(e.name);
|
||||
} */
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
getWeightTimeShow(time) {
|
||||
if (time == null) return ''
|
||||
return time.split(' ')[1]
|
||||
},
|
||||
getDataSourceTypeShow(val) {
|
||||
if (val == 2) return '【筛上】'
|
||||
if (val == 3) return '【筛下】'
|
||||
return ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content-title {
|
||||
height: 110rpx;
|
||||
width: 100%;
|
||||
font-size: 46rpx;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.content-title-name {
|
||||
padding: 20rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content-main-height {
|
||||
height: calc(100vh - 250rpx);
|
||||
}
|
||||
|
||||
.content-main-left {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
|
||||
.u-tab-item {
|
||||
padding: 10rpx;
|
||||
height: 200rpx;
|
||||
background: #f6f6f6;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 36rpx;
|
||||
color: #444;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
border-width: 4rpx;
|
||||
border-bottom: dotted;
|
||||
}
|
||||
|
||||
.u-tab-item-active {
|
||||
position: relative;
|
||||
color: #0055a2;
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.u-tab-item-active::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
|
||||
height: 32rpx;
|
||||
left: 0;
|
||||
top: 39rpx;
|
||||
}
|
||||
|
||||
.content-main-right {
|
||||
height: calc(100vh - 410rpx);
|
||||
}
|
||||
|
||||
.content-main-right-operation {
|
||||
height: 160rpx;
|
||||
padding-top: 30rpx;
|
||||
}
|
||||
|
||||
.btn-operation {
|
||||
height: 100rpx;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
</style>
|
||||
425
pages/analysis/sample/sample-send.vue
Normal file
425
pages/analysis/sample/sample-send.vue
Normal file
@@ -0,0 +1,425 @@
|
||||
<!--送样-->
|
||||
<template>
|
||||
<view class="page">
|
||||
<navbar-back :autoBack="false" title="样品分析-送样" @leftClick="customBack"></navbar-back>
|
||||
<u-row class="content-title" gutter="16">
|
||||
<u-col span="4">
|
||||
<view class="content-title-name">
|
||||
<text>任务列表</text>
|
||||
</view>
|
||||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
<u-col span="8">
|
||||
<view class="content-title-name">
|
||||
<text>样品列表</text>
|
||||
</view>
|
||||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
</u-row>
|
||||
<u-row class="content-main-height" gutter="16" align="top">
|
||||
<u-col span="4">
|
||||
<scroll-view
|
||||
scroll-y
|
||||
scroll-with-animation
|
||||
class="content-main-height content-main-left"
|
||||
:scroll-top="scrollTop"
|
||||
>
|
||||
<view
|
||||
v-for="(task, index) in taskList"
|
||||
:key="index"
|
||||
class="u-tab-item"
|
||||
:class="[current == index ? 'u-tab-item-active' : '']"
|
||||
:data-current="index"
|
||||
@tap.stop="swichTask(index)"
|
||||
>
|
||||
<u-row style="width: 100%">
|
||||
<u-col span="2" style="text-align: center">
|
||||
<u-icon :color="taskStyle(task)" name="tags-fill" size="34"></u-icon>
|
||||
</u-col>
|
||||
<u-col span="10">
|
||||
<view>
|
||||
<text style="font-size: 42rpx">{{ task.taskNo }}</text>
|
||||
</view>
|
||||
<view style="margin-top: 20rpx">
|
||||
<text>{{ task.taskName }}</text>
|
||||
</view>
|
||||
<view class="x-f" style="margin-top: 20rpx">
|
||||
<u-icon color="" name="clock"></u-icon>
|
||||
<text style="margin-left: 10rpx">{{ task.taskOperTime }}</text>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</u-col>
|
||||
<u-col span="8">
|
||||
<view class="content-main-height">
|
||||
<scroll-view scroll-y scroll-with-animation class="content-main-right">
|
||||
<block v-for="(sample, index) in sampleList" :key="index">
|
||||
<view style="padding: 10rpx; font-size: 36rpx">
|
||||
<u-row>
|
||||
<u-col span="3" style="text-align: center">
|
||||
<view>
|
||||
<text>【{{ sample.sort }}】</text>
|
||||
</view>
|
||||
<!-- <u-row>-->
|
||||
<!-- <u-col span="6" style="text-align: center;">-->
|
||||
<!-- <u-checkbox v-model="sample.checked" v-if="sample.sampleProcessNo == 'F39'" @change="selectSample(sample)"></u-checkbox>-->
|
||||
<!-- </u-col>-->
|
||||
<!-- <u-col span="6" style="text-align: center;">-->
|
||||
<!-- -->
|
||||
<!-- </u-col>-->
|
||||
<!-- </u-row>-->
|
||||
</u-col>
|
||||
<u-col span="9" class="sample_desc">
|
||||
<view>
|
||||
<view>
|
||||
<text style="padding-left: 20rpx">{{ sample.sampleCode }}</text>
|
||||
</view>
|
||||
<view>
|
||||
<text style="padding-left: 20rpx"
|
||||
>{{ sample.dataSourceType | getDataSourceTypeShow }}{{ sample.sampleName }}</text
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
<view class="sample_desc_warn" v-if="sample.sampleProcessNo != 'F39'">
|
||||
状态异常:{{ sample.sampleProcessNo }}
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
<u-line style="padding: 10rpx" color="#bbb" />
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
<view class="content-main-right-operation">
|
||||
<u-row>
|
||||
<u-col span="4"></u-col>
|
||||
<u-col span="4"></u-col>
|
||||
<u-col span="4">
|
||||
<u-button
|
||||
class="btn-operation"
|
||||
:disabled="this.taskList.length <= 0"
|
||||
type="success"
|
||||
@click="confirmReceipt"
|
||||
>确认送样</u-button
|
||||
>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
scrollTop: 0, //tab标题的滚动条位置
|
||||
current: 0, // 预设当前项的值
|
||||
menuHeight: 0, // 左边菜单的高度
|
||||
menuItemHeight: 0, // 左边菜单item的高度
|
||||
currentTask: '', //当前选中任务
|
||||
currentTaskNo: '', //当前选中的任务编号
|
||||
currentTaskType: '', //当前任务类型
|
||||
taskList: [],
|
||||
sampleList: []
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
//获取任务列表
|
||||
this.getAssayTask()
|
||||
},
|
||||
methods: {
|
||||
//返回首页
|
||||
customBack() {
|
||||
uni.reLaunch({
|
||||
url: '/pages/analysis/index/index'
|
||||
})
|
||||
},
|
||||
selectSample(sample) {
|
||||
if (sample.checked) sample.checked = false
|
||||
else sample.checked = true
|
||||
},
|
||||
taskStyle(task) {
|
||||
if (task.weightTaskStatus == 0 && task.reviewCount > 0) {
|
||||
return 'red'
|
||||
}
|
||||
if (task.weightTaskStatus == 1 && task.reviewCount > 0) {
|
||||
return 'red'
|
||||
}
|
||||
if (task.weightTaskStatus == 2 && task.reviewCount > 0) {
|
||||
return 'green'
|
||||
}
|
||||
return ''
|
||||
},
|
||||
sampleStyle(sample) {
|
||||
//console.log(sample);
|
||||
if (sample.weightSubmitStatus == 0 && sample.reviewCount > 0) {
|
||||
return 'color: red'
|
||||
}
|
||||
if (sample.weightSubmitStatus == 1 && sample.reviewCount > 0) {
|
||||
//return 'color: #e0861a';
|
||||
return 'color: green'
|
||||
}
|
||||
if (sample.weightSubmitStatus == 2 && sample.reviewCount > 0) {
|
||||
return 'color: green'
|
||||
}
|
||||
return ''
|
||||
},
|
||||
//确认送样
|
||||
confirmReceipt() {
|
||||
//检查是否选中所有
|
||||
// let checkedSampleList = this.sampleList.filter(item => item.checked);
|
||||
// if (checkedSampleList.length != this.sampleList.length) {
|
||||
// this.$helper.showToast({
|
||||
// title: '样品未全部勾选,请检查!'
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
//检查是否所有样品都在F39
|
||||
const checkList = this.sampleList.filter(item => item.sampleProcessNo != 'F39')
|
||||
if (checkList.length > 0) {
|
||||
this.$helper.showToast({
|
||||
title: '部分样品状态异常,请联系技术支持人员处理!'
|
||||
})
|
||||
return
|
||||
}
|
||||
const checkedSampleList = this.sampleList
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确认送样?',
|
||||
cancelColor: '#0055A2',
|
||||
confirmColor: '#0055A2',
|
||||
success: res => {
|
||||
if (res.cancel) {
|
||||
return
|
||||
}
|
||||
const sampleIdList = checkedSampleList.map(item => item.busSubCsampleId)
|
||||
const data = {
|
||||
busAssayTaskId: this.currentTask.id,
|
||||
sampleSourceType: 2,
|
||||
sampleProcessNo: 'F39',
|
||||
isGenSampleHandover: false,
|
||||
sampleIdList: sampleIdList
|
||||
}
|
||||
uni.showLoading({
|
||||
title: '正在提交...'
|
||||
})
|
||||
this.$u.api
|
||||
.execSendSample(data)
|
||||
.then(res => {
|
||||
let msg = '发生错误,请稍后再试!'
|
||||
if (!res.success) {
|
||||
if (res.message) {
|
||||
msg = res.message
|
||||
}
|
||||
this.$helper.showToast({
|
||||
title: msg
|
||||
})
|
||||
return
|
||||
}
|
||||
this.$helper.showToast({
|
||||
title: '操作成功!'
|
||||
})
|
||||
this.getAssayTask()
|
||||
})
|
||||
.catch(err => {
|
||||
this.$helper.showToast({
|
||||
title: '提交失败!'
|
||||
})
|
||||
console.log(err)
|
||||
})
|
||||
.finally(() => {
|
||||
uni.hideLoading()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
//切换任务
|
||||
async swichTask(index) {
|
||||
if (index == this.current) return
|
||||
this.current = index
|
||||
// 如果为0,意味着尚未初始化
|
||||
// if (this.menuHeight == 0 || this.menuItemHeight == 0) {
|
||||
// await this.getElRect('menu-scroll-view', 'menuHeight');
|
||||
// await this.getElRect('u-tab-item', 'menuItemHeight');
|
||||
// }
|
||||
// // 将菜单菜单活动item垂直居中
|
||||
// this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2;
|
||||
|
||||
//获取任务详情
|
||||
this.currentTask = this.taskList[index]
|
||||
this.currentTaskNo = this.taskList[index].taskNo
|
||||
this.currentTaskType = this.taskList[index].taskType
|
||||
this.getAssayTaskDetail(this.currentTaskNo)
|
||||
},
|
||||
// 获取一个目标元素的高度
|
||||
getElRect(elClass, dataVal) {
|
||||
new Promise((resolve, reject) => {
|
||||
const query = uni.createSelectorQuery().in(this)
|
||||
query
|
||||
.select('.' + elClass)
|
||||
.fields({ size: true }, res => {
|
||||
// 如果节点尚未生成,res值为null,循环调用执行
|
||||
if (!res) {
|
||||
setTimeout(() => {
|
||||
this.getElRect(elClass)
|
||||
}, 10)
|
||||
return
|
||||
}
|
||||
this[dataVal] = res.height
|
||||
})
|
||||
.exec()
|
||||
})
|
||||
},
|
||||
getAssayTask() {
|
||||
//显示loading
|
||||
uni.showLoading({
|
||||
title: '加载中...'
|
||||
})
|
||||
const param = {
|
||||
operateType: 'send',
|
||||
assayOper: this.userInfo.realname
|
||||
}
|
||||
this.$u.api
|
||||
.getAssayTaskList(param)
|
||||
.then(res => {
|
||||
this.taskList = res.result
|
||||
if (!this.taskList || this.taskList.length == 0) {
|
||||
this.sampleList = []
|
||||
return
|
||||
}
|
||||
if (this.taskList && this.taskList.length > 0) {
|
||||
this.current = 0
|
||||
this.currentTask = this.taskList[0]
|
||||
this.currentTaskNo = this.taskList[0].taskNo
|
||||
this.currentTaskType = this.taskList[0].taskType
|
||||
this.getAssayTaskDetail(this.currentTaskNo)
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
.finally(() => {
|
||||
uni.hideLoading()
|
||||
})
|
||||
},
|
||||
getAssayTaskDetail(taskNo) {
|
||||
uni.showLoading({
|
||||
title: '加载中...'
|
||||
})
|
||||
const param = {
|
||||
taskNo: taskNo,
|
||||
waiting_receive: '1' //标记是收样
|
||||
}
|
||||
this.$u.api
|
||||
.getAssayTaskDetailListByTaskNo(param)
|
||||
.then(res => {
|
||||
const list = res.result
|
||||
list.forEach(item => {
|
||||
item.checked = false
|
||||
})
|
||||
this.sampleList = list
|
||||
this.showLoading = false
|
||||
})
|
||||
.catch(err => {
|
||||
this.showLoading = false
|
||||
console.log(err)
|
||||
})
|
||||
.finally(() => {
|
||||
uni.hideLoading()
|
||||
})
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
getDataSourceTypeShow(val) {
|
||||
if (val == 2) return '【筛上】'
|
||||
if (val == 3) return '【筛下】'
|
||||
return ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content-title {
|
||||
height: 110rpx;
|
||||
width: 100%;
|
||||
font-size: 46rpx;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.content-title-name {
|
||||
padding: 20rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content-main-height {
|
||||
height: calc(100vh - 250rpx);
|
||||
}
|
||||
|
||||
.content-main-left {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
|
||||
.u-tab-item {
|
||||
padding: 10rpx;
|
||||
height: 200rpx;
|
||||
background: #f6f6f6;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 36rpx;
|
||||
color: #444;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
border-width: 4rpx;
|
||||
border-bottom: dotted;
|
||||
}
|
||||
|
||||
.u-tab-item-active {
|
||||
position: relative;
|
||||
color: #0055a2;
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.u-tab-item-active::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
|
||||
height: 32rpx;
|
||||
left: 0;
|
||||
top: 39rpx;
|
||||
}
|
||||
|
||||
.content-main-right {
|
||||
height: calc(100vh - 410rpx);
|
||||
}
|
||||
|
||||
.content-main-right-operation {
|
||||
height: 160rpx;
|
||||
padding-top: 30rpx;
|
||||
}
|
||||
|
||||
.btn-operation {
|
||||
height: 100rpx;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
|
||||
.sample_desc {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: nowrap; /* 禁止换行 */
|
||||
justify-content: space-between !important;
|
||||
padding-right: 15px !important;
|
||||
}
|
||||
|
||||
.sample_desc_warn {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
319
pages/analysis/sample/sample-weigh.vue
Normal file
319
pages/analysis/sample/sample-weigh.vue
Normal file
@@ -0,0 +1,319 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<navbar-back :autoBack="false" title="样品称重" @leftClick="customBack"></navbar-back>
|
||||
<u-row class="content-title" gutter="16">
|
||||
<u-col span="4">
|
||||
<view class="content-title-name">
|
||||
<text>任务列表</text>
|
||||
</view>
|
||||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
<u-col span="8">
|
||||
<view class="content-title-name">
|
||||
<text>样品列表</text>
|
||||
</view>
|
||||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
</u-row>
|
||||
<u-row class="content-main-height" gutter="16" align="top">
|
||||
<u-col span="4">
|
||||
<scroll-view
|
||||
scroll-y
|
||||
scroll-with-animation
|
||||
class="content-main-height content-main-left"
|
||||
:scroll-top="scrollTop"
|
||||
>
|
||||
<view
|
||||
v-for="(task, index) in taskList"
|
||||
:key="index"
|
||||
class="u-tab-item"
|
||||
:class="[current == index ? 'u-tab-item-active' : '']"
|
||||
:data-current="index"
|
||||
@tap.stop="swichTask(index)"
|
||||
>
|
||||
<u-row style="width: 100%">
|
||||
<u-col span="2" style="text-align: center">
|
||||
<u-icon :color="taskStyle(task)" name="tags-fill" size="34"></u-icon>
|
||||
</u-col>
|
||||
<u-col span="10">
|
||||
<view>
|
||||
<text style="font-size: 42rpx">{{ task.taskNo }}</text>
|
||||
</view>
|
||||
<view style="margin-top: 20rpx">
|
||||
<text>{{ task.taskName }}</text>
|
||||
</view>
|
||||
<view class="x-f" style="margin-top: 20rpx">
|
||||
<u-icon name="clock"></u-icon>
|
||||
<text style="margin-left: 10rpx">{{ task.taskOperTime }}</text>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</u-col>
|
||||
<u-col span="8">
|
||||
<view class="content-main-height">
|
||||
<scroll-view scroll-y scroll-with-animation class="content-main-right">
|
||||
<block v-for="(sample, index) in sampleList" :key="index">
|
||||
<view v-if="currentTask.reviewCount == sample.reviewCount" style="padding: 10rpx; font-size: 36rpx">
|
||||
<u-row>
|
||||
<u-col span="2" style="text-align: center">
|
||||
<view>
|
||||
<text>【{{ sample.sort }}】</text>
|
||||
</view>
|
||||
</u-col>
|
||||
<u-col span="10">
|
||||
<view>
|
||||
<text style="padding-left: 20rpx">{{ sample.sampleCode }}</text>
|
||||
</view>
|
||||
<view>
|
||||
<text style="padding-left: 20rpx"
|
||||
>{{ sample.dataSourceType | getDataSourceTypeShow }}{{ sample.sampleName }}</text
|
||||
>
|
||||
</view>
|
||||
<block v-if="sample.sampleWeight && sample.weightSubmitStatus != 0">
|
||||
<view>
|
||||
<text v-if="sample.sampleWeight" style="padding-left: 20rpx">{{ sample.sampleWeight }} g</text>
|
||||
</view>
|
||||
</block>
|
||||
</u-col>
|
||||
</u-row>
|
||||
<u-line style="padding: 10rpx" color="#bbb" />
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
<view class="content-main-right-operation">
|
||||
<u-row>
|
||||
<u-col span="4"></u-col>
|
||||
<u-col span="4"></u-col>
|
||||
<u-col span="4">
|
||||
<u-button
|
||||
class="btn-operation"
|
||||
:disabled="this.taskList.length <= 0"
|
||||
type="success"
|
||||
@click="startWeighSample"
|
||||
>开始秤样</u-button
|
||||
>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
scrollTop: 0, //tab标题的滚动条位置
|
||||
current: 0, // 预设当前项的值
|
||||
menuHeight: 0, // 左边菜单的高度
|
||||
menuItemHeight: 0, // 左边菜单item的高度
|
||||
currentTask: '', //当前选中任务
|
||||
currentTaskNo: '', //当前选中的任务编号
|
||||
currentTaskType: '', //当前任务类型
|
||||
taskList: [],
|
||||
sampleList: []
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
//获取任务列表
|
||||
this.getAssayTask()
|
||||
},
|
||||
methods: {
|
||||
//返回首页
|
||||
customBack() {
|
||||
uni.reLaunch({
|
||||
url: '/pages/analysis/index/index'
|
||||
})
|
||||
},
|
||||
taskStyle(task) {
|
||||
if (task.weightTaskStatus == 0 && task.reviewCount > 0) {
|
||||
return 'red'
|
||||
}
|
||||
if (task.weightTaskStatus == 1 && task.reviewCount > 0) {
|
||||
return 'red'
|
||||
}
|
||||
if (task.weightTaskStatus == 2 && task.reviewCount > 0) {
|
||||
return 'green'
|
||||
}
|
||||
return ''
|
||||
},
|
||||
sampleStyle(sample) {
|
||||
//console.log(sample);
|
||||
if (sample.weightSubmitStatus == 0 && sample.reviewCount > 0) {
|
||||
return 'color: red'
|
||||
}
|
||||
if (sample.weightSubmitStatus == 1 && sample.reviewCount > 0) {
|
||||
//return 'color: #e0861a';
|
||||
return 'color: green'
|
||||
}
|
||||
if (sample.weightSubmitStatus == 2 && sample.reviewCount > 0) {
|
||||
return 'color: green'
|
||||
}
|
||||
return ''
|
||||
},
|
||||
//开始秤样
|
||||
startWeighSample() {
|
||||
uni.navigateTo({
|
||||
url:
|
||||
'/pages/auncel/auncel-weigh?currentTaskNo=' + this.currentTaskNo + '¤tTaskType=' + this.currentTaskType
|
||||
})
|
||||
},
|
||||
//切换任务
|
||||
async swichTask(index) {
|
||||
if (index == this.current) return
|
||||
this.current = index
|
||||
// 如果为0,意味着尚未初始化
|
||||
if (this.menuHeight == 0 || this.menuItemHeight == 0) {
|
||||
await this.getElRect('menu-scroll-view', 'menuHeight')
|
||||
await this.getElRect('u-tab-item', 'menuItemHeight')
|
||||
}
|
||||
// 将菜单菜单活动item垂直居中
|
||||
this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2
|
||||
|
||||
//获取任务详情
|
||||
this.currentTask = this.taskList[index]
|
||||
this.currentTaskNo = this.taskList[index].taskNo
|
||||
this.currentTaskType = this.taskList[index].taskType
|
||||
this.getAssayTaskDetail(this.currentTaskNo)
|
||||
},
|
||||
// 获取一个目标元素的高度
|
||||
getElRect(elClass, dataVal) {
|
||||
new Promise((resolve, reject) => {
|
||||
const query = uni.createSelectorQuery().in(this)
|
||||
query
|
||||
.select('.' + elClass)
|
||||
.fields({ size: true }, res => {
|
||||
// 如果节点尚未生成,res值为null,循环调用执行
|
||||
if (!res) {
|
||||
setTimeout(() => {
|
||||
this.getElRect(elClass)
|
||||
}, 10)
|
||||
return
|
||||
}
|
||||
this[dataVal] = res.height
|
||||
})
|
||||
.exec()
|
||||
})
|
||||
},
|
||||
getAssayTask() {
|
||||
//显示loading
|
||||
uni.showLoading({
|
||||
title: '加载中...'
|
||||
})
|
||||
const param = {
|
||||
operateType: 'weight',
|
||||
assayOper: this.userInfo.realname
|
||||
}
|
||||
this.$u.api
|
||||
.getAssayTaskList(param)
|
||||
.then(res => {
|
||||
this.taskList = res.result
|
||||
|
||||
if (this.taskList && this.taskList.length > 0) {
|
||||
this.currentTask = this.taskList[0]
|
||||
this.currentTaskNo = this.taskList[0].taskNo
|
||||
this.currentTaskType = this.taskList[0].taskType
|
||||
this.getAssayTaskDetail(this.currentTaskNo)
|
||||
}
|
||||
uni.hideLoading()
|
||||
})
|
||||
.catch(err => {
|
||||
uni.hideLoading()
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
getAssayTaskDetail(taskNo) {
|
||||
this.$u.api
|
||||
.getAssayTaskDetailListByTaskNo({ taskNo: taskNo })
|
||||
.then(res => {
|
||||
this.sampleList = res.result
|
||||
this.showLoading = false
|
||||
})
|
||||
.catch(err => {
|
||||
this.showLoading = false
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
getDataSourceTypeShow(val) {
|
||||
if (val == 2) return '【筛上】'
|
||||
if (val == 3) return '【筛下】'
|
||||
return ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content-title {
|
||||
height: 110rpx;
|
||||
width: 100%;
|
||||
font-size: 46rpx;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.content-title-name {
|
||||
padding: 20rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content-main-height {
|
||||
height: calc(100vh - 250rpx);
|
||||
}
|
||||
|
||||
.content-main-left {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
|
||||
.u-tab-item {
|
||||
padding: 10rpx;
|
||||
height: 200rpx;
|
||||
background: #f6f6f6;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 36rpx;
|
||||
color: #444;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
border-width: 4rpx;
|
||||
border-bottom: dotted;
|
||||
}
|
||||
|
||||
.u-tab-item-active {
|
||||
position: relative;
|
||||
color: #0055a2;
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.u-tab-item-active::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
|
||||
height: 32rpx;
|
||||
left: 0;
|
||||
top: 39rpx;
|
||||
}
|
||||
|
||||
.content-main-right {
|
||||
height: calc(100vh - 410rpx);
|
||||
}
|
||||
|
||||
.content-main-right-operation {
|
||||
height: 160rpx;
|
||||
padding-top: 30rpx;
|
||||
}
|
||||
|
||||
.btn-operation {
|
||||
height: 100rpx;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
</style>
|
||||
1434
pages/analysis/sample/sample-work-detail.vue
Normal file
1434
pages/analysis/sample/sample-work-detail.vue
Normal file
File diff suppressed because it is too large
Load Diff
746
pages/analysis/sample/sample-work-edit-task.vue
Normal file
746
pages/analysis/sample/sample-work-edit-task.vue
Normal file
@@ -0,0 +1,746 @@
|
||||
<template>
|
||||
<view>
|
||||
<navbar-back titleWidth="800" :title="title"></navbar-back>
|
||||
<u-row>
|
||||
<u-col span="1"></u-col>
|
||||
<u-col span="10">
|
||||
<scroll-view scroll-y scroll-with-animation :scroll-top="scrollTop">
|
||||
<u-form :model="taskInstance" ref="uForm" label-width="210">
|
||||
<view class="form-item-my" v-for="(field, index) in formFields" :key="'field_' + index">
|
||||
<view
|
||||
class="label-my"
|
||||
:style="{ fontWeight: checkFeadToDetailField(field.headToDetailField) ? 'bold' : 'normal' }"
|
||||
>{{ field.label }}</view
|
||||
>
|
||||
<view class="content-my">
|
||||
<view v-if="field.type == 'title' && field.display" class="content-title">
|
||||
{{ field.textValue }}
|
||||
</view>
|
||||
<!--普通输入框-->
|
||||
<u-input
|
||||
v-if="
|
||||
field.type == 'input' &&
|
||||
(field.decimalCount == null || field.decimalCount == '' || Number(field.decimalCount == null) < 0)
|
||||
"
|
||||
v-model="field.value"
|
||||
clearable
|
||||
:placeholder="field.placeholder"
|
||||
:disabled="field.fillingWay != '1'"
|
||||
/>
|
||||
<!--数字,限制小数位数-->
|
||||
<u-input
|
||||
v-if="field.type == 'input' && field.decimalCount != null && Number(field.decimalCount == null) >= 0"
|
||||
type="number"
|
||||
clearable
|
||||
@blur="event => checkDecimal(event, field)"
|
||||
v-model="field.value"
|
||||
:placeholder="field.placeholder"
|
||||
:disabled="field.fillingWay != '1'"
|
||||
/>
|
||||
<!--select-->
|
||||
<view v-if="field.type == 'select'" class="x-bc select-my" @click="handleFieldClick(field)">
|
||||
<text v-if="field.valueText">{{ field.valueText }}</text>
|
||||
<text v-else>请选择</text>
|
||||
<u-icon name="arrow-down" size="20"></u-icon>
|
||||
</view>
|
||||
<u-picker
|
||||
v-if="field.type == 'select'"
|
||||
:show="field.showPicker"
|
||||
:columns="[field.options]"
|
||||
keyName="displayName"
|
||||
@cancel="field.showPicker = false"
|
||||
@confirm="event => pickerConfirm(event, field)"
|
||||
/>
|
||||
<!--日期-->
|
||||
<view v-if="field.type == 'date'" class="x-bc select-my" @click="handleFieldClick(field)">
|
||||
<text v-if="field.value">{{ field.value }}</text>
|
||||
<text v-else>请选择</text>
|
||||
<u-icon name="calendar-fill" size="20"></u-icon>
|
||||
</view>
|
||||
|
||||
<u-datetime-picker
|
||||
v-if="field.type == 'date'"
|
||||
:show="field.showPicker"
|
||||
v-model="curDate"
|
||||
mode="date"
|
||||
@cancel="field.showPicker = false"
|
||||
@confirm="event => pickerConfirm(event, field)"
|
||||
></u-datetime-picker>
|
||||
</view>
|
||||
</view>
|
||||
</u-form>
|
||||
</scroll-view>
|
||||
<u-button type="primary" @click="saveHeadData">保存</u-button>
|
||||
</u-col>
|
||||
<u-col span="1"> </u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/nx/request'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import { calcAnalysisValue } from '@/nx/helper/calcAnalysisValue'
|
||||
import nx from '@/nx'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
title: '编辑指派单',
|
||||
taskInstance: {},
|
||||
scrollTop: 0, //tab标题的滚动条位置
|
||||
currentTaskNo: '', //当前任务样品
|
||||
showDicPicker: false,
|
||||
curDate: Number(new Date()),
|
||||
//字段值对象
|
||||
formValue: {},
|
||||
//后端返回的字段结构
|
||||
sourceFormFields: [],
|
||||
//处理后的字段结构
|
||||
formFields: [],
|
||||
sampleList: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
dynamicFieldPlaceholder(field) {
|
||||
return '请输入'
|
||||
}
|
||||
},
|
||||
onLoad(param) {
|
||||
if (param.currentTaskNo) {
|
||||
this.currentTaskNo = param.currentTaskNo
|
||||
}
|
||||
this.title = '样品分析-任务指派单:' + this.currentTaskNo
|
||||
this.loadHeadFieldsAndValueByTaskNo()
|
||||
this.getSampleList(this.currentTaskNo)
|
||||
},
|
||||
methods: {
|
||||
handleFieldClick(field) {
|
||||
if (field.type == 'date') {
|
||||
if (field.fillingWay == '1') {
|
||||
field.showPicker = true
|
||||
}
|
||||
return
|
||||
}
|
||||
field.showPicker = true
|
||||
},
|
||||
checkFeadToDetailField(headToDetailField) {
|
||||
if (headToDetailField && headToDetailField.trim() != '') {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
getSampleList(taskNo) {
|
||||
this.$u.api
|
||||
.getAssayTaskDetailListByTaskNo({ taskNo: taskNo })
|
||||
.then(res => {
|
||||
this.sampleList = res.result
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err)
|
||||
})
|
||||
},
|
||||
//返回上一页
|
||||
// customBack() {
|
||||
// uni.redirectTo({
|
||||
// url: "/pages/sample/sample-work-detail"
|
||||
// });
|
||||
// },
|
||||
navRightClick() {},
|
||||
//处理小数位数:补0或去除多余位数
|
||||
checkDecimal(e, field) {
|
||||
if (e == '') return
|
||||
const decimalCount = field.decimalCount
|
||||
if (decimalCount == null || decimalCount == '' || isNaN(decimalCount)) return
|
||||
const count = Number(field.decimalCount)
|
||||
const value = field.value
|
||||
const pos = value.indexOf('.') + 1
|
||||
let length = value.length - pos
|
||||
if (pos == 0) {
|
||||
length = 0
|
||||
}
|
||||
while (length < count) {
|
||||
if (field.value.indexOf('.') < 0) field.value += '.'
|
||||
field.value = field.value + '0'
|
||||
length++
|
||||
}
|
||||
if (count === 0) {
|
||||
field.value = parseInt(field.value) + ''
|
||||
} else if (length > count) {
|
||||
field.value = field.value.substring(0, pos + count)
|
||||
}
|
||||
},
|
||||
updateFieldValue(name, val) {
|
||||
for (const field of this.formFields) {
|
||||
if (field.prop == name) {
|
||||
field.value = val
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
assembleFields() {
|
||||
const me = this
|
||||
const formFields = []
|
||||
for (const field of this.sourceFormFields) {
|
||||
//日期类型的默认值
|
||||
if (field.type == 'date') {
|
||||
const value = field.value
|
||||
field.showPicker = false
|
||||
if (value == 'curDate') {
|
||||
field.value = me.$helper.dateFormat(new Date(), 'yyyy-MM-dd')
|
||||
}
|
||||
}
|
||||
if (field.type == 'select') {
|
||||
field.showPicker = false
|
||||
}
|
||||
formFields.push(field)
|
||||
}
|
||||
//先序列化再转json,避免json里定义的方法丢失
|
||||
this.formFields = JSON.parse(JSON.stringify(formFields, replacer), reviver)
|
||||
|
||||
// this.formFields = formFields;
|
||||
},
|
||||
//绑定数据
|
||||
bindFormValue() {
|
||||
const me = this
|
||||
//formValue
|
||||
for (const field of me.formFields) {
|
||||
const prop = field.prop
|
||||
if (prop) {
|
||||
const value = me.formValue[prop]
|
||||
if (value) {
|
||||
field.value = value
|
||||
if (field.type == 'select') {
|
||||
field.valueText = value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
//获取表单字段和值(老数据)
|
||||
loadHeadFieldsAndValueByTaskNo() {
|
||||
const me = this
|
||||
const currentTaskNo = me.currentTaskNo
|
||||
this.$u.api
|
||||
.queryHeadValueByTaskNo({ taskNo: currentTaskNo })
|
||||
.then(res => {
|
||||
const result = res.result
|
||||
const formConf = result.formConf
|
||||
me.sourceFormFields = eval(formConf)
|
||||
me.formValue = JSON.parse(result.formValue)
|
||||
//加载和处理表单字段
|
||||
me.assembleFields()
|
||||
//绑定数据
|
||||
me.bindFormValue()
|
||||
//读取字段里的动态选项
|
||||
me.loadFieldApiData()
|
||||
console.log('formFields', this.formFields)
|
||||
})
|
||||
.catch(err => {
|
||||
//如果没有查到数据,按配置读取新的表单字段
|
||||
me.getHeadFields()
|
||||
})
|
||||
},
|
||||
// 获取表单字段(新数据)
|
||||
getHeadFields() {
|
||||
const me = this
|
||||
const currentTaskNo = this.currentTaskNo
|
||||
uni.showLoading({
|
||||
title: '加载中...'
|
||||
})
|
||||
this.$u.api
|
||||
.queryHeadFieldsByTaskNo({ taskNo: currentTaskNo })
|
||||
.then(res => {
|
||||
me.sourceFormFields = me.analysisFormAndFields(res)
|
||||
//加载和处理表单字段
|
||||
me.assembleFields()
|
||||
//读取字段里的动态选项
|
||||
me.loadFieldApiData()
|
||||
})
|
||||
.finally(() => {
|
||||
uni.hideLoading()
|
||||
})
|
||||
},
|
||||
analysisFormAndFields(formRet) {
|
||||
const fieldsArray = []
|
||||
for (const form of formRet) {
|
||||
let content = cloneDeep(form.content)
|
||||
content = eval('(' + content + ')')
|
||||
const column = content.column
|
||||
for (const field of column) {
|
||||
fieldsArray.push(field)
|
||||
}
|
||||
}
|
||||
return fieldsArray
|
||||
},
|
||||
//将抬头字段值同步保存到明细字段
|
||||
saveHeadValueToDetail(onComplete) {
|
||||
//循环抬头字段,提取需哟保存到明细的字段
|
||||
const conf = []
|
||||
for (const field of this.formFields) {
|
||||
const prop = field.prop
|
||||
const headToDetailField = field.headToDetailField
|
||||
if (prop && headToDetailField && headToDetailField.trim() != '') {
|
||||
const value = field.value
|
||||
const r = {
|
||||
prop: field.prop,
|
||||
value: value,
|
||||
headToDetailField: headToDetailField
|
||||
}
|
||||
conf.push(r)
|
||||
}
|
||||
}
|
||||
const data = {
|
||||
taskNo: this.currentTaskNo,
|
||||
conf: conf
|
||||
}
|
||||
this.$u.api.saveHeadValueToDetail(data).then(res => {
|
||||
if (onComplete) onComplete()
|
||||
})
|
||||
},
|
||||
handleSave() {
|
||||
//显示loading
|
||||
uni.showLoading({
|
||||
title: '正在保存...'
|
||||
})
|
||||
//组装数据
|
||||
const formValue = {}
|
||||
for (const field of this.formFields) {
|
||||
const prop = field.prop
|
||||
if (prop) {
|
||||
formValue[prop] = field.value
|
||||
}
|
||||
}
|
||||
const value = {
|
||||
taskNo: this.currentTaskNo,
|
||||
formValue: JSON.stringify(formValue),
|
||||
formConf: JSON.stringify(this.sourceFormFields, replacer)
|
||||
}
|
||||
this.$u.api
|
||||
.saveHeadValue(value)
|
||||
.then(async res => {
|
||||
await this.saveHeadValueToDetail(async () => {
|
||||
if (this.checkPropertyEquality()) {
|
||||
await this.processIds(this.sampleList, 100)
|
||||
} else {
|
||||
uni.hideLoading()
|
||||
// this.$helper.showToast({
|
||||
// title: '保存成功!'
|
||||
// });
|
||||
uni.redirectTo({
|
||||
url: '/pages/analysis/sample/sample-work-detail?currentTaskNo=' + this.currentTaskNo
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
uni.hideLoading()
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
// 检查字段修改前和修改后字段值是否相等
|
||||
checkPropertyEquality() {
|
||||
for (const field of this.formFields) {
|
||||
const prop = field.prop
|
||||
if (prop && field['headToDetailField'] && field['headToDetailField'].trim() !== '') {
|
||||
const flag = this.formValue[prop] !== field.value ? true : false
|
||||
if (flag) return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
//保存抬头字段
|
||||
saveHeadData() {
|
||||
if (this.checkPropertyEquality()) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '您修改的字段将影响样品分析结果,系统将重新计算',
|
||||
showCancel: false,
|
||||
success: res => {
|
||||
if (res.confirm) {
|
||||
this.handleSave()
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.handleSave()
|
||||
}
|
||||
},
|
||||
// 通过样品id查询明细
|
||||
async getSampleDataById(taskDetailId) {
|
||||
let fieldGroup = []
|
||||
const { result, additionalProperties } = await this.$u.api.queryFieldsByTaskDetail({
|
||||
taskDetailId,
|
||||
isSearchSRange: '0'
|
||||
})
|
||||
fieldGroup = result
|
||||
const conAssayTaskId = additionalProperties.conAssayTaskId
|
||||
const busSubCSampleId = additionalProperties.busSubCSampleId
|
||||
const detail = additionalProperties.taskDetail
|
||||
//处理硫值、硫量:未保存过的数据,读取接口返回的硫值、硫量
|
||||
// this.loadSValue(detail);
|
||||
//按公式计算值,并检查原数据与计算后的数据是否一致
|
||||
try {
|
||||
calcAnalysisValue(fieldGroup)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
let valueList = []
|
||||
let cupNum = 0
|
||||
for (const g of fieldGroup) {
|
||||
for (const f of g.fields) {
|
||||
if (f.dicKey == 'bh' || f.dicKey == 'bh_up') cupNum = f.value
|
||||
valueList.push({
|
||||
id: f.detailId,
|
||||
type: f.pOrE,
|
||||
value: f.value,
|
||||
name: f.name,
|
||||
dataType: f.dataType
|
||||
})
|
||||
}
|
||||
}
|
||||
let params = {
|
||||
busSubCSampleId,
|
||||
conAssayTaskId,
|
||||
// measureTime : this.curSample.measureTime,
|
||||
elementParamValueList: valueList,
|
||||
busAssayTaskDetailId: taskDetailId
|
||||
}
|
||||
if (typeof cupNum != 'undefined' && cupNum != null && cupNum != '' && cupNum != 0 && cupNum != '0') {
|
||||
//提交杯号,保存到后台
|
||||
params.cupNum = cupNum
|
||||
}
|
||||
return params
|
||||
},
|
||||
// 提交样品
|
||||
async submitData(data) {
|
||||
try {
|
||||
await this.$u.api.saveDetailValue(data)
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
},
|
||||
async processIds(list, interval) {
|
||||
let index = 0
|
||||
const intervalId = setInterval(async () => {
|
||||
if (index < list.length) {
|
||||
const item = list[index]
|
||||
index++
|
||||
const params = await this.getSampleDataById(item['id'])
|
||||
await this.submitData(params)
|
||||
} else {
|
||||
clearInterval(intervalId) // 所有任务完成后清除定时器
|
||||
uni.redirectTo({
|
||||
url: '/pages/analysis/sample/sample-work-detail?currentTaskNo=' + this.currentTaskNo
|
||||
})
|
||||
}
|
||||
}, interval)
|
||||
},
|
||||
|
||||
async apiRequest(url) {
|
||||
return request({
|
||||
url: url,
|
||||
method: 'GET',
|
||||
custom: {
|
||||
isApiEncryption: true
|
||||
}
|
||||
})
|
||||
},
|
||||
//读取字段里的API选项
|
||||
async loadFieldApiData() {
|
||||
const formFields = this.formFields
|
||||
let changeFlag = false
|
||||
for (const field of formFields) {
|
||||
const dicUrl = field.dicUrl
|
||||
const type = field.type
|
||||
if (dicUrl && dicUrl != '') {
|
||||
//读取API选项
|
||||
try {
|
||||
const res = await this.apiRequest(dicUrl)
|
||||
|
||||
const data = res
|
||||
const confLabel = field.props.label
|
||||
const confValue = field.props.value
|
||||
const emptyItem = { name: '', displayName: '' }
|
||||
emptyItem[confLabel] = ''
|
||||
emptyItem[confValue] = ''
|
||||
//设置valueText、displayName
|
||||
for (const item of data) {
|
||||
if (item[confValue] == field.value) {
|
||||
changeFlag = true
|
||||
field.valueText = item[confLabel]
|
||||
}
|
||||
}
|
||||
// data.unshift(emptyItem) //添加空数据
|
||||
field.options = data
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
if (changeFlag) {
|
||||
const formFields = this.formFields
|
||||
// this.formFields = JSON.parse(JSON.stringify(formFields));
|
||||
this.formFields = JSON.parse(JSON.stringify(formFields, replacer), reviver)
|
||||
}
|
||||
},
|
||||
/*
|
||||
* 选择器组件确认事件
|
||||
* event: 事件默认参数
|
||||
* field: 当前字段
|
||||
* 处理逻辑:
|
||||
* field.value = 选中的值
|
||||
* field.valueText = 选中的文本
|
||||
* todo: 关联字段在动态字段的change事件处理
|
||||
* */
|
||||
pickerConfirm(event, field) {
|
||||
const me = this
|
||||
if (field.type == 'date') {
|
||||
field.value = nx.$dayjs(event.value).format(field.format)
|
||||
field.showPicker = false
|
||||
return
|
||||
}
|
||||
const confLabel = field.props.label
|
||||
const confValue = field.props.value
|
||||
const selected = event.value[0]
|
||||
const value = selected[confValue]
|
||||
const displayName = selected[confLabel]
|
||||
field.value = value
|
||||
field.valueText = displayName
|
||||
if (typeof field.change == 'function') {
|
||||
field.change({ value }, selected, me)
|
||||
}
|
||||
field.showPicker = false
|
||||
},
|
||||
checkLoadSValue() {
|
||||
const vKey = 'sRange'
|
||||
const vF = this.getFieldByKey(vKey)
|
||||
if (vF == null) return false
|
||||
const v = vF.value
|
||||
if (v == null || v == '') return true
|
||||
try {
|
||||
if (v == 0 || number(v) == 0) return true
|
||||
} catch (e) {}
|
||||
return false
|
||||
},
|
||||
//读取硫值、硫量
|
||||
loadSValue(detail) {
|
||||
let flag = this.checkLoadSValue()
|
||||
if (!flag) return
|
||||
const vKey = 'sValue'
|
||||
const rKey = 'sRange'
|
||||
const vF = this.getFieldByKey(vKey)
|
||||
if (vF != null) {
|
||||
vF.value = detail.svalue
|
||||
}
|
||||
const rF = this.getFieldByKey(rKey)
|
||||
if (rF != null) {
|
||||
rF.value = detail.srange
|
||||
}
|
||||
},
|
||||
getFieldByKey(key) {
|
||||
const group = this.fieldGroup
|
||||
let field = null
|
||||
for (let g of group) {
|
||||
for (let f of g.fields) {
|
||||
const dicKey = f.dicKey
|
||||
if (dicKey && dicKey == key) {
|
||||
field = f
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// console.log('field', JSON.stringify(field));
|
||||
return field
|
||||
}
|
||||
}
|
||||
}
|
||||
// 自定义 replacer,将函数转换为字符串。json序列化和反序列化时避免函数丢失
|
||||
function replacer(key, value) {
|
||||
if (typeof value === 'function') {
|
||||
return value.toString()
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// 自定义 reviver,将字符串转换回函数.json序列化和反序列化时避免函数丢失
|
||||
const functionKeys = ['change', 'dicFormatter']
|
||||
function reviver(key, value) {
|
||||
if (functionKeys.includes(key)) {
|
||||
// 将字符串转换为函数
|
||||
return new Function('return ' + value)()
|
||||
}
|
||||
return value
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.navbar-right {
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.content-title {
|
||||
width: 100%;
|
||||
font-size: 20px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.content-title-name {
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content-main-height {
|
||||
height: calc(100vh - 125px);
|
||||
}
|
||||
|
||||
.content-main-left {
|
||||
height: calc(100vh - 205px);
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
|
||||
.form-item-my {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.label-my {
|
||||
width: 170px; /* 标签宽度 */
|
||||
padding-right: 10px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.label-my sub {
|
||||
font-size: 0.6em; /* 调整下标字体大小 */
|
||||
vertical-align: sub; /* 调整下标垂直对齐 */
|
||||
}
|
||||
|
||||
.content-my {
|
||||
flex: 1;
|
||||
padding-left: 7px;
|
||||
.select-my {
|
||||
color: #303133;
|
||||
font-size: 15px;
|
||||
padding: 6px 8px;
|
||||
border: 1px solid #dcdcdc;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.u-tab-item {
|
||||
height: 80px;
|
||||
background: #f6f6f6;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 18px;
|
||||
color: #444;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
border-width: 2px;
|
||||
border-bottom: dotted;
|
||||
}
|
||||
|
||||
.u-tab-item-active {
|
||||
position: relative;
|
||||
color: #0055a2;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.u-tab-item-active::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
height: 16px;
|
||||
left: 0;
|
||||
top: 20px;
|
||||
}
|
||||
|
||||
.content-main-left-operation {
|
||||
height: 80px;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.content-main-right {
|
||||
height: calc(100vh - 205px);
|
||||
}
|
||||
|
||||
.content-main-right-operation {
|
||||
height: 80px;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.auncel-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.auncel {
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
background-image: url(/static/images/auncel.png);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.auncel-title {
|
||||
width: 100%;
|
||||
height: 210px;
|
||||
}
|
||||
|
||||
.auncel-weight {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.weight {
|
||||
width: 100%;
|
||||
min-width: 200px;
|
||||
height: 100px;
|
||||
padding: 0 15px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
//background-color: #2c405a;
|
||||
}
|
||||
|
||||
.weight-data {
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
color: #4cd964;
|
||||
text-align: right;
|
||||
line-height: 100px;
|
||||
letter-spacing: 2px;
|
||||
font-size: 75px;
|
||||
font-family: zzjc-lcd;
|
||||
}
|
||||
|
||||
.weight-data-yellow {
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
color: #ffff00;
|
||||
text-align: right;
|
||||
line-height: 100px;
|
||||
letter-spacing: 2px;
|
||||
font-size: 75px;
|
||||
font-family: zzjc-lcd;
|
||||
}
|
||||
|
||||
.weight-data-warning {
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
color: #ff3333;
|
||||
text-align: right;
|
||||
line-height: 100px;
|
||||
font-size: 75px;
|
||||
font-family: zzjc-lcd;
|
||||
}
|
||||
|
||||
.weight-unit {
|
||||
color: #ffffff;
|
||||
font-size: 65px;
|
||||
line-height: 100px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
</style>
|
||||
379
pages/analysis/sample/sample-work-list.vue
Normal file
379
pages/analysis/sample/sample-work-list.vue
Normal file
@@ -0,0 +1,379 @@
|
||||
<template>
|
||||
<view>
|
||||
<navbar-back :autoBack="false" title="样品分析" @leftClick="customBack"></navbar-back>
|
||||
<u-row class="content-title" gutter="16">
|
||||
<u-col span="4">
|
||||
<view class="content-title-name">
|
||||
<text>任务列表</text>
|
||||
</view>
|
||||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
<u-col span="8">
|
||||
<view class="content-title-name">
|
||||
<text>样品列表</text>
|
||||
</view>
|
||||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||||
</u-col>
|
||||
</u-row>
|
||||
<u-row class="content-main-height" gutter="16" align="top">
|
||||
<u-col span="4">
|
||||
<scroll-view
|
||||
scroll-y
|
||||
scroll-with-animation
|
||||
class="content-main-height content-main-left"
|
||||
:scroll-top="scrollTop"
|
||||
>
|
||||
<view
|
||||
v-for="(task, index) in taskList"
|
||||
:key="index"
|
||||
class="u-tab-item"
|
||||
:class="[current === index ? 'u-tab-item-active' : '']"
|
||||
@tap.stop="swichTask(index)"
|
||||
>
|
||||
<u-row style="width: 100%">
|
||||
<u-col span="2" style="text-align: center">
|
||||
<u-icon :color="taskStyle(task)" name="tags-fill" size="34"></u-icon>
|
||||
</u-col>
|
||||
<u-col span="10">
|
||||
<view class="fs18">{{ task.taskNo }}</view>
|
||||
<view style="margin-top: 10px">{{ task.taskName }}</view>
|
||||
<view class="x-f" style="margin-top: 10px">
|
||||
<u-icon color="" name="clock"></u-icon>
|
||||
<text style="margin-left: 5px">{{ task.taskOperTime }}</text>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</u-col>
|
||||
<u-col span="8">
|
||||
<view class="content-main-height">
|
||||
<scroll-view scroll-y scroll-with-animation class="content-main-right">
|
||||
<block v-for="(sample, index) in sampleList" :key="index">
|
||||
<view v-if="currentTask.reviewCount === sample.reviewCount" style="padding: 5px; font-size: 16px">
|
||||
<u-row>
|
||||
<u-col span="3" style="text-align: center">
|
||||
<u-row>
|
||||
<u-col span="6" style="text-align: center">
|
||||
<u-checkbox
|
||||
v-model="sample.checked"
|
||||
v-if="
|
||||
sample.sampleProcessNo === currentNode &&
|
||||
sample.rollbackStatus !== 'running' &&
|
||||
sample.rollbackStatus !== 'finished'
|
||||
"
|
||||
@change="() => selectSample(sample)"
|
||||
></u-checkbox>
|
||||
</u-col>
|
||||
<u-col span="6" style="text-align: center">
|
||||
<view
|
||||
><text>【{{ sample.sort }}】</text></view
|
||||
>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</u-col>
|
||||
<u-col span="9">
|
||||
<view class="sample_desc">
|
||||
<view>
|
||||
<view
|
||||
><text style="padding-left: 10px">{{ sample.sampleCode }}</text></view
|
||||
>
|
||||
<view>
|
||||
<text style="padding-left: 10px">
|
||||
{{ getDataSourceTypeShow(sample.dataSourceType) }}{{ sample.sampleName }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="sample_desc_warn" v-if="sample.sampleProcessNo !== currentNode">
|
||||
当前节点:{{ getProcessNameShow(sample.sampleProcessNo) }}
|
||||
</view>
|
||||
<view class="sample_desc_warn" v-if="sample.rollbackStatus === 'revoke'"> 样品退回被驳回 </view>
|
||||
<view class="sample_desc_warn" v-if="sample.rollbackStatus === 'running'"> 样品退回审批中 </view>
|
||||
<view class="sample_desc_warn" v-if="sample.rollbackStatus === 'finished'">
|
||||
样品已退回,请联系管理员处理
|
||||
</view>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
<u-line style="padding: 5px" color="#bbb" />
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
<view class="content-main-right-operation">
|
||||
<u-row>
|
||||
<u-col span="3.5"></u-col>
|
||||
<u-col span="4">
|
||||
<u-button class="btn-operation" type="warning" @click="showRollbackModal">申请退回样品</u-button>
|
||||
</u-col>
|
||||
<u-col span="4">
|
||||
<u-button class="btn-operation" :disabled="taskList.length === 0" type="success" @click="startWork">
|
||||
开始分析
|
||||
</u-button>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
|
||||
<!-- 退回样品弹窗 -->
|
||||
<up-modal
|
||||
:show="showRollbackModalFlag"
|
||||
showCancelButton
|
||||
@confirm="applyRollbackSample"
|
||||
@cancel="showRollbackModalFlag = false"
|
||||
title="退回说明"
|
||||
width="500px"
|
||||
>
|
||||
<u--textarea v-model="rollbackContent" placeholder="请输入退回原因或说明"></u--textarea>
|
||||
</up-modal>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { onLoad, onBackPress } from '@dcloudio/uni-app'
|
||||
import nx from '@/nx'
|
||||
import { useScreenOrientation } from '@/nx/hooks/useScreenOrientation'
|
||||
|
||||
// 响应式数据
|
||||
const currentNode = ref('F31')
|
||||
const dicSampleProcessCodeList = ref([])
|
||||
const showRollbackModalFlag = ref(false)
|
||||
const rollbackContent = ref('')
|
||||
const scrollTop = ref(0)
|
||||
const current = ref(0)
|
||||
const currentTask = ref({})
|
||||
const currentTaskNo = ref('')
|
||||
const currentTaskType = ref('')
|
||||
const taskList = ref([])
|
||||
const sampleList = ref([])
|
||||
|
||||
// 计算属性
|
||||
const userInfo = computed(() => nx.$store('user').userInfo)
|
||||
|
||||
// 方法
|
||||
const customBack = () => {
|
||||
uni.reLaunch({ url: '/pages/analysis/index/index' })
|
||||
}
|
||||
|
||||
const selectSample = sample => {
|
||||
sample.checked = !sample.checked
|
||||
}
|
||||
|
||||
const taskStyle = task => {
|
||||
if ((task.weightTaskStatus === 0 || task.weightTaskStatus === 1) && task.reviewCount > 0) return 'red'
|
||||
if (task.weightTaskStatus === 2 && task.reviewCount > 0) return 'green'
|
||||
return ''
|
||||
}
|
||||
|
||||
const showRollbackModal = () => {
|
||||
const checkedSampleList = sampleList.value.filter(item => item.checked)
|
||||
if (checkedSampleList.length === 0) {
|
||||
uni.showToast({ title: '请选择要退回的样品!', icon: 'none' })
|
||||
return
|
||||
}
|
||||
showRollbackModalFlag.value = true
|
||||
}
|
||||
|
||||
const applyRollbackSample = () => {
|
||||
const checkedSampleList = sampleList.value.filter(item => item.checked)
|
||||
if (!rollbackContent.value.trim()) {
|
||||
uni.showToast({ title: '请输入退回说明!', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
showRollbackModalFlag.value = false
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '发起申请,退回已勾选的样品,是否继续?',
|
||||
cancelColor: '#0055A2',
|
||||
confirmColor: '#0055A2',
|
||||
success: res => {
|
||||
if (res.cancel) return
|
||||
const detailIdList = checkedSampleList.map(item => item.id)
|
||||
const data = {
|
||||
remark: rollbackContent.value,
|
||||
taskId: currentTask.value.id,
|
||||
detailIds: detailIdList.join(',')
|
||||
}
|
||||
|
||||
uni.showLoading({ title: '正在发起申请...' })
|
||||
nx.$api.assayTask
|
||||
.createRollbackApply(data)
|
||||
.then(() => {
|
||||
getAssayTaskDetail(currentTaskNo.value)
|
||||
})
|
||||
.catch(console.error)
|
||||
.finally(() => {
|
||||
uni.hideLoading()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const checkWork = () => {
|
||||
let checkedSampleList = sampleList.value.filter(
|
||||
item => item.rollbackStatus === 'running' || item.rollbackStatus === 'finished'
|
||||
)
|
||||
if (checkedSampleList.length > 0) {
|
||||
uni.showToast({ title: '存在未处理的退回申请,请处理后再分析!', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
checkedSampleList = sampleList.value.filter(item => item.sampleProcessNo !== currentNode.value)
|
||||
if (checkedSampleList.length > 0) {
|
||||
uni.showToast({ title: '部分样品状态异常,请联系管理员处理!', icon: 'none', duration: 2300 })
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const startWork = () => {
|
||||
if (!checkWork()) return
|
||||
uni.navigateTo({
|
||||
url: `/pages/analysis/sample/sample-work-detail?currentTaskNo=${currentTaskNo.value}`
|
||||
})
|
||||
}
|
||||
|
||||
const swichTask = async index => {
|
||||
if (index === current.value) return
|
||||
current.value = index
|
||||
rollbackContent.value = ''
|
||||
|
||||
const task = taskList.value[index]
|
||||
currentTask.value = task
|
||||
currentTaskNo.value = task.taskNo
|
||||
currentTaskType.value = task.taskType
|
||||
getAssayTaskDetail(task.taskNo)
|
||||
}
|
||||
|
||||
const getAssayTask = () => {
|
||||
rollbackContent.value = ''
|
||||
const param = {
|
||||
finishStatus: 'waiting',
|
||||
assayOper: userInfo.value.nickname
|
||||
}
|
||||
nx.$api.auncel.getAssayTaskList(param).then(res => {
|
||||
if (res) {
|
||||
taskList.value = res
|
||||
if (taskList.value.length > 0) {
|
||||
const first = taskList.value[0]
|
||||
currentTask.value = first
|
||||
currentTaskNo.value = first.taskNo
|
||||
currentTaskType.value = first.taskType
|
||||
getAssayTaskDetail(first.taskNo)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getAssayTaskDetail = taskNo => {
|
||||
sampleList.value = []
|
||||
nx.$api.assayTask.getAssayTaskDetailListByTaskNo({ taskNo }).then(res => {
|
||||
const list = res.result || []
|
||||
list.forEach(item => (item.checked = false))
|
||||
sampleList.value = list
|
||||
})
|
||||
}
|
||||
|
||||
const getDicSampleProcessCodeList = () => {
|
||||
nx.$api.assayTask.queryQmsDicSampleProcessCodeList().then(res => {
|
||||
dicSampleProcessCodeList.value = res.records || []
|
||||
})
|
||||
}
|
||||
|
||||
const getProcessNameShow = val => {
|
||||
const item = dicSampleProcessCodeList.value.find(i => i.processCode === val)
|
||||
return item ? item.processName : val
|
||||
}
|
||||
|
||||
const getDataSourceTypeShow = val => {
|
||||
if (val === 2) return '【筛上】'
|
||||
if (val === 3) return '【筛下】'
|
||||
return ''
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
onLoad(() => {
|
||||
const { lockOrientation } = useScreenOrientation()
|
||||
lockOrientation('landscape')
|
||||
getDicSampleProcessCodeList()
|
||||
getAssayTask()
|
||||
})
|
||||
|
||||
onBackPress(() => {
|
||||
customBack()
|
||||
return true
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* 样式保持不变 */
|
||||
.content-title {
|
||||
height: 50px;
|
||||
width: 100%;
|
||||
font-size: 20px;
|
||||
font-weight: 300;
|
||||
}
|
||||
.content-title-name {
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
.content-main-height {
|
||||
height: calc(100vh - 125px);
|
||||
}
|
||||
.content-main-left {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
.u-tab-item {
|
||||
padding: 5px;
|
||||
height: 100px;
|
||||
background: #f6f6f6;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
color: #444;
|
||||
line-height: 1;
|
||||
border-width: 2px;
|
||||
border-bottom: dotted;
|
||||
}
|
||||
.u-tab-item-active {
|
||||
position: relative;
|
||||
color: #0055a2;
|
||||
font-weight: 600;
|
||||
background: #fff;
|
||||
}
|
||||
.u-tab-item-active::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
height: 16px;
|
||||
left: 0;
|
||||
top: 20px;
|
||||
}
|
||||
.content-main-right {
|
||||
height: calc(100vh - 205px);
|
||||
}
|
||||
.content-main-right-operation {
|
||||
height: 80px;
|
||||
padding-top: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
.btn-operation {
|
||||
height: 50px;
|
||||
font-size: 18px;
|
||||
width: 95%;
|
||||
}
|
||||
.sample_desc {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.sample_desc_warn {
|
||||
color: red;
|
||||
padding-right: 10px;
|
||||
}
|
||||
</style>
|
||||
240
pages/analysis/setting/print.vue
Normal file
240
pages/analysis/setting/print.vue
Normal file
@@ -0,0 +1,240 @@
|
||||
<template>
|
||||
<view>
|
||||
<navbar-back title="打印服务">
|
||||
<view class="navbar-right" slot="right">
|
||||
<view class="message-box right-item" @click="refreshPrint">
|
||||
<up-icon name="reload" color="#fff" size="20" />
|
||||
</view>
|
||||
<view class="dot-box right-item" @click="addPrintShow">
|
||||
<up-icon name="plus" color="#fff" size="20" />
|
||||
</view>
|
||||
</view>
|
||||
</navbar-back>
|
||||
|
||||
<view>
|
||||
<u-swipe-action
|
||||
v-for="(print, index) in printList"
|
||||
:key="index"
|
||||
:index="index"
|
||||
:options="options"
|
||||
@click="printSwipeClick"
|
||||
>
|
||||
<view class="item u-border-bottom">
|
||||
<image :src="`/static/images/print${print.isOpen ? '' : '-close'}.png`" mode="aspectFill" />
|
||||
<view style="width: 100%; padding-left: 30px; margin: 30px">
|
||||
<u-row>
|
||||
<u-col span="6">
|
||||
<text>服务名称:{{ print.printName }}</text>
|
||||
</u-col>
|
||||
<u-col span="6">
|
||||
<text>服务IP地址:{{ print.printIp }}</text>
|
||||
</u-col>
|
||||
</u-row>
|
||||
<u-row>
|
||||
<u-col span="6">
|
||||
<text>服务端口:{{ print.printPort }}</text>
|
||||
</u-col>
|
||||
<u-col span="6">
|
||||
<text>连接状态:{{ print.isOpen ? '连接正常!!!' : '连接关闭!!!' }}</text>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</view>
|
||||
</u-swipe-action>
|
||||
</view>
|
||||
|
||||
<u-modal
|
||||
:show="printShow"
|
||||
title="添加打印服务"
|
||||
show-cancel-button
|
||||
width="50vw"
|
||||
confirm-text="添加"
|
||||
@confirm="addPrint"
|
||||
@cancel="printShow = false"
|
||||
>
|
||||
<view class="slot-content">
|
||||
<u-form :model="form">
|
||||
<u-form-item label="名称">
|
||||
<u-input v-model="form.printName" />
|
||||
</u-form-item>
|
||||
<u-form-item label="IP">
|
||||
<u-input v-model="form.printIp" />
|
||||
</u-form-item>
|
||||
<u-form-item label="端口">
|
||||
<u-input v-model="form.printPort" type="number" />
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
</view>
|
||||
</u-modal>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
|
||||
// 响应式数据
|
||||
const printShow = ref(false)
|
||||
const printList = ref([])
|
||||
|
||||
const form = ref({
|
||||
printName: '',
|
||||
printIp: '',
|
||||
printPort: 22333
|
||||
})
|
||||
|
||||
const options = [
|
||||
{
|
||||
text: '删除',
|
||||
style: {
|
||||
fontSize: '28rpx',
|
||||
backgroundColor: 'rgb(255,58,49)'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
// 方法
|
||||
const addPrintShow = () => {
|
||||
if (printList.value.length > 0) {
|
||||
uni.showToast({
|
||||
title: '已存在打印服务!',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
form.value = {
|
||||
printName: '',
|
||||
printIp: '',
|
||||
printPort: 22333
|
||||
}
|
||||
printShow.value = true
|
||||
}
|
||||
|
||||
const refreshPrint = () => {
|
||||
const printListData = uni.getStorageSync('KEY_PRINT_LIST') || []
|
||||
if (printListData.length > 0) {
|
||||
printListData.forEach(print => {
|
||||
uni.$print.open(print.printIp)
|
||||
})
|
||||
uni.showToast({
|
||||
title: '刷新成功!',
|
||||
icon: 'none'
|
||||
})
|
||||
} else {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '未配置打印服务,请点击右边的“+”配置打印服务!',
|
||||
showCancel: false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const addPrint = () => {
|
||||
const { printName, printIp, printPort } = form.value
|
||||
|
||||
if (!printName.trim()) {
|
||||
uni.showToast({ title: '打印服务名称不允许为空!', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!printIp.trim()) {
|
||||
uni.showToast({ title: '打印服务IP不允许为空!', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
const ipReg =
|
||||
/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/
|
||||
if (!ipReg.test(printIp)) {
|
||||
uni.showToast({ title: '打印服务IP不正确!', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
let storedList = uni.getStorageSync('KEY_PRINT_LIST') || []
|
||||
const exists = storedList.some(p => p.printIp === printIp)
|
||||
if (exists) {
|
||||
uni.showToast({ title: '打印服务已存在!', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
storedList.push({
|
||||
printName,
|
||||
printIp,
|
||||
printPort,
|
||||
isDefault: storedList.length === 0
|
||||
})
|
||||
|
||||
uni.$print.open(printIp)
|
||||
uni.setStorageSync('KEY_PRINT_LIST', storedList)
|
||||
refreshList()
|
||||
printShow.value = false
|
||||
}
|
||||
|
||||
const printSwipeClick = (index, optionsIndex) => {
|
||||
if (optionsIndex === 0) {
|
||||
const delPrint = printList.value[index]
|
||||
uni.$print.close(delPrint.printIp)
|
||||
|
||||
printList.value.splice(index, 1)
|
||||
|
||||
if (delPrint.isDefault && printList.value.length > 0) {
|
||||
printList.value[0].isDefault = true
|
||||
}
|
||||
|
||||
uni.setStorageSync('KEY_PRINT_LIST', printList.value)
|
||||
uni.showToast({ title: '删除成功!', icon: 'none' })
|
||||
}
|
||||
}
|
||||
|
||||
const refreshList = () => {
|
||||
const stored = uni.getStorageSync('KEY_PRINT_LIST') || []
|
||||
printList.value = stored.map(print => {
|
||||
const printer = uni.$print.printMap?.get(print.printIp)
|
||||
return {
|
||||
...print,
|
||||
isOpen: printer ? printer.isOpen : false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
refreshList()
|
||||
uni.$on('printStatus', refreshList)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
uni.$off('printStatus', refreshList)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.navbar-right {
|
||||
margin-right: 12px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.right-item {
|
||||
margin: 0 6px;
|
||||
position: relative;
|
||||
color: #ffffff;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.slot-content {
|
||||
font-size: 14px;
|
||||
color: $u-content-color;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 60px;
|
||||
flex: 0 0 60px;
|
||||
height: 60px;
|
||||
margin-right: 10px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
</style>
|
||||
23
pages/analysis/setting/setting.vue
Normal file
23
pages/analysis/setting/setting.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<view>
|
||||
<navbar-back title="系统设置"></navbar-back>
|
||||
<view>
|
||||
<u-cell-group title="打印设置">
|
||||
<u-cell icon="order" title="打印服务" @click="nx.$router.go('/pages/analysis/setting/print')"></u-cell>
|
||||
</u-cell-group>
|
||||
<u-cell-group title="天平状态">
|
||||
<u-cell
|
||||
icon="hourglass-half-fill"
|
||||
title="查看天平"
|
||||
@click="nx.$router.go('/pages/analysis/auncel/auncel-status')"
|
||||
></u-cell>
|
||||
</u-cell-group>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import nx from '@/nx'
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
Reference in New Issue
Block a user