Quellcode durchsuchen

feat(home): 增加 AR 看房功能

- 在首页添加 AR 看房、厂房参观和创新空间体验功能- 实现 AR 对话框,展示户型数据并启动 AR 体验
- 优化首页样式,增加更多视觉元素
nahida vor 10 Monaten
Ursprung
Commit
cb8c141c77
1 geänderte Dateien mit 511 neuen und 31 gelöschten Zeilen
  1. 511 31
      src/views/home.vue

+ 511 - 31
src/views/home.vue

@@ -8,7 +8,6 @@
             <h2 class="text-4xl font-extrabold text-gray-900 mb-4">核心业务模块</h2>
             <p class="text-xl text-gray-600">为您提供全方位的园区服务解决方案</p>
           </div>
-
           <el-row :gutter="32" class="justify-center">
             <!-- 公租房模块 -->
             <el-col :xs="24" :sm="12" :md="8" class="mb-8">
@@ -33,27 +32,58 @@
                     </p>
                     <div class="space-y-3 mb-6">
                       <div class="flex items-center text-sm text-gray-600">
-                        <el-icon class="mr-2 text-green-500"><Check /></el-icon>
+                        <el-icon class="mr-2 text-green-500">
+                          <Check />
+                        </el-icon>
                         在线申请与签订
                       </div>
                       <div class="flex items-center text-sm text-gray-600">
-                        <el-icon class="mr-2 text-green-500"><Check /></el-icon>
+                        <el-icon class="mr-2 text-green-500">
+                          <Check />
+                        </el-icon>
                         AR全景看房
                       </div>
                       <div class="flex items-center text-sm text-gray-600">
-                        <el-icon class="mr-2 text-green-500"><Check /></el-icon>
+                        <el-icon class="mr-2 text-green-500">
+                          <Check />
+                        </el-icon>
                         24/7 维护服务
                       </div>
                     </div>
-                    <el-button type="primary" round class="w-full" @click="toZflbLink('housing')">
-                      <el-icon class="mr-1"><ArrowRight /></el-icon>
-                      立即申请
-                    </el-button>
+                    <div class="space-y-3">
+                      <div>
+                        <el-button
+                          type="primary"
+                          round
+                          class="w-full"
+                          @click="toZflbLink('housing')"
+                        >
+                          <el-icon class="mr-1">
+                            <ArrowRight />
+                          </el-icon>
+                          立即申请
+                        </el-button>
+                      </div>
+                      <div>
+                        <el-button
+                          type="info"
+                          round
+                          class="w-full bg-gradient-to-r from-cyan-500 to-blue-500 border-0 text-white hover:from-cyan-600 hover:to-blue-600"
+                          @click="openARDialog('housing')"
+                          :disabled="housingTypes.length === 0"
+                          :loading="loadingStates.housing"
+                        >
+                          <el-icon class="mr-1" v-if="!loadingStates.housing">
+                            <Camera />
+                          </el-icon>
+                          {{ loadingStates.housing ? '加载中...' : 'AR看房体验' }}
+                        </el-button>
+                      </div>
+                    </div>
                   </div>
                 </div>
               </el-card>
             </el-col>
-
             <!-- 标准化厂房模块 -->
             <el-col :xs="24" :sm="12" :md="8" class="mb-8">
               <el-card
@@ -77,27 +107,58 @@
                     </p>
                     <div class="space-y-3 mb-6">
                       <div class="flex items-center text-sm text-gray-600">
-                        <el-icon class="mr-2 text-green-500"><Check /></el-icon>
+                        <el-icon class="mr-2 text-green-500">
+                          <Check />
+                        </el-icon>
                         标准化设计建造
                       </div>
                       <div class="flex items-center text-sm text-gray-600">
-                        <el-icon class="mr-2 text-green-500"><Check /></el-icon>
+                        <el-icon class="mr-2 text-green-500">
+                          <Check />
+                        </el-icon>
                         完善配套设施
                       </div>
                       <div class="flex items-center text-sm text-gray-600">
-                        <el-icon class="mr-2 text-green-500"><Check /></el-icon>
+                        <el-icon class="mr-2 text-green-500">
+                          <Check />
+                        </el-icon>
                         灵活租赁方案
                       </div>
                     </div>
