华西海圻ELN前端工程
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

620 lines
23 KiB

import moment from 'moment'
import { getLatestSn, getLatestSnArr } from '@/api/template';
import { isValueEmpty, getStringWidth } from '@/utils/index';
import { isCommonUnit } from "@/utils/conTools";
import { sj_subpackage, sj_startConfiguration, sj_configurationCompleted } from '@/api/business/sj/sj';
import {convertConcentration} from "@/utils/conConverter";//浓度单位转换
import {volumeConverter} from "@/utils/volConverter";//体积单位转换
import * as XLSX from 'xlsx'
export default {
dicts: [
'business_pztj',
'business_cctj',
'business_nddw',
'business_tjdw',
'business_yxqdw',
'business_rqcz',
'business_sp_jmdyzqdyp', //色谱-编号-准确度与精密度
'business_sp_nbgzy', //色谱-编号-内标工作液
'business_sp_zkgzy', //色谱-编号-质控工作液
'business_sp_bqgzy', //色谱-编号-标曲工作液
'business_sp_bzqxzkypzbb', //色谱-编号-标准曲线/质控样品制备表
'business_sp_tqhsl', //色谱-编号-提取回收率
'business_sp_qxwdx', //色谱-编号-全血稳定性
'business_sp_cbyhgzywdx', //色谱-编号-储备液和工作液稳定性
'business_sp_rxjzxy', //色谱-编号-溶血基质效应
'business_sp_jzxy', //色谱-编号-基质效应
'business_sp_xzxytyx', //色谱-编号-选择性与特异性
'business_sp_zdybs', //色谱-编号-最大样本数
'business_sp_xskkx', //色谱-编号-稀释可靠性
'business_sp_cbydb', //色谱-编号-储备液对比
'business_pcr_gzy', // PCR-编号-工作液
'business_lba_jg', // LBA006-结果
'business_cftj', // 存放条件
'business_yplx', // 样品类型
'business_sydd', // 毒理-Ames实验地点
'business_dl_ameswrqk', // 毒理-Ames污染情况
],
props: {
templateData: {
type: Object,
default: () => { }
}
},
watch: {
templateData: {
immediate: true,
deep: true,
handler(v) {
if (v) {
const {
studySubjectId,
studyId,
studyMc,
studySn,
templateMc,
templateMcEn,
templateSn,
startDate,
bdmc,
endDate,
id
} = v
if (v.resource) {
//type 类型:1:试剂;3:给药制剂;5:麻精药;7:供试品
//试验试剂信息 试剂
// this.resource = _.filter(JSON.parse(v.resource), function (o) {
// return o.type == 1 || o.elnType == 1
// })
// //试验物资信息 供试品、给药制剂、麻精药
// this.resourceWz = _.filter(JSON.parse(v.resource), function (o) {
// return o.type == 3 || o.type == 5 || o.type == 7 || o.elnType == 3|| o.elnType == 5 || o.elnType == 7
// })
//试验试剂信息
this.resourceSj = _.filter(JSON.parse(v.resource), function (o) {
return o.type == 1 || o.elnType == 1
})
//供试品信息
this.resourceGsp = _.filter(JSON.parse(v.resource), function (o) {
return o.type == 7 || o.elnType == 7
})
//给药制剂信息
this.resourceGyzj = _.filter(JSON.parse(v.resource), function (o) {
return o.type == 3 || o.elnType == 3
})
//麻精药信息
this.resourceMjy = _.filter(JSON.parse(v.resource), function (o) {
return o.type == 5 || o.elnType == 5
})
}
if (v.yqResource) {
//仪器信息
this.yqResource = JSON.parse(v.yqResource)
}
this.product = v.product || null
if (v.bdnr) {
this.formData = {
...JSON.parse(v.bdnr),
studySubjectId,
studyId,
studyMc,
studySn,
templateMc,
templateMcEn,
templateSn,
startDate,
bdmc,
endDate,
id
}
} else {
this.formData = {
studySubjectId,
studyId,
studyMc,
studySn,
templateMc,
templateMcEn,
templateSn,
startDate,
bdmc,
endDate,
id
}
}
const { effectivePeriod, effectivePeriodUnit, expireDate } =
this.formData
//实际填报的时候,如果有了开始时间,并且有有效周期,但是没有失效日,就计算失效日为开始时间+有效周期
if (
startDate &&
this.fillType === 'actFill' &&
effectivePeriod &&
effectivePeriodUnit &&
!expireDate
) {
const start = moment(startDate)
const unit = effectivePeriodUnit === '天' ? 'days' : 'hours'
const end = start
.add(Number(effectivePeriod), unit)
.format('YYYY-MM-DD HH:mm:ss')
this.formData = { ...this.formData, expireDate: end }
}
console.log(this.formData, 'formData from templateData')
this.setTemplateData(v)
}
}
}
},
data() {
return {
formData: {},
templateDetail: {},
product: null,//产物:1:试剂;3:给药制剂;5:麻精药
resource: [], //试验试剂信息--弃用
resourceWz: [], //物资信息--弃用
resourceSj: [],//试验试剂信息
resourceGsp: [],//供试品信息
resourceGyzj: [],//给药制剂信息
resourceMjy: [],//麻精药信息
yqResource: [], //仪器信息
jcbList: [], //检测板信息
resourceTmp: [],//试验试剂信息提交用
yqResourceTmp: [], //仪器信息提交用
jcbListTmp: [], //检测板信息提交用
sjColumns: [
{ label: 'template.common.reagentName', prop: "mc" },//名称
{ label: 'template.common.reagentCode', prop: "bh" },//编号
{ label: 'template.common.reagentNo', prop: "ph" },//批号 试剂,供试品才有
{ label: 'template.common.concentration', prop: "ndz" },//浓度
{ label: 'template.common.source', prop: "ly" },//来源
{ label: 'template.common.reagentExpireDate', prop: "sxrq" },//失效日期
],
gspColumns: [
{ label: 'template.common.wzName', prop: "mc" },//名称
{ label: 'template.common.wzCode', prop: "bh" },//编号
{ label: 'template.common.reagentNo', prop: "ph" },//批号 试剂,供试品才有
{ label: 'template.common.wzSource', prop: "ly" },//来源
{ label: 'template.common.wzConcentration', prop: "ndz" },//浓度
{ label: 'template.common.wzExpireDate', prop: "sxrq" },//失效日期
],
gyzjColumns: [
{ label: 'template.common.wzName', prop: "mc" },//名称
{ label: 'template.common.wzCode', prop: "bh" },//编号
{ label: 'template.common.wzSource', prop: "ly" },//来源
{ label: 'template.common.wzConcentration', prop: "ndz" },//浓度
{ label: 'template.common.wzExpireDate', prop: "sxrq" },//失效日期
],
mjyColumns: [
{ label: 'template.common.wzName', prop: "mc" },//名称
{ label: 'template.common.wzCode', prop: "bh" },//编号
{ label: 'template.common.wzSource', prop: "ly" },//来源
{ label: 'template.common.wzConcentration', prop: "ndz" },//浓度
{ label: 'template.common.wzExpireDate', prop: "sxrq" },//失效日期
],
//弃用
sysjColumns: [
{ label: 'template.common.reagentName', prop: "mc" },//名称
{ label: 'template.common.reagentCode', prop: "bh" },//编号
{ label: 'template.common.reagentNo', prop: "ph" },//批号 试剂,供试品才有
{ label: 'template.common.concentration', prop: "ndz" },//浓度
{ label: 'template.common.source', prop: "ly" },//来源
{ label: 'template.common.reagentExpireDate', prop: "sxrq" },//失效日期
],
//弃用
sywzColumns: [
{ label: 'template.common.wzName', prop: "mc" },//名称
{ label: 'template.common.wzCode', prop: "bh" },//编号
{ label: 'template.common.wzSource', prop: "ly" },//来源
{ label: 'template.common.wzConcentration', prop: "ndz" },//浓度
{ label: 'template.common.wzExpireDate', prop: "sxrq" },//失效日期
],
yqColumns: [
{ label: 'template.common.instrumentName', prop: "mc" },//仪器名称
{ label: 'template.common.instrumentModel', prop: "xh" },//仪器型号
{ label: 'template.common.instrumentCode', prop: "bh" },//仪器编号
{ label: 'template.common.nextTestDate', prop: "jzrq" },//下次测试/校准/检定日期
],
}
},
mounted() { },
unmounted() {
this.setTemplateData({})
},
methods: {
//试剂弹窗确认前
onBeforeReagentSubmit(data){
const {selectData, callback, key, formFields} = data;
const {subTargetStartSolution} = formFields;
//判断选择的浓度单位和预制的浓度单位是否一致
if(key === "subStartSolution" && !isCommonUnit(selectData.row.nddw,[subTargetStartSolution])){//选择起始源溶液需要同步更新table的变更记录。
callback.prevent('浓度单位与预制不符,请重新选择或申请废止并重新预制。');
}
},
getFormDataByTemplateData() {
let o = {};
const { bdnr } = this.templateData
if (bdnr) {
o = JSON.parse(bdnr)
}
return o;
},
//开始配置
//postData: {bh: '123456'}
async startConfigRequest(postData) {
const res = await sj_startConfiguration(postData)
if (res.code === 200) {
this.$message.success('开始配置成功')
} else {
this.$message.error('开始配置失败')
}
},
//完成配置
async configCompleteRequest(postData) {
const res = await sj_configurationCompleted(postData)
if (res.code === 200) {
this.$message.success('完成配置成功')
} else {
this.$message.error('完成配置失败')
}
},
//分装
async subPackageRequest(postData) {
const res = await sj_subpackage(postData)
if (res.code === 200) {
this.$message.success('分装成功')
} else {
this.$message.error('分装失败')
}
},
//获取打印配置
getBasePrintConfig(data = {}) {
const { printCode, type, row = {} } = data;
const { stepStorageCondition, startDate, expireDate } = this.formData;;
const { nickName, name } = this.$store.getters;
const lang = this.$i18n.locale;
const printConfig = {
"品名": "暂时还不知道品名是哪个字段",
"存储条件": stepStorageCondition,
"配制日期": moment(startDate).format("YYYY-MM-DD"),
"有效期至": moment(expireDate).format("YYYY-MM-DD HH:mm"),
"配置者": lang === "zh_CN" ? nickName : name,
//type==="subPackage"从分装打印过来的,
//type==="row" 从列表上点过来的
"编号": type === "subPackage" ? printCode : (row.targetSolutionCode + row.subTargetSolutionCode),
}
return printConfig
},
async getLatestSn(count = 1) {
const res = await getLatestSn({ count })
if (res.code === 200) {
return res.data
}
return []
},
//获取最新的多个编号
async getLatestSnArr(params) {
const res = await getLatestSnArr(params)
if (res.code === 200) {
return res.data
}
return []
},
getResource() {
return this.resourceTmp
},
getYqResource() {
return this.yqResourceTmp
},
getJcbList() {
return this.jcbListTmp
},
//根据ref数组获取直接formData
getFilledFormDataByRefs(refArr = []) {
let result = {}
refArr.map((ref) => {
const refData = this.$refs[ref]?.getFilledFormData() || {}
for (const [key, value] of Object.entries(refData)) {
let index = 0
// 如果当前键是可能重复的字段,且结果对象中已经存在该键,则添加索引后缀
if (
(key === 'headerSelectFields' || key === 'stepTableFormData') &&
result.hasOwnProperty(key)
) {
// 为重复字段生成带索引的键名,从1开始(因为第一个组件不需要后缀)
const newKey = `${key}_${++index}`
result[newKey] = value
} else {
// 正常合并其他字段
result[key] = value
}
}
})
return result
},
//统一校验form表单是否填写
async validFormFields(refArr = []) {
let result = {}
const refs = refArr.map((ref) => {
let refData = {}
if (this.$refs[ref][0]) {
refData = this.$refs[ref][0]?.getFormData() || {}
} else {
refData = this.$refs[ref]?.getFormData() || {}
}
return refData
})
const validFormData = await Promise.all(refs).catch((err) => {
// this.$message.error(err);
if (err.errorType && err.errorType === 'step') {
this.$message.error('请添加步骤')
return
}
this.$message.error('表单内容未填完,请填写后再提交')
})
if (validFormData) {
validFormData.forEach((item) => {
for (const [key, value] of Object.entries(item)) {
let index = 0
// 如果当前键是可能重复的字段,且结果对象中已经存在该键,则添加索引后缀
if (
(key === 'headerSelectFields' || key === 'stepTableFormData') &&
result.hasOwnProperty(key)
) {
// 为重复字段生成带索引的键名,从1开始(因为第一个组件不需要后缀)
const newKey = `${key}_${++index}`
result[newKey] = value
} else {
// 正常合并其他字段
result[key] = value
}
}
})
return result
}
return false
},
//试验配制条件options
getDictOptions(dictType) {
return this.dict.type[dictType] || []
},
setTemplateData(data) {
this.$store.commit('template/SET_TEMPLATE_DATA', data)
},
//统一处理删除行
deleteRow(index,ref) {
if(ref){
this.$refs[ref].deleteRow(index);
return;
}
this.$refs.stepTableRef.deleteRow(index)
},
//统一处理浓度校验异常
onCommonVerifyNdException(formFields,data){
const {callback,rowIndex, key,dataSource} = data;
const keys = [
'actStartSolutionVolume',
'actDiluentVolume',
]
if(keys.includes(key)){
const {targetAcSolution} = formFields;
if (rowIndex === 0) {//第一行的浓度取选择的溶液,
if (isValueEmpty(targetAcSolution)) {
callback.prevent("请先选择起始源溶液")
}
} else {
//非第一行的浓度取上一行的浓度
const prevItem = dataSource[rowIndex - 1]
const prevConcentration = prevItem.actSolutionConcentration;
if (!prevConcentration) {
callback.prevent("请先计算上一行的实际目标溶液浓度")
}
}
}
},
//统一处理blur事件,因为有效周期和过期日期是相关的,所以需要在有效周期失焦时更新过期日期
onHandleBlur(fields) {
const {
key,
codeSTD,
targetStartSolution,
subTargetStartSolution,//预设起始源溶液浓度单位
} = fields
const { startDate } = this.formData
if (key === 'codeSTD') {
//起始编号STD失焦时,更新stepDataSource
const arr = Array.from({ length: codeSTD }, (item, index) => ({
actSolutionVolumePrecision: 3, //小数点精度默认为3
actSolutionConcentrationPrecision: 3, //小数点精度默认为3
targetDiluentVolumePrecision: 3, //小数点精度默认为3
targetStartSolutionVolumePrecision: 3, //小数点精度默认为3
targetSolutionCode: `STD${Number(codeSTD) - index}`
}))
this.$refs.stepTableRef.updateDataSource(arr)
} else if (key === 'targetStartSolution' || key === 'subTargetStartSolution') {
//起始溶液体积失焦时,更新目标溶液预计浓度
const arr = this.$refs.stepTableRef?.getDataSource();
const {headerSelectFields} = this.$refs.stepTableRef?.getFilledFormData();
const params = {
subTargetStartSolution,
headerSelectFields
}
arr.forEach((item, rowIndex) => {
this.updateTargetStartSolutionVolume(
item,
targetStartSolution,
params
)
})
}
},
//批量更新目标起始源溶液体积
batchUpdateTargetStartSolutionVolume(arr, startConcentration, params) {
arr.forEach((item, rowIndex) => {
this.updateTargetStartSolutionVolume(
item,
startConcentration,
params
)
})
},
//统一处理table失焦事件
onHandleTableBlur(params) {
const { rowIndex, colKey, value, item, dataSource,headerSelectFields } = params
if (
colKey === 'targetSolutionVolume' ||
colKey === 'targetSolutionConcentration' ||
colKey === 'targetStartSolutionVolumePrecision' ||
colKey === 'targetDiluentVolumePrecision'
) {
const volume =
this.$refs.stepFormPackageRef?.getFormDataByKey(
'targetStartSolution'
)
const subTargetStartSolution =
this.$refs.stepFormPackageRef?.getFormDataByKey(
'subTargetStartSolution'
)
const params = {
subTargetStartSolution:subTargetStartSolution,
headerSelectFields
}
if (isValueEmpty(volume)) {
this.$message.error('请先选择预设起始源溶液浓度')
} else {
this.updateTargetStartSolutionVolume(item, volume,params)
}
} else if (
colKey === 'actStartSolutionVolume' ||
colKey === 'actDiluentVolume'
) {
//实际起始溶液体积和实际目标溶液体积
const {targetAcSolution,subTargetAcSolutionUnit} =
this.$refs.stepFormPackageRef?.getFilledFormData() //获取实际起始溶液浓度
const {headerSelectFields} = this.$refs.stepTableRef?.getFilledFormData();
const p = {
targetStartSolutionUnit:subTargetAcSolutionUnit,
headerSelectFields
}
if (isValueEmpty(targetAcSolution)) {
this.$message.error('请先选择起始源溶液')
return
} else {
const volResult = this.updateSjmbrynd(item, targetAcSolution,p)
if (!volResult) {
return
}
this.$refs.stepTableRef?.updateDataSourceByRowIndex(rowIndex, { actSolutionVolume: volResult.actVol, actSolutionConcentration: volResult.actNd }, "blur")
}
}
},
//计算目标溶液浓度
calcNd(item, targetAcSolution,params) {
console.log(params,"ppp")
//targetStartSolutionUnit(实际起始源溶液浓度单位)
const {targetStartSolutionUnit,headerSelectFields} = params;
//actStartSolutionVolumeUnit(实际起始源溶液体积单位)actSolutionVolumeUnit(实际目标溶液体积单位)
//actDiluentVolumeUnit(实际稀释液体积单位)actSolutionConcentrationUnit(实际目标溶液浓度单位)
const {actStartSolutionVolumeUnit,actSolutionVolumeUnit,actDiluentVolumeUnit,actSolutionConcentrationUnit} = headerSelectFields;
//实际源溶液浓度÷(实际终体积÷源溶液加入体积);
const precision = item.actSolutionConcentrationPrecision
const volPrecision = item.actSolutionVolumePrecision;
//实际稀释液体积
const actDiluentVolume = item.actDiluentVolume
//实际起始源溶液体积
const actStartSolutionVolume = item.actStartSolutionVolume
if(isValueEmpty(actStartSolutionVolume) || isValueEmpty(actDiluentVolume) || isValueEmpty(targetStartSolutionUnit)){
return false
}
const converActDiluentVolume = volumeConverter.convert(actDiluentVolume+actDiluentVolumeUnit,actSolutionVolumeUnit)
const converActStartSolutionVolume = volumeConverter.convert(actStartSolutionVolume+actStartSolutionVolumeUnit,actSolutionVolumeUnit)
//实际源溶液加入体积+实际稀释液加入体积
const actVol = (
Number(converActDiluentVolume) + Number(converActStartSolutionVolume)
).toFixed(volPrecision)
const targetStartVolUnit = actSolutionConcentrationUnit.split("/")[1];//先按照预设目标溶液浓度的单位标准
const converActVol = volumeConverter.convert(actVol+actSolutionVolumeUnit,targetStartVolUnit)
const converActDiluentVolume1 = volumeConverter.convert(actStartSolutionVolume+actStartSolutionVolumeUnit,targetStartVolUnit)
const converTargetAcSolution = convertConcentration.convert(targetAcSolution+targetStartSolutionUnit,actSolutionConcentrationUnit)
// 实际目标溶液浓度 = 实际源溶液浓度÷(实际终体积÷源溶液加入体积);
const actNd = (
parseFloat(converTargetAcSolution) / (
parseFloat(converActVol)/parseFloat(converActDiluentVolume1)
)
).toFixed(precision)
const nd = actNd === 'Infinity' ? 0 : Number(actNd)
console.log(actNd, targetAcSolution, actStartSolutionVolume, actVol, "actNd")
// item.actSolutionConcentration = actNd === 'Infinity' ? 0 : actNd
return { actVol: Number(actVol), actNd: nd }
},
//计算并更新实际目标溶液浓度 先计算实际目标溶液体积再计算实际目标溶液浓度
updateSjmbrynd(item, targetAcSolution,params) {
return this.calcNd(item, targetAcSolution,params)
},
//更新起始溶液体积时,计算预设起始溶液体积和预设稀释液体积
updateTargetStartSolutionVolume(item, volume,unitParams) {
const precision = item.targetStartSolutionVolumePrecision || 0
const concentration = item.targetSolutionConcentration
const targetVolume = item.targetSolutionVolume
const {subTargetStartSolution,headerSelectFields} = unitParams
const {targetSolutionConcentrationUnit,targetSolutionVolumeUnit,targetStartSolutionVolumeUnit,targetDiluentVolumeUnit} = headerSelectFields
if(
isValueEmpty(concentration) ||
isValueEmpty(targetVolume)||
isValueEmpty(subTargetStartSolution)||
isValueEmpty(targetSolutionConcentrationUnit)||
isValueEmpty(targetSolutionVolumeUnit)||
isValueEmpty(targetStartSolutionVolumeUnit)||
isValueEmpty(targetDiluentVolumeUnit)
){
return;
}
const targetStartVolUnit = targetSolutionConcentrationUnit.split("/")[1];//先按照预设目标溶液浓度的单位标准
//将起始溶液浓度转换为和预设目标溶液浓度一样的单位再计算;
const converStartCon = convertConcentration.convert(volume+subTargetStartSolution,targetSolutionConcentrationUnit)
//将预设目标溶液体积转换为和预设目标溶液浓度单位的分母一样的单位再计算;如:预设目标溶液浓度单位为mg/mL,预设目标溶液体积单位为uL,则将预设目标溶液体积转换为mL
const convertTargetVol = volumeConverter.convert(targetVolume+targetSolutionVolumeUnit,targetStartVolUnit)
//预设起始溶液体积:(目标溶液预计浓度 乘以 目标溶液预计体积)除以 起始溶液浓度
const result = Number((concentration * convertTargetVol) / converStartCon)
//根据预设起始溶液体积单位转换计算后的数据
const convertYsVol = volumeConverter.convert(result+targetStartVolUnit,targetStartSolutionVolumeUnit)
item.targetStartSolutionVolume = Number(convertYsVol.toFixed(
precision
))
// this.$refs.stepTableRef.updateDataSourceByRowIndex(rowIndex, { targetStartSolutionVolume: result });
if (targetVolume) {
//预设稀释液体积:目标溶液预计体积 减去 源溶液预计体积;
const precision1 = item.targetDiluentVolumePrecision || 0;
//将预设目标溶液体积转换为和预设起始溶液体积单位一样的单位再计算;
const convertTargetVol1 = volumeConverter.convert(targetVolume+targetSolutionVolumeUnit,targetStartSolutionVolumeUnit)
const result1 = (convertTargetVol1 - convertYsVol)
item.targetDiluentVolume = Number(volumeConverter.convert(result1+targetStartSolutionVolumeUnit,targetDiluentVolumeUnit).toFixed(precision1))
// this.$refs.stepTableRef.updateDataSourceByRowIndex(rowIndex, { targetDiluentVolume: result1 });
}
},
// 导出excel模板
exportExcel(headerArray, title = '导出模板') {
this.$modal.loading()
const ws = XLSX.utils.aoa_to_sheet([headerArray]);
const colWidths = headerArray.map(cell => getStringWidth(cell) + 2);
ws['!cols'] = colWidths.map(width => ({ wch: width }));
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');
XLSX.writeFile(wb, `${title}.xlsx`);
this.$modal.closeLoading()
},
}
}