<template> <div> <el-card shadow="never"> <el-skeleton :loading="loading" animated> <el-row :gutter="20" justify="space-between"> <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24"> <div class="flex items-center"> <img :src="avatar" alt="" class="w-40px h-40px rounded-[50%] mr-20px" /> <div class="text-20px text-700"> {{ t('workplace.welcome') }} {{ username }} {{ t('workplace.happyDay') }} </div> </div> </el-col> <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24"> <div class="flex h-40px items-center justify-end <sm:mt-10px"> <div class="px-8px text-right"> <div class="text-14px text-gray-400 mb-20px">今日待跟进</div> <CountTo class="text-20px number-font" :start-val="0" :end-val="10" :duration="2600" /> </div> <el-divider direction="vertical" border-style="dashed" /> <div class="px-8px text-right"> <div class="text-14px text-gray-400 mb-20px">今日已跟进</div> <CountTo class="text-20px number-font" :start-val="0" :end-val="25" :duration="2600" /> </div> <el-divider direction="vertical" border-style="dashed" /> <div class="px-8px text-right"> <div class="text-14px text-gray-400 mb-20px">今日已成交</div> <CountTo class="text-20px number-font" :start-val="0" :end-val="2" :duration="2600" /> </div> <el-divider direction="vertical" border-style="dashed" /> <div class="px-8px text-right"> <div class="text-14px text-gray-400 mb-20px">剩余过期数</div> <CountTo class="text-20px number-font" :start-val="0" :end-val="235" :duration="2600" /> </div> <el-divider direction="vertical" border-style="dashed" /> <div class="px-8px text-right"> <div class="text-14px text-red-600 mb-20px">未知意向数</div> <CountTo class="text-20px number-font" :start-val="0" :end-val="0" :duration="2600" /> </div> </div> </el-col> </el-row> </el-skeleton> </el-card> <el-row class="mt-10px" :gutter="10" justify="space-between"> <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24" class="mb-10px"> <el-card shadow="never"> <template #header> <div class="flex justify-between h-3"> <span>本月成交来源</span> </div> </template> <el-skeleton :loading="loading" animated> <Echart :options="pieOptionsData" :height="280" /> </el-skeleton> </el-card> </el-col> <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24" class="mb-10px"> <el-card shadow="never"> <template #header> <div class="flex justify-between h-3"> <span>成交率</span> </div> </template> <el-skeleton :loading="loading" animated> <el-skeleton :loading="loading" animated> <Echart :options="lineOptionsData" :height="280" /> </el-skeleton> </el-skeleton> </el-card> </el-col> <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24" class="mb-10px"> <el-card shadow="never"> <template #header> <div class="flex justify-between h-3"> <span>跟进榜Top10</span> <el-radio-group v-model="followDate" size="small"> <el-radio label="day">本日</el-radio> <el-radio label="month">本月</el-radio> </el-radio-group> </div> </template> <el-skeleton :loading="loading" animated> <ul class="follow-wrap"> <!-- <TransitionGroup name="flip"> --> <li class="follow-item number-font mb-18px text-14px" v-for="(item, index) in followList" :key="index" > <span class="mr-10px">NO.{{ index + 1 }}</span> <span class="mr-10px">{{ item.name }}</span> <span>已跟进{{ item.count }}条线索</span> </li> <br /> <!-- </TransitionGroup> --> </ul> </el-skeleton> </el-card> </el-col> <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24" class="mb-10px"> <el-card shadow="never"> <template #header> <div class="flex justify-between h-3"> <span>本月成交榜Top10</span> </div> </template> <el-skeleton :loading="loading" animated> <el-table :data="followList" size="small"> <el-table-column prop="sort" label="排名" width="50" /> <el-table-column prop="name" label="姓名" width="70" /> <el-table-column prop="count" label="跟进数量" width="70" /> <el-table-column prop="orgName" label="所属组织" /> </el-table> </el-skeleton> </el-card> </el-col> </el-row> </div> </template> <script setup lang="ts" name="Home"> import { set } from 'lodash-es' import { EChartsOption } from 'echarts' import { useUserStore } from '@/store/modules/user' import avatarImg from '@/assets/imgs/avatar.gif' import { pieOptions, lineOptions } from './echarts-data' const { t } = useI18n() const userStore = useUserStore() const loading = ref(false) const avatar = userStore.getUser.avatar ? userStore.getUser.avatar : avatarImg const username = userStore.getUser.nickname const followDate = ref('day') // 成交线索来源 const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption const getSaleClueSource = async () => { const data = [ { value: 335, name: '宝典' }, { value: 310, name: '一点通' }, { value: 234, name: '抖音' }, { value: 135, name: '小红书' }, { value: 1548, name: '转介绍' } ] 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 lineOptionsData = reactive<EChartsOption>(lineOptions) as EChartsOption const getMonthlySaleRate = async () => { const data = [ { estimate: 100, actual: 120, name: 'analysis.january' }, { estimate: 120, actual: 82, name: 'analysis.february' }, { estimate: 161, actual: 91, name: 'analysis.march' }, { estimate: 134, actual: 154, name: 'analysis.april' }, { estimate: 105, actual: 162, name: 'analysis.may' }, { estimate: 160, actual: 140, name: 'analysis.june' }, { estimate: 165, actual: 145, name: 'analysis.july' }, { estimate: 114, actual: 250, name: 'analysis.august' }, { estimate: 163, actual: 134, name: 'analysis.september' }, { estimate: 185, actual: 56, name: 'analysis.october' }, { estimate: 118, actual: 99, name: 'analysis.november' }, { estimate: 123, actual: 123, name: 'analysis.december' } ] set( lineOptionsData, 'xAxis.data', data.map((v) => t(v.name)) ) set(lineOptionsData, 'series', [ { name: t('analysis.estimate'), smooth: true, type: 'line', data: data.map((v) => v.estimate), animationDuration: 2800, animationEasing: 'cubicInOut' }, { name: t('analysis.actual'), smooth: true, type: 'line', itemStyle: {}, data: data.map((v) => v.actual), animationDuration: 2800, animationEasing: 'quadraticOut' } ]) } const followList = ref([ { sort: 1, name: '张三', count: 12, orgName: '销售1组' }, { sort: 2, name: '张三', count: 11, orgName: '销售3组' }, { sort: 3, name: '张三', count: 11, orgName: '销售1组' }, { sort: 4, name: '张三', count: 10, orgName: '销售1组' }, { sort: 5, name: '张三', count: 2, orgName: '销售2组' }, { sort: 6, name: '张三', count: 1, orgName: '销售1组' }, { sort: 2, name: '张三', count: 11, orgName: '销售3组' }, { sort: 3, name: '张三', count: 11, orgName: '销售1组' }, { sort: 4, name: '张三', count: 10, orgName: '销售1组' }, { sort: 5, name: '张三', count: 2, orgName: '销售2组' }, { sort: 6, name: '张三', count: 1, orgName: '销售1组' } ]) const getAllApi = async () => { await Promise.all([getSaleClueSource(), getMonthlySaleRate()]) loading.value = false } getAllApi() </script> <style lang="scss" scoped> @font-face { font-family: numberFont; src: url('@/assets/fonts/DISPLAY FREE TFB.ttf'); } .number-font { font-family: numberFont !important; } </style>