diff --git a/core/core-backend/src/main/java/io/dataease/copilot/manage/CopilotManage.java b/core/core-backend/src/main/java/io/dataease/copilot/manage/CopilotManage.java index 958547586f..45e103287e 100644 --- a/core/core-backend/src/main/java/io/dataease/copilot/manage/CopilotManage.java +++ b/core/core-backend/src/main/java/io/dataease/copilot/manage/CopilotManage.java @@ -104,7 +104,7 @@ public class CopilotManage { Map dsMap = (Map) sqlMap.get("dsMap"); boolean crossDs = Utils.isCrossDs(dsMap); if (crossDs) { - DEException.throwException("跨源数据集不支持该功能"); + DEException.throwException(Translator.get("i18n_copilot_cross_ds_error")); } // 调用copilot service 获取SQL和chart struct,将返回SQL中表名替换成数据集SQL @@ -302,7 +302,7 @@ public class CopilotManage { if (StringUtils.equalsIgnoreCase(receiveDTO.getChart().getType(), "pie")) { AxisFieldDTO column = receiveDTO.getChart().getColumn(); if (fields.size() != 2 || column == null) { - DEException.throwException("当前字段不足以构建饼图: " + JsonUtil.toJSONString(receiveDTO)); + DEException.throwException("build pie error: " + JsonUtil.toJSONString(receiveDTO)); } AxisDTO axisDTO = new AxisDTO(); AxisFieldDTO x = new AxisFieldDTO(); @@ -318,7 +318,7 @@ public class CopilotManage { y.setName(column.getName()); y.setValue(column.getValue()); } else { - DEException.throwException("当前字段不足以构建饼图: " + JsonUtil.toJSONString(receiveDTO)); + DEException.throwException("build pie error: " + JsonUtil.toJSONString(receiveDTO)); } axisDTO.setX(x); axisDTO.setY(y); diff --git a/core/core-backend/src/main/java/io/dataease/datasource/provider/ExcelUtils.java b/core/core-backend/src/main/java/io/dataease/datasource/provider/ExcelUtils.java index f41ac59953..b8ae99d1ea 100644 --- a/core/core-backend/src/main/java/io/dataease/datasource/provider/ExcelUtils.java +++ b/core/core-backend/src/main/java/io/dataease/datasource/provider/ExcelUtils.java @@ -15,6 +15,7 @@ import io.dataease.api.ds.vo.ExcelSheetData; import io.dataease.datasource.dao.auto.entity.CoreDatasource; import io.dataease.exception.DEException; import io.dataease.extensions.datasource.dto.DatasetTableDTO; +import io.dataease.extensions.datasource.dto.DatasourceDTO; import io.dataease.extensions.datasource.dto.DatasourceRequest; import io.dataease.extensions.datasource.dto.TableField; import io.dataease.utils.AuthUtils; @@ -40,6 +41,21 @@ public class ExcelUtils { private static TypeReference> TableFieldListTypeReference = new TypeReference>() { }; + private static TypeReference> sheets = new TypeReference>() { + }; + + public static void mergeSheets(CoreDatasource requestDatasource, DatasourceDTO sourceData) { + List newSheets = JsonUtil.parseList(requestDatasource.getConfiguration(), sheets); + List tableNames = newSheets.stream().map(ExcelSheetData::getDeTableName).collect(Collectors.toList()); + List oldSheets = JsonUtil.parseList(sourceData.getConfiguration(), sheets); + for (ExcelSheetData oldSheet : oldSheets) { + if (!tableNames.contains(oldSheet.getDeTableName())) { + newSheets.add(oldSheet); + } + } + requestDatasource.setConfiguration(JsonUtil.toJSONString(newSheets).toString()); + } + public static List getTables(DatasourceRequest datasourceRequest) throws DEException { List tableDescs = new ArrayList<>(); try { diff --git a/core/core-backend/src/main/java/io/dataease/datasource/server/DatasourceServer.java b/core/core-backend/src/main/java/io/dataease/datasource/server/DatasourceServer.java index 2f789541d9..a94d55fe6f 100644 --- a/core/core-backend/src/main/java/io/dataease/datasource/server/DatasourceServer.java +++ b/core/core-backend/src/main/java/io/dataease/datasource/server/DatasourceServer.java @@ -404,7 +404,7 @@ public class DatasourceServer implements DatasourceApi { List tables = ExcelUtils.getTables(datasourceRequest).stream().map(DatasetTableDTO::getTableName).collect(Collectors.toList()); if (dataSourceDTO.getEditType() == 0) { toCreateTables = tables; - toDeleteTables = sourceTables; + toDeleteTables = sourceTables.stream().filter(s -> tables.contains(s)).collect(Collectors.toList()); for (String deleteTable : toDeleteTables) { try { datasourceSyncManage.dropEngineTable(deleteTable); @@ -422,6 +422,7 @@ public class DatasourceServer implements DatasourceApi { } datasourceSyncManage.extractExcelData(requestDatasource, "all_scope"); dataSourceManage.checkName(dataSourceDTO); + ExcelUtils.mergeSheets(requestDatasource, sourceData); dataSourceManage.innerEdit(requestDatasource); } else { datasourceSyncManage.extractExcelData(requestDatasource, "add_scope"); @@ -735,11 +736,15 @@ public class DatasourceServer implements DatasourceApi { } } + private static final Integer replace = 0; + private static final Integer append = 1; + public ExcelFileData excelUpload(@RequestParam("file") MultipartFile file, @RequestParam("id") long datasourceId, @RequestParam("editType") Integer editType) throws DEException { + CoreDatasource coreDatasource = datasourceMapper.selectById(datasourceId); + ExcelUtils excelUtils = new ExcelUtils(); ExcelFileData excelFileData = excelUtils.excelSaveAndParse(file); - if (editType == 1 || editType == 0) { //按照excel sheet 名称匹配 - CoreDatasource coreDatasource = datasourceMapper.selectById(datasourceId); + if (Objects.equals(editType, append)) { //按照excel sheet 名称匹配,替换:0;追加:1 if (coreDatasource != null) { DatasourceRequest datasourceRequest = new DatasourceRequest(); datasourceRequest.setDatasource(transDTO(coreDatasource)); @@ -757,7 +762,6 @@ public class DatasourceServer implements DatasourceApi { oldTableFields.sort((o1, o2) -> { return o1.getName().compareTo(o2.getName()); }); - if (isEqual(newTableFields, oldTableFields)) { sheet.setDeTableName(datasetTableDTO.getTableName()); excelSheetDataList.add(sheet); @@ -770,8 +774,21 @@ public class DatasourceServer implements DatasourceApi { } excelFileData.setSheets(excelSheetDataList); } - } + } else { + if (coreDatasource != null) { + DatasourceRequest datasourceRequest = new DatasourceRequest(); + datasourceRequest.setDatasource(transDTO(coreDatasource)); + List datasetTableDTOS = ExcelUtils.getTables(datasourceRequest); + for (ExcelSheetData sheet : excelFileData.getSheets()) { + for (DatasetTableDTO datasetTableDTO : datasetTableDTOS) { + if (excelDataTableName(datasetTableDTO.getTableName()).equals(sheet.getTableName()) || isCsv(file.getOriginalFilename())) { + sheet.setDeTableName(datasetTableDTO.getTableName()); + } + } + } + } + } for (ExcelSheetData sheet : excelFileData.getSheets()) { for (int i = 0; i < sheet.getFields().size() - 1; i++) { for (int j = i + 1; j < sheet.getFields().size(); j++) { @@ -1155,8 +1172,11 @@ public class DatasourceServer implements DatasourceApi { if (!Arrays.asList("API", "Excel", "folder").contains(coreDatasource.getType())) { calciteProvider.updateDsPoolAfterCheckStatus(datasourceDTO); } + } catch (DEException e) { + datasourceDTO.setStatus("Error"); + DEException.throwException(e.getMessage()); } catch (Exception e) { - coreDatasource.setStatus("Error"); + datasourceDTO.setStatus("Error"); DEException.throwException(e.getMessage()); } finally { coreDatasource.setStatus(datasourceDTO.getStatus()); diff --git a/core/core-backend/src/main/resources/i18n/core_en_US.properties b/core/core-backend/src/main/resources/i18n/core_en_US.properties index 754ac8068e..2480b8638e 100644 --- a/core/core-backend/src/main/resources/i18n/core_en_US.properties +++ b/core/core-backend/src/main/resources/i18n/core_en_US.properties @@ -62,3 +62,45 @@ i18n_day=Day i18n_hour=Hour i18n_minute=Minute i18n_second=Second + +i18n_no_datasource_permission_to_create_column=No datasource permission, cannot create column +i18n_df_folder_cannot_to_search=Folder cannot for search data +i18n_df_no_primary_key=No primary key +i18n_df_cannot_operate_folder=Cannot Operate Folder +i18n_df_cannot_be_none=[%s] Cannot be null +i18n_df_value_cannot_be_none=[%s] value: %s Cannot be null +i18n_df_value_exists_in_database=[%s] value: %s Exists in database +i18n_df_data=Data +i18n_df_start=Start +i18n_df_end=End +i18n_df_datasource_not_found=datasource not found +i18n_df_datasource_does_not_enable_data_filling=function of dataFilling is not enabled +i18n_df_builtin_datasource=builtin datasource +i18n_df_folder_required=folder required +i18n_df_form_not_exists=form not exists +i18n_df_name_can_not_empty=name can not empty +i18n_df_template=template +i18n_df_task_status_is_null_or_finished=task status is null or finished +i18n_df_task_need_task_id=task need taskID +i18n_df_not_current_task_user=not current task user +i18n_df_miss_parameter=miss parameter +i18n_df_no_running_instance=no running instance +i18n_df_value=value +i18n_df_format_error=parse error +i18n_df_cannot_earlier_than=cannot earlier than +i18n_df_cannot_be_all_null=cannot be all null +i18n_df_value_not_in_range=value not in range +i18n_df_value_value_not_in_range=value: %s not in range +i18n_df_required=required +i18n_df_must_unique=must be unique +i18n_df_excel_parsing_error=Excel parse error +i18n_df_excel_is_empty=Excel is empty +i18n_df_excel_template_column_not_fit=count of template columns are not fit +i18n_df_selection=selection +i18n_df_date_format=date format +i18n_df_integer=integer +i18n_df_decimal=decimal +i18n_df_multiple_value_split=use ';' to split multiple value +i18n_df_email_type=email type +i18n_df_phone_type=phone type + diff --git a/core/core-backend/src/main/resources/i18n/core_zh_CN.properties b/core/core-backend/src/main/resources/i18n/core_zh_CN.properties index b63511eede..ae5e257be2 100644 --- a/core/core-backend/src/main/resources/i18n/core_zh_CN.properties +++ b/core/core-backend/src/main/resources/i18n/core_zh_CN.properties @@ -81,3 +81,48 @@ i18n_day=\u5929 i18n_hour=\u5C0F\u65F6 i18n_minute=\u5206\u949F i18n_second=\u79D2 + +i18n_no_datasource_permission_to_create_column=\u65E0\u6570\u636E\u6E90\u8BBF\u95EE\u6743\u9650\uFF0C\u65E0\u6CD5\u521B\u5EFA\u8868\u5B57\u6BB5 +i18n_df_folder_cannot_to_search=\u6587\u4EF6\u5939\u4E0D\u80FD\u67E5\u8BE2\u6570\u636E +i18n_df_no_primary_key=\u6CA1\u6709\u4E3B\u952E +i18n_df_cannot_operate_folder=\u4E0D\u80FD\u64CD\u4F5C\u6587\u4EF6\u5939 +i18n_df_cannot_be_none=[%s] \u4E0D\u80FD\u4E3A\u7A7A +i18n_df_value_cannot_be_none=[%s] \u503C: %s \u4E0D\u80FD\u4E3A\u7A7A +i18n_df_value_exists_in_database=[%s] \u503C: %s \u5728\u6570\u636E\u5E93\u4E2D\u5DF2\u5B58\u5728, \u4E0D\u80FD\u91CD\u590D +i18n_df_data=\u6570\u636E +i18n_df_start=\u5F00\u59CB +i18n_df_end=\u7ED3\u675F +i18n_df_datasource_not_found=\u6CA1\u6709\u627E\u5230\u6570\u636E\u6E90 +i18n_df_datasource_does_not_enable_data_filling=\u8BE5\u6570\u636E\u6E90\u6CA1\u6709\u542F\u7528\u6570\u636E\u586B\u62A5\u914D\u7F6E +i18n_df_builtin_datasource=\u5185\u5EFA\u6570\u636E\u5E93 +i18n_df_folder_required=\u76EE\u5F55\u5FC5\u9009 +i18n_df_form_not_exists=\u8868\u5355\u4E0D\u5B58\u5728 +i18n_df_name_can_not_empty=\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A +i18n_df_template=\u6A21\u677F +i18n_df_task_status_is_null_or_finished=\u4EFB\u52A1\u72B6\u6001\u4E3A\u7A7A\u6216\u5DF2\u5B8C\u6210 +i18n_df_task_need_task_id=\u9700\u6307\u5B9A\u4EFB\u52A1ID +i18n_df_not_current_task_user=\u4E0D\u662F\u5F53\u524D\u4EFB\u52A1\u7684\u76EE\u6807\u7528\u6237 +i18n_df_miss_parameter=\u7F3A\u5931\u53C2\u6570 +i18n_df_no_running_instance=\u5F53\u524D\u4EFB\u52A1\u6682\u65F6\u65E0\u8FD0\u884C\u5B9E\u4F8B +i18n_df_value=\u503C +i18n_df_format_error=\u683C\u5F0F\u89E3\u6790\u9519\u8BEF +i18n_df_cannot_earlier_than=\u4E0D\u80FD\u65E9\u4E8E +i18n_df_cannot_be_all_null=\u4E0D\u80FD\u53EA\u6709\u4E00\u4E2A\u4E3A\u7A7A +i18n_df_value_not_in_range=\u503C\u4E0D\u5728\u8303\u56F4\u5185 +i18n_df_value_value_not_in_range=\u503C: %s \u4E0D\u5728\u8303\u56F4\u5185 +i18n_df_required=\u5FC5\u586B +i18n_df_must_unique=\u4E0D\u5141\u8BB8\u91CD\u590D\u503C +i18n_df_excel_parsing_error=Excel\u89E3\u6790\u9519\u8BEF +i18n_df_excel_is_empty=\u8BE5Excel\u6CA1\u6709\u6570\u636E +i18n_df_excel_template_column_not_fit=\u6A21\u677F\u5B57\u6BB5\u4E2A\u6570\u4E0D\u5339\u914D +i18n_df_selection=\u9009\u9879\u503C\u4E3A +i18n_df_date_format=\u65E5\u671F\u683C\u5F0F +i18n_df_integer=\u6574\u5F62\u6570\u5B57 +i18n_df_decimal=\u5C0F\u6570\u6570\u5B57 +i18n_df_multiple_value_split=\u591A\u4E2A\u503C\u4F7F\u7528\u5206\u53F7";"\u5206\u5272 +i18n_df_email_type=\u90AE\u7BB1\u683C\u5F0F +i18n_df_phone_type=\u624B\u673A\u53F7\u683C\u5F0F + + + +i18n_copilot_cross_ds_error=\u8DE8\u6E90\u6570\u636E\u96C6\u4E0D\u652F\u6301\u8BE5\u529F\u80FD diff --git a/core/core-backend/src/main/resources/i18n/core_zh_TW.properties b/core/core-backend/src/main/resources/i18n/core_zh_TW.properties index afbff7d637..b68b352476 100644 --- a/core/core-backend/src/main/resources/i18n/core_zh_TW.properties +++ b/core/core-backend/src/main/resources/i18n/core_zh_TW.properties @@ -2,23 +2,38 @@ login.validator.name1=\u8CEC\u865F/\u90F5\u7BB1/\u624B\u6A5F\u865F\u4E0D\u80FD\u login.validator.pwd1=\u5BC6\u78BC\u4E0D\u80FD\u70BA\u7A7A i18n_menu.home=\u9996\u9801 -i18n_menu.workbranch=\u5DE5\u4F5C\u81FA +i18n_menu.workbranch=\u5DE5\u4F5C\u53F0 i18n_menu.visualized=\u53EF\u8996\u5316 i18n_menu.template=\u6A21\u7248 i18n_menu.application=\u61C9\u7528 i18n_menu.system=\u7CFB\u7D71\u7BA1\u7406 - +i18n_menu.template-market=\u6A21\u677F\u5E02\u5834 +i18n_menu.template-setting=\u6A21\u677F\u7BA1\u7406 i18n_menu.view=\u6578\u64DA\u5C55\u793A -i18n_menu.data=\u6578\u64DA\u6E96\u5099 +i18n_menu.data=\u6578\u64DA\u51C6\u5099 i18n_menu.panel=\u5100\u8868\u677F +i18n_menu.data-filling-manage=\u6578\u64DA\u586B\u5831 i18n_menu.screen=\u6578\u64DA\u5927\u5C4F i18n_menu.dataset=\u6578\u64DA\u96C6 i18n_menu.datasource=\u6578\u64DA\u6E90 i18n_menu.user=\u7528\u6236\u7BA1\u7406 i18n_menu.org=\u7D44\u7E54\u7BA1\u7406 i18n_menu.auth=\u6B0A\u9650\u914D\u7F6E -i18n_menu.sysVariable=\u7CFB\u7EDF\u53D8\u91CF -i18n_field_name_repeat=\u5177\u6709\u91CD\u8907\u7684\u6B04\u4F4D\u540D\u7A31\uFF1A +i18n_menu.report=\u5B9A\u6642\u5831\u544A +i18n_menu.sync=\u540C\u6B65\u7BA1\u7406 +i18n_menu.association=\u8840\u7DE3\u5206\u6790 +i18n_menu.threshold=\u544A\u8B66\u7BA1\u7406 +i18n_menu.summary=\u6982\u89BD +i18n_menu.ds=\u6578\u64DA\u9023\u63A5\u7BA1\u7406 +i18n_menu.task=\u4EFB\u52D9\u7BA1\u7406 +i18n_menu.embedded=\u5D4C\u5165\u5F0F\u7BA1\u7406 +i18n_menu.plugin=\u63D2\u4EF6\u7BA1\u7406 +i18n_menu.platform=\u5E73\u53F0\u5C0D\u63A5 +i18n_menu.appearance=\u5916\u89C0\u914D\u7F6E +i18n_menu.sysVariable=\u7CFB\u7D71\u8B8A\u91CF +i18n_menu.sysTypeface=\u5B57\u9AD4\u7BA1\u7406 +i18n_menu.font=\u5B57\u9AD4\u7BA1\u7406 +i18n_field_name_repeat=\u6709\u91CD\u5FA9\u5B57\u6BB5\u540D\uFF1A i18n_pid_not_eq_id=\u79FB\u52D5\u76EE\u6A19\u4E0D\u80FD\u662F\u81EA\u5DF1\u6216\u5B50\u76EE\u9304 i18n_ds_name_exists=\u8A72\u5206\u7D44\u4E0B\u540D\u7A31\u91CD\u5FA9 i18n_table_id_can_not_empty=\u67E5\u8A62\u7BC0\u9EDE\u4E0D\u80FD\u70BA\u7A7A @@ -32,14 +47,14 @@ i18n_union_field_can_not_empty=\u95DC\u806F\u5B57\u6BB5\u4E0D\u80FD\u70BA\u7A7A i18n_table_duplicate=\u76F8\u540C\u7BC0\u9EDE\u9700\u91CD\u65B0\u62D6\u5165\u624D\u80FD\u7E7C\u7E8C\u65B0\u5EFA\u6578\u64DA\u96C6 i18n_no_column_permission=\u6C92\u6709\u5217\u6B0A\u9650 i18n_fetch_error=SQL\u57F7\u884C\u5931\u6557\uFF0C\u8ACB\u6AA2\u67E5\u8868\u3001\u5B57\u6BB5\u3001\u95DC\u806F\u95DC\u7CFB\u7B49\u4FE1\u606F\u662F\u5426\u6B63\u78BA\u4E26\u91CD\u65B0\u7DE8\u8F2F\u3002 -i18n_no_datasource_permission=\u65E0\u6570\u636E\u6E90\u8BBF\u95EE\u6743\u9650 -i18n_no_dataset_permission=\u65e0\u6570\u636e\u96c6\u8bbf\u95ee\u6743\u9650 +i18n_no_datasource_permission=\u7121\u6578\u64DA\u6E90\u8A2A\u554F\u6B0A\u9650 +i18n_no_dataset_permission=\u7121\u6578\u64DA\u96C6\u8A2A\u554F\u6B0A\u9650 i18n_not_full=\u7576\u524D\u6578\u64DA\u6E90\u4E0D\u652F\u6301\u5168\u9023\u63A5 i18n_field_circular_ref=\u5B57\u6BB5\u5B58\u5728\u5FAA\u74B0\u5F15\u7528 i18n_chart_not_handler=\u7121\u6CD5\u8655\u7406\u8A72\u5716\u8868\u985E\u578B -i18n_chart_delete=\u8996\u5716\u4E0D\u5B58\u5728 +i18n_chart_delete=\u5716\u8868\u4E0D\u5B58\u5728 i18n_no_ds=\u6578\u64DA\u96C6\u4E0D\u5B58\u5728\u6216\u6C92\u6709\u6B0A\u9650 i18n_datasource_delete=\u6578\u64DA\u6E90\u4E0D\u5B58\u5728 i18n_gauge_field_change=\u6240\u7528\u5B57\u6BB5\u767C\u751F\u8B8A\u66F4\uFF0C\u8ACB\u91CD\u65B0\u7DE8\u8F2F @@ -53,9 +68,12 @@ i18n_invalid_ds=\u6578\u64DA\u6E90\u7121\u6548 i18n_user_disable=\u7528\u6236\u5DF2\u88AB\u7981\u7528\uFF0C\u7121\u6CD5\u767B\u9304 i18n_login_name_pwd_err=\u7528\u6236\u540D\u6216\u5BC6\u78BC\u932F\u8AA4 i18n_error_login_type=\u767B\u9304\u985E\u578B\u932F\u8AA4 -i18n_schema_is_empty=schema\u70BA\u7A7A\uFF01 -i18n_table_name_repeat=\u540D\u7A31\u91CD\u8907: -i18n_sql_not_empty=sql\u4E0D\u80FD\u70BA\u7A7A +i18n_schema_is_empty=schema \u70BA\u7A7A\uFF01 +i18n_table_name_repeat=\u540D\u7A31\u91CD\u5FA9: +i18n_sql_not_empty=sql \u4E0D\u80FD\u70BA\u7A7A +i18n_menu.parameter=\u7CFB\u7D71\u53C3\u6578 +i18n_user_old_pwd_error=\u539F\u59CB\u5BC6\u78BC\u932F\u8AA4 +i18n_menu.toolbox-log=\u64CD\u4F5C\u65E5\u5FD7 i18n_year=\u5E74 i18n_month=\u6708 @@ -63,3 +81,46 @@ i18n_day=\u5929 i18n_hour=\u5C0F\u6642 i18n_minute=\u5206\u9418 i18n_second=\u79D2 + +i18n_no_datasource_permission_to_create_column=\u7121\u6578\u64DA\u6E90\u8A2A\u554F\u6B0A\u9650\uFF0C\u7121\u6CD5\u5275\u5EFA\u8868\u5B57\u6BB5 +i18n_df_folder_cannot_to_search=\u6587\u4EF6\u593E\u4E0D\u80FD\u67E5\u8A62\u6578\u64DA +i18n_df_no_primary_key=\u6C92\u6709\u4E3B\u9375 +i18n_df_cannot_operate_folder=\u4E0D\u80FD\u64CD\u4F5C\u6587\u4EF6\u593E +i18n_df_cannot_be_none=[%s] \u4E0D\u80FD\u70BA\u7A7A +i18n_df_value_cannot_be_none=[%s] \u503C: %s \u4E0D\u80FD\u70BA\u7A7A +i18n_df_value_exists_in_database=[%s] \u503C: %s \u5728\u6578\u64DA\u5EAB\u4E2D\u5DF2\u5B58\u5728, \u4E0D\u80FD\u91CD\u5FA9 +i18n_df_data=\u6578\u64DA +i18n_df_start=\u958B\u59CB +i18n_df_end=\u7D50\u675F +i18n_df_datasource_not_found=\u6C92\u6709\u627E\u5230\u6578\u64DA\u6E90 +i18n_df_datasource_does_not_enable_data_filling=\u8A72\u6578\u64DA\u6E90\u6C92\u6709\u555F\u7528\u6578\u64DA\u586B\u5831\u914D\u7F6E +i18n_df_builtin_datasource=\u5167\u5EFA\u6578\u64DA\u5EAB +i18n_df_folder_required=\u76EE\u9304\u5FC5\u9078 +i18n_df_form_not_exists=\u8868\u55AE\u4E0D\u5B58\u5728 +i18n_df_name_can_not_empty=\u540D\u7A31\u4E0D\u80FD\u70BA\u7A7A +i18n_df_template=\u6A21\u677F +i18n_df_task_status_is_null_or_finished=\u4EFB\u52D9\u72C0\u614B\u70BA\u7A7A\u6216\u5DF2\u5B8C\u6210 +i18n_df_task_need_task_id=\u9700\u6307\u5B9A\u4EFB\u52D9ID +i18n_df_not_current_task_user=\u4E0D\u662F\u7576\u524D\u4EFB\u52D9\u7684\u76EE\u6A19\u7528\u6236 +i18n_df_miss_parameter=\u7F3A\u5931\u53C3\u6578 +i18n_df_no_running_instance=\u7576\u524D\u4EFB\u52D9\u66AB\u6642\u7121\u904B\u884C\u5BE6\u4F8B +i18n_df_value=\u503C +i18n_df_format_error=\u683C\u5F0F\u89E3\u6790\u932F\u8AA4 +i18n_df_cannot_earlier_than=\u4E0D\u80FD\u65E9\u4E8E +i18n_df_cannot_be_all_null=\u4E0D\u80FD\u53EA\u6709\u4E00\u500B\u70BA\u7A7A +i18n_df_value_not_in_range=\u503C\u4E0D\u5728\u8303\u570D\u5167 +i18n_df_value_value_not_in_range=\u503C: %s \u4E0D\u5728\u8303\u570D\u5167 +i18n_df_required=\u5FC5\u586B +i18n_df_must_unique=\u4E0D\u5141\u8A31\u91CD\u5FA9\u503C +i18n_df_excel_parsing_error=Excel\u89E3\u6790\u932F\u8AA4 +i18n_df_excel_is_empty=\u8A72Excel\u6C92\u6709\u6578\u64DA +i18n_df_excel_template_column_not_fit=\u6A21\u677F\u5B57\u6BB5\u500B\u6578\u4E0D\u5339\u914D +i18n_df_selection=\u9078\u9805\u503C\u70BA +i18n_df_date_format=\u65E5\u671F\u683C\u5F0F +i18n_df_integer=\u6574\u5F62\u6578\u5B57 +i18n_df_decimal=\u5C0F\u6578\u6578\u5B57 +i18n_df_multiple_value_split=\u591A\u500B\u503C\u4F7F\u7528\u5206\u865F";"\u5206\u5272 +i18n_df_email_type=\u90F5\u7BB1\u683C\u5F0F +i18n_df_phone_type=\u624B\u6A5F\u865F\u683C\u5F0F + + diff --git a/core/core-frontend/public/tinymce-dataease-private/langs/zh_CN.js b/core/core-frontend/public/tinymce-dataease-private/langs/zh_CN.js index e83b6c6c46..64f2997509 100644 --- a/core/core-frontend/public/tinymce-dataease-private/langs/zh_CN.js +++ b/core/core-frontend/public/tinymce-dataease-private/langs/zh_CN.js @@ -415,5 +415,9 @@ tinymce.addI18n('zh_CN', { "Whole words": "\u5168\u5b57\u5339\u914d", "Spellcheck": "\u62fc\u5199\u68c0\u67e5", "Caption": "\u6807\u9898", - "Insert template": "\u63d2\u5165\u6a21\u677f" + "Insert template": "\u63d2\u5165\u6a21\u677f", + "Cut column": "\u526a\u5207\u5217", + "Copy column": "\u590d\u5236\u5217", + "Paste column before": "\u7c98\u8d34\u5230\u524d\u65b9", + "Paste column after": "\u7c98\u8d34\u5230\u540e\u65b9" }); diff --git a/core/core-frontend/src/assets/svg/icon_warning_colorful_red.svg b/core/core-frontend/src/assets/svg/icon_warning_colorful_red.svg new file mode 100644 index 0000000000..a0ffc79110 --- /dev/null +++ b/core/core-frontend/src/assets/svg/icon_warning_colorful_red.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/core/core-frontend/src/components/data-visualization/RealTimeListTree.vue b/core/core-frontend/src/components/data-visualization/RealTimeListTree.vue index 5b888dbe3f..2c33a523cc 100644 --- a/core/core-frontend/src/components/data-visualization/RealTimeListTree.vue +++ b/core/core-frontend/src/components/data-visualization/RealTimeListTree.vue @@ -56,6 +56,7 @@ import treemapOrigin from '@/assets/svg/treemap-origin.svg' import waterfallOrigin from '@/assets/svg/waterfall-origin.svg' import wordCloudOrigin from '@/assets/svg/word-cloud-origin.svg' import tHeatmapOrigin from '@/assets/svg/t-heatmap-origin.svg' +import pictureGroupOrigin from '@/assets/svg/picture-group-origin.svg' import dvMore from '@/assets/svg/dv-more.svg' import dvExpandDown from '@/assets/svg/dv-expand-down.svg' import dvExpandRight from '@/assets/svg/dv-expand-right.svg' @@ -324,6 +325,7 @@ const iconMap = { 'waterfall-origin': waterfallOrigin, 'word-cloud-origin': wordCloudOrigin, 't-heatmap-origin': tHeatmapOrigin, + 'picture-group-origin': pictureGroupOrigin, group: group } const getIconName = item => { diff --git a/core/core-frontend/src/components/visualization/DvSidebar.vue b/core/core-frontend/src/components/visualization/DvSidebar.vue index 9653bf6e09..6aa475919a 100644 --- a/core/core-frontend/src/components/visualization/DvSidebar.vue +++ b/core/core-frontend/src/components/visualization/DvSidebar.vue @@ -1,11 +1,15 @@ @@ -184,4 +254,38 @@ const slideStyle = computed(() => { .ed-scrollbar__bar.is-vertical { width: var(--de-scroll-width); } + +.name-area-attr { + position: relative; + line-height: 24px; + height: 24px; + font-size: 14px !important; + overflow: hidden; + cursor: pointer; + input { + position: absolute; + left: 0; + width: 100%; + outline: none; + border: 1px solid #295acc; + border-radius: 4px; + padding: 0 4px; + height: 100%; + } +} + +.component-name-dark { + input { + position: absolute; + left: 0; + width: 100%; + color: @dv-canvas-main-font-color; + background-color: #050e21; + outline: none; + border: 1px solid #295acc; + border-radius: 4px; + padding: 0 4px; + height: 100%; + } +} diff --git a/core/core-frontend/src/custom-component/rich-text/DeRichTextView.vue b/core/core-frontend/src/custom-component/rich-text/DeRichTextView.vue index a01c0715cd..631e432ab8 100644 --- a/core/core-frontend/src/custom-component/rich-text/DeRichTextView.vue +++ b/core/core-frontend/src/custom-component/rich-text/DeRichTextView.vue @@ -132,6 +132,7 @@ const canEdit = ref(false) // 初始化配置 const tinymceId = 'tinymce-view-' + element.value.id + '-' + suffixId.value const myValue = ref('') +const cellDragStart = ref(0) const systemFontFamily = appearanceStore.fontList.map(item => item.name) const curFontFamily = () => { @@ -171,25 +172,107 @@ const init = ref({ branding: false, icons: 'vertical-content', vertical_align: element.value.propValue.verticalAlign, + table_default_attributes: { + width: '400' // 使用 table_default_attributes 设置表格的宽度 + }, + table_default_styles: { + width: '400px' // 或者使用 table_default_styles 设置宽度,单位为 px + }, setup: function (editor) { - // 在表格调整大小开始时 - editor.on('ObjectResizeStart', function (e) { - const { target, width, height } = e - if (target.nodeName === 'TABLE') { - // 将宽高根据缩放比例调整 - // e.width = width / props.scale - // e.height = height / props.scale - } - }) + let cloneHandle = null // 用于存储克隆的手柄 + let originalHandle = null // 用于存储原始手柄 + editor.on('init', () => { + const doc = editor.getDoc() + // 监测 mouseup、mousedown 和 mousemove 事件 + // 1.单元格问题 因为缩放问题 导致拖拽的坐标系有偏差,此处隐藏原有拖拽定位bar,并根据 + // 缩放比例动态调整时间定位bar的位置,这会代理鼠标移速和bar移速不同步问题,不过bar定位是准确的 + // 可以解决因为缩放导致tinymce 内部坐标系出错问题 + doc.addEventListener('mousedown', event => { + nextTick(() => { + originalHandle = event.target.closest('.ephox-snooker-resizer-bar-dragging') + if (originalHandle) { + // 克隆原始手柄 + cloneHandle = originalHandle.cloneNode(true) + cloneHandle.style.zIndex = 9999 // 提升克隆手柄的层级 + originalHandle.style.display = 'none' // 隐藏原始手柄 + // 将克隆手柄添加到原手柄的父元素中 + const parentDiv = originalHandle.parentNode // 获取原手柄的父元素 + parentDiv.appendChild(cloneHandle) // 将克隆手柄添加到父元素中 + } + }) + }) - // 在表格调整大小结束时 - editor.on('ObjectResized', function (e) { - const { target, width, height } = e - if (target.nodeName === 'TABLE') { - // 将最终调整的宽高根据缩放比例重设 - // target.style.width = `${width * props.scale}px` - // target.style.height = `${height scaleFactor}px` + // 监听 mousemove 事件以更新克隆手柄位置 + doc.addEventListener('mousemove', event => { + if (cloneHandle) { + // // 计算鼠标移动的距离 + if (cloneHandle.offsetHeight > cloneHandle.offsetWidth) { + // 计算鼠标移动的距离 + const offsetX = event.movementX * props.scale // 使用缩放比例进行调整 + cloneHandle.style.left = `${cloneHandle.offsetLeft + offsetX}px` // 更新克隆手柄的位置 + } else { + // 计算鼠标移动的距离 + const offsetY = event.movementY * props.scale // 使用缩放比例进行调整 + cloneHandle.style.top = `${cloneHandle.offsetTop + offsetY}px` // 更新克隆手柄的位置 + } + } + }) + + // 监听 mouseup 事件以结束调整 + doc.addEventListener('mouseup', event => { + if (cloneHandle) { + // 显示原始手柄并移除克隆手柄 + originalHandle.style.display = '' + if (cloneHandle) { + cloneHandle.parentNode.removeChild(cloneHandle) // 获取原手柄的父元素 + } + cloneHandle = null + originalHandle = null + } + }) + + // 函数:根据缩放比例调整 .mce-resizehandle 的位置和大小 + const adjustResizeHandles = (aLeft, aTop) => { + nextTick(() => { + const nodeRt = doc.getElementById('mceResizeHandlene') + const nodeRb = doc.getElementById('mceResizeHandlese') + const nodeLb = doc.getElementById('mceResizeHandlesw') + if (nodeRt) { + nodeRt.style.left = `${aLeft}px` + } + if (nodeRb) { + nodeRb.style.left = `${aLeft}px` + nodeRb.style.top = `${aTop}px` + } + if (nodeLb) { + nodeLb.style.top = `${aTop}px` + } + }) } + + // 监听 ObjectSelected 事件,点击表格时触发调整 + editor.on('ObjectSelected', event => { + if (event.target.nodeName === 'TABLE') { + adjustResizeHandles( + event.target.offsetWidth + event.target.offsetLeft, + event.target.offsetHeight + event.target.offsetTop + ) + } + }) + + // 监听 ObjectResized 事件,更新调整大小句柄 + // 在表格调整大小结束时 + // 解决移动表格corner点位resize时因为缩放导致的坐标系放大问题,进而导致移动错位问题 + editor.on('ObjectResized', function (e) { + const { target, width, height, origin } = e + if (target.nodeName === 'TABLE' && origin.indexOf('corner') > -1) { + // 将最终调整的宽高根据缩放比例重设 + target.style.width = `${width}px` + target.style.height = `${height}px` + } else if (target.nodeName === 'TABLE' && origin.indexOf('bar-col') > -1) { + // do nothing + } + }) }) } }) @@ -634,12 +717,6 @@ defineExpose({ width: 0px !important; height: 0px !important; } - ::v-deep(p) { - zoom: var(--de-canvas-scale); - } - ::v-deep(td span) { - zoom: var(--de-canvas-scale); - } } :deep(.ol) { diff --git a/core/core-frontend/src/custom-component/rich-text/DeRichTextViewFrame.vue b/core/core-frontend/src/custom-component/rich-text/DeRichTextViewFrame.vue new file mode 100644 index 0000000000..aefea08bf7 --- /dev/null +++ b/core/core-frontend/src/custom-component/rich-text/DeRichTextViewFrame.vue @@ -0,0 +1,751 @@ + + + + + + + diff --git a/core/core-frontend/src/custom-component/user-view/Component.vue b/core/core-frontend/src/custom-component/user-view/Component.vue index 1dab9cf588..822a8d75dd 100644 --- a/core/core-frontend/src/custom-component/user-view/Component.vue +++ b/core/core-frontend/src/custom-component/user-view/Component.vue @@ -1,5 +1,5 @@