重点函数 | SELECTEDVALUE 用法介绍

本文介绍了如何利用SELECTEDVALUE函数在Power BI中实现数据筛选与切换。通过示例一展示了如何创建参数表并书写度量值,使图表值与切片器联动;示例二解释了在多条件判断下,SELECTEDVALUE如何与图例关联,完成复杂的数据分析。文章还提及SELECTEDVALUE与HASONEVALUE、VALUES函数的关联,并提供了相关资源供读者实践。
部署运行你感兴趣的模型镜像


大家好,今天给大家分享一下SELECTEDVALUE函数的用法,先来看一下函数的说明:

SELECTEDVALUE ( Table[column] )

SELECTEDVALUE ( Table[column], "defaultvalue" )

SELECTEDVALUE ( Table[column], 0 )

函数返回第一个参数列的唯一引用值,如果参数列在上下文过滤器中不是唯一可用值,将返回空白或者第二个参数值(默认值)

话不多说,接下来我们一起看看SELECTEDVALUE在具体业务中的运用。

示例一

file

如上图,订单表中包含销售分区、订单金额、订单数量等信息。

要求:

展示各区域的销售完成情况,数值可以通过切片器切换销售额和销量。效果如下图:

思路:

数据源中,销售额和销售量信息分布在两个字段列上,无法通过选取现成的字段列来切片,需要手动创建参数表作为切片器。再通过书写度量值使得柱状图中显示的值与切片器相关联

步骤:

Step 1:新建参数表

value参数表 =DATATABLE("value",STRING,{{"销售额"},{"销售量"}})

file

Step 2:根据value的不同计算对应的聚合值书写度量值

 sum_value = SWITCH(SELECTEDVALUE('value参数表'[value]),
 "销售额",SUM('订单表'[订单金额(¥)]),
 "销售量",SUM('订单表'[订单数量]))

Step 3:可视化界面中,将value参数表中的value列作为切片器,完成。

是不是很简单呢,那我们再看另一个场景:

示例二

看到上面数据源里销售员的身份了吗,分为电话销售员和区域销售员,即一个订单的是由两类角色人员共同完成的,业绩双记。在另外一张表里,所有员工被标记了“是否新员工”,
file

现在老板要看各区域新老员工的业绩对比情况,效果如下图所示:

思路:

如果订单表中的员工类型只有电话销售或者只有区域销售,那么这个问题很简单,将订单表和人员表用员工ID建立关系就可以了。
现在的问题是,某个订单不能直接判断是否由新员工或者老员工完成,必须要和员工类型结合起来。

步骤:

Step 1:新建新老员工维度表

Dim新老员工 = SUMMARIZE('人员表','人员表'[是否新员工])

Step 2:写度量值,根据员工类型和是否新员工两个判断条件,计算对应的聚合值

values = SWITCH(SELECTEDVALUE('Dim员工类型'[员工类型]),

"电话销售",SWITCH(SELECTEDVALUE('Dim新老员工'[是否新员工]),

"新员工",CALCULATE([sum_value],FILTER('订单表',LOOKUPVALUE('人员表'[是否新员工],'人员表'[员工ID],'订单表'[电话销售员ID])="新员工")),

"老员工",CALCULATE([sum_value],FILTER('订单表',LOOKUPVALUE('人员表'[是否新员工],'人员表'[员工ID],'订单表'[电话销售员ID])="老员工"))),

"区域销售",SWITCH(SELECTEDVALUE('Dim新老员工'[是否新员工]),

"新员工",CALCULATE([sum_value],FILTER('订单表',LOOKUPVALUE('人员表'[是否新员工],'人员表'[员工ID],'订单表'[区域销售员ID])="新员工")),

"老员工",CALCULATE([sum_value],FILTER('订单表',LOOKUPVALUE('人员表'[是否新员工],'人员表'[员工ID],'订单表'[区域销售员ID])="老员工"))))

这个公式中包含了两层SELECTEDVALUE,

第一层的SELECTEDVALUE(‘Dim员工类型’[员工类型])作用与案例一相同,与切片器相关联;
第二层的SELECTEDVALUE(‘Dim新老员工’[是否新员工])没有与任何切片器关联,而是与分组依据相关联,即柱状图中的图例,这是小编认为SELECTEDVALUE函数最神奇的地方。
看过工作技巧 | 动态切换报表标题的读者朋友们可能会发现,SELECTEDVALUE和HASONEVALUE、VALUES的运用有一些相似之处,
实际上,在内部,SELECTEDVALUE只是语法糖,以下两个函数是等价的

SELECTEDVALUE( Table[column] )

IF (HASONEVALUE ( Table[column] ), VALUES ( Table[column] ) )

为了方便大家动手实践,在后台回复关键词“SELECTEDVALUE文件”即可获得本文中的数据源及PBI文件下载链接。

今天的内容就是这些,小伙伴们,下期再见!

  • PowerPivot工坊原创文章,转载请注明出处!

如果您想深入学习微软Power BI,欢迎登录网易云课堂试听学习我们的“从Excel到Power BI数据分析可视化”系列课程。或者关注我们的公众号(PowerPivot工坊)后猛戳”在线学习”。


长按下方二维码关注“Power Pivot工坊”获取更多微软Power BI、PowerPivot相关文章、资讯,欢迎小伙伴儿们转发分享~

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

<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个选择项
最新发布
10-17
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值