Commit be0092176455ad2f3963ca24b0ec1b876304bb96
1 parent
090611a7
处理,通知公告,任务中心
Showing
44 changed files
with
3934 additions
and
117 deletions
src/components/Charts/Keyboard.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div :id="id" :class="className" :style="{height:height,width:width}" /> | ||
| 3 | +</template> | ||
| 4 | + | ||
| 5 | +<script> | ||
| 6 | +import echarts from 'echarts' | ||
| 7 | +import resize from './mixins/resize' | ||
| 8 | + | ||
| 9 | +export default { | ||
| 10 | + mixins: [resize], | ||
| 11 | + props: { | ||
| 12 | + className: { | ||
| 13 | + type: String, | ||
| 14 | + default: 'chart' | ||
| 15 | + }, | ||
| 16 | + id: { | ||
| 17 | + type: String, | ||
| 18 | + default: 'chart' | ||
| 19 | + }, | ||
| 20 | + width: { | ||
| 21 | + type: String, | ||
| 22 | + default: '200px' | ||
| 23 | + }, | ||
| 24 | + height: { | ||
| 25 | + type: String, | ||
| 26 | + default: '200px' | ||
| 27 | + } | ||
| 28 | + }, | ||
| 29 | + data() { | ||
| 30 | + return { | ||
| 31 | + chart: null | ||
| 32 | + } | ||
| 33 | + }, | ||
| 34 | + mounted() { | ||
| 35 | + this.initChart() | ||
| 36 | + }, | ||
| 37 | + beforeDestroy() { | ||
| 38 | + if (!this.chart) { | ||
| 39 | + return | ||
| 40 | + } | ||
| 41 | + this.chart.dispose() | ||
| 42 | + this.chart = null | ||
| 43 | + }, | ||
| 44 | + methods: { | ||
| 45 | + initChart() { | ||
| 46 | + this.chart = echarts.init(document.getElementById(this.id)) | ||
| 47 | + | ||
| 48 | + const xAxisData = [] | ||
| 49 | + const data = [] | ||
| 50 | + const data2 = [] | ||
| 51 | + for (let i = 0; i < 50; i++) { | ||
| 52 | + xAxisData.push(i) | ||
| 53 | + data.push((Math.sin(i / 5) * (i / 5 - 10) + i / 6) * 5) | ||
| 54 | + data2.push((Math.sin(i / 5) * (i / 5 + 10) + i / 6) * 3) | ||
| 55 | + } | ||
| 56 | + this.chart.setOption({ | ||
| 57 | + backgroundColor: '#08263a', | ||
| 58 | + grid: { | ||
| 59 | + left: '5%', | ||
| 60 | + right: '5%' | ||
| 61 | + }, | ||
| 62 | + xAxis: [{ | ||
| 63 | + show: false, | ||
| 64 | + data: xAxisData | ||
| 65 | + }, { | ||
| 66 | + show: false, | ||
| 67 | + data: xAxisData | ||
| 68 | + }], | ||
| 69 | + visualMap: { | ||
| 70 | + show: false, | ||
| 71 | + min: 0, | ||
| 72 | + max: 50, | ||
| 73 | + dimension: 0, | ||
| 74 | + inRange: { | ||
| 75 | + color: ['#4a657a', '#308e92', '#b1cfa5', '#f5d69f', '#f5898b', '#ef5055'] | ||
| 76 | + } | ||
| 77 | + }, | ||
| 78 | + yAxis: { | ||
| 79 | + axisLine: { | ||
| 80 | + show: false | ||
| 81 | + }, | ||
| 82 | + axisLabel: { | ||
| 83 | + textStyle: { | ||
| 84 | + color: '#4a657a' | ||
| 85 | + } | ||
| 86 | + }, | ||
| 87 | + splitLine: { | ||
| 88 | + show: true, | ||
| 89 | + lineStyle: { | ||
| 90 | + color: '#08263f' | ||
| 91 | + } | ||
| 92 | + }, | ||
| 93 | + axisTick: { | ||
| 94 | + show: false | ||
| 95 | + } | ||
| 96 | + }, | ||
| 97 | + series: [{ | ||
| 98 | + name: 'back', | ||
| 99 | + type: 'bar', | ||
| 100 | + data: data2, | ||
| 101 | + z: 1, | ||
| 102 | + itemStyle: { | ||
| 103 | + normal: { | ||
| 104 | + opacity: 0.4, | ||
| 105 | + barBorderRadius: 5, | ||
| 106 | + shadowBlur: 3, | ||
| 107 | + shadowColor: '#111' | ||
| 108 | + } | ||
| 109 | + } | ||
| 110 | + }, { | ||
| 111 | + name: 'Simulate Shadow', | ||
| 112 | + type: 'line', | ||
| 113 | + data, | ||
| 114 | + z: 2, | ||
| 115 | + showSymbol: false, | ||
| 116 | + animationDelay: 0, | ||
| 117 | + animationEasing: 'linear', | ||
| 118 | + animationDuration: 1200, | ||
| 119 | + lineStyle: { | ||
| 120 | + normal: { | ||
| 121 | + color: 'transparent' | ||
| 122 | + } | ||
| 123 | + }, | ||
| 124 | + areaStyle: { | ||
| 125 | + normal: { | ||
| 126 | + color: '#08263a', | ||
| 127 | + shadowBlur: 50, | ||
| 128 | + shadowColor: '#000' | ||
| 129 | + } | ||
| 130 | + } | ||
| 131 | + }, { | ||
| 132 | + name: 'front', | ||
| 133 | + type: 'bar', | ||
| 134 | + data, | ||
| 135 | + xAxisIndex: 1, | ||
| 136 | + z: 3, | ||
| 137 | + itemStyle: { | ||
| 138 | + normal: { | ||
| 139 | + barBorderRadius: 5 | ||
| 140 | + } | ||
| 141 | + } | ||
| 142 | + }], | ||
| 143 | + animationEasing: 'elasticOut', | ||
| 144 | + animationEasingUpdate: 'elasticOut', | ||
| 145 | + animationDelay(idx) { | ||
| 146 | + return idx * 20 | ||
| 147 | + }, | ||
| 148 | + animationDelayUpdate(idx) { | ||
| 149 | + return idx * 20 | ||
| 150 | + } | ||
| 151 | + }) | ||
| 152 | + } | ||
| 153 | + } | ||
| 154 | +} | ||
| 155 | +</script> |
src/components/Charts/LineMarker.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div :id="id" :class="className" :style="{height:height,width:width}" /> | ||
| 3 | +</template> | ||
| 4 | + | ||
| 5 | +<script> | ||
| 6 | +import echarts from 'echarts' | ||
| 7 | +import resize from './mixins/resize' | ||
| 8 | + | ||
| 9 | +export default { | ||
| 10 | + mixins: [resize], | ||
| 11 | + props: { | ||
| 12 | + className: { | ||
| 13 | + type: String, | ||
| 14 | + default: 'chart' | ||
| 15 | + }, | ||
| 16 | + id: { | ||
| 17 | + type: String, | ||
| 18 | + default: 'chart' | ||
| 19 | + }, | ||
| 20 | + width: { | ||
| 21 | + type: String, | ||
| 22 | + default: '200px' | ||
| 23 | + }, | ||
| 24 | + height: { | ||
| 25 | + type: String, | ||
| 26 | + default: '200px' | ||
| 27 | + } | ||
| 28 | + }, | ||
| 29 | + data() { | ||
| 30 | + return { | ||
| 31 | + chart: null | ||
| 32 | + } | ||
| 33 | + }, | ||
| 34 | + mounted() { | ||
| 35 | + this.initChart() | ||
| 36 | + }, | ||
| 37 | + beforeDestroy() { | ||
| 38 | + if (!this.chart) { | ||
| 39 | + return | ||
| 40 | + } | ||
| 41 | + this.chart.dispose() | ||
| 42 | + this.chart = null | ||
| 43 | + }, | ||
| 44 | + methods: { | ||
| 45 | + initChart() { | ||
| 46 | + this.chart = echarts.init(document.getElementById(this.id)) | ||
| 47 | + | ||
| 48 | + this.chart.setOption({ | ||
| 49 | + backgroundColor: '#394056', | ||
| 50 | + title: { | ||
| 51 | + top: 20, | ||
| 52 | + text: 'Requests', | ||
| 53 | + textStyle: { | ||
| 54 | + fontWeight: 'normal', | ||
| 55 | + fontSize: 16, | ||
| 56 | + color: '#F1F1F3' | ||
| 57 | + }, | ||
| 58 | + left: '1%' | ||
| 59 | + }, | ||
| 60 | + tooltip: { | ||
| 61 | + trigger: 'axis', | ||
| 62 | + axisPointer: { | ||
| 63 | + lineStyle: { | ||
| 64 | + color: '#57617B' | ||
| 65 | + } | ||
| 66 | + } | ||
| 67 | + }, | ||
| 68 | + legend: { | ||
| 69 | + top: 20, | ||
| 70 | + icon: 'rect', | ||
| 71 | + itemWidth: 14, | ||
| 72 | + itemHeight: 5, | ||
| 73 | + itemGap: 13, | ||
| 74 | + data: ['CMCC', 'CTCC', 'CUCC'], | ||
| 75 | + right: '4%', | ||
| 76 | + textStyle: { | ||
| 77 | + fontSize: 12, | ||
| 78 | + color: '#F1F1F3' | ||
| 79 | + } | ||
| 80 | + }, | ||
| 81 | + grid: { | ||
| 82 | + top: 100, | ||
| 83 | + left: '2%', | ||
| 84 | + right: '2%', | ||
| 85 | + bottom: '2%', | ||
| 86 | + containLabel: true | ||
| 87 | + }, | ||
| 88 | + xAxis: [{ | ||
| 89 | + type: 'category', | ||
| 90 | + boundaryGap: false, | ||
| 91 | + axisLine: { | ||
| 92 | + lineStyle: { | ||
| 93 | + color: '#57617B' | ||
| 94 | + } | ||
| 95 | + }, | ||
| 96 | + data: ['13:00', '13:05', '13:10', '13:15', '13:20', '13:25', '13:30', '13:35', '13:40', '13:45', '13:50', '13:55'] | ||
| 97 | + }], | ||
| 98 | + yAxis: [{ | ||
| 99 | + type: 'value', | ||
| 100 | + name: '(%)', | ||
| 101 | + axisTick: { | ||
| 102 | + show: false | ||
| 103 | + }, | ||
| 104 | + axisLine: { | ||
| 105 | + lineStyle: { | ||
| 106 | + color: '#57617B' | ||
| 107 | + } | ||
| 108 | + }, | ||
| 109 | + axisLabel: { | ||
| 110 | + margin: 10, | ||
| 111 | + textStyle: { | ||
| 112 | + fontSize: 14 | ||
| 113 | + } | ||
| 114 | + }, | ||
| 115 | + splitLine: { | ||
| 116 | + lineStyle: { | ||
| 117 | + color: '#57617B' | ||
| 118 | + } | ||
| 119 | + } | ||
| 120 | + }], | ||
| 121 | + series: [{ | ||
| 122 | + name: 'CMCC', | ||
| 123 | + type: 'line', | ||
| 124 | + smooth: true, | ||
| 125 | + symbol: 'circle', | ||
| 126 | + symbolSize: 5, | ||
| 127 | + showSymbol: false, | ||
| 128 | + lineStyle: { | ||
| 129 | + normal: { | ||
| 130 | + width: 1 | ||
| 131 | + } | ||
| 132 | + }, | ||
| 133 | + areaStyle: { | ||
| 134 | + normal: { | ||
| 135 | + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ | ||
| 136 | + offset: 0, | ||
| 137 | + color: 'rgba(137, 189, 27, 0.3)' | ||
| 138 | + }, { | ||
| 139 | + offset: 0.8, | ||
| 140 | + color: 'rgba(137, 189, 27, 0)' | ||
| 141 | + }], false), | ||
| 142 | + shadowColor: 'rgba(0, 0, 0, 0.1)', | ||
| 143 | + shadowBlur: 10 | ||
| 144 | + } | ||
| 145 | + }, | ||
| 146 | + itemStyle: { | ||
| 147 | + normal: { | ||
| 148 | + color: 'rgb(137,189,27)', | ||
| 149 | + borderColor: 'rgba(137,189,2,0.27)', | ||
| 150 | + borderWidth: 12 | ||
| 151 | + | ||
| 152 | + } | ||
| 153 | + }, | ||
| 154 | + data: [220, 182, 191, 134, 150, 120, 110, 125, 145, 122, 165, 122] | ||
| 155 | + }, { | ||
| 156 | + name: 'CTCC', | ||
| 157 | + type: 'line', | ||
| 158 | + smooth: true, | ||
| 159 | + symbol: 'circle', | ||
| 160 | + symbolSize: 5, | ||
| 161 | + showSymbol: false, | ||
| 162 | + lineStyle: { | ||
| 163 | + normal: { | ||
| 164 | + width: 1 | ||
| 165 | + } | ||
| 166 | + }, | ||
| 167 | + areaStyle: { | ||
| 168 | + normal: { | ||
| 169 | + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ | ||
| 170 | + offset: 0, | ||
| 171 | + color: 'rgba(0, 136, 212, 0.3)' | ||
| 172 | + }, { | ||
| 173 | + offset: 0.8, | ||
| 174 | + color: 'rgba(0, 136, 212, 0)' | ||
| 175 | + }], false), | ||
| 176 | + shadowColor: 'rgba(0, 0, 0, 0.1)', | ||
| 177 | + shadowBlur: 10 | ||
| 178 | + } | ||
| 179 | + }, | ||
| 180 | + itemStyle: { | ||
| 181 | + normal: { | ||
| 182 | + color: 'rgb(0,136,212)', | ||
| 183 | + borderColor: 'rgba(0,136,212,0.2)', | ||
| 184 | + borderWidth: 12 | ||
| 185 | + | ||
| 186 | + } | ||
| 187 | + }, | ||
| 188 | + data: [120, 110, 125, 145, 122, 165, 122, 220, 182, 191, 134, 150] | ||
| 189 | + }, { | ||
| 190 | + name: 'CUCC', | ||
| 191 | + type: 'line', | ||
| 192 | + smooth: true, | ||
| 193 | + symbol: 'circle', | ||
| 194 | + symbolSize: 5, | ||
| 195 | + showSymbol: false, | ||
| 196 | + lineStyle: { | ||
| 197 | + normal: { | ||
| 198 | + width: 1 | ||
| 199 | + } | ||
| 200 | + }, | ||
| 201 | + areaStyle: { | ||
| 202 | + normal: { | ||
| 203 | + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ | ||
| 204 | + offset: 0, | ||
| 205 | + color: 'rgba(219, 50, 51, 0.3)' | ||
| 206 | + }, { | ||
| 207 | + offset: 0.8, | ||
| 208 | + color: 'rgba(219, 50, 51, 0)' | ||
| 209 | + }], false), | ||
| 210 | + shadowColor: 'rgba(0, 0, 0, 0.1)', | ||
| 211 | + shadowBlur: 10 | ||
| 212 | + } | ||
| 213 | + }, | ||
| 214 | + itemStyle: { | ||
| 215 | + normal: { | ||
| 216 | + color: 'rgb(219,50,51)', | ||
| 217 | + borderColor: 'rgba(219,50,51,0.2)', | ||
| 218 | + borderWidth: 12 | ||
| 219 | + } | ||
| 220 | + }, | ||
| 221 | + data: [220, 182, 125, 145, 122, 191, 134, 150, 120, 110, 165, 122] | ||
| 222 | + }] | ||
| 223 | + }) | ||
| 224 | + } | ||
| 225 | + } | ||
| 226 | +} | ||
| 227 | +</script> |
src/components/Charts/MixChart.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div :id="id" :class="className" :style="{height:height,width:width}" /> | ||
| 3 | +</template> | ||
| 4 | + | ||
| 5 | +<script> | ||
| 6 | +import echarts from 'echarts' | ||
| 7 | +import resize from './mixins/resize' | ||
| 8 | + | ||
| 9 | +export default { | ||
| 10 | + mixins: [resize], | ||
| 11 | + props: { | ||
| 12 | + className: { | ||
| 13 | + type: String, | ||
| 14 | + default: 'chart' | ||
| 15 | + }, | ||
| 16 | + id: { | ||
| 17 | + type: String, | ||
| 18 | + default: 'chart' | ||
| 19 | + }, | ||
| 20 | + width: { | ||
| 21 | + type: String, | ||
| 22 | + default: '200px' | ||
| 23 | + }, | ||
| 24 | + height: { | ||
| 25 | + type: String, | ||
| 26 | + default: '200px' | ||
| 27 | + } | ||
| 28 | + }, | ||
| 29 | + data() { | ||
| 30 | + return { | ||
| 31 | + chart: null | ||
| 32 | + } | ||
| 33 | + }, | ||
| 34 | + mounted() { | ||
| 35 | + this.initChart() | ||
| 36 | + }, | ||
| 37 | + beforeDestroy() { | ||
| 38 | + if (!this.chart) { | ||
| 39 | + return | ||
| 40 | + } | ||
| 41 | + this.chart.dispose() | ||
| 42 | + this.chart = null | ||
| 43 | + }, | ||
| 44 | + methods: { | ||
| 45 | + initChart() { | ||
| 46 | + this.chart = echarts.init(document.getElementById(this.id)) | ||
| 47 | + const xData = (function() { | ||
| 48 | + const data = [] | ||
| 49 | + for (let i = 1; i < 13; i++) { | ||
| 50 | + data.push(i + 'month') | ||
| 51 | + } | ||
| 52 | + return data | ||
| 53 | + }()) | ||
| 54 | + this.chart.setOption({ | ||
| 55 | + backgroundColor: '#344b58', | ||
| 56 | + title: { | ||
| 57 | + text: 'statistics', | ||
| 58 | + x: '20', | ||
| 59 | + top: '20', | ||
| 60 | + textStyle: { | ||
| 61 | + color: '#fff', | ||
| 62 | + fontSize: '22' | ||
| 63 | + }, | ||
| 64 | + subtextStyle: { | ||
| 65 | + color: '#90979c', | ||
| 66 | + fontSize: '16' | ||
| 67 | + } | ||
| 68 | + }, | ||
| 69 | + tooltip: { | ||
| 70 | + trigger: 'axis', | ||
| 71 | + axisPointer: { | ||
| 72 | + textStyle: { | ||
| 73 | + color: '#fff' | ||
| 74 | + } | ||
| 75 | + } | ||
| 76 | + }, | ||
| 77 | + grid: { | ||
| 78 | + left: '5%', | ||
| 79 | + right: '5%', | ||
| 80 | + borderWidth: 0, | ||
| 81 | + top: 150, | ||
| 82 | + bottom: 95, | ||
| 83 | + textStyle: { | ||
| 84 | + color: '#fff' | ||
| 85 | + } | ||
| 86 | + }, | ||
| 87 | + legend: { | ||
| 88 | + x: '5%', | ||
| 89 | + top: '10%', | ||
| 90 | + textStyle: { | ||
| 91 | + color: '#90979c' | ||
| 92 | + }, | ||
| 93 | + data: ['female', 'male', 'average'] | ||
| 94 | + }, | ||
| 95 | + calculable: true, | ||
| 96 | + xAxis: [{ | ||
| 97 | + type: 'category', | ||
| 98 | + axisLine: { | ||
| 99 | + lineStyle: { | ||
| 100 | + color: '#90979c' | ||
| 101 | + } | ||
| 102 | + }, | ||
| 103 | + splitLine: { | ||
| 104 | + show: false | ||
| 105 | + }, | ||
| 106 | + axisTick: { | ||
| 107 | + show: false | ||
| 108 | + }, | ||
| 109 | + splitArea: { | ||
| 110 | + show: false | ||
| 111 | + }, | ||
| 112 | + axisLabel: { | ||
| 113 | + interval: 0 | ||
| 114 | + | ||
| 115 | + }, | ||
| 116 | + data: xData | ||
| 117 | + }], | ||
| 118 | + yAxis: [{ | ||
| 119 | + type: 'value', | ||
| 120 | + splitLine: { | ||
| 121 | + show: false | ||
| 122 | + }, | ||
| 123 | + axisLine: { | ||
| 124 | + lineStyle: { | ||
| 125 | + color: '#90979c' | ||
| 126 | + } | ||
| 127 | + }, | ||
| 128 | + axisTick: { | ||
| 129 | + show: false | ||
| 130 | + }, | ||
| 131 | + axisLabel: { | ||
| 132 | + interval: 0 | ||
| 133 | + }, | ||
| 134 | + splitArea: { | ||
| 135 | + show: false | ||
| 136 | + } | ||
| 137 | + }], | ||
| 138 | + dataZoom: [{ | ||
| 139 | + show: true, | ||
| 140 | + height: 30, | ||
| 141 | + xAxisIndex: [ | ||
| 142 | + 0 | ||
| 143 | + ], | ||
| 144 | + bottom: 30, | ||
| 145 | + start: 10, | ||
| 146 | + end: 80, | ||
| 147 | + handleIcon: 'path://M306.1,413c0,2.2-1.8,4-4,4h-59.8c-2.2,0-4-1.8-4-4V200.8c0-2.2,1.8-4,4-4h59.8c2.2,0,4,1.8,4,4V413z', | ||
| 148 | + handleSize: '110%', | ||
| 149 | + handleStyle: { | ||
| 150 | + color: '#d3dee5' | ||
| 151 | + | ||
| 152 | + }, | ||
| 153 | + textStyle: { | ||
| 154 | + color: '#fff' }, | ||
| 155 | + borderColor: '#90979c' | ||
| 156 | + | ||
| 157 | + }, { | ||
| 158 | + type: 'inside', | ||
| 159 | + show: true, | ||
| 160 | + height: 15, | ||
| 161 | + start: 1, | ||
| 162 | + end: 35 | ||
| 163 | + }], | ||
| 164 | + series: [{ | ||
| 165 | + name: 'female', | ||
| 166 | + type: 'bar', | ||
| 167 | + stack: 'total', | ||
| 168 | + barMaxWidth: 35, | ||
| 169 | + barGap: '10%', | ||
| 170 | + itemStyle: { | ||
| 171 | + normal: { | ||
| 172 | + color: 'rgba(255,144,128,1)', | ||
| 173 | + label: { | ||
| 174 | + show: true, | ||
| 175 | + textStyle: { | ||
| 176 | + color: '#fff' | ||
| 177 | + }, | ||
| 178 | + position: 'insideTop', | ||
| 179 | + formatter(p) { | ||
| 180 | + return p.value > 0 ? p.value : '' | ||
| 181 | + } | ||
| 182 | + } | ||
| 183 | + } | ||
| 184 | + }, | ||
| 185 | + data: [ | ||
| 186 | + 709, | ||
| 187 | + 1917, | ||
| 188 | + 2455, | ||
| 189 | + 2610, | ||
| 190 | + 1719, | ||
| 191 | + 1433, | ||
| 192 | + 1544, | ||
| 193 | + 3285, | ||
| 194 | + 5208, | ||
| 195 | + 3372, | ||
| 196 | + 2484, | ||
| 197 | + 4078 | ||
| 198 | + ] | ||
| 199 | + }, | ||
| 200 | + | ||
| 201 | + { | ||
| 202 | + name: 'male', | ||
| 203 | + type: 'bar', | ||
| 204 | + stack: 'total', | ||
| 205 | + itemStyle: { | ||
| 206 | + normal: { | ||
| 207 | + color: 'rgba(0,191,183,1)', | ||
| 208 | + barBorderRadius: 0, | ||
| 209 | + label: { | ||
| 210 | + show: true, | ||
| 211 | + position: 'top', | ||
| 212 | + formatter(p) { | ||
| 213 | + return p.value > 0 ? p.value : '' | ||
| 214 | + } | ||
| 215 | + } | ||
| 216 | + } | ||
| 217 | + }, | ||
| 218 | + data: [ | ||
| 219 | + 327, | ||
| 220 | + 1776, | ||
| 221 | + 507, | ||
| 222 | + 1200, | ||
| 223 | + 800, | ||
| 224 | + 482, | ||
| 225 | + 204, | ||
| 226 | + 1390, | ||
| 227 | + 1001, | ||
| 228 | + 951, | ||
| 229 | + 381, | ||
| 230 | + 220 | ||
| 231 | + ] | ||
| 232 | + }, { | ||
| 233 | + name: 'average', | ||
| 234 | + type: 'line', | ||
| 235 | + stack: 'total', | ||
| 236 | + symbolSize: 10, | ||
| 237 | + symbol: 'circle', | ||
| 238 | + itemStyle: { | ||
| 239 | + normal: { | ||
| 240 | + color: 'rgba(252,230,48,1)', | ||
| 241 | + barBorderRadius: 0, | ||
| 242 | + label: { | ||
| 243 | + show: true, | ||
| 244 | + position: 'top', | ||
| 245 | + formatter(p) { | ||
| 246 | + return p.value > 0 ? p.value : '' | ||
| 247 | + } | ||
| 248 | + } | ||
| 249 | + } | ||
| 250 | + }, | ||
| 251 | + data: [ | ||
| 252 | + 1036, | ||
| 253 | + 3693, | ||
| 254 | + 2962, | ||
| 255 | + 3810, | ||
| 256 | + 2519, | ||
| 257 | + 1915, | ||
| 258 | + 1748, | ||
| 259 | + 4675, | ||
| 260 | + 6209, | ||
| 261 | + 4323, | ||
| 262 | + 2865, | ||
| 263 | + 4298 | ||
| 264 | + ] | ||
| 265 | + } | ||
| 266 | + ] | ||
| 267 | + }) | ||
| 268 | + } | ||
| 269 | + } | ||
| 270 | +} | ||
| 271 | +</script> |
src/components/Charts/Normal.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div :class="className" :style="{height: height,width: width}" ref="echarts"/> | ||
| 3 | +</template> | ||
| 4 | + | ||
| 5 | +<script> | ||
| 6 | + import echarts from 'echarts' | ||
| 7 | + require('echarts/theme/macarons') // echarts theme | ||
| 8 | + import resize from './mixins/resize' | ||
| 9 | + | ||
| 10 | + export default { | ||
| 11 | + name: 'chart', | ||
| 12 | + mixins: [resize], | ||
| 13 | + props: { | ||
| 14 | + className: { | ||
| 15 | + type: String, | ||
| 16 | + default: 'chart' | ||
| 17 | + }, | ||
| 18 | + width: { | ||
| 19 | + type: String, | ||
| 20 | + default: '100%' | ||
| 21 | + }, | ||
| 22 | + height: { | ||
| 23 | + type: String, | ||
| 24 | + default: '350px' | ||
| 25 | + }, | ||
| 26 | + autoResize: { | ||
| 27 | + type: Boolean, | ||
| 28 | + default: true | ||
| 29 | + }, | ||
| 30 | + options: { | ||
| 31 | + type: Object, | ||
| 32 | + default: {}, | ||
| 33 | + required: true | ||
| 34 | + } | ||
| 35 | + }, | ||
| 36 | + data() { | ||
| 37 | + return { | ||
| 38 | + chart: null | ||
| 39 | + } | ||
| 40 | + }, | ||
| 41 | + watch: { | ||
| 42 | + options: { | ||
| 43 | + deep: true, | ||
| 44 | + handler(options) { | ||
| 45 | + if (!this.chart && options) { | ||
| 46 | + this.initChart() | ||
| 47 | + } else { | ||
| 48 | + this.chart.setOption(this.options, true) | ||
| 49 | + } | ||
| 50 | + } | ||
| 51 | + } | ||
| 52 | + }, | ||
| 53 | + mounted() { | ||
| 54 | + this.$nextTick(() => { | ||
| 55 | + this.initChart() | ||
| 56 | + }) | ||
| 57 | + }, | ||
| 58 | + beforeDestroy() { | ||
| 59 | + if (!this.chart) { | ||
| 60 | + return | ||
| 61 | + } | ||
| 62 | + this.chart.dispose() | ||
| 63 | + this.chart = null | ||
| 64 | + }, | ||
| 65 | + methods: { | ||
| 66 | + initChart() { | ||
| 67 | + this.chart = echarts.init(this.$refs.echarts, 'macarons') | ||
| 68 | + this.chart.setOption(this.options) | ||
| 69 | + } | ||
| 70 | + } | ||
| 71 | + } | ||
| 72 | +</script> |
src/components/Charts/mixins/resize.js
0 → 100644
| 1 | +import { debounce } from '@/utils' | ||
| 2 | + | ||
| 3 | +export default { | ||
| 4 | + data() { | ||
| 5 | + return { | ||
| 6 | + $_sidebarElm: null, | ||
| 7 | + $_resizeHandler: null | ||
| 8 | + } | ||
| 9 | + }, | ||
| 10 | + mounted() { | ||
| 11 | + this.initListener() | ||
| 12 | + }, | ||
| 13 | + activated() { | ||
| 14 | + if (!this.$_resizeHandler) { | ||
| 15 | + // avoid duplication init | ||
| 16 | + this.initListener() | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + // when keep-alive chart activated, auto resize | ||
| 20 | + this.resize() | ||
| 21 | + }, | ||
| 22 | + beforeDestroy() { | ||
| 23 | + this.destroyListener() | ||
| 24 | + }, | ||
| 25 | + deactivated() { | ||
| 26 | + this.destroyListener() | ||
| 27 | + }, | ||
| 28 | + methods: { | ||
| 29 | + // use $_ for mixins properties | ||
| 30 | + // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential | ||
| 31 | + $_sidebarResizeHandler(e) { | ||
| 32 | + if (e.propertyName === 'width') { | ||
| 33 | + this.$_resizeHandler() | ||
| 34 | + } | ||
| 35 | + }, | ||
| 36 | + initListener() { | ||
| 37 | + this.$_resizeHandler = debounce(() => { | ||
| 38 | + this.resize() | ||
| 39 | + }, 100) | ||
| 40 | + window.addEventListener('resize', this.$_resizeHandler) | ||
| 41 | + | ||
| 42 | + this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0] | ||
| 43 | + this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler) | ||
| 44 | + }, | ||
| 45 | + destroyListener() { | ||
| 46 | + window.removeEventListener('resize', this.$_resizeHandler) | ||
| 47 | + this.$_resizeHandler = null | ||
| 48 | + | ||
| 49 | + this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler) | ||
| 50 | + }, | ||
| 51 | + resize() { | ||
| 52 | + const { chart } = this | ||
| 53 | + chart && chart.resize() | ||
| 54 | + } | ||
| 55 | + } | ||
| 56 | +} |
src/components/ColumnSettings/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-tooltip :content="$t('common.columnSettings')" placement="top"> | ||
| 3 | + <el-popover width="200" popper-class="columnSetting-popover"> | ||
| 4 | + <el-link icon="icon-ym icon-ym-options NCC-common-head-icon" :underline="false" | ||
| 5 | + slot="reference" /> | ||
| 6 | + <NCC-table :data="data" class="columnTable" :hasNO="false" size="mini" ref="columnTable" | ||
| 7 | + @selection-change="columnSelectionChange" @row-click="handleRowClick"> | ||
| 8 | + <el-table-column prop="label" label="列表字段" /> | ||
| 9 | + <el-table-column type="selection" width="50" align="center" /> | ||
| 10 | + </NCC-table> | ||
| 11 | + </el-popover> | ||
| 12 | + </el-tooltip> | ||
| 13 | +</template> | ||
| 14 | + | ||
| 15 | +<script> | ||
| 16 | +export default { | ||
| 17 | + name: 'ColumnSettings', | ||
| 18 | + model: { | ||
| 19 | + prop: 'value', | ||
| 20 | + event: 'change' | ||
| 21 | + }, | ||
| 22 | + props: { | ||
| 23 | + value: Array, | ||
| 24 | + data: { | ||
| 25 | + type: Array, | ||
| 26 | + default: () => [] | ||
| 27 | + } | ||
| 28 | + }, | ||
| 29 | + mounted() { | ||
| 30 | + this.$refs.columnTable.$refs.NCCTable.toggleAllSelection() | ||
| 31 | + }, | ||
| 32 | + methods: { | ||
| 33 | + handleRowClick(row) { | ||
| 34 | + this.$refs.columnTable.$refs.NCCTable.toggleRowSelection(row) | ||
| 35 | + }, | ||
| 36 | + columnSelectionChange(val) { | ||
| 37 | + this.$emit('change', val) | ||
| 38 | + } | ||
| 39 | + } | ||
| 40 | +} | ||
| 41 | +</script> | ||
| 42 | +<style lang="scss"> | ||
| 43 | +.columnSetting-popover { | ||
| 44 | + padding: 0 !important; | ||
| 45 | +} | ||
| 46 | +</style> | ||
| 0 | \ No newline at end of file | 47 | \ No newline at end of file |
src/components/CompanyForm/index.vue
| @@ -66,7 +66,7 @@ | @@ -66,7 +66,7 @@ | ||
| 66 | </el-form> | 66 | </el-form> |
| 67 | <span slot="footer" class="dialog-footer"> | 67 | <span slot="footer" class="dialog-footer"> |
| 68 | <el-button @click="close">取消</el-button> | 68 | <el-button @click="close">取消</el-button> |
| 69 | - <el-button type="primary" @click="confirm">确认</el-button> | 69 | + <el-button type="primary" @click="confirm" :loading="btnLoading">确认</el-button> |
| 70 | </span> | 70 | </span> |
| 71 | </el-dialog> | 71 | </el-dialog> |
| 72 | </div> | 72 | </div> |
| @@ -79,35 +79,36 @@ export default { | @@ -79,35 +79,36 @@ export default { | ||
| 79 | props: {}, | 79 | props: {}, |
| 80 | data() { | 80 | data() { |
| 81 | return { | 81 | return { |
| 82 | - visible: false, | ||
| 83 | - loading: false, | ||
| 84 | - dataForm: { | ||
| 85 | - id: '', | ||
| 86 | - id: undefined, | ||
| 87 | - companyName: undefined, | ||
| 88 | - socialCreditAgency: undefined, | ||
| 89 | - legalPerson: undefined, | ||
| 90 | - address: undefined, | ||
| 91 | - contactInformation: undefined, | ||
| 92 | - qualificationCertificate: [], | ||
| 93 | - otherInfo: undefined, | ||
| 94 | - }, | ||
| 95 | - rules: { | ||
| 96 | - companyName: [ | ||
| 97 | - { | ||
| 98 | - required: true, | ||
| 99 | - message: '请输入公司名称', | ||
| 100 | - trigger: 'blur' | ||
| 101 | - }, | ||
| 102 | - ], | ||
| 103 | - contactInformation: [ | ||
| 104 | - { | ||
| 105 | - pattern: /^1[3456789]\d{9}$|^0\d{2,3}-?\d{7,8}$/, | ||
| 106 | - message: '请输入正确的联系方式', | ||
| 107 | - trigger: 'blur' | ||
| 108 | - }, | ||
| 109 | - ], | ||
| 110 | - }, | 82 | + visible: false, |
| 83 | + loading: false, | ||
| 84 | + dataForm: { | ||
| 85 | + id: '', | ||
| 86 | + id: undefined, | ||
| 87 | + companyName: undefined, | ||
| 88 | + socialCreditAgency: undefined, | ||
| 89 | + legalPerson: undefined, | ||
| 90 | + address: undefined, | ||
| 91 | + contactInformation: undefined, | ||
| 92 | + qualificationCertificate: [], | ||
| 93 | + otherInfo: undefined, | ||
| 94 | + }, | ||
| 95 | + rules: { | ||
| 96 | + companyName: [ | ||
| 97 | + { | ||
| 98 | + required: true, | ||
| 99 | + message: '请输入公司名称', | ||
| 100 | + trigger: 'blur' | ||
| 101 | + }, | ||
| 102 | + ], | ||
| 103 | + contactInformation: [ | ||
| 104 | + { | ||
| 105 | + pattern: /^1[3456789]\d{9}$|^0\d{2,3}-?\d{7,8}$/, | ||
| 106 | + message: '请输入正确的联系方式', | ||
| 107 | + trigger: 'blur' | ||
| 108 | + }, | ||
| 109 | + ], | ||
| 110 | + }, | ||
| 111 | + btnLoading: false | ||
| 111 | }; | 112 | }; |
| 112 | }, | 113 | }, |
| 113 | watch: {}, | 114 | watch: {}, |
| @@ -122,25 +123,27 @@ export default { | @@ -122,25 +123,27 @@ export default { | ||
| 122 | this.$refs['elForm'].resetFields(); | 123 | this.$refs['elForm'].resetFields(); |
| 123 | }, | 124 | }, |
| 124 | async confirm() { | 125 | async confirm() { |
| 125 | - this.$refs['elForm'].validate((valid) => { | ||
| 126 | - if (valid) { | ||
| 127 | - request({ | ||
| 128 | - url: `/Extend/BaseComapnyInfo`, | ||
| 129 | - method: 'post', | ||
| 130 | - data: this.dataForm, | ||
| 131 | - }).then((res) => { | ||
| 132 | - this.$message({ | ||
| 133 | - message: res.msg, | ||
| 134 | - type: 'success', | ||
| 135 | - duration: 1000, | ||
| 136 | - onClose: () => { | ||
| 137 | - this.visible = false, | ||
| 138 | - this.$emit('refresh', true) | ||
| 139 | - } | ||
| 140 | - }) | ||
| 141 | - }) | ||
| 142 | - }}) | ||
| 143 | - | 126 | + this.$refs['elForm'].validate((valid) => { |
| 127 | + if (valid) { | ||
| 128 | + this.btnLoading = true; | ||
| 129 | + request({ | ||
| 130 | + url: `/Extend/BaseComapnyInfo`, | ||
| 131 | + method: 'post', | ||
| 132 | + data: this.dataForm, | ||
| 133 | + }).then((res) => { | ||
| 134 | + this.btnLoading = false; | ||
| 135 | + this.$message({ | ||
| 136 | + message: res.msg, | ||
| 137 | + type: 'success', | ||
| 138 | + duration: 1000, | ||
| 139 | + onClose: () => { | ||
| 140 | + this.visible = false, | ||
| 141 | + this.$emit('refresh', true) | ||
| 142 | + } | ||
| 143 | + }) | ||
| 144 | + }).catch(() => {this.btnLoading = false}) | ||
| 145 | + } | ||
| 146 | + }) | ||
| 144 | }, | 147 | }, |
| 145 | }, | 148 | }, |
| 146 | }; | 149 | }; |
src/components/Hamburger/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div style="padding: 0 15px;" @click="toggleClick"> | ||
| 3 | + <i class="icon-ym icon-ym-header-collapse1" v-if='isActive'></i> | ||
| 4 | + <i class="icon-ym icon-ym-header-expand" v-else></i> | ||
| 5 | + </div> | ||
| 6 | +</template> | ||
| 7 | + | ||
| 8 | +<script> | ||
| 9 | +export default { | ||
| 10 | + name: 'Hamburger', | ||
| 11 | + props: { | ||
| 12 | + isActive: { | ||
| 13 | + type: Boolean, | ||
| 14 | + default: false | ||
| 15 | + } | ||
| 16 | + }, | ||
| 17 | + methods: { | ||
| 18 | + toggleClick() { | ||
| 19 | + this.$emit('toggleClick') | ||
| 20 | + } | ||
| 21 | + } | ||
| 22 | +} | ||
| 23 | +</script> | ||
| 24 | + | ||
| 25 | +<style scoped> | ||
| 26 | +.icon-ym { | ||
| 27 | + font-size: 20px; | ||
| 28 | + color: #666666; | ||
| 29 | +} | ||
| 30 | +</style> | ||
| 0 | \ No newline at end of file | 31 | \ No newline at end of file |
src/components/HeaderSearch/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div :class="{'show':show}" class="header-search"> | ||
| 3 | + <i class="el-icon-search search-icon" @click.stop="click"></i> | ||
| 4 | + <el-select ref="headerSearchSelect" v-model="search" :remote-method="querySearch" filterable | ||
| 5 | + default-first-option remote placeholder="搜索:导航菜单" class="header-search-select" | ||
| 6 | + @change="change"> | ||
| 7 | + <el-option v-for="item in options" :key="item.path" :value="item" | ||
| 8 | + :label="item.title.join(' > ')" /> | ||
| 9 | + </el-select> | ||
| 10 | + </div> | ||
| 11 | +</template> | ||
| 12 | + | ||
| 13 | +<script> | ||
| 14 | +// fuse is a lightweight fuzzy-search module | ||
| 15 | +// make search results more in line with expectations | ||
| 16 | +import Fuse from 'fuse.js' | ||
| 17 | +import path from 'path' | ||
| 18 | +import i18n from '@/lang' | ||
| 19 | + | ||
| 20 | +export default { | ||
| 21 | + name: 'HeaderSearch', | ||
| 22 | + data() { | ||
| 23 | + return { | ||
| 24 | + search: '', | ||
| 25 | + options: [], | ||
| 26 | + searchPool: [], | ||
| 27 | + show: false, | ||
| 28 | + fuse: undefined | ||
| 29 | + } | ||
| 30 | + }, | ||
| 31 | + computed: { | ||
| 32 | + routes() { | ||
| 33 | + return this.$store.getters.permission_routes | ||
| 34 | + }, | ||
| 35 | + lang() { | ||
| 36 | + return this.$store.getters.language | ||
| 37 | + } | ||
| 38 | + }, | ||
| 39 | + watch: { | ||
| 40 | + lang() { | ||
| 41 | + this.searchPool = this.generateRoutes(this.routes) | ||
| 42 | + }, | ||
| 43 | + routes() { | ||
| 44 | + this.searchPool = this.generateRoutes(this.routes) | ||
| 45 | + }, | ||
| 46 | + searchPool(list) { | ||
| 47 | + this.initFuse(list) | ||
| 48 | + }, | ||
| 49 | + show(value) { | ||
| 50 | + if (value) { | ||
| 51 | + document.body.addEventListener('click', this.close) | ||
| 52 | + } else { | ||
| 53 | + document.body.removeEventListener('click', this.close) | ||
| 54 | + } | ||
| 55 | + } | ||
| 56 | + }, | ||
| 57 | + mounted() { | ||
| 58 | + this.searchPool = this.generateRoutes(this.routes) | ||
| 59 | + }, | ||
| 60 | + methods: { | ||
| 61 | + click() { | ||
| 62 | + this.show = !this.show | ||
| 63 | + if (this.show) { | ||
| 64 | + this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus() | ||
| 65 | + } | ||
| 66 | + }, | ||
| 67 | + close() { | ||
| 68 | + this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur() | ||
| 69 | + this.options = [] | ||
| 70 | + this.show = false | ||
| 71 | + }, | ||
| 72 | + change(val) { | ||
| 73 | + this.$router.push(val.path) | ||
| 74 | + this.search = '' | ||
| 75 | + this.options = [] | ||
| 76 | + this.$nextTick(() => { | ||
| 77 | + this.show = false | ||
| 78 | + }) | ||
| 79 | + }, | ||
| 80 | + initFuse(list) { | ||
| 81 | + this.fuse = new Fuse(list, { | ||
| 82 | + shouldSort: true, | ||
| 83 | + threshold: 0.4, | ||
| 84 | + location: 0, | ||
| 85 | + distance: 100, | ||
| 86 | + maxPatternLength: 32, | ||
| 87 | + minMatchCharLength: 1, | ||
| 88 | + keys: [{ | ||
| 89 | + name: 'title', | ||
| 90 | + weight: 0.7 | ||
| 91 | + }, { | ||
| 92 | + name: 'path', | ||
| 93 | + weight: 0.3 | ||
| 94 | + }] | ||
| 95 | + }) | ||
| 96 | + }, | ||
| 97 | + // Filter out the routes that can be displayed in the sidebar | ||
| 98 | + // And generate the internationalized title | ||
| 99 | + generateRoutes(routes, basePath = '/', prefixTitle = []) { | ||
| 100 | + let res = [] | ||
| 101 | + | ||
| 102 | + for (const router of routes) { | ||
| 103 | + // console.log(router); | ||
| 104 | + | ||
| 105 | + // skip hidden router | ||
| 106 | + if (router.hidden) { continue } | ||
| 107 | + | ||
| 108 | + const data = { | ||
| 109 | + path: path.resolve(basePath, router.path), | ||
| 110 | + title: [...prefixTitle] | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + if (router.meta && router.meta.title) { | ||
| 114 | + // generate internationalized title | ||
| 115 | + const i18ntitle = i18n.t(`route.${router.meta.title}`) | ||
| 116 | + | ||
| 117 | + let title = i18ntitle | ||
| 118 | + if (i18ntitle.indexOf('route.') > -1) title = router.meta.zhTitle | ||
| 119 | + data.title = [...data.title, title] | ||
| 120 | + | ||
| 121 | + if (router.redirect !== 'noRedirect') { | ||
| 122 | + // only push the routes with title | ||
| 123 | + // special case: need to exclude parent router without redirect | ||
| 124 | + res.push(data) | ||
| 125 | + } | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + // recursive child routes | ||
| 129 | + if (router.children) { | ||
| 130 | + const tempRoutes = this.generateRoutes(router.children, data.path, data.title) | ||
| 131 | + if (tempRoutes.length >= 1) { | ||
| 132 | + res = [...res, ...tempRoutes] | ||
| 133 | + } | ||
| 134 | + } | ||
| 135 | + } | ||
| 136 | + return res | ||
| 137 | + }, | ||
| 138 | + querySearch(query) { | ||
| 139 | + if (query !== '') { | ||
| 140 | + this.options = this.fuse.search(query) | ||
| 141 | + } else { | ||
| 142 | + this.options = [] | ||
| 143 | + } | ||
| 144 | + } | ||
| 145 | + } | ||
| 146 | +} | ||
| 147 | +</script> | ||
| 148 | + | ||
| 149 | +<style lang="scss" scoped> | ||
| 150 | +.header-search { | ||
| 151 | + font-size: 0 !important; | ||
| 152 | + | ||
| 153 | + .search-icon { | ||
| 154 | + cursor: pointer; | ||
| 155 | + font-size: 16px; | ||
| 156 | + vertical-align: middle; | ||
| 157 | + } | ||
| 158 | + | ||
| 159 | + .header-search-select { | ||
| 160 | + font-size: 20px; | ||
| 161 | + transition: width 0.2s; | ||
| 162 | + width: 0; | ||
| 163 | + overflow: hidden; | ||
| 164 | + background: transparent; | ||
| 165 | + border-radius: 0; | ||
| 166 | + display: inline-block; | ||
| 167 | + vertical-align: middle; | ||
| 168 | + | ||
| 169 | + >>> .el-input__inner { | ||
| 170 | + border-radius: 0; | ||
| 171 | + border: 0; | ||
| 172 | + // padding-left: 0; | ||
| 173 | + // padding-right: 0; | ||
| 174 | + box-shadow: none !important; | ||
| 175 | + border-bottom: 1px solid #d9d9d9; | ||
| 176 | + vertical-align: middle; | ||
| 177 | + } | ||
| 178 | + } | ||
| 179 | + | ||
| 180 | + &.show { | ||
| 181 | + .header-search-select { | ||
| 182 | + width: 210px; | ||
| 183 | + margin-left: 10px; | ||
| 184 | + } | ||
| 185 | + } | ||
| 186 | +} | ||
| 187 | +</style> |
src/components/InfoForm/index.vue
| @@ -220,7 +220,7 @@ | @@ -220,7 +220,7 @@ | ||
| 220 | </el-form> | 220 | </el-form> |
| 221 | <span slot="footer" class="dialog-footer"> | 221 | <span slot="footer" class="dialog-footer"> |
| 222 | <el-button @click="close">取消</el-button> | 222 | <el-button @click="close">取消</el-button> |
| 223 | - <el-button type="primary" @click="confirm">确认</el-button> | 223 | + <el-button type="primary" @click="confirm" :loading="btnLoading">确认</el-button> |
| 224 | </span> | 224 | </span> |
| 225 | </el-dialog> | 225 | </el-dialog> |
| 226 | </div> | 226 | </div> |
| @@ -312,6 +312,7 @@ export default { | @@ -312,6 +312,7 @@ export default { | ||
| 312 | systemTypeOptions: [], | 312 | systemTypeOptions: [], |
| 313 | systemClassOptions: [], | 313 | systemClassOptions: [], |
| 314 | areaOptions: [], | 314 | areaOptions: [], |
| 315 | + btnLoading: false, | ||
| 315 | }; | 316 | }; |
| 316 | }, | 317 | }, |
| 317 | watch: {}, | 318 | watch: {}, |
| @@ -388,6 +389,7 @@ export default { | @@ -388,6 +389,7 @@ export default { | ||
| 388 | async confirm() { | 389 | async confirm() { |
| 389 | this.$refs["infoForm"].validate((valid) => { | 390 | this.$refs["infoForm"].validate((valid) => { |
| 390 | if (valid) { | 391 | if (valid) { |
| 392 | + this.btnLoading = true; | ||
| 391 | switch (this.type) { | 393 | switch (this.type) { |
| 392 | case "add": | 394 | case "add": |
| 393 | addSystem(this.infoForm).then((res) => { | 395 | addSystem(this.infoForm).then((res) => { |
| @@ -395,9 +397,10 @@ export default { | @@ -395,9 +397,10 @@ export default { | ||
| 395 | message: "恭喜你,新增成功", | 397 | message: "恭喜你,新增成功", |
| 396 | type: "success", | 398 | type: "success", |
| 397 | }); | 399 | }); |
| 400 | + this.btnLoading = false; | ||
| 398 | this.$emit('reInit'); | 401 | this.$emit('reInit'); |
| 399 | this.close(); | 402 | this.close(); |
| 400 | - }); | 403 | + }).catch(() => { this.btnLoading = false }); |
| 401 | break; | 404 | break; |
| 402 | case "edit": | 405 | case "edit": |
| 403 | this.infoForm.id = this.systemId; | 406 | this.infoForm.id = this.systemId; |
| @@ -406,9 +409,10 @@ export default { | @@ -406,9 +409,10 @@ export default { | ||
| 406 | message: "恭喜你,修改成功", | 409 | message: "恭喜你,修改成功", |
| 407 | type: "success", | 410 | type: "success", |
| 408 | }); | 411 | }); |
| 412 | + this.btnLoading = false; | ||
| 409 | this.$emit('reInit'); | 413 | this.$emit('reInit'); |
| 410 | this.close(); | 414 | this.close(); |
| 411 | - }); | 415 | + }).catch(() => { this.btnLoading = false });; |
| 412 | break; | 416 | break; |
| 413 | 417 | ||
| 414 | default: | 418 | default: |
src/components/LangSelect/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-dropdown class="international" @command="handleSetLanguage"> | ||
| 3 | + <div> | ||
| 4 | + <i class="icon-ym icon-ym-header-language"></i> | ||
| 5 | + </div> | ||
| 6 | + <el-dropdown-menu slot="dropdown"> | ||
| 7 | + <el-dropdown-item :disabled="language==='zh'" command="zh"> | ||
| 8 | + 简体中文 | ||
| 9 | + </el-dropdown-item> | ||
| 10 | + <el-dropdown-item :disabled="language==='zhtw'" command="zhtw"> | ||
| 11 | + 繁体中文 | ||
| 12 | + </el-dropdown-item> | ||
| 13 | + <el-dropdown-item :disabled="language==='en'" command="en"> | ||
| 14 | + English | ||
| 15 | + </el-dropdown-item> | ||
| 16 | + </el-dropdown-menu> | ||
| 17 | + </el-dropdown> | ||
| 18 | +</template> | ||
| 19 | + | ||
| 20 | +<script> | ||
| 21 | +import { UpdateLanguage } from '@/api/permission/userSetting' | ||
| 22 | +import getPageTitle from '@/utils/get-page-title' | ||
| 23 | +export default { | ||
| 24 | + computed: { | ||
| 25 | + language() { | ||
| 26 | + return this.$store.getters.language | ||
| 27 | + } | ||
| 28 | + }, | ||
| 29 | + methods: { | ||
| 30 | + handleSetLanguage(lang) { | ||
| 31 | + UpdateLanguage({ language: lang }).then(res => { }) | ||
| 32 | + this.$i18n.locale = lang | ||
| 33 | + this.$store.dispatch('app/setLanguage', lang) | ||
| 34 | + let text = '切换成功' | ||
| 35 | + if (lang === 'en') text = 'Switch Language Success' | ||
| 36 | + if (lang === 'zhtw') text = '切換成功' | ||
| 37 | + document.title = getPageTitle(this.$route.meta.title, this.$route.meta.zhTitle) | ||
| 38 | + this.$message({ | ||
| 39 | + message: text, | ||
| 40 | + type: 'success' | ||
| 41 | + }) | ||
| 42 | + } | ||
| 43 | + } | ||
| 44 | +} | ||
| 45 | +</script> |
src/components/MarkdownEditor/default-options.js
0 → 100644
| 1 | +// doc: https://nhnent.github.io/tui.editor/api/latest/ToastUIEditor.html#ToastUIEditor | ||
| 2 | +export default { | ||
| 3 | + minHeight: '200px', | ||
| 4 | + previewStyle: 'vertical', | ||
| 5 | + useCommandShortcut: true, | ||
| 6 | + useDefaultHTMLSanitizer: true, | ||
| 7 | + usageStatistics: false, | ||
| 8 | + hideModeSwitch: false, | ||
| 9 | + toolbarItems: [ | ||
| 10 | + 'heading', | ||
| 11 | + 'bold', | ||
| 12 | + 'italic', | ||
| 13 | + 'strike', | ||
| 14 | + 'divider', | ||
| 15 | + 'hr', | ||
| 16 | + 'quote', | ||
| 17 | + 'divider', | ||
| 18 | + 'ul', | ||
| 19 | + 'ol', | ||
| 20 | + 'task', | ||
| 21 | + 'indent', | ||
| 22 | + 'outdent', | ||
| 23 | + 'divider', | ||
| 24 | + 'table', | ||
| 25 | + 'image', | ||
| 26 | + 'link', | ||
| 27 | + 'divider', | ||
| 28 | + 'code', | ||
| 29 | + 'codeblock' | ||
| 30 | + ] | ||
| 31 | +} |
src/components/MarkdownEditor/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div :id="id" /> | ||
| 3 | +</template> | ||
| 4 | + | ||
| 5 | +<script> | ||
| 6 | +// deps for editor | ||
| 7 | +import 'codemirror/lib/codemirror.css' // codemirror | ||
| 8 | +import 'tui-editor/dist/tui-editor.css' // editor ui | ||
| 9 | +import 'tui-editor/dist/tui-editor-contents.css' // editor content | ||
| 10 | + | ||
| 11 | +import Editor from 'tui-editor' | ||
| 12 | +import defaultOptions from './default-options' | ||
| 13 | + | ||
| 14 | +export default { | ||
| 15 | + name: 'MarkdownEditor', | ||
| 16 | + props: { | ||
| 17 | + value: { | ||
| 18 | + type: String, | ||
| 19 | + default: '' | ||
| 20 | + }, | ||
| 21 | + id: { | ||
| 22 | + type: String, | ||
| 23 | + required: false, | ||
| 24 | + default() { | ||
| 25 | + return 'markdown-editor-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '') | ||
| 26 | + } | ||
| 27 | + }, | ||
| 28 | + options: { | ||
| 29 | + type: Object, | ||
| 30 | + default() { | ||
| 31 | + return defaultOptions | ||
| 32 | + } | ||
| 33 | + }, | ||
| 34 | + mode: { | ||
| 35 | + type: String, | ||
| 36 | + default: 'markdown' | ||
| 37 | + }, | ||
| 38 | + height: { | ||
| 39 | + type: String, | ||
| 40 | + required: false, | ||
| 41 | + default: '300px' | ||
| 42 | + }, | ||
| 43 | + language: { | ||
| 44 | + type: String, | ||
| 45 | + required: false, | ||
| 46 | + default: 'en_US' // https://github.com/nhnent/tui.editor/tree/master/src/js/langs | ||
| 47 | + } | ||
| 48 | + }, | ||
| 49 | + data() { | ||
| 50 | + return { | ||
| 51 | + editor: null | ||
| 52 | + } | ||
| 53 | + }, | ||
| 54 | + computed: { | ||
| 55 | + editorOptions() { | ||
| 56 | + const options = Object.assign({}, defaultOptions, this.options) | ||
| 57 | + options.initialEditType = this.mode | ||
| 58 | + options.height = this.height | ||
| 59 | + options.language = this.language | ||
| 60 | + return options | ||
| 61 | + } | ||
| 62 | + }, | ||
| 63 | + watch: { | ||
| 64 | + value(newValue, preValue) { | ||
| 65 | + if (newValue !== preValue && newValue !== this.editor.getValue()) { | ||
| 66 | + this.editor.setValue(newValue) | ||
| 67 | + } | ||
| 68 | + }, | ||
| 69 | + language(val) { | ||
| 70 | + this.destroyEditor() | ||
| 71 | + this.initEditor() | ||
| 72 | + }, | ||
| 73 | + height(newValue) { | ||
| 74 | + this.editor.height(newValue) | ||
| 75 | + }, | ||
| 76 | + mode(newValue) { | ||
| 77 | + this.editor.changeMode(newValue) | ||
| 78 | + } | ||
| 79 | + }, | ||
| 80 | + mounted() { | ||
| 81 | + this.initEditor() | ||
| 82 | + }, | ||
| 83 | + destroyed() { | ||
| 84 | + this.destroyEditor() | ||
| 85 | + }, | ||
| 86 | + methods: { | ||
| 87 | + initEditor() { | ||
| 88 | + this.editor = new Editor({ | ||
| 89 | + el: document.getElementById(this.id), | ||
| 90 | + ...this.editorOptions | ||
| 91 | + }) | ||
| 92 | + if (this.value) { | ||
| 93 | + this.editor.setValue(this.value) | ||
| 94 | + } | ||
| 95 | + this.editor.on('change', () => { | ||
| 96 | + this.$emit('input', this.editor.getValue()) | ||
| 97 | + }) | ||
| 98 | + }, | ||
| 99 | + destroyEditor() { | ||
| 100 | + if (!this.editor) return | ||
| 101 | + this.editor.off('change') | ||
| 102 | + this.editor.remove() | ||
| 103 | + }, | ||
| 104 | + setValue(value) { | ||
| 105 | + this.editor.setValue(value) | ||
| 106 | + }, | ||
| 107 | + getValue() { | ||
| 108 | + return this.editor.getValue() | ||
| 109 | + }, | ||
| 110 | + setHtml(value) { | ||
| 111 | + this.editor.setHtml(value) | ||
| 112 | + }, | ||
| 113 | + getHtml() { | ||
| 114 | + return this.editor.getHtml() | ||
| 115 | + } | ||
| 116 | + } | ||
| 117 | +} | ||
| 118 | +</script> |
src/components/NCC-TreeTransfer/array.js
0 → 100644
| 1 | +/** | ||
| 2 | + * auth: weilan | ||
| 3 | + * github: https://github.com/hql7 | ||
| 4 | + * description: 一个数组操作函数库 | ||
| 5 | + */ | ||
| 6 | + | ||
| 7 | +// 从树形数据中递归筛选目标值 | ||
| 8 | +function valInDeep(arr = [], val, id, childs) { | ||
| 9 | + return arr.reduce((flat, item) => { | ||
| 10 | + return flat.concat( | ||
| 11 | + item[id] == val ? item : valInDeep(item[childs] || [], val, id, childs) | ||
| 12 | + ); | ||
| 13 | + }, []); | ||
| 14 | +} | ||
| 15 | + | ||
| 16 | +// 将树形数据向下递归为一维数组 | ||
| 17 | +function flattenDeep(arr = [], childs) { | ||
| 18 | + return arr.reduce((flat, item) => { | ||
| 19 | + return flat.concat( | ||
| 20 | + item, | ||
| 21 | + item[childs] ? flattenDeep(item[childs], childs) : [] | ||
| 22 | + ); | ||
| 23 | + }, []); | ||
| 24 | +} | ||
| 25 | + | ||
| 26 | +// 将树形数据向上将此支线递归为一维数组 | ||
| 27 | +function flattenDeepParents(arr, parent) { | ||
| 28 | + return arr.reduce((flat, item) => { | ||
| 29 | + return flat.concat( | ||
| 30 | + item[parent] || [], | ||
| 31 | + item[parent] ? flattenDeepParents([item[parent]], parent) : [] | ||
| 32 | + ); | ||
| 33 | + }, []); | ||
| 34 | +} | ||
| 35 | + | ||
| 36 | +// 根据条件递归祖先元素 | ||
| 37 | +function regDeepParents(row, parent, reg) { | ||
| 38 | + if (row[parent]) { | ||
| 39 | + reg && reg(row[parent]); | ||
| 40 | + regDeepParents(row[parent], parent, reg); | ||
| 41 | + } | ||
| 42 | +} | ||
| 43 | + | ||
| 44 | +// 将数组转化成树结构 | ||
| 45 | +function arrayToTree( | ||
| 46 | + array = [], | ||
| 47 | + options = { id: "id", pid: "pid", children: "children" } | ||
| 48 | +) { | ||
| 49 | + let array_ = []; // 创建储存剔除叶子节点后的骨架节点数组 | ||
| 50 | + let unique = {}; // 创建盒子辅助本轮children合并去重 | ||
| 51 | + array.forEach(item => { | ||
| 52 | + // 适应el-tree-transfer 将根节点pid重置为 0 | ||
| 53 | + let root = ["undefined", undefined, null].includes(item[options.pid]); | ||
| 54 | + if (root) item[options.pid] = 0; | ||
| 55 | + // 筛选可以插入当前节点的所有子节点 | ||
| 56 | + let children_array = array.filter( | ||
| 57 | + it => it[options.pid] === item[options.id] | ||
| 58 | + ); | ||
| 59 | + if (item.children && item.children instanceof Array) { | ||
| 60 | + // 去重合并数组 | ||
| 61 | + item.children.map(i => (unique[i[options.id]] = 1)); | ||
| 62 | + item.children.push( | ||
| 63 | + ...children_array.filter(i => unique[i[options.id]] !== 1) | ||
| 64 | + ); | ||
| 65 | + } else { | ||
| 66 | + item.children = children_array; | ||
| 67 | + } | ||
| 68 | + // 当children_array有数据时插入下一轮array_,当无数据时将最后留下来的根节点树形插入数组 | ||
| 69 | + let has_children = children_array.length > 0; | ||
| 70 | + if ( | ||
| 71 | + has_children || | ||
| 72 | + (!has_children && [0, "0"].includes(item[options.pid])) | ||
| 73 | + ) { | ||
| 74 | + array_.push(item); | ||
| 75 | + } | ||
| 76 | + }); | ||
| 77 | + // 当数组内仅有根节点时退出,否组继续处理 最终递归深度次 | ||
| 78 | + if (!array_.every(item => [0, "0"].includes(item[options.pid]))) { | ||
| 79 | + return arrayToTree(array_, options); | ||
| 80 | + } else { | ||
| 81 | + return array_; | ||
| 82 | + } | ||
| 83 | +} | ||
| 84 | + | ||
| 85 | +export { | ||
| 86 | + valInDeep, | ||
| 87 | + flattenDeep, | ||
| 88 | + flattenDeepParents, | ||
| 89 | + regDeepParents, | ||
| 90 | + arrayToTree | ||
| 91 | +}; |
src/components/NCC-TreeTransfer/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="transfer" :style="{ width, height }"> | ||
| 3 | + <template> | ||
| 4 | + <!-- 左侧穿梭框 原料框 --> | ||
| 5 | + <div class="transfer-left"> | ||
| 6 | + <h3 class="transfer-title"> | ||
| 7 | + <el-checkbox :indeterminate="from_is_indeterminate" v-model="from_check_all" | ||
| 8 | + @change="fromAllBoxChange" /> | ||
| 9 | + <span>{{ fromTitle }}</span> | ||
| 10 | + <slot name="title-left"></slot> | ||
| 11 | + </h3> | ||
| 12 | + <!-- 内容区 --> | ||
| 13 | + <div class="transfer-main"> | ||
| 14 | + <slot name="from"></slot> | ||
| 15 | + <el-input v-if="filter" :placeholder="placeholder" v-model="filterFrom" | ||
| 16 | + class="filter-tree" clearable /> | ||
| 17 | + <el-tree ref="from-tree" show-checkbox :lazy="lazy" :node-key="node_key" | ||
| 18 | + :load="leftloadNode" :props="defaultProps" :data="self_from_data" | ||
| 19 | + :default-expand-all="openAll" :highlight-current="highLight" | ||
| 20 | + :render-content="renderContentLeft" :filter-node-method="filterNodeFrom" | ||
| 21 | + :default-checked-keys="defaultCheckedKeys" :default-expanded-keys="from_expanded_keys" | ||
| 22 | + @check="fromTreeChecked"> | ||
| 23 | + <div slot-scope="{ node, data }"> | ||
| 24 | + <i :class="data.icon" /> | ||
| 25 | + <span style="padding-left: 4px;">{{ node.label }}</span> | ||
| 26 | + </div> | ||
| 27 | + </el-tree> | ||
| 28 | + <slot name="left-footer"></slot> | ||
| 29 | + </div> | ||
| 30 | + </div> | ||
| 31 | + <!-- 穿梭区 按钮框 --> | ||
| 32 | + <div class="transfer-center"> | ||
| 33 | + <template v-if="button_text"> | ||
| 34 | + <p class="transfer-center-item"> | ||
| 35 | + <el-button type="primary" @click="addToAims(true)" :disabled="from_disabled"> | ||
| 36 | + {{ fromButton || "添加" }} | ||
| 37 | + <i class="el-icon-arrow-right"></i> | ||
| 38 | + </el-button> | ||
| 39 | + </p> | ||
| 40 | + <p class="transfer-center-item"> | ||
| 41 | + <el-button type="primary" @click="removeToSource" :disabled="to_disabled" | ||
| 42 | + icon="el-icon-arrow-left">{{ toButton || "移除" }}</el-button> | ||
| 43 | + </p> | ||
| 44 | + </template> | ||
| 45 | + <template v-else> | ||
| 46 | + <p class="transfer-center-item"> | ||
| 47 | + <el-button type="primary" @click="addToAims(true)" icon="el-icon-arrow-right" | ||
| 48 | + :disabled="from_disabled" /> | ||
| 49 | + </p> | ||
| 50 | + <p class="transfer-center-item"> | ||
| 51 | + <el-button type="primary" @click="removeToSource" :disabled="to_disabled" | ||
| 52 | + icon="el-icon-arrow-left" /> | ||
| 53 | + </p> | ||
| 54 | + </template> | ||
| 55 | + </div> | ||
| 56 | + <!-- 右侧穿梭框 目标框 --> | ||
| 57 | + <div class="transfer-right"> | ||
| 58 | + <h3 class="transfer-title"> | ||
| 59 | + <el-checkbox :indeterminate="to_is_indeterminate" v-model="to_check_all" | ||
| 60 | + @change="toAllBoxChange" /> | ||
| 61 | + <span>{{ toTitle }}</span> | ||
| 62 | + <slot name="title-right"></slot> | ||
| 63 | + </h3> | ||
| 64 | + <!-- 内容区 --> | ||
| 65 | + <div class="transfer-main"> | ||
| 66 | + <slot name="to"></slot> | ||
| 67 | + <el-input v-if="filter" :placeholder="placeholder" v-model="filterTo" size="small" | ||
| 68 | + class="filter-tree" clearable /> | ||
| 69 | + <el-tree slot="to" ref="to-tree" show-checkbox :lazy="lazyRight" :data="self_to_data" | ||
| 70 | + :node-key="node_key" :props="defaultProps" :load="rightloadNode" | ||
| 71 | + :default-expand-all="openAll" :highlight-current="highLight" | ||
| 72 | + :render-content="renderContentRight" :filter-node-method="filterNodeTo" | ||
| 73 | + :default-expanded-keys="to_expanded_keys" @check="toTreeChecked"> | ||
| 74 | + <div slot-scope="{ node, data }"> | ||
| 75 | + <i :class="data.icon" /> | ||
| 76 | + <span style="padding-left: 4px;">{{ node.label }}</span> | ||
| 77 | + </div> | ||
| 78 | + </el-tree> | ||
| 79 | + <slot name="right-footer"></slot> | ||
| 80 | + </div> | ||
| 81 | + </div> | ||
| 82 | + </template> | ||
| 83 | + </div> | ||
| 84 | +</template> | ||
| 85 | + | ||
| 86 | +<script> | ||
| 87 | +import { arrayToTree } from './array'; | ||
| 88 | +export default { | ||
| 89 | + name: 'NCC-tree-transfer', | ||
| 90 | + data() { | ||
| 91 | + return { | ||
| 92 | + from_is_indeterminate: false, // 源数据是否半选 | ||
| 93 | + from_check_all: false, // 源数据是否全选 | ||
| 94 | + to_is_indeterminate: false, // 目标数据是否半选 | ||
| 95 | + to_check_all: false, // 目标数据是否全选 | ||
| 96 | + from_expanded_keys: [], // 源数据展开节点 | ||
| 97 | + to_expanded_keys: [], // 目标数据展开节点 | ||
| 98 | + from_disabled: true, // 添加按钮是否禁用 | ||
| 99 | + to_disabled: true, // 移除按钮是否禁用 | ||
| 100 | + from_check_keys: [], // 源数据选中key数组 以此属性关联穿梭按钮,总全选、半选状态 | ||
| 101 | + to_check_keys: [], // 目标数据选中key数组 以此属性关联穿梭按钮,总全选、半选状态 | ||
| 102 | + filterFrom: "", // 源数据筛选 | ||
| 103 | + filterTo: "", // 目标数据筛选 | ||
| 104 | + } | ||
| 105 | + }, | ||
| 106 | + props: { | ||
| 107 | + // 宽度 | ||
| 108 | + width: { | ||
| 109 | + type: String, | ||
| 110 | + default: "100%" | ||
| 111 | + }, | ||
| 112 | + // 高度 | ||
| 113 | + height: { | ||
| 114 | + type: String, | ||
| 115 | + default: "320px" | ||
| 116 | + }, | ||
| 117 | + // 标题 | ||
| 118 | + title: { | ||
| 119 | + type: Array, | ||
| 120 | + default: () => ["源列表", "目标列表"] | ||
| 121 | + }, | ||
| 122 | + // 穿梭按钮名字 | ||
| 123 | + button_text: Array, | ||
| 124 | + // 源数据 | ||
| 125 | + from_data: { | ||
| 126 | + type: Array, | ||
| 127 | + default: () => [] | ||
| 128 | + }, | ||
| 129 | + // 选中数据 | ||
| 130 | + to_data: { | ||
| 131 | + type: Array, | ||
| 132 | + default: () => [] | ||
| 133 | + }, | ||
| 134 | + // el-tree 配置项 | ||
| 135 | + defaultProps: { | ||
| 136 | + type: Object, | ||
| 137 | + default: () => { | ||
| 138 | + return { label: "fullName", children: "children" }; | ||
| 139 | + } | ||
| 140 | + }, | ||
| 141 | + // el-tree node-key 必须唯一 | ||
| 142 | + node_key: { | ||
| 143 | + type: String, | ||
| 144 | + default: "id" | ||
| 145 | + }, | ||
| 146 | + // 自定义 pid参数名 | ||
| 147 | + pid: { | ||
| 148 | + type: String, | ||
| 149 | + default: "parentId" | ||
| 150 | + }, | ||
| 151 | + // 是否启用筛选 | ||
| 152 | + filter: { | ||
| 153 | + type: Boolean, | ||
| 154 | + default: false | ||
| 155 | + }, | ||
| 156 | + // 是否展开所有节点 | ||
| 157 | + openAll: { | ||
| 158 | + type: Boolean, | ||
| 159 | + default: false | ||
| 160 | + }, | ||
| 161 | + // 左侧自定义树节点 | ||
| 162 | + renderContentLeft: Function, | ||
| 163 | + // 右侧自定义树节点 | ||
| 164 | + renderContentRight: Function, | ||
| 165 | + // 是否展开节点 | ||
| 166 | + transferOpenNode: { | ||
| 167 | + type: Boolean, | ||
| 168 | + default: true | ||
| 169 | + }, | ||
| 170 | + // 源数据 默认选中节点 | ||
| 171 | + defaultCheckedKeys: { | ||
| 172 | + type: Array, | ||
| 173 | + default: () => [] | ||
| 174 | + }, | ||
| 175 | + // 源数据 默认展开节点 | ||
| 176 | + defaultExpandedKeys: { | ||
| 177 | + type: Array, | ||
| 178 | + default: () => [] | ||
| 179 | + }, | ||
| 180 | + // 筛选placeholder | ||
| 181 | + placeholder: { | ||
| 182 | + type: String, | ||
| 183 | + default: "输入关键词" | ||
| 184 | + }, | ||
| 185 | + // 自定义筛选函数 | ||
| 186 | + filterNode: Function, | ||
| 187 | + // 默认穿梭一次默认选中数据 | ||
| 188 | + defaultTransfer: { | ||
| 189 | + type: Boolean, | ||
| 190 | + default: false | ||
| 191 | + }, | ||
| 192 | + // 是否开启arrayToTree | ||
| 193 | + arrayToTree: { | ||
| 194 | + type: Boolean, | ||
| 195 | + default: false | ||
| 196 | + }, | ||
| 197 | + // 是否启用懒加载 | ||
| 198 | + lazy: { | ||
| 199 | + type: Boolean, | ||
| 200 | + default: false | ||
| 201 | + }, | ||
| 202 | + // 右侧是否启用懒加载 | ||
| 203 | + lazyRight: { | ||
| 204 | + type: Boolean, | ||
| 205 | + default: false | ||
| 206 | + }, | ||
| 207 | + // 懒加载的回调函数 | ||
| 208 | + lazyFn: Function, | ||
| 209 | + // 是否高亮当前选中节点,默认值是 false。 | ||
| 210 | + highLight: { | ||
| 211 | + type: Boolean, | ||
| 212 | + default: false | ||
| 213 | + } | ||
| 214 | + }, | ||
| 215 | + created() { | ||
| 216 | + this.from_check_keys = this.defaultCheckedKeys; | ||
| 217 | + this.from_expanded_keys = this.defaultExpandedKeys; | ||
| 218 | + this.to_expanded_keys = this.defaultExpandedKeys; | ||
| 219 | + if (this.defaultTransfer && this.defaultCheckedKeys.length > 0) { | ||
| 220 | + this.$nextTick(() => { | ||
| 221 | + this.addToAims(false); | ||
| 222 | + }); | ||
| 223 | + } | ||
| 224 | + }, | ||
| 225 | + methods: { | ||
| 226 | + // -------------------------------提供输出函数--------------------- | ||
| 227 | + /** | ||
| 228 | + * 清空选中节点 | ||
| 229 | + * type:string left左边 right右边 all全部 默认all | ||
| 230 | + */ | ||
| 231 | + clearChecked(type = "all") { | ||
| 232 | + if (type === "left") { | ||
| 233 | + this.$refs["from-tree"].setCheckedKeys([]); | ||
| 234 | + this.from_is_indeterminate = false; | ||
| 235 | + this.from_check_all = false; | ||
| 236 | + } else if (type === "right") { | ||
| 237 | + this.$refs["to-tree"].setCheckedKeys([]); | ||
| 238 | + this.to_is_indeterminate = false; | ||
| 239 | + this.to_check_all = false; | ||
| 240 | + } else { | ||
| 241 | + this.$refs["from-tree"].setCheckedKeys([]); | ||
| 242 | + this.$refs["to-tree"].setCheckedKeys([]); | ||
| 243 | + this.from_is_indeterminate = false; | ||
| 244 | + this.from_check_all = false; | ||
| 245 | + this.to_is_indeterminate = false; | ||
| 246 | + this.to_check_all = false; | ||
| 247 | + } | ||
| 248 | + }, | ||
| 249 | + // 添加按钮 | ||
| 250 | + addToAims(emit) { | ||
| 251 | + // 获取选中通过穿梭框的keys - 仅用于传送纯净的id数组到父组件同后台通信 | ||
| 252 | + let keys = this.$refs["from-tree"].getCheckedKeys(); | ||
| 253 | + // 获取半选通过穿梭框的keys - 仅用于传送纯净的id数组到父组件同后台通信 | ||
| 254 | + let harfKeys = this.$refs["from-tree"].getHalfCheckedKeys(); | ||
| 255 | + // 选中节点数据 | ||
| 256 | + let arrayCheckedNodes = this.$refs["from-tree"].getCheckedNodes(); | ||
| 257 | + // 获取选中通过穿梭框的nodes - 仅用于传送选中节点数组到父组件同后台通信需求 | ||
| 258 | + let nodes = JSON.parse(JSON.stringify(arrayCheckedNodes)); | ||
| 259 | + // 半选中节点数据 | ||
| 260 | + let arrayHalfCheckedNodes = this.$refs["from-tree"].getHalfCheckedNodes(); | ||
| 261 | + // 获取半选通过穿梭框的nodes - 仅用于传送选中节点数组到父组件同后台通信需求 | ||
| 262 | + let halfNodes = JSON.parse(JSON.stringify(arrayHalfCheckedNodes)); | ||
| 263 | + | ||
| 264 | + // 自定义参数读取设置 | ||
| 265 | + let children__ = this.defaultProps.children || "children"; | ||
| 266 | + let pid__ = this.pid || "parentId"; | ||
| 267 | + let id__ = this["node_key"] || "id"; | ||
| 268 | + | ||
| 269 | + /* | ||
| 270 | + * 先整合目标树没有父节点的叶子节点选中,需要整理出来此叶子节点的父节点直到根节点路径 - 此时所有骨架节点已有 | ||
| 271 | + * 再将所有末端叶子节点根据pid直接推入目标树即可 | ||
| 272 | + * 声明新盒子将所有半选节点的子节点清除 - 只保留骨架 因为排序是先父后子 因此不存在子元素处理好插入时父元素还没处理的情况 | ||
| 273 | + * 下面一二步是为了搭建出来目标树没有根节点躯干节点时的叶子选中,给此叶子搭建出根节点和躯干节点 | ||
| 274 | + */ | ||
| 275 | + | ||
| 276 | + // let不存在状态提升 因此在函数调用之前赋值 并递归为以为数组! | ||
| 277 | + let self_to_data = JSON.stringify(this.self_to_data); | ||
| 278 | + // 第一步 | ||
| 279 | + let skeletonHalfCheckedNodes = JSON.parse( | ||
| 280 | + JSON.stringify(arrayHalfCheckedNodes) | ||
| 281 | + ); // 深拷贝数据 - 半选节点 | ||
| 282 | + // 筛选目标树不存在的骨架节点 - 半选内的节点 | ||
| 283 | + let newSkeletonHalfCheckedNodes = []; | ||
| 284 | + skeletonHalfCheckedNodes.forEach(item => { | ||
| 285 | + if (!inquireIsExist(item)) { | ||
| 286 | + newSkeletonHalfCheckedNodes.push(item); | ||
| 287 | + } | ||
| 288 | + }); | ||
| 289 | + // 筛选到目标树不存在的骨架后在处理每个骨架节点-非末端叶子节点 - 半选节点 | ||
| 290 | + newSkeletonHalfCheckedNodes.forEach(item => { | ||
| 291 | + item[children__] = []; | ||
| 292 | + [0, "-1"].includes(item[pid__]) | ||
| 293 | + ? this.$refs["to-tree"].append(item) | ||
| 294 | + : this.$refs["to-tree"].append(item, item[pid__]); | ||
| 295 | + }); | ||
| 296 | + | ||
| 297 | + // 第二步 | ||
| 298 | + // 筛选目标树不存在的骨架节点 - 全选内的节点 | ||
| 299 | + let newSkeletonCheckedNodes = []; | ||
| 300 | + nodes.forEach(item => { | ||
| 301 | + if (!inquireIsExist(item)) { | ||
| 302 | + newSkeletonCheckedNodes.push(item); | ||
| 303 | + } | ||
| 304 | + }); | ||
| 305 | + // 筛选到目标树不存在的骨架后在处理每个骨架节点-非末端叶子节点 - 全选节点 | ||
| 306 | + newSkeletonCheckedNodes.forEach(item => { | ||
| 307 | + if (item[children__] && item[children__].length > 0) { | ||
| 308 | + item[children__] = []; | ||
| 309 | + [0, "-1"].includes(item[pid__]) | ||
| 310 | + ? this.$refs["to-tree"].append(item) | ||
| 311 | + : this.$refs["to-tree"].append(item, item[pid__]); | ||
| 312 | + } | ||
| 313 | + }); | ||
| 314 | + | ||
| 315 | + // 第三步 处理末端叶子元素 - 声明新盒子筛选出所有末端叶子节点 | ||
| 316 | + let leafCheckedNodes = arrayCheckedNodes.filter( | ||
| 317 | + item => !item[children__] || item[children__].length === 0 | ||
| 318 | + ); | ||
| 319 | + // 末端叶子插入目标树 | ||
| 320 | + leafCheckedNodes.forEach(item => { | ||
| 321 | + if (!inquireIsExist(item)) { | ||
| 322 | + this.$refs["to-tree"].append(item, item[pid__]); | ||
| 323 | + } | ||
| 324 | + }); | ||
| 325 | + | ||
| 326 | + // 递归查询data内是否存在item函数 | ||
| 327 | + function inquireIsExist(item, strData = self_to_data) { | ||
| 328 | + // 将树形数据格式化成一维字符串 然后通过匹配来判断是否已存在 | ||
| 329 | + let strItem = | ||
| 330 | + typeof item[id__] == "number" | ||
| 331 | + ? `"${id__}":${item[id__]},` | ||
| 332 | + : `"${id__}":"${item[id__]}"`; | ||
| 333 | + let reg = RegExp(strItem); | ||
| 334 | + let existed = reg.test(strData); | ||
| 335 | + return existed; | ||
| 336 | + } | ||
| 337 | + | ||
| 338 | + // 左侧删掉选中数据 | ||
| 339 | + arrayCheckedNodes.map(item => this.$refs["from-tree"].remove(item)); | ||
| 340 | + | ||
| 341 | + // 处理完毕按钮恢复禁用状态 | ||
| 342 | + this.from_check_keys = []; | ||
| 343 | + | ||
| 344 | + // 目标数据节点展开 | ||
| 345 | + if (this.transferOpenNode && !this.lazy) { | ||
| 346 | + this.to_expanded_keys = keys; | ||
| 347 | + } | ||
| 348 | + | ||
| 349 | + // 传递信息给父组件 | ||
| 350 | + emit && | ||
| 351 | + this.$emit("addBtn", this.self_from_data, this.self_to_data, { | ||
| 352 | + keys, | ||
| 353 | + nodes, | ||
| 354 | + harfKeys, | ||
| 355 | + halfNodes | ||
| 356 | + }); | ||
| 357 | + | ||
| 358 | + // 处理完毕取消选中 | ||
| 359 | + this.$refs["from-tree"].setCheckedKeys([]); | ||
| 360 | + }, | ||
| 361 | + // 移除按钮 | ||
| 362 | + removeToSource() { | ||
| 363 | + // 获取选中通过穿梭框的keys - 仅用于传送纯净的id数组到父组件同后台通信 | ||
| 364 | + let keys = this.$refs["to-tree"].getCheckedKeys(); | ||
| 365 | + // 获取半选通过穿梭框的keys - 仅用于传送纯净的id数组到父组件同后台通信 | ||
| 366 | + let harfKeys = this.$refs["to-tree"].getHalfCheckedKeys(); | ||
| 367 | + // 获取选中通过穿梭框的nodes 选中节点数据 | ||
| 368 | + let arrayCheckedNodes = this.$refs["to-tree"].getCheckedNodes(); | ||
| 369 | + // 获取选中通过穿梭框的nodes - 仅用于传送选中节点数组到父组件同后台通信需求 | ||
| 370 | + let nodes = JSON.parse(JSON.stringify(arrayCheckedNodes)); | ||
| 371 | + // 半选中节点数据 | ||
| 372 | + let arrayHalfCheckedNodes = this.$refs["to-tree"].getHalfCheckedNodes(); | ||
| 373 | + // 获取半选通过穿梭框的nodes - 仅用于传送选中节点数组到父组件同后台通信需求 | ||
| 374 | + let halfNodes = JSON.parse(JSON.stringify(arrayHalfCheckedNodes)); | ||
| 375 | + | ||
| 376 | + // 自定义参数读取设置 | ||
| 377 | + let children__ = this.defaultProps.children || "children"; | ||
| 378 | + let pid__ = this.pid || "parentId"; | ||
| 379 | + let id__ = this["node_key"] || "id"; | ||
| 380 | + | ||
| 381 | + /* | ||
| 382 | + * 先整合目标树没有父节点的叶子节点选中,需要整理出来此叶子节点的父节点直到根节点路径 - 此时所有骨架节点已有 | ||
| 383 | + * 再将所有末端叶子节点根据pid直接推入目标树即可 | ||
| 384 | + * 声明新盒子将所有半选节点的子节点清除 - 只保留骨架 因为排序是先父后子 因此不存在子元素处理好插入时父元素还没处理的情况 | ||
| 385 | + * 下面一二步是为了搭建出来目标树没有根节点躯干节点时的叶子选中,给此叶子搭建出根节点和躯干节点 | ||
| 386 | + */ | ||
| 387 | + | ||
| 388 | + // let不存在状态提升 因此在函数调用之前赋值 并递归为以为数组! | ||
| 389 | + let self_from_data = JSON.stringify(this.self_from_data); | ||
| 390 | + // 第一步 | ||
| 391 | + let skeletonHalfCheckedNodes = JSON.parse( | ||
| 392 | + JSON.stringify(arrayHalfCheckedNodes) | ||
| 393 | + ); // 深拷贝数据 - 半选节点 | ||
| 394 | + // 筛选目标树不存在的骨架节点 - 半选内的节点 | ||
| 395 | + let newSkeletonHalfCheckedNodes = []; | ||
| 396 | + skeletonHalfCheckedNodes.forEach(item => { | ||
| 397 | + if (!inquireIsExist(item)) { | ||
| 398 | + newSkeletonHalfCheckedNodes.push(item); | ||
| 399 | + } | ||
| 400 | + }); | ||
| 401 | + // 筛选到目标树不存在的骨架后在处理每个骨架节点-非末端叶子节点 - 半选节点 | ||
| 402 | + newSkeletonHalfCheckedNodes.forEach(item => { | ||
| 403 | + item[children__] = []; | ||
| 404 | + [0, "-1"].includes(item[pid__]) | ||
| 405 | + ? this.$refs["from-tree"].append(item) | ||
| 406 | + : this.$refs["from-tree"].append(item, item[pid__]); | ||
| 407 | + }); | ||
| 408 | + | ||
| 409 | + // 第二步 | ||
| 410 | + // 筛选目标树不存在的骨架节点 - 全选内的节点 | ||
| 411 | + let newSkeletonCheckedNodes = []; | ||
| 412 | + nodes.forEach(item => { | ||
| 413 | + if (!inquireIsExist(item)) { | ||
| 414 | + newSkeletonCheckedNodes.push(item); | ||
| 415 | + } | ||
| 416 | + }); | ||
| 417 | + // 筛选到目标树不存在的骨架后在处理每个骨架节点-非末端叶子节点 - 全选节点 | ||
| 418 | + newSkeletonCheckedNodes.forEach(item => { | ||
| 419 | + if (item[children__] && item[children__].length > 0) { | ||
| 420 | + item[children__] = []; | ||
| 421 | + [0, "-1"].includes(item[pid__]) | ||
| 422 | + ? this.$refs["from-tree"].append(item) | ||
| 423 | + : this.$refs["from-tree"].append(item, item[pid__]); | ||
| 424 | + } | ||
| 425 | + }); | ||
| 426 | + | ||
| 427 | + // 第三步 处理末端叶子元素 - 声明新盒子筛选出所有末端叶子节点 | ||
| 428 | + let leafCheckedNodes = arrayCheckedNodes.filter( | ||
| 429 | + item => !item[children__] || item[children__].length == 0 | ||
| 430 | + ); | ||
| 431 | + // 末端叶子插入目标树 | ||
| 432 | + leafCheckedNodes.forEach(item => { | ||
| 433 | + if (!inquireIsExist(item)) { | ||
| 434 | + this.$refs["from-tree"].append(item, item[pid__]); | ||
| 435 | + } | ||
| 436 | + }); | ||
| 437 | + | ||
| 438 | + // 递归查询data内是否存在item函数 | ||
| 439 | + function inquireIsExist(item, strData = self_from_data) { | ||
| 440 | + // 将树形数据格式化成一维字符串 然后通过匹配来判断是否已存在 | ||
| 441 | + let strItem = | ||
| 442 | + typeof item[id__] == "number" | ||
| 443 | + ? `"${id__}":${item[id__]},` | ||
| 444 | + : `"${id__}":"${item[id__]}"`; | ||
| 445 | + let reg = RegExp(strItem); | ||
| 446 | + let existed = reg.test(strData); | ||
| 447 | + return existed; | ||
| 448 | + } | ||
| 449 | + | ||
| 450 | + // 右侧删掉选中数据 | ||
| 451 | + arrayCheckedNodes.map(item => this.$refs["to-tree"].remove(item)); | ||
| 452 | + | ||
| 453 | + // 处理完毕按钮恢复禁用状态 | ||
| 454 | + this.to_check_keys = []; | ||
| 455 | + | ||
| 456 | + // 目标数据节点展开 | ||
| 457 | + if (this.transferOpenNode && !this.lazy) { | ||
| 458 | + this.from_expanded_keys = keys; | ||
| 459 | + } | ||
| 460 | + | ||
| 461 | + // 传递信息给父组件 | ||
| 462 | + this.$emit("removeBtn", this.self_from_data, this.self_to_data, { | ||
| 463 | + keys, | ||
| 464 | + nodes, | ||
| 465 | + harfKeys, | ||
| 466 | + halfNodes | ||
| 467 | + }); | ||
| 468 | + // 处理完毕取消选中 | ||
| 469 | + this.$refs["to-tree"].setCheckedKeys([]); | ||
| 470 | + }, | ||
| 471 | + // 异步加载左侧 | ||
| 472 | + leftloadNode(node, resolve) { | ||
| 473 | + if (node.level === 0) { | ||
| 474 | + return resolve(this.self_from_data); | ||
| 475 | + } | ||
| 476 | + this.lazyFn && this.lazyFn(node, resolve, "left"); | ||
| 477 | + }, | ||
| 478 | + // 异步加载右侧 | ||
| 479 | + rightloadNode(node, resolve) { | ||
| 480 | + if (node.level === 0) { | ||
| 481 | + return resolve(this.self_to_data); | ||
| 482 | + } | ||
| 483 | + | ||
| 484 | + this.lazyFn && this.lazyFn(node, resolve, "right"); | ||
| 485 | + }, | ||
| 486 | + // 源树选中事件 - 是否禁用穿梭按钮 | ||
| 487 | + fromTreeChecked(nodeObj, treeObj) { | ||
| 488 | + this.from_check_keys = treeObj.checkedNodes | ||
| 489 | + this.$nextTick(() => { | ||
| 490 | + | ||
| 491 | + this.$emit("left-check-change", nodeObj, treeObj, this.from_check_all) | ||
| 492 | + }) | ||
| 493 | + }, | ||
| 494 | + // 目标树选中事件 - 是否禁用穿梭按钮 | ||
| 495 | + toTreeChecked(nodeObj, treeObj) { | ||
| 496 | + this.to_check_keys = treeObj.checkedNodes; | ||
| 497 | + this.$nextTick(() => { | ||
| 498 | + this.$emit("right-check-change", nodeObj, treeObj, this.to_check_all); | ||
| 499 | + }); | ||
| 500 | + }, | ||
| 501 | + // 源数据 总全选checkbox | ||
| 502 | + fromAllBoxChange(val) { | ||
| 503 | + if (this.self_from_data.length === 0) { | ||
| 504 | + return; | ||
| 505 | + } | ||
| 506 | + if (val) { | ||
| 507 | + this.from_check_keys = this.self_from_data; | ||
| 508 | + this.$refs["from-tree"].setCheckedNodes(this.self_from_data); | ||
| 509 | + } else { | ||
| 510 | + this.$refs["from-tree"].setCheckedNodes([]); | ||
| 511 | + this.from_check_keys = []; | ||
| 512 | + } | ||
| 513 | + this.$emit("left-check-change", null, null, this.from_check_all); | ||
| 514 | + }, | ||
| 515 | + // 目标数据 总全选checkbox | ||
| 516 | + toAllBoxChange(val) { | ||
| 517 | + if (this.self_to_data.length === 0) { | ||
| 518 | + return; | ||
| 519 | + } | ||
| 520 | + if (val) { | ||
| 521 | + this.to_check_keys = this.self_to_data; | ||
| 522 | + this.$refs["to-tree"].setCheckedNodes(this.self_to_data); | ||
| 523 | + } else { | ||
| 524 | + this.$refs["to-tree"].setCheckedNodes([]); | ||
| 525 | + this.to_check_keys = []; | ||
| 526 | + } | ||
| 527 | + this.$emit("right-check-change", null, null, this.to_check_all); | ||
| 528 | + }, | ||
| 529 | + // 源数据 筛选 | ||
| 530 | + filterNodeFrom(value, data) { | ||
| 531 | + if (this.filterNode) { | ||
| 532 | + return this.filterNode(value, data, "form"); | ||
| 533 | + } | ||
| 534 | + if (!value) return true; | ||
| 535 | + return data[this.defaultProps.label].indexOf(value) !== -1; | ||
| 536 | + }, | ||
| 537 | + // 目标数据筛选 | ||
| 538 | + filterNodeTo(value, data) { | ||
| 539 | + if (this.filterNode) { | ||
| 540 | + return this.filterNode(value, data, "to"); | ||
| 541 | + } | ||
| 542 | + if (!value) return true; | ||
| 543 | + return data[this.defaultProps.label].indexOf(value) !== -1; | ||
| 544 | + }, | ||
| 545 | + }, | ||
| 546 | + computed: { | ||
| 547 | + // 左侧数据 | ||
| 548 | + self_from_data() { | ||
| 549 | + let from_array = [...this.from_data]; | ||
| 550 | + if (!this.arrayToTree) { | ||
| 551 | + from_array.forEach(item => { | ||
| 552 | + item[this.pid] = 0; | ||
| 553 | + }); | ||
| 554 | + return from_array; | ||
| 555 | + } else { | ||
| 556 | + return arrayToTree(from_array, { | ||
| 557 | + id: this.node_key, | ||
| 558 | + pid: this.pid, | ||
| 559 | + children: this.defaultProps.children | ||
| 560 | + }); | ||
| 561 | + } | ||
| 562 | + }, | ||
| 563 | + // 右侧数据 | ||
| 564 | + self_to_data() { | ||
| 565 | + let to_array = [...this.to_data]; | ||
| 566 | + if (!this.arrayToTree) { | ||
| 567 | + to_array.forEach(item => { | ||
| 568 | + item[this.pid] = 0; | ||
| 569 | + }); | ||
| 570 | + return to_array; | ||
| 571 | + } else { | ||
| 572 | + return arrayToTree(to_array, { | ||
| 573 | + id: this.node_key, | ||
| 574 | + pid: this.pid, | ||
| 575 | + children: this.defaultProps.children | ||
| 576 | + }); | ||
| 577 | + } | ||
| 578 | + }, | ||
| 579 | + // 左侧菜单名 | ||
| 580 | + fromTitle() { | ||
| 581 | + let [text] = this.title; | ||
| 582 | + return text; | ||
| 583 | + }, | ||
| 584 | + // 右侧菜单名 | ||
| 585 | + toTitle() { | ||
| 586 | + let [, text] = this.title; | ||
| 587 | + return text; | ||
| 588 | + }, | ||
| 589 | + // 右侧菜单名2 | ||
| 590 | + toTitleSecond() { | ||
| 591 | + let [, , text] = this.title; | ||
| 592 | + return text; | ||
| 593 | + }, | ||
| 594 | + // 右侧菜单名3 | ||
| 595 | + toTitleThird() { | ||
| 596 | + let [, , , text] = this.title; | ||
| 597 | + return text; | ||
| 598 | + }, | ||
| 599 | + // 上部按钮名 | ||
| 600 | + fromButton() { | ||
| 601 | + if (this.button_text == undefined) { | ||
| 602 | + return; | ||
| 603 | + } | ||
| 604 | + | ||
| 605 | + let [text] = this.button_text; | ||
| 606 | + return text; | ||
| 607 | + }, | ||
| 608 | + // 下部按钮名 | ||
| 609 | + toButton() { | ||
| 610 | + if (this.button_text == undefined) { | ||
| 611 | + return; | ||
| 612 | + } | ||
| 613 | + let [, text] = this.button_text; | ||
| 614 | + return text; | ||
| 615 | + } | ||
| 616 | + }, | ||
| 617 | + watch: { | ||
| 618 | + // 左侧 状态监测 | ||
| 619 | + from_check_keys(val) { | ||
| 620 | + if (val.length > 0) { | ||
| 621 | + // 穿梭按钮是否禁用 | ||
| 622 | + this.from_disabled = false; | ||
| 623 | + // 总半选是否开启 | ||
| 624 | + this.from_is_indeterminate = true; | ||
| 625 | + | ||
| 626 | + // 总全选是否开启 - 根据选中节点中为根节点的数量是否和源数据长度相等 | ||
| 627 | + let allCheck = val.filter(item => item[this.pid] === 0); | ||
| 628 | + if (allCheck.length == this.self_from_data.length) { | ||
| 629 | + // 关闭半选 开启全选 | ||
| 630 | + this.from_is_indeterminate = false; | ||
| 631 | + this.from_check_all = true; | ||
| 632 | + } else { | ||
| 633 | + this.from_is_indeterminate = true; | ||
| 634 | + this.from_check_all = false; | ||
| 635 | + } | ||
| 636 | + } else { | ||
| 637 | + this.from_disabled = true; | ||
| 638 | + this.from_is_indeterminate = false; | ||
| 639 | + this.from_check_all = false; | ||
| 640 | + } | ||
| 641 | + }, | ||
| 642 | + // 右侧 状态监测 | ||
| 643 | + to_check_keys(val) { | ||
| 644 | + if (val.length > 0) { | ||
| 645 | + // 穿梭按钮是否禁用 | ||
| 646 | + this.to_disabled = false; | ||
| 647 | + // 总半选是否开启 | ||
| 648 | + this.to_is_indeterminate = true; | ||
| 649 | + | ||
| 650 | + // 总全选是否开启 - 根据选中节点中为根节点的数量是否和源数据长度相等 | ||
| 651 | + let allCheck = val.filter(item => item[this.pid] === 0); | ||
| 652 | + if (allCheck.length == this.self_to_data.length) { | ||
| 653 | + // 关闭半选 开启全选 | ||
| 654 | + this.to_is_indeterminate = false; | ||
| 655 | + this.to_check_all = true; | ||
| 656 | + } else { | ||
| 657 | + this.to_is_indeterminate = true; | ||
| 658 | + this.to_check_all = false; | ||
| 659 | + } | ||
| 660 | + } else { | ||
| 661 | + this.to_disabled = true; | ||
| 662 | + this.to_is_indeterminate = false; | ||
| 663 | + this.to_check_all = false; | ||
| 664 | + } | ||
| 665 | + }, | ||
| 666 | + // 左侧 数据筛选 | ||
| 667 | + filterFrom(val) { | ||
| 668 | + this.$refs["from-tree"].filter(val); | ||
| 669 | + }, | ||
| 670 | + // 右侧 数据筛选 | ||
| 671 | + filterTo(val) { | ||
| 672 | + this.$refs["to-tree"].filter(val); | ||
| 673 | + }, | ||
| 674 | + // 监视默认选中 | ||
| 675 | + defaultCheckedKeys(val) { | ||
| 676 | + if (this.defaultTransfer && val.length > 0) { | ||
| 677 | + this.$nextTick(() => { | ||
| 678 | + this.addToAims(false); | ||
| 679 | + }); | ||
| 680 | + } | ||
| 681 | + }, | ||
| 682 | + // 监视默认展开 | ||
| 683 | + defaultExpandedKeys(val) { | ||
| 684 | + let _form = new Set(this.from_expanded_keys.concat(val)); | ||
| 685 | + this.from_expanded_keys = [..._form]; | ||
| 686 | + let _to = new Set(this.to_expanded_keys.concat(val)); | ||
| 687 | + this.to_expanded_keys = [..._to]; | ||
| 688 | + } | ||
| 689 | + } | ||
| 690 | +}; | ||
| 691 | +</script> | ||
| 692 | + | ||
| 693 | +<style lang="scss" scoped> | ||
| 694 | +.el-tree { | ||
| 695 | + min-width: 100%; | ||
| 696 | + display: inline-block !important; | ||
| 697 | +} | ||
| 698 | + | ||
| 699 | +.transfer { | ||
| 700 | + position: relative; | ||
| 701 | + overflow: hidden; | ||
| 702 | +} | ||
| 703 | + | ||
| 704 | +.transfer-left { | ||
| 705 | + position: absolute; | ||
| 706 | + top: 0; | ||
| 707 | + left: 0; | ||
| 708 | +} | ||
| 709 | + | ||
| 710 | +.transfer-right { | ||
| 711 | + position: absolute; | ||
| 712 | + top: 0; | ||
| 713 | + right: 0; | ||
| 714 | +} | ||
| 715 | + | ||
| 716 | +.transfer-right-item { | ||
| 717 | + height: calc((100% - 41px) / 2); | ||
| 718 | +} | ||
| 719 | + | ||
| 720 | +.transfer-right-small { | ||
| 721 | + height: 41px; | ||
| 722 | +} | ||
| 723 | + | ||
| 724 | +.transfer-right-only { | ||
| 725 | + height: 100%; | ||
| 726 | +} | ||
| 727 | + | ||
| 728 | +.transfer-main { | ||
| 729 | + padding: 10px; | ||
| 730 | + // height: calc(100% - 41px); | ||
| 731 | + box-sizing: border-box; | ||
| 732 | + overflow: hidden; | ||
| 733 | + .el-tree { | ||
| 734 | + height: calc(100vh - 590px); | ||
| 735 | + overflow: auto; | ||
| 736 | + } | ||
| 737 | +} | ||
| 738 | + | ||
| 739 | +.transfer-left, | ||
| 740 | +.transfer-right { | ||
| 741 | + border: 1px solid #ebeef5; | ||
| 742 | + width: 40%; | ||
| 743 | + height: 100%; | ||
| 744 | + box-sizing: border-box; | ||
| 745 | + border-radius: 5px; | ||
| 746 | + vertical-align: middle; | ||
| 747 | +} | ||
| 748 | + | ||
| 749 | +.transfer-center { | ||
| 750 | + position: absolute; | ||
| 751 | + top: 50%; | ||
| 752 | + left: 40%; | ||
| 753 | + width: 20%; | ||
| 754 | + transform: translateY(-50%); | ||
| 755 | + text-align: center; | ||
| 756 | +} | ||
| 757 | + | ||
| 758 | +.transfer-center-item { | ||
| 759 | + padding: 10px; | ||
| 760 | + overflow: hidden; | ||
| 761 | +} | ||
| 762 | + | ||
| 763 | +.address-list-center { | ||
| 764 | + height: 100%; | ||
| 765 | +} | ||
| 766 | + | ||
| 767 | +.address-list-center > .transfer-center-item { | ||
| 768 | + height: 50%; | ||
| 769 | + padding: 70px 10px 0; | ||
| 770 | + box-sizing: border-box; | ||
| 771 | + overflow: hidden; | ||
| 772 | +} | ||
| 773 | + | ||
| 774 | +.address-list-center > .address-only-item { | ||
| 775 | + height: 100%; | ||
| 776 | + position: relative; | ||
| 777 | +} | ||
| 778 | + | ||
| 779 | +.address-only-item > .address-first-btn { | ||
| 780 | + position: absolute; | ||
| 781 | + top: 50%; | ||
| 782 | + left: 50%; | ||
| 783 | + transform: translate(-50%, -50%); | ||
| 784 | +} | ||
| 785 | + | ||
| 786 | +.transfer-title { | ||
| 787 | + border-bottom: 1px solid #ebeef5; | ||
| 788 | + padding: 0 15px; | ||
| 789 | + height: 40px; | ||
| 790 | + line-height: 40px; | ||
| 791 | + color: #333; | ||
| 792 | + font-size: 16px; | ||
| 793 | + background-color: #f5f7fa; | ||
| 794 | + font-weight: normal; | ||
| 795 | +} | ||
| 796 | + | ||
| 797 | +.transfer-title .el-checkbox { | ||
| 798 | + margin-right: 10px; | ||
| 799 | +} | ||
| 800 | + | ||
| 801 | +.filter-tree { | ||
| 802 | + margin-bottom: 10px; | ||
| 803 | +} | ||
| 804 | + | ||
| 805 | +.u-clear { | ||
| 806 | + float: right; | ||
| 807 | + color: #67c23a; | ||
| 808 | + font-size: 14px; | ||
| 809 | + cursor: pointer; | ||
| 810 | +} | ||
| 811 | +</style> |
src/components/NCC-enlarge/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="enlarge-main"> | ||
| 3 | + <img :src="img" class="enlarge-img" @click="dialogVisible = true" title="点击查看放大" /> | ||
| 4 | + <el-dialog :visible.sync="dialogVisible" append-to-body width="600px" | ||
| 5 | + class="NCC-dialog NCC-dialog_center enlarge-dialog"> | ||
| 6 | + <img width="100%" :src="img" alt /> | ||
| 7 | + </el-dialog> | ||
| 8 | + </div> | ||
| 9 | +</template> | ||
| 10 | + | ||
| 11 | +<script> | ||
| 12 | +export default { | ||
| 13 | + props: ["img"], | ||
| 14 | + data() { | ||
| 15 | + return { | ||
| 16 | + dialogVisible: false | ||
| 17 | + } | ||
| 18 | + } | ||
| 19 | +} | ||
| 20 | +</script> | ||
| 21 | + | ||
| 22 | +<style lang="scss" scoped> | ||
| 23 | +.enlarge-main { | ||
| 24 | + cursor: pointer; | ||
| 25 | + display: inline-block; | ||
| 26 | + width: 120px; | ||
| 27 | + height: 120px; | ||
| 28 | + overflow: hidden; | ||
| 29 | + margin: 0 8px 8px 0; | ||
| 30 | + border: 1px solid #c0ccda; | ||
| 31 | + border-radius: 6px; | ||
| 32 | + -webkit-box-sizing: border-box; | ||
| 33 | + box-sizing: border-box; | ||
| 34 | + .enlarge-img { | ||
| 35 | + width: 120px; | ||
| 36 | + height: 120px; | ||
| 37 | + object-fit: contain; | ||
| 38 | + } | ||
| 39 | +} | ||
| 40 | +</style> | ||
| 0 | \ No newline at end of file | 41 | \ No newline at end of file |
src/components/NCC-tableOperation/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="ncc-table-opts"> | ||
| 3 | + <!--左侧插槽--> | ||
| 4 | + <slot name="left" /> | ||
| 5 | + <template v-if="isJudgePer"> | ||
| 6 | + <el-button size="mini" type="text" @click="edit()" v-if="hasEdit" :disabled="editDisabled" | ||
| 7 | + v-has="editPerCode">{{ editText === '编辑' ? $t(`common.editBtn`) : editText }}</el-button> | ||
| 8 | + </template> | ||
| 9 | + <template v-else> | ||
| 10 | + <el-button size="mini" type="text" @click="edit()" v-if="hasEdit" :disabled="editDisabled"> | ||
| 11 | + {{ editText === '编辑' ? $t(`common.editBtn`) : editText }}</el-button> | ||
| 12 | + </template> | ||
| 13 | + <!-- 中间插槽 --> | ||
| 14 | + <slot name="center" /> | ||
| 15 | + <template v-if="isJudgePer"> | ||
| 16 | + <el-button size="mini" type="text" class="NCC-table-delBtn" @click="del()" v-if="hasDel" | ||
| 17 | + :disabled="delDisabled" v-has="delPerCode"> | ||
| 18 | + {{ delText === '删除' ? $t(`common.delBtn`) : delText }}</el-button> | ||
| 19 | + </template> | ||
| 20 | + <template v-else> | ||
| 21 | + <el-button size="mini" type="text" class="NCC-table-delBtn" @click="del()" v-if="hasDel" | ||
| 22 | + :disabled="delDisabled">{{ delText === '删除' ? $t(`common.delBtn`) : delText }}</el-button> | ||
| 23 | + </template> | ||
| 24 | + <!-- 默认右侧插槽 --> | ||
| 25 | + <slot /> | ||
| 26 | + </div> | ||
| 27 | +</template> | ||
| 28 | +<script> | ||
| 29 | +export default { | ||
| 30 | + props: { | ||
| 31 | + delText: { | ||
| 32 | + type: String, | ||
| 33 | + default: '删除' | ||
| 34 | + }, | ||
| 35 | + editText: { | ||
| 36 | + type: String, | ||
| 37 | + default: '编辑' | ||
| 38 | + }, | ||
| 39 | + // 是否展示编辑按钮 | ||
| 40 | + hasEdit: { | ||
| 41 | + type: Boolean, | ||
| 42 | + default: true | ||
| 43 | + }, | ||
| 44 | + // 是否展示删除按钮 | ||
| 45 | + hasDel: { | ||
| 46 | + type: Boolean, | ||
| 47 | + default: true | ||
| 48 | + }, | ||
| 49 | + editDisabled: { | ||
| 50 | + type: Boolean, | ||
| 51 | + default: false | ||
| 52 | + }, | ||
| 53 | + delDisabled: { | ||
| 54 | + type: Boolean, | ||
| 55 | + default: false | ||
| 56 | + }, | ||
| 57 | + // 编辑按钮权限标识 | ||
| 58 | + editPerCode: { | ||
| 59 | + type: String, | ||
| 60 | + default: 'btn_edit' | ||
| 61 | + }, | ||
| 62 | + // 删除按钮权限标识 | ||
| 63 | + delPerCode: { | ||
| 64 | + type: String, | ||
| 65 | + default: 'btn_remove' | ||
| 66 | + }, | ||
| 67 | + // 是否开启权限判断 | ||
| 68 | + isJudgePer: { | ||
| 69 | + type: Boolean, | ||
| 70 | + default: false | ||
| 71 | + }, | ||
| 72 | + }, | ||
| 73 | + data() { | ||
| 74 | + return {} | ||
| 75 | + }, | ||
| 76 | + methods: { | ||
| 77 | + del() { | ||
| 78 | + this.$emit('del') | ||
| 79 | + }, | ||
| 80 | + edit() { | ||
| 81 | + this.$emit('edit') | ||
| 82 | + } | ||
| 83 | + } | ||
| 84 | +} | ||
| 85 | +</script> | ||
| 0 | \ No newline at end of file | 86 | \ No newline at end of file |
src/components/NCC-topOperation/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="ncc-opts"> | ||
| 3 | + <!--左侧插槽--> | ||
| 4 | + <slot name="left" /> | ||
| 5 | + <template v-if="isJudgePer"> | ||
| 6 | + <el-button type="primary" @click="add" icon="el-icon-plus" v-has="addPerCode"> | ||
| 7 | + {{ addText === '新建' ? $t(`common.addBtn`) : addText }} | ||
| 8 | + </el-button> | ||
| 9 | + </template> | ||
| 10 | + <template v-else> | ||
| 11 | + <el-button type="primary" @click="add" icon="el-icon-plus"> | ||
| 12 | + {{ addText === '新建' ? $t(`common.addBtn`) : addText }} | ||
| 13 | + </el-button> | ||
| 14 | + </template> | ||
| 15 | + <!-- 默认右侧插槽 --> | ||
| 16 | + <slot /> | ||
| 17 | + </div> | ||
| 18 | +</template> | ||
| 19 | +<script> | ||
| 20 | +export default { | ||
| 21 | + props: { | ||
| 22 | + refreshText: { | ||
| 23 | + type: String, | ||
| 24 | + default: '刷新' | ||
| 25 | + }, | ||
| 26 | + addText: { | ||
| 27 | + type: String, | ||
| 28 | + default: '新建' | ||
| 29 | + }, | ||
| 30 | + // 刷新加载状态 | ||
| 31 | + loading: { | ||
| 32 | + type: Boolean, | ||
| 33 | + default: false | ||
| 34 | + }, | ||
| 35 | + // 是否展示刷新按钮 | ||
| 36 | + hasRefresh: { | ||
| 37 | + type: Boolean, | ||
| 38 | + default: true | ||
| 39 | + }, | ||
| 40 | + // 新增按钮权限标识 | ||
| 41 | + addPerCode: { | ||
| 42 | + type: String, | ||
| 43 | + default: 'btn_add' | ||
| 44 | + }, | ||
| 45 | + // 是否开启权限判断 | ||
| 46 | + isJudgePer: { | ||
| 47 | + type: Boolean, | ||
| 48 | + default: false | ||
| 49 | + } | ||
| 50 | + }, | ||
| 51 | + data() { | ||
| 52 | + return {} | ||
| 53 | + }, | ||
| 54 | + methods: { | ||
| 55 | + refresh() { | ||
| 56 | + this.$emit('refresh') | ||
| 57 | + }, | ||
| 58 | + add() { | ||
| 59 | + this.$emit('add') | ||
| 60 | + } | ||
| 61 | + } | ||
| 62 | +} | ||
| 63 | +</script> | ||
| 64 | +<style lang="scss" scoped> | ||
| 65 | +.ncc-opts { | ||
| 66 | + display: inline-block; | ||
| 67 | +} | ||
| 68 | +</style> | ||
| 0 | \ No newline at end of file | 69 | \ No newline at end of file |
src/components/NCC-uploadBtn/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-upload :action="define.comUrl+url" :headers="{ Authorization: $store.getters.token}" | ||
| 3 | + :on-success="handleSuccess" :before-upload="beforeUpload" :show-file-list="false" | ||
| 4 | + class="upload-btn"> | ||
| 5 | + <el-button :type="buttonType" icon="el-icon-upload2" :loading="loading">{{buttonText}} | ||
| 6 | + </el-button> | ||
| 7 | + </el-upload> | ||
| 8 | +</template> | ||
| 9 | + | ||
| 10 | +<script> | ||
| 11 | +export default { | ||
| 12 | + name: 'NCC-uploadBtn', | ||
| 13 | + data() { | ||
| 14 | + return { | ||
| 15 | + loading: false | ||
| 16 | + } | ||
| 17 | + }, | ||
| 18 | + props: { | ||
| 19 | + url: { | ||
| 20 | + type: String, | ||
| 21 | + default: "" | ||
| 22 | + }, | ||
| 23 | + buttonText: { | ||
| 24 | + type: String, | ||
| 25 | + default: '导入' | ||
| 26 | + }, | ||
| 27 | + buttonType: { | ||
| 28 | + type: String, | ||
| 29 | + default: 'text' | ||
| 30 | + } | ||
| 31 | + }, | ||
| 32 | + methods: { | ||
| 33 | + beforeUpload() { | ||
| 34 | + this.loading = true | ||
| 35 | + }, | ||
| 36 | + handleSuccess(res) { | ||
| 37 | + this.loading = false | ||
| 38 | + if (res.code == 200) { | ||
| 39 | + this.$message({ | ||
| 40 | + message: res.msg, | ||
| 41 | + type: 'success', | ||
| 42 | + duration: 1000 | ||
| 43 | + }) | ||
| 44 | + this.$emit('on-success') | ||
| 45 | + } else { | ||
| 46 | + this.$message({ | ||
| 47 | + message: res.msg, | ||
| 48 | + type: 'error', | ||
| 49 | + duration: 1000 | ||
| 50 | + }) | ||
| 51 | + } | ||
| 52 | + } | ||
| 53 | + } | ||
| 54 | +}; | ||
| 55 | +</script> | ||
| 56 | +<style lang="scss" scoped> | ||
| 57 | +.upload-btn { | ||
| 58 | + display: inline-block; | ||
| 59 | + margin: 0 10px; | ||
| 60 | +} | ||
| 61 | +</style> | ||
| 0 | \ No newline at end of file | 62 | \ No newline at end of file |
src/components/NCC-userBox/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-dialog :title="'选择'+title" :close-on-click-modal="false" :visible.sync="visible" | ||
| 3 | + class="NCC-dialog NCC-dialog_center NCC-dialog-tree" lock-scroll append-to-body | ||
| 4 | + width='450px'> | ||
| 5 | + <el-input placeholder="输入姓名或者编号进行过滤" v-model="keyword" clearable @keyup.enter.native="getList"> | ||
| 6 | + <el-button slot="append" icon="el-icon-search" @click="getList"></el-button> | ||
| 7 | + </el-input> | ||
| 8 | + <el-tree :data="treeData" :props="props" highlight-current :expand-on-click-node="false" | ||
| 9 | + check-on-click-node @node-click="handleNodeClick" class="NCC-common-el-tree" node-key="id" | ||
| 10 | + v-loading="loading" lazy :load="loadNode"> | ||
| 11 | + <span class="custom-tree-node" slot-scope="{ node, data }"> | ||
| 12 | + <i :class="data.icon"></i> | ||
| 13 | + <span class="text">{{node.label}}</span> | ||
| 14 | + </span> | ||
| 15 | + </el-tree> | ||
| 16 | + <span slot="footer" class="dialog-footer"> | ||
| 17 | + <el-button @click="visible = false">{{$t('common.cancelButton')}}</el-button> | ||
| 18 | + <el-button type="primary" @click="dataFormSubmit()">{{$t('common.confirmButton')}}</el-button> | ||
| 19 | + </span> | ||
| 20 | + </el-dialog> | ||
| 21 | +</template> | ||
| 22 | + | ||
| 23 | +<script> | ||
| 24 | +import { getImUserSelector } from '@/api/permission/user' | ||
| 25 | +export default { | ||
| 26 | + name: 'UserBox', | ||
| 27 | + props: { | ||
| 28 | + title: { | ||
| 29 | + type: String, | ||
| 30 | + default: '审批人' | ||
| 31 | + } | ||
| 32 | + }, | ||
| 33 | + data() { | ||
| 34 | + return { | ||
| 35 | + visible: false, | ||
| 36 | + id: '', | ||
| 37 | + nodeId: '0', | ||
| 38 | + props: { | ||
| 39 | + children: 'children', | ||
| 40 | + label: 'fullName', | ||
| 41 | + value: 'id', | ||
| 42 | + isLeaf: 'isLeaf' | ||
| 43 | + }, | ||
| 44 | + treeData: [], | ||
| 45 | + loading: false, | ||
| 46 | + keyword: '' | ||
| 47 | + } | ||
| 48 | + }, | ||
| 49 | + methods: { | ||
| 50 | + init() { | ||
| 51 | + this.visible = true | ||
| 52 | + this.keyword = '' | ||
| 53 | + this.nodeId = '0' | ||
| 54 | + this.getList() | ||
| 55 | + }, | ||
| 56 | + getList() { | ||
| 57 | + this.loading = true | ||
| 58 | + if (this.keyword) this.nodeId = '0' | ||
| 59 | + getImUserSelector(this.nodeId, this.keyword).then(res => { | ||
| 60 | + this.treeData = res.data.list | ||
| 61 | + this.loading = false | ||
| 62 | + }) | ||
| 63 | + }, | ||
| 64 | + loadNode(node, resolve) { | ||
| 65 | + if (node.level === 0) { | ||
| 66 | + this.nodeId = '0' | ||
| 67 | + return resolve(this.treeData) | ||
| 68 | + } | ||
| 69 | + this.nodeId = node.data.id | ||
| 70 | + getImUserSelector(this.nodeId).then(res => { | ||
| 71 | + resolve(res.data.list) | ||
| 72 | + }) | ||
| 73 | + }, | ||
| 74 | + handleNodeClick(data) { | ||
| 75 | + if (data.type !== 'user') return | ||
| 76 | + this.id = data.id | ||
| 77 | + }, | ||
| 78 | + dataFormSubmit() { | ||
| 79 | + if (!this.id) { | ||
| 80 | + this.$message({ | ||
| 81 | + message: `请选择${this.title}`, | ||
| 82 | + type: 'error', | ||
| 83 | + duration: 1000, | ||
| 84 | + }) | ||
| 85 | + return | ||
| 86 | + } | ||
| 87 | + this.visible = false | ||
| 88 | + this.$emit('submit', this.id) | ||
| 89 | + }, | ||
| 90 | + } | ||
| 91 | +} | ||
| 92 | +</script> | ||
| 0 | \ No newline at end of file | 93 | \ No newline at end of file |
src/components/NCC-userSelect/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="userSelect-container"> | ||
| 3 | + <div class="userSelect-input" @click="openDialog"> | ||
| 4 | + <el-input :placeholder="placeholder" v-model="innerValue" readonly :disabled="disabled"> | ||
| 5 | + <i slot="suffix" class="el-input__icon el-icon-circle-close" @click.stop="clear" | ||
| 6 | + v-if="clearable"></i> | ||
| 7 | + <i slot="suffix" class="el-input__icon el-icon-arrow-down" | ||
| 8 | + :class="{'clearable':clearable}"></i> | ||
| 9 | + </el-input> | ||
| 10 | + </div> | ||
| 11 | + <el-dialog title="选择用户" :close-on-click-modal="false" :visible.sync="visible" | ||
| 12 | + class="NCC-dialog NCC-dialog_center transfer-dialog" lock-scroll append-to-body | ||
| 13 | + width="800px" :modal-append-to-body="false"> | ||
| 14 | + <div class="transfer__body" :element-loading-text="$t('common.loadingText')"> | ||
| 15 | + <div class="transfer-pane"> | ||
| 16 | + <div class="transfer-pane__tools"> | ||
| 17 | + <el-input placeholder="输入关键词进行搜索" v-model="keyword" @keyup.enter.native="getList"> | ||
| 18 | + <el-button slot="append" icon="el-icon-search" @click="getList"></el-button> | ||
| 19 | + </el-input> | ||
| 20 | + </div> | ||
| 21 | + <div class="transfer-pane__body"> | ||
| 22 | + <el-tree :data="treeData" :props="props" highlight-current :expand-on-click-node="false" | ||
| 23 | + check-on-click-node @node-click="handleNodeClick" class="NCC-common-el-tree" | ||
| 24 | + node-key="id" v-loading="loading" lazy :load="loadNode"> | ||
| 25 | + <span class="custom-tree-node" slot-scope="{ node, data }"> | ||
| 26 | + <i :class="data.icon"></i> | ||
| 27 | + <span class="text">{{node.label}}</span> | ||
| 28 | + </span> | ||
| 29 | + </el-tree> | ||
| 30 | + </div> | ||
| 31 | + </div> | ||
| 32 | + <div class="transfer-pane"> | ||
| 33 | + <div class="transfer-pane__tools"> | ||
| 34 | + <span>已选</span> | ||
| 35 | + <el-button @click="removeAll" type="text">清空列表</el-button> | ||
| 36 | + </div> | ||
| 37 | + <div class="transfer-pane__body shadow right-pane"> | ||
| 38 | + <template> | ||
| 39 | + <div v-for="(item, index) in selectedData" :key=" index" class="selected-item"> | ||
| 40 | + <span>{{ item.fullName}}</span> | ||
| 41 | + <i class="el-icon-delete" @click="removeData(index)"></i> | ||
| 42 | + </div> | ||
| 43 | + </template> | ||
| 44 | + </div> | ||
| 45 | + </div> | ||
| 46 | + </div> | ||
| 47 | + <span slot="footer" class="dialog-footer"> | ||
| 48 | + <el-button @click="visible=false">{{$t('common.cancelButton')}}</el-button> | ||
| 49 | + <el-button type="primary" @click="confirm">{{$t('common.confirmButton')}}</el-button> | ||
| 50 | + </span> | ||
| 51 | + </el-dialog> | ||
| 52 | + </div> | ||
| 53 | +</template> | ||
| 54 | + | ||
| 55 | +<script> | ||
| 56 | +import { getImUserSelector, getUserInfoList } from '@/api/permission/user' | ||
| 57 | +export default { | ||
| 58 | + name: 'userSelect', | ||
| 59 | + props: { | ||
| 60 | + value: { | ||
| 61 | + default: '' | ||
| 62 | + }, | ||
| 63 | + interfaceId: { | ||
| 64 | + type: String, | ||
| 65 | + default: '' | ||
| 66 | + }, | ||
| 67 | + placeholder: { | ||
| 68 | + type: String, | ||
| 69 | + default: '请选择' | ||
| 70 | + }, | ||
| 71 | + disabled: { | ||
| 72 | + type: Boolean, | ||
| 73 | + default: false | ||
| 74 | + }, | ||
| 75 | + multiple: { | ||
| 76 | + type: Boolean, | ||
| 77 | + default: false | ||
| 78 | + }, | ||
| 79 | + clearable: { | ||
| 80 | + type: Boolean, | ||
| 81 | + default: true | ||
| 82 | + } | ||
| 83 | + }, | ||
| 84 | + data() { | ||
| 85 | + return { | ||
| 86 | + visible: false, | ||
| 87 | + keyword: '', | ||
| 88 | + nodeId: '', | ||
| 89 | + innerValue: '', | ||
| 90 | + loading: false, | ||
| 91 | + props: { | ||
| 92 | + children: 'children', | ||
| 93 | + label: 'fullName', | ||
| 94 | + isLeaf: 'isLeaf' | ||
| 95 | + }, | ||
| 96 | + treeData: [], | ||
| 97 | + selectedData: [], | ||
| 98 | + } | ||
| 99 | + }, | ||
| 100 | + watch: { | ||
| 101 | + value(val) { | ||
| 102 | + this.setDefault() | ||
| 103 | + } | ||
| 104 | + }, | ||
| 105 | + created() { | ||
| 106 | + this.setDefault() | ||
| 107 | + }, | ||
| 108 | + methods: { | ||
| 109 | + clear() { | ||
| 110 | + if (this.disabled) return | ||
| 111 | + this.innerValue = '' | ||
| 112 | + this.selectedData = [] | ||
| 113 | + this.$emit('input', '') | ||
| 114 | + this.$emit('change', '', '') | ||
| 115 | + }, | ||
| 116 | + openDialog() { | ||
| 117 | + if (this.disabled) return | ||
| 118 | + this.visible = true | ||
| 119 | + this.keyword = '' | ||
| 120 | + this.nodeId = '0' | ||
| 121 | + this.getList() | ||
| 122 | + }, | ||
| 123 | + confirm() { | ||
| 124 | + let txt = '', ids = '' | ||
| 125 | + for (let i = 0; i < this.selectedData.length; i++) { | ||
| 126 | + txt += (i ? ',' : '') + this.selectedData[i].fullName | ||
| 127 | + ids += (i ? ',' : '') + this.selectedData[i].id | ||
| 128 | + } | ||
| 129 | + this.innerValue = txt | ||
| 130 | + this.$emit('input', ids) | ||
| 131 | + this.$emit('change', ids, this.selectedData) | ||
| 132 | + this.visible = false | ||
| 133 | + }, | ||
| 134 | + setDefault() { | ||
| 135 | + this.selectedData = [] | ||
| 136 | + if (!this.value) return this.innerValue = '' | ||
| 137 | + const arr = this.value.split(',') | ||
| 138 | + getUserInfoList(arr).then(res => { | ||
| 139 | + const list = res.data.list | ||
| 140 | + this.selectedData = list | ||
| 141 | + let txt = '' | ||
| 142 | + for (let i = 0; i < list.length; i++) { | ||
| 143 | + txt += (i ? ',' : '') + list[i].fullName | ||
| 144 | + } | ||
| 145 | + this.innerValue = txt | ||
| 146 | + }) | ||
| 147 | + }, | ||
| 148 | + getList() { | ||
| 149 | + this.loading = true | ||
| 150 | + if (this.keyword) this.nodeId = '0' | ||
| 151 | + getImUserSelector(this.nodeId, this.keyword).then(res => { | ||
| 152 | + this.treeData = res.data.list | ||
| 153 | + this.loading = false | ||
| 154 | + }) | ||
| 155 | + }, | ||
| 156 | + loadNode(node, resolve) { | ||
| 157 | + if (node.level === 0) { | ||
| 158 | + this.nodeId = '0' | ||
| 159 | + return resolve(this.treeData) | ||
| 160 | + } | ||
| 161 | + this.nodeId = node.data.id | ||
| 162 | + getImUserSelector(this.nodeId).then(res => { | ||
| 163 | + resolve(res.data.list) | ||
| 164 | + }) | ||
| 165 | + }, | ||
| 166 | + handleNodeClick(data) { | ||
| 167 | + if (data.type !== 'user') return | ||
| 168 | + const boo = this.selectedData.some(o => o.id === data.id) | ||
| 169 | + if (boo) return | ||
| 170 | + const item = { | ||
| 171 | + id: data.id, | ||
| 172 | + fullName: data.fullName | ||
| 173 | + } | ||
| 174 | + this.multiple ? this.selectedData.push(item) : this.selectedData = [item] | ||
| 175 | + }, | ||
| 176 | + removeAll() { | ||
| 177 | + this.selectedData = [] | ||
| 178 | + }, | ||
| 179 | + removeData(index) { | ||
| 180 | + this.selectedData.splice(index, 1) | ||
| 181 | + }, | ||
| 182 | + }, | ||
| 183 | +} | ||
| 184 | +</script> | ||
| 185 | +<style lang="scss" scoped> | ||
| 186 | +.userSelect-container { | ||
| 187 | + width: 100%; | ||
| 188 | + .userSelect-input { | ||
| 189 | + width: 100%; | ||
| 190 | + cursor: pointer; | ||
| 191 | + .is-disabled { | ||
| 192 | + &:hover { | ||
| 193 | + .el-icon-circle-close { | ||
| 194 | + display: none; | ||
| 195 | + } | ||
| 196 | + .el-icon-arrow-down { | ||
| 197 | + display: inline-block; | ||
| 198 | + } | ||
| 199 | + } | ||
| 200 | + >>> input { | ||
| 201 | + cursor: not-allowed; | ||
| 202 | + } | ||
| 203 | + } | ||
| 204 | + >>> input { | ||
| 205 | + cursor: pointer; | ||
| 206 | + } | ||
| 207 | + .el-icon-circle-close { | ||
| 208 | + display: none; | ||
| 209 | + } | ||
| 210 | + &:hover { | ||
| 211 | + .el-icon-circle-close { | ||
| 212 | + display: block; | ||
| 213 | + } | ||
| 214 | + .el-icon-arrow-down.clearable { | ||
| 215 | + display: none; | ||
| 216 | + } | ||
| 217 | + } | ||
| 218 | + } | ||
| 219 | +} | ||
| 220 | +</style> | ||
| 0 | \ No newline at end of file | 221 | \ No newline at end of file |
src/components/NCCEditor/quill.vue
| 1 | <template> | 1 | <template> |
| 2 | <div :class="prefixCls"> | 2 | <div :class="prefixCls"> |
| 3 | - <quill-editor v-model="content" ref="myQuillEditor" :content="value" :options="editorOption" | 3 | + <quill-editor v-model="content" ref="myQuillEditor" :content="value" :options="editorOption" :disabled="disabled" |
| 4 | @blur="onEditorBlur($event)" @focus="onEditorFocus($event)" @ready="onEditorReady($event)" | 4 | @blur="onEditorBlur($event)" @focus="onEditorFocus($event)" @ready="onEditorReady($event)" |
| 5 | @change="onEditorChange($event)"> | 5 | @change="onEditorChange($event)"> |
| 6 | </quill-editor> | 6 | </quill-editor> |
| @@ -29,6 +29,10 @@ export default { | @@ -29,6 +29,10 @@ export default { | ||
| 29 | placeholder: { | 29 | placeholder: { |
| 30 | type: String, | 30 | type: String, |
| 31 | default: '请输入内容...' | 31 | default: '请输入内容...' |
| 32 | + }, | ||
| 33 | + disabled: { | ||
| 34 | + type: Boolean, | ||
| 35 | + default: false | ||
| 32 | } | 36 | } |
| 33 | }, | 37 | }, |
| 34 | data() { | 38 | data() { |
| @@ -47,11 +51,11 @@ export default { | @@ -47,11 +51,11 @@ export default { | ||
| 47 | [{ align: [] }], | 51 | [{ align: [] }], |
| 48 | [{ direction: "rtl" }], | 52 | [{ direction: "rtl" }], |
| 49 | ["clean"], | 53 | ["clean"], |
| 50 | - ["link", "image"], | 54 | + // ["link", "image"], |
| 51 | ] | 55 | ] |
| 52 | }, | 56 | }, |
| 53 | theme: 'snow', | 57 | theme: 'snow', |
| 54 | - placeholder: this.placeholder | 58 | + placeholder: this.placeholder, |
| 55 | } | 59 | } |
| 56 | } | 60 | } |
| 57 | }, | 61 | }, |
src/components/SizeSelect/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-dropdown trigger="click" @command="handleSetSize"> | ||
| 3 | + <div> | ||
| 4 | + <i class="ym-custom ym-custom-format-size" /> | ||
| 5 | + </div> | ||
| 6 | + <el-dropdown-menu slot="dropdown"> | ||
| 7 | + <el-dropdown-item v-for="item of sizeOptions" :key="item.value" :disabled="size===item.value" | ||
| 8 | + :command="item.value"> | ||
| 9 | + {{ | ||
| 10 | + item.label }} | ||
| 11 | + </el-dropdown-item> | ||
| 12 | + </el-dropdown-menu> | ||
| 13 | + </el-dropdown> | ||
| 14 | +</template> | ||
| 15 | + | ||
| 16 | +<script> | ||
| 17 | +export default { | ||
| 18 | + data() { | ||
| 19 | + return { | ||
| 20 | + sizeOptions: [ | ||
| 21 | + { label: 'Default', value: 'default' }, | ||
| 22 | + { label: 'Medium', value: 'medium' }, | ||
| 23 | + { label: 'Small', value: 'small' }, | ||
| 24 | + { label: 'Mini', value: 'mini' } | ||
| 25 | + ] | ||
| 26 | + } | ||
| 27 | + }, | ||
| 28 | + computed: { | ||
| 29 | + size() { | ||
| 30 | + return this.$store.getters.size | ||
| 31 | + } | ||
| 32 | + }, | ||
| 33 | + methods: { | ||
| 34 | + handleSetSize(size) { | ||
| 35 | + this.$ELEMENT.size = size | ||
| 36 | + this.$store.dispatch('app/setSize', size) | ||
| 37 | + this.refreshView() | ||
| 38 | + this.$message({ | ||
| 39 | + message: 'Switch Size Success', | ||
| 40 | + type: 'success' | ||
| 41 | + }) | ||
| 42 | + }, | ||
| 43 | + refreshView() { | ||
| 44 | + // In order to make the cached page re-rendered | ||
| 45 | + this.$store.dispatch('tagsView/delAllCachedViews', this.$route) | ||
| 46 | + | ||
| 47 | + const { fullPath } = this.$route | ||
| 48 | + | ||
| 49 | + this.$nextTick(() => { | ||
| 50 | + this.$router.replace({ | ||
| 51 | + path: '/redirect' + fullPath | ||
| 52 | + }) | ||
| 53 | + }) | ||
| 54 | + } | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | +} | ||
| 58 | +</script> |
src/components/VisualPortal/CommonFunc/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-card shadow="never" class="commonFunc-box"> | ||
| 3 | + <div slot="header" class="portal-common-title"> | ||
| 4 | + <span>{{title}}</span> | ||
| 5 | + </div> | ||
| 6 | + <div class="commonFunc-box-body"> | ||
| 7 | + <router-link class="item" :to="'/'+item.urlAddress" v-for="(item,i) in menuList" :key="i"> | ||
| 8 | + <i :class="item.icon" :style="{color:item.iconBackgroundColor||'#1890FF'}"></i> | ||
| 9 | + <p class="name">{{item.fullName}}</p> | ||
| 10 | + </router-link> | ||
| 11 | + </div> | ||
| 12 | + </el-card> | ||
| 13 | +</template> | ||
| 14 | +<script> | ||
| 15 | +export default { | ||
| 16 | + props: { | ||
| 17 | + title: { type: String, default: '' }, | ||
| 18 | + list: { type: Array, default: () => [] } | ||
| 19 | + }, | ||
| 20 | + data() { | ||
| 21 | + return { | ||
| 22 | + menuList: [] | ||
| 23 | + } | ||
| 24 | + }, | ||
| 25 | + created() { | ||
| 26 | + this.menuList = this.list.filter(o => o.id) | ||
| 27 | + }, | ||
| 28 | + watch: { | ||
| 29 | + list: { | ||
| 30 | + handler(val) { | ||
| 31 | + this.menuList = val.filter(o => o.id) | ||
| 32 | + }, | ||
| 33 | + deep: true | ||
| 34 | + } | ||
| 35 | + } | ||
| 36 | +} | ||
| 37 | +</script> | ||
| 38 | +<style lang="scss" scoped> | ||
| 39 | +.commonFunc-box { | ||
| 40 | + >>> .el-card__body { | ||
| 41 | + width: 100%; | ||
| 42 | + height: calc(100% - 55px); | ||
| 43 | + } | ||
| 44 | + .commonFunc-box-body { | ||
| 45 | + padding: 0 30px; | ||
| 46 | + height: 100%; | ||
| 47 | + display: flex; | ||
| 48 | + justify-content: space-between; | ||
| 49 | + align-items: center; | ||
| 50 | + .item { | ||
| 51 | + display: block; | ||
| 52 | + text-align: center; | ||
| 53 | + i { | ||
| 54 | + display: inline-block; | ||
| 55 | + height: 40px; | ||
| 56 | + font-size: 40px; | ||
| 57 | + margin-bottom: 10px; | ||
| 58 | + } | ||
| 59 | + .name { | ||
| 60 | + font-size: 14px; | ||
| 61 | + line-height: 20px; | ||
| 62 | + } | ||
| 63 | + } | ||
| 64 | + } | ||
| 65 | +} | ||
| 66 | +</style> | ||
| 0 | \ No newline at end of file | 67 | \ No newline at end of file |
src/components/VisualPortal/DataBoard/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-row :gutter="10" class="dataBoard"> | ||
| 3 | + <el-col :span="6" class="dataBoard-item" v-for="(item,i) in menuList" :key="i"> | ||
| 4 | + <el-card shadow="never"> | ||
| 5 | + <div class="dataBoard-body"> | ||
| 6 | + <i :class="item.icon+' dataBoard-body-item dataBoard-body-item'+(i+1)"></i> | ||
| 7 | + <div class="text"> | ||
| 8 | + <p class="num">{{item.num}}</p> | ||
| 9 | + <p class="name">{{item.fullName}}</p> | ||
| 10 | + </div> | ||
| 11 | + </div> | ||
| 12 | + </el-card> | ||
| 13 | + </el-col> | ||
| 14 | + </el-row> | ||
| 15 | +</template> | ||
| 16 | +<script> | ||
| 17 | +import { getCountData } from '@/api/home' | ||
| 18 | +export default { | ||
| 19 | + props: { | ||
| 20 | + title: { type: String, default: '' }, | ||
| 21 | + // list: { type: Array, default: () => [] } | ||
| 22 | + }, | ||
| 23 | + data() { | ||
| 24 | + return { | ||
| 25 | + menuList: [] | ||
| 26 | + } | ||
| 27 | + }, | ||
| 28 | + created() { | ||
| 29 | + this.getData() | ||
| 30 | + }, | ||
| 31 | + methods: { | ||
| 32 | + getData() { | ||
| 33 | + getCountData().then(res => { | ||
| 34 | + this.menuList = res.data.list | ||
| 35 | + }) | ||
| 36 | + } | ||
| 37 | + }, | ||
| 38 | + watch: { | ||
| 39 | + list: { | ||
| 40 | + handler(val) { | ||
| 41 | + this.menuList = val | ||
| 42 | + }, | ||
| 43 | + deep: true | ||
| 44 | + } | ||
| 45 | + } | ||
| 46 | +} | ||
| 47 | +</script> | ||
| 48 | +<style lang="scss" scoped> | ||
| 49 | +.dataBoard { | ||
| 50 | + height: 100%; | ||
| 51 | + overflow: hidden; | ||
| 52 | + .dataBoard-item { | ||
| 53 | + height: 100%; | ||
| 54 | + } | ||
| 55 | + >>> .el-card { | ||
| 56 | + width: 100%; | ||
| 57 | + height: 100%; | ||
| 58 | + .el-card__body { | ||
| 59 | + padding: 0; | ||
| 60 | + height: 100%; | ||
| 61 | + } | ||
| 62 | + } | ||
| 63 | + .dataBoard-body { | ||
| 64 | + padding-left: 30px; | ||
| 65 | + height: 100%; | ||
| 66 | + display: flex; | ||
| 67 | + align-items: center; | ||
| 68 | + .dataBoard-body-item { | ||
| 69 | + width: 66px; | ||
| 70 | + height: 66px; | ||
| 71 | + margin-right: 16px; | ||
| 72 | + border-radius: 50%; | ||
| 73 | + text-align: center; | ||
| 74 | + line-height: 66px; | ||
| 75 | + font-size: 36px; | ||
| 76 | + flex-shrink: 0; | ||
| 77 | + &.dataBoard-body-item1 { | ||
| 78 | + background: #f2ebfb; | ||
| 79 | + color: #7b1ae1; | ||
| 80 | + } | ||
| 81 | + &.dataBoard-body-item2 { | ||
| 82 | + background: #edf8fe; | ||
| 83 | + color: #4ab8ff; | ||
| 84 | + } | ||
| 85 | + &.dataBoard-body-item3 { | ||
| 86 | + background: #fff7e4; | ||
| 87 | + color: #ff8b58; | ||
| 88 | + } | ||
| 89 | + &.dataBoard-body-item4 { | ||
| 90 | + background: #fff2f5; | ||
| 91 | + color: #fc5b87; | ||
| 92 | + } | ||
| 93 | + } | ||
| 94 | + .text { | ||
| 95 | + display: inline-block; | ||
| 96 | + height: 56px; | ||
| 97 | + .num { | ||
| 98 | + font-size: 20px; | ||
| 99 | + line-height: 36px; | ||
| 100 | + } | ||
| 101 | + .name { | ||
| 102 | + font-size: 14px; | ||
| 103 | + color: #666; | ||
| 104 | + } | ||
| 105 | + } | ||
| 106 | + } | ||
| 107 | +} | ||
| 108 | +</style> | ||
| 0 | \ No newline at end of file | 109 | \ No newline at end of file |
src/components/VisualPortal/HAnnularChart/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-card shadow="never" class="portal-eChart-box"> | ||
| 3 | + <div slot="header" class="portal-common-title"> | ||
| 4 | + <span>{{title}}</span> | ||
| 5 | + </div> | ||
| 6 | + <div class="eChart-box-body"> | ||
| 7 | + <div ref="chart" id="chart" v-show="!isEmpty"></div> | ||
| 8 | + <div class="portal-common-noData portal-common-noData-eChart" v-show="isEmpty"> | ||
| 9 | + <img src="@/assets/images/portal-nodata.png" alt="" class="noData-img"> | ||
| 10 | + <p class="noData-txt">暂无数据</p> | ||
| 11 | + </div> | ||
| 12 | + </div> | ||
| 13 | + </el-card> | ||
| 14 | +</template> | ||
| 15 | +<script> | ||
| 16 | +import echartMixin from '@/components/VisualPortal/mixins' | ||
| 17 | +export default { | ||
| 18 | + mixins: [echartMixin] | ||
| 19 | +} | ||
| 20 | +</script> |
src/components/VisualPortal/HAreaChart/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-card shadow="never" class="portal-eChart-box"> | ||
| 3 | + <div slot="header" class="portal-common-title"> | ||
| 4 | + <span>{{title}}</span> | ||
| 5 | + </div> | ||
| 6 | + <div class="eChart-box-body"> | ||
| 7 | + <div ref="chart" id="chart" v-show="!isEmpty"></div> | ||
| 8 | + <div class="portal-common-noData portal-common-noData-eChart" v-show="isEmpty"> | ||
| 9 | + <img src="@/assets/images/portal-nodata.png" alt="" class="noData-img"> | ||
| 10 | + <p class="noData-txt">暂无数据</p> | ||
| 11 | + </div> | ||
| 12 | + </div> | ||
| 13 | + </el-card> | ||
| 14 | +</template> | ||
| 15 | +<script> | ||
| 16 | +import echartMixin from '@/components/VisualPortal/mixins' | ||
| 17 | +export default { | ||
| 18 | + mixins: [echartMixin] | ||
| 19 | +} | ||
| 20 | +</script> |
src/components/VisualPortal/HBarChart/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-card shadow="never" class="portal-eChart-box"> | ||
| 3 | + <div slot="header" class="portal-common-title"> | ||
| 4 | + <span>{{title}}</span> | ||
| 5 | + </div> | ||
| 6 | + <div class="eChart-box-body"> | ||
| 7 | + <div ref="chart" id="chart" v-show="!isEmpty"></div> | ||
| 8 | + <div class="portal-common-noData portal-common-noData-eChart" v-show="isEmpty"> | ||
| 9 | + <img src="@/assets/images/portal-nodata.png" alt="" class="noData-img"> | ||
| 10 | + <p class="noData-txt">暂无数据</p> | ||
| 11 | + </div> | ||
| 12 | + </div> | ||
| 13 | + </el-card> | ||
| 14 | +</template> | ||
| 15 | +<script> | ||
| 16 | +import { getProjectMonthLine } from "@/api/home"; | ||
| 17 | +import echarts from 'echarts' | ||
| 18 | +import resize from '@/components/Charts/mixins/resize' | ||
| 19 | +export default { | ||
| 20 | + mixins: [resize], | ||
| 21 | + props: { | ||
| 22 | + title: { type: String, default: '' }, | ||
| 23 | + option: { type: Object, default: () => { } } | ||
| 24 | + }, | ||
| 25 | + data() { | ||
| 26 | + return { | ||
| 27 | + chart: null, | ||
| 28 | + currOption: {}, | ||
| 29 | + isEmpty: false | ||
| 30 | + } | ||
| 31 | + }, | ||
| 32 | + created() { | ||
| 33 | + this.getData(); | ||
| 34 | + }, | ||
| 35 | + methods: { | ||
| 36 | + getData() { | ||
| 37 | + getProjectMonthLine().then((res) => { | ||
| 38 | + window.console.log("柱状图:" + res.data.chartdata); | ||
| 39 | + this.currOption = res.data.chartdata; | ||
| 40 | + this.initChart(); | ||
| 41 | + }); | ||
| 42 | + }, | ||
| 43 | + initChart() { | ||
| 44 | + this.chart = echarts.init(this.$refs.chart); | ||
| 45 | + this.chart.setOption(this.currOption); | ||
| 46 | + setTimeout(() => { | ||
| 47 | + this.$nextTick(() => { | ||
| 48 | + this.chart.resize(); | ||
| 49 | + }); | ||
| 50 | + }, 50); | ||
| 51 | + }, | ||
| 52 | + }, | ||
| 53 | + beforeDestroy() { | ||
| 54 | + if (!this.chart) return; | ||
| 55 | + this.chart.dispose(); | ||
| 56 | + this.chart = null; | ||
| 57 | + }, | ||
| 58 | +} | ||
| 59 | +</script> | ||
| 0 | \ No newline at end of file | 60 | \ No newline at end of file |
src/components/VisualPortal/HEmail/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-card shadow="never" class="portal-todoList-box"> | ||
| 3 | + <div slot="header" class="portal-common-title"> | ||
| 4 | + <span>{{title}}</span> | ||
| 5 | + </div> | ||
| 6 | + <div class="portal-todoList-box-body"> | ||
| 7 | + <template v-if="list.length"> | ||
| 8 | + <router-link class="item" to="/extend/email" v-for="(item, i) in list" :key="i"> | ||
| 9 | + <span class="name">{{item.fullName}}</span> | ||
| 10 | + <span class="time">{{item.creatorTime | toDateText()}}</span> | ||
| 11 | + </router-link> | ||
| 12 | + </template> | ||
| 13 | + <div class="portal-common-noData" v-else> | ||
| 14 | + <img src="@/assets/images/portal-nodata.png" alt="" class="noData-img"> | ||
| 15 | + <p class="noData-txt">暂无数据</p> | ||
| 16 | + </div> | ||
| 17 | + </div> | ||
| 18 | + </el-card> | ||
| 19 | +</template> | ||
| 20 | +<script> | ||
| 21 | +import { getEmail } from '@/api/home' | ||
| 22 | +export default { | ||
| 23 | + props: { | ||
| 24 | + title: { type: String, default: '' } | ||
| 25 | + }, | ||
| 26 | + data() { | ||
| 27 | + return { | ||
| 28 | + list: [] | ||
| 29 | + } | ||
| 30 | + }, | ||
| 31 | + created() { | ||
| 32 | + this.getData() | ||
| 33 | + }, | ||
| 34 | + methods: { | ||
| 35 | + getData() { | ||
| 36 | + getEmail().then(res => { | ||
| 37 | + this.list = res.data.list.slice(0, 7) | ||
| 38 | + }) | ||
| 39 | + } | ||
| 40 | + } | ||
| 41 | +} | ||
| 42 | +</script> | ||
| 0 | \ No newline at end of file | 43 | \ No newline at end of file |
src/components/VisualPortal/HLineChart/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-card shadow="never" class="portal-eChart-box"> | ||
| 3 | + <div slot="header" class="portal-common-title"> | ||
| 4 | + <span>{{title}}</span> | ||
| 5 | + </div> | ||
| 6 | + <div class="eChart-box-body"> | ||
| 7 | + <div ref="chart" id="chart" v-show="!isEmpty"></div> | ||
| 8 | + <div class="portal-common-noData portal-common-noData-eChart" v-show="isEmpty"> | ||
| 9 | + <img src="@/assets/images/portal-nodata.png" alt="" class="noData-img"> | ||
| 10 | + <p class="noData-txt">暂无数据</p> | ||
| 11 | + </div> | ||
| 12 | + </div> | ||
| 13 | + </el-card> | ||
| 14 | +</template> | ||
| 15 | +<script> | ||
| 16 | +import echartMixin from '@/components/VisualPortal/mixins' | ||
| 17 | +export default { | ||
| 18 | + mixins: [echartMixin] | ||
| 19 | +} | ||
| 20 | +</script> | ||
| 0 | \ No newline at end of file | 21 | \ No newline at end of file |
src/components/VisualPortal/HNotice/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-card shadow="never" class="portal-todoList-box"> | ||
| 3 | + <div slot="header" class="portal-common-title"> | ||
| 4 | + <span>{{title}}</span> | ||
| 5 | + </div> | ||
| 6 | + <div class="portal-todoList-box-body"> | ||
| 7 | + <template v-if="list.length"> | ||
| 8 | + <router-link class="item" to="/messageRecord" v-for="(item, i) in list" :key="i"> | ||
| 9 | + <span class="name">{{item.fullName}}</span> | ||
| 10 | + <span class="time">{{item.creatorTime | toDate('yyyy-MM-dd')}}</span> | ||
| 11 | + </router-link> | ||
| 12 | + </template> | ||
| 13 | + <div class="portal-common-noData" v-else> | ||
| 14 | + <img src="@/assets/images/portal-nodata.png" alt="" class="noData-img"> | ||
| 15 | + <p class="noData-txt">暂无数据</p> | ||
| 16 | + </div> | ||
| 17 | + </div> | ||
| 18 | + </el-card> | ||
| 19 | +</template> | ||
| 20 | +<script> | ||
| 21 | +import { getArticle } from '@/api/home' | ||
| 22 | +export default { | ||
| 23 | + props: { | ||
| 24 | + title: { type: String, default: '' } | ||
| 25 | + }, | ||
| 26 | + data() { | ||
| 27 | + return { | ||
| 28 | + list: [] | ||
| 29 | + } | ||
| 30 | + }, | ||
| 31 | + created() { | ||
| 32 | + this.getData() | ||
| 33 | + }, | ||
| 34 | + methods: { | ||
| 35 | + getData() { | ||
| 36 | + getArticle().then(res => { | ||
| 37 | + this.list = res.data.list.slice(0, 7) | ||
| 38 | + }) | ||
| 39 | + } | ||
| 40 | + } | ||
| 41 | +} | ||
| 42 | +</script> | ||
| 0 | \ No newline at end of file | 43 | \ No newline at end of file |
src/components/VisualPortal/HPieChart/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-card shadow="never" class="portal-eChart-box"> | ||
| 3 | + <div slot="header" class="portal-common-title"> | ||
| 4 | + <span>{{title}}</span> | ||
| 5 | + </div> | ||
| 6 | + <div class="eChart-box-body"> | ||
| 7 | + <div ref="chart" id="chart" v-show="!isEmpty"></div> | ||
| 8 | + <div class="portal-common-noData portal-common-noData-eChart" v-show="isEmpty"> | ||
| 9 | + <img src="@/assets/images/portal-nodata.png" alt="" class="noData-img"> | ||
| 10 | + <p class="noData-txt">暂无数据</p> | ||
| 11 | + </div> | ||
| 12 | + </div> | ||
| 13 | + </el-card> | ||
| 14 | +</template> | ||
| 15 | +<script> | ||
| 16 | +import echartMixin from '@/components/VisualPortal/mixins' | ||
| 17 | +export default { | ||
| 18 | + mixins: [echartMixin] | ||
| 19 | +} | ||
| 20 | +</script> | ||
| 0 | \ No newline at end of file | 21 | \ No newline at end of file |
src/components/VisualPortal/HRadarChart/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-card shadow="never" class="portal-eChart-box"> | ||
| 3 | + <div slot="header" class="portal-common-title"> | ||
| 4 | + <span>{{title}}</span> | ||
| 5 | + </div> | ||
| 6 | + <div class="eChart-box-body"> | ||
| 7 | + <div ref="chart" id="chart" v-show="!isEmpty"></div> | ||
| 8 | + <div class="portal-common-noData portal-common-noData-eChart" v-show="isEmpty"> | ||
| 9 | + <img src="@/assets/images/portal-nodata.png" alt="" class="noData-img"> | ||
| 10 | + <p class="noData-txt">暂无数据</p> | ||
| 11 | + </div> | ||
| 12 | + </div> | ||
| 13 | + </el-card> | ||
| 14 | +</template> | ||
| 15 | +<script> | ||
| 16 | +import echartMixin from '@/components/VisualPortal/mixins' | ||
| 17 | +export default { | ||
| 18 | + mixins: [echartMixin] | ||
| 19 | +} | ||
| 20 | +</script> | ||
| 0 | \ No newline at end of file | 21 | \ No newline at end of file |
src/components/VisualPortal/Layout/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-scrollbar class="layout-area"> | ||
| 3 | + <template v-if="layout.length"> | ||
| 4 | + <grid-layout :layout.sync="layout" :row-height="40" :is-draggable="false" | ||
| 5 | + :is-resizable="false"> | ||
| 6 | + <grid-item v-for="item in layout" :x="item.x" :y="item.y" :w="item.w" :h="item.h" | ||
| 7 | + :i="item.i" :key="item.i" static> | ||
| 8 | + <Todo v-if="item.nccKey==='todo'" :title="item.title" /> | ||
| 9 | + <CommonFunc v-if="item.nccKey==='commonFunc'" :title="item.title" :list="item.list" /> | ||
| 10 | + <TodoList v-if="item.nccKey==='todoList'" :title="item.title" /> | ||
| 11 | + <HNotice v-if="item.nccKey==='notice'" :title="item.title" /> | ||
| 12 | + <HEmail v-if="item.nccKey==='email'" :title="item.title" /> | ||
| 13 | + <DataBoard v-if="item.nccKey==='dataBoard'" :title="item.title" :list="item.list" /> | ||
| 14 | + <HBarChart v-if="item.nccKey==='barChart'" :title="item.title" :option="item.option" | ||
| 15 | + :dataType="item.dataType" :propsApi="item.propsApi" /> | ||
| 16 | + <HAnnularChart v-if="item.nccKey==='annularChart'" :title="item.title" | ||
| 17 | + :option=" item.option" :dataType="item.dataType" :propsApi="item.propsApi" /> | ||
| 18 | + <HAreaChart v-if="item.nccKey==='areaChart'" :title="item.title" :option="item.option" | ||
| 19 | + :dataType="item.dataType" :propsApi="item.propsApi" /> | ||
| 20 | + <HLineChart v-if="item.nccKey==='lineChart'" :title="item.title" :option="item.option" | ||
| 21 | + :dataType="item.dataType" :propsApi="item.propsApi" /> | ||
| 22 | + <HPieChart v-if="item.nccKey==='pieChart'" :title="item.title" :option="item.option" | ||
| 23 | + :dataType="item.dataType" :propsApi="item.propsApi" /> | ||
| 24 | + <HRadarChart v-if="item.nccKey==='radarChart'" :title="item.title" :option="item.option" | ||
| 25 | + :dataType="item.dataType" :propsApi="item.propsApi" /> | ||
| 26 | + <div class="mask" v-if="mask"></div> | ||
| 27 | + </grid-item> | ||
| 28 | + </grid-layout> | ||
| 29 | + </template> | ||
| 30 | + <div class="portal-layout-nodata" v-else> | ||
| 31 | + <img src="@/assets/images/dashboard-nodata.png" alt="" class="layout-nodata-img"> | ||
| 32 | + <p class="layout-nodata-txt">暂无数据</p> | ||
| 33 | + </div> | ||
| 34 | + </el-scrollbar> | ||
| 35 | +</template> | ||
| 36 | + | ||
| 37 | +<script> | ||
| 38 | +import { | ||
| 39 | + Todo, | ||
| 40 | + CommonFunc, | ||
| 41 | + TodoList, | ||
| 42 | + HNotice, | ||
| 43 | + HEmail, | ||
| 44 | + DataBoard, | ||
| 45 | + HBarChart, | ||
| 46 | + HAnnularChart, | ||
| 47 | + HAreaChart, | ||
| 48 | + HLineChart, | ||
| 49 | + HPieChart, | ||
| 50 | + HRadarChart | ||
| 51 | +} from "@/components/VisualPortal" | ||
| 52 | +import VueGridLayout from 'vue-grid-layout' | ||
| 53 | +export default { | ||
| 54 | + props: { | ||
| 55 | + layout: { type: Array, default: () => [] }, | ||
| 56 | + mask: { type: Boolean, default: false }, | ||
| 57 | + }, | ||
| 58 | + components: { | ||
| 59 | + GridLayout: VueGridLayout.GridLayout, | ||
| 60 | + GridItem: VueGridLayout.GridItem, | ||
| 61 | + Todo, | ||
| 62 | + CommonFunc, | ||
| 63 | + TodoList, | ||
| 64 | + HNotice, | ||
| 65 | + HEmail, | ||
| 66 | + DataBoard, | ||
| 67 | + HBarChart, | ||
| 68 | + HAnnularChart, | ||
| 69 | + HAreaChart, | ||
| 70 | + HLineChart, | ||
| 71 | + HPieChart, | ||
| 72 | + HRadarChart | ||
| 73 | + }, | ||
| 74 | +} | ||
| 75 | +</script> | ||
| 76 | +<style lang="scss" scoped> | ||
| 77 | +.layout-area { | ||
| 78 | + height: 100%; | ||
| 79 | + overflow: hidden; | ||
| 80 | + >>> .el-scrollbar__wrap { | ||
| 81 | + margin-bottom: 0 !important; | ||
| 82 | + overflow-x: auto; | ||
| 83 | + } | ||
| 84 | + >>> .el-scrollbar__bar.is-horizontal > div { | ||
| 85 | + display: none; | ||
| 86 | + } | ||
| 87 | + >>> .el-card { | ||
| 88 | + width: 100%; | ||
| 89 | + height: 100%; | ||
| 90 | + .el-card__body { | ||
| 91 | + padding: 0; | ||
| 92 | + } | ||
| 93 | + } | ||
| 94 | + .vue-grid-item { | ||
| 95 | + position: relative; | ||
| 96 | + .mask { | ||
| 97 | + position: absolute; | ||
| 98 | + top: 0; | ||
| 99 | + left: 0; | ||
| 100 | + width: 100%; | ||
| 101 | + height: 100%; | ||
| 102 | + z-index: 1; | ||
| 103 | + } | ||
| 104 | + } | ||
| 105 | +} | ||
| 106 | +</style> | ||
| 0 | \ No newline at end of file | 107 | \ No newline at end of file |
src/components/VisualPortal/Todo/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-card shadow="never" class="todo-box"> | ||
| 3 | + <div slot="header" class="portal-common-title"> | ||
| 4 | + <span>{{title}}</span> | ||
| 5 | + </div> | ||
| 6 | + <div class="todo-box-body"> | ||
| 7 | + <router-link class="item" to="/workFlow/flowTodo"> | ||
| 8 | + <i class="icon-ym icon-ym-flowTodo"></i> | ||
| 9 | + <div class="text"> | ||
| 10 | + <p class="num">{{toBeReviewed}}</p> | ||
| 11 | + <p class="name">待我审核</p> | ||
| 12 | + </div> | ||
| 13 | + </router-link> | ||
| 14 | + <router-link class="item" to="/workFlow/entrust"> | ||
| 15 | + <i class="icon-ym icon-ym-flowEntrust"></i> | ||
| 16 | + <div class="text"> | ||
| 17 | + <p class="num">{{entrust}}</p> | ||
| 18 | + <p class="name">流程委托</p> | ||
| 19 | + </div> | ||
| 20 | + </router-link> | ||
| 21 | + <router-link class="item" to="/workFlow/flowDone"> | ||
| 22 | + <i class="icon-ym icon-ym-flowDone"></i> | ||
| 23 | + <div class="text"> | ||
| 24 | + <p class="num">{{flowDone}}</p> | ||
| 25 | + <p class="name">已办事宜</p> | ||
| 26 | + </div> | ||
| 27 | + </router-link> | ||
| 28 | + </div> | ||
| 29 | + </el-card> | ||
| 30 | +</template> | ||
| 31 | +<script> | ||
| 32 | +import { getFlowTodoCount } from '@/api/home' | ||
| 33 | +export default { | ||
| 34 | + props: { | ||
| 35 | + title: { type: String, default: '' } | ||
| 36 | + }, | ||
| 37 | + data() { | ||
| 38 | + return { | ||
| 39 | + entrust: 0, | ||
| 40 | + flowDone: 0, | ||
| 41 | + toBeReviewed: 0 | ||
| 42 | + } | ||
| 43 | + }, | ||
| 44 | + created() { | ||
| 45 | + this.getData() | ||
| 46 | + }, | ||
| 47 | + methods: { | ||
| 48 | + getData() { | ||
| 49 | + getFlowTodoCount().then(res => { | ||
| 50 | + this.entrust = res.data.entrust || 0 | ||
| 51 | + this.flowDone = res.data.flowDone || 0 | ||
| 52 | + this.toBeReviewed = res.data.toBeReviewed || 0 | ||
| 53 | + }) | ||
| 54 | + } | ||
| 55 | + } | ||
| 56 | +} | ||
| 57 | +</script> | ||
| 58 | +<style lang="scss" scoped> | ||
| 59 | +.todo-box { | ||
| 60 | + >>> .el-card__body { | ||
| 61 | + width: 100%; | ||
| 62 | + height: calc(100% - 55px); | ||
| 63 | + } | ||
| 64 | + .todo-box-body { | ||
| 65 | + padding: 0 30px; | ||
| 66 | + height: 100%; | ||
| 67 | + display: flex; | ||
| 68 | + justify-content: space-between; | ||
| 69 | + align-items: center; | ||
| 70 | + .item { | ||
| 71 | + height: 56px; | ||
| 72 | + display: block; | ||
| 73 | + i { | ||
| 74 | + width: 56px; | ||
| 75 | + height: 56px; | ||
| 76 | + margin-right: 14px; | ||
| 77 | + border-radius: 50%; | ||
| 78 | + color: #fff; | ||
| 79 | + display: inline-block; | ||
| 80 | + vertical-align: top; | ||
| 81 | + text-align: center; | ||
| 82 | + line-height: 56px; | ||
| 83 | + font-size: 30px; | ||
| 84 | + &.icon-ym-flowTodo { | ||
| 85 | + background: #f68900; | ||
| 86 | + } | ||
| 87 | + &.icon-ym-flowEntrust { | ||
| 88 | + background: #1890ff; | ||
| 89 | + } | ||
| 90 | + &.icon-ym-flowDone { | ||
| 91 | + background: #7b1ae1; | ||
| 92 | + } | ||
| 93 | + } | ||
| 94 | + .text { | ||
| 95 | + display: inline-block; | ||
| 96 | + height: 56px; | ||
| 97 | + .num { | ||
| 98 | + font-size: 20px; | ||
| 99 | + line-height: 36px; | ||
| 100 | + } | ||
| 101 | + .name { | ||
| 102 | + font-size: 14px; | ||
| 103 | + color: #666; | ||
| 104 | + } | ||
| 105 | + } | ||
| 106 | + } | ||
| 107 | + } | ||
| 108 | +} | ||
| 109 | +</style> | ||
| 0 | \ No newline at end of file | 110 | \ No newline at end of file |
src/components/VisualPortal/TodoList/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-card shadow="never" class="portal-todoList-box"> | ||
| 3 | + <div slot="header" class="portal-common-title"> | ||
| 4 | + <span>{{title}}</span> | ||
| 5 | + </div> | ||
| 6 | + <div class="portal-todoList-box-body"> | ||
| 7 | + <template v-if="list.length"> | ||
| 8 | + <router-link class="item" to="/workFlow/flowTodo" v-for="(item, i) in list" :key="i"> | ||
| 9 | + <span class="name">{{item.fullName}}</span> | ||
| 10 | + <span class="time">{{item.creatorTime | toDate('yyyy-MM-dd')}}</span> | ||
| 11 | + </router-link> | ||
| 12 | + </template> | ||
| 13 | + <div class="portal-common-noData" v-else> | ||
| 14 | + <img src="@/assets/images/portal-nodata.png" alt="" class="noData-img"> | ||
| 15 | + <p class="noData-txt">暂无数据</p> | ||
| 16 | + </div> | ||
| 17 | + </div> | ||
| 18 | + </el-card> | ||
| 19 | +</template> | ||
| 20 | +<script> | ||
| 21 | +import { getFlowTodo } from '@/api/home' | ||
| 22 | +export default { | ||
| 23 | + props: { | ||
| 24 | + title: { type: String, default: '' } | ||
| 25 | + }, | ||
| 26 | + data() { | ||
| 27 | + return { | ||
| 28 | + list: [] | ||
| 29 | + } | ||
| 30 | + }, | ||
| 31 | + created() { | ||
| 32 | + this.getData() | ||
| 33 | + }, | ||
| 34 | + methods: { | ||
| 35 | + getData() { | ||
| 36 | + getFlowTodo().then(res => { | ||
| 37 | + this.list = res.data.list.slice(0, 7) | ||
| 38 | + }) | ||
| 39 | + } | ||
| 40 | + } | ||
| 41 | +} | ||
| 42 | +</script> | ||
| 0 | \ No newline at end of file | 43 | \ No newline at end of file |
src/components/VisualPortal/index.js
0 → 100644
| 1 | +// 门户设计专供 | ||
| 2 | +export { default as Todo } from '@/components/VisualPortal/Todo' | ||
| 3 | +export { default as CommonFunc } from '@/components/VisualPortal/CommonFunc' | ||
| 4 | +export { default as TodoList } from '@/components/VisualPortal/TodoList' | ||
| 5 | +export { default as HNotice } from '@/components/VisualPortal/HNotice' | ||
| 6 | +export { default as HEmail } from '@/components/VisualPortal/HEmail' | ||
| 7 | +export { default as DataBoard } from '@/components/VisualPortal/DataBoard' | ||
| 8 | +export { default as HBarChart } from '@/components/VisualPortal/HBarChart' | ||
| 9 | +export { default as HAnnularChart } from '@/components/VisualPortal/HAnnularChart' | ||
| 10 | +export { default as HAreaChart } from '@/components/VisualPortal/HAreaChart' | ||
| 11 | +export { default as HLineChart } from '@/components/VisualPortal/HLineChart' | ||
| 12 | +export { default as HPieChart } from '@/components/VisualPortal/HPieChart' | ||
| 13 | +export { default as HRadarChart } from '@/components/VisualPortal/HRadarChart' | ||
| 0 | \ No newline at end of file | 14 | \ No newline at end of file |
src/components/VisualPortal/mixins/index.js
0 → 100644
| 1 | +import echarts from 'echarts' | ||
| 2 | +import resize from '@/components/Charts/mixins/resize' | ||
| 3 | +import { previewDataInterface } from '@/api/systemData/dataInterface' | ||
| 4 | + | ||
| 5 | +export default { | ||
| 6 | + mixins: [resize], | ||
| 7 | + props: { | ||
| 8 | + title: { type: String, default: '' }, | ||
| 9 | + dataType: { type: String, default: 'static' }, | ||
| 10 | + propsApi: { type: String, default: '' }, | ||
| 11 | + option: { type: Object, default: () => {} } | ||
| 12 | + }, | ||
| 13 | + data() { | ||
| 14 | + return { | ||
| 15 | + chart: null, | ||
| 16 | + currOption: {}, | ||
| 17 | + isEmpty: false | ||
| 18 | + } | ||
| 19 | + }, | ||
| 20 | + mounted() { | ||
| 21 | + if (this.dataType === 'dynamic') { | ||
| 22 | + if (!this.propsApi) return | ||
| 23 | + previewDataInterface(this.propsApi).then(res => { | ||
| 24 | + this.currOption = res.data | ||
| 25 | + this.resetChart() | ||
| 26 | + }) | ||
| 27 | + } else { | ||
| 28 | + this.currOption = this.option | ||
| 29 | + this.initChart() | ||
| 30 | + } | ||
| 31 | + }, | ||
| 32 | + watch: { | ||
| 33 | + option: { | ||
| 34 | + handler(val) { | ||
| 35 | + this.currOption = val | ||
| 36 | + this.resetChart() | ||
| 37 | + }, | ||
| 38 | + deep: true | ||
| 39 | + }, | ||
| 40 | + dataType(val) { | ||
| 41 | + if (val !== 'dynamic') { | ||
| 42 | + this.currOption = this.option | ||
| 43 | + this.resetChart() | ||
| 44 | + } | ||
| 45 | + }, | ||
| 46 | + propsApi(val) { | ||
| 47 | + if (this.dataType === 'static') return | ||
| 48 | + if (!val) return | ||
| 49 | + previewDataInterface(val).then(res => { | ||
| 50 | + this.currOption = res.data | ||
| 51 | + this.resetChart() | ||
| 52 | + }) | ||
| 53 | + } | ||
| 54 | + }, | ||
| 55 | + methods: { | ||
| 56 | + initChart() { | ||
| 57 | + this.chart = echarts.init(this.$refs.chart) | ||
| 58 | + this.chart.setOption(this.currOption) | ||
| 59 | + setTimeout(() => { | ||
| 60 | + this.$nextTick(() => { | ||
| 61 | + this.chart.resize(); | ||
| 62 | + }) | ||
| 63 | + }, 50); | ||
| 64 | + }, | ||
| 65 | + resetChart() { | ||
| 66 | + this.isEmpty = JSON.stringify(this.currOption) === "{}" | ||
| 67 | + this.chart && this.chart.dispose() | ||
| 68 | + this.chart = null | ||
| 69 | + if (!this.isEmpty) this.initChart() | ||
| 70 | + } | ||
| 71 | + }, | ||
| 72 | + beforeDestroy() { | ||
| 73 | + if (!this.chart) return | ||
| 74 | + this.chart.dispose() | ||
| 75 | + this.chart = null | ||
| 76 | + } | ||
| 77 | +} | ||
| 0 | \ No newline at end of file | 78 | \ No newline at end of file |
src/components/index.js
| @@ -12,6 +12,28 @@ import Screenfull from '@/components/Screenfull' | @@ -12,6 +12,28 @@ import Screenfull from '@/components/Screenfull' | ||
| 12 | import NCCTreeSelect from '@/components/NCC-treeSelect' | 12 | import NCCTreeSelect from '@/components/NCC-treeSelect' |
| 13 | import NCCAddress from '@/components/Generator/components/Address' | 13 | import NCCAddress from '@/components/Generator/components/Address' |
| 14 | import SelsctLoad from '@/components/SelsctLoad' | 14 | import SelsctLoad from '@/components/SelsctLoad' |
| 15 | +import topOperation from '@/components/NCC-topOperation/index' | ||
| 16 | +import tableOperation from '@/components/NCC-tableOperation' | ||
| 17 | +import UserBox from '@/components/NCC-userBox' | ||
| 18 | +import ColumnSettings from '@/components/ColumnSettings' | ||
| 19 | +import UserSelect from '@/components/NCC-userSelect' | ||
| 20 | +import uploadBtn from '@/components/NCC-uploadBtn' | ||
| 21 | +// 代码生成器专供 | ||
| 22 | +import NCCText from '@/components/Generator/components/NCCText' | ||
| 23 | +import NCCUploadImg from '@/components/Generator/components/Upload/UploadImg' | ||
| 24 | +import PopupSelect from '@/components/Generator/components/PopupSelect' | ||
| 25 | +import NumRange from '@/components/Generator/components/NumRange' | ||
| 26 | +import ComSelect from '@/components/Generator/components/ComSelect' | ||
| 27 | +import PosSelect from '@/components/Generator/components/PosSelect' | ||
| 28 | +import DicSelect from '@/components/Generator/components/DicSelect' | ||
| 29 | +import BillRule from '@/components/Generator/components/BillRule' | ||
| 30 | +import NCCInputTable from '@/components/Generator/components/InputTable' | ||
| 31 | +import GroupTitle from '@/components/Generator/components/GroupTitle' | ||
| 32 | +import RelationForm from '@/components/Generator/components/RelationForm' | ||
| 33 | +import RelationFormAttr from '@/components/Generator/components/RelationFormAttr' | ||
| 34 | +import RelationFlow from '@/components/Generator/components/RelationFlow' | ||
| 35 | +import RelationFlowAttr from '@/components/Generator/components/RelationFlowAttr' | ||
| 36 | +import Calculate from '@/components/Generator/components/Calculate' | ||
| 15 | 37 | ||
| 16 | export default { | 38 | export default { |
| 17 | install(Vue, options) { | 39 | install(Vue, options) { |
| @@ -22,13 +44,34 @@ export default { | @@ -22,13 +44,34 @@ export default { | ||
| 22 | Vue.component('InfoEditRecord', InfoEditRecord) | 44 | Vue.component('InfoEditRecord', InfoEditRecord) |
| 23 | Vue.component('Pagination', Pagination) | 45 | Vue.component('Pagination', Pagination) |
| 24 | Vue.component('NCCTable', NCCTable) | 46 | Vue.component('NCCTable', NCCTable) |
| 47 | + Vue.component('SelsctLoad', SelsctLoad) | ||
| 48 | + Vue.component('NCCTreeSelect', NCCTreeSelect) | ||
| 49 | + Vue.component('topOpts', topOperation) | ||
| 50 | + Vue.component('tableOpts', tableOperation) | ||
| 51 | + Vue.component('uploadBtn', uploadBtn) | ||
| 52 | + Vue.component('UserBox', UserBox) | ||
| 53 | + Vue.component('NCCText', NCCText) | ||
| 25 | Vue.component('NCCUploadFz', NCCUploadFz) | 54 | Vue.component('NCCUploadFz', NCCUploadFz) |
| 26 | - Vue.component('NCCQuill', NCCQuill) | 55 | + Vue.component('NCCUploadImg', NCCUploadImg) |
| 56 | + Vue.component('PopupSelect', PopupSelect) | ||
| 57 | + Vue.component('NumRange', NumRange) | ||
| 58 | + Vue.component('ComSelect', ComSelect) | ||
| 27 | Vue.component('DepSelect', DepSelect) | 59 | Vue.component('DepSelect', DepSelect) |
| 28 | - Vue.component('NCCTreeSelect', NCCTreeSelect) | ||
| 29 | - Vue.component('Screenfull', Screenfull) | 60 | + Vue.component('PosSelect', PosSelect) |
| 61 | + Vue.component('UserSelect', UserSelect) | ||
| 62 | + Vue.component('DicSelect', DicSelect) | ||
| 63 | + Vue.component('BillRule', BillRule) | ||
| 64 | + Vue.component('NCCInputTable', NCCInputTable) | ||
| 30 | Vue.component('NCCAddress', NCCAddress) | 65 | Vue.component('NCCAddress', NCCAddress) |
| 31 | - Vue.component('SelsctLoad', SelsctLoad) | 66 | + Vue.component('GroupTitle', GroupTitle) |
| 67 | + Vue.component('RelationForm', RelationForm) | ||
| 68 | + Vue.component('RelationFormAttr', RelationFormAttr) | ||
| 69 | + Vue.component('RelationFlow', RelationFlow) | ||
| 70 | + Vue.component('RelationFlowAttr', RelationFlowAttr) | ||
| 71 | + Vue.component('Calculate', Calculate) | ||
| 72 | + Vue.component('NCCQuill', NCCQuill) | ||
| 73 | + Vue.component('Screenfull', Screenfull) | ||
| 74 | + Vue.component('ColumnSettings', ColumnSettings) | ||
| 32 | 75 | ||
| 33 | } | 76 | } |
| 34 | } | 77 | } |
| 35 | \ No newline at end of file | 78 | \ No newline at end of file |
src/views/baseSpecialAction/dynamicModel/list/Form.vue
| @@ -51,6 +51,7 @@ import Parser from '@/components/Generator/parser/Parser' | @@ -51,6 +51,7 @@ import Parser from '@/components/Generator/parser/Parser' | ||
| 51 | import ParserMixin from '@/components/Generator/parser/mixin' | 51 | import ParserMixin from '@/components/Generator/parser/mixin' |
| 52 | import PrintBrowse from '@/components/PrintBrowse' | 52 | import PrintBrowse from '@/components/PrintBrowse' |
| 53 | import { deepClone } from '@/utils' | 53 | import { deepClone } from '@/utils' |
| 54 | +import request from "@/utils/request"; | ||
| 54 | export default { | 55 | export default { |
| 55 | components: { Parser, PrintBrowse }, | 56 | components: { Parser, PrintBrowse }, |
| 56 | mixins: [ParserMixin], | 57 | mixins: [ParserMixin], |
| @@ -69,6 +70,7 @@ export default { | @@ -69,6 +70,7 @@ export default { | ||
| 69 | useFormPermission: false, | 70 | useFormPermission: false, |
| 70 | printBrowseVisible: false, | 71 | printBrowseVisible: false, |
| 71 | formOperates: [], | 72 | formOperates: [], |
| 73 | + taskId: '', | ||
| 72 | } | 74 | } |
| 73 | }, | 75 | }, |
| 74 | methods: { | 76 | methods: { |
| @@ -79,12 +81,13 @@ export default { | @@ -79,12 +81,13 @@ export default { | ||
| 79 | if (this.isPreview) return this.$message({ message: '功能预览不支持打印', type: 'warning' }) | 81 | if (this.isPreview) return this.$message({ message: '功能预览不支持打印', type: 'warning' }) |
| 80 | this.printBrowseVisible = true | 82 | this.printBrowseVisible = true |
| 81 | }, | 83 | }, |
| 82 | - init(formConf, modelId, id, isPreview, useFormPermission) { | 84 | + init(formConf, modelId, id, isPreview, useFormPermission, taskId) { |
| 83 | this.formConf = deepClone(JSON.parse(formConf)) | 85 | this.formConf = deepClone(JSON.parse(formConf)) |
| 84 | this.modelId = modelId | 86 | this.modelId = modelId |
| 85 | this.isPreview = isPreview | 87 | this.isPreview = isPreview |
| 86 | this.useFormPermission = useFormPermission | 88 | this.useFormPermission = useFormPermission |
| 87 | this.dataForm.id = id || '' | 89 | this.dataForm.id = id || '' |
| 90 | + this.taskId = taskId | ||
| 88 | this.getFormOperates() | 91 | this.getFormOperates() |
| 89 | this.loading = true | 92 | this.loading = true |
| 90 | this.$nextTick(() => { | 93 | this.$nextTick(() => { |
| @@ -150,20 +153,33 @@ export default { | @@ -150,20 +153,33 @@ export default { | ||
| 150 | const formMethod = this.dataForm.id ? updateModel : createModel | 153 | const formMethod = this.dataForm.id ? updateModel : createModel |
| 151 | formMethod(this.modelId, this.dataForm).then(res => { | 154 | formMethod(this.modelId, this.dataForm).then(res => { |
| 152 | console.info(res); | 155 | console.info(res); |
| 153 | - alert(res.data.Id); | 156 | + let itemId = !this.dataForm.id ? res.data.Id : ''; |
| 154 | this.$message({ | 157 | this.$message({ |
| 155 | message: res.msg, | 158 | message: res.msg, |
| 156 | type: 'success', | 159 | type: 'success', |
| 157 | duration: 1500, | 160 | duration: 1500, |
| 158 | - onClose: () => { | 161 | + onClose: async () => { |
| 159 | if (callback && typeof callback === "function") callback() | 162 | if (callback && typeof callback === "function") callback() |
| 160 | this.visible = false | 163 | this.visible = false |
| 161 | this.btnLoading = false | 164 | this.btnLoading = false |
| 165 | + !this.dataForm.id && this.toSaveItemid(itemId) | ||
| 162 | this.$emit('refreshDataList', true) | 166 | this.$emit('refreshDataList', true) |
| 163 | } | 167 | } |
| 164 | }) | 168 | }) |
| 165 | }).catch(() => { this.btnLoading = false }) | 169 | }).catch(() => { this.btnLoading = false }) |
| 166 | }, | 170 | }, |
| 171 | + async toSaveItemid(itemId) { | ||
| 172 | + console.log(11); | ||
| 173 | + let res = await request({ | ||
| 174 | + url: '/Extend/BaseSpecialActionInfo/UpdateState', | ||
| 175 | + method: "PUT", | ||
| 176 | + data: { | ||
| 177 | + id: this.taskId, | ||
| 178 | + itemId | ||
| 179 | + }, | ||
| 180 | + }) | ||
| 181 | + return res | ||
| 182 | + }, | ||
| 167 | dataFormSubmit() { | 183 | dataFormSubmit() { |
| 168 | if (this.isPreview) return this.$message({ message: '功能预览不支持数据保存', type: 'warning' }) | 184 | if (this.isPreview) return this.$message({ message: '功能预览不支持数据保存', type: 'warning' }) |
| 169 | this.$refs.dynamicForm && this.$refs.dynamicForm.submitForm() | 185 | this.$refs.dynamicForm && this.$refs.dynamicForm.submitForm() |
src/views/baseSpecialAction/index.vue
| @@ -49,10 +49,10 @@ | @@ -49,10 +49,10 @@ | ||
| 49 | </el-table-column> | 49 | </el-table-column> |
| 50 | <el-table-column prop="deadline" label="截止日期" align="left" :formatter="ncc.tableDateFormat" show-overflow-tooltip/> | 50 | <el-table-column prop="deadline" label="截止日期" align="left" :formatter="ncc.tableDateFormat" show-overflow-tooltip/> |
| 51 | <el-table-column prop="creatorUserId" show-overflow-tooltip label="创建用户" align="left"/> | 51 | <el-table-column prop="creatorUserId" show-overflow-tooltip label="创建用户" align="left"/> |
| 52 | - <el-table-column label="操作" fixed="right" width="130"> | 52 | + <el-table-column label="操作" fixed="right" width="100"> |
| 53 | <template slot-scope="scope"> | 53 | <template slot-scope="scope"> |
| 54 | - <el-button type="text" @click="addOrUpdateHandle(scope.row.id)">发布任务</el-button> | ||
| 55 | - <el-button type="text" @click="toDetail(scope.row)" v-if="scope.row.state == '已发布'">行动情况</el-button> | 54 | + <el-button type="text" @click="addOrUpdateHandle(scope.row.id)" v-if="scope.row.state == '未发布'">发布任务</el-button> |
| 55 | + <el-button type="text" @click="toDetail(scope.row)" v-else>处理情况</el-button> | ||
| 56 | </template> | 56 | </template> |
| 57 | </el-table-column> | 57 | </el-table-column> |
| 58 | </NCC-table> | 58 | </NCC-table> |
src/views/baseSpecialhandle/index.vue
| @@ -39,7 +39,8 @@ | @@ -39,7 +39,8 @@ | ||
| 39 | show-overflow-tooltip /> | 39 | show-overflow-tooltip /> |
| 40 | <el-table-column label="操作" fixed="right" width="130"> | 40 | <el-table-column label="操作" fixed="right" width="130"> |
| 41 | <template slot-scope="scope"> | 41 | <template slot-scope="scope"> |
| 42 | - <el-button type="text" @click="toFillForm(scope.row)">处理</el-button> | 42 | + <el-button type="text" @click="toFillForm(scope.row)">{{scope.row.state == '已填写' ? '修改' : '处理'}}</el-button> |
| 43 | + <!-- <el-button type="text" @click="toFillForm(scope.row)" v-if="scope.row.state == '已填写'">详情</el-button> --> | ||
| 43 | </template> | 44 | </template> |
| 44 | </el-table-column> | 45 | </el-table-column> |
| 45 | </NCC-table> | 46 | </NCC-table> |
| @@ -49,7 +50,7 @@ | @@ -49,7 +50,7 @@ | ||
| 49 | </div> | 50 | </div> |
| 50 | </div> | 51 | </div> |
| 51 | </div> | 52 | </div> |
| 52 | - <NCCForm v-if="dialogVisible" ref="NCCForm" @refresh="refresh" /> | 53 | + <NCCForm v-if="dialogVisible" ref="NCCForm" @refreshDataList="refresh" /> |
| 53 | <!-- <el-dialog title="专项行动处理" :visible.sync="dialogVisible" fullscreen :modal="false"> | 54 | <!-- <el-dialog title="专项行动处理" :visible.sync="dialogVisible" fullscreen :modal="false"> |
| 54 | <iframe | 55 | <iframe |
| 55 | :src="nestedPageUrl" | 56 | :src="nestedPageUrl" |
| @@ -86,6 +87,7 @@ export default { | @@ -86,6 +87,7 @@ export default { | ||
| 86 | dialogVisible: false, | 87 | dialogVisible: false, |
| 87 | nestedPageUrl: '', | 88 | nestedPageUrl: '', |
| 88 | viewportHeight: 0, | 89 | viewportHeight: 0, |
| 90 | + taskId: '', | ||
| 89 | }; | 91 | }; |
| 90 | }, | 92 | }, |
| 91 | created() { | 93 | created() { |
| @@ -135,9 +137,9 @@ export default { | @@ -135,9 +137,9 @@ export default { | ||
| 135 | }, | 137 | }, |
| 136 | toFillForm(row) { | 138 | toFillForm(row) { |
| 137 | this.dialogVisible = true; | 139 | this.dialogVisible = true; |
| 138 | - var Itemid= "588014226493146373";//数据id,没有的话就是新增 ,有的话就是修改 | ||
| 139 | - Itemid=""; | ||
| 140 | - var modelId=row.formId;//关联的表单id | 140 | + var Itemid = row.itemId || '';//数据id,没有的话就是新增 ,有的话就是修改 |
| 141 | + var modelId = row.formId;//关联的表单id | ||
| 142 | + var taskId = row.id; // 当前专项行动id | ||
| 141 | var isPreview = false;//固定死,值不变 | 143 | var isPreview = false;//固定死,值不变 |
| 142 | var useFormPermission = false;//固定死,值不变 | 144 | var useFormPermission = false;//固定死,值不变 |
| 143 | var formData = []; | 145 | var formData = []; |
| @@ -147,7 +149,8 @@ export default { | @@ -147,7 +149,8 @@ export default { | ||
| 147 | params:null | 149 | params:null |
| 148 | }).then(res => { | 150 | }).then(res => { |
| 149 | formData = res.data.formData; | 151 | formData = res.data.formData; |
| 150 | - this.$refs.NCCForm.init(formData, modelId, Itemid, isPreview, useFormPermission) | 152 | + console.log(res, formData, modelId, Itemid, isPreview, useFormPermission); |
| 153 | + this.$refs.NCCForm.init(formData, modelId, Itemid, isPreview, useFormPermission, taskId) | ||
| 151 | }); | 154 | }); |
| 152 | 155 | ||
| 153 | // this.nestedPageUrl = `http://8.130.38.56:8043/old/#/previewModel?isPreview=1&id=${row.originId}`; | 156 | // this.nestedPageUrl = `http://8.130.38.56:8043/old/#/previewModel?isPreview=1&id=${row.originId}`; |
| @@ -195,6 +198,7 @@ export default { | @@ -195,6 +198,7 @@ export default { | ||
| 195 | this.formVisible = false; | 198 | this.formVisible = false; |
| 196 | if (isrRefresh) this.reset(); | 199 | if (isrRefresh) this.reset(); |
| 197 | }, | 200 | }, |
| 201 | + | ||
| 198 | reset() { | 202 | reset() { |
| 199 | for (let key in this.query) { | 203 | for (let key in this.query) { |
| 200 | this.query[key] = undefined; | 204 | this.query[key] = undefined; |
src/views/overView/Overview.vue
| @@ -3,10 +3,18 @@ | @@ -3,10 +3,18 @@ | ||
| 3 | <el-row :gutter="20"> | 3 | <el-row :gutter="20"> |
| 4 | <el-col :span="16"> | 4 | <el-col :span="16"> |
| 5 | <div class="item-box todo"> | 5 | <div class="item-box todo"> |
| 6 | - <div class="item-title">事件中心</div> | 6 | + <div class="item-title"> |
| 7 | + <div class="left">任务中心</div> | ||
| 8 | + <div class="right"> | ||
| 9 | + <!-- <el-button type="success" size="mini" style="margin-right: 10px;" v-if="isSHILevel" @click="announceMsg">发布</el-button> --> | ||
| 10 | + <el-tooltip effect="dark" content="刷新" placement="top"> | ||
| 11 | + <el-link icon="icon-ym icon-ym-Refresh NCC-common-head-icon" :underline="false" @click="resetTask"/> | ||
| 12 | + </el-tooltip> | ||
| 13 | + </div> | ||
| 14 | + </div> | ||
| 7 | <div class="item-body"> | 15 | <div class="item-body"> |
| 8 | <template> | 16 | <template> |
| 9 | - <el-table :data="todoTableData" style="width: 100%" stripe> | 17 | + <el-table :data="taskList" style="width: 100%" stripe v-loading="taskLoading"> |
| 10 | <el-table-column type="index" width="50"> </el-table-column> | 18 | <el-table-column type="index" width="50"> </el-table-column> |
| 11 | <el-table-column | 19 | <el-table-column |
| 12 | prop="teskName" | 20 | prop="teskName" |
| @@ -44,6 +52,7 @@ | @@ -44,6 +52,7 @@ | ||
| 44 | </template> | 52 | </template> |
| 45 | </el-table-column> | 53 | </el-table-column> |
| 46 | </el-table> | 54 | </el-table> |
| 55 | + <pagination :total="taskTotal" :page.sync="taskListQuery.currentPage" :limit.sync="taskListQuery.pageSize" @pagination="getAllTaskList" /> | ||
| 47 | </template> | 56 | </template> |
| 48 | </div> | 57 | </div> |
| 49 | </div> | 58 | </div> |
| @@ -111,60 +120,74 @@ | @@ -111,60 +120,74 @@ | ||
| 111 | <div class="item-box msg"> | 120 | <div class="item-box msg"> |
| 112 | <div class="item-title"> | 121 | <div class="item-title"> |
| 113 | <div class="left">通知公告</div> | 122 | <div class="left">通知公告</div> |
| 114 | - <el-tooltip effect="dark" content="刷新" placement="top"> | ||
| 115 | - <el-link | ||
| 116 | - icon="icon-ym icon-ym-Refresh NCC-common-head-icon" | ||
| 117 | - :underline="false" | ||
| 118 | - @click="resetMsg()" | ||
| 119 | - /> | ||
| 120 | - </el-tooltip> | 123 | + <div class="right"> |
| 124 | + <el-button type="success" size="mini" style="margin-right: 10px;" v-if="isSHILevel" @click="announceMsg">发布</el-button> | ||
| 125 | + <el-tooltip effect="dark" content="刷新" placement="top"> | ||
| 126 | + <el-link icon="icon-ym icon-ym-Refresh NCC-common-head-icon" :underline="false" @click="resetMsg"/> | ||
| 127 | + </el-tooltip> | ||
| 128 | + </div> | ||
| 121 | </div> | 129 | </div> |
| 122 | <div class="item-body"> | 130 | <div class="item-body"> |
| 123 | <template> | 131 | <template> |
| 124 | - <el-table :data="msgList" style="width: 100%" stripe> | ||
| 125 | - <el-table-column | ||
| 126 | - prop="teskName" | ||
| 127 | - label="内容" | ||
| 128 | - show-overflow-tooltip | ||
| 129 | - > | 132 | + <el-table :data="msgList" style="width: 100%" stripe v-loading="msgLoading"> |
| 133 | + <el-table-column prop="title" label="标题" show-overflow-tooltip> | ||
| 130 | </el-table-column> | 134 | </el-table-column> |
| 131 | - <el-table-column | ||
| 132 | - prop="teskCode" | ||
| 133 | - label="事件" | ||
| 134 | - show-overflow-tooltip | ||
| 135 | - > | 135 | + <el-table-column label="操作" fixed="right" width="80"> |
| 136 | + <template slot-scope="scope"> | ||
| 137 | + <el-button type="text" @click="checkDetail(scope.row)">详情</el-button> | ||
| 138 | + </template> | ||
| 136 | </el-table-column> | 139 | </el-table-column> |
| 137 | </el-table> | 140 | </el-table> |
| 141 | + <pagination :total="msgTotal" :page.sync="msgListQuery.currentPage" :limit.sync="msgListQuery.pageSize" @pagination="getAllMsgList" /> | ||
| 138 | </template> | 142 | </template> |
| 139 | </div> | 143 | </div> |
| 140 | </div> | 144 | </div> |
| 141 | </el-col> | 145 | </el-col> |
| 142 | </el-row> | 146 | </el-row> |
| 147 | + <MsgForm v-if="MsgFormVisible" ref="MsgForm" @refreshDataList="msgRefresh"/> | ||
| 143 | </div> | 148 | </div> |
| 144 | </template> | 149 | </template> |
| 145 | 150 | ||
| 146 | <script> | 151 | <script> |
| 147 | -import { | ||
| 148 | - todoObj, | ||
| 149 | - tipObj, | ||
| 150 | - areaObj, | ||
| 151 | - chObj, | ||
| 152 | -} from "@/assets/mockdata/demodata.json"; | ||
| 153 | -import { computed } from "vue"; | 152 | +import request from "@/utils/request"; |
| 153 | +import MsgForm from "./msgForm.vue" | ||
| 154 | export default { | 154 | export default { |
| 155 | name: "Overview", | 155 | name: "Overview", |
| 156 | + components: { MsgForm }, | ||
| 156 | data() { | 157 | data() { |
| 157 | return { | 158 | return { |
| 158 | todoTableData: [], | 159 | todoTableData: [], |
| 159 | - msgList: [], | ||
| 160 | tipTableData: [], | 160 | tipTableData: [], |
| 161 | aimList: [], | 161 | aimList: [], |
| 162 | + | ||
| 163 | + msgLoading: false, | ||
| 164 | + msgListQuery: { | ||
| 165 | + currentPage: 1, | ||
| 166 | + pageSize: 20, | ||
| 167 | + }, | ||
| 168 | + msgQuery: { | ||
| 169 | + keyword: '' | ||
| 170 | + }, | ||
| 171 | + msgList: [], | ||
| 172 | + msgTotal: 0, | ||
| 173 | + MsgFormVisible: false, | ||
| 174 | + | ||
| 175 | + taskLoading: false, | ||
| 176 | + taskListQuery: { | ||
| 177 | + currentPage: 1, | ||
| 178 | + pageSize: 20, | ||
| 179 | + }, | ||
| 180 | + taskQuery: { | ||
| 181 | + keyword: '' | ||
| 182 | + }, | ||
| 183 | + taskList: [], | ||
| 184 | + taskTotal: 0, | ||
| 185 | + TaskFormVisible: false | ||
| 162 | }; | 186 | }; |
| 163 | }, | 187 | }, |
| 164 | created() { | 188 | created() { |
| 165 | - this.getMsgList(); | ||
| 166 | - this.getTipList(); | ||
| 167 | - this.getAimList(); | 189 | + this.getAllMsgList(); |
| 190 | + this.getAllTaskList(); | ||
| 168 | }, | 191 | }, |
| 169 | computed: { | 192 | computed: { |
| 170 | isSHILevel() { | 193 | isSHILevel() { |
| @@ -173,29 +196,90 @@ export default { | @@ -173,29 +196,90 @@ export default { | ||
| 173 | }, | 196 | }, |
| 174 | }, | 197 | }, |
| 175 | methods: { | 198 | methods: { |
| 176 | - getMsgList() { | ||
| 177 | - for (let index = 0; index < 10; index++) { | ||
| 178 | - this.msgList.push(todoObj); | ||
| 179 | - this.todoTableData.push(todoObj); | 199 | + // 通知公告 |
| 200 | + getAllMsgList() { | ||
| 201 | + this.msgLoading = true; | ||
| 202 | + let _query = { | ||
| 203 | + ...this.msgListQuery, | ||
| 204 | + ...this.msgQuery, | ||
| 205 | + }; | ||
| 206 | + let query = {}; | ||
| 207 | + for (let key in _query) { | ||
| 208 | + if (Array.isArray(_query[key])) { | ||
| 209 | + query[key] = _query[key].join(); | ||
| 210 | + } else { | ||
| 211 | + query[key] = _query[key]; | ||
| 212 | + } | ||
| 180 | } | 213 | } |
| 214 | + request({ | ||
| 215 | + url: '/SubDev/ZyOaArticle', | ||
| 216 | + method: "GET", | ||
| 217 | + params: query, | ||
| 218 | + }).then((res) => { | ||
| 219 | + this.msgList = res.data.list; | ||
| 220 | + this.msgTotal = res.data.pagination.total; | ||
| 221 | + this.msgLoading = false; | ||
| 222 | + }); | ||
| 181 | }, | 223 | }, |
| 182 | resetMsg() { | 224 | resetMsg() { |
| 183 | this.msgList = []; | 225 | this.msgList = []; |
| 184 | - this.getMsgList(); | 226 | + this.msgListQuery = { |
| 227 | + currentPage: 1, | ||
| 228 | + pageSize: 20, | ||
| 229 | + }; | ||
| 230 | + this.getAllMsgList(); | ||
| 185 | }, | 231 | }, |
| 186 | - getTipList() { | ||
| 187 | - for (let index = 0; index < 10; index++) { | ||
| 188 | - this.tipTableData.push(tipObj); | ||
| 189 | - } | 232 | + msgRefresh(val) { |
| 233 | + this.MsgFormVisible = false; | ||
| 234 | + val && this.getAllMsgList(); | ||
| 235 | + }, | ||
| 236 | + checkDetail(row) { | ||
| 237 | + console.log(row); | ||
| 238 | + this.MsgFormVisible = true; | ||
| 239 | + this.$nextTick(() => { | ||
| 240 | + this.$refs.MsgForm.init(row.id, true); | ||
| 241 | + }) | ||
| 190 | }, | 242 | }, |
| 191 | - getAimList() { | ||
| 192 | - for (let index = 0; index < 12; index++) { | ||
| 193 | - if (Math.random() > 0.5) { | ||
| 194 | - this.aimList.push(areaObj); | 243 | + // 发布消息通知 |
| 244 | + announceMsg() { | ||
| 245 | + this.MsgFormVisible = true; | ||
| 246 | + this.$nextTick(() => { | ||
| 247 | + this.$refs.MsgForm.init(); | ||
| 248 | + }) | ||
| 249 | + }, | ||
| 250 | + | ||
| 251 | + // 任务中心 | ||
| 252 | + getAllTaskList() { | ||
| 253 | + this.taskLoading = true; | ||
| 254 | + let _query = { | ||
| 255 | + ...this.taskListQuery, | ||
| 256 | + ...this.taskQuery, | ||
| 257 | + }; | ||
| 258 | + let query = {}; | ||
| 259 | + for (let key in _query) { | ||
| 260 | + if (Array.isArray(_query[key])) { | ||
| 261 | + query[key] = _query[key].join(); | ||
| 195 | } else { | 262 | } else { |
| 196 | - this.aimList.push(chObj); | 263 | + query[key] = _query[key]; |
| 197 | } | 264 | } |
| 198 | } | 265 | } |
| 266 | + request({ | ||
| 267 | + url: '/Extend/BaseTaskCenter/GetListByCurretUser', | ||
| 268 | + method: "GET", | ||
| 269 | + params: query, | ||
| 270 | + }).then((res) => { | ||
| 271 | + this.taskList = res.data.list; | ||
| 272 | + this.taskTotal = res.data.pagination.total; | ||
| 273 | + this.taskLoading = false; | ||
| 274 | + }); | ||
| 275 | + }, | ||
| 276 | + resetTask() { | ||
| 277 | + this.taskList = []; | ||
| 278 | + this.taskListQuery = { | ||
| 279 | + currentPage: 1, | ||
| 280 | + pageSize: 20, | ||
| 281 | + }; | ||
| 282 | + this.getAllTaskList(); | ||
| 199 | }, | 283 | }, |
| 200 | }, | 284 | }, |
| 201 | }; | 285 | }; |
| @@ -234,7 +318,7 @@ export default { | @@ -234,7 +318,7 @@ export default { | ||
| 234 | } | 318 | } |
| 235 | } | 319 | } |
| 236 | .item-body { | 320 | .item-body { |
| 237 | - height: calc(100% - 68px); | 321 | + height: calc(100% - 95px); |
| 238 | margin: 0 13px; | 322 | margin: 0 13px; |
| 239 | // padding-bottom: 28px; | 323 | // padding-bottom: 28px; |
| 240 | .el-table { | 324 | .el-table { |
src/views/overView/msgForm.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-dialog | ||
| 3 | + :title="isDetail ? '通知详情' : '发布通知'" | ||
| 4 | + :close-on-click-modal="false" | ||
| 5 | + :visible.sync="visible" | ||
| 6 | + class="NCC-dialog NCC-dialog_center msg-dialog" | ||
| 7 | + lock-scroll | ||
| 8 | + width="50%" | ||
| 9 | + > | ||
| 10 | + <el-row :gutter="15" style="padding-top: 10px"> | ||
| 11 | + <el-form | ||
| 12 | + ref="elForm" | ||
| 13 | + :model="dataForm" | ||
| 14 | + size="small" | ||
| 15 | + label-width="100px" | ||
| 16 | + label-position="right" | ||
| 17 | + :disabled="!!isDetail" | ||
| 18 | + :rules="rules"> | ||
| 19 | + <el-col :span="24"> | ||
| 20 | + <el-form-item label="通知标题" prop="title"> | ||
| 21 | + <el-input v-model="dataForm.title"></el-input> | ||
| 22 | + </el-form-item> | ||
| 23 | + </el-col> | ||
| 24 | + <el-col :span="24"> | ||
| 25 | + <el-form-item label="内容" prop="bodyContent"> | ||
| 26 | + <NCC-Quill v-model="dataForm.bodyContent" placeholder="请输入内容..." :disabled="!!isDetail" /> | ||
| 27 | + </el-form-item> | ||
| 28 | + </el-col> | ||
| 29 | + <el-col :span="24"> | ||
| 30 | + <el-form-item label="图片上传" prop="imgUrl"> | ||
| 31 | + <NCC-UploadFz v-model="dataForm.imgUrl" :fileSize="5" sizeUnit="MB" :limit="9" buttonText="点击上传" /> | ||
| 32 | + </el-form-item> | ||
| 33 | + </el-col> | ||
| 34 | + </el-form> | ||
| 35 | + </el-row> | ||
| 36 | + <span slot="footer" class="dialog-footer"> | ||
| 37 | + <el-button @click="visible = false">取 消</el-button> | ||
| 38 | + <el-button type="primary" @click="dataFormSubmit()" v-if="!isDetail">确 定</el-button> | ||
| 39 | + </span> | ||
| 40 | + </el-dialog> | ||
| 41 | + </template> | ||
| 42 | + <script> | ||
| 43 | + import request from "@/utils/request"; | ||
| 44 | + export default { | ||
| 45 | + components: {}, | ||
| 46 | + props: [], | ||
| 47 | + data() { | ||
| 48 | + return { | ||
| 49 | + loading: false, | ||
| 50 | + visible: false, | ||
| 51 | + isDetail: false, | ||
| 52 | + dataForm: { | ||
| 53 | + id: '', | ||
| 54 | + title: '', | ||
| 55 | + bodyContent: '', | ||
| 56 | + imgUrl: [], | ||
| 57 | + categoryId: 'cc225c68421644f79037aaf624ccccc0', | ||
| 58 | + isType: '0', | ||
| 59 | + }, | ||
| 60 | + rules: { | ||
| 61 | + title: [ | ||
| 62 | + { required: true, message: '请输入标题', trigger: 'blur' }, | ||
| 63 | + ], | ||
| 64 | + bodyContent: [ | ||
| 65 | + { required: true, message: '请输入内容', trigger: 'blur' }, | ||
| 66 | + ], | ||
| 67 | + }, | ||
| 68 | + }; | ||
| 69 | + }, | ||
| 70 | + computed: {}, | ||
| 71 | + watch: {}, | ||
| 72 | + created() { | ||
| 73 | + | ||
| 74 | + }, | ||
| 75 | + mounted() {}, | ||
| 76 | + beforeDestroy() { | ||
| 77 | + }, | ||
| 78 | + methods: { | ||
| 79 | + | ||
| 80 | + goBack() { | ||
| 81 | + this.$emit("refresh"); | ||
| 82 | + }, | ||
| 83 | + init(id, isDetail) { | ||
| 84 | + this.dataForm.id = id || 0; | ||
| 85 | + this.visible = true; | ||
| 86 | + this.isDetail = isDetail || false; | ||
| 87 | + this.$nextTick(() => { | ||
| 88 | + this.$refs["elForm"].resetFields(); | ||
| 89 | + if(this.dataForm.id) { | ||
| 90 | + request({ | ||
| 91 | + url: `/SubDev/ZyOaArticle/${this.dataForm.id}`, | ||
| 92 | + method: "GET", | ||
| 93 | + }).then((res) => { | ||
| 94 | + this.dataForm = res.data; | ||
| 95 | + console.log(this.dataForm); | ||
| 96 | + }); | ||
| 97 | + } | ||
| 98 | + }); | ||
| 99 | + }, | ||
| 100 | + dataFormSubmit() { | ||
| 101 | + this.$refs['elForm'].validate((valid) => { | ||
| 102 | + if (valid) { | ||
| 103 | + request({ | ||
| 104 | + url: `/SubDev/ZyOaArticle`, | ||
| 105 | + method: 'post', | ||
| 106 | + data: this.dataForm, | ||
| 107 | + }).then((res) => { | ||
| 108 | + this.$message({ | ||
| 109 | + message: res.msg, | ||
| 110 | + type: 'success', | ||
| 111 | + duration: 1000, | ||
| 112 | + onClose: () => { | ||
| 113 | + this.visible = false, this.$emit('refresh', true) | ||
| 114 | + } | ||
| 115 | + }) | ||
| 116 | + }) | ||
| 117 | + } | ||
| 118 | + }) | ||
| 119 | + }, | ||
| 120 | + }, | ||
| 121 | + }; | ||
| 122 | + </script> | ||
| 123 | + <style lang="scss" scoped> | ||
| 124 | + .msg-dialog { | ||
| 125 | + :deep(.el-dialog__body) { | ||
| 126 | + max-height: 50vh; | ||
| 127 | + overflow-y: scroll; | ||
| 128 | + } | ||
| 129 | + } | ||
| 130 | + </style> | ||
| 131 | + | ||
| 0 | \ No newline at end of file | 132 | \ No newline at end of file |