<template>
<div class="app-container">
<el-form
:model="queryParams"
ref="queryRef"
:inline="true"
v-show="showSearch"
label-width="68px"
>
<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="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="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="handleCreate(scope.row)"
></el-button>
</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="测试" 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: 20px">
<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-card>
<!-- 图片上传区域 -->
<el-card header="图片上传" style="margin-bottom: 20px">
</el-card>
<!-- 可编辑的表单区域 -->
<el-card header="编辑信息">
<!-- <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> -->
<!-- 动态数据行区域(根据标签页类型显示不同的字段) -->
<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: 100px;
"
>测试用例列表</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)"
/>
</div>
<!-- 右侧:按钮和标题 -->
<!-- <div style="display: flex; align-items: center;">
<el-button
type="primary"
size="small"
@click="addDataRow(index)"
>添加空白用例</el-button>
</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>
</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,
} from "@/api/quality/standard/quasd.js";
import { getSrc } from "@/utils/interceptSrc";
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);
// 初始化标签页数据
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, // 添加加载状态
};
// 加载模板数据
await loadTemplateOptions(tabIndex, sourceData.pageNumber);
// 加载已保存的测试用例数据
await loadSavedDataRows(tabIndex, sourceData.pfcNo, sourceData.pageNumber);
}
// 加载已保存的测试用例数据
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: "BOND TEST", width: 120 },
{ prop: "testMethod", 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;
}
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 {
// 构建保存数据
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.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");
handleQuery();
}
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>
这是我目前的页面,需要在图片上传区域加一个照片墙用于上传图片和回显,我希望可以参考刚刚我提供的案例那样去实现,后端的接口我已经写好了@PostMapping("/images/upload")
public AjaxResult uploadImages(@RequestParam("files") MultipartFile[] files,
@RequestParam String pfcNo,
@RequestParam String pageNumber) {
try {
if (files == null || files.length == 0) {
return AjaxResult.error("上传文件不能为空");
}
int successCount = qualityStandardService.uploadImages(files, pfcNo, pageNumber);
return AjaxResult.success("上传成功,共上传 " + successCount + " 张图片");
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("上传失败: " + e.getMessage());
}
}@Override
public Integer uploadImages(MultipartFile[] files, String pfcNo, String pageNumber) {
if (files == null || files.length == 0) {
throw new ServiceException("上传文件不能为空");
}
int successCount = 0;
String username = SecurityUtils.getUsername();
Date now = MyDateUtils.getNowDate();
for (MultipartFile file : files) {
try {
// 跳过空文件
if (file.isEmpty()) {
continue;
}
QualityShoeDesign qualityShoeDesign = new QualityShoeDesign();
// 执行上传
R<ToolsFile> fileResult = remoteFileService.upload(file, MinioBucketNameConstants.SHOEDESIGN,
SecurityUtils.getFact(), file.getOriginalFilename(), FileEnum.LOCAL, SecurityConstants.INNER);
if (MyStringUtils.isNull(fileResult) || MyStringUtils.isNull(fileResult.getData())) {
throw new ServiceException("文件服务器异常");
}
qualityShoeDesign.setPfcNo(pfcNo);
qualityShoeDesign.setPageNumber(pageNumber);
qualityShoeDesign.setFilePath(fileResult.getData().getUrl());
qualityShoeDesign.setOriginalName(file.getOriginalFilename());
qualityShoeDesign.setCreateBy(username);
qualityShoeDesign.setCreateTime(now);
// 插入记录
int result = qualityStandardMapper.insertQualityShoeDesign(qualityShoeDesign);
if (result > 0) {
successCount++;
}
} catch (Exception e) {
// 记录错误日志,但继续处理其他文件
log.error("上传文件失败: {}", file.getOriginalFilename(), e);
}
}
if (successCount == 0) {
throw new ServiceException("所有文件上传失败");
}
return successCount;
}@GetMapping("/images/list")
public AjaxResult getImages(@RequestParam String pfcNo,
@RequestParam String pageNumber) {
try {
List<QualityShoeDesign> images = qualityStandardService.getImagesByPfcNoAndPage(pfcNo, pageNumber);
return AjaxResult.success(images);
} catch (Exception e) {
return AjaxResult.error("获取图片列表失败: " + e.getMessage());
}
}这些是上传代码和获取图片代码,请帮我生成合适的前端vue代码,图片上传我要可多选的
最新发布