浏览代码

首页统计分析&更新测试环境

Xiao_123 6 月之前
父节点
当前提交
6ab620bedb

+ 4 - 4
.env.local

@@ -4,15 +4,15 @@ NODE_ENV=development
 VITE_DEV=true
 
 # 请求路径
-VITE_BASE_URL='https://www.menduner.com:1443/' # 生产环境
-# VITE_BASE_URL='http://192.168.3.80' # 测试环境
+# VITE_BASE_URL='https://www.menduner.com:1443/' # 生产环境
+VITE_BASE_URL='http://192.168.3.80' # 测试环境
 
 # 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持 S3 服务
 VITE_UPLOAD_TYPE=server
 
 # 上传路径
-VITE_UPLOAD_URL='https://www.menduner.com:1443/admin-api/infra/file/upload' # 生产环境
-# VITE_UPLOAD_URL='http://192.168.3.80/admin-api/infra/file/upload' # 测试环境
+# VITE_UPLOAD_URL='https://www.menduner.com:1443/admin-api/infra/file/upload' # 生产环境
+VITE_UPLOAD_URL='http://192.168.3.80/admin-api/infra/file/upload' # 测试环境
 
 # 接口地址
 VITE_API_URL=/admin-api

+ 21 - 0
src/api/home/index.ts

@@ -0,0 +1,21 @@
+import request from '@/config/axios'
+
+// 统计人才简历数量
+export const getNewResumeNum = (params) => {
+  return request.get({ url: '/menduner/system/home/get/person/count', params })
+}
+
+// 统计个人注册用户数量
+export const getNewRegisterUserNum = (params) => {
+  return request.get({ url: '/menduner/system/home/get/user/count', params })
+}
+
+// 统计新注册企业数量
+export const getNewRegisterEnterpriseNum = (params) => {
+  return request.get({ url: '/menduner/system/home/get/enterprise/count', params })
+}
+
+// 统计新企业用户数量
+export const getNewEnterpriseUserNum = (params) => {
+  return request.get({ url: '/menduner/system/home/get/enterprise-user/count', params })
+}

+ 5 - 0
src/api/menduner/system/enterprise/message/index.ts

@@ -107,4 +107,9 @@ export const EnterpriseApi = {
   closeEnterpriseJob: async (ids: array) => {
     return await request.post({ url: `/menduner/system/job-advertised/disable?ids=${ids}` })
   },
+
+  // 职位删除
+  deleteJob: async (id: string) => {
+    return await request.delete({ url: `/menduner/system/job-advertised/delete?id=${id}` })
+  }
 }

+ 384 - 0
src/views/Home/Index copy.vue

