lifanagju_citu 8 hónapja
szülő
commit
9d2ace8ec3

+ 50 - 0
src/api/menduner/system/analysis/statisticAnalysis.ts

@@ -0,0 +1,50 @@
+import request from '@/config/axios'
+
+// 统计分析 API
+export const statisticAnalysisApi = {
+  // 获取发布职位浏览量统计分析明细
+  getAnalysisJobBrowseNumPage: async (params: any) => {
+    return await request.get({ url: `/menduner/system/analysis/get/job/browse/num/page`, params })
+  },
+
+  // 获取新投递简历统计分析明细
+  getAnalysisJobCvNewPage: async (params: any) => {
+    return await request.get({ url: `/menduner/system/analysis/get/job/cv/new/page`, params })
+  },
+
+  // 获取已查看简历统计分析明细
+  getAnalysisJobCvLookPage: async (params: any) => {
+    return await request.get({ url: `/menduner/system/analysis/get/job/cv/look/page`, params })
+  },
+
+  // 获取待面试统计分析明细
+  getAnalysisInterviewWaitPage: async (params: any) => {
+    return await request.get({ url: `/menduner/system/analysis/get/interview/wait/page`, params })
+  },
+
+  // 获取完成面试统计分析明细
+  getAnalysisInterviewCompletePage: async (params: any) => {
+    return await request.get({ url: `/menduner/system/analysis/get/interview/wait/page`, params })
+  },
+
+  
+  // 获取投递简历的性别分布
+  getAnalysisJobCvSexCount: async (params: any) => {
+    return await request.get({ url: `/menduner/system/analysis/get/job/cv/sex/count`, params })
+  },
+
+  // 获取投递简历的年龄分布
+  getAnalysisJobCvAgeCount: async (params: any) => {
+    return await request.get({ url: `/menduner/system/analysis/get/job/cv/age/count`, params })
+  },
+
+  // 获取投递简历的工作经验分布
+  getAnalysisJobCvExpCount: async (params: any) => {
+    return await request.get({ url: `/menduner/system/analysis/get/job/cv/exp/count`, params })
+  },
+
+  // 获取投递简历的学历分布
+  getAnalysisJobCvEduCount: async (params: any) => {
+    return await request.get({ url: `/menduner/system/analysis/get/job/cv/edu/count`, params })
+  },
+}

+ 24 - 6
src/views/menduner/system/analysis/statisticAnalysis/components/AgeDistribution.vue

@@ -10,13 +10,21 @@
   </el-card>
 </template>
 
-<script setup>
+<script lang="ts" setup>
+import { EChartsOption } from 'echarts'
 defineOptions({name: 'AgeDistribution'})
 const props = defineProps({
-  title: String,
+  title: {
+    type: String,
+    default: () => ''
+  },
+  data: {
+    type: Array,
+    default: () => []
+  },
 })
 
