于宏哲PHP 10 months ago
parent
commit
ab5c3f947a
  1. 19
      admin/src/app/views/campus_person_role/components/campus-person-role-edit.vue
  2. 46
      admin/src/app/views/statistics/components/PerformanceTable.vue
  3. 527
      admin/src/app/views/statistics/home.vue
  4. 188
      admin/src/app/views/statistics/home1.vue
  5. 1
      niucloud/app/adminapi/controller/campus_person_role/CampusPersonRole.php
  6. 3
      niucloud/app/adminapi/controller/sys/System.php
  7. 5
      niucloud/app/adminapi/route/sys.php
  8. 14
      niucloud/app/common.php
  9. 41
      niucloud/app/model/personnel/PersonnelSummary.php
  10. 11
      niucloud/app/service/admin/campus_person_role/CampusPersonRoleService.php
  11. 298
      niucloud/app/service/admin/sys/SystemService.php

19
admin/src/app/views/campus_person_role/components/campus-person-role-edit.vue

@ -93,6 +93,16 @@
/> />
</el-select> --> </el-select> -->
<!-- </el-form-item> --> <!-- </el-form-item> -->
<el-form-item v-if="formData.tasks.task_date" :label="`${formData.tasks.task_date} 任务`"
>
<el-input
v-model="formData.tasks.task_num"
placeholder="请输入任务数量"
/>
</el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
@ -130,7 +140,11 @@ let showDialog = ref(false)
const loading = ref(false) const loading = ref(false)
const pageName = route.meta.title const pageName = route.meta.title
// const tasks = ref([
// { month: '2025-03', value: '123', editable: false },
// { month: '2025-04', value: '123', editable: false },
// { month: '2025-05', value: '123', editable: true }, //
// ]);
/** /**
* 表单数据 * 表单数据
*/ */
@ -139,7 +153,8 @@ const initialFormData = {
campus_id: '', campus_id: '',
person_id: '', person_id: '',
role_id: '', role_id: '',
dept_id: '' dept_id: '',
tasks:{}
} }
if(pageName == '市场人员列表'){ if(pageName == '市场人员列表'){

46
admin/src/app/views/statistics/components/PerformanceTable.vue

@ -0,0 +1,46 @@
<template>
<div class="overflow-x-auto shadow-lg rounded-xl border border-gray-200 mb-6">
<table class="min-w-full text-sm text-left text-gray-700">
<thead class="bg-gray-100 text-gray-800 uppercase tracking-wider">
<tr>
<th v-for="(col, i) in columns" :key="i" class="px-4 py-2 border">
{{ col }}
</th>
</tr>
</thead>
<tbody>
<tr
v-for="(row, rIndex) in rows"
:key="rIndex"
class="hover:bg-gray-50"
>
<td v-for="(col, cIndex) in columns" :key="cIndex" class="px-4 py-2 border">
{{ row[cIndex] || '0' }}
</td>
</tr>
<!-- 合计行 -->
<tr v-if="showTotalRow" class="bg-gray-50 font-semibold text-gray-900">
<td v-for="(col, cIndex) in columns" :key="cIndex" class="px-4 py-2 border">
{{ totalRow[col] || (cIndex === 0 ? '合计' : '') }}
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script setup>
defineProps({
columns: Array,
rows: Array,
showTotalRow: {
type: Boolean,
default: false,
},
totalRow: {
type: Object,
default: () => ({}),
},
})
</script>

527
admin/src/app/views/statistics/home.vue

@ -1,188 +1,433 @@
<template> <template>
<div class="main-container"> <div class="main-container" v-loading="loading">
<!-- 实时概况 --> <!-- 实时概况 -->
<el-card shadow="never" class="!border-none"> <el-card shadow="never" class="!border-none">
<template #header> <template #header>
<span class="text-lg font-extrabold mr-[10px]">统计概括</span> <span class="text-lg font-extrabold mr-[10px]">年度业绩情况</span>
<span class="text-sm text-[#a19f98]">查看校区员工资源和学员的实时数据</span>
</template> </template>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="6"> <el-col :span="12">
<div class="text-sm text-[#a19f98] leading-8 "> <span class="text-sm">{{list.year}}年年度业绩完成情况</span>
<el-statistic :value="info.campus_count"> <div class="overflow-x-auto shadow-lg rounded-xl border border-gray-200 mb-6">
<template #title> <table class="min-w-full text-sm text-left text-gray-700">
<div style="display: inline-flex; align-items: center"> <thead class="bg-gray-100 text-gray-800 uppercase tracking-wider">
<span class="mr-[5px]">校区数量</span> <tr>
</div> <th class="px-4 py-2 border">序号</th>
</template> <th class="px-4 py-2 border">校区</th>
</el-statistic> <th class="px-4 py-2 border">任务</th>
<div class="text-sm text-[#a19f98] leading-8"> <th class="px-4 py-2 border">完成</th>
<th class="px-4 py-2 border">完成率</th>
</div> </tr>
</thead>
<tbody>
<tr v-for="(row, rIndex) in list.campus_list" :key="rIndex" class="hover:bg-gray-50">
<td class="px-4 py-2 border">{{rIndex+1}}</td>
<td class="px-4 py-2 border">{{row.campus_name}}</td>
<td class="px-4 py-2 border">{{row.year_task_num}}</td>
<td class="px-4 py-2 border">{{row.year_complete_num}}</td>
<td class="px-4 py-2 border">{{row.complete}}%</td>
</tr>
<tr>
<td class="px-4 py-2 border">合计</td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 border">{{list.complete_rate}}%</td>
</tr>
</tbody>
</table>
</div>
</el-col>
<el-col :span="12">
<span class="text-sm">{{list.year}}年年度月卡续费完成情况</span>
<div class="overflow-x-auto shadow-lg rounded-xl border border-gray-200 mb-6">
<table class="min-w-full text-sm text-left text-gray-700">
<thead class="bg-gray-100 text-gray-800 uppercase tracking-wider">
<tr>
<th class="px-4 py-2 border">序号</th>
<th class="px-4 py-2 border">校区</th>
<th class="px-4 py-2 border">到期</th>
<th class="px-4 py-2 border">续费</th>
<th class="px-4 py-2 border">续费率</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, rIndex) in list.campus_list" :key="rIndex" class="hover:bg-gray-50">
<td class="px-4 py-2 border">{{rIndex+1}}</td>
<td class="px-4 py-2 border">{{row.campus_name}}</td>
<td class="px-4 py-2 border">{{row.year_expire_num}}</td>
<td class="px-4 py-2 border">{{row.year_renew_num}}</td>
<td class="px-4 py-2 border">{{row.xf_complete}}%</td>
</tr>
<tr>
<td class="px-4 py-2 border">合计</td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 border">{{list.xf_complete_rate}}%</td>
</tr>
</tbody>
</table>
</div> </div>
</el-col> </el-col>
<el-col :span="6"> </el-row>
<div class="text-sm text-[#a19f98] leading-8 "> </el-card>
<el-statistic :value="info.personnel_count">
<template #title>
<div style="display: inline-flex; align-items: center">
<span class="mr-[5px]">员工数量</span>
</div>
</template>
</el-statistic>
<div class="text-sm text-[#a19f98] leading-8">
</div>
<el-card shadow="never" class="!border-none">
<template #header>
<span class="text-lg font-extrabold mr-[10px]">月度校区业绩情况</span>
</template>
<el-row :gutter="20">
<el-col :span="12">
<span class="text-sm">{{list.month}}月业绩完成情况</span>
<div class="overflow-x-auto shadow-lg rounded-xl border border-gray-200 mb-6">
<table class="min-w-full text-sm text-left text-gray-700">
<thead class="bg-gray-100 text-gray-800 uppercase tracking-wider">
<tr>
<th class="px-4 py-2 border">序号</th>
<th class="px-4 py-2 border">校区</th>
<th class="px-4 py-2 border">任务</th>
<th class="px-4 py-2 border">完成</th>
<th class="px-4 py-2 border">完成率</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, rIndex) in list.campus_list" :key="rIndex" class="hover:bg-gray-50">
<td class="px-4 py-2 border">{{rIndex+1}}</td>
<td class="px-4 py-2 border">{{row.campus_name}}</td>
<td class="px-4 py-2 border">{{row.month_task_num}}</td>
<td class="px-4 py-2 border">{{row.month_complete_num}}</td>
<td class="px-4 py-2 border">{{row.month_complete}}%</td>
</tr>
<tr>
<td class="px-4 py-2 border">合计</td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 border">{{list.month_complete_rate}}%</td>
</tr>
</tbody>
</table>
</div> </div>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="12">
<div class="text-sm text-[#a19f98] leading-8 "> <span class="text-sm">{{list.month}}月月卡续费完成情况</span>
<el-statistic :value="info.customerResources_count"> <div class="overflow-x-auto shadow-lg rounded-xl border border-gray-200 mb-6">
<template #title> <table class="min-w-full text-sm text-left text-gray-700">
<div style="display: inline-flex; align-items: center"> <thead class="bg-gray-100 text-gray-800 uppercase tracking-wider">
<span class="mr-[5px]">资源数量</span> <tr>
</div> <th class="px-4 py-2 border">序号</th>
</template> <th class="px-4 py-2 border">校区</th>
</el-statistic> <th class="px-4 py-2 border">到期</th>
<th class="px-4 py-2 border">续费</th>
<div class="text-sm text-[#a19f98] leading-8"> <th class="px-4 py-2 border">续费率</th>
<span>昨日新增</span> <th class="px-4 py-2 border">流失率</th>
<span>{{info.customerResources_day_count}}</span> </tr>
</div> </thead>
<tbody>
<tr v-for="(row, rIndex) in list.campus_list" :key="rIndex" class="hover:bg-gray-50">
<td class="px-4 py-2 border">{{rIndex+1}}</td>
<td class="px-4 py-2 border">{{row.campus_name}}</td>
<td class="px-4 py-2 border">{{row.month_expire_num}}</td>
<td class="px-4 py-2 border">{{row.month_renew_num}}</td>
<td class="px-4 py-2 border">{{row.month_xf_complete}}%</td>
<td class="px-4 py-2 border">{{row.ls_month_xf_complete}}%</td>
</tr>
<tr>
<td class="px-4 py-2 border">合计</td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 border">{{list.month_xf_complete_rate}}%</td>
<td class="px-4 py-2 border">{{list.ls_month_xf_complete_rate}}%</td>
</tr>
</tbody>
</table>
</div> </div>
</el-col> </el-col>
<el-col :span="6"> </el-row>
<div class="text-sm text-[#a19f98] leading-8 "> </el-card>
<el-statistic :value="info.student_count">
<template #title>
<div style="display: inline-flex; align-items: center"> <el-card shadow="never" class="!border-none">
<span class="mr-[5px]">学员数量</span>
</div> <template #header>
</template> <span class="text-lg font-extrabold mr-[10px]">月度个人业绩情况</span>
</el-statistic> </template>
<div class="text-sm text-[#a19f98] leading-8">
<span>昨日新增</span>
<span>{{info.student_day_count}}</span> <el-row :gutter="20">
</div> <el-col :span="8">
<span class="text-sm">{{list.month}}月销售业绩完成排名 </span>
<div class="overflow-x-auto shadow-lg rounded-xl border border-gray-200 mb-6">
<table class="min-w-full text-sm text-left text-gray-700">
<thead class="bg-gray-100 text-gray-800 uppercase tracking-wider">
<tr>
<th class="px-4 py-2 border">序号</th>
<th class="px-4 py-2 border">销售</th>
<th class="px-4 py-2 border">月度</th>
<th class="px-4 py-2 border">年度</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, rIndex) in list.wx_summary_list" :key="rIndex"
class="hover:bg-gray-50">
<td class="px-4 py-2 border">{{rIndex+1}}</td>
<td class="px-4 py-2 border">{{row.name}}</td>
<td class="px-4 py-2 border">{{row.complete_num}}</td>
<td class="px-4 py-2 border">{{row.year_complete_num}}</td>
</tr>
</tbody>
</table>
</div> </div>
</el-col> </el-col>
<el-col :span="8">
<span class="text-sm">{{list.month}}月销售月卡续费完成排名</span>
<div class="overflow-x-auto shadow-lg rounded-xl border border-gray-200 mb-6">
<table class="min-w-full text-sm text-left text-gray-700">
<thead class="bg-gray-100 text-gray-800 uppercase tracking-wider">
<tr>
<th class="px-4 py-2 border">序号</th>
<th class="px-4 py-2 border">销售</th>
<th class="px-4 py-2 border">到期</th>
<th class="px-4 py-2 border">续费</th>
<th class="px-4 py-2 border">续费率</th>
<th class="px-4 py-2 border">流失率</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, rIndex) in list.xf_summary_list" :key="rIndex"
class="hover:bg-gray-50">
<td class="px-4 py-2 border">{{rIndex+1}}</td>
<td class="px-4 py-2 border">{{row.name}}</td>
<td class="px-4 py-2 border">{{row.expire_num}}</td>
<td class="px-4 py-2 border">{{row.renew_num}}</td>
<td class="px-4 py-2 border">{{row.xf_complete}}%</td>
<td class="px-4 py-2 border">{{row.ls_xf_complete}}%</td>
</tr>
</tbody>
</table>
</div>
</el-col>
</el-row>
<el-col :span="8">
<span class="text-sm">{{list.month}}月教练月卡续费完成排名</span>
<div class="overflow-x-auto shadow-lg rounded-xl border border-gray-200 mb-6">
<table class="min-w-full text-sm text-left text-gray-700">
<thead class="bg-gray-100 text-gray-800 uppercase tracking-wider">
<tr>
<th class="px-4 py-2 border">序号</th>
<th class="px-4 py-2 border">教练</th>
<th class="px-4 py-2 border">到期</th>
<th class="px-4 py-2 border">续费</th>
<th class="px-4 py-2 border">续费率</th>
<th class="px-4 py-2 border">流失率</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, rIndex) in list.xf_jl_summary_list" :key="rIndex"
class="hover:bg-gray-50">
<td class="px-4 py-2 border">{{rIndex+1}}</td>
<td class="px-4 py-2 border">{{row.name}}</td>
<td class="px-4 py-2 border">{{row.expire_num}}</td>
<td class="px-4 py-2 border">{{row.renew_num}}</td>
<td class="px-4 py-2 border">{{row.xf_complete}}%</td>
<td class="px-4 py-2 border">{{row.ls_xf_complete}}%</td>
</tr>
</tbody>
</table>
</div>
</el-col>
</el-row>
</el-card> </el-card>
<!-- 实时概况 end -->
<el-row :gutter="15" class="mt-[15px]">
<el-col :span="24">
<el-card shadow="never" class="!border-none">
<template #header>
<span class="text-lg font-extrabold">资源增长趋势</span>
</template>
<div >
<el-button :type="activeRange === 'week' ? 'primary' : 'default'" size="small"
@click="changeRange('week')"></el-button>
<el-button :type="activeRange === 'month' ? 'primary' : 'default'" size="small"
@click="changeRange('month')"></el-button>
<el-button :type="activeRange === 'year' ? 'primary' : 'default'" size="small"
@click="changeRange('year')"></el-button>
<el-card shadow="never" class="!border-none">
<template #header>
<span class="text-lg font-extrabold mr-[10px]">资源及到访情况</span>
</template>
<el-row :gutter="20">
<el-col :span="12">
<span class="text-sm">{{list.month}}月资源完成情况</span>
<div class="overflow-x-auto shadow-lg rounded-xl border border-gray-200 mb-6">
<table class="min-w-full text-sm text-left text-gray-700">
<thead class="bg-gray-100 text-gray-800 uppercase tracking-wider">
<tr>
<th class="px-4 py-2 border">序号</th>
<th class="px-4 py-2 border">校区</th>
<th class="px-4 py-2 border">任务</th>
<th class="px-4 py-2 border">完成</th>
<th class="px-4 py-2 border">完成率</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, rIndex) in list.campus_list" :key="rIndex" class="hover:bg-gray-50">
<td class="px-4 py-2 border">{{rIndex+1}}</td>
<td class="px-4 py-2 border">{{row.campus_name}}</td>
<td class="px-4 py-2 border">{{row.month_task_num}}</td>
<td class="px-4 py-2 border">{{row.month_zy_complete_num}}</td>
<td class="px-4 py-2 border">{{row.month_zy_complete}}%</td>
</tr>
<tr>
<td class="px-4 py-2 border">合计</td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 border">{{list.zy_complete_rate}}%</td>
</tr>
</tbody>
</table>
</div> </div>
<div ref="visitStat" :style="{ width: '100%', height: '300px' }">
</el-col>
<el-col :span="12">
<span class="text-sm">{{list.month}}月资源到访情况</span>
<div class="overflow-x-auto shadow-lg rounded-xl border border-gray-200 mb-6">
<table class="min-w-full text-sm text-left text-gray-700">
<thead class="bg-gray-100 text-gray-800 uppercase tracking-wider">
<tr>
<th class="px-4 py-2 border">序号</th>
<th class="px-4 py-2 border">校区</th>
<th class="px-4 py-2 border">资源</th>
<th class="px-4 py-2 border">到访</th>
<th class="px-4 py-2 border">到访率</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, rIndex) in list.campus_list" :key="rIndex" class="hover:bg-gray-50">
<td class="px-4 py-2 border">{{rIndex+1}}</td>
<td class="px-4 py-2 border">{{row.campus_name}}</td>
<td class="px-4 py-2 border">{{row.month_resource_num}}</td>
<td class="px-4 py-2 border">{{row.month_visit_num}}</td>
<td class="px-4 py-2 border">{{row.visit_num_rate}}%</td>
</tr>
<tr>
<td class="px-4 py-2 border">合计</td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 border">{{list.zy_visit_complete_rate}}%</td>
</tr>
</tbody>
</table>
</div> </div>
</el-card> </el-col>
</el-col>
</el-row>
</el-row>
</el-card>
</div> </div>
</template> </template>
<script lang="ts" setup>
import { ref, reactive } from 'vue' <script setup>
import { getHome } from '@/app/api/sys' import PerformanceTable from '@/app/views/statistics/components/PerformanceTable.vue'
import * as echarts from 'echarts' import {
const visitStat = ref<any>(null) getHome
const activeRange = ref<'week' | 'month' | 'year'>('week') } from '@/app/api/sys'
import {
const info = reactive({ ref,
campus_count: 0, reactive
personnel_count: 0, } from 'vue'
customerResources_count: 0,
customerResources_day_count: 0, const loading = ref(true);
student_count: 0,
student_day_count: 0, const list = reactive({
customer: [] year: '',
month: '',
campus_list: [],
complete_rate: '',
xf_complete_rate: '',
month_complete_rate: '',
month_xf_complete_rate: '',
ls_month_xf_complete_rate: '',
wx_summary_list: [],
xf_summary_list: [],
xf_jl_summary_list: [],
zy_complete_rate: '',
zy_visit_complete_rate: ''
}) })
const changeRange = (range) => {
activeRange.value = range
Init(range) //
}
const Init = (range) => { const Init = (range) => {
loading.value = true
getHome({'date':range}) getHome({
'date': ''
})
.then((res) => { .then((res) => {
info.campus_count = res.data.campus_count list.year = res.data.year
info.personnel_count = res.data.personnel_count list.month = res.data.month
info.customerResources_count = res.data.customerResources_count list.campus_list = res.data.campus_list
info.customerResources_day_count = res.data.customerResources_day_count list.complete_rate = res.data.complete_rate
info.student_count = res.data.student_count list.xf_complete_rate = res.data.xf_complete_rate
info.student_day_count = res.data.student_day_count
info.customer = res.data.customer list.month_complete_rate = res.data.month_complete_rate
drawChart(''); list.month_xf_complete_rate = res.data.month_xf_complete_rate
list.ls_month_xf_complete_rate = res.data.ls_month_xf_complete_rate
list.wx_summary_list = res.data.wx_summary_list
list.xf_summary_list = res.data.xf_summary_list
list.xf_jl_summary_list = res.data.xf_jl_summary_list
list.zy_complete_rate = res.data.zy_complete_rate
list.zy_visit_complete_rate = res.data.zy_visit_complete_rate
loading.value = false
}) })
.catch(() => { .catch(() => {
loading.value = false
}) })
} }
Init(); Init();
const drawChart = (item : any) => {
let value = info.customer.value
if (item) value = item
if (!visitStat.value) return
const visitStatChart = echarts.init(visitStat.value)
const visitStatOption = ref({
// title: {
// text: ''
// },
legend: {},
xAxis: {
data: []
},
yAxis: {},
tooltip: {
trigger: 'axis'
},
series: [
{
type: 'line',
data: []
}
]
})
visitStatOption.value.xAxis.data = info.customer.time
visitStatOption.value.series[0].data = value
visitStatChart.setOption(visitStatOption.value)
}
</script> </script>
<style lang="scss" scoped></style>