@@ -0,0 +1,384 @@
+<template>
+  <div>
+    <el-card shadow="never">
+      <el-skeleton :loading="loading" animated>
+        <el-row :gutter="16" justify="space-between">
+          <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24">
+            <div class="flex items-center">
+              <!-- <el-avatar :src="avatar" :size="70" class="mr-16px">
+                <img src="@/assets/imgs/avatar.gif" alt="" />
+              </el-avatar> -->
+              <div>
+                <div class="text-20px">
+                  {{ t('workplace.welcome') }} {{ username }} {{ t('workplace.happyDay') }}
+                </div>
+                <!-- <div class="mt-10px text-14px text-gray-500">
+                  {{ t('workplace.toady') }},20℃ - 32℃!
+                </div> -->
+              </div>
+            </div>
+          </el-col>
+          <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24">
+            <div class="h-70px flex items-center justify-end lt-sm:mt-10px">
+              <div class="px-8px text-right">
+                <div class="mb-16px text-14px text-gray-400">{{ t('workplace.project') }}</div>
+                <CountTo
+                  class="text-20px"
+                  :start-val="0"
+                  :end-val="totalSate.project"
+                  :duration="2600"
+                />
+              </div>
+              <el-divider direction="vertical" />
+              <div class="px-8px text-right">
+                <div class="mb-16px text-14px text-gray-400">{{ t('workplace.toDo') }}</div>
+                <CountTo
+                  class="text-20px"
+                  :start-val="0"
+                  :end-val="totalSate.todo"
+                  :duration="2600"
+                />
+              </div>
+              <el-divider direction="vertical" border-style="dashed" />
+              <div class="px-8px text-right">
+                <div class="mb-16px text-14px text-gray-400">{{ t('workplace.access') }}</div>
+                <CountTo
+                  class="text-20px"
+                  :start-val="0"
+                  :end-val="totalSate.access"
+                  :duration="2600"
+                />
+              </div>
+            </div>
+          </el-col>
+        </el-row>
+      </el-skeleton>
+    </el-card>
+  </div>
+
+  <el-row class="mt-8px" :gutter="8" justify="space-between">
+    <el-col :xl="16" :lg="16" :md="24" :sm="24" :xs="24" class="mb-8px">
+      <!-- <el-card shadow="never">
+        <template #header>
+          <div class="h-3 flex justify-between">
+            <span>{{ t('workplace.project') }}</span>
+            <el-link type="primary" :underline="false">{{ t('action.more') }}</el-link>
+          </div>
+        </template>
+        <el-skeleton :loading="loading" animated>
+          <el-row>
+            <el-col
+              v-for="(item, index) in projects"
+              :key="`card-${index}`"
+              :xl="8"
+              :lg="8"
+              :md="8"
+              :sm="24"
+              :xs="24"
+            >
+              <el-card shadow="hover">
+                <div class="flex items-center">
+                  <Icon :icon="item.icon" :size="25" class="mr-8px" />
+                  <span class="text-16px">{{ item.name }}</span>
+                </div>
+                <div class="mt-16px text-14px text-gray-400">{{ t(item.message) }}</div>
+                <div class="mt-16px flex justify-between text-12px text-gray-400">
+                  <span>{{ item.personal }}</span>
+                  <span>{{ formatTime(item.time, 'yyyy-MM-dd') }}</span>
+                </div>
+              </el-card>
+            </el-col>
+          </el-row>
+        </el-skeleton>
+      </el-card> -->
+
+      <el-card shadow="never" class="mt-8px">
+        <el-skeleton :loading="loading" animated>
+          <el-row :gutter="20" justify="space-between">
+            <el-col :xl="10" :lg="24" :md="24" :sm="24" :xs="24">
+              <el-card shadow="hover" class="mb-8px">
+                <el-skeleton :loading="loading" animated>
+                  <Echart :options="pieOptionsData" :height="280" />
+                </el-skeleton>
+              </el-card>
+            </el-col>
+            <el-col :xl="14" :lg="24" :md="24" :sm="24" :xs="24">
+              <el-card shadow="hover" class="mb-8px">
+                <el-skeleton :loading="loading" animated>
+                  <Echart :options="barOptionsData" :height="280" />
+                </el-skeleton>
+              </el-card>
+            </el-col>
+          </el-row>
+        </el-skeleton>
+      </el-card>
+    </el-col>
+    <el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-8px">
+      <!-- <el-card shadow="never">
+        <template #header>
+          <div class="h-3 flex justify-between">
+            <span>{{ t('workplace.shortcutOperation') }}</span>
+          </div>
+        </template>
+        <el-skeleton :loading="loading" animated>
+          <el-row>
+            <el-col v-for="item in shortcut" :key="`team-${item.name}`" :span="8" class="mb-8px">
+              <div class="flex items-center">
+                <Icon :icon="item.icon" class="mr-8px" />
+                <el-link type="default" :underline="false" @click="setWatermark(item.name)">
+                  {{ item.name }}
+                </el-link>
+              </div>
+            </el-col>
+          </el-row>
+        </el-skeleton>
+      </el-card> -->
+      <el-card shadow="never" class="mt-8px">
+        <template #header>
+          <div class="h-3 flex justify-between">
+            <span>{{ t('workplace.notice') }}</span>
+            <el-link type="primary" :underline="false">{{ t('action.more') }}</el-link>
+          </div>
+        </template>
+        <el-skeleton :loading="loading" animated>
+          <div v-for="(item, index) in notice" :key="`dynamics-${index}`">
+            <div class="flex items-center">
+              <el-avatar :src="avatar" :size="35" class="mr-16px">
+                <img src="@/assets/imgs/avatar.gif" alt="" />
+              </el-avatar>
+              <div>
+                <div class="text-14px">
+                  <Highlight :keys="item.keys.map((v) => t(v))">
+                    {{ item.type }} : {{ item.title }}
+                  </Highlight>
+                </div>
+                <div class="mt-16px text-12px text-gray-400">
+                  {{ formatTime(item.date, 'yyyy-MM-dd') }}
+                </div>
+              </div>
+            </div>
+            <el-divider />
+          </div>
+        </el-skeleton>
+      </el-card>
+    </el-col>
+  </el-row>
+</template>
+<script lang="ts" setup>
+import { set } from 'lodash-es'
+import { EChartsOption } from 'echarts'
+import { formatTime } from '@/utils'
+
+import { useUserStore } from '@/store/modules/user'
+import { useWatermark } from '@/hooks/web/useWatermark'
+import type { WorkplaceTotal, Project, Notice, Shortcut } from './types'
+import { pieOptions, barOptions } from './echarts-data'
+
+defineOptions({ name: 'Home' })
+
+const { t } = useI18n()
+const userStore = useUserStore()
+const { setWatermark } = useWatermark()
+const loading = ref(true)
+const avatar = userStore.getUser.avatar
+const username = userStore.getUser.nickname
+const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption
+// 获取统计数
+let totalSate = reactive<WorkplaceTotal>({
+  project: 0,
+  access: 0,
+  todo: 0
+})
+
+const getCount = async () => {
+  const data = {
+    project: 40,
+    access: 2340,
+    todo: 10
+  }
+  totalSate = Object.assign(totalSate, data)
+}
+
+// 获取项目数
+let projects = reactive<Project[]>([])
+const getProject = async () => {
+  const data = [
+    {
+      name: 'Github',
+      icon: 'akar-icons:github-fill',
+      message: 'workplace.introduction',
+      personal: 'Archer',
+      time: new Date()
+    },
+    {
+      name: 'Vue',
+      icon: 'logos:vue',
+      message: 'workplace.introduction',
+      personal: 'Archer',
+      time: new Date()
+    },
+    {
+      name: 'Angular',
+      icon: 'logos:angular-icon',
+      message: 'workplace.introduction',
+      personal: 'Archer',
+      time: new Date()
+    },
+    {
+      name: 'React',
+      icon: 'logos:react',
+      message: 'workplace.introduction',
+      personal: 'Archer',
+      time: new Date()
+    },
+    {
+      name: 'Webpack',
+      icon: 'logos:webpack',
+      message: 'workplace.introduction',
+      personal: 'Archer',
+      time: new Date()
+    },
+    {
+      name: 'Vite',
+      icon: 'vscode-icons:file-type-vite',
+      message: 'workplace.introduction',
+      personal: 'Archer',
+      time: new Date()
+    }
+  ]
+  projects = Object.assign(projects, data)
+}
+
+// 获取通知公告
+let notice = reactive<Notice[]>([])
+const getNotice = async () => {
+  const data = [
+    {
+      title: '系统升级版本',
+      type: '通知',
+      keys: ['通知', '升级'],
+      date: new Date()
+    },
+    {
+      title: '系统凌晨维护',
+      type: '公告',
+      keys: ['公告', '维护'],
+      date: new Date()
+    },
+    {
+      title: '系统升级版本',
+      type: '通知',
+      keys: ['通知', '升级'],
+      date: new Date()
+    },
+    {
+      title: '系统凌晨维护',
+      type: '公告',
+      keys: ['公告', '维护'],
+      date: new Date()
+    }
+  ]
+  notice = Object.assign(notice, data)
+}
+
+// 获取快捷入口
+let shortcut = reactive<Shortcut[]>([])
+
+const getShortcut = async () => {
+  const data = [
+    {
+      name: 'Github',
+      icon: 'akar-icons:github-fill',
+      url: 'github.io'
+    },
+    {
+      name: 'Vue',
+      icon: 'logos:vue',
+      url: 'vuejs.org'
+    },
+    {
+      name: 'Vite',
+      icon: 'vscode-icons:file-type-vite',
+      url: 'https://vitejs.dev/'
+    },
+    {
+      name: 'Angular',
+      icon: 'logos:angular-icon',
+      url: 'github.io'
+    },
+    {
+      name: 'React',
+      icon: 'logos:react',
+      url: 'github.io'
+    },
+    {
+      name: 'Webpack',
+      icon: 'logos:webpack',
+      url: 'github.io'
+    }
+  ]
+  shortcut = Object.assign(shortcut, data)
+}
+
+// 用户来源
+const getUserAccessSource = async () => {
+  const data = [
+    { value: 335, name: 'analysis.directAccess' },
+    { value: 310, name: 'analysis.mailMarketing' },
+    { value: 234, name: 'analysis.allianceAdvertising' },
+    { value: 135, name: 'analysis.videoAdvertising' },
+    { value: 1548, name: 'analysis.searchEngines' }
+  ]
+  set(
+    pieOptionsData,
+    'legend.data',
+    data.map((v) => t(v.name))
+  )
+  pieOptionsData!.series![0].data = data.map((v) => {
+    return {
+      name: t(v.name),
+      value: v.value
+    }
+  })
+}
+const barOptionsData = reactive<EChartsOption>(barOptions) as EChartsOption
+
+// 周活跃量
+const getWeeklyUserActivity = async () => {
+  const data = [
+    { value: 13253, name: 'analysis.monday' },
+    { value: 34235, name: 'analysis.tuesday' },
+    { value: 26321, name: 'analysis.wednesday' },
+    { value: 12340, name: 'analysis.thursday' },
+    { value: 24643, name: 'analysis.friday' },
+    { value: 1322, name: 'analysis.saturday' },
+    { value: 1324, name: 'analysis.sunday' }
+  ]
+  set(
+    barOptionsData,
+    'xAxis.data',
+    data.map((v) => t(v.name))
+  )
+  set(barOptionsData, 'series', [
+    {
+      name: t('analysis.activeQuantity'),
+      data: data.map((v) => v.value),
+      type: 'bar'
+    }
+  ])
+}
+
+const getAllApi = async () => {
+  await Promise.all([
+    getCount(),
+    getProject(),
+    getNotice(),
+    getShortcut(),
+    getUserAccessSource(),
+    getWeeklyUserActivity()
+  ])
+  loading.value = false
+}
+
+getAllApi()
+</script>

