spring
2025-11-20 5384750e59bbb27c54e090100429c48eaba46df0
src/pages/production/wire/selfInspect/index.vue
@@ -1,103 +1,571 @@
<template>
  <view class="list">
    <z-paging ref="pagingRef" v-model="cardList" :fixed="false" @query="getList">
      <template #top>
        <CardTitle title="拉丝自检" :hideAction="false" />
    <CardTitle title="自检管理" :hideAction="false" :full="false">
      <template #action>
        <wd-button
          icon="file-add"
          :round="false"
          size="small"
          custom-class="add_btn"
          @click="handleOpenAddDialog"
        >
          新增自检
        </wd-button>
      </template>
      <wd-card v-for="(item, index) in cardList" :key="index" type="rectangle" custom-class="round">
    </CardTitle>
    <!-- 自检列表(卡片样式) -->
    <view class="inspection-list">
      <wd-card
        v-for="(item, index) in dataList"
        :key="item.id || index"
        class="card_bg"
        style="margin-bottom: 12px"
      >
        <template #title>
          <view class="flex justify-between">
            <view>
              <wd-icon name="a-rootlist" color="#0D867F"></wd-icon>
              <text class="text-[#252525] ml-2 font-medium">{{ item.inspectionProject }}</text>
          <view class="flex justify-between w-full">
            <view class="flex items-center">
              <wd-icon name="file" color="#0D867F" size="20px"></wd-icon>
              <text class="font-medium text-[#252525] ml-2">自检记录 #{{ index + 1 }}</text>
            </view>
            <view class="text-[#A8A8A8]" @click="toEdit">编辑</view>
            <view class="flex gap-2">
              <wd-button
                plain
                type="primary"
                size="small"
                @click="handleEdit(item)"
                style="margin-right: 10px"
              >
                编辑
              </wd-button>
              <wd-button plain type="error" size="small" @click="handleDelete(item)">
                删除
              </wd-button>
            </view>
          </view>
        </template>
        <ProductionCard :data="cardAttr" :value="item" color="#0D867F" />
        <view class="card-content">
          <!-- 基本信息 -->
          <view class="info-section">
            <view class="section-header">
              <wd-icon name="info" color="#0D867F" size="16px"></wd-icon>
              <text class="section-title">基本信息</text>
            </view>
            <view class="info-grid">
              <view class="info-item">
                <text class="info-label">自检时间:</text>
                <text class="info-value">{{ item.fixedInfo?.recordDate || "-" }}</text>
              </view>
              <view class="info-item">
                <text class="info-label">机台:</text>
                <text class="info-value">{{ item.fixedInfo?.deviceModel || "-" }}</text>
              </view>
              <view class="info-item">
                <text class="info-label">班组:</text>
                <text class="info-value">{{ item.fixedInfo?.teamName || "-" }}</text>
              </view>
              <view class="info-item">
                <text class="info-label">首检单号:</text>
                <text class="info-value">{{ item.fixedInfo?.firstNo || "-" }}</text>
              </view>
            </view>
          </view>
          <!-- 原材料信息 -->
          <view class="info-section">
            <view class="section-header">
              <wd-icon name="folder" color="#0D867F" size="16px"></wd-icon>
              <text class="section-title">原材料信息</text>
            </view>
            <view class="info-grid">
              <view class="info-item">
                <text class="info-label">型号:</text>
                <text class="info-value">{{ item.fixedInfo?.poleModel || "-" }}</text>
              </view>
              <view class="info-item">
                <text class="info-label">批次:</text>
                <text class="info-value">{{ item.fixedInfo?.poleNumber || "-" }}</text>
              </view>
              <view class="info-item">
                <text class="info-label">生产轴数:</text>
                <text class="info-value">{{ item.fixedInfo?.outputNumber || "-" }}</text>
              </view>
              <view class="info-item">
                <text class="info-label">定径模具:</text>
                <text class="info-value">{{ item.fixedInfo?.lastSlot || "-" }}</text>
              </view>
            </view>
          </view>
          <!-- 单丝直径 -->
          <view class="info-section">
            <view class="section-header">
              <wd-icon name="setting" color="#0D867F" size="16px"></wd-icon>
              <text class="section-title">单丝直径(mm)</text>
            </view>
            <view class="info-grid">
              <view class="info-item">
                <text class="info-label">规格型号:</text>
                <text class="info-value">{{ item.fixedInfo?.model || "-" }}</text>
              </view>
              <view class="info-item">
                <text class="info-label">最大值:</text>
                <text class="info-value">
                  {{
                    item.inspectionResult?.maxDia !== null &&
                    item.inspectionResult?.maxDia !== undefined
                      ? item.inspectionResult.maxDia
                      : "-"
                  }}
                </text>
              </view>
              <view class="info-item">
                <text class="info-label">最小值:</text>
                <text class="info-value">
                  {{
                    item.inspectionResult?.minDia !== null &&
                    item.inspectionResult?.minDia !== undefined
                      ? item.inspectionResult.minDia
                      : "-"
                  }}
                </text>
              </view>
            </view>
          </view>
          <!-- 成盘质量 -->
          <view class="info-section">
            <view class="section-header">
              <wd-icon name="check" color="#0D867F" size="16px"></wd-icon>
              <text class="section-title">成盘质量</text>
            </view>
            <view class="info-grid">
              <view class="info-item">
                <text class="info-label">卷绕紧密:</text>
                <text class="info-value">
                  {{ item.inspectionResult?.windingTightness || "是" }}
                </text>
              </view>
              <view class="info-item">
                <text class="info-label">排列整齐:</text>
                <text class="info-value">
                  {{ item.inspectionResult?.arrangementNeatness || "是" }}
                </text>
              </view>
              <view class="info-item-full">
                <text class="info-label">外层铝线离侧板边缘距离(mm):</text>
                <text
                  class="info-value"
                  :style="{
                    color: item.inspectionResult?.aluminumWireDistance < 25 ? '#f56c6c' : '',
                  }"
                >
                  {{ item.inspectionResult?.aluminumWireDistance || "-" }}
                </text>
              </view>
            </view>
          </view>
          <!-- 其他信息 -->
          <view class="info-section">
            <view class="section-header">
              <wd-icon name="more" color="#0D867F" size="16px"></wd-icon>
              <text class="section-title">其他信息</text>
            </view>
            <view class="info-grid">
              <view class="info-item-full">
                <text class="info-label">外观质量:</text>
                <text class="info-value">
                  {{ getAppearanceLabel(item.inspectionResult?.appearance) }}
                </text>
              </view>
              <view class="info-item">
                <text class="info-label">成品模后接头情况:</text>
                <text class="info-value">{{ item.inspectionResult?.jointCondition || "无" }}</text>
              </view>
              <view class="info-item">
                <text class="info-label">结论:</text>
                <text
                  class="info-value"
                  :style="{
                    color: item.inspectionResult?.conclusion === '合格' ? '#67c23a' : '#f56c6c',
                    fontWeight: '500',
                  }"
                >
                  {{ item.inspectionResult?.conclusion || "合格" }}
                </text>
              </view>
              <view class="info-item">
                <text class="info-label">记录人:</text>
                <text class="info-value">{{ item.fixedInfo?.createUserName || "-" }}</text>
              </view>
            </view>
          </view>
        </view>
      </wd-card>
    </z-paging>
    <wd-popup v-model="dialog.visible" position="bottom" custom-class="yl-popup">
      <view class="action px-3">
        <wd-button type="text" @click="cancel">取消</wd-button>
        <wd-button type="text" @click="submit">确定</wd-button>
      </view>
      <SelfInspectForm />
    </view>
    <!-- 新增/编辑弹框 -->
    <wd-popup v-model="dialogVisible" position="bottom" custom-class="yl-popup">
      <SelfInspectForm
        :visible="dialogVisible"
        :form-data="currentFormData"
        :appearance-options="appearanceOptions"
        :previous-appearance-value="previousAppearanceValueMap.get(currentFormData?.id || '')"
        @update:visible="dialogVisible = $event"
        @submit="handleFormSubmit"
        @close="handleCloseDialog"
      />
    </wd-popup>
    <wd-toast />
  </view>