-const chartOptions = {
+const chartOptions = reactive<EChartsOption>({
   tooltip: {
     trigger: 'axis',
     axisPointer: {
@@ -31,18 +39,28 @@ const chartOptions = {
   },
   xAxis: {
     type: 'category',
-    data: ['16-20', '21-25', '26-30', '31-35', '36-40', '41-45', '46-50', '51-55', '56-60']
+    data: []
   },
   yAxis: {
     type: 'value'
   },
   series: [
     {
-      data: [10, 20, 200, 240, 90, 3, 1, 0, 1],
+      data: [],
       type: 'bar'
     }
   ]
-}
+}) as EChartsOption
+
+watch(() => props.data, (newVal: any) => {
+  if (!Object.keys(newVal).length) {
+    chartOptions.xAxis.data = []
+    chartOptions.series![0].data = []
+    return
+  }
+  chartOptions.xAxis.data = newVal.x || []
+  chartOptions.series![0].data = newVal.y || []
+})
 </script>
 <style lang="scss" scoped>
 </style>

+ 24 - 6
src/views/menduner/system/analysis/statisticAnalysis/components/Education.vue

@@ -10,13 +10,21 @@
   </el-card>
 </template>
 
-<script setup>
+<script lang="ts" setup>
+import { EChartsOption } from 'echarts'
 defineOptions({name: 'Education'})
 const props = defineProps({
-  title: String,
+  title: {
+    type: String,
+    default: () => ''
+  },
+  data: {
+    type: Array,
+    default: () => []
+  },
 })
 
-const chartOptions = {
+const chartOptions = reactive<EChartsOption>({
   tooltip: {
     trigger: 'axis',
     axisPointer: {
@@ -31,18 +39,28 @@ const chartOptions = {
   },
   xAxis: {
     type: 'category',
-    data: ['初中及以下', '中专/中技', '高中', '大专', '本科', '硕士', '博士', '其他']
+    data: []
   },
   yAxis: {
     type: 'value'
   },
   series: [
     {
-      data: [0, 4, 757, 57, 75, 5, 5, 574],
+      data: [],
       type: 'bar'
     }
   ]
-}
+}) as EChartsOption
+
+watch(() => props.data, (newVal: any) => {
+  if (!Object.keys(newVal).length) {
+    chartOptions.xAxis.data = []
+    chartOptions.series![0].data = []
+    return
+  }
+  chartOptions.xAxis.data = newVal.x || []
+  chartOptions.series![0].data = newVal.y || []
+})
 </script>
 <style lang="scss" scoped>
 </style>

+ 22 - 6
src/views/menduner/system/analysis/statisticAnalysis/components/GenderDistribution.vue

@@ -10,13 +10,21 @@
   </el-card>
 </template>
 
-<script setup>
+<script lang="ts" setup>
+import { EChartsOption } from 'echarts'
 defineOptions({name: 'GenderDistribution'})
 const props = defineProps({
-  title: String,
+  title: {
+    type: String,
+    default: () => ''
+  },
+  data: {
+    type: Array,
+    default: () => []
+  },
 })
 
-const chartOptions = {
+const chartOptions = reactive<EChartsOption>({
   tooltip: {
     trigger: 'item',
     confine: true,
@@ -29,8 +37,8 @@ const chartOptions = {
       type: 'pie',
       radius: '50%',
       data: [
-        { value: 400, name: '男' },
-        { value: 100, name: '女' },
+        // { value: 400, name: '男' },
+        // { value: 100, name: '女' },
       ],
       emphasis: {
         itemStyle: {
@@ -41,7 +49,15 @@ const chartOptions = {
       }
     }
   ]
-}
+}) as EChartsOption
+
+watch(() => props.data, (newVal) => {
+    if (newVal?.length) {
+      chartOptions.series![0].data = newVal.map((e: any) => ({ value: e.value, name: e.key }))
+    } else {
+      chartOptions.series = []
+    }
+})
 </script>
 <style lang="scss" scoped>
 </style>

+ 24 - 6
src/views/menduner/system/analysis/statisticAnalysis/components/WorkExperience.vue

@@ -10,13 +10,21 @@
   </el-card>
 </template>
 
-<script setup>
+<script lang="ts" setup>
+import { EChartsOption } from 'echarts'
 defineOptions({name: 'WorkExperience'})
 const props = defineProps({
-  title: String,
+  title: {
+    type: String,
+    default: () => ''
+  },
+  data: {
+    type: Array,
+    default: () => []
+  },
 })
 
-const chartOptions = {
+const chartOptions = reactive<EChartsOption>({
   tooltip: {
     trigger: 'axis',
     axisPointer: {
@@ -31,18 +39,28 @@ const chartOptions = {
   },
   xAxis: {
     type: 'category',
-    data: ['在校生', '应届生', '1年以内', '1-3年', '3-5年', '5-10年', '10-20年', '20年以上']
+    data:  []
   },
   yAxis: {
     type: 'value'
   },
   series: [
     {
-      data: [25, 77, 866, 575, 698, 58, 6, 7],
+      data:  [],
       type: 'bar'
     }
   ]
-}
+}) as EChartsOption
+
+watch(() => props.data, (newVal: any) => {
+  if (!Object.keys(newVal).length) {
+    chartOptions.xAxis.data = []
+    chartOptions.series![0].data = []
+    return
+  }
+  chartOptions.xAxis.data = newVal.x || []
+  chartOptions.series![0].data = newVal.y || []
+})
 </script>
 <style lang="scss" scoped>
 </style>

+ 154 - 52
src/views/menduner/system/analysis/statisticAnalysis/index.vue

@@ -71,8 +71,8 @@
             </el-select>
           </el-form-item>
         </div>
-        <el-form-item label="" prop="dateType">
-          <el-radio-group v-model="queryParams.dateType" @change="radioChange" class="!w-240px">
+        <el-form-item label="" prop="type">
+          <el-radio-group v-model="queryParams.type" @change="typeChange" class="!w-240px">
             <el-radio-button label="最近七天" value="0" />
             <el-radio-button label="上个月" value="1" />
             <el-radio-button label="上季度" value="2" />
@@ -87,7 +87,7 @@
             end-placeholder="结束日期"
             :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
             class="!w-240px"
-            @change="dateRangeChange"
+            @change="timeRangeChange"
           />
         </el-form-item>
         <el-form-item>
@@ -108,55 +108,35 @@
       <!-- 数据对照 -->
       <el-row :gutter="16" class="row">
         <el-col :md="4" :sm="12" :xs="24" :loading="loading">
-          <ComparisonCard
-            tag="今日"
-            title="浏览量"
-            :value="4"
-          />
+          <ComparisonCard  title="职位浏览量" :value="pageViews.total" />
         </el-col>
         <el-col :md="4" :sm="12" :xs="24" :loading="loading">
-          <ComparisonCard
-            tag="今日"
-            title="收到的简历"
-            :value="4"
-          />
+          <ComparisonCard  title="收到的简历" :value="resumeReceived.total" />
         </el-col>
         <el-col :md="4" :sm="12" :xs="24" :loading="loading">
-          <ComparisonCard
-            tag="今日"
-            title="已查看简历"
-            :value="4"
-          />
+          <ComparisonCard  title="已查看简历" :value="resumeViewed.total" />
         </el-col>
         <el-col :md="4" :sm="12" :xs="24" :loading="loading">
-          <ComparisonCard
-            tag="今日"
-            title="已邀面试"
-            :value="4"
-          />
+          <ComparisonCard  title="已邀面试" :value="invitedInterviews.total" />
         </el-col>
         <el-col :md="4" :sm="12" :xs="24" :loading="loading">
-          <ComparisonCard
-            tag="今日"
-            title="面试完成"
-            :value="4"
-          />
+          <ComparisonCard  title="面试完成" :value="invitedCompleted.total" />
         </el-col>
       </el-row>
       <el-row :gutter="16" class="row">
         <el-col :md="12">
-          <GenderDistribution title="性别分布" />
+          <genderDistribution :data="genderDistributionData" title="性别分布" />
         </el-col>
         <el-col :md="12">
-          <AgeDistribution title="年龄分布" />
+          <ageDistribution :data="ageDistributionData" title="年龄分布" />
         </el-col>
       </el-row>
       <el-row :gutter="16" class="row">
         <el-col :md="12">
-          <WorkExperience title="工作年限分布" />
+          <workExperience :data="workExperienceData" title="工作年限分布" />
         </el-col>
         <el-col :md="12">
-          <Education title="学历分布" />
+          <education :data="educationData" title="学历分布" />
         </el-col>
       </el-row>
     </div>
@@ -165,10 +145,11 @@
 
 <script setup>
 import ComparisonCard from './components/ComparisonCard.vue'
-import GenderDistribution from './components/GenderDistribution.vue'
-import AgeDistribution from './components/AgeDistribution.vue'
-import WorkExperience from './components/WorkExperience.vue'
-import Education from './components/Education.vue'
+import genderDistribution from './components/GenderDistribution.vue'
+import ageDistribution from './components/AgeDistribution.vue'
+import workExperience from './components/WorkExperience.vue'
+import education from './components/Education.vue'
+import { statisticAnalysisApi } from '@/api/menduner/system/analysis/statisticAnalysis'
 defineOptions({name: 'StatisticAnalysis'})
 
 const loading = ref(true) // 加载中
@@ -179,11 +160,14 @@ onMounted(async () => {
   loading.value = false
 })
 
-
+// const pageParams = {
+//   pageNo: 1,
+//   pageSize: 10,
+// }
 const queryParams = reactive({
-  // pageNo: 1,
-  // pageSize: 10,
-  dateType: '0',
+  pageNo: 1,
+  pageSize: 10,
+  type: '0',
   enterpriseId: undefined,
   deptId: undefined,
   userId: undefined,
@@ -198,26 +182,144 @@ const resetQuery = () => {
   handleQuery()
 }
 
-/** 搜索按钮操作 */
-const handleQuery = () => {
-  // queryParams.pageNo = 1
-  // getList()
-}
-const radioChange = (value) => {
+const typeChange = (value) => { // 
   if (value) {
     queryParams.dateRange = []
     handleQuery()
   }
 }
-const dateRangeChange = (value) => {
-  if (value?.length) {
-    queryParams.dateType = undefined
-  } else {
-    queryParams.dateType = '0'
-  }
+const timeRangeChange = (value) => {
+  if (value?.length) queryParams.type = '99' // 自定义
+  else queryParams.type = '0'
   handleQuery()
 }
 
+// 职位浏览量
+const pageViews = reactive({ list: [], total: 0 })
+const getPageViewsList = async () => {
+  loading.value = true
+  try {
+    const data = await statisticAnalysisApi.getAnalysisJobBrowseNumPage(queryParams)
+    pageViews.list = data.list
+    pageViews.total = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+// 收到的简历
+const resumeReceived = reactive({ list: [], total: 0 })
+const getResumeReceivedList = async () => {
+  loading.value = true
+  try {
+    const data = await statisticAnalysisApi.getAnalysisJobCvNewPage(queryParams)
+    resumeReceived.list = data.list
+    resumeReceived.total = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+// 已查看简历
+const resumeViewed = reactive({ list: [], total: 0 })
+const getResumeViewedList = async () => {
+  loading.value = true
+  try {
+    const data = await statisticAnalysisApi.getAnalysisJobCvLookPage(queryParams)
+    resumeViewed.list = data.list
+    resumeViewed.total = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+// 已邀面试
+const invitedInterviews = reactive({ list: [], total: 0 })
+const getInvitedInterviewsList = async () => {
+  loading.value = true
+  try {
+    const data = await statisticAnalysisApi.getAnalysisInterviewWaitPage(queryParams)
+    invitedInterviews.list = data.list
+    invitedInterviews.total = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+// 面试完成
+const invitedCompleted = reactive({ list: [], total: 0 })
+const getInvitedCompletedList = async () => {
+  loading.value = true
+  try {
+    const data = await statisticAnalysisApi.getAnalysisInterviewCompletePage(queryParams)
+    invitedCompleted.list = data.list
+    invitedCompleted.total = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+// 性别分布
+const genderDistributionData = ref(null)
+const getAnalysisJobCvSexCount = async () => {
+  try {
+    const data = await statisticAnalysisApi.getAnalysisJobCvSexCount(queryParams)
+    if (data) genderDistributionData.value = data
+    console.log('性别分布', data)
+  } catch (error) {
+    console.log(error)
+  }
+}
+// 年龄分布
+const ageDistributionData = ref(null)
+const getAnalysisJobCvAgeCount = async () => {
+  try {
+    const data = await statisticAnalysisApi.getAnalysisJobCvAgeCount(queryParams)
+    if (data) ageDistributionData.value = data
+  } catch (error) {
+    console.log(error)
+  }
+}
+// 工作年限分布
+const workExperienceData = ref(null)
+const getAnalysisJobCvExpCount = async () => {
+  try {
+    const data = await statisticAnalysisApi.getAnalysisJobCvExpCount(queryParams)
+    if (data) workExperienceData.value = data
+  } catch (error) {
+    console.log(error)
+  }
+}
+// 学历分布
+const educationData = ref(null)
+const getAnalysisJobCvEduCount = async () => {
+  try {
+    const data = await statisticAnalysisApi.getAnalysisJobCvEduCount(queryParams)
+    if (data) educationData.value = data
+  } catch (error) {
+    console.log(error)
+  }
+}
+
+
+/** 搜索按钮操作 */
+let customTimeObj
+const handleQuery = () => {
+  customTimeObj = queryParams.type === '99' && queryParams.dateRange?.length === 2 ? customTimeObj = { 'time[0]': queryParams.dateRange.date[0] + ' 00:00:00', 'time[1]': queryParams.dateRange.date[1] + ' 23:59:59' } : {}
+  queryParams.value = { ...queryParams, ...customTimeObj }
+  queryParams.pageNo = 1
+  getPageViewsList()
+  getResumeReceivedList()
+  getResumeViewedList()
+  getInvitedInterviewsList()
+  getInvitedCompletedList()
+  getAnalysisJobCvSexCount()
+  getAnalysisJobCvAgeCount()
+  getAnalysisJobCvExpCount()
+  getAnalysisJobCvEduCount()
+}
+handleQuery()
+
 const enterpriseOption = [
   { label: '企业 1', value: '1' },
   { label: '企业 2', value: '2' },