+ 165 - 357
src/views/Home/Index.vue

@@ -1,384 +1,192 @@
 <template>
-  <div>
-    <el-card shadow="never">
-      <el-skeleton :loading="loading" animated>
-        <el-row :gutter="16" justify="space-between">
-          <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24">
-            <div class="flex items-center">
-              <!-- <el-avatar :src="avatar" :size="70" class="mr-16px">
-                <img src="@/assets/imgs/avatar.gif" alt="" />
-              </el-avatar> -->
-              <div>
-                <div class="text-20px">
-                  {{ t('workplace.welcome') }} {{ username }} {{ t('workplace.happyDay') }}
-                </div>
-                <!-- <div class="mt-10px text-14px text-gray-500">
-                  {{ t('workplace.toady') }},20℃ - 32℃!
-                </div> -->
-              </div>
-            </div>
-          </el-col>
-          <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24">
-            <div class="h-70px flex items-center justify-end lt-sm:mt-10px">
-              <div class="px-8px text-right">
-                <div class="mb-16px text-14px text-gray-400">{{ t('workplace.project') }}</div>
-                <CountTo
-                  class="text-20px"
-                  :start-val="0"
-                  :end-val="totalSate.project"
-                  :duration="2600"
-                />
-              </div>
-              <el-divider direction="vertical" />
-              <div class="px-8px text-right">
-                <div class="mb-16px text-14px text-gray-400">{{ t('workplace.toDo') }}</div>
-                <CountTo
-                  class="text-20px"
-                  :start-val="0"
-                  :end-val="totalSate.todo"
-                  :duration="2600"
-                />
-              </div>
-              <el-divider direction="vertical" border-style="dashed" />
-              <div class="px-8px text-right">
-                <div class="mb-16px text-14px text-gray-400">{{ t('workplace.access') }}</div>
-                <CountTo
-                  class="text-20px"
-                  :start-val="0"
-                  :end-val="totalSate.access"
-                  :duration="2600"
-                />
-              </div>
-            </div>
-          </el-col>
-        </el-row>
-      </el-skeleton>
-    </el-card>
-  </div>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+    >
+      <el-form-item label="" prop="type">
+        <el-radio-group v-model="queryParams.type" @change="typeChange" class="!w-300px">
+          <!-- <el-radio-button label="全部" value="-1" /> -->
+          <el-radio-button label="每天" value="3" />
+          <el-radio-button label="每周" value="0" />
+          <el-radio-button label="每月" value="4" />
+          <el-radio-button label="每年" value="5" />
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="" prop="time">
+        <span class="mr-3">自定义日期</span>
+        <el-date-picker
+          v-model="queryParams.time"
+          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="timeRangeChange"
+        />
+      </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-form-item>
+    </el-form>
+  </ContentWrap>
 