-                    <el-button type="success" round class="w-full" @click="toZflbLink('factory')">
-                      <el-icon class="mr-1"><ArrowRight /></el-icon>
-                      查看厂房
-                    </el-button>
+                    <div class="space-y-3">
+                      <div>
+                        <el-button
+                          type="success"
+                          round
+                          class="w-full"
+                          @click="toZflbLink('factory')"
+                        >
+                          <el-icon class="mr-1">
+                            <ArrowRight />
+                          </el-icon>
+                          查看厂房
+                        </el-button>
+                      </div>
+                      <div>
+                        <el-button
+                          type="info"
+                          round
+                          class="w-full bg-gradient-to-r from-emerald-500 to-green-500 border-0 text-white hover:from-emerald-600 hover:to-green-600"
+                          @click="openARDialog('factory')"
+                          :disabled="factoryTypes.length === 0"
+                          :loading="loadingStates.factory"
+                        >
+                          <el-icon class="mr-1" v-if="!loadingStates.factory">
+                            <Camera />
+                          </el-icon>
+                          {{ loadingStates.factory ? '加载中...' : 'AR厂房参观' }}
+                        </el-button>
+                      </div>
+                    </div>
                   </div>
                 </div>
               </el-card>
             </el-col>
-
             <!-- 创新创业基地模块 -->
             <el-col :xs="24" :sm="12" :md="8" class="mb-8">
               <el-card
@@ -121,27 +182,60 @@
                     </p>
                     <div class="space-y-3 mb-6">
                       <div class="flex items-center text-sm text-gray-600">
-                        <el-icon class="mr-2 text-green-500"><Check /></el-icon>
+                        <el-icon class="mr-2 text-green-500">
+                          <Check />
+                        </el-icon>
                         创业孵化服务
                       </div>
                       <div class="flex items-center text-sm text-gray-600">
-                        <el-icon class="mr-2 text-green-500"><Check /></el-icon>
+                        <el-icon class="mr-2 text-green-500">
+                          <Check />
+                        </el-icon>
                         政策扶持指导
                       </div>
                       <div class="flex items-center text-sm text-gray-600">
-                        <el-icon class="mr-2 text-green-500"><Check /></el-icon>
+                        <el-icon class="mr-2 text-green-500">
+                          <Check />
+                        </el-icon>
                         投资对接平台
                       </div>
                     </div>
-                    <el-button
-                      type="warning"
-                      round
-                      class="w-full"
-                      @click="toZflbLink('innovation')"
-                    >
-                      <el-icon class="mr-1"><ArrowRight /></el-icon>
-                      加入孵化
-                    </el-button>
+                    <div class="space-y-3">
+                      <div>
+                        <el-button
+                          type="warning"
+                          round
+                          class="w-full"
+                          @click="toZflbLink('innovation')"
+                        >
+                          <el-icon class="mr-1">
+                            <ArrowRight />
+                          </el-icon>
+                          加入孵化
+                        </el-button>
+                      </div>
+                      <div>
+                        <el-button
+                          v-if="businessModules.innovation.arEnabled && innovationTypes.length > 0"
+                          type="info"
+                          round
+                          class="w-full bg-gradient-to-r from-purple-500 to-pink-500 border-0 text-white hover:from-purple-600 hover:to-pink-600"
+                          @click="openARDialog('innovation')"
+                          :loading="loadingStates.innovation"
+                        >
+                          <el-icon class="mr-1" v-if="!loadingStates.innovation">
+                            <Camera />
+                          </el-icon>
+                          {{ loadingStates.innovation ? '加载中...' : 'AR空间体验' }}
+                        </el-button>
+                        <el-button v-else type="info" round class="w-full" disabled>
+                          <el-icon class="mr-1">
+                            <Clock />
+                          </el-icon>
+                          {{ innovationTypes.length === 0 ? '暂无可用户型' : 'AR功能即将上线' }}
+                        </el-button>
+                      </div>
+                    </div>
                   </div>
                 </div>
               </el-card>
@@ -150,16 +244,329 @@
         </div>
       </div>
     </el-main>
