From 44b56f759f2dbab12459d109d47152d40f68e0e0 Mon Sep 17 00:00:00 2001 From: wangjiahao <1522128093@qq.com> Date: Fri, 22 Jul 2022 10:40:36 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E4=BB=AA=E8=A1=A8=E6=9D=BF):=20=E4=BB=AA?= =?UTF-8?q?=E8=A1=A8=E6=9D=BF=E8=B7=B3=E8=BD=AC=E5=A4=96=E9=83=A8=E9=93=BE?= =?UTF-8?q?=E6=8E=A5=E6=97=B6=E6=94=AF=E6=8C=81=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E8=AE=BE=E7=BD=AE=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?S2=E8=A1=A8=E6=A0=BC=E8=B7=B3=E8=BD=AC=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=82=B9=E5=87=BB=E6=97=B6=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E6=95=B4=E8=A1=8C=E6=95=B0=E6=8D=AE=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../canvas/custom-component/UserView.vue | 61 ++-- frontend/src/lang/en.js | 3 + frontend/src/lang/tw.js | 3 + frontend/src/lang/zh.js | 3 + .../views/chart/components/ChartComponent.vue | 9 +- .../chart/components/ChartComponentG2.vue | 8 +- .../chart/components/ChartComponentS2.vue | 42 +-- .../src/views/panel/LinkJumpSet/index.vue | 329 ++++++++++++++++-- 8 files changed, 378 insertions(+), 80 deletions(-) diff --git a/frontend/src/components/canvas/custom-component/UserView.vue b/frontend/src/components/canvas/custom-component/UserView.vue index c1afd1191f..498a06a4cd 100644 --- a/frontend/src/components/canvas/custom-component/UserView.vue +++ b/frontend/src/components/canvas/custom-component/UserView.vue @@ -625,14 +625,24 @@ export default { }, jumpClick(param) { - let dimension, jumpInfo, sourceInfo, jumpFieldName - // 倒序取最后一个能匹配的 - for (let i = param.dimensionList.length - 1; i >= 0; i--) { - dimension = param.dimensionList[i] - sourceInfo = param.viewId + '#' + dimension.id - jumpInfo = this.nowPanelJumpInfo[sourceInfo] - if (jumpInfo) { - break + let dimension, jumpInfo, sourceInfo + // 如果有名称name 获取和name匹配的dimension 否则倒序取最后一个能匹配的 + if (param.name) { + param.dimensionList.forEach(dimensionItem => { + if (dimensionItem.value === param.name) { + dimension = dimensionItem + sourceInfo = param.viewId + '#' + dimension.id + jumpInfo = this.nowPanelJumpInfo[sourceInfo] + } + }) + } else { + for (let i = param.dimensionList.length - 1; i >= 0; i--) { + dimension = param.dimensionList[i] + sourceInfo = param.viewId + '#' + dimension.id + jumpInfo = this.nowPanelJumpInfo[sourceInfo] + if (jumpInfo) { + break + } } } if (jumpInfo) { @@ -667,21 +677,8 @@ export default { }) } } else { - let url = jumpInfo.content - // 是否追加点击参数 - if (jumpInfo.attachParams && this.chart.data && this.chart.data.sourceFields) { - this.chart.data.sourceFields.forEach(item => { - if (item.id === dimension.id) { - jumpFieldName = item.name - } - }) - const urlAttachParams = jumpFieldName + '=' + dimension.value - if (url.indexOf('?') > -1) { - url = url + '&' + urlAttachParams - } else { - url = url + '?' + urlAttachParams - } - } + const colList = [...param.dimensionList, ...param.quotaList] + const url = this.setIdValueTrans('id', 'value', jumpInfo.content, colList) window.open(url, jumpInfo.jumpType) } } else { @@ -692,6 +689,24 @@ export default { }) } }, + setIdValueTrans(from, to, content, colList) { + if (!content) { + return content + } + let name2Id = content + const nameIdMap = colList.reduce((pre, next) => { + pre[next[from]] = next[to] + return pre + }, {}) + const on = content.match(/\[(.+?)\]/g) + if (on) { + on.forEach(itm => { + const ele = itm.slice(1, -1) + name2Id = name2Id.replace(itm, nameIdMap[ele]) + }) + } + return name2Id + }, resetDrill() { const length = this.drillClickDimensionList.length diff --git a/frontend/src/lang/en.js b/frontend/src/lang/en.js index e32ba2f01f..b129d78861 100644 --- a/frontend/src/lang/en.js +++ b/frontend/src/lang/en.js @@ -1499,6 +1499,9 @@ export default { sure_bt: 'Confirm' }, panel: { + target_url: 'Target Url', + target_url_tips: 'You can click fields to splice URLs or parameters', + select_world: 'Select World', template_market: 'Template Market', template_preview: 'Template Preview', apply: 'Apply', diff --git a/frontend/src/lang/tw.js b/frontend/src/lang/tw.js index a59fd3d2b0..cd2e199014 100644 --- a/frontend/src/lang/tw.js +++ b/frontend/src/lang/tw.js @@ -1500,6 +1500,9 @@ export default { sure_bt: '確定' }, panel: { + target_url: '目标URL', + target_url_tips: '可以点击字段用来拼接URL或者参数', + select_world: '点击选择字段', template_market: '模板市场', template_preview: '预览模板', apply: '应用', diff --git a/frontend/src/lang/zh.js b/frontend/src/lang/zh.js index e2cae89bd6..e30a4efee1 100644 --- a/frontend/src/lang/zh.js +++ b/frontend/src/lang/zh.js @@ -1508,6 +1508,9 @@ export default { sure_bt: '确定' }, panel: { + target_url: '目标URL', + target_url_tips: '可以点击字段用来拼接URL或者参数', + select_world: '点击选择字段', template_market: '模板市场', template_preview: '预览模板', apply: '应用', diff --git a/frontend/src/views/chart/components/ChartComponent.vue b/frontend/src/views/chart/components/ChartComponent.vue index 1e6fae8001..ad91b3de3a 100644 --- a/frontend/src/views/chart/components/ChartComponent.vue +++ b/frontend/src/views/chart/components/ChartComponent.vue @@ -332,18 +332,23 @@ export default { } return } + const quotaList = this.pointParam.data.quotaList + quotaList[0]['value'] = this.pointParam.data.value const linkageParam = { option: 'linkage', + name: this.pointParam.data.name, viewId: this.chart.id, dimensionList: this.pointParam.data.dimensionList, - quotaList: this.pointParam.data.quotaList + quotaList: quotaList } const jumpParam = { option: 'jump', + name: this.pointParam.data.name, viewId: this.chart.id, dimensionList: this.pointParam.data.dimensionList, - quotaList: this.pointParam.data.quotaList + quotaList: quotaList } + jumpParam.quotaList[0]['value'] = this.pointParam.data.value switch (trackAction) { case 'drill': this.$emit('onChartClick', this.pointParam) diff --git a/frontend/src/views/chart/components/ChartComponentG2.vue b/frontend/src/views/chart/components/ChartComponentG2.vue index 6ff036748b..1c22f98532 100644 --- a/frontend/src/views/chart/components/ChartComponentG2.vue +++ b/frontend/src/views/chart/components/ChartComponentG2.vue @@ -271,17 +271,21 @@ export default { } return } + const quotaList = this.pointParam.data.quotaList + quotaList[0]['value'] = this.pointParam.data.value const linkageParam = { option: 'linkage', + name: this.pointParam.data.name, viewId: this.chart.id, dimensionList: this.pointParam.data.dimensionList, - quotaList: this.pointParam.data.quotaList + quotaList: quotaList } const jumpParam = { option: 'jump', + name: this.pointParam.data.name, viewId: this.chart.id, dimensionList: this.pointParam.data.dimensionList, - quotaList: this.pointParam.data.quotaList + quotaList: quotaList } switch (trackAction) { diff --git a/frontend/src/views/chart/components/ChartComponentS2.vue b/frontend/src/views/chart/components/ChartComponentS2.vue index 3275054a00..489f6b8f20 100644 --- a/frontend/src/views/chart/components/ChartComponentS2.vue +++ b/frontend/src/views/chart/components/ChartComponentS2.vue @@ -221,38 +221,20 @@ export default { antVAction(param) { const cell = this.myChart.getCell(param.target) const meta = cell.getMeta() - - let xAxis = [] - if (this.chart.xaxis) { - xAxis = JSON.parse(this.chart.xaxis) - } - let drillFields = [] - if (this.chart.drillFields) { - try { - drillFields = JSON.parse(this.chart.drillFields) - } catch (err) { - drillFields = JSON.parse(JSON.stringify(this.chart.drillFields)) - } - } - - let field = {} - if (this.chart.drill) { - field = drillFields[this.chart.drillFilters.length] - // check click field is drill? - if (field.dataeaseName !== meta.valueField) { - return - } - } else { - if (meta.colIndex < xAxis.length) { - field = xAxis[meta.colIndex] - } - } - + const nameIdMap = this.chart.data.fields.reduce((pre, next) => { + pre[next['dataeaseName']] = next['id'] + return pre + }, {}) + const rowData = this.chart.data.tableRow[meta.rowIndex] const dimensionList = [] - dimensionList.push({ id: field.id, value: meta.fieldValue }) + for (const key in rowData) { + dimensionList.push({ id: nameIdMap[key], value: rowData[key] }) + } this.pointParam = { data: { - dimensionList: dimensionList + dimensionList: dimensionList, + quotaList: [], + name: meta.fieldValue } } @@ -291,12 +273,14 @@ export default { } const linkageParam = { option: 'linkage', + name: this.pointParam.data.name, viewId: this.chart.id, dimensionList: this.pointParam.data.dimensionList, quotaList: this.pointParam.data.quotaList } const jumpParam = { option: 'jump', + name: this.pointParam.data.name, viewId: this.chart.id, dimensionList: this.pointParam.data.dimensionList, quotaList: this.pointParam.data.quotaList diff --git a/frontend/src/views/panel/LinkJumpSet/index.vue b/frontend/src/views/panel/LinkJumpSet/index.vue index 66aaad1b9d..60ce7bba70 100644 --- a/frontend/src/views/panel/LinkJumpSet/index.vue +++ b/frontend/src/views/panel/LinkJumpSet/index.vue @@ -71,9 +71,6 @@ {{ $t('panel.new_window') }} - - 附加点击参数 - @@ -137,17 +134,87 @@ {{ $t('panel.add_jump_field') }} - - - - + + + + + + {{$t(panel.target_url)}} + +
+ {{$t(panel.target_url_tips)}} +
+ +
+
+ +
+
+ + + + {{$t(panel.select_world)}} + +
+ 引用字段以 "[" 开始, "]" 结束 +
+ 请勿修改引用内容,否则将引用失败 +
+ 若输入与引用字段相同格式的内容,将被当作引用字段处理 +
+ +
+
+ +
+ + + + + + + + + {{ item.sourceFieldName }} + + + +
+
+
+
@@ -168,11 +235,35 @@ import { queryPanelJumpInfo, queryWithViewId, updateJumpSet } from '@/api/panel/ import { groupTree } from '@/api/panel/panel' import { detailList } from '@/api/panel/panelView' import { mapState } from 'vuex' -import { deepCopy } from '@/components/canvas/utils/utils' import { checkAddHttp } from '@/utils/urlUtils' +import draggable from 'vuedraggable' +import { codemirror } from 'vue-codemirror' +// 核心样式 +import 'codemirror/lib/codemirror.css' +// 引入主题后还需要在 options 中指定主题才会生效 +import 'codemirror/theme/solarized.css' +import 'codemirror/mode/sql/sql.js' +// require active-line.js +import 'codemirror/addon/selection/active-line.js' +// closebrackets +import 'codemirror/addon/edit/closebrackets.js' +// keyMap +import 'codemirror/mode/clike/clike.js' +import 'codemirror/addon/edit/matchbrackets.js' +import 'codemirror/addon/comment/comment.js' +import 'codemirror/addon/dialog/dialog.js' +import 'codemirror/addon/dialog/dialog.css' +import 'codemirror/addon/search/searchcursor.js' +import 'codemirror/addon/search/search.js' +import 'codemirror/keymap/emacs.js' +// 引入代码自动提示插件 +import 'codemirror/addon/hint/show-hint.css' +import 'codemirror/addon/hint/sql-hint' +import 'codemirror/addon/hint/show-hint' + export default { - components: { }, + components: { codemirror, draggable }, props: { viewId: { type: String, @@ -181,6 +272,9 @@ export default { }, data() { return { + name2Auto: [], + searchField: '', + searchFunction: '', loading: false, inputType: 'self', fieldName: 'name', @@ -198,7 +292,7 @@ export default { children: 'children' }, linkJump: null, - linkJumpInfoArray: null, + linkJumpInfoArray: [], mapJumpInfoArray: {}, panelList: [], linkJumpInfo: null, @@ -213,8 +307,18 @@ export default { targetFieldId: null }, currentLinkPanelViewArray: [], - viewIdFieldArrayMap: {} - + viewIdFieldArrayMap: {}, + cmOption: { + tabSize: 2, + styleActiveLine: true, + lineNumbers: true, + line: true, + mode: 'text/x-sql', + theme: 'solarized', + hintOptions: { // 自定义提示选项 + completeSingle: false // 当匹配只有一项的时候是否自动补全 + } + } } }, computed: { @@ -230,9 +334,13 @@ export default { panelInfo() { return this.$store.state.panel.panelInfo }, + codemirror() { + return this.$refs.myCm.codemirror + }, ...mapState([ 'componentData', - 'canvasStyleData' + 'canvasStyleData', + 'panelViewDetailsInfo' ]) }, watch: { @@ -247,6 +355,8 @@ export default { }, methods: { init() { + const chartDetails = JSON.parse(this.panelViewDetailsInfo[this.viewId]) + const checkStr = chartDetails.xaxis + chartDetails.xaxisExt + chartDetails.yaxis + chartDetails.yaxisExt // 获取可关联的仪表板 groupTree({}).then(rsp => { this.panelList = rsp.data @@ -254,9 +364,15 @@ export default { // 获取当前视图的关联信息 queryWithViewId(this.panelInfo.id, this.viewId).then(rsp => { this.linkJump = rsp.data - this.linkJumpInfoArray = this.linkJump.linkJumpInfoArray + this.linkJumpInfoArray = [] + this.linkJump.linkJumpInfoArray.forEach(linkJumpInfo => { + if (checkStr.indexOf(linkJumpInfo.sourceFieldId) > -1) { + this.mapJumpInfoArray[linkJumpInfo.sourceFieldId] = linkJumpInfo + this.linkJumpInfoArray.push(linkJumpInfo) + } + }) this.linkJumpInfoArray.forEach(linkJumpInfo => { - this.mapJumpInfoArray[linkJumpInfo.sourceFieldId] = linkJumpInfo + linkJumpInfo.content = this.setNameIdTrans('sourceFieldId', 'sourceFieldName', linkJumpInfo.content, this.name2Auto) }) const firstNode = this.linkJumpInfoArray[0] this.$nextTick(() => { @@ -264,10 +380,6 @@ export default { this.nodeClick(firstNode) }) }) - // 获取当前视图的字段信息 - // getTableFieldWithViewId(this.viewId).then(rsp => { - // this.sourceViewFields = rsp.data - // }) }, handleExceed(file) { }, @@ -276,6 +388,9 @@ export default { }, save() { this.linkJumpInfo.content = checkAddHttp(this.linkJumpInfo.content) + this.linkJumpInfoArray.forEach(jumpInfo => { + jumpInfo.content = this.setNameIdTrans('sourceFieldName', 'sourceFieldId', jumpInfo.content) + }) updateJumpSet(this.linkJump).then(rsp => { this.$message({ message: '保存成功', @@ -306,6 +421,9 @@ export default { if (this.linkJumpInfo.targetPanelId) { this.getPanelViewList(this.linkJumpInfo.targetPanelId) } + setTimeout(() => { + this.matchToAuto() + }, 500) }, // 获取当前视图字段 关联仪表板的视图信息列表 getPanelViewList(panelId) { @@ -356,6 +474,53 @@ export default { this.$refs.linkJumpInfoTree.setCurrentKey(data.sourceFieldId) this.nodeClick(data) }) + }, + onCmReady(cm) { + this.codemirror.setSize('-webkit-fill-available', 'auto') + }, + onCmFocus(cm) { + }, + onCmCodeChange(newCode) { + // this.fieldForm.originName = newCode + }, + insertFieldToCodeMirror(param) { + const pos1 = this.$refs.myCm.codemirror.getCursor() + const pos2 = {} + pos2.line = pos1.line + pos2.ch = pos1.ch + this.$refs.myCm.codemirror.replaceRange(param, pos2) + this.$refs.myCm.codemirror.markText(pos2, { line: pos2.line, ch: param.length + pos2.ch }, { atomic: true, selectRight: true }) + }, + matchToAuto() { + if (!this.name2Auto.length) return + this.name2Auto.forEach(ele => { + const search = this.$refs.myCm.codemirror.getSearchCursor(ele, { line: 0, ch: 0 }) + if (search.find()) { + const { from, to } = search.pos + this.$refs.myCm.codemirror.markText({ line: from.line, ch: from.ch - 1 }, { line: to.line, ch: to.ch + 1 }, { atomic: true, selectRight: true }) + } + }) + }, + setNameIdTrans(from, to, originName, name2Auto) { + if (!originName) { + return originName + } + let name2Id = originName + const nameIdMap = this.linkJumpInfoArray.reduce((pre, next) => { + pre[next[from]] = next[to] + return pre + }, {}) + const on = originName.match(/\[(.+?)\]/g) + if (on) { + on.forEach(itm => { + const ele = itm.slice(1, -1) + if (name2Auto) { + name2Auto.push(nameIdMap[ele]) + } + name2Id = name2Id.replace(ele, nameIdMap[ele]) + }) + } + return name2Id } } } @@ -488,4 +653,120 @@ export default { /deep/ .el-tree--highlight-current .el-tree-node.is-current >.el-tree-node__content { background-color: #8dbbef !important; } +.codemirror { + height: 190px; + overflow-y: auto; + font-size: 12px; +} + +.codemirror >>> .CodeMirror-scroll { + height: 200px; + overflow-y: auto; + font-size: 12px; +} + +.padding-lr { + padding: 0 4px; +} + +.field-height { + height: calc(100% - 25px); + margin-top: 4px; +} + +.drag-list { + height: calc(100% - 26px); + overflow: auto; +} + +.item-dimension { + padding: 2px 10px; + margin: 2px 2px 0 2px; + border: solid 1px #eee; + text-align: left; + color: #606266; + /*background-color: rgba(35,46,64,.05);*/ + background-color: white; + display: block; + word-break: break-all; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.blackTheme .item-dimension { + border: solid 1px; + border-color: #495865; + color: #F2F6FC; + background-color: var(--MainBG); +} + +.item-dimension + .item-dimension { + margin-top: 2px; +} + +.item-dimension:hover { + color: #1890ff; + background: #e8f4ff; + border-color: #a3d3ff; + cursor: pointer; +} + +.blackTheme .item-dimension:hover { + /* color: var(--Main); */ + background: var(--ContentBG); + /* cursor: pointer; */ +} + +.item-quota { + padding: 2px 10px; + margin: 2px 2px 0 2px; + border: solid 1px #eee; + text-align: left; + color: #606266; + /*background-color: rgba(35,46,64,.05);*/ + background-color: white; + display: block; + word-break: break-all; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.blackTheme .item-quota { + + border: solid 1px; + border-color: #495865; + color: #F2F6FC; + background-color: var(--MainBG); + +} + +.item-quota + .item-quota { + margin-top: 2px; +} + +.item-quota:hover { + color: #67c23a; + background: #f0f9eb; + border-color: #b2d3a3; + cursor: pointer; +} + +.blackTheme .item-quota:hover { + background: var(--ContentBG); +} + +span { + font-size: 12px; +} + +.field-height ::v-deep .el-divider--horizontal{ + margin: 2px 0!important; +} + +::v-deep .CodeMirror { + height: 190px!important; +} +