-  <el-row class="mt-8px" :gutter="8" justify="space-between">
-    <el-col :xl="16" :lg="16" :md="24" :sm="24" :xs="24" class="mb-8px">
-      <!-- <el-card shadow="never">
-        <template #header>
-          <div class="h-3 flex justify-between">
-            <span>{{ t('workplace.project') }}</span>
-            <el-link type="primary" :underline="false">{{ t('action.more') }}</el-link>
-          </div>
-        </template>
-        <el-skeleton :loading="loading" animated>
-          <el-row>
-            <el-col
-              v-for="(item, index) in projects"
-              :key="`card-${index}`"
-              :xl="8"
-              :lg="8"
-              :md="8"
-              :sm="24"
-              :xs="24"
-            >
-              <el-card shadow="hover">
-                <div class="flex items-center">
-                  <Icon :icon="item.icon" :size="25" class="mr-8px" />
-                  <span class="text-16px">{{ item.name }}</span>
-                </div>
-                <div class="mt-16px text-14px text-gray-400">{{ t(item.message) }}</div>
-                <div class="mt-16px flex justify-between text-12px text-gray-400">
-                  <span>{{ item.personal }}</span>
-                  <span>{{ formatTime(item.time, 'yyyy-MM-dd') }}</span>
-                </div>
-              </el-card>
-            </el-col>
-          </el-row>
-        </el-skeleton>
-      </el-card> -->
-
-      <el-card shadow="never" class="mt-8px">
-        <el-skeleton :loading="loading" animated>
-          <el-row :gutter="20" justify="space-between">
-            <el-col :xl="10" :lg="24" :md="24" :sm="24" :xs="24">
-              <el-card shadow="hover" class="mb-8px">
-                <el-skeleton :loading="loading" animated>
-                  <Echart :options="pieOptionsData" :height="280" />
-                </el-skeleton>
-              </el-card>
-            </el-col>
-            <el-col :xl="14" :lg="24" :md="24" :sm="24" :xs="24">
-              <el-card shadow="hover" class="mb-8px">
-                <el-skeleton :loading="loading" animated>
-                  <Echart :options="barOptionsData" :height="280" />
-                </el-skeleton>
-              </el-card>
-            </el-col>
-          </el-row>
-        </el-skeleton>
-      </el-card>
-    </el-col>
-    <el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-8px">
-      <!-- <el-card shadow="never">
-        <template #header>
-          <div class="h-3 flex justify-between">
-            <span>{{ t('workplace.shortcutOperation') }}</span>
-          </div>
-        </template>
-        <el-skeleton :loading="loading" animated>
-          <el-row>
-            <el-col v-for="item in shortcut" :key="`team-${item.name}`" :span="8" class="mb-8px">
-              <div class="flex items-center">
-                <Icon :icon="item.icon" class="mr-8px" />
-                <el-link type="default" :underline="false" @click="setWatermark(item.name)">
-                  {{ item.name }}
-                </el-link>
-              </div>
-            </el-col>
-          </el-row>
-        </el-skeleton>
-      </el-card> -->
-      <el-card shadow="never" class="mt-8px">
-        <template #header>
-          <div class="h-3 flex justify-between">
-            <span>{{ t('workplace.notice') }}</span>
-            <el-link type="primary" :underline="false">{{ t('action.more') }}</el-link>
-          </div>
-        </template>
-        <el-skeleton :loading="loading" animated>
-          <div v-for="(item, index) in notice" :key="`dynamics-${index}`">
-            <div class="flex items-center">
-              <el-avatar :src="avatar" :size="35" class="mr-16px">
-                <img src="@/assets/imgs/avatar.gif" alt="" />
-              </el-avatar>
-              <div>
-                <div class="text-14px">
-                  <Highlight :keys="item.keys.map((v) => t(v))">
-                    {{ item.type }} : {{ item.title }}
-                  </Highlight>
-                </div>
-                <div class="mt-16px text-12px text-gray-400">
-                  {{ formatTime(item.date, 'yyyy-MM-dd') }}
-                </div>
-              </div>
+  <el-row class="mt-8px" :gutter="10" justify="space-between">
+    <el-col :xl="12" :lg="12" :md="24" :sm="24" :xs="24" class="mb-8px" v-for="(val, index) in list" :key="index">
+      <el-skeleton :loading="val.loading" animated>
+        <el-card shadow="hover" class="mb-8px">
+          <template #header>
+            <div class="h-3 flex justify-between">
+              <span>{{ val.title }}</span>
             </div>