+    <!-- AR看房对话框 -->
+    <el-dialog
+      v-model="arDialogVisible"
+      :title="arDialogTitle"
+      width="600px"
+      align-center
+      class="ar-dialog"
+    >
+      <div class="text-center">
+        <div class="mb-6">
+          <el-icon :size="80" class="text-blue-500 mb-4">
+            <Camera />
+          </el-icon>
+          <h3 class="text-2xl font-bold text-gray-800 mb-2">选择户型进行AR体验</h3>
+          <p class="text-gray-600">沉浸式全景体验,让您身临其境</p>
+        </div>
+
+        <!-- 加载状态 -->
+        <div v-if="loadingStates[currentARType]" class="py-8">
+          <el-icon class="animate-spin text-4xl text-blue-500 mb-4">
+            <Loader />
+          </el-icon>
+          <p class="text-gray-600">正在加载户型数据...</p>
+        </div>
+
+        <!-- 无数据状态 -->
+        <div v-else-if="getCurrentTypeData().length === 0" class="py-8">
+          <el-icon class="text-4xl text-gray-400 mb-4">
+            <House />
+          </el-icon>
+          <p class="text-gray-600">暂无可用的户型数据</p>
+        </div>
+
+        <!-- 公租房户型选择 -->
+        <div v-else-if="currentARType === 'housing'" class="space-y-4">
+          <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
+            <el-card
+              v-for="type in housingTypes"
+              :key="type.id"
+              class="cursor-pointer hover:shadow-lg transition-all duration-300 border-2 hover:border-blue-400"
+              @click="startARExperience('housing', type.id)"
+            >
+              <div class="text-center p-4">
+                <el-icon :size="48" class="text-blue-500 mb-3">
+                  <component :is="getHouseTypeIcon(type)" />
+                </el-icon>
+                <h4 class="text-lg font-semibold mb-2">{{ type.accountNumber || '未命名户型' }}</h4>
+                <p class="text-sm text-gray-600 mb-2">面积:{{ type.area || '待定' }}</p>
+                <p class="text-xs text-gray-500 mb-3">地址:{{ type.address || '待定' }}</p>
+                <div class="flex items-center justify-center text-sm text-gray-500">
+                  <el-icon class="mr-1">
+                    <Eye />
+                  </el-icon>
+                  <span>360°全景体验</span>
+                </div>
+              </div>
+            </el-card>
+          </div>
+        </div>
+
+        <!-- 厂房户型选择 -->
+        <div v-else-if="currentARType === 'factory'" class="space-y-4">
+          <el-card
+            v-for="type in factoryTypes"
+            :key="type.id"
+            class="cursor-pointer hover:shadow-lg transition-all duration-300 border-2 hover:border-green-400"
+            @click="startARExperience('factory', type.id)"
+          >
+            <div class="text-center p-6">
+              <el-icon :size="64" class="text-green-500 mb-4">
+                <Factory />
+              </el-icon>
+              <h4 class="text-xl font-semibold mb-3">{{ type.accountNumber || '标准化厂房' }}</h4>
+              <p class="text-gray-600 mb-2">面积:{{ type.area || '待定' }}</p>
+              <p class="text-sm text-gray-500 mb-4">地址:{{ type.address || '待定' }}</p>
+              <div class="grid grid-cols-2 gap-4 text-sm text-gray-600 mb-4">
+                <div class="flex items-center">
+                  <el-icon class="mr-2 text-green-500">
+                    <Check />
+                  </el-icon>
+                  <span>完善电力配套</span>
+                </div>
+                <div class="flex items-center">
+                  <el-icon class="mr-2 text-green-500">
+                    <Check />
+                  </el-icon>
+                  <span>货运通道便利</span>
+                </div>
+                <div class="flex items-center">
+                  <el-icon class="mr-2 text-green-500">
+                    <Check />
+                  </el-icon>
+                  <span>消防设施齐全</span>
+                </div>
+                <div class="flex items-center">
+                  <el-icon class="mr-2 text-green-500">
+                    <Check />
+                  </el-icon>
+                  <span>环保标准达标</span>
+                </div>
+              </div>
+              <div class="flex items-center justify-center text-sm text-gray-500">
+                <el-icon class="mr-1">
+                  <Eye />
+                </el-icon>
+                <span>沉浸式厂房体验</span>
+              </div>
+            </div>
+          </el-card>
+        </div>
+
+        <!-- 创新创业基地户型选择 -->
+        <div v-else-if="currentARType === 'innovation'" class="space-y-4">
+          <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
+            <el-card
+              v-for="type in innovationTypes"
+              :key="type.id"
+              class="cursor-pointer hover:shadow-lg transition-all duration-300 border-2 hover:border-purple-400"
+              @click="startARExperience('innovation', type.id)"
+            >
+              <div class="text-center p-4">
+                <el-icon :size="48" class="text-purple-500 mb-3">
+                  <component :is="getHouseTypeIcon(type)" />
+                </el-icon>
+                <h4 class="text-lg font-semibold mb-2">{{ type.accountNumber || '创新空间' }}</h4>
+                <p class="text-sm text-gray-600 mb-2">面积:{{ type.area || '待定' }}</p>
+                <p class="text-xs text-gray-500 mb-3">地址:{{ type.address || '待定' }}</p>
+                <div class="grid grid-cols-1 gap-2 text-xs text-gray-600 mb-3">
+                  <div class="flex items-center">
+                    <el-icon class="mr-1 text-purple-500">
+                      <Check />
+                    </el-icon>
+                    <span>创新孵化环境</span>
+                  </div>
+                  <div class="flex items-center">
+                    <el-icon class="mr-1 text-purple-500">
+                      <Check />
+                    </el-icon>
+                    <span>政策扶持服务</span>
+                  </div>
+                </div>
+                <div class="flex items-center justify-center text-sm text-gray-500">
+                  <el-icon class="mr-1">
+                    <Eye />
+                  </el-icon>
+                  <span>360°创业环境体验</span>
+                </div>
+              </div>
+            </el-card>
+          </div>
+        </div>
+      </div>
+
+      <template #footer>
+        <div class="text-center">
+          <el-button @click="arDialogVisible = false">取消</el-button>
+        </div>
+      </template>
+    </el-dialog>
   </el-container>
 </template>
 
 <script setup lang="ts">
