zhiqi/src/views/order/intention/Step2.vue

466 lines
12 KiB
Vue

<template>
<div class="step2-container">
<div class="main-row">
<div class="step-indicator">
<div :class="['circle', currentStep === 1 ? 'active' : '']">1</div>
<div class="line"></div>
<div :class="['circle', currentStep === 2 ? 'active' : '']">2</div>
</div>
<div class="right-content">
<div v-if="currentStep === 1">
<div class="step-title">第一步:选择车型</div>
<el-form label-width="120px" class="model-form">
<el-form-item label="车型列表" required>
<el-select
v-model="selectedCarTypeProxy"
placeholder="请选择车型"
filterable
@change="handleCarTypeChange"
>
<el-option-group
v-for="group in carTypeOptions"
:key="group.label"
:label="group.label"
>
<el-option
v-for="option in group.options"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-option-group>
</el-select>
</el-form-item>
<el-form-item label="计划购买数量" required>
<el-input-number v-model="planCount" :min="1" :max="999" />
</el-form-item>
<el-form-item label="计划交付时间" required>
<el-date-picker
v-model="deliveryTime"
type="date"
placeholder="选择日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
</el-form-item>
<el-form-item label="计划交付方式" required>
<el-radio-group v-model="deliveryMethod">
<el-radio label="self">自行提货</el-radio>
<el-radio label="logistics">物流配送</el-radio>
</el-radio-group>
</el-form-item>
<!-- 其他车型的额外表单 -->
<template v-if="selectedCarTypeProxy === '其他'">
<el-form-item label="可参考车型列表">
<el-select
v-model="referenceCarType"
placeholder="请选择参考车型"
filterable
@change="handleReferenceCarTypeChange"
>
<el-option-group
v-for="group in referenceCarTypeOptions"
:key="group.label"
:label="group.label"
>
<el-option
v-for="option in group.options"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-option-group>
</el-select>
</el-form-item>
<el-form-item label="车型输入">
<el-input v-model="modelInput" placeholder="请输入车型" />
</el-form-item>
<el-form-item label="车型描述">
<el-input
type="textarea"
:rows="5"
v-model="modelDesc"
placeholder="请输入车型描述"
/>
</el-form-item>
</template>
</el-form>
</div>
<div v-else>
<div class="step">
<div class="step-left">
<div class="step-title">
第一步:车型{{
selectedCarTypeProxy === "其他"
? "其他"
: selectedCarTypeProxy
}}
<div
v-if="selectedCarTypeProxy === '其他'"
class="reference-model"
>
参考车型:{{ referenceCarType || "未选择" }}
</div>
</div>
<div
class="step-title"
:style="{
marginTop:
selectedCarTypeProxy === '其他' ? '165px' : '192px',
}"
>
第二步:选择轮对商品
</div>
</div>
<div class="image-box right-align">
<img
src="/images/3D.png"
alt="3D结构图"
class="main-img"
/>
</div>
</div>
<div class="table-title">商品参数选择</div>
<div class="tree-table-row">
<el-tree
:data="treeData"
:props="treeProps"
node-key="id"
highlight-current
@current-change="handleTreeSelect"
class="tree-box"
default-expand-all
/>
<el-table
:data="selectedPartInfo ? [selectedPartInfo] : []"
border
class="part-table"
style="width: 600px; margin-left: 24px"
>
<el-table-column prop="name" label="部件名称">
<template #default="scope">
<el-input v-model="scope.row.name" />
</template>
</el-table-column>
<el-table-column prop="spec" label="规格">
<template #default="scope">
<el-input v-model="scope.row.spec" />
</template>
</el-table-column>
<el-table-column prop="desc" label="描述">
<template #default="scope">
<el-input v-model="scope.row.desc" />
</template>
</el-table-column>
</el-table>
</div>
</div>
<div class="btn-row">
<el-button @click="handlePrevStep">上一步</el-button>
<el-button type="primary" @click="handleNextStep">下一步</el-button>
</div>
</div>
</div>
<!-- 车型信息弹窗 -->
<car-model-dialog
v-model="carModelDialogVisible"
:car-model="selectedCarModel"
/>
</div>
</template>
<script setup>
import { ref, computed, watch } from "vue";
import { carTypeOptions, treeData, partInfoMap } from "@/data/stepMockData";
import CarModelDialog from "@/components/CarModelDialog.vue";
const props = defineProps({
form: Object,
selectedCarType: String,
});
const emit = defineEmits(["update:form", "prev-step", "next-step"]);
const currentStep = ref(1);
const carModelDialogVisible = ref(false);
const selectedCarModel = ref(null);
const referenceCarType = ref("");
const deliveryTime = ref("");
const deliveryMethod = ref("");
// 计算属性:参考车型选项(排除"其他"选项)
const referenceCarTypeOptions = computed(() => {
return carTypeOptions.map((group) => ({
...group,
options: group.options.filter((option) => option.value !== "其他"),
}));
});
// 彻底双向绑定
const selectedCarTypeProxy = computed({
get() {
return props.form?.selectedCarType ?? "其他";
},
set(val) {
if (props.form) {
props.form.selectedCarType = val;
emit("update:form", props.form);
}
},
});
const planCount = computed({
get() {
return props.form?.planCount ?? "";
},
set(val) {
if (props.form) {
props.form.planCount = val;
emit("update:form", props.form);
}
},
});
const modelInput = computed({
get() {
return props.form?.modelInput ?? "";
},
set(val) {
if (props.form) {
props.form.modelInput = val;
emit("update:form", props.form);
}
},
});
const modelDesc = computed({
get() {
return props.form?.modelDesc ?? "";
},
set(val) {
if (props.form) {
props.form.modelDesc = val;
emit("update:form", props.form);
}
},
});
const selectedPartInfo = computed({
get() {
return props.form?.selectedPartInfo ?? null;
},
set(val) {
if (props.form) {
props.form.selectedPartInfo = val;
emit("update:form", props.form);
}
},
});
// 监听车型变化,清空表单
watch(selectedCarTypeProxy, (newVal, oldVal) => {
if (newVal !== oldVal) {
// 清空所有相关字段
if (props.form) {
props.form.planCount = "";
props.form.modelInput = "";
props.form.modelDesc = "";
props.form.selectedPartInfo = null;
emit("update:form", props.form);
}
}
});
// 模拟树形结构数据
const treeProps = { children: "children", label: "label" };
function handleTreeSelect(node) {
if (node && node.id && partInfoMap[node.id]) {
selectedPartInfo.value = { ...partInfoMap[node.id] };
} else {
selectedPartInfo.value = null;
}
}
function handleCarTypeChange(value) {
// 只有非"其他"选项才显示车型信息弹窗
if (value !== "其他") {
const selectedOption = carTypeOptions
.flatMap((group) => group.options)
.find((option) => option.value === value);
if (selectedOption) {
selectedCarModel.value = {
name: selectedOption.label,
description: selectedOption.description || "",
specifications: selectedOption.specifications || {},
image: selectedOption.image || "",
};
carModelDialogVisible.value = true;
}
}
}
function handleReferenceCarTypeChange(value) {
// 显示参考车型信息弹窗
const selectedOption = referenceCarTypeOptions.value
.flatMap((group) => group.options)
.find((option) => option.value === value);
if (selectedOption) {
selectedCarModel.value = {
name: selectedOption.label,
description: selectedOption.description || "",
specifications: selectedOption.specifications || {},
image: selectedOption.image || "",
};
carModelDialogVisible.value = true;
}
}
function handlePrevStep() {
if (currentStep.value === 2) {
currentStep.value = 1;
} else {
emit("prev-step");
}
}
function handleNextStep() {
if (currentStep.value === 1) {
currentStep.value = 2;
} else {
emit("next-step");
}
}
</script>
<style scoped lang="scss">
.step2-container {
background: #fff;
padding: 24px;
border-radius: 8px;
}
.main-row {
display: flex;
align-items: flex-start;
}
.step-indicator {
display: flex;
flex-direction: column;
align-items: center;
margin-right: 24px;
margin-top: 10px;
}
.circle {
width: 32px;
height: 32px;
border-radius: 50%;
background: #ccc;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
margin-bottom: 8px;
}
.circle.active {
background: #2156f3;
}
.line {
width: 4px;
height: 170px;
background: #ccc;
margin-bottom: 8px;
}
.right-content {
flex: 1;
}
.step {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
}
.step-left {
flex: 1;
margin-right: 10px;
}
.step-title {
font-size: 18px;
margin: 15px 0;
color: #333;
font-weight: 500;
&.active {
color: #2156f3;
}
.reference-model {
font-size: 14px;
color: #666;
margin-top: 8px;
padding-left: 20px;
position: relative;
&::before {
content: "";
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 12px;
height: 12px;
background: #2156f3;
border-radius: 50%;
}
}
}
.image-box.right-align {
display: flex;
justify-content: flex-end;
align-items: flex-start;
margin-bottom: 16px;
}
.table-title {
font-weight: bold;
margin: 16px 0 8px 0;
color: #333;
}
.tree-table-row {
display: flex;
align-items: flex-start;
border: 1px solid #bbb;
border-radius: 4px;
padding: 12px;
background: #fff;
}
.tree-box {
min-width: 340px;
max-width: 400px;
margin-right: 24px;
background: #fff;
}
.part-table {
min-width: 350px;
max-width: 600px;
}
.model-form {
max-width: 900px;
margin-top: 16px;
}
.btn-row {
display: flex;
justify-content: flex-end;
gap: 16px;
margin-top: 20px;
}
.main-img {
width: 580px;
height: 260px;
object-fit: contain;
border-radius: 8px;
border: 1px solid #eee;
}
</style>