1407 lines
39 KiB
Vue
1407 lines
39 KiB
Vue
<template>
|
||
<view>
|
||
<navbar-back :autoBack="false" titleWidth="800" :title="title" @leftClick="customBack">
|
||
<view class="navbar-right" @click="navRightClick">
|
||
<text>填写任务单</text>
|
||
<u-icon color="" name="edit-pen" size="19"></u-icon>
|
||
</view>
|
||
</navbar-back>
|
||
|
||
<u-row gutter="8">
|
||
<u-col span="3">
|
||
<up-tabs
|
||
:current="activeAssayTypeIndex"
|
||
:list="assayGroups"
|
||
lineColor="#5ac725"
|
||
:activeStyle="{
|
||
fontWeight: 'bold',
|
||
color: '#0055a2'
|
||
}"
|
||
:itemStyle="{
|
||
height: '35px'
|
||
}"
|
||
@change="handleAssayTypeChange"
|
||
></up-tabs>
|
||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||
</u-col>
|
||
<u-col span="6">
|
||
<view class="content-title-name">
|
||
<view class="current-sample-code">{{ currentSampleData.sampleCode }}</view>
|
||
<view>数据采集或录入</view>
|
||
</view>
|
||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||
</u-col>
|
||
<u-col span="3">
|
||
<u-dropdown style="height: 35px">
|
||
<u-dropdown-item
|
||
v-model="curParameterKey"
|
||
:title="curParameterTitle"
|
||
height="70vh"
|
||
:options="fieldGroup"
|
||
@change="parameterClassifyChange"
|
||
></u-dropdown-item>
|
||
</u-dropdown>
|
||
<u-gap height="5" bg-color="#0055A2"></u-gap>
|
||
</u-col>
|
||
</u-row>
|
||
<u-row gutter="8" align="top">
|
||
<u-col span="3">
|
||
<scroll-view class="content-left-scroll" scroll-with-animation scroll-y :scroll-top="scrollTop">
|
||
<view
|
||
v-for="(sample, index) in sampleDataList"
|
||
:key="index"
|
||
class="u-tab-item"
|
||
:class="[
|
||
currentSampleIndex === index ? 'u-tab-item-active' : '',
|
||
sample.rollbackStatus === 'in_progress' ? 'u-tab-item-disabled' : ''
|
||
]"
|
||
:data-current="index"
|
||
@tap.stop="switchSample(index, false)"
|
||
>
|
||
<u-badge type="warning" :value="index + 1"></u-badge>
|
||
<view class="ml20">
|
||
<view>
|
||
{{ sample.sampleCode }}
|
||
</view>
|
||
<view> {{ sample.sampleName }} </view>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
<u-button
|
||
v-if="taskIngredientsStatus === 'allow_submit'"
|
||
class="btn-operation"
|
||
type="primary"
|
||
@click="submitTask()"
|
||
>数据上报</u-button
|
||
>
|
||
<u-button
|
||
v-else
|
||
class="btn-operation"
|
||
type="primary"
|
||
:disabled="taskIngredientsStatus === 'in_progress'"
|
||
@click="handleIngredients()"
|
||
>{{ taskIngredientsStatus === 'initial' ? '下发配料' : '等待配料' }}</u-button
|
||
>
|
||
</u-col>
|
||
<u-col span="6">
|
||
<view class="field-name" v-html="selectedField.title" />
|
||
<zzjc-num-keyboard
|
||
ref="myKeyboard"
|
||
v-show="selectedField.fillingWay == 'keyboard' && selectedField.type != 'select'"
|
||
:numKeyboardParam="numKeyboardParam"
|
||
></zzjc-num-keyboard>
|
||
<view v-if="selectedField.fillingWay == 'collect'" class="y-f">
|
||
<view class="auncel" @click="selectAuncel">
|
||
<view class="code">{{ currentAuncel.code }}</view>
|
||
<view class="auncel-title"> 杯号:{{ currentCupNum }} </view>
|
||
<view class="auncel-weight">
|
||
<view class="weight">
|
||
<view
|
||
:style="{ textAlign: !currentAuncel.isConnected ? 'center' : 'right' }"
|
||
:class="
|
||
currentAuncel.weightStable === 0
|
||
? 'weight-data-yellow'
|
||
: currentAuncel.weightStable === 1
|
||
? 'weight-data'
|
||
: 'weight-data-warning'
|
||
"
|
||
>
|
||
{{ currentAuncel.weightData }}
|
||
</view>
|
||
</view>
|
||
<view class="weight-unit">{{ currentAuncel.weightUnit }}</view>
|
||
</view>
|
||
</view>
|
||
|
||
<u-button
|
||
class="btn-operation"
|
||
type="success"
|
||
:disabled="confirmWeightDisabled"
|
||
shape="circle"
|
||
@click="saveAuncelData"
|
||
>
|
||
确认采集
|
||
</u-button>
|
||
</view>
|
||
<view v-if="selectedField.fillingWay === 'input'" class="p8">
|
||
<up-textarea v-model="inputValue" placeholder="请输入内容"></up-textarea>
|
||
<view class="x-c mt20 pl100 pr100">
|
||
<up-button @click="handleResetInputValue" style="width: 30%" :plain="true" text="清空"></up-button>
|
||
<up-button
|
||
@click="selectedField.value = inputValue"
|
||
style="width: 30%"
|
||
type="success"
|
||
text="确认"
|
||
></up-button>
|
||
</view>
|
||
</view>
|
||
</u-col>
|
||
<u-col span="3">
|
||
<view>
|
||
<scroll-view class="content-right-scroll" scroll-y scroll-with-animation>
|
||
<view>
|
||
<!-- <template v-for="(fields, groupIndex) in fieldGroup" :key="'group_' + groupIndex"> -->
|
||
<!-- <view> -->
|
||
<!-- 组名 -->
|
||
<!-- <view class="my-collapse" @click="fields.open = !fields.open">
|
||
<text class="title">{{ fields.title }}</text>
|
||
<u-icon :name="fields.open ? 'arrow-up' : 'arrow-down'"></u-icon>
|
||
</view>
|
||
<view
|
||
class="content"
|
||
:id="'elId' + groupIndex"
|
||
:style="{ height: fields.open ? collaHeights[groupIndex] + 'px' : '0' }"
|
||
> -->
|
||
<up-collapse ref="collapseRef" :value="activeCollapses" :border="false">
|
||
<template v-for="(fields, groupIndex) in currentGroup">
|
||
<up-collapse-item v-if="fields.label !== '全部'">
|
||
<template #title>
|
||
<text class="font-bold">{{ fields.label }}</text>
|
||
</template>
|
||
<template v-for="(field, fieldIndex) in fields.fields" :key="groupIndex + '-' + fieldIndex">
|
||
<view
|
||
class="form-item-my"
|
||
@click="fieldClick(field, groupIndex + '-' + fieldIndex)"
|
||
v-show="field.hidden != 1"
|
||
:class="{
|
||
'selected-field': groupFieldIndex === groupIndex + '-' + fieldIndex,
|
||
'disabled-field': !field.isEdit
|
||
}"
|
||
>
|
||
<view
|
||
:class="['label-my', { 'label-high-light': field.highlight == 1 }]"
|
||
v-html="field.title"
|
||
></view>
|
||
<view class="content-my">
|
||
<!--
|
||
如果是select,渲染2个组件:1个input、1个picker.
|
||
field.valueText用于显示picker选中的文本
|
||
1,键盘输入,2、天平,3、自动计算,4、文本输入
|
||
-->
|
||
<!-- <u-input
|
||
border="bottom"
|
||
style="width: 120px"
|
||
v-if="field.fillingWay == 'input'"
|
||
v-model="field.value"
|
||
placeholder="请输入"
|
||
/> -->
|
||
|
||
<!-- <view v-if="field.type === 'select'" class="x-bc select-my" @click="field.showPicker = true">
|
||
<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="dictValue"
|
||
@cancel="field.showPicker = false"
|
||
@confirm="event => dicPickerConfirm(event, field)"
|
||
/> -->
|
||
<!--普通输入框 使用文本显示-->
|
||
<view class="content-my-text" v-if="field.dataType != 'select'">
|
||
<text v-if="!field.value" class="content-my-text-placeholder">{{
|
||
!field.fillingWay || field.fillingWay == 'calculate' ? '计算值' : '请输入'
|
||
}}</text>
|
||
<text
|
||
v-else
|
||
:class="['content-my-text-value', { 'field-high-light': field.highlight == 1 }]"
|
||
>{{ field.value }}</text
|
||
>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view
|
||
v-if="field.validation"
|
||
class="fs12"
|
||
:class="field.validation?.promptType === 'warning' ? 'valid-warning' : 'valid-error'"
|
||
>{{ field.validation?.promptMsg }}</view
|
||
>
|
||
</template>
|
||
</up-collapse-item>
|
||
</template>
|
||
</up-collapse>
|
||
<!-- </view>
|
||
</view> -->
|
||
<!-- </template> -->
|
||
</view>
|
||
</scroll-view>
|
||
<u-button class="btn-operation" type="success" @click="saveDetail()">保存样品数据</u-button>
|
||
</view>
|
||
</u-col>
|
||
</u-row>
|
||
<!-- 天平选择-->
|
||
<auncel-select-popup
|
||
ref="auncelSelector"
|
||
v-model:showAuncelSelector="showAuncelSelector"
|
||
:previousAuncelId="currentAuncel.id"
|
||
@doSelect="auncelDoSelect"
|
||
></auncel-select-popup>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, reactive, computed, nextTick, watch, getCurrentInstance } from 'vue'
|
||
import { onLoad, onBackPress, onShow, onHide, onUnload } from '@dcloudio/uni-app'
|
||
import request from '@/nx/request'
|
||
import {
|
||
calcAnalysisValue,
|
||
handleRoundFiveNumber,
|
||
calcRowAnalysisValue,
|
||
math,
|
||
groupByField,
|
||
validateElementRange
|
||
} from '@/nx/helper/calcAnalysisValue'
|
||
import { number } from 'mathjs'
|
||
import AuncelSelectPopup from '@/components/sample/auncel-select-popup.vue'
|
||
import { getTenantId } from '@/defaultBaseUrl'
|
||
import { useScreenOrientation } from '@/nx/hooks/useScreenOrientation'
|
||
import nx from '@/nx'
|
||
import { getDataSourceTypeShow } from '../common'
|
||
import tools from '@/nx/utils/tools'
|
||
|
||
const { proxy } = getCurrentInstance()
|
||
|
||
// 响应式数据定义
|
||
const taskId = ref('')
|
||
const taskIngredientsStatus = ref('') //配料状态
|
||
const configReportTemplateKey = ref('')
|
||
const elId = nx.$helper.uuid()
|
||
const scrollTop = ref(0) //tab标题的滚动条位置
|
||
const menuHeight = ref(0) // 左边菜单的高度
|
||
const menuItemHeight = ref(0) // 左边菜单item的高度
|
||
const weightDataIsToZero = ref(false) //重量数据是否归零
|
||
const currentSampleIndex = ref(0) // 预设当前项的值
|
||
let sampleDataList = ref([])
|
||
const title = ref('')
|
||
const numKeyboardParam = reactive({
|
||
decimal: '-1' //数字键盘小数位数,-1为不限制
|
||
})
|
||
const showAuncelSelector = ref(false) //显示天平选择框
|
||
const currentAuncel = ref({
|
||
id: '',
|
||
name: '',
|
||
code: '',
|
||
weightStable: 0,
|
||
weightData: '请选天平',
|
||
weightUnit: ''
|
||
})
|
||
let selectedField = ref({})
|
||
const groupFieldIndex = ref('') //分组的索引
|
||
const curParameterTitle = ref('选择字段分类')
|
||
const curParameterKey = ref('all')
|
||
const conAssayTaskId = ref('')
|
||
const busSubCSampleId = ref('')
|
||
let fieldGroup = ref([])
|
||
const collaHeights = ref([])
|
||
const cupNumKey = '杯号'
|
||
const inputValue = ref('')
|
||
|
||
function handleResetInputValue() {
|
||
inputValue.value = ''
|
||
}
|
||
// refs
|
||
const myKeyboard = ref(null)
|
||
const auncelSelector = ref(null)
|
||
|
||
// 计算属性
|
||
const confirmWeightDisabled = computed(() => {
|
||
if (currentAuncel.value.weightStable === 1 && Number(currentAuncel.value.weightData) > 0) {
|
||
return false
|
||
}
|
||
return true
|
||
})
|
||
|
||
const userInfo = computed(() => nx.$store('user').userInfo)
|
||
|
||
// 方法定义
|
||
const getDomHeight = async () => {
|
||
await nextTick() // 等待 DOM 更新完成
|
||
collaHeights.value = []
|
||
if (fieldGroup.value.length) {
|
||
fieldGroup.value.forEach((item, index) => {
|
||
proxy.$u.getRect('#elId' + index).then(res => {
|
||
collaHeights.value.push(res.height)
|
||
})
|
||
})
|
||
}
|
||
}
|
||
|
||
//返回上一页
|
||
const customBack = () => {
|
||
uni.redirectTo({
|
||
url: '/pages/analysis/sample/sample-work-list'
|
||
})
|
||
}
|
||
|
||
const navRightClick = () => {
|
||
let url = '/pages/analysis/sample/sample-work-edit-task'
|
||
url += '?currentTaskId=' + taskId.value
|
||
uni.navigateTo({
|
||
url: url
|
||
})
|
||
}
|
||
|
||
const parameterClassifyChange = v => {
|
||
curParameterKey.value = v
|
||
curParameterTitle.value = currentGroup.value[0].label
|
||
groupFieldIndex.value = ''
|
||
selectedField.value = {}
|
||
collapseRef.value.init()
|
||
autoNextField()
|
||
}
|
||
|
||
const fieldClick = (field, key) => {
|
||
if (!field.isEdit) return
|
||
if (field.fillingWay === 'input') {
|
||
inputValue.value = field.value
|
||
}
|
||
selectedField.value = field
|
||
groupFieldIndex.value = key
|
||
if (myKeyboard.value) {
|
||
myKeyboard.value.clearNum()
|
||
}
|
||
//判断小数位数
|
||
let decimalPosition = field.decimalPosition
|
||
if (decimalPosition == null || decimalPosition < -1) decimalPosition = -1
|
||
numKeyboardParam.decimal = decimalPosition
|
||
if (field.fillingWay == 'collect') {
|
||
listenDeviceData()
|
||
} else {
|
||
closeDeviceListener()
|
||
}
|
||
}
|
||
|
||
//自动切换到下一个字段
|
||
const autoNextField = () => {
|
||
let groupIndex = 0
|
||
let fieldIndex = 0
|
||
if (typeof groupFieldIndex.value === 'undefined' || groupFieldIndex.value === '') groupFieldIndex.value = '0-'
|
||
const indexV = groupFieldIndex.value.split('-')
|
||
groupIndex = number(indexV[0])
|
||
fieldIndex = indexV[1] === '' ? -1 : number(indexV[1])
|
||
const group = currentGroup.value[groupIndex]
|
||
const fields = group.fields
|
||
if (fields.length > fieldIndex + 1) {
|
||
//切换到下一个字段
|
||
const key = groupIndex + '-' + (fieldIndex + 1)
|
||
fieldClick(fields[fieldIndex + 1], key)
|
||
}
|
||
}
|
||
|
||
//自动切换到下一个样品
|
||
const autoNextSample = indexParam => {
|
||
let index = 0
|
||
if (indexParam !== undefined) {
|
||
index = indexParam
|
||
} else {
|
||
index = currentSampleIndex.value + 1
|
||
}
|
||
|
||
// 在数组范围内,且当前样品是 in_progress,就继续往后找
|
||
while (index < sampleDataList.value.length) {
|
||
const sample = sampleDataList.value[index]
|
||
|
||
if (sample.rollbackStatus !== 'in_progress') {
|
||
// 找到了合法的样品,切换
|
||
switchSample(index, true)
|
||
return
|
||
}
|
||
index++
|
||
}
|
||
}
|
||
|
||
//手动切换样品
|
||
const switchSample = async (index, autoFlag) => {
|
||
// if (!autoFlag) {
|
||
// const shouldContinue = await tools.showPromiseModal(
|
||
// '提示',
|
||
// `请确认样品【${currentSampleData.value.sampleCode}】数据已经保存,是否继续?`
|
||
// )
|
||
// if (!shouldContinue) {
|
||
// return // 用户点了取消,直接退出
|
||
// }
|
||
// }
|
||
//重置天平归0
|
||
weightDataIsToZero.value = false
|
||
if (index === currentSampleIndex.value) return
|
||
currentSampleIndex.value = index
|
||
// 如果为0,意味着尚未初始化
|
||
if (menuHeight.value === 0 || menuItemHeight.value === 0) {
|
||
const rect = await getElRect('u-tab-item')
|
||
menuItemHeight.value = rect.height
|
||
}
|
||
// 将菜单菜单活动item垂直居中
|
||
scrollTop.value = index * menuItemHeight.value + menuItemHeight.value / 2 - menuHeight.value / 2 - 50
|
||
uni.showLoading({ title: '加载中...' })
|
||
setValueToField()
|
||
autoGenerateCupNum()
|
||
setTimeout(() => {
|
||
uni.hideLoading()
|
||
}, 500)
|
||
}
|
||
|
||
// 获取一个目标元素的高度
|
||
const getElRect = (elClass, maxRetry = 50) => {
|
||
return new Promise((resolve, reject) => {
|
||
let retryCount = 0
|
||
const execQuery = () => {
|
||
uni
|
||
.createSelectorQuery()
|
||
.in(proxy)
|
||
.select('.' + elClass)
|
||
.fields({ size: true, rect: true })
|
||
.exec(res => {
|
||
const result = res[0] // exec 返回数组,取第一个
|
||
if (result) {
|
||
resolve(result)
|
||
} else if (retryCount < maxRetry) {
|
||
retryCount++
|
||
setTimeout(execQuery, 10)
|
||
} else {
|
||
reject(new Error(`无法获取元素 .${elClass} 的尺寸,已重试 ${maxRetry} 次`))
|
||
}
|
||
})
|
||
}
|
||
|
||
execQuery()
|
||
})
|
||
}
|
||
|
||
//读取样品明细字段
|
||
const getDetailFieldsAndStatus = autoSelectNextField => {
|
||
const taskDetailId = currentSampleData.value.id
|
||
//读取回收率配置
|
||
loadConRecoveryList()
|
||
conAssayTaskId.value = res.additionalProperties.conAssayTaskId
|
||
busSubCSampleId.value = res.additionalProperties.busSubCSampleId
|
||
const detail = res.additionalProperties.taskDetail
|
||
//处理硫值、硫量:未保存过的数据,读取接口返回的硫值、硫量
|
||
loadSValue(detail)
|
||
calAndCheck()
|
||
}
|
||
|
||
const checkLoadSValue = () => {
|
||
const vKey = 'sRange'
|
||
const vF = 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
|
||
}
|
||
|
||
//读取硫值、硫量
|
||
const loadSValue = detail => {
|
||
let flag = checkLoadSValue()
|
||
if (!flag) return
|
||
const vKey = 'sValue'
|
||
const rKey = 'sRange'
|
||
const vF = getFieldByKey(vKey)
|
||
if (vF !== null) {
|
||
vF.value = detail.svalue
|
||
}
|
||
const rF = getFieldByKey(rKey)
|
||
if (rF !== null) {
|
||
rF.value = detail.srange
|
||
}
|
||
}
|
||
|
||
const getFieldByKey = key => {
|
||
const group = fieldGroup.value
|
||
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
|
||
}
|
||
}
|
||
}
|
||
return field
|
||
}
|
||
|
||
//按公式计算值,并检查原数据与计算后的数据是否一致
|
||
const calAndCheck = () => {
|
||
//提取原本数值
|
||
const oldVal = fitUpValues()
|
||
calcAnalysisValue(fieldGroup.value)
|
||
if (checkDataNew(oldVal)) return
|
||
const newVal = fitUpValues(oldVal)
|
||
//检查是否一致
|
||
let modifyFlag = false
|
||
for (const o in oldVal) {
|
||
let old = oldVal[o]
|
||
if (old === null) old = 0
|
||
//判断是否number
|
||
try {
|
||
if (number(old) !== number(newVal[o])) {
|
||
modifyFlag = true
|
||
}
|
||
} catch (e) {
|
||
if (old !== newVal[o]) modifyFlag = true
|
||
}
|
||
}
|
||
if (modifyFlag)
|
||
uni.showToast({
|
||
title: '数据有修改,请检查所有样品,并重新保存!',
|
||
duration: 2000,
|
||
icon: 'error'
|
||
})
|
||
}
|
||
|
||
//检查是否是新数据
|
||
const checkDataNew = data => {
|
||
for (const o in data) {
|
||
if (data[o] !== null && data[o] !== '0') return false
|
||
}
|
||
return true
|
||
}
|
||
|
||
//组装表单值,用于数据比对
|
||
const fitUpValues = () => {
|
||
const val = {}
|
||
for (const g of fieldGroup.value) {
|
||
for (const f of g.fields) {
|
||
const detailId = f.detailId
|
||
if (!detailId) continue
|
||
val[detailId] = f.value
|
||
}
|
||
}
|
||
return val
|
||
}
|
||
|
||
const checkBh = () => {
|
||
//检查杯号
|
||
let hasHb = true
|
||
for (const g of fieldGroup.value) {
|
||
for (const f of g.fields) {
|
||
if (f.title && f.title.indexOf(cupNumKey) >= 0) {
|
||
if (typeof f.value === 'undefined' || f.value === null || f.value === '') hasHb = false
|
||
}
|
||
}
|
||
}
|
||
if (!hasHb) {
|
||
nx.$helper.showToast({
|
||
title: '杯号不能为空,请填写杯号!'
|
||
})
|
||
return false
|
||
}
|
||
return true
|
||
}
|
||
const checkRange = async () => {
|
||
for (const g of fieldGroup.value) {
|
||
for (const f of g.fields) {
|
||
if (f.validation) {
|
||
if (f.validation.promptType === 'error') {
|
||
nx.$helper.showToast({
|
||
title: '存在范围校验错误,请修正后再保存!',
|
||
icon: 'error',
|
||
duration: 2000
|
||
})
|
||
return false
|
||
}
|
||
if (f.validation.promptType === 'warning') {
|
||
const confirm = await tools.showPromiseModal('提示', '检测到范围警告,是否继续保存?')
|
||
return confirm
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return true // 无问题,通过
|
||
}
|
||
const saveAuncelData = () => {
|
||
//保存数据
|
||
if (!weightDataIsToZero.value) {
|
||
nx.$helper.showToast({
|
||
title: '天平必须先回零!'
|
||
})
|
||
return
|
||
}
|
||
//获取当前重量
|
||
let weight = currentAuncel.value.weightData
|
||
selectedField.value.value = weight
|
||
//计算
|
||
try {
|
||
calcAnalysisValue(fieldGroup.value)
|
||
} catch (e) {
|
||
console.error(e)
|
||
}
|
||
|
||
//自动跳转下一个字段
|
||
setTimeout(() => {
|
||
autoNextField()
|
||
weightDataIsToZero.value = false
|
||
}, 100)
|
||
}
|
||
let dynamicFormData = reactive({})
|
||
const saveDetail = async () => {
|
||
//检查杯号
|
||
if (!checkBh()) return
|
||
// 检查范围校验
|
||
if (!(await checkRange())) return
|
||
setValueToSample()
|
||
let params = {
|
||
businessAssayTaskId: taskId.value
|
||
}
|
||
|
||
// 如果是空白样和标样就需要根据配置信息来计算质控样、分析样
|
||
if (activeAssayTypeKey.value === 'kby' || activeAssayTypeKey.value === 'by') {
|
||
// 处理其他页签的输入变化
|
||
const configInfomation = currentAssayType.value.configQCSampleMethodInfo
|
||
const row = currentSampleData.value
|
||
configInfomation.forEach(item => {
|
||
const sourceKey = item.source
|
||
const sourceValue = row[sourceKey]
|
||
if (sourceValue !== undefined) {
|
||
if (item.calcMethod === 'calculateAverageValue') {
|
||
item.value = calcAverageValue(sourceKey, currentAssayType.value.tableData)
|
||
} else {
|
||
item.value = handleRoundFiveNumber(row[sourceKey].value, row.decimalPosition)
|
||
}
|
||
// 如果处理后的值不为空,重新赋值该字段到其他样品类型下的样品上,并触发每一个样品的计算
|
||
if (item.value !== null) {
|
||
for (const col of currentAssayType.value.columns) {
|
||
if (col.fieldIndex === sourceKey) {
|
||
dynamicFormData[item.target] = row[sourceKey].value
|
||
}
|
||
}
|
||
updateTableDataByConfigFields()
|
||
}
|
||
}
|
||
})
|
||
params.formValue = JSON.stringify(dynamicFormData)
|
||
params.assayTaskAnalysisDataList = assayGroups.value.map(item => ({
|
||
datas: item.tableData,
|
||
analysisType: item.value
|
||
}))
|
||
} else {
|
||
const datas = currentSampleData.value
|
||
params.assayTaskAnalysisDataList = [{ datas: [datas], analysisType: activeAssayTypeKey.value }]
|
||
}
|
||
|
||
await nx.$api.assayTask.saveBatchSmpleAndQcAnalysis(params)
|
||
// getSampleAnalysisByTaskId()
|
||
autoNextSample()
|
||
}
|
||
// 计算表格列平均值
|
||
function calcAverageValue(fieldIndex, tableData) {
|
||
const rows = tableData.map(row => row[fieldIndex])
|
||
const decimalPosition = rows[0].decimalPosition
|
||
const values = rows.map(row => Number(row.value))
|
||
if (values.some(item => item == null)) return null
|
||
return handleRoundFiveNumber(math.mean(values), decimalPosition)
|
||
}
|
||
|
||
// 表格数据更新后重新计算
|
||
function updateTableDataByConfigFields() {
|
||
let needCalcTabs = []
|
||
needCalcTabs = assayGroups.value.filter(t => t.value !== 'by' && t.value !== 'kby')
|
||
if (needCalcTabs.length === 0) return
|
||
for (const key in dynamicFormData) {
|
||
for (const tab of needCalcTabs) {
|
||
const columnObj = tab.columns.find(c => {
|
||
if (c.formula) {
|
||
let FromKey = c.formula.split(':')
|
||
return FromKey[1] === key
|
||
}
|
||
return false
|
||
})
|
||
if (!columnObj) continue
|
||
tab.tableData.forEach(row => {
|
||
// 赋值配置列参与计算
|
||
row[columnObj.fieldIndex].value = dynamicFormData[key]
|
||
calcRowAnalysisValue(row, columnObj, tab.columns)
|
||
})
|
||
}
|
||
}
|
||
}
|
||
|
||
// 把字段值保存回样品数据中
|
||
function setValueToSample() {
|
||
let fields = fieldGroup.value.flatMap(item => item.fields)
|
||
fields.forEach(item => {
|
||
if (
|
||
currentSampleData.value.hasOwnProperty(item.fieldIndex) &&
|
||
nx.$test.object(currentSampleData.value[item.fieldIndex])
|
||
) {
|
||
currentSampleData.value[item.fieldIndex].value = item.value
|
||
}
|
||
})
|
||
}
|
||
|
||
//自动生成杯号(仅顺序称重):第一杯:手填,后续杯 = 上一杯 + 1
|
||
const autoGenerateCupNum = () => {
|
||
let cupNum = 0
|
||
let currentIndex = currentSampleIndex.value
|
||
//第一杯
|
||
if (currentIndex === 0) return
|
||
//取上一个样品的杯号
|
||
const sample = sampleDataList.value[currentIndex - 1]
|
||
cupNum = sample[cupNumFieldIndex.value].value
|
||
//杯号赋值到当前样品
|
||
putCupNum(Number(cupNum) + 1, currentIndex, Number(cupNum))
|
||
}
|
||
|
||
const putCupNum = (cupNum, sampleIndex, lastCupNum) => {
|
||
for (const fields of fieldGroup.value) {
|
||
if (typeof fields === 'undefined') continue
|
||
//杯号
|
||
for (const field of fields.fields) {
|
||
if (field.fieldIndex === cupNumFieldIndex.value) {
|
||
if (typeof field.value === 'undefined' || field.value === null || field.value === '') {
|
||
field.value = cupNum
|
||
return true
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
const loadConRecoveryList = () => {
|
||
const conBaseSampleId = currentSampleData.value.conBaseSampleId
|
||
const rParam = {
|
||
pageNo: 1,
|
||
pageSize: -1,
|
||
conBaseSampleId: conBaseSampleId
|
||
}
|
||
const storageKey = 'ConRecoveryRateList'
|
||
nx.$api.assayTask
|
||
.queryConRecoveryRateList(rParam)
|
||
.then(res => {
|
||
const result = res.result
|
||
if (typeof result === 'undefined' || result === null || !result) {
|
||
uni.setStorage(storageKey, [])
|
||
return
|
||
}
|
||
const records = result.records
|
||
if (!records || records.length === 0) {
|
||
uni.setStorage(storageKey, [])
|
||
return
|
||
}
|
||
uni.setStorageSync(storageKey, records)
|
||
})
|
||
.catch(err => {
|
||
console.error(err)
|
||
})
|
||
}
|
||
|
||
// 分析样品组
|
||
let assayGroups = ref([])
|
||
const activeAssayTypeKey = ref('')
|
||
const activeAssayTypeIndex = ref(0)
|
||
//元素结果范围
|
||
let conRangeElementAnalysisList = ref([])
|
||
// 杯号fieldIndex
|
||
const cupNumFieldIndex = ref('')
|
||
const currentAssayType = computed(() => {
|
||
return assayGroups.value.find(item => item.value === activeAssayTypeKey.value)
|
||
})
|
||
// 当前样品数据
|
||
const currentSampleData = computed(() => {
|
||
if (sampleDataList.value.length > 0) {
|
||
return sampleDataList.value[currentSampleIndex.value]
|
||
}
|
||
return {}
|
||
})
|
||
watch(
|
||
() => currentAssayType.value,
|
||
() => {
|
||
sampleDataList.value = currentAssayType.value.tableData
|
||
fieldGroup.value = groupByField(currentAssayType.value.columns, cupNumFieldIndex)
|
||
autoNextSample(0)
|
||
setValueToField()
|
||
// getDomHeight()
|
||
activeCollapses.value = fieldGroup.value.map((_, index) => index)
|
||
}
|
||
)
|
||
const currentCupNum = computed(() => {
|
||
for (const item of fieldGroup.value) {
|
||
const field = item.fields.find(field => field.fieldIndex === cupNumFieldIndex.value)
|
||
if (field) {
|
||
return field.value
|
||
}
|
||
}
|
||
return null
|
||
})
|
||
const currentGroup = computed(() => {
|
||
if (!currentAssayType.value || curParameterKey.value === 'all') {
|
||
return fieldGroup.value
|
||
} else {
|
||
return fieldGroup.value.filter(g => g.value === curParameterKey.value)
|
||
}
|
||
})
|
||
watch(
|
||
() => currentGroup.value,
|
||
() => {
|
||
fieldGroup.value.forEach(item => {
|
||
item.fields.forEach(field => {
|
||
const validation = validateElementRange(
|
||
field.fieldIndex,
|
||
currentSampleData.value,
|
||
conRangeElementAnalysisList.value
|
||
)
|
||
field.validation = validation
|
||
})
|
||
})
|
||
}
|
||
)
|
||
const collapseRef = ref()
|
||
const activeCollapses = ref([])
|
||
function handleAssayTypeChange({ index, value }) {
|
||
activeAssayTypeKey.value = value
|
||
activeAssayTypeIndex.value = index
|
||
currentSampleIndex.value = 0
|
||
groupFieldIndex.value = ''
|
||
selectedField.value = {}
|
||
curParameterKey.value = 'all'
|
||
curParameterTitle.value = '选择字段分类'
|
||
collapseRef.value.init()
|
||
}
|
||
// 获取任务数据
|
||
async function getSampleAnalysisByTaskId() {
|
||
const {
|
||
assayTaskAnalysisDataList,
|
||
configAssayMethodProjectRangeList,
|
||
businessAssayTasNo,
|
||
formValue,
|
||
ingredientsStatus
|
||
} = await nx.$api.assayTask.batchSampleAndQcAnalysisByTaskId(taskId.value)
|
||
title.value = '样品分析-任务单编号:' + businessAssayTasNo
|
||
taskIngredientsStatus.value = ingredientsStatus
|
||
// 处理分析数据
|
||
assayGroups.value = assayTaskAnalysisDataList.map(group => {
|
||
// 必须深拷贝 datas!防止多个表格共享引用
|
||
const tableData = JSON.parse(JSON.stringify(group.datas || []))
|
||
const columns = group.columns.filter(item => item.paramNo) || []
|
||
|
||
return {
|
||
value: group.analysisType,
|
||
name: group.analysisName,
|
||
columns,
|
||
tableData,
|
||
configQCSampleMethodInfo: group.configQCSampleMethod?.configInfomation
|
||
? JSON.parse(group.configQCSampleMethod['configInfomation'])['set']
|
||
: []
|
||
}
|
||
})
|
||
dynamicFormData = formValue ? JSON.parse(formValue) : {}
|
||
// 默认激活第一个 类型
|
||
if (!activeAssayTypeKey.value) {
|
||
activeAssayTypeKey.value = assayGroups.value.length > 0 ? assayGroups.value[0].value : ''
|
||
}
|
||
conRangeElementAnalysisList.value = configAssayMethodProjectRangeList || []
|
||
}
|
||
// 设置字段值
|
||
function setValueToField() {
|
||
for (const group of fieldGroup.value) {
|
||
group.fields.forEach(field => {
|
||
let value = getFieldValue(field)
|
||
field.value = value
|
||
})
|
||
}
|
||
}
|
||
function getFieldValue(field) {
|
||
const fieldValue = currentSampleData.value[field.fieldIndex]?.value
|
||
if (fieldValue) {
|
||
return fieldValue
|
||
} else {
|
||
return ''
|
||
}
|
||
}
|
||
|
||
const apiRequest = async url => {
|
||
return request({
|
||
url: url,
|
||
method: 'GET'
|
||
})
|
||
}
|
||
|
||
//读取字段里的API选项
|
||
const loadFieldApiData = async fieldGroups => {
|
||
for (const fields of fieldGroups) {
|
||
for (const field of fields.fields) {
|
||
const api = field.api
|
||
const type = field.type
|
||
if (type === 'select' && api && api !== '') {
|
||
//读取API选项
|
||
try {
|
||
const res = await apiRequest(api)
|
||
const data = res
|
||
field.options = data
|
||
field.rangeKey = 'displayName'
|
||
} catch (e) {}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* 选择器组件确认事件
|
||
* event: 事件默认参数
|
||
* field: 当前字段
|
||
* 处理逻辑:
|
||
* field.value = 选中的值
|
||
* field.valueText = 选中的文本
|
||
* */
|
||
const dicPickerConfirm = (event, field) => {
|
||
const checked = event.value[0]
|
||
const displayName = checked.displayName
|
||
const value = checked.dictValue
|
||
const extField1 = checked.extField1
|
||
field.value = value
|
||
field.valueText = value
|
||
|
||
const relatedFieldNo = '8'
|
||
//查找并处理关联字段
|
||
for (const fieldGroup of fieldGroup.value) {
|
||
for (const field of fieldGroup.fields) {
|
||
if (field.paramNo === relatedFieldNo) {
|
||
field.value = extField1
|
||
break
|
||
}
|
||
}
|
||
}
|
||
//触发计算公式
|
||
calcAnalysisValue(fieldGroup.value)
|
||
}
|
||
// 天平监听
|
||
const listenDeviceData = () => {
|
||
//监听websocket返回来的数据
|
||
//设备数据
|
||
uni.$on('deviceData', res => {
|
||
switch (res.deviceType) {
|
||
case 'balance':
|
||
if (currentAuncel.value.id === res.deviceId) {
|
||
currentAuncel.value.weightData = res.weightData
|
||
currentAuncel.value.weightUnit = res.weightUnit
|
||
currentAuncel.value.weightStable = res.weightStable
|
||
currentAuncel.value.isConnected = true
|
||
if (Number(res.weightData) === 0) {
|
||
weightDataIsToZero.value = true
|
||
}
|
||
}
|
||
break
|
||
default:
|
||
break
|
||
}
|
||
})
|
||
//设备状态
|
||
uni.$on('deviceStatus', res => {
|
||
if (currentAuncel.value.id === res.deviceId) {
|
||
if (res.connected === 0) {
|
||
currentAuncel.value.weightStable = 0
|
||
currentAuncel.value.weightData = '天平断开'
|
||
currentAuncel.value.weightUnit = ''
|
||
}
|
||
}
|
||
currentAuncel.value.isConnected = res.connected
|
||
})
|
||
//控制设备状态
|
||
uni.$on('controlDevice', res => {
|
||
if (currentAuncel.value.id === res.deviceId) {
|
||
currentAuncel.value.id = ''
|
||
currentAuncel.value.name = ''
|
||
currentAuncel.value.code = ''
|
||
currentAuncel.value.weightStable = 0
|
||
currentAuncel.value.weightData = '请选天平'
|
||
currentAuncel.value.weightUnit = ''
|
||
}
|
||
})
|
||
//连接断开
|
||
uni.$on('connClose', res => {
|
||
//重置
|
||
currentAuncel.value.weightData = ''
|
||
currentAuncel.value.weightUnit = ''
|
||
currentAuncel.value.weightStable = 0
|
||
currentAuncel.value.controlUserName = ''
|
||
currentAuncel.value.isConnected = false
|
||
})
|
||
}
|
||
const closeDeviceListener = () => {
|
||
uni.$off('deviceData')
|
||
uni.$off('deviceStatus')
|
||
uni.$off('controlDevice')
|
||
uni.$off('connClose')
|
||
}
|
||
const loadDevice = () => {
|
||
//注册websocket
|
||
let 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.open()
|
||
}
|
||
|
||
// 键盘监听
|
||
const listenNumKeyboard = () => {
|
||
//键盘监听
|
||
uni.$on('keyboardOK', res => {
|
||
if (res === null) {
|
||
clearFieldVal()
|
||
return
|
||
}
|
||
//自动补全小数位数
|
||
const decimalPosition = selectedField.value.decimalPosition || 0
|
||
let val = res.val
|
||
selectedField.value.value = handleRoundFiveNumber(val, decimalPosition)
|
||
calcAnalysisValue(fieldGroup.value)
|
||
//自动跳转下一个字段
|
||
setTimeout(() => {
|
||
autoNextField()
|
||
}, 60)
|
||
})
|
||
}
|
||
const clearFieldVal = () => {
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: '清空当前字段的值,是否继续?',
|
||
cancelColor: '#0055A2',
|
||
confirmColor: '#0055A2',
|
||
success: res => {
|
||
if (res.cancel) {
|
||
return
|
||
}
|
||
selectedField.value.value = ''
|
||
//重新计算
|
||
calcAnalysisValue(fieldGroup.value)
|
||
}
|
||
})
|
||
}
|
||
const closeNumKeyBoardListener = () => {
|
||
uni.$off('keyboardOK')
|
||
}
|
||
|
||
const closeDeviceLink = () => {
|
||
const deviceId = currentAuncel.value.id
|
||
releaseDeviceControl(deviceId)
|
||
}
|
||
|
||
//释放设备控制
|
||
const releaseDeviceControl = deviceId => {
|
||
if (!deviceId || deviceId === '') return
|
||
let controlDevice = {
|
||
msgId: deviceId,
|
||
cmd: 'controlDevice',
|
||
clientType: 'caaClient',
|
||
data: {
|
||
deviceId: deviceId,
|
||
isControl: false,
|
||
controlRealName: userInfo.value.nickname
|
||
}
|
||
}
|
||
//发送控制数据
|
||
nx.$measure.send(JSON.stringify(controlDevice))
|
||
}
|
||
|
||
// 天平选择
|
||
const selectAuncel = () => {
|
||
showAuncelSelector.value = true
|
||
}
|
||
// 天平选择回调
|
||
const auncelDoSelect = res => {
|
||
const data = res.data
|
||
if (data) {
|
||
currentAuncel.value.id = data.deviceId
|
||
currentAuncel.value.name = data.deviceName
|
||
currentAuncel.value.code = data.deviceCode
|
||
}
|
||
}
|
||
|
||
//提交任务单
|
||
const submitTask = () => {
|
||
if (checkSampleReturning()) return
|
||
const url = `/pages/analysis/sample/pdf-preview?businessAssayTaskId=${taskId.value}&reportKey=${configReportTemplateKey.value}&showConfirmBtn=true`
|
||
uni.navigateTo({ url })
|
||
}
|
||
// 配料下发
|
||
function handleIngredients() {
|
||
if (checkSampleReturning()) return
|
||
const params = {
|
||
businessAssayTaskId: taskId.value
|
||
}
|
||
nx.$api.assayTask.taskIngredients(params).then(res => {
|
||
getSampleAnalysisByTaskId()
|
||
})
|
||
}
|
||
function checkSampleReturning() {
|
||
const analysisSampleData = assayGroups.value.find(t => t.value == 'analysis').tableData
|
||
const hasReturning = analysisSampleData.some(item => item.rollbackStatus === 'in_progress')
|
||
if (hasReturning) {
|
||
nx.$helper.showToast('该任务单存在退回中的样品')
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
// 生命周期
|
||
const { lockOrientation } = useScreenOrientation()
|
||
|
||
onLoad(param => {
|
||
lockOrientation('landscape')
|
||
if (param.currentTaskId) {
|
||
taskId.value = param.currentTaskId
|
||
configReportTemplateKey.value = param.configReportTemplateKey
|
||
getSampleAnalysisByTaskId()
|
||
}
|
||
loadFieldApiData(fieldGroup.value)
|
||
listenNumKeyboard()
|
||
})
|
||
|
||
onShow(() => {
|
||
loadDevice()
|
||
listenDeviceData()
|
||
})
|
||
|
||
onHide(() => {
|
||
closeDeviceListener()
|
||
})
|
||
|
||
onUnload(() => {
|
||
closeDeviceLink()
|
||
closeDeviceListener()
|
||
closeNumKeyBoardListener()
|
||
})
|
||
|
||
onBackPress(() => {
|
||
customBack()
|
||
return true
|
||
})
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
/* 原始样式保留不变 */
|
||
.navbar-right {
|
||
font-size: 16px;
|
||
color: #fff;
|
||
display: flex;
|
||
}
|
||
|
||
.content-title-name {
|
||
font-size: 18px;
|
||
font-weight: 300;
|
||
padding: 4px 0;
|
||
display: flex;
|
||
justify-content: center;
|
||
}
|
||
|
||
.current-sample-code {
|
||
font-weight: bold;
|
||
margin-right: 20px;
|
||
}
|
||
|
||
.form-item-my {
|
||
display: flex;
|
||
align-items: center;
|
||
min-height: 35px;
|
||
font-size: 13px;
|
||
border-bottom: 1px solid #dcdcdc;
|
||
}
|
||
.selected-field {
|
||
background-color: #bada55;
|
||
}
|
||
.disabled-field {
|
||
background-color: #eee;
|
||
}
|
||
.label-my {
|
||
flex: 5;
|
||
}
|
||
|
||
.label-high-light {
|
||
color: #000;
|
||
font-weight: 600;
|
||
font-size: 1.2em;
|
||
}
|
||
|
||
.field-high-light {
|
||
color: #000;
|
||
font-weight: 600;
|
||
font-size: 1.2em;
|
||
}
|
||
|
||
.label-my sub {
|
||
font-size: 0.6em;
|
||
vertical-align: sub;
|
||
}
|
||
|
||
.content-my {
|
||
flex: 2;
|
||
text-align: right;
|
||
padding-right: 4px;
|
||
.select-my {
|
||
color: #303133;
|
||
font-size: 15px;
|
||
padding: 6px 8px;
|
||
border: 1px solid #dcdcdc;
|
||
border-radius: 5px;
|
||
}
|
||
}
|
||
|
||
.content-my-text-value {
|
||
color: rgb(48, 49, 51);
|
||
}
|
||
.content-my-text-placeholder {
|
||
color: #c0c4cc;
|
||
}
|
||
.content-left-scroll {
|
||
height: 68vh;
|
||
}
|
||
.content-right-scroll {
|
||
height: 68vh;
|
||
}
|
||
.valid-warning {
|
||
color: orange;
|
||
}
|
||
.valid-error {
|
||
color: red;
|
||
}
|
||
|
||
.u-tab-item {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 16px;
|
||
color: #444;
|
||
padding: 4px 8px;
|
||
box-sizing: border-box;
|
||
border-bottom: 2px dotted #444;
|
||
}
|
||
|
||
.u-tab-item-active {
|
||
color: #0055a2;
|
||
font-weight: 600;
|
||
}
|
||
.u-tab-item-disabled {
|
||
background-color: #ddd;
|
||
pointer-events: none;
|
||
opacity: 0.6;
|
||
}
|
||
|
||
.btn-operation {
|
||
width: 80%;
|
||
font-size: 18px;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.auncel {
|
||
width: 90%;
|
||
height: 55vh;
|
||
background-image: url(/static/images/auncel.png);
|
||
background-repeat: no-repeat;
|
||
background-size: 100% 100%;
|
||
background-position: center;
|
||
display: flex;
|
||
flex-direction: column;
|
||
position: relative;
|
||
.code {
|
||
position: absolute;
|
||
top: 10px;
|
||
left: 50px;
|
||
}
|
||
}
|
||
|
||
.auncel-title {
|
||
flex: 3;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
font-size: 32px;
|
||
}
|
||
|
||
.auncel-weight {
|
||
flex: 2.5;
|
||
display: flex;
|
||
align-items: center;
|
||
padding-bottom: 20px;
|
||
box-sizing: border-box;
|
||
position: relative;
|
||
}
|
||
|
||
.weight {
|
||
font-size: 42px;
|
||
width: 100%;
|
||
padding: 0 60px;
|
||
}
|
||
|
||
.weight-data {
|
||
color: #4cd964;
|
||
font-family: zzjc-lcd;
|
||
}
|
||
|
||
.weight-data-yellow {
|
||
color: #ffff00;
|
||
font-family: zzjc-lcd;
|
||
}
|
||
|
||
.weight-data-warning {
|
||
color: #ff3333;
|
||
font-family: zzjc-lcd;
|
||
}
|
||
|
||
.weight-unit {
|
||
position: absolute;
|
||
right: 30px;
|
||
color: #ffffff;
|
||
font-size: 32px;
|
||
}
|
||
@media (max-width: 700px) {
|
||
.auncel {
|
||
height: 45vh;
|
||
}
|
||
.auncel-title {
|
||
font-size: 20px;
|
||
}
|
||
.auncel-weight {
|
||
padding-bottom: 15px;
|
||
}
|
||
.weight {
|
||
font-size: 26px;
|
||
}
|
||
.weight-unit {
|
||
font-size: 20px;
|
||
}
|
||
}
|
||
|
||
.field-name {
|
||
font-size: 26px;
|
||
padding: 8px;
|
||
}
|
||
|
||
.my-collapse {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 5px 10px 5px 0;
|
||
.title {
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
.content {
|
||
overflow: hidden;
|
||
padding-right: 10px;
|
||
transition: height 100ms;
|
||
}
|
||
|
||
@media (max-width: 700px) {
|
||
.content-left-scroll {
|
||
height: 45vh;
|
||
}
|
||
.content-right-scroll {
|
||
height: 55vh;
|
||
}
|
||
.field-name {
|
||
font-size: 16px;
|
||
}
|
||
}
|
||
</style>
|