forked from github/dataease
Merge branch 'dev-v2' into pr@dev-v2@refactor_workbranc
This commit is contained in:
commit
81df4a1073
@ -109,6 +109,7 @@ public class MapManage {
|
||||
@CacheEvict(cacheNames = WORLD_MAP_CACHE, key = "'world_map'")
|
||||
@Transactional
|
||||
public void saveMapGeo(GeometryNodeCreator request, MultipartFile file) {
|
||||
validateCode(request.getCode());
|
||||
if (ObjectUtils.isEmpty(file) || file.isEmpty()) {
|
||||
DEException.throwException("geometry file is require");
|
||||
}
|
||||
@ -154,6 +155,7 @@ public class MapManage {
|
||||
@CacheEvict(cacheNames = WORLD_MAP_CACHE, key = "'world_map'")
|
||||
@Transactional
|
||||
public void deleteGeo(String code) {
|
||||
validateCode(code);
|
||||
if (!StringUtils.startsWith(code, GEO_PREFIX)) {
|
||||
DEException.throwException("内置Geometry,禁止删除");
|
||||
}
|
||||
@ -209,5 +211,20 @@ public class MapManage {
|
||||
return code.substring(0, 3);
|
||||
}
|
||||
|
||||
public void validateCode(String code) {
|
||||
if (StringUtils.isBlank(code)) DEException.throwException("区域编码不能为空");
|
||||
String busiGeoCode = getBusiGeoCode(code);
|
||||
if (!isNumeric(busiGeoCode)) {
|
||||
DEException.throwException("有效区域编码只能是数字");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isNumeric(String str) {
|
||||
for (int i = str.length(); --i >= 0; ) {
|
||||
int chr = str.charAt(i);
|
||||
if (chr < 48 || chr > 57)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
"axios": "^1.3.3",
|
||||
"crypto-js": "^4.1.1",
|
||||
"dayjs": "^1.11.9",
|
||||
"element-plus-secondary": "^0.5.3",
|
||||
"element-plus-secondary": "^0.5.4",
|
||||
"element-resize-detector": "^1.2.4",
|
||||
"file-saver": "^2.0.5",
|
||||
"html-to-image": "^1.11.11",
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 34 KiB |
@ -92,7 +92,9 @@ const navigate = computed(() => appearanceStore.getNavigate)
|
||||
border-color: #1f232926 !important;
|
||||
}
|
||||
|
||||
.system,
|
||||
.system {
|
||||
color: #000 !important;
|
||||
}
|
||||
.de-logo {
|
||||
color: #3371ff !important;
|
||||
}
|
||||
|
@ -642,6 +642,7 @@ export default {
|
||||
table_header_font_color: '表头字体',
|
||||
table_item_font_color: '表格字体',
|
||||
table_show_index: '显示序号',
|
||||
table_header_sort: '开启表头排序',
|
||||
stripe: '斑马纹',
|
||||
start_angle: '起始角度',
|
||||
end_angle: '结束角度',
|
||||
|
@ -221,6 +221,10 @@ declare interface ChartTableHeaderAttr {
|
||||
* 序号表头名称
|
||||
*/
|
||||
indexLabel: string
|
||||
/**
|
||||
* 表头排序开关
|
||||
*/
|
||||
tableHeaderSort: boolean
|
||||
}
|
||||
/**
|
||||
* 单元格属性
|
||||
|
@ -3,6 +3,7 @@ import '../../assets/font/index.css'
|
||||
import '@/style/index.less'
|
||||
import '@/plugins/svg-icon'
|
||||
import 'normalize.css/normalize.css'
|
||||
import '@antv/s2/dist/style.min.css'
|
||||
import App from './App.vue'
|
||||
import { setupI18n } from '@/plugins/vue-i18n'
|
||||
import { setupStore } from '@/store'
|
||||
|
@ -1,6 +1,7 @@
|
||||
import '@/style/index.less'
|
||||
import '@/plugins/svg-icon'
|
||||
import 'normalize.css/normalize.css'
|
||||
import '@antv/s2/dist/style.min.css'
|
||||
import { setupI18n } from '@/plugins/vue-i18n'
|
||||
import { setupStore } from '@/store'
|
||||
import { setupElementPlus } from '@/plugins/element-plus'
|
||||
|
@ -3,6 +3,7 @@ import '../../assets/font/index.css'
|
||||
import '@/style/index.less'
|
||||
import '@/plugins/svg-icon'
|
||||
import 'normalize.css/normalize.css'
|
||||
import '@antv/s2/dist/style.min.css'
|
||||
import App from './App.vue'
|
||||
import { setupI18n } from '@/plugins/vue-i18n'
|
||||
import { setupStore } from '@/store'
|
||||
|
@ -58,6 +58,7 @@ import '../../assets/font/index.css'
|
||||
import '@/style/index.less'
|
||||
import '@/plugins/svg-icon'
|
||||
import 'normalize.css/normalize.css'
|
||||
import '@antv/s2/dist/style.min.css'
|
||||
import AppElement from './App.vue'
|
||||
import { setupI18n } from '@/plugins/vue-i18n'
|
||||
import { setupStore } from '@/store'
|
||||
|
@ -236,6 +236,21 @@ onMounted(() => {
|
||||
@blur="changeTableHeader('indexLabel')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="t('chart.table_show_index')"
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
v-if="showProperty('tableHeaderSort')"
|
||||
>
|
||||
<el-checkbox
|
||||
size="small"
|
||||
:effect="themes"
|
||||
v-model="state.tableHeaderForm.tableHeaderSort"
|
||||
@change="changeTableHeader('tableHeaderSort')"
|
||||
>
|
||||
{{ t('chart.table_header_sort') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
|
@ -329,7 +329,8 @@ export const DEFAULT_TABLE_HEADER: ChartTableHeaderAttr = {
|
||||
tableHeaderBgColor: '#6D9A49',
|
||||
tableHeaderFontColor: '#000000',
|
||||
tableTitleFontSize: 12,
|
||||
tableTitleHeight: 36
|
||||
tableTitleHeight: 36,
|
||||
tableHeaderSort: false
|
||||
}
|
||||
export const DEFAULT_TABLE_CELL: ChartTableCellAttr = {
|
||||
tableFontColor: '#000000',
|
||||
|
@ -127,37 +127,6 @@ export class Waterfall extends G2PlotChartView<WaterfallOptions, G2Waterfall> {
|
||||
fill: setGradientColor(hexColorToRGBA(totalColorRgba, alpha), gradient, 270)
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
items: [
|
||||
{
|
||||
name: '增加',
|
||||
value: '',
|
||||
marker: {
|
||||
style: {
|
||||
fill: setGradientColor(hexColorToRGBA(risingColorRgba, alpha), gradient, 270)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '减少',
|
||||
value: '',
|
||||
marker: {
|
||||
style: {
|
||||
fill: setGradientColor(hexColorToRGBA(fallingColorRgba, alpha), gradient, 270)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '合计',
|
||||
value: '',
|
||||
marker: {
|
||||
style: {
|
||||
fill: setGradientColor(hexColorToRGBA(totalColorRgba, alpha), gradient, 270)
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
risingFill: setGradientColor(hexColorToRGBA(risingColorRgba, alpha), gradient, 270),
|
||||
fallingFill: setGradientColor(hexColorToRGBA(fallingColorRgba, alpha), gradient, 270)
|
||||
}
|
||||
@ -256,9 +225,55 @@ export class Waterfall extends G2PlotChartView<WaterfallOptions, G2Waterfall> {
|
||||
}
|
||||
}
|
||||
|
||||
protected configLegend(chart: Chart, options: WaterfallOptions): WaterfallOptions {
|
||||
const tmp = super.configLegend(chart, options)
|
||||
if (!tmp.legend) {
|
||||
return tmp
|
||||
}
|
||||
const customAttr = parseJson(chart.customAttr)
|
||||
const { colors, gradient, alpha } = customAttr.basicStyle
|
||||
const [risingColorRgba, fallingColorRgba, totalColorRgba] = colors
|
||||
return {
|
||||
...tmp,
|
||||
legend: {
|
||||
...tmp.legend,
|
||||
items: [
|
||||
{
|
||||
name: '增加',
|
||||
value: '',
|
||||
marker: {
|
||||
style: {
|
||||
fill: setGradientColor(hexColorToRGBA(risingColorRgba, alpha), gradient, 270)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '减少',
|
||||
value: '',
|
||||
marker: {
|
||||
style: {
|
||||
fill: setGradientColor(hexColorToRGBA(fallingColorRgba, alpha), gradient, 270)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '合计',
|
||||
value: '',
|
||||
marker: {
|
||||
style: {
|
||||
fill: setGradientColor(hexColorToRGBA(totalColorRgba, alpha), gradient, 270)
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected setupOptions(chart: Chart, options: WaterfallOptions): WaterfallOptions {
|
||||
return flow(
|
||||
this.configTheme,
|
||||
this.configLegend,
|
||||
this.configBasicStyle,
|
||||
this.configLabel,
|
||||
this.configTooltip,
|
||||
|
@ -91,9 +91,6 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
||||
active: { stroke: 'green', lineWidth: 1 }
|
||||
},
|
||||
tooltip: {},
|
||||
zoom: {
|
||||
position: 'bottomright'
|
||||
},
|
||||
legend: false,
|
||||
// 禁用线上地图数据
|
||||
customFetchGeoData: () => null
|
||||
@ -101,6 +98,7 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
||||
options = this.setupOptions(chart, options, drawOption, geoJson)
|
||||
const view = new Choropleth(container, options)
|
||||
const dotLayer = this.getDotLayer(chart, geoJson, drawOption)
|
||||
this.configZoomButton(view)
|
||||
view.once('loaded', () => {
|
||||
view.addLayer(dotLayer)
|
||||
view.on('fillAreaLayer:click', (ev: MapMouseEvent) => {
|
||||
|
@ -90,9 +90,6 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
||||
active: { stroke: 'green', lineWidth: 1 }
|
||||
},
|
||||
tooltip: {},
|
||||
zoom: {
|
||||
position: 'bottomright'
|
||||
},
|
||||
legend: {
|
||||
position: 'bottomleft'
|
||||
},
|
||||
@ -101,6 +98,7 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
||||
}
|
||||
options = this.setupOptions(chart, options, drawOption, geoJson)
|
||||
const view = new Choropleth(container, options)
|
||||
this.configZoomButton(view)
|
||||
view.once('loaded', () => {
|
||||
view.on('fillAreaLayer:click', (ev: MapMouseEvent) => {
|
||||
const data = ev.feature.properties
|
||||
|
@ -16,6 +16,10 @@ export class TableInfo extends S2ChartView<TableSheet> {
|
||||
properties = TABLE_EDITOR_PROPERTY
|
||||
propertyInner = {
|
||||
...TABLE_EDITOR_PROPERTY_INNER,
|
||||
'table-header-selector': [
|
||||
...TABLE_EDITOR_PROPERTY_INNER['table-header-selector'],
|
||||
'tableHeaderSort'
|
||||
],
|
||||
'basic-style-selector': [
|
||||
'tableColumnMode',
|
||||
'tableBorderColor',
|
||||
@ -101,7 +105,10 @@ export class TableInfo extends S2ChartView<TableSheet> {
|
||||
height: containerDom.offsetHeight,
|
||||
showSeriesNumber: customAttr.tableHeader.showIndex,
|
||||
style: this.configStyle(chart),
|
||||
conditions: this.configConditions(chart)
|
||||
conditions: this.configConditions(chart),
|
||||
tooltip: {
|
||||
getContainer: () => containerDom
|
||||
}
|
||||
}
|
||||
// 开启序号之后,第一列就是序号列,修改 label 即可
|
||||
if (s2Options.showSeriesNumber) {
|
||||
@ -128,6 +135,8 @@ export class TableInfo extends S2ChartView<TableSheet> {
|
||||
}
|
||||
// tooltip
|
||||
this.configTooltip(s2Options)
|
||||
// header interaction
|
||||
this.configHeaderInteraction(chart, s2Options)
|
||||
// 开始渲染
|
||||
const newChart = new TableSheet(containerDom, s2DataConfig, s2Options)
|
||||
|
||||
|
@ -13,7 +13,13 @@ const { t } = useI18n()
|
||||
*/
|
||||
export class TableNormal extends S2ChartView<TableSheet> {
|
||||
properties = TABLE_EDITOR_PROPERTY
|
||||
propertyInner = TABLE_EDITOR_PROPERTY_INNER
|
||||
propertyInner = {
|
||||
...TABLE_EDITOR_PROPERTY_INNER,
|
||||
'table-header-selector': [
|
||||
...TABLE_EDITOR_PROPERTY_INNER['table-header-selector'],
|
||||
'tableHeaderSort'
|
||||
]
|
||||
}
|
||||
axis: AxisType[] = ['xAxis', 'yAxis', 'drill', 'filter']
|
||||
axisConfig: AxisConfig = {
|
||||
xAxis: {
|
||||
@ -102,7 +108,10 @@ export class TableNormal extends S2ChartView<TableSheet> {
|
||||
height: containerDom.offsetHeight,
|
||||
showSeriesNumber: customAttr.tableHeader.showIndex,
|
||||
style: this.configStyle(chart),
|
||||
conditions: this.configConditions(chart)
|
||||
conditions: this.configConditions(chart),
|
||||
tooltip: {
|
||||
getContainer: () => containerDom
|
||||
}
|
||||
}
|
||||
// 开启序号之后,第一列就是序号列,修改 label 即可
|
||||
if (s2Options.showSeriesNumber) {
|
||||
@ -122,6 +131,8 @@ export class TableNormal extends S2ChartView<TableSheet> {
|
||||
}
|
||||
// tooltip
|
||||
this.configTooltip(s2Options)
|
||||
// header interaction
|
||||
this.configHeaderInteraction(chart, s2Options)
|
||||
// 开始渲染
|
||||
const newChart = new TableSheet(containerDom, s2DataConfig, s2Options)
|
||||
|
||||
|
@ -83,7 +83,7 @@ export class TablePivot extends S2ChartView<PivotSheet> {
|
||||
columns.push(ele.dataeaseName)
|
||||
meta.push({
|
||||
field: ele.dataeaseName,
|
||||
name: ele.name,
|
||||
name: ele.chartShowName ?? ele.name,
|
||||
formatter: value => {
|
||||
if (!f) {
|
||||
return value
|
||||
|
@ -21,6 +21,11 @@ import {
|
||||
LIST_CLASS
|
||||
} from '@antv/l7plot-component/dist/esm/legend/category/constants'
|
||||
import substitute from '@antv/util/esm/substitute'
|
||||
import { Plot as L7Plot } from '@antv/l7plot/dist/esm/core/plot'
|
||||
import type { PlotOptions } from '@antv/l7plot/dist/esm/types'
|
||||
import { Zoom } from '@antv/l7'
|
||||
import { createL7Icon } from '@antv/l7-component/es/utils/icon'
|
||||
import { DOM } from '@antv/l7-utils'
|
||||
|
||||
export function getPadding(chart: Chart): number[] {
|
||||
if (chart.drill) {
|
||||
@ -814,3 +819,47 @@ export function configL7Legend(): LegendOptions {
|
||||
}
|
||||
}
|
||||
}
|
||||
class CustomZoom extends Zoom {
|
||||
resetButtonGroup(container) {
|
||||
DOM.clearChildren(container)
|
||||
this['zoomInButton'] = this['createButton'](
|
||||
this.controlOption.zoomInText,
|
||||
this.controlOption.zoomInTitle,
|
||||
'l7-button-control',
|
||||
container,
|
||||
this.zoomIn
|
||||
)
|
||||
const resetBtnIconText = createL7Icon('l7-icon-round')
|
||||
this['createButton'](resetBtnIconText, 'Reset', 'l7-button-control', container, () => {
|
||||
this.mapsService.setZoomAndCenter(
|
||||
this.controlOption['initZoom'],
|
||||
this.controlOption['center']
|
||||
)
|
||||
})
|
||||
if (this.controlOption.showZoom) {
|
||||
this['zoomNumDiv'] = this['createButton'](
|
||||
'0',
|
||||
'',
|
||||
'l7-button-control l7-control-zoom__number',
|
||||
container
|
||||
)
|
||||
}
|
||||
this['zoomOutButton'] = this['createButton'](
|
||||
this.controlOption.zoomOutText,
|
||||
this.controlOption.zoomOutTitle,
|
||||
'l7-button-control',
|
||||
container,
|
||||
this.zoomOut
|
||||
)
|
||||
this['updateDisabled']()
|
||||
}
|
||||
}
|
||||
export function configL7Zoom(plot: L7Plot<PlotOptions>) {
|
||||
plot.once('loaded', () => {
|
||||
const zoomOptions = {
|
||||
initZoom: plot.scene.getZoom(),
|
||||
center: plot.scene.getCenter()
|
||||
} as any
|
||||
plot.scene.addControl(new CustomZoom(zoomOptions))
|
||||
})
|
||||
}
|
||||
|
@ -632,24 +632,60 @@ class SortTooltip extends BaseTooltip {
|
||||
left: `${this.position?.x}px`,
|
||||
top: `${this.position?.y}px`,
|
||||
pointerEvents: enterable ? 'all' : 'none',
|
||||
zIndex: 9999
|
||||
zIndex: 9999,
|
||||
position: 'absolute'
|
||||
},
|
||||
visible: true
|
||||
})
|
||||
}
|
||||
}
|
||||
export function configTooltip(option: S2Options) {
|
||||
const SORT_DEFAULT =
|
||||
'<svg t="1711681787276" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4355" width="200" height="200"><path d="M922.345786 372.183628l-39.393195 38.687114L676.138314 211.079416l0 683.909301-54.713113 0L621.425202 129.010259l53.320393 0L922.345786 372.183628zM349.254406 894.989741 101.654214 651.815349l39.393195-38.687114 206.814276 199.792349L347.861686 129.010259l54.713113 0 0 765.978459L349.254406 894.988718z" fill="{fill}" p-id="4356"></path></svg>'
|
||||
const SORT_UP =
|
||||
'<svg t="1711682928245" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11756" width="200" height="200"><path d="M960 704L512 256 64 704z" fill="{fill}" p-id="11757"></path></svg>'
|
||||
const SORT_DOWN =
|
||||
'<svg t="1711681879346" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4655" width="200" height="200"><path d="M64 320l448 448 448-448z" fill="{fill}" p-id="4656"></path></svg>'
|
||||
|
||||
function svg2Base64(svg) {
|
||||
return `data:image/svg+xml;charset=utf-8;base64,${btoa(svg)}`
|
||||
}
|
||||
|
||||
export function configHeaderInteraction(chart: Chart, option: S2Options) {
|
||||
const { tableHeaderFontColor, tableHeaderSort } = parseJson(chart.customAttr).tableHeader
|
||||
if (!tableHeaderSort) {
|
||||
return
|
||||
}
|
||||
const iconColor = tableHeaderFontColor ?? '#666'
|
||||
const sortDefault = svg2Base64(SORT_DEFAULT.replace('{fill}', iconColor))
|
||||
const sortUp = svg2Base64(SORT_UP.replace('{fill}', iconColor))
|
||||
const sortDown = svg2Base64(SORT_DOWN.replace('{fill}', iconColor))
|
||||
// 防止缓存
|
||||
const randomSuffix = Math.random()
|
||||
const sortIconMap = {
|
||||
asc: 'SortUp',
|
||||
desc: 'SortDown'
|
||||
}
|
||||
option.tooltip = {
|
||||
...option.tooltip,
|
||||
renderTooltip: sheet => new SortTooltip(sheet)
|
||||
asc: `customSortUp${randomSuffix}`,
|
||||
desc: `customSortDown${randomSuffix}`
|
||||
}
|
||||
option.customSVGIcons = [
|
||||
{
|
||||
name: `customSortDefault${randomSuffix}`,
|
||||
svg: sortDefault
|
||||
},
|
||||
{
|
||||
name: `customSortUp${randomSuffix}`,
|
||||
svg: sortUp
|
||||
},
|
||||
{
|
||||
name: `customSortDown${randomSuffix}`,
|
||||
svg: sortDown
|
||||
}
|
||||
]
|
||||
option.headerActionIcons = [
|
||||
{
|
||||
iconNames: ['GroupAsc', 'SortUp', 'SortDown'],
|
||||
iconNames: [
|
||||
`customSortDefault${randomSuffix}`,
|
||||
`customSortUp${randomSuffix}`,
|
||||
`customSortDown${randomSuffix}`
|
||||
],
|
||||
belongsCell: 'colCell',
|
||||
displayCondition: (meta, iconName) => {
|
||||
if (meta.field === SERIES_NUMBER_FIELD) {
|
||||
@ -660,7 +696,7 @@ export function configTooltip(option: S2Options) {
|
||||
if (sortType) {
|
||||
return iconName === sortIconMap[sortType]
|
||||
}
|
||||
return iconName === 'GroupAsc'
|
||||
return iconName === `customSortDefault${randomSuffix}`
|
||||
},
|
||||
onClick: props => {
|
||||
const { meta, event } = props
|
||||
@ -677,6 +713,16 @@ export function configTooltip(option: S2Options) {
|
||||
]
|
||||
}
|
||||
|
||||
export function configTooltip(option: S2Options) {
|
||||
option.tooltip = {
|
||||
...option.tooltip,
|
||||
adjustPosition: ({ event }) => {
|
||||
return getTooltipPosition(event)
|
||||
},
|
||||
renderTooltip: sheet => new SortTooltip(sheet)
|
||||
}
|
||||
}
|
||||
|
||||
export function copyContent(s2Instance, event, fieldMeta) {
|
||||
event.preventDefault()
|
||||
const cell = s2Instance.getCell(event.target)
|
||||
@ -706,3 +752,30 @@ export function copyContent(s2Instance, event, fieldMeta) {
|
||||
copyString(content, true)
|
||||
}
|
||||
}
|
||||
|
||||
function getTooltipPosition(event) {
|
||||
const s2Instance = event.s2Instance
|
||||
const { x, y } = event
|
||||
const result = { x: x + 15, y: y + 10 }
|
||||
if (!s2Instance) {
|
||||
return result
|
||||
}
|
||||
const { height, width } = s2Instance.getCanvasElement().getBoundingClientRect()
|
||||
const { offsetHeight, offsetWidth } = s2Instance.tooltip.getContainer()
|
||||
if (offsetWidth > width) {
|
||||
result.x = 0
|
||||
}
|
||||
if (offsetHeight > height) {
|
||||
result.y = 0
|
||||
}
|
||||
if (!(result.x || result.y)) {
|
||||
return result
|
||||
}
|
||||
if (result.x && result.x + offsetWidth > width) {
|
||||
result.x -= result.x + offsetWidth - width
|
||||
}
|
||||
if (result.y && result.y + offsetHeight > height) {
|
||||
result.y -= offsetHeight + 15
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
@ -6,7 +6,8 @@ import {
|
||||
configL7Label,
|
||||
configL7Legend,
|
||||
configL7Style,
|
||||
configL7Tooltip
|
||||
configL7Tooltip,
|
||||
configL7Zoom
|
||||
} from '@/views/chart/components/js/panel/common/common_antv'
|
||||
import {
|
||||
AntVAbstractChartView,
|
||||
@ -73,6 +74,10 @@ export abstract class L7PlotChartView<
|
||||
options.source.data = data
|
||||
return options
|
||||
}
|
||||
|
||||
protected configZoomButton(plot: P) {
|
||||
configL7Zoom(plot)
|
||||
}
|
||||
protected constructor(name: string, defaultData?: any[]) {
|
||||
super(ChartLibraryType.L7_PLOT, name)
|
||||
this.defaultData = defaultData
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
} from '@/views/chart/components/js/panel/types'
|
||||
import { S2Theme, SpreadSheet, Style, S2Options } from '@antv/s2'
|
||||
import {
|
||||
configHeaderInteraction,
|
||||
configTooltip,
|
||||
getConditions,
|
||||
getCustomTheme,
|
||||
@ -44,6 +45,10 @@ export abstract class S2ChartView<P extends SpreadSheet> extends AntVAbstractCha
|
||||
configTooltip(option)
|
||||
}
|
||||
|
||||
protected configHeaderInteraction(chart: Chart, option: S2Options) {
|
||||
configHeaderInteraction(chart, option)
|
||||
}
|
||||
|
||||
protected configConditions(chart: Chart) {
|
||||
return getConditions(chart)
|
||||
}
|
||||
|
@ -404,7 +404,7 @@ const autoHeightStyle = computed(() => {
|
||||
@trackClick="trackClick"
|
||||
/>
|
||||
<div v-if="!isError" class="canvas-content">
|
||||
<div style="height: 100%" :id="containerId"></div>
|
||||
<div style="position: relative; height: 100%" :id="containerId"></div>
|
||||
</div>
|
||||
<el-row :style="autoHeightStyle" v-if="showPage && !isError">
|
||||
<div :style="autoStyle" class="table-page-info">
|
||||
|
@ -208,8 +208,14 @@ const save = () => {
|
||||
<span class="open-mobile">开启移动端</span>
|
||||
<el-switch size="small" v-model="dvInfo.mobileLayout" />
|
||||
<span class="open-mobile-line"></span>
|
||||
<el-tooltip effect="dark" content="切换至PC端布局" placement="bottom">
|
||||
<el-icon @click="handleBack">
|
||||
<el-tooltip
|
||||
:show-arrow="false"
|
||||
:offset="9"
|
||||
effect="dark"
|
||||
content="切换至PC端布局"
|
||||
placement="bottom"
|
||||
>
|
||||
<el-icon @click="handleBack" class="switch-pc">
|
||||
<Icon name="icon_pc_outlined" />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
@ -296,7 +302,26 @@ const save = () => {
|
||||
.mobile-save {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.switch-pc {
|
||||
&::after {
|
||||
content: '';
|
||||
border-radius: 4px;
|
||||
display: none;
|
||||
position: absolute;
|
||||
width: calc(100% + 10px);
|
||||
height: calc(100% + 10px);
|
||||
top: -5px;
|
||||
left: -5px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&::after {
|
||||
display: block;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
position: relative;
|
||||
}
|
||||
.open-mobile-line {
|
||||
background: #ffffff4d;
|
||||
width: 1px;
|
||||
@ -349,7 +374,7 @@ const save = () => {
|
||||
|
||||
.mobile-header {
|
||||
margin-top: 20px;
|
||||
height: 44px;
|
||||
height: 43px;
|
||||
display: flex;
|
||||
img {
|
||||
height: 100%;
|
||||
|
@ -81,6 +81,13 @@ const dataClick = val => {
|
||||
directId.value.push(val.id)
|
||||
}
|
||||
|
||||
const handleDir = index => {
|
||||
if (index === directId.value.length - 1) return
|
||||
directId.value = directId.value.slice(0, index + 1)
|
||||
directName.value = directName.value.slice(0, index + 1)
|
||||
activeDirectName.value = directName.value[directName.value.length - 1]
|
||||
}
|
||||
|
||||
const getTree = async () => {
|
||||
const request = { busiFlag: 'dashboard' } as BusiTreeRequest
|
||||
await interactiveStore.setInteractive(request)
|
||||
@ -127,8 +134,10 @@ onMounted(() => {
|
||||
<Icon name="icon_right_outlined"></Icon>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div v-for="(ele, index) in [...directName]" :key="ele">
|
||||
<span class="label">{{ ele }}</span>
|
||||
<div v-for="(ele, index) in [...directName]" @click="handleDir(index)" :key="ele">
|
||||
<span class="label ellipsis" :class="index !== directName.length - 1 && 'primary-name'">{{
|
||||
ele
|
||||
}}</span>
|
||||
<el-icon v-if="index !== directName.length - 1">
|
||||
<Icon name="icon_right_outlined"></Icon>
|
||||
</el-icon>
|
||||
@ -168,16 +177,20 @@ onMounted(() => {
|
||||
padding: 12px 16px;
|
||||
color: #646a73;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
align-items: center;
|
||||
& > div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
max-width: 250px;
|
||||
}
|
||||
|
||||
.ed-icon {
|
||||
|
@ -48,11 +48,47 @@ const findName = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let directIdCopy = []
|
||||
let directNameCopy = []
|
||||
|
||||
const dfsOrgTree = (arr, depth) => {
|
||||
arr.forEach(item => {
|
||||
const { name, id } = item
|
||||
if (depth <= directIdCopy.length) {
|
||||
if (depth < directIdCopy.length) {
|
||||
directIdCopy = directIdCopy.slice(0, depth)
|
||||
directNameCopy = directNameCopy.slice(0, depth)
|
||||
}
|
||||
directIdCopy.splice(directIdCopy.length - 1, 1, id)
|
||||
directNameCopy.splice(directNameCopy.length - 1, 1, name)
|
||||
} else {
|
||||
directIdCopy.push(id)
|
||||
directNameCopy.push(name)
|
||||
}
|
||||
|
||||
let nextDepth = depth + 1
|
||||
|
||||
if (id === userStore.getOid) {
|
||||
directName.value = [...directNameCopy]
|
||||
directId.value = [...directIdCopy]
|
||||
nextDepth = 999
|
||||
}
|
||||
if (item?.children?.length && nextDepth !== 999) {
|
||||
dfsOrgTree(item?.children, nextDepth)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
mountedOrg().then(res => {
|
||||
orgOption = res.data as OrgTreeNode[]
|
||||
tableData.value = res.data as OrgTreeNode[]
|
||||
findName()
|
||||
dfsOrgTree(orgOption, 1)
|
||||
directName.value.pop()
|
||||
directId.value.pop()
|
||||
activeDirectName.value = directName.value[directName.value.length - 1]
|
||||
})
|
||||
})
|
||||
|
||||
@ -84,6 +120,13 @@ const orgCellClick = (type, val) => {
|
||||
}
|
||||
}
|
||||
|
||||
const handleDir = index => {
|
||||
if (index === directId.value.length - 1) return
|
||||
directId.value = directId.value.slice(0, index + 1)
|
||||
directName.value = directName.value.slice(0, index + 1)
|
||||
activeDirectName.value = directName.value[directName.value.length - 1]
|
||||
}
|
||||
|
||||
const tableData = ref([])
|
||||
const directName = ref([])
|
||||
const directId = ref([])
|
||||
@ -134,8 +177,13 @@ const activeTableData = computed(() => {
|
||||
@click-left="onClickLeft"
|
||||
/>
|
||||
<div class="grey">
|
||||
<div class="flex-align-center" v-for="(ele, index) in directName" :key="ele">
|
||||
<span :class="ele !== activeDirectName && 'active'">{{ ele }}</span>
|
||||
<div
|
||||
@click="handleDir(index)"
|
||||
class="flex-align-center"
|
||||
v-for="(ele, index) in directName"
|
||||
:key="ele"
|
||||
>
|
||||
<span class="ellipsis" :class="ele !== activeDirectName && 'active'">{{ ele }}</span>
|
||||
<el-icon v-if="directName.length > 1 && index !== directName.length - 1">
|
||||
<Icon name="icon_right_outlined"></Icon>
|
||||
</el-icon>
|
||||
@ -202,6 +250,14 @@ const activeTableData = computed(() => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
& > div {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ellipsis {
|
||||
max-width: 250px;
|
||||
}
|
||||
|
||||
.active {
|
||||
color: var(--ed-color-primary);
|
||||
}
|
||||
|
@ -230,8 +230,8 @@ watch(
|
||||
align-items: center;
|
||||
}
|
||||
.main-color {
|
||||
font-size: 21.33px;
|
||||
padding: 5.33px;
|
||||
font-size: 18px;
|
||||
padding: 3px;
|
||||
margin-right: 12px;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="tsx" setup>
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { ref, reactive, shallowRef, computed, watch, onBeforeMount, nextTick } from 'vue'
|
||||
import { ref, reactive, shallowRef, computed, watch, onBeforeMount, nextTick, unref } from 'vue'
|
||||
import ArrowSide from '@/views/common/DeResourceArrow.vue'
|
||||
import {
|
||||
ElIcon,
|
||||
@ -25,6 +25,7 @@ import { save } from '@/api/visualization/dataVisualization'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { fieldType } from '@/utils/attr'
|
||||
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||
import treeSort from '@/utils/treeSortUtils'
|
||||
|
||||
import {
|
||||
DEFAULT_CANVAS_STYLE_DATA_LIGHT,
|
||||
@ -59,7 +60,8 @@ const router = useRouter()
|
||||
const route = useRoute()
|
||||
const { t } = useI18n()
|
||||
const state = reactive({
|
||||
datasetTree: [] as BusiTreeNode[]
|
||||
datasetTree: [] as BusiTreeNode[],
|
||||
curSortType: 'time_desc'
|
||||
})
|
||||
|
||||
const resourceGroupOpt = ref()
|
||||
@ -79,6 +81,13 @@ const resourceOptFinish = param => {
|
||||
}
|
||||
}
|
||||
|
||||
let originResourceTree = []
|
||||
|
||||
const sortTypeChange = sortType => {
|
||||
state.datasetTree = treeSort(originResourceTree, sortType)
|
||||
state.curSortType = sortType
|
||||
}
|
||||
|
||||
const resourceCreate = (pid, name) => {
|
||||
// 新建基础信息
|
||||
const newResourceId = guid()
|
||||
@ -201,9 +210,11 @@ const getData = () => {
|
||||
if (nodeData.length && nodeData[0]['id'] === '0' && nodeData[0]['name'] === 'root') {
|
||||
rootManage.value = nodeData[0]['weight'] >= 7
|
||||
state.datasetTree = nodeData[0]['children'] || []
|
||||
originResourceTree = cloneDeep(unref(state.datasetTree))
|
||||
return
|
||||
}
|
||||
state.datasetTree = nodeData
|
||||
originResourceTree = cloneDeep(unref(state.datasetTree))
|
||||
})
|
||||
.finally(() => {
|
||||
dtLoading.value = false
|
||||
@ -439,6 +450,27 @@ const defaultTab = [
|
||||
name: 'structPreview'
|
||||
}
|
||||
]
|
||||
|
||||
const sortList = [
|
||||
{
|
||||
name: '按创建时间升序',
|
||||
value: 'time_asc'
|
||||
},
|
||||
{
|
||||
name: '按创建时间降序',
|
||||
value: 'time_desc',
|
||||
divided: true
|
||||
},
|
||||
{
|
||||
name: '按照名称升序',
|
||||
value: 'name_asc'
|
||||
},
|
||||
{
|
||||
name: '按照名称降序',
|
||||
value: 'name_desc'
|
||||
}
|
||||
]
|
||||
|
||||
const tablePanes = ref([])
|
||||
const tablePaneList = computed(() => {
|
||||
return nodeInfo.weight >= 7 ? [...defaultTab, ...tablePanes.value] : [...defaultTab]
|
||||
@ -545,6 +577,34 @@ const getMenuList = (val: boolean) => {
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-dropdown @command="sortTypeChange" trigger="click">
|
||||
<el-icon class="insert-filter filter-icon-span">
|
||||
<Icon
|
||||
v-show="state.curSortType.includes('asc')"
|
||||
name="dv-sort-asc"
|
||||
class="opt-icon"
|
||||
></Icon>
|
||||
<Icon
|
||||
v-show="state.curSortType.includes('desc')"
|
||||
name="dv-sort-desc"
|
||||
class="opt-icon"
|
||||
></Icon>
|
||||
</el-icon>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu style="width: 246px">
|
||||
<template :key="ele.value" v-for="ele in sortList">
|
||||
<el-dropdown-item
|
||||
class="ed-select-dropdown__item"
|
||||
:class="ele.value === state.curSortType && 'selected'"
|
||||
:command="ele.value"
|
||||
>
|
||||
{{ ele.name }}
|
||||
</el-dropdown-item>
|
||||
<li v-if="ele.divided" class="ed-dropdown-menu__item--divided"></li>
|
||||
</template>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
|
||||
<el-scrollbar class="custom-tree">
|
||||
@ -727,6 +787,43 @@ const getMenuList = (val: boolean) => {
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import '@/style/mixin.less';
|
||||
.insert-filter {
|
||||
display: inline-block;
|
||||
font-weight: 400 !important;
|
||||
font-family: '阿里巴巴普惠体 3.0 55 Regular L3';
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
color: var(--TextPrimary, #1f2329);
|
||||
-webkit-appearance: none;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
outline: 0;
|
||||
margin: 0;
|
||||
transition: 0.1s;
|
||||
border-radius: 3px;
|
||||
|
||||
&:active {
|
||||
color: #000;
|
||||
border-color: #3a8ee6;
|
||||
background-color: red;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(31, 35, 41, 0.1);
|
||||
color: #3a8ee6;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-icon-span {
|
||||
border: 1px solid #dcdfe6;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 4px;
|
||||
padding: 7px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
.dataset-manage {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
@ -786,6 +883,7 @@ const getMenuList = (val: boolean) => {
|
||||
|
||||
.search-bar {
|
||||
padding-bottom: 10px;
|
||||
width: calc(100% - 40px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script lang="tsx" setup>
|
||||
import { computed, reactive, ref, shallowRef, nextTick, watch, onMounted } from 'vue'
|
||||
import { computed, unref, reactive, ref, shallowRef, nextTick, watch, onMounted } from 'vue'
|
||||
import { dsTypes } from '@/views/visualized/data/datasource/form/option'
|
||||
import type { TabPaneName, ElMessageBoxOptions } from 'element-plus-secondary'
|
||||
import { ElIcon, ElMessageBox, ElMessage, ElScrollbar, ElAside } from 'element-plus-secondary'
|
||||
@ -41,6 +41,7 @@ import type { BusiTreeNode, BusiTreeRequest } from '@/models/tree/TreeNode'
|
||||
import { useMoveLine } from '@/hooks/web/useMoveLine'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { interactiveStoreWithOut } from '@/store/modules/interactive'
|
||||
import treeSort from '@/utils/treeSortUtils'
|
||||
const interactiveStore = interactiveStoreWithOut()
|
||||
interface Field {
|
||||
fieldShortName: string
|
||||
@ -61,6 +62,7 @@ const state = reactive({
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
},
|
||||
curSortType: 'time_desc',
|
||||
filterTable: []
|
||||
})
|
||||
|
||||
@ -157,6 +159,12 @@ const selectDataset = row => {
|
||||
})
|
||||
}
|
||||
|
||||
let originResourceTree = []
|
||||
|
||||
const sortTypeChange = sortType => {
|
||||
state.datasourceTree = treeSort(originResourceTree, sortType)
|
||||
state.curSortType = sortType
|
||||
}
|
||||
const handleSizeChange = pageSize => {
|
||||
state.paginationConfig.currentPage = 1
|
||||
state.paginationConfig.pageSize = pageSize
|
||||
@ -382,8 +390,10 @@ const listDs = () => {
|
||||
if (nodeData.length && nodeData[0]['id'] === '0' && nodeData[0]['name'] === 'root') {
|
||||
rootManage.value = nodeData[0]['weight'] >= 7
|
||||
state.datasourceTree = nodeData[0]['children'] || []
|
||||
originResourceTree = cloneDeep(unref(state.datasourceTree))
|
||||
return
|
||||
}
|
||||
originResourceTree = cloneDeep(unref(state.datasourceTree))
|
||||
state.datasourceTree = nodeData
|
||||
})
|
||||
.finally(() => {
|
||||
@ -414,7 +424,25 @@ const dfsDatasourceTree = (ds, id) => {
|
||||
listDs()
|
||||
|
||||
const creatDsFolder = ref()
|
||||
|
||||
const sortList = [
|
||||
{
|
||||
name: '按创建时间升序',
|
||||
value: 'time_asc'
|
||||
},
|
||||
{
|
||||
name: '按创建时间降序',
|
||||
value: 'time_desc',
|
||||
divided: true
|
||||
},
|
||||
{
|
||||
name: '按照名称升序',
|
||||
value: 'name_asc'
|
||||
},
|
||||
{
|
||||
name: '按照名称降序',
|
||||
value: 'name_desc'
|
||||
}
|
||||
]
|
||||
const tableData = shallowRef([])
|
||||
const tabData = shallowRef([])
|
||||
const handleNodeClick = data => {
|
||||
@ -752,6 +780,34 @@ const getMenuList = (val: boolean) => {
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-dropdown @command="sortTypeChange" trigger="click">
|
||||
<el-icon class="insert-filter filter-icon-span">
|
||||
<Icon
|
||||
v-show="state.curSortType.includes('asc')"
|
||||
name="dv-sort-asc"
|
||||
class="opt-icon"
|
||||
></Icon>
|
||||
<Icon
|
||||
v-show="state.curSortType.includes('desc')"
|
||||
name="dv-sort-desc"
|
||||
class="opt-icon"
|
||||
></Icon>
|
||||
</el-icon>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu style="width: 246px">
|
||||
<template :key="ele.value" v-for="ele in sortList">
|
||||
<el-dropdown-item
|
||||
class="ed-select-dropdown__item"
|
||||
:class="ele.value === state.curSortType && 'selected'"
|
||||
:command="ele.value"
|
||||
>
|
||||
{{ ele.name }}
|
||||
</el-dropdown-item>
|
||||
<li v-if="ele.divided" class="ed-dropdown-menu__item--divided"></li>
|
||||
</template>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<el-scrollbar @scroll="handleScroll" ref="scrollbarRef" class="custom-tree">
|
||||
<el-tree
|
||||
@ -1408,6 +1464,43 @@ const getMenuList = (val: boolean) => {
|
||||
<style lang="less" scoped>
|
||||
@import '@/style/mixin.less';
|
||||
|
||||
.insert-filter {
|
||||
display: inline-block;
|
||||
font-weight: 400 !important;
|
||||
font-family: '阿里巴巴普惠体 3.0 55 Regular L3';
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
color: var(--TextPrimary, #1f2329);
|
||||
-webkit-appearance: none;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
outline: 0;
|
||||
margin: 0;
|
||||
transition: 0.1s;
|
||||
border-radius: 3px;
|
||||
|
||||
&:active {
|
||||
color: #000;
|
||||
border-color: #3a8ee6;
|
||||
background-color: red;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(31, 35, 41, 0.1);
|
||||
color: #3a8ee6;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-icon-span {
|
||||
border: 1px solid #dcdfe6;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 4px;
|
||||
padding: 7px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
.datasource-manage {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
@ -1467,6 +1560,7 @@ const getMenuList = (val: boolean) => {
|
||||
|
||||
.search-bar {
|
||||
padding-bottom: 10px;
|
||||
width: calc(100% - 40px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -359,7 +359,7 @@ const getEmptyDesc = (): string => {
|
||||
>
|
||||
<el-icon
|
||||
class="hover-icon hover-icon-in-table"
|
||||
@click="executeCancelStore(scope.row)"
|
||||
@click.stop="executeCancelStore(scope.row)"
|
||||
>
|
||||
<Icon name="icon_cancel_store"></Icon>
|
||||
</el-icon>
|
||||
@ -370,7 +370,7 @@ const getEmptyDesc = (): string => {
|
||||
<el-tooltip effect="dark" content="打开数据集" placement="top">
|
||||
<el-icon
|
||||
class="hover-icon hover-icon-in-table"
|
||||
@click="
|
||||
@click.stop="
|
||||
openDataset(activeName === 'recent' ? scope.row.id : scope.row.resourceId)
|
||||
"
|
||||
>
|
||||
|
2
de-xpack
2
de-xpack
@ -1 +1 @@
|
||||
Subproject commit 137b8218ee27ecdd58656076423ae1bde1596007
|
||||
Subproject commit 299cd6287249a793abd799f39c40b45d01eb2336
|
Loading…
Reference in New Issue
Block a user