Browse Source

统计分析

lifanagju_citu 8 months ago
parent
commit
28608863b8

+ 48 - 0
src/views/menduner/system/analysis/statisticAnalysis/components/AgeDistribution.vue

@@ -0,0 +1,48 @@
+<!--  -->
+<template>
+  <el-card shadow="never">
+    <template #header>
+      <CardTitle :title="props.title" />
+    </template>
+    <div>
+      <Echart :height="300" :options="chartOptions" />
+    </div>
+  </el-card>
+</template>
+
+<script setup>
+defineOptions({name: 'AgeDistribution'})
+const props = defineProps({
+  title: String,
+})
+
+const chartOptions = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'shadow'
+    }
+  },
+  grid: {
+    left: '3%',
+    right: '4%',
+    bottom: '3%',
+    containLabel: true
+  },
+  xAxis: {
+    type: 'category',
+    data: ['16-20', '21-25', '26-30', '31-35', '36-40', '41-45', '46-50', '51-55', '56-60']
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      data: [10, 20, 200, 240, 90, 3, 1, 0, 1],
+      type: 'bar'
+    }
+  ]
+}
+</script>
+<style lang="scss" scoped>
+</style>

+ 42 - 0
src/views/menduner/system/analysis/statisticAnalysis/components/ComparisonCard.vue

@@ -0,0 +1,42 @@
+<template>
+  <div class="flex flex-col gap-2 bg-[var(--el-bg-color-overlay)] p-6">
+    <div class="flex items-center justify-between text-gray-500">
+      <span>{{ title }}</span>
+      <el-tag>{{ tag }}</el-tag>
+    </div>
+    <div class="flex flex-row items-baseline justify-between">
+      <CountTo :prefix="prefix" :end-val="value" :decimals="decimals" class="text-3xl" />
+      <span :class="toNumber(percent) > 0 ? 'text-red-500' : 'text-green-500'">
+        {{ Math.abs(toNumber(percent)) }}%
+        <Icon :icon="toNumber(percent) > 0 ? 'ep:caret-top' : 'ep:caret-bottom'" class="!text-sm" />
+      </span>
+    </div>
+    <el-divider class="mb-1! mt-2!" />
+    <div class="flex flex-row items-center justify-between text-sm">
+      <span class="text-gray-500">昨日数据</span>
+      <span>{{ prefix || '' }}{{ reference }}</span>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+import { propTypes } from '@/utils/propTypes'
+import { toNumber } from 'lodash-es'
+import { calculateRelativeRate } from '@/utils'
+
+/** 交易对照卡片 */
+defineOptions({ name: 'ComparisonCard' })
+
+const props = defineProps({
+  title: propTypes.string.def('').isRequired,
+  tag: propTypes.string.def(''),
+  prefix: propTypes.string.def(''),
+  value: propTypes.number.def(0).isRequired,
+  reference: propTypes.number.def(0).isRequired,
+  decimals: propTypes.number.def(0)
+})
+
+// 计算环比
+const percent = computed(() =>
+  calculateRelativeRate(props.value as number, props.reference as number)
+)
+</script>

+ 48 - 0
src/views/menduner/system/analysis/statisticAnalysis/components/Education.vue

@@ -0,0 +1,48 @@
+<!--  -->
+<template>
+  <el-card shadow="never">
+    <template #header>
+      <CardTitle :title="props.title" />
+    </template>
+    <div>
+      <Echart :height="300" :options="chartOptions" />
+    </div>
+  </el-card>
+</template>
+
+<script setup>
+defineOptions({name: 'Education'})
+const props = defineProps({
+  title: String,
+})
+
+const chartOptions = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'shadow'
+    }
+  },
+  grid: {
+    left: '3%',
+    right: '4%',
+    bottom: '3%',
+    containLabel: true
+  },
+  xAxis: {
+    type: 'category',
+    data: ['初中及以下', '中专/中技', '高中', '大专', '本科', '硕士', '博士', '其他']
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      data: [0, 4, 757, 57, 75, 5, 5, 574],
+      type: 'bar'
+    }
+  ]
+}
+</script>
+<style lang="scss" scoped>
+</style>

+ 47 - 0
src/views/menduner/system/analysis/statisticAnalysis/components/GenderDistribution.vue

@@ -0,0 +1,47 @@
+<!--  -->
+<template>
+  <el-card shadow="never">
+    <template #header>
+      <CardTitle :title="props.title" />
+    </template>
+    <div>
+      <Echart :height="300" :options="chartOptions" />
+    </div>
+  </el-card>
+</template>
+
+<script setup>
+defineOptions({name: 'GenderDistribution'})
+const props = defineProps({
+  title: String,
+})
+
+const chartOptions = {
+  tooltip: {
+    trigger: 'item',
+    confine: true,
+    formatter: '{a} <br/>{b} : {c} ({d}%)'
+  },
+  legend: {},
+  series: [
+    {
+      name: props.title,
+      type: 'pie',
+      radius: '50%',
+      data: [
+        { value: 400, name: '男' },
+        { value: 100, name: '女' },
+      ],
+      emphasis: {
+        itemStyle: {
+          shadowBlur: 10,
+          shadowOffsetX: 0,
+          shadowColor: 'rgba(0, 0, 0, 0.5)'
+        }
+      }
+    }
+  ]
+}
+</script>
+<style lang="scss" scoped>
+</style>

