Browse Source

blockly编程游戏
1、配置可行走矩阵视图化
2、方格尺寸改为地图横竖尺寸,前端自适应

liyanbo 7 months ago
parent
commit
a42215cd80
3 changed files with 564 additions and 171 deletions
  1. 1 1
      src/api/ai/mapgame/index.ts
  2. 559 167
      src/views/ai/mapgame/MapGameForm.vue
  3. 4 3
      src/views/ai/mapgame/index.vue

+ 1 - 1
src/api/ai/mapgame/index.ts

@@ -7,7 +7,7 @@ export interface MapGameVO {
   info: string // 简介
   userImage: string // 人物图标
   userDirection: number // 人物朝向
-  mapTileSize: number // 地图方格尺寸
+  mapTileSize: string // 地图方格尺寸
   mapStartPoint: string // 地图开始坐标
   mapBackground: string // 地图背景图
   mapEndPoint: string // 地图结束坐标

+ 559 - 167
src/views/ai/mapgame/MapGameForm.vue

@@ -37,132 +37,253 @@
           </el-form-item>
         </el-col>
         <el-col :span="12">
-          <el-form-item label="地图方格尺寸" prop="mapTileSize">
-            <el-input-number v-model="formData.mapTileSize" :min="10" :max="200">
-              <template #suffix>
-                <span>px</span>
-              </template>
-            </el-input-number>
+          <!-- 地图开始坐标 - 拆分为X轴和Y轴 -->
+          <el-form-item label="地图开始坐标" required>
+            <div class="coordinate-group">
+              X:
+              <el-input-number
+                v-model="mapStartPointX"
+                placeholder="X轴"
+                :min="1"
+                :max="mapTileX"
+                :step="1"
+                style="width: 120px"
+              />
+              Y:
+              <el-input-number
+                v-model="mapStartPointY"
+                placeholder="Y轴"
+                :min="1"
+                :max="mapTileY"
+                :step="1"
+                style="width: 120px"
+              />
+            </div>
           </el-form-item>
         </el-col>
-      </el-row>
-
-      <!-- 地图开始坐标 - 拆分为X轴和Y轴 -->
-      <el-form-item label="地图开始坐标" required>
-        <div class="coordinate-group">
-          X:
-          <el-input-number
-            v-model="mapStartPointX"
-            placeholder="X轴"
-            :min="1"
-            :step="1"
-            style="width: 120px"
-          />
-          Y:
-          <el-input-number
-            v-model="mapStartPointY"
-            placeholder="Y轴"
-            :min="1"
-            :step="1"
-            style="width: 120px"
-          />
-        </div>
-      </el-form-item>
-
-      <!-- 地图结束坐标 - 拆分为X轴和Y轴 -->
-      <el-form-item label="地图结束坐标" required>
-        <div class="coordinate-group">
-          X:
-          <el-input-number
-            v-model="mapEndPointX"
-            placeholder="X轴"
-            :min="1"
-            :step="1"
-            style="width: 120px"
-          />
-          Y:
-          <el-input-number
-            v-model="mapEndPointY"
-            placeholder="Y轴"
-            :min="1"
-            :step="1"
-            style="width: 120px"
-          />
-        </div>
-      </el-form-item>
+        <el-col :span="12">
+          <el-form-item label="地图方格尺寸" required>
+            <div class="coordinate-group">
+              X:
+              <el-input-number
+                v-model="mapTileX"
+                placeholder="横向数量"
+                :min="1"
+                :step="1"
+                style="width: 120px"
+              />
+              Y:
+              <el-input-number
+                v-model="mapTileY"
+                placeholder="纵向数量"
+                :min="1"
+                :step="1"
+                style="width: 120px"
+              />
+            </div>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
 
-      <!-- 地图可行走坐标 - 动态添加 -->
-      <el-form-item label="地图可行走坐标" required>
-        <div class="walkable-points-container">
-          <div class="walkable-point-item">
-            <span style="width: 130px"> 横坐标</span>
-            <span style="width: 130px"> 纵坐标</span>
-            <span style="width: 120px"> 方格类型</span>
-            <span style="width: 120px"> 任务类型</span>
-            <span style="width: 100px"> 方格图标</span>
-            <span style="width: 100px"> 完成状态</span>
-            <span style="width: 200px"> 提示语</span>
-          </div>
-          <div v-for="(point, index) in walkablePoints" :key="index" class="walkable-point-item">
-            X:
-            <el-input-number
-              v-model="point.x"
-              placeholder="X轴"
-              :min="1"
-              :step="1"
-              style="width: 100px"
-            />
-            Y:
-            <el-input-number
-              v-model="point.y"
-              placeholder="Y轴"
-              :min="1"
-              :step="1"
-              style="width: 100px"
-            />
-            <el-select v-model="point.type" placeholder="类型" style="width: 120px" clearable>
-              <el-option
-                v-for="dict in getStrDictOptions(DICT_TYPE.AI_BLOCKLY_MAP_TYPE)"
-                :key="dict.value"
-                :label="dict.label"
-                :value="dict.value"
+          <!-- 地图结束坐标 - 拆分为X轴和Y轴 -->
+          <el-form-item label="地图结束坐标" required>
+            <div class="coordinate-group">
+              X:
+              <el-input-number
+                v-model="mapEndPointX"
+                placeholder="X轴"
+                :min="1"
+                :max="mapTileX"
+                :step="1"
+                style="width: 120px"
               />
-            </el-select>
-            <el-select v-model="point.need" placeholder="任务" style="width: 120px" clearable>
-              <el-option
-                v-for="dict in getStrDictOptions(DICT_TYPE.AI_BLOCKLY_MAP_TYPE)"
-                :key="dict.value"
-                :label="dict.label"
-                :value="dict.value"
+              Y:
+              <el-input-number
+                v-model="mapEndPointY"
+                placeholder="Y轴"
+                :min="1"
+                :max="mapTileY"
+                :step="1"
+                style="width: 120px"
               />
-            </el-select>
-            <UploadImg v-model="point.img" title="点击上传图标" />
-            <UploadImg v-model="point.needImg" title="点击上传图标" />
-            <el-input v-model="point.tip" placeholder="提示语" style="flex: 1; min-width: 200px" />
-            <el-button
-              @click="removeWalkablePoint(index)"
-              type="danger"
-              circle
-              :disabled="walkablePoints.length <= 2"
-            >
-              <Icon icon="ep:delete"
-            /></el-button>
-          </div>
-        </div>
-        <el-button @click="addWalkablePoint" type="primary" style="margin-top: 10px"
-          >+ 添加坐标</el-button
-        >
-      </el-form-item>
+            </div>
+          </el-form-item>
+        </el-col>
+      </el-row>
 
-      <!--      <el-form-item label="json数据" prop="jsonData">
-        <el-input
-          v-model="formData.jsonData"
-          type="textarea"
-          placeholder="请输入JSON格式数据"
-          :rows="3"
-          show-word-limit
-        />
-      </el-form-item>-->
+      <!-- 地图可行走坐标 - 动态矩阵显示 -->
+      <el-form-item label="地图方格配置" required>
+        <el-row type="flex" style="width: 100%;">
+          <!-- 左侧方格矩阵 -->
+          <el-col :span="10">
+            <div class="map-grid-container">
+              <div
+                class="map-grid"
+                :style="{ gridTemplateColumns: `repeat(${mapTileX || 5}, 1fr)`,
+                 gridTemplateRows: `repeat(${mapTileY || 5}, 1fr)` ,
+                 backgroundImage: formData.mapBackground ? `url(${formData.mapBackground})` : 'none', backgroundSize: 'cover',
+                 backgroundPosition: 'center' }"
+              >
+                <div
+                  v-for="(cell, index) in gridCells"
+                  :key="index"
+                  class="grid-cell"
+                  :class="{
+                    'walkable': isWalkable(cell.x, cell.y),
+                    'selected': selectedPoint && selectedPoint.x === cell.x && selectedPoint.y === cell.y,
+                    'has-icon': getPointByXY(cell.x, cell.y)?.img
+                  }"
+                  @click="selectCell(cell)"
+                >
+                  <div class="cell-coordinate">{{ cell.x }},{{ cell.y }}</div>
+                  <div v-if="getPointByXY(cell.x, cell.y)?.img" class="cell-icon">
+                    <img :src="getPointByXY(cell.x, cell.y).img" alt="图标" />
+                  </div>
+                </div>
+              </div>
+            </div>
+          </el-col>
+
+          <!-- 右侧配置项 -->
+          <el-col :span="14">
+            <div class="point-config-container" v-if="selectedPoint">
+              <el-form
+                label-width="100px"
+                :model="selectedPoint"
+                class="config-form"
+                size="large"
+              >
+                <el-card class="config-card" shadow="hover">
+                  <template #header>
+                    <div class="card-header">
+                      <span>坐标配置</span>
+                      <el-tag size="small" type="info">{{ selectedPoint.x }},{{ selectedPoint.y }}</el-tag>
+                    </div>
+                  </template>
+
+                  <!-- 第一行:是否可行走和是否自动触发 -->
+                  <div class="config-row">
+                    <el-form-item label="是否可行走" class="config-item">
+                      <el-switch
+                        v-model="selectedPoint.walkable"
+                        active-text="是"
+                        inactive-text="否"
+                        size="large"
+                      />
+                    </el-form-item>
+                  </div>
+
+                  <template v-if="selectedPoint.walkable">
+                    <!-- 第二行:地图类型和任务条件 -->
+                    <div class="config-row">
+
+                      <el-form-item label="地图类型" class="config-item">
+                        <el-select
+                          v-model="selectedPoint.type"
+                          placeholder="选择地图类型"
+                          style="width: 100%"
+                          clearable
+                          @change="() => {}"
+                          size="large"
+                        >
+                          <el-option
+                            v-for="dict in getStrDictOptions(DICT_TYPE.AI_BLOCKLY_MAP_TYPE)"
+                            :key="dict.value"
+                            :label="dict.label"
+                            :value="dict.value"
+                          />
+                        </el-select>
+                      </el-form-item>
+
+                      <el-form-item
+                        label="是否必须完成"
+                        class="config-item"
+                        v-if="selectedPoint.type === 'task'"
+                      >
+                        <el-switch
+                          v-model="selectedPoint.must"
+                          active-text="是"
+                          inactive-text="否"
+                          size="large"
+                        />
+                      </el-form-item>
+                    </div>
+
+                    <!-- 第三行:两个图标 -->
+                    <div class="config-row">
+                      <el-form-item label="初始图标" class="config-item" v-if="selectedPoint.type !== ''">
+                        <div class="icon-upload-wrapper">
+                          <UploadImg
+                            v-model="selectedPoint.img"
+                            title="点击上传初始图标"
+                            class="custom-upload"
+                          />
+                          <div v-if="selectedPoint.img" class="upload-tip">已上传</div>
+                        </div>
+                      </el-form-item>
+
+                      <el-form-item
+                        label="完成图标"
+                        class="config-item"
+                        v-if="selectedPoint.type !== '' && selectedPoint.type === 'task'"
+                      >
+                        <div class="icon-upload-wrapper">
+                          <UploadImg
+                            v-model="selectedPoint.endImg"
+                            title="点击上传完成图标"
+                            class="custom-upload"
+                          />
+                          <div v-if="selectedPoint.endImg" class="upload-tip">已上传</div>
+                        </div>
+                      </el-form-item>
+                    </div>
+
+                    <el-form-item label="提示语" class="form-item-full" v-if="selectedPoint.type !== '' && selectedPoint.type !== 'task'">
+                      <el-input
+                        v-model="selectedPoint.tip"
+                        placeholder="输入初始提示语"
+                        style="width: 100%"
+                        show-word-limit
+                        maxlength="100"
+                        type="textarea"
+                        :rows="2"
+                      />
+                    </el-form-item>
+
+                    <el-form-item label="未完成提示语" class="form-item-full" v-if="selectedPoint.type !== '' && selectedPoint.type === 'task'">
+                      <el-input
+                        v-model="selectedPoint.unfinishedTip"
+                        placeholder="输入未完成提示语"
+                        style="width: 100%"
+                        show-word-limit
+                        maxlength="100"
+                        type="textarea"
+                        :rows="2"
+                      />
+                    </el-form-item>
+
+                    <el-form-item label="完成提示语" class="form-item-full" v-if="selectedPoint.type !== '' && selectedPoint.type === 'task'">
+                      <el-input
+                        v-model="selectedPoint.finishedTip"
+                        placeholder="输入完成提示语"
+                        style="width: 100%"
+                        show-word-limit
+                        maxlength="100"
+                        type="textarea"
+                        :rows="2"
+                      />
+                    </el-form-item>
+                  </template>
+                </el-card>
+              </el-form>
+            </div>
+
+            <div v-else class="no-selection">
+              <el-empty description="请点击左侧方格进行配置" />
+            </div>
+          </el-col>
+        </el-row>
+      </el-form-item>
 
       <el-row>
         <el-col :span="12">
