|
|
@@ -1,8 +1,16 @@
|
|
|
+<!--
|
|
|
+ * @Author: wanglj 471442253@qq.com
|
|
|
+ * @Date: 2023-01-11 15:52:49
|
|
|
+ * @LastEditors: wanglj
|
|
|
+ * @LastEditTime: 2023-02-17 17:57:12
|
|
|
+ * @Description: file content
|
|
|
+ * @FilePath: \opms_frontend\src\views\index\index.vue
|
|
|
+-->
|
|
|
<!--
|
|
|
* @Author: wanglj 471442253@qq.com
|
|
|
* @Date: 2022-12-13 10:28:33
|
|
|
* @LastEditors: wanglj
|
|
|
- * @LastEditTime: 2023-01-11 19:16:12
|
|
|
+ * @LastEditTime: 2023-02-15 17:52:56
|
|
|
* @Description: file content
|
|
|
* @FilePath: \opms_frontend\src\views\index\index.vue
|
|
|
-->
|
|
|
@@ -12,157 +20,110 @@
|
|
|
<el-card class="board">
|
|
|
<div slot="header" class="card-title">
|
|
|
<span>个人看板</span>
|
|
|
- <vab-icon icon="question-line" />
|
|
|
+ <div class="buttons">
|
|
|
+ <el-button v-show="!editFlag" type="text" @click="editFlag = true">编辑布局</el-button>
|
|
|
+ <el-button v-show="editFlag" type="text" @click="visible = true">添加指标</el-button>
|
|
|
+ <el-button v-show="editFlag" type="text" @click="saveLayout">保存布局</el-button>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <ul>
|
|
|
- <li>
|
|
|
- <vab-icon icon="account-circle-line" />
|
|
|
- <div class="text">
|
|
|
- <p class="num">124</p>
|
|
|
- <p>当前客户数(个)</p>
|
|
|
- </div>
|
|
|
- </li>
|
|
|
- <li>
|
|
|
- <vab-icon icon="user-add-line" />
|
|
|
- <div class="text">
|
|
|
- <p class="num">124</p>
|
|
|
- <p>新增客户数(个)</p>
|
|
|
- </div>
|
|
|
- </li>
|
|
|
- <li>
|
|
|
- <vab-icon icon="account-pin-box-line" />
|
|
|
- <div class="text">
|
|
|
- <p class="num">124</p>
|
|
|
- <p>跟进客户数(个)</p>
|
|
|
- </div>
|
|
|
- </li>
|
|
|
- <li>
|
|
|
- <vab-icon icon="account-circle-line" />
|
|
|
- <div class="text">
|
|
|
- <p class="num">124</p>
|
|
|
- <p>合同订单数(个)</p>
|
|
|
- </div>
|
|
|
- </li>
|
|
|
- </ul>
|
|
|
- <ul>
|
|
|
- <li>
|
|
|
- <vab-icon icon="exchange-cny-fill" />
|
|
|
- <div class="text">
|
|
|
- <p class="num">{{ parseFloat(123).toFixed(2) }}</p>
|
|
|
- <p>合同订单金额(元)</p>
|
|
|
- </div>
|
|
|
- </li>
|
|
|
- <li>
|
|
|
- <vab-icon icon="mail-add-line" />
|
|
|
- <div class="text">
|
|
|
- <p class="num">124</p>
|
|
|
- <p>新增机会数(个)</p>
|
|
|
- </div>
|
|
|
- </li>
|
|
|
- <li>
|
|
|
- <vab-icon icon="exchange-cny-fill" />
|
|
|
- <div class="text">
|
|
|
- <p class="num">{{ parseFloat(123).toFixed(2) }}</p>
|
|
|
- <p>新增机会金额(元)</p>
|
|
|
- </div>
|
|
|
- </li>
|
|
|
- <li>
|
|
|
- <vab-icon icon="account-circle-line" />
|
|
|
- <div class="text">
|
|
|
- <p class="num">124</p>
|
|
|
- <p>采购合同数(个)</p>
|
|
|
- </div>
|
|
|
- </li>
|
|
|
- </ul>
|
|
|
- <ul>
|
|
|
- <li>
|
|
|
- <vab-icon icon="money-cny-circle-line" />
|
|
|
- <div class="text">
|
|
|
- <p class="num">{{ parseFloat(123).toFixed(2) }}</p>
|
|
|
- <p>采购金额(元)</p>
|
|
|
- </div>
|
|
|
- </li>
|
|
|
- <li>
|
|
|
- <vab-icon icon="money-cny-circle-line" />
|
|
|
- <div class="text">
|
|
|
- <p class="num">{{ parseFloat(123).toFixed(2) }}</p>
|
|
|
- <p>应收未收(元)</p>
|
|
|
- </div>
|
|
|
- </li>
|
|
|
- <li>
|
|
|
- <vab-icon icon="money-cny-circle-line" />
|
|
|
- <div class="text">
|
|
|
- <p class="num">{{ parseFloat(123).toFixed(2) }}</p>
|
|
|
- <p>计划付款(元)</p>
|
|
|
- </div>
|
|
|
- </li>
|
|
|
- <li>
|
|
|
- <vab-icon icon="money-cny-circle-line" />
|
|
|
- <div class="text">
|
|
|
- <p class="num">{{ parseFloat(123).toFixed(2) }}</p>
|
|
|
- <p>当前库存成本(元)</p>
|
|
|
- </div>
|
|
|
- </li>
|
|
|
- </ul>
|
|
|
- </el-card>
|
|
|
- <el-row class="chart-row" :gutter="12" type="flex">
|
|
|
- <el-col :span="12">
|
|
|
- <el-card class="chart">
|
|
|
- <div slot="header" class="card-title">
|
|
|
- <span>销售预测</span>
|
|
|
- <div class="buttons">
|
|
|
- <el-select v-model="forecast" style="width: 120px">
|
|
|
- <el-option label="公司数据" value="1" />
|
|
|
- </el-select>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div id="bar"></div>
|
|
|
- </el-card>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-card class="chart">
|
|
|
- <div slot="header" class="card-title">
|
|
|
- <span>销售漏斗</span>
|
|
|
- <div class="buttons">
|
|
|
- <el-select v-model="forecast" style="width: 120px">
|
|
|
- <el-option label="公司数据" value="1" />
|
|
|
- </el-select>
|
|
|
- <el-date-picker
|
|
|
- v-model="date"
|
|
|
- :clearable="false"
|
|
|
- style="width: 120px; margin-left: 10px"
|
|
|
- value-format="yyyy-MM-dd" />
|
|
|
+ <el-row align="middle" :gutter="10" type="flex">
|
|
|
+ <VueDragger
|
|
|
+ v-model="privateBoard"
|
|
|
+ :animation="500"
|
|
|
+ :disabled="!editFlag"
|
|
|
+ drag-class="drag"
|
|
|
+ :force-fallback="true"
|
|
|
+ ghost-class="ghost"
|
|
|
+ handle=".mover">
|
|
|
+ <el-col v-for="(item, index) in privateBoard" :key="index" class="mover" :span="6">
|
|
|
+ <div class="board-container">
|
|
|
+ <vab-icon class="icon" :icon="item.report_icon" />
|
|
|
+ <div class="text">
|
|
|
+ <p class="num">{{ item.id }}</p>
|
|
|
+ <p>{{ item.report_name }}</p>
|
|
|
+ </div>
|
|
|
+ <vab-icon v-show="editFlag" class="close" icon="close-fill" @click.stop="handleDel(index)" />
|
|
|
</div>
|
|
|
+ </el-col>
|
|
|
+ </VueDragger>
|
|
|
+ </el-row>
|
|
|
+ </el-card>
|
|
|
+ <grid-layout
|
|
|
+ :class="{ grid: editFlag }"
|
|
|
+ :col-num="24"
|
|
|
+ :is-draggable="editFlag"
|
|
|
+ :is-mirrored="false"
|
|
|
+ :is-resizable="editFlag"
|
|
|
+ :layout.sync="layout"
|
|
|
+ :margin="[10, 10]"
|
|
|
+ :row-height="30"
|
|
|
+ :use-css-transforms="true"
|
|
|
+ :use-style-cursor="false"
|
|
|
+ :vertical-compact="true"
|
|
|
+ @layout-ready="layoutReadyEvent">
|
|
|
+ <grid-item
|
|
|
+ v-for="(item, index) in layout"
|
|
|
+ :key="index"
|
|
|
+ :h="item.h"
|
|
|
+ :i="item.i"
|
|
|
+ :w="item.w"
|
|
|
+ :x="item.x"
|
|
|
+ :y="item.y"
|
|
|
+ @resized="handleResize">
|
|
|
+ <h4>
|
|
|
+ {{ item.name }}
|
|
|
+ <!-- <div class="buttons">
|
|
|
+ <el-select v-model="forecast" style="width: 120px">
|
|
|
+ <el-option label="公司数据" value="1" />
|
|
|
+ </el-select>
|
|
|
+ </div> -->
|
|
|
+ <div class="buttons">
|
|
|
+ <el-button v-show="!editFlag" type="text" @click="refresh(item, index)">刷新</el-button>
|
|
|
+ <vab-icon v-show="editFlag" icon="close-fill" @click="gridDel(index)" />
|
|
|
</div>
|
|
|
- <div id="funnel"></div>
|
|
|
- </el-card>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
+ </h4>
|
|
|
+ <div :id="item.i"></div>
|
|
|
+ </grid-item>
|
|
|
+ </grid-layout>
|
|
|
</div>
|
|
|
<div class="right">
|
|
|
<el-card class="calendar">
|
|
|
<div slot="header" class="card-title">
|
|
|
<span>日程安排</span>
|
|
|
- <el-button style="padding: 0" type="text">添加</el-button>
|
|
|
+ <!-- <el-button style="padding: 0" type="text">添加</el-button> -->
|
|
|
</div>
|
|
|
<div class="week">
|
|
|
- <vab-icon icon="arrow-left-s-line" />
|
|
|
+ <vab-icon
|
|
|
+ icon="arrow-left-s-line"
|
|
|
+ @click="
|
|
|
+ date -= 7
|
|
|
+ getDateList()
|
|
|
+ " />
|
|
|
<ul>
|
|
|
- <li v-for="item in list" :key="item.date" :class="{ active: item.day == '日' }">
|
|
|
- <span>{{ item.day }}</span>
|
|
|
+ <li
|
|
|
+ v-for="(item, index) in list"
|
|
|
+ :key="index"
|
|
|
+ :class="{ active: item.day == day }"
|
|
|
+ @click="dateClick(item)">
|
|
|
+ <span>{{ dayList[item.day] }}</span>
|
|
|
<span>{{ item.date }}</span>
|
|
|
</li>
|
|
|
</ul>
|
|
|
- <vab-icon icon="arrow-right-s-line" />
|
|
|
+ <vab-icon
|
|
|
+ icon="arrow-right-s-line"
|
|
|
+ @click="
|
|
|
+ date += 7
|
|
|
+ getDateList()
|
|
|
+ " />
|
|
|
</div>
|
|
|
<el-timeline>
|
|
|
<el-timeline-item v-for="(activity, index) in activities" :key="index">
|
|
|
- <div class="detail" :class="{ active: index > 2 }">
|
|
|
+ <div class="detail" :class="{ active: activity.active }">
|
|
|
<p class="time">
|
|
|
- {{ activity.timestamp }}
|
|
|
- <el-button type="text">详情</el-button>
|
|
|
+ {{ activity.schDate }}
|
|
|
+ <!-- <el-button type="text">详情</el-button> -->
|
|
|
</p>
|
|
|
- <p>{{ activity.content }}</p>
|
|
|
+ <p>{{ activity.schTitle }}</p>
|
|
|
</div>
|
|
|
</el-timeline-item>
|
|
|
</el-timeline>
|
|
|
@@ -192,101 +153,215 @@
|
|
|
</ul>
|
|
|
</el-card>
|
|
|
</div>
|
|
|
+ <!-- 添加个人看板 -->
|
|
|
+ <el-dialog title="添加个人看板" :visible.sync="visible" @open="getBoardOptions">
|
|
|
+ <el-tabs v-model="activeName" type="card">
|
|
|
+ <el-tab-pane label="看板数据" name="first">
|
|
|
+ <ul class="add-board">
|
|
|
+ <li v-for="(item, index) in addBoard" :key="index" @click="item.checked = !item.checked">
|
|
|
+ <div class="board-container">
|
|
|
+ <vab-icon class="icon" :icon="item.reportIcon" />
|
|
|
+ <div class="text">
|
|
|
+ <p class="num">{{ item.id }}</p>
|
|
|
+ <p>{{ item.reportName }}</p>
|
|
|
+ </div>
|
|
|
+ <vab-icon v-show="item.checked" class="check" icon="check-fill" />
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </el-tab-pane>
|
|
|
+ <el-tab-pane label="销售指标" name="second">
|
|
|
+ <ul class="add-board">
|
|
|
+ <li v-for="(item, index) in addLayout" :key="index" @click="item.checked = !item.checked">
|
|
|
+ <div class="board-container">
|
|
|
+ <vab-icon class="icon" :icon="item.reportIcon" />
|
|
|
+ <div class="text">
|
|
|
+ <p class="num">{{ item.id }}</p>
|
|
|
+ <p>{{ item.reportName }}</p>
|
|
|
+ </div>
|
|
|
+ <vab-icon v-show="item.checked" class="check" icon="check-fill" />
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </el-tab-pane>
|
|
|
+ </el-tabs>
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="visible = false">取 消</el-button>
|
|
|
+ <el-button type="primary" @click="save">确 定</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import * as echarts from 'echarts'
|
|
|
+ import VueDragger from 'vuedraggable'
|
|
|
+ import VueGridLayout from 'vue-grid-layout'
|
|
|
+ import to from 'await-to-js'
|
|
|
+ import indexApi from '@/api/index'
|
|
|
import messageApi from '@/api/system/message'
|
|
|
-
|
|
|
export default {
|
|
|
name: 'Index',
|
|
|
+ components: {
|
|
|
+ VueDragger,
|
|
|
+ GridLayout: VueGridLayout.GridLayout,
|
|
|
+ GridItem: VueGridLayout.GridItem,
|
|
|
+ },
|
|
|
data() {
|
|
|
return {
|
|
|
- list: [
|
|
|
+ editFlag: false,
|
|
|
+ privateBoard: [
|
|
|
{
|
|
|
- day: '日',
|
|
|
- date: '09',
|
|
|
+ report_name: '当前客户数(个)',
|
|
|
+ id: 1,
|
|
|
+ report_icon: 'account-circle-line',
|
|
|
+ checked: false,
|
|
|
},
|
|
|
{
|
|
|
- day: '一',
|
|
|
- date: '10',
|
|
|
+ report_name: '新增客户数(个)',
|
|
|
+ id: 2,
|
|
|
+ report_icon: 'user-add-line',
|
|
|
+ checked: false,
|
|
|
},
|
|
|
{
|
|
|
- day: '二',
|
|
|
- date: '11',
|
|
|
+ report_name: '跟进客户数(个)',
|
|
|
+ id: 3,
|
|
|
+ report_icon: 'account-pin-box-line',
|
|
|
+ checked: false,
|
|
|
},
|
|
|
{
|
|
|
- day: '三',
|
|
|
- date: '12',
|
|
|
+ report_name: '合同订单数(个)',
|
|
|
+ id: 4,
|
|
|
+ report_icon: 'account-circle-line',
|
|
|
+ checked: false,
|
|
|
},
|
|
|
{
|
|
|
- day: '四',
|
|
|
- date: '13',
|
|
|
+ report_name: '合同订单金额(元)',
|
|
|
+ id: 5,
|
|
|
+ report_icon: 'exchange-cny-fill',
|
|
|
+ checked: false,
|
|
|
},
|
|
|
{
|
|
|
- day: '五',
|
|
|
- date: '14',
|
|
|
+ report_name: '新增机会数(个)',
|
|
|
+ id: 6,
|
|
|
+ report_icon: 'mail-add-line',
|
|
|
+ checked: false,
|
|
|
},
|
|
|
{
|
|
|
- day: '六',
|
|
|
- date: '15',
|
|
|
+ report_name: '新增机会金额(元)',
|
|
|
+ id: 7,
|
|
|
+ report_icon: 'exchange-cny-fill',
|
|
|
+ checked: false,
|
|
|
},
|
|
|
- ],
|
|
|
- activities: [
|
|
|
{
|
|
|
- type: '内部分享',
|
|
|
- content: '活动按期开始',
|
|
|
- timestamp: '2018-04-15',
|
|
|
+ report_name: '采购合同数(个)',
|
|
|
+ id: 8,
|
|
|
+ report_icon: 'account-circle-line',
|
|
|
+ checked: false,
|
|
|
},
|
|
|
{
|
|
|
- type: '内部分享',
|
|
|
- content: '如何建立良好的客户关系',
|
|
|
- timestamp: '2018-04-13',
|
|
|
+ report_name: '采购金额(元)',
|
|
|
+ id: 9,
|
|
|
+ report_icon: 'money-cny-circle-line',
|
|
|
+ checked: false,
|
|
|
},
|
|
|
{
|
|
|
- type: '内部分享',
|
|
|
- content: '创建成功',
|
|
|
- timestamp: '2018-04-11',
|
|
|
+ report_name: '应收未收(元)',
|
|
|
+ id: 10,
|
|
|
+ report_icon: 'money-cny-circle-line',
|
|
|
+ checked: false,
|
|
|
},
|
|
|
{
|
|
|
- type: '内部分享',
|
|
|
- content: '创建成功',
|
|
|
- timestamp: '2018-04-11',
|
|
|
+ report_name: '计划付款(元)',
|
|
|
+ id: 11,
|
|
|
+ report_icon: 'money-cny-circle-line',
|
|
|
+ checked: false,
|
|
|
},
|
|
|
{
|
|
|
- type: '内部分享',
|
|
|
- content: '创建成功',
|
|
|
- timestamp: '2018-04-11',
|
|
|
+ report_name: '当前库存成本(元)',
|
|
|
+ id: 12,
|
|
|
+ report_icon: 'money-cny-circle-line',
|
|
|
+ checked: false,
|
|
|
},
|
|
|
],
|
|
|
- chartBar: {},
|
|
|
- chartFunnel: {},
|
|
|
+ addBoard: [],
|
|
|
+ addLayout: [],
|
|
|
+ visible: false,
|
|
|
+ layout: [],
|
|
|
+ day: -1,
|
|
|
+ list: [],
|
|
|
+ activities: [],
|
|
|
+ charts: [],
|
|
|
+ activeName: 'first',
|
|
|
forecast: '1',
|
|
|
- date: '2023-01-10',
|
|
|
+ date: 0,
|
|
|
+ dayList: ['日', '一', '二', '三', '四', '五', '六'],
|
|
|
messageList: [],
|
|
|
msgTypeOptions: [],
|
|
|
}
|
|
|
},
|
|
|
mounted() {
|
|
|
- this.initBar()
|
|
|
- this.initFunnel()
|
|
|
- window.addEventListener('resize', this.handleResize)
|
|
|
+ this.init()
|
|
|
+ this.getDateList()
|
|
|
+ this.getOptions()
|
|
|
+ this.handleNoticeList()
|
|
|
this.$baseEventBus.$on('receivedMessage', () => {
|
|
|
console.log('---------------通知更新公告----------------')
|
|
|
this.handleNoticeList()
|
|
|
})
|
|
|
- this.getOptions()
|
|
|
- this.handleNoticeList()
|
|
|
+ window.addEventListener('resize', this.handleResize)
|
|
|
},
|
|
|
methods: {
|
|
|
- initBar() {
|
|
|
- this.chartBar = echarts.init(document.getElementById('bar'))
|
|
|
+ // 布局信息
|
|
|
+ async init() {
|
|
|
+ const [err, res] = await to(indexApi.getHomeReport({ module_code: 'HomePage' }))
|
|
|
+ if (err) return
|
|
|
+ const obj = JSON.parse(res.data.configInfo)
|
|
|
+ this.privateBoard = obj.num_report_config
|
|
|
+ this.layout = obj.data_report_config.map((item) => {
|
|
|
+ return {
|
|
|
+ x: item.location_x,
|
|
|
+ y: item.location_y,
|
|
|
+ i: item.id,
|
|
|
+ desc: item.report_desc,
|
|
|
+ name: item.report_name,
|
|
|
+ type: item.report_type,
|
|
|
+ h: item.size_h,
|
|
|
+ w: item.size_w,
|
|
|
+ }
|
|
|
+ })
|
|
|
+ await this.$nextTick()
|
|
|
+ this.initChart()
|
|
|
+ },
|
|
|
+ initChart() {
|
|
|
+ console.log(this.layout, 'layout')
|
|
|
+ this.charts = []
|
|
|
+ for (let i = 0; i < this.layout.length; i++) {
|
|
|
+ this.getChartSize(this.layout[i].i)
|
|
|
+ this.drawChart(this.layout[i].i, i)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ //刷新
|
|
|
+ refresh(item, index) {
|
|
|
+ this.charts[index].dispose()
|
|
|
+ this.drawChart(item.i, index)
|
|
|
+ },
|
|
|
+ getChartSize(id) {
|
|
|
+ console.log(id, 'id')
|
|
|
+ const bar = document.getElementById(id)
|
|
|
+ console.log(bar, 'bar')
|
|
|
+ bar.style.height = bar.parentNode.clientHeight - 65 + 'px'
|
|
|
+ bar.style.width = bar.parentNode.clientWidth + 'px'
|
|
|
+ },
|
|
|
+ async drawChart(id, i) {
|
|
|
+ const chartBar = echarts.init(document.getElementById(id))
|
|
|
+ const [err, res] = await to(indexApi.getHomeDataReportData({ id }))
|
|
|
+ if (err) return
|
|
|
const option = {
|
|
|
grid: {
|
|
|
- bottom: 20,
|
|
|
- top: 20,
|
|
|
- right: 0,
|
|
|
+ bottom: 30,
|
|
|
+ top: 40,
|
|
|
+ right: 10,
|
|
|
},
|
|
|
tooltip: {
|
|
|
trigger: 'axis',
|
|
|
@@ -294,37 +369,37 @@
|
|
|
xAxis: [
|
|
|
{
|
|
|
type: 'category',
|
|
|
- // prettier-ignore
|
|
|
- data: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
|
|
|
+ data: res.data.data.xData,
|
|
|
+ axisTick: {
|
|
|
+ alignWithLabel: true,
|
|
|
+ },
|
|
|
},
|
|
|
],
|
|
|
yAxis: [
|
|
|
{
|
|
|
type: 'value',
|
|
|
+ name: '(元)',
|
|
|
},
|
|
|
],
|
|
|
series: [
|
|
|
{
|
|
|
- name: 'Rainfall',
|
|
|
+ name: '销售指标',
|
|
|
type: 'bar',
|
|
|
- data: [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3],
|
|
|
+ data: res.data.data.yDataTarget,
|
|
|
},
|
|
|
{
|
|
|
- name: 'Evaporation',
|
|
|
+ name: '销售额度',
|
|
|
type: 'bar',
|
|
|
- data: [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3],
|
|
|
+ data: res.data.data.yDataReal,
|
|
|
},
|
|
|
],
|
|
|
}
|
|
|
- this.chartBar.setOption(option)
|
|
|
+ chartBar.setOption(option)
|
|
|
+ this.charts[i] = chartBar
|
|
|
},
|
|
|
initFunnel() {
|
|
|
this.chartFunnel = echarts.init(document.getElementById('funnel'))
|
|
|
const option = {
|
|
|
- grid: {
|
|
|
- top: 0,
|
|
|
- bottom: 0,
|
|
|
- },
|
|
|
tooltip: {
|
|
|
trigger: 'item',
|
|
|
formatter: '{b} : {d}%',
|
|
|
@@ -339,8 +414,8 @@
|
|
|
{
|
|
|
name: '销售漏斗',
|
|
|
type: 'funnel',
|
|
|
- top: 0,
|
|
|
- bottom: 0,
|
|
|
+ top: 10,
|
|
|
+ bottom: 10,
|
|
|
minSize: '20%',
|
|
|
maxSize: '100%',
|
|
|
label: {
|
|
|
@@ -359,8 +434,8 @@
|
|
|
{
|
|
|
name: '销售漏斗',
|
|
|
type: 'funnel',
|
|
|
- top: 0,
|
|
|
- bottom: 0,
|
|
|
+ top: 10,
|
|
|
+ bottom: 10,
|
|
|
minSize: '20%',
|
|
|
maxSize: '100%',
|
|
|
z: 1,
|
|
|
@@ -376,12 +451,101 @@
|
|
|
}
|
|
|
this.chartFunnel.setOption(option)
|
|
|
},
|
|
|
- handleResize() {
|
|
|
- this.$nextTick(() => {
|
|
|
- this.chartBar.resize()
|
|
|
- this.chartFunnel.resize()
|
|
|
+ async handleResize() {
|
|
|
+ await this.$nextTick()
|
|
|
+ for (let i = 0; i < this.layout.length; i++) {
|
|
|
+ this.getChartSize(this.layout[i].i)
|
|
|
+ this.charts[i].resize()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ layoutReadyEvent() {
|
|
|
+ this.initChart()
|
|
|
+ },
|
|
|
+ handleDel(index) {
|
|
|
+ this.privateBoard.splice(index, 1)
|
|
|
+ },
|
|
|
+ gridDel(index) {
|
|
|
+ this.layout.splice(index, 1)
|
|
|
+ },
|
|
|
+ async save() {
|
|
|
+ const board = this.addBoard.filter((item) => item.checked == true)
|
|
|
+ for (const item of board) {
|
|
|
+ this.privateBoard.push({
|
|
|
+ report_name: item.reportName,
|
|
|
+ id: item.id,
|
|
|
+ report_icon: item.reportIcon,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ const layout = this.addLayout.filter((item) => item.checked == true)
|
|
|
+ for (const item of layout) {
|
|
|
+ const index = this.layout.findIndex((each) => each.i == item.id)
|
|
|
+ if (index > -1) continue
|
|
|
+ this.layout.push({ x: 0, y: 0, w: 12, h: 10, i: item.id, type: 'bar', name: item.reportName })
|
|
|
+ }
|
|
|
+ this.visible = false
|
|
|
+ await this.$nextTick()
|
|
|
+ this.initChart()
|
|
|
+ },
|
|
|
+ async saveLayout() {
|
|
|
+ this.editFlag = false
|
|
|
+ const params = {
|
|
|
+ module_code: 'HomePage',
|
|
|
+ data_report_config: [],
|
|
|
+ num_report_config: this.privateBoard,
|
|
|
+ }
|
|
|
+ params.data_report_config = this.layout.map((item) => {
|
|
|
+ return {
|
|
|
+ location_x: item.x,
|
|
|
+ location_y: item.y,
|
|
|
+ id: item.i,
|
|
|
+ report_desc: item.desc,
|
|
|
+ report_name: item.name,
|
|
|
+ report_type: item.type,
|
|
|
+ size_h: item.h,
|
|
|
+ size_w: item.w,
|
|
|
+ }
|
|
|
+ })
|
|
|
+ const [err, res] = await to(indexApi.setUpHomeConfig(params))
|
|
|
+ if (err) return
|
|
|
+ this.$message.success(res.msg)
|
|
|
+ },
|
|
|
+ getDateList() {
|
|
|
+ const now = new Date()
|
|
|
+ const date = new Date(now.getTime() + this.date * 1000 * 60 * 60 * 24)
|
|
|
+ const day = date.getDay()
|
|
|
+ this.day = day
|
|
|
+ this.list = new Array(7)
|
|
|
+ for (let i = 0; i < this.list.length; i++) {
|
|
|
+ this.list[i] = {}
|
|
|
+ const flag = -(day - i)
|
|
|
+ const time = new Date(date.getTime() + flag * 1000 * 60 * 60 * 24)
|
|
|
+ this.list[i].time = new Date(time)
|
|
|
+ this.list[i].day = this.list[i].time.getDay()
|
|
|
+ this.list[i].date = this.list[i].time.getDate()
|
|
|
+ if (flag == 0) this.dateClick(this.list[i])
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async dateClick(item) {
|
|
|
+ this.day = item.day
|
|
|
+ const [err, res] = await to(indexApi.getSchedule({ schDate: this.parseTime(item.time) }))
|
|
|
+ if (err) return
|
|
|
+ this.activities = res.data.list || []
|
|
|
+ const date = new Date().getTime()
|
|
|
+ this.activities.forEach((item) => {
|
|
|
+ const start = new Date(item.schDate).getTime()
|
|
|
+ const end = new Date(item.schDateEnd).getTime()
|
|
|
+ item.active = start <= date && end >= date
|
|
|
})
|
|
|
},
|
|
|
+ async getBoardOptions() {
|
|
|
+ this.activeName = 'first'
|
|
|
+ const [err, res] = await to(indexApi.getReportList())
|
|
|
+ if (err) return
|
|
|
+ const arr = res.data.list || []
|
|
|
+ arr.forEach((item) => (item.checked = false))
|
|
|
+ this.addLayout = arr.filter((item) => item.reportType == 20)
|
|
|
+ this.addBoard = arr.filter((item) => item.reportType == 10)
|
|
|
+ },
|
|
|
getOptions() {
|
|
|
this.getDicts('sys_msg_type').then((response) => {
|
|
|
this.msgTypeOptions = response.data.values || []
|
|
|
@@ -426,10 +590,10 @@
|
|
|
font-size: 16px;
|
|
|
font-weight: 700;
|
|
|
line-height: 22px;
|
|
|
+ height: 22px;
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
align-items: center;
|
|
|
-
|
|
|
i {
|
|
|
font-weight: normal;
|
|
|
cursor: pointer;
|
|
|
@@ -445,84 +609,42 @@
|
|
|
margin-right: 10px;
|
|
|
overflow-x: hidden;
|
|
|
overflow-y: auto;
|
|
|
-
|
|
|
.board {
|
|
|
- height: 60%;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
-
|
|
|
+ margin-bottom: 2px;
|
|
|
::v-deep .el-card__body {
|
|
|
flex: 1;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
justify-content: space-around;
|
|
|
}
|
|
|
-
|
|
|
- ul {
|
|
|
- height: 60px;
|
|
|
- display: flex;
|
|
|
-
|
|
|
- li {
|
|
|
- flex: 1;
|
|
|
- height: 60px;
|
|
|
+ .el-row {
|
|
|
+ height: 100%;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ > div,
|
|
|
+ > div span {
|
|
|
display: flex;
|
|
|
+ height: 100%;
|
|
|
align-items: center;
|
|
|
- padding: 0 20px;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+ .ghost {
|
|
|
+ background: #ecf5ff;
|
|
|
+ }
|
|
|
+ .drag {
|
|
|
+ background: pink;
|
|
|
+ }
|
|
|
+ .el-col {
|
|
|
+ display: flex;
|
|
|
+ height: 60px;
|
|
|
+ margin: 20px 0;
|
|
|
user-select: none;
|
|
|
cursor: pointer;
|
|
|
-
|
|
|
- + li {
|
|
|
- border-left: 1px solid #eee;
|
|
|
- }
|
|
|
-
|
|
|
- i {
|
|
|
- font-size: 32px;
|
|
|
- border-radius: 4px;
|
|
|
- width: 40px;
|
|
|
- height: 40px;
|
|
|
- color: #1d66dc;
|
|
|
- background: #ecf5ff;
|
|
|
-
|
|
|
- &.ri-money-cny-circle-line {
|
|
|
- color: #e6a23c;
|
|
|
- background: #fdf6ec;
|
|
|
- }
|
|
|
-
|
|
|
- &.ri-exchange-cny-fill {
|
|
|
- color: #f56c6c;
|
|
|
- background: #fef0f0;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .text {
|
|
|
- padding-left: 10px;
|
|
|
- color: #9499a0;
|
|
|
-
|
|
|
- .num {
|
|
|
- font-size: 22px;
|
|
|
- font-weight: bold;
|
|
|
- color: #333;
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- .chart-row {
|
|
|
- // height: calc(40% - 12px);
|
|
|
- // .el-card {
|
|
|
- // height: 100%;
|
|
|
- // display: flex;
|
|
|
- // flex-direction: column;
|
|
|
- // ::v-deep .el-card__body {
|
|
|
- // flex: 1;
|
|
|
- // > div {
|
|
|
- // height: 100%;
|
|
|
- // width: 100%;
|
|
|
- // }
|
|
|
- // }
|
|
|
- // }
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
.right {
|
|
|
@@ -573,7 +695,6 @@
|
|
|
height: 48px;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
-
|
|
|
ul {
|
|
|
flex: 1;
|
|
|
display: flex;
|
|
|
@@ -585,7 +706,8 @@
|
|
|
flex-direction: column;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
-
|
|
|
+ user-select: none;
|
|
|
+ cursor: pointer;
|
|
|
&.active span:last-child {
|
|
|
background: rgb(34, 76, 218);
|
|
|
color: #fff;
|
|
|
@@ -675,9 +797,104 @@
|
|
|
::v-deep .el-timeline-item__tail {
|
|
|
border-left: 2px dashed #e4e7ed;
|
|
|
}
|
|
|
-
|
|
|
- #funnel,
|
|
|
- #bar {
|
|
|
- height: 300px;
|
|
|
+ // #funnel,
|
|
|
+ // #bar {
|
|
|
+ // height: 100%;
|
|
|
+ // }
|
|
|
+ .vue-grid-layout {
|
|
|
+ margin-left: -10px;
|
|
|
+ margin-right: -10px;
|
|
|
+ &.grid {
|
|
|
+ background: linear-gradient(90deg, #fff 10px, transparent 0), linear-gradient(#fff 10px, transparent 0);
|
|
|
+ background-size: calc((100% - 10px) / 24) 40px;
|
|
|
+ background-position: top 0px left 0px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .vue-grid-item {
|
|
|
+ background: #fff;
|
|
|
+ border: 1px solid #ebeef5;
|
|
|
+ border-radius: 4px;
|
|
|
+ box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
|
|
|
+ overflow: hidden;
|
|
|
+ h4 {
|
|
|
+ line-height: 22px;
|
|
|
+ height: 54px;
|
|
|
+ font-size: 16px;
|
|
|
+ padding: 16px 20px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ border-bottom: 1px solid #ebeef5;
|
|
|
+ i {
|
|
|
+ font-size: 24px;
|
|
|
+ font-weight: bold;
|
|
|
+ cursor: pointer;
|
|
|
+ &:hover {
|
|
|
+ color: #1d66dc;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .board-container {
|
|
|
+ display: flex;
|
|
|
+ height: 60px;
|
|
|
+ border: 1px solid #eee;
|
|
|
+ align-items: center;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 0 10px;
|
|
|
+ flex: 1;
|
|
|
+ cursor: pointer;
|
|
|
+ user-select: none;
|
|
|
+ &:hover {
|
|
|
+ box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
|
|
|
+ }
|
|
|
+ .icon {
|
|
|
+ font-size: 32px;
|
|
|
+ border-radius: 4px;
|
|
|
+ width: 40px;
|
|
|
+ height: 40px;
|
|
|
+ color: #1d66dc;
|
|
|
+ background: #ecf5ff;
|
|
|
+ &.ri-money-cny-circle-line {
|
|
|
+ color: #e6a23c;
|
|
|
+ background: #fdf6ec;
|
|
|
+ }
|
|
|
+ &.ri-exchange-cny-fill {
|
|
|
+ color: #f56c6c;
|
|
|
+ background: #fef0f0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .full-icon {
|
|
|
+ flex: 1;
|
|
|
+ font-size: 32px;
|
|
|
+ }
|
|
|
+ .close {
|
|
|
+ font-size: 32px;
|
|
|
+ transition: 0.3s all;
|
|
|
+ &:hover {
|
|
|
+ color: #1d66dc;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .check {
|
|
|
+ font-size: 32px;
|
|
|
+ color: #67c23a;
|
|
|
+ }
|
|
|
+ .text {
|
|
|
+ padding-left: 10px;
|
|
|
+ color: #9499a0;
|
|
|
+ flex: 1;
|
|
|
+ .num {
|
|
|
+ font-size: 22px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #333;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .add-board {
|
|
|
+ height: 500px;
|
|
|
+ overflow: auto;
|
|
|
+ li + li {
|
|
|
+ margin-top: 10px;
|
|
|
+ }
|
|
|
}
|
|
|
</style>
|