Browse Source

feat: 对接服务

bill 2 years ago
parent
commit
7ce92ea2ec

+ 2 - 2
index.html

@@ -2,9 +2,9 @@
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
-    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
+    <link rel="icon" type="image/svg+xml" href="//4dkk.4dage.com/FDKKIMG/icon/kankan_icon.ico" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>Vite + Vue + TS</title>
+    <title>四维全景VR</title>
   </head>
   <body>
     <div id="app"></div>

+ 4 - 3
src/api/constant.ts

@@ -8,11 +8,12 @@ export const ResCodeDesc: { [key in ResCode]: string } = {
   [ResCode.SUCCESS]: '请求成功'
 }
 
+export const GET_USER = '/takelook/getUserInfo'
+
+export const GET_SCENE_LIST = '/takelook/sceneList'
+
 export const GET_ROOM_LIST = '/takelook/roomList'
 export const GET_ROOM = '/takelook/roomInfo'
 export const SET_ROOM = '/takelook/roomAddOrUpdate'
 export const DEL_ROOM = '/takelook/roomDelete'
 export const GET_ROOM_MINI_CODE = '/takelook/roomGetShareCode'
-export const GET_SECELE_LIST = '/takelook/sceneList'
-
-export const GET_SCENE_LIST = '/takelook/sceneList'

+ 7 - 0
src/api/index.ts

@@ -2,3 +2,10 @@ export * from './room'
 export * from './user'
 export * from './instance'
 export * from './scene'
+
+export type PageResult<T> = {
+  pageNum: number
+  PageSize: number
+  total: number
+  list: T[]
+}

+ 68 - 69
src/api/room.ts

@@ -1,5 +1,21 @@
-import { GET_ROOM_LIST, GET_ROOM_MINI_CODE } from './constant'
+import {
+  GET_ROOM_LIST,
+  GET_ROOM_MINI_CODE,
+  DEL_ROOM,
+  SET_ROOM
+} from './constant'
 import axios from './instance'
