Merge branch 'dev-v2' into pr@dev-v2@refactor_flyway

This commit is contained in:
王嘉豪 2024-08-22 19:58:25 +08:00 committed by GitHub
commit b38059240e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 229 additions and 58 deletions

View File

@ -10,6 +10,7 @@ import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@Component
public class IndicatorHandler extends YoyChartHandler {
@ -36,23 +37,19 @@ public class IndicatorHandler extends YoyChartHandler {
var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis);
var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis);
var allFields = (List<ChartViewFieldDTO>) filterResult.getContext().get("allFields");
ChartViewFieldDTO chartViewFieldDTO = yAxis.get(0);
ChartFieldCompareDTO compareCalc = chartViewFieldDTO.getCompareCalc();
ChartViewFieldDTO yAxisChartViewFieldDTO = yAxis.get(0);
ChartFieldCompareDTO compareCalc = yAxisChartViewFieldDTO.getCompareCalc();
boolean isYoy = org.apache.commons.lang3.StringUtils.isNotEmpty(compareCalc.getType())
&& !org.apache.commons.lang3.StringUtils.equalsIgnoreCase(compareCalc.getType(), "none");
if (isYoy) {
xAxis.clear();
// 设置维度字段从同环比中获取用户选择的字段
xAxis.addAll(allFields.stream().filter(i -> org.springframework.util.StringUtils.endsWithIgnoreCase(i.getId().toString(), yAxis.get(0).getCompareCalc().getField().toString())).toList());
xAxis.addAll(allFields.stream().filter(i -> org.springframework.util.StringUtils.endsWithIgnoreCase(i.getId().toString(), compareCalc.getField().toString())).toList());
xAxis.get(0).setSort("desc");
if (org.springframework.util.StringUtils.endsWithIgnoreCase("month_mom", compareCalc.getType())) {
xAxis.get(0).setDateStyle("y_M");
}
if (org.springframework.util.StringUtils.endsWithIgnoreCase("day_mom", compareCalc.getType())) {
if(Objects.isNull(compareCalc.getCustom())){
xAxis.get(0).setDateStyle("y_M_d");
}
if (org.springframework.util.StringUtils.endsWithIgnoreCase("year_mom", compareCalc.getType())) {
xAxis.get(0).setDateStyle("y");
}else{
xAxis.get(0).setDateStyle(compareCalc.getCustom().getTimeType());
}
}
formatResult.getAxisMap().put(ChartAxis.xAxis, xAxis);

View File

@ -137,7 +137,7 @@ public class CoreChartView implements Serializable {
private Long updateTime;
/**
* 缩略图
* 缩略图
*/
private String snapshot;
@ -206,6 +206,16 @@ public class CoreChartView implements Serializable {
*/
private Boolean aggregate;
private String flowMapStartName;
private String flowMapEndName;
/**
* 颜色维度field
*/
private String extColor;
public Long getId() {
return id;
}
@ -510,6 +520,30 @@ public class CoreChartView implements Serializable {
this.aggregate = aggregate;
}
public String getFlowMapStartName() {
return flowMapStartName;
}
public void setFlowMapStartName(String flowMapStartName) {
this.flowMapStartName = flowMapStartName;
}
public String getFlowMapEndName() {
return flowMapEndName;
}
public void setFlowMapEndName(String flowMapEndName) {
this.flowMapEndName = flowMapEndName;
}
public String getExtColor() {
return extColor;
}
public void setExtColor(String extColor) {
this.extColor = extColor;
}
@Override
public String toString() {
return "CoreChartView{" +
@ -551,6 +585,9 @@ public class CoreChartView implements Serializable {
", copyFrom = " + copyFrom +
", copyId = " + copyId +
", aggregate = " + aggregate +
", flowMapStartName=" + flowMapStartName +
", flowMapEndName=" + flowMapEndName +
", extColor=" + extColor +
"}";
}
}

View File

@ -329,6 +329,9 @@ public class ChartViewManege {
record.setDrillFields(objectMapper.writeValueAsString(dto.getDrillFields()));
record.setCustomFilter(objectMapper.writeValueAsString(dto.getCustomFilter()));
record.setViewFields(objectMapper.writeValueAsString(dto.getViewFields()));
record.setFlowMapStartName(objectMapper.writeValueAsString(dto.getFlowMapStartName()));
record.setFlowMapEndName(objectMapper.writeValueAsString(dto.getFlowMapEndName()));
record.setExtColor(objectMapper.writeValueAsString(dto.getExtColor()));
return record;
}
@ -354,6 +357,9 @@ public class ChartViewManege {
dto.setDrillFields(JsonUtil.parseList(record.getDrillFields(), tokenType));
dto.setCustomFilter(JsonUtil.parseObject(record.getCustomFilter(), FilterTreeObj.class));
dto.setViewFields(JsonUtil.parseList(record.getViewFields(), tokenType));
dto.setFlowMapStartName(JsonUtil.parseList(record.getFlowMapStartName(), tokenType));
dto.setFlowMapEndName(JsonUtil.parseList(record.getFlowMapEndName(), tokenType));
dto.setExtColor(JsonUtil.parseList(record.getExtColor(), tokenType));
return dto;

View File

@ -12,5 +12,13 @@ ALTER TABLE `visualization_outer_params_target_view_info`
MODIFY COLUMN `target_view_id` varchar(50) NULL DEFAULT NULL COMMENT '联动视图ID/联动过滤项ID' ,
ADD COLUMN `target_ds_id` varchar(50) NULL COMMENT '联动数据集id/联动过滤组件id' ;
alter table `core_chart_view`
add flow_map_start_name longtext comment '流向地图起点名称field';
alter table `core_chart_view`
add flow_map_end_name longtext comment '流向地图终点名称field';
alter table `core_chart_view`
add ext_color longtext comment '颜色维度field';
update visualization_outer_params_target_view_info tvi INNER JOIN core_chart_view ccv on tvi.target_view_id = ccv.id
set tvi.target_ds_id = ccv.table_id

View File

@ -61,5 +61,12 @@ ALTER TABLE `visualization_outer_params_target_view_info`
MODIFY COLUMN `target_view_id` varchar(50) NULL DEFAULT NULL COMMENT '联动视图ID/联动过滤项ID' ,
ADD COLUMN `target_ds_id` varchar(50) NULL COMMENT '联动数据集id/联动过滤组件id' ;
alter table `core_chart_view`
add flow_map_start_name longtext comment '流向地图起点名称field';
alter table `core_chart_view`
add flow_map_end_name longtext comment '流向地图终点名称field';
alter table `core_chart_view`
add ext_color longtext comment '颜色维度field';
update visualization_outer_params_target_view_info tvi INNER JOIN core_chart_view ccv on tvi.target_view_id = ccv.id
set tvi.target_ds_id = ccv.table_id

View File

@ -11,6 +11,7 @@ import { ElDivider } from 'element-plus-secondary'
import eventBus from '@/utils/eventBus'
import { getCurInfo } from '@/store/modules/data-visualization/common'
import { useEmitt } from '@/hooks/web/useEmitt'
import { XpackComponent } from '@/components/plugin'
const dvMainStore = dvMainStoreWithOut()
const copyStore = copyStoreWithOut()
const lockStore = lockStoreWithOut()
@ -245,6 +246,11 @@ const editQueryCriteria = () => {
<li @click="downComponent">下移一层</li>
<li @click="topComponent">置于顶层</li>
<li @click="bottomComponent">置于底层</li>
<xpack-component
:chart="curComponent"
is-screen
jsname="L2NvbXBvbmVudC90aHJlc2hvbGQtd2FybmluZy9FZGl0QmFySGFuZGxlcg=="
/>
<li
@click="categoryChange('hidden')"
v-show="

View File

@ -146,10 +146,18 @@ onMounted(() => {
</el-menu>
<div class="operate-setting" v-if="!desktop">
<XpackComponent jsname="c3dpdGNoZXI=" />
<el-icon style="margin: 0 10px" class="ai-icon copilot-icon" v-if="!showOverlayCopilot">
<el-icon
style="margin: 0 10px"
class="ai-icon copilot-icon"
v-if="!showOverlayCopilot && appearanceStore.getShowCopilot"
>
<Icon name="copilot" @click="handleCopilotClick" />
</el-icon>
<Copilot @confirm="copilotConfirm" v-if="showOverlayCopilot" class="copilot-icon-tips" />
<Copilot
@confirm="copilotConfirm"
v-if="showOverlayCopilot && appearanceStore.getShowCopilot"
class="copilot-icon-tips"
/>
<el-icon
style="margin: 0 10px"
@ -181,7 +189,7 @@ onMounted(() => {
:base-url="aiBaseUrl"
></ai-component>
<div v-if="showOverlay && appearanceStore.getShowAi" class="overlay"></div>
<div v-if="showOverlayCopilot" class="overlay"></div>
<div v-if="showOverlayCopilot && appearanceStore.getShowCopilot" class="overlay"></div>
</div>
</el-header>
<ExportExcel ref="ExportExcelRef"></ExportExcel>

View File

@ -12,8 +12,11 @@ interface AppearanceState {
customColor?: string
navigateBg?: string
navigate?: string
mobileLogin?: string
mobileLoginBg?: string
help?: string
showAi?: string
showCopilot?: string
showDoc?: string
showAbout?: string
bg?: string
@ -36,9 +39,12 @@ export const useAppearanceStore = defineStore('appearanceStore', {
customColor: '',
navigateBg: '',
navigate: '',
mobileLogin: '',
mobileLoginBg: '',
help: '',
showDoc: '0',
showAi: '0',
showCopilot: '0',
showAbout: '0',
bg: '',
login: '',
@ -60,6 +66,18 @@ export const useAppearanceStore = defineStore('appearanceStore', {
}
return null
},
getMobileLogin(): string {
if (this.mobileLogin) {
return baseUrl + this.mobileLogin
}
return null
},
getMobileLoginBg(): string {
if (this.mobileLoginBg) {
return baseUrl + this.mobileLoginBg
}
return null
},
getHelp(): string {
return this.help
},
@ -117,6 +135,9 @@ export const useAppearanceStore = defineStore('appearanceStore', {
getShowAi(): boolean {
return isBtnShow(this.showAi)
},
getShowCopilot(): boolean {
return isBtnShow(this.showCopilot)
},
getShowDoc(): boolean {
return isBtnShow(this.showDoc)
},
@ -128,6 +149,12 @@ export const useAppearanceStore = defineStore('appearanceStore', {
setNavigate(data: string) {
this.navigate = data
},
setMobileLogin(data: string) {
this.mobileLogin = data
},
setMobileLoginBg(data: string) {
this.mobileLoginBg = data
},
setHelp(data: string) {
this.help = data
},
@ -177,8 +204,11 @@ export const useAppearanceStore = defineStore('appearanceStore', {
return
}
this.navigate = data.navigate
this.mobileLogin = data.mobileLogin
this.mobileLoginBg = data.mobileLoginBg
this.help = data.help
this.showAi = data.showAi
this.showCopilot = data.showCopilot
this.showDoc = data.showDoc
this.showAbout = data.showAbout
this.navigateBg = data.navigateBg

View File

@ -81,7 +81,10 @@ const setLicense = lic => {
dynamicCardClass.value = 'about-card-medium'
}
}
const removeDistributeModule = () => {
const key = 'xpack-model-distributed'
localStorage.removeItem(key)
}
const importLic = file => {
const reader = new FileReader()
reader.onload = function (e) {
@ -93,6 +96,7 @@ const importLic = file => {
reader.readAsText(file)
}
const validateHandler = (param, success) => {
removeDistributeModule()
validateApi(param).then(success)
}
const getLicense = result => {

View File

@ -402,7 +402,7 @@ onMounted(() => {
</el-dropdown-item>-->
<el-dropdown-item
@click.prevent
v-if="!item.chartId && chart.type !== 'table-info' && item.summary !== ''"
v-if="chart.type !== 'table-info' && item.summary !== ''"
>
<el-dropdown
:effect="themes"

View File

@ -32,14 +32,42 @@ const { compareItem, chart } = toRefs(props)
const state = reactive({
fieldList: [],
compareList: []
compareList: [],
dateFormatter: 'y_M_d'
})
const dateFormatterList = [
{ name: '年', value: 'y' },
{ name: '年月', value: 'y_M' },
{ name: '年月日', value: 'y_M_d' }
]
const changeDateFormatter = () => {
const checkedField = state.fieldList.filter(ele => ele.id === compareItem.value.compareCalc.field)
if (checkedField && checkedField.length > 0) {
checkedField[0].dateStyle = state.dateFormatter
if (!compareItem.value.compareCalc.custom) {
compareItem.value.compareCalc.custom = { timeType: 'y_M_d' }
}
compareItem.value.compareCalc.custom.timeType = state.dateFormatter
}
initCompareType()
}
const initDateFormatter = () => {
const timeType = compareItem.value.compareCalc.custom?.timeType
if (isIndicator.value && timeType) {
state.dateFormatter = timeType
changeDateFormatter()
}
}
watch(
() => props.chart,
() => {
initFieldList()
initCompareType()
initDateFormatter()
},
{ deep: true }
)
@ -109,15 +137,6 @@ const initCompareType = () => {
} else {
state.compareList = []
}
if (isIndicator.value) {
state.compareList = [
{ name: 'day_mom', value: 'day_mom' },
{ name: 'month_mom', value: 'month_mom' },
{ name: 'year_mom', value: 'year_mom' },
{ name: 'month_yoy', value: 'month_yoy' },
{ name: 'year_yoy', value: 'year_yoy' }
]
}
//
if (
(!compareItem.value.compareCalc.type ||
@ -136,9 +155,9 @@ const fieldFormatter = field => {
return field.name + '(' + t('chart.' + field.dateStyle) + ')'
}
}
initFieldList()
initCompareType()
initDateFormatter()
</script>
<template>
@ -158,12 +177,25 @@ initCompareType()
/>
</el-select>
</el-form-item>
<el-form-item v-if="isIndicator" :label="t('chart.datePattern')">
<el-select
v-model="state.dateFormatter"
:placeholder="t('chart.date_format')"
@change="changeDateFormatter"
>
<el-option
v-for="field in dateFormatterList"
:key="field.value"
:label="field.name"
:value="field.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('chart.compare_type')">
<el-radio-group v-model="compareItem.compareCalc.type">
<el-radio v-for="radio in state.compareList" :key="radio.value" :label="radio.value">{{
t('chart.' + radio.value)
}}</el-radio>
<el-radio v-for="radio in state.compareList" :key="radio.value" :label="radio.value"
>{{ t('chart.' + radio.value) }}
</el-radio>
</el-radio-group>
</el-form-item>
@ -196,18 +228,22 @@ initCompareType()
.ed-form-item {
margin-bottom: 10px !important;
}
.compare-form :deep(.ed-form-item__label) {
font-size: 12px !important;
font-weight: 400 !important;
padding-top: 8px !important;
}
.compare-form :deep(.ed-radio__label) {
font-size: 12px !important;
font-weight: 400 !important;
}
.el-select-dropdown__item :deep(span) {
font-size: 12px !important;
}
.exp-style {
color: #c0c4cc;
font-size: 12px;

View File

@ -72,7 +72,16 @@ export class TableHeatmap extends G2PlotChartView<HeatmapOptions, Heatmap> {
limit: 1
}
}
protected getDefaultLength = (chart, l) => {
const containerDom = document.getElementById(chart.container)
const containerHeight = containerDom?.clientHeight || 100
const containerWidth = containerDom?.clientWidth || 100
let defaultLength = containerHeight - containerHeight * 0.5
if (l.orient !== 'vertical') {
defaultLength = containerWidth - containerWidth * 0.5
}
return defaultLength
}
async drawChart(drawOptions: G2PlotDrawOptions<Heatmap>): Promise<Heatmap> {
const { chart, container, action } = drawOptions
const xAxis = deepCopy(chart.xAxis)
@ -84,8 +93,6 @@ export class TableHeatmap extends G2PlotChartView<HeatmapOptions, Heatmap> {
const xField = xAxis[0].dataeaseName
const xFieldExt = xAxisExt[0].dataeaseName
const extColorField = extColor[0].dataeaseName
const containerDom = document.getElementById(container)
const containerHeight = containerDom?.clientHeight || 100
// data
const data = cloneDeep(chart.data.tableRow)
data.forEach(i => {
@ -114,13 +121,13 @@ export class TableHeatmap extends G2PlotChartView<HeatmapOptions, Heatmap> {
layout: 'vertical',
position: 'right',
slidable: true,
maxHeight: containerHeight - containerHeight * 0.2,
label: {
align: 'left',
spacing: 10
}
}
}
chart.container = container
const options = this.setupOptions(chart, initOptions)
const { Heatmap } = await import('@antv/g2plot/esm/plots/heatmap')
const newChart = new Heatmap(container, options)
@ -166,18 +173,10 @@ export class TableHeatmap extends G2PlotChartView<HeatmapOptions, Heatmap> {
newChart.on('afterrender', ev => {
const l = JSON.parse(JSON.stringify(parseJson(chart.customStyle).legend))
if (l.show) {
const extColor = deepCopy(chart.extColor)
const containerDom = document.getElementById(container)
const containerHeight = containerDom?.clientHeight || 100
const containerWidth = containerDom?.clientWidth || 100
let defaultLength = getLegend(chart)
if (l.orient === 'vertical') {
defaultLength = containerHeight - containerHeight * 0.5
} else {
defaultLength = containerWidth - containerWidth * 0.5
const rail = ev.view.getController('legend').option[extColor[0].dataeaseName]?.['rail']
if (rail) {
rail.defaultLength = this.getDefaultLength(chart, l)
}
ev.view.getController('legend').option[extColor[0].dataeaseName]['rail'].defaultLength =
defaultLength
}
})
return newChart
@ -251,12 +250,16 @@ export class TableHeatmap extends G2PlotChartView<HeatmapOptions, Heatmap> {
tmpOptions.legend.minWidth = 10
tmpOptions.legend.maxHeight = 600
tmpOptions.legend.maxWidth = 600
const containerDom = document.getElementById(chart.container)
const containerHeight = containerDom?.clientHeight || 100
const containerWidth = containerDom?.clientWidth || 100
let defaultLength = containerHeight - containerHeight * 0.5
if (l.orient === 'vertical') {
tmpOptions.legend.offsetY = -5
} else {
defaultLength = containerWidth - containerWidth * 0.5
}
tmpOptions.legend.rail = {
defaultLength: 100
}
tmpOptions.legend.rail = { defaultLength: defaultLength }
tmpOptions.legend.label = {
spacing: 10,
style: {
@ -272,6 +275,7 @@ export class TableHeatmap extends G2PlotChartView<HeatmapOptions, Heatmap> {
chart.customStyle.legend.orient = 'vertical'
chart.customStyle.legend.vPosition = 'center'
chart.customStyle.legend.hPosition = 'right'
chart.customStyle.legend.rail = { defaultLength: 100 }
return chart
}

View File

@ -526,6 +526,7 @@ eventBus.on('handleNew', handleNew)
@loaded="XpackLoaded"
@load-fail="XpackLoaded"
/>
<xpack-component jsname="L2NvbXBvbmVudC90aHJlc2hvbGQtd2FybmluZy9UaHJlc2hvbGREaWFsb2c=" />
<canvas-cache-dialog ref="canvasCacheOutRef" @doUseCache="doUseCache"></canvas-cache-dialog>
<dv-preview
v-if="fullscreenFlag"

View File

@ -1,7 +1,9 @@
<script lang="ts" setup>
import { ref } from 'vue'
import VanCellGroup from 'vant/es/cell-group'
import mobileWholeBg from '@/assets/img/bg-mobile.png'
import mobileDeTop from '@/assets/img/mobile-de-top.png'
import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
import { showToast } from 'vant'
import { loginApi, queryDekey } from '@/api/login'
import { useAppStoreWithOut } from '@/store/modules/app'
@ -22,6 +24,7 @@ const { wsCache } = useCache()
const appStore = useAppStoreWithOut()
const userStore = useUserStoreWithOut()
const router = useRouter()
const appearanceStore = useAppearanceStoreWithOut()
const username = ref('')
const password = ref('')
@ -55,7 +58,18 @@ const inputFocus = ref('')
const handleFocus = val => {
inputFocus.value = val
}
const mobileLogin = ref('')
const mobileLoginBg = ref('')
const loadAppearance = () => {
if (appearanceStore.getMobileLogin) {
mobileLogin.value = appearanceStore.getMobileLogin
}
if (appearanceStore.getMobileLoginBg) {
mobileLoginBg.value = appearanceStore.getMobileLoginBg
}
}
loadAppearance()
const handleBlur = () => {
inputFocus.value = ''
}
@ -101,8 +115,9 @@ const usernameEndValidate = ({ status, message }) => {
<template>
<div class="de-mobile-login" v-loading="duringLogin">
<img class="mobile-login_bg" :src="mobileLoginBg ? mobileLoginBg : mobileWholeBg" alt="" />
<div class="mobile-login-content">
<img width="120" height="31" :src="mobileDeTop" alt="" />
<img width="120" height="31" :src="mobileLogin ? mobileLogin : mobileDeTop" alt="" />
<div class="mobile-login-welcome">用户登录</div>
<van-form @submit="onSubmit">
<van-cell-group inset>
@ -157,7 +172,13 @@ const usernameEndValidate = ({ status, message }) => {
position: relative;
background-size: contain;
background-repeat: no-repeat;
background-image: url(../../../assets/img/bg-mobile.png);
.mobile-login_bg {
width: 100%;
height: 100%;
position: relative;
z-index: 1;
}
.mobile-login-content {
background: linear-gradient(180deg, rgba(255, 255, 255, 0.94) 0%, #ffffff 58.86%);
@ -170,6 +191,7 @@ const usernameEndValidate = ({ status, message }) => {
width: 100%;
height: 70%;
padding: 24px 16px;
z-index: 10;
--van-cell-group-inset-padding: 0;
--van-cell-group-inset-radius: 0;
--van-cell-group-background: transparent;

View File

@ -924,7 +924,7 @@ const getMenuList = (val: boolean) => {
</el-button>
<el-button type="primary" @click="exportDataset">
<template #icon>
<Icon name="el-icon-download"></Icon>
<Icon name="dv-preview-download"></Icon>
</template>
数据集导出
</el-button>
@ -1048,6 +1048,7 @@ const getMenuList = (val: boolean) => {
<el-form
ref="exportFormRef"
class="de-form-item"
@submit.prevent
:model="exportForm"
:rules="exportFormRules"
:before-close="closeExport"

View File

@ -533,7 +533,8 @@ const defaultForm = {
description: '',
type: 'API',
apiConfiguration: [],
paramsConfiguration: []
paramsConfiguration: [],
enableDataFill: false
}
const form = reactive<Form>(cloneDeep(defaultForm))
const defaultForm2 = {
@ -859,6 +860,8 @@ defineExpose({
<style lang="less">
.datasource-drawer-fullscreen {
z-index: 1000 !important;
.ed-drawer__body {
padding: 0;
}

@ -1 +1 @@
Subproject commit bab1ca0e386dc0f4941b163e626253b8d6f11bc2
Subproject commit d47c2a58d47a50924b38e6d68b382cd9692c389e

View File

@ -10,10 +10,7 @@ import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
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 org.springframework.web.bind.annotation.*;
import java.util.List;
@ -70,4 +67,8 @@ public interface ThresholdApi {
@Operation(summary = "视图是否设置了阈值告警")
@GetMapping("/anyThreshold/{chartId}")
boolean anyThreshold(@PathVariable("chartId") Long chartId);
@Operation(summary = "根据视图ID删除")
@GetMapping("/deleteWithChart/{chartId}")
void deleteWithChart(@PathVariable("chartId") Long chartId);
}