</template>
<script setup lang="ts">
import CardTitle from "@/components/card-title/index.vue";
import ProductionCard from "../../components/ProductionCard.vue";
import { useToast } from "wot-design-uni";
import SelfInspectForm from "./form.vue";
import { useToast, dayjs } from "wot-design-uni";
import { onLoad } from "@dcloudio/uni-app";
import { ref } from "vue";
import ManageApi from "@/api/product/manage";
import SelfInspectForm from "./form.vue";
const pagingRef = ref();
const paramsId = ref();
const toast = useToast();
const dialog = reactive({
  visible: false,
});
const cardAttr = ref<any[]>([
  {
    label: "单位",
    prop: "inspectionUnit",
  },
  {
    label: "标准值",
    prop: "standardValue",
  },
  {
    label: "自检值",
    prop: "inspectionItem",
  },
  {
    label: "自检结果",
    prop: "inspectionResult",
    color: "#FF1E1E",
  },
]);
const cardList = ref<any[]>([]);
const wireId = ref<string>("");
const poleModel = ref<string>("");
const poleNumber = ref<string>("");
// const addReport = () => {
//   dialog.visible = true;
// };
// 数据列表
const dataList = ref<any[]>([]);
const loading = ref(false);
const toEdit = () => {
  uni.navigateTo({
    url: "/pages/production/wire/selfInspect/edit",
  });
};
const submit = () => {
  toast.show("提交");
  dialog.visible = false;
// 外观选项
const appearanceOptions = ref<Array<{ label: string; value: string | number }>>([]);
// 存储每行外观质量的之前的值
const previousAppearanceValueMap = ref<Map<string, string[]>>(new Map());
// 弹框相关
const dialogVisible = ref(false);
const currentFormData = ref<any>(null);
// 加载外观字典数据
const loadAppearanceDict = async () => {
  try {
    const qualityRes = await ManageApi.dictAPI("draw_appearance_quality");
    if (qualityRes.data && Array.isArray(qualityRes.data)) {
      appearanceOptions.value = qualityRes.data.map((item: any) => ({
        label: item.dictLabel || "",
        value: item.dictValue || "",
      }));
    }
  } catch (error) {
    console.error("加载外观字典失败:", error);
  }
};
const cancel = () => {
  toast.show("取消");
  dialog.visible = false;
// 获取外观标签
const getAppearanceLabel = (value: string | string[]) => {
  if (Array.isArray(value) && value.length > 0) {
    const labels = value.map((v) => {
      const option = appearanceOptions.value.find((item) => item.value === v);
      return option ? option.label : v;
    });
    return labels.join(", ");
  }
  if (typeof value === "string" && value) {
    const option = appearanceOptions.value.find((item) => item.value === value);
    return option ? option.label : value;
  }
  return "无";
};
const getList = async () => {
  const { data } = await ManageApi.getSelfInspection({
    outPutId: paramsId.value,
    type: "拉丝",
  });
  pagingRef.value.complete(data);
// 获取数据
const getData = async () => {
  if (!wireId.value) return;
  loading.value = true;
  try {
    const { code, data } = await ManageApi.getSelfInspection({
      wireId: wireId.value,
      poleModel: poleModel.value,
      poleNumber: poleNumber.value,
    });
    if (code === 200) {
      dataList.value = data || [];
      // 初始化每行的 previousAppearanceValue
      dataList.value.forEach((item) => {
        if (item.id) {
          previousAppearanceValueMap.value.set(
            item.id,
            JSON.parse(JSON.stringify(item.inspectionResult?.appearance || []))
          );
        }
      });
    }
  } catch (error) {
    console.error("获取自检数据失败:", error);
    toast.error("获取自检数据失败");
  } finally {
    loading.value = false;
  }
};
onLoad((options: any) => {
  paramsId.value = options.id;
// 存储从接口获取的原始数据(用于保存时补充缺失字段)
const originalApiData = ref<any>(null);
// 打开新增弹框
const handleOpenAddDialog = async () => {
  const newItem = {
    id: `temp_${Date.now()}`,
    fixedInfo: {
      firstNo: "",
      recordDate: dayjs().format("YYYY-MM-DD"),
      deviceModel: "",
      teamName: "",
      workShift: "",
      poleModel: poleModel.value || "",
      poleNumber: poleNumber.value || "",
      outputNumber: "",
      lastSlot: "",
      model: "",
      createUserName: "",
      id: null,
      teamId: null,
      wireId: wireId.value ? Number(wireId.value) : null,
    },
    inspectionResult: {
      maxDia: null,
      minDia: null,
      appearance: ["无外观问题"],
      windingTightness: "是",
      arrangementNeatness: "是",
      aluminumWireDistance: 25,
      jointCondition: "无",
      conclusion: "合格",
      dia: null,
      twistedLayer: null,
      wireId: wireId.value ? String(wireId.value) : null,
    },
    isEditing: true,
    isNew: true,
  };
  // 调用API获取默认数据
  try {
    const { code, data } = await ManageApi.getDrawInspectStyleByGetDrawInspect({
      wireId: wireId.value,
      poleModel: poleModel.value,
      poleNumber: poleNumber.value,
    });
    if (code === 200 && data) {
      // 保存原始接口数据,用于提交时补充缺失字段
      originalApiData.value = JSON.parse(JSON.stringify(data));
      if (data.fixedInfo) {
        const clonedFixedInfo = JSON.parse(JSON.stringify(data.fixedInfo));
        // 合并数据,保留表单中已有的值,补充接口返回的值
        Object.assign(newItem.fixedInfo, clonedFixedInfo, {
          // 确保这些字段从接口数据中获取
          id: clonedFixedInfo.id || null,
          teamId: clonedFixedInfo.teamId || null,
          wireId: clonedFixedInfo.wireId || (wireId.value ? Number(wireId.value) : null),
        });
      }
      if (data.drawWireInfo) {
        const clonedDrawWireInfo = JSON.parse(JSON.stringify(data.drawWireInfo));
        // 合并数据,保留表单中已有的值,补充接口返回的值
        Object.assign(newItem.inspectionResult, clonedDrawWireInfo, {
          // 确保这些字段从接口数据中获取
          dia: clonedDrawWireInfo.dia || null,
          twistedLayer: clonedDrawWireInfo.twistedLayer || null,
          wireId: clonedDrawWireInfo.wireId || (wireId.value ? String(wireId.value) : null),
        });
      }
    }
  } catch (error) {
    console.error("获取默认数据失败:", error);
  }
  currentFormData.value = JSON.parse(JSON.stringify(newItem));
  previousAppearanceValueMap.value.set(
    currentFormData.value.id,
    JSON.parse(JSON.stringify(currentFormData.value.inspectionResult.appearance || []))
  );
  dialogVisible.value = true;
};
// 编辑自检
const handleEdit = async (row: any) => {
  // 编辑时也需要获取接口数据,确保有所有必要字段
  try {
    const { code, data } = await ManageApi.getDrawInspectStyleByGetDrawInspect({
      wireId: wireId.value,
      poleModel: poleModel.value,
      poleNumber: poleNumber.value,
    });
    if (code === 200 && data) {
      originalApiData.value = JSON.parse(JSON.stringify(data));
    }
  } catch (error) {
    console.error("获取默认数据失败:", error);
  }
  currentFormData.value = JSON.parse(JSON.stringify(row));
  previousAppearanceValueMap.value.set(
    row.id,
    JSON.parse(JSON.stringify(row.inspectionResult.appearance || []))
  );
  dialogVisible.value = true;
};
// 表单提交
const handleFormSubmit = async (formData: any) => {
  const aluminumWireDistance = formData.inspectionResult.aluminumWireDistance;
  if (aluminumWireDistance < 25) {
    toast.error("外层铝线离侧板边缘距离不能低于25mm");
    return;
  }
  // 构建提交数据,确保包含所有必要字段
  const saveData: any = {
    fixedInfo: JSON.parse(JSON.stringify(formData.fixedInfo)),
    inspectionResult: JSON.parse(JSON.stringify(formData.inspectionResult)),
    wireId: wireId.value,
  };
  // 编辑时,确保 fixedInfo.id 被正确传递
  // 优先使用 formData 中的 id(编辑时应该存在)
  if (formData.fixedInfo?.id !== null && formData.fixedInfo?.id !== undefined) {
    saveData.fixedInfo.id = formData.fixedInfo.id;
  } else if (!formData.isNew) {
    // 如果不是新增,尝试从数据列表中查找 id
    const existingItem = dataList.value.find((item) => item.id === formData.id);
    if (existingItem?.fixedInfo?.id) {
      saveData.fixedInfo.id = existingItem.fixedInfo.id;
    }
  }
  // 如果是从接口获取的数据,补充表单中没有的字段
  if (originalApiData.value) {
    // 补充 fixedInfo 中缺失的字段
    if (originalApiData.value.fixedInfo) {
      const apiFixedInfo = originalApiData.value.fixedInfo;
      // 确保这些字段存在(如果表单中没有,使用接口返回的值)
      // 只有在 saveData.fixedInfo.id 不存在时才使用接口返回的 id
      if (apiFixedInfo.id !== undefined && !saveData.fixedInfo.id) {
        saveData.fixedInfo.id = apiFixedInfo.id;
      }
      if (apiFixedInfo.teamId !== undefined) {
        saveData.fixedInfo.teamId = apiFixedInfo.teamId;
      }
      if (apiFixedInfo.wireId !== undefined) {
        saveData.fixedInfo.wireId = apiFixedInfo.wireId;
      }
      // 补充其他可能缺失的字段
      if (apiFixedInfo.recordDate && !saveData.fixedInfo.recordDate) {
        saveData.fixedInfo.recordDate = apiFixedInfo.recordDate;
      }
    }
    // 补充 inspectionResult 中缺失的字段
    if (originalApiData.value.drawWireInfo) {
      const apiInspectionResult = originalApiData.value.drawWireInfo;
      // 确保这些字段存在(如果表单中没有,使用接口返回的值)
      if (apiInspectionResult.dia !== undefined) {
        saveData.inspectionResult.dia = apiInspectionResult.dia;
      }
      if (apiInspectionResult.twistedLayer !== undefined) {
        saveData.inspectionResult.twistedLayer = apiInspectionResult.twistedLayer;
      }
      if (apiInspectionResult.wireId !== undefined) {
        saveData.inspectionResult.wireId = apiInspectionResult.wireId;
      }
    }
  }
  // 确保 wireId 字段存在
  if (!saveData.fixedInfo.wireId && wireId.value) {
    saveData.fixedInfo.wireId = Number(wireId.value);
  }
  if (!saveData.inspectionResult.wireId && wireId.value) {
    saveData.inspectionResult.wireId = String(wireId.value);
  }
  try {
    const { code, data } = await ManageApi.addSelfInspection(saveData);
    if (code === 200) {
      toast.success("保存成功");
      dialogVisible.value = false;
      originalApiData.value = null; // 清空原始数据
      previousAppearanceValueMap.value.delete(formData.id);
      await getData();
    } else {
      toast.error(data || "保存失败");
    }
  } catch (error) {
    console.error("保存失败:", error);
    toast.error("保存失败");
  }
};
// 关闭弹框
const handleCloseDialog = () => {
  dialogVisible.value = false;
  currentFormData.value = null;
  originalApiData.value = null; // 清空原始数据
};
// 删除自检
const handleDelete = async (row: any) => {
  try {
    const res = await uni.showModal({
      title: "提示",
      content: "确定删除该自检记录吗?",
    });
    if (res.confirm) {
      if (row.fixedInfo?.id && !row.isNew) {
        const { code } = await ManageApi.deleteSelfInspection(row.fixedInfo.id);
        if (code === 200) {
          toast.success("删除成功");
          await getData();
        } else {
          toast.error("删除失败");
        }
      } else {
        const index = dataList.value.findIndex((item) => item.id === row.id);
        if (index !== -1) {
          dataList.value.splice(index, 1);
          toast.success("删除成功");
        }
      }
    }
  } catch (error) {
    console.error("删除自检失败:", error);
    toast.error("删除失败");
  }
};
onLoad(async (options: any) => {
  wireId.value = options.wireId || "";
  poleModel.value = options.poleModel || "";
  poleNumber.value = options.poleNumber || "";
  await loadAppearanceDict();
  await getData();
});
</script>
<style lang="scss" scoped>
.list {
  height: calc(100vh - 30px);
  padding: 12px;
  min-height: calc(100vh - 30px);
  padding: 12px 4px;
  background: #f3f9f8;
  :deep() {
@@ -107,8 +575,75 @@
  }
}
.action {
.inspection-list {
  margin-top: 12px;
}
.card_bg {
  box-shadow: 0px 0px 12px 0px rgba(0, 0, 0, 0.05);
  padding-bottom: 10px;
  border-radius: 8px;
  overflow: hidden;
}
.card-content {
  padding: 0 4px;
}
.info-section {
  margin-bottom: 16px;
  &:last-child {
    margin-bottom: 0;
  }
}
.section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
  padding-bottom: 8px;
  border-bottom: 1px solid #e6e6e6;
}
.section-title {
  font-size: 14px;
  font-weight: 600;
  color: #252525;
  margin-left: 6px;
}
.info-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px 16px;
}
.info-item {
  display: flex;
  align-items: flex-start;
  min-height: 24px;
}
.info-item-full {
  display: flex;
  align-items: flex-start;
  min-height: 24px;
  grid-column: 1 / -1;
}
.info-label {
  font-size: 13px;
  color: #646874;
  margin-right: 8px;
  white-space: nowrap;
  flex-shrink: 0;
}
.info-value {
  font-size: 13px;
  color: #252525;
  flex: 1;
  word-break: break-all;
}
</style>