spring
2025-11-20 5384750e59bbb27c54e090100429c48eaba46df0
fix: 完成拉丝自检、原材料自检优化
已修改11个文件
1548 ■■■■ 文件已修改
.env.development 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/product/attachment.ts 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/product/manage.ts 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/product/wire.ts 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/production/wire/attachment/index.vue 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/production/wire/report/rawMaterial.vue 222 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/production/wire/report/reportManage.vue 59 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/production/wire/report/wire.vue 49 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/production/wire/selfInspect/form.vue 381 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/production/wire/selfInspect/index.vue 677 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env.development
@@ -14,6 +14,6 @@
# API 服务器的 URL
#VITE_APP_API_URL = 'http://114.132.189.42:7002/mes'
VITE_APP_API_URL = 'http://114.132.10.119:7002/mes'
VITE_APP_API_URL = 'http://192.168.10.119:7002/mes'
# VITE_APP_API_URL = 'http://192.168.100.131:7002/mes' #
src/api/product/attachment.ts
@@ -13,6 +13,7 @@
  // 上传单个附件文件
  uploadSingleFile(filePath: string) {
    return new Promise<BaseResult<any>>((resolve, reject) => {
      console.log("开始上传文件:", filePath);
      uni.uploadFile({
        url: `${baseApi}/app/addAttachmentFiles`,
        filePath: filePath,
@@ -21,35 +22,44 @@
          Authorization: getToken() ? `Bearer ${getToken()}` : "",
        },
        success: (uploadRes) => {
          console.log("上传响应:", uploadRes);
          try {
            const result = JSON.parse(uploadRes.data) as BaseResult<any>;
            console.log("解析后的结果:", result);
            // 业务状态码 00000 表示成功
            if (result.code === ResultCodeEnum.SUCCESS) {
              resolve(result);
            } else {
              // 其他业务处理失败
              const errorMsg = result.msg || "文件上传失败";
              console.error("上传失败:", errorMsg, result);
              uni.showToast({
                title: result.msg || "文件上传失败",
                title: errorMsg,
                icon: "none",
              });
              reject({
                message: result.msg || "业务处理失败",
                message: errorMsg,
                code: result.code,
              });
            }
          } catch (e) {
            reject(e);
            console.error("解析上传响应失败:", e, uploadRes.data);
            reject({
              message: "解析上传响应失败",
              error: e,
            });
          }
        },
        fail: (error) => {
          console.log("upload fail error", error);
          console.error("上传请求失败:", error);
          const errorMsg = error.errMsg || "文件上传请求失败";
          uni.showToast({
            title: "文件上传请求失败",
            title: errorMsg,
            icon: "none",
            duration: 2000,
          });
          reject({
            message: "文件上传请求失败",
            message: errorMsg,
            error,
          });
        },
src/api/product/manage.ts
@@ -29,11 +29,37 @@
  },
  // 查询自检信息
  getSelfInspection(params: any) {
    return request<BaseResult<any>>({
      url: "/app/getSelfInspection",
      method: "GET",
      data: params,
  getSelfInspection(data: any) {
    return request<BaseResult<any[]>>({
      url: "/wireInspection/getDrawInspectInfoListByGetDrawInspect",
      method: "POST",
      data: data,
    });
  },
  // 新增自检
  addSelfInspection(data: any) {
    return request<BaseResult<any[]>>({
      url: "/wireInspection/saveDrawInspectionRecord",
      method: "POST",
      data: data,
    });
  },
  // 删除自检
  deleteSelfInspection(ids: string | number) {
    return request<BaseResult<any[]>>({
      url: `/wireInspection/deleteDrawWireInspectionRecord/${ids}`,
      method: "POST",
    });
  },
  // 获取自检样式数据
  getDrawInspectStyleByGetDrawInspect(data: any) {
    return request<BaseResult<any[]>>({
      url: "/wireInspection/getDrawInspectStyleByGetDrawInspect",
      method: "POST",
      data: data,
    });
  },
src/api/product/wire.ts
@@ -32,7 +32,7 @@
  // 新增杆包
  addRodBagTree(data: any) {
    return request<BaseResult<any>>({
      url: "/app/addRodBagTree",
      url: "/wireOutput/addRodBagTree",
      method: "POST",
      data: data,
    });
@@ -41,8 +41,8 @@
  // 删除杆包
  deleteRodBagTree(data: any) {
    return request<BaseResult<any>>({
      url: "/app/deleteRodBagTree",
      method: "DELETE",
      url: "/wireOutput/deleteRodBagTree",
      method: "POST",
      data: data,
    });
  },
src/pages.json
@@ -196,7 +196,7 @@
    {
      "path": "pages/production/wire/selfInspect/index",
      "style": {
        "navigationBarTitleText": "拉丝自检"
        "navigationBarTitleText": "自检管理"
      }
    },
    {
src/pages/production/wire/attachment/index.vue
@@ -36,23 +36,6 @@
            </view>
          </template>
          <!-- 视频预览 -->
          <template v-else-if="isVideoType(item.url)">
            <video
              v-if="!item.loadError"
              :src="getFullUrl(item.url)"
              class="media-preview"
              :controls="false"
              :show-center-play-btn="false"
              @error="onVideoError(item)"
            />
            <!-- 视频加载失败显示默认图标 -->
            <view v-else class="file-icon-wrapper">
              <wd-icon name="video" size="48px" color="#ccc" />
              <text class="file-name error-text">加载失败</text>
            </view>
          </template>
          <!-- 其他文件类型显示图标 -->
          <view v-else class="file-icon-wrapper">
            <wd-icon name="file-outline" size="48px" color="#999" />
@@ -91,7 +74,7 @@
const detailData = ref<any>({});
// 获取完整的图片/视频 URL
// 获取完整的图片 URL
const getFullUrl = (url: string) => {
  if (!url) return "";
  // 如果已经是完整的 URL(http 或 https 开头),直接返回
@@ -118,12 +101,6 @@
  return ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(extension);
};
// 判断是否为视频类型
const isVideoType = (urlOrFileName: string) => {
  const extension = getExtension(urlOrFileName);
  return ["mp4", "mov", "avi", "wmv", "flv", "mkv", "webm"].includes(extension);
};
// 图片加载成功
const onImageLoad = (item: any) => {
  item.loadError = false;
@@ -132,12 +109,6 @@
// 图片加载失败
const onImageError = (item: any) => {
  console.error("图片加载失败:", item.url);
  item.loadError = true;
};
// 视频加载失败
const onVideoError = (item: any) => {
  console.error("视频加载失败:", item.url);
  item.loadError = true;
};
@@ -178,20 +149,14 @@
const addAttachment = () => {
  // 显示选择文件类型的弹窗
  uni.showActionSheet({
    itemList: ["选择图片", "选择视频", "拍照", "录像"],
    itemList: ["选择图片", "拍照"],
    success: (res) => {
      switch (res.tapIndex) {
        case 0: // 选择图片
          chooseImages();
          break;
        case 1: // 选择视频
          chooseVideos();
          break;
        case 2: // 拍照
        case 1: // 拍照
          takePhoto();
          break;
        case 3: // 录像
          recordVideo();
          break;
      }
    },
@@ -219,22 +184,6 @@
  });
};
// 选择视频
const chooseVideos = () => {
  uni.chooseVideo({
    sourceType: ["album"],
    maxDuration: 60,
    camera: "back",
    success: async (res) => {
      await handleFileUpload([res.tempFilePath]);
    },
    fail: (error) => {
      console.error("选择视频失败:", error);
      toast.show("选择视频失败");
    },
  });
};
// 拍照
const takePhoto = () => {
  uni.chooseImage({
@@ -248,22 +197,6 @@
    fail: (error) => {
      console.error("拍照失败:", error);
      toast.show("拍照失败");
    },
  });
};
// 录像
const recordVideo = () => {
  uni.chooseVideo({
    sourceType: ["camera"],
    maxDuration: 60,
    camera: "back",
    success: async (res) => {
      await handleFileUpload([res.tempFilePath]);
    },
    fail: (error) => {
      console.error("录像失败:", error);
      toast.show("录像失败");
    },
  });
};
@@ -382,14 +315,6 @@
    case "bmp":
    case "webp":
      return "image";
    case "mp4":
    case "mov":
    case "avi":
    case "wmv":
    case "flv":
    case "mkv":
    case "webm":
      return "video";
    case "pdf":
      return "pdf";
    case "doc":
@@ -516,14 +441,3 @@
  }
}
</style>
src/pages/production/wire/report/rawMaterial.vue
@@ -30,6 +30,7 @@
                  v-model="materialData.conductivity"
                  range-key="label"
                  placeholder="请输入"
                  type="number"
                ></wd-input>
              </wd-form-item>
              <wd-form-item label="抗拉强度(Mpa)" prop="tensileStrength" required>
@@ -37,6 +38,7 @@
                  v-model="materialData.tensileStrength"
                  range-key="label"
                  placeholder="请输入"
                  type="number"
                ></wd-input>
              </wd-form-item>
              <wd-form-item label="电阻率(nΩ·m)" prop="resistivity" required>
@@ -44,6 +46,7 @@
                  v-model="materialData.resistivity"
                  range-key="label"
                  placeholder="请输入"
                  type="number"
                ></wd-input>
              </wd-form-item>
              <wd-form-item label="伸长率(%)" prop="elongationRate" required>
@@ -51,15 +54,25 @@
                  v-model="materialData.elongationRate"
                  range-key="label"
                  placeholder="请输入"
                  type="number"
                ></wd-input>
              </wd-form-item>
              <wd-form-item label="外观质量" prop="appearanceQuality" required>
                <wd-select-picker
                  v-model="materialData.appearanceQuality"
                  range-key="label"
                  :columns="drawing_appearanceQuality"
                  placeholder="请选择"
                ></wd-select-picker>
                <view class="checkbox-group">
                  <wd-checkbox
                    v-for="option in drawing_appearanceQuality"
                    :key="option.value"
                    :modelValue="
                      Array.isArray(materialData.appearanceQuality)
                        ? materialData.appearanceQuality.includes(String(option.value))
                        : false
                    "
                    shape="square"
                    @change="(val) => handleAppearanceQualityCheckbox(String(option.value), val)"
                  >
                    {{ option.label }}
                  </wd-checkbox>
                </view>
              </wd-form-item>
            </wd-form>
          </view>
@@ -73,7 +86,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { ref, onMounted, watch, nextTick } from "vue";
import { useToast } from "wot-design-uni";
import ManageApi from "@/api/product/manage";
@@ -131,9 +144,104 @@
const activeTab = ref("reel"); // 与tab的name保持一致
const toast = useToast();
// 存储前一个外观质量值,用于比较变化
const previousAppearanceQuality = ref<string[]>([]);
// 处理外观质量下拉框的互斥选择逻辑
const handleAppearanceQualityChange = (
  selectedValues: string[],
  allOptions: Array<{ label: string; value: string | number }>
): string[] => {
  // 如果没有选项数据,直接返回
  if (!allOptions || allOptions.length === 0) {
    return selectedValues;
  }
  // 获取之前的值
  const previousValues = previousAppearanceQuality.value || [];
  // 查找"无外观问题"选项的值
  const noIssueOption = allOptions.find(
    (item) => item.label === "无外观问题" || item.value === "无外观问题"
  );
  if (!noIssueOption) {
    // 如果字典中没有"无外观问题"选项,直接返回
    return selectedValues;
  }
  const noIssueValue = String(noIssueOption.value);
  // 检查当前选中值中是否包含"无外观问题"
  const hasNoIssue = selectedValues.includes(noIssueValue);
  // 检查之前是否包含"无外观问题"
  const hadNoIssue = previousValues.includes(noIssueValue);
  // 判断是否新选择了"无外观问题"(之前没有,现在有)
  const isNewlySelectedNoIssue = !hadNoIssue && hasNoIssue;
  // 判断是否移除了"无外观问题"(之前有,现在没有)
  const isRemovedNoIssue = hadNoIssue && !hasNoIssue;
  // 判断是否在"无外观问题"已选中的情况下选择了其他选项
  const isSelectingOtherWithNoIssue =
    hadNoIssue && hasNoIssue && selectedValues.length > previousValues.length;
  let result: string[];
  if (isNewlySelectedNoIssue) {
    // 如果新选择了"无外观问题",则只保留"无外观问题"
    result = [noIssueValue];
  } else if (isSelectingOtherWithNoIssue) {
    // 如果"无外观问题"已经被选中,且新选择了其他选项,则移除"无外观问题"
    result = selectedValues.filter((val) => val !== noIssueValue);
  } else if (isRemovedNoIssue) {
    // 如果移除了"无外观问题",直接返回(已经是其他选项了)
    result = selectedValues;
  } else {
    result = selectedValues;
  }
  // 保存当前值作为下一次的前一个值
  previousAppearanceQuality.value = result;
  return result;
};
// 处理复选框的change事件
const handleAppearanceQualityCheckbox = (optionValue: string, checked: boolean) => {
  const currentValues = Array.isArray(materialData.value.appearanceQuality)
    ? materialData.value.appearanceQuality
    : [];
  let newValues: string[];
  if (checked) {
    // 选中
    newValues = [...currentValues, optionValue];
  } else {
    // 取消选中
    newValues = currentValues.filter((v) => v !== optionValue);
  }
  // 应用互斥逻辑
  const result = handleAppearanceQualityChange(
    newValues,
    drawing_appearanceQuality.value as Array<{ label: string; value: string | number }>
  );
  // 更新值
  materialData.value.appearanceQuality = result;
};
// 本地响应式数据,用于存储用户输入
const materialData = ref<Record<string, any>>({});
const initializeData = () => {
  // 查找"无外观问题"的值
  const noIssueOption = drawing_appearanceQuality.value.find(
    (item) => item.label === "无外观问题" || item.value === "无外观问题"
  );
  const defaultAppearanceQuality = noIssueOption ? [String(noIssueOption.value)] : [];
  // 初始化原材料数据
  materialData.value = {
    model: "",
@@ -142,8 +250,11 @@
    tensileStrength: "",
    resistivity: "",
    elongationRate: "",
    appearanceQuality: "",
    appearanceQuality: defaultAppearanceQuality,
  };
  // 初始化前一个值
  previousAppearanceQuality.value = defaultAppearanceQuality;
};
// 初始化数据
@@ -152,7 +263,32 @@
// 在组件挂载时异步加载数据字典
onMounted(async () => {
  await loadDictData();
  // 字典数据加载完成后,重新初始化数据,确保默认值能正确匹配
  initializeData();
});
// 监听外观质量变化,应用互斥逻辑
watch(
  () => materialData.value.appearanceQuality,
  (newValue, oldValue) => {
    const normalizedNewValue = Array.isArray(newValue) ? newValue : [];
    const normalizedOldValue = Array.isArray(oldValue) ? oldValue : [];
    // 应用互斥逻辑
    const result = handleAppearanceQualityChange(
      normalizedNewValue,
      drawing_appearanceQuality.value as Array<{ label: string; value: string | number }>
    );
    // 如果值被修改了,异步更新,避免在监听中同步修改
    if (JSON.stringify(result) !== JSON.stringify(normalizedNewValue)) {
      nextTick(() => {
        materialData.value.appearanceQuality = result;
      });
    }
  },
  { deep: true }
);
// 监听props变化,更新本地数据
@@ -166,6 +302,30 @@
};
const handleSubmit = async () => {
  // 表单验证
  if (
    !materialData.value.model ||
    materialData.value.model === "" ||
    !materialData.value.spec ||
    materialData.value.spec === "" ||
    !materialData.value.conductivity ||
    materialData.value.conductivity === "" ||
    !materialData.value.tensileStrength ||
    materialData.value.tensileStrength === "" ||
    !materialData.value.resistivity ||
    materialData.value.resistivity === "" ||
    !materialData.value.elongationRate ||
    materialData.value.elongationRate === "" ||
    !materialData.value.appearanceQuality ||
    (Array.isArray(materialData.value.appearanceQuality) &&
      materialData.value.appearanceQuality.length === 0) ||
    (!Array.isArray(materialData.value.appearanceQuality) &&
      materialData.value.appearanceQuality === "")
  ) {
    toast.error("请填写完整的必填项");
    return false;
  }
  try {
    // 调用API提交数据
    await ManageApi.addWireRawMaterialInspect({
@@ -273,47 +433,13 @@
  width: 100%;
}
// 美化选择器样式 - 增加权重确保样式生效
:deep(.wd-select-picker) {
  & .wd-select-picker__option {
    text-align: center !important;
    padding: 12px 0 !important;
    font-size: 16px !important;
  }
  & .wd-select-picker__confirm {
    border-radius: 8px !important;
    background-color: #409eff !important;
    color: white !important;
    font-weight: 500 !important;
  }
  & .wd-select-picker__header {
    padding: 10px 0 !important;
    border-bottom: 1px solid #e6e6e6 !important;
  }
  & .wd-select-picker__title {
    font-size: 16px !important;
    font-weight: 500 !important;
  }
.checkbox-group {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
// 确保选择器内部选项居中 - 更通用的选择器
:deep(.wd-select-picker__content) {
  .wd-select-picker__option {
    text-align: center !important;
    padding: 12px 0 !important;
    font-size: 16px !important;
  }
}
// 直接针对选项元素的选择器
:deep([class*="select-picker"].wd-popup) {
  .wd-select-picker__option {
    text-align: center !important;
    padding: 12px 0 !important;
    font-size: 16px !important;
  }
:deep(.wd-checkbox) {
  margin-right: 0;
}
</style>
src/pages/production/wire/report/reportManage.vue
@@ -1,7 +1,7 @@
<template>
  <view class="report-manage-page">
    <view class="pt-2">
      <wd-card class="card_bg">
    <view class="pt-2 fixed-header-card">
      <wd-card class="card_bg header-card">
        <template #title>
          <view class="flex justify-between w-full">
            <text class="font-medium text-[#252525]">报工管理</text>
@@ -195,7 +195,9 @@
        </wd-row>
        <template #footer>
          <view class="flex gap-2">
            <wd-button plain size="small" @click="toAttachment(child)">附件</wd-button>
            <wd-button plain size="small" @click="toAttachment(child)" style="margin-right: 10px">
              附件
            </wd-button>
            <wd-button plain type="error" size="small" @click="handleDeleteSingle(child)">
              删除
            </wd-button>
@@ -242,7 +244,7 @@
          </wd-cell-group>
        </view>
        <view class="dialog-footer">
          <wd-button plain @click="closeAddDialog">取消</wd-button>
          <wd-button plain @click="closeAddDialog" style="margin-right: 10px">取消</wd-button>
          <wd-button type="primary" class="ml-2" @click="handleSaveNewChild">保存</wd-button>
        </view>
      </view>
@@ -578,12 +580,27 @@
.report-manage-page {
  min-height: 100vh;
  background: #f3f9f8;
  padding-bottom: 20px;
  padding: 0 4px 20px 4px;
}
.card_bg {
  box-shadow: 0px 0px 12px 0px rgba(0, 0, 0, 0.05);
  padding-bottom: 10px;
}
.fixed-header-card {
  position: sticky;
  top: 0;
  z-index: 100;
  background: #f3f9f8;
  padding: 8px 0;
}
.header-card {
  border: none;
  margin: 0;
  border-radius: 0;
  box-shadow: none;
}
.icon_box {
@@ -649,7 +666,37 @@
}
.page-content {
  padding: 12px;
  padding: 12px 4px;
  margin-top: 12px;
}
// 弹框 z-index 需要高于固定头部卡片
:deep(.yl-popup) {
  z-index: 400 !important;
}
// 弹框遮罩层 z-index 也需要高于固定头部卡片(使用更高的值确保在固定头部之上)
:deep(.wd-popup__mask),
:deep(.wd-popup-mask),
:deep([class*="popup"][class*="mask"]),
:deep(.wd-overlay),
:deep([class*="overlay"]) {
  z-index: 300 !important;
}
.wd-card {
  margin-left: 5px;
  margin-right: 5px;
  margin-top: 0px;
}
</style>
<style lang="scss">
// 全局样式:确保弹框遮罩层 z-index 高于固定头部卡片
.wd-popup__mask,
.wd-popup-mask,
[class*="popup"][class*="mask"],
.wd-overlay,
[class*="overlay"] {
  z-index: 300 !important;
}
</style>
src/pages/production/wire/report/wire.vue
@@ -116,10 +116,17 @@
        </view>
        <template #footer>
          <view class="flex justify-start">
            <wd-button plain size="small" type="primary" @click="openChildDialog(item)">
          <view class="flex justify-start gap-2">
            <wd-button
              plain
              size="small"
              type="primary"
              @click="openChildDialog(item)"
              style="margin-right: 10px"
            >
              报工管理
            </wd-button>
            <wd-button plain size="small" @click="() => toSelfInspect(item)">自检</wd-button>
          </view>
        </template>
      </wd-card>
@@ -151,13 +158,14 @@
              label="杆包号"
              label-width="100px"
              placeholder="请输入杆包号"
              type="number"
            />
            <wd-input
              v-model="newParentData.poleWeight"
              label="杆重(kg)"
              label-width="100px"
              type="number"
              placeholder="请输入杆重"
              type="number"
            />
            <wd-picker
              v-model="newParentData.supplier"
@@ -169,7 +177,7 @@
          </wd-cell-group>
        </view>
        <view class="dialog-footer">
          <wd-button plain @click="closeParentDialog">取消</wd-button>
          <wd-button plain @click="closeParentDialog" style="margin-right: 10px">取消</wd-button>
          <wd-button type="primary" class="ml-2" @click="handleSaveNewParent">保存</wd-button>
        </view>
      </view>
@@ -490,6 +498,13 @@
  drawFormRef.visible = false;
};
// 跳转到自检页面
const toSelfInspect = (row: any) => {
  uni.navigateTo({
    url: `/pages/production/wire/selfInspect/index?wireId=${paramsId.value}&poleModel=${row.poleModel || ""}&poleNumber=${row.poleNumber || ""}`,
  });
};
onLoad(async (options: any) => {
  paramsId.value = options.id;
  await getDetailData(options.id);
@@ -501,7 +516,7 @@
<style lang="scss" scoped>
.list {
  min-height: calc(100vh - 30px);
  padding: 12px;
  padding: 12px 4px;
  background: #f3f9f8;
  :deep() {
@@ -543,6 +558,30 @@
  border-radius: 12px 12px 0 0;
}
.dialog-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px;
  border-bottom: 1px solid #e6e6e6;
  position: sticky;
  top: 0;
  background: #fff;
  z-index: 10;
}
.dialog-title {
  font-size: 16px;
  color: #333;
  font-weight: 500;
}
.close-icon {
  font-size: 20px;
  color: #999;
  padding: 4px;
}
.dialog-content {
  flex: 1;
  overflow-y: auto;
src/pages/production/wire/selfInspect/form.vue
@@ -1,66 +1,333 @@
<template>
  <wd-form ref="form" :model="model" class="relative form_box">
    <wd-cell-group :border="true">
      <wd-input
        v-model="model.selfInspectName"
        label="自检名称"
        label-width="100px"
        prop="selfInspectName"
        clearable
        placeholder="请输入自检名称"
      />
      <wd-input
        v-model="model.unit"
        label="单位"
        label-width="100px"
        prop="unit"
        clearable
        placeholder="请输入单位"
      />
      <wd-input
        v-model="model.standard"
        label="标准值"
        label-width="100px"
        prop="standard"
        clearable
        placeholder="请输入标准值"
      />
      <wd-input
        v-model="model.selfInspectValue"
        label="自检值"
        label-width="100px"
        prop="selfInspectValue"
        clearable
        placeholder="请输入自检值"
      />
      <wd-input
        v-model="model.selfInspectResult"
        label="自检结果"
        label-width="100px"
        prop="selfInspectResult"
        clearable
        placeholder="请输入自检结果"
      />
    </wd-cell-group>
  </wd-form>
  <view class="form-container">
    <view class="dialog-header">
      <text class="dialog-title">{{ isEdit ? "编辑自检" : "新增自检" }}</text>
      <wd-icon name="close" class="close-icon" @click="handleClose"></wd-icon>
    </view>
    <view class="dialog-content">
      <wd-form ref="formRef" :model="formData">
        <!-- 基本信息 -->
        <view class="section-title">基本信息</view>
        <wd-cell-group border>
          <wd-input
            v-model="formData.fixedInfo.firstNo"
            label="首检单号"
            label-width="120px"
            placeholder="请输入首检单号"
          />
          <wd-input
            v-model="formData.fixedInfo.lastSlot"
            label="定径模具"
            label-width="120px"
            placeholder="请输入定径模具"
          />
        </wd-cell-group>
        <!-- 单丝直径 -->
        <view class="section-title">单丝直径(mm)</view>
        <wd-cell-group border>
          <wd-cell title="最大值" label-width="120px">
            <wd-input-number
              v-model="formData.inspectionResult.maxDia"
              :min="0"
              :precision="3"
              :step="0.01"
              placeholder="请输入最大值"
              :max="
                formData.inspectionResult.minDia !== null &&
                formData.inspectionResult.minDia !== undefined
                  ? undefined
                  : 999999
              "
            />
          </wd-cell>
          <wd-cell title="最小值" label-width="120px">
            <wd-input-number
              v-model="formData.inspectionResult.minDia"
              :min="0"
              :precision="3"
              :step="0.01"
              placeholder="请输入最小值"
              :max="
                formData.inspectionResult.maxDia !== null &&
                formData.inspectionResult.maxDia !== undefined
                  ? formData.inspectionResult.maxDia
                  : 999999
              "
            />
          </wd-cell>
        </wd-cell-group>
        <!-- 外观 -->
        <view class="section-title">外观</view>
        <wd-cell-group border>
          <wd-cell title="外观质量" label-width="120px">
            <view class="checkbox-group">
              <wd-checkbox
                v-for="option in appearanceOptions"
                :key="option.value"
                :modelValue="
                  Array.isArray(formData.inspectionResult.appearance)
                    ? formData.inspectionResult.appearance.includes(String(option.value))
                    : false
                "
                shape="square"
                @change="(val) => handleAppearanceChange(String(option.value), val)"
              >
                {{ option.label }}
              </wd-checkbox>
            </view>
          </wd-cell>
        </wd-cell-group>
        <!-- 成盘质量 -->
        <view class="section-title">成盘质量</view>
        <wd-cell-group border>
          <wd-cell title="卷绕紧密" label-width="120px">
            <wd-radio-group v-model="formData.inspectionResult.windingTightness" size="small">
              <wd-radio value="是">是</wd-radio>
              <wd-radio value="否">否</wd-radio>
            </wd-radio-group>
          </wd-cell>
          <wd-cell title="排列整齐" label-width="120px">
            <wd-radio-group v-model="formData.inspectionResult.arrangementNeatness" size="small">
              <wd-radio value="是">是</wd-radio>
              <wd-radio value="否">否</wd-radio>
            </wd-radio-group>
          </wd-cell>
          <wd-cell title="外层铝线离侧板边缘距离(mm)" label-width="200px">
            <wd-input-number
              v-model="formData.inspectionResult.aluminumWireDistance"
              :min="0"
              :precision="0"
              placeholder="请输入距离"
              :class="{ 'text-danger': formData.inspectionResult.aluminumWireDistance < 25 }"
            />
          </wd-cell>
        </wd-cell-group>
        <!-- 其他信息 -->
        <view class="section-title">其他信息</view>
        <wd-cell-group border>
          <wd-cell title="成品模后接头情况" label-width="120px">
            <wd-radio-group v-model="formData.inspectionResult.jointCondition" size="small">
              <wd-radio value="有">有</wd-radio>
              <wd-radio value="无">无</wd-radio>
            </wd-radio-group>
          </wd-cell>
          <wd-cell title="结论" label-width="120px">
            <wd-radio-group v-model="formData.inspectionResult.conclusion" size="small">
              <wd-radio value="合格">合格</wd-radio>
              <wd-radio value="不合格">不合格</wd-radio>
            </wd-radio-group>
          </wd-cell>
        </wd-cell-group>
      </wd-form>
    </view>
    <view class="dialog-footer">
      <wd-button plain @click="handleClose" style="margin-right: 10px">取消</wd-button>
      <wd-button type="primary" class="ml-2" @click="handleSubmit">保存</wd-button>
    </view>
  </view>
</template>
<script setup lang="ts">
import useFormData from "@/hooks/useFormData";
const { form: model } = useFormData({
  selfInspectName: undefined, // 自检名称
  unit: undefined, // 单位
  standard: undefined, // 标准值
  selfInspectValue: undefined, // 自检值
  selfInspectResult: undefined, // 自检值
});
import { ref, watch, computed } from "vue";
import { dayjs } from "wot-design-uni";
const props = defineProps<{
  visible: boolean;
  formData: any;
  appearanceOptions: Array<{ label: string; value: string | number }>;
  previousAppearanceValue?: string[];
}>();
const emit = defineEmits<{
  (e: "update:visible", value: boolean): void;
  (e: "submit", data: any): void;
  (e: "close"): void;
}>();
const formRef = ref();
const isEdit = computed(() => !!props.formData?.id && !props.formData?.isNew);
// 存储前一个外观质量值
const previousAppearanceValue = ref<string[]>(props.previousAppearanceValue || []);
// 处理外观质量互斥逻辑
const handleAppearanceQualityChange = (
  selectedValues: string[],
  previousValues: string[],
  allOptions: Array<{ label: string; value: string | number }>
): string[] => {
  if (!allOptions || allOptions.length === 0) {
    return selectedValues;
  }
  const noIssueOption = allOptions.find(
    (item) => item.label === "无外观问题" || item.value === "无外观问题"
  );
  if (!noIssueOption) {
    return selectedValues;
  }
  const noIssueValue = String(noIssueOption.value);
  const hasNoIssue = selectedValues.includes(noIssueValue);
  const hadNoIssue = previousValues.includes(noIssueValue);
  const isNewlySelectedNoIssue = !hadNoIssue && hasNoIssue;
  const isSelectingOtherWithNoIssue =
    hadNoIssue && hasNoIssue && selectedValues.length > previousValues.length;
  let result: string[];
  if (isNewlySelectedNoIssue) {
    result = [noIssueValue];
  } else if (isSelectingOtherWithNoIssue) {
    result = selectedValues.filter((val) => val !== noIssueValue);
  } else {
    result = selectedValues;
  }
  return result;
};
// 处理外观选择变化
const handleAppearanceChange = (optionValue: string, checked: boolean) => {
  const currentValues = Array.isArray(props.formData.inspectionResult.appearance)
    ? props.formData.inspectionResult.appearance
    : [];
  let newValues: string[];
  if (checked) {
    newValues = [...currentValues, optionValue];
  } else {
    newValues = currentValues.filter((v: string) => v !== optionValue);
  }
  const processedValues = handleAppearanceQualityChange(
    newValues,
    previousAppearanceValue.value,
    props.appearanceOptions
  );
  props.formData.inspectionResult.appearance = JSON.parse(JSON.stringify(processedValues));
  previousAppearanceValue.value = JSON.parse(JSON.stringify(processedValues));
};
const handleClose = () => {
  emit("update:visible", false);
  emit("close");
};
const handleSubmit = () => {
  // 验证单丝直径:最大值应该大于或等于最小值
  const maxDia = props.formData.inspectionResult.maxDia;
  const minDia = props.formData.inspectionResult.minDia;
  if (maxDia !== null && minDia !== null && maxDia < minDia) {
    uni.showToast({
      title: "单丝直径最大值不能小于最小值",
      icon: "none",
    });
    return;
  }
  // 验证外层铝线离侧板边缘距离
  const aluminumWireDistance = props.formData.inspectionResult.aluminumWireDistance;
  if (aluminumWireDistance < 25) {
    uni.showToast({
      title: "外层铝线离侧板边缘距离不能低于25mm",
      icon: "none",
    });
    return;
  }
  emit("submit", props.formData);
};
// 监听 visible 变化,初始化 previousAppearanceValue
watch(
  () => props.visible,
  (newVal) => {
    if (newVal && props.formData?.inspectionResult?.appearance) {
      previousAppearanceValue.value = JSON.parse(
        JSON.stringify(props.formData.inspectionResult.appearance || [])
      );
    }
  }
);
</script>
<style lang="scss" scoped>
.form_box {
.form-container {
  max-height: 80vh;
  display: flex;
  flex-direction: column;
  background: #fff;
  border-radius: 12px 12px 0 0;
}
.submit_btn {
  position: absolute;
  bottom: 0;
  width: 100%;
.dialog-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px;
  border-bottom: 1px solid #e6e6e6;
  position: sticky;
  top: 0;
  background: #fff;
  z-index: 10;
}
.dialog-title {
  font-size: 16px;
  color: #333;
  font-weight: 500;
}
.close-icon {
  font-size: 20px;
  color: #999;
  padding: 4px;
}
.dialog-content {
  flex: 1;
  overflow-y: auto;
  padding: 16px;
}
.section-title {
  font-size: 14px;
  font-weight: 700;
  color: #252525;
  margin: 16px 0 8px 0;
  padding-bottom: 8px;
  border-bottom: 1px solid #e6e6e6;
}
.checkbox-group {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
:deep(.wd-checkbox) {
  margin-right: 0;
}
.dialog-footer {
  display: flex;
  justify-content: flex-end;
  padding: 16px;
  border-top: 1px solid #e6e6e6;
  gap: 8px;
}
.text-danger {
  :deep(.wd-input-number__input) {
    color: #f56c6c;
    border-color: #f56c6c;
  }
}
</style>
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>