-            <el-divider />
-          </div>
-        </el-skeleton>
-      </el-card>
+          </template>
+          <el-skeleton :loading="val.loading" animated>
+            <Echart :options="val.options" :height="280" />
+          </el-skeleton>
+        </el-card>
+      </el-skeleton>
     </el-col>
   </el-row>
 </template>
-<script lang="ts" setup>
-import { set } from 'lodash-es'
-import { EChartsOption } from 'echarts'
-import { formatTime } from '@/utils'
-
-import { useUserStore } from '@/store/modules/user'
-import { useWatermark } from '@/hooks/web/useWatermark'
-import type { WorkplaceTotal, Project, Notice, Shortcut } from './types'
-import { pieOptions, barOptions } from './echarts-data'
 
+<script setup>
 defineOptions({ name: 'Home' })
+import { cloneDeep } from 'lodash-es'
+import { getNewResumeNum, getNewRegisterUserNum, getNewRegisterEnterpriseNum, getNewEnterpriseUserNum } from '@/api/home'
 
-const { t } = useI18n()
-const userStore = useUserStore()
-const { setWatermark } = useWatermark()
-const loading = ref(true)
-const avatar = userStore.getUser.avatar
-const username = userStore.getUser.nickname
-const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption
-// 获取统计数
-let totalSate = reactive<WorkplaceTotal>({
-  project: 0,
-  access: 0,
-  todo: 0
+const queryFormRef = ref()
+const queryParams = reactive({
+  type: '3',
+  time: []
 })
-
-const getCount = async () => {
-  const data = {
-    project: 40,
-    access: 2340,
-    todo: 10
-  }
-  totalSate = Object.assign(totalSate, data)
-}
-
-// 获取项目数
-let projects = reactive<Project[]>([])
-const getProject = async () => {
-  const data = [
-    {
-      name: 'Github',
-      icon: 'akar-icons:github-fill',
-      message: 'workplace.introduction',
-      personal: 'Archer',
-      time: new Date()
-    },
-    {
-      name: 'Vue',
-      icon: 'logos:vue',
-      message: 'workplace.introduction',
-      personal: 'Archer',
-      time: new Date()
-    },
-    {
-      name: 'Angular',
-      icon: 'logos:angular-icon',
-      message: 'workplace.introduction',
-      personal: 'Archer',
-      time: new Date()
-    },
-    {
-      name: 'React',
-      icon: 'logos:react',
-      message: 'workplace.introduction',
-      personal: 'Archer',
-      time: new Date()
-    },
-    {
-      name: 'Webpack',
-      icon: 'logos:webpack',
-      message: 'workplace.introduction',
-      personal: 'Archer',
-      time: new Date()
+const barCommonOptions = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'shadow'
+    }
+  },
+  grid: {
+    left: 50,
+    bottom: 50,
+    right: 40,
+    top: 30
+  },
+  xAxis: {
+    type: 'category',
+    name: '',
+    data: [],
+    axisTick: {
+      alignWithLabel: true
     },
-    {
-      name: 'Vite',
-      icon: 'vscode-icons:file-type-vite',
-      message: 'workplace.introduction',
-      personal: 'Archer',
-      time: new Date()
+    axisLabel: {
+      rotate: 30
+    }
+  },
+  yAxis: {
+    type: 'value',
+    name: '人'
+  },
+  series: [
+    { 
+      data: [],
+      type: 'line',
+      // barWidth: 20,
+      label: { show: true }
     }
   ]
-  projects = Object.assign(projects, data)
 }
 
-// 获取通知公告
-let notice = reactive<Notice[]>([])
-const getNotice = async () => {
-  const data = [
-    {
-      title: '系统升级版本',
-      type: '通知',
-      keys: ['通知', '升级'],
-      date: new Date()
-    },
-    {
-      title: '系统凌晨维护',
-      type: '公告',
-      keys: ['公告', '维护'],
-      date: new Date()
-    },
-    {
-      title: '系统升级版本',
-      type: '通知',
-      keys: ['通知', '升级'],
-      date: new Date()
-    },
-    {
-      title: '系统凌晨维护',
-      type: '公告',
-      keys: ['公告', '维护'],
-      date: new Date()
-    }
-  ]
-  notice = Object.assign(notice, data)
+const getCommonOptions = (yAxisName) => {
+  const options = cloneDeep(barCommonOptions)
+  if (yAxisName) options.yAxis.name = yAxisName
+  return options
 }
+const list = ref([
+  {
+    api: getNewRegisterUserNum,
+    title: '新个人用户注册数量统计',
+    loading: false,
+    options: getCommonOptions()
+  },
+  {
+    api: getNewResumeNum,
+    title: '新增简历数量统计',
+    loading: false,
+    options: getCommonOptions('份')
+  },
+  {
+    api: getNewRegisterEnterpriseNum,
+    title: '新注册企业数量统计',
+    loading: false,
+    options: getCommonOptions()
+  },
+  {
+    api: getNewEnterpriseUserNum,
+    title: '新企业用户数量统计',
+    loading: false,
+    options: getCommonOptions()
+  }
+])
 
-// 获取快捷入口
-let shortcut = reactive<Shortcut[]>([])
+/** 图表数据请求 */
+const fetchData = async (api) => {
+  try {
+    const data = await api(queryParams)
+    return data
+  } catch (error) {
+    console.error('Error fetching data:', error)
+    return null
+  }
+}
 
-const getShortcut = async () => {
-  const data = [
-    {
-      name: 'Github',
-      icon: 'akar-icons:github-fill',
-      url: 'github.io'
-    },
-    {
-      name: 'Vue',
-      icon: 'logos:vue',
-      url: 'vuejs.org'
-    },
-    {
-      name: 'Vite',
-      icon: 'vscode-icons:file-type-vite',
-      url: 'https://vitejs.dev/'
-    },
-    {
-      name: 'Angular',
-      icon: 'logos:angular-icon',
-      url: 'github.io'
-    },
-    {
-      name: 'React',
-      icon: 'logos:react',
-      url: 'github.io'
-    },
-    {
-      name: 'Webpack',
-      icon: 'logos:webpack',
-      url: 'github.io'
-    }
-  ]
-  shortcut = Object.assign(shortcut, data)
+const unitArr = {
+  '3': '小时',
+  '0': '日',
+  '4': '日',
+  '5': '月'
 }
+async function fetchAllData() {
+  list.value.forEach(item => item.loading = true)
+  const promises = list.value.map(item => fetchData(item.api))
+  try {
+    const results = await Promise.all(promises)
+    results.forEach((result, index) => {
+      list.value[index].options.xAxis.name = unitArr[queryParams.type]
+      list.value[index].options.xAxis.data = result.x
+      list.value[index].options.series[0].data = result.y
+      list.value[index].loading = false
+    })
+  } catch (error) {
+    list.value.forEach(item => item.loading = false)
+  }
+}
+fetchAllData()
 
-// 用户来源
-const getUserAccessSource = async () => {
-  const data = [
-    { value: 335, name: 'analysis.directAccess' },
-    { value: 310, name: 'analysis.mailMarketing' },
-    { value: 234, name: 'analysis.allianceAdvertising' },
-    { value: 135, name: 'analysis.videoAdvertising' },
-    { value: 1548, name: 'analysis.searchEngines' }
-  ]
-  set(
-    pieOptionsData,
-    'legend.data',
-    data.map((v) => t(v.name))
-  )
-  pieOptionsData!.series![0].data = data.map((v) => {
-    return {
-      name: t(v.name),
-      value: v.value
-    }
-  })
+/** 类型选择操作 */
+const typeChange = (value) => {
+  if (value) queryParams.time = []
 }
-const barOptionsData = reactive<EChartsOption>(barOptions) as EChartsOption
 
-// 周活跃量
-const getWeeklyUserActivity = async () => {
-  const data = [
-    { value: 13253, name: 'analysis.monday' },
-    { value: 34235, name: 'analysis.tuesday' },
-    { value: 26321, name: 'analysis.wednesday' },
-    { value: 12340, name: 'analysis.thursday' },
-    { value: 24643, name: 'analysis.friday' },
-    { value: 1322, name: 'analysis.saturday' },
-    { value: 1324, name: 'analysis.sunday' }
-  ]
-  set(
-    barOptionsData,
-    'xAxis.data',
-    data.map((v) => t(v.name))
-  )
-  set(barOptionsData, 'series', [
-    {
-      name: t('analysis.activeQuantity'),
-      data: data.map((v) => v.value),
-      type: 'bar'
-    }
-  ])
+/** 自定义时间选择操作 */
+const timeRangeChange = (value) => {
+  if (value?.length) queryParams.type = '99'
+  else queryParams.type = '0'
 }
 
-const getAllApi = async () => {
-  await Promise.all([
-    getCount(),
-    getProject(),
-    getNotice(),
-    getShortcut(),
-    getUserAccessSource(),
-    getWeeklyUserActivity()
-  ])
-  loading.value = false
+/** 搜索按钮操作 */
+const handleQuery = async () => {
+  fetchAllData()
 }
 
-getAllApi()
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
 </script>

+ 15 - 0
src/views/menduner/system/enterprise/message/details/components/job.vue

@@ -45,6 +45,7 @@
       <template #default="scope">
         <el-button link type="primary" @click="openDetail(scope.row)">详情</el-button>
         <el-button link type="primary" @click="handleActions(scope.row.id, 0)">刷新</el-button>
+        <el-button link type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
         <el-button v-if="scope.row.status === '1'" link type="success" @click="handleActions(scope.row.id, 1)">开启</el-button>
         <el-button v-if="scope.row.status === '0'" link type="danger" @click="handleActions(scope.row.id, 2)">关闭</el-button>
       </template>
@@ -110,6 +111,7 @@ const props = defineProps({
   id: String
 })
 
+const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 const loading = ref(false)
 const tableData = ref([])
@@ -169,6 +171,19 @@ const openDetail = (item) => {
   itemData.value = item
   dialogVisible.value = true
 }
+
+/** 删除按钮操作 */
+const handleDelete = async (id) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await EnterpriseApi.deleteJob(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
 </script>
 
 <style scoped lang="scss">

+ 2 - 2
src/views/menduner/system/invoice/index.vue

@@ -91,7 +91,7 @@
       <el-table-column label="支付订单编号" align="center" prop="payOrderId" />
       <el-table-column label="开票金额" align="center" prop="price">
         <template #default="scope">
-          {{ scope.row.price ? (scope.row.price / 10.0).toFixed(2) + '元' : '' }}
+          {{ scope.row.price ? (scope.row.price / 100).toFixed(2) + '元' : '' }}
         </template>
       </el-table-column>
       <el-table-column label="发票类型" align="center" prop="category">
@@ -110,7 +110,7 @@
       <el-table-column label="联系电话" align="center" prop="phone" />
       <el-table-column label="开户银行" align="center" prop="enterpriseBankTitle" />
       <el-table-column label="开户账号" align="center" prop="enterpriseBankNo" />
-      <el-table-column label="已开发票地址" align="center" prop="fileUrl" :show-overflow-tooltip="true"/>
+      <el-table-column label="已开发票地址" align="center" prop="fileUrl" />
       <el-table-column label="操作" align="center">
         <template #default="scope">
           <el-button v-hasPermi="['member:invoice-list:status']" v-if="scope.row.status !== 1" link type="primary" @click="handleUpload(scope.row.id)">

+ 23 - 5
src/views/menduner/system/job/index.vue

@@ -130,14 +130,16 @@
           <dict-tag :type="DICT_TYPE.MENDUNER_EDUCATION_TYPE" :value="scope.row.eduType" />
         </template>
       </el-table-column>
-      <el-table-column label="最低薪资" align="center" prop="payFrom" />
-      <el-table-column label="最高薪资" align="center" prop="payTo" />
-      <el-table-column label="计薪时段" align="center" prop="payUnit">
+      <el-table-column label="薪资" align="center" prop="payFrom">
         <template #default="scope">
-          <dict-tag :type="DICT_TYPE.MENDUNER_PAY_UNIT" :value="scope.row.payUnit" />
+          {{ scope.row.payFrom && scope.row.payTo ? scope.row.payFrom + '-' + scope.row.payTo + '/' + getIntDictOptions(DICT_TYPE.MENDUNER_PAY_UNIT).find(e => e.value === Number(scope.row.payUnit))?.label : '面议' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="点数" align="center" prop="hirePrice">
+        <template #default="scope">
+          {{ scope.row.hirePrice / 100 }}
         </template>
       </el-table-column>
-      <el-table-column label="点数" align="center" prop="hirePrice" />
       <el-table-column label="职位状态" align="center" prop="status">
         <template #default="scope">
           <dict-tag :type="DICT_TYPE.MENDUNER_JOB_STATUS" :value="scope.row.status" />
@@ -153,6 +155,7 @@
       <el-table-column label="操作" align="center">
         <template #default="scope">
           <el-button v-if="scope.row.status === '0'" link type="primary" @click="openForm('update', scope.row.id)">编辑</el-button>
+          <el-button link type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
           <el-button v-if="scope.row.status === '0'" link type="primary" @click="handleAction(0, scope.row.id)">关闭</el-button>
           <el-button v-if="scope.row.status === '1'" link type="primary" @click="handleAction(1, scope.row.id)">激活</el-button>
         </template>
@@ -178,11 +181,13 @@ import { JobAdvertisedApi, JobAdvertisedVO } from '@/api/menduner/system/job'
 import JobAdvertisedForm from './JobAdvertisedForm.vue'
 import { dealDictArrayData } from '@/utils/transform/position'
 import { getDict } from '@/hooks/web/useDictionaries'
+import { EnterpriseApi } from '@/api/menduner/system/enterprise/message'
 
 /** 门墩儿-招聘职位 列表 */
 defineOptions({ name: 'JobAdvertised' })
 
 const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
 
 const loading = ref(true) // 列表的加载中
 const list = ref<JobAdvertisedVO[]>([]) // 列表的数据
@@ -272,6 +277,19 @@ const handleAction = async (index: number, id: number) => {
   } catch {}
 }
 
+/** 删除按钮操作 */
+const handleDelete = async (id) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await EnterpriseApi.deleteJob(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
 /** 初始化 **/
 onMounted(() => {
   getList()

+ 9 - 9
src/views/menduner/system/order/index.vue

@@ -91,9 +91,9 @@
   <!-- 列表 -->
   <ContentWrap>
     <el-table v-loading="loading" :data="list" :stripe="true">
-      <el-table-column label="编号" align="center" prop="id" :show-overflow-tooltip="true" />
-      <el-table-column label="用户编号" align="center" prop="userId" :show-overflow-tooltip="true" />
-      <el-table-column label="商品名字" align="center" prop="spuName" :show-overflow-tooltip="true" />
+      <!-- <el-table-column label="编号" align="center" prop="id" :show-overflow-tooltip="true" /> -->
+      <!-- <el-table-column label="用户编号" align="center" prop="userId" :show-overflow-tooltip="true" /> -->
+      <el-table-column label="商品名字" align="center" prop="spuName" />
       <el-table-column label="价格" align="center" prop="price">
         <template #default="scope">
           {{ (scope.row.price / 100.0).toFixed(2) }}
@@ -104,23 +104,23 @@
           {{ scope.row.payStatus ? '已支付' : '未支付' }}
         </template>
       </el-table-column>
-      <el-table-column label="支付订单编号" align="center" prop="payOrderId" :show-overflow-tooltip="true" />
+      <el-table-column label="支付订单编号" align="center" prop="payOrderId" />
       <el-table-column label="支付渠道" align="center" prop="payChannelCode">
         <template #default="scope">
           <dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="scope.row.payChannelCode" />
         </template>
       </el-table-column>
-      <el-table-column label="订单支付时间" align="center" prop="payTime" :formatter="dateFormatter" width="180px" :show-overflow-tooltip="true" />
-      <el-table-column label="退款订单编号" align="center" prop="payRefundId" :show-overflow-tooltip="true" />
+      <el-table-column label="订单支付时间" align="center" prop="payTime" :formatter="dateFormatter" width="180px" />
+      <el-table-column label="退款订单编号" align="center" prop="payRefundId" />
       <el-table-column label="退款金额" align="center" prop="refundPrice" />
-      <el-table-column label="退款时间" align="center" prop="refundTime" :formatter="dateFormatter" width="180px" :show-overflow-tooltip="true" />
+      <el-table-column label="退款时间" align="center" prop="refundTime" :formatter="dateFormatter" width="180px" />
       <el-table-column label="订单取消类型" align="center" prop="cancelType">
         <template #default="scope">
           <dict-tag :type="DICT_TYPE.MENDUNER_TRADE_ORDER_CANCEL_TYPE" :value="scope.row.cancelType" />
         </template>
       </el-table-column>
-      <el-table-column label="订单取消时间" align="center" prop="cancelTime" :formatter="dateFormatter" width="180px" :show-overflow-tooltip="true" />
-      <el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180px" :show-overflow-tooltip="true" />
+      <el-table-column label="订单取消时间" align="center" prop="cancelTime" :formatter="dateFormatter" width="180px" />
+      <el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180px" />
       <el-table-column label="操作" align="center">
         <template #default="scope">
           <el-button link type="primary" @click="handlePay(scope.row)" v-if="!scope.row.payStatus && scope.row.cancelType !== '10'">