<template>
|
<view class="fixed-header">
|
<view class="header-container">
|
<wd-button
|
icon="file-add"
|
:round="false"
|
size="small"
|
custom-class="add_btn"
|
@click="editList"
|
v-if="!isEdit"
|
>
|
编辑
|
</wd-button>
|
<wd-button
|
icon="close"
|
type="info"
|
:round="false"
|
size="small"
|
custom-class="add_btn"
|
@click="close"
|
v-if="isEdit"
|
>
|
取消
|
</wd-button>
|
<wd-button
|
icon="check"
|
type="success"
|
:round="false"
|
size="small"
|
custom-class="add_btn"
|
@click="saveList"
|
v-if="isEdit"
|
>
|
保存
|
</wd-button>
|
<view class="placeholder"></view>
|
<view class="scan-info">
|
<text class="scan-device-text">当前扫码机台: {{ scannedDeviceModel || "未扫码" }}</text>
|
</view>
|
<view class="scan-wrapper" @click="openScan">
|
<wd-icon name="scan" size="24px" color="#0D867F"></wd-icon>
|
</view>
|
</view>
|
</view>
|
<view class="list">
|
<!-- 基本信息模块 -->
|
<wd-row>
|
<view style="margin: 10rpx">
|
<text class="title">{{ "基本信息" }}</text>
|
</view>
|
<wd-col :span="24">
|
<wd-form-item label="日期" prop="recordDate">
|
{{ formatDate(detailData.fixedInfo?.recordDate) }}
|
</wd-form-item>
|
<wd-form-item label="机台" prop="deviceModel">
|
{{ formatValue(detailData.fixedInfo?.deviceModel) }}
|
</wd-form-item>
|
<wd-form-item label="班次" prop="workShift">
|
{{ formatValue(detailData.fixedInfo?.workShift) }}
|
</wd-form-item>
|
<wd-form-item label="班组" prop="teamName">
|
{{ formatValue(detailData.fixedInfo?.teamName) }}
|
</wd-form-item>
|
<wd-form-item label="单丝规格" prop="model">
|
{{ formatValue(detailData.fixedInfo?.model) }}
|
</wd-form-item>
|
<wd-form-item label="生产轴数" prop="outputNumber">
|
{{ formatValue(detailData.fixedInfo?.outputNumber, "轴") }}
|
</wd-form-item>
|
<wd-form-item label="型号" prop="poleModel">
|
{{ formatValue(detailData.fixedInfo?.poleModel) }}
|
</wd-form-item>
|
<wd-form-item label="批次" prop="poleNumber">
|
{{ formatValue(detailData.fixedInfo?.poleNumber) }}
|
</wd-form-item>
|
<wd-form-item label="记录人" prop="createUserName">
|
{{ formatValue(detailData.fixedInfo?.createUserName) }}
|
</wd-form-item>
|
<wd-form-item label="首检盘号" prop="firstNo">
|
{{ formatValue(detailData.fixedInfo?.firstNo) }}
|
</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="processInspectionUserName">
|
{{ detailData.processInspectionUserName || "-" }}
|
</wd-form-item>
|
<wd-form-item label="状态" prop="status">
|
<wd-tag custom-class="space" :type="getStatusType(detailData.status)">
|
{{ getStatusText(detailData.status) }}
|
</wd-tag>
|
</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="dia">
|
{{ formatValue(detailData.inspectionResult?.dia, "mm") || "-" }}
|
</wd-form-item>
|
|
<wd-form-item label="最大直径" prop="maxDia" required>
|
<template v-if="isEdit">
|
<wd-input v-model="formData.maxDia" placeholder="请输入最大直径(mm)" type="number" />
|
</template>
|
<template v-else>
|
{{ formatValue(detailData.inspectionResult?.maxDia, "mm") || "-" }}
|
</template>
|
</wd-form-item>
|
|
<wd-form-item label="最小直径" prop="minDia" required>
|
<template v-if="isEdit">
|
<wd-input v-model="formData.minDia" placeholder="请输入最小直径(mm)" type="number" />
|
</template>
|
<template v-else>
|
{{ formatValue(detailData.inspectionResult?.minDia, "mm") || "-" }}
|
</template>
|
</wd-form-item>
|
|
<wd-form-item label="外观" prop="appearance" required>
|
<template v-if="isEdit">
|
<view style="display: flex; flex-wrap: wrap; gap: 10px">
|
<wd-checkbox
|
v-for="(opt, idx) in appearanceOptions"
|
:key="idx"
|
:value="opt.value"
|
:modelValue="formData.appearance?.includes(opt.value) || false"
|
@click="handleAppearanceClick(opt.value)"
|
style="width: 100px"
|
>
|
{{ opt.label }}
|
</wd-checkbox>
|
</view>
|
</template>
|
<template v-else>
|
{{ formatProductAppearance(formData.appearance) }}
|
</template>
|
</wd-form-item>
|
|
<wd-form-item label="卷绕紧密" prop="windingTightness" required>
|
<template v-if="isEdit">
|
<wd-radio-group
|
v-model="formData.windingTightness"
|
inline
|
class="conclusion-radio-group"
|
>
|
<wd-radio
|
v-for="(opt, idx) in sampleCompleteOptions"
|
:key="idx"
|
:value="opt.value"
|
shape="dot"
|
>
|
{{ opt.label }}
|
</wd-radio>
|
</wd-radio-group>
|
</template>
|
<template v-else>
|
{{ formatValue(detailData.inspectionResult?.windingTightness) }}
|
</template>
|
</wd-form-item>
|
|
<wd-form-item label="排列整齐" prop="arrangementNeatness" required>
|
<template v-if="isEdit">
|
<wd-radio-group
|
v-model="formData.arrangementNeatness"
|
inline
|
class="conclusion-radio-group"
|
>
|
<wd-radio
|
v-for="(opt, idx) in sampleCompleteOptions"
|
:key="idx"
|
:value="opt.value"
|
shape="dot"
|
>
|
{{ opt.label }}
|
</wd-radio>
|
</wd-radio-group>
|
</template>
|
<template v-else>
|
{{ formatValue(detailData.inspectionResult?.arrangementNeatness) }}
|
</template>
|
</wd-form-item>
|
|
<wd-form-item
|
label="外层铝线离侧板边缘距离"
|
prop="aluminumWireDistance"
|
label-width="360rpx"
|
required
|
>
|
<template v-if="isEdit">
|
<wd-input
|
v-model="formData.aluminumWireDistance"
|
placeholder="请输入距离(mm)"
|
type="number"
|
/>
|
</template>
|
<template v-else>
|
{{ formatValue(detailData.inspectionResult?.aluminumWireDistance, "mm") || "-" }}
|
</template>
|
</wd-form-item>
|
|
<wd-form-item label="成品模后接头情况" prop="jointCondition" label-width="280rpx" required>
|
<template v-if="isEdit">
|
<wd-radio-group v-model="formData.jointCondition" inline class="conclusion-radio-group">
|
<wd-radio
|
v-for="(opt, idx) in jointConditionOptions"
|
:key="idx"
|
:value="opt.value"
|
shape="dot"
|
>
|
{{ opt.label }}
|
</wd-radio>
|
</wd-radio-group>
|
</template>
|
<template v-else>
|
{{ formatValue(detailData.inspectionResult?.jointCondition) || "-" }}
|
</template>
|
</wd-form-item>
|
|
<wd-form-item label="结论" prop="conclusion" required>
|
<template v-if="isEdit">
|
<wd-radio-group v-model="formData.conclusion" inline class="conclusion-radio-group">
|
<wd-radio
|
v-for="(opt, idx) in conclusionOptions"
|
:key="idx"
|
:value="opt.value"
|
shape="dot"
|
>
|
{{ opt.label }}
|
</wd-radio>
|
</wd-radio-group>
|
</template>
|
<template v-else>
|
{{ formatValue(detailData.inspectionResult?.conclusion) || "-" }}
|
</template>
|
</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="isFully"
|
required
|
label-width="420rpx"
|
>
|
<template v-if="isEdit">
|
<wd-radio-group v-model="formData.isFully" inline class="conclusion-radio-group">
|
<wd-radio
|
v-for="(opt, idx) in sampleCompleteOptions"
|
:key="idx"
|
:value="opt.value"
|
shape="dot"
|
>
|
{{ opt.label }}
|
</wd-radio>
|
</wd-radio-group>
|
</template>
|
<template v-else>
|
<wd-tag
|
custom-class="space"
|
:type="detailData.processInspectionResult?.isFully ? 'success' : 'danger'"
|
>
|
{{ detailData.processInspectionResult?.isFully ? "是" : "否" }}
|
</wd-tag>
|
</template>
|
</wd-form-item>
|
</wd-col>
|
</wd-row>
|
|
<!-- 附件模块 -->
|
<wd-row class="attachment-section">
|
<view style="margin: 10rpx">
|
<text class="title">{{ "附件" }}</text>
|
</view>
|
<wd-col :span="24">
|
<AttachmentUpload
|
:detailData="detailData"
|
:isEdit="isEdit"
|
:deviceType="paramsType"
|
ref="attachmentRef"
|
/>
|
</wd-col>
|
</wd-row>
|
<wd-popup v-model="show" custom-style="border-radius:32rpx;" @close="handleClose">
|
<div class="image-preview">
|
<img :src="previewImageUrl" alt="预览图片" style="width: 100%; height: auto" />
|
</div>
|
</wd-popup>
|
<wd-toast />
|
</view>
|
</template>
|
|
<script setup lang="ts">
|
import { ref, reactive, computed, onUnmounted } from "vue";
|
import { onLoad, onShow, onHide } from "@dcloudio/uni-app";
|
import RoutingInspectionApi from "@/api/routingInspection/routingInspection";
|
import { useToast } from "wot-design-uni";
|
import AttachmentUpload from "../upload.vue";
|
import { useUserStore } from "@/store/modules/user";
|
import { useScanCode } from "@/composables/useScanCode";
|
|
// 核心状态
|
const paramsId = ref("");
|
const paramsType = ref("");
|
const detailData = ref<any>({});
|
const show = ref(false);
|
const previewImageUrl = ref("");
|
const isEdit = ref(false);
|
const tempFiles = ref<any[]>([]);
|
const toast = useToast();
|
const attachmentRef = ref<any>(null);
|
|
// 获取当前登录用户信息
|
const userStore = useUserStore();
|
const userInfo: any = computed(() => userStore.userInfo);
|
|
// 使用扫码管理 composable(全局监听器,不随页面切换关闭)
|
const {
|
deviceUid,
|
deviceModel: scannedDeviceModel,
|
loadFromCache,
|
enableListener,
|
} = useScanCode("scanLS");
|
|
// 表单数据
|
const formData = reactive({
|
dia: "",
|
maxDia: "",
|
minDia: "",
|
appearance: [] as string[],
|
windingTightness: "",
|
arrangementNeatness: "",
|
aluminumWireDistance: "",
|
jointCondition: "",
|
conclusion: "",
|
isFully: "",
|
});
|
|
// 外观选项
|
const appearanceOptions = [
|
{ label: "无外观问题", value: "无外观问题" },
|
{ label: "表面划伤", value: "表面划伤" },
|
{ label: "直径不均", value: "直径不均" },
|
{ label: "其他缺陷", value: "其他缺陷" },
|
];
|
const sampleCompleteOptions = [
|
{ label: "是", value: "是" },
|
{ label: "否", value: "否" },
|
];
|
const jointConditionOptions = [
|
{ label: "有", value: "有" },
|
{ label: "无", value: "无" },
|
];
|
const conclusionOptions = [
|
{ label: "合格", value: "合格" },
|
{ label: "不合格", value: "不合格" },
|
];
|
// 状态映射
|
const getStatusType = (status: number) => {
|
switch (status) {
|
case 0:
|
return "warning";
|
case 1:
|
return "danger";
|
case 2:
|
return "primary";
|
case 3:
|
return "success";
|
default:
|
return "default";
|
}
|
};
|
|
const getStatusText = (status: number) => {
|
switch (status) {
|
case 0:
|
return "待巡检";
|
case 1:
|
return "已驳回";
|
case 2:
|
return "待审核";
|
case 3:
|
return "通过";
|
default:
|
return "未知";
|
}
|
};
|
|
// 格式化工具
|
const formatProductAppearance = (productAppearance: string[]) => {
|
if (!productAppearance || !Array.isArray(productAppearance) || !productAppearance.length) {
|
return "-";
|
}
|
return productAppearance.join("、");
|
};
|
|
// 处理外观选择的互斥逻辑
|
const handleAppearanceClick = (value: string) => {
|
// 确保 appearance 是数组
|
if (!Array.isArray(formData.appearance)) {
|
formData.appearance = [];
|
}
|
|
const currentValues = [...formData.appearance];
|
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];
|
}
|
}
|
|
formData.appearance = newSelection;
|
};
|
|
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 initFormData = () => {
|
const inspectionResult = detailData.value.inspectionResult || {};
|
const processInspectionResult = detailData.value.processInspectionResult || {};
|
formData.dia = inspectionResult.dia || "";
|
formData.maxDia = inspectionResult.maxDia || "";
|
formData.minDia = inspectionResult.minDia || "";
|
// 确保 appearance 是数组
|
formData.appearance = Array.isArray(inspectionResult.appearance)
|
? inspectionResult.appearance
|
: inspectionResult.appearance
|
? [inspectionResult.appearance]
|
: [];
|
formData.windingTightness = inspectionResult.windingTightness || "";
|
formData.arrangementNeatness = inspectionResult.arrangementNeatness || "";
|
formData.aluminumWireDistance = inspectionResult.aluminumWireDistance || "";
|
formData.jointCondition = inspectionResult.jointCondition || "";
|
formData.conclusion = inspectionResult.conclusion || "";
|
formData.isFully = processInspectionResult.isFully ? "是" : "否";
|
};
|
|
// 获取详情
|
const getDetailData = async (id: string, deviceType: string) => {
|
try {
|
const response = await RoutingInspectionApi.getDrawInspectInfoById({ id });
|
detailData.value = response.data;
|
|
// 如果巡检员为空,默认设置为当前登录用户
|
if (!detailData.value.processInspectionUserName) {
|
detailData.value.processInspectionUserName =
|
userInfo.value?.nickName || userInfo.value?.userName || "";
|
}
|
|
tempFiles.value = [];
|
initFormData();
|
} catch (error) {
|
console.error("获取详情失败:", error);
|
}
|
};
|
|
// 页面加载
|
onLoad((options: any) => {
|
paramsId.value = options.id;
|
paramsType.value = options.deviceType;
|
getDetailData(options.id, options.deviceType);
|
});
|
|
// 编辑切换
|
const editList = () => {
|
isEdit.value = true;
|
};
|
|
// 取消编辑
|
const close = () => {
|
isEdit.value = false;
|
tempFiles.value = [];
|
initFormData();
|
};
|
|
// 保存编辑
|
const saveList = async () => {
|
// 校验
|
if (!formData.maxDia) return uni.showToast({ title: "最大直径为必填项", icon: "none" });
|
if (!formData.minDia) return uni.showToast({ title: "最小直径为必填项", icon: "none" });
|
if (!formData.appearance.length) return uni.showToast({ title: "外观为必填项", icon: "none" });
|
if (!formData.windingTightness) return uni.showToast({ title: "卷绕紧密为必填项", icon: "none" });
|
if (!formData.arrangementNeatness)
|
return uni.showToast({ title: "排列整齐为必填项", icon: "none" });
|
if (!formData.aluminumWireDistance)
|
return uni.showToast({ title: "外层铝线离侧板边缘距离为必填项", icon: "none" });
|
if (!formData.jointCondition)
|
return uni.showToast({ title: "成品模后接头情况为必填项", icon: "none" });
|
if (!formData.conclusion) return uni.showToast({ title: "结论为必填项", icon: "none" });
|
if (!formData.isFully) return uni.showToast({ title: "铝杆样品是否齐全为必填项", icon: "none" });
|
|
// 验证扫码数据(从缓存或新扫码获取)
|
console.log("保存前检查 deviceUid:", deviceUid.value);
|
if (!deviceUid.value) {
|
return uni.showToast({
|
title: "请先扫描设备二维码",
|
icon: "none",
|
duration: 2000,
|
});
|
}
|
const { newFiles } = attachmentRef.value.getSubmitFiles();
|
console.log("newFiles", newFiles);
|
const allFileIds = [...newFiles];
|
// 提交
|
try {
|
const res = await RoutingInspectionApi.drawPatrolCheckInspection({
|
deviceUid: deviceUid.value,
|
id: paramsId.value,
|
inspectionResult: {
|
dia: formData.dia,
|
maxDia: formData.maxDia,
|
minDia: formData.minDia,
|
appearance: formData.appearance,
|
windingTightness: formData.windingTightness,
|
arrangementNeatness: formData.arrangementNeatness,
|
aluminumWireDistance: formData.aluminumWireDistance,
|
jointCondition: formData.jointCondition,
|
conclusion: formData.conclusion,
|
},
|
result: { isFully: formData.isFully },
|
processInspectionAttachmentList: allFileIds,
|
});
|
if (res.code === 200) {
|
// 设置刷新标记,告诉列表页需要刷新
|
uni.setStorageSync("needRefreshInspectionList", true);
|
|
uni.showToast({
|
title: "保存成功",
|
icon: "success",
|
duration: 1500,
|
});
|
// 延迟返回列表页,让用户看到成功提示
|
setTimeout(() => {
|
uni.navigateBack({
|
delta: 1,
|
});
|
}, 1500);
|
} else {
|
uni.showModal({ title: res.msg || "保存失败", icon: "error" });
|
}
|
} catch (e) {
|
console.error("保存失败:", e);
|
uni.showModal({ title: e.message || "保存失败", icon: "error" });
|
}
|
};
|
|
const handleClose = () => {
|
show.value = false;
|
};
|
|
const openScan = () => {
|
console.log("indexLS - 点击扫码按钮(全局扫码模式,无需手动触发)");
|
// 全局扫码模式下,硬件扫码会自动触发,无需手动调用
|
uni.showToast({
|
title: "请使用扫码枪扫描",
|
icon: "none",
|
});
|
};
|
|
// 页面显示时的处理
|
onShow(() => {
|
console.log("========== indexLS - onShow 触发 ==========");
|
// 重新启用监听器(确保监听器有效)
|
enableListener();
|
// 加载缓存(更新UI显示)
|
const cachedData = loadFromCache();
|
|
// 如果没有缓存数据,提示用户需要扫码
|
if (!cachedData || !cachedData.uid) {
|
console.log("⚠️ 未检测到扫码缓存,用户需要扫描设备二维码");
|
// 在编辑模式下才提示
|
if (isEdit.value) {
|
setTimeout(() => {
|
uni.showToast({
|
title: "请扫描设备二维码后再保存",
|
icon: "none",
|
duration: 2000,
|
});
|
}, 500);
|
}
|
}
|
});
|
</script>
|
|
<style lang="scss" scoped>
|
.fixed-header {
|
position: fixed;
|
top: 44;
|
left: 0;
|
right: 0;
|
background: #f3f9f8;
|
z-index: 999;
|
padding: 12px;
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
min-height: 60px;
|
box-sizing: border-box;
|
overflow: visible;
|
}
|
|
.header-container {
|
display: flex;
|
align-items: center;
|
width: 100%;
|
gap: 10px;
|
}
|
|
.placeholder {
|
flex: 1;
|
}
|
|
.scan-info {
|
display: flex;
|
align-items: center;
|
margin-right: 10px;
|
|
.scan-device-text {
|
font-size: 14px;
|
color: #0d867f;
|
font-weight: 500;
|
}
|
}
|
|
.scan-wrapper {
|
width: 38px;
|
height: 38px;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
padding: 6px;
|
flex-shrink: 0;
|
}
|
|
.list {
|
padding: 12px;
|
padding-top: 84px;
|
background: #f3f9f8;
|
min-height: 100vh;
|
box-sizing: border-box;
|
overflow-y: auto;
|
}
|
|
.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;
|
}
|
|
.attachment-section {
|
width: 100%;
|
}
|
|
.attachment-grid {
|
display: flex;
|
flex-wrap: wrap;
|
gap: 10px;
|
padding: 10px 0;
|
}
|
|
.attachment-item {
|
width: calc(25% - 10px);
|
box-sizing: border-box;
|
position: relative;
|
}
|
|
.upload-btn {
|
width: 80px;
|
height: 80px;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
border: 1px dashed #ccc;
|
border-radius: 4px;
|
box-sizing: border-box;
|
}
|
|
.upload-icon {
|
font-size: 32px;
|
color: #0d867f;
|
}
|
|
.delete-icon {
|
position: absolute;
|
top: -8px;
|
right: -8px;
|
width: 24px;
|
height: 24px;
|
background-color: rgba(255, 0, 0, 0.8);
|
color: white;
|
border-radius: 50%;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
z-index: 10;
|
}
|
|
@media (max-width: 768px) {
|
.attachment-item {
|
width: calc(25% - 10px);
|
margin: 10;
|
}
|
}
|
|
:deep(.wd-form-item) {
|
margin-bottom: 8rpx;
|
}
|
|
:deep(.wd-input, .wd-select, .wd-radio-group, .wd-checkbox-group) {
|
width: 100%;
|
box-sizing: border-box;
|
}
|
|
:deep(.wd-form-item__label)::after {
|
content: "*";
|
color: red;
|
margin-left: 4rpx;
|
}
|
|
:deep(.wd-select) {
|
width: 100%;
|
}
|
|
:deep(.wd-checkbox) {
|
margin-right: 0;
|
}
|
.conclusion-radio-group {
|
display: flex;
|
align-items: flex-start; // 垂直方向顶部对齐(上移关键)
|
gap: 20rpx; // 选项之间的间距
|
}
|
</style>
|