图表分析-导入员工及分布

This commit is contained in:
caoqianming 2020-10-10 17:36:24 +08:00
parent baa352d0c1
commit 808d488373
20 changed files with 482 additions and 115 deletions

View File

@ -13,4 +13,26 @@ export function searchCandidates(data) {
method: 'post',
data
})
}
export function getAdmindata1() {
//各管理员录入学员数
return request({
url: '/analyse/admindata1/',
method: 'get',
})
}
export function getCompanydis() {
return request({
url: '/analyse/companydis/',
method: 'get',
})
}
export function getConsumerdis() {
return request({
url: '/analyse/consumerdis/',
method: 'get',
})
}

View File

@ -0,0 +1,55 @@
<template>
<div class="app-container">
<el-card>
<bar-chart :chartData="admindata1" />
</el-card>
<el-row :gutter="6" style="margin-top:6px">
<el-col :xs="24" :md="12">
<el-card>
<china-map :chartData="companydis" />
</el-card>
</el-col>
<el-col :xs="24" :md="12">
<el-card>
<china-map :chartData="consumerdis" />
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import BarChart from '../components/BarChart'
import ChinaMap from '../components/ChinaMap'
import { getAdmindata1, getCompanydis, getConsumerdis } from '@/api/analyse'
export default {
components:{BarChart, ChinaMap},
data(){
return {
admindata1:{},
companydis:{}
}
},
created(){
this.getadmindata1()
this.getcompanydis()
this.getconsumerdis()
},
methods:{
getadmindata1(){
getAdmindata1().then(res=>{
this.admindata1 = res.data
})
},
getcompanydis(){
getCompanydis().then(res=>{
this.companydis = res.data
})
},
getconsumerdis(){
getConsumerdis().then(res=>{
this.consumerdis = res.data
})
}
}
}
</script>

View File

@ -0,0 +1,124 @@
<template>
<div :class="className" :style="{ height: height, width: width }" />
</template>
<script>
import echarts from "echarts";
//require('echarts/theme/macarons') // echarts theme
import resize from "./mixins/resize";
const animationDuration = 1000;
export default {
mixins: [resize],
props: {
className: {
type: String,
default: "chart",
},
width: {
type: String,
default: "100%",
},
height: {
type: String,
default: "300px",
},
chartData: {
type: Object,
required: true,
},
},
data() {
return {
chart: null,
};
},
watch: {
chartData: {
deep: true,
handler(val) {
this.initChart(val);
},
},
},
mounted() {
this.$nextTick(() => {
this.initChart();
});
},
beforeDestroy() {
if (!this.chart) {
return;
}
this.chart.dispose();
this.chart = null;
},
methods: {
initChart() {
this.chart = echarts.init(this.$el, "macarons");
if (!this.chartData.s) {
return;
}
let series = [];
for (var i = 0; i < this.chartData.s.length; i++) {
series.push({
name: this.chartData.s[i].name,
type: "bar",
stack: "vistors",
barWidth: "60%",
data: this.chartData.s[i].data,
animationDuration,
});
}
this.chart.setOption({
title: {
text: this.chartData.t,
},
tooltip: {
trigger: "axis",
axisPointer: {
//
type: "shadow", // 线'line' | 'shadow'
},
},
toolbox: {
show: true,
feature: {
dataView: { show: true, readOnly: true },
saveAsImage: { show: true },
},
},
grid: {
top: 40,
left: "2%",
right: "2%",
bottom: "3%",
containLabel: true,
},
xAxis: [
{
type: "category",
data: this.chartData.x.data,
axisTick: {
alignWithLabel: true,
},
"axisLabel":{
interval: 0
}
},
],
yAxis: [
{
type: "value",
axisTick: {
show: false,
},
},
],
series: series,
});
},
},
};
</script>

View File

