仓储物流 - 仓储服务详情,预约弹窗表单开发
This commit is contained in:
parent
b7d7a01ad9
commit
7fdf516d0a
2
sub-operation-service/components.d.ts
vendored
2
sub-operation-service/components.d.ts
vendored
@ -7,6 +7,8 @@ export {}
|
||||
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
AreaCascader: typeof import('./src/components/AreaCascader/index.vue')['default']
|
||||
AreaSelect: typeof import('./src/components/AreaSelect/index.vue')['default']
|
||||
BreadComp: typeof import('./src/components/breadComp.vue')['default']
|
||||
CenterMap: typeof import('./src/components/centerMap.vue')['default']
|
||||
CodeDialog: typeof import('./src/components/code-dialog/index.vue')['default']
|
||||
|
9
sub-operation-service/src/apis/common.js
Normal file
9
sub-operation-service/src/apis/common.js
Normal file
@ -0,0 +1,9 @@
|
||||
import request from '@/utils/axios';
|
||||
|
||||
//云南省所有区域信息
|
||||
export function getRegion(code) {
|
||||
let codeVal = code ? code : '530000';
|
||||
return request('/goods/goodInfoManage/goodArea?areaCode=' + codeVal, {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.0 MiB |
Binary file not shown.
After Width: | Height: | Size: 1.0 MiB |
Binary file not shown.
After Width: | Height: | Size: 928 KiB |
Binary file not shown.
After Width: | Height: | Size: 226 KiB |
149
sub-operation-service/src/components/AreaCascader/index.vue
Normal file
149
sub-operation-service/src/components/AreaCascader/index.vue
Normal file
@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<div class="area-cascader-container" :style="containerStyle">
|
||||
<!-- 一行显示模式 -->
|
||||
<template v-if="!splitRows">
|
||||
<div v-if="label" class="area-cascader-label">{{ label }}</div>
|
||||
<div class="controls">
|
||||
<el-cascader v-model="regionModel" :options="areaOptions" :props="cascaderProps" :placeholder="areaPlaceholder" style="flex: 1" clearable />
|
||||
<span v-if="showSeparator" class="area-cascader-separator">{{ separator }}</span>
|
||||
<el-select v-model="gridModel" :placeholder="gridPlaceholder" style="flex: 1" :disabled="!regionModel" clearable>
|
||||
<el-option v-for="item in gridOptions" :key="item.id" :label="item.gridName" :value="item.id" />
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 两行显示模式 -->
|
||||
<template v-else>
|
||||
<div class="area-item">
|
||||
<div class="area-cascader-label">所属行政区域</div>
|
||||
<el-cascader v-model="regionModel" style="flex: 1" :options="areaOptions" :props="cascaderProps" :placeholder="areaPlaceholder" clearable />
|
||||
</div>
|
||||
<div class="area-item">
|
||||
<div class="area-cascader-label">网格</div>
|
||||
<el-select v-model="gridModel" style="flex: 1" :placeholder="gridPlaceholder" :disabled="!regionModel" clearable>
|
||||
<el-option v-for="item in gridOptions" :key="item.id" :label="item.gridName" :value="item.id" />
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import request from '@/utils/axios';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
|
||||
const props = defineProps({
|
||||
regionCode: { type: String, default: '' },
|
||||
gridId: { type: [String, Number], default: '' },
|
||||
label: { type: String, default: '行政区域-网格:' },
|
||||
areaPlaceholder: { type: String, default: '请选择区域' },
|
||||
gridPlaceholder: { type: String, default: '请选择网格' },
|
||||
width: { type: [Number, String], default: 500 },
|
||||
showSeparator: { type: Boolean, default: false },
|
||||
separator: { type: String, default: '-' },
|
||||
splitRows: { type: Boolean, default: false },
|
||||
});
|
||||
const emit = defineEmits(['update:regionCode', 'update:gridId']);
|
||||
|
||||
const userStore = useUserStore();
|
||||
const areaOptions = ref([]);
|
||||
const gridOptions = ref([]);
|
||||
|
||||
// computed 双向绑定 regionModel & gridModel
|
||||
const regionModel = computed({
|
||||
get() {
|
||||
return props.regionCode;
|
||||
},
|
||||
set(val) {
|
||||
emit('update:regionCode', val);
|
||||
// reset grid when region changes
|
||||
emit('update:gridId', '');
|
||||
gridOptions.value = [];
|
||||
fetchGridList(val);
|
||||
},
|
||||
});
|
||||
const gridModel = computed({
|
||||
get() {
|
||||
return props.gridId;
|
||||
},
|
||||
set(val) {
|
||||
emit('update:gridId', val);
|
||||
},
|
||||
});
|
||||
|
||||
const cascaderProps = computed(() => ({
|
||||
label: 'areaName',
|
||||
value: 'areaCode',
|
||||
children: 'areaChildVOS',
|
||||
emitPath: false,
|
||||
expandTrigger: 'hover',
|
||||
}));
|
||||
|
||||
async function fetchAreaData() {
|
||||
try {
|
||||
const res = await request.get('/system/area/region', { params: { areaCode: '530000' } });
|
||||
areaOptions.value = res.data || [];
|
||||
} catch (err) {
|
||||
console.error('区域数据加载失败', err);
|
||||
}
|
||||
}
|
||||
async function fetchGridList(regionCode) {
|
||||
if (!regionCode) return;
|
||||
try {
|
||||
const res = await request.get('/land-resource/gridManage/page', { params: { regionCode } });
|
||||
gridOptions.value = res.data?.records || [];
|
||||
} catch (err) {
|
||||
console.error('网格数据加载失败', err);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await fetchAreaData();
|
||||
|
||||
// 初始化时如果有区域编码,加载对应网格
|
||||
if (props.regionCode) {
|
||||
await fetchGridList(props.regionCode);
|
||||
}
|
||||
});
|
||||
|
||||
// 样式计算
|
||||
const containerStyle = computed(() => ({
|
||||
width: typeof props.width === 'number' ? `${props.width}px` : props.width,
|
||||
display: 'flex',
|
||||
gap: '18px',
|
||||
flexDirection: props.splitRows ? 'column' : 'row',
|
||||
}));
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.area-cascader-container {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.area-cascader-label {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
text-align: right;
|
||||
line-height: 32px;
|
||||
width: 120px;
|
||||
box-sizing: border-box;
|
||||
padding-right: 12px;
|
||||
}
|
||||
.controls {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex: 1;
|
||||
}
|
||||
.area-item {
|
||||
display: flex;
|
||||
gap: 0;
|
||||
align-items: center;
|
||||
/* background-color: antiquewhite; */
|
||||
}
|
||||
.area-cascader-separator {
|
||||
align-self: center;
|
||||
font-size: 16px;
|
||||
color: #606266;
|
||||
}
|
||||
</style>
|
126
sub-operation-service/src/components/AreaSelect/index.vue
Normal file
126
sub-operation-service/src/components/AreaSelect/index.vue
Normal file
@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<div class="area-select-container" :style="{ width: width + 'px' }">
|
||||
<div v-if="label" class="area-select-label">{{ label }}</div>
|
||||
<el-cascader
|
||||
v-bind="$attrs"
|
||||
v-model="selectedAreaPath"
|
||||
:options="areaOptions"
|
||||
:props="cascaderProps"
|
||||
:placeholder="placeholder"
|
||||
style="flex: 1"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, onMounted, computed } from 'vue';
|
||||
import request from '@/utils/axios';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
|
||||
const props = defineProps({
|
||||
inheritAttrs: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
modelValue: {
|
||||
type: [Array, String],
|
||||
default: () => [],
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: '所属行政区域:',
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请选择行政区域',
|
||||
},
|
||||
width: {
|
||||
type: [Number, String],
|
||||
default: 500,
|
||||
},
|
||||
emitPath: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
const areaOptions = ref([]);
|
||||
|
||||
// 检查计算属性有没有循环依赖用
|
||||
// const selectedAreaPath = props.emitPath ? ref([].concat(props.modelValue)) : ref(props.modelValue);
|
||||
|
||||
const selectedAreaPath = computed({
|
||||
get() {
|
||||
// 初始回显 & 外部变更都走这里
|
||||
if (props.emitPath) {
|
||||
return Array.isArray(props.modelValue) ? props.modelValue : [];
|
||||
} else {
|
||||
return typeof props.modelValue === 'string' ? props.modelValue : '';
|
||||
}
|
||||
},
|
||||
set(val) {
|
||||
// 组件内部选中时走这里
|
||||
if (props.emitPath) {
|
||||
emit('update:modelValue', Array.isArray(val) ? val : []);
|
||||
} else {
|
||||
emit('update:modelValue', typeof val === 'string' ? val : '');
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// 自定义字段映射
|
||||
const cascaderProps = computed(() => ({
|
||||
label: 'areaName',
|
||||
value: 'areaCode',
|
||||
children: 'areaChildVOS',
|
||||
emitPath: props.emitPath,
|
||||
expandTrigger: 'hover',
|
||||
}));
|
||||
|
||||
const fetchAreaData = async () => {
|
||||
try {
|
||||
const res = await request.get('/system/area/region', {
|
||||
params: {
|
||||
areaCode: '530000',
|
||||
},
|
||||
});
|
||||
areaOptions.value = res.data ?? [];
|
||||
// console.log('AreaSelect区域数据', areaOptions.value);
|
||||
} catch (err) {
|
||||
console.error('加载行政区域失败', err);
|
||||
}
|
||||
};
|
||||
// !!!禁止使用外部更新,会造成循环依赖
|
||||
// // 外部更新 => 内部同步
|
||||
// watch(
|
||||
// () => props.modelValue,
|
||||
// (val) => {
|
||||
// selectedAreaPath.value = [...val];
|
||||
// }
|
||||
// );
|
||||
|
||||
onMounted(() => {
|
||||
fetchAreaData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.area-select-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.area-select-label {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
width: 120px;
|
||||
line-height: 32px;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
@ -2,77 +2,129 @@
|
||||
<section>
|
||||
<common>
|
||||
<template #main>
|
||||
<el-card shadow="none" style="border-radius: 14px">
|
||||
<el-card shadow="never" style="border-radius: 14px">
|
||||
<div class="title">
|
||||
<span @click="toBack(-1)">仓储</span>
|
||||
<span class="mx-10"> > </span>
|
||||
<span style="color: rgba(37, 191, 130, 1)">申请仓储</span>
|
||||
<span style="color: rgba(37, 191, 130, 1)">发布需求</span>
|
||||
</div>
|
||||
<div class="max-w-7xl mx-auto p-4">
|
||||
<img src="@/assets/images/warehouseLogistics/img17.png" fit="cover" class="storage-image" />
|
||||
<img src="@/assets/images/warehouseLogistics/img17.png" fit="cover" class="storage-image" />
|
||||
</el-card>
|
||||
<div class="storage-content">
|
||||
<div class="storage-content-title">填写仓储需求表</div>
|
||||
<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="flex items-center mb-8">
|
||||
<div class="flex items-center mr-4">
|
||||
<img :src="state.data.imgPath" fit="cover" class="rounded-lg shadow image-box" />
|
||||
<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>
|
||||
<div class="flex-1">
|
||||
<h3 class="text-xl font-bold mb-2">{{ state.data.name }}</h3>
|
||||
<div class="text-gray-600 mb-2">
|
||||
<span>{{ state.data.parentTitle }}</span>
|
||||
<img :src="getAssetsFile('images/warehouseLogistics/认证.png')" alt="" style="width: 20px; margin: 0 5px" />
|
||||
<img :src="getAssetsFile('images/warehouseLogistics/优先级.png')" alt="" style="width: 20px" />
|
||||
</div>
|
||||
<div class="storage-tags">
|
||||
<el-tag
|
||||
v-for="(tags, indexT) in state.data.tag"
|
||||
:key="indexT"
|
||||
effect="plain"
|
||||
round
|
||||
style="background-color: rgba(37, 191, 130, 0.2); color: #25bf82"
|
||||
>
|
||||
{{ tags }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<p class="mt-2 text-gray-700">联系人:{{ state.data.contactName }}</p>
|
||||
<p class="mt-2 text-gray-700">联系电话:{{ state.data.contactPhone }}</p>
|
||||
<p class="mt-2 text-gray-700">
|
||||
<el-icon><Location /></el-icon> {{ state.data.address }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="text-gray-500 text-sm flex items-center" style="text-align: right">
|
||||
<div>
|
||||
<span style="color: #999999">报价:</span>
|
||||
<span class="ml-2 text-green-500 font-bold">
|
||||
¥{{ state.data.price }}/{{
|
||||
state.data.priceSpec === 1 ? 'm³' : state.data.priceSpec === 2 ? '间' : state.data.priceSpec === 3 ? '㎡' : ''
|
||||
}}/{{ state.data.timeSpec === 1 ? '天' : state.data.timeSpec === 2 ? '月' : state.data.timeSpec === 3 ? '年' : '' }}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<el-button size="large" type="primary" @click="goDei">
|
||||
<el-icon class="el-icon--right"><ChatLineRound /></el-icon>
|
||||
留下信息
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-6">
|
||||
<h3 class="text-lg font-bold mb-4" style="margin-top: 30px">产品详细介绍</h3>
|
||||
<div class="bg-white p-4 rounded-lg shadow-sm">
|
||||
<p style="text-align: left" class="mb-4 text-gray-700" v-html="state.data.content ? state.data.content : '暂无介绍内容'"></p>
|
||||
</div>
|
||||
</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>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" size="large" style="width: 200px; margin-top: 20px" @click="application"> 提交 </el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card shadow="none" style="border-radius: 14px; margin-top: 20px">
|
||||
<div class="max-w-7xl mx-auto p-4" style="padding-top: 0">
|
||||
<img src="@/assets/images/warehouseLogistics/img18.png" fit="cover" class="storage-image" />
|
||||
<div>
|
||||
<el-button style="padding: 10px 40px" size="default" type="primary" @click="application">提交</el-button>
|
||||
<el-button style="padding: 10px 40px" size="default" type="plain">取消</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
</common>
|
||||
</section>
|
||||
@ -83,6 +135,8 @@ 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();
|
||||
@ -92,6 +146,213 @@ const state = reactive({
|
||||
data: {},
|
||||
});
|
||||
|
||||
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);
|
||||
};
|
||||
@ -116,6 +377,7 @@ const queryDetail = () => {
|
||||
onMounted(() => {
|
||||
state.query.id = route.query.id;
|
||||
// queryDetail();
|
||||
getArea();
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@ -132,231 +394,31 @@ $text-dark: #25bf82; // 深色文字
|
||||
$text-regular: #606266; // 常规文字
|
||||
$border-color: #dcdfe6; // 边框颜色
|
||||
|
||||
// 弹窗整体样式
|
||||
:deep(.custom-inquiry-dialog) {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
|
||||
.el-dialog__header {
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid #f2f6fc;
|
||||
.el-dialog__title {
|
||||
font-size: 18px;
|
||||
color: $text-dark;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
padding: 20px 28px;
|
||||
}
|
||||
|
||||
.el-form-item__label {
|
||||
color: $text-regular;
|
||||
font-size: 14px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.info-section {
|
||||
padding: 0px 50px;
|
||||
margin-bottom: 24px;
|
||||
.info-item {
|
||||
margin-bottom: 12px;
|
||||
.label {
|
||||
color: $text-regular;
|
||||
margin-right: 8px;
|
||||
font-size: 20px;
|
||||
}
|
||||
.value {
|
||||
color: $text-dark;
|
||||
font-weight: 500;
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 输入框样式覆盖
|
||||
:deep(.el-input) {
|
||||
.el-input__inner {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
border-radius: 4px;
|
||||
&:focus {
|
||||
border-color: $primary-color;
|
||||
}
|
||||
}
|
||||
.el-input__suffix {
|
||||
color: $text-regular;
|
||||
right: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
// 下拉菜单样式
|
||||
:deep(.custom-select-dropdown) {
|
||||
.el-select-dropdown__item {
|
||||
color: $text-regular;
|
||||
&.selected {
|
||||
color: $primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 按钮组样式
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
.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%);
|
||||
}
|
||||
}
|
||||
}
|
||||
.bac {
|
||||
background: rgba(37, 191, 130, 0.1);
|
||||
border: 1px solid rgba(37, 191, 130, 0.5);
|
||||
border-radius: 8px;
|
||||
padding: 2px 5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.image-box {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
.storage-image {
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.text-gray-500 {
|
||||
height: 300px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: start !important;
|
||||
font-size: 20px !important;
|
||||
color: #000000 !important;
|
||||
padding-top: 30px;
|
||||
}
|
||||
|
||||
.text-gray-600 {
|
||||
font-size: 20px;
|
||||
color: #000000 !important;
|
||||
}
|
||||
|
||||
.flex-1 {
|
||||
width: 40%;
|
||||
height: 300px;
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.max-w-7xl {
|
||||
max-width: 80rem;
|
||||
.storage-content {
|
||||
padding: 20px;
|
||||
margin-top: 20px;
|
||||
border-radius: 14px;
|
||||
background-color: #fff;
|
||||
border-radius: 10px;
|
||||
.storage-image {
|
||||
width: 100%;
|
||||
.storage-content-title {
|
||||
font-size: 26px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.dialog-custom-title {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.mx-auto {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.p-4 {
|
||||
padding: 1rem;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.items-center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mb-4 {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.mr-4 {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.text-green-500 {
|
||||
color: #25bf82;
|
||||
}
|
||||
|
||||
.text-lg {
|
||||
font-size: 1.125rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.font-bold {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.rounded-lg {
|
||||
border-radius: 0.5rem;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.shadow {
|
||||
box-shadow:
|
||||
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
||||
0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.text-xl {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.text-gray-600 {
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
.text-gray-700 {
|
||||
color: #000000;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.text-sm {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.space-x-2 {
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.bg-green-500 {
|
||||
background-color: #4caf50;
|
||||
}
|
||||
|
||||
.py-2 {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.px-4 {
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.mt-4 {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
@ -37,10 +37,10 @@
|
||||
</div>
|
||||
<div class="center-text">
|
||||
<div class="center-text-lable">计价单位:</div>
|
||||
<div class="flex-1">{{ state.data.pricingUnit }}</div>
|
||||
<div class="flex-1">{{ state.data.price }}</div>
|
||||
</div>
|
||||
<div style="margin-top: 20px">
|
||||
<el-button size="large" type="primary" @click="dialogVisible = true">立即预约</el-button>
|
||||
<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>
|
||||
@ -48,8 +48,8 @@
|
||||
</div>
|
||||
|
||||
<div class="warehouse-detail-title">
|
||||
<img :src="getAssetsFile('images/warehouseLogistics/product.png')" alt="" style="width: 30px" />
|
||||
<div class="center-title" style="margin: 0 0 4px 10px">仓储信息</div>
|
||||
<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">
|
||||
@ -59,34 +59,170 @@
|
||||
<div class="flex-1">{{ state.storageInfor.productType }}</div>
|
||||
</div>
|
||||
<div class="center-text">
|
||||
<div class="center-text-lable">仓库面积:</div>
|
||||
<div class="flex-1">{{ state.data.storageArea }}</div>
|
||||
<div class="center-text-lable">可用面积:</div>
|
||||
<div class="flex-1">{{ state.data.usableArea }}</div>
|
||||
<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="1000" center>
|
||||
<!-- <h3>立即预约</h3> -->
|
||||
<img src="@/assets/images/warehouseLogistics/img28.png" fit="cover" class="storage-image" />
|
||||
|
||||
<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 @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="dialogVisible = false"> 提交 </el-button>
|
||||
<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, watch, onMounted } from 'vue';
|
||||
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();
|
||||
@ -113,6 +249,12 @@ const state = reactive({
|
||||
storageInfor: {
|
||||
leaseTerm: '1-3年(可分段报价)', //预计租期
|
||||
productType: '水果(需控温0-5℃,湿度85%-90%)', //货品类型
|
||||
warehousePurpose: '新开仓(需配套分拣服务)', //仓库用途
|
||||
paymentMethod: '押一付三,需开具正规发票', //付款方式
|
||||
warehouseType: '冷库(无霜型优先)', //仓库类型
|
||||
buildingType: '不限(钢混/轻钢均可)', //建筑类型
|
||||
bottomFloorHeight: '25米(称重22吨/㎡)', //底层层高
|
||||
fireProtectionLevel: '丙二类及以上', //消防等级
|
||||
},
|
||||
});
|
||||
const allData = ref([
|
||||
@ -183,6 +325,211 @@ const allData = ref([
|
||||
},
|
||||
]);
|
||||
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);
|
||||
@ -202,18 +549,19 @@ const queryDetail = () => {
|
||||
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);
|
||||
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: 16px;
|
||||
padding: 20px 20px 0 20px;
|
||||
}
|
||||
.title {
|
||||
text-align: left;
|
||||
@ -228,58 +576,6 @@ $text-dark: #25bf82; // 深色文字
|
||||
$text-regular: #606266; // 常规文字
|
||||
$border-color: #dcdfe6; // 边框颜色
|
||||
|
||||
// 弹窗整体样式
|
||||
:deep(.custom-inquiry-dialog) {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
|
||||
.el-dialog__header {
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid #f2f6fc;
|
||||
.el-dialog__title {
|
||||
font-size: 18px;
|
||||
color: $text-dark;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
padding: 20px 28px;
|
||||
}
|
||||
|
||||
.el-form-item__label {
|
||||
color: $text-regular;
|
||||
font-size: 14px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
// 输入框样式覆盖
|
||||
:deep(.el-input) {
|
||||
.el-input__inner {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
border-radius: 4px;
|
||||
&:focus {
|
||||
border-color: $primary-color;
|
||||
}
|
||||
}
|
||||
.el-input__suffix {
|
||||
color: $text-regular;
|
||||
right: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
// 下拉菜单样式
|
||||
:deep(.custom-select-dropdown) {
|
||||
.el-select-dropdown__item {
|
||||
color: $text-regular;
|
||||
&.selected {
|
||||
color: $primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 按钮组样式
|
||||
.dialog-footer {
|
||||
text-align: center;
|
||||
@ -308,7 +604,7 @@ $border-color: #dcdfe6; // 边框颜色
|
||||
font-size: 22px;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
margin: 16px 0;
|
||||
margin: 20px 0 15px 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
@ -350,6 +646,9 @@ $border-color: #dcdfe6; // 边框颜色
|
||||
color: #25bf82;
|
||||
}
|
||||
}
|
||||
.page-title {
|
||||
margin: 0 0 4px 10px;
|
||||
}
|
||||
.warehouse-content-align {
|
||||
text-align: left;
|
||||
}
|
||||
@ -371,4 +670,14 @@ $border-color: #dcdfe6; // 边框颜色
|
||||
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>
|
||||
|
@ -39,7 +39,7 @@
|
||||
<div v-else style="padding-bottom: 20px">
|
||||
<div v-for="(item, index) in state.data" :key="index" class="warehouse-content-box">
|
||||
<div class="warehouse-content-box-left">
|
||||
<img :src="item.imageUrl" fit="cover" />
|
||||
<img :src="item.imageUrl" fit="cover" draggable="false" />
|
||||
</div>
|
||||
<div class="warehouse-content-box-center">
|
||||
<p class="center-title">
|
||||
@ -364,116 +364,6 @@ const priceConfirm = () => {
|
||||
.active {
|
||||
color: rgba(37, 191, 130, 1);
|
||||
}
|
||||
.storage-card {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20px;
|
||||
border: 0;
|
||||
border-radius: 24px;
|
||||
}
|
||||
.storage-content {
|
||||
@include flex-column;
|
||||
|
||||
gap: 16px;
|
||||
&-top {
|
||||
@include flex-row;
|
||||
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.storage-price-left {
|
||||
text-align: left;
|
||||
}
|
||||
.storage-image {
|
||||
margin-right: 16px;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border-radius: 8px;
|
||||
object-fit: cover;
|
||||
cursor: pointer;
|
||||
}
|
||||
.storage-image1 {
|
||||
margin-right: 0;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 0;
|
||||
object-fit: cover;
|
||||
}
|
||||
.storage-info {
|
||||
padding-right: 50px;
|
||||
flex: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
.storage-title,
|
||||
.storage-desc,
|
||||
.storage-tags,
|
||||
.storage-location {
|
||||
overflow: hidden;
|
||||
margin: 10px 0;
|
||||
width: 100%;
|
||||
}
|
||||
.storage-title {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #000000;
|
||||
@include ellipsis;
|
||||
}
|
||||
.storage-desc {
|
||||
font-size: 16px;
|
||||
color: #999999;
|
||||
@include ellipsis;
|
||||
i {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
.storage-tags {
|
||||
span {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
.storage-location {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
color: #000000;
|
||||
}
|
||||
.storage-price {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&-left {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
.price-label {
|
||||
margin-right: 10px;
|
||||
font-size: 16px;
|
||||
color: #999999;
|
||||
}
|
||||
.price-amount {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #25bf82;
|
||||
}
|
||||
.contact-btn {
|
||||
width: 152px;
|
||||
height: 48px;
|
||||
font-size: 20px;
|
||||
border-radius: 8px;
|
||||
background: #25bf82 !important;
|
||||
:deep(.el-icon) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
.rank-badge {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 20px;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.warehouse-content-box {
|
||||
min-height: 150px;
|
||||
|
Loading…
x
Reference in New Issue
Block a user