Merge remote-tracking branch 'origin/dev-v2' into dev-v2

This commit is contained in:
wangjiahao 2024-01-22 18:29:38 +08:00
commit c56d811259
24 changed files with 364 additions and 256 deletions

View File

@ -7,4 +7,7 @@ assignees: xuwei-fit2cloud, yayanpei-fit2cloud
--- ---
DataEase 版本:
**请描述您的需求或者改进建议.** **请描述您的需求或者改进建议.**

View File

@ -3,7 +3,7 @@ name: Bug 提交
about: 提交产品缺陷帮助我们更好的改进 about: 提交产品缺陷帮助我们更好的改进
title: "[Bug]" title: "[Bug]"
labels: 状态:待处理 labels: 状态:待处理
assignees: BBchicken-9527, Shenguobin0102, zrfit assignees: BBchicken-9527, Shenguobin0102
--- ---

View File

@ -6,7 +6,6 @@ import io.dataease.api.dataset.dto.DatasetTableDTO;
import io.dataease.api.dataset.dto.SqlVariableDetails; import io.dataease.api.dataset.dto.SqlVariableDetails;
import io.dataease.api.dataset.union.DatasetGroupInfoDTO; import io.dataease.api.dataset.union.DatasetGroupInfoDTO;
import io.dataease.api.dataset.vo.DataSetBarVO; import io.dataease.api.dataset.vo.DataSetBarVO;
import io.dataease.commons.constants.OptConstants;
import io.dataease.constant.LogOT; import io.dataease.constant.LogOT;
import io.dataease.constant.LogST; import io.dataease.constant.LogST;
import io.dataease.dataset.manage.DatasetGroupManage; import io.dataease.dataset.manage.DatasetGroupManage;
@ -44,11 +43,13 @@ public class DatasetTreeServer implements DatasetTreeApi {
return datasetGroupManage.save(dto, false); return datasetGroupManage.save(dto, false);
} }
@DeLog(id = "#p0.id", ot = LogOT.MODIFY, st = LogST.DATASET)
@Override @Override
public DatasetNodeDTO move(DatasetGroupInfoDTO dto) throws Exception { public DatasetNodeDTO move(DatasetGroupInfoDTO dto) throws Exception {
return datasetGroupManage.move(dto); return datasetGroupManage.move(dto);
} }
@DeLog(id = "#p0", ot = LogOT.DELETE, st = LogST.DATASET)
@Override @Override
public void delete(Long id) { public void delete(Long id) {
datasetGroupManage.delete(id); datasetGroupManage.delete(id);

View File

@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import io.dataease.api.ds.vo.DatasourceDTO; import io.dataease.api.ds.vo.DatasourceDTO;
import io.dataease.commons.constants.OptConstants; import io.dataease.commons.constants.OptConstants;
import io.dataease.constant.DataSourceType; import io.dataease.constant.DataSourceType;
import io.dataease.constant.LogOT;
import io.dataease.constant.LogST;
import io.dataease.datasource.dao.auto.entity.CoreDatasource; import io.dataease.datasource.dao.auto.entity.CoreDatasource;
import io.dataease.datasource.dao.auto.mapper.CoreDatasourceMapper; import io.dataease.datasource.dao.auto.mapper.CoreDatasourceMapper;
import io.dataease.datasource.dao.ext.mapper.DataSourceExtMapper; import io.dataease.datasource.dao.ext.mapper.DataSourceExtMapper;
@ -12,6 +14,7 @@ import io.dataease.datasource.dao.ext.po.DataSourceNodePO;
import io.dataease.datasource.dto.DatasourceNodeBO; import io.dataease.datasource.dto.DatasourceNodeBO;
import io.dataease.exception.DEException; import io.dataease.exception.DEException;
import io.dataease.license.config.XpackInteract; import io.dataease.license.config.XpackInteract;
import io.dataease.log.DeLog;
import io.dataease.model.BusiNodeRequest; import io.dataease.model.BusiNodeRequest;
import io.dataease.model.BusiNodeVO; import io.dataease.model.BusiNodeVO;
import io.dataease.operation.manage.CoreOptRecentManage; import io.dataease.operation.manage.CoreOptRecentManage;
@ -25,7 +28,6 @@ import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
@Component @Component
public class DataSourceManage { public class DataSourceManage {
@ -71,12 +73,14 @@ public class DataSourceManage {
return TreeUtils.mergeTree(nodes, BusiNodeVO.class, false); return TreeUtils.mergeTree(nodes, BusiNodeVO.class, false);
} }
@DeLog(id = "#p0.id", pid = "#p0.pid", ot = LogOT.CREATE, st = LogST.DATASOURCE)
@XpackInteract(value = "datasourceResourceTree", before = false) @XpackInteract(value = "datasourceResourceTree", before = false)
public void innerSave(CoreDatasource coreDatasource) { public void innerSave(CoreDatasource coreDatasource) {
coreDatasourceMapper.insert(coreDatasource); coreDatasourceMapper.insert(coreDatasource);
coreOptRecentManage.saveOpt(coreDatasource.getId(), OptConstants.OPT_RESOURCE_TYPE.DATASOURCE,OptConstants.OPT_TYPE.NEW); coreOptRecentManage.saveOpt(coreDatasource.getId(), OptConstants.OPT_RESOURCE_TYPE.DATASOURCE, OptConstants.OPT_TYPE.NEW);
} }
@DeLog(id = "#p0.id", ot = LogOT.MODIFY, st = LogST.DATASOURCE)
@XpackInteract(value = "datasourceResourceTree", before = false) @XpackInteract(value = "datasourceResourceTree", before = false)
public void innerEdit(CoreDatasource coreDatasource) { public void innerEdit(CoreDatasource coreDatasource) {
UpdateWrapper<CoreDatasource> updateWrapper = new UpdateWrapper<>(); UpdateWrapper<CoreDatasource> updateWrapper = new UpdateWrapper<>();
@ -84,9 +88,10 @@ public class DataSourceManage {
coreDatasource.setUpdateTime(System.currentTimeMillis()); coreDatasource.setUpdateTime(System.currentTimeMillis());
coreDatasource.setUpdateBy(AuthUtils.getUser().getUserId()); coreDatasource.setUpdateBy(AuthUtils.getUser().getUserId());
coreDatasourceMapper.update(coreDatasource, updateWrapper); coreDatasourceMapper.update(coreDatasource, updateWrapper);
coreOptRecentManage.saveOpt(coreDatasource.getId(), OptConstants.OPT_RESOURCE_TYPE.DATASOURCE,OptConstants.OPT_TYPE.UPDATE); coreOptRecentManage.saveOpt(coreDatasource.getId(), OptConstants.OPT_RESOURCE_TYPE.DATASOURCE, OptConstants.OPT_TYPE.UPDATE);
} }
@DeLog(id = "#p0.id", ot = LogOT.MODIFY, st = LogST.DATASOURCE)
@XpackInteract(value = "datasourceResourceTree", before = false) @XpackInteract(value = "datasourceResourceTree", before = false)
public void innerEditStatus(CoreDatasource coreDatasource) { public void innerEditStatus(CoreDatasource coreDatasource) {
UpdateWrapper<CoreDatasource> updateWrapper = new UpdateWrapper<>(); UpdateWrapper<CoreDatasource> updateWrapper = new UpdateWrapper<>();
@ -94,6 +99,7 @@ public class DataSourceManage {
coreDatasourceMapper.update(coreDatasource, updateWrapper); coreDatasourceMapper.update(coreDatasource, updateWrapper);
} }
@DeLog(id = "#p0.id", ot = LogOT.MODIFY, st = LogST.DATASOURCE)
@XpackInteract(value = "datasourceResourceTree", before = false) @XpackInteract(value = "datasourceResourceTree", before = false)
public void move(DatasourceDTO dataSourceDTO) { public void move(DatasourceDTO dataSourceDTO) {
Long id = dataSourceDTO.getId(); Long id = dataSourceDTO.getId();
@ -106,6 +112,6 @@ public class DataSourceManage {
sourceData.setPid(dataSourceDTO.getPid()); sourceData.setPid(dataSourceDTO.getPid());
sourceData.setName(dataSourceDTO.getName()); sourceData.setName(dataSourceDTO.getName());
coreDatasourceMapper.updateById(sourceData); coreDatasourceMapper.updateById(sourceData);
coreOptRecentManage.saveOpt(sourceData.getId(), OptConstants.OPT_RESOURCE_TYPE.DATASOURCE,OptConstants.OPT_TYPE.UPDATE); coreOptRecentManage.saveOpt(sourceData.getId(), OptConstants.OPT_RESOURCE_TYPE.DATASOURCE, OptConstants.OPT_TYPE.UPDATE);
} }
} }

View File

@ -14,6 +14,8 @@ import io.dataease.api.ds.vo.*;
import io.dataease.commons.constants.TaskStatus; import io.dataease.commons.constants.TaskStatus;
import io.dataease.commons.utils.CommonThreadPool; import io.dataease.commons.utils.CommonThreadPool;
import io.dataease.constant.DataSourceType; import io.dataease.constant.DataSourceType;
import io.dataease.constant.LogOT;
import io.dataease.constant.LogST;
import io.dataease.dataset.dto.DatasourceSchemaDTO; import io.dataease.dataset.dto.DatasourceSchemaDTO;
import io.dataease.dataset.manage.DatasetDataManage; import io.dataease.dataset.manage.DatasetDataManage;
import io.dataease.dataset.utils.TableUtils; import io.dataease.dataset.utils.TableUtils;
@ -35,6 +37,7 @@ import io.dataease.i18n.Translator;
import io.dataease.job.sechedule.CheckDsStatusJob; import io.dataease.job.sechedule.CheckDsStatusJob;
import io.dataease.job.sechedule.ScheduleManager; import io.dataease.job.sechedule.ScheduleManager;
import io.dataease.license.config.XpackInteract; import io.dataease.license.config.XpackInteract;
import io.dataease.log.DeLog;
import io.dataease.model.BusiNodeRequest; import io.dataease.model.BusiNodeRequest;
import io.dataease.model.BusiNodeVO; import io.dataease.model.BusiNodeVO;
import io.dataease.system.dao.auto.entity.CoreSysSetting; import io.dataease.system.dao.auto.entity.CoreSysSetting;
@ -136,7 +139,7 @@ public class DatasourceServer implements DatasourceApi {
dataSourceManage.move(dataSourceDTO); dataSourceManage.move(dataSourceDTO);
} }
case "rename" -> { case "rename" -> {
if(StringUtils.isEmpty(dataSourceDTO.getName())){ if (StringUtils.isEmpty(dataSourceDTO.getName())) {
DEException.throwException("名称不能为空!"); DEException.throwException("名称不能为空!");
} }
CoreDatasource datasource = datasourceMapper.selectById(dataSourceDTO.getId()); CoreDatasource datasource = datasourceMapper.selectById(dataSourceDTO.getId());
@ -550,6 +553,7 @@ public class DatasourceServer implements DatasourceApi {
return datasourceDTO; return datasourceDTO;
} }
@DeLog(id = "#p0", ot = LogOT.DELETE, st = LogST.DATASOURCE)
@Override @Override
@XpackInteract(value = "datasourceResourceTree", before = false) @XpackInteract(value = "datasourceResourceTree", before = false)
public void delete(Long datasourceId) throws DEException { public void delete(Long datasourceId) throws DEException {

View File

@ -17,8 +17,10 @@ import io.dataease.chart.manage.ChartViewManege;
import io.dataease.commons.constants.DataVisualizationConstants; import io.dataease.commons.constants.DataVisualizationConstants;
import io.dataease.commons.constants.OptConstants; import io.dataease.commons.constants.OptConstants;
import io.dataease.constant.CommonConstants; import io.dataease.constant.CommonConstants;
import io.dataease.constant.LogOT;
import io.dataease.exception.DEException; import io.dataease.exception.DEException;
import io.dataease.license.config.XpackInteract; import io.dataease.license.config.XpackInteract;
import io.dataease.log.DeLog;
import io.dataease.model.BusiNodeRequest; import io.dataease.model.BusiNodeRequest;
import io.dataease.model.BusiNodeVO; import io.dataease.model.BusiNodeVO;
import io.dataease.operation.manage.CoreOptRecentManage; import io.dataease.operation.manage.CoreOptRecentManage;
@ -89,6 +91,7 @@ public class DataVisualizationServer implements DataVisualizationApi {
@Resource @Resource
private VisualizationWatermarkMapper watermarkMapper; private VisualizationWatermarkMapper watermarkMapper;
@DeLog(id = "#p0", ot = LogOT.READ, stExp = "#p1")
@Override @Override
public DataVisualizationVO findCopyResource(Long dvId, String busiFlag) { public DataVisualizationVO findCopyResource(Long dvId, String busiFlag) {
DataVisualizationVO result = findById(dvId, busiFlag); DataVisualizationVO result = findById(dvId, busiFlag);
@ -121,6 +124,7 @@ public class DataVisualizationServer implements DataVisualizationApi {
return null; return null;
} }
@DeLog(id = "#p0.id", pid = "#p0.pid", ot = LogOT.CREATE, stExp = "#p0.type")
@Override @Override
@Transactional @Transactional
public String saveCanvas(DataVisualizationBaseRequest request) { public String saveCanvas(DataVisualizationBaseRequest request) {
@ -133,11 +137,13 @@ public class DataVisualizationServer implements DataVisualizationApi {
visualizationInfo.setSelfWatermarkStatus(0); visualizationInfo.setSelfWatermarkStatus(0);
} }
Long newDvId = coreVisualizationManage.innerSave(visualizationInfo); Long newDvId = coreVisualizationManage.innerSave(visualizationInfo);
request.setId(newDvId);
//保存视图信 //保存视图信
chartDataManage.saveChartViewFromVisualization(request.getComponentData(), newDvId, request.getCanvasViewInfo()); chartDataManage.saveChartViewFromVisualization(request.getComponentData(), newDvId, request.getCanvasViewInfo());
return newDvId.toString(); return newDvId.toString();
} }
@DeLog(id = "#p0.id", ot = LogOT.MODIFY, stExp = "#p0.type")
@Override @Override
@Transactional @Transactional
public void updateCanvas(DataVisualizationBaseRequest request) { public void updateCanvas(DataVisualizationBaseRequest request) {
@ -178,6 +184,7 @@ public class DataVisualizationServer implements DataVisualizationApi {
* @Description: 更新基础信息 * @Description: 更新基础信息
* 为什么单独接口1.基础信息更新频繁数据且数据载量较小2.防止出现更新过多信息的情况造成视图的误删等操作 * 为什么单独接口1.基础信息更新频繁数据且数据载量较小2.防止出现更新过多信息的情况造成视图的误删等操作
*/ */
@DeLog(id = "#p0.id", ot = LogOT.MODIFY, stExp = "#p0.type")
@Override @Override
@Transactional @Transactional
public void updateBase(DataVisualizationBaseRequest request) { public void updateBase(DataVisualizationBaseRequest request) {
@ -191,6 +198,7 @@ public class DataVisualizationServer implements DataVisualizationApi {
/** /**
* @Description: 逻辑删除可视化信息将delete_flag 置为0 * @Description: 逻辑删除可视化信息将delete_flag 置为0
*/ */
@DeLog(id = "#p0", ot = LogOT.DELETE, stExp = "#p1")
@Transactional @Transactional
@Override @Override
public void deleteLogic(Long dvId, String busiFlag) { public void deleteLogic(Long dvId, String busiFlag) {
@ -203,6 +211,7 @@ public class DataVisualizationServer implements DataVisualizationApi {
return coreVisualizationManage.tree(request); return coreVisualizationManage.tree(request);
} }
@DeLog(id = "#p0.id", pid = "#p0.pid", ot = LogOT.MODIFY, stExp = "#p0.type")
@Transactional @Transactional
@Override @Override
public void move(DataVisualizationBaseRequest request) { public void move(DataVisualizationBaseRequest request) {

View File

@ -24,7 +24,7 @@
"axios": "^1.3.3", "axios": "^1.3.3",
"crypto-js": "^4.1.1", "crypto-js": "^4.1.1",
"dayjs": "^1.11.9", "dayjs": "^1.11.9",
"element-plus-secondary": "^0.4.15", "element-plus-secondary": "^0.4.16",
"element-resize-detector": "^1.2.4", "element-resize-detector": "^1.2.4",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"html-to-image": "^1.11.11", "html-to-image": "^1.11.11",

View File

@ -194,6 +194,8 @@ const indicatorSuffixClass = ref<CSSProperties>({
'font-synthesis': 'weight style' 'font-synthesis': 'weight style'
}) })
const showSuffix = ref<boolean>(DEFAULT_INDICATOR_STYLE.suffixEnable)
const suffixContent = ref('') const suffixContent = ref('')
const indicatorNameShow = ref(false) const indicatorNameShow = ref(false)
@ -293,6 +295,7 @@ const renderChart = async view => {
'font-synthesis': 'weight style' 'font-synthesis': 'weight style'
} }
showSuffix.value = customAttr.indicator.suffixEnable
suffixContent.value = defaultTo(customAttr.indicator.suffix, '') suffixContent.value = defaultTo(customAttr.indicator.suffix, '')
} }
if (customAttr.indicatorName && customAttr.indicatorName.show) { if (customAttr.indicatorName && customAttr.indicatorName.show) {
@ -359,7 +362,7 @@ defineExpose({
<div :style="contentStyle"> <div :style="contentStyle">
<div> <div>
<span :style="indicatorClass">{{ formattedResult }}</span> <span :style="indicatorClass">{{ formattedResult }}</span>
<span :style="indicatorSuffixClass">{{ suffixContent }}</span> <span :style="indicatorSuffixClass" v-if="showSuffix">{{ suffixContent }}</span>
</div> </div>
<div v-if="indicatorNameShow"> <div v-if="indicatorNameShow">
<span :style="indicatorNameClass">{{ resultName }}</span> <span :style="indicatorNameClass">{{ resultName }}</span>

View File

@ -5,6 +5,7 @@ import { type DatePickType } from 'element-plus-secondary'
import { getCustomTime } from './time-format' import { getCustomTime } from './time-format'
interface SelectConfig { interface SelectConfig {
timeType: string timeType: string
timeGranularityMultiple: DatePickType
defaultValue: [Date, Date] defaultValue: [Date, Date]
selectValue: [Date, Date] selectValue: [Date, Date]
defaultValueCheck: boolean defaultValueCheck: boolean
@ -25,6 +26,7 @@ const props = defineProps({
type: Object as PropType<SelectConfig>, type: Object as PropType<SelectConfig>,
default: () => { default: () => {
return { return {
timeGranularityMultiple: 'datetimerange',
defaultValue: [], defaultValue: [],
selectValue: [], selectValue: [],
timeType: 'fixed', timeType: 'fixed',
@ -136,14 +138,19 @@ const init = () => {
onBeforeMount(() => { onBeforeMount(() => {
init() init()
}) })
const formatDate = computed(() => {
return (config.value.timeGranularityMultiple as string) === 'yearrange' ? 'YYYY' : undefined
})
</script> </script>
<template> <template>
<el-date-picker <el-date-picker
disabled disabled
v-model="selectValue" v-model="selectValue"
type="datetimerange" :type="config.timeGranularityMultiple"
:prefix-icon="Calendar" :prefix-icon="Calendar"
:format="formatDate"
:range-separator="$t('cron.to')" :range-separator="$t('cron.to')"
:start-placeholder="$t('datasource.start_time')" :start-placeholder="$t('datasource.start_time')"
:end-placeholder="$t('datasource.end_time')" :end-placeholder="$t('datasource.end_time')"

View File

@ -197,6 +197,12 @@ const setTypeChange = () => {
nextTick(() => { nextTick(() => {
curComponent.value.field.id = '' curComponent.value.field.id = ''
inputCom.value?.displayTypeChange?.() inputCom.value?.displayTypeChange?.()
if (
+curComponent.value.displayType === 7 &&
['yearrange', 'monthrange', 'datetimerange'].includes(curComponent.value.timeGranularity)
) {
curComponent.value.timeGranularityMultiple = curComponent.value.timeGranularity
}
}) })
} }
@ -635,6 +641,13 @@ const dynamicTime = computed(() => {
const relativeToCurrentTypeList = computed(() => { const relativeToCurrentTypeList = computed(() => {
if (!curComponent.value) return [] if (!curComponent.value) return []
let index = ['year', 'month', 'date', 'datetime'].indexOf(curComponent.value.timeGranularity) + 1
if (+curComponent.value.displayType === 7) {
index =
['yearrange', 'monthrange', 'datetimerange'].indexOf(
curComponent.value.timeGranularityMultiple
) + 1
}
return [ return [
{ {
label: '年', label: '年',
@ -648,7 +661,7 @@ const relativeToCurrentTypeList = computed(() => {
label: '日', label: '日',
value: 'date' value: 'date'
} }
].slice(0, ['year', 'month', 'date', 'datetime'].indexOf(curComponent.value.timeGranularity) + 1) ].slice(0, index)
}) })
const timeGranularityChange = (val: string) => { const timeGranularityChange = (val: string) => {
@ -662,6 +675,15 @@ const timeGranularityChange = (val: string) => {
curComponent.value.relativeToCurrent = relativeToCurrentList.value[0]?.value curComponent.value.relativeToCurrent = relativeToCurrentList.value[0]?.value
} }
} }
const timeGranularityMultipleChange = (val: string) => {
if (
['yearrange', 'monthrange', 'datetimerange'].indexOf(val) <
['year', 'month', 'date'].indexOf(curComponent.value.relativeToCurrentType)
) {
curComponent.value.relativeToCurrentType = 'year'
}
}
const aroundList = [ const aroundList = [
{ {
label: '前', label: '前',
@ -968,9 +990,12 @@ defineExpose({
<div class="value"> <div class="value">
<template v-if="curComponent.displayType === '7'"> <template v-if="curComponent.displayType === '7'">
<el-select <el-select
@change="timeGranularityMultipleChange"
placeholder="请选择时间粒度" placeholder="请选择时间粒度"
v-model="curComponent.timeGranularityMultiple" v-model="curComponent.timeGranularityMultiple"
> >
<el-option label="年" value="yearrange" />
<el-option label="年月" value="monthrange" />
<el-option label="年月日时分秒" value="datetimerange" /> <el-option label="年月日时分秒" value="datetimerange" />
</el-select> </el-select>
</template> </template>
@ -1284,7 +1309,13 @@ defineExpose({
</div> </div>
</template> </template>
<template v-else-if="dynamicTime && curComponent.displayType === '7'"> <template v-else-if="dynamicTime && curComponent.displayType === '7'">
<div class="setting"> <div
class="setting"
:class="
['yearrange', 'monthrange'].includes(curComponent.timeGranularityMultiple) &&
'is-year-month-range'
"
>
<div class="setting-label">开始时间</div> <div class="setting-label">开始时间</div>
<div class="setting-input with-date range"> <div class="setting-input with-date range">
<el-input-number <el-input-number
@ -1311,7 +1342,13 @@ defineExpose({
<el-time-picker v-model="curComponent.arbitraryTime" /> <el-time-picker v-model="curComponent.arbitraryTime" />
</div> </div>
</div> </div>
<div class="setting"> <div
class="setting"
:class="
['yearrange', 'monthrange'].includes(curComponent.timeGranularityMultiple) &&
'is-year-month-range'
"
>
<div class="setting-label">结束时间</div> <div class="setting-label">结束时间</div>
<div class="setting-input with-date range"> <div class="setting-input with-date range">
<el-input-number <el-input-number
@ -1651,6 +1688,7 @@ defineExpose({
padding-left: 24px; padding-left: 24px;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
.range-title, .range-title,
.params-start, .params-start,
.params-end { .params-end {
@ -1729,6 +1767,20 @@ defineExpose({
} }
} }
} }
&.is-year-month-range {
.setting-input {
&.with-date {
.ed-input-number,
.ed-select {
width: 103px;
}
}
.ed-date-editor.ed-input {
display: none;
}
}
}
} }
} }
} }

View File

@ -121,6 +121,10 @@ onBeforeMount(() => {
defineExpose({ defineExpose({
displayTypeChange displayTypeChange
}) })
const formatDate = computed(() => {
return (config.value.timeGranularityMultiple as string) === 'yearrange' ? 'YYYY' : undefined
})
</script> </script>
<template> <template>
@ -128,6 +132,7 @@ defineExpose({
v-model="selectValue" v-model="selectValue"
:type="config.timeGranularityMultiple" :type="config.timeGranularityMultiple"
:style="selectStyle" :style="selectStyle"
:format="formatDate"
v-if="multiple" v-if="multiple"
@change="handleValueChange" @change="handleValueChange"
:prefix-icon="Calendar" :prefix-icon="Calendar"

View File

@ -1102,7 +1102,7 @@ export default {
select_year: '选择年', select_year: '选择年',
sql_variable_limit_1: '1SQL 变量只能在 WHERE 条件中使用', sql_variable_limit_1: '1SQL 变量只能在 WHERE 条件中使用',
sql_variable_limit_2: sql_variable_limit_2:
"2、示例select * from table_name where column_name1='${'{'}param_name1{'}'}' and column_name2 in ( ${'{'}param_name2{'}'} ) ", "2、示例select * from table_name where column_name1='${'{'}param_name1{'}'}' and column_name2 in (${'{'}param_name2{'}'})",
select_month: '选择月', select_month: '选择月',
select_date: '选择日期', select_date: '选择日期',
select_time: '选择时间', select_time: '选择时间',

View File

@ -44,6 +44,7 @@ declare interface ChartIndicatorStyle {
letterSpace: string letterSpace: string
fontShadow: boolean fontShadow: boolean
suffixEnable: boolean
suffix: string suffix: string
suffixFontSize: string suffixFontSize: string
suffixColor: string suffixColor: string

View File

@ -149,6 +149,7 @@ watch(
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-left: 4px"> <el-form-item class="form-item" :class="'form-item-' + themes" style="padding-left: 4px">
<el-select <el-select
size="small"
:effect="themes" :effect="themes"
v-model="state.indicatorNameForm.letterSpace" v-model="state.indicatorNameForm.letterSpace"
:placeholder="t('chart.quota_letter_space')" :placeholder="t('chart.quota_letter_space')"

View File

@ -360,152 +360,170 @@ watch(
<el-divider class="m-divider" :class="{ 'divider-dark': themes === 'dark' }" /> <el-divider class="m-divider" :class="{ 'divider-dark': themes === 'dark' }" />
<el-form-item <el-form-item class="form-item" :class="'form-item-' + themes">
class="form-item" <el-checkbox
:class="'form-item-' + themes" size="small"
:label="t('chart.indicator_suffix')"
>
<el-input
v-model="state.indicatorValueForm.suffix"
:placeholder="t('chart.indicator_suffix_placeholder')"
maxlength="10"
@change="changeTitleStyle('suffix')"
/>
</el-form-item>
<el-form-item class="form-item" :class="'form-item-' + themes" :effect="themes">
<el-select
:effect="themes" :effect="themes"
v-model="state.indicatorValueForm.suffixFontFamily" v-model="state.indicatorValueForm.suffixEnable"
:placeholder="t('chart.font_family')" @change="changeTitleStyle('suffixEnable')"
@change="changeTitleStyle('suffixFontFamily')"
> >
<el-option {{ t('chart.indicator_suffix') }}
v-for="option in fontFamily" </el-checkbox>
:key="option.value"
:label="option.name"
:value="option.value"
/>
</el-select>
</el-form-item> </el-form-item>
<div style="display: flex"> <div style="padding-left: 22px">
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-right: 4px"> <el-form-item class="form-item" :class="'form-item-' + themes">
<el-color-picker <el-input
:effect="themes" :disabled="!state.indicatorValueForm.suffixEnable"
v-model="state.indicatorValueForm.suffixColor" v-model="state.indicatorValueForm.suffix"
class="color-picker-style" :placeholder="t('chart.indicator_suffix_placeholder')"
:predefine="predefineColors" maxlength="10"
@change="changeTitleStyle('suffixColor')" @change="changeTitleStyle('suffix')"
is-custom
/> />
</el-form-item> </el-form-item>
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding: 0 4px">
<el-tooltip content="字号" :effect="toolTip" placement="top">
<el-select
style="width: 56px"
:effect="themes"
v-model="state.indicatorValueForm.suffixFontSize"
:placeholder="t('chart.text_fontsize')"
size="small"
@change="changeTitleStyle('suffixFontSize')"
>
<el-option
v-for="option in fontSizeList"
:key="option.value"
:label="option.name"
:value="option.value"
/>
</el-select>
</el-tooltip>
</el-form-item>
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-left: 4px"> <el-form-item class="form-item" :class="'form-item-' + themes" :effect="themes">
<el-select <el-select
:disabled="!state.indicatorValueForm.suffixEnable"
:effect="themes" :effect="themes"
v-model="state.indicatorValueForm.suffixLetterSpace" v-model="state.indicatorValueForm.suffixFontFamily"
:placeholder="t('chart.quota_letter_space')" :placeholder="t('chart.font_family')"
@change="changeTitleStyle('suffixLetterSpace')" @change="changeTitleStyle('suffixFontFamily')"
> >
<template #prefix>
<el-icon>
<Icon name="icon_letter-spacing_outlined" />
</el-icon>
</template>
<el-option <el-option
v-for="option in fontLetterSpace" v-for="option in fontFamily"
:key="option.value" :key="option.value"
:label="option.name" :label="option.name"
:value="option.value" :value="option.value"
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<div style="display: flex">
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-right: 4px">
<el-color-picker
:disabled="!state.indicatorValueForm.suffixEnable"
:effect="themes"
v-model="state.indicatorValueForm.suffixColor"
class="color-picker-style"
:predefine="predefineColors"
@change="changeTitleStyle('suffixColor')"
is-custom
/>
</el-form-item>
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding: 0 4px">
<el-tooltip content="字号" :effect="toolTip" placement="top">
<el-select
:disabled="!state.indicatorValueForm.suffixEnable"
style="width: 56px"
:effect="themes"
v-model="state.indicatorValueForm.suffixFontSize"
:placeholder="t('chart.text_fontsize')"
size="small"
@change="changeTitleStyle('suffixFontSize')"
>
<el-option
v-for="option in fontSizeList"
:key="option.value"
:label="option.name"
:value="option.value"
/>
</el-select>
</el-tooltip>
</el-form-item>
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-left: 4px">
<el-select
size="small"
:disabled="!state.indicatorValueForm.suffixEnable"
:effect="themes"
v-model="state.indicatorValueForm.suffixLetterSpace"
:placeholder="t('chart.quota_letter_space')"
@change="changeTitleStyle('suffixLetterSpace')"
>
<template #prefix>
<el-icon>
<Icon name="icon_letter-spacing_outlined" />
</el-icon>
</template>
<el-option
v-for="option in fontLetterSpace"
:key="option.value"
:label="option.name"
:value="option.value"
/>
</el-select>
</el-form-item>
</div>
<el-space>
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-checkbox
:disabled="!state.indicatorValueForm.suffixEnable"
:effect="themes"
class="icon-checkbox"
v-model="state.indicatorValueForm.suffixIsBolder"
@change="changeTitleStyle('suffixIsBolder')"
>
<el-tooltip :effect="toolTip" placement="top">
<template #content>
{{ t('chart.bolder') }}
</template>
<div
class="icon-btn"
:class="{
dark: themes === 'dark',
active: state.indicatorValueForm.suffixIsBolder
}"
>
<el-icon>
<Icon name="icon_bold_outlined" />
</el-icon>
</div>
</el-tooltip>
</el-checkbox>
</el-form-item>
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-checkbox
:disabled="!state.indicatorValueForm.suffixEnable"
:effect="themes"
class="icon-checkbox"
v-model="state.indicatorValueForm.suffixIsItalic"
@change="changeTitleStyle('suffixIsItalic')"
>
<el-tooltip :effect="toolTip" placement="top">
<template #content>
{{ t('chart.italic') }}
</template>
<div
class="icon-btn"
:class="{
dark: themes === 'dark',
active: state.indicatorValueForm.suffixIsItalic
}"
>
<el-icon>
<Icon name="icon_italic_outlined" />
</el-icon>
</div>
</el-tooltip>
</el-checkbox>
</el-form-item>
</el-space>
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-checkbox
:disabled="!state.indicatorValueForm.suffixEnable"
size="small"
:effect="themes"
v-model="state.indicatorValueForm.suffixFontShadow"
@change="changeTitleStyle('suffixFontShadow')"
>
{{ t('chart.font_shadow') }}
</el-checkbox>
</el-form-item>
</div> </div>
<el-space>
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-checkbox
:effect="themes"
class="icon-checkbox"
v-model="state.indicatorValueForm.suffixIsBolder"
@change="changeTitleStyle('suffixIsBolder')"
>
<el-tooltip :effect="toolTip" placement="top">
<template #content>
{{ t('chart.bolder') }}
</template>
<div
class="icon-btn"
:class="{
dark: themes === 'dark',
active: state.indicatorValueForm.suffixIsBolder
}"
>
<el-icon>
<Icon name="icon_bold_outlined" />
</el-icon>
</div>
</el-tooltip>
</el-checkbox>
</el-form-item>
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-checkbox
:effect="themes"
class="icon-checkbox"
v-model="state.indicatorValueForm.suffixIsItalic"
@change="changeTitleStyle('suffixIsItalic')"
>
<el-tooltip :effect="toolTip" placement="top">
<template #content>
{{ t('chart.italic') }}
</template>
<div
class="icon-btn"
:class="{
dark: themes === 'dark',
active: state.indicatorValueForm.suffixIsItalic
}"
>
<el-icon>
<Icon name="icon_italic_outlined" />
</el-icon>
</div>
</el-tooltip>
</el-checkbox>
</el-form-item>
</el-space>
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-checkbox
size="small"
:effect="themes"
v-model="state.indicatorValueForm.suffixFontShadow"
@change="changeTitleStyle('suffixFontShadow')"
>
{{ t('chart.font_shadow') }}
</el-checkbox>
</el-form-item>
</el-form> </el-form>
</div> </div>
</template> </template>

View File

@ -359,6 +359,7 @@ export const DEFAULT_INDICATOR_STYLE: ChartIndicatorStyle = {
letterSpace: '0', letterSpace: '0',
fontShadow: false, fontShadow: false,
suffixEnable: true,
suffix: '', suffix: '',
suffixFontSize: '14', suffixFontSize: '14',
suffixColor: '#5470C6', suffixColor: '#5470C6',

View File

@ -607,7 +607,7 @@ const iconSize = computed<string>(() => {
</template> </template>
<div <div
class="icons-container" class="icons-container"
:class="{ 'is-editing': titleEditStatus }" :class="{ 'is-editing': titleEditStatus, 'icons-container__dark': themes === 'dark' }"
v-if="trackMenu.length > 0 || state.title_remark.show" v-if="trackMenu.length > 0 || state.title_remark.show"
> >
<el-tooltip :effect="toolTip" placement="top" v-if="state.title_remark.show"> <el-tooltip :effect="toolTip" placement="top" v-if="state.title_remark.show">
@ -712,6 +712,10 @@ const iconSize = computed<string>(() => {
color: #646a73; color: #646a73;
&.icons-container__dark {
color: #a6a6a6;
}
&.is-editing { &.is-editing {
gap: 6px; gap: 6px;
} }

View File

@ -759,10 +759,6 @@ const getMenuList = (val: boolean) => {
height: calc(100vh - 56px); height: calc(100vh - 56px);
overflow: auto; overflow: auto;
position: relative; position: relative;
&.h100 {
height: 100%;
}
} }
.dataset-content { .dataset-content {

View File

@ -1576,8 +1576,6 @@ const getMenuList = (val: boolean) => {
overflow: auto; overflow: auto;
position: relative; position: relative;
&.h100 { &.h100 {
height: 100%;
.datasource-table { .datasource-table {
height: calc(100% - 140px); height: calc(100% - 140px);
} }

@ -1 +1 @@
Subproject commit 2012e4fb3c3169330cc70b09e4e77d144b22031b Subproject commit 19d1cc14aaa7ff5297ebe8f3b8ea3c706f164cc3

View File

@ -7,6 +7,9 @@ DE_RUNNING_BASE=${DE_BASE}/dataease2.0
need_init_apisix=false need_init_apisix=false
compose_files="-f docker-compose.yml" compose_files="-f docker-compose.yml"
compose_cmd="docker-compose" compose_cmd="docker-compose"
server_url=""
current_version=""
latest_version=""
set -a set -a
source ${DE_RUNNING_BASE}/.env source ${DE_RUNNING_BASE}/.env
@ -107,7 +110,84 @@ function _healthcheck() {
} }
function _get_current_version() { function _get_current_version() {
de_current_version=$(grep "^ image:.*dataease:" ${DE_RUNNING_BASE}/docker-compose.yml | awk -F'dataease:' '{print $2}') de_current_version=$(grep "^ image:.*dataease:" ${DE_RUNNING_BASE}/docker-compose.yml | awk -F'dataease:' '{print $2}')
echo $de_current_version if test -z $de_current_version; then
echo "获取当前版本失败,请检查当前版本是否正确"
exit 1
fi
current_version=$de_current_version
}
function _get_available_server() {
git_urls=('github.com')
for git_url in ${git_urls[*]}; do
echo -ne "检测 ${git_url} ... "
curl -m 5 -kIs https://${git_url} >/dev/null
if [ $? != 0 ]; then
echo "failed"
else
echo "ok"
server_url=${git_url}
break
fi
done
}
function _get_latest_version() {
rm -f /tmp/de_latest_release
_get_available_server
if [[ "x${server_url}" == "x" ]];then
echo "无法连接版本服务器,请稍候重试"
exit 1
fi
if [[ -x "$(command -v python)" ]]; then
py_cmd='python'
elif [[ -x "$(command -v python3)" ]]; then
py_cmd='python3'
fi
$py_cmd - <<EOF
# -*- coding: UTF-8 -*-
import os
import json
import re
latest_release=""
release_pattern="v2\.\d+\.\d+$"
def get_releases(page):
try:
releases=os.popen("curl -s https://api.github.com/repos/dataease/dataease/releases?page=%d" % (page)).read()
releases=[ x["name"] for x in json.loads(releases) if x["prerelease"] == False ]
except Exception as e:
print(str(e))
print("Failed to obtain Release information, please check the network.")
exit(1)
else:
for release in releases:
if re.search(release_pattern,release) != None:
return release
page = 1
while (page <= 3):
latest_release = get_releases(page)
if (latest_release != "" and latest_release != None):
break
page += 1
if latest_release == None or latest_release == "":
print("Failed to obtain latest version, please try again.")
exit(1)
# 记录最新版本号
os.popen("echo "+latest_release+" > /tmp/de_latest_release")
EOF
if [ ! -f /tmp/de_latest_release ]; then
echo "获取最新版本失败,请检查网络连接是否正常"
exit 1
fi
latest_version=$(cat /tmp/de_latest_release)
} }
function status() { function status() {
echo echo
@ -164,117 +244,26 @@ function reload() {
function version() { function version() {
echo echo
_get_current_version _get_current_version
_get_latest_version
echo "current version is $current_version"
echo "latest version is $latest_version"
} }
function upgrade() { function upgrade() {
echo version
git_urls=('github.com')
if [[ -x "$(command -v python)" ]]; then
py_cmd='python'
elif [[ -x "$(command -v python3)" ]]; then
py_cmd='python3'
fi
for git_url in ${git_urls[*]}; do
success="true"
for i in {1..3}; do
echo -ne "检测 ${git_url} ... ${i} "
curl -m 5 -kIs https://${git_url} >/dev/null
if [ $? != 0 ]; then
echo "failed"
success="false"
break
else
echo "ok"
fi
done
if [[ ${success} == "true" ]]; then
server_url=${git_url}
break
fi
done
if [[ "x${server_url}" == "x" ]]; then
echo "没有找到稳定的下载服务器,请访问 https://community.fit2cloud.com/#/products/dataease/downloads 下载离线安装包"
exit 1
fi
if [[ "${server_url}" == "gitee.com" ]]; then
owner='fit2cloud-feizhiyun'
repo='DataEase'
else
owner='dataease'
repo='dataease'
fi
export DE_VERSION=$(_get_current_version)
if test -z $DE_VERSION; then
echo "获取当前版本失败,请检查当前版本是否正确"
exit 1
fi
echo "检测当前版本为${DE_VERSION}"
rm -f /tmp/de_latest_release
$py_cmd - <<EOF
# -*- coding: UTF-8 -*-
import os
import json
import re
latest_release=""
release_pattern=""
current_version="$DE_VERSION"
server_url="$server_url"
release_pattern="v2\.\d+\.\d+$"
def get_releases(page):
try:
if server_url == "gitee.com":
releases=os.popen("curl -s https://gitee.com/api/v5/repos/fit2cloud-feizhiyun/DataEase/releases?direction=desc&page=%d" % (page)).read()
else:
releases=os.popen("curl -s https://api.github.com/repos/dataease/dataease/releases?page=%d" % (page)).read()
releases=[ x["name"] for x in json.loads(releases) if x["prerelease"] == False ]
except Exception as e:
print(str(e))
print("Failed to obtain Release information, please check the network.")
exit(1)
else:
for release in releases:
if re.search(release_pattern,release) != None:
return release
page = 1
while (page <= 3):
latest_release = get_releases(page)
if (latest_release != "" and latest_release != None):
break
page += 1
if latest_release == None or latest_release == "":
print("Failed to obtain latest version, please try again.")
exit(1)
else:
print("latest version is %s" % (latest_release))
# 记录最新版本号
os.popen("echo "+latest_release+" > /tmp/de_latest_release")
EOF
if [ ! -f /tmp/de_latest_release ]; then
echo "获取最新版本失败,请检查网络连接是否正常"
exit 1
fi
latest_version=$(cat /tmp/de_latest_release)
if [ "${latest_version}" = "" ]; then if [ "${latest_version}" = "" ]; then
echo "未获取到最新版本" echo "未获取到最新版本"
exit 1 exit 1
elif [ "${latest_version}" = "${DE_VERSION}" ]; then elif [ "${latest_version}" = "${current_version}" ]; then
echo "最新版本与当前版本一致,退出升级过程" echo "最新版本与当前版本一致,退出升级过程"
exit 0 exit 0
else else
echo "检测到 ${server_url} 上最新版本为 ${latest_version} 即将执行在线升级..." if [[ ! "$latest_version" =~ ^v2.* ]];then
echo "获取到的最新版本与当前版本不匹配,请访问 https://community.fit2cloud.com/#/products/dataease/downloads 下载离线安装包"
exit 1
else
echo "检测到 ${server_url} 上最新版本为 ${latest_version} 即将执行在线升级..."
fi
fi fi
sleep 2 sleep 2
@ -283,11 +272,11 @@ EOF
cd /tmp cd /tmp
installer_file="dataease-online-installer-${latest_version}.tar.gz" installer_file="dataease-online-installer-${latest_version}.tar.gz"
download_url="https://${server_url}/${owner}/${repo}/releases/download/${latest_version}/$installer_file" download_url="https://${server_url}/dataease/dataease/releases/download/${latest_version}/$installer_file"
curl -LOk -m 60 -o $installer_file $download_url curl -LOk -m 60 -o $installer_file $download_url
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo -e "\e[31m升级失败:连接下载服务器超时!\n可手动下载升级包然后执行\e[1;33m /bin/bash install.sh \e[0;31m离线升级也可以重新执行一次 dectl upgrade 命令。\e[0m" echo -e "\e[31m升级失败:连接下载服务器超时!\n可手动下载升级包然后执行\e[1;33m /bin/bash install.sh \e[0;31m离线升级也可以重新执行一次 dectl upgrade 命令。\e[0m"
return 2 exit 1
fi fi
if [ ! -f $installer_file ]; then if [ ! -f $installer_file ]; then

View File

@ -16,4 +16,8 @@ public class LogGridVO implements Serializable {
private String ip; private String ip;
private Long time; private Long time;
private boolean success;
private String msg;
} }

View File

@ -152,4 +152,8 @@ public interface UserApi {
@Hidden @Hidden
@GetMapping("/firstEchelon/{limit}") @GetMapping("/firstEchelon/{limit}")
List<Long> firstEchelon(@PathVariable("limit") Long limit); List<Long> firstEchelon(@PathVariable("limit") Long limit);
@Hidden
@GetMapping("/queryByAccount")
CurUserVO queryByAccount(String account);
} }

View File

@ -13,7 +13,9 @@ public @interface DeLog {
String pid() default ""; String pid() default "";
LogST st(); LogST st() default LogST.PANEL;
LogOT ot(); LogOT ot();
String stExp() default "";
} }