@ -0,0 +1,175 @@
<template>
<div :class="className" :style="{ height: height, width: width }" />
</template>
<script>
import echarts from "echarts";
//require('echarts/theme/macarons') // echarts theme
require('echarts/map/js/china')
import resize from "./mixins/resize";
const animationDuration = 1000;
const nameMap = {
"南海诸岛" : "南海诸岛",
'北京市' :'北京',
'天津市' :'天津',
'上海市' :'上海',
'重庆市' :'重庆',
'河北省' :'河北',
'河南省' :'河南',
'云南省' :'云南',
'辽宁省' :'辽宁',
'黑龙江省' : '黑龙江',
'湖南省' :'湖南',
'安徽省' :'安徽',
'山东省' :'山东',
'新疆维吾尔自治区' :'新疆',
'江苏省' :'江苏',
'浙江省' :'浙江',
'江西省' :'江西',
'湖北省' :'湖北',
'广西壮族自治区' : '广西',
'甘肃省' :'甘肃',
'山西省' :'山西',
'内蒙古自治区' : "内蒙古",
'陕西省' :'陕西',
'吉林省' :'吉林',
'福建省' :'福建',
'贵州省' :'贵州',
'广东省' :'广东',
'青海省' :'青海',
'西藏自治区' :'西藏',
'四川省' :'四川',
'宁夏回族自治区' :'宁夏',
'海南省' :'海南',
'台湾' :'台湾',
'香港' :'香港',
'澳门' :'澳门'
}
export default {
mixins: [resize],
props: {
className: {
type: String,
default: "chart",
},
width: {
type: String,
default: "100%",
},
height: {
type: String,
default: "400px",
},
chartData: {
type: Object,
required: true,
},
},
data() {
return {
chart: null,
};
},
watch: {
chartData: {
deep: true,
handler(val) {
this.initChart(val);
},
},
},
mounted() {
this.$nextTick(() => {
this.initChart();
});
},
beforeDestroy() {
if (!this.chart) {
return;
}
this.chart.dispose();
this.chart = null;
},
methods: {
initChart() {
this.chart = echarts.init(this.$el, "macarons");
if(!this.chartData.t){
return
}
var optionMap = {
title: {
text: this.chartData.t,
},
tooltip: {},
legend: {
orient: 'vertical',
left: 'left',
data:['']
},
visualMap: {
min: 0,
max: 10000,
left: '5%',
top: 'bottom',
text: ['多','少'],
calculable : true,
color:['#0237fe','#edf1fe']
},
geo: {
map: 'china',
zoom: 1.2,
label: {
show: true
},
itemStyle: {
borderColor: 'rgba(0, 0, 0, 0.2)',
emphasis: {
shadowBlur: 20,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
},
series : [
{
name: '分布',
type: 'map',
left:'20%',
geoIndex: 0,
// mapType: 'china',
// selectedMode: true,//single ;multiple flase
// itemStyle: {
// normal:{
// borderColor: 'rgba(0, 0, 0, 0.2)',
// },
// emphasis:{
// label: {
// show: true,//
// },
// areaColor:'#d97a80',//
// shadowOffsetX: 0,
// shadowOffsetY: 0,
// shadowBlur: 20,
// borderWidth:0,
// shadowColor: 'rgba(0, 0, 0, 0.5)',
// }
// },
// showLegendSymbol: false,
// label: {
// normal: {
// show: false
// },
// emphasis: {
// show: false
// }
// },
data:this.chartData.s
}
]
}
this.chart.setOption(optionMap);
}
},
};
</script>

View File

@ -4,7 +4,7 @@
<script>
import echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
// require('echarts/theme/macarons') // echarts theme
import resize from './mixins/resize'
export default {
@ -63,6 +63,9 @@ export default {
},
setOptions({ expectedData, actualData } = {}) {
this.chart.setOption({
title:{
text:'趋势分析'
},
xAxis: {
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
boundaryGap: false,

View File

@ -1,102 +0,0 @@
<template>
<div :class="className" :style="{height:height,width:width}" />
</template>
<script>
import echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import resize from './mixins/resize'
const animationDuration = 6000
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '300px'
}
},
data() {
return {
chart: null
}
},
mounted() {
this.$nextTick(() => {
this.initChart()
})
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(this.$el, 'macarons')
this.chart.setOption({
tooltip: {
trigger: 'axis',
axisPointer: { //
type: 'shadow' // 线'line' | 'shadow'
}
},
grid: {
top: 10,
left: '2%',
right: '2%',
bottom: '3%',
containLabel: true
},
xAxis: [{
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
axisTick: {
alignWithLabel: true
}
}],
yAxis: [{
type: 'value',
axisTick: {
show: false
}
}],
series: [{
name: 'pageA',
type: 'bar',
stack: 'vistors',
barWidth: '60%',
data: [79, 52, 200, 334, 390, 330, 220],
animationDuration
}, {
name: 'pageB',
type: 'bar',
stack: 'vistors',
barWidth: '60%',
data: [80, 52, 200, 334, 390, 330, 220],
animationDuration
}, {
name: 'pageC',
type: 'bar',
stack: 'vistors',
barWidth: '60%',
data: [30, 52, 200, 334, 390, 330, 220],
animationDuration
}]
})
}
}
}
</script>

View File

@ -3,15 +3,16 @@
<panel-group @handleSetLineChartData="handleSetLineChartData" />
<el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
<line-chart :chart-data="lineChartData" />
<bar-chart :chartData="admindata1" />
</el-row>
</div>
</template>
<script>
import PanelGroup from './components/PanelGroup'
import LineChart from './components/LineChart'
import PanelGroup from '../components/PanelGroup'
import LineChart from '../components/LineChart'
import BarChart from '../components/BarChart'
import { getAdmindata1, getCompanydis, getConsumerdis } from '@/api/analyse'
const lineChartData = {
'访问用户': {
expectedData: [100, 120, 161, 134, 105, 160, 165],
@ -36,16 +37,26 @@ export default {
components: {
PanelGroup,
LineChart,
BarChart
},
data() {
return {
lineChartData: lineChartData.注册用户
lineChartData: lineChartData.访问用户,
admindata1:{}
}
},
created() {
this.getadmindata1()
},
methods: {
handleSetLineChartData(type) {
this.lineChartData = lineChartData[type]
}
},
getadmindata1(){
getAdmindata1().then(res=>{
this.admindata1 = res.data
})
},
}
}
</script>

View File

@ -7,5 +7,8 @@ from .views import *
urlpatterns = [
path('basic/', BasicCount.as_view()),
path('quota/', Quota.as_view()),
path('admindata1/', Admindata1.as_view()),
path('companydis/', Companydis.as_view()),
path('consumerdis/', Consumerdis.as_view()),
path('searchcandidates/', SearchCandidates.as_view())
]

View File

@ -10,6 +10,8 @@ from question.models import Question
import pickle
import requests
from lxml import etree
from django.db.models import Count
from rbac.models import UserProfile
# Create your views here.
class BasicCount(APIView):
@ -23,7 +25,42 @@ class BasicCount(APIView):
ret['test_count'] = ExamTest.objects.filter(is_delete=False).count()
ret['question_count'] = Question.objects.filter(is_delete=False).count()
return Response(ret)
class Admindata1(APIView):
"""
各管理员录入学员数-柱状图
"""
def get(self, request, format=None):
ret = {'x':{'name':'管理员', 'data':[]}, 's':[{'name':'学员数', 'data':[]}], 't':'各管理员录入学员数'}
tmp = UserProfile.objects.filter(is_delete=False).annotate(total=Count('consumer_create_admin')).order_by('-total').values('username', 'total')
for i in tmp:
ret['x']['data'].append(i['username'])
ret['s'][0]['data'].append(i['total'])
return Response(ret)
class Companydis(APIView):
"""
单位分布
"""
def get(self, request, format=None):
ret = {'s':[{'name':'浙江', 'value':5000}], 't':'单位分布'}
# tmp = UserProfile.objects.filter(is_delete=False).annotate(total=Count('consumer_create_admin')).order_by('-total').values('username', 'total')
# for i in tmp:
# ret['x']['data'].append(i['username'])
# ret['s'][0]['data'].append(i['total'])
return Response(ret)
class Consumerdis(APIView):
"""
学员分布
"""
def get(self, request, format=None):
ret = {'s':[{'name':'河北', 'value':5000}], 't':'学员分布'}
# tmp = UserProfile.objects.filter(is_delete=False).annotate(total=Count('consumer_create_admin')).order_by('-total').values('username', 'total')
# for i in tmp:
# ret['x']['data'].append(i['username'])
# ret['s'][0]['data'].append(i['total'])
return Response(ret)
class Quota(APIView):
'''
获取考试名额

View File

@ -13,7 +13,7 @@ class Company(CommonModel):
name = models.CharField(max_length=60, verbose_name='名称', unique=True)
pid = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='')
create_admin = models.ForeignKey(UserProfile, default=1, on_delete=models.DO_NOTHING)
geo = JSONField('地理位置', null=True, blank=True)
class Meta:
verbose_name = '客户企业'
verbose_name_plural = verbose_name
@ -73,7 +73,7 @@ class Consumer(CommonModel):
realname = models.CharField('真实姓名', max_length=100, null=True, blank=True)
ID_number1 = models.CharField('身份证号', max_length=100, null=True, blank=True)
create_admin = models.ForeignKey(UserProfile, on_delete=models.SET_NULL, null=True, blank=True)
create_admin = models.ForeignKey(UserProfile, on_delete=models.SET_NULL, null=True, blank=True, related_name='consumer_create_admin')
exceed_date = models.DateField('账号过期', null=True, blank=True)

View File

@ -30,11 +30,10 @@ from .filters import ConsumerFilter
from .exports import export_consumer
from .models import Company, Consumer, PaySubject, SendCode, ConsumerPerm, ConsumerRole
from .serializers import CompanySerializer, ConsumerSerializer, ConsumerPermSerializer, ConsumerRoleSerializer, ConsumerDetailSerializer
import requests
from lxml import etree
from rbac.models import UserProfile
from django.http import Http404
import time
appid = 'wxf1e9471c93f05ad6'
secret = '4bf7f9bd6c52634586bbe792a1f0a834'
sms_appid = '100172'
@ -92,6 +91,16 @@ class ConsumerPermViewSet(ModelViewSet):
ordering_fields = ['create_time']
ordering = ['-create_time']
def getPosition(address):
url = 'http://restapi.amap.com/v3/geocode/geo'
par = {'address': address, 'key': '86e0993305a427ac2d0b5371ad97f242'}
res = requests.get(url, par)
json_data = json.loads(res.text)
if json_data['status'] == '1' and int(json_data['count']) > 0:
return json_data
return None
class CompanyViewSet(ModelViewSet):
"""
客户企业增删改查
@ -108,7 +117,18 @@ class CompanyViewSet(ModelViewSet):
ordering = ['-id']
def perform_create(self, serializer):
serializer.save(create_admin=self.request.user)
instance = serializer.save(create_admin=self.request.user)
geo = getPosition(instance.name)
if geo:
instance.geo = geo
instance.save()
def perform_update(self, serializer):
instance = serializer.save()
geo = getPosition(instance.name)
if geo:
instance.geo = geo
instance.save()
def get_queryset(self):
queryset = self.queryset
@ -150,6 +170,21 @@ class CompanyViewSet(ModelViewSet):
else:
return Response({"error":"账号错误"})
@action(methods=['put'], detail=False, url_name='correct_geo',perms_map=[{'*':'correct_geo'}])
def correctgeo(self, request, *args, **kwargs):
"""
地理位置
"""
companys = Company.objects.exclude(geo__isnull=True).order_by('-create_time')
for i in companys:
geo = getPosition(i.name)
if geo:
i.geo = geo
i.save()
time.sleep(1)
return Response(status=status.HTTP_200_OK)
class ConsumerViewSet(ModelViewSet):
"""
学员增删改查
@ -374,6 +409,10 @@ class ConsumerViewSet(ModelViewSet):
companyobj = Company.objects.get(name=companyname)
else:
companyobj = Company.objects.create(name=companyname, create_admin=request.user)
geo = getPosition(companyobj.name)
if geo:
companyobj.geo = geo
companyobj.save()
workscope = sheet['d'+str(m)].value
role = sheet['e'+str(m)].value
if Consumer.objects.filter(username = username).exists():