feat:样品分析

This commit is contained in:
houjunxiang
2025-10-14 18:16:51 +08:00
parent b5aed8573a
commit 5916b8c833
14 changed files with 574 additions and 671 deletions

View File

@@ -1,7 +1,7 @@
<template>
<view class="y-f" style="height: 55vh">
<view class="weight">
<view class="weight-data"> {{ nums }}</view>
<view class="weight-data">{{ nums }}</view>
</view>
<view class="keyboard-container">
@@ -21,114 +21,90 @@
<view @click="jianshao()" class="oner flex1">
<u-icon name="arrow-leftward" bold></u-icon>
</view>
<view @click="setNull()" class="oner flex1 mt10 mb10"> 清空 </view>
<view class="oner confirm" @click="ok()"> 确认 </view>
<view @click="setNull()" class="oner flex1 mt10 mb10">清空</view>
<view class="oner confirm" @click="ok()">确认</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'zzjc-num-keyboard',
props: {
numKeyboardParam: {
type: Object,
default: null
} //小数位数,-1为不限制
},
data() {
return {
nums: '',
numbers: [
{
text: '1'
},
{
text: '2'
},
{
text: '3'
},
{
text: '4'
},
{
text: '5'
},
{
text: '6'
},
{
text: '7'
},
{
text: '8'
},
{
text: '9'
},
{
text: '0',
class: 'zero'
},
{
text: '.'
}
]
}
},
created() {},
methods: {
//确认
ok() {
const val = {
val: this.nums
}
this.nums = ''
uni.$emit('keyboardOK', val)
},
/*
* 清空
* 数字类型改为0其他类型改为空
* */
setNull() {
this.nums = ''
uni.$emit('keyboardOK', null)
},
clearNum() {
this.nums = ''
},
jianshao() {
if (this.nums) {
this.nums = this.nums.substring(0, this.nums.length - 1)
}
},
changeNums(item, index) {
this.sumindex = index
if (item.text == '.') {
if (this.nums.indexOf('.') != -1 || this.nums.length == 0) {
return false
}
}
//检查小数位数
let decimal = this.numKeyboardParam.decimal
if (decimal == null) decimal = -1
if (this.nums.split('.') && this.nums.split('.')[1] && decimal != -1) {
if (this.nums.split('.')[1].length >= decimal) {
return false
}
}
this.nums = this.nums + item.text
},
<script setup>
import { ref, computed } from 'vue'
getListItemStyle(index) {
return {
background: this.numbers[index].background
}
}
// Props
const props = defineProps({
numKeyboardParam: {
type: Object,
default: () => null
}
})
// Emits虽然你用的是 uni.$emit但也可以定义 emit 用于规范)
// const emit = defineEmits(['keyboardOK'])
// Data
const nums = ref('')
const numbers = ref([
{ text: '1' },
{ text: '2' },
{ text: '3' },
{ text: '4' },
{ text: '5' },
{ text: '6' },
{ text: '7' },
{ text: '8' },
{ text: '9' },
{ text: '0', class: 'zero' },
{ text: '.' }
])
// Methods
const ok = () => {
const val = { val: nums.value }
nums.value = ''
if (val.val) {
uni.$emit('keyboardOK', val)
}
}
const setNull = () => {
nums.value = ''
uni.$emit('keyboardOK', null)
}
const clearNum = () => {
nums.value = ''
}
const jianshao = () => {
if (nums.value) {
nums.value = nums.value.substring(0, nums.value.length - 1)
}
}
const changeNums = (item, index) => {
if (item.text === '.') {
if (nums.value.indexOf('.') !== -1 || nums.value.length === 0) {
return false
}
}
// 检查小数位数限制
let decimal = props.numKeyboardParam?.decimal ?? -1
const parts = nums.value.split('.')
if (parts.length === 2 && decimal !== -1) {
if (parts[1].length >= decimal) {
return false
}
}
nums.value += item.text
}
const getListItemStyle = index => {
return {
background: numbers.value[index]?.background || ''
}
}
defineExpose({ clearNum })
</script>
<style lang="scss" scoped>
@@ -142,7 +118,7 @@ export default {
}
.keypad {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 默认 3 列 */
grid-template-columns: repeat(3, 1fr);
gap: 10px;
padding: 10px;
flex: 4;
@@ -161,7 +137,6 @@ export default {
box-sizing: border-box;
}
/* 0 占两列 */
.zero {
width: 98%;
grid-column: span 2;

View File

@@ -1,6 +1,43 @@
import request from '@/nx/request'
const taskDetailPrefix = '/qms/bus/qmsBusAssayTaskDetail'
const taskPrefix = '/qms/bus/qmsBusAssayTask'
// 获取任务
const getAssayTaskList = params => {
return request({
url: '/qms/business-assay-task/page',
method: 'GET',
params: {
pageSize: 999,
pageNo: 1,
...params
}
})
}
// 获取样品列表
const getAssayTaskDataList = params => {
return request({
url: `/qms/business-assay-task-data/list`,
params,
method: 'GET'
})
}
// 获取样品分析配置数据
const getSampleAnalysisByTaskId = businessAssayTaskId => {
return request({
url: '/qms/bus/sample/analysis/batchSampleAnalysisByTaskId',
method: 'GET',
params: { businessAssayTaskId }
})
}
// 获取指派单动态配置项
const getDynamicBaseFormSchema = params => {
return request({
url: '/qms/common/data/data-collection-field/queryEffectiveFields',
method: 'GET',
params
})
}
// 获取任务明细
const getAssayTaskDetailListByTaskNo = params => {
return request({
@@ -114,11 +151,11 @@ const saveHeadValue = params => {
}
// 保存任务明细
const saveDetailValue = params => {
const saveDetailValue = data => {
return request({
url: '/qms/bus/qmsBusAssayTask/saveTaskDetail',
url: '/qms/bus/sample/analysis/saveBatchSampleAnalysis',
method: 'POST',
data: params,
data,
custom: {
showSuccess: true
}
@@ -138,11 +175,9 @@ const submitTaskDetail = params => {
const submitTask = params => {
return request({
url: '/qms/bus/qmsBusAssayTask/submitTaskByTaskNo',
url: '/qms/bus/sample/analysis/submitSampleAnalysisByTaskId',
method: 'POST',
params: {
...params
},
params,
custom: {
showSuccess: true
}
@@ -218,6 +253,10 @@ const queryQmsDicSampleProcessCodeList = () => {
}
export default {
getAssayTaskList,
getAssayTaskDataList,
getSampleAnalysisByTaskId,
getDynamicBaseFormSchema,
getAssayTaskDetailListByTaskNo,
getAssayTaskDetailById,
queryFieldsByTaskDetail,

View File

@@ -1,13 +1,5 @@
import request from '@/nx/request'
const taskPrefix = '/qms/bus/qmsBusAssayTask'
// 获取任务
const getAssayTaskList = params => {
return request({
url: taskPrefix + '/listTaskForPAD',
method: 'GET',
params
})
}
export const getConAssayTaskWithReportTemplateContent = id => {
return request({
@@ -27,7 +19,6 @@ export const queryTaskDetailListByAssayTaskId = params => {
}
export default {
getAssayTaskList,
getConAssayTaskWithReportTemplateContent,
queryTaskDetailListByAssayTaskId
}

View File

@@ -713,6 +713,24 @@ const uuid = () => {
return uuid
}
// 自定义 replacer将函数转换为字符串。json序列化和反序列化时避免函数丢失
function replacer(key, value) {
if (typeof value === 'function') {
return value.toString()
}
return value
}
// 自定义 reviver将字符串转换回函数.json序列化和反序列化时避免函数丢失
const functionKeys = ['change', 'dicFormatter']
function reviver(key, value) {
if (functionKeys.includes(key)) {
// 将字符串转换为函数
return new Function('return ' + value)()
}
return value
}
export default {
range,
getPx,
@@ -745,5 +763,7 @@ export default {
getRootUrl,
copyText,
showToast,
uuid
uuid,
replacer,
reviver
}

View File

@@ -87,32 +87,43 @@ http.interceptors.request.use(
const token = getAccessToken()
if (token) config.header['Authorization'] = token
if (token) config.header['Authorization'] = 'Bearer ' + token
config.header['Accept'] = '*/*'
config.header['tenant-id'] = getTenantId()
const method = config.method?.toUpperCase()
// 防止 GET 请求缓存
if (method === 'GET') {
config.header['Cache-Control'] = 'no-cache'
config.header['Pragma'] = 'no-cache'
}
let params = config.params || {}
let data = config.data || false
if (process.env.NODE_ENV == 'development') console.log('development--params', params)
if (process.env.NODE_ENV == 'development') console.log('development--data', data)
// if (process.env.NODE_ENV == 'development') console.log('development--params', params)
// if (process.env.NODE_ENV == 'development') console.log('development--data', data)
const visitCompanyId = getVisitCompanyId()
// const visitCompanyId = getVisitCompanyId()
const visitCompanyId = '101'
if (visitCompanyId !== undefined && visitCompanyId !== null && visitCompanyId !== '') {
config.header['visit-company-id'] = visitCompanyId
const visitCompanyName = getVisitCompanyName()
// const visitCompanyName = getVisitCompanyName()
const visitCompanyName = '"深圳总公司'
if (visitCompanyName !== undefined && visitCompanyName !== null) {
config.header['visit-company-name'] = encodeURIComponent(visitCompanyName || '')
}
}
const visitDeptId = getVisitDeptId()
// const visitDeptId = getVisitDeptId()
const visitDeptId = '103'
if (visitDeptId !== undefined && visitDeptId !== null && visitDeptId !== '') {
config.header['visit-dept-id'] = visitDeptId
const visitDeptName = getVisitDeptName()
// const visitDeptName = getVisitDeptName()
const visitDeptName = '研发部门'
if (visitDeptName !== undefined && visitDeptName !== null) {
config.header['visit-dept-name'] = encodeURIComponent(visitDeptName || '')
}
}
config.header['__companyDeptRetried'] = '1'
return config
},
error => {
@@ -133,7 +144,6 @@ http.interceptors.response.use(
const userStore = $store('user')
response.config.custom.showLoading && closeLoading()
console.log('response', JSON.parse(JSON.stringify(response.data)))
if (!response.config.custom.isTransformResponse) {
return Promise.resolve(response.data)
}

View File

@@ -26,7 +26,7 @@ const popupShow = ref(false)
const isAllowAgainPrint = ref(false)
const menuItemList = ref([
{ url: '/pages/analysis/sample/sample-receive', otherConf: { icon: 'arrow-downward' }, name: '收样' },
// { url: '/pages/analysis/sample/sample-receive', otherConf: { icon: 'arrow-downward' }, name: '收样' },
{ url: '/pages/analysis/sample/sample-work-list', otherConf: { icon: 'edit-pen-fill' }, name: '样品分析' },
{ url: '/pages/analysis/sample/sample-report', otherConf: { icon: 'arrow-upward' }, name: '数据上报' },
{ url: '/pages/analysis/sample/sample-report-search', otherConf: { icon: 'search' }, name: '待审数据' },

View File

@@ -11,7 +11,7 @@
<view class="mt3 mb3">{{ task.taskName }}{{ task.assayOper }}</view>
<view class="x-f">
<u-icon name="clock"></u-icon>
<text class="ml5">{{ task.taskOperTime }}</text>
<text class="ml5">{{ taskOperatorTime }}</text>
</view>
</u-col>
</u-row>
@@ -19,7 +19,7 @@
</template>
<script setup>
import { computed } from 'vue'
import nx from '@/nx'
const props = defineProps({
task: {
@@ -36,6 +36,7 @@ const props = defineProps({
}
})
const taskOperatorTime = nx.$dayjs(props.task.taskOperatorTime).format('YYYY-MM-DD HH:mm:ss')
const emit = defineEmits(['click'])
const handleClick = () => {

View File

@@ -189,7 +189,7 @@ function getAssayTask() {
finishStatus: 'submited,finished'
}
nx.$api.auncel.getAssayTaskList(param).then(res => {
nx.$api.assayTask.getAssayTaskList(param).then(res => {
taskList.value = res || []
if (taskList.value.length > 0) {
const first = taskList.value[0]

View File

@@ -98,20 +98,8 @@ import { getDataSourceTypeShow } from '../common'
const currentNode = ref('F30')
const scrollTop = ref(0)
const current = ref(0)
const taskList = ref([
{ id: 1, taskNo: 'TASK-1', taskName: '任务1', taskOperTime: '2022-03-01 10:00:00' },
{ id: 1, taskNo: 'TASK-1', taskName: '任务1', taskOperTime: '2022-03-01 10:00:00' },
{ id: 1, taskNo: 'TASK-1', taskName: '任务1', taskOperTime: '2022-03-01 10:00:00' },
{ id: 1, taskNo: 'TASK-1', taskName: '任务1', taskOperTime: '2022-03-01 10:00:00' },
{ id: 1, taskNo: 'TASK-1', taskName: '任务1', taskOperTime: '2022-03-01 10:00:00' },
{ id: 1, taskNo: 'TASK-1', taskName: '任务1', taskOperTime: '2022-03-01 10:00:00' },
{ id: 1, taskNo: 'TASK-1', taskName: '任务1', taskOperTime: '2022-03-01 10:00:00' },
{ id: 1, taskNo: 'TASK-1', taskName: '任务1', taskOperTime: '2022-03-01 10:00:00' },
{ id: 1, taskNo: 'TASK-1', taskName: '任务1', taskOperTime: '2022-03-01 10:00:00' }
])
const sampleList = ref([
{ id: 1, sampleCode: 'SAMPLE-1', sampleName: '样品1', sort: 1, checked: false, sampleProcessNo: 'F30' }
])
const taskList = ref([])
const sampleList = ref([])
const dicSampleProcessCodeList = ref([])
// 计算属性
@@ -188,7 +176,7 @@ const getAssayTask = () => {
assayOper: userInfo.value.nickname
}
nx.$api.auncel
nx.$api.assayTask
.getAssayTaskList(param)
.then(res => {
taskList.value = res || []

View File

@@ -155,7 +155,7 @@ const getAssayTask = () => {
wfStatus: 'running',
assayOper: userInfo.value.realname
}
nx.$api.auncel.getAssayTaskList(param).then(res => {
nx.$api.assayTask.getAssayTaskList(param).then(res => {
taskList.value = res
if (taskList.value.length > 0) {
current.value = 0

View File

@@ -19,6 +19,7 @@
v-for="(task, index) in taskList"
:key="index"
:task="task"
:seq="index + 1"
:active="current === index"
@click="switchTask(index)"
/>
@@ -167,7 +168,7 @@ const getAssayTask = () => {
wfStatus: '0,revoke',
assayOper: userInfo.value.nickname
}
nx.$api.auncel
nx.$api.assayTask
.getAssayTaskList(param)
.then(res => {
taskList.value = res

View File

@@ -34,7 +34,7 @@
<u-dropdown-item
v-model="curParameterClassify"
:title="curParameterTitle"
height="340px"
height="70vh"
:options="optionParameterClassify"
@change="parameterClassifyChange"
></u-dropdown-item>
@@ -44,12 +44,12 @@
v-for="(sample, index) in leftList"
:key="index"
class="u-tab-item"
:class="[current.value === index ? 'u-tab-item-active' : '']"
:class="currentSampleIndex === index ? 'u-tab-item-active' : ''"
:data-current="index"
@tap.stop="switchSample(index, false)"
>
<view class="pr5"> {{ sample.sort }} </view>
<view>
<u-badge type="warning" :value="index + 1"></u-badge>
<view class="ml20">
<view>
{{ sample.sampleCode }}
</view>
@@ -60,19 +60,19 @@
<u-button class="btn-operation" type="primary" @click="submitTask()">提交指派单</u-button>
</u-col>
<u-col span="6">
<view class="field-name" v-html="selectedField.value.name" />
<view class="field-name" v-html="selectedField.title" />
<zzjc-num-keyboard
ref="myKeyboard"
v-show="selectedField.value.fillingWay === '1' && selectedField.value.type !== 'select'"
v-show="selectedField.fillingWay == '1' && selectedField.type != 'select'"
:numKeyboardParam="numKeyboardParam"
></zzjc-num-keyboard>
<view v-if="selectedField.value.fillingWay === '2'" class="y-f">
<view v-if="selectedField.fillingWay == '2'" class="y-f">
<view class="auncel" @click="selectAuncel">
<view class="auncel-title"> {{ currentAuncel.code }}</view>
<view class="auncel-weight">
<view class="weight">
<view
:style="{ textAlign: currentAuncel.isConnected != 1 ? 'center' : 'right' }"
:style="{ textAlign: !currentAuncel.isConnected ? 'center' : 'right' }"
:class="
currentAuncel.weightStable === 0
? 'weight-data-yellow'
@@ -90,7 +90,6 @@
<u-button
class="btn-operation"
v-if="currentAuncel.code !== ''"
type="success"
:disabled="confirmWeightDisabled"
shape="circle"
@@ -106,7 +105,7 @@
<view>
<u-form :model="curSample" ref="uForm" label-width="140">
<template v-for="(fields, groupIndex) in fieldGroup" :key="'group_' + groupIndex">
<view v-if="curParameterKey.value === '' || curParameterKey.value === fields.title">
<view>
<!-- 组名 -->
<view class="my-collapse" @click="fields.open = !fields.open">
<text class="title">{{ fields.title }}</text>
@@ -122,35 +121,31 @@
v-for="(field, fieldIndex) in fields.fields"
@click="fieldClick(field, groupIndex + '-' + fieldIndex)"
:key="groupIndex + '-' + fieldIndex"
v-show="field.hidden !== 1 && field.hidden !== '1'"
:class="{ 'selected-field': selectedFieldIndex.value === 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 || field.highlight === '1' }
]"
v-html="
field.name +
(typeof field.unit !== 'undefined' && field.unit !== null && field.unit !== ''
? '(' + field.unit + ')'
: '')
"
:class="['label-my', { 'label-high-light': field.highlight == 1 }]"
v-html="field.title"
></view>
<view class="content-my">
<!--
如果是select渲染2个组件1个input1个picker.
field.valueText用于显示picker选中的文本
1键盘输入2天平3自动计算4文本输入
-->
<u-input
border="bottom"
style="width: 120px"
v-if="field.fillingWay === 4"
v-if="field.fillingWay == 4"
v-model="field.value"
:placeholder="field.placeholder"
type="text"
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-else>请选择</text>
<u-icon name="arrow-down" size="20"></u-icon>
@@ -162,18 +157,15 @@
keyName="dictValue"
@cancel="field.showPicker = false"
@confirm="event => dicPickerConfirm(event, field)"
/>
/> -->
<!--普通输入框 使用文本显示-->
<view class="content-my-text" v-if="field.type !== 'select' && field.fillingWay !== 4">
<text v-if="!field.value || field.value === ''" class="content-my-text-placeholder">{{
field.placeholder
<view class="content-my-text" v-if="field.dataType != 'select' && field.fillingWay != 4">
<text v-if="!field.value" class="content-my-text-placeholder">{{
!field.fillingWay || field.fillingWay == 3 ? '计算值' : '请输入'
}}</text>
<text
v-else
:class="[
'content-my-text-value',
{ 'field-high-light': field.highlight === 1 || field.highlight === '1' }
]"
:class="['content-my-text-value', { 'field-high-light': field.highlight == 1 }]"
>{{ field.value }}</text
>
</view>
@@ -200,7 +192,7 @@
</template>
<script setup>
import { ref, reactive, computed, nextTick, onMounted } from 'vue'
import { ref, reactive, computed, nextTick, getCurrentInstance } from 'vue'
import { onLoad, onBackPress, onShow, onHide, onUnload } from '@dcloudio/uni-app'
import request from '@/nx/request'
import { calcAnalysisValue } from '@/nx/helper/calcAnalysisValue'
@@ -209,26 +201,26 @@ import AuncelSelectPopup from '@/components/sample/auncel-select-popup.vue'
import { getTenantId } from '@/defaultBaseUrl'
import { useScreenOrientation } from '@/nx/hooks/useScreenOrientation'
import nx from '@/nx'
import text from '@/uview-plus/components/u-text/text'
import { getDataSourceTypeShow } from '../common'
const { proxy } = getCurrentInstance()
// 响应式数据定义
const taskId = ref('')
const elId = nx.$helper.uuid()
const scrollTop = ref(0) //tab标题的滚动条位置
const current = ref(0) // 预设当前项的值
const menuHeight = ref(0) // 左边菜单的高度
const menuItemHeight = ref(0) // 左边菜单item的高度
const orderGenBH = ref(true) //顺序生成杯号
const weightDataIsToZero = ref(false) //重量数据是否归零
const currentSample = ref({}) //当前样品
const currentTaskNo = ref('') //当前任务指派单号
const currentTaskId = ref('') //当前任务指派单id
const currentTaskType = ref('') //当前任务类型
const currentSampleIndex = ref(0) // 预设当前项的值
let sampleDataList = []
const title = ref('')
const numKeyboardParam = reactive({
decimal: '-1' //数字键盘小数位数,-1为不限制
})
const showAuncelSelector = ref(false) //显示天平选择框
const currentAuncel = reactive({
const currentAuncel = ref({
id: '',
name: '',
code: '',
@@ -236,48 +228,60 @@ const currentAuncel = reactive({
weightData: '请选天平',
weightUnit: ''
})
const selectedField = ref({})
const selectedFieldIndex = ref('')
let selectedField = ref({})
const groupFieldIndex = ref('') //分组的索引
const leftList = ref([])
const curSample = ref({})
const showDicPicker = ref(false)
const curParameterTitle = ref('选择字段分类')
const curParameterKey = ref('')
const curParameterClassify = ref('')
const conAssayTaskId = ref('')
const busSubCSampleId = ref('')
const optionParameterClassify = ref([])
const paramFieldApiRet = ref([])
const fieldGroup = ref([])
let fieldGroup = ref([])
const collaHeights = ref([])
const cupNumKey = '杯号'
// refs
const myKeyboard = ref(null)
const auncelSelector = ref(null)
// 计算属性
const confirmWeightDisabled = computed(() => {
if (currentSample.value.sampleCode && currentAuncel.weightStable === 1 && Number(currentAuncel.weightData) > 0) {
if (
currentSample.value.sampleCode &&
currentAuncel.value.weightStable === 1 &&
Number(currentAuncel.value.weightData) > 0
) {
return false
}
return true
})
const checkCupNumReadonly = computed(() => {
if (!currentAuncel.value || currentAuncel.value.id === '') return true
return false
// 当前样品数据索引
const currentSampleDataIndex = computed(() => {
if (sampleDataList.length > 0) {
return sampleDataList.findIndex(item => item.businessAssayTaskDataId === currentSample.value.id)
}
return -1
})
// 当前操作字段索引
const currentFieldKey = computed(() => {
return selectedField.value.fieldIndex
})
const userInfo = computed(() => nx.$store('user').userInfo)
// 方法定义
const getDomHeight = () => {
const getDomHeight = async () => {
await nextTick() // 等待 DOM 更新完成
collaHeights.value = []
nextTick(() => {
if (fieldGroup.value.length) {
fieldGroup.value.forEach((item, index) => {
nx.getRect('#elId' + index).then(res => {
collaHeights.value.push(res.height)
})
if (fieldGroup.value.length) {
fieldGroup.value.forEach((item, index) => {
proxy.$u.getRect('#elId' + index).then(res => {
collaHeights.value.push(res.height)
})
}
})
})
}
}
//返回上一页
@@ -289,7 +293,7 @@ const customBack = () => {
const navRightClick = () => {
let url = '/pages/analysis/sample/sample-work-edit-task'
url += '?currentTaskNo=' + currentTaskNo.value
url += '?currentTaskId=' + taskId.value
uni.navigateTo({
url: url
})
@@ -307,24 +311,20 @@ const parameterClassifyChange = (v, a) => {
if (v === '') groupIndex.value = 0
if (groupIndex.value > 0) groupIndex.value--
//自动选中字段
selectedFieldIndex.value = groupIndex.value + '-'
groupFieldIndex.value = groupIndex.value + '-'
autoNextField()
}
const fieldClick = (field, key) => {
try {
myKeyboard.value.clearNum()
} catch (e) {
console.error(e)
}
if (field.fillingWay === 4) return
myKeyboard.value.clearNum()
if (field.fillingWay == 4 || !field.fillingWay || field.fillingWay == 3) return
selectedField.value = field
selectedFieldIndex.value = key
groupFieldIndex.value = key
//判断小数位数
let dataType = field.dataType
if (dataType == null || dataType < -1) dataType = -1
numKeyboardParam.decimal = dataType
if (field.fillingWay === 2) {
let decimalPosition = field.decimalPosition
if (decimalPosition == null || decimalPosition < -1) decimalPosition = -1
numKeyboardParam.decimal = decimalPosition
if (field.fillingWay == 2) {
listenDeviceData()
} else {
closeDeviceListener()
@@ -333,20 +333,15 @@ const fieldClick = (field, key) => {
//自动切换到下一个字段
const autoNextField = () => {
//selectedFieldIndex是groupIndex-fieldIndex
let groupIndex = 0
let fieldIndex = 0
if (typeof selectedFieldIndex.value === 'undefined' || selectedFieldIndex.value === '')
selectedFieldIndex.value = '0-'
const indexV = selectedFieldIndex.value.split('-')
if (typeof groupFieldIndex.value === 'undefined' || groupFieldIndex.value === '') groupFieldIndex.value = '0-'
const indexV = groupFieldIndex.value.split('-')
groupIndex = number(indexV[0])
fieldIndex = indexV[1] === '' ? -1 : number(indexV[1])
const group = fieldGroup.value[groupIndex]
const fields = group.fields
if (fields.length > fieldIndex + 1) {
//如果下一个字段是计算,不自动切换
const fillingWay = fields[fieldIndex + 1].fillingWay || ''
if (fillingWay === '3') return
//切换到下一个字段
const key = groupIndex + '-' + (fieldIndex + 1)
fieldClick(fields[fieldIndex + 1], key)
@@ -355,11 +350,10 @@ const autoNextField = () => {
//自动切换到下一个样品
const autoNextSample = () => {
//仅在顺序称重时自动切换
// if (!orderWeighChecked.value)
// return;
if (leftList.value.length <= current.value + 1) return
const index = current.value + 1
if (leftList.value.length <= currentSampleIndex.value + 1) return
const index = currentSampleIndex.value + 1
groupFieldIndex.value = ''
selectedField.value = {}
switchSample(index, true)
}
@@ -367,44 +361,53 @@ const autoNextSample = () => {
const switchSample = async (index, autoFlag) => {
//重置天平归0
weightDataIsToZero.value = false
//清空数字键盘数据
myKeyboard.value.clearNum()
if (index === current.value) return
// if (orderWeighChecked.value && !autoFlag) return;//顺序称重不允许选中
current.value = index
if (index === currentSampleIndex.value) return
setValueToSample()
currentSampleIndex.value = index
// 如果为0意味着尚未初始化
if (menuHeight.value === 0 || menuItemHeight.value === 0) {
// await getElRect('menu-scroll-view', 'menuHeight');
await getElRect('u-tab-item', 'menuItemHeight')
const rect = await getElRect('u-tab-item')
menuItemHeight.value = rect.height
}
// 将菜单菜单活动item垂直居中
scrollTop.value = index * menuItemHeight.value + menuItemHeight.value / 2 - menuHeight.value / 2 - 50
//修改当前选中的selectedFieldIndex
if (typeof selectedFieldIndex.value !== 'undefined' && selectedFieldIndex.value.indexOf('-') > 0) {
selectedFieldIndex.value = selectedFieldIndex.value.split('-')[0] + '-'
}
//修改当前选中的groupFieldIndex
// if (typeof groupFieldIndex.value !== 'undefined' && groupFieldIndex.value.indexOf('-') > 0) {
// groupFieldIndex.value = groupFieldIndex.value.split('-')[0] + '-'
// }
uni.showLoading({ title: '加载中...' })
currentSample.value = leftList.value[index]
//读取样品明细字段
getDetailFieldsAndStatus(true)
setValueToField()
autoGenerateCupNum()
setTimeout(() => {
uni.hideLoading()
}, 500)
}
// 获取一个目标元素的高度
const getElRect = (elClass, dataVal) => {
const getElRect = (elClass, maxRetry = 50) => {
return new Promise((resolve, reject) => {
const query = uni.createSelectorQuery().in(this)
query
.select('.' + elClass)
.fields({ size: true }, res => {
// 如果节点尚未生成res值为null循环调用执行
if (!res) {
setTimeout(() => {
getElRect(elClass)
}, 10)
return
}
this[dataVal] = res.height
})
.exec()
let retryCount = 0
const execQuery = () => {
uni
.createSelectorQuery()
.in(proxy)
.select('.' + elClass)
.fields({ size: true, rect: true })
.exec(res => {
const result = res[0] // exec 返回数组,取第一个
if (result) {
resolve(result)
} else if (retryCount < maxRetry) {
retryCount++
setTimeout(execQuery, 10)
} else {
reject(new Error(`无法获取元素 .${elClass} 的尺寸,已重试 ${maxRetry}`))
}
})
}
execQuery()
})
}
@@ -413,55 +416,13 @@ const getDetailFieldsAndStatus = autoSelectNextField => {
const taskDetailId = currentSample.value.id
//读取回收率配置
loadConRecoveryList()
//查询字段
nx.$api.assayTask.queryFieldsByTaskDetail({ taskDetailId: taskDetailId }).then(res => {
fieldGroup.value = []
if (!res.success) {
nx.$helper.showToast({
title: res.message
})
return
}
//处理“填写&计算”字段:如果后台存了值,则不自动计算
const groupList = res.result
for (const g of groupList) {
g.open = true
for (const f of g.fields) {
if (f.fillingWay === '1' && f.value != null && f.value !== '') {
f.valueTypeManual = '1'
}
}
}
fieldGroup.value = groupList
const arr = [
{
label: '全部',
value: ''
}
]
for (const g of fieldGroup.value) {
const title = g.title
const o = {
label: title,
value: title
}
arr.push(o)
}
// 计算样品详情高度
getDomHeight()
optionParameterClassify.value = arr //字段分类
conAssayTaskId.value = res.additionalProperties.conAssayTaskId
busSubCSampleId.value = res.additionalProperties.busSubCSampleId
const detail = res.additionalProperties.taskDetail
//处理硫值、硫量:未保存过的数据,读取接口返回的硫值、硫量
loadSValue(detail)
//自动生成杯号
autoGenerateCupNum()
//自动选择下一个字段
if (autoSelectNextField) autoNextField()
//按公式计算值,并检查原数据与计算后的数据是否一致
calAndCheck()
})
optionParameterClassify.value = arr //字段分类
conAssayTaskId.value = res.additionalProperties.conAssayTaskId
busSubCSampleId.value = res.additionalProperties.busSubCSampleId
const detail = res.additionalProperties.taskDetail
//处理硫值、硫量:未保存过的数据,读取接口返回的硫值、硫量
loadSValue(detail)
calAndCheck()
}
const checkLoadSValue = () => {
@@ -568,7 +529,6 @@ const clearFieldVal = () => {
return
}
selectedField.value.value = ''
selectedField.value.valueTypeManual = '0'
//重新计算
calcAnalysisValue(fieldGroup.value)
}
@@ -593,7 +553,7 @@ const checkBh = () => {
let hasHb = true
for (const g of fieldGroup.value) {
for (const f of g.fields) {
if (f.dicKey && f.dicKey.indexOf('bh_') >= 0) {
if (f.title && f.title.indexOf(cupNumKey) >= 0) {
if (typeof f.value === 'undefined' || f.value === null || f.value === '') hasHb = false
}
}
@@ -608,8 +568,6 @@ const checkBh = () => {
}
const saveAuncelData = () => {
//检查杯号
if (!checkBh()) return
//保存数据
if (!weightDataIsToZero.value) {
nx.$helper.showToast({
@@ -618,10 +576,10 @@ const saveAuncelData = () => {
return
}
//获取当前重量
let weight = currentAuncel.weightData
let weight = currentAuncel.value.weightData
selectedField.value.value = weight
const curFieldDicKey = selectedField.value.dicKey
const curFieldDicKey = selectedField.dicKey
let upDownFlag = ''
if (curFieldDicKey && curFieldDicKey !== '' && curFieldDicKey.indexOf('_') > 0) {
upDownFlag = curFieldDicKey.substring(curFieldDicKey.lastIndexOf('_') + 1)
@@ -640,15 +598,15 @@ const saveAuncelData = () => {
}
const auncelNoField = getFieldByKey(auncelNoFieldKey)
if (auncelNoField !== null) {
auncelNoField.value = currentAuncel.code
auncelNoField.value = currentAuncel.value.code
}
const measureTimeField = getFieldByKey(measureTimeFieldKey)
if (measureTimeField !== null) {
measureTimeField.value = nx.$dayjs.format('yyyy-MM-dd hh:mm:ss')
measureTimeField.value = nx.$dayjs().format('YYYY-MM-DD HH:mm:ss')
}
}
//指派单明细上的称重时间
curSample.value.measureTime = nx.$dayjs.format('yyyy-MM-dd hh:mm:ss')
curSample.value.measureTime = nx.$dayjs().format('YYYY-MM-DD HH:mm:ss')
//计算
try {
calcAnalysisValue(fieldGroup.value)
@@ -662,92 +620,36 @@ const saveAuncelData = () => {
}, 100)
}
const checkSubmit = () => {
//检查必填字段
let fieldNames = ''
for (const g of fieldGroup.value) {
for (const f of g.fields) {
let name = f.shortName
if (name === null || name === '') name = f.name
if (f.allowNull === 1 || f.allowNull === '1') continue
if (f.value === null || f.value === '') {
fieldNames += name + ''
}
}
}
if (fieldNames !== '') {
nx.$helper.showToast({
title: '请填写必填字段:' + fieldNames
})
return false
}
//检查不能为0的字段
fieldNames = ''
for (const g of fieldGroup.value) {
for (const f of g.fields) {
let name = f.shortName
if (name === null || name === '') name = f.name
//检查不可为0的数据
if (f.notZero === 1 || f.notZero === '1') {
if (f.value === null || f.value === '' || number(f.value) === 0) {
fieldNames += name + ''
}
}
}
}
if (fieldNames !== '') {
nx.$helper.showToast({
title: '这几个值不能为0请检查' + fieldNames
})
return false
}
return true
}
const saveDetail = () => {
const saveDetail = async () => {
//检查杯号
if (!checkBh()) return
const valueList = []
let cupNum = 0
let detailId = currentSample.value.id
for (const g of fieldGroup.value) {
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 = {
businessAssayTaskId: taskId.value,
datas: sampleDataList
}
setValueToSample()
await nx.$api.assayTask.saveDetailValue(params)
autoNextSample()
}
// 把字段值保存回样品数据中
function setValueToSample() {
let fields = fieldGroup.value.flatMap(item => item.fields)
fields.forEach(item => {
if (sampleDataList[currentSampleDataIndex.value].hasOwnProperty(item.fieldIndex)) {
sampleDataList[currentSampleDataIndex.value][item.fieldIndex].value = item.value
}
// 初始化的时候保存杯号到样品中后续自动生成杯号用
if (item.title === cupNumKey && currentSampleIndex.value == 0) {
leftList.value[currentSampleIndex.value].cupNum = item.value
}
}
const data = {
busSubCSampleId: busSubCSampleId.value,
conAssayTaskId: conAssayTaskId.value,
measureTime: curSample.value.measureTime,
elementParamValueList: valueList,
busAssayTaskDetailId: detailId
}
if (typeof cupNum !== 'undefined' && cupNum !== null && cupNum !== '' && cupNum !== 0 && cupNum !== '0') {
//提交杯号,保存到后台
data.cupNum = cupNum
//标记当前杯号
markCurCupNum(cupNum)
}
nx.$api.assayTask.saveDetailValue(data).then(res => {
//如果仅保存,在这里触发切换
setTimeout(() => {
autoNextSample()
}, 1000)
})
}
//提交任务指派单
const submitTask = () => {
const data = {
taskNo: currentTaskNo.value
const params = {
businessAssayTaskId: taskId.value
}
const msg = '请确认所有样品数据都已保存,然后再提交指派单!是否继续?'
uni.showModal({
@@ -758,7 +660,7 @@ const submitTask = () => {
success: res => {
if (res.cancel) return
nx.$api.assayTask.submitTask(data).then(res => {
nx.$api.assayTask.submitTask(params).then(res => {
uni.navigateTo({
url: '/pages/analysis/sample/sample-report'
})
@@ -769,37 +671,24 @@ const submitTask = () => {
//自动生成杯号(仅顺序称重):第一杯:手填,后续杯 = 上一杯 + 1
const autoGenerateCupNum = () => {
if (!orderGenBH.value) return
let cupNum = 0
let current = current.value
if (typeof current === 'undefined' || current === null) current = 0
let current = currentSampleIndex.value
//第一杯
if (current === 0) {
cupNum = 1
putCupNum(cupNum)
return
}
if (current === 0) return
//取上一个样品的杯号
const sample = leftList.value[current - 1]
cupNum = sample.cupNum
if (typeof cupNum === 'undefined' || cupNum === null || cupNum === '') return
//杯号赋值到当前样品
putCupNum(Number(cupNum) + 1, current, Number(cupNum))
}
const markCurCupNum = cupNum => {
currentSample.value.cupNum = cupNum
}
const putCupNum = (cupNum, sampleIndex, lastCupNum) => {
if (typeof sampleIndex === 'undefined' || sampleIndex === null) sampleIndex = 0
const cupNumKey = 'bh'
leftList.value[sampleIndex].cupNum = cupNum
for (const fields of fieldGroup.value) {
if (typeof fields === 'undefined') continue
//杯号
for (const field of fields.fields) {
if (field.dicKey === cupNumKey) {
if (field.title === cupNumKey) {
if (typeof field.value === 'undefined' || field.value === null || field.value === '') {
field.value = cupNum
return true
@@ -865,27 +754,48 @@ const loadConRecoveryList = () => {
})
}
const getAssayTaskDetail = taskNo => {
const getAssayTaskSampleList = businessAssayTaskId => {
leftList.value = []
nx.$api.assayTask
.getAssayTaskDetailListByTaskNo({ taskNo: taskNo })
.getAssayTaskDataList({ businessAssayTaskId })
.then(res => {
let dataList = res.result
dataList.forEach((item, index) => {
leftList.value.push(item)
})
if (leftList.value.length === 0) {
return
}
current.value = 0
leftList.value = res
currentSampleIndex.value = 0
currentSample.value = leftList.value[0]
getDetailFieldsAndStatus(true)
})
.catch(err => {
console.error(err)
})
}
async function getSampleAnalysisByTaskId(businessAssayTaskId) {
const data = await nx.$api.assayTask.getSampleAnalysisByTaskId(businessAssayTaskId)
sampleDataList = data.datas
let columns = data.columns.filter(item => item.paramNo)
fieldGroup.value = [{ open: true, fields: columns, title: '样品分析' }]
setValueToField()
title.value = '样品分析-任务指派单:' + data.businessAssayTasNo
getDomHeight()
autoNextField()
}
// 设置字段值
function setValueToField() {
for (const group of fieldGroup.value) {
group.fields.forEach(field => {
let value = getFieldValue(field)
field.value = value
})
}
}
function getFieldValue(field) {
const fieldValue = sampleDataList[currentSampleDataIndex.value][field.fieldIndex].value
if (fieldValue) {
return fieldValue
} else {
return ''
}
}
const apiRequest = async url => {
return request({
url: url,
@@ -948,11 +858,11 @@ const listenDeviceData = () => {
uni.$on('deviceData', res => {
switch (res.deviceType) {
case 'balance':
if (currentAuncel.id === res.deviceId) {
currentAuncel.weightData = res.weightData
currentAuncel.weightUnit = res.weightUnit
currentAuncel.weightStable = res.weightStable
currentAuncel.isConnected = 1
if (currentAuncel.value.id === res.deviceId) {
currentAuncel.value.weightData = res.weightData
currentAuncel.value.weightUnit = res.weightUnit
currentAuncel.value.weightStable = res.weightStable
currentAuncel.value.isConnected = true
if (Number(res.weightData) === 0) {
weightDataIsToZero.value = true
}
@@ -964,34 +874,34 @@ const listenDeviceData = () => {
})
//设备状态
uni.$on('deviceStatus', res => {
if (currentAuncel.id === res.deviceId) {
if (currentAuncel.value.id === res.deviceId) {
if (res.connected === 0) {
currentAuncel.weightStable = 0
currentAuncel.weightData = '天平断开'
currentAuncel.weightUnit = ''
currentAuncel.value.weightStable = 0
currentAuncel.value.weightData = '天平断开'
currentAuncel.value.weightUnit = ''
}
}
currentAuncel.isConnected = res.connected
currentAuncel.value.isConnected = res.connected
})
//控制设备状态
uni.$on('controlDevice', res => {
if (currentAuncel.id === res.deviceId) {
currentAuncel.id = ''
currentAuncel.name = ''
currentAuncel.code = ''
currentAuncel.weightStable = 0
currentAuncel.weightData = '请选天平'
currentAuncel.weightUnit = ''
if (currentAuncel.value.id === res.deviceId) {
currentAuncel.value.id = ''
currentAuncel.value.name = ''
currentAuncel.value.code = ''
currentAuncel.value.weightStable = 0
currentAuncel.value.weightData = '请选天平'
currentAuncel.value.weightUnit = ''
}
})
//连接断开
uni.$on('connClose', res => {
//重置
currentAuncel.weightData = ''
currentAuncel.weightUnit = ''
currentAuncel.weightStable = 0
currentAuncel.controlUserName = ''
currentAuncel.isConnected = 0
currentAuncel.value.weightData = ''
currentAuncel.value.weightUnit = ''
currentAuncel.value.weightStable = 0
currentAuncel.value.controlUserName = ''
currentAuncel.value.isConnected = false
})
}
const closeDeviceListener = () => {
@@ -1025,22 +935,21 @@ const listenNumKeyboard = () => {
return
}
//自动补全小数位数
const dataType = selectedField.value.dataType || 0
const decimalPosition = selectedField.value.decimalPosition || 0
let val = res.val
//判断val小数位如果小于设定位数则补全
if (dataType > 0) {
if (decimalPosition > 0) {
if (val === '') val = '0'
if (typeof val === 'number') val += ''
let dotLen = 0
if (val.indexOf('.') > 0) dotLen = val.length - val.indexOf('.') - 1
else val += '.'
while (dotLen < dataType) {
while (dotLen < decimalPosition) {
dotLen++
val += '0'
}
}
selectedField.value.value = val
selectedField.value.valueTypeManual = '1' //标记为手动值,不参与计算
const dicKey = selectedField.value.dicKey
if (dicKey && dicKey === 'bh_down') {
autoFillBhUp(val)
@@ -1057,7 +966,7 @@ const closeNumKeyBoardListener = () => {
}
const closeDeviceLink = () => {
const deviceId = currentAuncel.id
const deviceId = currentAuncel.value.id
releaseDeviceControl(deviceId)
}
@@ -1078,11 +987,6 @@ const releaseDeviceControl = deviceId => {
nx.$measure.send(JSON.stringify(controlDevice))
}
const getDataSourceTypeShow = val => {
if (val === 2) return '【筛上】'
if (val === 3) return '【筛下】'
return ''
}
// 天平选择
const selectAuncel = () => {
showAuncelSelector.value = true
@@ -1091,26 +995,22 @@ const selectAuncel = () => {
const auncelDoSelect = res => {
const data = res.data
if (data) {
currentAuncel.id = data.deviceId
currentAuncel.name = data.deviceName
currentAuncel.code = data.deviceCode
currentAuncel.value.id = data.deviceId
currentAuncel.value.name = data.deviceName
currentAuncel.value.code = data.deviceCode
}
}
// refs
const myKeyboard = ref(null)
const auncelSelector = ref(null)
// 生命周期
const { lockOrientation } = useScreenOrientation()
onLoad(param => {
lockOrientation('landscape')
if (param.currentTaskNo) {
currentTaskNo.value = param.currentTaskNo
currentTaskType.value = param.currentTaskType
if (param.currentTaskId) {
taskId.value = param.currentTaskId
getAssayTaskSampleList(taskId.value)
getSampleAnalysisByTaskId(taskId.value)
}
title.value = '样品分析-任务指派单:' + param.currentTaskNo
getAssayTaskDetail(currentTaskNo.value)
loadFieldApiData(fieldGroup.value)
listenNumKeyboard()
})
@@ -1163,10 +1063,14 @@ onBackPress(() => {
margin-bottom: 10px;
height: 35px;
font-size: 13px;
border-bottom: 1px solid #dcdcdc;
}
.selected-field {
background-color: #bada55;
}
.disabled-field {
background-color: #eee;
}
.label-my {
flex: 5;
}
@@ -1191,6 +1095,7 @@ onBackPress(() => {
.content-my {
flex: 2;
text-align: right;
padding-right: 4px;
.select-my {
color: #303133;
font-size: 15px;
@@ -1216,11 +1121,10 @@ onBackPress(() => {
.u-tab-item {
display: flex;
align-items: center;
justify-content: space-around;
font-size: 16px;
color: #444;
font-weight: 400;
padding: 4px 0;
padding: 4px 8px;
box-sizing: border-box;
border-bottom: 2px dotted #444;
}

View File

@@ -5,70 +5,65 @@
<u-col span="1"></u-col>
<u-col span="10">
<scroll-view scroll-y scroll-with-animation :scroll-top="scrollTop">
<u-form :model="taskInstance" ref="uForm" label-width="210">
<view class="form-item-my" v-for="(field, index) in formFields" :key="'field_' + index">
<view
class="label-my"
:style="{ fontWeight: checkFeadToDetailField(field.headToDetailField) ? 'bold' : 'normal' }"
>{{ field.label }}</view
>
<view class="content-my">
<view v-if="field.type == 'title' && field.display" class="content-title">
{{ field.textValue }}
</view>
<!--普通输入框-->
<u-input
v-if="
field.type == 'input' &&
(field.decimalCount == null || field.decimalCount == '' || Number(field.decimalCount) < 0)
"
v-model="field.value"
clearable
:placeholder="field.placeholder"
:disabled="field.fillingWay != '1'"
/>
<!--数字,限制小数位数-->
<u-input
v-if="field.type == 'input' && field.decimalCount != null && Number(field.decimalCount) >= 0"
type="number"
clearable
@blur="event => checkDecimal(event, field)"
v-model="field.value"
:placeholder="field.placeholder"
:disabled="field.fillingWay != '1'"
/>
<!--select-->
<view v-if="field.type == 'select'" class="x-bc select-my" @click="handleFieldClick(field)">
<text v-if="field.valueText">{{ field.valueText }}</text>
<text v-else>请选择</text>
<u-icon name="arrow-down" size="20"></u-icon>
</view>
<u-picker
v-if="field.type == 'select'"
:show="field.showPicker"
:columns="[field.options]"
keyName="displayName"
@cancel="field.showPicker = false"
@confirm="event => pickerConfirm(event, field)"
/>
<!--日期-->
<view v-if="field.type == 'date'" class="x-bc select-my" @click="handleFieldClick(field)">
<text v-if="field.value">{{ field.value }}</text>
<text v-else>请选择</text>
<u-icon name="calendar-fill" size="20"></u-icon>
</view>
<u-datetime-picker
v-if="field.type == 'date'"
:show="field.showPicker"
v-model="curDate"
mode="date"
@cancel="field.showPicker = false"
@confirm="event => pickerConfirm(event, field)"
></u-datetime-picker>
<view class="form-item-my" v-for="(field, index) in formFields" :key="'field_' + index">
<view
class="label-my"
:style="{ fontWeight: checkFeadToDetailField(field.headToDetailField) ? 'bold' : 'normal' }"
>{{ field.label }}</view
>
<view class="content-my">
<view v-if="field.type == 'title'" class="content-title">
{{ field.value }}
</view>
<!--普通输入框-->
<u-input
v-if="field.type == 'Input'"
v-model="field.value"
clearable
:placeholder="field.placeholder"
:disabled="field.disabled || field.fillingWay == 3"
/>
<!--数字限制小数位数-->
<u-input
v-if="field.type == 'decimal'"
type="number"
clearable
@blur="event => checkDecimal(event, field)"
v-model="field.value"
:placeholder="field.placeholder"
:disabled="field.disabled || field.fillingWay == 3"
/>
<!--select-->
<view v-if="field.type == 'select'" class="x-bc select-my" @click="handleFieldClick(field)">
<text v-if="field.value">{{ field.value }}</text>
<text v-else>请选择</text>
<u-icon name="arrow-down" size="20"></u-icon>
</view>
<u-picker
v-if="field.type == 'select'"
:show="field.showPicker"
:columns="[field.options]"
keyName="displayName"
@cancel="field.showPicker = false"
@confirm="event => pickerConfirm(event, field)"
/>
<!--日期-->
<view v-if="field.type == 'date'" class="x-bc select-my" @click="handleFieldClick(field)">
<text v-if="field.value">{{ nx.$dayjs(field.value).format('YYYY-MM-DD HH:mm:ss') }}</text>
<text v-else>请选择</text>
<u-icon name="calendar-fill" size="20"></u-icon>
</view>
<u-datetime-picker
v-if="field.type == 'date'"
:show="field.showPicker"
v-model="curDate"
mode="datetime"
@cancel="field.showPicker = false"
@confirm="event => pickerConfirm(event, field)"
></u-datetime-picker>
</view>
</u-form>
</view>
</scroll-view>
<u-button type="primary" @click="saveHeadData">保存</u-button>
</u-col>
@@ -85,8 +80,6 @@ import { calcAnalysisValue } from '@/nx/helper/calcAnalysisValue'
import nx from '@/nx'
import { onLoad } from '@dcloudio/uni-app'
// ========== data ==========
// 标题
const title = ref('编辑指派单')
// 表单模型
@@ -95,6 +88,7 @@ const taskInstance = ref({})
const scrollTop = ref(0)
// 当前任务样品
const currentTaskNo = ref('')
const currentTaskId = ref('')
// 字典选择器显示
const showDicPicker = ref(false)
// 当前日期(用于日期选择器)
@@ -111,23 +105,54 @@ const sampleList = ref([])
// 表单引用
const uForm = ref(null)
const staticFormSchema = [
{ type: 'title', value: '分析原始记录单' },
{ label: '检测方法', type: 'Input', fieldKey: 'configAssayMethodName', disabled: true },
{ label: '分析人', type: 'Input', fieldKey: 'assayOperator', disabled: true },
{ label: '检测时间', type: 'date', fieldKey: 'assayTime' },
{ label: '小数值', type: 'decimal', fieldKey: 'num', decimalPosition: 4, placeholder: '请输入' }
]
let dynamicFormSchema = []
// 页面加载
onLoad(param => {
if (param.currentTaskNo) {
currentTaskNo.value = param.currentTaskNo
if (param.currentTaskId) {
currentTaskId.value = param.currentTaskId
}
title.value = '样品分析-任务指派单:' + currentTaskNo.value
loadHeadFieldsAndValueByTaskNo()
getSampleList(currentTaskNo.value)
// loadHeadFieldsAndValueByTaskNo()
// getSampleList(currentTaskNo.value)
loadTaskDetail()
})
// ========== methods ==========
function loadTaskDetail() {
nx.$api.assayTask.getSampleAnalysisByTaskId(currentTaskId.value).then(async res => {
taskInstance.value = res
formValue.value = {
configAssayMethodName: res.configAssayMethodName,
assayOperator: res.assayOperator,
assayTime: res.assayTime,
...JSON.parse(res.formValue)
}
title.value = '样品分析-任务指派单:' + res.businessAssayTasNo
const data = await nx.$api.assayTask.getDynamicBaseFormSchema({ dataCollectionId: res.dataCollectionId })
dynamicFormSchema = data.map(item => ({
label: item.fieldName,
fieldKey: item.fieldKey,
type: item.fieldType,
value: '',
placeholder: '请输入'
}))
formFields.value = [...staticFormSchema, ...dynamicFormSchema]
bindFormValue()
})
}
// 点击字段(打开选择器)
function handleFieldClick(field) {
if (field.type == 'date') {
field.showPicker = true
if (field.fillingWay == '1') {
field.showPicker = true
}
return
}
@@ -155,22 +180,11 @@ function getSampleList(taskNo) {
})
}
// 返回上一页(原注释保留,未启用)
// function customBack() {
// uni.redirectTo({
// url: "/pages/sample/sample-work-detail"
// });
// }
// 右上角导航点击(空实现)
function navRightClick() {}
// 处理小数位数补0或去除多余位数
function checkDecimal(e, field) {
if (e == '') return
const decimalCount = field.decimalCount
if (decimalCount == null || decimalCount == '' || isNaN(decimalCount)) return
const count = Number(field.decimalCount)
const decimalCount = field.decimalPosition
const count = Number(decimalCount)
const value = field.value
const pos = value.indexOf('.') + 1
let length = value.length - pos
@@ -207,21 +221,18 @@ function assembleFields() {
formFieldsArr.push(field)
}
//先序列化再转json避免json里定义的方法丢失
formFields.value = JSON.parse(JSON.stringify(formFieldsArr, replacer), reviver)
formFields.value = JSON.parse(JSON.stringify(formFieldsArr, nx.$helper.replacer), nx.$helper.reviver)
}
// 绑定数据(将 formValue 填入字段)
function bindFormValue() {
//formValue
for (const field of formFields.value) {
const prop = field.prop
if (prop) {
const value = formValue.value[prop]
const fieldKey = field.fieldKey
if (fieldKey) {
const value = formValue.value[fieldKey]
if (value) {
field.value = value
if (field.type == 'select') {
field.valueText = value
}
}
}
}
@@ -473,7 +484,7 @@ async function loadFieldApiData() {
}
if (changeFlag) {
// 重新序列化以触发响应式更新(保留函数)
formFields.value = JSON.parse(JSON.stringify(formFieldsVal, replacer), reviver)
formFields.value = JSON.parse(JSON.stringify(formFieldsVal, nx.$helper.replacer), nx.$helper.reviver)
}
}
@@ -553,24 +564,6 @@ function getFieldByKey(key) {
}
// ========== 工具函数(保留原位置) ==========
// 自定义 replacer将函数转换为字符串。json序列化和反序列化时避免函数丢失
function replacer(key, value) {
if (typeof value === 'function') {
return value.toString()
}
return value
}
// 自定义 reviver将字符串转换回函数.json序列化和反序列化时避免函数丢失
const functionKeys = ['change', 'dicFormatter']
function reviver(key, value) {
if (functionKeys.includes(key)) {
// 将字符串转换为函数
return new Function('return ' + value)()
}
return value
}
</script>
<style lang="scss" scoped>

View File

@@ -8,20 +8,18 @@
<up-badge v-if="taskList.length > 0" class="ml5" :value="taskList.length" type="warning"></up-badge>
</view>
<u-gap height="5" bg-color="#0055A2"></u-gap>
<scroll-view
style="height: 75vh"
scroll-y
scroll-with-animation
class="content-main-left"
:scroll-top="scrollTop"
>
<TaskItem
v-for="(task, index) in taskList"
:key="index"
:task="task"
:active="current === index"
@click="switchTask(index)"
/>
<scroll-view style="height: 75vh" scroll-y scroll-with-animation class="content-main-left">
<template v-if="taskList.length > 0">
<TaskItem
v-for="(task, index) in taskList"
:key="index"
:task="task"
:seq="index + 1"
:active="current === index"
@click="switchTask(index)"
/>
</template>
<up-empty v-else text="暂无数据" mode="list"> </up-empty>
</scroll-view>
</u-col>
<u-col span="8">
@@ -31,56 +29,54 @@
<u-gap height="5" bg-color="#0055A2"></u-gap>
<view>
<scroll-view scroll-y scroll-with-animation style="height: calc(75vh - 60px)">
<block v-for="(sample, index) in sampleList" :key="index">
<view v-if="currentTask.reviewCount === sample.reviewCount" class="p5 fs16">
<u-row>
<u-col span="3" class="text-center">
<u-row>
<u-col span="6" class="text-center">
<u-checkbox
v-model="sample.checked"
v-if="
sample.sampleProcessNo === currentNode &&
<u-checkbox-group placement="column" v-model="checkedSampleCodes">
<block v-for="(sample, index) in sampleList" :key="index">
<view v-if="currentTask.reviewCount === sample.reviewCount" class="p5 fs16">
<u-row>
<u-col span="3" class="text-center">
<u-row>
<u-col span="6" class="text-center">
<!-- v-if="
sample.rollbackStatus !== 'running' &&
sample.rollbackStatus !== 'finished'
"
@change="() => selectSample(sample)"
></u-checkbox>
</u-col>
<u-col span="6" class="text-center">
<view
><text>【{{ sample.sort }}】</text></view
>
</u-col>
</u-row>
</u-col>
<u-col span="9">
<view class="sample_desc">
<view>
<view
><text class="pl10">{{ sample.sampleCode }}</text></view
>
" -->
<u-checkbox :name="sample.id"></u-checkbox>
</u-col>
<u-col span="6" class="text-center">
<view
><text>{{ index + 1 }}</text></view
>
</u-col>
</u-row>
</u-col>
<u-col span="9">
<view class="sample_desc">
<view>
<text class="pl10">
{{ getDataSourceTypeShow(sample.dataSourceType) }}{{ sample.sampleName }}
</text>
<view
><text class="pl10">{{ sample.sampleCode }}</text></view
>
<view>
<text class="pl10">
{{ getDataSourceTypeShow(sample.dataSourceType) }}{{ sample.sampleName }}
</text>
</view>
</view>
</view>
<view class="sample_desc_warn" v-if="sample.sampleProcessNo !== currentNode">
<!-- <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>
</view>
</u-col>
</u-row>
<u-line class="p5" color="#bbb" />
</view>
</block>
</u-col>
</u-row>
<u-line class="p5" color="#bbb" />
</view>
</block>
</u-checkbox-group>
</scroll-view>
<view class="content-main-right-operation">
<u-row>
@@ -114,7 +110,7 @@
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { ref, computed, getCurrentInstance } from 'vue'
import { onLoad, onBackPress } from '@dcloudio/uni-app'
import nx from '@/nx'
import { useScreenOrientation } from '@/nx/hooks/useScreenOrientation'
@@ -126,13 +122,11 @@ const currentNode = ref('F31')
const dicSampleProcessCodeList = ref([])
const showRollbackModalFlag = ref(false)
const rollbackContent = ref('')
const scrollTop = ref(0)
const current = ref(0)
const currentTask = ref({})
const currentTaskNo = ref('')
const currentTaskType = ref('')
const taskList = ref([])
const sampleList = ref([])
const checkedSampleCodes = ref([])
// 计算属性
const userInfo = computed(() => nx.$store('user').userInfo)
@@ -141,14 +135,8 @@ const userInfo = computed(() => nx.$store('user').userInfo)
const customBack = () => {
uni.reLaunch({ url: '/pages/analysis/index/index' })
}
const selectSample = sample => {
sample.checked = !sample.checked
}
const showRollbackModal = () => {
const checkedSampleList = sampleList.value.filter(item => item.checked)
if (checkedSampleList.length === 0) {
if (checkedSampleCodes.length === 0) {
uni.showToast({ title: '请选择要退回的样品!', icon: 'none' })
return
}
@@ -156,7 +144,6 @@ const showRollbackModal = () => {
}
const applyRollbackSample = () => {
const checkedSampleList = sampleList.value.filter(item => item.checked)
if (!rollbackContent.value.trim()) {
uni.showToast({ title: '请输入退回说明!', icon: 'none' })
return
@@ -170,14 +157,13 @@ const applyRollbackSample = () => {
confirmColor: '#0055A2',
success: res => {
if (res.cancel) return
const detailIdList = checkedSampleList.map(item => item.id)
const data = {
remark: rollbackContent.value,
taskId: currentTask.value.id,
detailIds: detailIdList.join(',')
detailIds: checkedSampleCodes.value.join(',')
}
nx.$api.assayTask.createRollbackApply(data).then(() => {
getAssayTaskDetail(currentTaskNo.value)
getAssayTaskDetail(currentTask.value.id)
})
}
})
@@ -200,9 +186,9 @@ const checkWork = () => {
}
const startWork = () => {
if (!checkWork()) return
// if (!checkWork()) return
uni.navigateTo({
url: `/pages/analysis/sample/sample-work-detail?currentTaskNo=${currentTaskNo.value}`
url: `/pages/analysis/sample/sample-work-detail?currentTaskId=${currentTask.value.id}`
})
}
@@ -210,38 +196,33 @@ const switchTask = async index => {
if (index === current.value) return
current.value = index
rollbackContent.value = ''
const task = taskList.value[index]
currentTask.value = task
currentTaskNo.value = task.taskNo
currentTaskType.value = task.taskType
getAssayTaskDetail(task.taskNo)
getAssayTaskDetail(task.id)
checkedSampleCodes.value = []
}
const getAssayTask = () => {
rollbackContent.value = ''
const param = {
finishStatus: 'waiting',
assayOper: userInfo.value.nickname
taskStatus: 'submit'
// assayOper: userInfo.value.nickname
}
nx.$api.auncel.getAssayTaskList(param).then(res => {
nx.$api.assayTask.getAssayTaskList(param).then(res => {
if (res) {
taskList.value = res
taskList.value = res.list
if (taskList.value.length > 0) {
const first = taskList.value[0]
currentTask.value = first
currentTaskNo.value = first.taskNo
currentTaskType.value = first.taskType
getAssayTaskDetail(first.taskNo)
currentTask.value = taskList.value[0]
getAssayTaskDetail(currentTask.value.id)
}
}
})
}
const getAssayTaskDetail = taskNo => {
const getAssayTaskDetail = businessAssayTaskId => {
sampleList.value = []
nx.$api.assayTask.getAssayTaskDetailListByTaskNo({ taskNo }).then(res => {
const list = res.result || []
nx.$api.assayTask.getAssayTaskDataList({ businessAssayTaskId }).then(res => {
const list = res || []
list.forEach(item => (item.checked = false))
sampleList.value = list
})
@@ -262,8 +243,8 @@ const getProcessNameShow = val => {
onLoad(() => {
const { lockOrientation } = useScreenOrientation()
lockOrientation('landscape')
getDicSampleProcessCodeList()
// getAssayTask()
// getDicSampleProcessCodeList()
getAssayTask()
})
onBackPress(() => {