+import type { PageResult, Scene } from './'
+
+type SRoom = {
+  roomId: number
+  roomTitle: string
+  roomInfo: string
+  roomHostName: string
+  roomCoverUrl: string
+  roomViewCount: number
+  createTime: string
+}
 
 export interface RoomScene {
   num: string
@@ -15,78 +31,61 @@ export interface Room {
   viewCount: number
   cover: string
   leaderName: string
-  userName: string
-  shareUrl: string
-  scenes: RoomScene[]
 }
 
 export type Rooms = Room[]
 
-export const fetchRomms = async () => {
-  const test: Rooms = [
-    {
-      id: 1,
-      title: '1212121212121212121212121212121212121212121212121212121212121212',
-      desc: '1231',
-      cover: 'https://4dkk.4dage.com/head/18819272208/head_1662022947583.png',
-      leaderName: 'asdasd',
-      userName: 'aaa',
-      shareUrl: 'http://www.4dkankan.com',
-      time: '2020-03-02',
-      viewCount: 1002,
-      scenes: [
-        {
-          num: 't-cc',
-          cover:
-            'https://4dkk.4dage.com/head/18819272208/head_1662022947583.png',
-          title: '田心村'
-        }
-      ]
-    },
-    {
-      id: 2,
-      title: '12',
-      desc: '1231',
-      cover: 'https://4dkk.4dage.com/head/18819272208/head_1662022947583.png',
-      leaderName: 'asdasd',
-      time: '2020-03-02',
-      userName: 'aaa',
-      shareUrl: 'http://www.4dkankan.com',
-      viewCount: 1002,
-      scenes: [
-        {
-          num: 't-cc',
-          cover:
-            'https://4dkk.4dage.com/head/18819272208/head_1662022947583.png',
-          title: '田心村'
-        }
-      ]
-    },
-    {
-      id: 3,
-      title: '12',
-      time: '2020-03-02',
-      viewCount: 1002,
-      desc: '1231',
-      userName: 'aaa',
-      shareUrl: 'http://www.4dkankan.com',
-      cover: 'https://4dkk.4dage.com/head/18819272208/head_1662022947583.png',
-      leaderName: 'asdasd',
-      scenes: [
-        {
-          num: 't-cc',
-          cover:
-            'https://4dkk.4dage.com/head/18819272208/head_1662022947583.png',
-          title: '田心村'
-        }
-      ]
-    }
-  ]
-  // const res = await axios.get<Room[]>(GET_ROOM_LIST)
-  return test
+const serverToLocal = (sroom: SRoom): Room => ({
+  id: sroom.roomId,
+  title: sroom.roomTitle,
+  desc: sroom.roomInfo,
+  time: sroom.createTime,
+  viewCount: sroom.roomViewCount,
+  cover: sroom.roomCoverUrl,
+  leaderName: sroom.roomHostName
+})
+const localToServer = (room: Room): SRoom => ({
+  roomId: room.id,
+  roomTitle: room.title,
+  roomInfo: room.desc,
+  roomHostName: room.leaderName,
+  roomCoverUrl: room.cover,
+  roomViewCount: room.viewCount,
+  createTime: room.time
+})
+
+export const fetchRomms = async (): Promise<Rooms> => {
+  const res = await axios.post<PageResult<SRoom>>(GET_ROOM_LIST, {
+    pageNum: 1,
+    pageSize: 1000
+  })
+  return res.list.map(serverToLocal)
+}
+
+export const deleteRoom = async (room: Room) => {
+  await axios.post(DEL_ROOM, { roomId: room.id })
+}
+
+export const insertRoom = async (
+  room: Omit<Room, 'id'>,
+  numList: Scene['num'][]
+) => {
+  const sroom = await axios.post<SRoom>(SET_ROOM, {
+    ...localToServer({ ...room, id: -1 }),
+    roomId: null,
+    createTime: null,
+    numList
+  })
+  return serverToLocal(sroom)
+}
+
+export const updateRoom = async (room: Room, numList: Scene['num'][]) => {
+  await axios.post(SET_ROOM, {
+    ...localToServer(room),
+    numList
+  })
 }
 
-export const fetchRoomMiniCode = (room: Room) => {
-  return 'https://4dkk.4dage.com/head/18819272208/head_1662022947583.png'
-  // return axios.get<string>(GET_ROOM_MINI_CODE, { params: { roomId: room.id } })
+export const fetchRoomMiniCode = async (room: Room) => {
+  return axios.get<string>(GET_ROOM_MINI_CODE, { params: { roomId: room.id } })
 }

+ 40 - 34
src/api/scene.ts

@@ -1,8 +1,19 @@
 import axios from './instance'
-import { GET_SCENE_LIST } from './constant'
+import { GET_SCENE_LIST, GET_ROOM } from './constant'
+import type { PageResult, Room } from './'
+
+type SScene = {
+  id: number
+  name: string
+  num: string
+  title: string
+  sceneName: string
+  thumb: string
+  createTime: string
+}
 
 export interface Scene {
-  id: string
+  id: number
   num: string
   title: string
   cover: string
@@ -11,36 +22,31 @@ export interface Scene {
 
 export type Scenes = Scene[]
 
-export const fetchScenes = async () => {
-  return [
-    {
-      id: '1',
-      num: 't-cc',
-      time: '2020-03-02',
-      cover: 'https://4dkk.4dage.com/head/18819272208/head_1662022947583.png',
-      title: '田心村'
-    },
-    {
-      id: '2',
-      num: 't-cc2',
-      time: '2020-03-02',
-      cover: 'https://4dkk.4dage.com/head/18819272208/head_1662022947583.png',
-      title: '田心村'
-    },
-    {
-      id: '3',
-      num: 't-cc3',
-      time: '2020-03-02',
-      cover: 'https://4dkk.4dage.com/head/18819272208/head_1662022947583.png',
-      title: '田心村'
-    },
-    {
-      id: '4',
-      num: 't-cc4',
-      time: '2020-03-02',
-      cover: 'https://4dkk.4dage.com/head/18819272208/head_1662022947583.png',
-      title: '田心村'
-    }
-  ]
-  // return axios.get<Scenes>(GET_SCENE_LIST)
+const serverToLocal = (sscene: SScene): Scene => ({
+  ...sscene,
+  cover: sscene.thumb,
+  time: sscene.createTime
+})
+
+export const fetchScenes = async (): Promise<Scenes> => {
+  const params = {
+    status: 2,
+    pageNum: 1,
+    pageSize: 1000,
+    sceneName: ''
+  }
+
+  const [kkScenes, kjScenes] = await Promise.all([
+    axios.post<PageResult<SScene>>(GET_SCENE_LIST, { type: 0, ...params }),
+    axios.post<PageResult<SScene>>(GET_SCENE_LIST, { type: 1, ...params })
+  ])
+
+  return kkScenes.list.concat(kjScenes.list).map(serverToLocal)
+}
+
+export const fetchRoomScenes = async (roomId: Room['id']) => {
+  const res = await axios.get<Room & { sceneData: SScene[] }>(GET_ROOM, {
+    params: { roomId }
+  })
+  return res.sceneData.map(serverToLocal)
 }

+ 13 - 6
src/api/user.ts

@@ -1,4 +1,5 @@
-import axios from 'axios'
+import axios from './instance'
+import { GET_USER } from './constant'
 
 export interface User {
   nickname: string
@@ -6,11 +7,17 @@ export interface User {
   avatar: string
 }
 
-export const fetchUser = async () => {
-  // const res = axios.get<User>('')
+type SUser = {
+  head: string
+  nickName: string
+  userName: string
+}
+
+export const fetchUser = async (): Promise<User> => {
+  const res = await axios.post<{ data: SUser }>(GET_USER)
   return {
-    nickname: 'aaa',
-    phone: '15919209354',
-    avatar: 'https://4dkk.4dage.com/head/18819272208/head_1662022947583.png'
+    nickname: res.data.nickName,
+    avatar: res.data.head,
+    phone: res.data.userName
   }
 }

+ 10 - 2
src/components/loading/index.ts

@@ -16,8 +16,15 @@ export const showLoading = function (
   if (closeStack.length) {
     closeStack.push({ key })
   } else {
-    const { destroy } = mount(Loading, { app, props })
-    closeStack.push({ key, close: destroy })
+    const timeout = setTimeout(() => {
+      const { destroy } = mount(Loading, { app, props })
+      item.close = destroy
+    }, 300)
+    const item: Stack[number] = {
+      key,
+      close: () => clearTimeout(timeout)
+    }
+    closeStack.push(item)
   }
 }
 
@@ -25,6 +32,7 @@ export const hideLoading = function (hkey?: LoginMark) {
   if (closeStack.length) {
     const { key } = closeStack[closeStack.length - 1]
     if (key === hkey) {
+      console.log('hide')
       const stack = closeStack.pop()
       stack?.close && stack?.close()
     }

+ 59 - 0
src/components/loading/index.vue

@@ -24,3 +24,62 @@ export default defineComponent({
   props: props
 })
 </script>
+
+<style lang="scss" scoped>
+.ui-loading {
+  position: absolute;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+  background-color: rgba($color: #000000, $alpha: 0.3);
+  --width: 15px;
+  --color: #fff;
+}
+.ui-loading__box {
+  position: relative;
+  width: 100px;
+  height: 100px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  .default {
+    div {
+      width: var(--width);
+      height: var(--width);
+      background: var(--color);
+      border-radius: 50%;
+      display: inline-block;
+      margin-left: calc(var(--width) * 0.6);
+    }
+    div:nth-child(1) {
+      animation: ui-loading-default 1s -0.5s linear infinite;
+    }
+    div:nth-child(2) {
+      animation: ui-loading-default 1s -0.25s linear infinite;
+    }
+    div:nth-child(3) {
+      animation: ui-loading-default 1s 0s linear infinite;
+    }
+  }
+}
+
+@keyframes ui-loading-default {
+  0% {
+    transform: scale(1);
+    opacity: 1;
+  }
+  50% {
+    transform: scale(0.5);
+    opacity: 0.5;
+  }
+  100% {
+    transform: scale(1);
+    opacity: 0.8;
+  }
+}
+</style>

+ 1 - 2
src/main.ts

@@ -1,6 +1,5 @@
 import { createApp } from 'vue'
-import 'ant-design-vue/lib/modal/style/index.css'
-import 'ant-design-vue/lib/message/style/index.css'
+import 'ant-design-vue/lib/message/style/index.less'
 import './style.css'
 import App from './App.vue'
 import router from './router'

+ 1 - 0
src/store/index.ts

@@ -3,6 +3,7 @@ import { createPinia } from 'pinia'
 export * from './room'
 export * from './user'
 export * from './scene'
+export * from './constant'
 
 export const pinia = createPinia()
 export default pinia

+ 30 - 9
src/store/room.ts

@@ -1,25 +1,30 @@
-import { fetchRomms, fetchRoomMiniCode } from '@/api'
 import { defineStore } from 'pinia'
 import { TemplateId } from './constant'
 import { useUserStore } from './user'
+import {
+  fetchRomms,
+  fetchRoomMiniCode,
+  insertRoom,
+  updateRoom,
+  deleteRoom,
+  fetchRoomScenes
+} from '@/api'
 
-import { Room as SRoom } from '@/api'
+import { Room as SRoom, Scenes } from '@/api'
 
 export type { RoomScene } from '@/api'
 export type Rooms = Room[]
-export type Room = SRoom & { miniCode?: string }
+export type Room = SRoom & { miniCode?: string; scenes: Scenes }
 
 export const createRoom = (room: Partial<Room>): Room => {
   const user = useUserStore().current
   return {
     id: TemplateId,
-    userName: user.nickname,
     leaderName: user.nickname,
     title: '',
     time: new Date().toDateString(),
     viewCount: 0,
     desc: '',
-    shareUrl: '',
     cover: '',
     scenes: [],
     ...room
@@ -31,14 +36,22 @@ export const useRoomStore = defineStore('room', {
     list: [] as Rooms
   }),
   getters: {
+    getNums:
+      () =>
+      <T extends Pick<Room, 'scenes'>>(room: T) =>
+        room.scenes.map(scene => scene.num),
+    getShareUrl: () => (room: Room) =>
+      `https://test.4dkankan.com?roomId=${room.id}`,
     filter: state => (keyowrd: string) =>
       state.list.filter(room => room.title.includes(keyowrd))
   },
   actions: {
-    async fetch() {
-      this.list = await fetchRomms()
+    async fetchList() {
+      const srooms = await fetchRomms()
+      this.list = srooms.map(room => ({ ...room, scenes: [] }))
     },
     async delete(room: Room) {
+      await deleteRoom(room)
       const index = this.list.indexOf(room)
       if (~index) {
         this.list.splice(index, 1)
@@ -46,14 +59,22 @@ export const useRoomStore = defineStore('room', {
     },
     async update(room: Room) {
       const storeRoom = this.list.find(({ id }) => id === room.id)
+      await updateRoom(room, this.getNums(room))
       if (storeRoom) {
         Object.assign(storeRoom, room)
       }
     },
     async insert(room: Omit<Room, 'id'>) {
-      this.list.push({ ...room, id: -1 })
+      await insertRoom(room, this.getNums(room))
+      // const sroom =
+      // this.list.push({ ...room, ...sroom })
+      this.fetchList()
     },
-    async setMiniCode(room: Room) {
+    async setRoomScenes(room: Room) {
+      const scenes = await fetchRoomScenes(room.id)
+      room.scenes = scenes
+    },
+    async setRoomMiniCode(room: Room) {
       const code = room.miniCode || (await fetchRoomMiniCode(room))
       room.miniCode = code
     }

+ 22 - 24
src/views/room/edit-room/index.vue

@@ -1,7 +1,7 @@
 <template>
   <a-modal
     :visible="visible"
-    title="创建房间"
+    :title="`${!room ? '创建' : '修改'}房间`"
     :after-close="onCancel"
     width="912px"
     @cancel="visible = false"
@@ -19,21 +19,19 @@
         保存
       </a-button>
       <a-button
+        v-if="room"
         class="action-bottom"
         type="primary"
         size="middle"
-        @click="onSave && onSave(current)"
+        @click="startSync"
       >
         开始带看
       </a-button>
     </template>
     <div class="edit-room-layout">
       <div class="scene">
-        <template v-if="!current.scenes.length">
-          {{ current }}
-        </template>
         <iframe
-          v-else
+          v-if="current.scenes.length"
           :src="`https://test.4dkankan.com/spg.html?m=${current.scenes[0].num}`"
           frameborder="0"
         />
@@ -86,12 +84,15 @@
 
 <script lang="ts">
 import { ref, defineComponent, reactive } from 'vue'
-import { createRoom } from '@/store'
+import { createRoom, useRoomStore } from '@/store'
 import { props } from './props'
+import { message } from 'ant-design-vue'
 import EditScenes from './scene-list.vue'
 
-import type { RoomScene } from '@/store'
-import { FormInstance, message } from 'ant-design-vue'
+import type { Scene } from '@/store'
+import type { FormInstance } from 'ant-design-vue'
+
+const roomStore = useRoomStore()
 
 export default defineComponent({
   name: 'EditRoom',
@@ -101,27 +102,23 @@ export default defineComponent({
     const visible = ref(true)
     const formRef = ref<FormInstance>()
     const current = reactive(createRoom(props.room || {}))
-    const deleteScene = (scene: RoomScene) => {
+    const deleteScene = (scene: Scene) => {
       const index = current.scenes.indexOf(scene)
       if (~index) {
         current.scenes.splice(index, 1)
       }
     }
     const saveRoom = async () => {
-      try {
-        await formRef.value?.validate()
-        if (!current.scenes.length) {
-          return message.error('至少添加一个场景')
-        }
-
-        current.cover = current.scenes[0].cover
-        props.onSave && props.onSave(current)
-        visible.value = false
-      } catch (config: any) {
-        if (config && config.errorFields && config.errorFields.length) {
-          message.error(config.errorFields[0].errors.join(','))
-        }
+      await formRef.value?.validate()
+      if (!current.scenes.length) {
+        return message.error('至少添加一个场景')
       }
+      current.cover = current.scenes[0].cover
+      props.onSave && props.onSave(current)
+      visible.value = false
+    }
+    const startSync = () => {
+      window.open(roomStore.getShareUrl(current))
     }
 
     return {
@@ -129,7 +126,8 @@ export default defineComponent({
       current,
       formRef,
       deleteScene,
-      saveRoom
+      saveRoom,
+      startSync
     }
   }
 })

+ 1 - 2
src/views/room/edit-room/props.ts

@@ -3,8 +3,7 @@ import type { PropType, ExtractPropTypes } from 'vue'
 
 export const props = {
   room: {
-    type: Object as PropType<Room>,
-    required: true
+    type: Object as PropType<Room>
   },
   onSave: {
     type: Function as PropType<(room: Room) => void>

+ 5 - 5
src/views/room/edit-room/scene-list.vue

@@ -27,21 +27,21 @@ import { useSceneStore } from '@/store'
 import { diffArrayChange } from '@/shared'
 import SceneList from '@/views/scene/list.vue'
 
-import type { RoomScene } from '@/store'
+import type { Scene } from '@/store'
 import { renderModal } from '@/helper'
 
 defineOptions<{ name: 'RoomSceneList' }>()
-const props = defineProps<{ scenes: RoomScene[] }>()
+const props = defineProps<{ scenes: Scene[] }>()
 const emit = defineEmits<{
-  (e: 'delete', scene: RoomScene): void
-  (e: 'insert', scene: RoomScene): void
+  (e: 'delete', scene: Scene): void
+  (e: 'insert', scene: Scene): void
 }>()
 
 const addMarked = Symbol('add-scene')
 const current = computed(() => [addMarked, ...props.scenes])
 const sceneStore = useSceneStore()
 
-const deleteScene = (scene: RoomScene) => {
+const deleteScene = (scene: Scene) => {
   Modal.confirm({
     content: '删除后无法恢复,是否确认?',
     title: '删除场景',

+ 15 - 7
src/views/room/list.vue

@@ -21,7 +21,10 @@
         创建作品
       </a-button>
     </template>
-    <a-list :grid="{ gutter: 20, column: 5 }" :data-source="roomList">
+    <a-list
+      :grid="{ gutter: 20, xl: 5, lg: 4, md: 3, sm: 2, xs: 1, column: 5 }"
+      :data-source="roomList"
+    >
       <template #renderItem="{ item }">
         <a-list-item>
           <RoomSign
@@ -56,6 +59,7 @@ import RoomSign from './sign.vue'
 import Share from './modal/share.vue'
 import MiniSync from './modal/mini-sync.vue'
 import DataList from '@/components/data-list/index.vue'
+import { app } from '@/main'
 
 import type { Room } from '@/store'
 
@@ -63,7 +67,7 @@ defineOptions({ name: 'RoomList' })
 
 const addMarked = Symbol('add-room')
 const roomStore = useRoomStore()
-roomStore.fetch()
+roomStore.fetchList()
 
 const keyword = ref('')
 const roomList = computed(() => [addMarked, ...roomStore.filter(keyword.value)])
@@ -80,22 +84,23 @@ const deleteRoom = (room: Room) => {
   })
 }
 const shareRoom = async (room: Room) => {
-  await roomStore.setMiniCode(room)
+  await roomStore.setRoomMiniCode(room)
   Modal.confirm({
     content: createVNode(Share, { room }),
     title: '分享',
     icon: null,
     width: '500px',
     okText: '复制链接',
+    appContext: app._context,
     cancelText: '取消',
     onOk: async (room: Room) => {
-      await copyText(room.shareUrl)
+      await copyText(roomStore.getShareUrl(room))
       message.success('链接复制成功')
     }
   })
 }
 const miniSyncRoom = async (room: Room) => {
-  await roomStore.setMiniCode(room)
+  await roomStore.setRoomMiniCode(room)
   Modal.info({
     content: createVNode(MiniSync, { room }),
     title: '小程序带看',
@@ -105,9 +110,12 @@ const miniSyncRoom = async (room: Room) => {
     cancelText: null
   })
 }
-const webSyncRoom = (room: Room) => window.open(room.shareUrl)
+const webSyncRoom = (room: Room) => window.open(roomStore.getShareUrl(room))
 
-const editRoom = (room?: Room) => {
+const editRoom = async (room?: Room) => {
+  if (room) {
+    await roomStore.setRoomScenes(room)
+  }
   renderModal(EditRoom, {
     room,
     onSave(actionRoom) {

+ 4 - 1
src/views/room/modal/share.vue

@@ -5,7 +5,7 @@
     class="share-form"
   >
     <a-form-item label="作品链接">
-      <a-input disabled :value="room.shareUrl" />
+      <a-input disabled :value="roomStore.getShareUrl(room)" />
     </a-form-item>
     <a-form-item label="作品葵花码">
       <img :src="room.miniCode" class="mini-code" />
@@ -14,10 +14,13 @@
 </template>
 
 <script lang="ts" setup>
+import { useRoomStore } from '@/store'
 import type { Room } from '@/store'
 
 defineOptions({ name: 'RoomShare' })
 defineProps<{ room: Room }>()
+
+const roomStore = useRoomStore()
 </script>
 
 <style lang="scss" scoped>

+ 1 - 1
src/views/room/sign.vue

@@ -49,7 +49,7 @@
       <h4 v-else>{{ room.title }}</h4>
       <div class="desc">
         <span>{{ room.time }}</span>
-        <span><eye-outlined />{{ room.viewCount }}</span>
+        <span><eye-outlined /> {{ room.viewCount }}</span>
       </div>
     </div>
   </a-card>

+ 33 - 19
src/views/scene/list.vue

@@ -14,26 +14,28 @@
           <search-outlined class="search-icon" />
         </template>
       </a-input>
-      <DataList :data-source="filterScenes" :keyword="keyword" name="场景">
-        <div class="scene-list">
-          <a-table
-            row-key="num"
-            :columns="sceneColumns"
-            :data-source="filterScenes"
-            :pagination="false"
-            :row-selection="{
-              selectedRowKeys: selectedSceneKeys,
-              onChange: keys => (selectedSceneKeys = keys as SceneKey[])
-            }"
-          >
-            <template #bodyCell="{ column, record }">
-              <template v-if="column.key === 'cover'">
-                <img :src="record.cover" />
+      <div class="scene-list-layout">
+        <DataList :data-source="filterScenes" :keyword="keyword" name="场景">
+          <div class="scene-list">
+            <a-table
+              row-key="num"
+              :columns="sceneColumns"
+              :data-source="filterScenes"
+              :pagination="false"
+              :row-selection="{
+                selectedRowKeys: selectedSceneKeys,
+                onChange: keys => (selectedSceneKeys = keys as SceneKey[])
+              }"
+            >
+              <template #bodyCell="{ column, record }">
+                <template v-if="column.key === 'cover'">
+                  <img :src="record.cover" class="scene-cover" />
+                </template>
               </template>
-            </template>
-          </a-table>
-        </div>
-      </DataList>
+            </a-table>
+          </div>
+        </DataList>
+      </div>
     </div>
   </a-modal>
 </template>
@@ -94,10 +96,22 @@ const saveHandler = () => {
   border-bottom: none;
 }
 
+.scene-cover {
+  width: 38px;
+  height: 38px;
+}
+
 .search-icon {
   color: #1890ff;
   font-size: 18px;
 }
+
+.scene-list-layout {
+  max-height: 500px;
+  overflow-y: auto;
+  margin-right: -20px;
+  padding-right: 10px;
+}
 </style>
 
 <style lang="scss">

+ 2 - 2
vite.config.ts

@@ -8,9 +8,9 @@ import { resolve } from 'path'
 
 const proxy = {
   '/api': {
-    target: 'http://192.168.0.38:8818',
+    target: 'http://v4-test.4dkankan.com/',
     changeOrigin: true,
-    rewrite: path => path.replace(/^\/local/, '')
+    rewrite: path => path.replace(/^\/api/, '')
   }
 }