@@ -210,7 +331,7 @@ const formData = ref({
   info: undefined,
   userImage: 'https://learn-ai.com.cn/admin-api/infra/file/29/get/20251107/user_1762504554550.png',
   userDirection: 0,
-  mapTileSize: undefined,
+  mapTileSize: undefined, // 保持兼容性
   mapStartPoint: undefined,
   mapBackground: undefined,
   mapEndPoint: undefined,
@@ -225,30 +346,84 @@ const mapStartPointX = ref<number>()
 const mapStartPointY = ref<number>()
 const mapEndPointX = ref<number>()
 const mapEndPointY = ref<number>()
+const mapTileX = ref<number>(5) // 横向数量,默认5
+const mapTileY = ref<number>(5) // 纵向数量,默认5
+
+// 选中的点
+const selectedPoint = ref<WalkablePoint | null>(null)
+
+// 所有格子数据
+const gridCells = computed(() => {
+  const cells = []
+  for (let y = 1; y <= (mapTileY.value || 5); y++) {
+    for (let x = 1; x <= (mapTileX.value || 5); x++) {
+      cells.push({ x, y })
+    }
+  }
+  return cells
+})
 
 // 可行走点接口定义
 interface WalkablePoint {
   x: number
   y: number
+  walkable: boolean
   type: string
-  need: string
+  must: boolean
   img: string
-  needImg: string
+  endImg: string
   tip: string
+  unfinishedTip: string
+  finishedTip: string
 }
 
 // 可行走点数组
-const walkablePoints = ref<WalkablePoint[]>([{ x: 0, y: 0, type: '', need: '', img:'', needImg:'', tip: '' }])
+const walkablePoints = ref<WalkablePoint[]>([])
 
 const formRules = reactive({
   name: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
   userImage: [{ required: true, message: '人物图标不能为空', trigger: 'blur' }],
   mapBackground: [{ required: true, message: '地图背景图不能为空', trigger: 'blur' }],
-  mapTileSize: [{ required: true, message: '地图方格尺寸不能为空', trigger: 'blur' }],
   userDirection: [{ required: true, message: '人物朝向不能为空', trigger: 'blur' }]
 })
 const formRef = ref() // 表单 Ref
 
+/** 获取指定坐标的点配置 */
+const getPointByXY = (x: number, y: number): WalkablePoint | undefined => {
+  return walkablePoints.value.find(point => point.x === x && point.y === y)
+}
+
+/** 判断指定坐标是否可行走 */
+const isWalkable = (x: number, y: number): boolean => {
+  const point = getPointByXY(x, y)
+  return point ? point.walkable : false
+}
+
+/** 选择格子 */
+const selectCell = (cell: { x: number, y: number }) => {
+  // 查找是否已有该点的配置
+  let point = getPointByXY(cell.x, cell.y)
+
+  // 如果没有,创建新的配置
+  if (!point) {
+    point = {
+      x: cell.x,
+      y: cell.y,
+      walkable: false,
+      type: '',
+      must: false,
+      img: '',
+      endImg: '',
+      tip: '',
+      unfinishedTip: '',
+      finishedTip: ''
+    }
+    walkablePoints.value.push(point)
+  }
+
+  selectedPoint.value = point
+}
+
 /** 打开弹窗 */
 const open = async (type: string, id?: number) => {
   dialogVisible.value = true
@@ -286,12 +461,37 @@ const open = async (type: string, id?: number) => {
         }
       }
 
+      // 解析地图尺寸 - 如果有旧的mapTileSize,设置合理的默认值
+      if (data.mapTileSize) {
+        try {
+          const point = JSON.parse(data.mapTileSize)
+          mapTileX.value = point.x
+          mapTileY.value = point.y
+        } catch (e) {
+          console.error('解析地图结束坐标失败:', e)
+        }
+      }
+
+      // 解析地图可行走点
       if (data.mapWalkablePoints) {
         try {
-          walkablePoints.value = JSON.parse(data.mapWalkablePoints)
+          const points = JSON.parse(data.mapWalkablePoints)
+          // 转换为新的格式,如果是旧格式需要兼容
+          walkablePoints.value = points.map((p: any) => ({
+            x: p.x,
+            y: p.y,
+            walkable: true,
+            type: p.type || '',
+            must: p.must || false,
+            img: p.img || '',
+            endImg: p.endImg || '',
+            tip: p.tip || '',
+            unfinishedTip: p.unfinishedTip || '',
+            finishedTip: p.finishedTip || ''
+          }))
         } catch (e) {
           console.error('解析地图可行走坐标失败:', e)
-          walkablePoints.value = [{ x: 0, y: 0, type: '', need: '', img:'', needImg:'', tip: '' }]
+          walkablePoints.value = []
         }
       }
     } finally {
@@ -301,18 +501,6 @@ const open = async (type: string, id?: number) => {
 }
 defineExpose({ open }) // 提供 open 方法,用于打开弹窗
 
-/** 添加可行走点 */
-const addWalkablePoint = () => {
-  walkablePoints.value.push({ x: 0, y: 0, type: '', need: '', img:'', needImg:'', tip: '' })
-}
-
-/** 移除可行走点 */
-const removeWalkablePoint = (index: number) => {
-  if (walkablePoints.value.length > 1) {
-    walkablePoints.value.splice(index, 1)
-  }
-}
-
 /** 提交表单 */
 const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
 const submitForm = async () => {
@@ -327,6 +515,11 @@ const submitForm = async () => {
     return
   }
 
+  if (mapTileX.value === undefined || mapTileY.value === undefined) {
+    message.error('地图方格尺寸不能为空')
+    return
+  }
+
   // 检查可行走点数据
   const hasInvalidPoint = walkablePoints.value.some(
     (point) => point.x === undefined || point.y === undefined
@@ -344,9 +537,31 @@ const submitForm = async () => {
   const submitData = { ...formData.value } as MapGameVO
 
   // 设置坐标JSON
+  submitData.mapTileSize = JSON.stringify({ x: mapTileX.value, y: mapTileY.value })
   submitData.mapStartPoint = JSON.stringify({ x: mapStartPointX.value, y: mapStartPointY.value })
   submitData.mapEndPoint = JSON.stringify({ x: mapEndPointX.value, y: mapEndPointY.value })
-  submitData.mapWalkablePoints = JSON.stringify(walkablePoints.value)
+
+  // 只保存可行走的点
+  const walkableOnlyPoints = walkablePoints.value.filter(point => point.walkable)
+  submitData.mapWalkablePoints = JSON.stringify(walkableOnlyPoints)
+
+  // 过滤出有效的可行走点 - 修复后的代码
+  const validWalkablePoints = walkablePoints.value.filter(point => {
+    // 同时检查:1) walkable为true 2) 坐标在有效范围内
+    const isWalkable = point.walkable
+    const isValidX = point.x <= mapTileX.value
+    const isValidY = point.y <= mapTileY.value
+    return isWalkable && isValidX && isValidY
+  })
+
+  // 移除重复的点(基于x和y坐标)
+  const uniquePoints = validWalkablePoints.filter((point, index, self) => {
+    return index === self.findIndex(p => p.x === point.x && p.y === point.y)
+  })
+
+  // 保存有效的可行走点
+  submitData.mapWalkablePoints = JSON.stringify(uniquePoints)
+
 
   // 提交请求
   formLoading.value = true
@@ -372,8 +587,7 @@ const resetForm = () => {
     id: undefined,
     name: undefined,
     info: undefined,
-    userImage:
-      'https://learn-ai.com.cn/admin-api/infra/file/29/get/20251107/user_1762504554550.png',
+    userImage: 'https://learn-ai.com.cn/admin-api/infra/file/29/get/20251107/user_1762504554550.png',
     userDirection: 0,
     mapTileSize: undefined,
     mapStartPoint: undefined,
@@ -385,12 +599,15 @@ const resetForm = () => {
     status: 0
   }
 
-  // 重置新增的响应式数据
+  // 重置响应式数据
   mapStartPointX.value = undefined
   mapStartPointY.value = undefined
   mapEndPointX.value = undefined
   mapEndPointY.value = undefined
-  walkablePoints.value = [{ x: 0, y: 0, type: '', need: '', img:'', needImg:'', tip: '' }]
+  mapTileX.value = 5
+  mapTileY.value = 5
+  walkablePoints.value = []
+  selectedPoint.value = null
 
   formRef.value?.resetFields()
 }
@@ -404,41 +621,216 @@ const resetForm = () => {
   gap: 8px;
 }
 
-.coordinate-separator {
-  font-size: 16px;
-  color: #606266;
-}
-
-/* 可行走点样式 */
-.walkable-points-container {
-  max-height: 400px;
-  overflow-y: auto;
+/* 地图网格样式 */
+.map-grid-container {
+  overflow: auto;
   border: 1px solid #dcdfe6;
   border-radius: 4px;
-  padding: 15px;
+  padding: 10px;
   background-color: #f9f9f9;
 }
 
-.walkable-point-item {
+.map-grid {
+  display: grid;
+  gap: 2px;
+  width: 100%;
+}
+
+.grid-cell {
+  aspect-ratio: 1;
+  border: 1px solid #dcdfe6;
+  background-color: rgba(255, 255, 255, 0.9);
+  cursor: pointer;
+  position: relative;
   display: flex;
   align-items: center;
-  gap: 10px;
-  margin-bottom: 10px;
+  justify-content: center;
+  transition: all 0.3s;
+  min-height: 40px;
+}
+
+.grid-cell:hover {
+  border-color: #409eff;
+}
+
+.grid-cell.selected {
+  border: 3px solid #409eff;
+  background-color: rgba(236, 245, 255, 0.8);
+  box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.3);
+  transform: scale(1.05);
+  z-index: 10;
+}
+/* 同时优化选中状态与其他状态的组合样式 */
+.grid-cell.selected.walkable {
+  border: 3px solid #409eff;
+  background-color: rgba(230, 247, 233, 0.8); /* 结合可行走的背景色 */
+  box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.3);
+}
+
+.grid-cell.selected.has-icon {
+  border: 3px solid #409eff;
+  background-color: rgba(255, 243, 230, 0.8); /* 结合有图标的背景色 */
+  box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.3);
+}
+
+.grid-cell.walkable {
+  background-color: rgba(240, 249, 235, 0.8);
+  border: 3px solid rgb(103, 194, 58);
+}
+
+.grid-cell.has-icon {
+  background-color: rgba(253, 246, 236, 0.8);
+}
+
+.cell-coordinate {
+  position: absolute;
+  top: 2px;
+  left: 4px;
+  font-size: 12px;
+  color: #909399;
+}
+
+.cell-icon {
+  max-width: 80%;
+  max-height: 80%;
+}
+
+.cell-icon img {
+  max-width: 100%;
+  max-height: 100%;
+  object-fit: contain;
+}
+
+/* 右侧配置区域样式 */
+.point-config-container {
+  overflow-y: auto;
   padding: 10px;
-  background-color: #fff;
-  border-radius: 4px;
-  border: 1px solid #e4e7ed;
-  text-align: center;
 }
 
-.walkable-point-item:last-child {
+.config-form {
+  width: 100%;
+}
+
+.config-card {
   margin-bottom: 0;
+  border-radius: 8px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  font-weight: bold;
+  color: #303133;
+}
+
+.form-item-row {
+  margin-bottom: 20px;
+}
+
+.form-grid {
+  display: grid;
+  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+  gap: 20px;
+  margin-bottom: 20px;
+}
+
+.form-item-col {
+  margin-bottom: 0;
+}
+
+.icon-upload-container {
+  margin-bottom: 20px;
+}
+
+.icon-upload-item {
+  margin-bottom: 15px;
+}
+
+.custom-upload {
+  display: flex;
+  align-items: center;
+}
+
+.upload-tip {
+  margin-left: 10px;
+  font-size: 12px;
+  color: #67c23a;
+}
+
+/* 优化空状态样式 */
+.no-selection {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  height: 300px;
+  background-color: #f5f7fa;
+  border-radius: 8px;
+  border: 1px dashed #dcdfe6;
 }
 
-/* 确保上传组件预览图不超过行高 */
-.walkable-point-item :deep(.el-upload) {
-  max-height: 32px;
-  max-width: 100px;
-  margin-bottom: -6px;
+/* 优化滚动条样式 */
+.point-config-container::-webkit-scrollbar {
+  width: 8px;
+  height: 8px;
+}
+
+.point-config-container::-webkit-scrollbar-thumb {
+  border-radius: 4px;
+  background: #c0c4cc;
+}
+
+.point-config-container::-webkit-scrollbar-track {
+  background: #f0f0f0;
+  border-radius: 4px;
+}
+
+/* 配置项行布局 */
+.config-row {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 20px;
+  margin-bottom: 20px;
+  align-items: flex-start;
+}
+
+.config-item {
+  flex: 1;
+  min-width: 200px;
+  margin-bottom: 0 !important;
+}
+
+.form-item-full {
+  margin-bottom: 20px;
+}
+
+/* 图标上传包装器 */
+.icon-upload-wrapper {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+}
+
+/* 上传提示 */
+.upload-tip {
+  font-size: 12px;
+  color: #67c23a;
+  margin-top: 4px;
+}
+
+/* 调整标签宽度以适应行布局 */
+:deep(.el-form-item__label) {
+  white-space: nowrap;
+}
+
+/* 响应式调整 */
+@media screen and (max-width: 768px) {
+  .config-row {
+    flex-direction: column;
+  }
+
+  .config-item {
+    width: 100%;
+  }
 }
 </style>

+ 4 - 3
src/views/ai/mapgame/index.vue

@@ -96,18 +96,19 @@
       </el-table-column>
       <el-table-column label="地图方格尺寸" align="center" prop="mapTileSize" >
         <template #default="scope">
-          {{ scope.row.mapTileSize }}px
+          <span v-if="scope.row.mapTileSize">{{JSON.parse(scope.row.mapTileSize).x + '-' + JSON.parse(scope.row.mapTileSize).y}}</span>
+          <span v-else>-</span>
         </template>
       </el-table-column>
       <el-table-column label="地图开始坐标" align="center" prop="mapStartPoint">
         <template #default="scope">
-          <LazyJsonViewer v-if="scope.row.mapStartPoint" :json-data="scope.row.mapStartPoint" />
+          <span v-if="scope.row.mapStartPoint">{{JSON.parse(scope.row.mapStartPoint).x + '-' + JSON.parse(scope.row.mapStartPoint).y}}</span>
           <span v-else>-</span>
         </template>
       </el-table-column>
       <el-table-column label="地图结束坐标" align="center" prop="mapEndPoint">
         <template #default="scope">
-          <LazyJsonViewer v-if="scope.row.mapEndPoint" :json-data="scope.row.mapEndPoint" />
+          <span v-if="scope.row.mapEndPoint">{{JSON.parse(scope.row.mapEndPoint).x + '-' + JSON.parse(scope.row.mapEndPoint).y}}</span>
           <span v-else>-</span>
         </template>
       </el-table-column>