+ 48 - 0
src/views/menduner/system/analysis/statisticAnalysis/components/WorkExperience.vue

@@ -0,0 +1,48 @@
+<!--  -->
+<template>
+  <el-card shadow="never">
+    <template #header>
+      <CardTitle :title="props.title" />
+    </template>
+    <div>
+      <Echart :height="300" :options="chartOptions" />
+    </div>
+  </el-card>
+</template>
+
+<script setup>
+defineOptions({name: 'WorkExperience'})
+const props = defineProps({
+  title: String,
+})
+
+const chartOptions = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'shadow'
+    }
+  },
+  grid: {
+    left: '3%',
+    right: '4%',
+    bottom: '3%',
+    containLabel: true
+  },
+  xAxis: {
+    type: 'category',
+    data: ['在校生', '应届生', '1年以内', '1-3年', '3-5年', '5-10年', '10-20年', '20年以上']
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      data: [25, 77, 866, 575, 698, 58, 6, 7],
+      type: 'bar'
+    }
+  ]
+}
+</script>
+<style lang="scss" scoped>
+</style>

+ 170 - 0
src/views/menduner/system/analysis/statisticAnalysis/index.vue

@@ -0,0 +1,170 @@
+<!--  -->
+<template>
+  <div>
+    <ContentWrap>
+      <!-- 搜索工作栏 -->
+      <el-form
+        class="-mb-15px"
+        :model="queryParams"
+        ref="queryFormRef"
+        :inline="true"
+        label-width="120px"
+      >
+        <el-form-item label="" prop="dateType">
+          <el-radio-group v-model="queryParams.dateType" @change="radioChange">
+            <el-radio-button label="最近七天" value="0" />
+            <el-radio-button label="上个月" value="1" />
+            <el-radio-button label="上季度" value="2" />
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="" prop="dateRange">
+          <el-date-picker
+            v-model="queryParams.dateRange"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            type="daterange"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+            class="!w-240px"
+            @change="dateRangeChange"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+          <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+          <el-button
+            type="success"
+            plain
+            @click="null"
+            :loading="false"
+          >
+            <Icon icon="ep:download" class="mr-5px" /> 导出
+          </el-button>
+        </el-form-item>
+      </el-form>
+    </ContentWrap>
+    <div class="flex flex-col">
+      <!-- 数据对照 -->
+      <el-row :gutter="16" class="row">
+        <el-col :md="4" :sm="12" :xs="24" :loading="loading">
+          <ComparisonCard
+            tag="今日"
+            title="浏览量"
+            prefix="¥"
+            ::decimals="2"
+            :value="4"
+            :reference="2"
+          />
+        </el-col>
+        <el-col :md="4" :sm="12" :xs="24" :loading="loading">
+          <ComparisonCard
+            tag="今日"
+            title="收到简历数"
+            :value="4"
+            :reference="2"
+          />
+        </el-col>
+        <el-col :md="4" :sm="12" :xs="24" :loading="loading">
+          <ComparisonCard
+            tag="今日"
+            title="已查看简历数"
+            :value="4"
+            :reference="2"
+          />
+        </el-col>
+        <el-col :md="4" :sm="12" :xs="24" :loading="loading">
+          <ComparisonCard
+            tag="今日"
+            title="面试-已邀约数"
+            :value="4"
+            :reference="2"
+          />
+        </el-col>
+        <el-col :md="4" :sm="12" :xs="24" :loading="loading">
+          <ComparisonCard
+            tag="今日"
+            title="面试-完成数"
+            :value="4"
+            :reference="2"
+          />
+        </el-col>
+      </el-row>
+      <el-row :gutter="16" class="row">
+        <el-col :md="12">
+          <GenderDistribution title="性别分布" />
+        </el-col>
+        <el-col :md="12">
+          <AgeDistribution title="年龄分布" />
+        </el-col>
+      </el-row>
+      <el-row :gutter="16" class="row">
+        <el-col :md="12">
+          <WorkExperience title="工作年限分布" />
+        </el-col>
+        <el-col :md="12">
+          <Education title="学历分布" />
+        </el-col>
+      </el-row>
+    </div>
+</div>
+</template>
+
+<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'
+defineOptions({name: 'StatisticAnalysis'})
+
+const loading = ref(true) // 加载中
+
+/** 初始化 **/
+onMounted(async () => {
+  // loading.value = true
+  loading.value = false
+})
+
+
+const queryParams = reactive({
+  // pageNo: 1,
+  // pageSize: 10,
+  dateType: '0',
+  dateRange: []
+})
+
+const queryFormRef = ref() // 搜索的表单
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  // queryParams.pageNo = 1
+  // getList()
+}
+const radioChange = (value) => {
+  if (value) {
+    queryParams.dateRange = []
+    handleQuery()
+  }
+}
+const dateRangeChange = (value) => {
+  if (value?.length) {
+    queryParams.dateType = undefined
+  } else {
+    queryParams.dateType = '0'
+  }
+  handleQuery()
+}
+
+</script>
+<style lang="scss" scoped>
+.row {
+  .el-col {
+    margin-bottom: 1rem;
+  }
+}
+</style>