spring
2025-11-19 8cc901ed214f3885b34a07d0520fbcfd50063439
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">
      <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">
    <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="formData.structureFormula"
              placeholder="请输入成品结构"
              clearable
              :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="formData.twistedOuterDiameter"
              placeholder="请输入绞合外径"
              clearable
              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="item.actualValue1"
              placeholder="请输入根数"
              clearable
              type="number"
              :disabled="isViewMode"
            />
          </wd-form-item>
          <wd-form-item label="实测直径" prop="actualValue2" required>
            <wd-input
              v-model="item.actualValue2"
              placeholder="请输入直径"
              clearable
              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="item.pitch"
              placeholder="请输入节距"
              clearable
              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>