Bladeren bron

数据图表

zhengnaiwen_citu 5 maanden geleden
bovenliggende
commit
d1a71b89ec

+ 2 - 1
src/components/AutoComponents/ECharts/eCharts.js

@@ -2,7 +2,7 @@
 // 引入 ECharts 核心模块,核心模块提供了 ECharts 使用必须要的接口。
 import * as ECharts from 'echarts/core'
 // 引入柱状图图表,图表后缀都为 Chart
-import { BarChart, LineChart, TreeChart } from 'echarts/charts'
+import { BarChart, LineChart, TreeChart, PieChart } from 'echarts/charts'
 // 引入标题,提示框,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component
 import {
   TitleComponent,
@@ -30,6 +30,7 @@ class EChartsComponent {
         BarChart,
         LineChart,
         TreeChart,
+        PieChart,
         LabelLayout,
         UniversalTransition,
         LegendComponent,

+ 3 - 3
src/components/AutoComponents/ECharts/index.vue

@@ -18,12 +18,12 @@ export default {
   },
   beforeDestroy () {
     window.removeEventListener('resize', this.onResize)
-    this.chart.getEl().dispose()
+    this.chart && this.chart.getEl().dispose()
   },
   methods: {
-    onInit (type) {
+    onInit () {
       // 注册必须的组件
-      this.chart = new EChartsComponent(this.$refs[this.id], type)
+      this.chart = new EChartsComponent(this.$refs[this.id])
       this.$refs[this.id].style.width = this.$refs[this.id].offsetWidth + 'px'
       this.$refs[this.id].style.height = this.$refs[this.id].offsetHeight + 'px'
       window.addEventListener('resize', this.onResize)

+ 16 - 1
src/components/AutoComponents/MDialog/index.vue

@@ -114,5 +114,20 @@ export default {
 </script>
 
 <style lang="scss" scoped>
-
+::v-deep .el-dialog {
+  &.is-fullscreen {
+    height: 100vh;
+    border-spacing: 0; /* 避免单元格间距影响 */
+    display: table;
+    .el-dialog__header, .el-dialog__footer {
+      display: table-cell; /* 固定高度的行 */
+      height: 1px; /* 最小高度,内容撑开 */
+    }
+    .el-dialog__body {
+      display: table-row; /* 自动填充剩余高度 */
+      height: 100%; /* 关键:占满剩余空间 */
+      padding: 0;
+    }
+  }
+}
 </style>

+ 41 - 0
src/styles/index.scss

@@ -85,4 +85,45 @@ $max-classes: 10;
 
 .d-flex {
   display: flex;
+}
+
+.justify-center {
+  justify-content: center;
+}
+
+.justify-between {
+  justify-content: space-between;
+}
+
+.justify-around {
+  justify-content: space-around;
+}
+
+.align-center {
+  align-items: center;
+}
+
+.align-start {
+  align-items: flex-start;
+}
+
+.align-end {
+  align-items: flex-end;
+}
+
+.flex-column {
+  flex-direction: column;
+}
+
+.flex-wrap {
+  flex-wrap: wrap;
+}
+
+.fullscreen {
+  width: 100%;
+  height: 100%;
+}
+
+.border-box {
+  box-sizing: border-box;
 }

+ 27 - 0
src/views/dataChart/chartType/index.vue

@@ -0,0 +1,27 @@
+<template>
+  <div>
+    <el-input type="textarea" v-model="text"></el-input>
+    <m-button @click="submit">提交</m-button>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'chartType',
+  data () {
+    return {
+      text: 'Hello, World!'
+    }
+  },
+  methods: {
+    submit () {
+      console.log(this.text)
+      console.log(JSON.parse(this.text))
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 41 - 9
src/views/dataChart/privateChart.vue → src/views/dataChart/privateChart/index.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="pa-3 white">
-    <m-search class="mb-3" :items="searchItems" v-model="searchValue" @search="onSearch"></m-search>
+    <m-search class="mb-3" :items="searchItems" v-model="searchValues" @search="onSearch"></m-search>
     <m-table
       v-loading="loading"
       :items="items"
@@ -10,20 +10,31 @@
       :total="total"
       @page-change="onPageChange"
     >
+      <template #status="{ row }">
+        <el-tag size="small" :type="row.status === 1 ? 'success' : 'danger'">{{ row.status === 1 ? '启用' : '停用'}}</el-tag>
+      </template>
       <template #card-tools>
         <m-button type="orange" icon="el-icon-plus" @click="onAdd">新增</m-button>
       </template>
       <template #actions="{ row }">
         <m-button type="primary" text @click="onEdit(row)">编辑</m-button>
         <m-button type="danger" text @click="onDelete(row)">删除</m-button>
+        <m-button :type="row.status === 1 ? 'danger' : 'success'" text @click="onStatus(row)">
+          {{ row.status === 1 ? '停用' : '启用' }}
+        </m-button>
       </template>
     </m-table>
+    <PrivateChartEdit ref="privateChartEditRefs" fullscreen></PrivateChartEdit>
   </div>
 </template>
 
 <script>
+import PrivateChartEdit from './privateChartEdit.vue'
 export default {
   name: 'PrivateChart',
+  components: {
+    PrivateChartEdit
+  },
   data () {
     return {
       searchItems: [
@@ -41,10 +52,28 @@ export default {
       },
       headers: [
         { label: '名称', prop: 'name' },
+        { label: '制作者', prop: 'author' },
+        { label: '制作时间', prop: 'createDate' },
+        { label: '状态', prop: 'status' },
         { label: '描述', prop: 'desc' },
-        { label: '操作', prop: 'actions', fixed: 'right', width: 300 }
+        { label: '操作', prop: 'actions' }
+      ],
+      items: [
+        {
+          name: '图表1',
+          author: '张三',
+          createDate: '2021-01-01',
+          status: 1,
+          desc: '这是一个图表'
+        },
+        {
+          name: '图表2',
+          author: '李四',
+          createDate: '2021-01-02',
+          status: 0,
+          desc: '这是另一个图表'
+        }
       ],
-      items: [],
       total: 0,
       pageInfo: {
         current: 1,
@@ -61,30 +90,33 @@ export default {
         // this.items = data.list || []
         // this.total = data.total || 0
       } catch (error) {
-        this.message.error(error.message || '请求失败')
+        this.$message.error(error)
       } finally {
         this.loading = false
       }
     },
     onAdd () {
-      this.refs.templateRefs.open()
+      this.$refs.privateChartEditRefs.open()
     },
     onEdit (item) {
-      this.refs.templateRefs.open(item)
+      this.$refs.privateChartEditRefs.open(item)
     },
     onDelete (row) {
-      this.confirm('确定删除吗?', '提示')
+      this.$confirm('确定删除吗?', '提示')
         .then(async () => {
           try {
             // await ApiName({ id: row.id })
-            this.message.success('删除成功')
+            this.$message.success('删除成功')
             this.onInit()
           } catch (error) {
-            this.message.error(error.message || '删除失败')
+            this.$message.error(error)
           }
         })
         .catch(_ => {})
     },
+    onStatus (item) {
+      item.status = item.status === 1 ? 0 : 1
+    },
     onSearch () {
       this.pageInfo.current = 1
       this.onInit()

+ 80 - 0
src/views/dataChart/privateChart/privateChartEdit.vue

@@ -0,0 +1,80 @@
+<template>
+  <m-dialog ref="dialog" v-bind="$attrs" title="图表编辑">
+    <div class="pa-3 fullscreen border-box">
+      <m-card shadow="never" class="fullscreen border-box" :body-style="{ height: '100%', padding: 0 }">
+        <div class="d-flex box fullscreen">
+          <div class="box-left">
+            <PrivateChartEditType ref="privateChartEditTypeRefs" @change="onChangeOption"></PrivateChartEditType>
+          </div>
+          <div class="box-main border-box">
+            <PrivateChartEditShow ref="privateChartEditShowRefs" class="fullscreen"></PrivateChartEditShow>
+          </div>
+          <div class="box-right">
+            <PrivateChartEditParams ref="privateChartEditParamsRefs" class="fullscreen" @change="onChangParams"></PrivateChartEditParams>
+          </div>
+        </div>
+      </m-card>
+    </div>
+  </m-dialog>
+</template>
+
+<script>
+import PrivateChartEditShow from './privateChartEditShow.vue'
+import PrivateChartEditType from './privateChartEditType.vue'
+import PrivateChartEditParams from './privateChartEditParams.vue'
+export default {
+  name: 'privateChartEdit',
+  components: {
+    PrivateChartEditShow,
+    PrivateChartEditType,
+    PrivateChartEditParams
+  },
+  data () {
+    return {
+      key: null,
+      option: {},
+      data: [[1, 2, 3, 4, 5, 6]]
+    }
+  },
+  methods: {
+    open () {
+      this.$refs.dialog.open()
+    },
+    setData (data) {
+      this.$refs.privateChartEditShowRefs.setData(data, this.key, this.option)
+    },
+    // 改变整体option
+    onChangeOption (key, data) {
+      this.key = key
+      this.option = data.option
+      this.setData(this.data)
+    },
+    // 改变数据参数
+    onChangParams (data) {
+      this.data = data
+      this.setData(data)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.border-box {
+  box-sizing: border-box;
+}
+.box {
+  $left: 300px;
+  $right: 500px;
+  &-left {
+    width: $left;
+  }
+  &-main {
+    padding: 20px;
+    width: calc(100% - #{$left} - #{$right});
+    height: 100%;
+  }
+  &-right {
+    width: $right;
+  }
+}
+</style>

+ 41 - 0
src/views/dataChart/privateChart/privateChartEditParams.vue

@@ -0,0 +1,41 @@
+<template>
+  <div class="content">
+    <el-tabs type="border-card" v-model="activeName" @tab-click="handleClick" class="fullHeigh">
+      <el-tab-pane label="参数配置" name="first">
+        <p v-for="i in 50" :key="i">参数配置</p>
+      </el-tab-pane>
+      <el-tab-pane label="快速咨询" name="second">快速咨询</el-tab-pane>
+    </el-tabs>
+  </div>
+</template>
+
+<script>
+// 数据模块
+export default {
+  name: 'privateChartEditParams',
+  data () {
+    return {
+      activeName: 'first'
+    }
+  },
+  methods: {
+    handleClick (tab, event) {
+      console.log(tab, event)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.content {
+  padding: 10px;
+  box-sizing: border-box;
+}
+.fullHeigh {
+  height: 100%;
+}
+::v-deep .el-tabs__content {
+  height: calc(100% - 40px);
+  overflow: auto;
+}
+</style>

+ 54 - 0
src/views/dataChart/privateChart/privateChartEditShow.vue

@@ -0,0 +1,54 @@
+<template>
+  <e-charts ref="chart"></e-charts>
+</template>
+
+<script>
+// 展示模块
+import { cloneDeep } from 'lodash'
+import * as Charts from '../utils/options.js'
+export default {
+  name: 'PrivateChartEditShow',
+  data () {
+    return {
+      // 组件数据
+      chart: null,
+      key: null
+    }
+  },
+  methods: {
+    /**
+     * 接收一组二维数组,用于设置图表数据
+     * @param data: Array 图表数据 [ [], [] ]
+     */
+    setData (data, key, config = {
+      xAxisData: []
+    }) {
+      this.chart.showLoading()
+      // 根据key值处理data
+      this.data = data || [[]]
+      const _option = cloneDeep(Charts[key].option)
+      const series = _option.series
+      series.forEach((item, index) => {
+        item.data = this.data[index]
+      })
+      if (_option.xAxis?.data) {
+        _option.xAxis.data = config?.xAxisData?.length ?? this.data[0].map((e, i) => i)
+      }
+      console.log(_option)
+      this.chart.setOption(_option, this.key !== key)
+      this.key = key
+      this.chart.hideLoading()
+    }
+  },
+  mounted () {
+    // 组件挂载完成后的钩子函数
+    this.$nextTick(() => {
+      this.chart = this.$refs.chart.onInit()
+    })
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 56 - 0
src/views/dataChart/privateChart/privateChartEditType.vue

@@ -0,0 +1,56 @@
+<template>
+  <div class="fullHeight pa-3">
+    <div v-for="(chart, key) in Charts" :key="key" class="chart-type mb-3" @click="onChange(chart, key)">
+      <div>
+        <span class="mdi" :class="chart.icon"></span>
+      </div>
+      <div>
+        {{ chart.title }}
+      </div>
+    </div>
+
+  </div>
+</template>
+
+<script>
+// 属性模块
+import * as Charts from '../utils/options.js'
+export default {
+  name: 'privateChartEditType',
+  data () {
+    return {
+      Charts
+    }
+  },
+  methods: {
+    onChange (data, key) {
+      this.$emit('change', key, data)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.fullHeight {
+  height: 100%;
+  box-sizing: border-box;
+}
+.chart-type {
+  width: 100px;
+  height: 100px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  padding: 10px;
+  border: 1px solid #ccc;
+  border-radius: 5px;
+  cursor: pointer;
+  .mdi {
+    font-size: 30px;
+  }
+  &:hover {
+    background-color: #f5f5f5;
+  }
+}
+</style>

+ 1 - 0
src/views/dataChart/shareChart.vue → src/views/dataChart/shareChart/index.vue

@@ -27,6 +27,7 @@ export default {
   name: 'ShareChart',
   data () {
     return {
+      searchValue: {},
       searchItems: [
         {
           label: '名称',

+ 74 - 0
src/views/dataChart/utils/options.js

@@ -0,0 +1,74 @@
+export const line = {
+  title: '折线图',
+  icon: 'mdi-chart-line',
+  option: {
+    xAxis: {
+      type: 'category',
+      data: []
+    },
+    yAxis: {
+      type: 'value'
+    },
+    series: [
+      {
+        data: [],
+        type: 'line',
+        smooth: true
+      }
+    ]
+  }
+}
+
+export const bar = {
+  title: '柱状图',
+  icon: 'mdi-chart-bar',
+  option: {
+    xAxis: {
+      type: 'category',
+      data: []
+    },
+    yAxis: {
+      type: 'value'
+    },
+    series: [
+      {
+        data: [],
+        type: 'bar'
+      }
+    ]
+  }
+}
+
+export const pie = {
+  title: '饼图',
+  icon: 'mdi-chart-pie',
+  option: {
+    title: {
+      text: 'Referer of a Website',
+      subtext: 'Fake Data',
+      left: 'center'
+    },
+    tooltip: {
+      trigger: 'item'
+    },
+    legend: {
+      orient: 'vertical',
+      left: 'left'
+    },
+    series: [
+      {
+        name: 'Access From',
+        type: 'pie',
+        radius: '50%',
+        data: [],
+        emphasis: {
+          itemStyle: {
+            shadowBlur: 10,
+            shadowOffsetX: 0,
+            shadowColor: 'rgba(0, 0, 0, 0.5)'
+          }
+        }
+      }
+    ]
+  }
+}

+ 4 - 1
src/views/system/menu/menuEdit.vue

@@ -1,5 +1,5 @@
 <template>
-  <MDialog ref="editDialog" v-bind="$attrs" @sure="handleSaveEdit">
+  <MDialog ref="editDialog" :title="title" v-bind="$attrs" @sure="handleSaveEdit">
     <MForm ref="editForm" :items="editForm" v-model="editValues">
       <template #parentId>
         <el-popover
@@ -40,6 +40,9 @@
 import { MENU_TYPE } from '@/utils/dict'
 export default {
   name: 'menu-edit',
+  props: {
+    title: String
+  },
   data () {
     return {
       popover: false,