This commit is contained in:
JenniferW 2025-06-13 10:04:11 +08:00
parent de35e4b951
commit 81c53e71ef
2 changed files with 477 additions and 80 deletions

View File

@ -93,35 +93,35 @@ export const carTypeOptions = [
}
];
export const treeData = [
{
id: 1,
label: "D310000000032,动力轮对轴箱组装(带联轴节)",
children: [
{
id: 2,
label: "D311000000013,动力轮对(带轴承+联轴节)",
children: [
{ id: 3, label: "D311001000011,动力轮对" },
{ id: 4, label: "D325000000013,左轴箱组装" },
{ id: 5, label: "D326000000037,左轴端装置" },
{ id: 6, label: "D325000000014,右轴箱组装" },
{ id: 7, label: "D326000000038,右轴端装置" },
],
},
],
},
];
// export const treeData = [
// {
// id: 1,
// label: "D310000000032,动力轮对轴箱组装(带联轴节)",
// children: [
// {
// id: 2,
// label: "D311000000013,动力轮对(带轴承+联轴节)",
// children: [
// { id: 3, label: "D311001000011,动力轮对" },
// { id: 4, label: "D325000000013,左轴箱组装" },
// { id: 5, label: "D326000000037,左轴端装置" },
// { id: 6, label: "D325000000014,右轴箱组装" },
// { id: 7, label: "D326000000038,右轴端装置" },
// ],
// },
// ],
// },
// ];
export const partInfoMap = {
1: { id: 1, name: "动力轮对轴箱组装", spec: "组装件", desc: "包含轮对、轴箱等" },
2: { id: 2, name: "动力轮对", spec: "带轴承+联轴节", desc: "动力传递部件" },
3: { id: 3, name: "动力轮对", spec: "标准型", desc: "主驱动部件" },
4: { id: 4, name: "左轴箱组装", spec: "组装件", desc: "左侧支撑" },
5: { id: 5, name: "左轴端装置", spec: "端装置", desc: "左端保护" },
6: { id: 6, name: "右轴箱组装", spec: "组装件", desc: "右侧支撑" },
7: { id: 7, name: "右轴端装置", spec: "端装置", desc: "右端保护" },
};
// export const partInfoMap = {
// 1: { id: 1, name: "动力轮对轴箱组装", spec: "组装件", desc: "包含轮对、轴箱等" },
// 2: { id: 2, name: "动力轮对", spec: "带轴承+联轴节", desc: "动力传递部件" },
// 3: { id: 3, name: "动力轮对", spec: "标准型", desc: "主驱动部件" },
// 4: { id: 4, name: "左轴箱组装", spec: "组装件", desc: "左侧支撑" },
// 5: { id: 5, name: "左轴端装置", spec: "端装置", desc: "左端保护" },
// 6: { id: 6, name: "右轴箱组装", spec: "组装件", desc: "右侧支撑" },
// 7: { id: 7, name: "右轴端装置", spec: "端装置", desc: "右端保护" },
// };
export const defaultPaymentTerms = "货物出厂验收合格前,买方需将所提货物全额货款支付给卖方。";
export const defaultObjectionTerms = "买方提出对产品质量异议的时间为收到货物起5个工作日内卖方应在收到异议书次日起3个工作日内与买方沟通通过技术指导方式解决问题如不能解决买方可以要求卖方前往修理如修理后仍不能使用买方可以提出更换请求。如买方在收到货物后5日内未提出异议则视为同意卖方处理意见。";
@ -145,7 +145,7 @@ export const productTreeData = [
{
code: "D311001000011",
label: "D311001000011,动力轮对",
replaceable: true,
replaceable: false,
image: '/src/assets/images/cars/1_1_1.jpg',
children: [
{
@ -217,12 +217,6 @@ export const productTreeData = [
label: "D326000000037,左轴端装置",
replaceable: false,
image: '/src/assets/images/cars/4.jpg'
},
{
code: "D326000000038",
label: "D326000000038,右轴端装置",
replaceable: false,
image: '/src/assets/images/cars/1_2_1.jpg'
}
]
}

View File

@ -118,30 +118,126 @@
</div>
</div>
<div class="table-title">商品参数选择</div>
<!-- 一级菜单作为表头 -->
<div
class="header-title"
v-for="item in firstLevelItems"
:key="item.code"
>
<div class="header-code">编号{{ item.code }}</div>
<div class="header-name">名称{{ item.label }}</div>
</div>
<div class="tree-table-row">
<el-tree
:data="treeData"
:props="treeProps"
node-key="code"
highlight-current
@node-click="handleNodeClick"
class="tree-box"
/>
<div class="part-detail-box" v-if="selectedNode">
<img
:src="selectedNode.image || '/images/part-default.png'"
class="part-img"
/>
<div class="part-info">
<div class="part-label">{{ selectedNode.label }}</div>
<div v-if="selectedNode.replaceable">
<el-button
type="primary"
@click="openReplaceDialog(selectedNode)"
>替换</el-button
>
</div>
</div>
<!-- 二级菜单作为tab页 -->
<div class="tab-container">
<el-tabs v-model="activeTab" @tab-click="handleTabClick">
<el-tab-pane
v-for="item in secondLevelItems"
:key="item.code"
:name="item.code"
>
<template #label>
<div class="custom-tab-label">
<div class="tab-label-image">
<img
:src="item.image || '/images/part-default.png'"
class="tab-img"
/>
</div>
<div class="tab-label-info">
<div class="tab-label-code">{{ item.code }}</div>
<div class="tab-label-name">{{ item.label }}</div>
</div>
</div>
</template>
<!-- 三级及以下树形结构 -->
<div class="tab-content">
1111
<template v-if="item.children && item.children.length">
<div
v-for="thirdLevel in item.children"
:key="thirdLevel.code"
class="third-level-section"
>
<div class="third-level-header">
<div class="third-level-title">
<span class="third-level-code">{{
thirdLevel.code
}}</span>
<span class="third-level-name">{{
thirdLevel.label
}}</span>
</div>
<div
class="third-level-actions"
v-if="
thirdLevel.children && thirdLevel.children.length
"
>
<el-button
type="primary"
link
@click="openReplaceDialog(thirdLevel)"
>
替换
</el-button>
</div>
</div>
<!-- 四级及以下菜单 -->
<div
v-if="
thirdLevel.children && thirdLevel.children.length
"
class="fourth-level-container"
>
<div
v-for="fourthLevel in thirdLevel.children"
:key="fourthLevel.code"
class="fourth-level-item"
>
<div class="fourth-level-content">
<div
class="fourth-level-image"
v-if="fourthLevel.image"
>
<img
:src="fourthLevel.image"
class="fourth-level-img"
/>
</div>
<div class="fourth-level-info">
<div class="fourth-level-code">
{{ fourthLevel.code }}
</div>
<div class="fourth-level-name">
{{ fourthLevel.label }}
</div>
</div>
</div>
<div
class="fourth-level-actions"
v-if="
fourthLevel.children &&
fourthLevel.children.length
"
>
<el-button
type="primary"
link
@click="openReplaceDialog(fourthLevel)"
>
替换
</el-button>
</div>
</div>
</div>
</div>
</template>
</div>
</el-tab-pane>
</el-tabs>
</div>
</div>
<el-dialog
@ -180,7 +276,11 @@
<script setup>
import { ref, computed, watch, onMounted } from "vue";
import { carTypeOptions, productTreeData, replacePartsMap } from "@/data/stepMockData";
import {
carTypeOptions,
productTreeData,
replacePartsMap,
} from "@/data/stepMockData";
import CarModelDialog from "@/components/CarModelDialog.vue";
const props = defineProps({
@ -286,20 +386,48 @@ const selectedNode = ref(null);
const replaceDialogVisible = ref(false);
const replaceList = ref([]);
const replaceSelected = ref(null);
const activeTab = ref("");
//
const firstLevelItems = computed(() => {
return treeData.value.map((item) => ({
code: item.code,
label: item.label,
}));
});
//
const secondLevelItems = computed(() => {
const activeFirstLevel = treeData.value.find(
(item) => item.code === activeTab.value
);
return activeFirstLevel?.children || [];
});
// tab
function handleTabClick(tab) {
activeTab.value = tab.props.name;
selectedNode.value = null;
}
//
function handleNodeClick(node) {
selectedNode.value = node;
}
//
function openReplaceDialog(node) {
replaceList.value = replacePartsMap[node.code] || [];
replaceSelected.value = null;
replaceDialogVisible.value = true;
}
//
function handleReplace() {
if (!replaceSelected.value) return;
const newPart = replaceList.value.find(item => item.code === replaceSelected.value);
const newPart = replaceList.value.find(
(item) => item.code === replaceSelected.value
);
if (newPart) {
selectedNode.value.code = newPart.code;
selectedNode.value.label = newPart.label;
@ -310,7 +438,7 @@ function handleReplace() {
const treeProps = {
label: "label",
children: "children"
children: "children",
};
function handleCarTypeChange(value) {
@ -366,7 +494,9 @@ function handleNextStep() {
}
onMounted(() => {
// No need to fetch data here as treeData is already populated
if (treeData.value.length > 0) {
activeTab.value = treeData.value[0].code;
}
});
</script>
@ -463,37 +593,67 @@ onMounted(() => {
}
.tree-table-row {
display: flex;
align-items: flex-start;
flex-direction: column;
border: 1px solid #bbb;
border-radius: 4px;
padding: 12px;
background: #fff;
}
.tree-box {
min-width: 340px;
max-width: 400px;
margin-right: 24px;
background: #fff;
.header-title {
flex: 1;
padding: 10px;
border-radius: 4px;
}
.part-detail-box {
min-width: 350px;
max-width: 600px;
margin-left: 24px;
.header-code,
.header-name {
font-size: 14px;
color: #333;
margin-bottom: 5px;
}
.tab-container {
width: 100%;
}
.tab-header {
background: #f5f7fa;
border-radius: 4px;
padding: 16px;
margin-bottom: 20px;
}
.tab-header-item {
display: flex;
gap: 20px;
align-items: center;
}
.tab-header-image {
width: 200px;
height: 150px;
flex-shrink: 0;
}
.tab-header-info {
flex: 1;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 12px;
}
.tab-header-code,
.tab-header-name {
font-size: 14px;
color: #333;
line-height: 1.5;
}
.part-img {
width: 220px;
height: 180px;
width: 100%;
height: 100%;
object-fit: contain;
border-radius: 8px;
border-radius: 4px;
border: 1px solid #eee;
margin-bottom: 16px;
}
.part-info {
font-size: 16px;
color: #333;
.sub-tree {
margin-top: 20px;
padding: 16px;
background: #fff;
border: 1px solid #eee;
border-radius: 4px;
}
.model-form {
max-width: 900px;
@ -512,4 +672,247 @@ onMounted(() => {
border-radius: 8px;
border: 1px solid #eee;
}
.custom-tab-label {
display: flex;
flex-direction: column;
align-items: center;
padding: 8px 0;
}
.tab-label-image {
width: 80px;
height: 60px;
margin-bottom: 8px;
}
.tab-img {
width: 100%;
height: 100%;
object-fit: contain;
border-radius: 4px;
border: 1px solid #eee;
}
.tab-label-info {
text-align: center;
}
.tab-label-code {
font-size: 12px;
color: #666;
margin-bottom: 4px;
}
.tab-label-name {
font-size: 14px;
color: #333;
font-weight: 500;
}
:deep(.el-tabs__item) {
height: auto !important;
padding: 0 20px !important;
}
:deep(.el-tabs__nav) {
display: flex;
gap: 20px;
}
:deep(.el-tabs__item.is-active) {
.tab-label-code,
.tab-label-name {
color: var(--el-color-primary);
}
}
.custom-tree-node {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
padding: 8px 0;
}
.node-content {
display: flex;
align-items: center;
gap: 12px;
}
.node-image {
width: 60px;
height: 45px;
flex-shrink: 0;
}
.node-img {
width: 100%;
height: 100%;
object-fit: contain;
border-radius: 4px;
border: 1px solid #eee;
}
.node-info {
display: flex;
flex-direction: column;
gap: 4px;
}
.node-code {
font-size: 12px;
color: #666;
}
.node-name {
font-size: 14px;
color: #333;
}
.node-actions {
display: flex;
gap: 8px;
}
:deep(.el-tree-node__content) {
height: auto !important;
padding: 4px 0 !important;
}
:deep(.el-tree-node__children) {
padding-left: 24px;
}
:deep(.el-tree-node.is-current > .el-tree-node__content) {
background-color: var(--el-color-primary-light-9);
}
:deep(.el-tree-node__content:hover) {
background-color: var(--el-color-primary-light-9);
}
.tab-content {
padding: 16px;
background: #fff;
border: 1px solid #eee;
border-radius: 4px;
margin-top: 16px;
min-height: 200px;
}
.third-level-section {
margin-bottom: 24px;
&:last-child {
margin-bottom: 0;
}
}
.third-level-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px;
background: #f5f7fa;
border-radius: 4px;
margin-bottom: 12px;
}
.third-level-title {
display: flex;
align-items: center;
gap: 12px;
}
.third-level-code {
font-size: 14px;
color: #666;
}
.third-level-name {
font-size: 16px;
color: #333;
font-weight: 500;
}
.fourth-level-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 16px;
padding: 0 12px;
}
.fourth-level-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px;
border: 1px solid #eee;
border-radius: 4px;
background: #fff;
transition: all 0.3s ease;
&:hover {
border-color: var(--el-color-primary);
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
}
.fourth-level-content {
display: flex;
align-items: center;
gap: 12px;
}
.fourth-level-image {
width: 60px;
height: 45px;
flex-shrink: 0;
}
.fourth-level-img {
width: 100%;
height: 100%;
object-fit: contain;
border-radius: 4px;
border: 1px solid #eee;
}
.fourth-level-info {
display: flex;
flex-direction: column;
gap: 4px;
}
.fourth-level-code {
font-size: 12px;
color: #666;
}
.fourth-level-name {
font-size: 14px;
color: #333;
}
:deep(.el-tabs__content) {
overflow: visible;
}
:deep(.el-tabs__item) {
height: auto !important;
padding: 0 20px !important;
}
:deep(.el-tabs__nav) {
display: flex;
gap: 20px;
}
:deep(.el-tabs__item.is-active) {
.tab-label-code,
.tab-label-name {
color: var(--el-color-primary);
}
}
</style>