188
admin/src/app/views/statistics/home1.vue

@ -0,0 +1,188 @@
<template>
<div class="main-container">
<!-- 实时概况 -->
<el-card shadow="never" class="!border-none">
<template #header>
<span class="text-lg font-extrabold mr-[10px]">统计概括</span>
<span class="text-sm text-[#a19f98]">查看校区员工资源和学员的实时数据</span>
</template>
<el-row :gutter="20">
<el-col :span="6">
<div class="text-sm text-[#a19f98] leading-8 ">
<el-statistic :value="info.campus_count">
<template #title>
<div style="display: inline-flex; align-items: center">
<span class="mr-[5px]">校区数量</span>
</div>
</template>
</el-statistic>
<div class="text-sm text-[#a19f98] leading-8">
</div>
</div>
</el-col>
<el-col :span="6">
<div class="text-sm text-[#a19f98] leading-8 ">
<el-statistic :value="info.personnel_count">
<template #title>
<div style="display: inline-flex; align-items: center">
<span class="mr-[5px]">员工数量</span>
</div>
</template>
</el-statistic>
<div class="text-sm text-[#a19f98] leading-8">
</div>
</div>
</el-col>
<el-col :span="6">
<div class="text-sm text-[#a19f98] leading-8 ">
<el-statistic :value="info.customerResources_count">
<template #title>
<div style="display: inline-flex; align-items: center">
<span class="mr-[5px]">资源数量</span>
</div>
</template>
</el-statistic>
<div class="text-sm text-[#a19f98] leading-8">
<span>昨日新增</span>
<span>{{info.customerResources_day_count}}</span>
</div>
</div>
</el-col>
<el-col :span="6">
<div class="text-sm text-[#a19f98] leading-8 ">
<el-statistic :value="info.student_count">
<template #title>
<div style="display: inline-flex; align-items: center">
<span class="mr-[5px]">学员数量</span>
</div>
</template>
</el-statistic>
<div class="text-sm text-[#a19f98] leading-8">
<span>昨日新增</span>
<span>{{info.student_day_count}}</span>
</div>
</div>
</el-col>
</el-row>
</el-card>
<!-- 实时概况 end -->
<el-row :gutter="15" class="mt-[15px]">
<el-col :span="24">
<el-card shadow="never" class="!border-none">
<template #header>
<span class="text-lg font-extrabold">资源增长趋势</span>
</template>
<div >
<el-button :type="activeRange === 'week' ? 'primary' : 'default'" size="small"
@click="changeRange('week')"></el-button>
<el-button :type="activeRange === 'month' ? 'primary' : 'default'" size="small"
@click="changeRange('month')"></el-button>
<el-button :type="activeRange === 'year' ? 'primary' : 'default'" size="small"
@click="changeRange('year')"></el-button>
</div>
<div ref="visitStat" :style="{ width: '100%', height: '300px' }">
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive } from 'vue'
import { getHome } from '@/app/api/sys'
import * as echarts from 'echarts'
const visitStat = ref<any>(null)
const activeRange = ref<'week' | 'month' | 'year'>('week')
const info = reactive({
campus_count: 0,
personnel_count: 0,
customerResources_count: 0,
customerResources_day_count: 0,
student_count: 0,
student_day_count: 0,
customer: []
})
const changeRange = (range) => {
activeRange.value = range
Init(range) //
}
const Init = (range) => {
getHome({'date':range})
.then((res) => {
info.campus_count = res.data.campus_count
info.personnel_count = res.data.personnel_count
info.customerResources_count = res.data.customerResources_count
info.customerResources_day_count = res.data.customerResources_day_count
info.student_count = res.data.student_count
info.student_day_count = res.data.student_day_count
info.customer = res.data.customer
drawChart('');
})
.catch(() => {
})
}
Init();
const drawChart = (item : any) => {
let value = info.customer.value
if (item) value = item
if (!visitStat.value) return
const visitStatChart = echarts.init(visitStat.value)
const visitStatOption = ref({
// title: {
// text: ''
// },
legend: {},
xAxis: {
data: []
},
yAxis: {},
tooltip: {
trigger: 'axis'
},
series: [
{
type: 'line',
data: []
}
]
})
visitStatOption.value.xAxis.data = info.customer.time
visitStatOption.value.series[0].data = value
visitStatChart.setOption(visitStatOption.value)
}
</script>
<style lang="scss" scoped></style>