-import { ElButton, ElCard, ElCol, ElContainer, ElIcon, ElMain, ElRow } from 'element-plus'
-import { ArrowRight, Building, Check, Factory, Lightbulb } from 'lucide-vue-next'
+import { onMounted, ref } from 'vue'
+import {
+  ElButton,
+  ElCard,
+  ElCol,
+  ElContainer,
+  ElDialog,
+  ElIcon,
+  ElMain,
+  ElMessage,
+  ElRow,
+} from 'element-plus'
+import {
+  ArrowRight,
+  Building,
+  Building2,
+  Camera,
+  Check,
+  Clock,
+  Eye,
+  Factory,
+  Home,
+  House,
+  Lightbulb,
+  Loader,
+} from 'lucide-vue-next'
 import { useRouter } from 'vue-router'
+import { clientGet } from '@/utils/request.ts'
+
+interface HouseType {
+  id: string
+  accountNumber?: string //户型名字
+  address?: string //地址
+  area?: string //面积
+  roomType?: number // 户型类型:1-公租房,2-厂房,3-创新创业基地
+}
+
+interface HouseTypeReponse extends BaseResponse {
+  data: HouseType[]
+}
 
 const router = useRouter()
 
+// AR对话框相关状态
+const arDialogVisible = ref(false)
+const arDialogTitle = ref('')
+const currentARType = ref<'housing' | 'factory' | 'innovation'>('housing')
+
+// 加载状态
+const loadingStates = ref({
+  housing: false,
+  factory: false,
+  innovation: false,
+})
+
+// 业务模块配置
+const businessModules = ref({
+  housing: {
+    enabled: true,
+    arEnabled: true,
+  },
+  factory: {
+    enabled: true,
+    arEnabled: true,
+  },
+  innovation: {
+    enabled: true,
+    arEnabled: true,
+  },
+})
+
+// 户型数据 - 改为从接口获取
+const housingTypes = ref<HouseType[]>([])
+const factoryTypes = ref<HouseType[]>([])
+const innovationTypes = ref<HouseType[]>([])
+
+// 获取户型数据
+const getHouseType = async (roomType: number) => {
+  const typeMap = {
+    1: 'housing',
+    2: 'factory',
+    3: 'innovation',
+  } as const
+
+  const currentType = typeMap[roomType as keyof typeof typeMap]
+  if (!currentType) return
+
+  loadingStates.value[currentType] = true
+
+  try {
+    const res = await clientGet<
+      {
+        roomType: number
+      },
+      HouseTypeReponse
+    >('/houseType/getByRoomType', {
+      params: {
+        roomType,
+      },
+    })
+
+    if (res.code !== 200) {
+      ElMessage.error(res.msg || '获取户型数据失败')
+      return
+    }
+
+    // 根据类型存储数据
+    switch (roomType) {
+      case 1:
+        housingTypes.value = res.data || []
+        break
+      case 2:
+        factoryTypes.value = res.data || []
+        break
+      case 3:
+        innovationTypes.value = res.data || []
+        break
+    }
+
+    // console.log(`${currentType} 户型数据:`, res.data)
+  } catch (error) {
+    console.error(`获取${currentType}户型数据失败:`, error)
+    ElMessage.error('网络请求失败,请稍后重试')
+  } finally {
+    loadingStates.value[currentType] = false
+  }
+}
+
+// 获取当前类型的数据
+const getCurrentTypeData = () => {
+  switch (currentARType.value) {
+    case 'housing':
+      return housingTypes.value
+    case 'factory':
+      return factoryTypes.value
+    case 'innovation':
+      return innovationTypes.value
+    default:
+      return []
+  }
+}
+
+// 根据户型获取图标
+const getHouseTypeIcon = (type: HouseType) => {
+  // 可以根据户型名称或其他字段来判断图标
+  if (type.accountNumber?.includes('一室') || type.accountNumber?.includes('单间')) {
+    return Home
+  }
+  if (type.accountNumber?.includes('两室') || type.accountNumber?.includes('多室')) {
+    return Building2
+  }
+  if (type.roomType === 2) {
+    return Factory
+  }
+  if (type.roomType === 3) {
+    return Lightbulb
+  }
+  return Building
+}
+
 const toZflbLink = (currentActive: string) => {
   router.push({
     path: '/zf/zflb',
@@ -168,6 +575,45 @@ const toZflbLink = (currentActive: string) => {
     },
   })
 }
