瀏覽代碼

更新字典查库,(blockly所需要的字典)

liyanbo 3 月之前
父節點
當前提交
ba52f2e725
共有 5 個文件被更改,包括 203 次插入38 次删除
  1. 38 26
      src/api/blockly/blockly.js
  2. 14 0
      src/api/system/dict.js
  3. 18 10
      src/components/blockly/MapGame.vue
  4. 115 0
      src/utils/dictUtils.js
  5. 18 2
      src/utils/loginUtils.js

+ 38 - 26
src/api/blockly/blockly.js

@@ -1,7 +1,7 @@
 import * as Blockly from "blockly";
 import 'blockly/msg/zh-hans';
-import { javascriptGenerator } from "blockly/javascript";
-import { pythonGenerator } from "blockly/python";
+import {javascriptGenerator} from "blockly/javascript";
+import {pythonGenerator} from "blockly/python";
 // 导入图片资源
 import about_turnImage from '@/assets/images/blockly/component/about_turn.png';
 import move_backwardImage from '@/assets/images/blockly/component/move_backward.png';
@@ -13,31 +13,43 @@ import useImage from '@/assets/images/blockly/component/use.png';
 import pauseImage from '@/assets/images/blockly/component/pause.png';
 import play_soundImage from '@/assets/images/blockly/component/sound.png';
 import constructImage from '@/assets/images/blockly/component/construct.png';
+import {DICT_TYPE} from '@/utils/dictUtils.js';
 
-// 积木形状字典
-const BLOCKLY_SHAPE_DICT = {
-  polygon_gem: { value: 'polygon_gem', label: '多边形宝石', img: "https://learn-ai.com.cn/admin-api/infra/file/29/get/20260104/2-18扣过的物品_1767512705721.png" }, // 多边形宝石
-  SQUARE_GEM: { value: 'square_gem', label: '正方形宝石', img: "https://learn-ai.com.cn/admin-api/infra/file/29/get/20260104/2-22-2扣过的物品_1767507589513.png" }, // 正方形宝石
-  TRIANGLE_GEM: { value: 'triangle_gem', label: '三角形宝石', img: "https://learn-ai.com.cn/admin-api/infra/file/29/get/20260104/2-17扣过的物品_1767512591147.png" }, // 三角形宝石
-  RED_MARK: { value: 'red_mark', label: '红色标记', img: "https://learn-ai.com.cn/admin-api/infra/file/29/get/20260104/2-21-1扣过的物品_1767507553979.png" }, // 红色标记
-  GREEN_MARK: { value: 'green_mark', label: '绿色标记', img: "https://learn-ai.com.cn/admin-api/infra/file/29/get/20260104/2-21-2扣过的物品_1767507565373.png" }, // 绿色标记
-  BLUE_MARK: { value: 'blue_mark', label: '蓝色标记', img: "https://learn-ai.com.cn/admin-api/infra/file/29/get/20260104/2-23扣过的物品_1767507448751.png" } // 蓝色标记
+
+// 安全地获取和解析字典数据
+const getDictDataFromStorage = (dictType) => {
+  try {
+    const data = localStorage.getItem(dictType);
+    return data ? JSON.parse(data) : [];
+  } catch (error) {
+    console.error(`解析${dictType}字典数据失败:`, error);
+    return [];
+  }
 };
 
 // 地图元素类型字典
-const BLOCKLY_MAP_TYPE_DICT = {
-  ICE: 'ice', // 冰块
-  TASK: 'task', // 钥匙
-  ITEM: 'item', // 物品
-  TRAP: 'trap' // 陷阱
-};
+const savedMapTypeDict = getDictDataFromStorage(DICT_TYPE.AI_BLOCKLY_MAP_TYPE);
+const BLOCKLY_MAP_TYPE_DICT = savedMapTypeDict.reduce((acc, item) => {
+  acc[item.value.toUpperCase()] = item.value;
+  return acc;
+}, {});
 
-// 自定义积木字典
-const BLOCKLY_CUSTOMIZE_DICT = {
-  PAUSE: 'pause', // 暂停
-  PLAY_SOUND: 'play_sound', // 播放音效
-  CONSTRUCT: 'construct' // 修建
-};
+// 特殊积木字典
+const blocklyMapSpecialDict = getDictDataFromStorage(DICT_TYPE.BLOCKLY_MAP_SPECIAL);
+const BLOCKLY_MAP_SPECIAL_DICT = blocklyMapSpecialDict.reduce((acc, item) => {
+  acc[item.value.toUpperCase()] = item.value;
+  return acc;
+}, {});
+// 地图标记字典
+const blocklyMapMarkDict = getDictDataFromStorage(DICT_TYPE.BLOCKLY_MAP_MARK);
+const BLOCKLY_MAP_MARK_DICT = blocklyMapMarkDict.reduce((acc, item) => {
+  acc[item.value.toUpperCase()] = {
+    value: item.value,
+    label: item.label,
+    img: item.cssClass
+  };
+  return acc;
+}, {});
 
 /**
  * 定义所有可用的自定义积木配置
@@ -259,7 +271,7 @@ const availableBlocks = {
         {
           "type": "field_dropdown",
           "name": "SHAPE",
-          "options": Object.values(BLOCKLY_SHAPE_DICT).map(shape => [
+          "options": Object.values(BLOCKLY_MAP_MARK_DICT).map(shape => [
             {
               "src": shape.img,
               "width": 30,
@@ -680,7 +692,7 @@ export function getAllPythonGeneratorsConfig() {
 }
 
 // 导出字典常量
-export { BLOCKLY_SHAPE_DICT, BLOCKLY_MAP_TYPE_DICT, BLOCKLY_CUSTOMIZE_DICT };
+export {  BLOCKLY_MAP_TYPE_DICT, BLOCKLY_MAP_MARK_DICT, BLOCKLY_MAP_SPECIAL_DICT };
 
 export default {
   registerCustomBlocks,
@@ -690,7 +702,7 @@ export default {
   initBlockly,
   getAllBlocksConfig,
   getAllGeneratorsConfig,
-  BLOCKLY_SHAPE_DICT,
   BLOCKLY_MAP_TYPE_DICT,
-  BLOCKLY_CUSTOMIZE_DICT
+  BLOCKLY_MAP_MARK_DICT,
+  BLOCKLY_MAP_SPECIAL_DICT
 };

+ 14 - 0
src/api/system/dict.js

@@ -0,0 +1,14 @@
+import axios from '@/utils/request';
+/**
+ * 获取字典数据列表
+ * @param {string} type - 字典类型
+ * @returns {Promise} - 返回包含字典数据的Promise
+ */
+export function getSimpleDictDataList(type) {
+    return axios({
+        url: "/system/dict-data/simple-list",
+        method: 'get',
+        data: type ? { dictType: type } : {},
+    })
+}
+

+ 18 - 10
src/components/blockly/MapGame.vue

@@ -153,7 +153,7 @@ import passRouteMp3 from '@/assets/music/blockly/pass_route.MP3';
 import errorMp3 from '@/assets/music/blockly/error.MP3'
 
 // 游戏接口数据
-import { registerCustomBlocks, registerJavaScriptGenerators, registerPythonGenerators, initBlockly, BLOCKLY_MAP_TYPE_DICT, BLOCKLY_CUSTOMIZE_DICT } from '@/api/blockly/blockly.js';
+import { registerCustomBlocks, registerJavaScriptGenerators, registerPythonGenerators, initBlockly, BLOCKLY_MAP_TYPE_DICT, BLOCKLY_MAP_SPECIAL_DICT } from '@/api/blockly/blockly.js';
 import {playMp3} from "@/api/blockly/music.js";
 
 import cupbg from '@/assets/blockly/cupbg.png' // 通关后奖杯底图
@@ -542,17 +542,25 @@ function generateToolboxXml() {
 
   // 确保blocklySpecialBlocks是数组
   const specialBlocks = Array.isArray(props.blocklySpecialBlocks) ? props.blocklySpecialBlocks : [];
+  // 获取所有特殊积木类型
+  const specialBlockTypes = Object.values(BLOCKLY_MAP_SPECIAL_DICT);
+
+  specialBlockTypes.forEach(blockType => {
+    if (specialBlocks.includes(blockType)) {
+      toolboxXml += `<block type="${blockType}"></block>`;
+    }
+  })
 
   // 根据允许的特殊积木动态添加
-  if (specialBlocks.includes(BLOCKLY_CUSTOMIZE_DICT.PAUSE)) {
-    toolboxXml += '<block type="pause"></block>';
-  }
-  if (specialBlocks.includes(BLOCKLY_CUSTOMIZE_DICT.PLAY_SOUND)) {
-    toolboxXml += '<block type="play_sound"></block>';
-  }
-  if (specialBlocks.includes(BLOCKLY_CUSTOMIZE_DICT.CONSTRUCT)) {
-    toolboxXml += '<block type="construct"></block>';
-  }
+  // if (specialBlocks.includes(BLOCKLY_MAP_SPECIAL_DICT.PAUSE)) {
+  //   toolboxXml += '<block type="pause"></block>';
+  // }
+  // if (specialBlocks.includes(BLOCKLY_MAP_SPECIAL_DICT.PLAY_SOUND)) {
+  //   toolboxXml += '<block type="play_sound"></block>';
+  // }
+  // if (specialBlocks.includes(BLOCKLY_MAP_SPECIAL_DICT.CONSTRUCT)) {
+  //   toolboxXml += '<block type="construct"></block>';
+  // }
 
   toolboxXml += `
     </category>

+ 115 - 0
src/utils/dictUtils.js

@@ -0,0 +1,115 @@
+import { getSimpleDictDataList } from '@/api/system/dict.js';
+
+// ========== Blockly - 地图编程游戏  ==========
+// 字典类型常量定义(统一管理)
+export const DICT_TYPE = {
+  AI_BLOCKLY_MAP_TYPE: 'ai_blockly_map_type', // 地图类型
+  BLOCKLY_COURSE_LABEL: 'blockly_course_label', // 课程标签
+  BLOCKLY_COURSE_CONTENT_TYPE: 'blockly_course_content_type', // 课程内容类型
+  BLOCKLY_MAP_SPECIAL: 'blockly_map_special', // 地图特殊方块类型
+  BLOCKLY_MAP_MARK: 'blockly_map_mark' // 地图标记标签
+};
+
+// 所有字典类型值的数组(从DICT_TYPE中自动提取)
+const ALL_DICT_TYPES = Object.values(DICT_TYPE);
+
+// 字典缓存配置
+const DICT_CONFIG = {
+  // 缓存过期时间(毫秒)
+  EXPIRY_TIME: 24 * 60 * 60 * 1000, // 24小时
+  // 过期时间存储键后缀
+  EXPIRY_SUFFIX: '_expiry'
+};
+
+/**
+ * 检查缓存是否过期
+ * @param {string} dictType - 字典类型
+ * @returns {boolean} - 是否已过期
+ */
+const isCacheExpired = (dictType) => {
+  const expiryKey = `${dictType}${DICT_CONFIG.EXPIRY_SUFFIX}`;
+  const expiryTime = localStorage.getItem(expiryKey);
+
+  if (!expiryTime) return true;
+
+  return Date.now() > parseInt(expiryTime);
+};
+
+/**
+ * 设置带过期时间的缓存
+ * @param {string} dictType - 字典类型
+ * @param {any} data - 要缓存的数据
+ */
+const setCacheWithExpiry = (dictType, data) => {
+  localStorage.setItem(dictType, JSON.stringify(data));
+
+  // 设置过期时间
+  const expiryKey = `${dictType}${DICT_CONFIG.EXPIRY_SUFFIX}`;
+  const expiryTime = Date.now() + DICT_CONFIG.EXPIRY_TIME;
+  localStorage.setItem(expiryKey, expiryTime.toString());
+};
+
+/**
+ * 获取单个字典数据
+ * @param {string} dictType - 字典类型(使用DICT_TYPE中的常量)
+ * @returns {Promise<Array>} - 字典数据数组
+ */
+export const getDictData = async (dictType) => {
+  try {
+    // 检查是否为DICT_TYPE中定义的类型
+    if (!ALL_DICT_TYPES.includes(dictType)) {
+      console.warn(`不支持的字典类型: ${dictType}`);
+      return [];
+    }
+
+    // 检查缓存是否存在且未过期
+    const cachedData = localStorage.getItem(dictType);
+    if (cachedData && !isCacheExpired(dictType)) {
+      return JSON.parse(cachedData);
+    }
+
+    // 缓存不存在或已过期,从服务器获取
+    const res = await getSimpleDictDataList(dictType);
+    if (res.code === 0) {
+      // 存储到localStorage并设置过期时间
+      setCacheWithExpiry(dictType, res.data);
+      return res.data;
+    } else {
+      throw new Error('获取字典数据失败');
+    }
+  } catch (error) {
+    console.error(`获取${dictType}字典数据失败:`, error);
+    return [];
+  }
+};
+
+/**
+ * 更新所有字典数据
+ * @returns {Promise<Object>} - 包含所有支持的字典数据的对象
+ */
+export const updateAllDictData = async () => {
+  try {
+    // 并行获取所有DICT_TYPE中定义的字典数据
+    const dictPromises = ALL_DICT_TYPES.map(type => getDictData(type));
+    const dictDataArray = await Promise.all(dictPromises);
+
+    // 构建返回对象
+    const result = {};
+    ALL_DICT_TYPES.forEach((type, index) => {
+      result[type] = dictDataArray[index];
+    });
+
+    return result;
+  } catch (error) {
+    console.error('获取所有字典数据失败:', error);
+    // 返回空数据
+    const result = {};
+    ALL_DICT_TYPES.forEach(type => {
+      result[type] = [];
+    });
+    return result;
+  }
+};
+
+// 导出配置
+export { DICT_CONFIG };

+ 18 - 2
src/utils/loginUtils.js

@@ -1,6 +1,7 @@
 import { ref, computed } from 'vue'
 import { getTenantIdByName, login, smsLogin, smsCode } from '@/api/login/login.js'
 import { ElLoading, ElMessage } from 'element-plus'
+import { updateAllDictData } from './dictUtils.js';
 
 // 登录数据结构
 const createLoginData = () => {
@@ -155,8 +156,13 @@ const loginLogic = async (loginForm, tenantId, isAuthorized, router, redirectPat
         text: '正在加载系统中...',
         background: 'rgba(0, 0, 0, 0.7)'
       })
+
+      // 获取字典数据
+      await getDictData();
+
       // 登录成功后,跳转到指定的页面
       router.push(redirectPath)
+
       return true
     } else if (res.code === 1002000009) {
       // 未授权状态,切换到短信验证码登录
@@ -179,6 +185,16 @@ const loginLogic = async (loginForm, tenantId, isAuthorized, router, redirectPat
   }
 }
 
+// 添加获取字典数据的函数
+const getDictData = async () => {
+  try {
+    // 使用新的字典管理工具更新所有字典
+    await updateAllDictData();
+  } catch (error) {
+    console.error('获取字典数据失败:', error);
+  }
+};
+
 // 本地存储管理
 const loadLoginData = (loginData) => {
   const storedTenantName = localStorage.getItem('tenantName')
@@ -233,7 +249,7 @@ const generateRules = (isAuthorized) => {
 }
 
 // 自动登录逻辑(用于QuickLogin和PromotionLogin)
-  const autoLogin = async (tenantName, username, password, router, redirectPath) => {
+const autoLogin = async (tenantName, username, password, router, redirectPath) => {
   let loading = null
   try {
     // 显示全局加载状态
@@ -298,4 +314,4 @@ export {
   checkLoginStatus,
   generateRules,
   autoLogin
-}
+}