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

501 lines
21 KiB

  1. import _ from "lodash";
  2. import { getuuid, isEqual, isValueEmpty } from "@/utils/index.js";
  3. import { isShowOtherByCheckboxTree } from "@/utils/formPackageCommon.js";
  4. export default {
  5. inject: ["getZdxgjl", "updateZdxgjl"],
  6. watch: {
  7. formData: {
  8. immediate: true,
  9. deep: true, // 深度监听,以便检测嵌套对象变化
  10. handler(v) {
  11. if (v) {
  12. this.handleFormField(true);
  13. }
  14. }
  15. },
  16. fieldItemLabel: {
  17. immediate: true,
  18. deep: true, // 深度监听,以便检测嵌套对象变化
  19. handler(v) {
  20. if (v) {
  21. console.log(v, "fieldItemLabel")
  22. }
  23. }
  24. },
  25. formConfig: {
  26. immediate: true,
  27. deep: true, // 深度监听,以便检测嵌套对象变化
  28. handler(v) {
  29. this.handleFormField();
  30. }
  31. }
  32. },
  33. data() {
  34. return {
  35. uuid: getuuid(),
  36. oldFormFields: {},
  37. clickableKey: "",
  38. }
  39. },
  40. mounted() {
  41. this.handleFormField();
  42. },
  43. unmounted() {
  44. this.formFields = {};//清空当前填写的数据
  45. },
  46. methods: {
  47. onSelectChange(key, val, type) {
  48. // 获取对应的配置
  49. const currentConfig = this.allFieldsConfig[key];
  50. if (currentConfig.selectTo) {
  51. this.formFields[currentConfig.selectTo] = val;
  52. }
  53. this.onValueChangeCompareTo(key, val);
  54. this.formFields[key] = val;
  55. this.$emit("select", { key, value: val, type, ...this.formFields });
  56. // 清除该表单项的错误状态
  57. if (this.errors[key]) {
  58. this.$set(this.errors, key, false);
  59. }
  60. },
  61. //试剂/仪器等弹窗提交
  62. onRegentSubmit(data, inputValue, key, item) {
  63. this.updateFormData(key, inputValue);
  64. this.$emit("onRegentSubmit", { selectInfo: data, inputValue, key, config: item });
  65. },
  66. getRegentItem(item, fieldCode = "type") {
  67. const type = item[fieldCode];
  68. console.log(item, "type")
  69. return {
  70. label: "",
  71. type,
  72. fillType: item.subFillType || item.fillType,
  73. parentLabel: item.label,
  74. filledCodes: item.filledCodes,
  75. qxbdType: item.qxbdType,
  76. checkType: item.checkType,
  77. }
  78. },
  79. handleClickButton(key) {
  80. this.$emit("clickButton", key)
  81. },
  82. getFillType(type) {
  83. const typeObj = {
  84. actFill: "orange-border",//实际填写的边框颜色
  85. green: "green-border",
  86. preFill: "blue-border",//预填写的边框颜色
  87. }
  88. return typeObj[type] || ""
  89. },
  90. onInputNumberChange(key, val) {
  91. this.formFields[key] = val;
  92. // 清除该表单项的错误状态
  93. if (this.errors[key]) {
  94. this.$set(this.errors, key, false);
  95. }
  96. },
  97. //批量更新表单数据
  98. batchUpdateFormData(data) {
  99. const cloneFormFields = JSON.parse(JSON.stringify(this.formFields));
  100. Object.keys(data).forEach(key => {
  101. this.oldFormFields[key] = cloneFormFields[key];
  102. this.formFields[key] = data[key];
  103. // 清除该表单项的错误状态
  104. if (this.errors[key]) {
  105. this.$set(this.errors, key, false);
  106. }
  107. })
  108. },
  109. //更新表单数据
  110. updateFormData(key, value, data) {
  111. const { isUpdateRecord, signData } = data || {};
  112. // 深拷贝当前表单数据,避免直接修改原数据
  113. const cloneFormFields = JSON.parse(JSON.stringify(this.formFields));
  114. this.oldFormFields[key] = cloneFormFields[key];
  115. this.formFields[key] = value;
  116. // 清除该表单项的错误状态
  117. if (this.errors[key]) {
  118. this.$set(this.errors, key, false);
  119. }
  120. if (isUpdateRecord) {
  121. setTimeout(() => {
  122. this.$refs[key][0].handleUpdateRecord(signData, { oldValue: this.oldFormFields[key], inputValue: value });
  123. }, 10);
  124. }
  125. },
  126. handleClickable(sItem, key) {
  127. if (this.templateFillType !== 'actFill') {
  128. return
  129. }
  130. this.clickableKey = key;
  131. this.$emit("clickable", sItem)
  132. },
  133. //根据span判断一行显示几列
  134. getSpanClass(sItem) {
  135. const spanArr = ["full-row", "", "three-row"]
  136. if (sItem.span) {
  137. return spanArr[sItem.span - 1]
  138. }
  139. return ""
  140. },
  141. //获取其他下拉框的配置
  142. getOtherItem(sItem) {
  143. return {
  144. label: sItem.otherLabel ? this.$t(sItem.otherLabel) : this.$t("template.common.other"),
  145. fillType: sItem.fillType,
  146. maxlength: sItem.otherMaxlength || 50,
  147. parentLabel: sItem.label,
  148. }
  149. },
  150. getRadioOtherItem(sItem) {
  151. return {
  152. // label: sItem.otherLabel ? this.$t(sItem.otherLabel) : this.$t("template.common.other"),
  153. fillType: sItem.fillType,
  154. maxlength: sItem.otherMaxlength || 50,
  155. parentLabel: sItem.label,
  156. }
  157. },
  158. getClickableItem(sItem) {
  159. return {
  160. label: "",
  161. type: "clickable",
  162. fillType: sItem.subFillType || sItem.fillType,
  163. parentLabel: sItem.label,
  164. }
  165. },
  166. getSubItem(sItem) {
  167. const config = {
  168. label: "",
  169. options: sItem.subOptions || [],
  170. fillType: sItem.subFillType || sItem.fillType,
  171. parentLabel: sItem.label,
  172. }
  173. if (sItem.subDisabled) {
  174. config.disabled = sItem.subDisabled;
  175. }
  176. return config;
  177. },
  178. // 根据formConfig回填form表单数据
  179. handleFormField(update = false) {
  180. const result = {};
  181. let config = {};
  182. const { formConfig, formData, formFields } = this;
  183. // 遍历配置
  184. formConfig.forEach((item) => {
  185. if (item.config) {
  186. // 合并配置项
  187. config = { ...config, ...item.config }
  188. // 处理每个配置项
  189. Object.keys(item.config).forEach(key => {
  190. const currentConfig = item.config[key];
  191. let value = formData[key];
  192. // 如果formFields中已经有值,保持原值(用户输入或之前设置的值)
  193. if (formFields[key] !== null &&
  194. formFields[key] !== undefined &&
  195. formFields[key] !== ''
  196. // typeof formFields[key] !== 'object'
  197. ) {
  198. // 保留原值,不使用formData中的值
  199. result[key] = formFields[key];
  200. } else {
  201. // 使用formData中的值
  202. result[key] = value;
  203. }
  204. // 处理特殊字段 - "其他"字段
  205. if (currentConfig.otherCode) {
  206. const { otherCode, type } = currentConfig;
  207. //如果是更新的话,优先使用formFields中的值
  208. if (update) {
  209. result[otherCode] = formFields[otherCode] || formData[otherCode] || '';
  210. } else {
  211. result[otherCode] = formData[otherCode] || formFields[otherCode] || '';
  212. }
  213. config[otherCode] = { label: "template.common.other", parentType: type, parentKey: key, type: "input", fillType: currentConfig.fillType }
  214. }
  215. if (currentConfig.subKey) {
  216. const { subKey } = currentConfig;
  217. if (update) {
  218. result[subKey] = formFields[subKey] || formData[subKey] || '';
  219. } else {
  220. result[subKey] = formData[subKey] || formFields[subKey] || '';
  221. }
  222. config[subKey] = { label: currentConfig.label, subKey, type: currentConfig.subType, fillType: currentConfig.subFillType || currentConfig.fillType, selectTo: currentConfig.selectTo }
  223. }
  224. // 检查compareTo字段
  225. if (currentConfig.compareTo && formData[currentConfig.compareTo] && result[key]) {
  226. const compareToValue = formData[currentConfig.compareTo];
  227. const currentValue = result[key];
  228. this.compareFieldsIsEqual(currentValue, compareToValue, key)
  229. }
  230. // 检查compareTo字段
  231. if (currentConfig.subCompareTo && formData[currentConfig.subCompareTo] && result[currentConfig.subKey]) {
  232. const compareToValue = formData[currentConfig.subCompareTo];
  233. const currentValue = result[currentConfig.subKey];
  234. this.compareFieldsIsEqual(currentValue, compareToValue, currentConfig.subKey)
  235. }
  236. });
  237. // 处理可能存在的直接otherCode字段
  238. if (item.config?.otherCode) {
  239. config[item.config?.otherCode] = item.config?.otherCode;
  240. }
  241. }
  242. });
  243. // 处理selectInfo_开头的字段,步骤表单需要保留selectInfo_开头的字段
  244. const selectInfoKeys = Object.keys(formData).filter(key => key.startsWith("selectInfo_"));
  245. selectInfoKeys.forEach(key => {
  246. result[key] = formData[key];
  247. })
  248. // 更新表单字段
  249. this.formFields = result;
  250. this.allFieldsConfig = config;
  251. },
  252. //比较值是否相等
  253. compareFieldsIsEqual(currentValue, compareToValue, key) {
  254. if (!currentValue || !compareToValue) return;
  255. // 如果当前值与compareTo字段的值不相等,则设置橙色背景
  256. if (isEqual(currentValue, compareToValue)) {
  257. // 如果相等,移除橙色背景(如果之前设置了的话)
  258. this.$set(this.orangeBgFields, key, false);
  259. } else {
  260. this.$set(this.orangeBgFields, key, true);
  261. }
  262. },
  263. //判断是否禁用
  264. getDisabled() {
  265. const { item } = this;
  266. const { fillType } = item;
  267. if (item.hasOwnProperty("disabled")) {
  268. return item.disabled
  269. } else {
  270. if (fillType === "actFill") {//当模板状态是实际填写时,只有当fillType是actFill时才能填写
  271. return this.templateFillType !== "actFill"
  272. } else if (fillType === "preFill") {//当模板状态是预填写时,只有当fillType是preFill才能填写
  273. return this.templateFillType !== "preFill"
  274. } else {
  275. return true
  276. }
  277. }
  278. },
  279. // 表单数据校验
  280. validateFormData() {
  281. const { formFields, allFieldsConfig } = this;
  282. const errors = [];
  283. // 清空之前的错误状态
  284. this.errors = {};
  285. for (const key in allFieldsConfig) {
  286. const o = allFieldsConfig[key];
  287. if (o.otherCode) {//
  288. if (o.type === "select") {
  289. const isSelectedOther = this.isShowOther(formFields[key]);
  290. if (!isSelectedOther) {//如果其他选项没有被选择,清空其他字段
  291. formFields[o.otherCode] = "";
  292. }
  293. } else if (o.subType === "select") {
  294. const isSelectedOther = this.isShowOther(formFields[o.subKey]);
  295. if (!isSelectedOther) {//如果其他选项没有被选择,清空其他字段
  296. formFields[o.otherCode] = "";
  297. }
  298. } else if (o.type === "radioAndOther") {
  299. const isSelectedOther = this.isShowOtherByRadioAndOther(formFields[key]);
  300. if (!isSelectedOther) {//如果其他选项没有被选择,清空其他字段
  301. formFields[o.otherCode] = "";
  302. }
  303. }
  304. }
  305. if (o.type === "attachment"&&o.fillType === this.templateFillType) {
  306. const attValue = formFields[key];
  307. if (!attValue || attValue == "[]") {
  308. errors.push({
  309. field: key,
  310. label: o.label,
  311. error: "请上传附件"
  312. });
  313. this.$set(this.errors, key, true);
  314. }
  315. } else if (o.type === "fqyq" &&o.fillType === this.templateFillType) {
  316. const fqyqValue = formFields[key] || {};
  317. const {mainRadio, subRadio,inputValue} = fqyqValue;
  318. if (!mainRadio) {
  319. errors.push({
  320. field: key,
  321. label: o.label,
  322. error: "请选择是否在规定时间完成"
  323. });
  324. this.$set(this.errors, key, true);
  325. } else {
  326. if (mainRadio==="是") {
  327. if (!subRadio) {
  328. errors.push({
  329. field: key,
  330. label: o.label,
  331. error: "请选择是否在规定时间完成"
  332. });
  333. this.$set(this.errors, key, true);
  334. }else if(!inputValue){
  335. errors.push({
  336. field: key,
  337. label: o.label,
  338. error: "请输入信息"
  339. });
  340. this.$set(this.errors, key, true);
  341. }
  342. }
  343. }
  344. continue
  345. }else if(o.type === "checkboxTree"&&o.fillType === this.templateFillType){
  346. const checkboxTreeValue = formFields[key] || {};
  347. const {checkedValues=[],otherValues = {}} = checkboxTreeValue;;
  348. const {options = []} = o;
  349. //需要校验第一层是否有选中项
  350. const parentOptions = options.map(item => item.label);
  351. const isChecked = parentOptions.some(option => {
  352. var found = checkedValues.find(item => item.label === option);
  353. return found && found.checked === true;
  354. });
  355. //获取所有选中的选项
  356. const allCheckedOptions = checkedValues.filter(item => item.checked).map(item => item.label);
  357. //再筛选出需要显示其他输入框的选项
  358. const otherOptions = allCheckedOptions.filter((label)=>isShowOtherByCheckboxTree(label))
  359. const isHasOtherInfo = otherOptions.every(item => otherValues[item]);
  360. console.log(otherOptions,allCheckedOptions,isHasOtherInfo,"otherOptions")
  361. console.log(o,checkedValues,otherValues,options,isChecked,"checkboxTreeValue")
  362. if (!isChecked || !isHasOtherInfo) {
  363. errors.push({
  364. field: key,
  365. label: o.label,
  366. error: "请选择方法学验证"
  367. });
  368. this.$set(this.errors, key, true);
  369. }
  370. continue
  371. }
  372. if (isValueEmpty(formFields[key])) {
  373. // 其他字段需要判断是否显示再校验
  374. if (o.label === "template.common.other" && !this.isShowOther(formFields[o.parentKey]) && o.parentType !== "radioAndOther") {
  375. continue
  376. }
  377. if (o.type === "radioAndOther" && o.label === "template.common.other" && !this.isShowOtherByRadioAndOther(formFields[o.parentKey])) {
  378. continue
  379. }
  380. //span的字段不校验
  381. if (o.type === "span" || o.type === "text" || o.type === "button") {
  382. continue
  383. }
  384. if (o.fillType === this.templateFillType && !o.disabled) {
  385. let prefix = "";
  386. if (o.type === "input" || o.type === "inputNumber" || o.type === "textarea") {
  387. prefix = "填写";
  388. } else {
  389. prefix = "选择";
  390. }
  391. const errorItem = {
  392. field: key,
  393. label: o.label,
  394. error: `${prefix}${o.label}`
  395. };
  396. errors.push(errorItem);
  397. this.$set(this.errors, key, true);
  398. }
  399. }
  400. }
  401. console.log(errors, "errors")
  402. return {
  403. valid: errors.length === 0,
  404. errors: errors
  405. };
  406. },
  407. getFormData() {
  408. // 同时执行数据校验和子组件校验
  409. const validateResult = this.validateFormData();
  410. const subComponentValidateResult = this.validateSubComponents();
  411. // const subComponentValidateResult = {valid: true, error: ''};
  412. return new Promise((resolve, reject) => {
  413. if (validateResult.valid && subComponentValidateResult.valid) {
  414. resolve(this.formFields);
  415. } else if (!validateResult.valid) {
  416. // this.$message.error("表单内容未填完,请填写后再提交");
  417. reject(validateResult.errors[0].error);
  418. } else {
  419. reject(subComponentValidateResult.error);
  420. }
  421. });
  422. },
  423. // 子组件校验钩子方法,子组件可以重写此方法来添加额外的校验逻辑
  424. validateSubComponents() {
  425. return {
  426. valid: true,
  427. error: ''
  428. };
  429. },
  430. //直接获取表单数据,不做校验
  431. getFilledFormData() {
  432. return this.formFields;
  433. },
  434. getFormDataByKey(key) {
  435. return this.formFields[key];
  436. },
  437. onBlur(key, val) {
  438. // compareTo 功能:当fillType==="actFill"时,判断当前值是否与compareTo字段的值一样,如果不一样则将当前input框的背景色标记成橙色
  439. this.onValueChangeCompareTo(key, val);
  440. this.$emit("blur", { key, value: val, ...this.formFields });
  441. },
  442. onValueChangeCompareTo(key, val, compKey) {
  443. // compareTo 功能:当fillType==="actFill"时,判断当前值是否与compareTo字段的值一样,如果不一样则将当前input框的背景色标记成橙色
  444. const currentFieldConfig = this.allFieldsConfig[key];
  445. if (currentFieldConfig && currentFieldConfig.fillType === "actFill" && (currentFieldConfig.compareTo || compKey)) {
  446. const compareToKey = compKey || currentFieldConfig.compareTo;
  447. const compareToValue = this.formFields[compareToKey];
  448. this.compareFieldsIsEqual(val, compareToValue, key);
  449. }
  450. },
  451. onAttachmentChange(key, val) {
  452. this.formFields[key] = val;
  453. // 清除该表单项的错误状态
  454. if (this.errors[key]) {
  455. this.$set(this.errors, key, false);
  456. }
  457. // 如果是checkboxList类型,需要处理otherValues
  458. if (val && typeof val === 'object' && val.otherValues) {
  459. // 将otherValues中的每个值也保存到formFields中
  460. Object.keys(val.otherValues).forEach(otherCode => {
  461. this.formFields[otherCode] = val.otherValues[otherCode];
  462. });
  463. }
  464. },
  465. //复制
  466. onCopy(config, key) {
  467. const { formFields } = this;
  468. if (config.copyFrom) {
  469. formFields[key] = formFields[config.copyFrom];
  470. this.onBlur(key, formFields[key]);
  471. }
  472. },
  473. resetRecord(key) {
  474. this.formFields = { ...this.formFields, ...this.oldFormFields };
  475. this.oldFormFields = {};
  476. },
  477. }
  478. }