소스 검색

feat:合并master分支到optimize分支

liu.tao3 1 년 전
부모
커밋
aab1946633
25개의 변경된 파일1033개의 추가작업 그리고 334개의 파일을 삭제
  1. 39 2
      .gitignore
  2. 0 41
      DataRoom/.gitignore
  3. 1 1
      DataRoom/dataroom-core/pom.xml
  4. 20 20
      DataRoom/dataroom-server/src/main/resources/logback-spring.xml
  5. 353 0
      DataRoom/dataroom-server/src/test/java/DataMigrationTest.java
  6. 175 0
      DataRoom/dataroom-server/src/test/java/GetResourceSqlTest.java
  7. 60 2
      DataRoom/doc/update.sql
  8. 8 4
      data-room-ui/example/customDatasetComponents/jsDataSet/OutputFieldDialog.vue
  9. 159 135
      data-room-ui/example/customDatasetComponents/jsDataSet/index.vue
  10. 41 41
      data-room-ui/package-lock.json
  11. 16 5
      data-room-ui/packages/BigScreenComponentMag/SideMenu.vue
  12. 4 13
      data-room-ui/packages/BigScreenComponentMag/index.vue
  13. 41 43
      data-room-ui/packages/BigScreenDesign/RightSetting/DataSetting.vue
  14. 3 1
      data-room-ui/packages/BigScreenRun/index.vue
  15. 74 9
      data-room-ui/packages/BizComponent/index.vue
  16. 6 9
      data-room-ui/packages/ComponentList/index.vue
  17. 0 1
      data-room-ui/packages/DataSetManagement/src/DatasetTypeDialog.vue
  18. 0 1
      data-room-ui/packages/DataSetManagement/src/OriginalEditForm.vue
  19. 2 2
      data-room-ui/packages/DataSetManagement/src/ScriptEditForm.vue
  20. 1 1
      data-room-ui/packages/DataSetManagement/src/index.vue
  21. 26 0
      data-room-ui/packages/js/mixins/commonMixins.js
  22. 0 1
      data-room-ui/packages/js/mixins/multipleSelectMixin.js
  23. 1 1
      data-room-ui/packages/js/store/actions.js
  24. 1 0
      data-room-ui/packages/js/store/state.js
  25. 2 1
      data-room-ui/vue.config.example.js

+ 39 - 2
.gitignore

@@ -3,6 +3,7 @@ gc-starter-dashboard-ui
 chuangDa
 chuangDa.zip
 deploy.sh
+bigScreen
 dist
 gc-starter-lowcode-ui
 ### VisualStudioCode template
@@ -277,8 +278,6 @@ dist
 # TODO: where does this rule come from?
 docs/_book
 
-# TODO: where does this rule come from?
-test/
 
 ### Windows template
 # Windows thumbnail cache files
@@ -370,3 +369,41 @@ GitHub.sublime-settings
 lib
 gc-starter-lowcode-ui
 libApp
+
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+# 忽略配置文件提交
+application-*.yml
+!application-demo.yml

+ 0 - 41
DataRoom/.gitignore

@@ -1,41 +0,0 @@
-HELP.md
-target/
-!.mvn/wrapper/maven-wrapper.jar
-!**/src/main/**/target/
-!**/src/test/**/target/
-
-### STS ###
-.apt_generated
-.classpath
-.factorypath
-.project
-.settings
-.springBeans
-.sts4-cache
-
-### IntelliJ IDEA ###
-.idea
-*.iws
-*.iml
-*.ipr
-
-### NetBeans ###
-/nbproject/private/
-/nbbuild/
-/dist/
-/nbdist/
-/.nb-gradle/
-build/
-!**/src/main/**/build/
-!**/src/test/**/build/
-
-### VS Code ###
-.vscode/
-
-# 忽略配置文件提交
-application-*.yml
-!application-demo.yml
-
-logs
-upload.sh
-

+ 1 - 1
DataRoom/dataroom-core/pom.xml

@@ -21,7 +21,7 @@
         <dependency>
             <groupId>com.gccloud</groupId>
             <artifactId>dataset-core</artifactId>
-            <version>0.0.1.2023062001.Alpha</version>
+            <version>0.0.1.2023062101.Alpha</version>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>

+ 20 - 20
DataRoom/dataroom-server/src/main/resources/logback-spring.xml

@@ -26,25 +26,25 @@
         </encoder>
     </appender>
 
-<!--    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">-->
-<!--        &lt;!&ndash; 追加日志到原文件结尾 &ndash;&gt;-->
-<!--        <Prudent>true</Prudent>-->
-<!--        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">-->
-<!--            &lt;!&ndash;格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %method 方法名  %L 行数 %msg:日志消息,%n是换行符&ndash;&gt;-->
-<!--            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %X{traceId:-} [%thread] %-5level %logger{56}.%method:%L - %msg%n</pattern>-->
-<!--            <charset>utf-8</charset>-->
-<!--        </encoder>-->
-<!--        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">-->
-<!--            &lt;!&ndash;日志文件输出的文件名 每小时生成日志文件&ndash;&gt;-->
-<!--            <FileNamePattern>${LOG_PATH}/%d{yyyy-MM-dd}.%i.log</FileNamePattern>-->
-<!--            &lt;!&ndash;日志文件保留天数&ndash;&gt;-->
-<!--            <MaxHistory>30</MaxHistory>-->
-<!--            &lt;!&ndash; 除按日志记录之外,还配置了日志文件不能超过100M(默认),若超过100M,日志文件会以索引0开始, &ndash;&gt;-->
-<!--            <maxFileSize>100MB</maxFileSize>-->
-<!--            &lt;!&ndash;  日志文件大小和超过10GMB会清空之前的 &ndash;&gt;-->
-<!--            <totalSizeCap>10GB</totalSizeCap>-->
-<!--        </rollingPolicy>-->
-<!--    </appender>-->
+    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 追加日志到原文件结尾 -->
+        <Prudent>true</Prudent>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %method 方法名  %L 行数 %msg:日志消息,%n是换行符-->
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %X{traceId:-} [%thread] %-5level %logger{56}.%method:%L - %msg%n</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <!--日志文件输出的文件名 每小时生成日志文件-->
+            <FileNamePattern>${LOG_PATH}/%d{yyyy-MM-dd}.%i.log</FileNamePattern>
+            <!--日志文件保留天数-->
+            <MaxHistory>30</MaxHistory>
+            <!-- 除按日志记录之外,还配置了日志文件不能超过100M(默认),若超过100M,日志文件会以索引0开始, -->
+            <maxFileSize>100MB</maxFileSize>
+            <!--  日志文件大小和超过10GMB会清空之前的 -->
+            <totalSizeCap>10GB</totalSizeCap>
+        </rollingPolicy>
+    </appender>
 
     <!--  SpringBoot 默认的  -->
     <logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR"/>
@@ -70,7 +70,7 @@
     </springProfile>
 
     <root level="INFO">
-<!--        <appender-ref ref="FILE"/>-->
+        <appender-ref ref="FILE"/>
         <appender-ref ref="CONSOLE"/>
     </root>
 

+ 353 - 0
DataRoom/dataroom-server/src/test/java/DataMigrationTest.java

@@ -0,0 +1,353 @@
+import com.alibaba.druid.pool.DruidDataSource;
+import com.gccloud.common.utils.JSON;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * @author hongyang
+ * @version 1.0
+ * @date 2023/6/20 15:29
+ */
+@Slf4j
+@RunWith(SpringRunner.class)
+public class DataMigrationTest {
+
+    /**
+     * 版本升级处理数据集数据迁移
+     * 执行前请:
+     * 1. 执行doc/update.sql
+     * 2. 修改数据库连接信息
+     */
+    @Test
+    public void dataMigration() {
+        // 设置数据源
+        DruidDataSource dataSource = new DruidDataSource();
+        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
+        dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/dataroom?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=UTF-8");
+        dataSource.setUsername("root");
+        dataSource.setPassword("pwd");
+        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
+        // 处理数据源
+        log.info("开始处理数据源");
+        handleDataSource(jdbcTemplate);
+        // 处理分类
+        log.info("开始处理分类");
+        handleCategory(jdbcTemplate);
+        // 处理数据集
+        log.info("开始处理数据集");
+        handleDataset(jdbcTemplate);
+
+    }
+
+
+    /**
+     * 数据源数据迁移
+     * @param jdbcTemplate
+     */
+    private static void handleDataSource(JdbcTemplate jdbcTemplate) {
+        String migrateSql = "INSERT INTO ds_datasource (id, source_name, source_type, driver_class_name, url, host, port, username, password, module_code, editable, remark, update_date, create_date, del_flag)\n" +
+                "SELECT id, source_name, source_type, driver_class_name, url, host, port, username, password, module_code, editable, remark, update_date, create_date, del_flag\n" +
+                "FROM big_screen_datasource_config where del_flag = 0";
+        jdbcTemplate.execute(migrateSql);
+        String updateSql = "UPDATE ds_datasource SET source_type = 'PostgreSQL' where  source_type = 'TelePG'";
+        jdbcTemplate.execute(updateSql);
+        String updateSql2 = "UPDATE ds_datasource SET source_type = 'Mysql' where  source_type = 'TeleDB'";
+        jdbcTemplate.execute(updateSql2);
+        log.info("数据源数据迁移完成");
+    }
+
+    /**
+     * 分类树ids更新SQL
+     */
+    public static final String updateSql = "update ds_category_tree set ids = '%s' where id = '%s'";
+
+    /**
+     * 分类树数据迁移
+     * @param jdbcTemplate
+     */
+    private static void handleCategory(JdbcTemplate jdbcTemplate) {
+        String migrateSql = "INSERT INTO ds_category_tree (id, name, parent_id, type, module_code, update_date, create_date, del_flag)\n" +
+                "SELECT id, name, parent_id, table_name, module_code, update_date, create_date, del_flag\n" +
+                "FROM big_screen_category_tree where del_flag = 0";
+        jdbcTemplate.execute(migrateSql);
+        String sql = "select * from ds_category_tree where del_flag = 0";
+        List<Map<String, Object>> categoryList = jdbcTemplate.queryForList(sql);
+        // 根据parent_id组装成树形结构,将子节点放到父节点的children中,并组装ids
+        Map<String, Map<String, Object>> categoryMap = Maps.newHashMap();
+        categoryList.forEach(category -> categoryMap.put(category.get("id").toString(), category));
+        categoryList.forEach(category -> {
+            String parentId = category.get("parent_id").toString();
+            if (StringUtils.isBlank(parentId) || "0".equals(parentId)) {
+                return;
+            }
+            Map<String, Object> parentCategory = categoryMap.get(parentId);
+            if (parentCategory == null) {
+                return;
+            }
+            List<Map<String, Object>> children = (List<Map<String, Object>>) parentCategory.get("children");
+            if (children == null) {
+                children = Lists.newArrayList();
+                parentCategory.put("children", children);
+            }
+            children.add(category);
+        });
+        // 取出根节点
+        List<Map<String, Object>> rootCategoryList = categoryList.stream().filter(category -> {
+            String parentId = category.get("parent_id").toString();
+            return StringUtils.isBlank(parentId) || "0".equals(parentId);
+        }).collect(Collectors.toList());
+        // 处理ids
+        handleIds(rootCategoryList, "");
+        List<String> updateSqlList = Lists.newArrayList();
+        // 类型修改
+        updateSqlList.add("update ds_category_tree set type = 'dataset' where type = 'r_dataset'");
+        // 组装update sql
+        getUpdateSql(rootCategoryList, updateSqlList);
+        // 批量执行update sql
+        jdbcTemplate.batchUpdate(updateSqlList.toArray(new String[0]));
+        log.info("分类树数据迁移完成");
+
+    }
+
+    /**
+     * 处理分类树ids
+     * @param categoryList
+     * @param parentIds
+     */
+    private static void handleIds(List<Map<String, Object>> categoryList, String parentIds) {
+        if (categoryList == null || categoryList.isEmpty()) {
+            return;
+        }
+        categoryList.forEach(category -> {
+            String id = category.get("id").toString();
+            String ids = parentIds + "," + id;
+            if (StringUtils.isBlank(parentIds)) {
+                ids = id;
+            }
+            category.put("ids", ids);
+            List<Map<String, Object>> children = (List<Map<String, Object>>) category.get("children");
+            handleIds(children, ids);
+        });
+
+    }
+
+    /**
+     * 组装分类树update sql
+     * @param categoryList
+     * @param updateSqlList
+     */
+    private static void getUpdateSql(List<Map<String, Object>> categoryList, List<String> updateSqlList) {
+        if (categoryList == null || categoryList.isEmpty()) {
+            return;
+        }
+        categoryList.forEach(category -> {
+            String id = category.get("id").toString();
+            String ids = category.get("ids").toString();
+            updateSqlList.add(String.format(updateSql, ids, id));
+            List<Map<String, Object>> children = (List<Map<String, Object>>) category.get("children");
+            getUpdateSql(children, updateSqlList);
+        });
+    }
+
+    /**
+     * 数据集新增SQL
+     */
+    public static final String insertSql = "INSERT INTO ds_dataset (id, name, code, type_id, remark, dataset_type, module_code, editable, source_id, cache, config) VALUES ('%s', '%s', '%s', %s, '%s', '%s', '%s', %s, %s, %s, '%s');";
+
+    /**
+     * 数据集数据迁移
+     * @param jdbcTemplate
+     */
+    private static void handleDataset(JdbcTemplate jdbcTemplate) {
+        // 新增SQL集合
+        List<String> insertSqlList = Lists.newArrayList();
+        // 处理JSON类型的数据集
+        String sql = "select * from big_screen_dataset where dataset_type = 'json' and del_flag = 0";
+        List<Map<String, Object>> jsonDatasetList = jdbcTemplate.queryForList(sql);
+        for (Map<String, Object> dataset : jsonDatasetList) {
+            String data = dataset.get("data").toString();
+            // 解析data
+            JSONObject dataJson = JSON.parseObject(data);
+            Object json = dataJson.get("json");
+            JSONObject fieldDesc = dataJson.getJSONObject("fieldDesc");
+            // 遍历fieldDesc,取出key和value
+            Set<String> keySet = fieldDesc.keySet();
+            List<Map<String, Object>> fieldList = Lists.newArrayList();
+            for (String key : keySet) {
+                Object value = fieldDesc.get(key);
+                Map<String, Object> fieldMap = Maps.newHashMap();
+                fieldMap.put("fieldName", key);
+                fieldMap.put("fieldDesc", value);
+                fieldList.add(fieldMap);
+            }
+            JSONObject jsonConfig = new JSONObject();
+            jsonConfig.put("fieldList", fieldList);
+            String jsonStr = JSON.toJSONString(json);
+            jsonConfig.put("json", escape(jsonStr));
+            jsonConfig.put("fieldDesc", fieldDesc);
+            jsonConfig.put("className", "com.gccloud.dataset.entity.config.JsonDataSetConfig");
+            String config = JSON.toJSONString(jsonConfig);
+            String insertSql = getInsertSql(dataset, config);
+            insertSqlList.add(insertSql);
+        }
+        // 处理script类型的数据集
+        sql = "select * from big_screen_dataset where dataset_type = 'script' and del_flag = 0";
+        List<Map<String, Object>> scriptDatasetList = jdbcTemplate.queryForList(sql);
+        for (Map<String, Object> dataset : scriptDatasetList) {
+            String data = dataset.get("data").toString();
+            // 解析data
+            JSONObject dataJson = JSON.parseObject(data);
+            Object script = dataJson.get("script");
+            Object paramsList = dataJson.get("paramsList");
+            JSONObject fieldDesc = dataJson.getJSONObject("fieldDesc");
+            // 遍历fieldDesc,取出key和value
+            Set<String> keySet = fieldDesc.keySet();
+            List<Map<String, Object>> fieldList = Lists.newArrayList();
+            for (String key : keySet) {
+                Object value = fieldDesc.get(key);
+                Map<String, Object> fieldMap = Maps.newHashMap();
+                fieldMap.put("fieldName", key);
+                fieldMap.put("fieldDesc", value);
+                fieldList.add(fieldMap);
+            }
+            JSONObject jsonConfig = new JSONObject();
+            jsonConfig.put("fieldList", fieldList);
+            jsonConfig.put("script", escape(script.toString()));
+            jsonConfig.put("paramsList", paramsList);
+            jsonConfig.put("fieldDesc", fieldDesc);
+            jsonConfig.put("className", "com.gccloud.dataset.entity.config.GroovyDataSetConfig");
+            String config = JSON.toJSONString(jsonConfig);
+            String insertSql = getInsertSql(dataset, config);
+            insertSqlList.add(insertSql);
+        }
+        // 处理original类型的数据集
+        sql = "select a.*,b.* from big_screen_dataset a left join big_screen_datasets_original b on a.dataset_rel_id = b.id where a.dataset_rel_id is not null and a.dataset_type = 'original' and a.del_flag = 0 and b.del_flag =0";
+        List<Map<String, Object>> originalDatasetList = jdbcTemplate.queryForList(sql);
+        for (Map<String, Object> dataset : originalDatasetList) {
+            String sourceId = dataset.get("source_id").toString();
+            String tableName = dataset.get("table_name").toString();
+            Object repeatStatus = dataset.get("repeat_status");
+            Object fieldDesc = dataset.get("field_desc");
+            JSONObject fieldDescObj = JSON.parseObject(fieldDesc.toString());
+            String fieldInfo = dataset.get("field_info").toString();
+            JSONArray fieldJson = JSON.parseArray(dataset.get("field_json").toString());
+            List<Map<String, Object>> fieldList = Lists.newArrayList();
+            fieldJson.toList().forEach(field -> {
+                Map<String, Object> fieldMap = Maps.newHashMap();
+                fieldMap.put("fieldName", ((Map) field).get("columnName"));
+                fieldMap.put("fieldType", ((Map) field).get("columnType"));
+                fieldMap.put("orderNum", ((Map) field).get("orderNum"));
+                fieldMap.put("sourceTable", ((Map) field).get("sourceTable"));
+                fieldMap.put("fieldDesc", ((Map) field).get("fieldDesc"));
+                fieldList.add(fieldMap);
+            });
+            JSONObject jsonConfig = new JSONObject();
+            jsonConfig.put("sourceId", sourceId);
+            jsonConfig.put("tableName", tableName);
+            jsonConfig.put("repeatStatus", repeatStatus);
+            jsonConfig.put("fieldDesc", fieldDescObj);
+            jsonConfig.put("fieldInfo", fieldInfo);
+            jsonConfig.put("fieldList", fieldList);
+            jsonConfig.put("className", "com.gccloud.dataset.entity.config.OriginalDataSetConfig");
+            String config = JSON.toJSONString(jsonConfig);
+            String insertSql = getInsertSql(dataset, config);
+            insertSqlList.add(insertSql);
+        }
+        // 处理custom、storedProcedure类型的数据集
+        sql = "select a.*, b.*\n" +
+                "from big_screen_dataset a\n" +
+                "         left join big_screen_datasets_custom b on a.dataset_rel_id = b.id\n" +
+                "where a.dataset_rel_id is not null\n" +
+                "  and ( a.dataset_type = 'storedProcedure' or a.dataset_type = 'custom')\n" +
+                "  and a.del_flag = 0\n" +
+                "  and b.del_flag = 0\n";
+        List<Map<String, Object>> customDatasetList = jdbcTemplate.queryForList(sql);
+        for (Map<String, Object> dataset : customDatasetList) {
+            String sourceId = dataset.get("source_id").toString();
+            String sqlProcess = dataset.get("sql_process").toString();
+            Object fieldDesc = dataset.get("field_desc");
+            JSONObject fieldDescObj = JSON.parseObject(fieldDesc.toString());
+            Object paramList = dataset.get("param_config");
+            JSONArray fieldJson = JSON.parseArray(dataset.get("field_json").toString());
+            List<Map<String, Object>> fieldList = Lists.newArrayList();
+            fieldJson.toList().forEach(field -> {
+                Map<String, Object> fieldMap = Maps.newHashMap();
+                fieldMap.put("fieldName", ((Map) field).get("columnName"));
+                fieldMap.put("fieldType", ((Map) field).get("columnType"));
+                fieldMap.put("orderNum", ((Map) field).get("orderNum"));
+                fieldMap.put("sourceTable", ((Map) field).get("sourceTable"));
+                fieldMap.put("fieldDesc", ((Map) field).get("fieldDesc"));
+                fieldList.add(fieldMap);
+            });
+            JSONObject jsonConfig = new JSONObject();
+            jsonConfig.put("sourceId", sourceId);
+            jsonConfig.put("sqlProcess", escape(sqlProcess));
+            jsonConfig.put("fieldDesc", fieldDescObj);
+            jsonConfig.put("fieldList", fieldList);
+            JSONArray paramsList = new JSONArray();
+            if (StringUtils.isNotBlank(paramList.toString())) {
+                paramsList = JSON.parseArray(paramList.toString());
+            }
+            jsonConfig.put("paramsList", paramsList);
+            if (dataset.get("dataset_type").toString().equals("storedProcedure")) {
+                jsonConfig.put("className", "com.gccloud.dataset.entity.config.StoredProcedureDataSetConfig");
+            } else {
+                jsonConfig.put("className", "com.gccloud.dataset.entity.config.CustomDataSetConfig");
+            }
+            String config = JSON.toJSONString(jsonConfig);
+            String insertSql = getInsertSql(dataset, config);
+            insertSqlList.add(insertSql);
+        }
+        // 批量新增
+        insertSqlList.forEach(jdbcTemplate::execute);
+        log.info("数据集配置迁移完成");
+    }
+
+    /**
+     * 组装数据集插入sql
+     * @param dataset
+     * @param config
+     * @return
+     */
+    private static String getInsertSql(Map<String, Object> dataset, String config) {
+        String id = dataset.get("id").toString();
+        String name = dataset.get("name").toString();
+        String type_id = dataset.get("type_id") == null ? "null" : dataset.get("type_id").toString();
+        String remark = dataset.get("remark").toString();
+        String dataset_type = dataset.get("dataset_type").toString();
+        String module_code = "";
+        String editable = dataset.get("editable").toString();
+        String source_id = dataset.get("source_id") == null ? "null" : dataset.get("source_id").toString();
+        String code = "";
+        String cache = "0";
+        return String.format(insertSql, id, name, code, type_id, remark, dataset_type, module_code, editable, source_id, cache, config);
+    }
+
+    /**
+     * 转义字符串
+     * @param str
+     * @return
+     */
+    private static String escape(String str) {
+        str = str.replace("\\", "\\\\");
+        str = str.replace("'", "\\'");
+        str = str.replace("\"", "\\\"");
+        str = str.replace("\n", "\\n");
+        str = str.replace("\r", "\\r");
+        str = str.replace("\t", "\\t");
+        return str;
+    }
+}

+ 175 - 0
DataRoom/dataroom-server/src/test/java/GetResourceSqlTest.java

@@ -0,0 +1,175 @@
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 用于批量生成资源文件的sql
+ * @author hongyang
+ * @version 1.0
+ * @date 2023/5/30 13:55
+ */
+@Slf4j
+@RunWith(SpringRunner.class)
+public class GetResourceSqlTest {
+
+    /**
+     * 需要处理的文件夹
+     */
+    public static final String FOLDER_PATH = "/Users/liuchengbiao/Desktop/大屏资源";
+
+    /**
+     * 服务存储文件的位置,即配置文件中的gc.file.basePath
+     */
+    public static final String FILE_BASE_PATH = "/root/bigscreen/file";
+
+    /**
+     * 静态资源接口前缀,即配置文件中的gc.file.urlPrefix
+     */
+    public static final String FILE_URL_PREFIX = "http://gcpaas.gccloud.com/bigScreenServer/static";
+
+    /**
+     * 文件所属分组编码
+     */
+    public static final String FILE_GROUP_CODE = "other";
+
+    @Test
+    public void getResourceSql() {
+        List<String> sqlList = new ArrayList<>();
+
+        // 需要处理的文件夹
+        File folder = new File(FOLDER_PATH);
+
+        if (!folder.exists() || !folder.isDirectory()) {
+            log.error("文件夹不存在");
+            return;
+        }
+        File[] subFiles = folder.listFiles();
+        if (subFiles == null) {
+            log.error("文件夹为空");
+            return;
+        }
+        for (File subFile : subFiles) {
+            String typeCode = FILE_GROUP_CODE;
+            if (subFile.isDirectory()) {
+                // 获取文件夹名称
+                String folderName = subFile.getName();
+                // 生成编码
+                typeCode = RandomStringUtils.randomAlphanumeric(10).toLowerCase();
+                // 创建时间
+                String currentDate = getCurrentDateTime();
+                String insertTypeSql = "INSERT INTO big_screen_type (name, code, type, order_num, update_date, create_date, del_flag) VALUES ('%s', '%s', '%s', %s, '%s', '%s', %s);";
+                String insertTypeSqlFormat = String.format(insertTypeSql, folderName, typeCode, "resourceCatalog", 0, currentDate, currentDate, 0);
+                sqlList.add("# 分组");
+                sqlList.add(insertTypeSqlFormat);
+                sqlList.add("# 资源");
+            }
+            handleFile(subFile, "", sqlList, typeCode);
+        }
+        // 将sql输出到文件
+        String sql = String.join("\n", sqlList);
+        String fileName = "big_screen_file.sql";
+        String filePath = FOLDER_PATH + "/" + fileName;
+        // 写入文件
+        try {
+            FileUtils.write(new File(filePath), sql, "UTF-8");
+        } catch (Exception e) {
+            log.error("写入sql文件失败");
+            log.error(ExceptionUtils.getStackTrace(e));
+        }
+        log.info("sql生成到文件:{}", FOLDER_PATH + "/big_screen_file.sql");
+        log.info("重命名后的文件路径:{}", FOLDER_PATH + "_重命名");
+    }
+
+
+    /**
+     * 处理文件/文件夹
+     * @param file 文件/文件夹
+     * @param relativePath 相对路径(相对于FOLDER_PATH)
+     * @param sqlList sql列表
+     */
+    private static void handleFile(File file, String relativePath, List<String> sqlList, String typeCode) {
+        if (file.isDirectory()) {
+            File[] files = file.listFiles();
+            if (files == null) {
+                return;
+            }
+            for (File subFile : files) {
+                String subRelativePath = relativePath + "/" + file.getName();
+                handleFile(subFile, subRelativePath, sqlList, typeCode);
+            }
+            return;
+        }
+        // 原始文件名
+        String originalName = file.getName();
+        // 文件后缀
+        String extension = getFileExtension(originalName);
+        // 新文件名
+        String newFileName = IdWorker.getIdStr()+ "." + extension;
+        // 新文件路径
+        String newPath = FOLDER_PATH + "_重命名" + relativePath + "/" + newFileName;
+        // 复制文件
+        Path sourcePath = file.toPath();
+        Path targetPath = new File(newPath).toPath();
+        try {
+            // 创建文件夹
+            Files.createDirectories(targetPath.getParent());
+            Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
+        } catch (Exception e) {
+            log.error(ExceptionUtils.getStackTrace(e));
+        }
+        // 在服务器上的文件路径
+        String path = FILE_BASE_PATH + relativePath;
+        // 文件访问地址
+        String url = FILE_URL_PREFIX + relativePath + "/" + newFileName;
+        // 替换可能存在的反斜杠
+        url = url.replace("\\", "/");
+        // 文件大小
+        long size = file.length();
+        // 创建时间
+        String currentDate = getCurrentDateTime();
+        // 生成sql
+        String sql = String.format("INSERT INTO big_screen_file (module, original_name, new_name, extension, path, url, size, download_count, create_date, update_date, del_flag) VALUES ('%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', %d);",
+                typeCode, originalName, newFileName, extension, path, url, size, 0, currentDate, currentDate, 0);
+        sqlList.add(sql);
+    }
+
+
+    /**
+     * 获取文件后缀
+     * @param fileName
+     * @return
+     */
+    private static String getFileExtension(String fileName) {
+        int dotIndex = fileName.lastIndexOf('.');
+        if (dotIndex > 0 && dotIndex < fileName.length() - 1) {
+            return fileName.substring(dotIndex + 1);
+        }
+        return "";
+    }
+
+
+    /**
+     * 获取当前时间
+     * @return
+     */
+    private static String getCurrentDateTime() {
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Date currentDate = new Date();
+        return dateFormat.format(currentDate);
+    }
+}
+

+ 60 - 2
DataRoom/doc/update.sql

@@ -1,2 +1,60 @@
-UPDATE big_screen_page SET config = REPLACE(config, '"className":"com.gccloud.bigscreen', '"className":"com.gccloud.dataroom') WHERE type = 'bigScreen';
-UPDATE big_screen_page SET config = REPLACE(config, '"className":"com.gccloud.dataroom.core.module.manage.dto.BigScreenPageDTO', '"className":"com.gccloud.dataroom.core.module.manage.dto.DataRoomPageDTO') WHERE type = 'bigScreen';
+
+-- 更新大屏配置的类名
+UPDATE big_screen_page SET config = REPLACE(config, '"className":"com.gccloud.bigscreen', '"className":"com.gccloud.dataroom');
+UPDATE big_screen_page SET config = REPLACE(config, '"className":"com.gccloud.dataroom.core.module.manage.dto.BigScreenPageDTO', '"className":"com.gccloud.dataroom.core.module.manage.dto.DataRoomPageDTO');
+
+-- 新增数据集相关的表
+
+DROP TABLE IF EXISTS `ds_category_tree`;
+CREATE TABLE `ds_category_tree` (
+  `id` bigint(64) NOT NULL AUTO_INCREMENT COMMENT '主键',
+  `ids` text COMMENT 'id序列',
+  `name` varchar(255) DEFAULT NULL COMMENT '名称',
+  `parent_id` bigint(64) DEFAULT NULL COMMENT '父级ID',
+  `type` varchar(255) NOT NULL,
+  `module_code` varchar(255) DEFAULT NULL,
+  `update_date` timestamp                        NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
+  `create_date` timestamp                        NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `del_flag` tinyint(2) NOT NULL DEFAULT '0' COMMENT '删除标识',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='数据集种类树';
+
+
+DROP TABLE IF EXISTS `ds_datasource`;
+CREATE TABLE `ds_datasource` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
+  `source_name` varchar(255) DEFAULT NULL COMMENT '数据源名称',
+  `source_type` varchar(255) DEFAULT NULL COMMENT '数据源类型',
+  `driver_class_name` varchar(255) DEFAULT NULL COMMENT '连接驱动',
+  `url` varchar(255) DEFAULT NULL COMMENT '连接url',
+  `host` varchar(255) DEFAULT NULL COMMENT '主机',
+  `port` int(16) DEFAULT NULL COMMENT '端口',
+  `username` varchar(255) DEFAULT NULL COMMENT '用户名',
+  `password` text COMMENT '密码',
+  `module_code` varchar(255) DEFAULT NULL COMMENT '模块编码',
+  `editable` tinyint(2) DEFAULT '0' COMMENT '是否可编辑,0 不可编辑 1 可编辑',
+  `remark` varchar(255) DEFAULT NULL,
+  `update_date` timestamp                        NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
+  `create_date` timestamp                        NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `del_flag` tinyint(2) NOT NULL DEFAULT '0' COMMENT '删除标识',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='数据源配置表';
+
+DROP TABLE IF EXISTS `ds_dataset`;
+CREATE TABLE `ds_dataset` (
+  `id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '主键',
+  `name` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '名称',
+  `code` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '编码',
+  `type_id` varchar(255) DEFAULT NULL COMMENT '种类ID',
+  `remark` text CHARACTER SET utf8 COMMENT '描述',
+  `dataset_type` varchar(64) CHARACTER SET utf8 NOT NULL COMMENT '数据集类型(自定义数据集 custom、模型数据集model、原始数据集original、API数据集api、JSON数据集 json)',
+  `module_code` varchar(255) COLLATE utf8_general_mysql500_ci DEFAULT NULL COMMENT '模块编码',
+  `editable` tinyint(2) NOT NULL DEFAULT '0' COMMENT '是否可编辑,0 不可编辑 1 可编辑',
+  `source_id` bigint(32) DEFAULT NULL COMMENT '数据源ID',
+  `cache` tinyint(1) DEFAULT 0 NOT NULL COMMENT '是否对执行结构缓存 0 不缓存 1 缓存',
+  `config` longtext COMMENT '数据集配置',
+  `update_date` timestamp                        NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
+  `create_date` timestamp                        NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `del_flag` tinyint(2) NOT NULL DEFAULT '0' COMMENT '删除标识',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB   DEFAULT CHARSET=utf8 COLLATE=utf8_general_mysql500_ci COMMENT='数据集表';

+ 8 - 4
data-room-ui/example/customDatasetComponents/jsDataSet/OutputFieldDialog.vue

@@ -11,7 +11,7 @@
     >
       <div class="bs-table-box">
         <el-table
-          :data="outputFieldList"
+          :data="insideFieldList"
           :border="true"
           align="center"
           class="bs-el-table"
@@ -72,11 +72,14 @@ export default {
   data () {
     return {
       dialogVisible: false,
-      structurePreviewListCopy: []
+      structurePreviewListCopy: [],
+      // 内部的输出字段列表 用于编辑
+      insideFieldList: []
     }
   },
   methods: {
     open () {
+      this.insideFieldList = cloneDeep(this.outputFieldList)
       this.dialogVisible = true
     },
     close () {
@@ -89,11 +92,12 @@ export default {
       this.dialogVisible = false
     },
     setField () {
-      if (this.outputFieldList.length) {
+      if (this.insideFieldList.length) {
         this.fieldDesc = {}
-        this.outputFieldList.forEach(key => {
+        this.insideFieldList.forEach(key => {
           this.fieldDesc[key.fieldName] = key.fieldDesc
         })
+        this.$emit('setFieldList', this.insideFieldList)
       } else {
         this.fieldDesc = null
       }

+ 159 - 135
data-room-ui/example/customDatasetComponents/jsDataSet/index.vue

@@ -9,7 +9,7 @@
           <template slot="content">
             <div class="page-header">
               <div class="page-header-left">
-                {{ !isEdit ? 'js数据集详情' : dataForm.id ? 'js数据集编辑' : 'js数据集新增' }}
+                {{ !isEdit ? 'JS数据集详情' : dataForm.id ? 'JS数据集编辑' : 'JS数据集新增' }}
               </div>
               <div class="page-header-right">
                 <el-button
@@ -140,7 +140,7 @@
             <div style="text-align: center; padding: 16px 0;">
               <el-button
                 type="primary"
-                @click="toExecute"
+                @click="scriptExecute()"
               >
                 执行
               </el-button>
@@ -154,7 +154,7 @@
           <div class="right-setting">
             <div class="paramConfig">
               <div class="title-style bs-title-style">
-                方法参数
+                动态参数
                 <el-button
                   type="text"
                   style="float: right;border: none;margin-top: -4px;"
@@ -200,7 +200,7 @@
               </div>
               <div class="field-wrap bs-field-wrap bs-scrollbar">
                 <div
-                  v-for="(field,key) in outputFieldList"
+                  v-for="(field, key) in outputFieldList"
                   :key="key"
                   class="field-item"
                   @click="$refs.outputFieldDialog.open()"
@@ -338,6 +338,7 @@
       <OutputFieldDialog
         ref="outputFieldDialog"
         :output-field-list="outputFieldList"
+        @setFieldList="(list) => { outputFieldList = list }"
       />
     </el-scrollbar>
     <FieldFillDialog
@@ -369,7 +370,7 @@ export default {
   props: {
     config: {
       type: Object,
-      default: () => {}
+      default: () => { }
     },
     isEdit: {
       type: Boolean,
@@ -448,8 +449,10 @@ export default {
     }
   },
   watch: {
-    'dataForm.config.script' () {
-      this.passTest = false
+    'dataForm.config.script' (val) {
+      if (!val) {
+        this.passTest = false
+      }
     }
   },
   mounted () {
@@ -603,10 +606,14 @@ export default {
         const javascript = this.dataForm.config.script
         let scriptMethod = null
         try {
-          scriptMethod = eval(`(${javascript})`)
+          const scriptAfterReplacement = javascript.replace(/\${(.*?)}/g, (match, p) => {
+            return `'${this.dataForm.config.paramsList.find(param => param.name === p).value}'`
+          })
+          // eslint-disable-next-line no-new-func
+          scriptMethod = new Function(scriptAfterReplacement)
         } catch (error) {
           this.passTest = false
-          this.$message.error('脚本执行错误,请检查脚本')
+          this.$message.error(`脚本执行错误,请检查脚本,具体错误:${error}`)
           return
         }
         // 调用方法生成随机数据
@@ -625,13 +632,29 @@ export default {
             }
           })
         })
-        this.outputFieldList = keys.map(item => {
-          return {
-            fieldName: item,
-            fieldDesc: ''
-          }
-        })
-        if (this.outputFieldList.length && this.fieldDesc) {
+        if (this.outputFieldList.length === 0) {
+          this.outputFieldList = keys.map(item => {
+            return {
+              fieldName: item,
+              fieldDesc: ''
+            }
+          })
+        }
+        // 如果脚本有变化,生成的keys和outputFieldList的长度不一致,就重新生成outputFieldList,仅添加变化的那个字段,其余的不变化
+        if (this.outputFieldList.length !== keys.length) {
+          const newKeys = keys.filter(item => {
+            return !this.outputFieldList.some(key => {
+              return key.fieldName === item
+            })
+          })
+          newKeys.forEach(item => {
+            this.outputFieldList.push({
+              fieldName: item,
+              fieldDesc: ''
+            })
+          })
+        }
+        if (this.outputFieldList.length && this.fieldDesc && !isInit) {
           this.buildFieldDesc()
         }
         // 如果有数据,就通过测试
@@ -651,15 +674,15 @@ export default {
       }
     },
     // 执行事件
-    toExecute () {
-      // if (this.dataForm.config.paramsList.length) {
-      //   this.isSet = false
-      //   this.paramsVisible = true
-      // } else {
-      // 无参数,直接执行脚本
-      this.scriptExecute()
-      // }
-    },
+    // toExecute () {
+    // if (this.dataForm.config.paramsList.length) {
+    //   this.isSet = false
+    //   this.paramsVisible = true
+    // } else {
+    // 无参数,直接执行脚本
+    // this.scriptExecute()
+    // }
+    // },
     // 清空分类
     clearType () {
       this.typeName = ''
@@ -697,151 +720,152 @@ export default {
 }
 </script>
 
-  <style lang="scss" scoped>
-  @import '../../../packages/assets/style/bsTheme.scss';
+<style lang="scss" scoped>
+@import '../../../packages/assets/style/bsTheme.scss';
 
-  .data-set-scrollbar {
-    height: 100%;
-    overflow-y: auto;
-    overflow-x: none;
+.data-set-scrollbar {
+  height: 100%;
+  overflow-y: auto;
+  overflow-x: none;
 
-    .el-scrollbar__view {
-      height: 100%;
-    }
-  }
-
-  /deep/ .el-input__inner {
-    width: 100% !important;
+  .el-scrollbar__view {
+    height: 100%;
   }
+}
 
-  .page-header {
-    display: flex;
-    position: relative;
+/deep/ .el-input__inner {
+  width: 100% !important;
+}
 
-    .page-header-right {
-      position: absolute;
-      right: 16px;
-    }
-  }
+.page-header {
+  display: flex;
+  position: relative;
 
-  .sql-config {
-    padding: 0 16px;
+  .page-header-right {
+    position: absolute;
+    right: 16px;
   }
+}
 
-  .operation {
-    /deep/ .el-select {
-      width: 200px !important;
-      margin-right: 16px;
-    }
+.sql-config {
+  padding: 0 16px;
+}
 
-    display: flex;
+.operation {
+  /deep/ .el-select {
+    width: 200px !important;
+    margin-right: 16px;
   }
 
-  /deep/ .CodeMirror {
-    height: 180px !important;
-    font-family: Helvetica, Tahoma;
-  }
+  display: flex;
+}
 
-  .no-border {
-    border: 0;
-  }
+/deep/ .CodeMirror {
+  height: 180px !important;
+  font-family: Helvetica, Tahoma;
+}
 
-  /deep/ .fieldDescCheck {
-    .el-dialog__body {
-      height: fit-content !important;
-      min-height: unset !important;
-    }
-  }
+.no-border {
+  border: 0;
+}
 
-  .title-style {
-    padding: 8px 12px;
-    background-color: #f6f7fb;
-    border-left: 5px solid var(--bs-el-color-primary);
-    margin: 16px 16px 0 0;
+/deep/ .fieldDescCheck {
+  .el-dialog__body {
+    height: fit-content !important;
+    min-height: unset !important;
   }
+}
 
-  .field-wrap {
-    // max-height: 110px;
-    overflow: auto;
-    margin-right: 16px;
-    cursor: pointer;
+.title-style {
+  padding: 8px 12px;
+  background-color: #f6f7fb;
+  border-left: 5px solid var(--bs-el-color-primary);
+  margin: 16px 16px 0 0;
+}
 
-    .field-item {
-      line-height: 32px;
-      padding: 0 12px 0 16px;
+.field-wrap {
+  // max-height: 110px;
+  overflow: auto;
+  margin-right: 16px;
+  cursor: pointer;
 
-      .edit_field {
-        display: none;
-      }
+  .field-item {
+    line-height: 32px;
+    padding: 0 12px 0 16px;
+
+    .edit_field {
+      display: none;
+    }
 
-      &:hover {
-        background-color: #f2f7fe;
+    &:hover {
+      background-color: #f2f7fe;
 
-        .edit_field {
-          display: block;
-        }
+      .edit_field {
+        display: block;
       }
     }
   }
+}
 
-  .right-setting {
-    height: 358px;
-    overflow: hidden;
-    display: flex;
-    flex-direction: column;
+.right-setting {
+  height: 358px;
+  overflow: hidden;
+  display: flex;
+  flex-direction: column;
 
-    .paramConfig {
-      max-height: 179px;
+  .paramConfig {
+    max-height: 179px;
 
-      .field-wrap {
-        max-height: 127px;
-      }
+    .field-wrap {
+      max-height: 127px;
     }
+  }
 
-    .structure {
-      flex: 1;
-      overflow: hidden;
+  .structure {
+    flex: 1;
+    overflow: hidden;
 
-      .field-wrap {
-        height: calc(100% - 40px);
-      }
+    .field-wrap {
+      height: calc(100% - 40px);
     }
   }
+}
 
-  .result-view {
-    font-size: 14px;
-    font-weight: 600;
-    color: var(--bs-el-text);
-    position: relative;
-    padding: 16px 0;
-    padding-left: 12px;
-    border-bottom: 1px solid var(--bs-background-1);
+.result-view {
+  font-size: 14px;
+  font-weight: 600;
+  color: var(--bs-el-text);
+  position: relative;
+  padding: 16px 0;
+  padding-left: 12px;
+  border-bottom: 1px solid var(--bs-background-1);
 
-    &::before {
-      content: "";
-      height: 14px;
-      position: absolute;
-      left: 0;
-      top: 50%;
-      transform: translateY(-50%);
-      border-left: 4px solid var(--bs-el-color-primary);
-    }
+  &::before {
+    content: "";
+    height: 14px;
+    position: absolute;
+    left: 0;
+    top: 50%;
+    transform: translateY(-50%);
+    border-left: 4px solid var(--bs-el-color-primary);
   }
+}
 
-  /deep/ .bs-table-box.is-Edit .el-table {
-    max-height: unset !important;
+/deep/ .bs-table-box.is-Edit .el-table {
+  max-height: unset !important;
 
-    .el-table__body-wrapper {
-      max-height: unset !important;
-    }
+  .el-table__body-wrapper {
+    max-height: unset !important;
   }
+}
 
-  .bs-table-box {
-    padding: 0;
-    height: 100% !important;
-    margin-bottom: 0 !important;
-  }
-  .tree-box{
-    padding: 0;
-  }
-  </style>
+.bs-table-box {
+  padding: 0;
+  height: 100% !important;
+  margin-bottom: 0 !important;
+}
+
+.tree-box {
+  padding: 0;
+}
+</style>

+ 41 - 41
data-room-ui/package-lock.json

@@ -3307,27 +3307,6 @@
         "whatwg-fetch": "^3.6.2"
       },
       "dependencies": {
-        "@vue/vue-loader-v15": {
-          "version": "npm:vue-loader@15.10.1",
-          "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.10.1.tgz",
-          "integrity": "sha512-SaPHK1A01VrNthlix6h1hq4uJu7S/z0kdLUb6klubo738NeQoLbS6V9/d8Pv19tU0XdQKju3D1HSKuI8wJ5wMA==",
-          "dev": true,
-          "requires": {
-            "@vue/component-compiler-utils": "^3.1.0",
-            "hash-sum": "^1.0.2",
-            "loader-utils": "^1.1.0",
-            "vue-hot-reload-api": "^2.3.0",
-            "vue-style-loader": "^4.1.0"
-          },
-          "dependencies": {
-            "hash-sum": {
-              "version": "1.0.2",
-              "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz",
-              "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==",
-              "dev": true
-            }
-          }
-        },
         "acorn-walk": {
           "version": "8.2.0",
           "resolved": "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-8.2.0.tgz",
@@ -3399,26 +3378,6 @@
             "tapable": "^2.0.0"
           }
         },
-        "json5": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
-          "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
-          "dev": true,
-          "requires": {
-            "minimist": "^1.2.0"
-          }
-        },
-        "loader-utils": {
-          "version": "1.4.2",
-          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz",
-          "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
-          "dev": true,
-          "requires": {
-            "big.js": "^5.2.2",
-            "emojis-list": "^3.0.0",
-            "json5": "^1.0.1"
-          }
-        },
         "ms": {
           "version": "2.1.2",
           "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz",
@@ -3636,6 +3595,47 @@
         "lodash": "^4.17.4"
       }
     },
+    "@vue/vue-loader-v15": {
+      "version": "npm:vue-loader@15.10.1",
+      "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.10.1.tgz",
+      "integrity": "sha512-SaPHK1A01VrNthlix6h1hq4uJu7S/z0kdLUb6klubo738NeQoLbS6V9/d8Pv19tU0XdQKju3D1HSKuI8wJ5wMA==",
+      "dev": true,
+      "requires": {
+        "@vue/component-compiler-utils": "^3.1.0",
+        "hash-sum": "^1.0.2",
+        "loader-utils": "^1.1.0",
+        "vue-hot-reload-api": "^2.3.0",
+        "vue-style-loader": "^4.1.0"
+      },
+      "dependencies": {
+        "hash-sum": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz",
+          "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==",
+          "dev": true
+        },
+        "json5": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+          "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+          "dev": true,
+          "requires": {
+            "minimist": "^1.2.0"
+          }
+        },
+        "loader-utils": {
+          "version": "1.4.2",
+          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz",
+          "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
+          "dev": true,
+          "requires": {
+            "big.js": "^5.2.2",
+            "emojis-list": "^3.0.0",
+            "json5": "^1.0.1"
+          }
+        }
+      }
+    },
     "@vue/vue2-jest": {
       "version": "27.0.0",
       "resolved": "https://registry.npmmirror.com/@vue/vue2-jest/-/vue2-jest-27.0.0.tgz",

+ 16 - 5
data-room-ui/packages/BigScreenComponentMag/SideMenu.vue

@@ -2,10 +2,10 @@
   <div class="side-catalog-wrap">
     <el-scrollbar class="side-catalog-box">
       <div
-        v-for="(com,index) in componentList"
+        v-for="(com, index) in componentList"
         :key="index"
         class="component-item-box"
-        :class="{'active-catalog':activeType === com.type}"
+        :class="{ 'active-catalog': activeType === com.type }"
         @click="componentHandle(com)"
       >
         {{ com.name }}
@@ -16,7 +16,7 @@
 <script>
 
 export default {
-  components: { },
+  components: {},
   data () {
     return {
       componentList: [
@@ -36,13 +36,24 @@ export default {
       activeType: 'component'
     }
   },
-  mounted () {
+  created () {
+    const type = this.$route?.query?.type
+    if (type) {
+      this.componentHandle(this.componentList.find(item => item.type === type))
+    } else {
+      this.componentHandle(this.componentList[0])
+    }
   },
   methods: {
     // 点击左侧组件
     componentHandle (com) {
       this.activeType = com.type
-      this.$emit('getPageInfo', com.type)
+      this.$router.push({
+        path: window.BS_CONFIG?.routers?.componentUrl || '/big-screen-components',
+        query: {
+          type: com.type
+        }
+      })
     }
   }
 }

+ 4 - 13
data-room-ui/packages/BigScreenComponentMag/index.vue

@@ -1,11 +1,7 @@
 <template>
   <div class="bs-manage-main-wrap">
-    <side-menu
-      @getPageInfo="getPageInfo"
-    />
-    <menu-content
-      :catalog-info="catalogInfo"
-    />
+    <side-menu />
+    <menu-content />
   </div>
 </template>
 <script>
@@ -18,15 +14,10 @@ export default {
   components: { SideMenu, MenuContent },
   data () {
     return {
-      catalogInfo: 'component'
     }
   },
-  mounted () {},
-  methods: {
-    getPageInfo (type) {
-      this.catalogInfo = type
-    }
-  }
+  mounted () { },
+  methods: {}
 }
 </script>
 

+ 41 - 43
data-room-ui/packages/BigScreenDesign/RightSetting/DataSetting.vue

@@ -28,11 +28,7 @@
               <data-set-select
                 :dataset-name="datasetName"
                 :ds-id="config.dataSource.businessKey"
-                @getDsId="
-                  dsId => {
-                    getDataSetDetailsById(dsId, 'treeTable');
-                  }
-                "
+                @getDsId="dsId => { getDataSetDetailsById(dsId, 'treeTable');}"
               />
             </el-form-item>
           </div>
@@ -713,57 +709,58 @@ export default {
     },
     // 根据数据集来获取数据集详情
     getDataSetDetailsById (id, type) {
-      this.config.dataSource.businessKey = id
-      getDataSetDetails(id).then(res => {
-        this.fieldsList = res.fields
-        // 初始化时以组件本来的参数设置为主
-        if (type === 'initial') {
-          for (const key in this.config.dataSource.params) {
-            const param = res?.params?.find(field => field.name === key)
-            this.params.push({
-              name: key,
-              value: this.config.dataSource.params[key],
-              type: param?.type,
-              remark: param?.remark
-            })
+      if (id) {
+        this.config.dataSource.businessKey = id
+        getDataSetDetails(id).then(res => {
+          this.fieldsList = res.fields
+          // 初始化时以组件本来的参数设置为主
+          if (type === 'initial') {
+            for (const key in this.config.dataSource.params) {
+              const param = res?.params?.find(field => field.name === key)
+              this.params.push({
+                name: key,
+                value: this.config.dataSource.params[key],
+                type: param?.type,
+                remark: param?.remark
+              })
+            }
+          } else {
+            this.params = res.params
           }
-        } else {
-          this.params = res.params
-        }
 
-        this.datasetName = res.name
-        // 选择数据集的时候,如果数据集类型是dataModel,则不显示参数配置
-        this.config.option.displayOption.params.enable = res.type !== 'dataModel'
-        // 根据数据集初始化组件的入参:inparams
-        if (res.type !== 'dataModel') {
-          this.config.inParams =
+          this.datasetName = res.name
+          // 选择数据集的时候,如果数据集类型是dataModel,则不显示参数配置
+          this.config.option.displayOption.params.enable = res.type !== 'dataModel'
+          // 根据数据集初始化组件的入参:inparams
+          if (res.type !== 'dataModel') {
+            this.config.inParams =
             this.params?.map(param => {
               return {
                 name: param.remark, // 参数名
                 code: param.name // 参数值
               }
             }) || []
-        } else {
-          this.config.inParams =
+          } else {
+            this.config.inParams =
             this.fieldsList?.map(field => {
               return {
                 name: field.fieldDesc, // 参数名
                 code: field.fieldName // 参数值
               }
             }) || []
-        }
-
-        // 根据数据集的参数初始化表单项
-        this.config.paramsList = this.params
-        if (type === 'treeTable') {
-          const enumeration = {
-            dataSetType: '1', // 数据集类型
-            dataSetKey: '', // 数据集
-            itemKeyName: '', // 选项显示字段
-            itemValueName: '', // 选项value字段
-            params: []
           }
-          this.config.fields =
+
+          // 根据数据集的参数初始化表单项
+          this.config.paramsList = this.params
+          if (type === 'treeTable') {
+            const enumeration = {
+              dataSetType: '1', // 数据集类型
+              dataSetKey: '', // 数据集
+              itemKeyName: '', // 选项显示字段
+              itemValueName: '', // 选项value字段
+              params: []
+            }
+            this.config.fields =
             this.params?.map(param => {
               return {
                 name: param.name,
@@ -776,8 +773,9 @@ export default {
                 queryRule: 'like'
               }
             }) || []
-        }
-      })
+          }
+        })
+      }
     },
     // 改变维度
     dimensionFieldListChange (list) {

+ 3 - 1
data-room-ui/packages/BigScreenRun/index.vue

@@ -154,7 +154,9 @@ export default {
     this.windowSize()
   },
   mounted () {
-    this.startTimer()
+    if (this.pageInfo.pageConfig.refreshConfig && this.pageInfo.pageConfig.refreshConfig.length > 0) {
+      this.startTimer()
+    }
   },
   beforeDestroy () {
     this.stopTimer()

+ 74 - 9
data-room-ui/packages/BizComponent/index.vue

@@ -13,7 +13,10 @@
         </div>
       </div>
       <div class="right-btn-wrap">
-        <CusBtn>
+        <CusBtn
+          :loading="loading"
+          @click.native="createdImg()"
+        >
           生成图片
         </CusBtn>
         <CusBtn
@@ -104,6 +107,7 @@
   </div>
 </template>
 <script>
+import { toJpeg, toPng } from 'html-to-image'
 import CusBtn from 'packages/BigScreenDesign/BtnLoading'
 // import MonacoEditor from 'packages/MonacoEditor'
 import BizComponentPreview from './Preview'
@@ -115,6 +119,13 @@ import 'codemirror/theme/material-darker.css'
 import 'codemirror/addon/selection/active-line.js'
 import 'codemirror/mode/vue/vue.js'
 
+import {
+  showSize,
+  dataURLtoBlob,
+  translateBlobToBase64
+} from 'packages/js/utils/compressImg'
+import * as imageConversion from 'image-conversion'
+
 export default {
   name: 'BizComponentDesign',
   components: {
@@ -220,18 +231,72 @@ export default {
     },
     backManagement () {
       this.$router.push({
-        path: window.BS_CONFIG?.routers?.componentUrl || '/big-screen-components'
+        path: window.BS_CONFIG?.routers?.componentUrl || '/big-screen-components',
+        query: {
+          type: 'bizComponent'
+        }
       })
     },
     save () {
       this.loading = true
-      updateBizComponent(this.form).then(() => {
-        this.$message.success('保存成功')
-      }).catch(() => {
-        this.$message.error('保存失败')
-      }).finally(() => {
-        this.loading = false
-      })
+      const node = document.querySelector('.bs-preview-inner')
+      toJpeg(node, { quality: 0.2 })
+        .then((dataUrl) => {
+          const that = this
+          if (showSize(dataUrl) > 200) {
+            const url = dataURLtoBlob(dataUrl)
+            // 压缩到500KB,这里的500就是要压缩的大小,可自定义
+            imageConversion
+              .compressAccurately(url, {
+                size: 200, // 图片大小压缩到100kb
+                width: 1280, // 宽度压缩到1280
+                height: 720 // 高度压缩到720
+              })
+              .then((res) => {
+                translateBlobToBase64(res, function (e) {
+                  this.form.coverPicture = e.result
+                  updateBizComponent(this.form)
+                    .then((res) => {
+                      that.$message.success('保存成功')
+                    })
+                    .finally(() => {
+                      that.loading = false
+                    })
+                })
+              })
+          } else {
+            this.form.coverPicture = dataUrl
+            updateBizComponent(this.form)
+              .then(() => {
+                this.$message.success('保存成功')
+              })
+              .finally(() => {
+                this.loading = false
+              })
+          }
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    createdImg () {
+      this.loading = true
+      const node = document.querySelector('.bs-preview-inner')
+      toPng(node)
+        .then((dataUrl) => {
+          const link = document.createElement('a')
+          link.download = `${this.form.name}.png`
+          link.href = dataUrl
+          link.click()
+          link.addEventListener('click', () => {
+            link.remove()
+          })
+          this.loading = false
+        })
+        .catch(() => {
+          this.$message.warning('出现未知错误,请重试')
+          this.loading = false
+        })
     }
   }
 }

+ 6 - 9
data-room-ui/packages/ComponentList/index.vue

@@ -120,7 +120,7 @@
           </div>
           <div class="big-screen-card-img">
             <el-image
-              :src="catalogInfo !== 'system'?screen.coverPicture:screen.img"
+              :src="catalogInfo !== 'system' ? screen.coverPicture : screen.img"
               fit="fill"
               style="width: 100%; height: 100%"
             >
@@ -201,16 +201,12 @@ import innerRemoteComponents, { getRemoteComponents } from 'packages/RemoteCompo
 export default {
   name: 'BigScreenList',
   mixins: [pageMixins],
-  props: {
-    catalogInfo: {
-      type: String,
-      default: ''
-    }
-  },
+  props: { },
   components: { EditForm, CatalogEditForm },
   data () {
     return {
       name: '',
+      catalogInfo: 'component',
       catalogVisible: false,
       templateLoading: false,
       searchKey: '',
@@ -230,7 +226,6 @@ export default {
       }
     },
     code () {
-      // return this.catalogInfo?.page?.code
       return ''
     },
     gridComputed () {
@@ -238,7 +233,8 @@ export default {
     }
   },
   watch: {
-    catalogInfo () {
+    $route (val) {
+      this.catalogInfo = val.query.type || 'component'
       this.reset()
       this.init()
     },
@@ -247,6 +243,7 @@ export default {
     }
   },
   mounted () {
+    this.catalogInfo = this.$route.query.type || 'component'
     this.init()
   },
   methods: {

+ 0 - 1
data-room-ui/packages/DataSetManagement/src/DatasetTypeDialog.vue

@@ -138,7 +138,6 @@ export default {
   methods: {
     // 选择新增类型
     openAddForm (type, componentName) {
-      console.log()
       this.dialogVisible = false
       this.$emit('openAddForm', type, componentName)
     }

+ 0 - 1
data-room-ui/packages/DataSetManagement/src/OriginalEditForm.vue

@@ -945,7 +945,6 @@ export default {
         this.currentCount = data.data.currentCount
         this.tableLoading = false
       }).catch((e) => {
-        console.log(e)
         this.dataPreviewList = []
         this.structurePreviewList = []
         this.structurePreviewListCopy = []

+ 2 - 2
data-room-ui/packages/DataSetManagement/src/ScriptEditForm.vue

@@ -667,6 +667,8 @@ export default {
         this.dataForm.paramsList = res.config.paramsList ? res.config.paramsList : []
         this.dataForm.fieldDesc = res.config.fieldDesc
         this.dataForm.fieldList = res.config.fieldList
+
+        this.paramsListCopy = _.cloneDeep(this.dataForm.paramsList)
         this.scriptExecute(true)
       })
     },
@@ -770,7 +772,6 @@ export default {
             }
           })
         }
-        console.log(this.structurePreviewList)
         if (this.structurePreviewList.length && this.dataForm.fieldDesc) {
           this.buildFieldDesc()
         }
@@ -778,7 +779,6 @@ export default {
         this.saveLoading = false
         this.passTest = true
       }).catch((e) => {
-        console.log(e)
         this.passTest = false
         this.saveLoading = false
       })

+ 1 - 1
data-room-ui/packages/DataSetManagement/src/index.vue

@@ -460,7 +460,7 @@ export default {
         { name: '全部', datasetType: '' },
         { name: '原始数据集', datasetType: 'original', componentName: 'OriginalEditForm' },
         { name: '自助数据集', datasetType: 'custom', componentName: 'CustomEditForm' },
-        { name: '存储过程数据集', datasetType: 'storedProcedure', componentName: 'CustomEditForm' },
+        { name: '存储过程数据集', datasetType: 'storedProcedure', componentName: 'StoredProcedureEditForm' },
         { name: 'JSON数据集', datasetType: 'json', componentName: 'JsonEditForm' },
         { name: '脚本数据集', datasetType: 'script', componentName: 'ScriptEditForm' }
       ]

+ 26 - 0
data-room-ui/packages/js/mixins/commonMixins.js

@@ -71,6 +71,19 @@ export default {
           size: size,
           type: config.type
         }).then((data) => {
+          if (data.executionByFrontend) {
+            try {
+              const scriptAfterReplacement = data.data.replace(/\${(.*?)}/g, (match, p) => {
+                // 根据parmas的key获取value
+                return `'${this.config.dataSource?.params[p]}' || '${p}'`
+              })
+              // eslint-disable-next-line no-new-func
+              const scriptMethod = new Function(scriptAfterReplacement)
+              data.data = scriptMethod()
+            } catch (error) {
+              console.error('数据集脚本执行失败', error)
+            }
+          }
           config = this.dataFormatting(config, data)
           this.changeChartConfig(config)
         }).catch((err) => {
@@ -97,6 +110,19 @@ export default {
       }
       return new Promise((resolve, reject) => {
         getUpdateChartInfo(params).then((data) => {
+          if (data.executionByFrontend) {
+            try {
+              const scriptAfterReplacement = data.data.replace(/\${(.*?)}/g, (match, p) => {
+                // 根据parmas的key获取value
+                return `'${this.config.dataSource?.params[p]}' || '${p}'`
+              })
+              // eslint-disable-next-line no-new-func
+              const scriptMethod = new Function(scriptAfterReplacement)
+              data.data = scriptMethod()
+            } catch (error) {
+              console.error('数据集脚本执行失败', error)
+            }
+          }
           config = this.dataFormatting(config, data)
           // this.changeChartConfig(config)
           if (this.chart) {

+ 0 - 1
data-room-ui/packages/js/mixins/multipleSelectMixin.js

@@ -133,7 +133,6 @@ export default {
       }
 
       if ((event.ctrlKey || event.metaKey) && event.keyCode === 86) {
-        console.log('粘贴')
         // 粘贴
         this.pasteCharts()
       }

+ 1 - 1
data-room-ui/packages/js/store/actions.js

@@ -38,7 +38,6 @@ export default {
   // 初始化缓存数据集字段
   getCacheDataFields ({ commit, dispatch }, { dataSetId }) {
     getDataSetDetails(dataSetId).then(data => {
-      console.log(2, data)
       commit('changeCacheDataFields', { dataSetId, data })
       commit('changeCacheDataParams', { dataSetId, data })
     })
@@ -65,6 +64,7 @@ export function handleResData (data) {
   }
   // 如果pageConfig中的cacheDataSets为null,赋值[]
   pageInfo.pageConfig.cacheDataSets = pageInfo.pageConfig.cacheDataSets || []
+  pageInfo.pageConfig.refreshConfig = pageInfo.pageConfig.refreshConfig || []
   pageInfo.chartList.forEach((chart) => {
     if (!['customComponent', 'remoteComponent'].includes(chart.type)) {
       chart.option = _.cloneDeep(setModules[chart.type])

+ 1 - 0
data-room-ui/packages/js/store/state.js

@@ -26,6 +26,7 @@ export const defaultData = {
       themeJson: {}, // 自定义主题配置
       // 缓存的数据集 { name: '', dataSetId: '' }
       cacheDataSets: [],
+      refreshConfig: [],
       // 自适应模式  无(none) 、自动(auto)、宽度铺满(fitWidth)、高度铺满(fitHeight)和 双向铺满(cover) 5 种自适应模式
       fitMode: 'none'
     },

+ 2 - 1
data-room-ui/vue.config.example.js

@@ -39,7 +39,8 @@ module.exports = {
       chunks: 'all'
     }
   },
-  publicPath: process.env.VUE_APP_HISTORY === 'y' ? process.env.VUE_APP_BASE : './',
+  publicPath:
+    process.env.VUE_APP_HISTORY === 'y' ? process.env.VUE_APP_BASE : './',
   outputDir: 'bigScreen',
   assetsDir: 'static',
   lintOnSave: false,