Commit 9a98f2c8 authored by daywrite's avatar daywrite

图表需求

parent a3cf1341
...@@ -89,6 +89,12 @@ ...@@ -89,6 +89,12 @@
"title": "系统设置", "title": "系统设置",
"appName": 'settings', "appName": 'settings',
"url": "/setting" "url": "/setting"
}, {
"icon": "fa-home",
"isRouteShow": 1,
"title": "统计分析",
"appName": 'analysis',
"url": "/analysis"
}], }],
homePage: { homePage: {
appName: 'reimbursement', appName: 'reimbursement',
......
.analysis-app {
.mt10 {
margin-top:10px;
}
.title-two {
margin: 0;
padding-left: 10px;
border-left-width: 2px;
border-left-style: solid;
border-left-color: #649fd7;
font-weight: 400;
font-size: 1.3em;
color: #649fd7;
}
}
...@@ -8,4 +8,5 @@ ...@@ -8,4 +8,5 @@
@import './profile-app.scss'; @import './profile-app.scss';
@import './service-app.scss'; @import './service-app.scss';
@import './punch-app.scss'; @import './punch-app.scss';
@import './setting\-app.scss'; @import './setting-app.scss';
@import './analysis-app.scss'
<template>
<section>
<div class="content">
<search-header
ref="searchHeader"
:title="'销售数据'"
@update:headerClear="() => searchClear()">
</search-header>
<time-search-form
ref="timeSearchForm"
formSearchKey="projectSearch"
@update:list="search => timeSearchForm(search)">
</time-search-form>
<search-form
ref="clientForm"
:filter="filter"
@update:clientList="form =>{ updateForm(form) }">
</search-form>
<div class="page-body-content">
<div class="mb10">
<singleRadioTool
:form-item="type"
:options-list="navArray"
@update:item="val => { typeChange(val) }">
</singleRadioTool>
</div>
<div class="mt10">
<el-row class="header-title" style="height: 100%;">
<el-col>
<span class="title-two">销售简报</span>
<countArr :list="result.countList"></countArr>
</el-col>
</el-row>
<el-row class="header-title" style="height: 100%;">
<el-col>
<span class="title-two">利润贡献</span>
<div id="c1" style="height:400px;"></div>
</el-col>
</el-row>
<el-row class="header-title" style="height: 100%;">
<el-col>
<span class="title-two">销售漏斗</span>
<div id="c1" style="height:400px;"></div>
</el-col>
</el-row>
<el-row class="header-title" style="height: 100%;">
<el-col>
<span class="title-two">商机成交</span>
</el-col>
<el-col :span="6"><div id="c3-1" style="height: 400px;"></div></el-col>
<el-col :span="6"><div id="c3-2" style="height: 400px;"></div></el-col>
<el-col :span="6"><div id="c3-3" style="height: 400px;"></div></el-col>
<el-col :span="6"><div id="c3-4" style="height: 400px;"></div></el-col>
</el-row>
<el-row class="header-title" style="height: 100%;">
<el-col>
<span class="title-two">明确需求</span>
<div id="c1" style="height:400px;"></div>
</el-col>
</el-row>
<el-row class="header-title" style="height: 100%;">
<el-col>
<span class="title-two">隐形需求</span>
<div id="c1" style="height:400px;"></div>
</el-col>
</el-row>
</div>
</div>
</div>
</section>
</template>
<script>
import SearchHeader from '../../common/searchHeader'
import SearchForm from '../../common/SearchForm'
import countArr from './countArr'
import TimeSearchForm from './timeSearchForm'
import singleRadioTool from '../../common/singleRadioTool'
import {
requestAPI,
api
} from '@/lib/commonMixin'
export default {
name: 'caseHome',
components: {
SearchHeader,
SearchForm,
TimeSearchForm,
singleRadioTool,
countArr
},
data () {
return {
filter: [],
form: {
},
type: 'all',
navArray: [],
result: {
countList: [{
key: 1,
name: 1,
value: 1,
bgcolor: 'red'
}, {
key: 1,
name: 1,
value: 1,
bgcolor: 'red'
}, {
key: 1,
name: 1,
value: 1,
bgcolor: 'red'
}, {
key: 1,
name: 1,
value: 1,
bgcolor: 'red'
}, {
key: 1,
name: 1,
value: 1,
bgcolor: 'red'
}, {
key: 1,
name: 1,
value: 1,
bgcolor: 'red'
}, {
key: 1,
name: 1,
value: 1,
bgcolor: 'red'
}, {
key: 1,
name: 1,
value: 1,
bgcolor: 'red'
}, {
key: 1,
name: 1,
value: 1,
bgcolor: 'red'
}, {
key: 1,
name: 1,
value: 1,
bgcolor: 'red'
}, {
key: 1,
name: 1,
value: 1,
bgcolor: 'red'
}]
}
}
},
mounted () {
this.init()
},
methods: {
init () {
this.getFilter()
// 利润图表
this.c1()
this.c31()
this.c32()
this.c33()
this.c34()
},
/* eslint-disable */
c34 () {
Highcharts.chart('c3-4', {
chart: {
type: 'column'
},
title: {
text: '堆叠柱形图'
},
xAxis: {
categories: ['苹果', '橘子']
},
yAxis: {
min: 0,
title: {
text: '水果消费总量'
},
stackLabels: { // 堆叠数据标签
enabled: true,
style: {
fontWeight: 'bold',
color: (Highcharts.theme && Highcharts.theme.textColor) || 'gray'
}
}
},
legend: {
align: 'right',
x: -30,
verticalAlign: 'top',
y: 25,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.background2) || 'white',
borderColor: '#CCC',
borderWidth: 1,
shadow: false
},
tooltip: {
formatter: function () {
return '<b>' + this.x + '</b><br/>' +
this.series.name + ': ' + this.y + '<br/>' +
'总量: ' + this.point.stackTotal;
}
},
plotOptions: {
column: {
stacking: 'normal',
dataLabels: {
enabled: true,
color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'white',
style: {
// 如果不需要数据标签阴影,可以将 textOutline 设置为 'none'
textOutline: '1px 1px black'
}
}
}
},
series: [{
name: '小张',
data: [5, 3]
}, {
name: '小彭',
data: [2, 2]
}, {
name: '小潘',
data: [3, 4]
}]
});
},
c33 () {
Highcharts.chart('c3-3', {
chart: {
type: 'column'
},
title: {
text: '堆叠柱形图'
},
xAxis: {
categories: ['苹果', '橘子']
},
yAxis: {
min: 0,
title: {
text: '水果消费总量'
},
stackLabels: { // 堆叠数据标签
enabled: true,
style: {
fontWeight: 'bold',
color: (Highcharts.theme && Highcharts.theme.textColor) || 'gray'
}
}
},
legend: {
align: 'right',
x: -30,
verticalAlign: 'top',
y: 25,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.background2) || 'white',
borderColor: '#CCC',
borderWidth: 1,
shadow: false
},
tooltip: {
formatter: function () {
return '<b>' + this.x + '</b><br/>' +
this.series.name + ': ' + this.y + '<br/>' +
'总量: ' + this.point.stackTotal;
}
},
plotOptions: {
column: {
stacking: 'normal',
dataLabels: {
enabled: true,
color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'white',
style: {
// 如果不需要数据标签阴影,可以将 textOutline 设置为 'none'
textOutline: '1px 1px black'
}
}
}
},
series: [{
name: '小张',
data: [5, 3]
}, {
name: '小彭',
data: [2, 2]
}, {
name: '小潘',
data: [3, 4]
}]
});
},
c32 () {
Highcharts.chart('c3-2', {
chart: {
type: 'column'
},
title: {
text: '堆叠柱形图'
},
xAxis: {
categories: ['苹果', '橘子']
},
yAxis: {
min: 0,
title: {
text: '水果消费总量'
},
stackLabels: { // 堆叠数据标签
enabled: true,
style: {
fontWeight: 'bold',
color: (Highcharts.theme && Highcharts.theme.textColor) || 'gray'
}
}
},
legend: {
align: 'right',
x: -30,
verticalAlign: 'top',
y: 25,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.background2) || 'white',
borderColor: '#CCC',
borderWidth: 1,
shadow: false
},
tooltip: {
formatter: function () {
return '<b>' + this.x + '</b><br/>' +
this.series.name + ': ' + this.y + '<br/>' +
'总量: ' + this.point.stackTotal;
}
},
plotOptions: {
column: {
stacking: 'normal',
dataLabels: {
enabled: true,
color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'white',
style: {
// 如果不需要数据标签阴影,可以将 textOutline 设置为 'none'
textOutline: '1px 1px black'
}
}
}
},
series: [{
name: '小张',
data: [5, 3]
}, {
name: '小彭',
data: [2, 2]
}, {
name: '小潘',
data: [3, 4]
}]
});
},
c31 () {
Highcharts.chart('c3-1', {
chart: {
type: 'column'
},
title: {
text: '堆叠柱形图'
},
xAxis: {
categories: ['苹果', '橘子']
},
yAxis: {
min: 0,
title: {
text: '水果消费总量'
},
stackLabels: { // 堆叠数据标签
enabled: true,
style: {
fontWeight: 'bold',
color: (Highcharts.theme && Highcharts.theme.textColor) || 'gray'
}
}
},
legend: {
align: 'right',
x: -30,
verticalAlign: 'top',
y: 25,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.background2) || 'white',
borderColor: '#CCC',
borderWidth: 1,
shadow: false
},
tooltip: {
formatter: function () {
return '<b>' + this.x + '</b><br/>' +
this.series.name + ': ' + this.y + '<br/>' +
'总量: ' + this.point.stackTotal;
}
},
plotOptions: {
column: {
stacking: 'normal',
dataLabels: {
enabled: true,
color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'white',
style: {
// 如果不需要数据标签阴影,可以将 textOutline 设置为 'none'
textOutline: '1px 1px black'
}
}
}
},
series: [{
name: '小张',
data: [5, 3]
}, {
name: '小彭',
data: [2, 2]
}, {
name: '小潘',
data: [3, 4]
}]
});
},
c1 () {
Highcharts.chart('c1', {
chart: {
type: 'column'
},
title: {
text: '2015年1月-5月,各浏览器的市场份额'
},
subtitle: {
text: '点击可查看具体的版本数据,数据来源: <a href="https://netmarketshare.com">netmarketshare.com</a>.'
},
xAxis: {
type: 'category'
},
yAxis: {
title: {
text: ''
},
labels: {
formatter: function () {
return (this.value / 10000) + '万'
},
},
plotLines:[{
color:'red',
dashStyle:'solid',
value: 100000,
label: '100000',
width:2
}]
},
legend: {
enabled: false
},
plotOptions: {
series: {
borderWidth: 0,
dataLabels: {
enabled: true,
format: '{point.y}'
}
}
},
tooltip: {
headerFormat: '<span style="font-size:11px">{series.name}</span><br>',
pointFormat: '<span style="color:{point.color}">{point.name}</span>: <b>{point.y:.2f}%</b> of total<br/>'
},
series: [{
name: '浏览器品牌',
colorByPoint: true,
data: [{
name: '刘人诚',
y: 1997600,
drilldown: '刘人诚'
}, {
name: '刘曦林',
y: 50000,
drilldown: '刘曦林'
}, {
name: '六老五',
y: 0,
drilldown: '六老五'
}]
}],
drilldown: {
series: [{
name: '刘人诚',
id: '刘人诚',
data: [
[
'上海契佳经贸发展有限公司',
1997600
]
]
}, {
name: '刘曦林',
id: '刘曦林',
data: [
[
'北京首东物业管理有限公司(首东国际投资有限公司)',
50000
]
]
}, {
name: '六老五',
id: '六老五',
data: [
[
'刘老五',
0
]
]
}]
}
});
},
// 1.查询条件
getFilter () {
requestAPI(api.getCaseFilter).then(res => {
let _inx = res.findIndex(item => item.key === 'CaseSearch[case_status]')
let _newRes = res.splice(_inx, 1)
this.filter = res
let _navArray = _newRes[0].value
_navArray.unshift({key: 'all', name: '全部'})
this.navArray = _navArray
})
},
typeChange (val) {
let ret = this.setParams({
...this.form,
page: this.pagenation.thispage
}, { 'CaseSearch[case_status]': val })
this.getList(ret)
},
// 3.2关键字后面的重置
searchClear () {
},
// 5.1查询条件
updateForm (search) {
let ret = this.setParams({
...this.form,
page: this.pagenation.thispage
}, search)
this.getList(ret)
},
// 5.3 TimeSearchForm
timeSearchForm (search) {
let ret = this.setParams({
...this.form,
page: this.pagenation.thispage
}, search)
this.getList(ret)
}
}
}
</script>
<style scoped lang="scss">
@include c('opearate-button') {
> .el-button {
margin-right:0px;
}
& .btn-primary .badge {
color: #333744;
background-color: #fff;
}
& .badge {
position: relative;
top: 0px;
left: -5px;
display: inline-block;
padding: 0px 5px;
font-size: 12px;
font-weight: 700;
line-height: 1;
text-align: center;
white-space: nowrap;
vertical-align: baseline;
border-radius: .25rem;
background:white;
color:#333744;
}
i {
display: inline-block;
padding-right: 3px;
}
}
</style>
<template>
<section class="obear-countArr-section">
<div class="obear-countArr-row">
<div class="obear-countArr-row__col" v-for="item in list" :key="item.key">
<div class="obear-countArr-option" :style="{'background-color': item.color}">
<span class="obear-countArr-option__label">{{ item.name }}</span>
<span class="obear-countArr-option__number">{{ item.value }}</span>
<span class="obear-countArr-option__unit"></span>
</div>
</div>
</div>
</section>
</template>
<script>
export default {
name: 'countArr',
props: {
list: Array
}
}
</script>
<style lang="scss" scoped>
@include c('countArr-section'){
background-color:white;
}
@include c('countArr-row'){
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
justify-content:start;
align-items:center;
@include e('col'){
position: relative;
// width: 100%;
width: 16.66%;
min-height: 1px;
padding-right: 15px;
padding-left: 15px;
// -ms-flex-preferred-size: 0;
// flex-basis: 0;
// -ms-flex-positive: 1;
// flex-grow: 1;
// max-width: 100%;
}
}
@include c('countArr-option'){
position: relative;
margin-top: 15px;
margin-bottom: 15px;
color: #FFF;
padding: 0 0 6px;
text-align: center;
border-top-right-radius: 4px;
border-top-left-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
background-color:#98c450;
@include e('label'){
display: block;
color: #fff;
font-size: 14px;
padding: 3px 0;
margin-bottom: 3px;
border-bottom: 1px solid #FFF;
border-top-right-radius: 4px;
border-top-left-radius: 4px;
}
@include e('number'){
font-size: 22px;
}
}
@include c('report-link'){
color: #FFF;
position: absolute;
bottom: 6px;
right: 6px;
}
</style>
<template>
<section>
<el-row class="form-content-time-top">
<el-form ref="clientTimeForm" :model="clientTimeForm" size="mini">
<el-col :span="8" :xs="24">
<el-form-item label="提交时间:" label-width="42">
<el-radio-group v-model="clientTimeForm[formSearchKey + '[period]']" size="mini">
<el-radio-button label="all">本周</el-radio-button>
<el-radio-button label="today">上周</el-radio-button>
<el-radio-button label="tomorrow">本月</el-radio-button>
<el-radio-button label="aftertomorrow">上月</el-radio-button>
</el-radio-group>
<el-dropdown>
<el-button type="primary" size="mini">
本财年<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>2017年</el-dropdown-item>
<el-dropdown-item>2018年</el-dropdown-item>
<el-dropdown-item>2019年</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-form-item>
</el-col>
</el-form>
<el-form ref="clientTimeRange" :model="clientTimeRange" size="mini">
<el-col :span="8" :offset="0" :xs="{span: 24, offset: 0}" class="form-content-time-range">
<el-form-item label-width="0">
<el-date-picker
size="mini"
v-model="clientTimeRange.from"
type="date"
value-format="yyyy-MM-dd"
placeholder="开始时间">
</el-date-picker>
<el-date-picker
size="mini"
v-model="clientTimeRange.to"
type="date"
value-format="yyyy-MM-dd"
placeholder="结束时间">
</el-date-picker>
<el-button type="primary" size="mini" @click="setSearchTime">确定</el-button>
</el-form-item>
</el-col>
</el-form>
</el-row>
</section>
</template>
<script>
import setParams from '../../common/setParams'
export default {
name: 'timeSearchForm',
mixins: [setParams],
props: ['formSearchKey'],
data () {
return {
clientTimeForm: {},
clientTimeRange: {
from: '',
to: ''
}
}
},
created () {
this.initParams()
this.init()
},
methods: {
init () {
this.$watch('clientTimeForm', (val) => {
let perid = val[this.formSearchKey + '[period]']
this.$emit('update:list', Object.assign({}, {[this.formSearchKey + '[period]']: perid}))
}, {deep: true})
},
initParams () {
this.setInitParams((ret) => {
this.$set(this.clientTimeForm, this.formSearchKey + '[period]', ret[this.formSearchKey + '[period]'] || 'all')
this.clientTimeRange.from = ret[this.formSearchKey + '[from]'] || ''
this.clientTimeRange.to = ret[this.formSearchKey + '[to]'] || ''
})
},
resetForm () {
this.clientTimeForm[this.formSearchKey + '[period]'] = 'all'
this.clientTimeRange.from = ''
this.clientTimeRange.to = ''
},
setSearchTime () {
let from = this.clientTimeRange.from
let to = this.clientTimeRange.to
this.$emit('update:list', Object.assign({}, {
[this.formSearchKey + '[from]']: from,
[this.formSearchKey + '[to]']: to
}, this.clientTimeForm))
}
},
watch: {
'formSearchKey': {
handler (val) {
this.$set(this.clientTimeForm, val + '[period]', 'all')
},
immediate: true
},
'clientTimeRange.from' (val) {
if (new Date(val) >= new Date(this.clientTimeRange.to)) {
this.clientTimeRange.to = val
}
},
'clientTimeRange.to' (val) {
if (new Date(val) <= new Date(this.clientTimeRange.from)) {
this.clientTimeRange.from = val
}
}
}
}
</script>
<style scoped>
.form-content-time-top {
background: #FFF;
}
.form-content-time-top .el-form-item {
margin: 7px 0 9px;
}
.form-content-time-top .el-col {
padding: 0 15px;
}
</style>
...@@ -11,6 +11,7 @@ import ProfileRoute from './routes/profile' ...@@ -11,6 +11,7 @@ import ProfileRoute from './routes/profile'
import ServiceRoute from './routes/service' import ServiceRoute from './routes/service'
import PunchRoute from './routes/punch' import PunchRoute from './routes/punch'
import SettingRoute from './routes/setting' import SettingRoute from './routes/setting'
import AnalysisRoute from './routes/analysis'
let routes = [] let routes = []
let reimRoutes = [] let reimRoutes = []
...@@ -23,6 +24,7 @@ let profileRoute = [] ...@@ -23,6 +24,7 @@ let profileRoute = []
let serviceRoute = [] let serviceRoute = []
let punchRoute = [] let punchRoute = []
let settingRoute = [] let settingRoute = []
let analysisRoute = []
const appName = 'schedule' const appName = 'schedule'
routes = [].concat(ScheduleRoute) routes = [].concat(ScheduleRoute)
...@@ -36,6 +38,7 @@ profileRoute = [].concat(ProfileRoute) ...@@ -36,6 +38,7 @@ profileRoute = [].concat(ProfileRoute)
serviceRoute = [].concat(ServiceRoute) serviceRoute = [].concat(ServiceRoute)
punchRoute = [].concat(PunchRoute) punchRoute = [].concat(PunchRoute)
settingRoute = [].concat(SettingRoute) settingRoute = [].concat(SettingRoute)
analysisRoute = [].concat(AnalysisRoute)
let RouterInit = () => { let RouterInit = () => {
portal.createApp(appName, {}, app => { portal.createApp(appName, {}, app => {
...@@ -71,6 +74,9 @@ let RouterInit = () => { ...@@ -71,6 +74,9 @@ let RouterInit = () => {
portal.createApp('settings', {}, app => { portal.createApp('settings', {}, app => {
app.mapRoute(settingRoute) app.mapRoute(settingRoute)
}) })
portal.createApp('analysis', {}, app => {
app.mapRoute(analysisRoute)
})
// portal.createApp('client', {}, app => { // portal.createApp('client', {}, app => {
// app.mapRoute([ // app.mapRoute([
// { // {
......
import AnalysisHome from '../components/analysis/analysis/analysisHome'
const routes = [{
path: '/analysis',
name: 'AnalysisHome',
component: AnalysisHome
}]
export default routes
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment