feat:待审数据

This commit is contained in:
houjunxiang
2025-11-11 20:51:08 +08:00
parent fb41fa9a03
commit 970a8b8eae
11 changed files with 416 additions and 651 deletions

View File

@@ -3,41 +3,16 @@
<view> <view>
<u-popup :show="showPopup" @close="close" @open="open" mode="left"> <u-popup :show="showPopup" @close="close" @open="open" mode="left">
<view class="detail_title"> <view class="detail_title">
{{ taskDetail.sampleCode }} {{ taskDetail.sampleName }}
{{ taskDetail.sampleAssayCode }}
</view> </view>
<view> <view>
<scroll-view scroll-y style="height: 100vh; width: 30vw"> <scroll-view scroll-y style="height: 100vh; width: 30vw">
<view style="padding: 10px"> <view style="padding: 10px">
<up-collapse :value="getAllIndexes(fieldGroup)" :accordion="false"> <view class="form-item-my" v-for="(field, index) in fields" :key="index">
<up-collapse-item <view class="label-my">{{ field.title }}</view>
v-for="(fields, groupIndex) in fieldGroup" <view class="value-my">{{ field.value }}</view>
:title="fields.title" </view>
:key="groupIndex"
v-if="curParameterKey === '' || curParameterKey === fields.title"
>
<view
class="form-item-my"
v-for="(field, fieldIndex) in fields.fields"
:key="groupIndex + '-' + fieldIndex"
>
<view
class="label-my"
v-html="
field.name +
(typeof field.unit !== 'undefined' && field.unit !== null ? '(' + field.unit + ')' : '')
"
></view>
<view class="content-my">
<view class="content-my-text" v-if="field.type !== 'select'">
<text class="content-my-text-value">{{ field.value }}</text>
</view>
<view class="content-my-text" v-else>
<text class="content-my-text-value">{{ field.valueText }}</text>
</view>
</view>
</view>
</up-collapse-item>
</up-collapse>
</view> </view>
<view class="p30"></view> <view class="p30"></view>
</scroll-view> </scroll-view>
@@ -56,23 +31,16 @@ const props = defineProps({
type: Boolean, type: Boolean,
default: false default: false
}, },
detailPopupParam: { detailId: {
type: Object, type: String,
default: () => ({ default: ''
taskDetailId: ''
})
} }
}) })
const emit = defineEmits(['update:showPopup']) const emit = defineEmits(['update:showPopup'])
// Data // Data
const curSample = ref({}) const fields = ref([])
const curParameterKey = ref('')
const fieldGroup = ref([])
const taskDetail = ref({}) const taskDetail = ref({})
const optionParameterClassify = ref([])
const conAssayTaskId = ref('')
const busSubCSampleId = ref('')
// Methods // Methods
const getAllIndexes = arr => { const getAllIndexes = arr => {
@@ -84,25 +52,12 @@ const close = () => {
} }
const getSampleData = () => { const getSampleData = () => {
const taskDetailId = props.detailPopupParam.taskDetailId const businessAssayTaskDataId = props.detailId
nx.$api.assayTask.queryFieldsByTaskDetail({ taskDetailId }).then(res => { nx.$api.assayTask.getSampleAnalysisDataByTaskDataId({ businessAssayTaskDataId }).then(res => {
fieldGroup.value = res.result taskDetail.value = res
fields.value = res.columns
const arr = [{ label: '全部', value: '' }]
for (const g of fieldGroup.value) {
const title = g.title
arr.push({
label: title,
value: title
})
}
optionParameterClassify.value = arr // 字段分类
conAssayTaskId.value = res.additionalProperties.conAssayTaskId
busSubCSampleId.value = res.additionalProperties.busSubCSampleId
taskDetail.value = res.additionalProperties.taskDetail
}) })
} }
const open = () => { const open = () => {
getSampleData() getSampleData()
} }
@@ -112,41 +67,20 @@ const open = () => {
.form-item-my { .form-item-my {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between;
margin-bottom: 10px; margin-bottom: 10px;
border-bottom: 1px solid #eee;
padding: 4px 0;
} }
.label-my { .label-my {
width: 180px; /* 标签宽度 */ color: #606266;
display: flex;
align-items: center;
}
.label-my sub {
font-size: 0.6em; /* 调整下标字体大小 */
vertical-align: sub; /* 调整下标垂直对齐 */
}
.content-my {
flex: 1;
padding-left: 7px;
}
.content-my-text {
height: 35px;
display: flex;
align-items: center;
}
.content-my-text-value {
color: rgb(48, 49, 51);
} }
.detail_title { .detail_title {
display: flex; text-align: center;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
font-size: 18px; font-size: 18px;
font-weight: 400; font-weight: 400;
padding-top: 30px; padding: 10px;
padding-bottom: 10px;
background-color: $uni-color-primary; background-color: $uni-color-primary;
color: #fff; color: #fff;
} }

View File

@@ -5,11 +5,9 @@ const taskPrefix = '/qms/bus/qmsBusAssayTask'
// 获取任务 // 获取任务
const getAssayTaskList = params => { const getAssayTaskList = params => {
return request({ return request({
url: '/qms/business-assay-task/page', url: '/qms/business-assay-task/list',
method: 'GET', method: 'GET',
params: { params: {
pageSize: 999,
pageNo: 1,
...params ...params
} }
}) })
@@ -107,16 +105,11 @@ const execSendSample = data => {
} }
// 获取任务明细字段 // 获取任务明细字段
const queryFieldsByTaskDetail = params => { const getSampleAnalysisDataByTaskDataId = params => {
return request({ return request({
url: '/qms/config/qmsConAssayTaskDetailField/queryFieldsByTaskDetail', url: '/qms/bus/sample/analysis/getSampleAnalysisDataByTaskDataId',
method: 'GET', method: 'GET',
params: { params
...params
},
custom: {
isTransformResponse: true
}
}) })
} }
@@ -125,9 +118,7 @@ const queryHeadFieldsByTaskNo = params => {
return request({ return request({
url: '/qms/config/qmsConAssayTaskHead/queryHeadFieldsByTaskNo', url: '/qms/config/qmsConAssayTaskHead/queryHeadFieldsByTaskNo',
method: 'GET', method: 'GET',
params: { params
...params
}
}) })
} }
@@ -136,9 +127,7 @@ const queryHeadValueByTaskNo = params => {
return request({ return request({
url: '/qms/bus/qmsBusAssayTaskHead/queryHeadValueByTaskNo', url: '/qms/bus/qmsBusAssayTaskHead/queryHeadValueByTaskNo',
method: 'GET', method: 'GET',
params: { params,
...params
},
custom: { custom: {
showError: false, showError: false,
isTransformResponse: true isTransformResponse: true
@@ -280,7 +269,7 @@ export default {
getDynamicBaseFormSchema, getDynamicBaseFormSchema,
getAssayTaskDetailListByTaskNo, getAssayTaskDetailListByTaskNo,
getAssayTaskDetailById, getAssayTaskDetailById,
queryFieldsByTaskDetail, getSampleAnalysisDataByTaskDataId,
queryHeadFieldsByTaskNo, queryHeadFieldsByTaskNo,
queryHeadValueByTaskNo, queryHeadValueByTaskNo,
saveHeadValue, saveHeadValue,

View File

@@ -46,6 +46,7 @@ export function calcAnalysisValue(group) {
if (formulaVal.startsWith('Get')) { if (formulaVal.startsWith('Get')) {
//计算公式为Get开头的都是执行方法 //计算公式为Get开头的都是执行方法
v = eval(formulaVal) v = eval(formulaVal)
} else if (formulaVal.startsWith('From')) {
} else { } else {
v = math.evaluate(formulaVal).toString() v = math.evaluate(formulaVal).toString()
v = isFinite(v) ? v.toString() : '' v = isFinite(v) ? v.toString() : ''
@@ -85,6 +86,7 @@ export function calcRowAnalysisValue(row, columnObj, dynamicsColumns) {
if (formulaVal.startsWith('Get')) { if (formulaVal.startsWith('Get')) {
formulaVal = formulaVal.replace(')', ",'" + row.conBaseSampleId + "')") formulaVal = formulaVal.replace(')', ",'" + row.conBaseSampleId + "')")
v = eval(formulaVal) v = eval(formulaVal)
} else if (formulaVal.startsWith('From')) {
} else { } else {
v = math.evaluate(formulaVal).toString() v = math.evaluate(formulaVal).toString()
v = isFinite(v) ? v : 0 v = isFinite(v) ? v : 0
@@ -326,3 +328,27 @@ function accAdd(arg1, arg2) {
} }
return (arg1 + arg2) / m return (arg1 + arg2) / m
} }
// 通过配置项分组
export function groupByField(list, groupKey = 'groupDictionaryBusinessKey') {
const groupMap = new Map()
list.unshift({ groupDictionaryBusinessKey: 'all', groupDictionaryBusinessName: '全部' })
for (const item of list) {
const key = item[groupKey]
if (!key) continue // 跳过没有 group 的项(可选)
if (!groupMap.has(key)) {
groupMap.set(key, {
value: key,
label: item.groupDictionaryBusinessName, // 假设 title 在每个 item 中,且同组相同
fields: []
})
}
// 把当前项(或仅需要的部分)推入 fields
groupMap.get(key).fields.push(item)
}
// 转为数组
return Array.from(groupMap.values())
}

View File

@@ -149,6 +149,7 @@ http.interceptors.response.use(
} }
const { code, data, msg } = response.data const { code, data, msg } = response.data
// 统一处理【公司/部门二次选择】:参考 PC 端逻辑,自动补全或提示选择后重试 // 统一处理【公司/部门二次选择】:参考 PC 端逻辑,自动补全或提示选择后重试
if (code === 400 && Array.isArray(data)) { if (code === 400 && Array.isArray(data)) {
debugger debugger
@@ -209,17 +210,19 @@ http.interceptors.response.use(
} }
} }
if ((code === 0 || code === 200) && response.config.custom.showSuccess) { if (code === 0 || code === 200) {
setTimeout(() => { if (response.config.custom.showSuccess) {
uni.showToast({ setTimeout(() => {
title: msg || response.config.custom.successMsg, uni.showToast({
icon: 'none' title: msg || response.config.custom.successMsg,
}) icon: 'none'
}, 100) })
}, 100)
}
$store('user').updateLastRequestTime()
return Promise.resolve(data)
} }
return Promise.reject(response.data)
$store('user').updateLastRequestTime()
return Promise.resolve(data)
}, },
error => { error => {
console.log('error', error) console.log('error', error)

View File

@@ -1,7 +1,8 @@
export default { export default {
isNullOrEmpty: function (value) { isEmpty: function (value) {
//是否为空 if (value === undefined || value === null) return true
return value === null || value === '' || value === undefined ? true : false if (typeof value === 'string' && value.trim() === '') return true
return false
}, },
trim: function (value) { trim: function (value) {
//去空格 //去空格
@@ -311,6 +312,20 @@ export default {
} }
}) })
}, },
showPromiseModal(title, content) {
return new Promise(resolve => {
uni.showModal({
title,
content,
cancelColor: '#0055A2',
confirmColor: '#0055A2',
success: res => {
resolve(res.confirm) // true 表示点击了确定false 表示取消
},
fail: () => resolve(false)
})
})
},
isRsk() { isRsk() {
let sysInfo = uni.getSystemInfoSync() let sysInfo = uni.getSystemInfoSync()
let brand = sysInfo.brand.toLowerCase() let brand = sysInfo.brand.toLowerCase()

View File

@@ -28,9 +28,9 @@ const isAllowAgainPrint = ref(false)
const menuItemList = ref([ const menuItemList = ref([
// { url: '/pages/analysis/sample/sample-receive', otherConf: { icon: 'arrow-downward' }, name: '收样' }, // { 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-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', otherConf: { icon: 'arrow-upward' }, name: '数据上报' },
{ url: '/pages/analysis/sample/sample-report-search', otherConf: { icon: 'search' }, 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/sample/sample-print', otherConf: { icon: 'file-text-fill' }, name: '单据补打' },
{ url: '/pages/analysis/setting/setting', otherConf: { icon: 'setting-fill' }, name: '系统设置' } { url: '/pages/analysis/setting/setting', otherConf: { icon: 'setting-fill' }, name: '系统设置' }
]) ])

View File

@@ -15,7 +15,7 @@ import { getBaseUrl } from '@/defaultBaseUrl'
import nx from '@/nx' import nx from '@/nx'
// 响应式数据 // 响应式数据
const taskId = ref('') const businessAssayTaskId = ref('')
const localFilePath = ref('') const localFilePath = ref('')
const reportKey = ref('') const reportKey = ref('')
const hideResultFlag = ref('') const hideResultFlag = ref('')
@@ -87,10 +87,10 @@ const loadPdfOnAndroid = async pdfUrl => {
const getPdf = async () => { const getPdf = async () => {
const printBaseUrl = getBaseUrl() const printBaseUrl = getBaseUrl()
const baseUrl = getBaseUrl() const baseUrl = getBaseUrl()
let dataUrl = `${baseUrl}/qms/bus/qmsBusAssayTask/getAssayTaskDataWithDetailData?taskId=${taskId.value}` let dataUrl = `${baseUrl}/qms/bus/sample/analysis-audit/crossAuditByTaskId?businessAssayTaskId=${businessAssayTaskId.value}`
dataUrl += `&hideResultFlag=${hideResultFlag.value}` dataUrl += `&hideResultFlag=${hideResultFlag.value}`
const token = nx.$store('user').token const token = nx.$store('user').token
let url = `${printBaseUrl}/report/gridpp/report/previewDocs` let url = `${printBaseUrl}/qms/config-report-template/preview`
url += `?token=${token}` url += `?token=${token}`
url += `&type=PDF` url += `&type=PDF`
url += `&reportKey=${reportKey.value}` url += `&reportKey=${reportKey.value}`
@@ -123,8 +123,8 @@ const deleteTmpFile = () => {
// 生命周期 // 生命周期
onLoad(param => { onLoad(param => {
if (param.taskId) { if (param.businessAssayTaskId) {
taskId.value = param.taskId businessAssayTaskId.value = param.businessAssayTaskId
reportKey.value = param.reportKey reportKey.value = param.reportKey
hideResultFlag.value = param.hideResultFlag hideResultFlag.value = param.hideResultFlag
} }

View File

@@ -40,25 +40,22 @@
> >
<u-col span="2" class="text-center" :style="sampleStyle(sample)"> <u-col span="2" class="text-center" :style="sampleStyle(sample)">
<view> <view>
<text>{{ sample.sort }}</text> <text>{{ index + 1 }}</text>
</view> </view>
</u-col> </u-col>
<u-col span="5"> <u-col span="5">
<view> <view>
<text class="pl5">{{ sample.sampleCode }}</text> <text class="pl5">{{ sample.sampleAssayCode }}</text>
</view> </view>
<view> <view>
<text class="pl5"> <text class="pl5">
{{ getDataSourceTypeShow(sample.dataSourceType) }}{{ sample.sampleName }} {{ getDataSourceTypeShow(sample.dataSourceType) }}{{ sample.sampleName }}
</text> </text>
</view> </view>
<view v-if="sample.sampleWeight">
<text class="pl5">{{ sample.sampleWeight }} g</text>
</view>
</u-col> </u-col>
<u-col span="5"> <u-col span="5">
<view> <view>
<text style="padding-left: 10px">{{ sample.remarks }}</text> <text style="padding-left: 10px">{{ sample.assayProject }}</text>
</view> </view>
</u-col> </u-col>
</u-row> </u-row>
@@ -70,7 +67,7 @@
<u-row> <u-row>
<u-col span="3"></u-col> <u-col span="3"></u-col>
<u-col span="6"> <u-col span="6">
<u-button class="btn-operation" type="primary" @click="previewPDF" v-if="currentTaskId.value"> <u-button class="btn-operation" type="primary" @click="previewPDF" v-if="currentTask.id">
任务单预览 任务单预览
</u-button> </u-button>
</u-col> </u-col>
@@ -84,7 +81,7 @@
<sample-detail-popup <sample-detail-popup
ref="sampleDetailPopup" ref="sampleDetailPopup"
v-model:showPopup="showDetailPopup" v-model:showPopup="showDetailPopup"
:detailPopupParam="detailPopupParam" :detailId="detailId"
></sample-detail-popup> ></sample-detail-popup>
</view> </view>
</template> </template>
@@ -102,14 +99,12 @@ const scrollTop = ref(0)
const current = ref(0) const current = ref(0)
const currentTask = ref({}) const currentTask = ref({})
const currentTaskId = ref('') const currentTaskId = ref('')
const currentTaskNo = ref('')
const conAssayTask = ref('')
const reviewNum = ref(0) const reviewNum = ref(0)
const selectedIndex = ref(-1) const selectedIndex = ref(-1)
const taskList = ref([]) const taskList = ref([])
const sampleList = ref([]) const sampleList = ref([])
const showDetailPopup = ref(false) const showDetailPopup = ref(false)
const detailPopupParam = ref({ taskDetailId: '' }) const detailId = ref('')
// 计算属性 // 计算属性
const userInfo = computed(() => nx.$store('user').userInfo) const userInfo = computed(() => nx.$store('user').userInfo)
@@ -135,66 +130,51 @@ const switchTask = async index => {
selectedIndex.value = -1 selectedIndex.value = -1
const task = taskList.value[index] const task = taskList.value[index]
currentTask.value = task currentTask.value = task
currentTaskNo.value = task.taskNo getAssayTaskDetail(task.id)
currentTaskId.value = task.id
getAssayTaskDetail(task.taskNo)
} }
const showSampleDetail = (detailId, index) => { const showSampleDetail = (id, index) => {
selectedIndex.value = index selectedIndex.value = index
console.log('detailId', detailId) detailId.value = id
detailPopupParam.value = { taskDetailId: detailId }
showDetailPopup.value = true showDetailPopup.value = true
} }
const getAssayTask = () => { const getAssayTask = () => {
taskList.value = [] taskList.value = []
sampleList.value = [] sampleList.value = []
current.value = 0
const param = { const param = {
finishStatus: 'finished', taskAssignStatus: 'submitted',
wfStatus: 'running', taskAssayStatus: 'submitted',
finishStatus: 'not_start',
flowStatus: 'not_start',
assayOper: userInfo.value.realname assayOper: userInfo.value.realname
} }
nx.$api.assayTask.getAssayTaskList(param).then(res => { nx.$api.assayTask.getAssayTaskList(param).then(res => {
taskList.value = res taskList.value = res
if (taskList.value.length > 0) { if (taskList.value.length > 0) {
current.value = 0
currentTask.value = taskList.value[0] currentTask.value = taskList.value[0]
currentTaskNo.value = taskList.value[0].taskNo getAssayTaskDetail(currentTask.value.id)
currentTaskId.value = taskList.value[0].id
getAssayTaskDetail(currentTaskNo.value)
} else {
current.value = 0
currentTask.value = {}
currentTaskNo.value = ''
currentTaskId.value = ''
} }
}) })
} }
const getAssayTaskDetail = taskNo => { const getAssayTaskDetail = businessAssayTaskId => {
reviewNum.value = 0 reviewNum.value = 0
nx.$api.assayTaskTemplateKey nx.$api.assayTask.getAssayTaskDataList({ businessAssayTaskId }).then(res => {
.getAssayTaskDetailListByTaskNo({ taskNo }) sampleList.value = res || []
.then(res => { })
sampleList.value = res.result || []
if (res.additionalProperties?.conAssayTask) {
conAssayTask.value = res.additionalProperties.conAssayTask
}
})
.catch(err => {
console.error(err)
})
} }
const previewPDF = () => { const previewPDF = () => {
const url = `/pages/analysis/sample/pdf-preview?taskId=${currentTaskId.value}&reportKey=${conAssayTask.value.assayTaskTemplateKey}` const { id, configReportTemplateKey } = currentTask.value
const url = `/pages/analysis/sample/pdf-preview?businessAssayTaskId=${id}&reportKey=${configReportTemplateKey}`
uni.navigateTo({ url }) uni.navigateTo({ url })
} }
// 生命周期 // 生命周期
onMounted(() => { onMounted(() => {
// getAssayTask() getAssayTask()
}) })
onBackPress(() => { onBackPress(() => {

View File

@@ -34,10 +34,10 @@
<u-col span="3"> <u-col span="3">
<u-dropdown style="height: 35px"> <u-dropdown style="height: 35px">
<u-dropdown-item <u-dropdown-item
v-model="curParameterClassify" v-model="curParameterKey"
:title="curParameterTitle" :title="curParameterTitle"
height="70vh" height="70vh"
:options="optionParameterClassify" :options="fieldGroup"
@change="parameterClassifyChange" @change="parameterClassifyChange"
></u-dropdown-item> ></u-dropdown-item>
</u-dropdown> </u-dropdown>
@@ -123,37 +123,38 @@
:style="{ height: fields.open ? collaHeights[groupIndex] + 'px' : '0' }" :style="{ height: fields.open ? collaHeights[groupIndex] + 'px' : '0' }"
> --> > -->
<up-collapse ref="collapseRef" :value="activeCollapses"> <up-collapse ref="collapseRef" :value="activeCollapses">
<up-collapse-item v-for="(fields, groupIndex) in fieldGroup" :title="fields.title"> <template v-for="(fields, groupIndex) in currentGroup">
<view <up-collapse-item v-if="fields.label !== '全部'" :title="fields.label">
class="form-item-my"
v-for="(field, fieldIndex) in fields.fields"
@click="fieldClick(field, groupIndex + '-' + fieldIndex)"
:key="groupIndex + '-' + fieldIndex"
v-show="field.hidden != 1"
:class="{
'selected-field': groupFieldIndex === groupIndex + '-' + fieldIndex,
'disabled-field': !field.isEdit
}"
>
<view <view
:class="['label-my', { 'label-high-light': field.highlight == 1 }]" class="form-item-my"
v-html="field.title" v-for="(field, fieldIndex) in fields.fields"
></view> @click="fieldClick(field, groupIndex + '-' + fieldIndex)"
<view class="content-my"> :key="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个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 == 'input'" 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>
@@ -166,18 +167,21 @@
@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 != 'input'"> <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 == 'calculate' ? '计算值' : '请输入' !field.fillingWay || field.fillingWay == 'calculate' ? '计算值' : '请输入'
}}</text> }}</text>
<text v-else :class="['content-my-text-value', { 'field-high-light': field.highlight == 1 }]">{{ <text
field.value v-else
}}</text> :class="['content-my-text-value', { 'field-high-light': field.highlight == 1 }]"
>{{ field.value }}</text
>
</view>
</view> </view>
</view> </view>
</view> </up-collapse-item>
</up-collapse-item> </template>
</up-collapse> </up-collapse>
<!-- </view> <!-- </view>
</view> --> </view> -->
@@ -202,13 +206,20 @@
import { ref, reactive, computed, nextTick, watch, 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, handleRoundFiveNumber, calcRowAnalysisValue, math } from '@/nx/helper/calcAnalysisValue' import {
calcAnalysisValue,
handleRoundFiveNumber,
calcRowAnalysisValue,
math,
groupByField
} 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'
import { useScreenOrientation } from '@/nx/hooks/useScreenOrientation' import { useScreenOrientation } from '@/nx/hooks/useScreenOrientation'
import nx from '@/nx' import nx from '@/nx'
import { getDataSourceTypeShow } from '../common' import { getDataSourceTypeShow } from '../common'
import tools from '@/nx/utils/tools'
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
@@ -238,11 +249,9 @@ let selectedField = ref({})
const groupFieldIndex = ref('') //分组的索引 const groupFieldIndex = ref('') //分组的索引
const curSample = ref({}) const curSample = ref({})
const curParameterTitle = ref('选择字段分类') const curParameterTitle = ref('选择字段分类')
const curParameterKey = ref('') const curParameterKey = ref('all')
const curParameterClassify = ref('')
const conAssayTaskId = ref('') const conAssayTaskId = ref('')
const busSubCSampleId = ref('') const busSubCSampleId = ref('')
const optionParameterClassify = ref([])
let fieldGroup = ref([]) let fieldGroup = ref([])
const collaHeights = ref([]) const collaHeights = ref([])
const cupNumKey = '杯号' const cupNumKey = '杯号'
@@ -262,17 +271,6 @@ const confirmWeightDisabled = computed(() => {
} }
return true return true
}) })
// 当前样品数据
const currentSampleData = computed(() => {
if (sampleDataList.value.length > 0) {
return sampleDataList.value[currentSampleIndex.value]
}
return {}
})
// 当前操作字段索引
const currentFieldKey = computed(() => {
return selectedField.value.fieldIndex
})
const userInfo = computed(() => nx.$store('user').userInfo) const userInfo = computed(() => nx.$store('user').userInfo)
@@ -304,24 +302,17 @@ const navRightClick = () => {
}) })
} }
const parameterClassifyChange = (v, a) => { const parameterClassifyChange = v => {
const groupIndex = ref(0)
curParameterKey.value = v curParameterKey.value = v
optionParameterClassify.value.forEach((item, index) => { curParameterTitle.value = currentGroup.value[0].label
if (item.value === v) { groupFieldIndex.value = ''
groupIndex.value = index selectedField.value = {}
curParameterTitle.value = item.label collapseRef.value.init()
}
})
if (v === '') groupIndex.value = 0
if (groupIndex.value > 0) groupIndex.value--
//自动选中字段
groupFieldIndex.value = groupIndex.value + '-'
autoNextField() autoNextField()
} }
const fieldClick = (field, key) => { const fieldClick = (field, key) => {
if (field.fillingWay == 'input' || !field.fillingWay || field.fillingWay == 'calculate') return if (!field.isEdit || field.fillingWay === 'input') return
selectedField.value = field selectedField.value = field
groupFieldIndex.value = key groupFieldIndex.value = key
if (myKeyboard.value) { if (myKeyboard.value) {
@@ -331,7 +322,7 @@ const fieldClick = (field, key) => {
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 == 'keyboard') { if (field.fillingWay == 'collect') {
listenDeviceData() listenDeviceData()
} else { } else {
closeDeviceListener() closeDeviceListener()
@@ -346,7 +337,7 @@ const autoNextField = () => {
const indexV = groupFieldIndex.value.split('-') const indexV = groupFieldIndex.value.split('-')
groupIndex = number(indexV[0]) groupIndex = number(indexV[0])
fieldIndex = indexV[1] === '' ? -1 : number(indexV[1]) fieldIndex = indexV[1] === '' ? -1 : number(indexV[1])
const group = fieldGroup.value[groupIndex] const group = currentGroup.value[groupIndex]
const fields = group.fields const fields = group.fields
if (fields.length > fieldIndex + 1) { if (fields.length > fieldIndex + 1) {
//切换到下一个字段 //切换到下一个字段
@@ -366,6 +357,15 @@ const autoNextSample = () => {
//手动切换样品 //手动切换样品
const switchSample = async (index, autoFlag) => { const switchSample = async (index, autoFlag) => {
if (!autoFlag) {
const shouldContinue = await tools.showPromiseModal(
'提示',
`请确认样品【${currentSampleData.value.sampleCode}】数据已经保存,是否继续?`
)
if (!shouldContinue) {
return // 用户点了取消,直接退出
}
}
//重置天平归0 //重置天平归0
weightDataIsToZero.value = false weightDataIsToZero.value = false
if (index === currentSampleIndex.value) return if (index === currentSampleIndex.value) return
@@ -378,10 +378,6 @@ const switchSample = async (index, autoFlag) => {
} }
// 将菜单菜单活动item垂直居中 // 将菜单菜单活动item垂直居中
scrollTop.value = index * menuItemHeight.value + menuItemHeight.value / 2 - menuHeight.value / 2 - 50 scrollTop.value = index * menuItemHeight.value + menuItemHeight.value / 2 - menuHeight.value / 2 - 50
//修改当前选中的groupFieldIndex
// if (typeof groupFieldIndex.value !== 'undefined' && groupFieldIndex.value.indexOf('-') > 0) {
// groupFieldIndex.value = groupFieldIndex.value.split('-')[0] + '-'
// }
uni.showLoading({ title: '加载中...' }) uni.showLoading({ title: '加载中...' })
setValueToField() setValueToField()
autoGenerateCupNum() autoGenerateCupNum()
@@ -422,7 +418,6 @@ const getDetailFieldsAndStatus = autoSelectNextField => {
const taskDetailId = currentSampleData.value.id const taskDetailId = currentSampleData.value.id
//读取回收率配置 //读取回收率配置
loadConRecoveryList() loadConRecoveryList()
optionParameterClassify.value = arr //字段分类
conAssayTaskId.value = res.additionalProperties.conAssayTaskId conAssayTaskId.value = res.additionalProperties.conAssayTaskId
busSubCSampleId.value = res.additionalProperties.busSubCSampleId busSubCSampleId.value = res.additionalProperties.busSubCSampleId
const detail = res.additionalProperties.taskDetail const detail = res.additionalProperties.taskDetail
@@ -623,6 +618,7 @@ const saveAuncelData = () => {
//自动跳转下一个字段 //自动跳转下一个字段
setTimeout(() => { setTimeout(() => {
autoNextField() autoNextField()
weightDataIsToZero.value = false
}, 100) }, 100)
} }
const dynamicFormData = {} const dynamicFormData = {}
@@ -662,7 +658,7 @@ const saveDetail = async () => {
})) }))
} else { } else {
const datas = sampleDataList.value[currentSampleIndex.value] const datas = sampleDataList.value[currentSampleIndex.value]
params.assayTaskAnalysisDataList = [{ datas, analysisType: activeAssayTypeKey.value }] params.assayTaskAnalysisDataList = [{ datas: [datas], analysisType: activeAssayTypeKey.value }]
} }
await nx.$api.assayTask.saveBatchSmpleAndQcAnalysis(params) await nx.$api.assayTask.saveBatchSmpleAndQcAnalysis(params)
@@ -836,16 +832,30 @@ let conRangeElementAnalysisList = []
const currentAssayType = computed(() => { const currentAssayType = computed(() => {
return assayGroups.value.find(item => item.value === activeAssayTypeKey.value) return assayGroups.value.find(item => item.value === activeAssayTypeKey.value)
}) })
// 当前样品数据
const currentSampleData = computed(() => {
if (sampleDataList.value.length > 0) {
return sampleDataList.value[currentSampleIndex.value]
}
return {}
})
watch( watch(
() => currentAssayType.value, () => currentAssayType.value,
() => { () => {
sampleDataList.value = currentAssayType.value.tableData sampleDataList.value = currentAssayType.value.tableData
fieldGroup.value = [{ open: true, fields: currentAssayType.value.columns, title: '样品分析' }] fieldGroup.value = groupByField(currentAssayType.value.columns)
setValueToField() setValueToField()
// getDomHeight() // getDomHeight()
activeCollapses.value = fieldGroup.value.map((_, index) => index) activeCollapses.value = fieldGroup.value.map((_, index) => index)
} }
) )
const currentGroup = computed(() => {
if (!currentAssayType.value || curParameterKey.value === 'all') {
return fieldGroup.value
} else {
return fieldGroup.value.filter(g => g.value === curParameterKey.value)
}
})
const collapseRef = ref() const collapseRef = ref()
const activeCollapses = ref([]) const activeCollapses = ref([])
function handleAssayTypeChange({ index, value }) { function handleAssayTypeChange({ index, value }) {
@@ -853,6 +863,9 @@ function handleAssayTypeChange({ index, value }) {
activeAssayTypeIndex.value = index activeAssayTypeIndex.value = index
currentSampleIndex.value = 0 currentSampleIndex.value = 0
groupFieldIndex.value = '' groupFieldIndex.value = ''
selectedField.value = {}
curParameterKey.value = 'all'
curParameterTitle.value = '选择字段分类'
collapseRef.value.init() collapseRef.value.init()
} }
// 获取任务指派单数据 // 获取任务指派单数据
@@ -864,7 +877,7 @@ async function getSampleAnalysisByTaskId() {
assayGroups.value = assayTaskAnalysisDataList.map(group => { assayGroups.value = assayTaskAnalysisDataList.map(group => {
// 必须深拷贝 datas防止多个表格共享引用 // 必须深拷贝 datas防止多个表格共享引用
const tableData = JSON.parse(JSON.stringify(group.datas || [])) const tableData = JSON.parse(JSON.stringify(group.datas || []))
const columns = group.columns || [] const columns = group.columns.filter(item => item.paramNo) || []
return { return {
value: group.analysisType, value: group.analysisType,
@@ -1112,7 +1125,6 @@ onLoad(param => {
lockOrientation('landscape') lockOrientation('landscape')
if (param.currentTaskId) { if (param.currentTaskId) {
taskId.value = param.currentTaskId taskId.value = param.currentTaskId
// getAssayTaskSampleList(taskId.value)
getSampleAnalysisByTaskId() getSampleAnalysisByTaskId()
} }
loadFieldApiData(fieldGroup.value) loadFieldApiData(fieldGroup.value)

View File

@@ -6,111 +6,104 @@
<u-col span="10"> <u-col span="10">
<scroll-view scroll-y scroll-with-animation :scroll-top="scrollTop"> <scroll-view scroll-y scroll-with-animation :scroll-top="scrollTop">
<view class="form-item-my" v-for="(field, index) in formFields" :key="'field_' + index"> <view class="form-item-my" v-for="(field, index) in formFields" :key="'field_' + index">
<view <template v-if="!field.hidden">
class="label-my" <view
:style="{ fontWeight: checkFeadToDetailField(field.headToDetailField) ? 'bold' : 'normal' }" class="label-my"
>{{ field.label }}</view :style="{ fontWeight: checkFeadToDetailField(field.headToDetailField) ? 'bold' : 'normal' }"
> >{{ field.label }}</view
<view class="content-my"> >
<view v-if="field.type == 'title'" class="content-title"> <view class="content-my">
{{ field.value }} <view v-if="field.type == 'title'" class="content-title">
</view> {{ field.value }}
<!--普通输入框--> </view>
<u-input <!--普通输入框-->
v-if="field.type == 'Input'" <u-input
v-model="field.value" v-if="field.type == 'Input'"
clearable v-model="field.value"
:placeholder="field.placeholder" clearable
:disabled="field.disabled || field.fillingWay == 'calculate'" :placeholder="field.placeholder"
/> :disabled="field.disabled || field.fillingWay == 'calculate'"
<!--数字限制小数位数--> />
<u-input <!--数字限制小数位数-->
v-if="field.type == 'decimal'" <u-input
type="number" v-if="field.type == 'decimal'"
clearable type="number"
@blur="event => checkDecimal(event, field)" clearable
v-model="field.value" @blur="event => checkDecimal(event, field)"
:placeholder="field.placeholder" v-model="field.value"
:disabled="field.disabled || field.fillingWay == 'calculate'" :placeholder="field.placeholder"
/> :disabled="field.disabled || field.fillingWay == 'calculate'"
<!--select--> />
<view v-if="field.type == 'select'" class="x-bc select-my" @click="handleFieldClick(field)"> <!--select-->
<text v-if="field.value">{{ field.value }}</text> <view v-if="field.type == 'select'" class="x-bc select-my" @click="handleFieldClick(field)">
<text v-else>请选择</text> <text v-if="field.value">{{ field.value }}</text>
<u-icon name="arrow-down" size="20"></u-icon> <text v-else>请选择</text>
</view> <u-icon name="arrow-down" size="20"></u-icon>
<u-picker </view>
v-if="field.type == 'select'" <u-picker
:show="field.showPicker" v-if="field.type == 'select'"
:columns="[field.options]" :show="field.showPicker"
keyName="displayName" :columns="[field.options]"
@cancel="field.showPicker = false" keyName="displayName"
@confirm="event => pickerConfirm(event, field)" @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">{{ nx.$dayjs(field.value).format('YYYY-MM-DD HH:mm:ss') }}</text> <view v-if="field.type == 'date'" class="x-bc select-my" @click="handleFieldClick(field)">
<text v-else>请选择</text> <text v-if="field.value">{{ nx.$dayjs(field.value).format('YYYY-MM-DD HH:mm:ss') }}</text>
<u-icon name="calendar-fill" size="20"></u-icon> <text v-else>请选择</text>
</view> <u-icon name="calendar-fill" size="20"></u-icon>
</view>
<u-datetime-picker <u-datetime-picker
v-if="field.type == 'date'" v-if="field.type == 'date'"
:show="field.showPicker" :show="field.showPicker"
v-model="curDate" v-model="curDate"
mode="datetime" mode="datetime"
@cancel="field.showPicker = false" @cancel="field.showPicker = false"
@confirm="event => pickerConfirm(event, field)" @confirm="event => pickerConfirm(event, field)"
></u-datetime-picker> ></u-datetime-picker>
</view> </view>
</template>
</view> </view>
</scroll-view> </scroll-view>
<u-button type="primary" @click="saveHeadData">保存</u-button> <u-button style="width: 50%" type="primary" @click="saveHeadData">保存</u-button>
</u-col> </u-col>
<u-col span="1"> </u-col> <u-col span="1"> </u-col>
</u-row> </u-row>
<up-loading-page :loading="pageLoading"></up-loading-page>
</view> </view>
</template> </template>
<script setup> <script setup>
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
import request from '@/nx/request'
import { cloneDeep } from 'lodash'
import { calcAnalysisValue } from '@/nx/helper/calcAnalysisValue'
import nx from '@/nx' import nx from '@/nx'
import { onLoad } from '@dcloudio/uni-app' import { onLoad } from '@dcloudio/uni-app'
import { calcRowAnalysisValue } from '@/nx/helper/calcAnalysisValue'
import tools from '@/nx/utils/tools'
const pageLoading = ref(false)
// 标题 // 标题
const title = ref('编辑指派单') const title = ref('编辑指派单')
// 表单模型
const taskInstance = ref({})
// tab标题的滚动条位置 // tab标题的滚动条位置
const scrollTop = ref(0) const scrollTop = ref(0)
// 当前任务样品 // 当前任务样品
const currentTaskNo = ref('')
const currentTaskId = ref('') const currentTaskId = ref('')
// 字典选择器显示 // 字典选择器显示
const showDicPicker = ref(false)
// 当前日期(用于日期选择器) // 当前日期(用于日期选择器)
const curDate = ref(Number(new Date())) const curDate = ref(Number(new Date()))
// 字段值对象 // 字段值对象
const formValue = ref({}) const formData = ref({})
// 后端返回的字段结构
const sourceFormFields = ref([])
// 处理后的字段结构 // 处理后的字段结构
const formFields = ref([]) const formFields = ref([])
// 样品列表
const sampleList = ref([])
// 表单引用
const uForm = ref(null)
const staticFormSchema = [ const staticFormSchema = [
{ label: '指派单号', fieldKey: 'businessAssayTaskId', hidden: true },
{ type: 'title', value: '分析原始记录单' }, { type: 'title', value: '分析原始记录单' },
{ label: '检测方法', type: 'Input', fieldKey: 'configAssayMethodName', disabled: true }, { label: '检测方法', type: 'Input', fieldKey: 'configAssayMethodName', disabled: true },
{ label: '分析人', type: 'Input', fieldKey: 'assayOperator', disabled: true }, { label: '分析人', type: 'Input', fieldKey: 'assayOperator', disabled: true },
{ label: '检测时间', type: 'date', fieldKey: 'assayTime' }, { label: '检测时间', type: 'date', fieldKey: 'assayTime' }
{ label: '小数值', type: 'decimal', fieldKey: 'num', decimalPosition: 4, placeholder: '请输入' }
] ]
let dynamicFormSchema = [] let dynamicFormSchema = []
@@ -119,35 +112,97 @@ onLoad(param => {
if (param.currentTaskId) { if (param.currentTaskId) {
currentTaskId.value = param.currentTaskId currentTaskId.value = param.currentTaskId
} }
// loadHeadFieldsAndValueByTaskNo()
// getSampleList(currentTaskNo.value)
loadTaskDetail() loadTaskDetail()
}) })
function loadTaskDetail() { let tabs = ref([])
nx.$api.assayTask.getSampleAnalysisByTaskId(currentTaskId.value).then(async res => { const dynamicFormData = ref({})
taskInstance.value = res async function loadTaskDetail() {
formValue.value = { pageLoading.value = true
configAssayMethodName: res.configAssayMethodName, const {
assayOperator: res.assayOperator, assayTaskAnalysisDataList,
assayTime: res.assayTime, businessAssayTasNo,
...JSON.parse(res.formValue) configAssayMethodName,
} assayOperator,
title.value = '样品分析-任务指派单:' + res.businessAssayTasNo assayTime,
const data = await nx.$api.assayTask.getDynamicBaseFormSchema({ dataCollectionId: res.dataCollectionId }) formValue,
dynamicFormSchema = data.map(item => ({ dataCollectionId,
label: item.fieldName, dataCollectionKey
fieldKey: item.fieldKey, } = await nx.$api.assayTask.batchSampleAndQcAnalysisByTaskId(currentTaskId.value)
type: item.fieldType, formData.value = {
value: '', businessAssayTaskId: currentTaskId.value,
placeholder: '请输入' configAssayMethodName: configAssayMethodName,
})) assayOperator: assayOperator,
formFields.value = [...staticFormSchema, ...dynamicFormSchema] assayTime: assayTime
bindFormValue() }
}) if (formValue) {
} formData.value = { ...formData.value, ...JSON.parse(formValue) }
dynamicFormData.value = JSON.parse(formValue)
}
title.value = '样品分析-任务指派单:' + businessAssayTasNo
// 查询动态字段
const dataCollectionParams = {}
if (dataCollectionId) {
dataCollectionParams.dataCollectionId = dataCollectionId
} else {
dataCollectionParams.dataCollectionKey = dataCollectionKey
}
const data = await nx.$api.assayTask.getDynamicBaseFormSchema(dataCollectionParams)
dynamicFormSchema = data.map(item => ({
label: item.fieldName,
fieldKey: item.fieldKey,
type: item.fieldType,
placeholder: '请输入'
}))
formFields.value = [...staticFormSchema, ...dynamicFormSchema]
bindFormValue()
// 处理样品分类数据
const tabGroups = assayTaskAnalysisDataList
tabs.value = tabGroups.map(group => {
// 必须深拷贝 datas防止多个表格共享引用
const tableData = JSON.parse(JSON.stringify(group.datas || []))
const columns = group.columns || []
return {
name: group.analysisType,
label: group.analysisName,
columns,
tableData,
configQCSampleMethodInfo: group.configQCSampleMethod?.configInfomation
? JSON.parse(group.configQCSampleMethod['configInfomation'])['set']
: []
}
})
pageLoading.value = false
}
// 空白样或者标样影响计算配置字段
const configQCSampleMethodInfos = computed(() => {
return tabs.value.filter(t => t.name === 'by' || t.name === 'kby').flatMap(tab => tab.configQCSampleMethodInfo)
})
// 表格数据更新后重新计算
async function updateTableDataByConfigFields() {
let needCalcTabs = []
needCalcTabs = tabs.value.filter(t => t.name !== 'by' && t.name !== 'kby')
const formData = realFormData.value
if (needCalcTabs.length === 0) return
for (const key in formData) {
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 = formData[key]
calcRowAnalysisValue(row, columnObj, tab.columns)
})
}
}
}
// 点击字段(打开选择器) // 点击字段(打开选择器)
function handleFieldClick(field) { function handleFieldClick(field) {
field.showPicker = true field.showPicker = true
@@ -162,18 +217,6 @@ function checkFeadToDetailField(headToDetailField) {
} }
} }
// 获取样品列表
function getSampleList(taskNo) {
nx.$api.assayTask
.getAssayTaskDetailListByTaskNo({ taskNo: taskNo })
.then(res => {
sampleList.value = res.result
})
.catch(err => {
console.error(err)
})
}
// 处理小数位数补0或去除多余位数 // 处理小数位数补0或去除多余位数
function checkDecimal(e, field) { function checkDecimal(e, field) {
if (e == '') return if (e == '') return
@@ -197,34 +240,12 @@ function checkDecimal(e, field) {
} }
} }
// 组装字段(处理默认值、初始化 picker 状态 // 绑定数据(将 formData 填入字段
function assembleFields() {
const formFieldsArr = []
for (const field of sourceFormFields.value) {
//日期类型的默认值
if (field.type == 'date') {
const value = field.value
field.showPicker = false
if (value == 'curDate') {
field.value = nx.$dayjs.format('yyyy-MM-dd')
}
}
if (field.type == 'select') {
field.showPicker = false
}
formFieldsArr.push(field)
}
//先序列化再转json避免json里定义的方法丢失
formFields.value = JSON.parse(JSON.stringify(formFieldsArr, nx.$helper.replacer), nx.$helper.reviver)
}
// 绑定数据(将 formValue 填入字段)
function bindFormValue() { function bindFormValue() {
//formValue
for (const field of formFields.value) { for (const field of formFields.value) {
const fieldKey = field.fieldKey const fieldKey = field.fieldKey
if (fieldKey) { if (fieldKey) {
const value = formValue.value[fieldKey] const value = formData.value[fieldKey]
if (value) { if (value) {
field.value = value field.value = value
} }
@@ -232,122 +253,76 @@ function bindFormValue() {
} }
} }
// 获取表单字段和值(老数据) const realFormData = computed(() => {
function loadHeadFieldsAndValueByTaskNo() { const formData = {}
nx.$api.assayTask
.queryHeadValueByTaskNo({ taskNo: currentTaskNo.value })
.then(res => {
const result = res.result
const formConf = result.formConf
sourceFormFields.value = eval(formConf)
formValue.value = JSON.parse(result.formValue)
//加载和处理表单字段
assembleFields()
//绑定数据
bindFormValue()
//读取字段里的动态选项
loadFieldApiData()
console.log('formFields', formFields.value)
})
.catch(err => {
//如果没有查到数据,按配置读取新的表单字段
getHeadFields()
})
}
// 获取表单字段(新数据)
function getHeadFields() {
nx.$api.assayTask.queryHeadFieldsByTaskNo({ taskNo: currentTaskNoVal }).then(res => {
sourceFormFields.value = analysisFormAndFields(res)
//加载和处理表单字段
assembleFields()
//读取字段里的动态选项
loadFieldApiData()
})
}
// 解析表单结构
function 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
}
// 将抬头字段值同步保存到明细字段
function saveHeadValueToDetail(onComplete) {
//循环抬头字段,提取需哟保存到明细的字段
const conf = []
for (const field of formFields.value) { for (const field of formFields.value) {
const prop = field.prop if (field.fieldKey) {
const headToDetailField = field.headToDetailField formData[field.fieldKey] = field.value
if (prop && headToDetailField && headToDetailField.trim() != '') {
const value = field.value
const r = {
prop: field.prop,
value: value,
headToDetailField: headToDetailField
}
conf.push(r)
} }
} }
const data = { return formData
taskNo: currentTaskNo.value, })
conf: conf
}
nx.$api.assayTask.saveHeadValueToDetail(data).then(res => {
if (onComplete) onComplete()
})
}
// 实际保存逻辑 // 实际保存逻辑
function handleSave() { async function handleSave(change) {
//组装数据 let params = {}
const formValueObj = {} if (change) {
for (const field of formFields.value) { // 计算样品数据
const prop = field.prop updateTableDataByConfigFields()
if (prop) { params = {
formValueObj[prop] = field.value ...realFormData.value,
formValue: JSON.stringify(getDynamicFormSchemaFormData(realFormData.value)),
assayTaskAnalysisDataList: tabs.value.map(item => ({
datas: item.tableData,
analysisType: item.name
}))
}
} else {
params = {
...realFormData.value,
formValue: JSON.stringify(getDynamicFormSchemaFormData(realFormData.value))
} }
} }
const value = { await nx.$api.assayTask.saveBatchSmpleAndQcAnalysis(params)
taskNo: currentTaskNo.value, uni.redirectTo({
formValue: JSON.stringify(formValueObj), url: '/pages/analysis/sample/sample-work-detail?currentTaskId=' + currentTaskId.value
formConf: JSON.stringify(sourceFormFields.value, replacer)
}
nx.$api.assayTask.saveHeadValue(value).then(async res => {
await saveHeadValueToDetail(async () => {
if (checkPropertyEquality()) {
await processIds(sampleList.value, 100)
} else {
uni.redirectTo({
url: '/pages/analysis/sample/sample-work-detail?currentTaskNo=' + currentTaskNo.value
})
}
})
}) })
} }
// 检查字段修改前和修改后字段值是否相等 function getDynamicFormSchemaFormData(obj) {
const includeKeys = new Set(dynamicFormSchema.filter(item => item.fieldKey).map(item => item.fieldKey))
return Object.fromEntries(Object.entries(obj).filter(([key]) => includeKeys.has(key)))
}
// 检查动态字段值在空白样或者标样的(影响计算配置字段)中是否变化
function checkPropertyEquality() { function checkPropertyEquality() {
for (const field of formFields.value) { if (configQCSampleMethodInfos.value.length === 0) return false
const prop = field.prop for (const config of configQCSampleMethodInfos.value) {
if (prop && field['headToDetailField'] && field['headToDetailField'].trim() !== '') { const target = config.target
const flag = formValue.value[prop] !== field.value ? true : false if (!target) continue
if (flag) return true const originalValue = dynamicFormData.value[target]
const currentValue = realFormData.value[target]
console.log('checkPropertyEquality', originalValue, currentValue)
if (!looseEqual(originalValue, currentValue)) {
return true
} }
} }
return false return false
} }
function looseEqual(a, b) {
const aEmpty = tools.isEmpty(a)
const bEmpty = tools.isEmpty(b)
if (aEmpty && bEmpty) {
return true // 都是空,算相等
}
if (aEmpty || bEmpty) {
return false // 一个空一个非空,不等
}
return a === b // 都非空,严格相等
}
// 保存抬头字段(带确认弹窗) // 保存抬头字段(带确认弹窗)
function saveHeadData() { function saveHeadData() {
if (!realFormData.value['assayTime']) return nx.$helper.showToast('请选择分析时间')
if (checkPropertyEquality()) { if (checkPropertyEquality()) {
uni.showModal({ uni.showModal({
title: '提示', title: '提示',
@@ -355,130 +330,12 @@ function saveHeadData() {
showCancel: false, showCancel: false,
success: res => { success: res => {
if (res.confirm) { if (res.confirm) {
handleSave() handleSave(true)
} }
} }
}) })
} else { } else {
handleSave() handleSave(false)
}
}
// 通过样品id查询明细
async function getSampleDataById(taskDetailId) {
let fieldGroup = []
const { result, additionalProperties } = await nx.$api.assayTask.queryFieldsByTaskDetail({
taskDetailId,
isSearchSRange: '0'
})
fieldGroup = result
const conAssayTaskId = additionalProperties.conAssayTaskId
const busSubCSampleId = additionalProperties.busSubCSampleId
const detail = additionalProperties.taskDetail
//处理硫值、硫量:未保存过的数据,读取接口返回的硫值、硫量
// 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 function submitData(data) {
try {
await nx.$api.assayTask.saveDetailValue(data)
} catch (error) {
throw error
}
}
// 批量处理样品(带间隔)
async function processIds(list, interval) {
let index = 0
const intervalId = setInterval(async () => {
if (index < list.length) {
const item = list[index]
index++
const params = await getSampleDataById(item['id'])
await submitData(params)
} else {
clearInterval(intervalId) // 所有任务完成后清除定时器
uni.redirectTo({
url: '/pages/analysis/sample/sample-work-detail?currentTaskNo=' + currentTaskNo.value
})
}
}, interval)
}
// 通用 API 请求
async function apiRequest(url) {
return request({
url: url,
method: 'GET'
})
}
// 读取字段里的API选项
async function loadFieldApiData() {
const formFieldsVal = formFields.value
let changeFlag = false
for (const field of formFieldsVal) {
const dicUrl = field.dicUrl
const type = field.type
if (dicUrl && dicUrl != '') {
//读取API选项
try {
const res = await 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) {
// 重新序列化以触发响应式更新(保留函数)
formFields.value = JSON.parse(JSON.stringify(formFieldsVal, nx.$helper.replacer), nx.$helper.reviver)
} }
} }
@@ -493,7 +350,7 @@ async function loadFieldApiData() {
* */ * */
function pickerConfirm(event, field) { function pickerConfirm(event, field) {
if (field.type == 'date') { if (field.type == 'date') {
field.value = nx.$dayjs(event.value).format(field.format) field.value = nx.$dayjs(event.value).valueOf()
field.showPicker = false field.showPicker = false
return return
} }
@@ -509,55 +366,6 @@ function pickerConfirm(event, field) {
} }
field.showPicker = false field.showPicker = false
} }
// 检查是否需要加载硫值(原逻辑保留)
function 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
}
// 读取硫值、硫量(原逻辑保留,未启用)
// function 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
// }
// }
// 根据 key 获取字段(依赖 fieldGroup但当前无 fieldGroup保留原逻辑结构
function getFieldByKey(key) {
// 注意:原代码中 this.fieldGroup 未定义,此处无法实现,保留函数结构
// 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
// }
// }
// }
// return field
return null
}
// ========== 工具函数(保留原位置) ==========
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -55,7 +55,7 @@
<view class="sample_desc"> <view class="sample_desc">
<view> <view>
<view <view
><text class="pl10">{{ sample.sampleCode }}</text></view ><text class="pl10">{{ sample.sampleAssayCode }}</text></view
> >
<view> <view>
<text class="pl10"> <text class="pl10">
@@ -67,9 +67,7 @@
</u-col> </u-col>
<u-col span="6"> <u-col span="6">
<view> <view>
<text class="pl10"> <text class="pl10" v-html="sample.assayProject"> </text>
{{ sample.assayProject }}
</text>
</view> </view>
</u-col> </u-col>
</u-row> </u-row>
@@ -212,7 +210,7 @@ const getAssayTask = () => {
} }
nx.$api.assayTask.getAssayTaskList(param).then(res => { nx.$api.assayTask.getAssayTaskList(param).then(res => {
if (res) { if (res) {
taskList.value = res.list taskList.value = res
if (taskList.value.length > 0) { if (taskList.value.length > 0) {
currentTask.value = taskList.value[0] currentTask.value = taskList.value[0]
getAssayTaskDetail(currentTask.value.id) getAssayTaskDetail(currentTask.value.id)