|
@@ -6,7 +6,7 @@
|
|
|
:rules="formRules"
|
|
:rules="formRules"
|
|
|
label-width="120px"
|
|
label-width="120px"
|
|
|
v-loading="formLoading"
|
|
v-loading="formLoading"
|
|
|
- >x
|
|
|
|
|
|
|
+ >
|
|
|
<el-form-item label="大纲课程" prop="bcType">
|
|
<el-form-item label="大纲课程" prop="bcType">
|
|
|
<el-tree-select
|
|
<el-tree-select
|
|
|
v-model="formData.bcType"
|
|
v-model="formData.bcType"
|
|
@@ -171,42 +171,7 @@
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
|
|
|
|
|
- <el-col :span="12">
|
|
|
|
|
- <el-form-item label="人物朝向" prop="blocklyUserDirection">
|
|
|
|
|
- <el-radio-group v-model="formData.blocklyUserDirection" size="large">
|
|
|
|
|
- <el-radio-button label="上" :value="0" />
|
|
|
|
|
- <el-radio-button label="右" :value="1" />
|
|
|
|
|
- <el-radio-button label="下" :value="2" />
|
|
|
|
|
- <el-radio-button label="左" :value="3" />
|
|
|
|
|
- </el-radio-group>
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- <el-col :span="12">
|
|
|
|
|
- <!-- 地图开始坐标 - 拆分为X轴和Y轴 -->
|
|
|
|
|
- <el-form-item label="地图开始坐标" required>
|
|
|
|
|
- <div class="coordinate-group">
|
|
|
|
|
- X:
|
|
|
|
|
- <el-input-number
|
|
|
|
|
- v-model="blocklyStartPointX"
|
|
|
|
|
- placeholder="X轴"
|
|
|
|
|
- :min="1"
|
|
|
|
|
- :max="blocklyTileX"
|
|
|
|
|
- :step="1"
|
|
|
|
|
- style="width: 120px"
|
|
|
|
|
- />
|
|
|
|
|
- Y:
|
|
|
|
|
- <el-input-number
|
|
|
|
|
- v-model="blocklyStartPointY"
|
|
|
|
|
- placeholder="Y轴"
|
|
|
|
|
- :min="1"
|
|
|
|
|
- :max="blocklyTileY"
|
|
|
|
|
- :step="1"
|
|
|
|
|
- style="width: 120px"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- <el-col :span="12">
|
|
|
|
|
|
|
+ <el-col :span="24">
|
|
|
<el-form-item label="地图方格尺寸" required>
|
|
<el-form-item label="地图方格尺寸" required>
|
|
|
<div class="coordinate-group">
|
|
<div class="coordinate-group">
|
|
|
X:
|
|
X:
|
|
@@ -228,28 +193,96 @@
|
|
|
</div>
|
|
</div>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
- <el-col :span="12">
|
|
|
|
|
- <!-- 地图结束坐标 - 拆分为X轴和Y轴 -->
|
|
|
|
|
- <el-form-item label="地图结束坐标" required>
|
|
|
|
|
- <div class="coordinate-group">
|
|
|
|
|
- X:
|
|
|
|
|
- <el-input-number
|
|
|
|
|
- v-model="blocklyEndPointX"
|
|
|
|
|
- placeholder="X轴"
|
|
|
|
|
- :min="1"
|
|
|
|
|
- :max="blocklyTileX"
|
|
|
|
|
- :step="1"
|
|
|
|
|
- style="width: 120px"
|
|
|
|
|
- />
|
|
|
|
|
- Y:
|
|
|
|
|
- <el-input-number
|
|
|
|
|
- v-model="blocklyEndPointY"
|
|
|
|
|
- placeholder="Y轴"
|
|
|
|
|
- :min="1"
|
|
|
|
|
- :max="blocklyTileY"
|
|
|
|
|
- :step="1"
|
|
|
|
|
- style="width: 120px"
|
|
|
|
|
- />
|
|
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 路线配置 -->
|
|
|
|
|
+ <el-col :span="24">
|
|
|
|
|
+ <el-form-item label="路线配置" required>
|
|
|
|
|
+ <el-button type="primary" @click="addRoute" style="margin-bottom: 12px;">新增路线</el-button>
|
|
|
|
|
+ <div class="route-config-container">
|
|
|
|
|
+ <div v-for="(route, index) in blocklyRoutes" :key="route.id" class="route-config-item">
|
|
|
|
|
+ <div class="route-row">
|
|
|
|
|
+ <div class="route-title">
|
|
|
|
|
+ <span>路线 {{ index + 1 }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="route-fields">
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 人物朝向 -->
|
|
|
|
|
+ <div class="route-field">
|
|
|
|
|
+ <span class="field-label">人物朝向:</span>
|
|
|
|
|
+ <el-radio-group v-model="route.direction" class="direction-radio">
|
|
|
|
|
+ <el-radio-button label="上" :value="0" />
|
|
|
|
|
+ <el-radio-button label="右" :value="1" />
|
|
|
|
|
+ <el-radio-button label="下" :value="2" />
|
|
|
|
|
+ <el-radio-button label="左" :value="3" />
|
|
|
|
|
+ </el-radio-group>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 开始坐标 -->
|
|
|
|
|
+ <div class="route-field">
|
|
|
|
|
+ <span class="field-label">开始坐标:</span>
|
|
|
|
|
+ <div class="coordinate-group">
|
|
|
|
|
+ <el-input-number
|
|
|
|
|
+ v-model="route.startPoint.x"
|
|
|
|
|
+ placeholder="X"
|
|
|
|
|
+ :min="1"
|
|
|
|
|
+ :max="blocklyTileX"
|
|
|
|
|
+ :step="1"
|
|
|
|
|
+ class="coordinate-input"
|
|
|
|
|
+ style="width: 100px"
|
|
|
|
|
+ />
|
|
|
|
|
+ <el-input-number
|
|
|
|
|
+ v-model="route.startPoint.y"
|
|
|
|
|
+ placeholder="Y"
|
|
|
|
|
+ :min="1"
|
|
|
|
|
+ :max="blocklyTileY"
|
|
|
|
|
+ :step="1"
|
|
|
|
|
+ class="coordinate-input"
|
|
|
|
|
+ style="width: 100px"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 结束坐标 -->
|
|
|
|
|
+ <div class="route-field">
|
|
|
|
|
+ <span class="field-label">结束坐标:</span>
|
|
|
|
|
+ <div class="coordinate-group">
|
|
|
|
|
+ <el-input-number
|
|
|
|
|
+ v-model="route.endPoint.x"
|
|
|
|
|
+ placeholder="X"
|
|
|
|
|
+ :min="1"
|
|
|
|
|
+ :max="blocklyTileX"
|
|
|
|
|
+ :step="1"
|
|
|
|
|
+ class="coordinate-input"
|
|
|
|
|
+ style="width: 100px"
|
|
|
|
|
+ />
|
|
|
|
|
+ <el-input-number
|
|
|
|
|
+ v-model="route.endPoint.y"
|
|
|
|
|
+ placeholder="Y"
|
|
|
|
|
+ :min="1"
|
|
|
|
|
+ :max="blocklyTileY"
|
|
|
|
|
+ :step="1"
|
|
|
|
|
+ class="coordinate-input"
|
|
|
|
|
+ style="width: 100px"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 删除按钮 -->
|
|
|
|
|
+ <div class="route-delete-btn">
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ type="danger"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ @click="deleteRoute(route.id)"
|
|
|
|
|
+ :disabled="blocklyRoutes.length <= 1"
|
|
|
|
|
+ plain
|
|
|
|
|
+ >
|
|
|
|
|
+ 删除
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
@@ -323,7 +356,7 @@
|
|
|
<template v-if="selectedBlocklyPoint.walkable">
|
|
<template v-if="selectedBlocklyPoint.walkable">
|
|
|
<!-- 第二行:地图类型 -->
|
|
<!-- 第二行:地图类型 -->
|
|
|
<div class="config-row" style="display: flex; flex-wrap: wrap; gap: 20px;">
|
|
<div class="config-row" style="display: flex; flex-wrap: wrap; gap: 20px;">
|
|
|
- <el-form-item label="地图类型" class="config-item"
|
|
|
|
|
|
|
+ <el-form-item label="地图类型" class="config-item"
|
|
|
:style="(selectedBlocklyPoint.type === 'task' || selectedBlocklyPoint.type === 'item') ? 'width: calc(50% - 20px);' : 'width: 100%;'">
|
|
:style="(selectedBlocklyPoint.type === 'task' || selectedBlocklyPoint.type === 'item') ? 'width: calc(50% - 20px);' : 'width: 100%;'">
|
|
|
<el-select
|
|
<el-select
|
|
|
v-model="selectedBlocklyPoint.type"
|
|
v-model="selectedBlocklyPoint.type"
|
|
@@ -516,16 +549,15 @@ const blocklyConfigTitle = ref('配置Blockly数据')
|
|
|
const blocklyConfigFormRef = ref() // Blockly配置表单Ref
|
|
const blocklyConfigFormRef = ref() // Blockly配置表单Ref
|
|
|
|
|
|
|
|
// Blockly配置相关响应式数据
|
|
// Blockly配置相关响应式数据
|
|
|
-const blocklyStartPointX = ref<number>()
|
|
|
|
|
-const blocklyStartPointY = ref<number>()
|
|
|
|
|
-const blocklyEndPointX = ref<number>()
|
|
|
|
|
-const blocklyEndPointY = ref<number>()
|
|
|
|
|
const blocklyTileX = ref<number>(6) // 横向数量,默认5
|
|
const blocklyTileX = ref<number>(6) // 横向数量,默认5
|
|
|
const blocklyTileY = ref<number>(5) // 纵向数量,默认5
|
|
const blocklyTileY = ref<number>(5) // 纵向数量,默认5
|
|
|
|
|
|
|
|
// 选中的点
|
|
// 选中的点
|
|
|
const selectedBlocklyPoint = ref<BlocklyWalkablePoint | null>(null)
|
|
const selectedBlocklyPoint = ref<BlocklyWalkablePoint | null>(null)
|
|
|
|
|
|
|
|
|
|
+// 路线ID计数器
|
|
|
|
|
+const routeIdCounter = ref(1)
|
|
|
|
|
+
|
|
|
// 可行走点接口定义
|
|
// 可行走点接口定义
|
|
|
interface BlocklyWalkablePoint {
|
|
interface BlocklyWalkablePoint {
|
|
|
x: number
|
|
x: number
|
|
@@ -542,9 +574,20 @@ interface BlocklyWalkablePoint {
|
|
|
finishedTip: string
|
|
finishedTip: string
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// 路线接口定义
|
|
|
|
|
+interface BlocklyRoute {
|
|
|
|
|
+ id: number
|
|
|
|
|
+ direction: number
|
|
|
|
|
+ startPoint: { x: number, y: number }
|
|
|
|
|
+ endPoint: { x: number, y: number }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// 可行走点数组
|
|
// 可行走点数组
|
|
|
const blocklyWalkablePoints = ref<BlocklyWalkablePoint[]>([])
|
|
const blocklyWalkablePoints = ref<BlocklyWalkablePoint[]>([])
|
|
|
|
|
|
|
|
|
|
+// 路线数组
|
|
|
|
|
+const blocklyRoutes = ref<BlocklyRoute[]>([])
|
|
|
|
|
+
|
|
|
const formData = ref({
|
|
const formData = ref({
|
|
|
id: undefined,
|
|
id: undefined,
|
|
|
bcName: undefined,
|
|
bcName: undefined,
|
|
@@ -553,13 +596,11 @@ const formData = ref({
|
|
|
|
|
|
|
|
blocklyInfo: undefined,
|
|
blocklyInfo: undefined,
|
|
|
blocklyUserImage: 'https://learn-ai.com.cn/admin-api/infra/file/29/get/20251107/user_1762504554550.png',
|
|
blocklyUserImage: 'https://learn-ai.com.cn/admin-api/infra/file/29/get/20251107/user_1762504554550.png',
|
|
|
- blocklyUserDirection: 0,
|
|
|
|
|
blocklyTileSize: undefined,
|
|
blocklyTileSize: undefined,
|
|
|
- blocklyStartPoint: undefined,
|
|
|
|
|
blocklyBackground: undefined,
|
|
blocklyBackground: undefined,
|
|
|
- blocklyEndPoint: undefined,
|
|
|
|
|
blocklyWalkablePoints: undefined,
|
|
blocklyWalkablePoints: undefined,
|
|
|
blocklySpecialBlocks: undefined,
|
|
blocklySpecialBlocks: undefined,
|
|
|
|
|
+ blocklyRouteList: undefined,
|
|
|
|
|
|
|
|
bcIsInspect: "false",
|
|
bcIsInspect: "false",
|
|
|
bcType: undefined,
|
|
bcType: undefined,
|
|
@@ -592,10 +633,13 @@ const blocklyGridCells = computed(() => {
|
|
|
const hasBlocklyConfig = computed(() => {
|
|
const hasBlocklyConfig = computed(() => {
|
|
|
return formData.value.blocklyUserImage &&
|
|
return formData.value.blocklyUserImage &&
|
|
|
formData.value.blocklyBackground &&
|
|
formData.value.blocklyBackground &&
|
|
|
- blocklyStartPointX.value !== undefined &&
|
|
|
|
|
- blocklyStartPointY.value !== undefined &&
|
|
|
|
|
- blocklyEndPointX.value !== undefined &&
|
|
|
|
|
- blocklyEndPointY.value !== undefined &&
|
|
|
|
|
|
|
+ blocklyRoutes.value.length > 0 &&
|
|
|
|
|
+ blocklyRoutes.value.every(route =>
|
|
|
|
|
+ route.startPoint.x !== undefined &&
|
|
|
|
|
+ route.startPoint.y !== undefined &&
|
|
|
|
|
+ route.endPoint.x !== undefined &&
|
|
|
|
|
+ route.endPoint.y !== undefined
|
|
|
|
|
+ ) &&
|
|
|
blocklyTileX.value !== undefined &&
|
|
blocklyTileX.value !== undefined &&
|
|
|
blocklyTileY.value !== undefined
|
|
blocklyTileY.value !== undefined
|
|
|
})
|
|
})
|
|
@@ -621,8 +665,7 @@ const formRules = reactive({
|
|
|
// Blockly配置表单验证规则
|
|
// Blockly配置表单验证规则
|
|
|
const blocklyConfigRules = reactive({
|
|
const blocklyConfigRules = reactive({
|
|
|
blocklyUserImage: [{ required: true, message: '人物图标不能为空', trigger: 'blur' }],
|
|
blocklyUserImage: [{ required: true, message: '人物图标不能为空', trigger: 'blur' }],
|
|
|
- blocklyBackground: [{ required: true, message: '地图背景图不能为空', trigger: 'blur' }],
|
|
|
|
|
- blocklyUserDirection: [{ required: true, message: '人物朝向不能为空', trigger: 'blur' }],
|
|
|
|
|
|
|
+ blocklyBackground: [{ required: true, message: '地图背景图不能为空', trigger: 'blur' }]
|
|
|
// blocklyInfo: [{ required: true, message: 'Blockly信息不能为空', trigger: 'blur' }]
|
|
// blocklyInfo: [{ required: true, message: 'Blockly信息不能为空', trigger: 'blur' }]
|
|
|
})
|
|
})
|
|
|
|
|
|
|
@@ -680,39 +723,87 @@ const open = async (type: string, id?: number) => {
|
|
|
formData.value.bcType = id ? Number(id) : undefined
|
|
formData.value.bcType = id ? Number(id) : undefined
|
|
|
}
|
|
}
|
|
|
// 修改时,设置数据
|
|
// 修改时,设置数据
|
|
|
- if (type === 'update' && id) {
|
|
|
|
|
- formLoading.value = true
|
|
|
|
|
- try {
|
|
|
|
|
- const blocklyData = await BlocklyApi.getBlockly(id)
|
|
|
|
|
- formData.value = {
|
|
|
|
|
- ...formData.value,
|
|
|
|
|
- ...blocklyData,
|
|
|
|
|
- bcContent: blocklyData.bcType === "image" ? blocklyData.bcContent?.split(',') : blocklyData.bcContent,
|
|
|
|
|
- bcInfo: blocklyData.bcInfo || ''
|
|
|
|
|
- }
|
|
|
|
|
- // 确保 bcType 为正确的 id 类型
|
|
|
|
|
- formData.value.bcType = blocklyData.bcType ? Number(blocklyData.bcType) : undefined
|
|
|
|
|
-
|
|
|
|
|
- // 处理回显数据 - 解析坐标JSON
|
|
|
|
|
- if (blocklyData.blocklyStartPoint) {
|
|
|
|
|
|
|
+ if (type === 'update' && id) {
|
|
|
|
|
+ formLoading.value = true
|
|
|
try {
|
|
try {
|
|
|
- const point = JSON.parse(blocklyData.blocklyStartPoint)
|
|
|
|
|
- blocklyStartPointX.value = point.x
|
|
|
|
|
- blocklyStartPointY.value = point.y
|
|
|
|
|
- } catch (e) {
|
|
|
|
|
- console.error('解析地图开始坐标失败:', e)
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (blocklyData.blocklyEndPoint) {
|
|
|
|
|
- try {
|
|
|
|
|
- const point = JSON.parse(blocklyData.blocklyEndPoint)
|
|
|
|
|
- blocklyEndPointX.value = point.x
|
|
|
|
|
- blocklyEndPointY.value = point.y
|
|
|
|
|
- } catch (e) {
|
|
|
|
|
- console.error('解析地图结束坐标失败:', e)
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ const blocklyData = await BlocklyApi.getBlockly(id)
|
|
|
|
|
+ formData.value = {
|
|
|
|
|
+ ...formData.value,
|
|
|
|
|
+ ...blocklyData,
|
|
|
|
|
+ bcContent: blocklyData.bcType === "image" ? blocklyData.bcContent?.split(',') : blocklyData.bcContent,
|
|
|
|
|
+ bcInfo: blocklyData.bcInfo || ''
|
|
|
|
|
+ }
|
|
|
|
|
+ // 确保 bcType 为正确的 id 类型
|
|
|
|
|
+ formData.value.bcType = blocklyData.bcType ? Number(blocklyData.bcType) : undefined
|
|
|
|
|
+
|
|
|
|
|
+ // 处理回显数据 - 解析路线JSON
|
|
|
|
|
+ if (blocklyData.blocklyRouteList) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ blocklyRoutes.value = JSON.parse(blocklyData.blocklyRouteList)
|
|
|
|
|
+ routeIdCounter.value = Math.max(...blocklyRoutes.value.map(route => route.id)) + 1
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.error('解析路线数据失败:', e)
|
|
|
|
|
+ // 如果没有路线数据,使用旧的单路线数据
|
|
|
|
|
+ blocklyRoutes.value = []
|
|
|
|
|
+ if (blocklyData.blocklyStartPoint && blocklyData.blocklyEndPoint) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const startPoint = JSON.parse(blocklyData.blocklyStartPoint)
|
|
|
|
|
+ const endPoint = JSON.parse(blocklyData.blocklyEndPoint)
|
|
|
|
|
+ blocklyRoutes.value.push({
|
|
|
|
|
+ id: routeIdCounter.value++,
|
|
|
|
|
+ direction: blocklyData.blocklyUserDirection || 0,
|
|
|
|
|
+ startPoint: startPoint,
|
|
|
|
|
+ endPoint: endPoint
|
|
|
|
|
+ })
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.error('解析旧路线数据失败:', e)
|
|
|
|
|
+ blocklyRoutes.value = [{
|
|
|
|
|
+ id: routeIdCounter.value++,
|
|
|
|
|
+ direction: 0,
|
|
|
|
|
+ startPoint: { x: undefined, y: undefined },
|
|
|
|
|
+ endPoint: { x: undefined, y: undefined }
|
|
|
|
|
+ }]
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ blocklyRoutes.value = [{
|
|
|
|
|
+ id: routeIdCounter.value++,
|
|
|
|
|
+ direction: 0,
|
|
|
|
|
+ startPoint: { x: undefined, y: undefined },
|
|
|
|
|
+ endPoint: { x: undefined, y: undefined }
|
|
|
|
|
+ }]
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 兼容旧数据结构
|
|
|
|
|
+ blocklyRoutes.value = []
|
|
|
|
|
+ if (blocklyData.blocklyStartPoint && blocklyData.blocklyEndPoint) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const startPoint = JSON.parse(blocklyData.blocklyStartPoint)
|
|
|
|
|
+ const endPoint = JSON.parse(blocklyData.blocklyEndPoint)
|
|
|
|
|
+ blocklyRoutes.value.push({
|
|
|
|
|
+ id: routeIdCounter.value++,
|
|
|
|
|
+ direction: blocklyData.blocklyUserDirection || 0,
|
|
|
|
|
+ startPoint: startPoint,
|
|
|
|
|
+ endPoint: endPoint
|
|
|
|
|
+ })
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.error('解析旧路线数据失败:', e)
|
|
|
|
|
+ blocklyRoutes.value = [{
|
|
|
|
|
+ id: routeIdCounter.value++,
|
|
|
|
|
+ direction: 0,
|
|
|
|
|
+ startPoint: { x: undefined, y: undefined },
|
|
|
|
|
+ endPoint: { x: undefined, y: undefined }
|
|
|
|
|
+ }]
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ blocklyRoutes.value = [{
|
|
|
|
|
+ id: routeIdCounter.value++,
|
|
|
|
|
+ direction: 0,
|
|
|
|
|
+ startPoint: { x: undefined, y: undefined },
|
|
|
|
|
+ endPoint: { x: undefined, y: undefined }
|
|
|
|
|
+ }]
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
// 解析地图尺寸
|
|
// 解析地图尺寸
|
|
|
if (blocklyData.blocklyTileSize) {
|
|
if (blocklyData.blocklyTileSize) {
|
|
@@ -767,17 +858,46 @@ const openBlocklyConfigDialog = () => {
|
|
|
blocklyConfigVisible.value = true
|
|
blocklyConfigVisible.value = true
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// 添加新路线
|
|
|
|
|
+const addRoute = () => {
|
|
|
|
|
+ blocklyRoutes.value.push({
|
|
|
|
|
+ id: routeIdCounter.value++,
|
|
|
|
|
+ direction: 0,
|
|
|
|
|
+ startPoint: { x: undefined, y: undefined },
|
|
|
|
|
+ endPoint: { x: undefined, y: undefined }
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 删除路线
|
|
|
|
|
+const deleteRoute = (routeId: number) => {
|
|
|
|
|
+ if (blocklyRoutes.value.length <= 1) {
|
|
|
|
|
+ message.warning('不能删除最后一条路线')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ const index = blocklyRoutes.value.findIndex(route => route.id === routeId)
|
|
|
|
|
+ if (index > -1) {
|
|
|
|
|
+ blocklyRoutes.value.splice(index, 1)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/** 保存Blockly配置 */
|
|
/** 保存Blockly配置 */
|
|
|
const saveBlocklyConfig = async () => {
|
|
const saveBlocklyConfig = async () => {
|
|
|
// 坐标数据验证
|
|
// 坐标数据验证
|
|
|
- if (blocklyStartPointX.value === undefined || blocklyStartPointY.value === undefined) {
|
|
|
|
|
- message.error('地图开始坐标不能为空')
|
|
|
|
|
|
|
+ if (blocklyRoutes.value.length === 0) {
|
|
|
|
|
+ message.error('至少需要配置一条路线')
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (blocklyEndPointX.value === undefined || blocklyEndPointY.value === undefined) {
|
|
|
|
|
- message.error('地图结束坐标不能为空')
|
|
|
|
|
- return
|
|
|
|
|
|
|
+ for (let i = 0; i < blocklyRoutes.value.length; i++) {
|
|
|
|
|
+ const route = blocklyRoutes.value[i]
|
|
|
|
|
+ if (route.startPoint.x === undefined || route.startPoint.y === undefined) {
|
|
|
|
|
+ message.error(`路线 ${i + 1} 的开始坐标不能为空`)
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if (route.endPoint.x === undefined || route.endPoint.y === undefined) {
|
|
|
|
|
+ message.error(`路线 ${i + 1} 的结束坐标不能为空`)
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (blocklyTileX.value === undefined || blocklyTileY.value === undefined) {
|
|
if (blocklyTileX.value === undefined || blocklyTileY.value === undefined) {
|
|
@@ -790,15 +910,14 @@ const saveBlocklyConfig = async () => {
|
|
|
|
|
|
|
|
// 设置坐标JSON
|
|
// 设置坐标JSON
|
|
|
formData.value.blocklyTileSize = JSON.stringify({ x: blocklyTileX.value, y: blocklyTileY.value })
|
|
formData.value.blocklyTileSize = JSON.stringify({ x: blocklyTileX.value, y: blocklyTileY.value })
|
|
|
- formData.value.blocklyStartPoint = JSON.stringify({ x: blocklyStartPointX.value, y: blocklyStartPointY.value })
|
|
|
|
|
- formData.value.blocklyEndPoint = JSON.stringify({ x: blocklyEndPointX.value, y: blocklyEndPointY.value })
|
|
|
|
|
|
|
+ formData.value.blocklyRouteList = JSON.stringify(blocklyRoutes.value)
|
|
|
|
|
|
|
|
// 只保存可行走的点
|
|
// 只保存可行走的点
|
|
|
const walkableOnlyPoints = blocklyWalkablePoints.value.filter(point => point.walkable)
|
|
const walkableOnlyPoints = blocklyWalkablePoints.value.filter(point => point.walkable)
|
|
|
formData.value.blocklyWalkablePoints = JSON.stringify(walkableOnlyPoints)
|
|
formData.value.blocklyWalkablePoints = JSON.stringify(walkableOnlyPoints)
|
|
|
|
|
|
|
|
blocklyConfigVisible.value = false
|
|
blocklyConfigVisible.value = false
|
|
|
- message.success('Blockly配置已保存')
|
|
|
|
|
|
|
+ message.success('Blockly配置已更改!')
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/** 提交表单 */
|
|
/** 提交表单 */
|
|
@@ -880,13 +999,11 @@ const resetForm = () => {
|
|
|
|
|
|
|
|
blocklyInfo: undefined,
|
|
blocklyInfo: undefined,
|
|
|
blocklyUserImage: 'https://learn-ai.com.cn/admin-api/infra/file/29/get/20251107/user_1762504554550.png',
|
|
blocklyUserImage: 'https://learn-ai.com.cn/admin-api/infra/file/29/get/20251107/user_1762504554550.png',
|
|
|
- blocklyUserDirection: 0,
|
|
|
|
|
blocklyTileSize: undefined,
|
|
blocklyTileSize: undefined,
|
|
|
- blocklyStartPoint: undefined,
|
|
|
|
|
blocklyBackground: undefined,
|
|
blocklyBackground: undefined,
|
|
|
- blocklyEndPoint: undefined,
|
|
|
|
|
blocklyWalkablePoints: undefined,
|
|
blocklyWalkablePoints: undefined,
|
|
|
blocklySpecialBlocks: undefined,
|
|
blocklySpecialBlocks: undefined,
|
|
|
|
|
+ blocklyRouteList: undefined,
|
|
|
|
|
|
|
|
bcIsInspect: "false",
|
|
bcIsInspect: "false",
|
|
|
bcType: undefined,
|
|
bcType: undefined,
|
|
@@ -897,15 +1014,19 @@ const resetForm = () => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 重置Blockly配置相关数据
|
|
// 重置Blockly配置相关数据
|
|
|
- blocklyStartPointX.value = undefined
|
|
|
|
|
- blocklyStartPointY.value = undefined
|
|
|
|
|
- blocklyEndPointX.value = undefined
|
|
|
|
|
- blocklyEndPointY.value = undefined
|
|
|
|
|
blocklyTileX.value = 6
|
|
blocklyTileX.value = 6
|
|
|
blocklyTileY.value = 5
|
|
blocklyTileY.value = 5
|
|
|
blocklyWalkablePoints.value = []
|
|
blocklyWalkablePoints.value = []
|
|
|
selectedBlocklyPoint.value = null
|
|
selectedBlocklyPoint.value = null
|
|
|
|
|
|
|
|
|
|
+ // 重置路线数据
|
|
|
|
|
+ blocklyRoutes.value = [{
|
|
|
|
|
+ id: routeIdCounter.value++,
|
|
|
|
|
+ direction: 0,
|
|
|
|
|
+ startPoint: { x: undefined, y: undefined },
|
|
|
|
|
+ endPoint: { x: undefined, y: undefined }
|
|
|
|
|
+ }]
|
|
|
|
|
+
|
|
|
// 重置上传进度状态
|
|
// 重置上传进度状态
|
|
|
uploadProgress.value = 0
|
|
uploadProgress.value = 0
|
|
|
isUploading.value = false
|
|
isUploading.value = false
|
|
@@ -1061,6 +1182,153 @@ color: #303133;
|
|
|
margin-bottom: 15px;
|
|
margin-bottom: 15px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/* 路线配置容器 */
|
|
|
|
|
+.route-config-container {
|
|
|
|
|
+ margin-top: 10px;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 路线配置项样式 */
|
|
|
|
|
+.route-config-item {
|
|
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
|
|
+ border-radius: 6px;
|
|
|
|
|
+ padding: 12px;
|
|
|
|
|
+ margin-bottom: 12px;
|
|
|
|
|
+ background-color: #ffffff;
|
|
|
|
|
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
|
|
|
|
+ transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.route-config-item:hover {
|
|
|
|
|
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
|
|
|
+ border-color: #409eff;
|
|
|
|
|
+ transform: translateY(-1px);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 路线行样式 */
|
|
|
|
|
+.route-row {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ margin-bottom: 8px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.route-row:last-child {
|
|
|
|
|
+ margin-bottom: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 路线标题样式 */
|
|
|
|
|
+.route-title {
|
|
|
|
|
+ display: inline-flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ height: 28px;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ font-size: 13px;
|
|
|
|
|
+ color: #409eff;
|
|
|
|
|
+ background-color: #ecf5ff;
|
|
|
|
|
+ padding: 0 10px;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ border-left: 2px solid #409eff;
|
|
|
|
|
+ margin-right: 15px;
|
|
|
|
|
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 路线字段容器 */
|
|
|
|
|
+.route-fields {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ gap: 20px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 路线字段样式 */
|
|
|
|
|
+.route-field {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 字段标签样式 */
|
|
|
|
|
+.field-label {
|
|
|
|
|
+ font-size: 13px;
|
|
|
|
|
+ color: #606266;
|
|
|
|
|
+ margin-right: 8px;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 坐标组样式 */
|
|
|
|
|
+.coordinate-group {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 5px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 坐标输入框样式 */
|
|
|
|
|
+.coordinate-input {
|
|
|
|
|
+ width: 60px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 方向单选按钮样式 */
|
|
|
|
|
+.direction-radio {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ border: 1px solid #dcdfe6;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.direction-radio .el-radio-button__inner {
|
|
|
|
|
+ padding: 4px 10px;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ border-radius: 0;
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ transition: all 0.2s;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.direction-radio .el-radio-button__orig-radio:checked + .el-radio-button__inner {
|
|
|
|
|
+ background-color: #409eff;
|
|
|
|
|
+ border-color: #409eff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.direction-radio .el-radio-button:first-child .el-radio-button__inner {
|
|
|
|
|
+ border-radius: 3px 0 0 3px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.direction-radio .el-radio-button:last-child .el-radio-button__inner {
|
|
|
|
|
+ border-radius: 0 3px 3px 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 删除按钮样式 */
|
|
|
|
|
+.route-delete-btn {
|
|
|
|
|
+ margin-left: auto;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 响应式调整 */
|
|
|
|
|
+@media (max-width: 768px) {
|
|
|
|
|
+ .route-row {
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .route-fields {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ margin-top: 8px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .route-delete-btn {
|
|
|
|
|
+ margin-left: 0;
|
|
|
|
|
+ margin-top: 8px;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 路线头部样式 - 保留用于兼容性 */
|
|
|
|
|
+.route-header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ margin-bottom: 15px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: #303133;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/* 图标上传包装器 */
|
|
/* 图标上传包装器 */
|
|
|
.icon-upload-wrapper {
|
|
.icon-upload-wrapper {
|
|
|
display: flex;
|
|
display: flex;
|