|
@@ -0,0 +1,793 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <z-paging
|
|
|
|
|
+ class="page"
|
|
|
|
|
+ ref="paging"
|
|
|
|
|
+ v-model="dataList"
|
|
|
|
|
+ :loading-more-enabled="false"
|
|
|
|
|
+ @query="queryList"
|
|
|
|
|
+ >
|
|
|
|
|
+ <!-- z-paging默认铺满全屏,此时页面所有view都应放在z-paging标签内,否则会被盖住 -->
|
|
|
|
|
+ <!-- 需要固定在页面顶部的view请通过slot="top"插入,包括自定义的导航栏 -->
|
|
|
|
|
+ <view class="list">
|
|
|
|
|
+ <!-- 工单基础信息 -->
|
|
|
|
|
+ <view class="item top">
|
|
|
|
|
+ <view class="item-content flex-row align-center">
|
|
|
|
|
+ <view class="item-title full-cell flex-row align-center">
|
|
|
|
|
+ <span class="item-title-width"
|
|
|
|
|
+ >{{ $t("operationRecordFilling.workOrderName") }}:</span
|
|
|
|
|
+ >
|
|
|
|
|
+ <span>{{ params.orderName }}</span>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="item-content flex-row align-center">
|
|
|
|
|
+ <view class="item-title full-cell flex-row align-center">
|
|
|
|
|
+ <span class="item-title-width"
|
|
|
|
|
+ >{{ $t("operationRecordFilling.responsiblePerson") }}:</span
|
|
|
|
|
+ >
|
|
|
|
|
+ <span>{{ params.userName }}</span>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="item-content flex-row align-center">
|
|
|
|
|
+ <view class="item-title full-cell flex-row align-center">
|
|
|
|
|
+ <span class="item-title-width"
|
|
|
|
|
+ >{{ $t("operation.createTime") }}:</span
|
|
|
|
|
+ >
|
|
|
|
|
+ <span>{{ params.createTime }}</span>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <!-- 填报列表 -->
|
|
|
|
|
+ <view class="item" v-for="(item, index) in dataList" :key="index">
|
|
|
|
|
+ <view class="item-module flex-row align-center justify-between">
|
|
|
|
|
+ <view class="module-name">
|
|
|
|
|
+ {{ item.deviceCode }}({{ item.deviceName }})
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="module-border"> </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="item-content flex-row align-center justify-between bold">
|
|
|
|
|
+ <view class="item-title flex-row align-center">
|
|
|
|
|
+ <span>{{ $t("operationRecordFilling.belongToTeam") }}:</span>
|
|
|
|
|
+ <span>{{ item.orgName }}</span>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view
|
|
|
|
|
+ class="item-content flex-row align-center justify-between bold"
|
|
|
|
|
+ v-for="sum in item.sumList"
|
|
|
|
|
+ >
|
|
|
|
|
+ <view class="item-title flex-row align-center word-break-all">
|
|
|
|
|
+ <span>{{ sum.name }}:</span>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="item-value flex-row align-center justify-end total">
|
|
|
|
|
+ <uni-easyinput
|
|
|
|
|
+ style="text-align: right"
|
|
|
|
|
+ :inputBorder="false"
|
|
|
|
|
+ :clearable="true"
|
|
|
|
|
+ :styles="{ disableColor: '#fff' }"
|
|
|
|
|
+ :value="`${sum.totalRunTime} ${
|
|
|
|
|
+ sum.modelAttr ? (sum.modelAttr.includes('Time') ? 'h' : '') : ''
|
|
|
|
|
+ }`"
|
|
|
|
|
+ :disabled="true"
|
|
|
|
|
+ ></uni-easyinput>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view
|
|
|
|
|
+ class="item-content flex-col align-center justify-between"
|
|
|
|
|
+ :class="{ 'bottom-bold': item.nonSumList.length > 0 }"
|
|
|
|
|
+ v-for="nosum in item.nonSumList"
|
|
|
|
|
+ >
|
|
|
|
|
+ <!-- isCollection为1,提示:以下数值取自PLC,如有不符请修改 -->
|
|
|
|
|
+ <uni-notice-bar
|
|
|
|
|
+ :text="$t('operationRecordFilling.plcNotice')"
|
|
|
|
|
+ v-if="nosum.isCollection == 1"
|
|
|
|
|
+ />
|
|
|
|
|
+ <view class="flex-row align-center justify-between item-content">
|
|
|
|
|
+ <view class="item-title flex-row align-center">
|
|
|
|
|
+ <span>{{ nosum.name }}:</span>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <!-- 判断填写项的属性 -->
|
|
|
|
|
+ <!-- type为double时,输入框为数字类型 -->
|
|
|
|
|
+ <view
|
|
|
|
|
+ class="item-value flex-row align-center justify-end"
|
|
|
|
|
+ v-if="nosum.type == 'double'"
|
|
|
|
|
+ >
|
|
|
|
|
+ <uni-easyinput
|
|
|
|
|
+ style="text-align: right"
|
|
|
|
|
+ :styles="{ disableColor: '#fff' }"
|
|
|
|
|
+ :inputBorder="false"
|
|
|
|
|
+ :clearable="true"
|
|
|
|
|
+ :placeholder="$t('operation.PleaseFillIn')"
|
|
|
|
|
+ :disabled="!isView"
|
|
|
|
|
+ v-model="nosum.fillContent"
|
|
|
|
|
+ :type="'digit'"
|
|
|
|
|
+ @blur="
|
|
|
|
|
+ nosum.threshold > 0
|
|
|
|
|
+ ? checkThreshold(nosum)
|
|
|
|
|
+ : checkLessThreshold(nosum)
|
|
|
|
|
+ "
|
|
|
|
|
+ @change="handleFillContentChange(nosum, item)"
|
|
|
|
|
+ ></uni-easyinput>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <!-- type为textarea时,输入框为文本类型 -->
|
|
|
|
|
+ <view
|
|
|
|
|
+ class="item-value flex-row align-center justify-end"
|
|
|
|
|
+ v-else-if="nosum.type == 'textarea'"
|
|
|
|
|
+ >
|
|
|
|
|
+ <uni-easyinput
|
|
|
|
|
+ style="text-align: right"
|
|
|
|
|
+ :styles="{ disableColor: '#fff' }"
|
|
|
|
|
+ :inputBorder="false"
|
|
|
|
|
+ :clearable="true"
|
|
|
|
|
+ :placeholder="$t('operation.PleaseFillIn')"
|
|
|
|
|
+ :disabled="!isView"
|
|
|
|
|
+ v-model="nosum.fillContent"
|
|
|
|
|
+ :type="'textarea'"
|
|
|
|
|
+ :autoHeight="true"
|
|
|
|
|
+ :maxlength="-1"
|
|
|
|
|
+ ></uni-easyinput>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <!-- type为enum时,使用下拉菜单 -->
|
|
|
|
|
+ <view
|
|
|
|
|
+ class="item-value textarea flex-row align-center justify-end"
|
|
|
|
|
+ v-else-if="nosum.type == 'enum' && nosum.description !== null"
|
|
|
|
|
+ >
|
|
|
|
|
+ <uni-data-select
|
|
|
|
|
+ :localdata="nosum.enumList"
|
|
|
|
|
+ :styles="{ disableColor: '#fff' }"
|
|
|
|
|
+ :clear="false"
|
|
|
|
|
+ :disabled="!isView"
|
|
|
|
|
+ :placeholder="$t('operation.PleaseSelect')"
|
|
|
|
|
+ v-model="nosum.fillContent"
|
|
|
|
|
+ ></uni-data-select>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <!-- 其他类型时,输入框为文本类型 -->
|
|
|
|
|
+ <view class="item-value flex-row align-center justify-end" v-else>
|
|
|
|
|
+ <uni-easyinput
|
|
|
|
|
+ style="text-align: right"
|
|
|
|
|
+ :styles="{ disableColor: '#fff' }"
|
|
|
|
|
+ :inputBorder="false"
|
|
|
|
|
+ :clearable="true"
|
|
|
|
|
+ :placeholder="$t('operation.PleaseFillIn')"
|
|
|
|
|
+ :disabled="!isView"
|
|
|
|
|
+ v-model="nosum.fillContent"
|
|
|
|
|
+ :type="'text'"
|
|
|
|
|
+ ></uni-easyinput>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <!-- 如果需要使用页脚,请使用slot="bottom"slot节点不支持通过v-if或v-show动态显示/隐藏,若需要动态控制,可将v-if添加在其子节点上 -->
|
|
|
|
|
+ <template #bottom>
|
|
|
|
|
+ <button
|
|
|
|
|
+ style="border-radius: 0"
|
|
|
|
|
+ type="primary"
|
|
|
|
|
+ @click="onSubmit()"
|
|
|
|
|
+ >
|
|
|
|
|
+ {{ $t("operation.save") }}
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </z-paging>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script setup>
|
|
|
|
|
+import { ref, reactive, getCurrentInstance, watch, onMounted } from "vue";
|
|
|
|
|
+import { onReady, onLoad } from "@dcloudio/uni-app";
|
|
|
|
|
+import dayjs from "dayjs";
|
|
|
|
|
+import {
|
|
|
|
|
+ getRecordFillingDetailGetPage,
|
|
|
|
|
+ getRecordFillingDetailGetAttrs,
|
|
|
|
|
+ recordFillingDetailInsertLog,
|
|
|
|
|
+ getRecordFillingDetail,
|
|
|
|
|
+ recordFillingUpOperationOrder,
|
|
|
|
|
+} from "@/api/recordFilling";
|
|
|
|
|
+import { getUserId, reloginByUserId } from "@/utils/auth.js";
|
|
|
|
|
+import { useDataDictStore } from "@/store/modules/dataDict";
|
|
|
|
|
+// 引用全局变量$t
|
|
|
|
|
+const { appContext } = getCurrentInstance();
|
|
|
|
|
+const t = appContext.config.globalProperties.$t;
|
|
|
|
|
+
|
|
|
|
|
+// 获取字典项
|
|
|
|
|
+const { getStrDictOptions, getIntDictOptions } = useDataDictStore();
|
|
|
|
|
+
|
|
|
|
|
+// -------------------------------------
|
|
|
|
|
+const isFromMsg = ref(false);
|
|
|
|
|
+const params = ref({});
|
|
|
|
|
+const isView = ref(false); // 是否编辑 -- view == 1为编辑状态
|
|
|
|
|
+
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ console.log("onMounted");
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+onReady(() => {
|
|
|
|
|
+ console.log("onReady");
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+onLoad(async (option) => {
|
|
|
|
|
+ console.log("onLoad", option);
|
|
|
|
|
+ await reloginByUserId(option.reloginUserId);
|
|
|
|
|
+ isFromMsg.value = !!option.reloginUserId;
|
|
|
|
|
+ // 初始化params
|
|
|
|
|
+ params.value = JSON.parse(option.param);
|
|
|
|
|
+ // 处理createTime
|
|
|
|
|
+ params.value.createTime = params.value.createTime
|
|
|
|
|
+ ? dayjs(Number.parseInt(params.value.createTime)).format("YYYY-MM-DD")
|
|
|
|
|
+ : "";
|
|
|
|
|
+ // 请求工单详情
|
|
|
|
|
+ if (params.value?.orderId) {
|
|
|
|
|
+ const detail = (await getRecordFillingDetail(params.value.orderId)).data;
|
|
|
|
|
+ console.log("🚀getRecordFillingDetail ~ detail:", detail);
|
|
|
|
|
+ params.value = {
|
|
|
|
|
+ ...params.value,
|
|
|
|
|
+ ...detail,
|
|
|
|
|
+ // 处理createTime
|
|
|
|
|
+ createTime: detail.createTime
|
|
|
|
|
+ ? dayjs(Number.parseInt(detail.createTime)).format("YYYY-MM-DD")
|
|
|
|
|
+ : "",
|
|
|
|
|
+ orderId: detail.id,
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ console.log("🚀 ~ params.value:", params.value);
|
|
|
|
|
+ // 处理是否可编辑 {0: '待填写', 1: '已完成', 2: '填写中', 3: '忽略'}
|
|
|
|
|
+ isView.value = params.value?.orderStatus % 2 == 0;
|
|
|
|
|
+ console.log("🚀 ~ isView.value:", isView.value);
|
|
|
|
|
+});
|
|
|
|
|
+const paging = ref(null);
|
|
|
|
|
+// v-model绑定的这个变量不要在分页请求结束中自己赋值,直接使用即可
|
|
|
|
|
+const dataList = ref([]);
|
|
|
|
|
+
|
|
|
|
|
+// 监听dataList变化,初始化时计算一次总和
|
|
|
|
|
+watch(
|
|
|
|
|
+ dataList,
|
|
|
|
|
+ (newVal) => {
|
|
|
|
|
+ // calculateTotalRunTime();
|
|
|
|
|
+ },
|
|
|
|
|
+ { deep: true }
|
|
|
|
|
+);
|
|
|
|
|
+
|
|
|
|
|
+// 处理fillContent变化的方法
|
|
|
|
|
+const handleFillContentChange = (nosum, deviceItem) => {
|
|
|
|
|
+ console.log("🚀 ~ nosum, deviceItem:", nosum, deviceItem);
|
|
|
|
|
+ // 处理增压机
|
|
|
|
|
+ if (
|
|
|
|
|
+ deviceItem.deviceName.includes("增压机") &&
|
|
|
|
|
+ nosum.name === "当日运转时间"
|
|
|
|
|
+ ) {
|
|
|
|
|
+ calculateTotalRunTime("增压机", "当日运转时间"); // 计算当日运转时间总和
|
|
|
|
|
+ }
|
|
|
|
|
+ // 处理提纯撬
|
|
|
|
|
+ if (deviceItem.deviceName.includes("提纯撬") && nosum.name === "当日注气量") {
|
|
|
|
|
+ calculateTotalRunTime("提纯撬", "当日注气量"); // 计算当日注气量总和
|
|
|
|
|
+ }
|
|
|
|
|
+ // 处理注水泵
|
|
|
|
|
+ if (deviceItem.deviceName.includes("注水泵") && nosum.name === "当日注水量") {
|
|
|
|
|
+ calculateTotalRunTime("注水泵", "当日注水量"); // 计算当日注水量总和
|
|
|
|
|
+ }
|
|
|
|
|
+ // 处理箱式变电站
|
|
|
|
|
+ if (
|
|
|
|
|
+ deviceItem.deviceName.includes("箱式变电站") &&
|
|
|
|
|
+ nosum.name === "当日用电量"
|
|
|
|
|
+ ) {
|
|
|
|
|
+ calculateTotalRunTime("箱式变电站", "当日用电量"); // 计算当日用电量总和
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 计算所有deviceName中包含deviceNameToMatch的对象中对应的reportName的fillContent总和并更新到reportName的fillContent中
|
|
|
|
|
+ * @param deviceNameToMatch {string} 设备名称包含的字符串
|
|
|
|
|
+ * @param reportName {string} 填写项名称
|
|
|
|
|
+ */
|
|
|
|
|
+const calculateTotalRunTime = (deviceNameToMatch, reportName) => {
|
|
|
|
|
+ console.log(
|
|
|
|
|
+ "🚀calculateTotalRunTime ~ deviceNameToMatch, reportName:",
|
|
|
|
|
+ deviceNameToMatch,
|
|
|
|
|
+ 12
|
|
|
|
|
+ );
|
|
|
|
|
+ // 查找isReport为1的对象
|
|
|
|
|
+ const reportItem = dataList.value.find((item) => item.isReport === 1);
|
|
|
|
|
+ console.log("🚀calculateTotalRunTime ~ reportItem:", reportItem);
|
|
|
|
|
+
|
|
|
|
|
+ if (!reportItem) return;
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @param deviceNameToMatch {string} 设备名称包含的字符串
|
|
|
|
|
+ * @param deviceName {string} 设备名称
|
|
|
|
|
+ * @param reportName {string} 填写项名称
|
|
|
|
|
+ * 查找[生产日报]中对应的填写项
|
|
|
|
|
+ * reportName -> deviceName:reportName
|
|
|
|
|
+ * 当日运转时间 -> 增压机:当日运转时间
|
|
|
|
|
+ * 当日注气量 -> 提纯撬:当日注气量
|
|
|
|
|
+ * 当日注水量 -> 注水泵:当日注水量
|
|
|
|
|
+ * 当日用电量 -> 箱式变电站:当日用电量
|
|
|
|
|
+ */
|
|
|
|
|
+ const targetItem = reportItem.nonSumList.find(
|
|
|
|
|
+ (item) => item.name === reportName
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ if (!targetItem) return;
|
|
|
|
|
+
|
|
|
|
|
+ // 计算所有deviceName中包含deviceNameToMatch的对象中对应的reportName的fillContent总和
|
|
|
|
|
+ let total = null;
|
|
|
|
|
+ dataList.value.forEach((item) => {
|
|
|
|
|
+ if (item.deviceName.includes(deviceNameToMatch) && item.nonSumList) {
|
|
|
|
|
+ item.nonSumList.forEach((nonSum) => {
|
|
|
|
|
+ // 只累加数字类型的值
|
|
|
|
|
+ if (
|
|
|
|
|
+ nonSum.type === "double" &&
|
|
|
|
|
+ nonSum.fillContent &&
|
|
|
|
|
+ nonSum.name === reportName
|
|
|
|
|
+ ) {
|
|
|
|
|
+ console.log("🚀 ~ nonSum.fillContent:", nonSum.fillContent);
|
|
|
|
|
+ console.log("🚀 ~ nonSum:", nonSum);
|
|
|
|
|
+ const value = Number(nonSum.fillContent) || 0;
|
|
|
|
|
+ total += value;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ console.log("🚀 ~ total:", total);
|
|
|
|
|
+ if (total !== null) {
|
|
|
|
|
+ // 更新目标值,保留两位小数
|
|
|
|
|
+ targetItem.fillContent = toFixed(total);
|
|
|
|
|
+ console.log("🚀 ~ targetItem.fillContent:", targetItem.fillContent);
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// @query所绑定的方法不要自己调用!!需要刷新列表数据时,只需要调用paging.value.reload()即可
|
|
|
|
|
+const queryList = (pageNo, pageSize) => {
|
|
|
|
|
+ const userId = uni.getStorageSync("userId");
|
|
|
|
|
+ if (!userId) {
|
|
|
|
|
+ paging.value.complete([]);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 此处请求仅为演示,请替换为自己项目中的请求
|
|
|
|
|
+ getRecordFillingDetailGetPage({
|
|
|
|
|
+ // pageNo,
|
|
|
|
|
+ // pageSize,
|
|
|
|
|
+ ...params.value,
|
|
|
|
|
+ deviceCategoryId: 1,
|
|
|
|
|
+ })
|
|
|
|
|
+ .then(async (res) => {
|
|
|
|
|
+ const resList = [].concat(res.data);
|
|
|
|
|
+
|
|
|
|
|
+ // 使用Promise.all等待所有异步请求完成
|
|
|
|
|
+ await Promise.all(
|
|
|
|
|
+ resList.map(async (item) => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const attrParams = {
|
|
|
|
|
+ deviceCode: item.deviceCode,
|
|
|
|
|
+ deviceName: item.deviceName,
|
|
|
|
|
+ deptId: item.deptId,
|
|
|
|
|
+ createTime: params.value.createTime,
|
|
|
|
|
+ deviceCategoryId: item.deviceCategoryId,
|
|
|
|
|
+ deviceId: item.deviceId,
|
|
|
|
|
+ userId: params.value.userId,
|
|
|
|
|
+ orderId: params.value.orderId,
|
|
|
|
|
+ };
|
|
|
|
|
+ // console.log(
|
|
|
|
|
+ // "getRecordFillingDetailGetAttrs- attrParams",
|
|
|
|
|
+ // attrParams
|
|
|
|
|
+ // );
|
|
|
|
|
+ const resAttrs = await getRecordFillingDetailGetAttrs({
|
|
|
|
|
+ pageNo: 1,
|
|
|
|
|
+ pageSize: 10,
|
|
|
|
|
+ ...attrParams,
|
|
|
|
|
+ });
|
|
|
|
|
+ // console.log("resAttrs", resAttrs);
|
|
|
|
|
+ if (resAttrs?.data) {
|
|
|
|
|
+ attrParams.createTime = attrParams.createTime
|
|
|
|
|
+ ? dayjs(attrParams.createTime).format("YYYY-MM-DD")
|
|
|
|
|
+ : "";
|
|
|
|
|
+ attrParams.id = attrParams.orderId;
|
|
|
|
|
+ delete attrParams.orderId;
|
|
|
|
|
+ delete attrParams.deviceName;
|
|
|
|
|
+ resAttrs.data.map((rtem) => {
|
|
|
|
|
+ // 将rtem中sumList和nonSumList两个数组中的
|
|
|
|
|
+ // fillContent字段判断是否为null, 如果为null,则赋值为0 不为null则保留两位小数
|
|
|
|
|
+ // 将attrParams合并到两个数组的每个对象中
|
|
|
|
|
+ // 然后将sumList和nonSumList分别赋值给item的sumList和nonSumList
|
|
|
|
|
+
|
|
|
|
|
+ if (rtem.sumList) {
|
|
|
|
|
+ rtem.sumList.map((sumItem) => {
|
|
|
|
|
+ if (
|
|
|
|
|
+ sumItem.fillContent == null ||
|
|
|
|
|
+ sumItem.fillContent == ""
|
|
|
|
|
+ ) {
|
|
|
|
|
+ // console.log("🚀 ~ rtem.sumList.map ~ sumItem:", sumItem);
|
|
|
|
|
+ // sumItem.fillContent = 0;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 如果是double类型,保留两位小数
|
|
|
|
|
+ if (sumItem.type == "double") {
|
|
|
|
|
+ sumItem.fillContent = toFixed(sumItem.fillContent);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // 将sumItem的id赋值给modelId
|
|
|
|
|
+ sumItem.modelId = sumItem.id;
|
|
|
|
|
+
|
|
|
|
|
+ sumItem.pointName = sumItem.name;
|
|
|
|
|
+ // 合并attrParams到sumItem中
|
|
|
|
|
+ sumItem = Object.assign(sumItem, attrParams);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ if (rtem.nonSumList) {
|
|
|
|
|
+ //
|
|
|
|
|
+ rtem.nonSumList.map((nonSumItem) => {
|
|
|
|
|
+ if (
|
|
|
|
|
+ nonSumItem.fillContent == null ||
|
|
|
|
|
+ nonSumItem.fillContent == ""
|
|
|
|
|
+ ) {
|
|
|
|
|
+ // console.log(
|
|
|
|
|
+ // "🚀 ~ rtem.nonSumList.map ~ nonSumItem:",
|
|
|
|
|
+ // nonSumItem
|
|
|
|
|
+ // );
|
|
|
|
|
+ // nonSumItem.fillContent = 0;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 如果是double类型,保留两位小数
|
|
|
|
|
+ if (nonSumItem.type == "double") {
|
|
|
|
|
+ nonSumItem.fillContent = toFixed(
|
|
|
|
|
+ nonSumItem.fillContent
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ nonSumItem.pointName = nonSumItem.name;
|
|
|
|
|
+ // 将nonSumItem的id赋值给modelId
|
|
|
|
|
+ nonSumItem.modelId = nonSumItem.id;
|
|
|
|
|
+ // 合并attrParams到nonSumItem中
|
|
|
|
|
+ nonSumItem = Object.assign(nonSumItem, attrParams);
|
|
|
|
|
+ // 如果是enum类型,且description不为null,则根据description获取对应字典项数组,赋值给enumList
|
|
|
|
|
+ if (nonSumItem.type == "enum" && nonSumItem.description) {
|
|
|
|
|
+ console.log("🚀 ~ onSumItem.description:");
|
|
|
|
|
+ nonSumItem.enumList =
|
|
|
|
|
+ nonSumItem.name === "非生产原因"
|
|
|
|
|
+ ? getIntDictOptions(nonSumItem.description).map(
|
|
|
|
|
+ (dict) => {
|
|
|
|
|
+ return {
|
|
|
|
|
+ ...dict,
|
|
|
|
|
+ text: dict.label,
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+ )
|
|
|
|
|
+ : getStrDictOptions(nonSumItem.description).map(
|
|
|
|
|
+ (dict) => {
|
|
|
|
|
+ return {
|
|
|
|
|
+ ...dict,
|
|
|
|
|
+ text: dict.label,
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+ );
|
|
|
|
|
+ console.log(
|
|
|
|
|
+ "🚀 ~ nonSumItem.enumList:",
|
|
|
|
|
+ nonSumItem.enumList
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ item.sumList = rtem.sumList;
|
|
|
|
|
+
|
|
|
|
|
+ item.nonSumList = rtem.nonSumList;
|
|
|
|
|
+ });
|
|
|
|
|
+ console.log("resAttrs-modelId", resAttrs);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error("获取属性失败", error);
|
|
|
|
|
+ // 可以选择设置默认值或标记错误状态
|
|
|
|
|
+ item.sumList = [];
|
|
|
|
|
+ item.nonSumList = [];
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ );
|
|
|
|
|
+ console.log("resList--", resList);
|
|
|
|
|
+ // 将请求结果通过complete传给z-paging处理,同时也代表请求结束,这一行必须调用
|
|
|
|
|
+ paging.value.complete(resList);
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch((res) => {
|
|
|
|
|
+ // 如果请求失败写paging.value.complete(false);
|
|
|
|
|
+ // 注意,每次都需要在catch中写这句话很麻烦,z-paging提供了方案可以全局统一处理
|
|
|
|
|
+ // 在底层的网络请求抛出异常时,写uni.$emit('z-paging-error-emit');即可
|
|
|
|
|
+ paging.value.complete(false);
|
|
|
|
|
+ });
|
|
|
|
|
+};
|
|
|
|
|
+// 判断是否小于阈值 (<0)
|
|
|
|
|
+const checkLessThreshold = (item) => {
|
|
|
|
|
+ if (item.fillContent < 0) {
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title:
|
|
|
|
|
+ item.name +
|
|
|
|
|
+ t("operationRecordFilling.fillContentCannotLessThanThreshold") +
|
|
|
|
|
+ "0",
|
|
|
|
|
+ icon: "none",
|
|
|
|
|
+ });
|
|
|
|
|
+ item.fillContent = ""; // 清空输入
|
|
|
|
|
+ return false; // 返回false表示校验失败
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+// 判断是否大于阈值
|
|
|
|
|
+const checkThreshold = (item) => {
|
|
|
|
|
+ checkLessThreshold(item);
|
|
|
|
|
+ // 如果threshold > 0,则判断fillContent是否大于threshold,如果大于则提示用户填写小于等于threshold的值
|
|
|
|
|
+ if (item.fillContent > item.threshold) {
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title:
|
|
|
|
|
+ item.name +
|
|
|
|
|
+ t("operationRecordFilling.fillContentCannotGreaterThanThreshold") +
|
|
|
|
|
+ item.threshold,
|
|
|
|
|
+ icon: "none",
|
|
|
|
|
+ });
|
|
|
|
|
+ item.fillContent = ""; // 清空输入
|
|
|
|
|
+ return false; // 返回false表示校验失败
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 保留两位小数
|
|
|
|
|
+const toFixed = (num) => {
|
|
|
|
|
+ if (num) {
|
|
|
|
|
+ num = Number(num);
|
|
|
|
|
+ num = num.toFixed(2);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ num = 0.0;
|
|
|
|
|
+ }
|
|
|
|
|
+ return num;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const onSubmit = async () => {
|
|
|
|
|
+ console.log("onSubmit", dataList.value);
|
|
|
|
|
+ // 1. 校验所有必填项
|
|
|
|
|
+ // 遍历dataList.value中nonSumList每个item(非生产日报 isReport!=1)的fillContent字段,
|
|
|
|
|
+ // 如果为null或者为空,则提示用户填写,
|
|
|
|
|
+ // 如果threshold > 0,则判断fillContent是否大于threshold,如果大于则提示用户填写小于等于threshold的值
|
|
|
|
|
+ // 如果所有项全部填写,则调用填写记录接口
|
|
|
|
|
+
|
|
|
|
|
+ for (const item of dataList.value) {
|
|
|
|
|
+ const nonSumList = item.nonSumList;
|
|
|
|
|
+ for (const nonSumItem of nonSumList) {
|
|
|
|
|
+ if (
|
|
|
|
|
+ (!item.isReport || item.isReport != 1) &&
|
|
|
|
|
+ (nonSumItem.fillContent == null || nonSumItem.fillContent === "")
|
|
|
|
|
+ ) {
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title:
|
|
|
|
|
+ t("operation.PleaseFillIn") +
|
|
|
|
|
+ item.deviceCode +
|
|
|
|
|
+ "(" +
|
|
|
|
|
+ item.deviceName +
|
|
|
|
|
+ ")" +
|
|
|
|
|
+ t("operation.allItem"),
|
|
|
|
|
+ icon: "none",
|
|
|
|
|
+ });
|
|
|
|
|
+ return; // 校验失败直接返回
|
|
|
|
|
+ }
|
|
|
|
|
+ if (nonSumItem.fillContent != "" && nonSumItem.fillContent != null) {
|
|
|
|
|
+ console.log("🚀 ~ nonSumItem:", nonSumItem);
|
|
|
|
|
+ console.log("🚀 ~ nonSumItem.fillContent:", nonSumItem.fillContent);
|
|
|
|
|
+ // 先将值转换为字符串进行操作
|
|
|
|
|
+ const fillContentStr = String(nonSumItem.fillContent);
|
|
|
|
|
+ // 将字符串转换为数字
|
|
|
|
|
+ const num = Number(fillContentStr);
|
|
|
|
|
+
|
|
|
|
|
+ // 检查转换后的数字是否有效
|
|
|
|
|
+ if (!isNaN(num)) {
|
|
|
|
|
+ // 检查是否包含小数(使用字符串检查)
|
|
|
|
|
+ if (fillContentStr.includes(".")) {
|
|
|
|
|
+ // 保留两位小数(假设toFixed是你定义的保留两位小数的函数)
|
|
|
|
|
+ nonSumItem.fillContent = toFixed(num);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 转换为整数
|
|
|
|
|
+ nonSumItem.fillContent = Math.floor(num);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // 如果threshold > 0,则判断fillContent是否大于threshold
|
|
|
|
|
+ if (nonSumItem.threshold > 0) {
|
|
|
|
|
+ if (nonSumItem.fillContent > nonSumItem.threshold) {
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title:
|
|
|
|
|
+ item.deviceCode +
|
|
|
|
|
+ "(" +
|
|
|
|
|
+ item.deviceName +
|
|
|
|
|
+ ")" +
|
|
|
|
|
+ nonSumItem.name +
|
|
|
|
|
+ t(
|
|
|
|
|
+ "operationRecordFilling.fillContentCannotGreaterThanThreshold"
|
|
|
|
|
+ ) +
|
|
|
|
|
+ nonSumItem.threshold,
|
|
|
|
|
+ icon: "none",
|
|
|
|
|
+ duration: 3000,
|
|
|
|
|
+ });
|
|
|
|
|
+ nonSumItem.fillContent = ""; // 清空输入
|
|
|
|
|
+ return; // 校验失败直接返回
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // 定义新的dataList副本 用于提交数据,避免修改原数据
|
|
|
|
|
+ const subDataList = JSON.parse(JSON.stringify(dataList.value));
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 处理副本:删除 enumList(仅修改副本,不影响原数据)
|
|
|
|
|
+ for (const item of subDataList) {
|
|
|
|
|
+ // 先判断 item.nonSumList 存在,避免空指针
|
|
|
|
|
+ if (item.nonSumList && item.nonSumList.length) {
|
|
|
|
|
+ for (const nonSumItem of item.nonSumList) {
|
|
|
|
|
+ if (nonSumItem.enumList) {
|
|
|
|
|
+ delete nonSumItem.enumList;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ console.log("提交用的副本数据:subDataList", subDataList);
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 2. 收集所有保存请求(不在这里处理导航)
|
|
|
|
|
+ const submitPromises = subDataList.map(async (item) => {
|
|
|
|
|
+ const submitData = [].concat(item.sumList).concat(item.nonSumList);
|
|
|
|
|
+ // 仅返回接口结果,不执行导航
|
|
|
|
|
+ return await recordFillingDetailInsertLog(submitData);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 等待所有请求完成
|
|
|
|
|
+ const results = await Promise.all(submitPromises);
|
|
|
|
|
+
|
|
|
|
|
+ // 4. 所有请求完成后,统一判断结果
|
|
|
|
|
+ const allSuccess = results.every((res) => res?.code === 0);
|
|
|
|
|
+ if (allSuccess) {
|
|
|
|
|
+ // 5. 调用更新工单状态接口
|
|
|
|
|
+ const upRes = await recordFillingUpOperationOrder({
|
|
|
|
|
+ id: params.value.orderId,
|
|
|
|
|
+ });
|
|
|
|
|
+ console.log("🚀 ~ upRes:", upRes)
|
|
|
|
|
+ if (upRes?.code === 0) {
|
|
|
|
|
+ console.log("工单状态更新成功");
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title: t("operation.success"),
|
|
|
|
|
+ duration: 1500,
|
|
|
|
|
+ icon: "none",
|
|
|
|
|
+ });
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ uni.navigateBack();
|
|
|
|
|
+ }, 1500);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.error("工单状态更新失败", upRes);
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title: t("operation.fail"),
|
|
|
|
|
+ icon: "none",
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title: t("operation.fail"),
|
|
|
|
|
+ icon: "none",
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error("保存失败", error);
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title: t("operation.fail"),
|
|
|
|
|
+ icon: "error",
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
|
+.page {
|
|
|
|
|
+ padding: 0;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.top {
|
|
|
|
|
+ padding: 10px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.list {
|
|
|
|
|
+ // margin-top: calc(10px);
|
|
|
|
|
+ padding: 10px;
|
|
|
|
|
+ height: calc(100%);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.item {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ // height: 204px;
|
|
|
|
|
+ background: #ffffff;
|
|
|
|
|
+ border-radius: 6px;
|
|
|
|
|
+ margin-bottom: 10px;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ padding: 20px 15px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.item-module {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 16px;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: #333333;
|
|
|
|
|
+ margin-bottom: 10px;
|
|
|
|
|
+
|
|
|
|
|
+ .module-border {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ left: -15px;
|
|
|
|
|
+ width: 0px;
|
|
|
|
|
+ height: 12px;
|
|
|
|
|
+ border: 1px solid #004098;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.item-content {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ // height: calc(38px);
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: #333333;
|
|
|
|
|
+ line-height: 20px;
|
|
|
|
|
+ border-bottom: 1px dashed #cacccf;
|
|
|
|
|
+
|
|
|
|
|
+ &:last-child {
|
|
|
|
|
+ border-bottom: none;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.bold {
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ // :deep(.uni-easyinput__content-input){
|
|
|
|
|
+ // padding-right: 0 !important;
|
|
|
|
|
+ // }
|
|
|
|
|
+ }
|
|
|
|
|
+ &.bottom-bold {
|
|
|
|
|
+ border-bottom: 1px dashed #cacccf;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.item-title {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ min-height: 38px;
|
|
|
|
|
+ width: 55%;
|
|
|
|
|
+
|
|
|
|
|
+ &.total {
|
|
|
|
|
+ :deep(.is-disabled) {
|
|
|
|
|
+ color: #333333 !important;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ &.full-cell {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ min-width: max-content;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.item-value {
|
|
|
|
|
+ width: 45%;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ &.textarea {
|
|
|
|
|
+ width: 65%;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+.word-break-all {
|
|
|
|
|
+ min-width: unset;
|
|
|
|
|
+}
|
|
|
|
|
+:deep(.uni-select) {
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ text-align: right;
|
|
|
|
|
+ padding-right: 0;
|
|
|
|
|
+ .uniui-bottom:before {
|
|
|
|
|
+ content: "\e6b5" !important;
|
|
|
|
|
+ font-size: 16px !important;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+:deep(.uni-select--disabled) {
|
|
|
|
|
+ color: #d5d5d5 !important;
|
|
|
|
|
+ background-color: transparent;
|
|
|
|
|
+ .uni-select__input-text {
|
|
|
|
|
+ color: #d5d5d5 !important;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+:deep(.uni-select__selector) {
|
|
|
|
|
+ text-align: left;
|
|
|
|
|
+}
|
|
|
|
|
+:deep(.uni-select__selector-item) {
|
|
|
|
|
+ border-bottom: 1px dashed #cacccf;
|
|
|
|
|
+ text-align: left;
|
|
|
|
|
+}
|
|
|
|
|
+:deep(.uni-easyinput__content-textarea) {
|
|
|
|
|
+ min-height: inherit;
|
|
|
|
|
+ margin: 10px;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|