| | |
| | | <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> |