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

808 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. const { effectivePeriod, effectivePeriodUnit, expireDate } =
  167. this.formData
  168. //实际填报的时候,如果有了开始时间,并且有有效周期,但是没有失效日,就计算失效日为开始时间+有效周期
  169. if (
  170. startDate &&
  171. this.fillType === 'actFill' &&
  172. effectivePeriod &&
  173. effectivePeriodUnit &&
  174. !expireDate
  175. ) {
  176. let end
  177. if (effectivePeriod === 'NA' || effectivePeriodUnit === 'NA') {
  178. end = 'NA'
  179. } else {
  180. const start = moment(startDate)
  181. const unit = effectivePeriodUnit === '天' ? 'days' : 'hours'
  182. end = start
  183. .add(Number(effectivePeriod), unit)
  184. .format('YYYY-MM-DD HH:mm:ss')
  185. }
  186. this.formData = { ...this.formData, expireDate: end }
  187. }
  188. this.setTemplateData(v)
  189. }
  190. }
  191. }
  192. },
  193. data() {
  194. return {
  195. formData: {},
  196. templateDetail: {},
  197. product: null, //产物:1:试剂;3:给药制剂;5:麻精药
  198. resource: [], //试验试剂信息--弃用
  199. resourceWz: [], //物资信息--弃用
  200. resourceSj: [], //试验试剂信息
  201. resourceGsp: [], //供试品信息
  202. resourceGyzj: [], //给药制剂信息
  203. resourceMjy: [], //麻精药信息
  204. yqResource: [], //仪器信息
  205. jcbList: [], //检测板信息
  206. xbxj: [], //细胞细菌信息
  207. resourceTmp: [], //试验试剂信息提交用
  208. yqResourceTmp: [], //仪器信息提交用
  209. jcbListTmp: [], //检测板信息提交用
  210. xbxjTmp: [], //细胞细菌信息提交用
  211. sjColumns: [
  212. { label: 'template.common.reagentName', prop: 'mc' }, //名称
  213. { label: 'template.common.reagentCode', prop: 'bh' }, //编号
  214. { label: 'template.common.reagentNo', prop: 'ph' }, //批号 试剂,供试品才有
  215. { label: 'template.common.concentration', prop: 'ndz' }, //浓度
  216. { label: 'template.common.source', prop: 'ly' }, //来源
  217. { label: 'template.common.reagentExpireDate', prop: 'sxrq' } //失效日期
  218. ],
  219. gspColumns: [
  220. { label: 'template.common.wzName', prop: 'mc' }, //名称
  221. { label: 'template.common.wzCode', prop: 'bh' }, //编号
  222. { label: 'template.common.reagentNo', prop: 'ph' }, //批号 试剂,供试品才有
  223. { label: 'template.common.wzSource', prop: 'ly' }, //来源
  224. { label: 'template.common.wzConcentration', prop: 'ndz' }, //浓度
  225. { label: 'template.common.wzExpireDate', prop: 'sxrq' } //失效日期
  226. ],
  227. gyzjColumns: [
  228. { label: 'template.common.wzName', prop: 'mc' }, //名称
  229. { label: 'template.common.wzCode', prop: 'bh' }, //编号
  230. { label: 'template.common.wzSource', prop: 'ly' }, //来源
  231. { label: 'template.common.wzConcentration', prop: 'ndz' }, //浓度
  232. { label: 'template.common.wzExpireDate', prop: 'sxrq' } //失效日期
  233. ],
  234. mjyColumns: [
  235. { label: 'template.common.wzName', prop: 'mc' }, //名称
  236. { label: 'template.common.wzCode', prop: 'bh' }, //编号
  237. { label: 'template.common.wzSource', prop: 'ly' }, //来源
  238. { label: 'template.common.wzConcentration', prop: 'ndz' }, //浓度
  239. { label: 'template.common.wzExpireDate', prop: 'sxrq' } //失效日期
  240. ],
  241. //弃用
  242. sysjColumns: [
  243. { label: 'template.common.reagentName', prop: 'mc' }, //名称
  244. { label: 'template.common.reagentCode', prop: 'bh' }, //编号
  245. { label: 'template.common.reagentNo', prop: 'ph' }, //批号 试剂,供试品才有
  246. { label: 'template.common.concentration', prop: 'ndz' }, //浓度
  247. { label: 'template.common.source', prop: 'ly' }, //来源
  248. { label: 'template.common.reagentExpireDate', prop: 'sxrq' } //失效日期
  249. ],
  250. //弃用
  251. sywzColumns: [
  252. { label: 'template.common.wzName', prop: 'mc' }, //名称
  253. { label: 'template.common.wzCode', prop: 'bh' }, //编号
  254. { label: 'template.common.wzSource', prop: 'ly' }, //来源
  255. { label: 'template.common.wzConcentration', prop: 'ndz' }, //浓度
  256. { label: 'template.common.wzExpireDate', prop: 'sxrq' } //失效日期
  257. ],
  258. yqColumns: [
  259. { label: 'template.common.instrumentName', prop: 'mc' }, //仪器名称
  260. { label: 'template.common.instrumentModel', prop: 'xh' }, //仪器型号
  261. { label: 'template.common.instrumentCode', prop: 'bh' }, //仪器编号
  262. { label: 'template.common.nextTestDate', prop: 'jzrq' } //下次测试/校准/检定日期
  263. ]
  264. }
  265. },
  266. mounted() {},
  267. unmounted() {
  268. this.setTemplateData({})
  269. },
  270. methods: {
  271. getuuid() {
  272. return getuuid()
  273. },
  274. // 只是更新已填写的表单数据,不触发校验
  275. justUpdateFilledFormData() {
  276. const params = {
  277. type: 'fieldChanged',
  278. newRecord: null,
  279. resourceList: null
  280. }
  281. EventBus.$emit('onModifyRecord', params)
  282. },
  283. //试剂弹窗确认前
  284. onBeforeReagentSubmit(data) {
  285. const { selectData, callback, key, formFields } = data
  286. const { subTargetStartSolution = "", targetStartSolution = "" } = formFields
  287. const { nd } = selectData.row
  288. const sjndArr = nd.split('/')
  289. const ytndArr = targetStartSolution.split('/')
  290. //判断选择的浓度单位和预制的浓度单位是否一致
  291. if (
  292. key === 'subStartSolution' &&
  293. !isCommonUnit(selectData.row.nddw, [subTargetStartSolution])
  294. ) {
  295. //选择起始源溶液需要同步更新table的变更记录。
  296. callback.prevent('浓度单位与预制不符,请重新选择或申请废止并重新预制。')
  297. } else if (nd === 'NA') {
  298. callback.prevent('当前实际浓度为NA,请重新选择')
  299. } else if (ytndArr.length !== sjndArr.length) {
  300. callback.prevent('起始溶液浓度和目标溶液浓度格式不一致,请重新选择')
  301. }
  302. },
  303. getFormDataByTemplateData() {
  304. let o = {}
  305. const { bdnr } = this.templateData
  306. if (bdnr) {
  307. o = JSON.parse(bdnr)
  308. }
  309. return o
  310. },
  311. //开始配制
  312. //postData: {bh: '123456'}
  313. async startConfigRequest(postData) {
  314. const res = await sj_startConfiguration(postData)
  315. if (res.code === 200) {
  316. this.$message.success('开始配制成功')
  317. } else {
  318. this.$message.error('开始配制失败')
  319. }
  320. },
  321. //完成配制
  322. async configCompleteRequest(postData) {
  323. const res = await sj_configurationCompleted(postData)
  324. if (res.code === 200) {
  325. this.$message.success('完成配制成功')
  326. } else {
  327. this.$message.error('完成配制失败')
  328. }
  329. },
  330. //分装
  331. async subPackageRequest(postData) {
  332. const res = await sj_subpackage(postData)
  333. if (res.code === 200) {
  334. this.$message.success('分装成功')
  335. } else {
  336. this.$message.error('分装失败')
  337. }
  338. },
  339. //获取打印配制
  340. getBasePrintConfig(data = {}) {
  341. const { printCode, type, row = {} } = data
  342. const { stepStorageCondition, startDate, expireDate } = this.formData
  343. const { nickName, name } = this.$store.getters
  344. const lang = this.$i18n.locale
  345. const printConfig = {
  346. 品名: '暂时还不知道品名是哪个字段',
  347. 存储条件: stepStorageCondition,
  348. 配制日期: moment(startDate).format('YYYY-MM-DD'),
  349. 有效期至: moment(expireDate).format('YYYY-MM-DD HH:mm'),
  350. 配制者: lang === 'zh_CN' ? nickName : name,
  351. //type==="subPackage"从分装打印过来的,
  352. //type==="row" 从列表上点过来的
  353. 编号:
  354. type === 'subPackage'
  355. ? printCode
  356. : row.targetSolutionCode + row.subTargetSolutionCode
  357. }
  358. return printConfig
  359. },
  360. async getLatestSn(count = 1) {
  361. const res = await getLatestSn({ count })
  362. if (res.code === 200) {
  363. return res.data
  364. }
  365. return []
  366. },
  367. //获取最新的多个编号
  368. async getLatestSnArr(params) {
  369. const res = await getLatestSnArr(params)
  370. if (res.code === 200) {
  371. return res.data
  372. }
  373. return []
  374. },
  375. getResource() {
  376. return this.resourceTmp
  377. },
  378. getYqResource() {
  379. return this.yqResourceTmp
  380. },
  381. getJcbList() {
  382. return this.jcbListTmp
  383. },
  384. getXbxj() {
  385. return this.xbxjTmp
  386. },
  387. //根据ref数组获取直接formData
  388. getFilledFormDataByRefs(refArr = []) {
  389. let result = {}
  390. refArr.map((ref) => {
  391. const refData = this.$refs[ref]?.getFilledFormData() || {}
  392. for (const [key, value] of Object.entries(refData)) {
  393. let index = 0
  394. // 如果当前键是可能重复的字段,且结果对象中已经存在该键,则添加索引后缀
  395. if (
  396. (key === 'headerSelectFields' || key === 'stepTableFormData') &&
  397. result.hasOwnProperty(key)
  398. ) {
  399. // 为重复字段生成带索引的键名,从1开始(因为第一个组件不需要后缀)
  400. const newKey = `${key}_${++index}`
  401. result[newKey] = value
  402. } else {
  403. // 正常合并其他字段
  404. result[key] = value
  405. }
  406. }
  407. })
  408. return result
  409. },
  410. //统一校验form表单是否填写
  411. async validFormFields(refArr = []) {
  412. let result = {}
  413. const refs = refArr.map((ref) => {
  414. let refData = {}
  415. if (this.$refs[ref]) {
  416. if (this.$refs[ref][0]) {
  417. refData = this.$refs[ref][0]?.getFormData() || {}
  418. } else {
  419. refData = this.$refs[ref]?.getFormData() || {}
  420. }
  421. }
  422. return refData
  423. })
  424. const validFormData = await Promise.all(refs).catch((err) => {
  425. // this.$message.error(err);
  426. if (err && err.errorType && err.errorType === 'step') {
  427. this.$message.error('请添加步骤')
  428. return
  429. }
  430. this.$message.error('表单内容未填完,请填写后再提交')
  431. })
  432. if (validFormData) {
  433. validFormData.forEach((item) => {
  434. for (const [key, value] of Object.entries(item)) {
  435. let index = 0
  436. // 如果当前键是可能重复的字段,且结果对象中已经存在该键,则添加索引后缀
  437. if (
  438. (key === 'headerSelectFields' || key === 'stepTableFormData') &&
  439. result.hasOwnProperty(key)
  440. ) {
  441. // 为重复字段生成带索引的键名,从1开始(因为第一个组件不需要后缀)
  442. const newKey = `${key}_${++index}`
  443. result[newKey] = value
  444. } else {
  445. // 正常合并其他字段
  446. result[key] = value
  447. }
  448. }
  449. })
  450. return result
  451. }
  452. return false
  453. },
  454. //试验配制条件options
  455. getDictOptions(dictType) {
  456. return this.dict.type[dictType] || []
  457. },
  458. setTemplateData(data) {
  459. this.$store.commit('template/SET_TEMPLATE_DATA', data)
  460. },
  461. //统一处理删除行
  462. deleteRow(index, ref) {
  463. if (ref) {
  464. this.$refs[ref].deleteRow(index)
  465. return
  466. }
  467. this.$refs.stepTableRef.deleteRow(index)
  468. },
  469. //统一处理浓度校验异常
  470. onCommonVerifyNdException(formFields, data) {
  471. const { callback, rowIndex, key, dataSource } = data
  472. const keys = ['actStartSolutionVolume', 'actDiluentVolume']
  473. if (keys.includes(key)) {
  474. const { targetAcSolution } = formFields
  475. if (rowIndex === 0) {
  476. //第一行的浓度取选择的溶液,
  477. if (isValueEmpty(targetAcSolution)) {
  478. callback.prevent('请先选择起始源溶液')
  479. }
  480. } else {
  481. //非第一行的浓度取上一行的浓度
  482. const prevItem = dataSource[rowIndex - 1]
  483. const prevConcentration = prevItem.actSolutionConcentration
  484. if (!prevConcentration) {
  485. callback.prevent('请先计算上一行的实际目标溶液浓度')
  486. }
  487. }
  488. }
  489. },
  490. //统一处理blur事件,因为有效周期和过期日期是相关的,所以需要在有效周期失焦时更新过期日期
  491. onHandleBlur(fields) {
  492. const {
  493. key,
  494. codeSTD,
  495. targetStartSolution,
  496. subTargetStartSolution //预设起始源溶液浓度单位
  497. } = fields
  498. const { startDate } = this.formData
  499. if (key === 'codeSTD') {
  500. //起始编号STD失焦时,更新stepDataSource
  501. const arr = Array.from({ length: codeSTD }, (item, index) => ({
  502. actSolutionVolumePrecision: 3, //小数点精度默认为3
  503. actSolutionConcentrationPrecision: 3, //小数点精度默认为3
  504. targetDiluentVolumePrecision: 3, //小数点精度默认为3
  505. targetStartSolutionVolumePrecision: 3, //小数点精度默认为3
  506. targetSolutionCode: `CA-WS-STD${Number(codeSTD) - index}`,
  507. id: getuuid(),
  508. rowIndex: index
  509. }))
  510. this.$refs.stepTableRef.updateDataSource(arr)
  511. } else if (
  512. key === 'targetStartSolution' ||
  513. key === 'subTargetStartSolution'
  514. ) {
  515. //起始溶液体积失焦时,更新目标溶液预计浓度
  516. const arr = this.$refs.stepTableRef?.getDataSource()
  517. const { headerSelectFields, stepTableFormData = [] } =
  518. this.$refs.stepTableRef?.getFilledFormData()
  519. const params = {
  520. subTargetStartSolution,
  521. headerSelectFields,
  522. dataSource: stepTableFormData
  523. }
  524. arr.forEach((item, rowIndex) => {
  525. this.updateTargetStartSolutionVolume(
  526. item,
  527. targetStartSolution,
  528. params
  529. )
  530. })
  531. }
  532. },
  533. //批量更新目标起始源溶液体积
  534. batchUpdateTargetStartSolutionVolume(arr, startConcentration, params) {
  535. params.dataSource = arr
  536. arr.forEach((item, rowIndex) => {
  537. this.updateTargetStartSolutionVolume(item, startConcentration, params)
  538. })
  539. },
  540. //统一处理table失焦事件
  541. onHandleTableBlur(params) {
  542. const { rowIndex, colKey, value, item, dataSource, headerSelectFields } =
  543. params
  544. if (
  545. colKey === 'targetSolutionVolume' ||
  546. colKey === 'targetSolutionConcentration' ||
  547. colKey === 'targetStartSolutionVolumePrecision' ||
  548. colKey === 'targetDiluentVolumePrecision'
  549. ) {
  550. const volume = this.$refs.stepFormPackageRef?.getFormDataByKey(
  551. 'targetStartSolution'
  552. )
  553. const subTargetStartSolution =
  554. this.$refs.stepFormPackageRef?.getFormDataByKey(
  555. 'subTargetStartSolution'
  556. )
  557. const params = {
  558. subTargetStartSolution: subTargetStartSolution,
  559. headerSelectFields,
  560. dataSource
  561. }
  562. if (isValueEmpty(volume)) {
  563. this.$message.error('请先选择预设起始源溶液浓度')
  564. } else {
  565. this.updateTargetStartSolutionVolume(item, volume, params)
  566. }
  567. } else if (
  568. colKey === 'actStartSolutionVolume' ||
  569. colKey === 'actDiluentVolume'
  570. ) {
  571. //实际起始溶液体积和实际目标溶液体积
  572. const { targetAcSolution, subTargetAcSolutionUnit } =
  573. this.$refs.stepFormPackageRef?.getFilledFormData() //获取实际起始溶液浓度
  574. const { headerSelectFields } =
  575. this.$refs.stepTableRef?.getFilledFormData()
  576. const p = {
  577. targetStartSolutionUnit: subTargetAcSolutionUnit,
  578. headerSelectFields
  579. }
  580. let initNd = 0
  581. if (rowIndex === 0) {
  582. initNd = targetAcSolution
  583. } else {
  584. initNd = dataSource[rowIndex - 1].actSolutionConcentration
  585. }
  586. if (isValueEmpty(initNd)) {
  587. console.log('initNd', initNd)
  588. this.$message.error('请先选择起始源溶液')
  589. return
  590. } else {
  591. const volResult = this.updateSjmbrynd(item, initNd, p)
  592. if (!volResult) {
  593. return
  594. }
  595. this.$refs.stepTableRef?.updateDataSourceByRowIndex(
  596. rowIndex,
  597. {
  598. actSolutionVolume: volResult.actVol,
  599. actSolutionConcentration: volResult.actNd
  600. },
  601. 'blur'
  602. )
  603. }
  604. }
  605. },
  606. //计算目标溶液浓度
  607. calcNd(item, targetAcSolution, params) {
  608. console.log(item, params, 'ppp')
  609. // debugger
  610. //targetStartSolutionUnit(实际起始源溶液浓度单位)
  611. const { targetStartSolutionUnit, headerSelectFields } = params
  612. const {
  613. actStartSolutionVolumeUnit,
  614. actSolutionVolumeUnit,
  615. actDiluentVolumeUnit,
  616. actSolutionConcentrationUnit
  617. } = headerSelectFields
  618. let initUnit = targetStartSolutionUnit
  619. if (item.rowIndex > 0) {
  620. initUnit = actSolutionConcentrationUnit
  621. }
  622. //actStartSolutionVolumeUnit(实际起始源溶液体积单位)actSolutionVolumeUnit(实际目标溶液体积单位)
  623. //actDiluentVolumeUnit(实际稀释液体积单位)actSolutionConcentrationUnit(实际目标溶液浓度单位)
  624. //实际源溶液浓度÷(实际终体积÷源溶液加入体积);
  625. const precision = item.actSolutionConcentrationPrecision
  626. const volPrecision = item.actSolutionVolumePrecision
  627. //实际稀释液体积
  628. const actDiluentVolume = item.actDiluentVolume
  629. //实际起始源溶液体积
  630. const actStartSolutionVolume = item.actStartSolutionVolume
  631. if (
  632. isValueEmpty(actStartSolutionVolume) ||
  633. isValueEmpty(actDiluentVolume) ||
  634. isValueEmpty(initUnit)
  635. ) {
  636. return false
  637. }
  638. const converActDiluentVolume = volumeConverter.convert(
  639. actDiluentVolume + actDiluentVolumeUnit,
  640. actSolutionVolumeUnit
  641. )
  642. const converActStartSolutionVolume = volumeConverter.convert(
  643. actStartSolutionVolume + actStartSolutionVolumeUnit,
  644. actSolutionVolumeUnit
  645. )
  646. //实际源溶液加入体积+实际稀释液加入体积
  647. const actVol = (
  648. Number(converActDiluentVolume) + Number(converActStartSolutionVolume)
  649. ).toFixed(volPrecision)
  650. const targetStartVolUnit = actSolutionConcentrationUnit.split('/')[1] //先按照预设目标溶液浓度的单位标准
  651. const converActVol = volumeConverter.convert(
  652. actVol + actSolutionVolumeUnit,
  653. targetStartVolUnit
  654. )
  655. const converActDiluentVolume1 = volumeConverter.convert(
  656. actStartSolutionVolume + actStartSolutionVolumeUnit,
  657. targetStartVolUnit
  658. )
  659. const converArr = (targetAcSolution + '').split('/')
  660. converArr.map((item) => {
  661. return convertConcentration.convert(
  662. item + initUnit,
  663. actSolutionConcentrationUnit
  664. )
  665. })
  666. // const converTargetAcSolution = convertConcentration.convert(targetAcSolution + initUnit, actSolutionConcentrationUnit)
  667. // 实际目标溶液浓度 = 实际源溶液浓度÷(实际终体积÷源溶液加入体积);
  668. // const actNd = (
  669. // parseFloat(converTargetAcSolution) / (
  670. // parseFloat(converActVol) / parseFloat(converActDiluentVolume1)
  671. // )
  672. // ).toFixed(precision)
  673. const actNdArr = converArr.map((item) => {
  674. return parseFloat(
  675. (item / (converActVol / converActDiluentVolume1)).toFixed(precision)
  676. )
  677. })
  678. // const nd = actNd === 'Infinity' ? 0 : Number(actNd)
  679. console.log(
  680. actNdArr,
  681. targetAcSolution,
  682. actStartSolutionVolume,
  683. actVol,
  684. 'actNd'
  685. )
  686. // item.actSolutionConcentration = actNd === 'Infinity' ? 0 : actNd
  687. return { actVol: Number(actVol), actNd: actNdArr.join('/') }
  688. },
  689. //计算并更新实际目标溶液浓度 先计算实际目标溶液体积再计算实际目标溶液浓度
  690. updateSjmbrynd(item, targetAcSolution, params) {
  691. return this.calcNd(item, targetAcSolution, params)
  692. },
  693. //更新起始溶液体积时,计算预设起始溶液体积和预设稀释液体积
  694. updateTargetStartSolutionVolume(item, volume, unitParams) {
  695. const { rowIndex } = item
  696. const {
  697. subTargetStartSolution,
  698. headerSelectFields,
  699. dataSource = []
  700. } = unitParams
  701. const {
  702. targetSolutionConcentrationUnit,
  703. targetSolutionVolumeUnit,
  704. targetStartSolutionVolumeUnit,
  705. targetDiluentVolumeUnit
  706. } = headerSelectFields
  707. let initNd = volume,
  708. unit = subTargetStartSolution
  709. //平行配制不会传dataSource;
  710. if (rowIndex > 0 && dataSource.length > 0) {
  711. initNd = dataSource[rowIndex - 1].targetSolutionConcentration
  712. unit = targetSolutionConcentrationUnit
  713. }
  714. const precision = item.targetStartSolutionVolumePrecision || 0
  715. const precision1 = item.targetDiluentVolumePrecision || 0
  716. const concentration = item.targetSolutionConcentration
  717. const targetVolume = item.targetSolutionVolume
  718. if (
  719. isValueEmpty(concentration) ||
  720. isValueEmpty(targetVolume) ||
  721. isValueEmpty(unit) ||
  722. isValueEmpty(targetSolutionConcentrationUnit) ||
  723. isValueEmpty(targetSolutionVolumeUnit) ||
  724. isValueEmpty(targetStartSolutionVolumeUnit) ||
  725. isValueEmpty(targetDiluentVolumeUnit)
  726. ) {
  727. return
  728. }
  729. const targetStartVolUnit = targetSolutionConcentrationUnit.split('/')[1] //先按照预设目标溶液浓度的单位标准
  730. //将预设目标溶液体积转换为和预设目标溶液浓度单位的分母一样的单位再计算;如:预设目标溶液浓度单位为mg/mL,预设目标溶液体积单位为uL,则将预设目标溶液体积转换为mL
  731. const convertTargetVol = volumeConverter.convert(
  732. targetVolume + targetSolutionVolumeUnit,
  733. targetStartVolUnit
  734. )
  735. const convertTargetVol1 = volumeConverter.convert(
  736. targetVolume + targetSolutionVolumeUnit,
  737. targetStartSolutionVolumeUnit
  738. )
  739. const initNdArr = (initNd + '').split('/')
  740. const transNdArr = initNdArr.map((con) => {
  741. return convertConcentration.convert(
  742. con + unit,
  743. targetSolutionConcentrationUnit
  744. )
  745. })
  746. const mbyjndArr = (concentration + '').split('/') //目标预计浓度
  747. if (mbyjndArr.length !== initNdArr.length) {
  748. this.$message.error('起始溶液浓度和目标溶液浓度格式不一致,请重新输入')
  749. return
  750. }
  751. //预设体积
  752. const ystjArr = mbyjndArr.map((con, index) => {
  753. const ystj = Number(
  754. (con * convertTargetVol) / (transNdArr[index] || transNdArr[0])
  755. )
  756. const convertYsVol = volumeConverter.convert(
  757. ystj + targetStartVolUnit,
  758. targetStartSolutionVolumeUnit
  759. )
  760. const xstj = convertTargetVol1 - convertYsVol //稀释体积
  761. return { qsrytj: convertYsVol, xstj }
  762. })
  763. if (ystjArr.length > 0) {
  764. const firstItem = ystjArr[0] //只取第一个计算
  765. item.targetStartSolutionVolume = Number(
  766. firstItem.qsrytj.toFixed(precision)
  767. )
  768. item.targetDiluentVolume = Number(
  769. volumeConverter
  770. .convert(
  771. firstItem.xstj + targetStartSolutionVolumeUnit,
  772. targetDiluentVolumeUnit
  773. )
  774. .toFixed(precision1)
  775. )
  776. }
  777. },
  778. // 导出excel模板
  779. exportExcel(headerArray, title = '导出模板') {
  780. this.$modal.loading()
  781. const ws = XLSX.utils.aoa_to_sheet([headerArray])
  782. const colWidths = headerArray.map((cell) => getStringWidth(cell) + 2)
  783. ws['!cols'] = colWidths.map((width) => ({ wch: width }))
  784. const wb = XLSX.utils.book_new()
  785. XLSX.utils.book_append_sheet(wb, ws, 'Sheet1')
  786. XLSX.writeFile(wb, `${title}.xlsx`)
  787. this.$modal.closeLoading()
  788. }
  789. }
  790. }