diff --git a/backend/src/main/java/io/dataease/ext/ExtChartViewMapper.xml b/backend/src/main/java/io/dataease/ext/ExtChartViewMapper.xml index 8b7a937419..c879ad7ea3 100644 --- a/backend/src/main/java/io/dataease/ext/ExtChartViewMapper.xml +++ b/backend/src/main/java/io/dataease/ext/ExtChartViewMapper.xml @@ -49,7 +49,8 @@ drill_fields, senior, SNAPSHOT, - data_from + data_from, + custom_sort ) SELECT id, `name`, @@ -78,7 +79,8 @@ drill_fields, senior, SNAPSHOT, - data_from from chart_view + data_from, + custom_sort from chart_view WHERE chart_view.id = #{id} @@ -112,7 +114,8 @@ drill_fields, senior, SNAPSHOT, - data_from + data_from, + custom_sort ) SELECT #{newViewId} as id, `name`, @@ -141,7 +144,8 @@ drill_fields, senior, SNAPSHOT, - data_from from chart_view_cache + data_from, + custom_sort from chart_view_cache WHERE chart_view_cache.id = #{sourceViewId} @@ -175,7 +179,8 @@ drill_fields, senior, SNAPSHOT, - data_from + data_from, + custom_sort ) SELECT id, `name`, @@ -204,7 +209,8 @@ drill_fields, senior, SNAPSHOT, - data_from from chart_view + data_from, + custom_sort from chart_view WHERE chart_view.scene_id = #{panelId} @@ -287,7 +293,8 @@ `chart_type`, `is_plugin`, `senior`, - `data_from`) + `data_from`, + `custom_sort`) SELECT #{newChartId}, GET_CHART_VIEW_COPY_NAME(#{oldChartId},#{panelId}) as `name`, #{panelId}, @@ -315,7 +322,8 @@ 'private', `is_plugin`, `senior`, - `data_from` + `data_from`, + `custom_sort` FROM chart_view WHERE id = #{oldChartId} @@ -365,7 +373,8 @@ custom_filter, drill_fields, SNAPSHOT, - data_from) + data_from, + custom_sort) SELECT pv_copy.chart_view_id AS id, `name`, title, @@ -392,7 +401,8 @@ custom_filter, drill_fields, SNAPSHOT, - data_from + data_from, + custom_sort FROM ( SELECT panel_id, copy_from_view, @@ -502,7 +512,8 @@ cv.drill_fields = cve.drill_fields, cv.senior = cve.senior, cv.SNAPSHOT = cve.SNAPSHOT, - cv.data_from = cve.data_from + cv.data_from = cve.data_from, + cv.custom_sort = cve.custom_sort where cve.id = cv.id and cv.id in #{viewId} @@ -538,7 +549,8 @@ cv.drill_fields = cve.drill_fields, cv.senior = cve.senior, cv.SNAPSHOT = cve.SNAPSHOT, - cv.data_from = cve.data_from + cv.data_from = cve.data_from, + cv.custom_sort = cve.custom_sort where cve.id = cv.id and cv.id =#{viewId} @@ -572,7 +584,8 @@ cv.drill_fields = cve.drill_fields, cv.senior = cve.senior, cv.SNAPSHOT = cve.SNAPSHOT, - cv.data_from = cve.data_from + cv.data_from = cve.data_from, + cv.custom_sort = cve.custom_sort where cve.id = cv.id and cv.id =#{viewId} diff --git a/backend/src/main/resources/db/migration/V35__1.11.sql b/backend/src/main/resources/db/migration/V35__1.11.sql new file mode 100644 index 0000000000..688d76e57a --- /dev/null +++ b/backend/src/main/resources/db/migration/V35__1.11.sql @@ -0,0 +1,4 @@ +ALTER TABLE `chart_view` ADD COLUMN `custom_sort` LONGTEXT COMMENT '自定义排序'; +UPDATE `chart_view` SET `custom_sort` = '[]'; +ALTER TABLE `chart_view_cache` ADD COLUMN `custom_sort` LONGTEXT COMMENT '自定义排序'; +UPDATE `chart_view_cache` SET `custom_sort` = '[]'; diff --git a/frontend/src/lang/en.js b/frontend/src/lang/en.js index 301bcba3a8..b077ed3258 100644 --- a/frontend/src/lang/en.js +++ b/frontend/src/lang/en.js @@ -1095,7 +1095,10 @@ export default { unit_hundred_million: 'Hundred Million', formatter_decimal_count_error: 'Range 0-10', gauge_threshold_compare_error: 'Range must added', - tick_count: 'Tick Split' + tick_count: 'Tick Split', + custom_sort: 'Custom Sort', + custom_sort_tip: 'Custom sort field first', + clean_custom_sort: 'Clean' }, dataset: { sheet_warn: 'There are multiple sheet pages, and the first one is extracted by default', diff --git a/frontend/src/lang/tw.js b/frontend/src/lang/tw.js index 88e9e0e780..00158e2831 100644 --- a/frontend/src/lang/tw.js +++ b/frontend/src/lang/tw.js @@ -1095,7 +1095,10 @@ export default { unit_hundred_million: '億', formatter_decimal_count_error: '請輸入0-10的整數', gauge_threshold_compare_error: '阈值範圍需逐級遞增', - tick_count: '刻度間隔數' + tick_count: '刻度間隔數', + custom_sort: '自定義排序', + custom_sort_tip: '自定義排序優先級高於字段排序', + clean_custom_sort: '清除自定義排序' }, dataset: { sheet_warn: '有多個 Sheet 頁,默認抽取第一個', diff --git a/frontend/src/lang/zh.js b/frontend/src/lang/zh.js index 6f669c4609..31ab9fa0ed 100644 --- a/frontend/src/lang/zh.js +++ b/frontend/src/lang/zh.js @@ -1097,7 +1097,10 @@ export default { unit_hundred_million: '亿', formatter_decimal_count_error: '请输入0-10的整数', gauge_threshold_compare_error: '阈值范围需逐级递增', - tick_count: '刻度间隔数' + tick_count: '刻度间隔数', + custom_sort: '自定义排序', + custom_sort_tip: '自定义排序优先级高于字段排序', + clean_custom_sort: '清除自定义排序' }, dataset: { sheet_warn: '有多个 Sheet 页,默认抽取第一个', diff --git a/frontend/src/views/chart/chart/bar/bar_antv.js b/frontend/src/views/chart/chart/bar/bar_antv.js index d84248628c..7e3ebc04ab 100644 --- a/frontend/src/views/chart/chart/bar/bar_antv.js +++ b/frontend/src/views/chart/chart/bar/bar_antv.js @@ -10,6 +10,7 @@ import { getSlider, getAnalyse } from '@/views/chart/chart/common/common_antv' +import { customSort } from '@/views/chart/chart/util' export function baseBarOptionAntV(plot, container, chart, action, isGroup, isStack) { // theme @@ -22,7 +23,13 @@ export function baseBarOptionAntV(plot, container, chart, action, isGroup, isSta const xAxis = getXAxis(chart) const yAxis = getYAxis(chart) // data - const data = chart.data.datas + let data + const cus = JSON.parse(chart.customSort) + if (cus && cus.length > 0) { + data = customSort(cus, chart.data.datas) + } else { + data = chart.data.datas + } // config const slider = getSlider(chart) const analyse = getAnalyse(chart) @@ -122,7 +129,13 @@ export function hBaseBarOptionAntV(plot, container, chart, action, isGroup, isSt const xAxis = getXAxis(chart) const yAxis = getYAxis(chart) // data - const data = chart.data.datas + let data + const cus = JSON.parse(chart.customSort) + if (cus && cus.length > 0) { + data = customSort(cus, chart.data.datas) + } else { + data = chart.data.datas + } // config const slider = getSlider(chart) const analyse = getAnalyse(chart) diff --git a/frontend/src/views/chart/chart/funnel/funnel_antv.js b/frontend/src/views/chart/chart/funnel/funnel_antv.js index 0d940e4a4a..da9d875c60 100644 --- a/frontend/src/views/chart/chart/funnel/funnel_antv.js +++ b/frontend/src/views/chart/chart/funnel/funnel_antv.js @@ -1,5 +1,6 @@ import { getLabel, getLegend, getPadding, getTheme, getTooltip } from '@/views/chart/chart/common/common_antv' import { Funnel } from '@antv/g2plot' +import { customSort } from '@/views/chart/chart/util' export function baseFunnelOptionAntV(plot, container, chart, action) { // theme @@ -10,7 +11,13 @@ export function baseFunnelOptionAntV(plot, container, chart, action) { // style const legend = getLegend(chart) // data - const data = chart.data.datas + let data + const cus = JSON.parse(chart.customSort) + if (cus && cus.length > 0) { + data = customSort(cus, chart.data.datas) + } else { + data = chart.data.datas + } // options const options = { theme: theme, diff --git a/frontend/src/views/chart/chart/line/line_antv.js b/frontend/src/views/chart/chart/line/line_antv.js index eb7d0eacc0..5544b34610 100644 --- a/frontend/src/views/chart/chart/line/line_antv.js +++ b/frontend/src/views/chart/chart/line/line_antv.js @@ -10,6 +10,7 @@ import { getSlider, getAnalyse } from '@/views/chart/chart/common/common_antv' +import { customSort } from '@/views/chart/chart/util' export function baseLineOptionAntV(plot, container, chart, action) { // theme @@ -22,7 +23,13 @@ export function baseLineOptionAntV(plot, container, chart, action) { const xAxis = getXAxis(chart) const yAxis = getYAxis(chart) // data - const data = chart.data.datas + let data + const cus = JSON.parse(chart.customSort) + if (cus && cus.length > 0) { + data = customSort(cus, chart.data.datas) + } else { + data = chart.data.datas + } // config const slider = getSlider(chart) const analyse = getAnalyse(chart) @@ -114,7 +121,13 @@ export function baseAreaOptionAntV(plot, container, chart, action) { const xAxis = getXAxis(chart) const yAxis = getYAxis(chart) // data - const data = chart.data.datas + let data + const cus = JSON.parse(chart.customSort) + if (cus && cus.length > 0) { + data = customSort(cus, chart.data.datas) + } else { + data = chart.data.datas + } // config const slider = getSlider(chart) const analyse = getAnalyse(chart) diff --git a/frontend/src/views/chart/chart/pie/pie_antv.js b/frontend/src/views/chart/chart/pie/pie_antv.js index d66180b364..99bfbc98fc 100644 --- a/frontend/src/views/chart/chart/pie/pie_antv.js +++ b/frontend/src/views/chart/chart/pie/pie_antv.js @@ -7,6 +7,7 @@ import { } from '@/views/chart/chart/common/common_antv' import { Pie, Rose } from '@antv/g2plot' +import { customSort } from '@/views/chart/chart/util' export function basePieOptionAntV(plot, container, chart, action) { // theme @@ -17,7 +18,13 @@ export function basePieOptionAntV(plot, container, chart, action) { // style const legend = getLegend(chart) // data - const data = chart.data.datas + let data + const cus = JSON.parse(chart.customSort) + if (cus && cus.length > 0) { + data = customSort(cus, chart.data.datas) + } else { + data = chart.data.datas + } // options const options = { theme: theme, @@ -106,7 +113,13 @@ export function basePieRoseOptionAntV(plot, container, chart, action) { // style const legend = getLegend(chart) // data - const data = chart.data.datas + let data + const cus = JSON.parse(chart.customSort) + if (cus && cus.length > 0) { + data = customSort(cus, chart.data.datas) + } else { + data = chart.data.datas + } // options const options = { theme: theme, diff --git a/frontend/src/views/chart/chart/radar/radar_antv.js b/frontend/src/views/chart/chart/radar/radar_antv.js index f0c06781fa..a83f0b1bcb 100644 --- a/frontend/src/views/chart/chart/radar/radar_antv.js +++ b/frontend/src/views/chart/chart/radar/radar_antv.js @@ -1,5 +1,6 @@ import { getLabel, getLegend, getPadding, getTheme, getTooltip } from '@/views/chart/chart/common/common_antv' import { Radar } from '@antv/g2plot' +import { customSort } from '@/views/chart/chart/util' export function baseRadarOptionAntV(plot, container, chart, action) { // theme @@ -10,7 +11,14 @@ export function baseRadarOptionAntV(plot, container, chart, action) { // style const legend = getLegend(chart) // data - const data = chart.data.datas + let data + const cus = JSON.parse(chart.customSort) + if (cus && cus.length > 0) { + data = customSort(cus, chart.data.datas) + } else { + data = chart.data.datas + } + const xAxis = { tickLine: null, line: null diff --git a/frontend/src/views/chart/chart/scatter/scatter_antv.js b/frontend/src/views/chart/chart/scatter/scatter_antv.js index 77fd43d137..259269f450 100644 --- a/frontend/src/views/chart/chart/scatter/scatter_antv.js +++ b/frontend/src/views/chart/chart/scatter/scatter_antv.js @@ -11,6 +11,7 @@ import { } from '@/views/chart/chart/common/common_antv' import { Scatter } from '@antv/g2plot' +import { customSort } from '@/views/chart/chart/util' export function baseScatterOptionAntV(plot, container, chart, action) { // theme @@ -23,7 +24,13 @@ export function baseScatterOptionAntV(plot, container, chart, action) { const xAxis = getXAxis(chart) const yAxis = getYAxis(chart) // data - const data = chart.data.datas + let data + const cus = JSON.parse(chart.customSort) + if (cus && cus.length > 0) { + data = customSort(cus, chart.data.datas) + } else { + data = chart.data.datas + } // config const slider = getSlider(chart) const analyse = getAnalyse(chart) diff --git a/frontend/src/views/chart/chart/util.js b/frontend/src/views/chart/chart/util.js index e97b22ee84..8189e32b5a 100644 --- a/frontend/src/views/chart/chart/util.js +++ b/frontend/src/views/chart/chart/util.js @@ -321,3 +321,36 @@ export const TYPE_CONFIGS = [ icon: 'map' } ] + +export function customSort(custom, data) { + const indexArr = [] + const joinArr = [] + for (let i = 0; i < custom.length; i++) { + const ele = custom[i] + for (let j = 0; j < data.length; j++) { + const d = data[j] + if (ele === d.field) { + joinArr.push(d) + indexArr.push(j) + } + } + } + // 取得 joinArr 就是两者的交集 + const indexArrData = [] + for (let i = 0; i < data.length; i++) { + indexArrData.push(i) + } + const indexResult = [] + for (let i = 0; i < indexArrData.length; i++) { + if (indexArr.indexOf(indexArrData[i]) === -1) { + indexResult.push(indexArrData[i]) + } + } + + const subArr = [] + for (let i = 0; i < indexResult.length; i++) { + subArr.push(data[indexResult[i]]) + } + + return joinArr.concat(subArr) +} diff --git a/frontend/src/views/chart/chart/waterfall/waterfall.js b/frontend/src/views/chart/chart/waterfall/waterfall.js index dddbc58032..1da7a0280f 100644 --- a/frontend/src/views/chart/chart/waterfall/waterfall.js +++ b/frontend/src/views/chart/chart/waterfall/waterfall.js @@ -8,6 +8,7 @@ import { getYAxis } from '@/views/chart/chart/common/common_antv' import { Waterfall } from '@antv/g2plot' +import { customSort } from '@/views/chart/chart/util' export function baseWaterfallOptionAntV(plot, container, chart, action) { // theme @@ -27,7 +28,13 @@ export function baseWaterfallOptionAntV(plot, container, chart, action) { delete yAxis.maxLimit } // data - const data = chart.data.datas + let data + const cus = JSON.parse(chart.customSort) + if (cus && cus.length > 0) { + data = customSort(cus, chart.data.datas) + } else { + data = chart.data.datas + } // total const total = { label: '合计', diff --git a/frontend/src/views/chart/components/compare/CustomSortEdit.vue b/frontend/src/views/chart/components/compare/CustomSortEdit.vue new file mode 100644 index 0000000000..067118bb7d --- /dev/null +++ b/frontend/src/views/chart/components/compare/CustomSortEdit.vue @@ -0,0 +1,125 @@ + + + + + diff --git a/frontend/src/views/chart/view/ChartEdit.vue b/frontend/src/views/chart/view/ChartEdit.vue index 18cc72fb0c..7c7c9a9240 100644 --- a/frontend/src/views/chart/view/ChartEdit.vue +++ b/frontend/src/views/chart/view/ChartEdit.vue @@ -347,6 +347,15 @@ {{ $t('chart.dimension_or_quota') }} + + + {{ $t('chart.shape_attr') }} - + {{ $t('chart.confirm') }} + + + + + + + @@ -1240,9 +1274,11 @@ import TotalCfg from '@/views/chart/components/shape-attr/TotalCfg' import LabelNormalText from '@/views/chart/components/normal/LabelNormalText' import { pluginTypes } from '@/api/chart/chart' import ValueFormatterEdit from '@/views/chart/components/value-formatter/ValueFormatterEdit' +import CustomSortEdit from '@/views/chart/components/compare/CustomSortEdit' export default { name: 'ChartEdit', components: { + CustomSortEdit, ValueFormatterEdit, LabelNormalText, TotalCfg, @@ -1344,7 +1380,8 @@ export default { }, customFilter: [], render: 'antv', - isPlugin: false + isPlugin: false, + customSort: [] }, moveId: -1, chart: { @@ -1395,7 +1432,9 @@ export default { preChartId: '', pluginRenderOptions: [], showValueFormatter: false, - valueFormatterItem: {} + valueFormatterItem: {}, + showCustomSort: false, + customSortList: [] } }, @@ -1488,6 +1527,7 @@ export default { this.resetDrill() this.initFromPanel() this.getChart(this.param.id) + this.getData(this.param.id) }, bindPluginEvent() { bus.$on('show-dimension-edit-filter', this.showDimensionEditFilter) @@ -1754,6 +1794,7 @@ export default { view.drillFields = JSON.stringify(view.drillFields) view.extBubble = JSON.stringify(view.extBubble) view.senior = JSON.stringify(view.senior) + view.customSort = JSON.stringify(view.customSort) delete view.data return view }, @@ -1804,6 +1845,7 @@ export default { const view = this.buildParam(true, 'chart', false, switchType) if (!view) return viewEditSave(this.panelInfo.id, view).then(() => { + this.getData(this.param.id) bus.$emit('view-in-cache', { type: 'propChange', viewId: this.param.id }) }) }, @@ -1822,6 +1864,7 @@ export default { view.customStyle = JSON.stringify(this.view.customStyle) view.customFilter = JSON.stringify(this.view.customFilter) view.senior = JSON.stringify(this.view.senior) + view.customSort = JSON.stringify(this.view.customSort) view.title = this.view.title view.stylePriority = this.view.stylePriority // view.data = this.data @@ -1867,12 +1910,12 @@ export default { } }, getData(id) { - this.hasEdit = false + // this.hasEdit = true if (id) { ajaxGetDataOnly(id, this.panelInfo.id, { filter: [], drill: this.drillClickDimensionList, - queryFrom: 'panelEdit' + queryFrom: 'panel' }).then(response => { this.initTableData(response.data.tableId) this.view = JSON.parse(JSON.stringify(response.data)) @@ -1887,6 +1930,7 @@ export default { this.view.customStyle = this.view.customStyle ? JSON.parse(this.view.customStyle) : {} this.view.customFilter = this.view.customFilter ? JSON.parse(this.view.customFilter) : {} this.view.senior = this.view.senior ? JSON.parse(this.view.senior) : {} + this.view.customSort = this.view.customSort ? JSON.parse(this.view.customSort) : [] // 将视图传入echart组件 this.chart = response.data this.data = response.data.data @@ -1938,6 +1982,7 @@ export default { this.view.customStyle = this.view.customStyle ? JSON.parse(this.view.customStyle) : {} this.view.customFilter = this.view.customFilter ? JSON.parse(this.view.customFilter) : {} this.view.senior = this.view.senior ? JSON.parse(this.view.senior) : {} + this.view.customSort = this.view.customSort ? JSON.parse(this.view.customSort) : [] // 将视图传入echart组件 this.chart = response.data @@ -2337,7 +2382,7 @@ export default { if ((this.view.type === 'map' || this.view.type === 'word-cloud' || this.view.type === 'label') && this.view.xaxis.length > 1) { this.view.xaxis = [this.view.xaxis[0]] } - this.calcData(true) + this.resetCustomSort() }, addXaxisExt(e) { if (this.view.type !== 'table-info') { @@ -2460,12 +2505,12 @@ export default { if (this.chart.type === 'map' || this.chart.type === 'buddle-map') { if (this.sendToChildren(param)) { this.drillClickDimensionList.push({ dimensionList: param.data.dimensionList }) - // this.getData(this.param.id) + this.getData(this.param.id) this.calcData(true, 'chart', false, false) } } else { this.drillClickDimensionList.push({ dimensionList: param.data.dimensionList }) - // this.getData(this.param.id) + this.getData(this.param.id) this.calcData(true, 'chart', false, false) } } else if (this.view.drillFields.length > 0) { @@ -2500,7 +2545,7 @@ export default { this.backToParent(index, length) } - // this.getData(this.param.id) + this.getData(this.param.id) this.calcData(true, 'chart', false, false) }, // 回到父级地图 @@ -2583,6 +2628,7 @@ export default { resetViewCacheCallBack(_this.param.id, _this.panelInfo.id, function(rsp) { _this.changeEditStatus(false) _this.getChart(_this.param.id, 'panel') + _this.getData(_this.param.id) bus.$emit('view-in-cache', { type: 'propChange', viewId: _this.param.id }) }) }, @@ -2647,6 +2693,27 @@ export default { } this.calcData(true) this.closeValueFormatter() + }, + + customSort() { + this.showCustomSort = true + }, + customSortChange(val) { + this.customSortList = val + }, + closeCustomSort() { + this.showCustomSort = false + }, + saveCustomSort() { + this.view.customSort = JSON.parse(JSON.stringify(this.customSortList)) + this.calcData(true) + this.closeCustomSort() + }, + resetCustomSort() { + this.chart.customSort = [] + this.view.customSort = [] + this.calcData(true) + this.closeCustomSort() } } }