فهرست منبع

feat(router): 添加租房列表页面- 在 route.ts 中添加了租房列表页面的路由配置
- 新增 zflb.vue 页面组件,实现租房列表功能
- 页面包含标签页导航、筛选条件、列表展示、分页等功能
-支持公租房、标准化厂房、创新创业基地三种类型的数据展示
- 实现了数据过滤、排序、分页等交互逻辑

nahida 10 ماه پیش
والد
کامیت
f93897980d
2فایلهای تغییر یافته به همراه693 افزوده شده و 1 حذف شده
  1. 17 1
      src/router/route.ts
  2. 676 0
      src/views/zf/zflb.vue

+ 17 - 1
src/router/route.ts

@@ -35,7 +35,23 @@ export const buildTree = (routes: RouterType[]): RouterType[] => {
 }
 
 export const routeList:RouterType[] = [
-
+  {
+    path: 'home',
+    name: '首页',
+    icon: 'Location',
+  },
+  {
+    path: 'zf/zflb',
+    name: '租房列表',
+    icon: 'Location',
+    addr: 'zf/zflb',
+  },
+  {
+    path: 'zf/fwxq',
+    name: '房屋详情',
+    icon: 'Location',
+    addr: 'zf/fwxq',
+  },
   {
     path: 'ar',
     name: 'AR',

+ 676 - 0
src/views/zf/zflb.vue

@@ -0,0 +1,676 @@
+<template>
+  <el-container class="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
+    <el-main class="h-full p-0">
+      <!-- 主要内容区域 -->
+      <div class="py-12 px-8">
+        <div class="w-full">
+          <!-- 标签页导航 -->
+          <el-tabs v-model="activeTab" class="mb-8" @tab-click="handleTabClick">
+            <el-tab-pane label="公租房" name="housing">
+              <template #label>
+                <div class="flex items-center">
+                  <el-icon class="mr-2"><Building /></el-icon>
+                  公租房
+                </div>
+              </template>
+            </el-tab-pane>
+            <el-tab-pane label="标准化厂房" name="factory">
+              <template #label>
+                <div class="flex items-center">
+                  <el-icon class="mr-2"><Factory /></el-icon>
+                  标准化厂房
+                </div>
+              </template>
+            </el-tab-pane>
+            <el-tab-pane label="创新创业基地" name="innovation">
+              <template #label>
+                <div class="flex items-center">
+                  <el-icon class="mr-2"><Lightbulb /></el-icon>
+                  创新创业基地
+                </div>
+              </template>
+            </el-tab-pane>
+          </el-tabs>
+
+          <!-- 筛选条件区域 -->
+          <el-card class="mb-8 shadow-lg rounded-2xl border-0">
+            <div class="p-4">
+              <h3 class="text-lg font-semibold mb-4 text-gray-800">筛选条件</h3>
+              <el-row :gutter="24">
+                <el-col :xs="24" :sm="12" :md="4">
+                  <div class="mb-4">
+                    <label class="block text-sm font-medium text-gray-700 mb-2"
+                      >租金范围 (元/月)</label
+                    >
+                    <el-select
+                      v-model="filters.priceRange"
+                      placeholder="选择租金范围"
+                      class="w-full"
+                    >
+                      <el-option label="不限" value=""></el-option>
+                      <el-option label="1000以下" value="0-1000"></el-option>
+                      <el-option label="1000-3000" value="1000-3000"></el-option>
+                      <el-option label="3000-5000" value="3000-5000"></el-option>
+                      <el-option label="5000以上" value="5000+"></el-option>
+                    </el-select>
+                  </div>
+                </el-col>
+                <el-col :xs="24" :sm="12" :md="4">
+                  <div class="mb-4">
+                    <label class="block text-sm font-medium text-gray-700 mb-2"
+                      >面积范围 (㎡)</label
+                    >
+                    <el-select
+                      v-model="filters.areaRange"
+                      placeholder="选择面积范围"
+                      class="w-full"
+                    >
+                      <el-option label="不限" value=""></el-option>
+                      <el-option label="50以下" value="0-50"></el-option>
+                      <el-option label="50-100" value="50-100"></el-option>
+                      <el-option label="100-200" value="100-200"></el-option>
+                      <el-option label="200以上" value="200+"></el-option>
+                    </el-select>
+                  </div>
+                </el-col>
+                <el-col :xs="24" :sm="12" :md="4">
+                  <div class="mb-4">
+                    <label class="block text-sm font-medium text-gray-700 mb-2">区域</label>
+                    <el-select v-model="filters.district" placeholder="选择区域" class="w-full">
+                      <el-option label="不限" value=""></el-option>
+                      <el-option label="高新区" value="高新区"></el-option>
+                      <el-option label="经开区" value="经开区"></el-option>
+                      <el-option label="工业园区" value="工业园区"></el-option>
+                      <el-option label="科技园区" value="科技园区"></el-option>
+                    </el-select>
+                  </div>
+                </el-col>
+                <el-col :xs="24" :sm="12" :md="4">
+                  <div class="mb-4">
+                    <label class="block text-sm font-medium text-gray-700 mb-2">楼栋</label>
+                    <el-select v-model="filters.building" placeholder="选择楼栋" class="w-full">
+                      <el-option label="不限" value=""></el-option>
+                      <el-option
+                        v-for="building in availableBuildings"
+                        :key="building"
+                        :label="building"
+                        :value="building"
+                      ></el-option>
+                    </el-select>
+                  </div>
+                </el-col>
+                <el-col :xs="24" :sm="12" :md="4" v-if="activeTab !== 'factory'">
+                  <div class="mb-4">
+                    <label class="block text-sm font-medium text-gray-700 mb-2">楼层</label>
+                    <el-select v-model="filters.floor" placeholder="选择楼层" class="w-full">
+                      <el-option label="不限" value=""></el-option>
+                      <el-option label="1楼" value="1楼"></el-option>
+                      <el-option label="2楼" value="2楼"></el-option>
+                      <el-option label="3楼" value="3楼"></el-option>
+                      <el-option label="4楼" value="4楼"></el-option>
+                      <el-option label="5楼及以上" value="5楼+"></el-option>
+                    </el-select>
+                  </div>
+                </el-col>
+                <el-col :xs="24" :sm="12" :md="4">
+                  <div class="mb-4 flex items-end">
+                    <el-button type="primary" @click="applyFilters" class="mr-2">
+                      <el-icon class="mr-1"><Search /></el-icon>
+                      搜索
+                    </el-button>
+                    <el-button @click="resetFilters">
+                      <el-icon class="mr-1"><RotateCcw /></el-icon>
+                      重置
+                    </el-button>
+                  </div>
+                </el-col>
+              </el-row>
+            </div>
+          </el-card>
+
+          <!-- 列表展示区域 -->
+          <div class="mb-6 flex justify-between items-center">
+            <div class="text-gray-600">
+              共找到
+              <span class="font-semibold text-blue-600">{{ filteredList.length }}</span> 个结果
+            </div>
+            <el-select v-model="sortBy" placeholder="排序方式" class="w-48">
+              <el-option label="默认排序" value="default"></el-option>
+              <el-option label="租金从低到高" value="price-asc"></el-option>
+              <el-option label="租金从高到低" value="price-desc"></el-option>
+              <el-option label="面积从小到大" value="area-asc"></el-option>
+              <el-option label="面积从大到小" value="area-desc"></el-option>
+            </el-select>
+          </div>
+
+          <!-- 列表内容 -->
+          <el-row :gutter="24">
+            <el-col
+              :xs="24"
+              :sm="12"
+              :lg="8"
+              :xl="6"
+              v-for="item in filteredList"
+              :key="item.id"
+              class="mb-6"
+            >
+              <el-card
+                class="h-full shadow-xl hover:shadow-2xl transition-all duration-300 rounded-2xl border-0 overflow-hidden group cursor-pointer"
+              >
+                <div class="p-6">
+                  <div class="flex justify-between items-start mb-4">
+                    <h3 class="text-xl font-bold text-gray-800">{{ item.buildingNumber }}</h3>
+                    <div class="text-right">
+                      <div class="text-2xl font-bold text-blue-600">{{ item.priceRange }}</div>
+                      <div class="text-sm text-gray-500">元/月</div>
+                    </div>
+                  </div>
+
+                  <div class="space-y-3 mb-6">
+                    <div class="flex items-center text-gray-600">
+                      <el-icon class="mr-2 text-blue-500"><MapPin /></el-icon>
+                      <span class="text-sm">{{ item.address }}</span>
+                    </div>
+                    <div class="flex items-center text-gray-600">
+                      <el-icon class="mr-2 text-green-500"><Maximize /></el-icon>
+                      <span class="text-sm">占地面积:{{ item.area }}㎡</span>
+                    </div>
+                    <div class="flex items-center text-gray-600" v-if="item.floor">
+                      <el-icon class="mr-2 text-purple-500"><Building2 /></el-icon>
+                      <span class="text-sm">楼层:{{ item.floor }}</span>
+                    </div>
+                    <div class="flex items-center text-gray-600" v-if="item.facilities">
+                      <el-icon class="mr-2 text-orange-500"><Settings /></el-icon>
+                      <span class="text-sm">配套:{{ item.facilities }}</span>
+                    </div>
+                    <!-- 状态标签移至下方 -->
+                    <div class="flex items-center pt-2">
+                      <el-tag :type="item.status === '可租' ? 'success' : 'warning'" size="small">
+                        {{ item.status }}
+                      </el-tag>
+                    </div>
+                  </div>
+
+                  <div class="flex gap-2">
+                    <el-button type="primary" size="small" class="w-full">
+                      <el-icon class="mr-1"><Eye /></el-icon>
+                      查看详情
+                    </el-button>
+                  </div>
+                </div>
+              </el-card>
+            </el-col>
+          </el-row>
+
+          <!-- 空状态 -->
+          <div v-if="filteredList.length === 0" class="text-center py-16">
+            <el-icon :size="64" class="text-gray-400 mb-4"><Search /></el-icon>
+            <h3 class="text-xl font-semibold text-gray-600 mb-2">暂无符合条件的结果</h3>
+            <p class="text-gray-500">请尝试调整筛选条件</p>
+          </div>
+
+          <!-- 分页 -->
+          <div class="flex justify-center mt-12" v-if="filteredList.length > 0">
+            <el-pagination
+              v-model:current-page="currentPage"
+              :page-size="pageSize"
+              :total="filteredList.length"
+              layout="prev, pager, next, jumper"
+              class="justify-center"
+            />
+          </div>
+        </div>
+      </div>
+    </el-main>
+  </el-container>
+</template>
+
+<script setup lang="ts">
+import { computed, onMounted, ref } from 'vue'
+import {
+  ElButton,
+  ElCard,
+  ElCol,
+  ElContainer,
+  ElIcon,
+  ElMain,
+  ElOption,
+  ElPagination,
+  ElRow,
+  ElSelect,
+  ElTabPane,
+  ElTabs,
+  ElTag,
+} from 'element-plus'
+import {
+  Building,
+  Building2,
+  Eye,
+  Factory,
+  Lightbulb,
+  MapPin,
+  Maximize,
+  RotateCcw,
+  Search,
+  Settings,
+} from 'lucide-vue-next'
+
+// 响应式数据
+const activeTab = ref('housing')
+const currentPage = ref(1)
+const pageSize = ref(12)
+const sortBy = ref('default')
+
+// 筛选条件
+const filters = ref({
+  priceRange: '',
+  areaRange: '',
+  district: '',
+  building: '',
+  floor: '',
+})
+
+// 模拟数据
+const housingData = ref([
+  {
+    id: 1,
+    buildingNumber: 'A栋-101',
+    priceRange: '1200-1500',
+    address: '高新区科技大道123号',
+    area: 85,
+    status: '可租',
+    floor: '1楼',
+    facilities: '家具齐全',
+    building: 'A栋',
+  },
+  {
+    id: 2,
+    buildingNumber: 'B栋-205',
+    priceRange: '1800-2200',
+    address: '经开区创新路456号',
+    area: 120,
+    status: '可租',
+    floor: '2楼',
+    facilities: '精装修',
+    building: 'B栋',
+  },
+  {
+    id: 3,
+    buildingNumber: 'C栋-308',
+    priceRange: '2500-3000',
+    address: '工业园区发展大道789号',
+    area: 150,
+    status: '已租',
+    floor: '3楼',
+    facilities: '豪华装修',
+    building: 'C栋',
+  },
+  {
+    id: 4,
+    buildingNumber: 'D栋-102',
+    priceRange: '900-1200',
+    address: '科技园区智慧路321号',
+    area: 65,
+    status: '可租',
+    floor: '1楼',
+    facilities: '基础装修',
+    building: 'D栋',
+  },
+  {
+    id: 5,
+    buildingNumber: 'E栋-401',
+    priceRange: '3200-3800',
+    address: '高新区未来街654号',
+    area: 180,
+    status: '可租',
+    floor: '4楼',
+    facilities: '智能家居',
+    building: 'E栋',
+  },
+  {
+    id: 6,
+    buildingNumber: 'F栋-203',
+    priceRange: '1600-2000',
+    address: '经开区产业路987号',
+    area: 95,
+    status: '可租',
+    floor: '2楼',
+    facilities: '简装修',
+    building: 'F栋',
+  },
+  {
+    id: 7,
+    buildingNumber: 'A栋-201',
+    priceRange: '1400-1700',
+    address: '高新区科技大道123号',
+    area: 90,
+    status: '可租',
+    floor: '2楼',
+    facilities: '精装修',
+    building: 'A栋',
+  },
+  {
+    id: 8,
+    buildingNumber: 'B栋-301',
+    priceRange: '2000-2400',
+    address: '经开区创新路456号',
+    area: 110,
+    status: '可租',
+    floor: '3楼',
+    facilities: '豪华装修',
+    building: 'B栋',
+  },
+])
+
+const factoryData = ref([
+  {
+    id: 1,
+    buildingNumber: '1号厂房',
+    priceRange: '8000-12000',
+    address: '工业园区制造大道100号',
+    area: 2000,
+    status: '可租',
+    facilities: '行车、配电',
+    building: '1号厂房',
+  },
+  {
+    id: 2,
+    buildingNumber: '2号厂房',
+    priceRange: '15000-20000',
+    address: '经开区工业路200号',
+    area: 3500,
+    status: '可租',
+    facilities: '净化车间',
+    building: '2号厂房',
+  },
+  {
+    id: 3,
+    buildingNumber: '3号厂房',
+    priceRange: '25000-30000',
+    address: '高新区生产基地300号',
+    area: 5000,
+    status: '已租',
+    facilities: '自动化设备',
+    building: '3号厂房',
+  },
+  {
+    id: 4,
+    buildingNumber: '4号厂房',
+    priceRange: '6000-8000',
+    address: '科技园区制造街400号',
+    area: 1500,
+    status: '可租',
+    facilities: '基础设施',
+    building: '4号厂房',
+  },
+  {
+    id: 5,
+    buildingNumber: '5号厂房',
+    priceRange: '18000-25000',
+    address: '工业园区智造路500号',
+    area: 4200,
+    status: '可租',
+    facilities: '环保设备',
+    building: '5号厂房',
+  },
+  {
+    id: 6,
+    buildingNumber: '6号厂房',
+    priceRange: '10000-15000',
+    address: '经开区产业大道600号',
+    area: 2800,
+    status: '可租',
+    facilities: '标准厂房',
+    building: '6号厂房',
+  },
+])
+
+const innovationData = ref([
+  {
+    id: 1,
+    buildingNumber: '创新楼A座-501',
+    priceRange: '3000-4000',
+    address: '科技园区创业大道50号',
+    area: 200,
+    status: '可租',
+    floor: '5楼',
+    facilities: '会议室、茶水间',
+    building: '创新楼A座',
+  },
+  {
+    id: 2,
+    buildingNumber: '孵化楼B座-302',
+    priceRange: '2500-3500',
+    address: '高新区孵化路80号',
+    area: 150,
+    status: '可租',
+    floor: '3楼',
+    facilities: '开放办公区',
+    building: '孵化楼B座',
+  },
+  {
+    id: 3,
+    buildingNumber: '科技楼C座-801',
+    priceRange: '5000-6500',
+    address: '经开区科技街120号',
+    area: 300,
+    status: '已租',
+    floor: '8楼',
+    facilities: '实验室、路演厅',
+    building: '科技楼C座',
+  },
+  {
+    id: 4,
+    buildingNumber: '创业楼D座-201',
+    priceRange: '2000-2800',
+    address: '工业园区创新路90号',
+    area: 120,
+    status: '可租',
+    floor: '2楼',
+    facilities: '基础办公',
+    building: '创业楼D座',
+  },
+  {
+    id: 5,
+    buildingNumber: '智慧楼E座-601',
+    priceRange: '4500-5800',
+    address: '科技园区智慧大道160号',
+    area: 250,
+    status: '可租',
+    floor: '6楼',
+    facilities: '智能办公系统',
+    building: '智慧楼E座',
+  },
+  {
+    id: 6,
+    buildingNumber: '未来楼F座-401',
+    priceRange: '3500-4500',
+    address: '高新区未来路200号',
+    area: 180,
+    status: '可租',
+    floor: '4楼',
+    facilities: '共享空间',
+    building: '未来楼F座',
+  },
+])
+
+// 计算属性
+const currentData = computed(() => {
+  switch (activeTab.value) {
+    case 'housing':
+      return housingData.value
+    case 'factory':
+      return factoryData.value
+    case 'innovation':
+      return innovationData.value
+    default:
+      return []
+  }
+})
+
+const availableBuildings = computed(() => {
+  const buildings = [...new Set(currentData.value.map((item) => item.building))]
+  return buildings.sort()
+})
+
+const filteredList = computed(() => {
+  let result = [...currentData.value]
+
+  // 实际筛选逻辑
+  if (filters.value.priceRange) {
+    result = result.filter((item) => {
+      const priceRange = item.priceRange.split('-').map((price) => {
+        const num = parseFloat(price.replace(/,/g, '').replace('+', ''))
+        return isNaN(num) ? Infinity : num
+      })
+      const filterRange = filters.value.priceRange.split('-').map((price) => {
+        const num = parseFloat(price.replace(/,/g, '').replace('+', ''))
+        return isNaN(num) ? Infinity : num
+      })
+
+      if (filterRange.length === 1) {
+        // 处理 "5000+" 这种情况
+        return priceRange[0] >= filterRange[0]
+      } else {
+        // 处理 "1000-3000" 这种情况
+        return (
+          (priceRange[0] >= filterRange[0] && priceRange[0] <= filterRange[1]) ||
+          (priceRange[1] >= filterRange[0] && priceRange[1] <= filterRange[1])
+        )
+      }
+    })
+  }
+
+  if (filters.value.areaRange) {
+    result = result.filter((item) => {
+      const areaRange = item.area
+      const [min, max] = filters.value.areaRange.split('-').map(Number)
+
+      if (max) {
+        return areaRange >= min && areaRange <= max
+      } else {
+        return areaRange >= min
+      }
+    })
+  }
+
+  if (filters.value.district) {
+    result = result.filter((item) => item.address.includes(filters.value.district))
+  }
+
+  if (filters.value.building) {
+    result = result.filter((item) => item.building === filters.value.building)
+  }
+
+  if (filters.value.floor && activeTab.value !== 'factory') {
+    result = result.filter((item) => item.floor === filters.value.floor)
+  }
+
+  // 排序逻辑
+  switch (sortBy.value) {
+    case 'price-asc':
+      result.sort((a, b) => {
+        const aPrice = parseFloat(a.priceRange.split('-')[0].replace(/,/g, ''))
+        const bPrice = parseFloat(b.priceRange.split('-')[0].replace(/,/g, ''))
+        return aPrice - bPrice
+      })
+      break
+    case 'price-desc':
+      result.sort((a, b) => {
+        const aPrice = parseFloat(a.priceRange.split('-')[0].replace(/,/g, ''))
+        const bPrice = parseFloat(b.priceRange.split('-')[0].replace(/,/g, ''))
+        return bPrice - aPrice
+      })
+      break
+    case 'area-asc':
+      result.sort((a, b) => a.area - b.area)
+      break
+    case 'area-desc':
+      result.sort((a, b) => b.area - a.area)
+      break
+    default:
+      // 默认排序可以按ID
+      result.sort((a, b) => a.id - b.id)
+  }
+
+  return result
+})
+
+// 方法
+const handleTabClick = (tab: any) => {
+  currentPage.value = 1
+  resetFilters()
+}
+
+const applyFilters = () => {
+  currentPage.value = 1
+  console.log('应用筛选条件:', filters.value)
+}
+
+const resetFilters = () => {
+  filters.value = {
+    priceRange: '',
+    areaRange: '',
+    district: '',
+    building: '',
+    floor: '',
+  }
+}
+
+const getIconByType = (type: string) => {
+  switch (type) {
+    case 'housing':
+      return Building
+    case 'factory':
+      return Factory
+    case 'innovation':
+      return Lightbulb
+    default:
+      return Building
+  }
+}
+
+onMounted(() => {
+  // 组件挂载后的初始化逻辑
+})
+</script>
+
+<style scoped>
+.el-card {
+  border: none;
+}
+
+.el-tabs__item {
+  font-weight: 600;
+}
+
+.el-tabs__active-bar {
+  background-color: #3b82f6;
+}
+
+.el-tabs__item.is-active {
+  color: #3b82f6;
+}
+
+.el-button {
+  font-weight: 600;
+}
+
+/* 渐变背景动画 */
+@keyframes gradient {
+  0% {
+    background-position: 0% 50%;
+  }
+  50% {
+    background-position: 100% 50%;
+  }
+  100% {
+    background-position: 0% 50%;
+  }
+}
+
+.bg-gradient-to-r {
+  background-size: 200% 200%;
+  animation: gradient 15s ease infinite;
+}
+</style>