diff --git a/components/sample/sample-detail-popup.vue b/components/sample/sample-detail-popup.vue index 860ba6c..9defde2 100644 --- a/components/sample/sample-detail-popup.vue +++ b/components/sample/sample-detail-popup.vue @@ -3,41 +3,16 @@ - {{ taskDetail.sampleCode }} + {{ taskDetail.sampleName }} + {{ taskDetail.sampleAssayCode }} - - - - - - - {{ field.value }} - - - {{ field.valueText }} - - - - - + + {{ field.title }} + {{ field.value }} + @@ -56,23 +31,16 @@ const props = defineProps({ type: Boolean, default: false }, - detailPopupParam: { - type: Object, - default: () => ({ - taskDetailId: '' - }) + detailId: { + type: String, + default: '' } }) const emit = defineEmits(['update:showPopup']) // Data -const curSample = ref({}) -const curParameterKey = ref('') -const fieldGroup = ref([]) +const fields = ref([]) const taskDetail = ref({}) -const optionParameterClassify = ref([]) -const conAssayTaskId = ref('') -const busSubCSampleId = ref('') // Methods const getAllIndexes = arr => { @@ -84,25 +52,12 @@ const close = () => { } const getSampleData = () => { - const taskDetailId = props.detailPopupParam.taskDetailId - nx.$api.assayTask.queryFieldsByTaskDetail({ taskDetailId }).then(res => { - fieldGroup.value = res.result - - const arr = [{ label: '全部', value: '' }] - for (const g of fieldGroup.value) { - const title = g.title - arr.push({ - label: title, - value: title - }) - } - optionParameterClassify.value = arr // 字段分类 - conAssayTaskId.value = res.additionalProperties.conAssayTaskId - busSubCSampleId.value = res.additionalProperties.busSubCSampleId - taskDetail.value = res.additionalProperties.taskDetail + const businessAssayTaskDataId = props.detailId + nx.$api.assayTask.getSampleAnalysisDataByTaskDataId({ businessAssayTaskDataId }).then(res => { + taskDetail.value = res + fields.value = res.columns }) } - const open = () => { getSampleData() } @@ -112,41 +67,20 @@ const open = () => { .form-item-my { display: flex; align-items: center; + justify-content: space-between; margin-bottom: 10px; + border-bottom: 1px solid #eee; + padding: 4px 0; } .label-my { - width: 180px; /* 标签宽度 */ - display: flex; - align-items: center; -} - -.label-my sub { - font-size: 0.6em; /* 调整下标字体大小 */ - vertical-align: sub; /* 调整下标垂直对齐 */ -} - -.content-my { - flex: 1; - padding-left: 7px; -} - -.content-my-text { - height: 35px; - display: flex; - align-items: center; -} -.content-my-text-value { - color: rgb(48, 49, 51); + color: #606266; } .detail_title { - display: flex; - justify-content: center; /* 水平居中 */ - align-items: center; /* 垂直居中 */ + text-align: center; font-size: 18px; font-weight: 400; - padding-top: 30px; - padding-bottom: 10px; + padding: 10px; background-color: $uni-color-primary; color: #fff; } diff --git a/nx/api/assayTask.js b/nx/api/assayTask.js index fc878cb..0b8b99b 100644 --- a/nx/api/assayTask.js +++ b/nx/api/assayTask.js @@ -5,11 +5,9 @@ const taskPrefix = '/qms/bus/qmsBusAssayTask' // 获取任务 const getAssayTaskList = params => { return request({ - url: '/qms/business-assay-task/page', + url: '/qms/business-assay-task/list', method: 'GET', params: { - pageSize: 999, - pageNo: 1, ...params } }) @@ -107,16 +105,11 @@ const execSendSample = data => { } // 获取任务明细字段 -const queryFieldsByTaskDetail = params => { +const getSampleAnalysisDataByTaskDataId = params => { return request({ - url: '/qms/config/qmsConAssayTaskDetailField/queryFieldsByTaskDetail', + url: '/qms/bus/sample/analysis/getSampleAnalysisDataByTaskDataId', method: 'GET', - params: { - ...params - }, - custom: { - isTransformResponse: true - } + params }) } @@ -125,9 +118,7 @@ const queryHeadFieldsByTaskNo = params => { return request({ url: '/qms/config/qmsConAssayTaskHead/queryHeadFieldsByTaskNo', method: 'GET', - params: { - ...params - } + params }) } @@ -136,9 +127,7 @@ const queryHeadValueByTaskNo = params => { return request({ url: '/qms/bus/qmsBusAssayTaskHead/queryHeadValueByTaskNo', method: 'GET', - params: { - ...params - }, + params, custom: { showError: false, isTransformResponse: true @@ -280,7 +269,7 @@ export default { getDynamicBaseFormSchema, getAssayTaskDetailListByTaskNo, getAssayTaskDetailById, - queryFieldsByTaskDetail, + getSampleAnalysisDataByTaskDataId, queryHeadFieldsByTaskNo, queryHeadValueByTaskNo, saveHeadValue, diff --git a/nx/helper/calcAnalysisValue.js b/nx/helper/calcAnalysisValue.js index 6dc70c6..99af0c6 100644 --- a/nx/helper/calcAnalysisValue.js +++ b/nx/helper/calcAnalysisValue.js @@ -46,6 +46,7 @@ export function calcAnalysisValue(group) { if (formulaVal.startsWith('Get')) { //计算公式为Get开头的,都是执行方法 v = eval(formulaVal) + } else if (formulaVal.startsWith('From')) { } else { v = math.evaluate(formulaVal).toString() v = isFinite(v) ? v.toString() : '' @@ -85,6 +86,7 @@ export function calcRowAnalysisValue(row, columnObj, dynamicsColumns) { if (formulaVal.startsWith('Get')) { formulaVal = formulaVal.replace(')', ",'" + row.conBaseSampleId + "')") v = eval(formulaVal) + } else if (formulaVal.startsWith('From')) { } else { v = math.evaluate(formulaVal).toString() v = isFinite(v) ? v : 0 @@ -326,3 +328,27 @@ function accAdd(arg1, arg2) { } 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()) +} diff --git a/nx/request/index.js b/nx/request/index.js index 4a6af67..b79f014 100644 --- a/nx/request/index.js +++ b/nx/request/index.js @@ -149,6 +149,7 @@ http.interceptors.response.use( } const { code, data, msg } = response.data + // 统一处理【公司/部门二次选择】:参考 PC 端逻辑,自动补全或提示选择后重试 if (code === 400 && Array.isArray(data)) { debugger @@ -209,17 +210,19 @@ http.interceptors.response.use( } } - if ((code === 0 || code === 200) && response.config.custom.showSuccess) { - setTimeout(() => { - uni.showToast({ - title: msg || response.config.custom.successMsg, - icon: 'none' - }) - }, 100) + if (code === 0 || code === 200) { + if (response.config.custom.showSuccess) { + setTimeout(() => { + uni.showToast({ + title: msg || response.config.custom.successMsg, + icon: 'none' + }) + }, 100) + } + $store('user').updateLastRequestTime() + return Promise.resolve(data) } - - $store('user').updateLastRequestTime() - return Promise.resolve(data) + return Promise.reject(response.data) }, error => { console.log('error', error) diff --git a/nx/utils/tools.js b/nx/utils/tools.js index 652a633..3be5f55 100644 --- a/nx/utils/tools.js +++ b/nx/utils/tools.js @@ -1,7 +1,8 @@ export default { - isNullOrEmpty: function (value) { - //是否为空 - return value === null || value === '' || value === undefined ? true : false + isEmpty: function (value) { + if (value === undefined || value === null) return true + if (typeof value === 'string' && value.trim() === '') return true + return false }, 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() { let sysInfo = uni.getSystemInfoSync() let brand = sysInfo.brand.toLowerCase() diff --git a/pages/analysis/index/index.vue b/pages/analysis/index/index.vue index 536ed7e..b089d1b 100644 --- a/pages/analysis/index/index.vue +++ b/pages/analysis/index/index.vue @@ -28,9 +28,9 @@ const isAllowAgainPrint = ref(false) const menuItemList = ref([ // { url: '/pages/analysis/sample/sample-receive', otherConf: { icon: 'arrow-downward' }, name: '收样' }, { url: '/pages/analysis/sample/sample-work-list', otherConf: { icon: 'edit-pen-fill' }, name: '样品分析' }, - { url: '/pages/analysis/sample/sample-report', otherConf: { icon: 'arrow-upward' }, name: '数据上报' }, + // { url: '/pages/analysis/sample/sample-report', otherConf: { icon: 'arrow-upward' }, name: '数据上报' }, { url: '/pages/analysis/sample/sample-report-search', otherConf: { icon: 'search' }, name: '待审数据' }, - { url: '/pages/analysis/sample/sample-print', otherConf: { icon: 'file-text-fill' }, name: '单据补打' }, + // { url: '/pages/analysis/sample/sample-print', otherConf: { icon: 'file-text-fill' }, name: '单据补打' }, { url: '/pages/analysis/setting/setting', otherConf: { icon: 'setting-fill' }, name: '系统设置' } ]) diff --git a/pages/analysis/sample/pdf-preview.vue b/pages/analysis/sample/pdf-preview.vue index 158447c..d496e1b 100644 --- a/pages/analysis/sample/pdf-preview.vue +++ b/pages/analysis/sample/pdf-preview.vue @@ -15,7 +15,7 @@ import { getBaseUrl } from '@/defaultBaseUrl' import nx from '@/nx' // 响应式数据 -const taskId = ref('') +const businessAssayTaskId = ref('') const localFilePath = ref('') const reportKey = ref('') const hideResultFlag = ref('') @@ -87,10 +87,10 @@ const loadPdfOnAndroid = async pdfUrl => { const getPdf = async () => { const printBaseUrl = 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}` 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 += `&type=PDF` url += `&reportKey=${reportKey.value}` @@ -123,8 +123,8 @@ const deleteTmpFile = () => { // 生命周期 onLoad(param => { - if (param.taskId) { - taskId.value = param.taskId + if (param.businessAssayTaskId) { + businessAssayTaskId.value = param.businessAssayTaskId reportKey.value = param.reportKey hideResultFlag.value = param.hideResultFlag } diff --git a/pages/analysis/sample/sample-report-search.vue b/pages/analysis/sample/sample-report-search.vue index f51129c..0ec8c3a 100644 --- a/pages/analysis/sample/sample-report-search.vue +++ b/pages/analysis/sample/sample-report-search.vue @@ -40,25 +40,22 @@ > - 【{{ sample.sort }}】 + 【{{ index + 1 }}】 - {{ sample.sampleCode }} + {{ sample.sampleAssayCode }} {{ getDataSourceTypeShow(sample.dataSourceType) }}{{ sample.sampleName }} - - {{ sample.sampleWeight }} g - - {{ sample.remarks }} + {{ sample.assayProject }} @@ -70,7 +67,7 @@ - + 任务单预览 @@ -84,7 +81,7 @@ @@ -102,14 +99,12 @@ const scrollTop = ref(0) const current = ref(0) const currentTask = ref({}) const currentTaskId = ref('') -const currentTaskNo = ref('') -const conAssayTask = ref('') const reviewNum = ref(0) const selectedIndex = ref(-1) const taskList = ref([]) const sampleList = ref([]) const showDetailPopup = ref(false) -const detailPopupParam = ref({ taskDetailId: '' }) +const detailId = ref('') // 计算属性 const userInfo = computed(() => nx.$store('user').userInfo) @@ -135,66 +130,51 @@ const switchTask = async index => { selectedIndex.value = -1 const task = taskList.value[index] currentTask.value = task - currentTaskNo.value = task.taskNo - currentTaskId.value = task.id - getAssayTaskDetail(task.taskNo) + getAssayTaskDetail(task.id) } -const showSampleDetail = (detailId, index) => { +const showSampleDetail = (id, index) => { selectedIndex.value = index - console.log('detailId', detailId) - detailPopupParam.value = { taskDetailId: detailId } + detailId.value = id showDetailPopup.value = true } const getAssayTask = () => { taskList.value = [] sampleList.value = [] + current.value = 0 const param = { - finishStatus: 'finished', - wfStatus: 'running', + taskAssignStatus: 'submitted', + taskAssayStatus: 'submitted', + finishStatus: 'not_start', + flowStatus: 'not_start', assayOper: userInfo.value.realname } nx.$api.assayTask.getAssayTaskList(param).then(res => { taskList.value = res if (taskList.value.length > 0) { - current.value = 0 currentTask.value = taskList.value[0] - currentTaskNo.value = taskList.value[0].taskNo - currentTaskId.value = taskList.value[0].id - getAssayTaskDetail(currentTaskNo.value) - } else { - current.value = 0 - currentTask.value = {} - currentTaskNo.value = '' - currentTaskId.value = '' + getAssayTaskDetail(currentTask.value.id) } }) } -const getAssayTaskDetail = taskNo => { +const getAssayTaskDetail = businessAssayTaskId => { reviewNum.value = 0 - nx.$api.assayTaskTemplateKey - .getAssayTaskDetailListByTaskNo({ taskNo }) - .then(res => { - sampleList.value = res.result || [] - if (res.additionalProperties?.conAssayTask) { - conAssayTask.value = res.additionalProperties.conAssayTask - } - }) - .catch(err => { - console.error(err) - }) + nx.$api.assayTask.getAssayTaskDataList({ businessAssayTaskId }).then(res => { + sampleList.value = res || [] + }) } 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 }) } // 生命周期 onMounted(() => { - // getAssayTask() + getAssayTask() }) onBackPress(() => { diff --git a/pages/analysis/sample/sample-work-detail.vue b/pages/analysis/sample/sample-work-detail.vue index b7d80a4..2ee935a 100644 --- a/pages/analysis/sample/sample-work-detail.vue +++ b/pages/analysis/sample/sample-work-detail.vue @@ -34,10 +34,10 @@ @@ -123,37 +123,38 @@ :style="{ height: fields.open ? collaHeights[groupIndex] + 'px' : '0' }" > --> - - + @@ -202,13 +206,20 @@ 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 } from '@/nx/helper/calcAnalysisValue' +import { + calcAnalysisValue, + handleRoundFiveNumber, + calcRowAnalysisValue, + math, + groupByField +} 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() @@ -238,11 +249,9 @@ let selectedField = ref({}) const groupFieldIndex = ref('') //分组的索引 const curSample = ref({}) const curParameterTitle = ref('选择字段分类') -const curParameterKey = ref('') -const curParameterClassify = ref('') +const curParameterKey = ref('all') const conAssayTaskId = ref('') const busSubCSampleId = ref('') -const optionParameterClassify = ref([]) let fieldGroup = ref([]) const collaHeights = ref([]) const cupNumKey = '杯号' @@ -262,17 +271,6 @@ const confirmWeightDisabled = computed(() => { } 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) @@ -304,24 +302,17 @@ const navRightClick = () => { }) } -const parameterClassifyChange = (v, a) => { - const groupIndex = ref(0) +const parameterClassifyChange = v => { curParameterKey.value = v - optionParameterClassify.value.forEach((item, index) => { - if (item.value === v) { - groupIndex.value = index - curParameterTitle.value = item.label - } - }) - if (v === '') groupIndex.value = 0 - if (groupIndex.value > 0) groupIndex.value-- - //自动选中字段 - groupFieldIndex.value = groupIndex.value + '-' + curParameterTitle.value = currentGroup.value[0].label + groupFieldIndex.value = '' + selectedField.value = {} + collapseRef.value.init() autoNextField() } const fieldClick = (field, key) => { - if (field.fillingWay == 'input' || !field.fillingWay || field.fillingWay == 'calculate') return + if (!field.isEdit || field.fillingWay === 'input') return selectedField.value = field groupFieldIndex.value = key if (myKeyboard.value) { @@ -331,7 +322,7 @@ const fieldClick = (field, key) => { let decimalPosition = field.decimalPosition if (decimalPosition == null || decimalPosition < -1) decimalPosition = -1 numKeyboardParam.decimal = decimalPosition - if (field.fillingWay == 'keyboard') { + if (field.fillingWay == 'collect') { listenDeviceData() } else { closeDeviceListener() @@ -346,7 +337,7 @@ const autoNextField = () => { const indexV = groupFieldIndex.value.split('-') groupIndex = number(indexV[0]) fieldIndex = indexV[1] === '' ? -1 : number(indexV[1]) - const group = fieldGroup.value[groupIndex] + const group = currentGroup.value[groupIndex] const fields = group.fields if (fields.length > fieldIndex + 1) { //切换到下一个字段 @@ -366,6 +357,15 @@ const autoNextSample = () => { //手动切换样品 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 @@ -378,10 +378,6 @@ const switchSample = async (index, autoFlag) => { } // 将菜单菜单活动item垂直居中 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: '加载中...' }) setValueToField() autoGenerateCupNum() @@ -422,7 +418,6 @@ const getDetailFieldsAndStatus = autoSelectNextField => { const taskDetailId = currentSampleData.value.id //读取回收率配置 loadConRecoveryList() - optionParameterClassify.value = arr //字段分类 conAssayTaskId.value = res.additionalProperties.conAssayTaskId busSubCSampleId.value = res.additionalProperties.busSubCSampleId const detail = res.additionalProperties.taskDetail @@ -623,6 +618,7 @@ const saveAuncelData = () => { //自动跳转下一个字段 setTimeout(() => { autoNextField() + weightDataIsToZero.value = false }, 100) } const dynamicFormData = {} @@ -662,7 +658,7 @@ const saveDetail = async () => { })) } else { 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) @@ -836,16 +832,30 @@ let conRangeElementAnalysisList = [] 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 = [{ open: true, fields: currentAssayType.value.columns, title: '样品分析' }] + fieldGroup.value = groupByField(currentAssayType.value.columns) setValueToField() // getDomHeight() 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 activeCollapses = ref([]) function handleAssayTypeChange({ index, value }) { @@ -853,6 +863,9 @@ function handleAssayTypeChange({ index, value }) { activeAssayTypeIndex.value = index currentSampleIndex.value = 0 groupFieldIndex.value = '' + selectedField.value = {} + curParameterKey.value = 'all' + curParameterTitle.value = '选择字段分类' collapseRef.value.init() } // 获取任务指派单数据 @@ -864,7 +877,7 @@ async function getSampleAnalysisByTaskId() { assayGroups.value = assayTaskAnalysisDataList.map(group => { // 必须深拷贝 datas!防止多个表格共享引用 const tableData = JSON.parse(JSON.stringify(group.datas || [])) - const columns = group.columns || [] + const columns = group.columns.filter(item => item.paramNo) || [] return { value: group.analysisType, @@ -1112,7 +1125,6 @@ onLoad(param => { lockOrientation('landscape') if (param.currentTaskId) { taskId.value = param.currentTaskId - // getAssayTaskSampleList(taskId.value) getSampleAnalysisByTaskId() } loadFieldApiData(fieldGroup.value) diff --git a/pages/analysis/sample/sample-work-edit-task.vue b/pages/analysis/sample/sample-work-edit-task.vue index c3f37b8..71888ad 100644 --- a/pages/analysis/sample/sample-work-edit-task.vue +++ b/pages/analysis/sample/sample-work-edit-task.vue @@ -6,111 +6,104 @@ - {{ field.label }} - - - {{ field.value }} - - - - - - - - {{ field.value }} - 请选择 - - - - - - {{ nx.$dayjs(field.value).format('YYYY-MM-DD HH:mm:ss') }} - 请选择 - - + - 保存 + 保存 +