华西海圻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.

809 lines
30 KiB

  1. import moment from 'moment'
  2. import { getLatestSn, getLatestSnArr } from '@/api/template'
  3. import { isValueEmpty, getStringWidth, getuuid } from '@/utils/index'
  4. import { isCommonUnit } from '@/utils/conTools'
  5. import {
  6. sj_subpackage,
  7. sj_startConfiguration,
  8. sj_configurationCompleted
  9. } from '@/api/business/sj/sj'
  10. import { convertConcentration } from '@/utils/conConverter' //浓度单位转换
  11. import { volumeConverter } from '@/utils/volConverter' //体积单位转换
  12. import * as XLSX from 'xlsx'
  13. import { EventBus } from '@/utils/eventBus'
  14. export default {
  15. dicts: [
  16. 'business_pztj',
  17. 'business_cctj',
  18. 'business_nddw',
  19. 'business_tjdw',
  20. 'business_zldw',
  21. 'business_yxqdw',
  22. 'business_rqcz',
  23. 'business_sp_jmdyzqdyp', //色谱-编号-准确度与精密度
  24. 'business_sp_nbgzy', //色谱-编号-内标工作液
  25. 'business_sp_zkgzy', //色谱-编号-质控工作液
  26. 'business_sp_bqgzy', //色谱-编号-标曲工作液
  27. 'business_sp_bzqxzkypzbb', //色谱-编号-标准曲线/质控样品制备表
  28. 'business_sp_tqhsl', //色谱-编号-提取回收率
  29. 'business_sp_qxwdx', //色谱-编号-全血稳定性
  30. 'business_sp_cbyhgzywdx', //色谱-编号-储备液和工作液稳定性
  31. 'business_sp_rxjzxy', //色谱-编号-溶血基质效应
  32. 'business_sp_jzxy', //色谱-编号-基质效应
  33. 'business_sp_xzxytyx', //色谱-编号-选择性与特异性
  34. 'business_sp_zdybs', //色谱-编号-最大样本数
  35. 'business_sp_xskkx', //色谱-编号-稀释可靠性
  36. 'business_sp_cbydb', //色谱-编号-储备液对比
  37. 'business_pcr_gzy', // PCR-编号-工作液
  38. 'business_lba_jg', // LBA006-结果
  39. 'business_cftj', // 存放条件
  40. 'business_yplx', // 样品类型
  41. 'business_sydd', // 毒理-Ames实验地点
  42. 'business_dl_ameswrqk', // 毒理-Ames污染情况
  43. 'business_dl_amescltj', // 毒理-Ames处理条件
  44. 'business_dl_amesbjjt', // 毒理-Ames背景菌苔
  45. 'business_dl_amescdqk', // 毒理-Ames沉淀情况
  46. 'business_dl_xbmc', // 毒理-Ames细胞名称
  47. 'business_dl_qsxjbltj', // 毒理-暴露条件
  48. 'business_rylx', // 溶液类型
  49. 'business_xbzb', // 细胞组别
  50. 'business_xblx', // 细胞类型
  51. 'business_pytj', // 毒理-培养条件
  52. 'business_fstj', // 毒理-复苏条件
  53. 'business_dsfs', //动技-递送方式
  54. 'business_knj', //动技-抗凝剂
  55. 'business_fhlr', //动技-复核内容
  56. 'business_fhfw', //动技-复核范围
  57. 'business_dwzs', // 动物种属
  58. 'business_cjdd', // 采集地点
  59. 'business_zpdd', // 制片地点
  60. 'business_cjbw', // 制片部位
  61. 'business_qywz', // 取样位置
  62. 'business_lba_ptjhbzqx_zkpx', // LBA-编号-配体结合分析标准曲线LBA005-质控平行
  63. 'business_lba_bqpx', //LBA-编号-配体结合分析标准曲线LBA005-标曲平行
  64. 'business_lba_ptjhfxyp', // LBA-编号-配体结合分析方法学样品制备表LBA007
  65. 'business_ada_kyktzkyp', // ADA-编号-抗药抗体质控样品配制记录表ADA005
  66. 'business_ada_kyktffxyp', // ADA-编号-抗药抗体方法学样品制备表ADA007
  67. 'business_dl_uav', // 毒理-紫外照射操作记录表-UVA-DL023
  68. 'business_pcr_fxffypzbb', //PCR-编号-分析方法学样品制备表
  69. 'business_dl_xbx', //毒理-紫外照射操作记录表-细胞系
  70. 'business_dl_dwzs', //毒理-紫外照射操作记录表-动物种属
  71. 'business_dl_sjqqtqk' //毒理-细胞收集/低渗及固定操作记录表-收集前其他情况
  72. ],
  73. props: {
  74. templateData: {
  75. type: Object,
  76. default: () => {}
  77. }
  78. },
  79. watch: {
  80. templateData: {
  81. immediate: true,
  82. deep: true,
  83. handler(v) {
  84. if (v) {
  85. const {
  86. studySubjectId,
  87. studyId,
  88. studyMc,
  89. studySn,
  90. templateMc,
  91. templateMcEn,
  92. templateId,
  93. templateSn,
  94. startDate,
  95. submittedCodes,
  96. bdmc,
  97. endDate,
  98. id
  99. } = v
  100. if (v.resource) {
  101. //type 类型:1:试剂;3:给药制剂;5:麻精药;7:供试品 9:细胞;11:细菌
  102. //试验试剂信息 试剂
  103. // this.resource = _.filter(JSON.parse(v.resource), function (o) {
  104. // return o.type == 1 || o.elnType == 1
  105. // })
  106. // //试验物资信息 供试品、给药制剂、麻精药
  107. // this.resourceWz = _.filter(JSON.parse(v.resource), function (o) {
  108. // return o.type == 3 || o.type == 5 || o.type == 7 || o.elnType == 3|| o.elnType == 5 || o.elnType == 7
  109. // })
  110. //试验试剂信息
  111. this.resourceSj = _.filter(JSON.parse(v.resource), function (o) {
  112. return o.type == 1 || o.elnType == 1
  113. })
  114. //供试品信息
  115. this.resourceGsp = _.filter(JSON.parse(v.resource), function (o) {
  116. return o.type == 7 || o.elnType == 7
  117. })
  118. //给药制剂信息
  119. this.resourceGyzj = _.filter(JSON.parse(v.resource), function (o) {
  120. return o.type == 3 || o.elnType == 3
  121. })
  122. //麻精药信息
  123. this.resourceMjy = _.filter(JSON.parse(v.resource), function (o) {
  124. return o.type == 5 || o.elnType == 5
  125. })
  126. }
  127. if (v.yqResource) {
  128. //仪器信息
  129. this.yqResource = JSON.parse(v.yqResource)
  130. }
  131. this.product = v.product || null
  132. if (v.bdnr) {
  133. this.formData = {
  134. ...JSON.parse(v.bdnr),
  135. studySubjectId,
  136. studyId,
  137. studyMc,
  138. studySn,
  139. templateMc,
  140. templateMcEn,
  141. templateId,
  142. templateSn,
  143. startDate,
  144. submittedCodes,
  145. bdmc,
  146. endDate,
  147. id
  148. }
  149. } else {
  150. this.formData = {
  151. studySubjectId,
  152. studyId,
  153. studyMc,
  154. studySn,
  155. templateMc,
  156. templateMcEn,
  157. templateId,
  158. templateSn,
  159. submittedCodes,
  160. startDate,
  161. bdmc,
  162. endDate,
  163. id
  164. }
  165. }
  166. console.log(this.formData,"templateData")
  167. const { effectivePeriod, effectivePeriodUnit, expireDate } =
  168. this.formData
  169. //实际填报的时候,如果有了开始时间,并且有有效周期,但是没有失效日,就计算失效日为开始时间+有效周期
  170. if (
  171. startDate &&
  172. this.fillType === 'actFill' &&
  173. effectivePeriod &&
  174. effectivePeriodUnit &&
  175. !expireDate
  176. ) {
  177. let end
  178. if (effectivePeriod === 'NA' || effectivePeriodUnit === 'NA') {
  179. end = 'NA'
  180. } else {
  181. const start = moment(startDate)
  182. const unit = effectivePeriodUnit === '天' ? 'days' : 'hours'
  183. end = start
  184. .add(Number(effectivePeriod), unit)
  185. .format('YYYY-MM-DD HH:mm:ss')
  186. }
  187. this.formData = { ...this.formData, expireDate: end }
  188. }
  189. this.setTemplateData(v)
  190. }
  191. }
  192. }
  193. },
  194. data() {
  195. return {
  196. formData: {},
  197. templateDetail: {},
  198. product: null, //产物:1:试剂;3:给药制剂;5:麻精药
  199. resource: [], //试验试剂信息--弃用
  200. resourceWz: [], //物资信息--弃用
  201. resourceSj: [], //试验试剂信息
  202. resourceGsp: [], //供试品信息
  203. resourceGyzj: [], //给药制剂信息
  204. resourceMjy: [], //麻精药信息
  205. yqResource: [], //仪器信息
  206. jcbList: [], //检测板信息
  207. xbxj: [], //细胞细菌信息
  208. resourceTmp: [], //试验试剂信息提交用
  209. yqResourceTmp: [], //仪器信息提交用
  210. jcbListTmp: [], //检测板信息提交用
  211. xbxjTmp: [], //细胞细菌信息提交用
  212. sjColumns: [
  213. { label: 'template.common.reagentName', prop: 'mc' }, //名称
  214. { label: 'template.common.reagentCode', prop: 'bh' }, //编号
  215. { label: 'template.common.reagentNo', prop: 'ph' }, //批号 试剂,供试品才有
  216. { label: 'template.common.concentration', prop: 'ndz' }, //浓度
  217. { label: 'template.common.source', prop: 'ly' }, //来源
  218. { label: 'template.common.reagentExpireDate', prop: 'sxrq' } //失效日期
  219. ],
  220. gspColumns: [
  221. { label: 'template.common.wzName', prop: 'mc' }, //名称
  222. { label: 'template.common.wzCode', prop: 'bh' }, //编号
  223. { label: 'template.common.reagentNo', prop: 'ph' }, //批号 试剂,供试品才有
  224. { label: 'template.common.wzSource', prop: 'ly' }, //来源
  225. { label: 'template.common.wzConcentration', prop: 'ndz' }, //浓度
  226. { label: 'template.common.wzExpireDate', prop: 'sxrq' } //失效日期
  227. ],
  228. gyzjColumns: [
  229. { label: 'template.common.wzName', prop: 'mc' }, //名称
  230. { label: 'template.common.wzCode', prop: 'bh' }, //编号
  231. { label: 'template.common.wzSource', prop: 'ly' }, //来源
  232. { label: 'template.common.wzConcentration', prop: 'ndz' }, //浓度
  233. { label: 'template.common.wzExpireDate', prop: 'sxrq' } //失效日期
  234. ],
  235. mjyColumns: [
  236. { label: 'template.common.wzName', prop: 'mc' }, //名称
  237. { label: 'template.common.wzCode', prop: 'bh' }, //编号
  238. { label: 'template.common.wzSource', prop: 'ly' }, //来源
  239. { label: 'template.common.wzConcentration', prop: 'ndz' }, //浓度
  240. { label: 'template.common.wzExpireDate', prop: 'sxrq' } //失效日期
  241. ],
  242. //弃用
  243. sysjColumns: [
  244. { label: 'template.common.reagentName', prop: 'mc' }, //名称
  245. { label: 'template.common.reagentCode', prop: 'bh' }, //编号
  246. { label: 'template.common.reagentNo', prop: 'ph' }, //批号 试剂,供试品才有
  247. { label: 'template.common.concentration', prop: 'ndz' }, //浓度
  248. { label: 'template.common.source', prop: 'ly' }, //来源
  249. { label: 'template.common.reagentExpireDate', prop: 'sxrq' } //失效日期
  250. ],
  251. //弃用
  252. sywzColumns: [
  253. { label: 'template.common.wzName', prop: 'mc' }, //名称
  254. { label: 'template.common.wzCode', prop: 'bh' }, //编号
  255. { label: 'template.common.wzSource', prop: 'ly' }, //来源
  256. { label: 'template.common.wzConcentration', prop: 'ndz' }, //浓度
  257. { label: 'template.common.wzExpireDate', prop: 'sxrq' } //失效日期
  258. ],
  259. yqColumns: [
  260. { label: 'template.common.instrumentName', prop: 'mc' }, //仪器名称
  261. { label: 'template.common.instrumentModel', prop: 'xh' }, //仪器型号
  262. { label: 'template.common.instrumentCode', prop: 'bh' }, //仪器编号
  263. { label: 'template.common.nextTestDate', prop: 'jzrq' } //下次测试/校准/检定日期
  264. ]
  265. }
  266. },
  267. mounted() {},
  268. unmounted() {
  269. this.setTemplateData({})
  270. },
  271. methods: {
  272. getuuid() {
  273. return getuuid()
  274. },
  275. // 只是更新已填写的表单数据,不触发校验
  276. justUpdateFilledFormData() {
  277. const params = {
  278. type: 'fieldChanged',
  279. newRecord: null,
  280. resourceList: null
  281. }
  282. EventBus.$emit('onModifyRecord', params)
  283. },
  284. //试剂弹窗确认前
  285. onBeforeReagentSubmit(data) {
  286. const { selectData, callback, key, formFields } = data
  287. const { subTargetStartSolution = "", targetStartSolution = "" } = formFields
  288. const { nd } = selectData.row
  289. const sjndArr = nd.split('/')
  290. const ytndArr = targetStartSolution.split('/')
  291. //判断选择的浓度单位和预制的浓度单位是否一致
  292. if (
  293. key === 'subStartSolution' &&
  294. !isCommonUnit(selectData.row.nddw, [subTargetStartSolution])
  295. ) {
  296. //选择起始源溶液需要同步更新table的变更记录。
  297. callback.prevent('浓度单位与预制不符,请重新选择或申请废止并重新预制。')
  298. } else if (nd === 'NA') {
  299. callback.prevent('当前实际浓度为NA,请重新选择')
  300. } else if (ytndArr.length !== sjndArr.length) {
  301. callback.prevent('起始溶液浓度和目标溶液浓度格式不一致,请重新选择')
  302. }
  303. },
  304. getFormDataByTemplateData() {
  305. let o = {}
  306. const { bdnr } = this.templateData
  307. if (bdnr) {
  308. o = JSON.parse(bdnr)
  309. }
  310. return o
  311. },
  312. //开始配制
  313. //postData: {bh: '123456'}
  314. async startConfigRequest(postData) {
  315. const res = await sj_startConfiguration(postData)
  316. if (res.code === 200) {
  317. this.$message.success('开始配制成功')
  318. } else {
  319. this.$message.error('开始配制失败')
  320. }
  321. },
  322. //完成配制
  323. async configCompleteRequest(postData) {
  324. const res = await sj_configurationCompleted(postData)
  325. if (res.code === 200) {
  326. this.$message.success('完成配制成功')
  327. } else {
  328. this.$message.error('完成配制失败')
  329. }
  330. },
  331. //分装
  332. async subPackageRequest(postData) {
  333. const res = await sj_subpackage(postData)
  334. if (res.code === 200) {
  335. this.$message.success('分装成功')
  336. } else {
  337. this.$message.error('分装失败')
  338. }
  339. },
  340. //获取打印配制
  341. getBasePrintConfig(data = {}) {
  342. const { printCode, type, row = {} } = data
  343. const { stepStorageCondition, startDate, expireDate } = this.formData
  344. const { nickName, name } = this.$store.getters
  345. const lang = this.$i18n.locale
  346. const printConfig = {
  347. 品名: '暂时还不知道品名是哪个字段',
  348. 存储条件: stepStorageCondition,
  349. 配制日期: moment(startDate).format('YYYY-MM-DD'),
  350. 有效期至: moment(expireDate).format('YYYY-MM-DD HH:mm'),
  351. 配制者: lang === 'zh_CN' ? nickName : name,
  352. //type==="subPackage"从分装打印过来的,
  353. //type==="row" 从列表上点过来的
  354. 编号:
  355. type === 'subPackage'
  356. ? printCode
  357. : row.targetSolutionCode + row.subTargetSolutionCode
  358. }
  359. return printConfig
  360. },
  361. async getLatestSn(count = 1) {
  362. const res = await getLatestSn({ count })
  363. if (res.code === 200) {
  364. return res.data
  365. }
  366. return []
  367. },
  368. //获取最新的多个编号
  369. async getLatestSnArr(params) {
  370. const res = await getLatestSnArr(params)
  371. if (res.code === 200) {
  372. return res.data
  373. }
  374. return []
  375. },
  376. getResource() {
  377. return this.resourceTmp
  378. },
  379. getYqResource() {
  380. return this.yqResourceTmp
  381. },
  382. getJcbList() {
  383. return this.jcbListTmp
  384. },
  385. getXbxj() {
  386. return this.xbxjTmp
  387. },
  388. //根据ref数组获取直接formData
  389. getFilledFormDataByRefs(refArr = []) {
  390. let result = {}
  391. refArr.map((ref) => {
  392. const refData = this.$refs[ref]?.getFilledFormData() || {}
  393. for (const [key, value] of Object.entries(refData)) {
  394. let index = 0
  395. // 如果当前键是可能重复的字段,且结果对象中已经存在该键,则添加索引后缀
  396. if (
  397. (key === 'headerSelectFields' || key === 'stepTableFormData') &&
  398. result.hasOwnProperty(key)
  399. ) {
  400. // 为重复字段生成带索引的键名,从1开始(因为第一个组件不需要后缀)
  401. const newKey = `${key}_${++index}`
  402. result[newKey] = value
  403. } else {
  404. // 正常合并其他字段
  405. result[key] = value
  406. }
  407. }
  408. })
  409. return result
  410. },
  411. //统一校验form表单是否填写
  412. async validFormFields(refArr = []) {
  413. let result = {}
  414. const refs = refArr.map((ref) => {
  415. let refData = {}
  416. if (this.$refs[ref]) {
  417. if (this.$refs[ref][0]) {
  418. refData = this.$refs[ref][0]?.getFormData() || {}
  419. } else {
  420. refData = this.$refs[ref]?.getFormData() || {}
  421. }
  422. }
  423. return refData
  424. })
  425. const validFormData = await Promise.all(refs).catch((err) => {
  426. // this.$message.error(err);
  427. if (err && err.errorType && err.errorType === 'step') {
  428. this.$message.error('请添加步骤')
  429. return
  430. }
  431. this.$message.error('表单内容未填完,请填写后再提交')
  432. })
  433. if (validFormData) {
  434. validFormData.forEach((item) => {
  435. for (const [key, value] of Object.entries(item)) {
  436. let index = 0
  437. // 如果当前键是可能重复的字段,且结果对象中已经存在该键,则添加索引后缀
  438. if (
  439. (key === 'headerSelectFields' || key === 'stepTableFormData') &&
  440. result.hasOwnProperty(key)
  441. ) {
  442. // 为重复字段生成带索引的键名,从1开始(因为第一个组件不需要后缀)
  443. const newKey = `${key}_${++index}`
  444. result[newKey] = value
  445. } else {
  446. // 正常合并其他字段
  447. result[key] = value
  448. }
  449. }
  450. })
  451. return result
  452. }
  453. return false
  454. },
  455. //试验配制条件options
  456. getDictOptions(dictType) {
  457. return this.dict.type[dictType] || []
  458. },
  459. setTemplateData(data) {
  460. this.$store.commit('template/SET_TEMPLATE_DATA', data)
  461. },
  462. //统一处理删除行
  463. deleteRow(index, ref) {
  464. if (ref) {
  465. this.$refs[ref].deleteRow(index)
  466. return
  467. }
  468. this.$refs.stepTableRef.deleteRow(index)
  469. },
  470. //统一处理浓度校验异常
  471. onCommonVerifyNdException(formFields, data) {
  472. const { callback, rowIndex, key, dataSource } = data
  473. const keys = ['actStartSolutionVolume', 'actDiluentVolume']
  474. if (keys.includes(key)) {
  475. const { targetAcSolution } = formFields
  476. if (rowIndex === 0) {
  477. //第一行的浓度取选择的溶液,
  478. if (isValueEmpty(targetAcSolution)) {
  479. callback.prevent('请先选择起始源溶液')
  480. }
  481. } else {
  482. //非第一行的浓度取上一行的浓度
  483. const prevItem = dataSource[rowIndex - 1]
  484. const prevConcentration = prevItem.actSolutionConcentration
  485. if (!prevConcentration) {
  486. callback.prevent('请先计算上一行的实际目标溶液浓度')
  487. }
  488. }
  489. }
  490. },
  491. //统一处理blur事件,因为有效周期和过期日期是相关的,所以需要在有效周期失焦时更新过期日期
  492. onHandleBlur(fields) {
  493. const {
  494. key,
  495. codeSTD,
  496. targetStartSolution,
  497. subTargetStartSolution //预设起始源溶液浓度单位
  498. } = fields
  499. const { startDate } = this.formData
  500. if (key === 'codeSTD') {
  501. //起始编号STD失焦时,更新stepDataSource
  502. const arr = Array.from({ length: codeSTD }, (item, index) => ({
  503. actSolutionVolumePrecision: 3, //小数点精度默认为3
  504. actSolutionConcentrationPrecision: 3, //小数点精度默认为3
  505. targetDiluentVolumePrecision: 3, //小数点精度默认为3
  506. targetStartSolutionVolumePrecision: 3, //小数点精度默认为3
  507. targetSolutionCode: `CA-WS-STD${Number(codeSTD) - index}`,
  508. id: getuuid(),
  509. rowIndex: index
  510. }))
  511. this.$refs.stepTableRef.updateDataSource(arr)
  512. } else if (
  513. key === 'targetStartSolution' ||
  514. key === 'subTargetStartSolution'
  515. ) {
  516. //起始溶液体积失焦时,更新目标溶液预计浓度
  517. const arr = this.$refs.stepTableRef?.getDataSource()
  518. const { headerSelectFields, stepTableFormData = [] } =
  519. this.$refs.stepTableRef?.getFilledFormData()
  520. const params = {
  521. subTargetStartSolution,
  522. headerSelectFields,
  523. dataSource: stepTableFormData
  524. }
  525. arr.forEach((item, rowIndex) => {
  526. this.updateTargetStartSolutionVolume(
  527. item,
  528. targetStartSolution,
  529. params
  530. )
  531. })
  532. }
  533. },
  534. //批量更新目标起始源溶液体积
  535. batchUpdateTargetStartSolutionVolume(arr, startConcentration, params) {
  536. params.dataSource = arr
  537. arr.forEach((item, rowIndex) => {
  538. this.updateTargetStartSolutionVolume(item, startConcentration, params)
  539. })
  540. },
  541. //统一处理table失焦事件
  542. onHandleTableBlur(params) {
  543. const { rowIndex, colKey, value, item, dataSource, headerSelectFields } =
  544. params
  545. if (
  546. colKey === 'targetSolutionVolume' ||
  547. colKey === 'targetSolutionConcentration' ||
  548. colKey === 'targetStartSolutionVolumePrecision' ||
  549. colKey === 'targetDiluentVolumePrecision'
  550. ) {
  551. const volume = this.$refs.stepFormPackageRef?.getFormDataByKey(
  552. 'targetStartSolution'
  553. )
  554. const subTargetStartSolution =
  555. this.$refs.stepFormPackageRef?.getFormDataByKey(
  556. 'subTargetStartSolution'
  557. )
  558. const params = {
  559. subTargetStartSolution: subTargetStartSolution,
  560. headerSelectFields,
  561. dataSource
  562. }
  563. if (isValueEmpty(volume)) {
  564. this.$message.error('请先选择预设起始源溶液浓度')
  565. } else {
  566. this.updateTargetStartSolutionVolume(item, volume, params)
  567. }
  568. } else if (
  569. colKey === 'actStartSolutionVolume' ||
  570. colKey === 'actDiluentVolume'
  571. ) {
  572. //实际起始溶液体积和实际目标溶液体积
  573. const { targetAcSolution, subTargetAcSolutionUnit } =
  574. this.$refs.stepFormPackageRef?.getFilledFormData() //获取实际起始溶液浓度
  575. const { headerSelectFields } =
  576. this.$refs.stepTableRef?.getFilledFormData()
  577. const p = {
  578. targetStartSolutionUnit: subTargetAcSolutionUnit,
  579. headerSelectFields
  580. }
  581. let initNd = 0
  582. if (rowIndex === 0) {
  583. initNd = targetAcSolution
  584. } else {
  585. initNd = dataSource[rowIndex - 1].actSolutionConcentration
  586. }
  587. if (isValueEmpty(initNd)) {
  588. console.log('initNd', initNd)
  589. this.$message.error('请先选择起始源溶液')
  590. return
  591. } else {
  592. const volResult = this.updateSjmbrynd(item, initNd, p)
  593. if (!volResult) {
  594. return
  595. }
  596. this.$refs.stepTableRef?.updateDataSourceByRowIndex(
  597. rowIndex,
  598. {
  599. actSolutionVolume: volResult.actVol,
  600. actSolutionConcentration: volResult.actNd
  601. },
  602. 'blur'
  603. )
  604. }
  605. }
  606. },
  607. //计算目标溶液浓度
  608. calcNd(item, targetAcSolution, params) {
  609. console.log(item, params, 'ppp')
  610. // debugger
  611. //targetStartSolutionUnit(实际起始源溶液浓度单位)
  612. const { targetStartSolutionUnit, headerSelectFields } = params
  613. const {
  614. actStartSolutionVolumeUnit,
  615. actSolutionVolumeUnit,
  616. actDiluentVolumeUnit,
  617. actSolutionConcentrationUnit
  618. } = headerSelectFields
  619. let initUnit = targetStartSolutionUnit
  620. if (item.rowIndex > 0) {
  621. initUnit = actSolutionConcentrationUnit
  622. }
  623. //actStartSolutionVolumeUnit(实际起始源溶液体积单位)actSolutionVolumeUnit(实际目标溶液体积单位)
  624. //actDiluentVolumeUnit(实际稀释液体积单位)actSolutionConcentrationUnit(实际目标溶液浓度单位)
  625. //实际源溶液浓度÷(实际终体积÷源溶液加入体积);
  626. const precision = item.actSolutionConcentrationPrecision
  627. const volPrecision = item.actSolutionVolumePrecision
  628. //实际稀释液体积
  629. const actDiluentVolume = item.actDiluentVolume
  630. //实际起始源溶液体积
  631. const actStartSolutionVolume = item.actStartSolutionVolume
  632. if (
  633. isValueEmpty(actStartSolutionVolume) ||
  634. isValueEmpty(actDiluentVolume) ||
  635. isValueEmpty(initUnit)
  636. ) {
  637. return false
  638. }
  639. const converActDiluentVolume = volumeConverter.convert(
  640. actDiluentVolume + actDiluentVolumeUnit,
  641. actSolutionVolumeUnit
  642. )
  643. const converActStartSolutionVolume = volumeConverter.convert(
  644. actStartSolutionVolume + actStartSolutionVolumeUnit,
  645. actSolutionVolumeUnit
  646. )
  647. //实际源溶液加入体积+实际稀释液加入体积
  648. const actVol = (
  649. Number(converActDiluentVolume) + Number(converActStartSolutionVolume)
  650. ).toFixed(volPrecision)
  651. const targetStartVolUnit = actSolutionConcentrationUnit.split('/')[1] //先按照预设目标溶液浓度的单位标准
  652. const converActVol = volumeConverter.convert(
  653. actVol + actSolutionVolumeUnit,
  654. targetStartVolUnit
  655. )
  656. const converActDiluentVolume1 = volumeConverter.convert(
  657. actStartSolutionVolume + actStartSolutionVolumeUnit,
  658. targetStartVolUnit
  659. )
  660. const converArr = (targetAcSolution + '').split('/')
  661. converArr.map((item) => {
  662. return convertConcentration.convert(
  663. item + initUnit,
  664. actSolutionConcentrationUnit
  665. )
  666. })
  667. // const converTargetAcSolution = convertConcentration.convert(targetAcSolution + initUnit, actSolutionConcentrationUnit)
  668. // 实际目标溶液浓度 = 实际源溶液浓度÷(实际终体积÷源溶液加入体积);
  669. // const actNd = (
  670. // parseFloat(converTargetAcSolution) / (
  671. // parseFloat(converActVol) / parseFloat(converActDiluentVolume1)
  672. // )
  673. // ).toFixed(precision)
  674. const actNdArr = converArr.map((item) => {
  675. return parseFloat(
  676. (item / (converActVol / converActDiluentVolume1)).toFixed(precision)
  677. )
  678. })
  679. // const nd = actNd === 'Infinity' ? 0 : Number(actNd)
  680. console.log(
  681. actNdArr,
  682. targetAcSolution,
  683. actStartSolutionVolume,
  684. actVol,
  685. 'actNd'
  686. )
  687. // item.actSolutionConcentration = actNd === 'Infinity' ? 0 : actNd
  688. return { actVol: Number(actVol), actNd: actNdArr.join('/') }
  689. },
  690. //计算并更新实际目标溶液浓度 先计算实际目标溶液体积再计算实际目标溶液浓度
  691. updateSjmbrynd(item, targetAcSolution, params) {
  692. return this.calcNd(item, targetAcSolution, params)
  693. },
  694. //更新起始溶液体积时,计算预设起始溶液体积和预设稀释液体积
  695. updateTargetStartSolutionVolume(item, volume, unitParams) {
  696. const { rowIndex } = item
  697. const {
  698. subTargetStartSolution,
  699. headerSelectFields,
  700. dataSource = []
  701. } = unitParams
  702. const {
  703. targetSolutionConcentrationUnit,
  704. targetSolutionVolumeUnit,
  705. targetStartSolutionVolumeUnit,
  706. targetDiluentVolumeUnit
  707. } = headerSelectFields
  708. let initNd = volume,
  709. unit = subTargetStartSolution
  710. //平行配制不会传dataSource;
  711. if (rowIndex > 0 && dataSource.length > 0) {
  712. initNd = dataSource[rowIndex - 1].targetSolutionConcentration
  713. unit = targetSolutionConcentrationUnit
  714. }
  715. const precision = item.targetStartSolutionVolumePrecision || 0
  716. const precision1 = item.targetDiluentVolumePrecision || 0
  717. const concentration = item.targetSolutionConcentration
  718. const targetVolume = item.targetSolutionVolume
  719. if (
  720. isValueEmpty(concentration) ||
  721. isValueEmpty(targetVolume) ||
  722. isValueEmpty(unit) ||
  723. isValueEmpty(targetSolutionConcentrationUnit) ||
  724. isValueEmpty(targetSolutionVolumeUnit) ||
  725. isValueEmpty(targetStartSolutionVolumeUnit) ||
  726. isValueEmpty(targetDiluentVolumeUnit)
  727. ) {
  728. return
  729. }
  730. const targetStartVolUnit = targetSolutionConcentrationUnit.split('/')[1] //先按照预设目标溶液浓度的单位标准
  731. //将预设目标溶液体积转换为和预设目标溶液浓度单位的分母一样的单位再计算;如:预设目标溶液浓度单位为mg/mL,预设目标溶液体积单位为uL,则将预设目标溶液体积转换为mL
  732. const convertTargetVol = volumeConverter.convert(
  733. targetVolume + targetSolutionVolumeUnit,
  734. targetStartVolUnit
  735. )
  736. const convertTargetVol1 = volumeConverter.convert(
  737. targetVolume + targetSolutionVolumeUnit,
  738. targetStartSolutionVolumeUnit
  739. )
  740. const initNdArr = (initNd + '').split('/')
  741. const transNdArr = initNdArr.map((con) => {
  742. return convertConcentration.convert(
  743. con + unit,
  744. targetSolutionConcentrationUnit
  745. )
  746. })
  747. const mbyjndArr = (concentration + '').split('/') //目标预计浓度
  748. if (mbyjndArr.length !== initNdArr.length) {
  749. this.$message.error('起始溶液浓度和目标溶液浓度格式不一致,请重新输入')
  750. return
  751. }
  752. //预设体积
  753. const ystjArr = mbyjndArr.map((con, index) => {
  754. const ystj = Number(
  755. (con * convertTargetVol) / (transNdArr[index] || transNdArr[0])
  756. )
  757. const convertYsVol = volumeConverter.convert(
  758. ystj + targetStartVolUnit,
  759. targetStartSolutionVolumeUnit
  760. )
  761. const xstj = convertTargetVol1 - convertYsVol //稀释体积
  762. return { qsrytj: convertYsVol, xstj }
  763. })
  764. if (ystjArr.length > 0) {
  765. const firstItem = ystjArr[0] //只取第一个计算
  766. item.targetStartSolutionVolume = Number(
  767. firstItem.qsrytj.toFixed(precision)
  768. )
  769. item.targetDiluentVolume = Number(
  770. volumeConverter
  771. .convert(
  772. firstItem.xstj + targetStartSolutionVolumeUnit,
  773. targetDiluentVolumeUnit
  774. )
  775. .toFixed(precision1)
  776. )
  777. }
  778. },
  779. // 导出excel模板
  780. exportExcel(headerArray, title = '导出模板') {
  781. this.$modal.loading()
  782. const ws = XLSX.utils.aoa_to_sheet([headerArray])
  783. const colWidths = headerArray.map((cell) => getStringWidth(cell) + 2)
  784. ws['!cols'] = colWidths.map((width) => ({ wch: width }))
  785. const wb = XLSX.utils.book_new()
  786. XLSX.utils.book_append_sheet(wb, ws, 'Sheet1')
  787. XLSX.writeFile(wb, `${title}.xlsx`)
  788. this.$modal.closeLoading()
  789. }
  790. }
  791. }