+
+// 打开AR对话框
+const openARDialog = (type: 'housing' | 'factory' | 'innovation') => {
+  currentARType.value = type
+  const titles = {
+    housing: 'AR看房体验',
+    factory: 'AR厂房参观',
+    innovation: 'AR创新空间体验',
+  }
+  arDialogTitle.value = titles[type]
+  arDialogVisible.value = true
+}
+
+// 开始AR体验
+const startARExperience = (type: 'housing' | 'factory' | 'innovation', houseId: string) => {
+  // const selectedHouse = getCurrentTypeData().find(house => house.id === houseId)
+
+  // console.log(`开始AR体验: ${type} - ${houseId}`, selectedHouse)
+
+  router.push({
+    path: '/ar/preview',
+    query: {
+      houseTypeId: houseId,
+      isTourist: 1,
+    },
+  })
+
+  arDialogVisible.value = false
+}
+
+// 组件挂载时获取所有户型数据
+onMounted(async () => {
+  // 并发获取所有类型的户型数据
+  await Promise.all([
+    getHouseType(1), // 公租房
+    getHouseType(2), // 厂房
+    getHouseType(3), // 创新创业基地
+  ])
+})
 </script>
 
 <style scoped>
@@ -180,6 +626,11 @@ const toZflbLink = (currentActive: string) => {
   font-weight: 600;
 }
 
+/* AR对话框样式 */
+.ar-dialog .el-dialog__body {
+  padding: 30px;
+}
+
 /* 渐变背景动画 */
 @keyframes gradient {
   0% {
@@ -192,4 +643,33 @@ const toZflbLink = (currentActive: string) => {
     background-position: 0% 50%;
   }
 }
+
+/* 卡片悬停效果增强 */
+.el-card:hover {
+  transform: translateY(-2px);
+}
+
+/* 按钮渐变效果 */
+.el-button[type='info'] {
+  transition: all 0.3s ease;
+}
+
+.el-button[type='info']:hover {
+  transform: translateY(-1px);
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+}
+
+/* 加载动画 */
+.animate-spin {
+  animation: spin 1s linear infinite;
+}
+
+@keyframes spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
 </style>