diff --git a/sub-operation-service/components.d.ts b/sub-operation-service/components.d.ts index 32f9580..8dca9c7 100644 --- a/sub-operation-service/components.d.ts +++ b/sub-operation-service/components.d.ts @@ -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'] diff --git a/sub-operation-service/src/apis/common.js b/sub-operation-service/src/apis/common.js new file mode 100644 index 0000000..9f38f3c --- /dev/null +++ b/sub-operation-service/src/apis/common.js @@ -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', + }); +} diff --git a/sub-operation-service/src/assets/images/warehouseLogistics/godown1.png b/sub-operation-service/src/assets/images/warehouseLogistics/godown1.png new file mode 100644 index 0000000..fbc81ca Binary files /dev/null and b/sub-operation-service/src/assets/images/warehouseLogistics/godown1.png differ diff --git a/sub-operation-service/src/assets/images/warehouseLogistics/godown2.png b/sub-operation-service/src/assets/images/warehouseLogistics/godown2.png new file mode 100644 index 0000000..6ea1519 Binary files /dev/null and b/sub-operation-service/src/assets/images/warehouseLogistics/godown2.png differ diff --git a/sub-operation-service/src/assets/images/warehouseLogistics/godown3.png b/sub-operation-service/src/assets/images/warehouseLogistics/godown3.png new file mode 100644 index 0000000..4984551 Binary files /dev/null and b/sub-operation-service/src/assets/images/warehouseLogistics/godown3.png differ diff --git a/sub-operation-service/src/assets/images/warehouseLogistics/map.png b/sub-operation-service/src/assets/images/warehouseLogistics/map.png new file mode 100644 index 0000000..5d503bc Binary files /dev/null and b/sub-operation-service/src/assets/images/warehouseLogistics/map.png differ diff --git a/sub-operation-service/src/components/AreaCascader/index.vue b/sub-operation-service/src/components/AreaCascader/index.vue new file mode 100644 index 0000000..b65c570 --- /dev/null +++ b/sub-operation-service/src/components/AreaCascader/index.vue @@ -0,0 +1,149 @@ + + + + + diff --git a/sub-operation-service/src/components/AreaSelect/index.vue b/sub-operation-service/src/components/AreaSelect/index.vue new file mode 100644 index 0000000..1f68bce --- /dev/null +++ b/sub-operation-service/src/components/AreaSelect/index.vue @@ -0,0 +1,126 @@ + + + + + diff --git a/sub-operation-service/src/views/warehouseLogistics/warehouse/application.vue b/sub-operation-service/src/views/warehouseLogistics/warehouse/application.vue index 6a8e4ef..123db85 100644 --- a/sub-operation-service/src/views/warehouseLogistics/warehouse/application.vue +++ b/sub-operation-service/src/views/warehouseLogistics/warehouse/application.vue @@ -2,77 +2,129 @@
@@ -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(); }); diff --git a/sub-operation-service/src/views/warehouseLogistics/warehouse/detail.vue b/sub-operation-service/src/views/warehouseLogistics/warehouse/detail.vue index c2c30d5..ac3b84a 100644 --- a/sub-operation-service/src/views/warehouseLogistics/warehouse/detail.vue +++ b/sub-operation-service/src/views/warehouseLogistics/warehouse/detail.vue @@ -37,10 +37,10 @@
计价单位:
-
{{ state.data.pricingUnit }}
+
{{ state.data.price }}
- 立即预约 + 立即预约 收藏 分享
@@ -48,8 +48,8 @@
- -
仓储信息
+ +
仓储信息
@@ -59,34 +59,170 @@
{{ state.storageInfor.productType }}
-
仓库面积:
-
{{ state.data.storageArea }}
-
可用面积:
-
{{ state.data.usableArea }}
+
仓库用途:
+
{{ state.storageInfor.warehousePurpose }}
+
付款方式:
+
{{ state.storageInfor.paymentMethod }}
+
+
+
仓库类型:
+
{{ state.storageInfor.warehouseType }}
+
建筑类型:
+
{{ state.storageInfor.buildingType }}
+
+
+
底层层高:
+
{{ state.storageInfor.bottomFloorHeight }}
+
消防等级:
+
{{ state.storageInfor.fireProtectionLevel }}
+ +
+ +
地理位置
+
+ + +
+ +
仓库图片
+
+ + + - - - + + + +
仓储信息
+ + + + + + + + + +
+ + + + + + +
+
+ +
租期与价格
+ + + + +
+ + + + + + + + + + + +
+
+ + + + +
货物详情
+ + + + + + + + + + + + + + + + + + +
diff --git a/sub-operation-service/src/views/warehouseLogistics/warehouse/index.vue b/sub-operation-service/src/views/warehouseLogistics/warehouse/index.vue index b2a18f7..2dcd401 100644 --- a/sub-operation-service/src/views/warehouseLogistics/warehouse/index.vue +++ b/sub-operation-service/src/views/warehouseLogistics/warehouse/index.vue @@ -39,7 +39,7 @@
- +

@@ -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;