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

This commit is contained in:
王嘉豪 2024-03-29 16:59:31 +08:00 committed by GitHub
commit 81df4a1073
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 565 additions and 72 deletions

View File

@ -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;
}
}

View File

@ -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

View File

@ -92,7 +92,9 @@ const navigate = computed(() => appearanceStore.getNavigate)
border-color: #1f232926 !important;
}
.system,
.system {
color: #000 !important;
}
.de-logo {
color: #3371ff !important;
}

View File

@ -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: '结束角度',

View File

@ -221,6 +221,10 @@ declare interface ChartTableHeaderAttr {
* 序号表头名称
*/
indexLabel: string
/**
* 表头排序开关
*/
tableHeaderSort: boolean
}
/**
* 单元格属性

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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>

View File

@ -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',

View File

@ -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,

View File

@ -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) => {

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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))
})
}

View File

@ -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
}

View File

@ -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

View File

@ -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)
}

View File

@ -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">

View File

@ -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%;

View File

@ -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 {

View File

@ -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);
}

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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)
"
>

@ -1 +1 @@
Subproject commit 137b8218ee27ecdd58656076423ae1bde1596007
Subproject commit 299cd6287249a793abd799f39c40b45d01eb2336