684 lines
22 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<section>
<common>
<template #main>
<div class="warehouse-detail">
<div class="title">
<span @click="toBack(-1)">仓储</span>
<span class="mx-10"> > </span>
<span style="color: rgba(37, 191, 130, 1)">查看详情</span>
</div>
<div class="detail-content-box">
<div class="detail-content-box-left">
<img :src="state.data.imageUrl" fit="cover" />
</div>
<div class="detail-content-box-center">
<p class="center-title">
<span class="highlight">{{ state.data.typeName }}</span>{{ state.data.title }}
</p>
<div class="center-text">
<div class="center-text-lable" style="line-height: 32px">参考价格</div>
<div class="flex-1">
<p class="top-text" style="line-height: 32px">{{ state.data.price }}</p>
</div>
</div>
<div class="center-text">
<div class="center-text-lable">仓库面积</div>
<div class="flex-1">{{ state.data.storageArea }}</div>
</div>
<div class="center-text">
<div class="center-text-lable">仓库区域</div>
<div class="flex-1">{{ state.data.location }}</div>
</div>
<div class="center-text">
<div class="center-text-lable">启动年月</div>
<div class="flex-1">2025年6月</div>
</div>
<div class="center-text">
<div class="center-text-lable">计价单位</div>
<div class="flex-1">{{ state.data.price }}</div>
</div>
<div style="margin-top: 20px">
<el-button size="large" type="primary" @click="reservation">立即预约</el-button>
<el-button size="large" plain style="width: 96px">收藏</el-button>
<el-button size="large" plain style="width: 96px">分享</el-button>
</div>
</div>
</div>
<div class="warehouse-detail-title">
<img :src="getAssetsFile('images/warehouseLogistics/product.png')" alt="" style="width: 30px" draggable="false" />
<div class="center-title page-title">仓储信息</div>
</div>
<div class="warehouse-content-align">
<div class="center-text">
<div class="center-text-lable">预计租期</div>
<div class="flex-1">{{ state.storageInfor.leaseTerm }}</div>
<div class="center-text-lable">货品类型</div>
<div class="flex-1">{{ state.storageInfor.productType }}</div>
</div>
<div class="center-text">
<div class="center-text-lable">仓库用途</div>
<div class="flex-1">{{ state.storageInfor.warehousePurpose }}</div>
<div class="center-text-lable">付款方式</div>
<div class="flex-1">{{ state.storageInfor.paymentMethod }}</div>
</div>
<div class="center-text">
<div class="center-text-lable">仓库类型</div>
<div class="flex-1">{{ state.storageInfor.warehouseType }}</div>
<div class="center-text-lable">建筑类型</div>
<div class="flex-1">{{ state.storageInfor.buildingType }}</div>
</div>
<div class="center-text">
<div class="center-text-lable">底层层高</div>
<div class="flex-1">{{ state.storageInfor.bottomFloorHeight }}</div>
<div class="center-text-lable">消防等级</div>
<div class="flex-1">{{ state.storageInfor.fireProtectionLevel }}</div>
</div>
</div>
<div class="warehouse-detail-title">
<img :src="getAssetsFile('images/warehouseLogistics/location.png')" alt="" style="width: 30px" />
<div class="center-title page-title">地理位置</div>
</div>
<img :src="getAssetsFile('images/warehouseLogistics/map.png')" alt="" style="width: 100%" draggable="false" />
<div class="warehouse-detail-title">
<img :src="getAssetsFile('images/warehouseLogistics/image.png')" alt="" style="width: 30px" />
<div class="center-title page-title">仓库图片</div>
</div>
<img :src="getAssetsFile('images/warehouseLogistics/godown1.png')" alt="" class="fill-img" draggable="false" />
<img :src="getAssetsFile('images/warehouseLogistics/godown2.png')" alt="" class="fill-img" draggable="false" />
<img :src="getAssetsFile('images/warehouseLogistics/godown3.png')" alt="" class="fill-img" draggable="false" />
</div>
</template>
</common>
<el-dialog v-model="dialogVisible" title="立即预约" width="800" center>
<el-form ref="formRef" :model="formInline" :rules="dialogRules" required class="dialog-form-container" :label-width="'80'">
<div class="dialog-custom-title">仓储信息</div>
<el-form-item label="需求面积" prop="requiredArea">
<el-input v-model="formInline.requiredArea" :size="formSize" clearable placeholder="请输入需求面积" :style="{ width: unifiedWidth }">
<template #append></template>
</el-input>
</el-form-item>
<el-form-item label="使用时间" prop="useDate">
<el-date-picker
v-model="formInline.useDate"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择使用时间"
:size="formSize"
:disabled-date="disableStartDate"
:style="{ width: unifiedWidth }"
/>
</el-form-item>
<el-form-item label="仓库位置" required>
<div style="display: flex; gap: 16px">
<el-form-item prop="selectedAddress">
<el-cascader
v-model="formInline.selectedAddress"
:options="addressOptions"
:props="cascaderProps"
placeholder="请选择省市区"
:size="formSize"
:style="{ width: unifiedWidth }"
/>
</el-form-item>
<el-form-item prop="detailAddress">
<el-input
v-model="formInline.detailAddress"
:size="formSize"
placeholder="详细地址(如街道、门牌号等)"
:style="{ width: unifiedWidth }"
/>
</el-form-item>
</div>
</el-form-item>
<div class="dialog-custom-title">租期与价格</div>
<el-form-item label="预计租期" prop="expectedLeaseTerm">
<el-date-picker
v-model="formInline.expectedLeaseTerm"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择预计租期"
:size="formSize"
:disabled-date="disableBeginDate"
:style="{ width: unifiedWidth }"
/>
</el-form-item>
<el-form-item label="价格预算" required>
<div style="display: flex; gap: 16px">
<el-form-item prop="baseBudget">
<el-input v-model="formInline.baseBudget" :size="formSize" clearable placeholder="请输入最低价" :style="{ width: unifiedWidth }">
<template #append>//</template>
</el-input>
</el-form-item>
<span style="line-height: 40px"> </span>
<el-form-item prop="highestBudget">
<el-input v-model="formInline.highestBudget" :size="formSize" clearable placeholder="请输入最高价" :style="{ width: unifiedWidth }">
<template #append>//</template>
</el-input>
</el-form-item>
</div>
</el-form-item>
<el-form-item label="截止日期" prop="closingDate">
<el-date-picker
v-model="formInline.closingDate"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择截止日期"
:size="formSize"
:disabled-date="disableDeadlineDate"
:style="{ width: unifiedWidth }"
/>
</el-form-item>
<div class="dialog-custom-title">货物详情</div>
<el-form-item label="货物类型" prop="goodsType">
<el-select v-model="formInline.goodsType" placeholder="请选择" :size="formSize" :style="{ width: unifiedWidth }">
<el-option v-for="item in goodsList" :key="item.id" :value="item.id" :label="item.name" />
</el-select>
</el-form-item>
<el-form-item label="货物重量" prop="goodsWeight">
<el-input v-model="formInline.goodsWeight" :size="formSize" clearable placeholder="请输入货物重量" :style="{ width: unifiedWidth }">
<template #append>Kg</template>
</el-input>
</el-form-item>
<el-form-item label="温度要求" prop="temperature">
<el-input v-model="formInline.temperature" :size="formSize" clearable placeholder="请输入温度要求" :style="{ width: unifiedWidth }">
<template #append></template>
</el-input>
</el-form-item>
<el-form-item label="详情描述" prop="detailedDescription">
<el-input
v-model="formInline.detailedDescription"
:size="formSize"
clearable
placeholder="请输入详情描述"
:style="{ width: unifiedWidth }"
></el-input>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button size="large" style="width: 120px" @click="dialogVisible = false">取消</el-button>
<el-button type="primary" size="large" style="width: 120px" @click="onSubmit"> 提交 </el-button>
</div>
</template>
</el-dialog>
</section>
</template>
<script setup>
import { ref, reactive, onMounted, nextTick } from 'vue';
import { getAssetsFile } from '@/utils';
import { useRoute, useRouter } from 'vue-router';
import Common from '../components/common.vue';
import { warehouseDetail } from '@/apis/warehouseLogistics.js';
import { ElMessage } from 'element-plus';
import { getRegion } from '@/apis/common';
const route = useRoute();
const router = useRouter();
import img1 from './../images/普通仓储/1.jpg';
import img2 from './../images/普通仓储/2.jpg';
import img3 from './../images/恒温仓储/1.jpg';
import img4 from './../images/冷库/4.jpg';
import img5 from './../images/气调仓储/1.jpg';
const state = reactive({
query: {},
data: {
imageUrl: img1,
typeId: 1,
typeName: '普通仓储',
title: '孟定边贸仓储中心',
operationUnit: '耿马宏泰物流有限公司 ',
pricingUnit: '元/㎡·月',
storageArea: '8,600㎡',
usableArea: '2,300㎡',
location: '孟定镇中缅大道8号',
price: '¥12元/㎡/月',
},
storageInfor: {
leaseTerm: '1-3年(可分段报价)', //预计租期
productType: '水果(需控温0-5℃湿度85%-90%)', //货品类型
warehousePurpose: '新开仓(需配套分拣服务)', //仓库用途
paymentMethod: '押一付三,需开具正规发票', //付款方式
warehouseType: '冷库(无霜型优先)', //仓库类型
buildingType: '不限(钢混/轻钢均可)', //建筑类型
bottomFloorHeight: '25米(称重22吨/㎡)', //底层层高
fireProtectionLevel: '丙二类及以上', //消防等级
},
});
const allData = ref([
{
imageUrl: img1,
typeId: 1,
typeName: '普通仓储',
title: '孟定边贸仓储中心',
operationUnit: '耿马宏泰物流有限公司 ',
pricingUnit: '元/㎡·月',
storageArea: '8,600㎡',
usableArea: '2,300㎡',
location: '孟定镇中缅大道8号',
price: '¥12元/㎡/月',
rank: '1',
},
{
imageUrl: img2,
typeId: 2,
typeName: '普通仓储',
title: '绿色食品园区集散仓',
operationUnit: '耿马县供销集团',
pricingUnit: '元/吨·天',
storageArea: '12,000㎡',
usableArea: '4,500㎡',
location: '绿色食品园区二期',
price: '¥1.5元/吨/月',
rank: '2',
},
{
imageUrl: img3,
typeId: 3,
typeName: '恒温仓储',
title: '蔗糖储备恒温库',
operationUnit: '耿马糖业有限公司',
pricingUnit: '元/托·月',
storageArea: '3,200㎡',
usableArea: '800㎡',
location: '耿马糖厂东侧',
price: '¥28元/托/月',
rank: '3',
},
{
imageUrl: img4,
typeId: 4,
typeName: '冷库',
title: '孟定果蔬冷链中心',
operationUnit: '临沧边境合作区管委会 ',
pricingUnit: '元/板·天',
storageArea: '5,000㎡',
usableArea: '1,200㎡',
location: '孟定海关监管区旁',
price: '¥2.8元/板/月',
rank: '4',
},
{
imageUrl: img5,
typeId: 5,
typeName: '气调仓储',
title: '高原蔬菜气调保鲜库',
operationUnit: '耿马高原农业合作社 ',
pricingUnit: '元/吨·月',
storageArea: '1,800㎡',
usableArea: '300㎡',
location: '勐撒镇蔬菜基地',
price: '¥45元/吨/月',
rank: '5',
},
]);
const dialogVisible = ref(false);
const unifiedWidth = '300px';
const formSize = 'large';
const formRef = ref(null);
const formInline = reactive({
requiredArea: '', //需求面积
useDate: '', //使用时间
selectedAddress: [], //选中的区域编码数组
areaAddress: '', //区域地址
detailAddress: '', //详细地址
expectedLeaseTerm: '', //预计租期
closingDate: '', //截止日期
baseBudget: '', //预算最低价
highestBudget: '', //预算最高价
goodsType: '', //货物类型
goodsWeight: '', //货物重量
temperature: '', //温度要求
detailedDescription: '', //详情描述
});
const resetForm = ref({ ...formInline });
const dialogRules = reactive({
// 仓储信息部分
requiredArea: [
{ required: true, message: '请输入需求面积', trigger: 'blur' },
{ pattern: /^\d+(\.\d{1,2})?$/, message: '请输入有效数字(最多两位小数)', trigger: 'blur' },
],
useDate: [{ required: true, message: '请选择使用时间', trigger: 'change' }],
selectedAddress: [{ required: true, message: '请选择省市区', trigger: 'change' }],
detailAddress: [
{ required: true, message: '请输入详细地址', trigger: 'blur' },
{ min: 3, max: 100, message: '长度在3到100个字符', trigger: 'blur' },
],
// 租期与价格部分
expectedLeaseTerm: [
{ required: true, message: '请选择预计租期', trigger: 'change' },
{
validator: (rule, value, callback) => {
if (value && formInline.useDate) {
const start = new Date(formInline.useDate);
const end = new Date(value);
if (end < start) {
callback(new Error('预计租期不能早于使用时间'));
} else {
callback();
}
} else {
callback();
}
},
trigger: 'change',
},
],
closingDate: [
{ required: true, message: '请选择截止日期', trigger: 'change' },
{
validator: (rule, value, callback) => {
if (value && formInline.expectedLeaseTerm) {
const start = new Date(formInline.expectedLeaseTerm);
const end = new Date(value);
if (end < start) {
callback(new Error('截止日期不能早于预计租期'));
} else {
callback();
}
} else {
callback();
}
},
trigger: 'change',
},
],
baseBudget: [
{ required: true, message: '请输入最低价', trigger: 'blur' },
{ pattern: /^\d+$/, message: '请输入整数金额', trigger: 'blur' },
],
highestBudget: [
{ required: true, message: '请输入最高价', trigger: 'blur' },
{
validator: (rule, value, callback) => {
if (value && formInline.baseBudget && Number(value) < Number(formInline.baseBudget)) {
callback(new Error('最高价不能低于最低价'));
} else {
callback();
}
},
trigger: 'blur',
},
],
goodsType: [{ required: true, message: '请选择货物类型', trigger: 'change' }],
goodsWeight: [
{ required: true, message: '请输入货物重量', trigger: 'blur' },
{ pattern: /^\d+(\.\d{1,2})?$/, message: '请输入有效数字(最多两位小数)', trigger: 'blur' },
],
temperature: [
{ required: true, message: '请输入温度要求', trigger: 'blur' },
{ pattern: /^\d+(\.\d{1,2})?$/, message: '请输入有效数字(最多两位小数)', trigger: 'blur' },
],
detailedDescription: [{ required: true, message: '请输入详情描述', trigger: 'blur' }],
});
// 禁用开始日期的逻辑(不能晚于已选的结束日期)
const disableStartDate = (time) => {
const today = new Date();
today.setHours(0, 0, 0, 0); // 清除时分秒,避免时间差影响比较[2,4](@ref)
// 1. 禁用当天之前的日期
if (time.getTime() < today.getTime()) {
return true;
}
// 2. 如果已选结束日期,则开始日期不能晚于结束日期
if (formInline.useDate) {
const endDate = new Date(formInline.useDate);
return time.getTime() > endDate.getTime();
}
return false;
};
// 禁用开始日期的逻辑(不能选择当天之前的)
const disableBeginDate = (time) => {
const today = new Date();
today.setHours(0, 0, 0, 0); // 清除时分秒,避免时间差影响比较[2,4](@ref)
// 规则1禁用当天之前的日期
if (time.getTime() < today.getTime()) {
return true;
}
// 规则2若已选截止日期则开始日期不能晚于截止日期
if (formInline.deadline) {
const endDate = new Date(formInline.deadline);
if (time.getTime() > endDate.getTime()) {
// 联动操作:开始日期大于截止日期时,重置截止日期
formInline.deadline = null; // 或设置为空字符串/默认值
// 可选触发UI更新如Vue中使用this.$forceUpdate()
}
return time.getTime() > endDate.getTime();
}
return false;
};
// 禁用结束日期的逻辑(不能早于已选的开始日期)
const disableDeadlineDate = (time) => {
const today = new Date();
today.setHours(0, 0, 0, 0);
const currentDate = new Date(time);
currentDate.setHours(0, 0, 0, 0);
// 不能早于今天
if (currentDate < today) return true;
// 不能早于开始日期
if (formInline.expectedLeaseTerm) {
const startDate = new Date(formInline.expectedLeaseTerm);
startDate.setHours(0, 0, 0, 0);
return currentDate < startDate;
}
return false;
};
const goodsList = ref([
{
id: 1,
name: '普通货物',
},
{
id: 2,
name: '特殊货物',
},
{
id: 3,
name: '冷藏货物',
},
]);
// 级联选择器配置
const cascaderProps = ref({
label: 'areaName', // 选项标签字段名
value: 'areaCode', // 选项值字段名
children: 'areaChildVOS', // 子选项字段名
emitPath: true,
expandTrigger: 'hover',
});
// 省市区数据(示例)
const addressOptions = ref([]);
const getArea = async () => {
const res = await getRegion();
if (res.code === 200) {
addressOptions.value = res.data;
} else {
ElMessage.error(res.message);
}
};
const reservation = () => {
dialogVisible.value = true;
Object.assign(formInline, resetForm.value);
};
const onSubmit = async () => {
await formRef.value.validate();
ElMessage.success('提交成功');
console.log(formInline);
dialogVisible.value = false;
};
const toBack = (level) => {
router.go(level);
};
const queryDetail = () => {
warehouseDetail(state.query.id).then((res) => {
if (res.code === 200) {
state.data = res.data;
for (let i in state.data) {
state.data[i].tag = state.data[i].tags.split(',');
}
}
});
};
onMounted(() => {
state.query.id = route.query.id;
// queryDetail();
console.log(route.query);
if (route.query.typeId) {
state.data = allData.value.find((item) => item.typeId == route.query.typeId);
console.log(state.data);
}
getArea();
});
</script>
<style lang="scss" scoped>
.warehouse-detail {
border-radius: 14px;
background-color: #fff;
padding: 20px 20px 0 20px;
}
.title {
text-align: left;
font-size: 18px;
font-weight: bold;
cursor: pointer;
}
/* 根据需要添加样式,这里仅提供基础样式 */
// 基础颜色配置
$primary-color: #25bf82; // 主色调
$text-dark: #25bf82; // 深色文字
$text-regular: #606266; // 常规文字
$border-color: #dcdfe6; // 边框颜色
// 按钮组样式
.dialog-footer {
text-align: center;
.el-button {
padding: 10px 24px;
border-radius: 4px;
font-size: 14px;
}
.cancel-btn {
color: $text-regular;
&:hover {
color: $primary-color;
border-color: $primary-color;
}
}
.submit-btn {
color: #fff;
background: $primary-color;
&:hover {
background: mix($primary-color, #fff, 85%);
}
}
}
.warehouse-detail-title {
font-size: 22px;
font-weight: bold;
text-align: left;
margin: 20px 0 15px 0;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
.detail-content-box {
height: 276px;
margin-top: 20px;
display: flex;
gap: 20px;
}
.detail-content-box-left {
height: 100%;
width: 40%;
border-radius: 14px;
position: relative;
overflow: hidden;
img {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
min-width: 100%;
min-height: 100%;
object-fit: cover;
}
}
.detail-content-box-center {
flex: 1;
text-align: left;
}
.center-title {
font-size: 22px;
font-weight: bold;
text-align: left;
margin-bottom: 10px;
.highlight {
color: #25bf82;
}
}
.page-title {
margin: 0 0 4px 10px;
}
.warehouse-content-align {
text-align: left;
}
.center-text {
font-size: 16px;
display: flex;
margin-bottom: 10px;
.center-text-lable {
color: #666;
width: 86px;
}
.flex-1 {
flex: 1;
text-align: left;
}
}
.top-text {
font-size: 22px;
color: #25bf82;
font-weight: bold;
}
.fill-img {
width: 100%;
margin-bottom: 20px;
}
.dialog-custom-title {
font-size: 20px;
font-weight: bold;
margin-bottom: 20px;
}
</style>