spring
2025-11-19 8cc901ed214f3885b34a07d0520fbcfd50063439
fix: 完成绞线自检,生产确认等功能新增
已修改13个文件
已删除1个文件
1537 ■■■■ 文件已修改
.env.development 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/product/manage.ts 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/product/twist.ts 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages.json 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/index/index.vue 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/production/detail/twistDetail.vue 53 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/production/index.vue 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/production/list/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/production/twist/report/draw.vue 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/production/twist/report/index.vue 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/production/twist/selfInspect/edit.vue 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/production/twist/selfInspect/form.vue 383 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/production/twist/selfInspect/index.vue 712 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/cache.ts 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env.development
@@ -9,11 +9,11 @@
# API åŸºç¡€è·¯å¾„,开发环境下的请求前缀
#VITE_APP_BASE_API = 'http://114.132.189.42:7002/mes'
# VITE_APP_BASE_API = 'http://114.132.189.42:7002/mes'
# VITE_APP_BASE_API = 'http://192.168.0.206:7002/mes' # é‚¹è£•
VITE_APP_BASE_API = 'http://192.168.100.131:7002/mes' #
VITE_APP_BASE_API = 'http://192.168.10.119:7002/mes' # é‚¹è£•
# VITE_APP_BASE_API = 'http://192.168.100.131:7002/mes' #
# API æœåŠ¡å™¨çš„ URL
#VITE_APP_API_URL = 'http://114.132.189.42:7002/mes'
# VITE_APP_API_URL = 'http://114.132.189.42:7002/mes'
VITE_APP_API_URL = 'http://192.168.100.131:7002/mes' #
VITE_APP_API_URL = 'http://114.132.10.119:7002/mes'
# VITE_APP_API_URL = 'http://192.168.100.131:7002/mes' #
src/api/product/manage.ts
@@ -96,6 +96,15 @@
      method: "GET",
    });
  },
  // èŽ·å–ç”Ÿäº§ç»Ÿè®¡
  getProductStatistics(params: any) {
    return request<BaseResult<any>>({
      url: "/app/getProductStatistics",
      method: "GET",
      data: params,
    });
  },
};
export default ManageApi;
src/api/product/twist.ts
@@ -97,6 +97,50 @@
      method: "DELETE",
    });
  },
  // èŽ·å–ç»žçº¿è‡ªæ£€åŸºæœ¬ä¿¡æ¯
  getStrandedWireInspectionRecordStyleByWireId(params: { wireId: number | string }) {
    return request<BaseResult<any>>({
      url: `/wireInspection/getStrandedWireInspectionRecordStyleByWireId`,
      method: "GET",
      data: params,
    });
  },
  // èŽ·å–ç»žçº¿è‡ªæ£€åˆ—è¡¨
  getStrandedInspectionInfoByWireId(params: { wireId: number | string }) {
    return request<BaseResult<any>>({
      url: `/wireInspection/getStrandedInspectionInfoByWireId`,
      method: "GET",
      data: params,
    });
  },
  // ä¿å­˜ç»žçº¿è‡ªæ£€åŸºæœ¬ä¿¡æ¯
  saveStrandedWireInspectionFixedRecord(data: any) {
    return request<BaseResult<any>>({
      url: `/wireInspection/saveStrandedWireInspectionFixedRecord`,
      method: "POST",
      data: data,
    });
  },
  // ä¿å­˜ç»žçº¿è‡ªæ£€å·¥è‰ºè®°å½•
  saveStrandedWireInspectionStructureRecord(data: any) {
    return request<BaseResult<any>>({
      url: `/wireInspection/saveStrandedWireInspectionStructureRecord`,
      method: "POST",
      data: data,
    });
  },
  // åˆ é™¤ç»žçº¿è‡ªæ£€å·¥è‰ºè®°å½•
  deleteStrandedWireInspectionStructureRecord(id: number) {
    return request<BaseResult<any>>({
      url: `/wireInspection/deleteStrandedWireInspectionStructureRecord/${id}`,
      method: "POST",
    });
  },
};
export default TwistApi;
src/pages.json
@@ -194,12 +194,6 @@
      }
    },
    {
      "path": "pages/production/wire/selfInspect/edit",
      "style": {
        "navigationBarTitleText": "编辑拉丝自检"
      }
    },
    {
      "path": "pages/production/wire/backman/index",
      "style": {
        "navigationBarTitleText": "杂工"
@@ -257,12 +251,6 @@
      "path": "pages/production/twist/selfInspect/index",
      "style": {
        "navigationBarTitleText": "绞线自检"
      }
    },
    {
      "path": "pages/production/twist/selfInspect/edit",
      "style": {
        "navigationBarTitleText": "绞线自检编辑"
      }
    },
    {
src/pages/index/index.vue
@@ -93,6 +93,7 @@
import WorkerCallingCard from "@/components/worker-calling-card/index.vue";
import HomeApi from "@/api/home";
import { useUserStore } from "@/store/modules/user";
import { setTeamId, setPrepareId } from "@/utils/cache";
const visitStatsData = ref<VisitStatsVO>({
  todayUvCount: 0,
@@ -249,6 +250,16 @@
  checkVersion();
  const { data } = await HomeApi.getIndex();
  // å­˜å‚¨ç­ç»„ID和生产准备ID
  if (data) {
    if (data.team) {
      setTeamId(data.team);
    }
    if (data.prepareId) {
      setPrepareId(data.prepareId);
    }
  }
  // åˆ¤æ–­æ˜¯å¦ä¸ºå·¡æ£€å‘˜è§’色
  if (data.deviceGroupName == "时效组") {
    navList[1].show = true;
src/pages/production/detail/twistDetail.vue
@@ -13,12 +13,7 @@
    />
    <view class="mx-3">
      <wd-grid class="rounded-lg" clickable>
        <wd-grid-item
          icon="computer"
          link-type="navigateTo"
          :url="`/pages/production/twist/report/index?id=${paramsId}`"
          text="报工"
        />
        <wd-grid-item icon="computer" @click="handleReportClick" text="报工" />
        <!-- <wd-grid-item
          icon="chart"
          text="自检"
@@ -46,6 +41,8 @@
import { onLoad } from "@dcloudio/uni-app";
import ProductCard from "@/components/product_card/index.vue";
import TwistApi from "@/api/product/twist";
import { getPrepareId, setPrepareId } from "@/utils/cache";
import HomeApi from "@/api/home";
const paramsId = ref();
const cardData = reactive({
@@ -69,9 +66,49 @@
  cardData.unAmount = data.unLength;
};
onLoad((options: any) => {
// èŽ·å–å¹¶ç¼“å­˜ç”Ÿäº§å‡†å¤‡ID
const initPrepareId = async () => {
  try {
    const { data } = await HomeApi.getIndex();
    if (data && data.prepareId) {
      setPrepareId(data.prepareId);
    }
  } catch (error) {
    console.error("获取生产准备ID失败:", error);
  }
};
// å¤„理报工点击
const handleReportClick = () => {
  const prepareId = getPrepareId();
  console.log("绞线表格报工检查 - prepareId值:", prepareId);
  // å¦‚æžœprepareId为空或未定义,说明生产准备未完成
  if (!prepareId) {
    console.log("绞线表格报工阻止 - ç”Ÿäº§å‡†å¤‡æœªå®Œæˆ");
    uni.showModal({
      title: "提示",
      content: "请在电脑端完成生产准备确认,再进行报工操作",
      showCancel: false,
      confirmText: "确定",
      success: () => {
        // ç”¨æˆ·ç‚¹å‡»ç¡®å®šåŽï¼Œä¸åšä»»ä½•操作
      },
    });
    return;
  }
  // å¦‚果有 prepareId,正常跳转
  uni.navigateTo({
    url: `/pages/production/twist/report/index?id=${paramsId.value}`,
  });
};
onLoad(async (options: any) => {
  paramsId.value = options.id;
  getDetailData(options.id);
  await getDetailData(options.id);
  // èŽ·å–å¹¶ç¼“å­˜ç”Ÿäº§å‡†å¤‡ID
  await initPrepareId();
});
</script>
src/pages/production/index.vue
@@ -4,7 +4,7 @@
      <wd-col :span="21">
        <wd-search
          v-model="searchKeyword"
          placeholder="请输入规格型号"
          placeholder="请输入"
          placeholder-left
          hide-cancel
          @search="handleSearch"
@@ -24,18 +24,8 @@
          :key="`wait-${searchKey}`"
          :api="ManageApi.getProductList"
          state="待完成"
          :model="searchKeyword"
          :search="searchKeyword"
          @ok="changeWait"
        />
      </wd-tab>
      <wd-tab :title="`部分完成(${total.partial})`" class="tab_bg">
        <ProductList
          ref="partialRef"
          :key="`partial-${searchKey}`"
          :api="ManageApi.getProductList"
          state="部分完成"
          :model="searchKeyword"
          @ok="changePartial"
        />
      </wd-tab>
      <wd-tab :title="`已生产(${total.already})`" class="tab_bg">
@@ -44,7 +34,7 @@
          :key="`already-${searchKey}`"
          :api="ManageApi.getProductList"
          state="已完成"
          :model="searchKeyword"
          :search="searchKeyword"
          @ok="changeAlready"
        />
      </wd-tab>
@@ -69,14 +59,12 @@
const toast = useToast();
const waitRef = ref();
const partialRef = ref();
const alreadyRef = ref();
const tab = ref<number>(0);
const searchKeyword = ref("");
const searchKey = ref(0);
const total = reactive({
  wait: 0,
  partial: 0,
  already: 0,
});
@@ -84,16 +72,31 @@
  total.wait = num;
};
const changePartial = (num: number) => {
  total.partial = num;
};
const changeAlready = (num: number) => {
  total.already = num;
};
// èŽ·å–ç»Ÿè®¡æ•°æ®
const getStatistics = async () => {
  try {
    const params: any = {};
    if (searchKeyword.value) {
      params.search = searchKeyword.value;
    }
    const { code, data } = await ManageApi.getProductStatistics(params);
    if (code === 200 && data) {
      total.wait = data["待完成"] || 0;
      total.already = data["已完成"] || 0;
    }
  } catch (error) {
    console.error("获取统计数据失败:", error);
  }
};
const handleSearch = () => {
  searchKey.value++;
  // æœç´¢æ—¶æ›´æ–°ç»Ÿè®¡æ•°æ®
  getStatistics();
};
const handleClear = () => {
@@ -124,6 +127,8 @@
onMounted(() => {
  // å¼€å¯å¹¿æ’­ç›‘听事件
  setupScanListener();
  // èŽ·å–ç»Ÿè®¡æ•°æ®
  getStatistics();
  console.log("显示1");
});
onUnmounted(() => {
src/pages/production/list/index.vue
@@ -51,7 +51,7 @@
    type: String,
    default: "",
  },
  model: {
  search: {
    type: String,
    default: "",
  },
@@ -80,8 +80,8 @@
    current: pageNo,
    size: pageSize,
  };
  if (props.model) {
    params.model = props.model;
  if (props.search) {
    params.search = props.search;
  }
  const { code, data } = await props.api(params);
  if (code == 200) {
src/pages/production/twist/report/draw.vue
@@ -62,45 +62,6 @@
            </template>
          </view>
        </wd-tab>
        <wd-tab title="芯线领用自检" name="steel">
          <view class="form-section">
            <wd-form :model="localSteelData">
              <wd-form-item label="规格型号" prop="model" required>
                <wd-input
                  v-model="localSteelData.model"
                  :disabled="false"
                  placeholder="请输入"
                ></wd-input>
              </wd-form-item>
              <wd-form-item label="绞向" prop="twistedDirection" required>
                <wd-input
                  v-model="localSteelData.twistedDirection"
                  :disabled="false"
                  placeholder="请输入"
                ></wd-input>
              </wd-form-item>
              <wd-form-item label="外径" prop="outerDiameter" required>
                <wd-input
                  v-model="localSteelData.outerDiameter"
                  :disabled="false"
                  placeholder="请输入"
                ></wd-input>
              </wd-form-item>
              <wd-form-item label="划伤" prop="scratch" required>
                <wd-radio-group v-model="localSteelData.scratch" cell shape="dot">
                  <wd-radio value="是">是</wd-radio>
                  <wd-radio value="否">否</wd-radio>
                </wd-radio-group>
              </wd-form-item>
              <wd-form-item label="油污" prop="oilStain" required>
                <wd-radio-group v-model="localSteelData.oilStain" cell shape="dot">
                  <wd-radio value="是">是</wd-radio>
                  <wd-radio value="否">否</wd-radio>
                </wd-radio-group>
              </wd-form-item>
            </wd-form>
          </view>
        </wd-tab>
        <wd-tab title="盘具领用自检" name="reel">
          <view class="form-section">
            <wd-form :model="localReelData">
@@ -163,7 +124,9 @@
                    :key="option.value"
                    :modelValue="
                      Array.isArray(localReelData.weldQuality)
                        ? localReelData.weldQuality.includes(String(option.value))
                        ? localReelData.weldQuality
                            .map((v) => String(v))
                            .includes(String(option.value))
                        : false
                    "
                    shape="square"
@@ -172,6 +135,45 @@
                    {{ option.label }}
                  </wd-checkbox>
                </view>
              </wd-form-item>
            </wd-form>
          </view>
        </wd-tab>
        <wd-tab title="芯线领用自检" name="steel">
          <view class="form-section">
            <wd-form :model="localSteelData">
              <wd-form-item label="规格型号" prop="model" required>
                <wd-input
                  v-model="localSteelData.model"
                  :disabled="false"
                  placeholder="请输入"
                ></wd-input>
              </wd-form-item>
              <wd-form-item label="绞向" prop="twistedDirection" required>
                <wd-input
                  v-model="localSteelData.twistedDirection"
                  :disabled="false"
                  placeholder="请输入"
                ></wd-input>
              </wd-form-item>
              <wd-form-item label="外径" prop="outerDiameter" required>
                <wd-input
                  v-model="localSteelData.outerDiameter"
                  :disabled="false"
                  placeholder="请输入"
                ></wd-input>
              </wd-form-item>
              <wd-form-item label="划伤" prop="scratch" required>
                <wd-radio-group v-model="localSteelData.scratch" cell shape="dot">
                  <wd-radio value="是">是</wd-radio>
                  <wd-radio value="否">否</wd-radio>
                </wd-radio-group>
              </wd-form-item>
              <wd-form-item label="油污" prop="oilStain" required>
                <wd-radio-group v-model="localSteelData.oilStain" cell shape="dot">
                  <wd-radio value="是">是</wd-radio>
                  <wd-radio value="否">否</wd-radio>
                </wd-radio-group>
              </wd-form-item>
            </wd-form>
          </view>
@@ -360,21 +362,29 @@
};
// å¤„理焊接质量复选框的change事件
const handleWeldQualityCheckbox = (optionValue: string, checked: boolean) => {
  const currentValues = Array.isArray(localReelData.value.weldQuality)
    ? localReelData.value.weldQuality
    : [];
  let newValues: string[];
  if (checked) {
    // é€‰ä¸­
    newValues = [...currentValues, optionValue];
  } else {
    // å–消选中
    newValues = currentValues.filter((v) => v !== optionValue);
const handleWeldQualityCheckbox = (optionValue: string, checked: any) => {
  // ç¡®ä¿ weldQuality æ˜¯æ•°ç»„
  if (!Array.isArray(localReelData.value.weldQuality)) {
    localReelData.value.weldQuality = [];
  }
  // æ›´æ–°å€¼
  const currentValues = [...localReelData.value.weldQuality.map((v) => String(v))];
  const optionValueStr = String(optionValue);
  // åˆ¤æ–­å½“前是否已选中
  const isCurrentlyChecked = currentValues.includes(optionValueStr);
  // æ ¹æ®å½“前状态切换:如果当前已选中,则取消选中;如果当前未选中,则选中
  let newValues: string[];
  if (isCurrentlyChecked) {
    // å½“前已选中,取消选中
    newValues = currentValues.filter((v) => v !== optionValueStr);
  } else {
    // å½“前未选中,选中
    newValues = [...currentValues, optionValueStr];
  }
  // ç›´æŽ¥æ›´æ–°å€¼
  localReelData.value.weldQuality = newValues;
};
@@ -457,7 +467,7 @@
            length: item.length || "",
            windingTightness: item.windingTightness || "是",
            arrangement: item.arrangement || "是",
            edgeDistance: item.edgeDistance || "",
            edgeDistance: item.edgeDistance || "25",
          };
        })
      : [
@@ -468,7 +478,7 @@
            length: "",
            windingTightness: "是",
            arrangement: "是",
            edgeDistance: "",
            edgeDistance: "25",
          },
        ];
@@ -510,7 +520,16 @@
    weldQualityValue = [props.reelToolingInfo.weldQuality as string];
  } else {
    // é»˜è®¤é€‰æ‹©"已磨光"和"已修平"
    // å¦‚果字典数据已加载,使用字典中的实际值;否则使用字符串
    if (weldQualityOptions.value.length > 0) {
      const defaultOptions = weldQualityOptions.value.filter(
        (opt) => opt.label === "已磨光" || opt.label === "已修平"
      );
      weldQualityValue = defaultOptions.map((opt) => String(opt.value));
    } else {
      // å­—典未加载时,使用字符串作为临时值,后续会在字典加载后重新初始化
    weldQualityValue = ["已磨光", "已修平"];
    }
  }
  localReelData.value = {
@@ -579,7 +598,8 @@
  { deep: true }
);
watch(() => props.steelRegulationInfo, initializeData, { deep: true });
watch(() => props.reelToolingInfo, initializeData, { deep: true });
// æ³¨æ„ï¼šä¸ç›‘听 props.reelToolingInfo çš„变化,避免覆盖用户的操作
// watch(() => props.reelToolingInfo, initializeData, { deep: true });
const handleTabChange = (tabName: string) => {
  activeTab.value = tabName;
@@ -693,6 +713,23 @@
// åœ¨ç»„件挂载时异步加载数据字典
onMounted(async () => {
  await loadDictData();
  // å­—典数据加载完成后,重新初始化数据,确保默认值能正确匹配
  // ä½†åªåˆå§‹åŒ– weldQuality å¦‚果它还是空数组或默认值
  if (
    !Array.isArray(localReelData.value.weldQuality) ||
    localReelData.value.weldQuality.length === 0 ||
    (localReelData.value.weldQuality.length === 2 &&
      localReelData.value.weldQuality.includes("已磨光") &&
      localReelData.value.weldQuality.includes("已修平"))
  ) {
    // åªæœ‰åœ¨æ˜¯é»˜è®¤å€¼æˆ–空数组时才重新初始化
    const defaultOptions = weldQualityOptions.value.filter(
      (opt) => opt.label === "已磨光" || opt.label === "已修平"
    );
    if (defaultOptions.length > 0) {
      localReelData.value.weldQuality = defaultOptions.map((opt) => String(opt.value));
    }
  }
});
watch(
  () => [props.singleRegulationInfoArray, props.steelRegulationInfo, props.reelToolingInfo],
src/pages/production/twist/report/index.vue
@@ -2,7 +2,29 @@
  <view class="list">
    <z-paging ref="pagingRef" v-model="twistReportList" :fixed="false" @query="getTwistReportList">
      <template #top>
        <CardTitle title="报工信息" :hideAction="true" :full="false" @action="addReport" />
        <CardTitle title="报工信息" :hideAction="false" :full="false">
          <template #action>
            <wd-button
              icon="chart"
              :round="false"
              size="small"
              plain
              style="margin-right: 10px"
              @click="handleSelfCheck"
            >
              è‡ªæ£€
            </wd-button>
            <wd-button
              icon="file-add"
              :round="false"
              size="small"
              custom-class="add_btn"
              @click="addReport"
            >
              æ–°å¢ž
            </wd-button>
          </template>
        </CardTitle>
      </template>
      <wd-card v-for="item in twistReportList" :key="item.id" type="rectangle" custom-class="round">
        <template #title>
@@ -19,14 +41,6 @@
        <template #footer>
          <wd-button size="small" plain style="margin-right: 10px" @click="toAttachment(item)">
            é™„ä»¶
          </wd-button>
          <wd-button
            size="small"
            plain
            style="margin-right: 10px"
            @click="handleSelfCheck(item.id)"
          >
            è‡ªæ£€
          </wd-button>
          <wd-button size="small" plain type="error" @click="handleDelete(item)">删除</wd-button>
        </template>
@@ -68,7 +82,7 @@
import TwistApi from "@/api/product/twist";
import Draw from "./draw.vue";
import HomeApi from "@/api/home";
import { setTeamId, getTeamId } from "@/utils/cache";
import { setTeamId, getTeamId, setPrepareId } from "@/utils/cache";
const drawFormRef = reactive({
  visible: false,
@@ -149,24 +163,30 @@
const twistReportList = ref<any[]>([]);
const teamId = ref<string | number | null>(null);
// èŽ·å–å¹¶ç¼“å­˜ç­ç»„ID
// èŽ·å–å¹¶ç¼“å­˜ç­ç»„ID和生产准备ID
const initTeamId = async () => {
  // å…ˆå°è¯•从缓存获取
  const cachedTeamId = getTeamId();
  if (cachedTeamId) {
    teamId.value = cachedTeamId;
    return;
  }
  // å¦‚果缓存中没有,则调用接口获取
  // è°ƒç”¨æŽ¥å£èŽ·å–æœ€æ–°æ•°æ®
  try {
    const { data } = await HomeApi.getIndex();
    if (data && data.team) {
    if (data) {
      // å­˜å‚¨ç­ç»„ID
      if (data.team) {
      teamId.value = data.team;
      setTeamId(data.team);
    }
      // å­˜å‚¨ç”Ÿäº§å‡†å¤‡ID
      if (data.prepareId) {
        setPrepareId(data.prepareId);
      }
    }
  } catch (error) {
    console.error("获取班组ID失败:", error);
    console.error("获取数据失败:", error);
  }
};
@@ -293,11 +313,10 @@
  }
};
const handleSelfCheck = (id: string) => {
  console.log("执行自检操作,ID:", id);
  uni.showToast({
    title: "自检功能开发中",
    icon: "none",
const handleSelfCheck = () => {
  // è·³è½¬åˆ°è‡ªæ£€é¡µé¢ï¼Œä¼ é€’ wireId
  uni.navigateTo({
    url: `/pages/production/twist/selfInspect/index?id=${paramsId.value}`,
  });
};
src/pages/production/twist/selfInspect/edit.vue
ÎļþÒÑɾ³ý
src/pages/production/twist/selfInspect/form.vue
@@ -1,66 +1,369 @@
<template>
  <wd-form ref="form" :model="model" class="relative form_box">
    <wd-cell-group :border="true">
  <view class="form-container">
    <wd-form ref="formRef" :model="formData">
      <!-- ç»“构检查 -->
      <wd-row>
        <view style="margin: 10rpx">
          <text class="title">结构检查</text>
        </view>
        <wd-col :span="24">
          <wd-form-item label="成品结构" prop="structureFormula" required>
      <wd-input
        v-model="model.selfInspectName"
        label="自检名称"
        label-width="100px"
        prop="selfInspectName"
              v-model="formData.structureFormula"
              placeholder="请输入成品结构"
        clearable
        placeholder="请输入自检名称"
              :disabled="isViewMode"
      />
          </wd-form-item>
          <wd-form-item label="记录位置" prop="recordPosition" required>
            <wd-select-picker
              v-model="formData.recordPosition"
              :columns="recordLocationColumns"
              type="radio"
              placeholder="请选择记录位置"
              :clearable="false"
              :disabled="isViewMode"
            />
          </wd-form-item>
          <wd-form-item label="绞合外径(mm)" prop="twistedOuterDiameter" required>
      <wd-input
        v-model="model.unit"
        label="单位"
        label-width="100px"
        prop="unit"
              v-model="formData.twistedOuterDiameter"
              placeholder="请输入绞合外径"
        clearable
        placeholder="请输入单位"
              type="number"
              :disabled="isViewMode"
      />
          </wd-form-item>
        </wd-col>
      </wd-row>
      <!-- ç»“构标准值和实测 -->
      <wd-row v-if="structureItems.length > 0">
        <view style="margin: 10rpx">
          <text class="title">结构标准值和实测</text>
        </view>
        <wd-col
          :span="24"
          v-for="(item, index) in structureItems"
          :key="index"
          style="padding-bottom: 10px"
        >
          <wd-form-item
            :label="item.structureName"
            label-width="180px"
            style="color: red"
            required
          />
          <wd-form-item label="标准值" prop="structureValue">
            <text>{{ item.structureValue || "-" }}</text>
          </wd-form-item>
          <wd-form-item label="实测根数" prop="actualValue1" required>
      <wd-input
        v-model="model.standard"
        label="标准值"
        label-width="100px"
        prop="standard"
              v-model="item.actualValue1"
              placeholder="请输入根数"
        clearable
        placeholder="请输入标准值"
              type="number"
              :disabled="isViewMode"
      />
          </wd-form-item>
          <wd-form-item label="实测直径" prop="actualValue2" required>
      <wd-input
        v-model="model.selfInspectValue"
        label="自检值"
        label-width="100px"
        prop="selfInspectValue"
              v-model="item.actualValue2"
              placeholder="请输入直径"
        clearable
        placeholder="请输入自检值"
              type="number"
              :disabled="isViewMode"
            >
              <template #append>mm</template>
            </wd-input>
          </wd-form-item>
        </wd-col>
      </wd-row>
      <!-- ç»žçº¿å·¥è‰ºè´¨é‡æŽ§åˆ¶ -->
      <wd-row v-if="twistItems.length > 0">
        <view style="margin: 10rpx">
          <text class="title">绞线工艺质量控制</text>
        </view>
        <wd-col
          :span="24"
          v-for="(item, index) in twistItems"
          :key="index"
          style="padding-bottom: 10px"
        >
          <wd-form-item :label="item.twistName" label-width="180px" style="color: red" required />
          <wd-form-item label="绞向" prop="direction" required>
            <wd-select-picker
              v-model="item.direction"
              :columns="twistDirectionColumns"
              type="radio"
              placeholder="请选择绞向"
              :clearable="false"
              :disabled="isViewMode"
      />
          </wd-form-item>
          <wd-form-item label="节距" prop="pitch" required>
      <wd-input
        v-model="model.selfInspectResult"
        label="自检结果"
        label-width="100px"
        prop="selfInspectResult"
              v-model="item.pitch"
              placeholder="请输入节距"
        clearable
        placeholder="请输入自检结果"
      />
    </wd-cell-group>
              type="number"
              :disabled="isViewMode"
              @input="updatePitchRatio(item)"
            >
              <template #append>mm</template>
            </wd-input>
          </wd-form-item>
          <wd-form-item label="节径比" prop="pitchRatio">
            <text>{{ calculatePitchRatio(item.pitch, item.dia) }}</text>
          </wd-form-item>
        </wd-col>
      </wd-row>
      <!-- å¤–观和结论 -->
      <wd-row>
        <view style="margin: 10rpx">
          <text class="title">外观和结论</text>
        </view>
        <wd-col :span="24">
          <wd-form-item label="成品外观" prop="productAppearance" required>
            <view v-if="!isViewMode" style="display: flex; flex-wrap: wrap; gap: 10px">
              <wd-checkbox
                v-for="(opt, idx) in appearanceOptions"
                :key="idx"
                :value="opt.value"
                :modelValue="formData.productAppearance.includes(opt.value)"
                @click="handleAppearanceClick(opt.value)"
                style="width: 100px"
              >
                {{ opt.label }}
              </wd-checkbox>
            </view>
            <text v-else>{{ formatProductAppearance(formData.productAppearance) }}</text>
          </wd-form-item>
          <wd-form-item label="结论" prop="conclusion" required>
            <wd-radio-group
              v-model="formData.conclusion"
              inline
              class="conclusion-radio-group"
              :disabled="isViewMode"
            >
              <wd-radio value="合格" shape="dot">合格</wd-radio>
              <wd-radio value="不合格" shape="dot">不合格</wd-radio>
            </wd-radio-group>
          </wd-form-item>
        </wd-col>
      </wd-row>
  </wd-form>
  </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, reactive, watch, computed } from "vue";
const props = defineProps({
  formData: {
    type: Object,
    default: () => ({}),
  },
  structureItems: {
    type: Array,
    default: () => [],
  },
  twistItems: {
    type: Array,
    default: () => [],
  },
  isViewMode: {
    type: Boolean,
    default: false,
  },
  recordLocation: {
    type: Array,
    default: () => [],
  },
  appearanceOptions: {
    type: Array,
    default: () => [],
  },
});
const emit = defineEmits(["update:formData", "update:structureItems", "update:twistItems"]);
const formRef = ref();
// ç»žå‘选项
const twistDirectionColumns = [
  { label: "左向", value: "左向" },
  { label: "右向", value: "右向" },
];
// è®°å½•位置选项
const recordLocationColumns = computed(() => {
  return props.recordLocation.map((item: any) => ({
    label: item.label,
    value: item.value,
  }));
});
// è®¡ç®—节径比
const calculatePitchRatio = (pitch: string, dia: string) => {
  if (!pitch || !dia) return "-";
  const pitchNum = parseFloat(pitch);
  const diaNum = parseFloat(dia);
  if (isNaN(pitchNum) || isNaN(diaNum) || diaNum === 0) return "-";
  return (pitchNum / diaNum).toFixed(2);
};
// æ›´æ–°èŠ‚å¾„æ¯”
const updatePitchRatio = (item: any) => {
  item.pitchRatio = calculatePitchRatio(item.pitch, item.dia);
  emit("update:twistItems", [...props.twistItems]);
};
// æ ¼å¼åŒ–产品外观显示
const formatProductAppearance = (productAppearance: string[]) => {
  if (!productAppearance || productAppearance.length === 0) return "-";
  return productAppearance.join("、");
};
// å¤„理产品外观选择的互斥逻辑
const handleAppearanceClick = (value: string) => {
  const currentValues = [...props.formData.productAppearance];
  const isCurrentlyChecked = currentValues.includes(value);
  let newSelection: string[] = [];
  if (value === "无外观问题") {
    if (isCurrentlyChecked) {
      newSelection = [];
    } else {
      newSelection = ["无外观问题"];
    }
  } else {
    if (isCurrentlyChecked) {
      newSelection = currentValues.filter((v) => v !== value);
    } else {
      const filteredValues = currentValues.filter((v) => v !== "无外观问题");
      newSelection = [...filteredValues, value];
    }
  }
  emit("update:formData", {
    ...props.formData,
    productAppearance: newSelection,
  });
};
// è¡¨å•验证
const validate = async () => {
  try {
    await formRef.value?.validate();
    return true;
  } catch (error) {
    return false;
  }
};
// éªŒè¯ç»“构项
const validateStructureItems = () => {
  for (const item of props.structureItems) {
    if (!item.actualValue1) {
      return { valid: false, message: `${item.structureName}实测根数为必填项` };
    }
    if (!item.actualValue2) {
      return { valid: false, message: `${item.structureName}实测直径为必填项` };
    }
  }
  return { valid: true };
};
// éªŒè¯ç»žçº¿å·¥è‰ºé¡¹
const validateTwistItems = () => {
  for (const item of props.twistItems) {
    if (!item.direction) {
      return { valid: false, message: `${item.twistName}绞向为必填项` };
    }
    if (!item.pitch) {
      return { valid: false, message: `${item.twistName}节距为必填项` };
    }
  }
  return { valid: true };
};
// å®Œæ•´éªŒè¯
const validateAll = async () => {
  // åŸºç¡€å­—段验证
  if (!props.formData.structureFormula) {
    return { valid: false, message: "成品结构为必填项" };
  }
  if (!props.formData.recordPosition) {
    return { valid: false, message: "记录位置为必填项" };
  }
  if (!props.formData.twistedOuterDiameter) {
    return { valid: false, message: "绞合外径为必填项" };
  }
  if (!props.formData.productAppearance || props.formData.productAppearance.length === 0) {
    return { valid: false, message: "成品外观为必填项" };
  }
  if (!props.formData.conclusion) {
    return { valid: false, message: "结论为必填项" };
  }
  // ç»“构项验证
  const structureResult = validateStructureItems();
  if (!structureResult.valid) {
    return structureResult;
  }
  // ç»žçº¿å·¥è‰ºé¡¹éªŒè¯
  const twistResult = validateTwistItems();
  if (!twistResult.valid) {
    return twistResult;
  }
  return { valid: true };
};
defineExpose({
  validate,
  validateAll,
});
</script>
<style lang="scss" scoped>
.form_box {
.form-container {
  padding: 12px;
  max-height: 70vh;
  overflow-y: auto;
}
.submit_btn {
.title {
  position: relative;
  margin-left: 10px;
  font-size: 14px;
  font-weight: 600;
  color: #0d867f;
}
.title::after {
  position: absolute;
  bottom: 0;
  width: 100%;
  content: "";
  top: 4px;
  left: -10px;
  width: 3px;
  height: 14px;
  background: #0d867f;
  border-radius: 2px;
}
.conclusion-radio-group {
  display: flex;
  align-items: flex-start;
  gap: 20rpx;
}
:deep(.wd-form-item) {
  margin-bottom: 8rpx;
}
</style>
src/pages/production/twist/selfInspect/index.vue
@@ -1,109 +1,697 @@
<template>
  <view class="list">
    <z-paging ref="pagingRef" v-model="cardList" :fixed="false" @query="getList">
      <template #top>
        <CardTitle title="绞线自检" :hideAction="false" />
    <!-- åŸºæœ¬ä¿¡æ¯æ¨¡å— -->
    <wd-row>
      <view style="margin: 10rpx" class="flex justify-between items-center">
        <text class="title">基本信息</text>
        <view class="flex gap-2">
          <wd-button v-if="!isEdit" type="primary" size="small" icon="edit" @click="handleEdit">
            ç¼–辑
          </wd-button>
          <wd-button v-if="isEdit" type="info" size="small" icon="close" @click="handleCancel">
            å–消
          </wd-button>
          <wd-button v-if="isEdit" type="success" size="small" icon="check" @click="handleSave">
            ä¿å­˜
          </wd-button>
        </view>
      </view>
      <wd-col :span="24">
        <wd-form-item label="日期" prop="recordDate">
          {{ formatDate(formData.recordDate) }}
        </wd-form-item>
        <wd-form-item label="机台" prop="deviceModel">
          {{ formatValue(formData.deviceModel) }}
        </wd-form-item>
        <wd-form-item label="班次" prop="workShift">
          {{ formatValue(formData.workShift) }}
        </wd-form-item>
        <wd-form-item label="产品类别" prop="productType">
          {{ formatValue(formData.productType) }}
        </wd-form-item>
        <wd-form-item label="型号规格" prop="model">
          {{ formatValue(formData.model) }}
        </wd-form-item>
        <wd-form-item label="生产长度" prop="actuallyLength">
          {{ formatValue(formData.actuallyLength, "m") }}
        </wd-form-item>
        <wd-form-item label="成品线盘号" prop="systemNo">
          {{ formatValue(formData.systemNo) }}
        </wd-form-item>
        <wd-form-item label="张力设置" prop="tensionSetting">
          <template v-if="isEdit">
            <wd-input v-model="formData.tensionSetting" placeholder="请输入张力设置" clearable />
      </template>
      <wd-card v-for="(item, index) in cardList" :key="index" type="rectangle" custom-class="round">
          <template v-else>
            {{ formatValue(formData.tensionSetting, "") }}
          </template>
        </wd-form-item>
      </wd-col>
    </wd-row>
    <!-- å·¥è‰ºè®°å½•模块 -->
    <wd-row>
      <view style="margin: 10rpx" class="flex justify-between items-center">
        <text class="title">工艺记录</text>
        <wd-button
          v-if="!isEdit"
          type="primary"
          size="small"
          icon="file-add"
          @click="handleAddInspection"
        >
          æ·»åŠ è‡ªæ£€
        </wd-button>
      </view>
      <wd-col :span="24">
        <wd-card
          v-for="(item, index) in inspectionList"
          :key="index"
          type="rectangle"
          custom-class="round"
          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>
                <text class="text-[#252525] font-medium">
                  è®°å½•位置:
                  {{
                    getRecordPositionLabel(
                      item.recordPosition || item.structureRecordResult?.recordPosition
                    )
                  }}
                </text>
            </view>
            <view class="text-[#A8A8A8]" @click="toEdit">编辑</view>
          </view>
        </template>
        <ProductionCard :data="cardAttr" :value="item" color="#0D867F" />
      </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 class="px-3 pb-3">
            <view class="flex mb-2">
              <text class="text-[#646874] mr-3">成品结构:</text>
              <text class="text-[#252525]">
                {{
                  item.structureRecordResult?.inspectStructure?.structureFormula ||
                  item.structureFormula ||
                  "-"
                }}
              </text>
      </view>
      <SelfInspectForm />
            <view class="flex mb-2">
              <text class="text-[#646874] mr-3">成品外观:</text>
              <text class="text-[#252525]">
                {{
                  getAppearanceLabel(
                    item.structureRecordResult?.productAppearance || item.productAppearance
                  )
                }}
              </text>
            </view>
            <view class="flex mb-2">
              <text class="text-[#646874] mr-3">结论:</text>
              <text
                class="text-[#252525]"
                :style="{
                  color:
                    (item.structureRecordResult?.conclusion || item.conclusion) === '合格'
                      ? '#67C23A'
                      : '#F56C6C',
                }"
              >
                {{ item.structureRecordResult?.conclusion || item.conclusion || "-" }}
              </text>
            </view>
            <view class="flex">
              <text class="text-[#646874] mr-3">记录人:</text>
              <text class="text-[#252525]">{{ item.createUserName || "-" }}</text>
            </view>
          </view>
          <template #footer>
            <view class="flex justify-end gap-2">
              <wd-button size="small" plain @click="handleViewInspection(item, index)">
                æŸ¥çœ‹
              </wd-button>
              <wd-button
                v-if="!isEdit"
                size="small"
                plain
                type="primary"
                @click="handleEditInspection(item, index)"
              >
                ä¿®æ”¹
              </wd-button>
              <wd-button
                v-if="!isEdit"
                size="small"
                plain
                type="error"
                @click="handleDeleteInspection(index)"
              >
                åˆ é™¤
              </wd-button>
            </view>
          </template>
        </wd-card>
        <view v-if="inspectionList.length === 0" class="text-center py-10 text-[#999]">
          æš‚无工艺记录
        </view>
      </wd-col>
    </wd-row>
    <!-- è‡ªæ£€å¼¹çª— -->
    <wd-popup
      v-model="inspectionDialogVisible"
      position="bottom"
      custom-class="yl-popup"
      :close-on-click-modal="false"
    >
      <view class="action px-3">
        <wd-button type="text" @click="inspectionDialogVisible = false">取消</wd-button>
        <wd-button v-if="!isViewMode" type="text" @click="handleSaveInspection">保存</wd-button>
      </view>
      <SelfInspectForm
        ref="inspectionFormRef"
        :form-data="inspectionForm"
        :structure-items="structureItems"
        :twist-items="twistItems"
        :is-view-mode="isViewMode"
        :record-location="recordLocation"
        :appearance-options="appearanceOptions"
        @update:form-data="(val) => Object.assign(inspectionForm, val)"
        @update:structure-items="(val) => (structureItems = val)"
        @update:twist-items="(val) => (twistItems = val)"
      />
    </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 TwistApi from "@/api/product/twist";
import ManageApi from "@/api/product/manage";
import { onLoad } from "@dcloudio/uni-app";
import { ref, reactive } from "vue";
const pagingRef = ref();
const paramsId = ref();
const paramsId = ref<string | number>("");
const toast = useToast();
const dialog = reactive({
  visible: false,
const isEdit = ref(false);
const isViewMode = ref(false);
const loading = ref(false);
// åŸºæœ¬ä¿¡æ¯è¡¨å•数据
const formData = reactive({
  id: undefined as number | string | undefined,
  recordDate: "",
  deviceModel: "",
  workShift: "",
  productType: "",
  model: "",
  actuallyLength: "",
  systemNo: "",
  tensionSetting: "",
  createUserName: "",
});
const cardAttr = ref<any[]>([
  {
    label: "单位",
    prop: "inspectionUnit",
  },
  {
    label: "标准值",
    prop: "standardValue",
  },
  {
    label: "自检值",
    prop: "inspectionItem",
  },
  {
    label: "自检结果",
    prop: "inspectionResult",
    color: "#FF1E1E",
  },
]);
const cardList = ref<any[]>([]);
// const addReport = () => {
//   dialog.visible = true;
// };
// å·¥è‰ºè®°å½•列表
const inspectionList = ref<any[]>([]);
const toEdit = () => {
  uni.navigateTo({
    url: "/pages/production/twist/selfInspect/edit",
// è‡ªæ£€å¼¹çª—
const inspectionDialogVisible = ref(false);
const inspectionFormRef = ref();
const currentEditIndex = ref(-1);
// è‡ªæ£€è¡¨å•数据
const inspectionForm = reactive({
  recordPosition: "",
  structureFormula: "",
  productAppearance: ["无外观问题"],
  conclusion: "合格",
  createUserName: "",
  twistedOuterDiameter: "",
});
// ç»“构检查数据
const structureItems = ref<any[]>([]);
// ç»žçº¿å·¥è‰ºæ•°æ®
const twistItems = ref<any[]>([]);
// å­˜å‚¨ä»ŽæŽ¥å£èŽ·å–çš„ç»“æž„å…¬å¼
const structureFormulaFromApi = ref("");
// å­—典数据
const recordLocation = ref<any>([]);
const appearanceOptions = ref<Array<{ label: string; value: string }>>([]);
// èŽ·å–å¤–è§‚æ ‡ç­¾
const getAppearanceLabel = (value: string | string[]) => {
  if (Array.isArray(value)) {
    return value.join("、") || "无";
  } else {
    return value || "无";
  }
};
// èŽ·å–è®°å½•ä½ç½®æ ‡ç­¾
const getRecordPositionLabel = (value: string) => {
  const option = recordLocation.value.find((item: any) => item.value === value);
  return option ? option.label : value || "-";
};
// æ ¼å¼åŒ–数值显示
const formatValue = (value: any, unit?: string) => {
  if (value === null || value === undefined || value === "") return "-";
  return unit ? `${value}${unit}` : value;
};
// æ ¼å¼åŒ–日期显示
const formatDate = (date: string) => {
  if (!date) return "-";
  return new Date(date).toLocaleDateString("zh-CN", {
    year: "numeric",
    month: "2-digit",
    day: "2-digit",
  });
};
const submit = () => {
  toast.show("提交");
  dialog.visible = false;
// è®¡ç®—节径比
const calculatePitchRatio = (pitch: string, dia: string) => {
  if (!pitch || !dia) return "-";
  const pitchNum = parseFloat(pitch);
  const diaNum = parseFloat(dia);
  if (isNaN(pitchNum) || isNaN(diaNum) || diaNum === 0) return "-";
  return (pitchNum / diaNum).toFixed(2);
};
const cancel = () => {
  toast.show("取消");
  dialog.visible = false;
};
// åˆå§‹åŒ–数据
const getData = async () => {
  if (!paramsId.value) {
    console.warn("wireId ä¸å­˜åœ¨");
    return;
  }
const getList = async () => {
  const { data } = await ManageApi.getSelfInspection({
    outPutId: paramsId.value,
    type: "绞线",
  loading.value = true;
  try {
    // èŽ·å–åŸºæœ¬ä¿¡æ¯
    const { code, data } = await TwistApi.getStrandedWireInspectionRecordStyleByWireId({
      wireId: paramsId.value,
  });
  pagingRef.value.complete(data);
    if (code === 200 && data) {
      // å›žæ˜¾æ•°æ®åˆ°è¡¨å•
      if (data.fixedInfo) {
        Object.assign(formData, data.fixedInfo);
      }
      if (data.tensionSetting !== undefined) {
        formData.tensionSetting = data.tensionSetting;
      }
      // å¤„理结构检查数据
      if (data.inspectStructure) {
        if (data.inspectStructure.structureFormula) {
          structureFormulaFromApi.value = data.inspectStructure.structureFormula;
          inspectionForm.structureFormula = data.inspectStructure.structureFormula;
        }
        if (data.inspectStructure.structureItems) {
          structureItems.value = data.inspectStructure.structureItems.map((item: any) => ({
            ...item,
            actualValue1: "",
            actualValue2: "",
          }));
        }
      }
      // å¤„理绞线工艺数据
      if (data.inspectTwist) {
        twistItems.value = data.inspectTwist.map((item: any) => ({
          ...item,
          pitch: "",
        }));
      }
    }
    // èŽ·å–è‡ªæ£€åˆ—è¡¨æ•°æ®
    await getInspectionList();
    // èŽ·å–å­—å…¸æ•°æ®
    await loadDictData();
  } catch (error) {
    console.error("获取自检数据失败:", error);
    toast.error("获取自检数据失败");
  } finally {
    loading.value = false;
  }
};
onLoad((options: any) => {
// èŽ·å–è‡ªæ£€åˆ—è¡¨æ•°æ®
const getInspectionList = async () => {
  if (!paramsId.value) {
    console.warn("wireId ä¸å­˜åœ¨");
    return;
  }
  try {
    const { code, data } = await TwistApi.getStrandedInspectionInfoByWireId({
      wireId: paramsId.value,
    });
    if (code === 200 && data) {
      inspectionList.value = data.structureInfos || [];
      inspectionList.value = inspectionList.value.map((item: any) => {
        return {
          ...item.structureRecordResult,
          ...item,
          structureFormula:
            item.structureRecordResult?.inspectStructure?.structureFormula || item.structureFormula,
        };
      });
    }
  } catch (error) {
    console.error("获取自检列表失败:", error);
  }
};
// åŠ è½½å­—å…¸æ•°æ®
const loadDictData = async () => {
  try {
    // è®°å½•位置字典
    const recordLocationRes = await ManageApi.dictAPI("record_location");
    if (recordLocationRes.data && Array.isArray(recordLocationRes.data)) {
      recordLocation.value = recordLocationRes.data.map((item: any) => ({
        label: item.dictLabel || "",
        value: item.dictValue || "",
      }));
    }
    // å¤–观选项字典
    const appearanceRes = await ManageApi.dictAPI("draw_appearance_quality");
    if (appearanceRes.data && Array.isArray(appearanceRes.data)) {
      appearanceOptions.value = appearanceRes.data.map((item: any) => ({
        label: item.dictLabel || "",
        value: item.dictValue || "",
      }));
    }
  } catch (error) {
    console.error("加载字典数据失败:", error);
  }
};
// ä¿å­˜åŸºæœ¬ä¿¡æ¯
const handleSave = async () => {
  if (!formData.tensionSetting) {
    toast.warning("请输入张力设置");
    return;
  }
  try {
    const submitData = {
      wireId: paramsId.value,
      strandedWireInspectionRecordId: formData.id,
      tensionSetting: formData.tensionSetting,
    };
    const { code } = await TwistApi.saveStrandedWireInspectionFixedRecord(submitData);
    if (code === 200) {
      toast.success("保存成功");
      isEdit.value = false;
      await getData();
    } else {
      toast.error("保存失败");
    }
  } catch (error) {
    console.error("保存失败:", error);
    toast.error("保存失败");
  }
};
// ç¼–辑
const handleEdit = () => {
  isEdit.value = true;
};
// å–消
const handleCancel = () => {
  isEdit.value = false;
  getData();
};
// æ·»åŠ è‡ªæ£€
const handleAddInspection = () => {
  currentEditIndex.value = -1;
  isViewMode.value = false;
  // æ¸…空表单
  Object.assign(inspectionForm, {
    recordPosition: "",
    structureFormula: structureFormulaFromApi.value || "",
    productAppearance: ["无外观问题"],
    conclusion: "合格",
    createUserName: "",
    twistedOuterDiameter: "",
  });
  // é‡ç½®ç»“构项和绞线工艺数据
  if (structureItems.value.length > 0) {
    structureItems.value = structureItems.value.map((item: any) => {
      let defaultActualValue1 = "";
      if (item.structureValue && typeof item.structureValue === "string") {
        const parts = item.structureValue.split("/");
        if (parts.length > 0 && parts[0].trim()) {
          defaultActualValue1 = parts[0].trim();
        }
      }
      return {
        ...item,
        actualValue1: defaultActualValue1,
        actualValue2: "",
      };
    });
  }
  if (twistItems.value.length > 0) {
    twistItems.value = twistItems.value.map((item: any) => ({
      ...item,
      direction: item.direction || "",
      pitch: "",
    }));
  }
  inspectionDialogVisible.value = true;
};
// ç¼–辑自检
const handleEditInspection = (row: any, index: number) => {
  currentEditIndex.value = index;
  isViewMode.value = false;
  const recordResult = row.structureRecordResult || {};
  const inspectStructure = recordResult.inspectStructure || row.inspectStructure || {};
  const inspectTwist = recordResult.inspectTwist || row.inspectTwist || [];
  // é‡ç»„表单数据
  Object.assign(inspectionForm, {
    recordPosition: recordResult.recordPosition || row.recordPosition || "",
    structureFormula: inspectStructure.structureFormula || row.structureFormula || "",
    productAppearance: recordResult.productAppearance || row.productAppearance || ["无外观问题"],
    conclusion: recordResult.conclusion || row.conclusion || "合格",
    twistedOuterDiameter:
      recordResult.twistedOuterDiameter ||
      inspectStructure.twistedOuterDiameter ||
      row.twistedOuterDiameter ||
      "",
    createUserName: row.createUserName || "",
  });
  // é‡ç»„结构项数据
  if (inspectStructure.structureItems) {
    structureItems.value = inspectStructure.structureItems.map((item: any) => ({
      ...item,
      actualValue1: item.actualValue1 || "",
      actualValue2: item.actualValue2 || "",
    }));
  }
  // é‡ç»„绞线工艺数据
  if (inspectTwist.length > 0) {
    twistItems.value = inspectTwist.map((item: any) => ({
      ...item,
      direction: item.direction || "",
      pitch: item.pitch || "",
      dia: item.dia || "",
      pitchRatio: item.pitchRatio || calculatePitchRatio(item.pitch, item.dia),
    }));
  }
  inspectionDialogVisible.value = true;
};
// æŸ¥çœ‹è‡ªæ£€
const handleViewInspection = (row: any, index: number) => {
  currentEditIndex.value = index;
  isViewMode.value = true;
  const recordResult = row.structureRecordResult || {};
  const inspectStructure = recordResult.inspectStructure || row.inspectStructure || {};
  const inspectTwist = recordResult.inspectTwist || row.inspectTwist || [];
  Object.assign(inspectionForm, {
    recordPosition: recordResult.recordPosition || row.recordPosition || "",
    structureFormula: inspectStructure.structureFormula || row.structureFormula || "",
    productAppearance: recordResult.productAppearance || row.productAppearance || [],
    conclusion: recordResult.conclusion || row.conclusion || "合格",
    twistedOuterDiameter:
      recordResult.twistedOuterDiameter ||
      inspectStructure.twistedOuterDiameter ||
      row.twistedOuterDiameter ||
      "",
    createUserName: row.createUserName || "",
  });
  if (inspectStructure.structureItems) {
    structureItems.value = inspectStructure.structureItems.map((item: any) => ({
      ...item,
      actualValue1: item.actualValue1 || "",
      actualValue2: item.actualValue2 || "",
    }));
  }
  if (inspectTwist.length > 0) {
    twistItems.value = inspectTwist.map((item: any) => ({
      ...item,
      direction: item.direction || "",
      pitch: item.pitch || "",
      dia: item.dia || "",
      pitchRatio: item.pitchRatio || calculatePitchRatio(item.pitch, item.dia),
    }));
  }
  inspectionDialogVisible.value = true;
};
// åˆ é™¤è‡ªæ£€
const handleDeleteInspection = async (index: number) => {
  const item = inspectionList.value[index];
  if (!item || !item.id) {
    toast.error("删除失败:记录ID不存在");
    return;
  }
  uni.showModal({
    title: "提示",
    content: "确定要删除这条工艺记录吗?",
    success: async (res) => {
      if (res.confirm) {
        try {
          const { code } = await TwistApi.deleteStrandedWireInspectionStructureRecord(item.id);
          if (code === 200) {
            inspectionList.value.splice(index, 1);
            toast.success("删除成功");
          } else {
            toast.error("删除失败");
          }
        } catch (error) {
          console.error("删除工艺记录失败:", error);
          toast.error("删除失败");
        }
      }
    },
  });
};
// ä¿å­˜è‡ªæ£€
const handleSaveInspection = async () => {
  if (!inspectionFormRef.value) return;
  const result = await inspectionFormRef.value.validateAll();
  if (!result.valid) {
    toast.warning(result.message || "请完成必填项");
    return;
  }
  try {
    const submitData = {
      wireId: paramsId.value,
      strandedWireInspectionRecordId: formData.id,
      tensionSetting: formData.tensionSetting,
      recordPosition: inspectionForm.recordPosition,
      id: currentEditIndex.value >= 0 ? inspectionList.value[currentEditIndex.value].id : undefined,
      inspectionStructureResult: {
        twistedOuterDiameter: inspectionForm.twistedOuterDiameter,
        recordPosition: inspectionForm.recordPosition,
        inspectStructure: {
          structureFormula: inspectionForm.structureFormula,
          structureItems: structureItems.value.map((item: any) => ({
            structureName: item.structureName,
            structureValue: item.structureValue,
            actualValue1: item.actualValue1,
            actualValue2: item.actualValue2,
          })),
        },
        inspectTwist: twistItems.value.map((item: any) => ({
          twistName: item.twistName,
          direction: item.direction,
          pitch: item.pitch,
          dia: item.dia,
          pitchRatio: calculatePitchRatio(item.pitch, item.dia),
        })),
        productAppearance: inspectionForm.productAppearance,
        conclusion: inspectionForm.conclusion,
      },
    };
    const { code } = await TwistApi.saveStrandedWireInspectionStructureRecord(submitData);
    if (code === 200) {
      toast.success(currentEditIndex.value >= 0 ? "修改成功" : "添加成功");
      inspectionDialogVisible.value = false;
      await getInspectionList();
    } else {
      toast.error("保存失败");
    }
  } catch (error) {
    console.error("保存工艺记录失败:", error);
    toast.error("保存失败");
  }
};
onLoad(async (options: any) => {
  paramsId.value = options.id;
  await getData();
});
</script>
<style lang="scss" scoped>
.list {
  height: calc(100vh - 120px);
  padding: 12px;
  background: #f3f9f8;
  min-height: 100vh;
  padding-bottom: 80px;
}
.title {
  position: relative;
  margin-left: 10px;
  font-size: 16px;
  font-weight: 500;
  color: #0d867f;
}
.title::after {
  position: absolute;
  content: "";
  top: 4px;
  left: -10px;
  width: 4px;
  height: 16px;
  background: #0d867f;
  border-radius: 2px;
}
  :deep() {
    .round {
      border-radius: 4px;
    }
  }
}
src/utils/cache.ts
@@ -2,6 +2,7 @@
const USER_INFO_KEY = "user-info";
const DICT_KEY = "dict";
const TEAM_ID_KEY = "team-id";
const PREPARE_ID_KEY = "prepare-id";
import { type DictData } from "@/api/system/dict";
// è®¾ç½® token
@@ -64,10 +65,26 @@
  uni.removeStorageSync(TEAM_ID_KEY);
}
// è®¾ç½®ç”Ÿäº§å‡†å¤‡ID
export function setPrepareId(prepareId: string | number) {
  uni.setStorageSync(PREPARE_ID_KEY, prepareId);
}
// èŽ·å–ç”Ÿäº§å‡†å¤‡ID
export function getPrepareId(): string | number | null {
  return uni.getStorageSync(PREPARE_ID_KEY) || null;
}
// æ¸…除生产准备ID
export function clearPrepareId() {
  uni.removeStorageSync(PREPARE_ID_KEY);
}
// æ¸…除所有缓存信息
export function clearAll() {
  clearToken();
  clearUserInfo();
  clearDictCache();
  clearTeamId();
  clearPrepareId();
}