<template>
<div class="app-container">
<el-form
:model="queryParams"
ref="queryRef"
:inline="true"
v-show="showSearch"
label-width="68px"
>
<el-form-item label="Season No" prop="seasonNo" label-width="140">
<el-input
v-model="queryParams.seasonNo"
placeholder="please input"
clearable
@keyup.enter="handleQueryTest"
/>
</el-form-item>
<el-form-item label="Colorwayid" prop="colorwayid" label-width="140">
<el-input
v-model="queryParams.colorwayid"
placeholder="please input"
clearable
@keyup.enter="handleQueryTest"
/>
</el-form-item>
<el-form-item label="Model No" prop="modelNo" label-width="140">
<el-input
v-model="queryParams.modelNo"
placeholder="please input"
clearable
@keyup.enter="handleQueryTest"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery"
>搜索</el-button
>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" plain @click="handleTest">新增</el-button>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="qsList">
<el-table-column label="seasonNo" align="center" prop="seasonNo">
</el-table-column>
<el-table-column label="stage" align="center" prop="stage">
</el-table-column>
<el-table-column label="modelNo" align="center" prop="modelNo">
</el-table-column>
<el-table-column label="colorwayid" align="center" prop="colorwayid">
</el-table-column>
<el-table-column label="pattern" align="center" prop="pattern">
</el-table-column>
<el-table-column label="firstsource" align="center" prop="firstsource">
</el-table-column>
<el-table-column
label="Operate"
align="center"
class-name="small-padding fixed-width"
>
<template #default="scope">
<el-tooltip content="Add" placement="top">
<el-button
link
type="primary"
icon="Plus"
@click="handleCreate(scope.row)"
></el-button>
</el-tooltip>
<el-tooltip content="Delete" placement="top">
<el-button
link
type="primary"
icon="Delete"
@click="handleDelete(scope.row)"
></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</div>
<el-dialog title="ADD" v-model="testDialog" width="1600px" append-to-body>
<div>
<el-form
:model="queryParams"
ref="testRef"
:inline="true"
label-width="108px"
>
<el-form-item label="seasonNo" prop="seasonNo" label-width="140">
<el-input
v-model="queryParams.seasonNo"
placeholder="please input"
clearable
@keyup.enter="handleQueryTest"
/>
</el-form-item>
<el-form-item label="colorwayid" prop="colorwayid" label-width="140">
<el-input
v-model="queryParams.colorwayid"
placeholder="please input"
clearable
@keyup.enter="handleQueryTest"
/>
</el-form-item>
<el-form-item label="modelNo" prop="modelNo" label-width="140">
<el-input
v-model="queryParams.modelNo"
placeholder="please input"
clearable
@keyup.enter="handleQueryTest"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQueryTest"
>Search</el-button
>
<el-button icon="Refresh" @click="resetQueryTest">Reset</el-button>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="ptrList">
<el-table-column label="seasonNo" align="center" prop="seasonNo">
</el-table-column>
<el-table-column label="stage" align="center" prop="stage">
</el-table-column>
<el-table-column label="modelNo" align="center" prop="modelNo">
</el-table-column>
<el-table-column label="Colorway Name" align="center" prop="colorwayid">
</el-table-column>
<el-table-column label="pattern" align="center" prop="pattern">
</el-table-column>
<el-table-column label="firstsource" align="center" prop="firstsource">
</el-table-column>
<el-table-column
label="Operate"
align="center"
class-name="small-padding fixed-width"
>
<template #default="scope">
<el-button
link
type="primary"
icon="Plus"
@click="handleAdd(scope.row)"
></el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="totalTest > 0"
:total="totalTest"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getTestList"
/>
</div>
</el-dialog>
<el-dialog title="创建" v-model="createDialog" width="1800px" append-to-body>
<div>
<el-tabs v-model="activeTab" type="card">
<el-tab-pane
v-for="(item, index) in mainList"
:key="index"
:label="getTabLabel(item)"
:name="index.toString()"
>
<!-- 每个标签页使用独立的表单和数据结构 -->
<div v-if="currentTabData[index]">
<!-- 基本信息区域(只读) -->
<el-card header="基本信息" style="margin-bottom: 15px">
<el-form
:model="currentTabData[index].baseInfo"
label-width="120px"
:inline="true"
>
<el-form-item label="Dev Style Name">
<el-input
v-model="currentTabData[index].baseInfo.modelNo"
readonly
style="width: 100px"
class="readonly-input"
/>
<el-input
v-model="currentTabData[index].baseInfo.modelName"
readonly
style="width: 150px"
class="readonly-input"
/>
</el-form-item>
<el-form-item label="Color Way Name" label-width="125">
<el-input
v-model="currentTabData[index].baseInfo.colorwayid"
readonly
style="width: 100px"
class="readonly-input"
/>
<el-input
v-model="currentTabData[index].baseInfo.colorwayname"
readonly
style="width: 400px"
class="readonly-input"
/>
<el-input
v-model="currentTabData[index].baseInfo.bomid"
readonly
style="width: 100px"
class="readonly-input"
/>
</el-form-item>
<el-form-item label="Stage" label-width="60">
<el-input
v-model="currentTabData[index].baseInfo.stage"
readonly
class="readonly-input"
style="width: 120px"
/>
</el-form-item>
<el-form-item label="DPA/STYLE" prop="prodCd" label-width="100">
<el-input
v-model="currentTabData[index].baseInfo.prodCd"
readonly
class="readonly-input"
/>
</el-form-item>
<el-form-item label="Season">
<el-input
v-model="currentTabData[index].baseInfo.seasonNo"
readonly
class="readonly-input"
style="width: 100px"
/>
</el-form-item>
<el-form-item
label="Version"
prop="pfcVersion"
label-width="80"
>
<el-input
v-model="currentTabData[index].baseInfo.pfcVersion"
readonly
style="width: 120px"
class="readonly-input"
/>
</el-form-item>
<el-form-item
label="Tool Code"
prop="pattern"
label-width="100"
>
<el-input
v-model="currentTabData[index].baseInfo.pattern"
readonly
class="readonly-input"
/>
</el-form-item>
<el-form-item label="PFC手册号" prop="pfcNo" label-width="100">
<el-input
v-model="currentTabData[index].baseInfo.pfcNo"
readonly
style="width: 100px"
class="readonly-input"
/>
</el-form-item>
<el-form-item label="Page Number">
<el-input
v-model="currentTabData[index].baseInfo.pageNumber"
readonly
class="readonly-input"
style="width: 80px"
/>
<el-input
v-model="currentTabData[index].baseInfo.stepno"
readonly
class="readonly-input"
style="width: 80px"
/>
</el-form-item>
<el-form-item
label="鞋码类型"
prop="sizeType"
label-width="100"
>
<el-input
v-model="currentTabData[index].baseInfo.sizeType"
readonly
class="readonly-input"
/>
</el-form-item>
</el-form>
<el-form
:model="currentTabData[index].formData"
:rules="getTabRules(index)"
label-width="120px"
>
<el-row>
<el-col :span="8">
<el-form-item label="STYLE NO" prop="styleNo">
<el-input
v-model="currentTabData[index].formData.styleNo"
placeholder="Please input"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="DPA" prop="dpa">
<el-input
v-model="currentTabData[index].formData.dpa"
placeholder="Please input"
/>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="TD CODE" prop="tdCode">
<el-input
v-model="currentTabData[index].formData.tdCode"
placeholder="Please input"
/>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="FACTORY" prop="factory">
<el-input
v-model="currentTabData[index].formData.factory"
placeholder="Please input"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="LAB TEST" prop="labTest">
<el-input
v-model="currentTabData[index].formData.labTest"
placeholder="Please input"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="APPROVED BY"
prop="approvedBy"
label-width="130"
>
<el-input
v-model="currentTabData[index].formData.approvedBy"
placeholder="Please input"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="APPROVED DATE"
prop="approvedDate"
label-width="180"
>
<el-date-picker
v-model="currentTabData[index].formData.approvedDate"
type="date"
placeholder="选择日期"
style="width: 50%"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="16">
<el-form-item label="具体描述" prop="description">
<el-input
v-model="currentTabData[index].formData.description"
placeholder="Please input"
type="textarea"
:rows="2"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<!-- 可编辑的表单区域 -->
<el-card header="编辑信息" style="margin-bottom: 15px">
<!-- 动态数据行区域(根据标签页类型显示不同的字段) -->
<div style="margin-top: 20px">
<!-- 将模板选择器和列表标题放在同一行 -->
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
"
>
<!-- 左侧:模板选择器 -->
<div style="display: flex; align-items: center; flex: 1">
<span
style="
font-weight: bold;
margin-right: 10px;
min-width: 50px;
"
>测试用例列表</span
>
<el-cascader
v-model="currentTabData[index].selectedTemplate"
:options="currentTabData[index].templateOptions"
:props="getCascaderProps(index)"
placeholder="请选择测试用例模板"
clearable
filterable
style="width: 350px; margin-right: 10px"
@change="handleTemplateSelect(index)"
popper-class="custom-cascader"
/>
</div>
</div>
<el-table
:data="currentTabData[index].dataRows"
border
v-loading="currentTabData[index].loading"
>
<!-- 根据页面类型动态显示列 -->
<el-table-column
v-for="column in getTableColumns(index)"
:key="column.prop"
:label="column.label"
:prop="column.prop"
:width="column.width"
>
<template #default="scope">
<el-input v-model="scope.row[column.prop]" size="small" />
</template>
</el-table-column>
<el-table-column label="Operate" width="80">
<template #default="scope">
<el-button
link
type="danger"
size="small"
@click="removeDataRow(index, scope.$index)"
>delete</el-button
>
</template>
</el-table-column>
</el-table>
</div>
</el-card>
<el-card header="鞋图上传" style="margin-bottom: 20px">
<el-upload
v-model:file-list="currentTabData[index].fileList"
:action="uploadUrl.url"
list-type="picture-card"
:multiple="true"
:on-preview="(file) => handlePictureCardPreview(file, index)"
:on-remove="(file) => handleRemove(file, index)"
:on-success="
(response, file, fileList) =>
handleUploadSuccess(index, response, file, fileList)
"
:on-error="handleUploadError"
:before-upload="(file) => beforeUpload(file, index)"
:headers="uploadUrl.headers"
:data="getUploadData(index)"
:auto-upload="true"
accept=".jpg,.jpeg,.png,.gif"
>
<el-icon><Plus /></el-icon>
</el-upload>
<el-dialog
v-model="currentTabData[index].dialogVisible"
style="width: 80%; max-width: 900px; height: 700px"
>
<img
w-full
:src="currentTabData[index].dialogImageUrl"
alt="Preview Image"
style="
max-width: 100%;
max-height: 100%;
display: block;
margin: 0 auto;
"
/>
</el-dialog>
</el-card>
</div>
</el-tab-pane>
</el-tabs>
<!-- 底部操作按钮 -->
<div style="text-align: center; margin-top: 20px">
<!-- <el-button type="primary" @click="handleSaveAll">保存所有</el-button> -->
<el-button type="success" @click="handleSaveCurrent"
>保存当前</el-button
>
<el-button @click="createDialog = false">取消</el-button>
</div>
</div>
</el-dialog>
</template>
<script setup name="User">
import {
ptrInfo,
addQualityStand,
qsInfo,
getQsMain,
getTemplateTree,
saveQualityStandards,
getSavedQualityStandards,
uploadImages,
getImages,
deleteImage,
delQualityStand,
} from "@/api/quality/standard/quasd.js";
import { getSrc } from "@/utils/interceptSrc";
import { getToken } from "@/utils/auth";
const { proxy } = getCurrentInstance();
const qsList = ref([]);
const ptrList = ref([]);
const mainList = ref([]);
const loading = ref(true);
const showSearch = ref(true);
const testDialog = ref(false);
const createDialog = ref(false);
const total = ref(0);
const totalTest = ref(0);
const activeTab = ref("0");
// 为每个标签页存储独立的数据
const currentTabData = ref({});
const data = reactive({
queryParams: {
pageNum: 1,
pageSize: 10,
stage: null,
modelNo: null,
colorwayid: null,
seasonNo: null,
pfcNo: null,
pattern: null,
firstsource: null,
pageNumber: null,
stepno: null,
pfcCaption: null,
},
rules: {
styleNo: [{ required: true, message: "STYLE NO不能为空", trigger: "blur" }],
dpa: [{ required: true, message: "DPA不能为空", trigger: "blur" }],
tdCode: [{ required: true, message: "TD CODE不能为空", trigger: "blur" }],
factory: [{ required: true, message: "FACTORY不能为空", trigger: "blur" }],
labTest: [{ required: true, message: "LAB TEST不能为空", trigger: "blur" }],
approvedBy: [
{ required: true, message: "APPROVED BY不能为空", trigger: "blur" },
],
approvedDate: [
{ required: true, message: "APPROVED DATE不能为空", trigger: "blur" },
],
// 其他验证规则...
},
});
const { queryParams, rules } = toRefs(data);
// 在setup顶部定义上传配置
const uploadUrl = reactive({
headers: { Authorization: "Bearer " + getToken() },
url: process.env.VITE_APP_BASE_API + "/quality/standard/images/upload",
});
// 初始化标签页数据
async function initTabData(tabIndex, sourceData) {
currentTabData.value[tabIndex] = {
baseInfo: { ...sourceData },
formData: {
styleNo: "",
dpa: "",
tdCode: "",
factory: "",
labTest: "",
approvedBy: "",
approvedDate: "",
description: "",
},
dataRows: [],
templateOptions: [],
selectedTemplate: [],
currentTemplateData: null,
loading: false, // 添加加载状态
fileList: [], // 图片列表
dialogVisible: false, // 预览对话框显示状态
dialogImageUrl: "", // 预览图片URL
};
// 加载模板数据
await loadTemplateOptions(tabIndex, sourceData.pageNumber);
// 加载已保存的测试用例数据
await loadSavedDataRows(tabIndex, sourceData.pfcNo, sourceData.pageNumber);
await loadImages(tabIndex, sourceData.pfcNo, sourceData.pageNumber);
}
// 新增:加载图片函数
async function loadImages(tabIndex, pfcNo, pageNumber) {
try {
const response = await getImages(pfcNo, pageNumber);
const images = response.data || [];
// 转换为el-upload需要的格式
currentTabData.value[tabIndex].fileList = images.map((image) => ({
uid: image.id, // 使用图片的唯一标识
name: image.originalName,
url: getSrc(image.filePath), // 确保getSrc能正确生成图片URL
status: "success",
response: image, // 保留原始数据,删除时可能会用到
}));
} catch (error) {
console.error("加载图片失败:", error);
proxy.$modal.msgError("加载图片失败");
}
}
// 获取上传参数(当前标签页的pfcNo和pageNumber)
function getUploadData(tabIndex) {
const baseInfo = currentTabData.value[tabIndex].baseInfo;
return {
pfcNo: baseInfo.pfcNo,
pageNumber: baseInfo.pageNumber,
};
}
// 图片预览处理
function handlePictureCardPreview(file, tabIndex) {
currentTabData.value[tabIndex].dialogImageUrl = file.url;
currentTabData.value[tabIndex].dialogVisible = true;
}
// 新增:删除图片处理
async function handleRemove(file, tabIndex) {
try {
if (file.status == "success") {
// 已上传的图片,调用删除接口
await deleteImage(file.response.id);
proxy.$modal.msgSuccess("删除成功");
}
// 从列表中移除
const index = currentTabData.value[tabIndex].fileList.findIndex(
(item) => item.uid == file.uid
);
if (index !== -1) {
currentTabData.value[tabIndex].fileList.splice(index, 1);
}
} catch (error) {
console.error("删除失败:", error);
proxy.$modal.msgError("删除失败");
}
}
// 上传成功处理
function handleUploadSuccess(tabIndex, response, file, fileList) {
if (response.code == 200) {
proxy.$modal.msgSuccess(response.msg);
// 更新文件列表(因为后端可能返回了新的URL等信息,但这里我们不需要额外处理,因为已经显示成功)
// 如果需要,可以更新fileList中的某个文件信息,但通常不需要,因为我们的fileList已经绑定了
} else {
proxy.$modal.msgError(response.msg || "上传失败");
// 标记为失败,以便显示错误
const index = currentTabData.value[tabIndex].fileList.findIndex(
(item) => item.uid === file.uid
);
if (index !== -1) {
currentTabData.value[tabIndex].fileList[index].status = "fail";
currentTabData.value[tabIndex].fileList.splice(index, 1, {
...currentTabData.value[tabIndex].fileList[index],
});
}
}
}
// 上传失败处理
function handleUploadError(error, file, fileList) {
console.error("上传失败:", error);
proxy.$modal.msgError("上传失败");
}
// 上传前验证
function beforeUpload(file, tabIndex) {
const isImage = file.type.startsWith("image/");
const isLt5M = file.size / 1024 / 1024 < 10;
if (!isImage) {
proxy.$modal.msgError("只能上传图片文件!");
return false;
}
if (!isLt5M) {
proxy.$modal.msgError("图片大小不能超过5MB!");
return false;
}
// 添加到文件列表(因为auto-upload为true,所以会自动上传)
// 注意:我们使用v-model绑定fileList,所以不需要手动添加
return true;
}
// 修改 uploadImagesForTab 函数
async function uploadImagesForTab(tabIndex) {
const currentTab = currentTabData.value[tabIndex];
const filesToUpload = currentTab.fileList.filter(
(file) => !file.status || file.status !== "success"
);
if (filesToUpload.length === 0) return;
const formData = new FormData();
// 正确添加字段 - 注意参数名必须与后端@RequestParam一致
formData.append("pfcNo", currentTab.baseInfo.pfcNo);
formData.append("pageNumber", currentTab.baseInfo.pageNumber);
// 正确添加文件数组 - 使用相同的key 'files'
filesToUpload.forEach((file, index) => {
formData.append("file", file.raw || file, file.name); // 第三个参数是文件名
});
try {
const response = await uploadImages(formData);
proxy.$modal.msgSuccess(response.msg || "图片上传成功");
// 更新已成功上传的文件状态
filesToUpload.forEach((file) => {
const listFile = currentTab.fileList.find((f) => f.uid === file.uid);
if (listFile) {
listFile.status = "success";
}
});
} catch (error) {
console.error("图片上传失败:", error);
proxy.$modal.msgError("图片上传失败: " + (error.message || "网络错误"));
}
}
// 加载已保存的测试用例数据
async function loadSavedDataRows(tabIndex, pfcNo, pageNumber) {
const currentTab = currentTabData.value[tabIndex];
try {
currentTab.loading = true;
const response = await getSavedQualityStandards(pfcNo, pageNumber);
const savedData = response.data || [];
if (savedData.length > 0) {
const currentTab = currentTabData.value[tabIndex];
// 转换已保存数据为表格行格式
currentTab.dataRows = savedData.map((item) => {
const row = {
templateId: item.templateId, // 保存模板ID
// 复制表单数据到当前标签页的表单中(只复制一次,取第一条数据)
...(currentTab.dataRows.length === 0
? {
// 这些字段会被表单数据覆盖,所以这里主要处理测试用例特定字段
}
: {}),
};
// 根据页面类型设置不同的字段
if (pageNumber == "P42" || pageNumber == "P124") {
// P42/P124字段
row.bondTest = item.bondTest || "";
row.testItem = item.testItem || "";
row.pictureRef = item.pictureRef || "";
row.materialOne = item.materialOne || "";
row.materialTwo = item.materialTwo || "";
row.speed = item.speed || "";
row.minSpec = item.minSpec || "";
row.peSpec = item.peSpec || "";
} else if (pageNumber == "P43" || pageNumber == "P125") {
// P43/P125字段
row.testMethod = item.testMethod || "";
row.testMethodName = item.testMethodName || "";
row.pictureRef = item.pictureRef || "";
row.flmc = item.flmc || "";
row.minSpec = item.minSpec || "";
if (pageNumber == "P43") {
row.testParameter = item.testParameter || "";
} else if (pageNumber == "P125") {
row.speed = item.speed || "";
}
}
// 设置可选字段
row.csan = item.csan || "";
row.pead = item.pead || "";
row.peSpec = item.peSpec || "";
return row;
});
// 设置表单数据(取第一条数据的表单信息)
if (savedData.length > 0) {
const firstItem = savedData[0];
currentTab.formData = {
styleNo: firstItem.styleNo || "",
dpa: firstItem.dpa || "",
tdCode: firstItem.tdCode || "",
factory: firstItem.factory || "",
labTest: firstItem.labTest || "",
approvedBy: firstItem.approvedBy || "",
approvedDate: firstItem.approvedDate || "",
description: firstItem.description || "",
};
}
console.log(`标签页 ${tabIndex} 加载了 ${savedData.length} 条已保存数据`);
}
} catch (error) {
console.error("加载已保存数据失败:", error);
} finally {
currentTab.loading = false;
}
}
// 加载模板选项
async function loadTemplateOptions(tabIndex, pageNumber) {
try {
const response = await getTemplateTree(pageNumber);
currentTabData.value[tabIndex].templateOptions = response.data || [];
} catch (error) {
console.error("加载模板数据失败:", error);
proxy.$modal.msgError("加载测试用例模板失败");
}
}
// 获取级联选择器配置
function getCascaderProps(tabIndex) {
const pageNumber = mainList.value[tabIndex]?.pageNumber;
// 所有页面使用相同的配置
return {
value: "value",
label: "label",
children: "children",
checkStrictly: false,
emitPath: true,
expandTrigger: "hover",
};
}
// 处理模板选择
function handleTemplateSelect(tabIndex) {
const currentTab = currentTabData.value[tabIndex];
const selectedValue = currentTab.selectedTemplate;
const pageNumber = mainList.value[tabIndex]?.pageNumber;
if (selectedValue && selectedValue.length > 0) {
// 找到选中的模板数据
const templateData = findTemplateData(
currentTab.templateOptions,
selectedValue
);
if (templateData && templateData.data) {
currentTab.currentTemplateData = templateData.data;
// 自动添加数据行
addDataRowFromTemplate(tabIndex);
} else {
// 如果不是叶子节点,不清空选择,让用户继续选择下级
if (
templateData &&
templateData.children &&
templateData.children.length > 0
) {
currentTab.currentTemplateData = null;
} else {
// 没有数据也没有子节点,清空选择
currentTab.selectedTemplate = [];
currentTab.currentTemplateData = null;
proxy.$modal.msgWarning("请选择有效的测试用例模板");
}
}
} else {
currentTab.currentTemplateData = null;
}
}
// 从模板添加数据行
function addDataRowFromTemplate(tabIndex) {
const currentTab = currentTabData.value[tabIndex];
if (currentTab.currentTemplateData) {
const columns = getTableColumns(tabIndex);
const newRow = {};
// 初始化所有字段为空
columns.forEach((col) => {
newRow[col.prop] = "";
});
// 用模板数据填充
fillRowWithTemplateData(newRow, currentTab.currentTemplateData, tabIndex);
currentTab.dataRows.push(newRow);
// 清空选择器
currentTab.selectedTemplate = [];
currentTab.currentTemplateData = null;
proxy.$modal.msgSuccess("已从模板添加测试用例");
}
}
// 在模板树中查找数据
function findTemplateData(options, path) {
if (!options || !path || path.length == 0) return null;
let currentLevel = options;
let result = null;
for (let i = 0; i < path.length; i++) {
const currentValue = path[i];
const found = currentLevel.find((item) => item.value == currentValue);
if (!found) return null;
if (i == path.length - 1) {
result = found;
} else {
currentLevel = found.children;
}
}
return result;
}
// 修改原有的添加数据行方法
function addDataRow(tabIndex) {
const currentTab = currentTabData.value[tabIndex];
const columns = getTableColumns(tabIndex);
// 创建新行
const newRow = {};
columns.forEach((col) => {
newRow[col.prop] = "";
});
currentTab.dataRows.push(newRow);
proxy.$modal.msgSuccess("已添加空白的测试用例行");
}
// 用模板数据填充行
function fillRowWithTemplateData(row, templateData, tabIndex) {
const pageNumber = mainList.value[tabIndex]?.pageNumber;
// 保存模板ID,用于后续保存操作
row.templateId = templateData.id;
if (pageNumber == "P42" || pageNumber == "P124") {
// P42/P124模板数据映射
const bondingData = templateData;
// 映射所有字段
row.bondTest = bondingData.bondTest || "";
row.testItem = bondingData.testItem || "";
row.pictureRef = bondingData.pictureRef || "";
row.materialOne = bondingData.materialOne || "";
row.materialTwo = bondingData.materialTwo || "";
row.speed = bondingData.speed || "";
row.minSpec = bondingData.minSpec || "";
row.peSpec = bondingData.peSpec || "";
row.csan = bondingData.csan || "";
row.pead = bondingData.pead || "";
} else if (pageNumber == "P43") {
// P43模板数据映射
const customData = templateData;
row.testMethod = customData.testMethod || "";
row.testMethodName = customData.testMethodName || "";
row.pictureRef = customData.pictureRef || "";
row.flmc = customData.flmc || "";
row.testParameter = customData.testParameter || ""; // P43特有
row.minSpec = customData.minSpec || "";
row.peSpec = customData.peSpec || "";
row.csan = customData.csan || "";
row.pead = customData.pead || "";
} else if (pageNumber == "P125") {
// P125模板数据映射
const customData = templateData;
row.testMethod = customData.testMethod || "";
row.testMethodName = customData.testMethodName || "";
row.pictureRef = customData.pictureRef || "";
row.flmc = customData.flmc || "";
row.speed = customData.speed || ""; // P125特有
row.minSpec = customData.minSpec || "";
row.peSpec = customData.peSpec || "";
row.csan = customData.csan || "";
row.pead = customData.pead || "";
}
}
/** 查询【请填写功能名称】列表 */
function getList() {
loading.value = true;
qsInfo(queryParams.value).then((response) => {
qsList.value = response.rows;
total.value = response.total;
loading.value = false;
});
}
function handleTest() {
testDialog.value = true;
getTestList();
}
// 根据页面类型获取表格列配置
function getTableColumns(tabIndex) {
const pageNumber = mainList.value[tabIndex]?.pageNumber;
// 根据不同的pageNumber返回不同的列配置
switch (pageNumber) {
case "P42": // Finished Shoe Bonding页面
return [
{ prop: "bondTest", label: "BOND TEST", width: 120 },
{ prop: "testItem", label: "TEST ITEM", width: 100 },
{ prop: "pictureRef", label: "PICTURE REF.#", width: 130 },
{ prop: "materialOne", label: "MATERIAL 1", width: 120 },
{ prop: "materialTwo", label: "MATERIAL 2", width: 120 },
{ prop: "speed", label: "Speed(mm/min)", width: 150 },
{ prop: "minSpec", label: "Min.Spec(kgf/cm)", width: 150 },
{ prop: "peSpec", label: "Product Exc.Spec", width: 150 },
{
prop: "csan",
label: "COMMENT SECTION Approver Name / Product Exception Detail...",
width: 250,
},
{ prop: "pead", label: "Product Exception Approved Date", width: 150 },
];
case "P43": // Finished Shoe Custom页面
return [
{ prop: "testMethod", label: "Nike Test Method #", width: 120 },
{ prop: "testMethodName", label: "Nike Test Method Name", width: 130 },
{ prop: "pictureRef", label: "PICTURE REF.#", width: 100 },
{ prop: "flmc", label: "FOCUSED LOCATION/MATERIAL/COLOR", width: 220 },
{ prop: "testParameter", label: "Test Parameter", width: 120 }, // P43特有
{ prop: "minSpec", label: "Min.Spec", width: 120 },
{ prop: "peSpec", label: "Product Exc.Spec", width: 120 },
{
prop: "csan",
label: "COMMENT SECTION Approver Name / Product Exception Detail...",
width: 250,
},
{ prop: "pead", label: "Product Exception Approved Date", width: 150 },
];
case "P124": //Fuse & No Sew Upper
return [
{ prop: "bondTest", label: "Nike Test Method #", width: 120 },
{ prop: "testItem", label: "TEST ITEM", width: 100 },
{ prop: "pictureRef", label: "PICTURE REF.#", width: 100 },
{ prop: "materialOne", label: "MATERIAL 1", width: 120 },
{ prop: "materialTwo", label: "MATERIAL 2", width: 120 },
{ prop: "speed", label: "Speed(mm/min)", width: 150 },
{ prop: "minSpec", label: "Min.Spec(kgf/cm)", width: 150 },
{ prop: "peSpec", label: "Product Exc.Spec", width: 150 },
{
prop: "csan",
label: "COMMENT SECTION Approver Name / Product Exception Detail...",
width: 250,
},
{ prop: "pead", label: "Product Exception Approved Date", width: 150 },
];
case "P125": // Sockliner页面
return [
{ prop: "testMethod", label: "Nike Test Method #", width: 120 },
{ prop: "testMethodName", label: "Nike Test Method Name", width: 130 },
{ prop: "pictureRef", label: "PICTURE REF.#", width: 100 },
{ prop: "flmc", label: "FOCUSED LOCATION/MATERIAL/COLOR", width: 220 },
{ prop: "speed", label: "Speed(mm/min)", width: 150 }, // P125特有
{ prop: "minSpec", label: "Min.Spec(kgf/cm)", width: 150 },
{ prop: "peSpec", label: "Product Exc.Spec", width: 150 },
{
prop: "csan",
label: "COMMENT SECTION Approver Name / Product Exception Detail...",
width: 250,
},
{ prop: "pead", label: "Product Exception Approved Date", width: 150 },
];
default:
return [];
}
}
// 获取标签页显示名称
function getTabLabel(item) {
return `${item.pfcCaption} (${item.pageNumber})`;
}
// 删除数据行
function removeDataRow(tabIndex, rowIndex) {
currentTabData.value[tabIndex].dataRows.splice(rowIndex, 1);
}
// 获取对应标签页的验证规则
function getTabRules(tabIndex) {
// 可以根据不同的标签页返回不同的验证规则
return data.rules;
}
function handleDelete(row) {
proxy.$modal
.confirm(
'确认删除该条记录吗?'
)
.then(function () {
return delQualityStand(row.pfcNo);
})
.then(() => {
handleQuery();
proxy.$modal.msgSuccess("Delete Successfully");
})
.catch(() => {});
}
async function handleCreate(row) {
createDialog.value = true;
try {
const response = await getQsMain(row.pfcNo);
mainList.value = response.data;
// 为每个标签页初始化独立的数据
for (let index = 0; index < mainList.value.length; index++) {
const item = mainList.value[index];
await initTabData(index, item);
}
// 设置默认激活第一个标签页
if (mainList.value.length > 0) {
activeTab.value = "0";
}
} catch (error) {
console.error("加载数据失败:", error);
proxy.$modal.msgError("加载数据失败");
}
}
// 保存当前标签页
async function handleSaveCurrent() {
const currentIndex = parseInt(activeTab.value);
const currentData = currentTabData.value[currentIndex];
const baseInfo = currentData.baseInfo;
try {
// 首先上传新添加的图片
await uploadImagesForTab(currentIndex);
// 构建保存数据
const saveDataList = [];
// 遍历当前标签页的所有测试用例
for (const dataRow of currentData.dataRows) {
const saveData = {
pageNumber: baseInfo.pageNumber, // 当前标签页的页码
pfcNo: baseInfo.pfcNo, // PFC手册号
templateId: dataRow.templateId, // 模板树第七层data的id
// 其他表单数据
// styleNo: currentData.formData.styleNo,
// dpa: currentData.formData.dpa,
// tdCode: currentData.formData.tdCode,
// factory: currentData.formData.factory,
// labTest: currentData.formData.labTest,
// approvedBy: currentData.formData.approvedBy,
// approvedDate: currentData.formData.approvedDate,
// description: currentData.formData.description
};
// 添加测试用例数据
// const pageNumber = baseInfo.pageNumber;
// if (pageNumber == 'P42' || pageNumber == 'P124') {
// // P42/P124字段
// saveData.testItem = dataRow.testItem || '';
// saveData.pictureRef = dataRow.pictureRef || '';
// saveData.materialOne = dataRow.materialOne || '';
// saveData.materialTwo = dataRow.materialTwo || '';
// saveData.speed = dataRow.speed || '';
// saveData.minSpec = dataRow.minSpec || '';
// saveData.bondTest = dataRow.bondTest || '';
// } else if (pageNumber == 'P43' || pageNumber == 'P125') {
// // P43/P125字段
// saveData.testMethod = dataRow.testMethod || '';
// saveData.testMethodName = dataRow.testMethodName || '';
// saveData.pictureRef = dataRow.pictureRef || '';
// saveData.flmc = dataRow.flmc || '';
// saveData.minSpec = dataRow.minSpec || '';
// if (pageNumber == 'P43') {
// saveData.testParameter = dataRow.testParameter || '';
// } else if (pageNumber == 'P125') {
// saveData.speed = dataRow.speed || '';
// }
// }
// 如果csan和pead不为空,也添加到保存数据中
if (dataRow.peSpec && dataRow.peSpec.trim() !== "") {
saveData.peSpec = dataRow.peSpec;
}
if (dataRow.csan && dataRow.csan.trim() !== "") {
saveData.csan = dataRow.csan;
}
if (dataRow.pead && dataRow.pead.trim() !== "") {
saveData.pead = dataRow.pead;
}
saveDataList.push(saveData);
}
console.log("保存数据:", saveDataList);
// 调用API保存数据
const response = await saveQualityStandards(saveDataList);
proxy.$modal.msgSuccess(
`保存 ${mainList.value[currentIndex].pfcCaption} 成功,共保存 ${saveDataList.length} 个测试用例`
);
// 保存成功后重新加载数据,确保数据一致性
await loadSavedDataRows(currentIndex, baseInfo.pfcNo, baseInfo.pageNumber);
} catch (error) {
console.error("保存失败:", error);
proxy.$modal.msgError("保存失败: " + (error.message || "未知错误"));
}
}
// 监听弹窗关闭
watch(createDialog, (newVal) => {
if (!newVal) {
// 关闭弹窗时清理数据
currentTabData.value = {};
mainList.value = [];
activeTab.value = "0";
}
});
// 保存所有标签页
function handleSaveAll() {
console.log("保存所有标签页数据:", currentTabData.value);
// 遍历所有标签页数据并保存
Object.keys(currentTabData.value).forEach((index) => {
const tabData = currentTabData.value[index];
console.log(`标签页 ${index} 数据:`, tabData);
// 调用API保存每个标签页的数据
});
proxy.$modal.msgSuccess("所有数据保存成功");
createDialog.value = false;
}
function getTestList() {
loading.value = true;
ptrInfo(queryParams.value).then((response) => {
ptrList.value = response.rows;
totalTest.value = response.total;
loading.value = false;
});
}
function handleAdd(row) {
addQualityStand(row).then((response) => {
proxy.$modal.msgSuccess("新增成功");
getList();
});
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
function handleQueryTest() {
queryParams.value.pageNum = 1;
getTestList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
function resetQueryTest() {
proxy.resetForm("testRef");
handleQueryTest();
}
getList();
</script>
<style scoped>
/* 为级联选择器添加样式,确保显示完整 */
:deep(.el-cascader) {
width: 450px; /* 增加宽度以显示更长的路径 */
margin-right: 10px;
}
:deep(.el-cascader__dropdown) {
max-height: 400px; /* 增加下拉框高度 */
}
.readonly-input :deep(.el-input__inner) {
background-color: #fff7e6;
}
/* 为级联选择器的标签添加更好的显示 */
:deep(.el-cascader-node__label) {
font-size: 14px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 300px;
}
/* 模板选择区域样式 */
.template-selector {
display: flex;
align-items: center;
margin-bottom: 15px;
padding: 10px;
background-color: #f8f9fa;
border-radius: 4px;
}
.template-selector-label {
font-weight: bold;
margin-right: 10px;
min-width: 120px;
}
.template-selector-hint {
margin-left: 10px;
color: #666;
font-size: 12px;
}
/* 图片上传样式 */
:deep(.el-upload-list--picture-card .el-upload-list__item) {
width: 100px;
height: 100px;
}
:deep(.el-upload--picture-card) {
width: 100px;
height: 100px;
line-height: 100px;
}
:deep(.el-upload-list--picture-card .el-upload-list__item-thumbnail) {
object-fit: contain;
}
.upload-tip {
margin-top: 10px;
color: #909399;
font-size: 12px;
}
</style>
<style>
/* 全局样式(不能加 scoped) */
.custom-cascader {
max-height: 400px !important; /* 整体最大高度 */
overflow-y: auto !important;
}
.custom-cascader .el-cascader-menu {
height: 400px !important; /* 每列高度 */
min-height: 300px !important;
overflow-y: auto !important;
}
.custom-cascader .el-cascader-menu__wrap {
max-height: 480px !important; /* 滚动区域高度 */
}
</style>为什么级联选择器的下拉面板最多只能展示6个选择项
最新发布