detail-old.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  1. <template>
  2. <z-paging
  3. class="page"
  4. ref="paging"
  5. v-model="dataList"
  6. :loading-more-enabled="false"
  7. @query="queryList"
  8. >
  9. <!-- z-paging默认铺满全屏,此时页面所有view都应放在z-paging标签内,否则会被盖住 -->
  10. <!-- 需要固定在页面顶部的view请通过slot="top"插入,包括自定义的导航栏 -->
  11. <view class="list">
  12. <!-- 工单基础信息 -->
  13. <view class="item top">
  14. <view class="item-content flex-row align-center">
  15. <view class="item-title full-cell flex-row align-center">
  16. <span class="item-title-width"
  17. >{{ $t("operationRecordFilling.workOrderName") }}:</span
  18. >
  19. <span>{{ params.orderName }}</span>
  20. </view>
  21. </view>
  22. <view class="item-content flex-row align-center">
  23. <view class="item-title full-cell flex-row align-center">
  24. <span class="item-title-width"
  25. >{{ $t("operationRecordFilling.responsiblePerson") }}:</span
  26. >
  27. <span>{{ params.userName }}</span>
  28. </view>
  29. </view>
  30. <view class="item-content flex-row align-center">
  31. <view class="item-title full-cell flex-row align-center">
  32. <span class="item-title-width"
  33. >{{ $t("operation.createTime") }}:</span
  34. >
  35. <span>{{ params.createTime }}</span>
  36. </view>
  37. </view>
  38. </view>
  39. <!-- 填报列表 -->
  40. <view class="item" v-for="(item, index) in dataList" :key="index">
  41. <view class="item-module flex-row align-center justify-between">
  42. <view class="module-name">
  43. {{ item.deviceCode }}({{ item.deviceName }})
  44. </view>
  45. <view class="module-border"> </view>
  46. </view>
  47. <view class="item-content flex-row align-center justify-between bold">
  48. <view class="item-title flex-row align-center">
  49. <span>{{ $t("operationRecordFilling.belongToTeam") }}:</span>
  50. <span>{{ item.orgName }}</span>
  51. </view>
  52. </view>
  53. <view
  54. class="item-content flex-row align-center justify-between bold"
  55. v-for="sum in item.sumList"
  56. >
  57. <view class="item-title flex-row align-center word-break-all">
  58. <span>{{ sum.name }}:</span>
  59. </view>
  60. <view class="item-value flex-row align-center justify-end total">
  61. <uni-easyinput
  62. style="text-align: right"
  63. :inputBorder="false"
  64. :clearable="true"
  65. :styles="{ disableColor: '#fff' }"
  66. :value="`${sum.totalRunTime} ${
  67. sum.modelAttr ? (sum.modelAttr.includes('Time') ? 'h' : '') : ''
  68. }`"
  69. :disabled="true"
  70. ></uni-easyinput>
  71. </view>
  72. </view>
  73. <view
  74. class="item-content flex-col align-center justify-between"
  75. :class="{ 'bottom-bold': item.nonSumList.length > 0 }"
  76. v-for="nosum in item.nonSumList"
  77. >
  78. <!-- isCollection为1,提示:以下数值取自PLC,如有不符请修改 -->
  79. <uni-notice-bar
  80. :text="$t('operationRecordFilling.plcNotice')"
  81. v-if="nosum.isCollection == 1"
  82. />
  83. <view class="flex-row align-center justify-between item-content">
  84. <view class="item-title flex-row align-center">
  85. <span>{{ nosum.name }}:</span>
  86. </view>
  87. <!-- 判断填写项的属性 -->
  88. <!-- type为double时,输入框为数字类型 -->
  89. <view
  90. class="item-value flex-row align-center justify-end"
  91. v-if="nosum.type == 'double'"
  92. >
  93. <uni-easyinput
  94. style="text-align: right"
  95. :styles="{ disableColor: '#fff' }"
  96. :inputBorder="false"
  97. :clearable="true"
  98. :placeholder="$t('operation.PleaseFillIn')"
  99. :disabled="!isView"
  100. v-model="nosum.fillContent"
  101. :type="'digit'"
  102. @blur="
  103. nosum.threshold > 0
  104. ? checkThreshold(nosum)
  105. : checkLessThreshold(nosum)
  106. "
  107. @change="handleFillContentChange(nosum, item)"
  108. ></uni-easyinput>
  109. </view>
  110. <!-- type为textarea时,输入框为文本类型 -->
  111. <view
  112. class="item-value flex-row align-center justify-end"
  113. v-else-if="nosum.type == 'textarea'"
  114. >
  115. <uni-easyinput
  116. style="text-align: right"
  117. :styles="{ disableColor: '#fff' }"
  118. :inputBorder="false"
  119. :clearable="true"
  120. :placeholder="$t('operation.PleaseFillIn')"
  121. :disabled="!isView"
  122. v-model="nosum.fillContent"
  123. :type="'textarea'"
  124. :autoHeight="true"
  125. :maxlength="-1"
  126. ></uni-easyinput>
  127. </view>
  128. <!-- type为enum时,使用下拉菜单 -->
  129. <view
  130. class="item-value textarea flex-row align-center justify-end"
  131. v-else-if="nosum.type == 'enum' && nosum.description !== null"
  132. >
  133. <uni-data-select
  134. :localdata="nosum.enumList"
  135. :styles="{ disableColor: '#fff' }"
  136. :clear="false"
  137. :disabled="!isView"
  138. :placeholder="$t('operation.PleaseSelect')"
  139. v-model="nosum.fillContent"
  140. ></uni-data-select>
  141. </view>
  142. <!-- 其他类型时,输入框为文本类型 -->
  143. <view class="item-value flex-row align-center justify-end" v-else>
  144. <uni-easyinput
  145. style="text-align: right"
  146. :styles="{ disableColor: '#fff' }"
  147. :inputBorder="false"
  148. :clearable="true"
  149. :placeholder="$t('operation.PleaseFillIn')"
  150. :disabled="!isView"
  151. v-model="nosum.fillContent"
  152. :type="'text'"
  153. ></uni-easyinput>
  154. </view>
  155. </view>
  156. </view>
  157. </view>
  158. </view>
  159. <!-- 如果需要使用页脚,请使用slot="bottom"slot节点不支持通过v-if或v-show动态显示/隐藏,若需要动态控制,可将v-if添加在其子节点上 -->
  160. <template #bottom>
  161. <button
  162. style="border-radius: 0"
  163. type="primary"
  164. @click="onSubmit()"
  165. >
  166. {{ $t("operation.save") }}
  167. </button>
  168. </template>
  169. </z-paging>
  170. </template>
  171. <script setup>
  172. import { ref, reactive, getCurrentInstance, watch, onMounted } from "vue";
  173. import { onReady, onLoad } from "@dcloudio/uni-app";
  174. import dayjs from "dayjs";
  175. import {
  176. getRecordFillingDetailGetPage,
  177. getRecordFillingDetailGetAttrs,
  178. recordFillingDetailInsertLog,
  179. getRecordFillingDetail,
  180. recordFillingUpOperationOrder,
  181. } from "@/api/recordFilling";
  182. import { getUserId, reloginByUserId } from "@/utils/auth.js";
  183. import { useDataDictStore } from "@/store/modules/dataDict";
  184. // 引用全局变量$t
  185. const { appContext } = getCurrentInstance();
  186. const t = appContext.config.globalProperties.$t;
  187. // 获取字典项
  188. const { getStrDictOptions, getIntDictOptions } = useDataDictStore();
  189. // -------------------------------------
  190. const isFromMsg = ref(false);
  191. const params = ref({});
  192. const isView = ref(false); // 是否编辑 -- view == 1为编辑状态
  193. onMounted(() => {
  194. console.log("onMounted");
  195. });
  196. onReady(() => {
  197. console.log("onReady");
  198. });
  199. onLoad(async (option) => {
  200. console.log("onLoad", option);
  201. await reloginByUserId(option.reloginUserId);
  202. isFromMsg.value = !!option.reloginUserId;
  203. // 初始化params
  204. params.value = JSON.parse(option.param);
  205. // 处理createTime
  206. params.value.createTime = params.value.createTime
  207. ? dayjs(Number.parseInt(params.value.createTime)).format("YYYY-MM-DD")
  208. : "";
  209. // 请求工单详情
  210. if (params.value?.orderId) {
  211. const detail = (await getRecordFillingDetail(params.value.orderId)).data;
  212. console.log("🚀getRecordFillingDetail ~ detail:", detail);
  213. params.value = {
  214. ...params.value,
  215. ...detail,
  216. // 处理createTime
  217. createTime: detail.createTime
  218. ? dayjs(Number.parseInt(detail.createTime)).format("YYYY-MM-DD")
  219. : "",
  220. orderId: detail.id,
  221. };
  222. }
  223. console.log("🚀 ~ params.value:", params.value);
  224. // 处理是否可编辑 {0: '待填写', 1: '已完成', 2: '填写中', 3: '忽略'}
  225. isView.value = params.value?.orderStatus % 2 == 0;
  226. console.log("🚀 ~ isView.value:", isView.value);
  227. });
  228. const paging = ref(null);
  229. // v-model绑定的这个变量不要在分页请求结束中自己赋值,直接使用即可
  230. const dataList = ref([]);
  231. // 监听dataList变化,初始化时计算一次总和
  232. watch(
  233. dataList,
  234. (newVal) => {
  235. // calculateTotalRunTime();
  236. },
  237. { deep: true }
  238. );
  239. // 处理fillContent变化的方法
  240. const handleFillContentChange = (nosum, deviceItem) => {
  241. console.log("🚀 ~ nosum, deviceItem:", nosum, deviceItem);
  242. // 处理增压机
  243. if (
  244. deviceItem.deviceName.includes("增压机") &&
  245. nosum.name === "当日运转时间"
  246. ) {
  247. calculateTotalRunTime("增压机", "当日运转时间"); // 计算当日运转时间总和
  248. }
  249. // 处理提纯撬
  250. if (deviceItem.deviceName.includes("提纯撬") && nosum.name === "当日注气量") {
  251. calculateTotalRunTime("提纯撬", "当日注气量"); // 计算当日注气量总和
  252. }
  253. // 处理注水泵
  254. if (deviceItem.deviceName.includes("注水泵") && nosum.name === "当日注水量") {
  255. calculateTotalRunTime("注水泵", "当日注水量"); // 计算当日注水量总和
  256. }
  257. // 处理箱式变电站
  258. if (
  259. deviceItem.deviceName.includes("箱式变电站") &&
  260. nosum.name === "当日用电量"
  261. ) {
  262. calculateTotalRunTime("箱式变电站", "当日用电量"); // 计算当日用电量总和
  263. }
  264. };
  265. /**
  266. * 计算所有deviceName中包含deviceNameToMatch的对象中对应的reportName的fillContent总和并更新到reportName的fillContent中
  267. * @param deviceNameToMatch {string} 设备名称包含的字符串
  268. * @param reportName {string} 填写项名称
  269. */
  270. const calculateTotalRunTime = (deviceNameToMatch, reportName) => {
  271. console.log(
  272. "🚀calculateTotalRunTime ~ deviceNameToMatch, reportName:",
  273. deviceNameToMatch,
  274. 12
  275. );
  276. // 查找isReport为1的对象
  277. const reportItem = dataList.value.find((item) => item.isReport === 1);
  278. console.log("🚀calculateTotalRunTime ~ reportItem:", reportItem);
  279. if (!reportItem) return;
  280. /**
  281. * @param deviceNameToMatch {string} 设备名称包含的字符串
  282. * @param deviceName {string} 设备名称
  283. * @param reportName {string} 填写项名称
  284. * 查找[生产日报]中对应的填写项
  285. * reportName -> deviceName:reportName
  286. * 当日运转时间 -> 增压机:当日运转时间
  287. * 当日注气量 -> 提纯撬:当日注气量
  288. * 当日注水量 -> 注水泵:当日注水量
  289. * 当日用电量 -> 箱式变电站:当日用电量
  290. */
  291. const targetItem = reportItem.nonSumList.find(
  292. (item) => item.name === reportName
  293. );
  294. if (!targetItem) return;
  295. // 计算所有deviceName中包含deviceNameToMatch的对象中对应的reportName的fillContent总和
  296. let total = null;
  297. dataList.value.forEach((item) => {
  298. if (item.deviceName.includes(deviceNameToMatch) && item.nonSumList) {
  299. item.nonSumList.forEach((nonSum) => {
  300. // 只累加数字类型的值
  301. if (
  302. nonSum.type === "double" &&
  303. nonSum.fillContent &&
  304. nonSum.name === reportName
  305. ) {
  306. console.log("🚀 ~ nonSum.fillContent:", nonSum.fillContent);
  307. console.log("🚀 ~ nonSum:", nonSum);
  308. const value = Number(nonSum.fillContent) || 0;
  309. total += value;
  310. }
  311. });
  312. }
  313. });
  314. console.log("🚀 ~ total:", total);
  315. if (total !== null) {
  316. // 更新目标值,保留两位小数
  317. targetItem.fillContent = toFixed(total);
  318. console.log("🚀 ~ targetItem.fillContent:", targetItem.fillContent);
  319. }
  320. };
  321. // @query所绑定的方法不要自己调用!!需要刷新列表数据时,只需要调用paging.value.reload()即可
  322. const queryList = (pageNo, pageSize) => {
  323. const userId = uni.getStorageSync("userId");
  324. if (!userId) {
  325. paging.value.complete([]);
  326. return;
  327. }
  328. // 此处请求仅为演示,请替换为自己项目中的请求
  329. getRecordFillingDetailGetPage({
  330. // pageNo,
  331. // pageSize,
  332. ...params.value,
  333. deviceCategoryId: 1,
  334. })
  335. .then(async (res) => {
  336. const resList = [].concat(res.data);
  337. // 使用Promise.all等待所有异步请求完成
  338. await Promise.all(
  339. resList.map(async (item) => {
  340. try {
  341. const attrParams = {
  342. deviceCode: item.deviceCode,
  343. deviceName: item.deviceName,
  344. deptId: item.deptId,
  345. createTime: params.value.createTime,
  346. deviceCategoryId: item.deviceCategoryId,
  347. deviceId: item.deviceId,
  348. userId: params.value.userId,
  349. orderId: params.value.orderId,
  350. };
  351. // console.log(
  352. // "getRecordFillingDetailGetAttrs- attrParams",
  353. // attrParams
  354. // );
  355. const resAttrs = await getRecordFillingDetailGetAttrs({
  356. pageNo: 1,
  357. pageSize: 10,
  358. ...attrParams,
  359. });
  360. // console.log("resAttrs", resAttrs);
  361. if (resAttrs?.data) {
  362. attrParams.createTime = attrParams.createTime
  363. ? dayjs(attrParams.createTime).format("YYYY-MM-DD")
  364. : "";
  365. attrParams.id = attrParams.orderId;
  366. delete attrParams.orderId;
  367. delete attrParams.deviceName;
  368. resAttrs.data.map((rtem) => {
  369. // 将rtem中sumList和nonSumList两个数组中的
  370. // fillContent字段判断是否为null, 如果为null,则赋值为0 不为null则保留两位小数
  371. // 将attrParams合并到两个数组的每个对象中
  372. // 然后将sumList和nonSumList分别赋值给item的sumList和nonSumList
  373. if (rtem.sumList) {
  374. rtem.sumList.map((sumItem) => {
  375. if (
  376. sumItem.fillContent == null ||
  377. sumItem.fillContent == ""
  378. ) {
  379. // console.log("🚀 ~ rtem.sumList.map ~ sumItem:", sumItem);
  380. // sumItem.fillContent = 0;
  381. } else {
  382. // 如果是double类型,保留两位小数
  383. if (sumItem.type == "double") {
  384. sumItem.fillContent = toFixed(sumItem.fillContent);
  385. }
  386. }
  387. // 将sumItem的id赋值给modelId
  388. sumItem.modelId = sumItem.id;
  389. sumItem.pointName = sumItem.name;
  390. // 合并attrParams到sumItem中
  391. sumItem = Object.assign(sumItem, attrParams);
  392. });
  393. }
  394. if (rtem.nonSumList) {
  395. //
  396. rtem.nonSumList.map((nonSumItem) => {
  397. if (
  398. nonSumItem.fillContent == null ||
  399. nonSumItem.fillContent == ""
  400. ) {
  401. // console.log(
  402. // "🚀 ~ rtem.nonSumList.map ~ nonSumItem:",
  403. // nonSumItem
  404. // );
  405. // nonSumItem.fillContent = 0;
  406. } else {
  407. // 如果是double类型,保留两位小数
  408. if (nonSumItem.type == "double") {
  409. nonSumItem.fillContent = toFixed(
  410. nonSumItem.fillContent
  411. );
  412. }
  413. }
  414. nonSumItem.pointName = nonSumItem.name;
  415. // 将nonSumItem的id赋值给modelId
  416. nonSumItem.modelId = nonSumItem.id;
  417. // 合并attrParams到nonSumItem中
  418. nonSumItem = Object.assign(nonSumItem, attrParams);
  419. // 如果是enum类型,且description不为null,则根据description获取对应字典项数组,赋值给enumList
  420. if (nonSumItem.type == "enum" && nonSumItem.description) {
  421. console.log("🚀 ~ onSumItem.description:");
  422. nonSumItem.enumList =
  423. nonSumItem.name === "非生产原因"
  424. ? getIntDictOptions(nonSumItem.description).map(
  425. (dict) => {
  426. return {
  427. ...dict,
  428. text: dict.label,
  429. };
  430. }
  431. )
  432. : getStrDictOptions(nonSumItem.description).map(
  433. (dict) => {
  434. return {
  435. ...dict,
  436. text: dict.label,
  437. };
  438. }
  439. );
  440. console.log(
  441. "🚀 ~ nonSumItem.enumList:",
  442. nonSumItem.enumList
  443. );
  444. }
  445. });
  446. }
  447. item.sumList = rtem.sumList;
  448. item.nonSumList = rtem.nonSumList;
  449. });
  450. console.log("resAttrs-modelId", resAttrs);
  451. }
  452. } catch (error) {
  453. console.error("获取属性失败", error);
  454. // 可以选择设置默认值或标记错误状态
  455. item.sumList = [];
  456. item.nonSumList = [];
  457. }
  458. })
  459. );
  460. console.log("resList--", resList);
  461. // 将请求结果通过complete传给z-paging处理,同时也代表请求结束,这一行必须调用
  462. paging.value.complete(resList);
  463. })
  464. .catch((res) => {
  465. // 如果请求失败写paging.value.complete(false);
  466. // 注意,每次都需要在catch中写这句话很麻烦,z-paging提供了方案可以全局统一处理
  467. // 在底层的网络请求抛出异常时,写uni.$emit('z-paging-error-emit');即可
  468. paging.value.complete(false);
  469. });
  470. };
  471. // 判断是否小于阈值 (<0)
  472. const checkLessThreshold = (item) => {
  473. if (item.fillContent < 0) {
  474. uni.showToast({
  475. title:
  476. item.name +
  477. t("operationRecordFilling.fillContentCannotLessThanThreshold") +
  478. "0",
  479. icon: "none",
  480. });
  481. item.fillContent = ""; // 清空输入
  482. return false; // 返回false表示校验失败
  483. }
  484. };
  485. // 判断是否大于阈值
  486. const checkThreshold = (item) => {
  487. checkLessThreshold(item);
  488. // 如果threshold > 0,则判断fillContent是否大于threshold,如果大于则提示用户填写小于等于threshold的值
  489. if (item.fillContent > item.threshold) {
  490. uni.showToast({
  491. title:
  492. item.name +
  493. t("operationRecordFilling.fillContentCannotGreaterThanThreshold") +
  494. item.threshold,
  495. icon: "none",
  496. });
  497. item.fillContent = ""; // 清空输入
  498. return false; // 返回false表示校验失败
  499. }
  500. };
  501. // 保留两位小数
  502. const toFixed = (num) => {
  503. if (num) {
  504. num = Number(num);
  505. num = num.toFixed(2);
  506. } else {
  507. num = 0.0;
  508. }
  509. return num;
  510. };
  511. const onSubmit = async () => {
  512. console.log("onSubmit", dataList.value);
  513. // 1. 校验所有必填项
  514. // 遍历dataList.value中nonSumList每个item(非生产日报 isReport!=1)的fillContent字段,
  515. // 如果为null或者为空,则提示用户填写,
  516. // 如果threshold > 0,则判断fillContent是否大于threshold,如果大于则提示用户填写小于等于threshold的值
  517. // 如果所有项全部填写,则调用填写记录接口
  518. for (const item of dataList.value) {
  519. const nonSumList = item.nonSumList;
  520. for (const nonSumItem of nonSumList) {
  521. if (
  522. (!item.isReport || item.isReport != 1) &&
  523. (nonSumItem.fillContent == null || nonSumItem.fillContent === "")
  524. ) {
  525. uni.showToast({
  526. title:
  527. t("operation.PleaseFillIn") +
  528. item.deviceCode +
  529. "(" +
  530. item.deviceName +
  531. ")" +
  532. t("operation.allItem"),
  533. icon: "none",
  534. });
  535. return; // 校验失败直接返回
  536. }
  537. if (nonSumItem.fillContent != "" && nonSumItem.fillContent != null) {
  538. console.log("🚀 ~ nonSumItem:", nonSumItem);
  539. console.log("🚀 ~ nonSumItem.fillContent:", nonSumItem.fillContent);
  540. // 先将值转换为字符串进行操作
  541. const fillContentStr = String(nonSumItem.fillContent);
  542. // 将字符串转换为数字
  543. const num = Number(fillContentStr);
  544. // 检查转换后的数字是否有效
  545. if (!isNaN(num)) {
  546. // 检查是否包含小数(使用字符串检查)
  547. if (fillContentStr.includes(".")) {
  548. // 保留两位小数(假设toFixed是你定义的保留两位小数的函数)
  549. nonSumItem.fillContent = toFixed(num);
  550. } else {
  551. // 转换为整数
  552. nonSumItem.fillContent = Math.floor(num);
  553. }
  554. }
  555. }
  556. // 如果threshold > 0,则判断fillContent是否大于threshold
  557. if (nonSumItem.threshold > 0) {
  558. if (nonSumItem.fillContent > nonSumItem.threshold) {
  559. uni.showToast({
  560. title:
  561. item.deviceCode +
  562. "(" +
  563. item.deviceName +
  564. ")" +
  565. nonSumItem.name +
  566. t(
  567. "operationRecordFilling.fillContentCannotGreaterThanThreshold"
  568. ) +
  569. nonSumItem.threshold,
  570. icon: "none",
  571. duration: 3000,
  572. });
  573. nonSumItem.fillContent = ""; // 清空输入
  574. return; // 校验失败直接返回
  575. }
  576. }
  577. }
  578. }
  579. // 定义新的dataList副本 用于提交数据,避免修改原数据
  580. const subDataList = JSON.parse(JSON.stringify(dataList.value));
  581. // 3. 处理副本:删除 enumList(仅修改副本,不影响原数据)
  582. for (const item of subDataList) {
  583. // 先判断 item.nonSumList 存在,避免空指针
  584. if (item.nonSumList && item.nonSumList.length) {
  585. for (const nonSumItem of item.nonSumList) {
  586. if (nonSumItem.enumList) {
  587. delete nonSumItem.enumList;
  588. }
  589. }
  590. }
  591. }
  592. console.log("提交用的副本数据:subDataList", subDataList);
  593. try {
  594. // 2. 收集所有保存请求(不在这里处理导航)
  595. const submitPromises = subDataList.map(async (item) => {
  596. const submitData = [].concat(item.sumList).concat(item.nonSumList);
  597. // 仅返回接口结果,不执行导航
  598. return await recordFillingDetailInsertLog(submitData);
  599. });
  600. // 3. 等待所有请求完成
  601. const results = await Promise.all(submitPromises);
  602. // 4. 所有请求完成后,统一判断结果
  603. const allSuccess = results.every((res) => res?.code === 0);
  604. if (allSuccess) {
  605. // 5. 调用更新工单状态接口
  606. const upRes = await recordFillingUpOperationOrder({
  607. id: params.value.orderId,
  608. });
  609. console.log("🚀 ~ upRes:", upRes)
  610. if (upRes?.code === 0) {
  611. console.log("工单状态更新成功");
  612. uni.showToast({
  613. title: t("operation.success"),
  614. duration: 1500,
  615. icon: "none",
  616. });
  617. setTimeout(() => {
  618. uni.navigateBack();
  619. }, 1500);
  620. } else {
  621. console.error("工单状态更新失败", upRes);
  622. uni.showToast({
  623. title: t("operation.fail"),
  624. icon: "none",
  625. });
  626. }
  627. } else {
  628. uni.showToast({
  629. title: t("operation.fail"),
  630. icon: "none",
  631. });
  632. }
  633. } catch (error) {
  634. console.error("保存失败", error);
  635. uni.showToast({
  636. title: t("operation.fail"),
  637. icon: "error",
  638. });
  639. }
  640. };
  641. </script>
  642. <style lang="scss" scoped>
  643. .page {
  644. padding: 0;
  645. box-sizing: border-box;
  646. }
  647. .top {
  648. padding: 10px;
  649. }
  650. .list {
  651. // margin-top: calc(10px);
  652. padding: 10px;
  653. height: calc(100%);
  654. }
  655. .item {
  656. width: 100%;
  657. // height: 204px;
  658. background: #ffffff;
  659. border-radius: 6px;
  660. margin-bottom: 10px;
  661. box-sizing: border-box;
  662. padding: 20px 15px;
  663. }
  664. .item-module {
  665. width: 100%;
  666. height: 16px;
  667. position: relative;
  668. font-weight: 600;
  669. font-size: 14px;
  670. color: #333333;
  671. margin-bottom: 10px;
  672. .module-border {
  673. position: absolute;
  674. left: -15px;
  675. width: 0px;
  676. height: 12px;
  677. border: 1px solid #004098;
  678. }
  679. }
  680. .item-content {
  681. position: relative;
  682. width: 100%;
  683. // height: calc(38px);
  684. box-sizing: border-box;
  685. font-weight: 500;
  686. font-size: 14px;
  687. color: #333333;
  688. line-height: 20px;
  689. border-bottom: 1px dashed #cacccf;
  690. &:last-child {
  691. border-bottom: none;
  692. }
  693. &.bold {
  694. font-weight: 600;
  695. // :deep(.uni-easyinput__content-input){
  696. // padding-right: 0 !important;
  697. // }
  698. }
  699. &.bottom-bold {
  700. border-bottom: 1px dashed #cacccf;
  701. }
  702. }
  703. .item-title {
  704. position: relative;
  705. min-height: 38px;
  706. width: 55%;
  707. &.total {
  708. :deep(.is-disabled) {
  709. color: #333333 !important;
  710. }
  711. }
  712. &.full-cell {
  713. width: 100%;
  714. min-width: max-content;
  715. }
  716. }
  717. .item-value {
  718. width: 45%;
  719. position: relative;
  720. &.textarea {
  721. width: 65%;
  722. }
  723. }
  724. .word-break-all {
  725. min-width: unset;
  726. }
  727. :deep(.uni-select) {
  728. border: none;
  729. text-align: right;
  730. padding-right: 0;
  731. .uniui-bottom:before {
  732. content: "\e6b5" !important;
  733. font-size: 16px !important;
  734. }
  735. }
  736. :deep(.uni-select--disabled) {
  737. color: #d5d5d5 !important;
  738. background-color: transparent;
  739. .uni-select__input-text {
  740. color: #d5d5d5 !important;
  741. }
  742. }
  743. :deep(.uni-select__selector) {
  744. text-align: left;
  745. }
  746. :deep(.uni-select__selector-item) {
  747. border-bottom: 1px dashed #cacccf;
  748. text-align: left;
  749. }
  750. :deep(.uni-easyinput__content-textarea) {
  751. min-height: inherit;
  752. margin: 10px;
  753. }
  754. </style>