【招生用户端】 新增# 工作台页面
parent
bb64589dfd
commit
a8cc9b437b
|
@ -52,4 +52,6 @@
|
|||
--el-box-shadow-lighter: 0px 0px 6px rgba(0, 0, 0, 0.12);
|
||||
--el-box-shadow-dark: 0px 16px 48px 16px rgba(0, 0, 0, 0.08), 0px 12px 32px rgba(0, 0, 0, 0.12), 0px 8px 16px -8px rgba(0, 0, 0, 0.16);
|
||||
--color-purple: #800080;
|
||||
--color-primary: #0e66fb;
|
||||
--color-gray: #d5d5d5;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<template>
|
||||
<div class="flex flex-col gap-[16px] bg-white p-[20px]">
|
||||
<div class="flex-row-between-center">
|
||||
<span>{{ title }}</span>
|
||||
<div class="flex flex-col gap-[16px] bg-white h-full">
|
||||
<div class="flex-row-between-center px-[20px] pt-[20px]">
|
||||
<span class="text-[20px] font-bold">{{ title }}</span>
|
||||
<slot name="right" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex-1 px-[20px] pb-[20px]">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
<template>
|
||||
<div class="flex-1 w-full">
|
||||
<card title="线索转化情况统计">
|
||||
<v-charts style="height: 350px" :option="option" :autoresize="true" />
|
||||
</card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import card from './card.vue'
|
||||
import vCharts from 'vue-echarts'
|
||||
|
||||
const data = [
|
||||
{ value: 1048, name: '有意向' },
|
||||
{ value: 735, name: '待领取' },
|
||||
{ value: 580, name: '转化中' },
|
||||
{ value: 484, name: '已添加' },
|
||||
{ value: 300, name: '异常待处理' },
|
||||
{ value: 300, name: '已成交' },
|
||||
{ value: 300, name: '已战败' }
|
||||
]
|
||||
const option = ref({
|
||||
color: ['#73DDFF', '#73ACFF', '#FDD56A', '#FDB36A', '#FD866A', '#9E87FF', '#58D5FF'],
|
||||
tooltip: {
|
||||
trigger: 'item'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
top: 'center',
|
||||
right: 0
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '',
|
||||
type: 'pie',
|
||||
radius: ['25%', '55%'],
|
||||
center: ['45%', '50%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: true,
|
||||
position: 'outside',
|
||||
formatter: params => {
|
||||
return `${params.name}:${params.percent}%`
|
||||
}
|
||||
},
|
||||
data
|
||||
}
|
||||
]
|
||||
})
|
||||
</script>
|
||||
<style scoped></style>
|
|
@ -0,0 +1,86 @@
|
|||
<template>
|
||||
<div class="flex-1 w-full chart-card">
|
||||
<card title="线索转客户统计">
|
||||
<v-charts style="height: 350px" :autoresize="true" :option="option" />
|
||||
</card>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import card from './card.vue'
|
||||
import vCharts from 'vue-echarts'
|
||||
|
||||
const data = [
|
||||
{ name: '湛江团队', clueNumber: 52, client: 52, rate: 100 },
|
||||
{ name: '广州团队', clueNumber: 8, client: 6, rate: 15 }
|
||||
]
|
||||
function createBarSeries(data, name, field) {
|
||||
return {
|
||||
name,
|
||||
type: 'bar',
|
||||
data: data.map(item => item[field])
|
||||
}
|
||||
}
|
||||
|
||||
function createLineSeries(data, name) {
|
||||
return {
|
||||
name,
|
||||
type: 'line',
|
||||
tooltip: {
|
||||
valueFormatter: function (value) {
|
||||
return (value as number) + '%'
|
||||
}
|
||||
},
|
||||
data: data.map(item => item.client),
|
||||
yAxisIndex: 1
|
||||
}
|
||||
}
|
||||
const xAxisData = () => data.map(item => item.name)
|
||||
const series = [
|
||||
createBarSeries(data, '线索数', 'clueNumber'),
|
||||
createBarSeries(data, '线索转客户数', 'client'),
|
||||
createLineSeries(data, '线索转客户率')
|
||||
]
|
||||
|
||||
const option = ref({
|
||||
color: ['#0E66FB', '#FAC858', '#96B2D9'],
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross',
|
||||
crossStyle: {
|
||||
color: '#999'
|
||||
}
|
||||
}
|
||||
},
|
||||
toolbox: {},
|
||||
legend: {},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: xAxisData()
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
formatter: '{value}'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
formatter: '{value} %'
|
||||
}
|
||||
}
|
||||
],
|
||||
series
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@media (max-width: 1000px) {
|
||||
.chart-card {
|
||||
flex: 1 0 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,63 @@
|
|||
<template>
|
||||
<div class="flex-1 w-full chart-card">
|
||||
<card title="成交客户统计">
|
||||
<v-charts style="height: 350px" :autoresize="true" :option="option" />
|
||||
</card>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import card from './card.vue'
|
||||
import vCharts from 'vue-echarts'
|
||||
|
||||
const data = [
|
||||
{ name: '湛江团队', clueNumber: 52, client: 52, rate: 100 },
|
||||
{ name: '广州团队', clueNumber: 8, client: 6, rate: 15 }
|
||||
]
|
||||
function createBarSeries(data, name, field) {
|
||||
return {
|
||||
name,
|
||||
type: 'bar',
|
||||
data: data.map(item => item[field])
|
||||
}
|
||||
}
|
||||
|
||||
const xAxisData = () => data.map(item => item.name)
|
||||
const series = [createBarSeries(data, '客户数', 'clueNumber'), createBarSeries(data, '成交客户数', 'client')]
|
||||
|
||||
const option = ref({
|
||||
color: ['#0E66FB', '#96B2D9'],
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross',
|
||||
crossStyle: {
|
||||
color: '#999'
|
||||
}
|
||||
}
|
||||
},
|
||||
toolbox: {},
|
||||
legend: {},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: xAxisData()
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
formatter: '{value}'
|
||||
}
|
||||
}
|
||||
],
|
||||
series
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@media (max-width: 1000px) {
|
||||
.chart-card {
|
||||
flex: 1 0 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,75 @@
|
|||
<template>
|
||||
<div class="flex-1 w-full">
|
||||
<card title="成交客户增长趋势">
|
||||
<v-charts style="height: 350px" :option="option" :autoresize="true" />
|
||||
</card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import vCharts from 'vue-echarts'
|
||||
import card from './card.vue'
|
||||
|
||||
const data = [
|
||||
{ label: '2025-02-24', value: 320 },
|
||||
{ label: '2025-02-25', value: 132 },
|
||||
{ label: '2025-02-26', value: 201 },
|
||||
{ label: '2025-02-27', value: 334 },
|
||||
{ label: '2025-02-28', value: 190 },
|
||||
{ label: '2025-03-01', value: 130 },
|
||||
{ label: '2025-03-02', value: 220 }
|
||||
]
|
||||
const xAxisData = data.map(item => item.label)
|
||||
const seriesData = data.map(item => item.value)
|
||||
const option = ref({
|
||||
color: ['#37A2FF'],
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {},
|
||||
toolbox: {},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: xAxisData,
|
||||
axisLabel: {
|
||||
interval: 0
|
||||
}
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value'
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '成交客户数量',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: '#9E87FFb3'
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: '#9E87FF03'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
data: seriesData
|
||||
}
|
||||
]
|
||||
})
|
||||
</script>
|
||||
<style scoped></style>
|
|
@ -1,10 +1,33 @@
|
|||
<template>
|
||||
<card title="数据简报">
|
||||
<div>333</div>
|
||||
<div class="data-overview">
|
||||
<div
|
||||
class="flex-1 bg-[#F7F8FA] flex flex-col gap-[12px] p-[20px] rounded-[8px]"
|
||||
v-for="(item, index) in dataOverview"
|
||||
:key="`unique-${index}`"
|
||||
>
|
||||
<span>{{ item.label }}</span>
|
||||
<span class="text-[20px]">{{ item.value }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import card from './card.vue'
|
||||
const dataOverview = ref([
|
||||
{ label: '新增跟进记录(个)', value: 60 },
|
||||
{ label: '新增客户(个)', value: 60 },
|
||||
{ label: '成交客户(个)', value: 60 },
|
||||
{ label: '转化中客户(个)', value: 60 },
|
||||
{ label: '异常待处理(个)', value: 60 },
|
||||
{ label: '战败客户(个)', value: 60 }
|
||||
])
|
||||
</script>
|
||||
<style scoped></style>
|
||||
<style scoped lang="scss">
|
||||
.data-overview {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<template>
|
||||
<div class="rank flex-1">
|
||||
<card title="TOP5">
|
||||
<template #right>
|
||||
<div class="positions">
|
||||
<span class="default" :class="{ active: item.id == postId }" v-for="item in positions" :key="item.id" @click="postId = item.id">
|
||||
{{ item.name }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-table :data="tableData">
|
||||
<el-table-column prop="index" label="排名" width="70" />
|
||||
<el-table-column prop="name" label="负责人" width="180" />
|
||||
<el-table-column prop="totalNumber" label="总数" />
|
||||
</el-table>
|
||||
</card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import card from './card.vue'
|
||||
const positions = ref([
|
||||
{ name: '电销', id: 5 },
|
||||
{ name: '招生', id: 6 }
|
||||
])
|
||||
const postId = ref(5)
|
||||
|
||||
const tableData = ref([
|
||||
{
|
||||
index: 1,
|
||||
name: 'John Brown',
|
||||
totalNumber: 32
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
name: 'John Brown',
|
||||
totalNumber: 32
|
||||
},
|
||||
{
|
||||
index: 3,
|
||||
name: 'John Brown',
|
||||
totalNumber: 32
|
||||
}
|
||||
])
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.rank {
|
||||
min-height: 350px;
|
||||
.positions {
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
span {
|
||||
padding: 5px 10px;
|
||||
border: 1px solid var(--color-gray);
|
||||
&:first-child {
|
||||
border-right-color: transparent;
|
||||
}
|
||||
&:last-child {
|
||||
border-left-color: transparent;
|
||||
}
|
||||
&.active {
|
||||
color: var(--color-primary);
|
||||
border-color: var(--color-primary);
|
||||
border-right-color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,91 +1,33 @@
|
|||
<template>
|
||||
<div class="workbench">
|
||||
<div class="workbench flex flex-col gap-[16px]">
|
||||
<data-overview />
|
||||
<div class="mb-4 function">2</div>
|
||||
<div class="lg:flex">
|
||||
<el-card class="flex-1 !border-none md:mr-4 mb-4" shadow="never">
|
||||
<template #header>
|
||||
<span>销售额趋势图(近15天)</span>
|
||||
</template>
|
||||
<div>
|
||||
<v-charts style="height: 350px" :option="workbenchData.businessOption" :autoresize="true" />
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card class="flex-1 !border-none md:mr-4 mb-4" shadow="never">
|
||||
<template #header>
|
||||
<span>用户访问量(近15天)</span>
|
||||
</template>
|
||||
<div>
|
||||
<v-charts style="height: 350px" :option="workbenchData.visitorOption" :autoresize="true" />
|
||||
</div>
|
||||
</el-card>
|
||||
<div class="flex gap-[16px] flex-wrap">
|
||||
<conversion-process-chart />
|
||||
<converted-chart />
|
||||
</div>
|
||||
<div class="flex gap-[16px] flex-wrap">
|
||||
<rank />
|
||||
<clue-status-pie />
|
||||
<!-- <converted-line-chart /> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import dataOverview from './components/data-overview.vue'
|
||||
import vCharts from 'vue-echarts'
|
||||
// 表单数据
|
||||
const workbenchData: any = reactive({
|
||||
businessOption: {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: []
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
itemStyle: {
|
||||
// 点的颜色。
|
||||
color: 'red'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '销售量',
|
||||
data: [],
|
||||
type: 'line',
|
||||
smooth: true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
visitorOption: {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: []
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
itemStyle: {
|
||||
// 点的颜色。
|
||||
color: 'red'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '访问量',
|
||||
data: [],
|
||||
type: 'line',
|
||||
smooth: true
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
// 获取工作台主页数据
|
||||
const getData = async () => {}
|
||||
|
||||
onMounted(() => {
|
||||
getData()
|
||||
})
|
||||
import conversionProcessChart from './components/conversion-process-chart.vue'
|
||||
import convertedChart from './components/converted-chart.vue'
|
||||
import rank from './components/rank.vue'
|
||||
import clueStatusPie from './components/clue-status-pie.vue'
|
||||
// import convertedLineChart from './components/converted-line-chart.vue'
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped>
|
||||
.wokrbench {
|
||||
&-center {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue