Merge branch 'dev-v2' of github.com:dataease/dataease into dev-v2

This commit is contained in:
wangjiahao 2024-08-07 17:28:49 +08:00
commit 76da32b1db
98 changed files with 2408 additions and 261 deletions

View File

@ -7,11 +7,11 @@ import java.io.Serializable;
/**
* <p>
*
* 数据源表
* </p>
*
* @author fit2cloud
* @since 2023-09-26
* @since 2024-07-09
*/
@TableName("core_datasource")
public class CoreDatasource implements Serializable {
@ -89,6 +89,11 @@ public class CoreDatasource implements Serializable {
*/
private String taskStatus;
/**
* 开启数据填报
*/
private Boolean enableDataFill;
public Long getId() {
return id;
}
@ -201,6 +206,14 @@ public class CoreDatasource implements Serializable {
this.taskStatus = taskStatus;
}
public Boolean getEnableDataFill() {
return enableDataFill;
}
public void setEnableDataFill(Boolean enableDataFill) {
this.enableDataFill = enableDataFill;
}
@Override
public String toString() {
return "CoreDatasource{" +
@ -218,6 +231,7 @@ public class CoreDatasource implements Serializable {
", status = " + status +
", qrtzInstance = " + qrtzInstance +
", taskStatus = " + taskStatus +
", enableDataFill = " + enableDataFill +
"}";
}
}

View File

@ -6,11 +6,11 @@ import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* 数据源表 Mapper 接口
* </p>
*
* @author fit2cloud
* @since 2023-09-26
* @since 2024-07-09
*/
@Mapper
public interface CoreDatasourceMapper extends BaseMapper<CoreDatasource> {

View File

@ -26,10 +26,10 @@ import org.apache.calcite.adapter.jdbc.JdbcSchema;
import org.apache.calcite.jdbc.CalciteConnection;
import org.apache.calcite.schema.Schema;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.io.File;
import java.io.IOException;
@ -54,6 +54,7 @@ public class CalciteProvider extends Provider {
private final String FILE_PATH = "/opt/dataease2.0/drivers";
private final String CUSTOM_PATH = "/opt/dataease2.0/custom-drivers/";
private static String split = "DE";
@Resource
private CommonThreadPool commonThreadPool;
@ -214,7 +215,9 @@ public class CalciteProvider extends Provider {
List<TableField> datasetTableFields = new ArrayList<>();
DatasourceSchemaDTO datasourceSchemaDTO = datasourceRequest.getDsList().entrySet().iterator().next().getValue();
datasourceRequest.setDatasource(datasourceSchemaDTO);
DatasourceConfiguration datasourceConfiguration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), DatasourceConfiguration.class);
String table = datasourceRequest.getTable();
if (StringUtils.isEmpty(table)) {
ResultSet resultSet = null;
@ -371,11 +374,20 @@ public class CalciteProvider extends Provider {
// schema
ResultSet resultSet = null;
try (ConnectionObj con = getConnection(datasourceRequest.getDatasource());
Statement statement = getStatement(con.getConnection(), datasourceConfiguration.getQueryTimeout())) {
PreparedStatement statement = getPreparedStatement(con.getConnection(), datasourceConfiguration.getQueryTimeout(), datasourceRequest.getQuery())) {
if (DatasourceConfiguration.DatasourceType.valueOf(value.getType()) == DatasourceConfiguration.DatasourceType.oracle) {
statement.executeUpdate("ALTER SESSION SET CURRENT_SCHEMA = " + datasourceConfiguration.getSchema());
}
resultSet = statement.executeQuery(datasourceRequest.getQuery());
if (CollectionUtils.isNotEmpty(datasourceRequest.getTableFieldWithValues())) {
LogUtil.info("execWithPreparedStatement sql: " + datasourceRequest.getQuery());
for (int i = 0; i < datasourceRequest.getTableFieldWithValues().size(); i++) {
statement.setObject(i + 1, datasourceRequest.getTableFieldWithValues().get(i).getValue(), datasourceRequest.getTableFieldWithValues().get(i).getType());
LogUtil.info("execWithPreparedStatement param[" + (i + 1) + "]: " + datasourceRequest.getTableFieldWithValues().get(i).getValue());
}
}
resultSet = statement.executeQuery();
fieldList = getField(resultSet, datasourceRequest);
dataList = getData(resultSet, datasourceRequest);
} catch (SQLException e) {
@ -397,6 +409,88 @@ public class CalciteProvider extends Provider {
return map;
}
@Override
public void exec(DatasourceRequest datasourceRequest) throws DEException {
DatasourceSchemaDTO value = datasourceRequest.getDsList().entrySet().iterator().next().getValue();
datasourceRequest.setDatasource(value);
DatasourceConfiguration datasourceConfiguration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), DatasourceConfiguration.class);
// schema
ResultSet resultSet = null;
try (ConnectionObj con = getConnection(datasourceRequest.getDatasource());
PreparedStatement statement = getPreparedStatement(con.getConnection(), datasourceConfiguration.getQueryTimeout(), datasourceRequest.getQuery())) {
if (DatasourceConfiguration.DatasourceType.valueOf(value.getType()) == DatasourceConfiguration.DatasourceType.oracle) {
statement.executeUpdate("ALTER SESSION SET CURRENT_SCHEMA = " + datasourceConfiguration.getSchema());
}
if (CollectionUtils.isNotEmpty(datasourceRequest.getTableFieldWithValues())) {
LogUtil.info("execWithPreparedStatement sql: " + datasourceRequest.getQuery());
for (int i = 0; i < datasourceRequest.getTableFieldWithValues().size(); i++) {
statement.setObject(i + 1, datasourceRequest.getTableFieldWithValues().get(i).getValue(), datasourceRequest.getTableFieldWithValues().get(i).getType());
LogUtil.info("execWithPreparedStatement param[" + (i + 1) + "]: " + datasourceRequest.getTableFieldWithValues().get(i).getValue());
}
}
statement.execute();
} catch (SQLException e) {
DEException.throwException("SQL ERROR: " + e.getMessage());
} catch (Exception e) {
DEException.throwException("Data source connection exception: " + e.getMessage());
} finally {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
@Override
public int executeUpdate(DatasourceRequest datasourceRequest) throws DEException {
DatasourceSchemaDTO value = datasourceRequest.getDsList().entrySet().iterator().next().getValue();
datasourceRequest.setDatasource(value);
DatasourceConfiguration datasourceConfiguration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), DatasourceConfiguration.class);
// schema
ResultSet resultSet = null;
try (ConnectionObj con = getConnection(datasourceRequest.getDatasource());
PreparedStatement statement = getPreparedStatement(con.getConnection(), datasourceConfiguration.getQueryTimeout(), datasourceRequest.getQuery())) {
if (DatasourceConfiguration.DatasourceType.valueOf(value.getType()) == DatasourceConfiguration.DatasourceType.oracle) {
statement.executeUpdate("ALTER SESSION SET CURRENT_SCHEMA = " + datasourceConfiguration.getSchema());
}
if (CollectionUtils.isNotEmpty(datasourceRequest.getTableFieldWithValues())) {
LogUtil.info("execWithPreparedStatement sql: " + datasourceRequest.getQuery());
for (int i = 0; i < datasourceRequest.getTableFieldWithValues().size(); i++) {
statement.setObject(i + 1, datasourceRequest.getTableFieldWithValues().get(i).getValue(), datasourceRequest.getTableFieldWithValues().get(i).getType());
LogUtil.info("execWithPreparedStatement param[" + (i + 1) + "]: " + datasourceRequest.getTableFieldWithValues().get(i).getValue());
}
}
return statement.executeUpdate();
} catch (SQLException e) {
DEException.throwException("SQL ERROR: " + e.getMessage());
} catch (Exception e) {
DEException.throwException("Data source connection exception: " + e.getMessage());
} finally {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return 0;
}
private List<TableField> getField(ResultSet rs, DatasourceRequest datasourceRequest) throws Exception {
List<TableField> fieldList = new ArrayList<>();
ResultSetMetaData metaData = rs.getMetaData();
@ -588,14 +682,14 @@ public class CalciteProvider extends Provider {
String[] databasePrams = matcher.group(3).split("\\?");
database = databasePrams[0];
}
sql = String.format("SELECT COLUMN_NAME,DATA_TYPE,COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '%s' AND TABLE_NAME = '%s'", database, datasourceRequest.getTable());
sql = String.format("SELECT COLUMN_NAME,DATA_TYPE,COLUMN_COMMENT,IF(COLUMN_KEY='PRI',1,0) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '%s' AND TABLE_NAME = '%s'", database, datasourceRequest.getTable());
break;
case oracle:
configuration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), Oracle.class);
if (StringUtils.isEmpty(configuration.getSchema())) {
DEException.throwException(Translator.get("i18n_schema_is_empty"));
}
sql = String.format("SELECT a.COLUMN_NAME , a.DATA_TYPE , b.COMMENTS FROM all_tab_columns a LEFT JOIN all_col_comments b ON a.owner = b.owner AND a.table_name = b.table_name AND a.column_name = b.column_name WHERE a.owner = '%s' AND a.table_name = '%s' ORDER BY a.table_name, a.column_id", configuration.getSchema(), datasourceRequest.getTable());
sql = String.format("SELECT a.COLUMN_NAME , a.DATA_TYPE , b.COMMENTS ,0 FROM all_tab_columns a LEFT JOIN all_col_comments b ON a.owner = b.owner AND a.table_name = b.table_name AND a.column_name = b.column_name WHERE a.owner = '%s' AND a.table_name = '%s' ORDER BY a.table_name, a.column_id", configuration.getSchema(), datasourceRequest.getTable());
break;
case db2:
configuration = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), Db2.class);
@ -611,7 +705,7 @@ public class CalciteProvider extends Provider {
}
sql = String.format("SELECT \n" +
" c.name ,t.name ,ep.value \n" +
" c.name ,t.name ,ep.value, 0 \n" +
"FROM \n" +
" sys.columns AS c\n" +
"LEFT JOIN sys.extended_properties AS ep ON c.object_id = ep.major_id AND c.column_id = ep.minor_id\n" +
@ -627,7 +721,8 @@ public class CalciteProvider extends Provider {
sql = String.format("SELECT\n" +
" a.attname AS ColumnName,\n" +
" t.typname,\n" +
" b.description AS ColumnDescription\n" +
" b.description AS ColumnDescription,\n" +
" 0\n" +
"FROM\n" +
" pg_class c\n" +
" JOIN pg_attribute a ON a.attrelid = c.oid\n" +
@ -646,7 +741,8 @@ public class CalciteProvider extends Provider {
sql = String.format("SELECT\n" +
" a.attname AS ColumnName,\n" +
" t.typname,\n" +
" b.description AS ColumnDescription\n" +
" b.description AS ColumnDescription,\n" +
" 0\n" +
"FROM\n" +
" pg_class c\n" +
" JOIN pg_attribute a ON a.attrelid = c.oid\n" +
@ -675,7 +771,8 @@ public class CalciteProvider extends Provider {
sql = String.format(" SELECT\n" +
" name,\n" +
" type,\n" +
" comment\n" +
" comment,\n" +
" 0\n" +
"FROM\n" +
" system.columns\n" +
"WHERE\n" +
@ -702,6 +799,10 @@ public class CalciteProvider extends Provider {
tableField.setDeExtractType(deType);
tableField.setDeType(deType);
tableField.setName(resultSet.getString(3));
try {
tableField.setPrimary(resultSet.getInt(4) > 0);
} catch (Exception e) {
}
return tableField;
}
@ -1092,6 +1193,32 @@ public class CalciteProvider extends Provider {
}
}
public Statement getStatement(Connection connection, int queryTimeout) {
if (connection == null) {
DEException.throwException("Failed to get connection!");
}
Statement stat = null;
try {
stat = connection.createStatement();
stat.setQueryTimeout(queryTimeout);
} catch (Exception e) {
DEException.throwException(e.getMessage());
}
return stat;
}
public PreparedStatement getPreparedStatement(Connection connection, int queryTimeout, String sql) throws Exception {
if (connection == null) {
throw new Exception("Failed to get connection!");
}
PreparedStatement stat = connection.prepareStatement(sql);
try {
stat.setQueryTimeout(queryTimeout);
} catch (Exception e) {
}
return stat;
}
protected boolean isDefaultClassLoader(String customDriver) {
return StringUtils.isEmpty(customDriver) || customDriver.equalsIgnoreCase("default");
}

View File

@ -1,5 +1,6 @@
package io.dataease.datasource.server;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -356,7 +357,8 @@ public class DatasourceServer implements DatasourceApi {
List<String> toCreateTables = new ArrayList<>();
List<String> toDeleteTables = new ArrayList<>();
if (dataSourceDTO.getType().equals(DatasourceConfiguration.DatasourceType.API.name())) {
List<String> sourceTables = ApiUtils.getTables(sourceTableRequest).stream().map(DatasetTableDTO::getTableName).collect(Collectors.toList());
requestDatasource.setEnableDataFill(null);
List<String> sourceTables = ApiUtils.getTables(sourceTableRequest).stream().map(DatasetTableDTO::getTableName).toList();
List<DatasetTableDTO> datasetTableDTOS = ApiUtils.getTables(datasourceRequest);
List<String> tables = datasetTableDTOS.stream().map(DatasetTableDTO::getTableName).collect(Collectors.toList());
checkName(datasetTableDTOS.stream().map(DatasetTableDTO::getName).collect(Collectors.toList()));
@ -410,6 +412,7 @@ public class DatasourceServer implements DatasourceApi {
dataSourceManage.checkName(dataSourceDTO);
dataSourceManage.innerEdit(requestDatasource);
} else if (dataSourceDTO.getType().equals(DatasourceConfiguration.DatasourceType.Excel.name())) {
requestDatasource.setEnableDataFill(null);
List<String> sourceTables = ExcelUtils.getTables(sourceTableRequest).stream().map(DatasetTableDTO::getTableName).collect(Collectors.toList());
List<String> tables = ExcelUtils.getTables(datasourceRequest).stream().map(DatasetTableDTO::getTableName).collect(Collectors.toList());
if (dataSourceDTO.getEditType() == 0) {
@ -439,6 +442,9 @@ public class DatasourceServer implements DatasourceApi {
dataSourceManage.innerEdit(requestDatasource);
}
} else {
if (!LicenseUtil.licenseValid()) {
requestDatasource.setEnableDataFill(null);
}
checkParams(dataSourceDTO.getConfiguration());
dataSourceManage.checkName(dataSourceDTO);
dataSourceManage.innerEdit(requestDatasource);
@ -515,12 +521,39 @@ public class DatasourceServer implements DatasourceApi {
return getDatasourceDTOById(datasourceId, false);
}
@Override
public DatasourceDTO innerGet(Long datasourceId) throws DEException {
return getDatasourceDTOById(datasourceId, false);
}
@Override
public List<DatasourceDTO> innerList(List<Long> ids) throws DEException {
List<DatasourceDTO> list = new ArrayList<>();
LambdaQueryWrapper<CoreDatasource> queryWrapper = new LambdaQueryWrapper<>();
if (ids != null) {
if (ids.isEmpty()) {
return list;
} else {
queryWrapper.in(CoreDatasource::getId, ids);
}
}
List<CoreDatasource> dsList = datasourceMapper.selectList(queryWrapper);
for (CoreDatasource datasource : dsList) {
list.add(convertCoreDatasource(datasource.getId(), false, datasource));
}
return list;
}
private DatasourceDTO getDatasourceDTOById(Long datasourceId, boolean hidePw) throws DEException {
DatasourceDTO datasourceDTO = new DatasourceDTO();
CoreDatasource datasource = datasourceMapper.selectById(datasourceId);
if (datasource == null) {
DEException.throwException("不存在的数据源!");
}
return convertCoreDatasource(datasourceId, hidePw, datasource);
}
private DatasourceDTO convertCoreDatasource(Long datasourceId, boolean hidePw, CoreDatasource datasource) {
DatasourceDTO datasourceDTO = new DatasourceDTO();
BeanUtils.copyBean(datasourceDTO, datasource);
if (datasourceDTO.getType().equalsIgnoreCase(DatasourceConfiguration.DatasourceType.API.toString())) {

View File

@ -0,0 +1,111 @@
package io.dataease.job.schedule;
import io.dataease.commons.utils.CronUtils;
import io.dataease.license.config.XpackInteract;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.ObjectUtils;
import org.quartz.JobDataMap;
import org.quartz.JobKey;
import org.quartz.TriggerKey;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.Map;
@Component("deDataFillingTaskExecutor")
public class DeDataFillingTaskExecutor {
protected static final String IS_TEMP_TASK = "isTempTask";
protected static final String IS_RETRY_TASK = "isRetryTask";
private static final String JOB_GROUP = "REPORT_TASK";
private static final String RETRY_JOB_GROUP = "RETRY_REPORT_TASK";
private static final String TEMP_JOB_GROUP = "TEMP_REPORT_TASK";
@Resource
private ScheduleManager scheduleManager;
@XpackInteract(value = "dataFillingTaskExecutor", replace = true)
public boolean execute(Map<String, Object> taskData) {
return false;
}
@XpackInteract(value = "dataFillingTaskExecutor", replace = true)
public void init() {
}
public void addOrUpdateTask(Long taskId, String cron, Long startTime, Long endTime) {
if (CronUtils.taskExpire(endTime)) {
return;
}
String key = taskId.toString();
JobKey jobKey = new JobKey(key, JOB_GROUP);
TriggerKey triggerKey = new TriggerKey(key, JOB_GROUP);
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("taskId", taskId);
jobDataMap.put(IS_TEMP_TASK, false);
Date end = null;
if (ObjectUtils.isNotEmpty(endTime)) end = new Date(endTime);
scheduleManager.addOrUpdateCronJob(jobKey, triggerKey, DeXpackDataFillingScheduleJob.class, cron, startTime == null ? null : new Date(startTime), end, jobDataMap);
}
public void addRetryTask(Long taskId, Integer retryLimit, Integer retryInterval) {
long saltTime = 3000L;
long interval = retryInterval == null ? 5L : retryInterval;
long intervalMill = interval * 60000L;
long now = System.currentTimeMillis();
String cron = "0 */" + interval + " * * * ?";
long endTime = (retryLimit + 1) * intervalMill + now - saltTime;
String key = taskId.toString();
if (CronUtils.taskExpire(endTime)) {
return;
}
JobKey jobKey = new JobKey(key, RETRY_JOB_GROUP);
TriggerKey triggerKey = new TriggerKey(key, RETRY_JOB_GROUP);
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("taskId", taskId);
jobDataMap.put(IS_RETRY_TASK, true);
Date end = null;
if (ObjectUtils.isNotEmpty(endTime)) end = new Date(endTime);
scheduleManager.addOrUpdateCronJob(jobKey, triggerKey, DeXpackDataFillingScheduleJob.class, cron, new Date(now), end, jobDataMap);
}
public boolean fireNow(Long taskId) throws Exception {
String key = taskId.toString();
JobKey jobKey = new JobKey(key, JOB_GROUP);
if (scheduleManager.exist(jobKey)) {
scheduleManager.fireNow(jobKey);
return true;
}
return false;
}
public void addTempTask(Long taskId, Long startTime) {
String key = taskId.toString();
JobKey jobKey = new JobKey(key, TEMP_JOB_GROUP);
TriggerKey triggerKey = new TriggerKey(key, TEMP_JOB_GROUP);
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put(IS_TEMP_TASK, true);
String cron = CronUtils.tempCron();
jobDataMap.put("taskId", taskId);
scheduleManager.addOrUpdateCronJob(jobKey, triggerKey, DeXpackDataFillingScheduleJob.class, cron, new Date(startTime), null, jobDataMap);
}
public void removeTask(Long taskId, boolean isTemp) {
String key = taskId.toString();
JobKey jobKey = new JobKey(key, isTemp ? TEMP_JOB_GROUP : JOB_GROUP);
TriggerKey triggerKey = new TriggerKey(key, isTemp ? TEMP_JOB_GROUP : JOB_GROUP);
scheduleManager.removeJob(jobKey, triggerKey);
}
public void removeRetryTask(Long taskId) {
String key = taskId.toString();
JobKey jobKey = new JobKey(key, RETRY_JOB_GROUP);
TriggerKey triggerKey = new TriggerKey(key, RETRY_JOB_GROUP);
scheduleManager.removeJob(jobKey, triggerKey);
}
public void clearRetryTask() throws Exception {
scheduleManager.clearByGroup(RETRY_JOB_GROUP);
}
}

View File

@ -0,0 +1,27 @@
package io.dataease.job.schedule;
import io.dataease.license.utils.LicenseUtil;
import io.dataease.utils.CommonBeanFactory;
import org.quartz.*;
import org.springframework.stereotype.Component;
import java.util.Objects;
@Component
public class DeXpackDataFillingScheduleJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
Trigger trigger = jobExecutionContext.getTrigger();
JobKey jobKey = trigger.getJobKey();
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
DeDataFillingTaskExecutor deTaskExecutor = CommonBeanFactory.getBean(DeDataFillingTaskExecutor.class);
assert deTaskExecutor != null;
LicenseUtil.validate();
boolean taskLoaded = deTaskExecutor.execute(jobDataMap);
if (!taskLoaded) {
Objects.requireNonNull(CommonBeanFactory.getBean(ScheduleManager.class)).removeJob(jobKey, trigger.getKey());
}
}
}

View File

@ -1,5 +1,6 @@
package io.dataease.listener;
import io.dataease.job.schedule.DeDataFillingTaskExecutor;
import io.dataease.job.schedule.DeTaskExecutor;
import io.dataease.license.utils.LicenseUtil;
import io.dataease.utils.LogUtil;
@ -16,6 +17,9 @@ public class XpackTaskStarter implements ApplicationRunner {
@Resource
private DeTaskExecutor deTaskExecutor;
@Resource
private DeDataFillingTaskExecutor deDataFillingTaskExecutor;
@Override
public void run(ApplicationArguments args) {
try {
@ -24,5 +28,11 @@ public class XpackTaskStarter implements ApplicationRunner {
} catch (Exception e) {
LogUtil.error(e.getMessage(), e.getCause());
}
try {
LicenseUtil.validate();
deDataFillingTaskExecutor.init();
} catch (Exception e) {
LogUtil.error(e.getMessage(), e.getCause());
}
}
}

View File

@ -100,6 +100,8 @@ public class MenuManage {
|| coreMenu.getId().equals(28L)
|| coreMenu.getId().equals(35L)
|| coreMenu.getId().equals(40L)
|| coreMenu.getId().equals(50L);
|| coreMenu.getId().equals(50L)
|| coreMenu.getId().equals(60L)
|| coreMenu.getId().equals(61L);
}
}

View File

@ -1,3 +1,6 @@
BEGIN;
INSERT INTO `core_sys_startup_job` VALUES ('chartFilterDynamic', 'chartFilterDynamic', 'ready');
COMMIT;
alter table `core_datasource`
add `enable_data_fill` tinyint default 0 null comment '启用数据填报功能';

View File

@ -1,3 +1,6 @@
BEGIN;
INSERT INTO `core_sys_startup_job` VALUES ('chartFilterDynamic', 'chartFilterDynamic', 'ready');
COMMIT;
alter table `core_datasource`
add `enable_data_fill` tinyint default 0 null comment '启用数据填报功能';

View File

@ -12,6 +12,7 @@ i18n_menu.template-setting=\u6A21\u677F\u7BA1\u7406
i18n_menu.view=\u6570\u636E\u5C55\u793A
i18n_menu.data=\u6570\u636E\u51C6\u5907
i18n_menu.panel=\u4EEA\u8868\u677F
i18n_menu.data-filling-manage=\u6570\u636E\u586B\u62A5
i18n_menu.screen=\u6570\u636E\u5927\u5C4F
i18n_menu.dataset=\u6570\u636E\u96C6
i18n_menu.datasource=\u6570\u636E\u6E90
@ -43,7 +44,7 @@ i18n_table_duplicate=\u76F8\u540C\u8282\u70B9\u9700\u91CD\u65B0\u62D6\u5165\u624
i18n_no_column_permission=\u6CA1\u6709\u5217\u6743\u9650
i18n_fetch_error=SQL\u6267\u884C\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u8868\u3001\u5B57\u6BB5\u3001\u5173\u8054\u5173\u7CFB\u7B49\u4FE1\u606F\u662F\u5426\u6B63\u786E\u5E76\u91CD\u65B0\u7F16\u8F91\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_dataset_permission=\u65E0\u6570\u636E\u96C6\u8BBF\u95EE\u6743\u9650
i18n_not_full=\u5F53\u524D\u6570\u636E\u6E90\u4E0D\u652F\u6301\u5168\u8FDE\u63A5
i18n_field_circular_ref=\u5B57\u6BB5\u5B58\u5728\u5FAA\u73AF\u5F15\u7528

View File

@ -0,0 +1,226 @@
import request from '@/config/axios'
import dayjs from 'dayjs'
export function formatDate(value, dateType) {
if (!value) {
return value
}
switch (dateType) {
case 'year':
return dayjs(value).format('YYYY')
case 'month':
case 'monthrange':
return dayjs(value).format('YYYY-MM')
case 'datetime':
case 'datetimerange':
return dayjs(value).format('YYYY-MM-DD HH:mm:ss')
default:
return dayjs(value).format('YYYY-MM-DD')
}
}
export interface ColumnItem {
props: string
label: string
date: boolean
dateType?: string
type: string
multiple: boolean
rangeIndex?: number
disabled?: boolean
}
export interface DataFillingOrFolder {
name: string
action?: string
id?: number | string
pid?: number | string
nodeType: 'folder' | 'data-filling'
union?: Array<{}>
allFields?: Array<{}>
}
export interface Tree {
name: string
value?: string | number
id: string | number
nodeType: string
createBy?: string
level: number
leaf?: boolean
pid: string | number
type?: string
createTime: number
children?: Tree[]
request: any
}
export interface DfFormSetting {
id?: string
name?: string
pid?: string
datasource?: string
tableName?: string
forms: Array<DfFormItem>
createIndex: boolean
tableIndexes: Array<any>
creator?: string
updater?: string
createTime?: number
updateTime?: number
weight?: number
}
export interface DfFormItem {
type: string
typeName: string
icon: string
order?: number
value?: any
id?: string
settings: FormItemSetting
old?: boolean
removed?: boolean
}
export interface FormItemSetting {
name?: string
placeholder?: string
required?: boolean
unique?: boolean
inputType?: string
optionSourceType?: 1 | 2
optionDatasource?: number
optionTable?: string
optionColumn?: string
optionOrder?: string
multiple?: boolean
dateType?: 'date' | 'daterange'
rangeSeparator?: string
startPlaceholder?: string
endPlaceholder?: string
options?: Array<FormItemSettingOptions>
mapping: {
columnName?: string
columnName1?: string
columnName2?: string
type?: string
}
}
export interface FormItemSettingOptions {
name: string
value: string
}
export interface SimpleDatasource {
id: string
pid: string
name: string
type: string
typeAlias: string
status: string
enableDataFill: boolean
}
export const listDataFillingForms = async (data): Promise<any> => {
return request
.post({ url: '/data-filling/tree', data: { ...data, ...{ busiFlag: 'data-filling' } } })
.then(res => {
return res?.data
})
}
export const createFolder = (data = {}): Promise<any> => {
return request
.post({ url: '/data-filling/save', data: { ...data, nodeType: 'folder' } })
.then(res => {
return res?.data
})
}
export const save = (data = {}): Promise<any> => {
return request.post({ url: '/data-filling/save', data }).then(res => {
return res?.data
})
}
export const move = (data = {}): Promise<any> => {
return request.post({ url: '/data-filling/move', data }).then(res => {
return res?.data
})
}
export const reName = (data = {}): Promise<any> => {
return request.post({ url: '/data-filling/rename', data }).then(res => {
return res?.data
})
}
export const listDatasourceList = (): Promise<Array<SimpleDatasource>> => {
return request.get({ url: '/data-filling/datasource/list' }).then(res => {
return res?.data
})
}
export const getDataFilling = async (id: string): Promise<any> => {
return request.get({ url: `/data-filling/get/${id}` }).then(res => {
return res?.data
})
}
export const deleteById = (id: string): Promise<any> => {
return request.get({ url: '/data-filling/delete/' + id })
}
export const deleteRowData = (formId: string, id: number): Promise<any> => {
return request.get({ url: `/data-filling/form/${formId}/delete/${id}` })
}
export const batchDeleteRowData = (formId: string, data: Array<any>): Promise<any> => {
return request.post({ url: `/data-filling/form/${formId}/batch-delete`, data })
}
export const getTableColumnData = (
optionDatasource,
optionTable,
optionColumn,
optionOrder
): Promise<any> => {
return request.post({
url: `/data-filling/form/${optionDatasource}/options`,
data: {
optionTable: optionTable,
optionColumn: optionColumn,
optionOrder: optionOrder
}
})
}
export const searchTable = (id, data): Promise<any> => {
return request.post({
url: '/data-filling/form/' + id + '/tableData',
data
})
}
export const saveFormRowData = (formId, data): Promise<any> => {
return request
.post({
url: '/data-filling/form/' + formId + '/rowData/save',
data
})
.then(res => {
return res?.data
})
}
export const saveTask = (data): Promise<any> => {
return request.post({
url: `/data-filling/task/save`,
data
})
}
export const getTaskInfo = (taskId): Promise<any> => {
return request.get({
url: `/data-filling/task/info/${taskId}`
})
}

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 2.5C4 1.94772 4.44772 1.5 5 1.5H14.8608C14.9949 1.5 15.1234 1.55387 15.2174 1.64951L19.8566 6.36941C19.9485 6.46292 20 6.58879 20 6.7199V21.5C20 22.0523 19.5523 22.5 19 22.5H5C4.44772 22.5 4 22.0523 4 21.5V2.5Z" fill="#3370FF"/>
<path d="M15 1.51978C15.0817 1.54345 15.1567 1.58778 15.2174 1.64952L19.8566 6.36942C19.8946 6.40806 19.9256 6.45223 19.949 6.50001H16.1351C15.5082 6.50001 15 5.99179 15 5.36488V1.51978Z" fill="#2B5FD9"/>
<path d="M8.07282 10.1818H15.6546C15.745 10.1818 15.8183 10.2551 15.8183 10.3455V11.1091C15.8183 11.1995 15.745 11.2727 15.6546 11.2727H8.07282C7.98244 11.2727 7.90918 11.1995 7.90918 11.1091V10.3455C7.90918 10.2551 7.98244 10.1818 8.07282 10.1818ZM8.07282 13.4546H15.6546C15.745 13.4546 15.8183 13.5278 15.8183 13.6182V14.3818C15.8183 14.4722 15.745 14.5455 15.6546 14.5455H8.07282C7.98244 14.5455 7.90918 14.4722 7.90918 14.3818V13.6182C7.90918 13.5278 7.98244 13.4546 8.07282 13.4546ZM8.07282 16.7273H12.1092C12.1996 16.7273 12.2728 16.8005 12.2728 16.8909V17.6546C12.2728 17.7449 12.1996 17.8182 12.1092 17.8182H8.07282C7.98244 17.8182 7.90918 17.7449 7.90918 17.6546V16.8909C7.90918 16.8005 7.98244 16.7273 8.07282 16.7273Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,11 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_8693_7580)">
<path d="M1.33332 2H14.6667C15.0348 2 15.3333 2.29848 15.3333 2.66667V13.3333C15.3333 13.7015 15.0348 14 14.6667 14H1.33332C0.965133 14 0.666656 13.7015 0.666656 13.3333V2.66667C0.666656 2.29848 0.965133 2 1.33332 2ZM1.99999 3.33333V12.6667H14V3.33333H1.99999Z" fill="#646A73"/>
<path d="M4.66667 5.02255C4.66667 4.82618 4.50748 4.66699 4.31112 4.66699H3.68889C3.49253 4.66699 3.33334 4.82618 3.33334 5.02255L3.33325 7.00033C3.33325 7.19669 3.49244 7.35588 3.68881 7.35588H4.31103C4.5074 7.35588 4.66659 7.19669 4.66659 7.00033L4.66667 5.02255Z" fill="#646A73"/>
</g>
<defs>
<clipPath id="clip0_8693_7580">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 812 B

View File

@ -0,0 +1,11 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_8693_4607)">
<path d="M7.99999 15.3337C12.0501 15.3337 15.3333 12.0504 15.3333 8.00033C15.3333 3.95024 12.0501 0.666992 7.99999 0.666992C3.9499 0.666992 0.666656 3.95024 0.666656 8.00033C0.666656 12.0504 3.9499 15.3337 7.99999 15.3337ZM7.99999 14.0003C4.68628 14.0003 1.99999 11.314 1.99999 8.00033C1.99999 4.68662 4.68628 2.00033 7.99999 2.00033C11.3137 2.00033 14 4.68662 14 8.00033C14 11.314 11.3137 14.0003 7.99999 14.0003Z" fill="#646A73"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.00001 10.6663C9.47277 10.6663 10.6667 9.47243 10.6667 7.99967C10.6667 6.52692 9.47277 5.33301 8.00001 5.33301C6.52725 5.33301 5.33334 6.52692 5.33334 7.99967C5.33334 9.47243 6.52725 10.6663 8.00001 10.6663Z" fill="#646A73"/>
</g>
<defs>
<clipPath id="clip0_8693_4607">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 959 B

View File

@ -0,0 +1,11 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_8096_189573)">
<path d="M1.33335 4H14.6667C15.0349 4 15.3334 4.29848 15.3334 4.66667V11.3333C15.3334 11.7015 15.0349 12 14.6667 12H1.33335C0.965164 12 0.666687 11.7015 0.666687 11.3333V4.66667C0.666687 4.29848 0.965164 4 1.33335 4ZM2.00002 5.33333V10.6667H14V5.33333H2.00002Z" fill="#646A73"/>
<path d="M4.66665 7.02255C4.66665 6.82618 4.50746 6.66699 4.31109 6.66699H3.68887C3.4925 6.66699 3.33331 6.82618 3.33331 7.02255V8.9781C3.33331 9.17447 3.4925 9.33366 3.68887 9.33366H4.31109C4.50746 9.33366 4.66665 9.17447 4.66665 8.9781V7.02255Z" fill="#646A73"/>
</g>
<defs>
<clipPath id="clip0_8096_189573">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 797 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.66666 1.77734H13.3333C13.8242 1.77734 14.2222 2.17531 14.2222 2.66623V13.3329C14.2222 13.8238 13.8242 14.2218 13.3333 14.2218H2.66666C2.17574 14.2218 1.77777 13.8238 1.77777 13.3329V2.66623C1.77777 2.17531 2.17574 1.77734 2.66666 1.77734ZM3.1111 3.11068V12.8885H12.8889V3.11068H3.1111ZM10.5524 5.52146C10.6566 5.41732 10.8254 5.41732 10.9296 5.52146L11.4952 6.08715C11.5994 6.19129 11.5994 6.36013 11.4952 6.46427L7.47259 10.4869C7.463 10.4965 7.45285 10.5052 7.44226 10.5131L7.35921 10.5961C7.25571 10.6996 7.08815 10.7003 6.98375 10.5978L4.63634 8.29133C4.53063 8.18747 4.52988 8.01734 4.63467 7.91255L5.20034 7.34688C5.30383 7.24339 5.47139 7.24265 5.57579 7.34523L7.16611 8.90778L10.5524 5.52146Z" fill="#646A73"/>
</svg>

After

Width:  |  Height:  |  Size: 834 B

View File

@ -33,6 +33,18 @@ const userDrawer = ref(false)
const init = () => {
userDrawer.value = true
}
const cleanrInnerValue = (index: number) => {
const field = componentList.value[index]?.field
if (!field) {
return
}
myRefs.value[index]?.clear()
for (let i = 0; i < state.conditions.length; i++) {
if (state.conditions[i].field === field) {
state.conditions[i].value = []
}
}
}
const clearInnerTag = (index?: number) => {
if (isNaN(index)) {
for (let i = 0; i < componentList.value.length; i++) {
@ -74,6 +86,7 @@ const filterChange = (value, field, operator) => {
if (!exits && value?.length) {
state.conditions.push({ field, value, operator })
}
treeFilterChange(value, field, operator)
}
const reset = () => {
clearFilter()
@ -82,14 +95,22 @@ const reset = () => {
const close = () => {
userDrawer.value = false
}
const emits = defineEmits(['trigger-filter'])
const emits = defineEmits(['trigger-filter', 'tree-filter-change'])
const trigger = () => {
emits('trigger-filter', state.conditions)
}
const treeFilterChange = (value, field, operator) => {
emits('tree-filter-change', {
value,
field,
operator
})
}
defineExpose({
init,
clearFilter,
close
close,
cleanrInnerValue
})
</script>

View File

@ -661,6 +661,11 @@ import wizard_quick_start from '@/assets/svg/wizard_quick_start.svg'
import wordCloudDark from '@/assets/svg/word-cloud-dark.svg'
import wordCloudOrigin from '@/assets/svg/word-cloud-origin.svg'
import wordCloud from '@/assets/svg/word-cloud.svg'
import icon_multi_line_outlined from '@/assets/svg/icon_multi-line_outlined.svg'
import icon_radio_outlined from '@/assets/svg/icon_radio_outlined.svg'
import icon_single_line_outlined from '@/assets/svg/icon_single-line_outlined.svg'
import icon_todo_outlined from '@/assets/svg/icon_todo_outlined.svg'
import icon_file_doc_colorful from '@/assets/svg/icon_file-doc_colorful.svg'
const iconMap = {
'401': _401,
'403': _403,
@ -1062,6 +1067,10 @@ const iconMap = {
'icon_right-association': icon_rightAssociation,
icon_right_outlined: icon_right_outlined,
icon_scroll_filled: icon_scroll_filled,
icon_radio_outlined: icon_radio_outlined,
icon_todo_outlined: icon_todo_outlined,
'icon_single-line_outlined': icon_single_line_outlined,
'icon_multi-line_outlined': icon_multi_line_outlined,
'icon_search-outline_outlined': icon_searchOutline_outlined,
icon_search: icon_search,
'icon_share-label_filled': icon_shareLabel_filled,
@ -1320,7 +1329,8 @@ const iconMap = {
wizard_quick_start: wizard_quick_start,
'word-cloud-dark': wordCloudDark,
'word-cloud-origin': wordCloudOrigin,
'word-cloud': wordCloud
'word-cloud': wordCloud,
'icon_file-doc_colorful': icon_file_doc_colorful
}
const props = defineProps({

View File

@ -3,11 +3,12 @@ import { toRefs, PropType, onBeforeMount, watch, computed } from 'vue'
import { Calendar } from '@element-plus/icons-vue'
import { type DatePickType } from 'element-plus-secondary'
import type { ManipulateType } from 'dayjs'
import { getAround } from './time-format-dayjs'
import { getAround, getCustomRange } from './time-format-dayjs'
interface SelectConfig {
regularOrTrends: string
regularOrTrendsValue: [Date, Date]
intervalType: string
relativeToCurrentRange: string
timeNum: number
relativeToCurrentType: ManipulateType
around: string
@ -27,6 +28,7 @@ const props = defineProps({
regularOrTrends: 'fixed',
timeNum: 0,
intervalType: 'none',
relativeToCurrentRange: 'custom',
relativeToCurrentType: 'year',
around: 'f',
timeGranularity: 'date',
@ -50,6 +52,7 @@ const timeConfig = computed(() => {
timeNum,
relativeToCurrentType,
around,
relativeToCurrentRange,
intervalType,
regularOrTrends,
timeGranularity,
@ -62,6 +65,7 @@ const timeConfig = computed(() => {
relativeToCurrentType,
around,
intervalType,
relativeToCurrentRange,
regularOrTrends,
timeGranularity,
timeNumRange,
@ -87,10 +91,13 @@ watch(
)
const init = () => {
console.log('relativeToCurrentRange')
const {
timeNum,
relativeToCurrentType,
around,
relativeToCurrentRange,
regularOrTrends,
timeNumRange,
relativeToCurrentTypeRange,
@ -117,6 +124,11 @@ const init = () => {
timeNumRange
)
if (!!relativeToCurrentRange && relativeToCurrentRange !== 'custom') {
config.value.regularOrTrendsValue = getCustomRange(relativeToCurrentRange)
return
}
config.value.regularOrTrendsValue = [startTime, endTime]
}

View File

@ -576,16 +576,21 @@ const isInRange = (ele, startWindowTime, timeStamp) => {
if (intervalType === 'timeInterval') {
const startTime =
regularOrTrends === 'fixed'
? regularOrTrendsValue[0]
? new Date(
dayjs(new Date(regularOrTrendsValue[0])).startOf(noTime).format('YYYY/MM/DD HH:mm:ss')
)
: getAround(relativeToCurrentType, around === 'f' ? 'subtract' : 'add', timeNum)
const endTime =
regularOrTrends === 'fixed'
? regularOrTrendsValue[1]
? new Date(
dayjs(new Date(regularOrTrendsValue[1])).endOf(noTime).format('YYYY/MM/DD HH:mm:ss')
)
: getAround(
relativeToCurrentTypeRange,
aroundRange === 'f' ? 'subtract' : 'add',
timeNumRange
)
return (
startWindowTime < +new Date(startTime) - 1000 ||
timeStamp > +new Date(endTime) ||
@ -760,7 +765,7 @@ const validate = () => {
'end-config'
)
: new Date(ele.defaultValue[1])
if (!relativeToCurrentRange || relativeToCurrentRange === 'custom') {
if (!!relativeToCurrentRange && relativeToCurrentRange !== 'custom') {
;[startTime, endTime] = getCustomRange(relativeToCurrentRange)
}
if (+startTime > +endTime) {
@ -1032,6 +1037,10 @@ const parameterCompletion = () => {
Object.entries(attributes).forEach(([key, val]) => {
!curComponent.value[key] && (curComponent.value[key] = val)
})
if (!curComponent.value.timeRange.relativeToCurrentRange) {
curComponent.value.timeRange.relativeToCurrentRange = 'custom'
}
}
const handleCondition = item => {

View File

@ -11,6 +11,7 @@ const props = defineProps({
dynamicWindow: false,
maximumSingleQuery: 0,
regularOrTrends: 'fixed',
relativeToCurrentRange: 'custom',
regularOrTrendsValue: '',
relativeToCurrent: 'custom',
timeNum: 0,
@ -173,6 +174,85 @@ const relativeToCurrentList = computed(() => {
}
]
})
const relativeToCurrentListRange = computed(() => {
let list = []
if (!timeRange.value) return list
switch (props.timeGranularityMultiple) {
case 'yearrange':
list = [
{
label: '今年',
value: 'thisYear'
},
{
label: '去年',
value: 'lastYear'
}
]
break
case 'monthrange':
list = [
{
label: '本月',
value: 'thisMonth'
},
{
label: '上月',
value: 'lastMonth'
},
{
label: '最近 3 个 月',
value: 'LastThreeMonths'
},
{
label: '最近 6 个 月',
value: 'LastSixMonths'
},
{
label: '最近 12 个 月',
value: 'LastTwelveMonths'
}
]
break
case 'daterange':
case 'datetimerange':
list = [
{
label: '今天',
value: 'today'
},
{
label: '昨天',
value: 'yesterday'
},
{
label: '最近 3 天',
value: 'LastThreeDays'
},
{
label: '月初至今',
value: 'monthBeginning'
},
{
label: '年初至今',
value: 'yearBeginning'
}
]
break
default:
break
}
return [
...list,
{
label: '自定义',
value: 'custom'
}
]
})
</script>
<template>
@ -200,7 +280,7 @@ const relativeToCurrentList = computed(() => {
</el-radio-group>
</div>
<template v-if="dynamicTime && timeRange.intervalType !== 'timeInterval'">
<div class="setting">
<div class="setting" v-if="timeRange.intervalType !== 'timeInterval'">
<div class="setting-label">相对当前</div>
<div class="setting-value select">
<el-select v-model="timeRange.relativeToCurrent">
@ -236,26 +316,12 @@ const relativeToCurrentList = computed(() => {
</div>
</template>
<template v-else-if="dynamicTime && timeRange.intervalType === 'timeInterval'">
<div
class="setting"
:class="
['yearrange', 'monthrange'].includes(timeGranularityMultiple) && 'is-year-month-range'
"
>
<div class="setting-label">开始时间</div>
<div class="setting-input range">
<el-input-number v-model="timeRange.timeNum" :min="0" controls-position="right" />
<el-select v-model="timeRange.relativeToCurrentType">
<div class="setting">
<div class="setting-label">相对当前</div>
<div class="setting-value select">
<el-select v-model="timeRange.relativeToCurrentRange">
<el-option
v-for="item in relativeToCurrentTypeList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-select v-model="timeRange.around">
<el-option
v-for="item in aroundList"
v-for="item in relativeToCurrentListRange"
:key="item.value"
:label="item.label"
:value="item.value"
@ -263,37 +329,68 @@ const relativeToCurrentList = computed(() => {
</el-select>
</div>
</div>
<div
class="setting"
:class="
['yearrange', 'monthrange'].includes(timeGranularityMultiple) && 'is-year-month-range'
"
>
<div class="setting-label">结束时间</div>
<div class="setting-input range">
<el-input-number
v-model="timeRange.timeNumRange"
:min="0"
controls-position="right"
/>
<el-select v-model="timeRange.relativeToCurrentTypeRange">
<el-option
v-for="item in relativeToCurrentTypeList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-select v-model="timeRange.aroundRange">
<el-option
v-for="item in aroundList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<template v-if="timeRange.relativeToCurrentRange === 'custom'">
<div
class="setting"
:class="
['yearrange', 'monthrange'].includes(timeGranularityMultiple) &&
'is-year-month-range'
"
>
<div class="setting-label">开始时间</div>
<div class="setting-input range">
<el-input-number v-model="timeRange.timeNum" :min="0" controls-position="right" />
<el-select v-model="timeRange.relativeToCurrentType">
<el-option
v-for="item in relativeToCurrentTypeList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-select v-model="timeRange.around">
<el-option
v-for="item in aroundList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</div>
</div>
<div
class="setting"
:class="
['yearrange', 'monthrange'].includes(timeGranularityMultiple) &&
'is-year-month-range'
"
>
<div class="setting-label">结束时间</div>
<div class="setting-input range">
<el-input-number
v-model="timeRange.timeNumRange"
:min="0"
controls-position="right"
/>
<el-select v-model="timeRange.relativeToCurrentTypeRange">
<el-option
v-for="item in relativeToCurrentTypeList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-select v-model="timeRange.aroundRange">
<el-option
v-for="item in aroundList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</div>
</template>
</template>
</div>
<div class="parameters" :class="dynamicTime && 'setting'">

View File

@ -299,11 +299,19 @@ const disabledDate = val => {
if (intervalType === 'timeInterval') {
const startTime =
regularOrTrends === 'fixed'
? regularOrTrendsValue[0]
? new Date(
dayjs(new Date(regularOrTrendsValue[0]))
.startOf(queryTimeType.value)
.format('YYYY/MM/DD HH:mm:ss')
)
: getAround(relativeToCurrentType, around === 'f' ? 'subtract' : 'add', timeNum)
const endTime =
regularOrTrends === 'fixed'
? regularOrTrendsValue[1]
? new Date(
dayjs(new Date(regularOrTrendsValue[1]))
.endOf(queryTimeType.value)
.format('YYYY/MM/DD HH:mm:ss')
)
: getAround(
relativeToCurrentTypeRange,
aroundRange === 'f' ? 'subtract' : 'add',

View File

@ -233,6 +233,7 @@ interface TimeRange {
regularOrTrends: string
regularOrTrendsValue: string
relativeToCurrent: string
relativeToCurrentRange: string
timeNum: number
relativeToCurrentType: ManipulateType
around: string

View File

@ -1,6 +1,7 @@
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { storeToRefs } from 'pinia'
import { getDynamicRange, getCustomTime } from '@/custom-component/v-query/time-format'
import { getCustomRange } from '@/custom-component/v-query/time-format-dayjs'
const dvMainStore = dvMainStoreWithOut()
const { componentData } = storeToRefs(dvMainStore)
@ -266,6 +267,7 @@ export const searchQuery = (queryComponentList, filter, curComponentId, firstLoa
timeNum,
relativeToCurrentType,
around,
relativeToCurrentRange,
arbitraryTime,
timeGranularity,
timeNumRange,
@ -275,7 +277,7 @@ export const searchQuery = (queryComponentList, filter, curComponentId, firstLoa
arbitraryTimeRange
} = item
const startTime = getCustomTime(
let startTime = getCustomTime(
timeNum,
relativeToCurrentType,
timeGranularity,
@ -284,7 +286,7 @@ export const searchQuery = (queryComponentList, filter, curComponentId, firstLoa
timeGranularityMultiple,
'start-panel'
)
const endTime = getCustomTime(
let endTime = getCustomTime(
timeNumRange,
relativeToCurrentTypeRange,
timeGranularity,
@ -293,6 +295,10 @@ export const searchQuery = (queryComponentList, filter, curComponentId, firstLoa
timeGranularityMultiple,
'end-panel'
)
if (!!relativeToCurrentRange && relativeToCurrentRange !== 'custom') {
;[startTime, endTime] = getCustomRange(relativeToCurrentRange)
}
item.defaultValue = [startTime, endTime]
item.selectValue = [startTime, endTime]
selectValue = [startTime, endTime]

View File

@ -1,7 +1,7 @@
import { ref, onBeforeUnmount, onMounted } from 'vue'
import { useCache } from '@/hooks/web/useCache'
type Sidebar = 'DATASET' | 'DASHBOARD' | 'DATASOURCE'
type Sidebar = 'DATASET' | 'DASHBOARD' | 'DATASOURCE' | 'DATA-FILLING'
export const useMoveLine = (type: Sidebar) => {
const { wsCache } = useCache('localStorage')

View File

@ -73,7 +73,7 @@ onMounted(() => {
border: 0px !important;
border-color: #ffffff !important;
font-weight: 500;
color: rgba(51, 112, 255, 1) !important;
color: var(--ed-color-primary, rgba(51, 112, 255, 1)) !important;
}
}
}

View File

@ -1,5 +1,15 @@
export default {
common: {
component: {
input: 'Input',
textarea: 'Textarea',
select: 'Select',
radio: 'Radio',
checkbox: 'Checkbox',
date: 'Date Picker',
dateRange: 'Date Range Picker',
add_component_hint: 'Click or drag the component on the left to add a field'
},
inputText: 'Please input',
account: 'Account',
email: 'Email',
@ -250,5 +260,163 @@ export default {
template_manage: {
name_already_exists_type: 'Classification name already exists',
the_same_category: 'The template name already exists under the same category'
},
data_fill: {
data_fill: 'Data Filling',
permission: 'Data Filling Permission',
enable: 'Enable',
enable_hint: 'Cannot disable after enable',
new_folder: 'New Folder',
form_manage: 'Form Manage',
my_job: 'My Job',
form: {
mobile_number_format_is_incorrect: 'Incorrect format of mobile phone number',
email_format_is_incorrect: 'The mailbox format is incorrect',
name: 'Name',
rename: 'Rename',
untitled: 'Untitled',
create_new_form: 'Create New Form',
copy_new_form: 'Copy Form',
edit_form: 'Edit Form',
title: 'Title',
no_form: 'Click to Create New',
form_list_name: 'Form List',
create_form: 'Create Form',
please_select: 'Please Select',
component: 'Component',
component_setting: 'Component Setting',
hint: 'Hint',
option: 'Option',
form_setting: 'Form Setting',
input_limit_50: 'No more than 50 characters',
confirm_delete: 'Confirm delete? (The tables created in database will not be deleted)',
list: 'Form List',
record: 'Fill Record',
task_manage: 'Task Manage',
form_name: 'Form Name',
commit_type: 'Form Commit Type',
commit_type_append: 'Append',
commit_type_update: 'Update',
commit_rule: 'Update Rules',
commit_rule_add: 'Add Update Rule',
commit_rule_settings: 'Update Rule Settings',
commit_rule_set: 'Set',
folder: 'Folder',
datasource: 'Datasource',
table: 'Table',
creator: 'Creator',
createTime: 'Create Time',
operation: 'Operation',
operator: 'Operator',
operate_time: 'Operate Time',
modify: 'Modify',
show: 'Show',
delete: 'Delete',
show_data: 'Show Data',
text: 'Text',
number: 'Number',
tel: 'Tel',
email: 'Email',
duplicate_error: 'Duplicate',
value_not_exists: 'Value Not Exists',
range_separator: 'Range Separator',
start_hint_word: 'Start Hint Word',
end_hint_word: 'End Hint Word',
input_type: 'Input Type',
date_type: 'Date Format',
check: 'Check',
set_required: 'Set Required',
set_unique: 'Set Unique',
set_multiple: 'Set Multiple',
use_datetime: 'Use Datetime',
custom: 'Custom',
use_datasource: 'Bind Datasource',
bind_column: 'Bind Column',
bind_complete: 'Bind',
option_value: 'Options',
add_option: 'Add Option',
form_name_cannot_none: 'Form name cannot be null',
form_update_rule_none: 'Update Rules cannot be null',
form_components_cannot_null: 'Form components cannot be null',
option_list_cannot_empty: 'Option list cannot be empty',
option_list_datasource_cannot_empty: 'Datasource Settings of option list cannot be empty',
component_setting_error: 'Component setting error',
table_name: 'Table',
form_column: 'Form Column',
column_name: 'Table Column',
column_type: 'Table Column Type',
create_index: 'Create Index',
add_index: 'Add Index',
index_name: 'Index Name',
create_index_hint:
'MySQL versions earlier than 8.0 or MariaDB versions earlier than 10.8.0 do not support Descending indexes',
index_column: 'Index Column',
order: 'Sort',
order_asc: 'Asc',
order_desc: 'Desc',
order_none: 'Default Order',
add_column: 'Add Column',
please_insert_start: 'Start Time Column Name',
please_insert_end: 'End Time Column Name',
save_form: 'Save Form',
default: 'default',
default_built_in: 'Built-in Database'
},
database: {
nvarchar: 'Nvarchar',
text: 'Text',
number: 'Number',
decimal: 'Decimal',
datetime: 'Datetime'
},
data: {
confirm_delete: 'Confirm delete?',
add_data: 'Add Data',
download_template: 'Download Template',
insert_data: 'Insert Data',
update_data: 'Update Data',
delete_data: 'Delete Data',
recent_committer: 'Recent Committer',
recent_commit_time: 'Recent Commit Time',
start: 'Start',
end: 'End',
id_is: 'ID [',
data_not_found: '] Not Found'
},
task: {
name: 'Name',
creator: 'Creator',
create_time: 'Create Time',
rate_type: 'Rate Type',
task_status: 'Status',
add_task: 'Add Task',
task_name: 'Task Name',
task_remain_time: 'Remaining Validity',
task_sender: 'Task Sender',
start_filling: 'Start Filling',
task_distribute_time: 'Distribution Time',
task_expiration_time: 'Expiration Time',
task_finished_time: 'Finished Time',
task_end_time: 'End Time',
edit_data: 'Edit Data',
show_data: 'Show Data',
confirm_enable: 'Confirm enable task?',
confirm_disable: 'Confirm disable task?',
edit_task: 'Edit Task',
create_task: 'Create Task',
edit: 'Edit',
stop: 'Stop',
start: 'Start',
delete: 'Delete',
no_time_limit: 'No Time Limit',
todo: 'Todo',
finished: 'Committed',
expired: 'Expired',
task_finish_in: 'Task Finished in ',
task_finish_in_suffix: '',
open_sub_task: 'Open Sub Tasks'
},
on_the_left: 'Please select a form on the left',
search_by_commit_name: 'Search by operator name'
}
}

View File

@ -1,5 +1,15 @@
export default {
common: {
component: {
input: '單行輸入',
textarea: '多行輸入',
select: '下拉框',
radio: '單選',
checkbox: '多選框',
date: '日期',
dateRange: '時間范圍',
add_component_hint: '點擊或拖拽左側組件添加字段'
},
inputText: '请输入',
add: '添加',
account: '账号',
@ -152,5 +162,162 @@ export default {
template_manage: {
name_already_exists_type: '分类名称已存在',
the_same_category: '同一分类下该模板名称已存在'
},
data_fill: {
data_fill: '數據填報',
permission: '填報權限',
enable: '開啟',
enable_hint: '數據填報開啟后可將表單數據存放至數據源中一旦開啟后后期不允許關閉',
new_folder: '新建文件夾',
form_manage: '表單管理',
my_job: '我的填報',
form: {
mobile_number_format_is_incorrect: '手機號碼格式不正確',
email_format_is_incorrect: '郵箱格式不正確',
name: '名稱',
rename: '重命名',
untitled: '未命名表單',
create_new_form: '新建表單',
copy_new_form: '復制表單',
edit_form: '編輯表單',
title: '標題',
no_form: '暫無表單點擊',
form_list_name: '填報表單',
create_form: '新建表單',
please_select: '請選擇',
component: '組件',
component_setting: '組件設置',
hint: '提示詞',
input_limit_50: '不超過50個字符',
option: '選項',
form_setting: '表單設置',
confirm_delete: '確認刪除(不會刪除已創建的數據庫表)',
list: '表單數據',
record: '提交記錄',
task_manage: '任務管理',
form_name: '表單名稱',
commit_type: '表單提交方式',
commit_type_append: '數據追加',
commit_type_update: '數據更新',
commit_rule: '更新條件',
commit_rule_add: '添加更新規則',
commit_rule_settings: '更新規則設置',
commit_rule_set: '已設置',
folder: '所屬文件夾',
datasource: '數據源',
table: '數據庫表',
creator: '創建人',
createTime: '創建時間',
operation: '操作',
operator: '操作人',
operate_time: '操作時間',
modify: '修改',
show: '查看',
delete: '刪除',
show_data: '查看數據',
text: '普通文本',
number: '數字',
tel: '手機號',
email: '郵箱',
duplicate_error: '重復',
value_not_exists: '值不存在',
range_separator: '分割字符',
start_hint_word: '開始提示詞',
end_hint_word: '結束提示詞',
input_type: '格式類型',
date_type: '展示粒度',
check: '校驗',
set_required: '設置為必填項',
set_unique: '不允許重復值',
set_multiple: '允許多選',
use_datetime: '使用日期時間',
custom: '自定義',
use_datasource: '綁定數據源',
bind_column: '綁定字段',
bind_complete: '已綁定',
option_value: '選項值',
add_option: '添加選項值',
form_name_cannot_none: '表單名稱不能為空',
form_update_rule_none: '請配置更新規則',
form_components_cannot_null: '請添加表單組件',
option_list_cannot_empty: '選項值不能為空',
option_list_datasource_cannot_empty: '選項值綁定數據源配置不能為空',
component_setting_error: '組件設置錯誤',
table_name: '數據庫表名',
form_column: '表單字段',
column_name: '數據庫表字段名稱',
column_type: '數據庫字段類型',
create_index: '創建索引',
add_index: '新增索引',
index_name: '索引名稱',
create_index_hint: 'MySQL 8.0 MariaDB 10.8.0 以下版本不支持索引降序排序',
index_column: '索引字段',
order: '排序',
order_asc: '升序',
order_desc: '降序',
order_none: '默認排序',
add_column: '新增字段',
please_insert_start: '請輸入開始時間',
please_insert_end: '請輸入結束時間',
save_form: '保存表單',
default: '默認',
default_built_in: '內建數據庫'
},
database: {
nvarchar: '字符串',
text: '長文本',
number: '整型數字',
decimal: '小數數字',
datetime: '日期'
},
data: {
confirm_delete: '確認刪除?',
add_data: '添加數據',
download_template: '下載模板',
insert_data: '插入數據',
update_data: '更新數據',
delete_data: '刪除數據',
recent_committer: '最近提交人',
recent_commit_time: '最近提交時間',
start: '開始',
end: '結束',
id_is: 'ID為[',
data_not_found: ']的數據不存在'
},
task: {
name: '名稱',
creator: '創建人',
create_time: '創建時間',
rate_type: '任務下發模式',
task_status: '任務狀態',
add_task: '添加任務',
task_name: '任務名稱',
task_remain_time: '任務有效期',
task_sender: '任務下發人',
start_filling: '立即填報',
task_distribute_time: '任務下發時間',
task_expiration_time: '任務過期時間',
task_finished_time: '任務完成時間',
task_end_time: '任務截止時間',
edit_data: '編輯數據',
show_data: '查看數據',
confirm_enable: '確認啟動任務單次任務會新建下發任務',
confirm_disable: '確認停止任務',
edit_task: '編輯任務',
create_task: '新建任務',
edit: '編輯',
stop: '停止',
start: '啟動',
delete: '刪除',
no_time_limit: '不限時',
todo: '待辦項',
finished: '已提交',
expired: '已過期',
task_finish_in: '在任務下發',
task_finish_in_suffix: '內完成填報',
open_sub_task: '查看子任務'
},
on_the_left: '請在左側選擇表單',
search_by_commit_name: '根據操作人名稱搜索'
}
}

View File

@ -1,5 +1,15 @@
export default {
common: {
component: {
input: '单行输入',
textarea: '多行输入',
select: '下拉框',
radio: '单选',
checkbox: '多选框',
date: '日期',
dateRange: '时间范围',
add_component_hint: '点击或拖拽左侧组件添加字段'
},
inputText: '请输入',
add: '添加',
account: '账号',
@ -2562,6 +2572,10 @@ export default {
once_a_day: '每天',
once_a_week: '每周',
once_a_month: '每月',
hour: '小时',
day: '天',
week: '周',
month: '月',
week_mon: '一',
week_tue: '二',
week_wed: '三',
@ -2578,5 +2592,162 @@ export default {
variable: {
give_up: 's',
save_apply: '保存并应用'
},
data_fill: {
data_fill: '数据填报',
permission: '填报权限',
enable: '开启',
enable_hint: '数据填报开启后可将表单数据存放至数据源中一旦开启后后期不允许关闭',
new_folder: '新建文件夹',
form_manage: '表单管理',
my_job: '我的填报',
form: {
special_characters_are_not_supported: '不支持特殊字符',
mobile_number_format_is_incorrect: '手机号码格式不正确',
name: '名称',
rename: '重命名',
untitled: '未命名表单',
create_new_form: '新建表单',
copy_new_form: '复制表单',
edit_form: '编辑表单',
title: '标题',
no_form: '暂无表单点击',
form_list_name: '填报表单',
create_form: '新建表单',
please_select: '请选择',
component: '组件',
component_setting: '组件设置',
hint: '提示词',
input_limit_50: '不超过50个字符',
option: '选项',
form_setting: '表单设置',
confirm_delete: '确认删除(不会删除已创建的数据库表)',
list: '表单数据',
record: '提交记录',
task_manage: '任务管理',
form_name: '表单名称',
commit_type: '表单提交方式',
commit_type_append: '数据追加',
commit_type_update: '数据更新',
commit_rule: '更新条件',
commit_rule_add: '添加更新规则',
commit_rule_settings: '更新规则设置',
commit_rule_set: '已设置',
folder: '所属文件夹',
datasource: '数据源',
table: '数据库表',
creator: '创建人',
createTime: '创建时间',
operation: '操作',
operator: '操作人',
operate_time: '操作时间',
modify: '修改',
show: '查看',
delete: '删除',
show_data: '查看数据',
text: '普通文本',
number: '数字',
tel: '手机号',
email: '邮箱',
duplicate_error: '重复',
value_not_exists: '值不存在',
range_separator: '分割字符',
start_hint_word: '开始提示词',
end_hint_word: '结束提示词',
input_type: '格式类型',
date_type: '展示粒度',
check: '校验',
set_required: '设置为必填项',
set_unique: '不允许重复值',
set_multiple: '允许多选',
use_datetime: '使用日期时间',
custom: '自定义',
use_datasource: '绑定数据源',
bind_column: '绑定字段',
bind_complete: '已绑定',
option_value: '选项值',
add_option: '添加选项值',
form_name_cannot_none: '表单名称不能为空',
form_update_rule_none: '请配置更新规则',
form_components_cannot_null: '请添加表单组件',
option_list_cannot_empty: '选项值不能为空',
option_list_datasource_cannot_empty: '选项值绑定数据源配置不能为空',
component_setting_error: '组件设置错误',
table_name: '数据库表名',
form_column: '表单字段',
column_name: '数据库表字段名称',
column_type: '数据库字段类型',
create_index: '创建索引',
add_index: '新增索引',
index_name: '索引名称',
create_index_hint: 'MySQL 8.0 MariaDB 10.8.0 以下版本不支持索引降序排序',
index_column: '索引字段',
order: '排序',
order_asc: '升序',
order_desc: '降序',
order_none: '默认排序',
add_column: '新增字段',
please_insert_start: '请输入开始时间',
please_insert_end: '请输入结束时间',
save_form: '保存表单',
default: '默认',
default_built_in: '内建数据库'
},
database: {
nvarchar: '字符串',
text: '长文本',
number: '整型数字',
decimal: '小数数字',
datetime: '日期'
},
data: {
confirm_delete: '确认删除?',
add_data: '添加数据',
download_template: '下载模板',
insert_data: '插入数据',
update_data: '更新数据',
delete_data: '删除数据',
recent_committer: '最近提交人',
recent_commit_time: '最近提交时间',
start: '开始',
end: '结束',
id_is: 'ID为[',
data_not_found: ']的数据不存在'
},
task: {
name: '名称',
creator: '创建人',
create_time: '创建时间',
rate_type: '任务下发模式',
task_status: '任务状态',
task_name: '任务名称',
add_task: '添加任务',
task_remain_time: '任务有效期',
task_sender: '任务下发人',
start_filling: '立即填报',
task_distribute_time: '任务下发时间',
task_expiration_time: '任务过期时间',
task_finished_time: '任务完成时间',
task_end_time: '任务截止时间',
edit_data: '编辑数据',
show_data: '查看数据',
confirm_enable: '确认启动任务单次任务会新建下发任务',
confirm_disable: '确认停止任务',
edit_task: '编辑任务',
create_task: '新建任务',
edit: '编辑',
stop: '停止',
start: '启动',
delete: '删除',
no_time_limit: '不限时',
todo: '待办项',
finished: '已提交',
expired: '已过期',
task_finish_in: '在任务下发',
task_finish_in_suffix: '内完成填报',
open_sub_task: '查看子任务'
},
on_the_left: '请在左侧选择表单',
search_by_commit_name: '根据操作人名称搜索'
}
}

View File

@ -113,8 +113,15 @@ onBeforeMount(async () => {
}
)
})
const userViewEnlargeOpen = () => {
userViewEnlargeRef.value.dialogInit(state.canvasStylePreview, viewInfo.value, config.value)
const userViewEnlargeOpen = (a, b) => {
console.log(a, b, 'item')
userViewEnlargeRef.value.dialogInit(
state.canvasStylePreview,
viewInfo.value,
config.value,
'details'
)
}
const onPointClick = param => {

View File

@ -1,5 +1,5 @@
import { defineStore } from 'pinia'
import { store } from '../index'
import { store } from '@/store'
import { queryTreeApi } from '@/api/visualization/dataVisualization'
import { getDatasetTree } from '@/api/dataset'
import { listDatasources } from '@/api/datasource'
@ -7,6 +7,7 @@ import type { BusiTreeRequest, BusiTreeNode } from '@/models/tree/TreeNode'
import { pathValid } from '@/store/modules/permission'
import { useCache } from '@/hooks/web/useCache'
import { useAppStoreWithOut } from '@/store/modules/app'
import { listDataFillingForms } from '@/api/data-filling'
const appStore = useAppStoreWithOut()
const { wsCache } = useCache()
export interface InnerInteractive {
@ -21,9 +22,9 @@ interface InteractiveState {
data: Record<number, InnerInteractive>
}
const apiMap = [queryTreeApi, queryTreeApi, getDatasetTree, listDatasources]
const apiMap = [queryTreeApi, queryTreeApi, getDatasetTree, listDatasources, listDataFillingForms]
const busiFlagMap = ['dashboard', 'dataV', 'dataset', 'datasource']
const busiFlagMap = ['dashboard', 'dataV', 'dataset', 'datasource', 'data-filling']
export const interactiveStore = defineStore('interactive', {
state: (): InteractiveState => ({

View File

@ -12,3 +12,5 @@ export function validUsername(str) {
}
export const PHONE_REGEX = '^1[3|4|5|7|8][0-9]{9}$'
export const EMAIL_REGEX = '^[a-zA-Z0-9_._-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$'

View File

@ -1,4 +1,4 @@
import { Column, ColumnOptions } from '@antv/g2plot/esm/plots/column'
import type { Column, ColumnOptions } from '@antv/g2plot/esm/plots/column'
import { cloneDeep, isEmpty } from 'lodash-es'
import {
G2PlotChartView,
@ -11,7 +11,7 @@ import {
setUpGroupSeriesColor,
setUpStackSeriesColor
} from '@/views/chart/components/js/util'
import { Datum } from '@antv/g2plot'
import type { Datum } from '@antv/g2plot'
import { valueFormatter } from '@/views/chart/components/js/formatter'
import {
BAR_AXIS_TYPE,
@ -22,6 +22,7 @@ import { getPadding, setGradientColor } from '@/views/chart/components/js/panel/
import { useI18n } from '@/hooks/web/useI18n'
import { DEFAULT_LABEL } from '@/views/chart/components/editor/util/chart'
import { clearExtremum, extremumEvt } from '@/views/chart/components/js/extremumUitl'
import { Group } from '@antv/g-canvas'
const { t } = useI18n()
const DEFAULT_DATA: any[] = []
@ -93,7 +94,7 @@ export class Bar extends G2PlotChartView<ColumnOptions, Column> {
}
}
drawChart(drawOptions: G2PlotDrawOptions<Column>): Column {
async drawChart(drawOptions: G2PlotDrawOptions<Column>): Promise<Column> {
const { chart, container, action } = drawOptions
if (!chart?.data?.data?.length) {
clearExtremum(chart)
@ -106,8 +107,9 @@ export class Bar extends G2PlotChartView<ColumnOptions, Column> {
data
}
const options: ColumnOptions = this.setupOptions(chart, initOptions)
const newChart = new Column(container, options)
let newChart = null
const { Column: ColumnClass } = await import('@antv/g2plot/esm/plots/column')
newChart = new ColumnClass(container, options)
newChart.on('interval:click', action)
extremumEvt(newChart, chart, options, container)
return newChart
@ -146,7 +148,7 @@ export class Bar extends G2PlotChartView<ColumnOptions, Column> {
return
}
const value = valueFormatter(data.value, labelCfg.formatterCfg)
const group = new G2PlotChartView.engine.Group({})
const group = new Group({})
group.addShape({
type: 'text',
attrs: {

View File

@ -9,14 +9,16 @@ import {
getYAxisExt,
setGradientColor
} from '@/views/chart/components/js/panel/common/common_antv'
import {
import type {
BidirectionalBar as G2BidirectionalBar,
BidirectionalBarOptions
} from '@antv/g2plot/esm/plots/bidirectional-bar'
import { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util'
import { useI18n } from '@/hooks/web/useI18n'
import { valueFormatter } from '@/views/chart/components/js/formatter'
import { Options } from '@antv/g2plot/esm'
import type { Options } from '@antv/g2plot/esm'
import { Group } from '@antv/g-canvas'
const { t } = useI18n()
/**
* 对称柱状图
@ -101,7 +103,7 @@ export class BidirectionalHorizontalBar extends G2PlotChartView<
}
}
drawChart(drawOptions: G2PlotDrawOptions<G2BidirectionalBar>): G2BidirectionalBar {
async drawChart(drawOptions: G2PlotDrawOptions<G2BidirectionalBar>): Promise<G2BidirectionalBar> {
const { chart, container, action } = drawOptions
if (!chart.data?.data?.length) {
return
@ -150,8 +152,11 @@ export class BidirectionalHorizontalBar extends G2PlotChartView<
}
}
}
const { BidirectionalBar: BidirectionalBarClass } = await import(
'@antv/g2plot/esm/plots/bidirectional-bar'
)
// 开始渲染
const newChart = new G2BidirectionalBar(container, options)
const newChart = new BidirectionalBarClass(container, options)
newChart.on('interval:click', action)
newChart.on('element:click', ev => {
@ -451,7 +456,7 @@ export class BidirectionalHorizontalBar extends G2PlotChartView<
} else {
res = valueFormatter(value, l.labelFormatter)
}
const group = new G2PlotChartView.engine.Group({})
const group = new Group({})
const isValue = param['series-field-key'] === 'value'
const textAlign = isValue && layoutHorizontal ? 'end' : 'start'
const isMiddle = label.position === 'middle'

View File

@ -2,7 +2,7 @@ import {
G2PlotChartView,
G2PlotDrawOptions
} from '@/views/chart/components/js/panel/types/impl/g2plot'
import { Bar, BarOptions } from '@antv/g2plot/esm/plots/bar'
import type { Bar, BarOptions } from '@antv/g2plot/esm/plots/bar'
import { getPadding, setGradientColor } from '@/views/chart/components/js/panel/common/common_antv'
import { cloneDeep } from 'lodash-es'
import {
@ -17,9 +17,10 @@ import {
BAR_EDITOR_PROPERTY,
BAR_EDITOR_PROPERTY_INNER
} from '@/views/chart/components/js/panel/charts/bar/common'
import { Datum } from '@antv/g2plot/esm/types/common'
import type { Datum } from '@antv/g2plot/esm/types/common'
import { useI18n } from '@/hooks/web/useI18n'
import { DEFAULT_LABEL } from '@/views/chart/components/editor/util/chart'
import { Group } from '@antv/g-canvas'
const { t } = useI18n()
const DEFAULT_DATA = []
@ -105,7 +106,7 @@ export class HorizontalBar extends G2PlotChartView<BarOptions, Bar> {
]
}
drawChart(drawOptions: G2PlotDrawOptions<Bar>): Bar {
async drawChart(drawOptions: G2PlotDrawOptions<Bar>): Promise<Bar> {
const { chart, container, action } = drawOptions
if (!chart.data?.data?.length) {
return
@ -122,6 +123,7 @@ export class HorizontalBar extends G2PlotChartView<BarOptions, Bar> {
const options = this.setupOptions(chart, initOptions)
const { Bar } = await import('@antv/g2plot/esm/plots/bar')
// 开始渲染
const newChart = new Bar(container, options)
@ -238,7 +240,7 @@ export class HorizontalBar extends G2PlotChartView<BarOptions, Bar> {
return
}
const value = valueFormatter(data.value, labelCfg.formatterCfg)
const group = new G2PlotChartView.engine.Group({})
const group = new Group({})
group.addShape({
type: 'text',
attrs: {

View File

@ -2,7 +2,7 @@ import { G2PlotChartView, G2PlotDrawOptions } from '../../types/impl/g2plot'
import { flow, hexColorToRGBA, parseJson } from '../../../util'
import { setGradientColor } from '../../common/common_antv'
import { useI18n } from '@/hooks/web/useI18n'
import { Bar as G2Progress, BarOptions } from '@antv/g2plot/esm/plots/bar'
import type { Bar as G2Progress, BarOptions } from '@antv/g2plot/esm/plots/bar'
import {
BAR_AXIS_TYPE,
BAR_EDITOR_PROPERTY_INNER
@ -66,7 +66,7 @@ export class ProgressBar extends G2PlotChartView<BarOptions, G2Progress> {
appendPadding: [0, 0, 10, 0]
}
drawChart(drawOptions: G2PlotDrawOptions<G2Progress>): G2Progress {
async drawChart(drawOptions: G2PlotDrawOptions<G2Progress>): Promise<G2Progress> {
const { chart, container, action } = drawOptions
if (!chart.data?.data?.length) {
return
@ -128,6 +128,7 @@ export class ProgressBar extends G2PlotChartView<BarOptions, G2Progress> {
}
const options = this.setupOptions(chart, initOptions)
const { Bar: G2Progress } = await import('@antv/g2plot/esm/plots/bar')
// 开始渲染
const newChart = new G2Progress(container, options)

View File

@ -2,7 +2,7 @@ import {
G2PlotChartView,
G2PlotDrawOptions
} from '@/views/chart/components/js/panel/types/impl/g2plot'
import { Bar, BarOptions } from '@antv/g2plot/esm/plots/bar'
import type { Bar, BarOptions } from '@antv/g2plot/esm/plots/bar'
import { getPadding, setGradientColor } from '@/views/chart/components/js/panel/common/common_antv'
import { cloneDeep, find } from 'lodash-es'
import { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util'
@ -107,7 +107,7 @@ export class RangeBar extends G2PlotChartView<BarOptions, Bar> {
]
}
drawChart(drawOptions: G2PlotDrawOptions<Bar>): Bar {
async drawChart(drawOptions: G2PlotDrawOptions<Bar>): Promise<Bar> {
const { chart, container, action } = drawOptions
if (!chart.data?.data?.length) {
return
@ -163,8 +163,9 @@ export class RangeBar extends G2PlotChartView<BarOptions, Bar> {
const options = this.setupOptions(chart, initOptions)
const { Bar: BarClass } = await import('@antv/g2plot/esm/plots/bar')
// 开始渲染
const newChart = new Bar(container, options)
const newChart = new BarClass(container, options)
newChart.on('interval:click', action)

View File

@ -1,4 +1,4 @@
import { WaterfallOptions, Waterfall as G2Waterfall } from '@antv/g2plot/esm/plots/waterfall'
import type { WaterfallOptions, Waterfall as G2Waterfall } from '@antv/g2plot/esm/plots/waterfall'
import { G2PlotChartView, G2PlotDrawOptions } from '../../types/impl/g2plot'
import { flow, hexColorToRGBA, parseJson } from '../../../util'
import { valueFormatter } from '../../../formatter'
@ -60,7 +60,7 @@ export class Waterfall extends G2PlotChartView<WaterfallOptions, G2Waterfall> {
]
}
axis: AxisType[] = ['xAxis', 'yAxis', 'filter', 'drill', 'extLabel', 'extTooltip']
public drawChart(drawOptions: G2PlotDrawOptions<G2Waterfall>): G2Waterfall {
async drawChart(drawOptions: G2PlotDrawOptions<G2Waterfall>): Promise<G2Waterfall> {
const { chart, container, action } = drawOptions
if (!chart.data?.data) {
return
@ -83,6 +83,7 @@ export class Waterfall extends G2PlotChartView<WaterfallOptions, G2Waterfall> {
]
}
const options = this.setupOptions(chart, baseOptions)
const { Waterfall: G2Waterfall } = await import('@antv/g2plot/esm/plots/waterfall')
const newChart = new G2Waterfall(container, options)
newChart.on('interval:click', action)
return newChart

View File

@ -2,7 +2,7 @@ import {
G2PlotChartView,
G2PlotDrawOptions
} from '@/views/chart/components/js/panel/types/impl/g2plot'
import { Area as G2Area, AreaOptions } from '@antv/g2plot/esm/plots/area'
import type { Area as G2Area, AreaOptions } from '@antv/g2plot/esm/plots/area'
import { getPadding, setGradientColor } from '@/views/chart/components/js/panel/common/common_antv'
import { cloneDeep } from 'lodash-es'
import {
@ -22,6 +22,7 @@ import { Datum } from '@antv/g2plot/esm/types/common'
import { useI18n } from '@/hooks/web/useI18n'
import { DEFAULT_LABEL } from '@/views/chart/components/editor/util/chart'
import { clearExtremum, extremumEvt } from '@/views/chart/components/js/extremumUitl'
import { Group } from '@antv/g-canvas'
const { t } = useI18n()
const DEFAULT_DATA = []
@ -94,7 +95,7 @@ export class Area extends G2PlotChartView<AreaOptions, G2Area> {
]
}
drawChart(drawOptions: G2PlotDrawOptions<G2Area>): G2Area {
async drawChart(drawOptions: G2PlotDrawOptions<G2Area>): Promise<G2Area> {
const { chart, container, action } = drawOptions
if (!chart.data.data?.length) {
clearExtremum(chart)
@ -110,6 +111,7 @@ export class Area extends G2PlotChartView<AreaOptions, G2Area> {
}
// options
const options = this.setupOptions(chart, initOptions)
const { Area: G2Area } = await import('@antv/g2plot/esm/plots/area')
// 开始渲染
const newChart = new G2Area(container, options)
@ -150,7 +152,7 @@ export class Area extends G2PlotChartView<AreaOptions, G2Area> {
return
}
const value = valueFormatter(data.value, labelCfg.formatterCfg)
const group = new G2PlotChartView.engine.Group({})
const group = new Group({})
group.addShape({
type: 'text',
attrs: {

View File

@ -2,7 +2,7 @@ import {
G2PlotChartView,
G2PlotDrawOptions
} from '@/views/chart/components/js/panel/types/impl/g2plot'
import { Line as G2Line, LineOptions } from '@antv/g2plot/esm/plots/line'
import type { Line as G2Line, LineOptions } from '@antv/g2plot/esm/plots/line'
import { getPadding } from '../../common/common_antv'
import {
flow,
@ -17,10 +17,11 @@ import {
LINE_EDITOR_PROPERTY,
LINE_EDITOR_PROPERTY_INNER
} from '@/views/chart/components/js/panel/charts/line/common'
import { Datum } from '@antv/g2plot/esm/types/common'
import type { Datum } from '@antv/g2plot/esm/types/common'
import { useI18n } from '@/hooks/web/useI18n'
import { DEFAULT_LABEL } from '@/views/chart/components/editor/util/chart'
import { clearExtremum, extremumEvt } from '@/views/chart/components/js/extremumUitl'
import { Group } from '@antv/g-canvas'
const { t } = useI18n()
const DEFAULT_DATA = []
@ -46,7 +47,7 @@ export class Line extends G2PlotChartView<LineOptions, G2Line> {
type: 'q'
}
}
drawChart(drawOptions: G2PlotDrawOptions<G2Line>): G2Line {
async drawChart(drawOptions: G2PlotDrawOptions<G2Line>): Promise<G2Line> {
const { chart, action, container } = drawOptions
if (!chart.data.data?.length) {
clearExtremum(chart)
@ -105,6 +106,7 @@ export class Line extends G2PlotChartView<LineOptions, G2Line> {
]
}
const options = this.setupOptions(chart, initOptions)
const { Line: G2Line } = await import('@antv/g2plot/esm/plots/line')
// 开始渲染
const newChart = new G2Line(container, options)
@ -147,7 +149,7 @@ export class Line extends G2PlotChartView<LineOptions, G2Line> {
return
}
const value = valueFormatter(data.value, labelCfg.formatterCfg)
const group = new G2PlotChartView.engine.Group({})
const group = new Group({})
group.addShape({
type: 'text',
attrs: {

View File

@ -2,12 +2,12 @@ import {
G2PlotChartView,
G2PlotDrawOptions
} from '@/views/chart/components/js/panel/types/impl/g2plot'
import { Mix, MixOptions } from '@antv/g2plot/esm/plots/mix'
import type { Mix, MixOptions } from '@antv/g2plot/esm/plots/mix'
import { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util'
import { LINE_EDITOR_PROPERTY_INNER } from '@/views/chart/components/js/panel/charts/line/common'
import { useI18n } from '@/hooks/web/useI18n'
import { valueFormatter } from '@/views/chart/components/js/formatter'
import { Options } from '@antv/g2plot/esm'
import type { Options } from '@antv/g2plot/esm'
const { t } = useI18n()
const DEFAULT_DATA = []
@ -206,7 +206,7 @@ export class StockLine extends G2PlotChartView<MixOptions, Mix> {
})
}
drawChart(drawOptions: G2PlotDrawOptions<Mix>): Mix {
async drawChart(drawOptions: G2PlotDrawOptions<Mix>): Promise<Mix> {
const { chart, action, container } = drawOptions
if (!chart.data.data?.length) {
return
@ -341,7 +341,8 @@ export class StockLine extends G2PlotChartView<MixOptions, Mix> {
...averageLines
]
})
const plot = new Mix(container, option)
const { Mix: MixClass } = await import('@antv/g2plot/esm/plots/mix')
const plot = new MixClass(container, option)
this.registerEvent(data, plot, averagesLineData)
plot.on('schema:click', evt => {
const selectSchema = evt.data.data[xAxisDataeaseName]

View File

@ -2,7 +2,7 @@ import {
G2PlotChartView,
G2PlotDrawOptions
} from '@/views/chart/components/js/panel/types/impl/g2plot'
import { Liquid as G2Liquid, LiquidOptions } from '@antv/g2plot/esm/plots/liquid'
import type { Liquid as G2Liquid, LiquidOptions } from '@antv/g2plot/esm/plots/liquid'
import { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util'
import { DEFAULT_MISC } from '@/views/chart/components/editor/util/chart'
import { valueFormatter } from '@/views/chart/components/js/formatter'
@ -50,7 +50,7 @@ export class Liquid extends G2PlotChartView<LiquidOptions, G2Liquid> {
}
}
drawChart(drawOptions: G2PlotDrawOptions<G2Liquid>): G2Liquid {
async drawChart(drawOptions: G2PlotDrawOptions<G2Liquid>): Promise<G2Liquid> {
const { chart, container } = drawOptions
if (!chart.data?.series) {
return
@ -59,6 +59,7 @@ export class Liquid extends G2PlotChartView<LiquidOptions, G2Liquid> {
percent: 0
}
const options = this.setupOptions(chart, initOptions)
const { Liquid: G2Liquid } = await import('@antv/g2plot/esm/plots/liquid')
// 开始渲染
return new G2Liquid(container, options)
}

View File

@ -2,7 +2,7 @@ import {
L7PlotChartView,
L7PlotDrawOptions
} from '@/views/chart/components/js/panel/types/impl/l7plot'
import { Choropleth, ChoroplethOptions } from '@antv/l7plot/dist/esm/plots/choropleth'
import type { Choropleth, ChoroplethOptions } from '@antv/l7plot/dist/esm/plots/choropleth'
import {
filterChartDataByRange,
flow,
@ -17,7 +17,7 @@ import {
mapRendered,
mapRendering
} from '@/views/chart/components/js/panel/common/common_antv'
import { FeatureCollection } from '@antv/l7plot/dist/esm/plots/choropleth/types'
import type { FeatureCollection } from '@antv/l7plot/dist/esm/plots/choropleth/types'
import { cloneDeep, defaultsDeep } from 'lodash-es'
import { useI18n } from '@/hooks/web/useI18n'
import { valueFormatter } from '../../../formatter'
@ -27,7 +27,7 @@ import {
MAP_EDITOR_PROPERTY_INNER,
MapMouseEvent
} from '@/views/chart/components/js/panel/charts/map/common'
import { CategoryLegendListItem } from '@antv/l7plot-component/dist/lib/types/legend'
import type { CategoryLegendListItem } from '@antv/l7plot-component/dist/lib/types/legend'
import createDom from '@antv/dom-util/esm/create-dom'
import {
CONTAINER_TPL,
@ -143,6 +143,7 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
}
const context = { drawOption, geoJson }
options = this.setupOptions(chart, options, context)
const { Choropleth } = await import('@antv/l7plot/dist/esm/plots/choropleth')
const view = new Choropleth(container, options)
this.configZoomButton(chart, view)
mapRendering(container)

View File

@ -2,7 +2,7 @@ import {
G2PlotChartView,
G2PlotDrawOptions
} from '@/views/chart/components/js/panel/types/impl/g2plot'
import { DualAxes, DualAxesOptions } from '@antv/g2plot/esm/plots/dual-axes'
import type { DualAxes, DualAxesOptions } from '@antv/g2plot/esm/plots/dual-axes'
import {
getAnalyse,
getLabel,
@ -21,10 +21,11 @@ import {
CHART_MIX_EDITOR_PROPERTY_INNER,
MixChartBasicStyle
} from './chart-mix-common'
import { Datum } from '@antv/g2plot/esm/types/common'
import type { Datum } from '@antv/g2plot/esm/types/common'
import { useI18n } from '@/hooks/web/useI18n'
import { DEFAULT_LABEL } from '@/views/chart/components/editor/util/chart'
import { Options } from '@antv/g2plot/esm'
import type { Options } from '@antv/g2plot/esm'
import { Group } from '@antv/g-canvas'
const { t } = useI18n()
const DEFAULT_DATA = []
@ -62,7 +63,7 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
type: 'q'
}
}
drawChart(drawOptions: G2PlotDrawOptions<DualAxes>): DualAxes {
async drawChart(drawOptions: G2PlotDrawOptions<DualAxes>): Promise<DualAxes> {
const { chart, action, container } = drawOptions
if (!chart.data?.left?.data?.length && !chart.data?.right?.data?.length) {
return
@ -138,7 +139,7 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
]
}
const options = this.setupOptions(chart, initOptions)
const { DualAxes } = await import('@antv/g2plot/esm/plots/dual-axes')
// 开始渲染
const newChart = new DualAxes(container, options)
@ -190,7 +191,7 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
return
}
const value = valueFormatter(data.value, labelCfg.formatterCfg)
const group = new G2PlotChartView.engine.Group({})
const group = new Group({})
group.addShape({
type: 'text',
attrs: {

View File

@ -1,4 +1,4 @@
import { FunnelOptions, Funnel as G2Funnel } from '@antv/g2plot/esm/plots/funnel'
import type { FunnelOptions, Funnel as G2Funnel } from '@antv/g2plot/esm/plots/funnel'
import { G2PlotChartView, G2PlotDrawOptions } from '../../types/impl/g2plot'
import { flow, setUpSingleDimensionSeriesColor } from '@/views/chart/components/js/util'
import { getPadding } from '../../common/common_antv'
@ -53,7 +53,7 @@ export class Funnel extends G2PlotChartView<FunnelOptions, G2Funnel> {
}
}
public drawChart(drawOptions: G2PlotDrawOptions<G2Funnel>): G2Funnel {
async drawChart(drawOptions: G2PlotDrawOptions<G2Funnel>): Promise<G2Funnel> {
const { chart, container, action } = drawOptions
if (!chart.data?.data) {
return
@ -104,6 +104,7 @@ export class Funnel extends G2PlotChartView<FunnelOptions, G2Funnel> {
}
}
const options = this.setupOptions(chart, baseOptions)
const { Funnel: G2Funnel } = await import('@antv/g2plot/esm/plots/funnel')
const newChart = new G2Funnel(container, options)
newChart.on('interval:click', action)
return newChart

View File

@ -2,7 +2,7 @@ import {
G2PlotChartView,
G2PlotDrawOptions
} from '@/views/chart/components/js/panel/types/impl/g2plot'
import { Gauge as G2Gauge, GaugeOptions } from '@antv/g2plot/esm/plots/gauge'
import type { Gauge as G2Gauge, GaugeOptions } from '@antv/g2plot/esm/plots/gauge'
import { flow, parseJson } from '@/views/chart/components/js/util'
import {
DEFAULT_LABEL,
@ -64,7 +64,7 @@ export class Gauge extends G2PlotChartView<GaugeOptions, G2Gauge> {
}
}
drawChart(drawOptions: G2PlotDrawOptions<G2Gauge>): G2Gauge {
async drawChart(drawOptions: G2PlotDrawOptions<G2Gauge>): Promise<G2Gauge> {
const { chart, container, scale } = drawOptions
if (!chart.data?.series) {
return
@ -96,6 +96,7 @@ export class Gauge extends G2PlotChartView<GaugeOptions, G2Gauge> {
}
}
const options = this.setupOptions(chart, initOptions, { scale })
const { Gauge: G2Gauge } = await import('@antv/g2plot/esm/plots/gauge')
return new G2Gauge(container, options)
}

View File

@ -2,7 +2,7 @@ import {
G2PlotChartView,
G2PlotDrawOptions
} from '@/views/chart/components/js/panel/types/impl/g2plot'
import { ScatterOptions, Scatter as G2Scatter } from '@antv/g2plot/esm/plots/scatter'
import type { ScatterOptions, Scatter as G2Scatter } from '@antv/g2plot/esm/plots/scatter'
import { flow, parseJson, setUpSingleDimensionSeriesColor } from '../../../util'
import { valueFormatter } from '@/views/chart/components/js/formatter'
import { useI18n } from '@/hooks/web/useI18n'
@ -121,7 +121,7 @@ export class Quadrant extends G2PlotChartView<ScatterOptions, G2Scatter> {
return [...new Set(arr.map(JSON.stringify))].map(JSON.parse) as T[]
}
public drawChart(drawOptions: G2PlotDrawOptions<G2Scatter>) {
async drawChart(drawOptions: G2PlotDrawOptions<G2Scatter>): Promise<G2Scatter> {
const { chart, container, action, quadrantDefaultBaseline } = drawOptions
if (!chart.data?.data) {
return
@ -203,6 +203,7 @@ export class Quadrant extends G2PlotChartView<ScatterOptions, G2Scatter> {
}
const options = this.setupOptions(chart, baseOptions)
const { Scatter: G2Scatter } = await import('@antv/g2plot/esm/plots/scatter')
const newChart = new G2Scatter(container, options)
newChart.on('point:click', action)
newChart.on('click', () => quadrantDefaultBaseline(defaultBaselineQuadrant))

View File

@ -1,11 +1,12 @@
import { RadarOptions, Radar as G2Radar } from '@antv/g2plot/esm/plots/radar'
import type { RadarOptions, Radar as G2Radar } from '@antv/g2plot/esm/plots/radar'
import { G2PlotChartView, G2PlotDrawOptions } from '../../types/impl/g2plot'
import { flow, parseJson } from '../../../util'
import { getPadding } from '../../common/common_antv'
import { valueFormatter } from '../../../formatter'
import { Datum } from '@antv/g2plot/esm/types/common'
import type { Datum } from '@antv/g2plot/esm/types/common'
import { useI18n } from '@/hooks/web/useI18n'
import { DEFAULT_LABEL } from '@/views/chart/components/editor/util/chart'
import { Group } from '@antv/g-canvas'
const { t } = useI18n()
@ -59,7 +60,7 @@ export class Radar extends G2PlotChartView<RadarOptions, G2Radar> {
}
}
public drawChart(drawOptions: G2PlotDrawOptions<G2Radar>): G2Radar {
async drawChart(drawOptions: G2PlotDrawOptions<G2Radar>): Promise<G2Radar> {
const { chart, container, action } = drawOptions
if (!chart.data?.data) {
return
@ -112,6 +113,7 @@ export class Radar extends G2PlotChartView<RadarOptions, G2Radar> {
]
}
const options = this.setupOptions(chart, baseOptions)
const { Radar: G2Radar } = await import('@antv/g2plot/esm/plots/radar')
const newChart = new G2Radar(container, options)
newChart.on('point:click', action)
return newChart
@ -149,7 +151,7 @@ export class Radar extends G2PlotChartView<RadarOptions, G2Radar> {
return
}
const value = valueFormatter(data.value, labelCfg.formatterCfg)
const group = new G2PlotChartView.engine.Group({})
const group = new Group({})
group.addShape({
type: 'text',
attrs: {

View File

@ -2,7 +2,7 @@ import {
G2PlotChartView,
G2PlotDrawOptions
} from '@/views/chart/components/js/panel/types/impl/g2plot'
import { Sankey, SankeyOptions } from '@antv/g2plot/esm/plots/sankey'
import type { Sankey, SankeyOptions } from '@antv/g2plot/esm/plots/sankey'
import { getPadding, setGradientColor } from '@/views/chart/components/js/panel/common/common_antv'
import { cloneDeep, get } from 'lodash-es'
import { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util'
@ -95,7 +95,7 @@ export class RangeBar extends G2PlotChartView<SankeyOptions, Sankey> {
]
}
drawChart(drawOptions: G2PlotDrawOptions<Sankey>): Sankey {
async drawChart(drawOptions: G2PlotDrawOptions<Sankey>): Promise<Sankey> {
const { chart, container, action } = drawOptions
if (!chart.data?.data?.length) {
return
@ -158,7 +158,7 @@ export class RangeBar extends G2PlotChartView<SankeyOptions, Sankey> {
}
const options = this.setupOptions(chart, initOptions)
const { Sankey } = await import('@antv/g2plot/esm/plots/sankey')
// 开始渲染
const newChart = new Sankey(container, options)

View File

@ -2,7 +2,7 @@ import {
G2PlotChartView,
G2PlotDrawOptions
} from '@/views/chart/components/js/panel/types/impl/g2plot'
import { ScatterOptions, Scatter as G2Scatter } from '@antv/g2plot/esm/plots/scatter'
import type { ScatterOptions, Scatter as G2Scatter } from '@antv/g2plot/esm/plots/scatter'
import { flow, parseJson } from '../../../util'
import { valueFormatter } from '../../../formatter'
import { getPadding } from '../../common/common_antv'
@ -85,7 +85,7 @@ export class Scatter extends G2PlotChartView<ScatterOptions, G2Scatter> {
limit: 1
}
}
public drawChart(drawOptions: G2PlotDrawOptions<G2Scatter>) {
async drawChart(drawOptions: G2PlotDrawOptions<G2Scatter>): Promise<G2Scatter> {
const { chart, container, action } = drawOptions
if (!chart.data?.data) {
return
@ -131,6 +131,7 @@ export class Scatter extends G2PlotChartView<ScatterOptions, G2Scatter> {
]
}
const options = this.setupOptions(chart, baseOptions)
const { Scatter: G2Scatter } = await import('@antv/g2plot/esm/plots/scatter')
const newChart = new G2Scatter(container, options)
newChart.on('point:click', action)
return newChart

View File

@ -55,7 +55,7 @@ export class Treemap extends G2PlotChartView<TreemapOptions, G2Treemap> {
}
}
public drawChart(drawOptions: G2PlotDrawOptions<G2Treemap>): G2Treemap {
async drawChart(drawOptions: G2PlotDrawOptions<G2Treemap>): Promise<G2Treemap> {
const { chart, container, action } = drawOptions
if (!chart.data?.data?.length) {
return
@ -102,6 +102,7 @@ export class Treemap extends G2PlotChartView<TreemapOptions, G2Treemap> {
]
}
const options = this.setupOptions(chart, baseOptions)
const { Treemap: G2Treemap } = await import('@antv/g2plot/esm/plots/treemap')
const newChart = new G2Treemap(container, options)
newChart.on('polygon:click', action)
return newChart

View File

@ -2,7 +2,7 @@ import {
G2PlotChartView,
G2PlotDrawOptions
} from '@/views/chart/components/js/panel/types/impl/g2plot'
import { WordCloud as G2WordCloud, WordCloudOptions } from '@antv/g2plot/esm/plots/word-cloud'
import type { WordCloud as G2WordCloud, WordCloudOptions } from '@antv/g2plot/esm/plots/word-cloud'
import { flow, parseJson } from '@/views/chart/components/js/util'
import { getPadding } from '@/views/chart/components/js/panel/common/common_antv'
import { valueFormatter } from '@/views/chart/components/js/formatter'
@ -56,7 +56,7 @@ export class WordCloud extends G2PlotChartView<WordCloudOptions, G2WordCloud> {
limit: 1
}
}
drawChart(drawOptions: G2PlotDrawOptions<G2WordCloud>): G2WordCloud {
async drawChart(drawOptions: G2PlotDrawOptions<G2WordCloud>): Promise<G2WordCloud> {
const { chart, container, action } = drawOptions
if (chart?.data) {
// data
@ -80,6 +80,7 @@ export class WordCloud extends G2PlotChartView<WordCloudOptions, G2WordCloud> {
interactions: []
}
const options = this.setupOptions(chart, initOptions)
const { WordCloud: G2WordCloud } = await import('@antv/g2plot/esm/plots/word-cloud')
const newChart = new G2WordCloud(container, options)
newChart.on('point:click', param => {
action({ x: param.x, y: param.y, data: { data: param.data.data.datum } })

View File

@ -2,7 +2,7 @@ import {
G2PlotChartView,
G2PlotDrawOptions
} from '@/views/chart/components/js/panel/types/impl/g2plot'
import { Pie as G2Pie, PieOptions } from '@antv/g2plot/esm/plots/pie'
import type { Pie as G2Pie, PieOptions } from '@antv/g2plot/esm/plots/pie'
import {
flow,
hexColorToRGBA,
@ -20,7 +20,7 @@ import {
PIE_EDITOR_PROPERTY,
PIE_EDITOR_PROPERTY_INNER
} from '@/views/chart/components/js/panel/charts/pie/common'
import { Datum } from '@antv/g2plot/esm/types/common'
import type { Datum } from '@antv/g2plot/esm/types/common'
import { add } from 'mathjs'
import isEmpty from 'lodash-es/isEmpty'
import { cloneDeep } from 'lodash-es'
@ -35,7 +35,7 @@ export class Pie extends G2PlotChartView<PieOptions, G2Pie> {
}
axisConfig = PIE_AXIS_CONFIG
drawChart(drawOptions: G2PlotDrawOptions<G2Pie>): G2Pie {
async drawChart(drawOptions: G2PlotDrawOptions<G2Pie>): Promise<G2Pie> {
const { chart, container, action } = drawOptions
if (!chart.data?.data?.length) {
return
@ -114,7 +114,7 @@ export class Pie extends G2PlotChartView<PieOptions, G2Pie> {
}
}
const options = this.setupOptions(chart, initOptions)
const { Pie: G2Pie } = await import('@antv/g2plot/esm/plots/pie')
const newChart = new G2Pie(container, options)
newChart.on('interval:click', action)
return newChart

View File

@ -26,7 +26,7 @@ export class Rose extends G2PlotChartView<RoseOptions, G2Rose> {
propertyInner: EditorPropertyInner = PIE_EDITOR_PROPERTY_INNER
axisConfig = PIE_AXIS_CONFIG
drawChart(drawOptions: G2PlotDrawOptions<G2Rose>): G2Rose {
async drawChart(drawOptions: G2PlotDrawOptions<G2Rose>): Promise<G2Rose> {
const { chart, container, action } = drawOptions
if (!chart?.data?.data?.length) {
return
@ -79,9 +79,8 @@ export class Rose extends G2PlotChartView<RoseOptions, G2Rose> {
}
}
const options = this.setupOptions(chart, baseOptions)
// custom color
// options.color = antVCustomColor(chart)
const { Rose: G2Rose } = await import('@antv/g2plot/esm/plots/rose')
// 开始渲染
const plot = new G2Rose(container, options)

View File

@ -1,5 +1,5 @@
import { PickOptions } from '@antv/g2plot/esm/core/plot'
import { Plot } from '@antv/g2plot/esm/core/plot'
import type { PickOptions } from '@antv/g2plot/esm/core/plot'
import type { Plot } from '@antv/g2plot/esm/core/plot'
import {
getAnalyse,
getAnalyseHorizontal,
@ -18,7 +18,7 @@ import {
ChartLibraryType,
ChartWrapper
} from '@/views/chart/components/js/panel/types'
import { getEngine } from '@antv/g2/esm/core'
import {
getColor,
getGroupColor,
@ -79,14 +79,12 @@ export abstract class G2PlotChartView<
O extends PickOptions = PickOptions,
P extends Plot<O> = Plot<O>
> extends AntVAbstractChartView {
protected static engine = getEngine('canvas')
/**
* 根据参数构建图表对象然后返回
* @param drawOptions 图表配置参数
* @return 生成的图表对象类型为 Plot 的子类
*/
public abstract drawChart(drawOptions: G2PlotDrawOptions<P>): G2PlotWrapper<O, P> | P
public abstract drawChart(drawOptions: G2PlotDrawOptions<P>): G2PlotWrapper<O, P> | P | Promise<P>
protected configTheme(chart: Chart, options: O): O {
const theme = getTheme(chart)

View File

@ -1,4 +1,4 @@
import { Scene } from '@antv/l7-scene'
import type { Scene } from '@antv/l7-scene'
import {
AntVAbstractChartView,
AntVDrawOptions,
@ -7,7 +7,7 @@ import {
} from '@/views/chart/components/js/panel/types'
import { cloneDeep, defaultsDeep } from 'lodash-es'
import { parseJson } from '@/views/chart/components/js/util'
import { ILayer } from '@antv/l7plot'
import type { ILayer } from '@antv/l7plot'
import {
configL7Label,
configL7Tooltip,

View File

@ -1,7 +1,7 @@
import { ViewLevel } from '@antv/l7plot/dist/esm/plots/choropleth/types'
import { FeatureCollection } from '@antv/l7plot/dist/esm/plots/choropleth/types'
import { PlotOptions } from '@antv/l7plot/dist/esm/types/plot'
import { Plot as L7Plot } from '@antv/l7plot/dist/esm/core/plot'
import type { ViewLevel } from '@antv/l7plot/dist/esm/plots/choropleth/types'
import type { FeatureCollection } from '@antv/l7plot/dist/esm/plots/choropleth/types'
import type { PlotOptions } from '@antv/l7plot/dist/esm/types/plot'
import type { Plot as L7Plot } from '@antv/l7plot/dist/esm/core/plot'
import {
configL7Label,
configL7Legend,

View File

@ -3,7 +3,7 @@ import {
AntVDrawOptions,
ChartLibraryType
} from '@/views/chart/components/js/panel/types'
import {
import type {
S2Theme,
SpreadSheet,
Style,

View File

@ -225,7 +225,7 @@ const renderChart = async (view, callback?) => {
await renderL7(chart, chartView as L7ChartView<any, any>, callback)
break
case ChartLibraryType.G2_PLOT:
renderG2Plot(chart, chartView as G2PlotChartView<any, any>)
await renderG2Plot(chart, chartView as G2PlotChartView<any, any>)
callback?.()
break
default:
@ -233,9 +233,9 @@ const renderChart = async (view, callback?) => {
}
}
let myChart = null
const renderG2Plot = (chart, chartView: G2PlotChartView<any, any>) => {
const renderG2Plot = async (chart, chartView: G2PlotChartView<any, any>) => {
myChart?.destroy()
myChart = chartView.drawChart({
myChart = await chartView.drawChart({
chartObj: myChart,
container: containerId,
chart: chart,

View File

@ -363,34 +363,32 @@ const confirmEditUnion = () => {
}, [])
if (!!idArr.length) {
ElMessageBox.confirm(
`${t('data_set.field')}${allfields.value
ElMessageBox.confirm('字段选择', {
confirmButtonText: t('dataset.confirm'),
cancelButtonText: t('common.cancel'),
showCancelButton: true,
tip: `${t('data_set.field')}: ${allfields.value
.filter(ele => [...new Set(idArr)].includes(ele.id) && ele.extField !== 2)
.map(ele => ele.name)
.join(',')}${t('data_set.want_to_continue')}`,
{
confirmButtonText: t('dataset.confirm'),
cancelButtonText: t('common.cancel'),
showCancelButton: true,
confirmButtonType: 'danger',
type: 'warning',
autofocus: false,
showClose: false,
callback: (action: Action) => {
if (action === 'confirm') {
delUpdateDsFields(currentNode.value.id, state.nodeList)
const [fir] = state.nodeList
if (fir.isShadow) {
delete fir.isShadow
}
closeEditUnion()
nextTick(() => {
emits('updateAllfields')
})
.join(',')}, 未被勾选, 与其相关的计算字段将被删除确认删除`,
confirmButtonType: 'danger',
type: 'warning',
autofocus: false,
showClose: false,
callback: (action: Action) => {
if (action === 'confirm') {
delUpdateDsFields(currentNode.value.id, state.nodeList)
const [fir] = state.nodeList
if (fir.isShadow) {
delete fir.isShadow
}
closeEditUnion()
nextTick(() => {
emits('updateAllfields')
})
}
}
)
})
return
}
}
@ -449,32 +447,26 @@ const handleCommand = (ele, command) => {
return pre
}, [])
fakeDelId = []
if (!!idArr.length) {
ElMessageBox.confirm(
`${t('field.want_to_continue')}${allfields.value
.filter(ele => [...new Set(idArr)].includes(ele.id) && ele.extField !== 2)
.map(ele => ele.name)
.join(',')}${t('data_set.want_to_continue')}`,
{
confirmButtonText: t('dataset.confirm'),
cancelButtonText: t('common.cancel'),
showCancelButton: true,
confirmButtonType: 'danger',
type: 'warning',
autofocus: false,
showClose: false,
callback: (action: Action) => {
if (action === 'confirm') {
delNode(ele.id, state.nodeList)
nextTick(() => {
emits('addComplete')
emits('updateAllfields')
})
}
ElMessageBox.confirm(`确定要删除 ${ele.tableName}`, {
confirmButtonText: t('dataset.confirm'),
cancelButtonText: t('common.cancel'),
showCancelButton: true,
tip: '删除后被关联的表或sql片段将被删除与其相关的计算字段也将被删除。',
confirmButtonType: 'danger',
type: 'warning',
autofocus: false,
showClose: false,
callback: (action: Action) => {
if (action === 'confirm') {
delNode(ele.id, state.nodeList)
nextTick(() => {
emits('addComplete')
emits('updateAllfields')
})
}
}
)
})
return
}
}
@ -531,6 +523,10 @@ const dfsNodeFieldBack = (list, { originName, datasetTableId }) => {
})
}
const dfsNodeFieldBackReal = ele => {
dfsNodeFieldBack(state.nodeList, ele)
}
const menuList = [
{
svgName: 'icon_text-box_outlined',
@ -1014,7 +1010,7 @@ defineExpose({
getNodeList,
setStateBack,
notConfirm,
dfsNodeFieldBack,
dfsNodeFieldBackReal,
initState,
setChangeStatus,
crossDatasources

View File

@ -467,8 +467,20 @@ const delFieldByIdFake = (arr, fakeAllfields) => {
}
const deleteField = item => {
ElMessageBox.confirm(t('dataset.confirm_delete'), {
let tip = ''
const idArr = allfields.value.reduce((pre, next) => {
if (next.extField !== 2) return pre
const idMap = next.originName.match(/\[(.+?)\]/g) || []
const result = idMap.map(itm => {
return itm.slice(1, -1)
})
pre = [...result, ...pre]
return pre
}, [])
tip = idArr.includes(item.id) ? `如果该字段被删除,与其相关的计算字段将被删除,确认删除?` : ''
ElMessageBox.confirm(`确认删除字段 ${item.name}`, {
confirmButtonText: t('dataset.confirm'),
tip,
cancelButtonText: t('common.cancel'),
showCancelButton: true,
confirmButtonType: 'danger',
@ -478,7 +490,7 @@ const deleteField = item => {
callback: (action: Action) => {
if (action === 'confirm') {
delFieldById([item.id])
datasetDrag.value.dfsNodeFieldBack(datasetDrag.value.getNodeList(), item)
datasetDrag.value.dfsNodeFieldBackReal(item)
ElMessage({
message: t('chart.delete_success'),
type: 'success'
@ -855,30 +867,28 @@ const confirmEditUnion = () => {
return pre
}, [])
ElMessageBox.confirm(
`${t('data_set.field')}${allfields.value
ElMessageBox.confirm('字段选择', {
confirmButtonText: t('dataset.confirm'),
cancelButtonText: t('common.cancel'),
showCancelButton: true,
tip: `${t('data_set.field')}: ${allfields.value
.filter(ele => [...new Set(idArr)].includes(ele.id) && ele.extField !== 2)
.map(ele => ele.name)
.join(',')}${t('data_set.want_to_continue')}`,
{
confirmButtonText: t('dataset.confirm'),
cancelButtonText: t('common.cancel'),
showCancelButton: true,
confirmButtonType: 'danger',
type: 'warning',
autofocus: false,
showClose: false,
callback: (action: Action) => {
if (action === 'confirm') {
datasetDrag.value.setStateBack(top, bottom)
setFieldAll()
editUnion.value = false
addComplete()
datasetDrag.value.setChangeStatus(to, from)
}
.join(',')}, 未被勾选, 与其相关的计算字段将被删除确认删除`,
confirmButtonType: 'danger',
type: 'warning',
autofocus: false,
showClose: false,
callback: (action: Action) => {
if (action === 'confirm') {
datasetDrag.value.setStateBack(top, bottom)
setFieldAll()
editUnion.value = false
addComplete()
datasetDrag.value.setChangeStatus(to, from)
}
}
)
})
return
}

View File

@ -14,6 +14,7 @@ import { CustomPassword } from '@/components/custom-password'
import { ElForm, ElMessage, ElMessageBox } from 'element-plus-secondary'
import Cron from '@/components/cron/src/Cron.vue'
import { ComponentPublicInstance } from 'vue'
import { XpackComponent } from '@/components/plugin'
const { t } = useI18n()
const prop = defineProps({
form: {
@ -28,6 +29,7 @@ const prop = defineProps({
configuration?: Configuration
apiConfiguration?: ApiConfiguration[]
paramsConfiguration?: ApiConfiguration[]
enableDataFill?: boolean
}>({
id: 0,
name: '',
@ -340,16 +342,16 @@ const setItemRef = (ele: ComponentPublicInstance | null | Element) => {
}
const copyItem = (item?: ApiConfiguration) => {
var newItem = JSON.parse(JSON.stringify(item))
const newItem = JSON.parse(JSON.stringify(item))
newItem.deTableName = ''
newItem.serialNumber =
form.value.apiConfiguration[form.value.apiConfiguration.length - 1].serialNumber + 1
var reg = new RegExp(item.name + '_copy_' + '([0-9]*)', 'gim')
var number = 0
for (var i = 1; i < form.value.apiConfiguration.length; i++) {
var match = form.value.apiConfiguration[i].name.match(reg)
const reg = new RegExp(item.name + '_copy_' + '([0-9]*)', 'gim')
let number = 0
for (let i = 1; i < form.value.apiConfiguration.length; i++) {
const match = form.value.apiConfiguration[i].name.match(reg)
if (match !== null) {
var num = match[0].substring(
const num = match[0].substring(
form.value.apiConfiguration[i].name.length + 5,
match[0].length - 1
)
@ -413,7 +415,7 @@ const resetForm = () => {
}
const returnItem = apiItem => {
var find = false
let find = false
if (apiItem.type !== 'params') {
apiItem.status = 'Success'
for (let i = 0; i < form.value.apiConfiguration.length; i++) {
@ -1227,6 +1229,12 @@ defineExpose({
</el-col>
</el-row>
</template>
<!-- 数据填报 -->
<XpackComponent
:form="form"
jsname="L2NvbXBvbmVudC9kYXRhLWZpbGxpbmcvRGF0YXNvdXJjZUVuYWJsZURhdGFGaWxsaW5n"
/>
</template>
</el-form>
<el-form

View File

@ -432,7 +432,7 @@ const saveDS = () => {
return
} else if (currentDsType.value === 'API') {
for (var i = 0; i < request.apiConfiguration.length; i++) {
for (let i = 0; i < request.apiConfiguration.length; i++) {
if (
request.apiConfiguration[i].deTableName === '' ||
request.apiConfiguration[i].deTableName === undefined ||
@ -445,7 +445,7 @@ const saveDS = () => {
uuid.v1().replaceAll('-', '').substring(0, 10)
}
request.apiConfiguration[i].jsonFields = []
for (var j = 0; j < request.apiConfiguration[i].fields.length; j++) {
for (let j = 0; j < request.apiConfiguration[i].fields.length; j++) {
request.apiConfiguration[i].fields[j].value = []
}
}

View File

@ -366,7 +366,8 @@ const defaultInfo = {
configuration: null,
syncSetting: null,
apiConfiguration: [],
weight: 0
weight: 0,
enableDataFill: false
}
const nodeInfo = reactive<Node>(cloneDeep(defaultInfo))
const infoList = computed(() => {
@ -504,7 +505,8 @@ const handleNodeClick = data => {
fileName,
size,
description,
lastSyncTime
lastSyncTime,
enableDataFill
} = res.data
if (configuration) {
configuration = JSON.parse(Base64.decode(configuration))
@ -531,7 +533,8 @@ const handleNodeClick = data => {
apiConfiguration: apiConfigurationStr,
paramsConfiguration: paramsStr,
weight: data.weight,
lastSyncTime
lastSyncTime,
enableDataFill
})
activeTab.value = ''
activeName.value = 'config'
@ -628,7 +631,8 @@ const editDatasource = (editType?: number) => {
fileName,
size,
description,
lastSyncTime
lastSyncTime,
enableDataFill
} = res.data
if (configuration) {
configuration = JSON.parse(Base64.decode(configuration))
@ -656,6 +660,7 @@ const editDatasource = (editType?: number) => {
apiConfiguration: apiConfigurationStr,
paramsConfiguration: paramsStr,
lastSyncTime,
enableDataFill,
isPlugin: arr && arr.length > 0,
staticMap: arr[0]?.staticMap
})

View File

@ -15,6 +15,7 @@ import ShareGrid from '@/views/share/share/ShareGrid.vue'
import ShareHandler from '@/views/share/share/ShareHandler.vue'
import { useAppStoreWithOut } from '@/store/modules/app'
import { useEmbedded } from '@/store/modules/embedded'
import { XpackComponent } from '@/components/plugin'
const userStore = useUserStoreWithOut()
const { resolve } = useRouter()
const { t } = useI18n()
@ -139,6 +140,10 @@ const tablePaneList = ref([
{ title: t('visualization.share_out'), name: 'share', disabled: false }
])
const loadedDataFilling = data => {
tablePaneList.value.push(data)
}
const busiAuthList = getBusiListWithPermission()
onMounted(() => {
!!busiAuthList.length &&
@ -419,6 +424,14 @@ const getEmptyDesc = (): string => {
</el-table-column>
</GridTable>
</div>
<XpackComponent
jsname="L21lbnUvZGF0YS9kYXRhLWZpbGxpbmcvZmlsbC9UYWJQYW5l"
@loaded="loadedDataFilling"
/>
<XpackComponent
jsname="L21lbnUvZGF0YS9kYXRhLWZpbGxpbmcvZmlsbC9UYWJQYW5lVGFibGU="
v-if="activeName === 'data-filling'"
/>
</div>
<el-empty
class="dashboard-type"

@ -1 +1 @@
Subproject commit 11240f0a32fc1916409c82580e79fb17bb7988eb
Subproject commit 4d92c0a241e569ff4060545584bd2d7d56c79016

View File

@ -32,6 +32,11 @@ function check_and_prepare_env_params() {
cd ${CURRENT_DIR}
if [ -f /usr/bin/dectl ]; then
v2_version=$(dectl version | head -n 2 | grep "v2.")
if [[ -z $v2_version ]];then
echo "系统当前版本不是 DataEase v2 版本系列,不支持升级到 v2请检查离线包版本。"
exit 1;
fi
# 获取已安装的 DataEase 的运行目录
DE_BASE=$(grep "^DE_BASE=" /usr/bin/dectl | cut -d'=' -f2)
DE_BASE_OLD=$DE_BASE
@ -46,12 +51,6 @@ function check_and_prepare_env_params() {
fi
INSTALL_TYPE='upgrade'
v2_version=$(dectl version | head -n 2 | grep "v2.")
if [[ -z $v2_version ]];then
echo "系统当前版本不是 DataEase v2 版本系列,不支持升级到 v2请检查离线包版本。"
exit 1;
fi
fi
set -a

View File

@ -74,6 +74,9 @@ public interface DatasourceApi {
@GetMapping("/get/{datasourceId}")
DatasourceDTO get(@PathVariable("datasourceId") Long datasourceId) throws DEException;
DatasourceDTO innerGet(Long datasourceId) throws DEException;
List<DatasourceDTO> innerList(List<Long> ids) throws DEException;
@DePermit({"#p0+':read'"})
@GetMapping("/hidePw/{datasourceId}")
DatasourceDTO hidePw(@PathVariable("datasourceId") Long datasourceId) throws DEException;

View File

@ -27,5 +27,7 @@ public class ReportGridVO implements Serializable {
private String creator;
private String updater;
private Long createTime;
}

View File

@ -0,0 +1,111 @@
package io.dataease.api.xpack.dataFilling;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.dataease.api.report.dto.ReportInstanceMsgRequest;
import io.dataease.api.report.vo.ReportGridVO;
import io.dataease.api.xpack.dataFilling.dto.*;
import io.dataease.auth.DeApiPath;
import io.dataease.exception.DEException;
import io.dataease.extensions.datasource.dto.SimpleDatasourceDTO;
import io.dataease.model.BusiNodeRequest;
import io.dataease.model.BusiNodeVO;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
import java.util.Map;
import static io.dataease.constant.AuthResourceEnum.DATA_FILLING;
@Tag(name = "数据填报")
@ApiSupport(order = 1000, author = "fit2cloud-someone")
@DeApiPath(value = "/data-filling", rt = DATA_FILLING)
public interface DataFillingApi {
@PostMapping("tree")
List<BusiNodeVO> tree(@RequestBody BusiNodeRequest request) throws DEException;
@GetMapping("/get/{id}")
DataFillingDTO get(@PathVariable("id") Long id);
@PostMapping("/move")
DataFillingDTO move(@RequestBody DataFillingDTO dataFillingDTO);
@PostMapping("/save")
DataFillingDTO save(@RequestBody DataFillingDTO dataFillingDTO) throws Exception;
@PostMapping("/rename")
DataFillingDTO rename(@RequestBody DataFillingDTO dataFillingDTO);
@GetMapping("delete/{id}")
void delete(@PathVariable("id") Long id);
@GetMapping("/datasource/list")
List<SimpleDatasourceDTO> listDatasourceList();
@PostMapping("/form/{optionDatasource}/options")
List<ColumnOption> listColumnData(@PathVariable("optionDatasource") Long optionDatasource, @RequestBody DatasourceOptionsRequest request) throws Exception;
@PostMapping("/form/{id}/tableData")
DataFillFormTableDataResponse tableData(@PathVariable Long id, @RequestBody DataFillFormTableDataRequest request) throws Exception;
@GetMapping("/form/{formId}/delete/{id}")
void deleteRowData(@PathVariable Long formId, @PathVariable Long id) throws Exception;
@PostMapping("/form/{formId}/batch-delete")
void batchDeleteRowData(@PathVariable Long formId, @RequestBody List<Long> ids) throws Exception;
@PostMapping("/form/{formId}/rowData/save")
DataFillFormTableDataResponse saveRowData(@PathVariable Long formId, @RequestBody Map<String, Object> data) throws Exception;
@GetMapping("/task/info/{taskId}")
TaskInfoVO info(@PathVariable("taskId") Long taskId);
@PostMapping("/task/save")
Long save(@RequestBody TaskInfoVO task);
@PostMapping("/task/logMsg")
String logMsg(@RequestBody ReportInstanceMsgRequest request);
@PostMapping("/task/page/{goPage}/{pageSize}")
IPage<ReportGridVO> taskPager(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody DfTaskInfoRequest request);
@PostMapping("/sub-task/page/{goPage}/{pageSize}")
IPage<DfSubTaskVo> subTaskPager(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody DfSubTaskInfoRequest request);
@PostMapping("/task/delete")
void batchDeleteTask(@RequestBody List<Long> ids) throws Exception;
@GetMapping("/task/{id}/stop")
void stopTask(@PathVariable Long id) throws Exception;
@GetMapping("/task/{id}/start")
void startTask(@PathVariable Long id) throws Exception;
@PostMapping("/sub-task/delete")
void batchDeleteSubTask(@RequestBody List<Long> ids) throws Exception;
@GetMapping("/sub-task/{id}/users/list/{type}")
List<Map<String, Object>> listSubTaskUser(@PathVariable Long id, @PathVariable String type) throws Exception;
@PostMapping("/user-task")
List<DfUserTaskVo> listUserTask(@RequestBody DfUserTaskRequest request) throws Exception;
@GetMapping("/user-task/list/{id}")
DfUserTaskData listUserTaskData(@PathVariable Long id) throws Exception;
@PostMapping("/user-task/saveData/{id}")
DataFillFormTableDataResponse saveFormRowData(@PathVariable Long id, @RequestBody Map<String, Object> data) throws Exception;
@PostMapping("/log/page/{goPage}/{pageSize}")
IPage<DfCommitLog> taskPager(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody DfCommitLogRequest request);
}

View File

@ -0,0 +1,23 @@
package io.dataease.api.xpack.dataFilling.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ColumnOption implements Serializable {
@Serial
private static final long serialVersionUID = -422787778573500470L;
private String name;
private Object value;
}

View File

@ -0,0 +1,31 @@
package io.dataease.api.xpack.dataFilling.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
@Data
@Accessors(chain = true)
public class DataFillFormTableDataRequest implements Serializable {
@Serial
private static final long serialVersionUID = -314618516232771747L;
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
private long currentPage;
private long pageSize;
private boolean withoutLogs = false;
private List<String> primaryKeyValueList;
}

View File

@ -0,0 +1,28 @@
package io.dataease.api.xpack.dataFilling.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serial;
import java.io.Serializable;
@Data
@Accessors(chain = true)
public class DataFillFormTableDataResponse implements Serializable {
@Serial
private static final long serialVersionUID = -6463885075511811532L;
private Object data;
private String fields;
private long total;
private long currentPage;
private long pageSize;
private String key;
}

View File

@ -0,0 +1,91 @@
package io.dataease.api.xpack.dataFilling.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
@Data
public class DataFillingDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
/**
* 名称
*/
private String name;
/**
* 父级ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long pid;
/**
* folder/form 目录或文件夹
*/
private String nodeType;
/**
* 表名
*/
private String tableName;
/**
* 数据源
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long datasource;
/**
* 表单内容
*/
private String forms;
/**
* 是否创建索引
*/
private Boolean createIndex;
/**
* 索引
*/
private String tableIndexes;
/**
* 创建人
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long createBy;
/**
* 创建时间
*/
private Long createTime;
/**
* 更新人
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long updateBy;
/**
* 更新时间
*/
private Long updateTime;
private String creator;
private String updater;
}

View File

@ -0,0 +1,11 @@
package io.dataease.api.xpack.dataFilling.dto;
import lombok.Getter;
@Getter
public class DatasourceOptionsRequest {
private String optionTable;
private String optionColumn;
private String optionOrder;
}

View File

@ -0,0 +1,37 @@
package io.dataease.api.xpack.dataFilling.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serial;
import java.io.Serializable;
@Data
@Accessors(chain = true)
public class DfCommitLog implements Serializable {
@Serial
private static final long serialVersionUID = 3175509273615697110L;
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@JsonSerialize(using = ToStringSerializer.class)
private Long formId;
@JsonSerialize(using = ToStringSerializer.class)
private Long dataId;
/**
* 操作 0删除 1插入 2更新
*/
private Integer operate;
private Long commitBy;
private String committer;
private Long commitTime;
}

View File

@ -0,0 +1,17 @@
package io.dataease.api.xpack.dataFilling.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
@Data
public class DfCommitLogRequest implements Serializable {
@Serial
private static final long serialVersionUID = 8186544152722934919L;
private Long formId;
private Integer operate;
}

View File

@ -0,0 +1,18 @@
package io.dataease.api.xpack.dataFilling.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
@Data
public class DfSubTaskInfoRequest implements Serializable {
@Serial
private static final long serialVersionUID = 3478936079850972546L;
@JsonSerialize(using = ToStringSerializer.class)
private Long taskId;
}

View File

@ -0,0 +1,56 @@
package io.dataease.api.xpack.dataFilling.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
@Data
@Accessors(chain = true)
public class DfSubTaskVo implements Serializable {
@Serial
private static final long serialVersionUID = 7440756474905083085L;
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@JsonSerialize(using = ToStringSerializer.class)
private Long taskId;
private Long startTime;
private Long endTime;
/**
* 任务下发状态
*/
private Integer execStatus;
/**
* 任务状态
* 1进行中/ 0已过期 根据endTime判断
*/
private Integer status;
/**
* 所有任务项 subInstance 个数
*/
private int totalCount;
private int unfinishedCount;
/**
* 完成率
* (totalCount - unfinishedCount) / totalCount
*/
private BigDecimal finishedRate;
private int totalUserCount;
private int unfinishedUserCount;
}

View File

@ -0,0 +1,25 @@
package io.dataease.api.xpack.dataFilling.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
@Data
public class DfTaskInfoRequest implements Serializable {
@Serial
private static final long serialVersionUID = 3478936079850972546L;
private List<Long> uidList;
private List<Integer> lastStatusList;
private List<Integer> statusList;
private List<Long> timeList;
private String keyword;
private Boolean timeDesc;
}

View File

@ -0,0 +1,56 @@
package io.dataease.api.xpack.dataFilling.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.dataease.utils.LongArray2StringSerialize;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
@Data
@Accessors(chain = true)
public class DfUserTaskData implements Serializable {
@Serial
private static final long serialVersionUID = -3635512734559897349L;
@Data
@Accessors(chain = true)
public static class DfSubInstance implements Serializable {
@Serial
private static final long serialVersionUID = 4847820854888692033L;
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@JsonSerialize(using = ToStringSerializer.class)
private Long taskId;
@JsonSerialize(using = ToStringSerializer.class)
private Long pid;
@JsonSerialize(using = ToStringSerializer.class)
private Long uid;
@JsonSerialize(using = ToStringSerializer.class)
private Long formId;
@JsonSerialize(using = ToStringSerializer.class)
private Long dataId;
private Long finishTime;
private Integer status;
}
@JsonSerialize(using = ToStringSerializer.class)
private Long formId;
private String formTitle;
@JsonSerialize(using = LongArray2StringSerialize.class)
private List<Long> dataIds;
private List<DfSubInstance> subInstances;
private String form;
private String formExtSetting;
}

View File

@ -0,0 +1,19 @@
package io.dataease.api.xpack.dataFilling.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serial;
import java.io.Serializable;
@Data
@Accessors(chain = true)
public class DfUserTaskRequest implements Serializable {
@Serial
private static final long serialVersionUID = 3930338226463461223L;
private String type;
private String taskName;
}

View File

@ -0,0 +1,42 @@
package io.dataease.api.xpack.dataFilling.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.dataease.utils.LongArray2StringSerialize;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
@Data
@Accessors(chain = true)
public class DfUserTaskVo implements Serializable {
@Serial
private static final long serialVersionUID = 2573431692696582629L;
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@JsonSerialize(using = ToStringSerializer.class)
private Long taskId;
@JsonSerialize(using = ToStringSerializer.class)
private Long formId;
private String taskName;
private Long startTime;
private Long endTime;
private Long finishTime;
@JsonSerialize(using = ToStringSerializer.class)
private Long assignBy;
private String assigner;
}

View File

@ -0,0 +1,38 @@
package io.dataease.api.xpack.dataFilling.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.dataease.utils.LongArray2StringSerialize;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
@Data
@Accessors(chain = true)
public class TaskInfoGridVO implements Serializable {
@Serial
private static final long serialVersionUID = -5178055146669970633L;
@JsonSerialize(using= ToStringSerializer.class)
private Long id;
private String name;
private Long lastExecTime;
private Integer lastExecStatus;
private Integer status;
private Long nextExecTime;
private String creatBy;
private String creator;
private Long createTime;
}

View File

@ -0,0 +1,73 @@
package io.dataease.api.xpack.dataFilling.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.dataease.utils.LongArray2StringSerialize;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
@Data
@Accessors(chain = true)
public class TaskInfoVO implements Serializable {
@Serial
private static final long serialVersionUID = 7074759598819246816L;
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@JsonSerialize(using = ToStringSerializer.class)
private Long formId;
private String name;
private List<Integer> reciFlagList;
@JsonSerialize(using = LongArray2StringSerialize.class)
private List<Long> uidList;
@JsonSerialize(using = LongArray2StringSerialize.class)
private List<Long> ridList;
private Integer fillType;
private Integer fitType;
private String fitColumn;
private Integer rateType;
private String rateVal;
private Long startTime;
private Long endTime;
@JsonSerialize(using = ToStringSerializer.class)
private Long createBy;
private String creator;
private Long createTime;
@JsonSerialize(using = ToStringSerializer.class)
private Long updateBy;
private String updater;
private Long updateTime;
private Integer publishRangeTime;
private Integer publishRangeTimeType;
private Integer status;
private Integer lastExecStatus;
private Long lastExecTime;
private Long nextExecTime;
private String formExtSetting;
}

View File

@ -61,4 +61,8 @@ public interface OrgApi {
@Operation(hidden = true)
@GetMapping("/detail/{oid}")
OrgDetailVO detail(@PathVariable("oid") Long oid);
@Operation(hidden = true)
@GetMapping("/subOrgs")
List<String> subOrgs();
}

View File

@ -190,4 +190,16 @@ public interface UserApi {
@GetMapping("/invalidPwd")
InvalidPwdVO invalidPwd();
@Hidden
@PostMapping("/subOrgUser")
List<UserItem> subOrgUser(@RequestBody List<Long> oidList);
List<Long> getRecipientUserIds(UserReciRequest request);
List<Long> getUserIdByAccount(String account);
List<Long> getUserIdByName(String name);
List<Map<String, Object>> listUserInfosByIds(List<Long> ids);
}

View File

@ -2,7 +2,7 @@ package io.dataease.constant;
public enum AuthResourceEnum {
PANEL(2, 1), SCREEN(3, 2), DATASET(5, 3), DATASOURCE(6, 4), SYSTEM(7, 0), USER(8, 5), ROLE(8, 6), ORG(9, 7), SYNC_DATASOURCE(23, 8), TASK(24, 9), SUMMARY(22, 10);
PANEL(2, 1), SCREEN(3, 2), DATASET(5, 3), DATASOURCE(6, 4), SYSTEM(7, 0), USER(8, 5), ROLE(8, 6), ORG(9, 7), SYNC_DATASOURCE(23, 8), TASK(24, 9), SUMMARY(22, 10), DATA_FILLING(60, 11);
private long menuId;

View File

@ -2,7 +2,7 @@ package io.dataease.constant;
public enum BusiResourceEnum {
PANEL(1), SCREEN(2), DATASET(3), DATASOURCE(4);
PANEL(1), SCREEN(2), DATASET(3), DATASOURCE(4), DATA_FILLING(8);
private int flag;

View File

@ -0,0 +1,29 @@
package io.dataease.constant;
import java.util.Arrays;
public enum DadaFillingFinishTaskEnum {
OPEN(0), FINISHED(1);
private Integer flag;
public Integer getFlag() {
return flag;
}
public void setFlag(Integer flag) {
this.flag = flag;
}
DadaFillingFinishTaskEnum(Integer flag) {
this.flag = flag;
}
DadaFillingFinishTaskEnum() {
}
public static DadaFillingFinishTaskEnum fromValue(Integer flag) {
return Arrays.stream(values()).filter(v -> v.flag.equals(flag)).findFirst().get();
}
}

View File

@ -0,0 +1,23 @@
package io.dataease.utils;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class LongArray2StringSerialize extends JsonSerializer<List<Long>> {
@Override
public void serialize(List<Long> longs, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
List<String> list = new ArrayList<>();
for (Long str : longs) {
if (str != null) {
list.add(str.toString());
}
}
jsonGenerator.writeObject(list);
}
}

View File

@ -89,4 +89,6 @@ public class DatasourceDTO implements Serializable {
* 任务状态
*/
private String taskStatus;
private Boolean enableDataFill;
}

View File

@ -4,6 +4,7 @@ import lombok.Data;
import org.springframework.util.StringUtils;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -24,6 +25,7 @@ public class DatasourceRequest implements Serializable {
private boolean previewData = false;
private boolean totalPageFlag;
private Map<Long, DatasourceSchemaDTO> dsList;
private List<TableFieldWithValue> tableFieldWithValues;
public DatasourceRequest() {
}

View File

@ -0,0 +1,24 @@
package io.dataease.extensions.datasource.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
@Data
public class SimpleDatasourceDTO implements Serializable {
@Serial
private static final long serialVersionUID = 2255370172449547802L;
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@JsonSerialize(using = ToStringSerializer.class)
private Long pid;
private String name;
private String type;
private String typeAlias;
private String status;
private Boolean enableDataFill;
}

View File

@ -19,7 +19,9 @@ public class TableField {
private Integer deExtractType;
private int extField;
private String jsonPath;
private boolean primary;
List<Object> value;
private int inCount;
}

View File

@ -0,0 +1,29 @@
package io.dataease.extensions.datasource.dto;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import java.io.Serial;
import java.io.Serializable;
@Getter
@Setter
@Accessors(chain = true)
public class TableFieldWithValue implements Serializable {
@Serial
private static final long serialVersionUID = -8852504196142402103L;
private Object value;
private String filedName;
private String typeName;
private Integer type;
public static TableFieldWithValue copy(TableFieldWithValue tableFieldWithValue) {
return new TableFieldWithValue()
.setValue(tableFieldWithValue.getValue())
.setFiledName(tableFieldWithValue.getFiledName())
.setTypeName(tableFieldWithValue.getTypeName())
.setType(tableFieldWithValue.getType());
}
}

View File

@ -92,6 +92,11 @@ public abstract class Provider {
*/
public abstract void hidePW(DatasourceDTO datasourceDTO);
public abstract void exec(DatasourceRequest datasourceRequest) throws DEException;
public abstract int executeUpdate(DatasourceRequest datasourceRequest) throws DEException;
@Getter
private static final Map<Long, Integer> lPorts = new HashMap<>();
@Getter