1
niucloud/app/adminapi/controller/campus_person_role/CampusPersonRole.php

@ -72,6 +72,7 @@ class CampusPersonRole extends BaseAdminController
["person_id",0], ["person_id",0],
["role_id",0], ["role_id",0],
["dept_id",0], ["dept_id",0],
["tasks",'']
]); ]);
$this->validate($data, 'app\validate\campus_person_role\CampusPersonRole.edit'); $this->validate($data, 'app\validate\campus_person_role\CampusPersonRole.edit');

3
niucloud/app/adminapi/controller/sys/System.php

@ -184,4 +184,7 @@ class System extends BaseAdminController
public function personnel_summary(){
return success(data: (new SystemService())->personnel_summary());
}
} }

5
niucloud/app/adminapi/route/sys.php

@ -312,6 +312,8 @@ Route::group('sys', function() {
//系统环境(不效验登录状态) //系统环境(不效验登录状态)
Route::group('sys', function() { Route::group('sys', function() {
Route::get('person_all', 'sys.System/person_all'); Route::get('person_all', 'sys.System/person_all');
Route::get('role_all', 'sys.System/role_all'); Route::get('role_all', 'sys.System/role_all');
Route::get('departments_all', 'sys.System/departments_all'); Route::get('departments_all', 'sys.System/departments_all');
@ -362,4 +364,7 @@ Route::group('sys', function() {
Route::get('web/copyright', 'sys.Config/getCopyright'); Route::get('web/copyright', 'sys.Config/getCopyright');
// 获取install.php配置 // 获取install.php配置
Route::get('install/config', 'sys.Config/getInstallConfig'); Route::get('install/config', 'sys.Config/getInstallConfig');
Route::get('personnel_summary', 'sys.System/personnel_summary');
}); });

14
niucloud/app/common.php

@ -2,6 +2,7 @@
use app\model\campus_person_role\CampusPersonRole; use app\model\campus_person_role\CampusPersonRole;
use app\model\personnel\Personnel; use app\model\personnel\Personnel;
use app\model\personnel\PersonnelSummary;
use app\model\sys\SysConfig; use app\model\sys\SysConfig;
use think\Container; use think\Container;
use think\Response; use think\Response;
@ -1236,3 +1237,16 @@ function get_dict_value($key,$value){
return $map[$value]; return $map[$value];
} }
//$date = 年月 $campus_person_role_id 人员角色表id
//$field complete_num 完成数量 expire_num 到期数量 renew_num 续费数量 resource_num 分配的资源数量 visit_num 到访数量
//$num 增加数量 默认1
function set_summary($date,$campus_person_role_id,$field,$num=1){
$personnel_summary = new PersonnelSummary();
$personnel_summary->where([
['task_date','=',$date],
['campus_person_role_id','=',$campus_person_role_id]
])->inc($field,$num)->update();
return true;
}

41
niucloud/app/model/personnel/PersonnelSummary.php

@ -0,0 +1,41 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\model\personnel;
use core\base\BaseModel;
use think\model\concern\SoftDelete;
use think\model\relation\HasMany;
use think\model\relation\HasOne;
/**
* 人力资源-人员模型
* Class Personnel
* @package app\model\personnel
*/
class PersonnelSummary extends BaseModel
{
/**
* 数据表主键
* @var string
*/
protected $pk = 'id';
/**
* 模型名称
* @var string
*/
protected $name = 'personnel_summary';
}

11
niucloud/app/service/admin/campus_person_role/CampusPersonRoleService.php

@ -14,6 +14,7 @@ namespace app\service\admin\campus_person_role;
use app\model\campus_person_role\CampusPersonRole; use app\model\campus_person_role\CampusPersonRole;
use app\model\campus\Campus; use app\model\campus\Campus;
use app\model\personnel\Personnel; use app\model\personnel\Personnel;
use app\model\personnel\PersonnelSummary;
use app\model\sys\SysRole; use app\model\sys\SysRole;
use app\model\departments\Departments; use app\model\departments\Departments;
@ -79,9 +80,12 @@ class CampusPersonRoleService extends BaseAdminService
*/ */
public function getInfo(int $id) public function getInfo(int $id)
{ {
$personnel_summary = new PersonnelSummary();
$field = 'id,campus_id,person_id,role_id,dept_id,created_at,updated_at,deleted_at'; $field = 'id,campus_id,person_id,role_id,dept_id,created_at,updated_at,deleted_at';
$info = $this->model->field($field)->where([['id', "=", $id]])->with(['campus','personnel','sysRole','departments'])->findOrEmpty()->toArray(); $info = $this->model->field($field)->where([['id', "=", $id]])->with(['campus','personnel','sysRole','departments'])->findOrEmpty()->toArray();
$info['tasks'] = $personnel_summary->where(['campus_person_role_id' => $info['id']])->order("id desc")->findOrEmpty()->toArray();
return $info; return $info;
} }
@ -108,10 +112,15 @@ class CampusPersonRoleService extends BaseAdminService
*/ */
public function edit(int $id, array $data) public function edit(int $id, array $data)
{ {
$tasks = $data['tasks'];
unset($data['tasks']);
if($this->model->where([['id', '<>', $id]])->where(['person_id' => $data['person_id']])->find()){ if($this->model->where([['id', '<>', $id]])->where(['person_id' => $data['person_id']])->find()){
return fail("重复操作"); return fail("重复操作");
} }
if($tasks){
$personnel_summary = new PersonnelSummary();
$personnel_summary->where(['id' => $tasks['id']])->update(['task_num' => $tasks['task_num']]);
}
$this->model->where([['id', '=', $id]])->update($data); $this->model->where([['id', '=', $id]])->update($data);
return success("操作成功"); return success("操作成功");

298
niucloud/app/service/admin/sys/SystemService.php

@ -19,8 +19,11 @@ use app\model\communication_records\CommunicationRecords;
use app\model\customer_resources\CustomerResources; use app\model\customer_resources\CustomerResources;
use app\model\departments\Departments; use app\model\departments\Departments;
use app\model\market_performance\MarketPerformance; use app\model\market_performance\MarketPerformance;
use app\model\order_table\OrderTable;
use app\model\personnel\Personnel; use app\model\personnel\Personnel;
use app\model\personnel\PersonnelSummary;
use app\model\student\Student; use app\model\student\Student;
use app\model\student_courses\StudentCourses;
use app\model\sys\SysConfig; use app\model\sys\SysConfig;
use app\model\sys\SysRole; use app\model\sys\SysRole;
use app\service\core\sys\CoreSysConfigService; use app\service\core\sys\CoreSysConfigService;
@ -239,7 +242,7 @@ class SystemService extends BaseAdminService
return $data; return $data;
} }
public function home(array $arr){ public function home1(array $arr){
$campus = new Campus(); $campus = new Campus();
$personnel = new Personnel(); $personnel = new Personnel();
$customerResources = new CustomerResources(); $customerResources = new CustomerResources();
@ -288,9 +291,276 @@ class SystemService extends BaseAdminService
$data['customer'][ 'value' ] = $value; $data['customer'][ 'value' ] = $value;
$data['customer'][ 'time' ] = $time; $data['customer'][ 'time' ] = $time;
$y = date('Y');
$m = date('m');
$campus = new Campus();
$campusPersonnelRole = new CampusPersonRole();
$order = new OrderTable();
$studentCourses = new StudentCourses();
$campus_list = $campus->select()->toArray();
$table = [
'table_1' => [],
'table_1_total' => 0,
'table_2' => [],
'table_2_total' => 0,
];
//年年度业绩完成情况
$total_task = 0;
$total_complete = 0;
//年年度月卡续费完成情况
$m_total_task = 0;
$m_total_complete = 0;
foreach ($campus_list as $key => $item) {
$task = $campusPersonnelRole->where(['campus_id' => $item['id']])->sum("task_num");
$complete = $order->alias("a")
->join(['school_customer_resources' => 'b'], 'a.resource_id = b.id', 'left')
->where(['b.campus' => $item['id'], 'order_status' => 'paid'])
->count();
$rate = $complete > 0 ? round($task / $complete, 2) : 0;
$table['table_1'][] = [
"序号" => $key + 1,
"校区" => $item['campus_name'],
"任务" => $task,
"完成" => $complete,
"完成率" => $rate.'%',
];
$total_task += $task;
$total_complete += $complete;
$m_task = $studentCourses
->alias("a")
->join(['school_student' => 'b'],'a.student_id = b.id','left')
->where([
['b.campus_id', '=',$item['id']],
['a.end_date','<',date("Y-m-d")]
])
->count();
$m_complete = $order->alias("a")
->join(['school_customer_resources' => 'b'], 'a.resource_id = b.id', 'left')
->where(['b.campus' => $item['id'], 'order_status' => 'paid','order_type' => '2'])
->count();
$m_rate = $m_complete > 0 ? round($m_task / $m_complete, 2) : 0;
$m_total_task += $m_task;
$m_total_complete += $m_complete;
$table['table_2'][] = [
"序号" => $key + 1,
"校区" => $item['campus_name'],
"到期" => $m_task,
"续费" => $m_complete,
"续费率" => $m_rate.'%',
];
}
$table['table_1_total'] = $total_complete > 0 ? round($total_task / $total_complete, 2) : '0';
$table['table_2_total'] = $m_total_complete > 0 ? round($m_total_task / $m_total_complete, 2) : '0';
return $data; return $data;
} }
public function home(array $arr){
$personnel_summary = new PersonnelSummary();
$campus = new Campus();
$campusPersonnelRole = new CampusPersonRole();
$order = new OrderTable();
$studentCourses = new StudentCourses();
$campus_list = $campus->where(['campus_status' => 1])->field("id,campus_name")->select()->toArray();
foreach ($campus_list as &$item) {
$item['year_task_num'] = 0; //任务数量
$item['year_complete_num'] = 0; //完成数量
$item['year_expire_num'] = 0; //到期数量
$item['year_renew_num'] = 0; //续费数量
$item['year_resource_num'] = 0; //分配的资源数量
$item['year_visit_num'] = 0; //分配的资源数量
$item['year_complete'] = 0; //完成率
$item['month_task_num'] = 0; //任务数量
$item['month_complete_num'] = 0; //完成数量
$item['month_expire_num'] = 0; //到期数量
$item['month_renew_num'] = 0; //续费数量
$item['month_resource_num'] = 0; //分配的资源数量
$item['month_visit_num'] = 0; //分配的资源数量
$item['month_complete'] = 0; //完成率
$item['month_zy_complete_num'] = 0; //资源完成数量
$item['month_zy_complete'] = 0; //资源完成率
$item['visit_num_rate'] = 0; //到访率
$list = $personnel_summary
->alias("a")
->join(['school_campus_person_role' => 'b'], 'a.campus_person_role_id = b.id', 'left')
->where(['a.role_type' => 1,'b.campus_id' => $item['id']])
->field("a.*")
->select();
foreach ($list as $val) {
$date = explode('-', $val['task_date']);
if($date[0] == date("Y")) {
$item['year_task_num'] += $val['task_num'];
$item['year_complete_num'] += $val['complete_num'];
$item['year_expire_num'] += $val['expire_num'];
$item['year_renew_num'] += $val['renew_num'];
$item['year_resource_num'] += $val['resource_num'];
$item['year_visit_num'] += $val['visit_num'];
if($date[1] == date("m")){
$item['month_task_num'] += $val['task_num'];
$item['month_complete_num'] += $val['complete_num'];
$item['month_expire_num'] += $val['expire_num'];
$item['month_renew_num'] += $val['renew_num'];
$item['month_resource_num'] += $val['resource_num'];
$item['month_visit_num'] += $val['visit_num'];
$complete = $order->alias("a")
->join(['school_customer_resources' => 'b'], 'a.resource_id = b.id', 'left')
->where(['b.campus' => $item['id'], 'order_status' => 'paid','order_type' => 1])
->count();
$item['month_zy_complete_num'] += $complete;
}
}
}
$item['complete'] = $item['year_complete_num'] > 0 ? round($item['year_complete_num'] / $item['year_task_num'], 2) : 0;
$item['xf_complete'] = $item['year_renew_num'] > 0 ? round($item['year_renew_num'] / $item['year_expire_num'], 2) : 0;
$item['month_complete'] = $item['month_complete_num'] > 0 ? round($item['month_complete_num'] / $item['month_task_num'], 2) : 0;
$item['month_xf_complete'] = $item['month_renew_num'] > 0 ? round($item['month_renew_num'] / $item['month_expire_num'], 2) : 0;
$item['ls_month_xf_complete'] = $item['month_expire_num'] > 0 ? round(($item['month_expire_num'] - $item['month_renew_num']) / $item['month_expire_num'], 2) : 0;
$item['month_zy_complete'] = ($item['month_zy_complete_num'] > 0 and $item['month_task_num'] > 0) ? round($item['month_zy_complete_num'] / $item['month_task_num'], 2) : 0;
$item['visit_num_rate'] = $item['month_visit_num'] > 0 ? round($item['month_visit_num'] / $item['month_resource_num'], 2) : 0;
}
//年度合计
$total_task = array_sum(array_column($campus_list, 'year_task_num'));
$total_complete = array_sum(array_column($campus_list, 'year_complete_num'));
$complete_rate = $total_complete > 0 ? round($total_complete / $total_task, 2) : 0;
$total_expire = array_sum(array_column($campus_list, 'year_expire_num'));
$total_renew = array_sum(array_column($campus_list, 'year_renew_num'));
$xf_complete_rate = $total_renew > 0 ? round($total_renew / $total_expire, 2) : 0;
//月度合计
$month_total_task = array_sum(array_column($campus_list, 'month_task_num'));
$month_total_complete = array_sum(array_column($campus_list, 'month_complete_num'));
$month_complete_rate = $month_total_complete > 0 ? round($month_total_complete / $month_total_task, 2) : 0;
$month_total_expire = array_sum(array_column($campus_list, 'month_expire_num'));
$month_total_renew = array_sum(array_column($campus_list, 'month_renew_num'));
$month_xf_complete_rate = $month_total_renew > 0 ? round($month_total_renew / $month_total_expire, 2) : 0;
$ls_month_xf_complete_rate = $month_total_expire > 0 ? round(($month_total_expire - $month_total_renew) / $month_total_expire, 2) : 0;
//资源合计
$zy_total_task = array_sum(array_column($campus_list, 'month_task_num'));
$zy_total_complete = array_sum(array_column($campus_list, 'month_zy_complete_num'));
$zy_complete_rate = $zy_total_complete > 0 ? round($zy_total_complete / $zy_total_task, 2) : 0;
$zy_month_visit_num = array_sum(array_column($campus_list, 'month_visit_num'));
$zy_month_resource_num = array_sum(array_column($campus_list, 'month_resource_num'));
$zy_visit_complete_rate = $zy_month_visit_num > 0 ? round($zy_month_visit_num / $zy_month_resource_num, 2) : 0;
//月度个人业绩情况
$personnel_summary_list = $personnel_summary
->alias("a")
->join(['school_campus_person_role' => 'b'], 'a.campus_person_role_id = b.id', 'left')
->join(['school_personnel' => 'c'], 'c.id = b.person_id', 'left')
->where(['a.role_type' => 1,'a.task_date' => date("Y-m")])
->field("a.*,c.name")
->select();
$year = date('Y');
foreach ($personnel_summary_list as &$row) {
$row['year_complete_num'] = $personnel_summary
->where(['campus_person_role_id' => $row['campus_person_role_id']])
->where('task_date', 'like', "$year-%")
->sum("complete_num");
$row['xf_complete'] = $row['renew_num'] > 0 ? round($row['renew_num'] / $row['expire_num'], 2) : 0;
$row['ls_xf_complete'] = $row['expire_num'] > 0 ? round(($row['expire_num'] - $row['renew_num']) / $row['expire_num'], 2) : 0;
}
$wx_summary_list = $personnel_summary_list->toArray();
usort($wx_summary_list, function($a, $b) {
return $b['complete_num'] <=> $a['complete_num'];
});
$xf_summary_list = $personnel_summary_list->toArray();
usort($xf_summary_list, function($a, $b) {
return $b['renew_num'] <=> $a['renew_num'];
});
$jl_personnel_summary_list = $personnel_summary
->alias("a")
->join(['school_campus_person_role' => 'b'], 'a.campus_person_role_id = b.id', 'left')
->join(['school_personnel' => 'c'], 'c.id = b.person_id', 'left')
->where(['a.role_type' => 2,'a.task_date' => date("Y-m")])
->field("a.*,c.name")
->select();
$year = date('Y');
foreach ($jl_personnel_summary_list as &$row) {
$row['year_complete_num'] = $personnel_summary
->where(['campus_person_role_id' => $row['campus_person_role_id']])
->where('task_date', 'like', "$year-%")
->sum("complete_num");
$row['xf_complete'] = $row['renew_num'] > 0 ? round($row['renew_num'] / $row['expire_num'], 2) : 0;
$row['ls_xf_complete'] = $row['expire_num'] > 0 ? round(($row['expire_num'] - $row['renew_num']) / $row['expire_num'], 2) : 0;
}
$xf_jl_summary_list = $jl_personnel_summary_list->toArray();
usort($xf_summary_list, function($a, $b) {
return $b['renew_num'] <=> $a['renew_num'];
});
return [
'year' => date("Y"),
'month' => date("m"),
'campus_list' => $campus_list,
'complete_rate' => $complete_rate,
'xf_complete_rate' => $xf_complete_rate,
'month_complete_rate' => $month_complete_rate,
'month_xf_complete_rate' => $month_xf_complete_rate,
'ls_month_xf_complete_rate' => $ls_month_xf_complete_rate,
'wx_summary_list' => $wx_summary_list,
'xf_summary_list' => $xf_summary_list,
'xf_jl_summary_list' => $xf_jl_summary_list,
'zy_complete_rate' => $zy_complete_rate,
'zy_visit_complete_rate' => $zy_visit_complete_rate
];
}
public function scsjtj(array $row){ public function scsjtj(array $row){
$customerResources = new CustomerResources(); $customerResources = new CustomerResources();
@ -360,4 +630,30 @@ class SystemService extends BaseAdminService
return $departments->select()->toArray(); return $departments->select()->toArray();
} }
//数据汇总表
public function personnel_summary(){
$campus_person_role = new CampusPersonRole();
$personnel_summary = new PersonnelSummary();
$role = [5,6];
$campus_person_role_list = $campus_person_role->where([
['role_id','in',$role]
])->select();
$insertArr = [];
foreach ($campus_person_role_list as $k => $v) {
$insertArr[] = [
'task_date' => date("Y-m"),
'campus_person_role_id' => $v['id'],
'role_type' => $v['role_id'] == 6 ? 1 : 2,
];
}
$personnel_summary->insertAll($insertArr);
return true;
}
} }

Loading…
Cancel
Save