feat:分析

This commit is contained in:
houjunxiang
2025-11-11 09:58:12 +08:00
parent 5916b8c833
commit fb41fa9a03
9 changed files with 311 additions and 149 deletions

View File

@@ -1,6 +1,6 @@
// 在此不用配置接口前缀 // 在此不用配置接口前缀
const isDev = process.env.NODE_ENV === 'development' const isDev = process.env.NODE_ENV === 'development'
const BaseUrl = isDev ? 'http://192.168.26.116:888/admin-api' : 'http://172.33.199.28:8088/api' const BaseUrl = isDev ? 'http://192.168.26.190:48080/admin-api' : 'http://172.33.199.28:8088/api'
// const BaseUrl = isDev ? 'http://localhost:9999' : '' // const BaseUrl = isDev ? 'http://localhost:9999' : ''
const upgradeBaseUrl = 'http://172.33.199.28:8088' const upgradeBaseUrl = 'http://172.33.199.28:8088'
@@ -31,5 +31,5 @@ export function getUpgradeBaseUrl() {
} }
export function getWebSocketUrl() { export function getWebSocketUrl() {
// return uni.getStorageSync('base_url').replace('/api', '') + '/ws' // return uni.getStorageSync('base_url').replace('/api', '') + '/ws'
return 'ws://192.168.26.178:8330' return 'ws://192.168.26.190:8330'
} }

View File

@@ -30,6 +30,14 @@ const getSampleAnalysisByTaskId = businessAssayTaskId => {
params: { businessAssayTaskId } params: { businessAssayTaskId }
}) })
} }
// 质控样
const batchSampleAndQcAnalysisByTaskId = businessAssayTaskId => {
return request({
url: '/qms/bus/sample/analysis/batchSampleAndQcAnalysisByTaskId',
method: 'GET',
params: { businessAssayTaskId }
})
}
// 获取指派单动态配置项 // 获取指派单动态配置项
const getDynamicBaseFormSchema = params => { const getDynamicBaseFormSchema = params => {
return request({ return request({
@@ -161,6 +169,17 @@ const saveDetailValue = data => {
} }
}) })
} }
// 批量保存任务
const saveBatchSmpleAndQcAnalysis = data => {
return request({
url: '/qms/bus/sample/analysis/saveBatchSmpleAndQcAnalysis',
method: 'POST',
data,
custom: {
showSuccess: true
}
})
}
// 提交任务明细-停用 // 提交任务明细-停用
const submitTaskDetail = params => { const submitTaskDetail = params => {
@@ -256,6 +275,8 @@ export default {
getAssayTaskList, getAssayTaskList,
getAssayTaskDataList, getAssayTaskDataList,
getSampleAnalysisByTaskId, getSampleAnalysisByTaskId,
batchSampleAndQcAnalysisByTaskId,
saveBatchSmpleAndQcAnalysis,
getDynamicBaseFormSchema, getDynamicBaseFormSchema,
getAssayTaskDetailListByTaskNo, getAssayTaskDetailListByTaskNo,
getAssayTaskDetailById, getAssayTaskDetailById,

View File

@@ -4,8 +4,9 @@ math.config({
number: 'BigNumber', number: 'BigNumber',
precision: 64 precision: 64
}) })
export { math }
/* /*
* 计算分析值*/ * 计算当前样品分析值*/
export function calcAnalysisValue(group) { export function calcAnalysisValue(group) {
try { try {
for (const g of group) { for (const g of group) {
@@ -57,6 +58,43 @@ export function calcAnalysisValue(group) {
} }
} }
// 根据样品和配置列计算分析值
export function calcRowAnalysisValue(row, columnObj, dynamicsColumns) {
if (!columnObj.paramNo) return
for (let i = 0; i < dynamicsColumns.length; i++) {
let curItem = dynamicsColumns[i]
if (curItem.fieldIndex === columnObj.fieldIndex) continue
let param = columnObj.fieldIndex.charAt(0) === 'p' ? 'p' + columnObj.paramNo : 'e' + columnObj.paramNo
if (curItem.formula && curItem.formula.includes(param)) {
let formula = curItem.formula
let formulas = formula.split('|')
let formulaVal = ''
formulas.forEach(f => {
if (f.charAt(0) === 'p') {
let o = dynamicsColumns.find(i => 'p' + i.paramNo === f)
formulaVal += row[o.fieldIndex]?.value ? row[o.fieldIndex].value : 0
} else if (f.charAt(0) === 'e') {
let o = dynamicsColumns.find(i => 'e' + i.paramNo === f)
formulaVal += row[o.fieldIndex]?.value ? row[o.fieldIndex].value : 0
} else {
formulaVal += f
}
})
let v
if (formulaVal.startsWith('Get')) {
formulaVal = formulaVal.replace(')', ",'" + row.conBaseSampleId + "')")
v = eval(formulaVal)
} else {
v = math.evaluate(formulaVal).toString()
v = isFinite(v) ? v : 0
}
row[curItem.fieldIndex].value = handleRoundFiveNumber(Number(v), row[curItem.fieldIndex].decimalPosition)
calcRowAnalysisValue(row, curItem, dynamicsColumns)
}
}
}
const findFieldInGroup = function (paramNo, group, p) { const findFieldInGroup = function (paramNo, group, p) {
for (const g of group) { for (const g of group) {
for (const f of g.fields) { for (const f of g.fields) {

View File

@@ -1,5 +1,6 @@
import $router from '@/nx/router' import $router from '@/nx/router'
import $helper from '@/nx/helper' import $helper from '@/nx/helper'
import $test from '@/nx/helper/test'
import $store from '@/nx/store' import $store from '@/nx/store'
import $measure from '@/nx/helper/measure' import $measure from '@/nx/helper/measure'
import $print from '@/nx/helper/print' import $print from '@/nx/helper/print'
@@ -21,7 +22,8 @@ const nx = {
$measure, $measure,
$print, $print,
$dayjs: dayjs, $dayjs: dayjs,
$api $api,
$test
} }
// 加载Nx底层依赖 // 加载Nx底层依赖

View File

@@ -48,6 +48,7 @@ onMounted(() => {
} }
} }
nx.$measure.setRegData(JSON.stringify(regData)) nx.$measure.setRegData(JSON.stringify(regData))
nx.$measure.open() nx.$measure.open()
// 监听 WebSocket 数据 // 监听 WebSocket 数据

View File

@@ -3,7 +3,7 @@
<view class="u-tab-item" :class="{ 'u-tab-item-active': active }" @tap.stop="handleClick"> <view class="u-tab-item" :class="{ 'u-tab-item-active': active }" @tap.stop="handleClick">
<u-row class="full-width"> <u-row class="full-width">
<u-col span="2" class="text-center" style="position: relative"> <u-col span="2" class="text-center" style="position: relative">
<u-icon :color="taskStyle(task)" name="tags-fill" size="34"></u-icon> <u-icon :color="taskStyle(task)" name="tags-fill" size="40"></u-icon>
<text class="seq">{{ seq }}</text> <text class="seq">{{ seq }}</text>
</u-col> </u-col>
<u-col span="10"> <u-col span="10">
@@ -72,7 +72,7 @@ const taskStyle = task => {
} }
.seq { .seq {
position: absolute; position: absolute;
top: 9px; top: 12px;
left: 12px; left: 12px;
color: #fff; color: #fff;
font-size: 11px; font-size: 11px;

View File

@@ -9,28 +9,30 @@
<u-row gutter="8"> <u-row gutter="8">
<u-col span="3"> <u-col span="3">
<view class="content-title-name"> <up-tabs
<text>待化验样品</text> :current="activeAssayTypeIndex"
</view> :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-gap height="5" bg-color="#0055A2"></u-gap>
</u-col> </u-col>
<u-col span="6"> <u-col span="6">
<view class="content-title-name"> <view class="content-title-name">
<view class="current-sample-code">{{ currentSample.sampleCode }}</view> <view class="current-sample-code">{{ currentSampleData.sampleCode }}</view>
<view>数据采集或录入</view> <view>数据采集或录入</view>
</view> </view>
<u-gap height="5" bg-color="#0055A2"></u-gap> <u-gap height="5" bg-color="#0055A2"></u-gap>
</u-col> </u-col>
<u-col span="3"> <u-col span="3">
<view class="content-title-name"> <u-dropdown style="height: 35px">
<text>样品详情</text>
</view>
<u-gap height="5" bg-color="#0055A2"></u-gap>
</u-col>
</u-row>
<u-row gutter="8" align="top">
<u-col span="3">
<u-dropdown>
<u-dropdown-item <u-dropdown-item
v-model="curParameterClassify" v-model="curParameterClassify"
:title="curParameterTitle" :title="curParameterTitle"
@@ -39,9 +41,14 @@
@change="parameterClassifyChange" @change="parameterClassifyChange"
></u-dropdown-item> ></u-dropdown-item>
</u-dropdown> </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"> <scroll-view class="content-left-scroll" scroll-with-animation scroll-y :scroll-top="scrollTop">
<view <view
v-for="(sample, index) in leftList" v-for="(sample, index) in sampleDataList"
:key="index" :key="index"
class="u-tab-item" class="u-tab-item"
:class="currentSampleIndex === index ? 'u-tab-item-active' : ''" :class="currentSampleIndex === index ? 'u-tab-item-active' : ''"
@@ -63,10 +70,10 @@
<view class="field-name" v-html="selectedField.title" /> <view class="field-name" v-html="selectedField.title" />
<zzjc-num-keyboard <zzjc-num-keyboard
ref="myKeyboard" ref="myKeyboard"
v-show="selectedField.fillingWay == '1' && selectedField.type != 'select'" v-show="selectedField.fillingWay == 'keyboard' && selectedField.type != 'select'"
:numKeyboardParam="numKeyboardParam" :numKeyboardParam="numKeyboardParam"
></zzjc-num-keyboard> ></zzjc-num-keyboard>
<view v-if="selectedField.fillingWay == '2'" class="y-f"> <view v-if="selectedField.fillingWay == 'collect'" class="y-f">
<view class="auncel" @click="selectAuncel"> <view class="auncel" @click="selectAuncel">
<view class="auncel-title"> {{ currentAuncel.code }}</view> <view class="auncel-title"> {{ currentAuncel.code }}</view>
<view class="auncel-weight"> <view class="auncel-weight">
@@ -103,11 +110,10 @@
<view> <view>
<scroll-view class="content-right-scroll" scroll-y scroll-with-animation> <scroll-view class="content-right-scroll" scroll-y scroll-with-animation>
<view> <view>
<u-form :model="curSample" ref="uForm" label-width="140"> <!-- <template v-for="(fields, groupIndex) in fieldGroup" :key="'group_' + groupIndex"> -->
<template v-for="(fields, groupIndex) in fieldGroup" :key="'group_' + groupIndex"> <!-- <view> -->
<view> <!-- 组名 -->
<!-- 组名 --> <!-- <view class="my-collapse" @click="fields.open = !fields.open">
<view class="my-collapse" @click="fields.open = !fields.open">
<text class="title">{{ fields.title }}</text> <text class="title">{{ fields.title }}</text>
<u-icon :name="fields.open ? 'arrow-up' : 'arrow-down'"></u-icon> <u-icon :name="fields.open ? 'arrow-up' : 'arrow-down'"></u-icon>
</view> </view>
@@ -115,37 +121,39 @@
class="content" class="content"
:id="'elId' + groupIndex" :id="'elId' + groupIndex"
:style="{ height: fields.open ? collaHeights[groupIndex] + 'px' : '0' }" :style="{ height: fields.open ? collaHeights[groupIndex] + 'px' : '0' }"
> > -->
<view <up-collapse ref="collapseRef" :value="activeCollapses">
class="form-item-my" <up-collapse-item v-for="(fields, groupIndex) in fieldGroup" :title="fields.title">
v-for="(field, fieldIndex) in fields.fields" <view
@click="fieldClick(field, groupIndex + '-' + fieldIndex)" class="form-item-my"
:key="groupIndex + '-' + fieldIndex" v-for="(field, fieldIndex) in fields.fields"
v-show="field.hidden != 1" @click="fieldClick(field, groupIndex + '-' + fieldIndex)"
:class="{ :key="groupIndex + '-' + fieldIndex"
'selected-field': groupFieldIndex === groupIndex + '-' + fieldIndex, v-show="field.hidden != 1"
'disabled-field': !field.isEdit :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="['label-my', { 'label-high-light': field.highlight == 1 }]"
<view class="content-my"> v-html="field.title"
<!-- ></view>
<view class="content-my">
<!--
如果是select渲染2个组件1个input1个picker. 如果是select渲染2个组件1个input1个picker.
field.valueText用于显示picker选中的文本 field.valueText用于显示picker选中的文本
1键盘输入2天平3自动计算4文本输入 1键盘输入2天平3自动计算4文本输入
--> -->
<u-input <u-input
border="bottom" border="bottom"
style="width: 120px" style="width: 120px"
v-if="field.fillingWay == 4" v-if="field.fillingWay == 'input'"
v-model="field.value" v-model="field.value"
placeholder="请输入" placeholder="请输入"
/> />
<!-- <view v-if="field.type === 'select'" class="x-bc select-my" @click="field.showPicker = true"> <!-- <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-if="field.valueText">{{ field.valueText }}</text>
<text v-else>请选择</text> <text v-else>请选择</text>
<u-icon name="arrow-down" size="20"></u-icon> <u-icon name="arrow-down" size="20"></u-icon>
@@ -158,23 +166,22 @@
@cancel="field.showPicker = false" @cancel="field.showPicker = false"
@confirm="event => dicPickerConfirm(event, field)" @confirm="event => dicPickerConfirm(event, field)"
/> --> /> -->
<!--普通输入框 使用文本显示--> <!--普通输入框 使用文本显示-->
<view class="content-my-text" v-if="field.dataType != 'select' && field.fillingWay != 4"> <view class="content-my-text" v-if="field.dataType != 'select' && field.fillingWay != 'input'">
<text v-if="!field.value" class="content-my-text-placeholder">{{ <text v-if="!field.value" class="content-my-text-placeholder">{{
!field.fillingWay || field.fillingWay == 3 ? '计算值' : '请输入' !field.fillingWay || field.fillingWay == 'calculate' ? '计算值' : '请输入'
}}</text> }}</text>
<text <text v-else :class="['content-my-text-value', { 'field-high-light': field.highlight == 1 }]">{{
v-else field.value
:class="['content-my-text-value', { 'field-high-light': field.highlight == 1 }]" }}</text>
>{{ field.value }}</text
>
</view>
</view>
</view> </view>
</view> </view>
</view> </view>
</template> </up-collapse-item>
</u-form> </up-collapse>
<!-- </view>
</view> -->
<!-- </template> -->
</view> </view>
</scroll-view> </scroll-view>
<u-button class="btn-operation" type="success" @click="saveDetail()">保存样品数据</u-button> <u-button class="btn-operation" type="success" @click="saveDetail()">保存样品数据</u-button>
@@ -192,10 +199,10 @@
</template> </template>
<script setup> <script setup>
import { ref, reactive, computed, nextTick, getCurrentInstance } from 'vue' import { ref, reactive, computed, nextTick, watch, getCurrentInstance } from 'vue'
import { onLoad, onBackPress, onShow, onHide, onUnload } from '@dcloudio/uni-app' import { onLoad, onBackPress, onShow, onHide, onUnload } from '@dcloudio/uni-app'
import request from '@/nx/request' import request from '@/nx/request'
import { calcAnalysisValue } from '@/nx/helper/calcAnalysisValue' import { calcAnalysisValue, handleRoundFiveNumber, calcRowAnalysisValue, math } from '@/nx/helper/calcAnalysisValue'
import { number } from 'mathjs' import { number } from 'mathjs'
import AuncelSelectPopup from '@/components/sample/auncel-select-popup.vue' import AuncelSelectPopup from '@/components/sample/auncel-select-popup.vue'
import { getTenantId } from '@/defaultBaseUrl' import { getTenantId } from '@/defaultBaseUrl'
@@ -212,9 +219,8 @@ const scrollTop = ref(0) //tab标题的滚动条位置
const menuHeight = ref(0) // 左边菜单的高度 const menuHeight = ref(0) // 左边菜单的高度
const menuItemHeight = ref(0) // 左边菜单item的高度 const menuItemHeight = ref(0) // 左边菜单item的高度
const weightDataIsToZero = ref(false) //重量数据是否归零 const weightDataIsToZero = ref(false) //重量数据是否归零
const currentSample = ref({}) //当前样品
const currentSampleIndex = ref(0) // 预设当前项的值 const currentSampleIndex = ref(0) // 预设当前项的值
let sampleDataList = [] let sampleDataList = ref([])
const title = ref('') const title = ref('')
const numKeyboardParam = reactive({ const numKeyboardParam = reactive({
decimal: '-1' //数字键盘小数位数,-1为不限制 decimal: '-1' //数字键盘小数位数,-1为不限制
@@ -230,7 +236,6 @@ const currentAuncel = ref({
}) })
let selectedField = ref({}) let selectedField = ref({})
const groupFieldIndex = ref('') //分组的索引 const groupFieldIndex = ref('') //分组的索引
const leftList = ref([])
const curSample = ref({}) const curSample = ref({})
const curParameterTitle = ref('选择字段分类') const curParameterTitle = ref('选择字段分类')
const curParameterKey = ref('') const curParameterKey = ref('')
@@ -249,7 +254,7 @@ const auncelSelector = ref(null)
// 计算属性 // 计算属性
const confirmWeightDisabled = computed(() => { const confirmWeightDisabled = computed(() => {
if ( if (
currentSample.value.sampleCode && currentSampleData.value.sampleCode &&
currentAuncel.value.weightStable === 1 && currentAuncel.value.weightStable === 1 &&
Number(currentAuncel.value.weightData) > 0 Number(currentAuncel.value.weightData) > 0
) { ) {
@@ -257,12 +262,12 @@ const confirmWeightDisabled = computed(() => {
} }
return true return true
}) })
// 当前样品数据索引 // 当前样品数据
const currentSampleDataIndex = computed(() => { const currentSampleData = computed(() => {
if (sampleDataList.length > 0) { if (sampleDataList.value.length > 0) {
return sampleDataList.findIndex(item => item.businessAssayTaskDataId === currentSample.value.id) return sampleDataList.value[currentSampleIndex.value]
} }
return -1 return {}
}) })
// 当前操作字段索引 // 当前操作字段索引
const currentFieldKey = computed(() => { const currentFieldKey = computed(() => {
@@ -316,15 +321,17 @@ const parameterClassifyChange = (v, a) => {
} }
const fieldClick = (field, key) => { const fieldClick = (field, key) => {
myKeyboard.value.clearNum() if (field.fillingWay == 'input' || !field.fillingWay || field.fillingWay == 'calculate') return
if (field.fillingWay == 4 || !field.fillingWay || field.fillingWay == 3) return
selectedField.value = field selectedField.value = field
groupFieldIndex.value = key groupFieldIndex.value = key
if (myKeyboard.value) {
myKeyboard.value.clearNum()
}
//判断小数位数 //判断小数位数
let decimalPosition = field.decimalPosition let decimalPosition = field.decimalPosition
if (decimalPosition == null || decimalPosition < -1) decimalPosition = -1 if (decimalPosition == null || decimalPosition < -1) decimalPosition = -1
numKeyboardParam.decimal = decimalPosition numKeyboardParam.decimal = decimalPosition
if (field.fillingWay == 2) { if (field.fillingWay == 'keyboard') {
listenDeviceData() listenDeviceData()
} else { } else {
closeDeviceListener() closeDeviceListener()
@@ -350,7 +357,7 @@ const autoNextField = () => {
//自动切换到下一个样品 //自动切换到下一个样品
const autoNextSample = () => { const autoNextSample = () => {
if (leftList.value.length <= currentSampleIndex.value + 1) return if (sampleDataList.value.length <= currentSampleIndex.value + 1) return
const index = currentSampleIndex.value + 1 const index = currentSampleIndex.value + 1
groupFieldIndex.value = '' groupFieldIndex.value = ''
selectedField.value = {} selectedField.value = {}
@@ -376,7 +383,6 @@ const switchSample = async (index, autoFlag) => {
// groupFieldIndex.value = groupFieldIndex.value.split('-')[0] + '-' // groupFieldIndex.value = groupFieldIndex.value.split('-')[0] + '-'
// } // }
uni.showLoading({ title: '加载中...' }) uni.showLoading({ title: '加载中...' })
currentSample.value = leftList.value[index]
setValueToField() setValueToField()
autoGenerateCupNum() autoGenerateCupNum()
setTimeout(() => { setTimeout(() => {
@@ -413,7 +419,7 @@ const getElRect = (elClass, maxRetry = 50) => {
//读取样品明细字段 //读取样品明细字段
const getDetailFieldsAndStatus = autoSelectNextField => { const getDetailFieldsAndStatus = autoSelectNextField => {
const taskDetailId = currentSample.value.id const taskDetailId = currentSampleData.value.id
//读取回收率配置 //读取回收率配置
loadConRecoveryList() loadConRecoveryList()
optionParameterClassify.value = arr //字段分类 optionParameterClassify.value = arr //字段分类
@@ -619,29 +625,96 @@ const saveAuncelData = () => {
autoNextField() autoNextField()
}, 100) }, 100)
} }
const dynamicFormData = {}
const saveDetail = async () => { const saveDetail = async () => {
//检查杯号 //检查杯号
if (!checkBh()) return if (!checkBh()) return
let params = {
businessAssayTaskId: taskId.value,
datas: sampleDataList
}
setValueToSample() setValueToSample()
await nx.$api.assayTask.saveDetailValue(params) let params = {
businessAssayTaskId: taskId.value
}
// 如果是空白样和标样就需要根据配置信息来计算质控样、分析样
if (activeAssayTypeKey.value === 'kby' || activeAssayTypeKey.value === 'by') {
// 处理其他页签的输入变化
const configInfomation = currentAssayType.value.configQCSampleMethodInfo
const row = sampleDataList.value[currentSampleIndex.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) {
dynamicFormData[item.target] = item.value
updateTableDataByConfigFields()
}
}
})
params.formValue = JSON.stringify(dynamicFormData)
params.assayTaskAnalysisDataList = assayGroups.value.map(item => ({
datas: item.tableData,
analysisType: item.value
}))
} else {
const datas = sampleDataList.value[currentSampleIndex.value]
params.assayTaskAnalysisDataList = [{ datas, analysisType: activeAssayTypeKey.value }]
}
await nx.$api.assayTask.saveBatchSmpleAndQcAnalysis(params)
getSampleAnalysisByTaskId()
autoNextSample() 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() { function setValueToSample() {
let fields = fieldGroup.value.flatMap(item => item.fields) let fields = fieldGroup.value.flatMap(item => item.fields)
fields.forEach(item => { fields.forEach(item => {
if (sampleDataList[currentSampleDataIndex.value].hasOwnProperty(item.fieldIndex)) { if (
sampleDataList[currentSampleDataIndex.value][item.fieldIndex].value = item.value sampleDataList.value[currentSampleIndex.value].hasOwnProperty(item.fieldIndex) &&
nx.$test.object(sampleDataList.value[currentSampleIndex.value][item.fieldIndex])
) {
sampleDataList.value[currentSampleIndex.value][item.fieldIndex].value = item.value
} }
// 初始化的时候保存杯号到样品中后续自动生成杯号用 // 初始化的时候保存杯号到样品中后续自动生成杯号用
if (item.title === cupNumKey && currentSampleIndex.value == 0) { if (item.title === cupNumKey && currentSampleIndex.value == 0) {
leftList.value[currentSampleIndex.value].cupNum = item.value sampleDataList.value[currentSampleIndex.value].cupNum = item.value
} }
}) })
} }
@@ -676,14 +749,14 @@ const autoGenerateCupNum = () => {
//第一杯 //第一杯
if (current === 0) return if (current === 0) return
//取上一个样品的杯号 //取上一个样品的杯号
const sample = leftList.value[current - 1] const sample = sampleDataList.value[current - 1]
cupNum = sample.cupNum cupNum = sample.cupNum
//杯号赋值到当前样品 //杯号赋值到当前样品
putCupNum(Number(cupNum) + 1, current, Number(cupNum)) putCupNum(Number(cupNum) + 1, current, Number(cupNum))
} }
const putCupNum = (cupNum, sampleIndex, lastCupNum) => { const putCupNum = (cupNum, sampleIndex, lastCupNum) => {
leftList.value[sampleIndex].cupNum = cupNum sampleDataList.value[sampleIndex].cupNum = cupNum
for (const fields of fieldGroup.value) { for (const fields of fieldGroup.value) {
if (typeof fields === 'undefined') continue if (typeof fields === 'undefined') continue
//杯号 //杯号
@@ -727,7 +800,7 @@ const putCupNum = (cupNum, sampleIndex, lastCupNum) => {
} }
const loadConRecoveryList = () => { const loadConRecoveryList = () => {
const conBaseSampleId = currentSample.value.conBaseSampleId const conBaseSampleId = currentSampleData.value.conBaseSampleId
const rParam = { const rParam = {
pageNo: 1, pageNo: 1,
pageSize: -1, pageSize: -1,
@@ -754,29 +827,60 @@ const loadConRecoveryList = () => {
}) })
} }
const getAssayTaskSampleList = businessAssayTaskId => { // 分析样品组
leftList.value = [] let assayGroups = ref([])
nx.$api.assayTask const activeAssayTypeKey = ref('')
.getAssayTaskDataList({ businessAssayTaskId }) const activeAssayTypeIndex = ref(0)
.then(res => { //元素结果范围
leftList.value = res let conRangeElementAnalysisList = []
currentSampleIndex.value = 0 const currentAssayType = computed(() => {
currentSample.value = leftList.value[0] return assayGroups.value.find(item => item.value === activeAssayTypeKey.value)
}) })
.catch(err => { watch(
console.error(err) () => currentAssayType.value,
}) () => {
sampleDataList.value = currentAssayType.value.tableData
fieldGroup.value = [{ open: true, fields: currentAssayType.value.columns, title: '样品分析' }]
setValueToField()
// getDomHeight()
activeCollapses.value = fieldGroup.value.map((_, index) => index)
}
)
const collapseRef = ref()
const activeCollapses = ref([])
function handleAssayTypeChange({ index, value }) {
activeAssayTypeKey.value = value
activeAssayTypeIndex.value = index
currentSampleIndex.value = 0
groupFieldIndex.value = ''
collapseRef.value.init()
} }
// 获取任务指派单数据
async function getSampleAnalysisByTaskId() {
const { assayTaskAnalysisDataList, configAssayMethodProjectRangeList, businessAssayTasNo } =
await nx.$api.assayTask.batchSampleAndQcAnalysisByTaskId(taskId.value)
title.value = '样品分析-任务指派单:' + businessAssayTasNo
// 处理分析数据
assayGroups.value = assayTaskAnalysisDataList.map(group => {
// 必须深拷贝 datas防止多个表格共享引用
const tableData = JSON.parse(JSON.stringify(group.datas || []))
const columns = group.columns || []
async function getSampleAnalysisByTaskId(businessAssayTaskId) { return {
const data = await nx.$api.assayTask.getSampleAnalysisByTaskId(businessAssayTaskId) value: group.analysisType,
sampleDataList = data.datas name: group.analysisName,
let columns = data.columns.filter(item => item.paramNo) columns,
fieldGroup.value = [{ open: true, fields: columns, title: '样品分析' }] tableData,
setValueToField() configQCSampleMethodInfo: group.configQCSampleMethod?.configInfomation
title.value = '样品分析-任务指派单:' + data.businessAssayTasNo ? JSON.parse(group.configQCSampleMethod['configInfomation'])['set']
getDomHeight() : []
autoNextField() }
})
// 默认激活第一个 类型
if (!activeAssayTypeKey.value) {
activeAssayTypeKey.value = assayGroups.value.length > 0 ? assayGroups.value[0].value : ''
}
conRangeElementAnalysisList = configAssayMethodProjectRangeList || []
} }
// 设置字段值 // 设置字段值
function setValueToField() { function setValueToField() {
@@ -788,7 +892,7 @@ function setValueToField() {
} }
} }
function getFieldValue(field) { function getFieldValue(field) {
const fieldValue = sampleDataList[currentSampleDataIndex.value][field.fieldIndex].value const fieldValue = sampleDataList.value[currentSampleIndex.value][field.fieldIndex]?.value
if (fieldValue) { if (fieldValue) {
return fieldValue return fieldValue
} else { } else {
@@ -1008,8 +1112,8 @@ onLoad(param => {
lockOrientation('landscape') lockOrientation('landscape')
if (param.currentTaskId) { if (param.currentTaskId) {
taskId.value = param.currentTaskId taskId.value = param.currentTaskId
getAssayTaskSampleList(taskId.value) // getAssayTaskSampleList(taskId.value)
getSampleAnalysisByTaskId(taskId.value) getSampleAnalysisByTaskId()
} }
loadFieldApiData(fieldGroup.value) loadFieldApiData(fieldGroup.value)
listenNumKeyboard() listenNumKeyboard()
@@ -1112,7 +1216,7 @@ onBackPress(() => {
color: #c0c4cc; color: #c0c4cc;
} }
.content-left-scroll { .content-left-scroll {
height: 60vh; height: 68vh;
} }
.content-right-scroll { .content-right-scroll {
height: 68vh; height: 68vh;

View File

@@ -21,7 +21,7 @@
v-model="field.value" v-model="field.value"
clearable clearable
:placeholder="field.placeholder" :placeholder="field.placeholder"
:disabled="field.disabled || field.fillingWay == 3" :disabled="field.disabled || field.fillingWay == 'calculate'"
/> />
<!--数字限制小数位数--> <!--数字限制小数位数-->
<u-input <u-input
@@ -31,7 +31,7 @@
@blur="event => checkDecimal(event, field)" @blur="event => checkDecimal(event, field)"
v-model="field.value" v-model="field.value"
:placeholder="field.placeholder" :placeholder="field.placeholder"
:disabled="field.disabled || field.fillingWay == 3" :disabled="field.disabled || field.fillingWay == 'calculate'"
/> />
<!--select--> <!--select-->
<view v-if="field.type == 'select'" class="x-bc select-my" @click="handleFieldClick(field)"> <view v-if="field.type == 'select'" class="x-bc select-my" @click="handleFieldClick(field)">
@@ -150,12 +150,6 @@ function loadTaskDetail() {
// 点击字段(打开选择器) // 点击字段(打开选择器)
function handleFieldClick(field) { function handleFieldClick(field) {
if (field.type == 'date') {
field.showPicker = true
if (field.fillingWay == '1') {
}
return
}
field.showPicker = true field.showPicker = true
} }

View File

@@ -33,7 +33,7 @@
<block v-for="(sample, index) in sampleList" :key="index"> <block v-for="(sample, index) in sampleList" :key="index">
<view v-if="currentTask.reviewCount === sample.reviewCount" class="p5 fs16"> <view v-if="currentTask.reviewCount === sample.reviewCount" class="p5 fs16">
<u-row> <u-row>
<u-col span="3" class="text-center"> <u-col span="2" class="text-center">
<u-row> <u-row>
<u-col span="6" class="text-center"> <u-col span="6" class="text-center">
<!-- v-if=" <!-- v-if="
@@ -49,28 +49,30 @@
</u-col> </u-col>
</u-row> </u-row>
</u-col> </u-col>
<u-col span="9"> <u-col span="10" class="flex">
<view class="sample_desc"> <u-row>
<view> <u-col span="6">
<view <view class="sample_desc">
><text class="pl10">{{ sample.sampleCode }}</text></view <view>
> <view
><text class="pl10">{{ sample.sampleCode }}</text></view
>
<view>
<text class="pl10">
{{ getDataSourceTypeShow(sample.dataSourceType) }}{{ sample.sampleName }}
</text>
</view>
</view>
</view>
</u-col>
<u-col span="6">
<view> <view>
<text class="pl10"> <text class="pl10">
{{ getDataSourceTypeShow(sample.dataSourceType) }}{{ sample.sampleName }} {{ sample.assayProject }}
</text> </text>
</view> </view>
</view> </u-col>
</u-row>
<!-- <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-col>
</u-row> </u-row>
<u-line class="p5" color="#bbb" /> <u-line class="p5" color="#bbb" />
@@ -136,7 +138,7 @@ const customBack = () => {
uni.reLaunch({ url: '/pages/analysis/index/index' }) uni.reLaunch({ url: '/pages/analysis/index/index' })
} }
const showRollbackModal = () => { const showRollbackModal = () => {
if (checkedSampleCodes.length === 0) { if (checkedSampleCodes.value.length === 0) {
uni.showToast({ title: '请选择要退回的样品!', icon: 'none' }) uni.showToast({ title: '请选择要退回的样品!', icon: 'none' })
return return
} }