初始化本地仓库
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
<!-- 分析页页面 -->
|
||||
<template>
|
||||
<div>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :xl="14" :lg="15" :xs="24">
|
||||
<TodaySales />
|
||||
</ElCol>
|
||||
<ElCol :xl="10" :lg="9" :xs="24">
|
||||
<VisitorInsights />
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :xl="10" :lg="10" :xs="24">
|
||||
<TotalRevenue />
|
||||
</ElCol>
|
||||
<ElCol :xl="7" :lg="7" :xs="24">
|
||||
<CustomerSatisfaction />
|
||||
</ElCol>
|
||||
<ElCol :xl="7" :lg="7" :xs="24">
|
||||
<TargetVsReality />
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :xl="10" :lg="10" :xs="24">
|
||||
<TopProducts />
|
||||
</ElCol>
|
||||
<ElCol :xl="7" :lg="7" :xs="24">
|
||||
<SalesMappingByCountry />
|
||||
</ElCol>
|
||||
<ElCol :xl="7" :lg="7" :xs="24">
|
||||
<VolumeServiceLevel />
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import TodaySales from './modules/today-sales.vue'
|
||||
import VisitorInsights from './modules/visitor-insights.vue'
|
||||
import TotalRevenue from './modules/total-revenue.vue'
|
||||
import CustomerSatisfaction from './modules/customer-satisfaction.vue'
|
||||
import TargetVsReality from './modules/target-vs-reality.vue'
|
||||
import TopProducts from './modules/top-products.vue'
|
||||
import SalesMappingByCountry from './modules/sales-mapping-by-country.vue'
|
||||
import VolumeServiceLevel from './modules/volume-service-level.vue'
|
||||
|
||||
defineOptions({ name: 'Analysis' })
|
||||
</script>
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<div class="art-card h-100 p-5 mb-5 max-sm:mb-4">
|
||||
<div class="art-card-header">
|
||||
<div class="title">
|
||||
<h4>客户满意度</h4>
|
||||
</div>
|
||||
</div>
|
||||
<ArtLineChart
|
||||
height="calc(100% - 30px)"
|
||||
:data="chartData"
|
||||
:xAxisData="xAxisData"
|
||||
:showLegend="true"
|
||||
:showAxisLabel="true"
|
||||
:showAxisLine="false"
|
||||
:showSplitLine="true"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { LineDataItem } from '@/types/component/chart'
|
||||
|
||||
const AREA_STYLE_CONFIG = {
|
||||
startOpacity: 0.08,
|
||||
endOpacity: 0
|
||||
} as const
|
||||
|
||||
/**
|
||||
* X 轴数据配置
|
||||
* 表示一周的天数(周一到周日)
|
||||
*/
|
||||
const xAxisData = ['1', '2', '3', '4', '5', '6', '7']
|
||||
|
||||
/**
|
||||
* 客户满意度图表数据
|
||||
* 对比上个月和本月的满意度趋势
|
||||
*/
|
||||
const chartData = computed<LineDataItem[]>(() => [
|
||||
{
|
||||
name: '上个月',
|
||||
data: [65, 72, 68, 75, 82, 78, 85],
|
||||
areaStyle: AREA_STYLE_CONFIG
|
||||
},
|
||||
{
|
||||
name: '本月',
|
||||
data: [78, 85, 82, 88, 92, 89, 95],
|
||||
areaStyle: AREA_STYLE_CONFIG
|
||||
}
|
||||
])
|
||||
</script>
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<div class="art-card h-82 p-5 mb-5 max-sm:mb-4">
|
||||
<div class="art-card-header">
|
||||
<div class="title">
|
||||
<h4>全国销售分布</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ArtRingChart
|
||||
:data="[
|
||||
{ value: 30, name: '北京' },
|
||||
{ value: 25, name: '上海' },
|
||||
{ value: 45, name: '广州' }
|
||||
]"
|
||||
:color="['#4C87F3', '#93F1B4', '#8BD8FC']"
|
||||
:radius="['46%', '60%']"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<div class="art-card h-100 p-5 mb-5 max-sm:mb-4">
|
||||
<div class="art-card-header">
|
||||
<div class="title">
|
||||
<h4>目标与实际</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ArtBarChart
|
||||
class="p-5"
|
||||
height="12rem"
|
||||
:data="revenueData"
|
||||
:xAxisData="weekDays"
|
||||
:showAxisLine="false"
|
||||
barWidth="28%"
|
||||
/>
|
||||
|
||||
<div class="px-5 mt-4">
|
||||
<div v-for="item in totalItems" :key="item.label" class="flex-c mb-5 last:mb-0">
|
||||
<div class="flex-c justify-start w-3/5 text-sm">
|
||||
<div class="w-10 h-10 mr-3 text-lg rounded-md flex-cc" :class="item.iconClass">
|
||||
<ArtSvgIcon :icon="item.icon" />
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col items-start">
|
||||
<span class="text-base text-g-800">{{ item.label }}</span>
|
||||
<span class="mt-1 text-xs text-g-500">{{ item.subLabel }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-lg font-normal" :class="item.valueClass">{{ item.value }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
interface RevenueDataItem {
|
||||
name: string
|
||||
data: number[]
|
||||
}
|
||||
|
||||
/**
|
||||
* 一周的日期标签
|
||||
*/
|
||||
const weekDays = ref(['周一', '周二', '周三', '周四', '周五', '周六', '周日'])
|
||||
|
||||
/**
|
||||
* 目标与实际销售数据
|
||||
* 展示一周内的线上销售情况
|
||||
*/
|
||||
const revenueData = ref<RevenueDataItem[]>([
|
||||
{
|
||||
name: '线上销售',
|
||||
data: [12, 13, 5, 15, 10, 15, 18]
|
||||
}
|
||||
])
|
||||
|
||||
/**
|
||||
* 统计项数据
|
||||
*/
|
||||
const totalItems = [
|
||||
{
|
||||
icon: 'ri:shopping-bag-line',
|
||||
iconClass: 'text-theme bg-theme/12',
|
||||
label: '实际销售额',
|
||||
subLabel: '全球',
|
||||
value: '8,823',
|
||||
valueClass: 'text-theme'
|
||||
},
|
||||
{
|
||||
icon: 'ri:money-dollar-circle-line',
|
||||
iconClass: 'text-theme bg-theme/12',
|
||||
label: '目标销售额',
|
||||
subLabel: '商业',
|
||||
value: '12,122',
|
||||
valueClass: 'text-theme'
|
||||
}
|
||||
]
|
||||
</script>
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<div class="art-card h-82 p-5 mb-5 overflow-hidden max-lg:h-auto max-sm:mb-4">
|
||||
<div class="art-card-header pr-0">
|
||||
<div class="title">
|
||||
<h4>今日销售</h4>
|
||||
<p>销售总结</p>
|
||||
</div>
|
||||
<div class="flex-cc h-7.5 min-w-17 border border-g-300 rounded-lg text-g-500 c-p">
|
||||
<ArtSvgIcon icon="ri:arrow-up-line" class="text-base mr-1.5" />
|
||||
<span class="text-xs">导出</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-2">
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="6" :xs="24" v-for="(item, index) in salesData" :key="index">
|
||||
<div
|
||||
class="flex px-5 flex-col justify-center h-55 border border-g-300/85 rounded-xl max-lg:mb-4 max-sm:flex-row max-sm:justify-between max-sm:items-center max-sm:h-40"
|
||||
>
|
||||
<div class="size-12 rounded-lg flex-cc bg-theme/10">
|
||||
<ArtSvgIcon :icon="item.icon" class="text-xl text-theme" />
|
||||
</div>
|
||||
|
||||
<div class="max-sm:ml-4 mt-3.5 max-sm:mt-0 max-sm:text-end">
|
||||
<ArtCountTo class="text-2xl font-medium" :target="item.value" :duration="1500" />
|
||||
<p class="mt-2 text-base text-g-600 max-sm:mt-1">{{ item.label }}</p>
|
||||
<small class="text-g-500 mt-1 max-sm:mt-0.5">
|
||||
较昨天
|
||||
<span
|
||||
class="font-medium"
|
||||
:class="[item.change.indexOf('+') === -1 ? 'text-danger' : 'text-success']"
|
||||
>{{ item.change }}</span
|
||||
>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
interface SalesDataItem {
|
||||
label: string
|
||||
value: number
|
||||
change: string
|
||||
icon: string
|
||||
class: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 今日销售数据统计
|
||||
* 包含销售额、订单量、产品销量和新客户数等关键指标
|
||||
*/
|
||||
const salesData = ref<SalesDataItem[]>([
|
||||
{
|
||||
label: '总销售额',
|
||||
value: 999,
|
||||
change: '+10%',
|
||||
icon: 'ri:bar-chart-box-ai-line',
|
||||
class: 'bg-theme'
|
||||
},
|
||||
{
|
||||
label: '总订单量',
|
||||
value: 300,
|
||||
change: '+15%',
|
||||
icon: 'ri:bar-chart-grouped-line',
|
||||
class: 'bg-warning'
|
||||
},
|
||||
{
|
||||
label: '产品销售量',
|
||||
value: 56,
|
||||
change: '-5%',
|
||||
icon: 'ri:bar-chart-2-line',
|
||||
class: 'bg-error'
|
||||
},
|
||||
{
|
||||
label: '新客户数',
|
||||
value: 68,
|
||||
change: '+8%',
|
||||
icon: 'ri:user-add-line',
|
||||
class: 'bg-success'
|
||||
}
|
||||
])
|
||||
</script>
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<div class="art-card h-82 p-5 mb-5 overflow-hidden max-sm:mb-4">
|
||||
<div class="art-card-header">
|
||||
<div class="title">
|
||||
<h4>热门产品</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overflow-auto h-full">
|
||||
<ArtTable
|
||||
:data="products"
|
||||
style="width: 100%"
|
||||
size="large"
|
||||
:border="false"
|
||||
:stripe="false"
|
||||
:header-cell-style="{ background: 'transparent' }"
|
||||
>
|
||||
<ElTableColumn prop="name" label="产品名称" width="200" />
|
||||
<ElTableColumn prop="popularity" label="销量">
|
||||
<template #default="scope">
|
||||
<ElProgress
|
||||
:percentage="scope.row.popularity"
|
||||
:color="getColor(scope.row.popularity)"
|
||||
:stroke-width="5"
|
||||
:show-text="false"
|
||||
/>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn prop="sales" label="销量" width="80">
|
||||
<template #default="scope">
|
||||
<span
|
||||
:style="{
|
||||
color: getColor(scope.row.popularity),
|
||||
backgroundColor: `rgba(${hexToRgb(getColor(scope.row.popularity))}, 0.08)`,
|
||||
border: '1px solid',
|
||||
padding: '3px 6px',
|
||||
borderRadius: '4px',
|
||||
fontSize: '12px'
|
||||
}"
|
||||
>{{ scope.row.sales }}</span
|
||||
>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</ArtTable>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { hexToRgb } from '@/utils/ui'
|
||||
|
||||
interface Product {
|
||||
name: string
|
||||
popularity: number
|
||||
sales: string
|
||||
}
|
||||
|
||||
const COLOR_THRESHOLDS = {
|
||||
LOW: 25,
|
||||
MEDIUM: 50,
|
||||
HIGH: 75
|
||||
} as const
|
||||
|
||||
const POPULARITY_COLORS = {
|
||||
LOW: '#00E096',
|
||||
MEDIUM: '#0095FF',
|
||||
HIGH: '#884CFF',
|
||||
VERY_HIGH: '#FE8F0E'
|
||||
} as const
|
||||
|
||||
/**
|
||||
* 热门产品列表数据
|
||||
* 包含产品名称、热度和销量信息
|
||||
*/
|
||||
const products = computed<Product[]>(() => [
|
||||
{ name: '智能手机', popularity: 10, sales: '100' },
|
||||
{ name: '笔记本电脑', popularity: 29, sales: '100' },
|
||||
{ name: '平板电脑', popularity: 65, sales: '100' },
|
||||
{ name: '智能手表', popularity: 32, sales: '100' },
|
||||
{ name: '无线耳机', popularity: 78, sales: '100' },
|
||||
{ name: '智能音箱', popularity: 41, sales: '100' }
|
||||
])
|
||||
|
||||
/**
|
||||
* 根据热度百分比获取对应的颜色
|
||||
* @param percentage 热度百分比 (0-100)
|
||||
* @returns 对应的颜色值
|
||||
*/
|
||||
const getColor = (percentage: number): string => {
|
||||
if (percentage < COLOR_THRESHOLDS.LOW) return POPULARITY_COLORS.LOW
|
||||
if (percentage < COLOR_THRESHOLDS.MEDIUM) return POPULARITY_COLORS.MEDIUM
|
||||
if (percentage < COLOR_THRESHOLDS.HIGH) return POPULARITY_COLORS.HIGH
|
||||
return POPULARITY_COLORS.VERY_HIGH
|
||||
}
|
||||
</script>
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<div class="art-card h-100 p-5 mb-5 max-sm:mb-4">
|
||||
<div class="art-card-header">
|
||||
<div class="title">
|
||||
<h4>总收入</h4>
|
||||
</div>
|
||||
</div>
|
||||
<ArtBarChart
|
||||
height="calc(100% - 30px)"
|
||||
:data="revenueData"
|
||||
:xAxisData="weekDays"
|
||||
:showLegend="true"
|
||||
:showAxisLine="false"
|
||||
barWidth="18%"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
interface RevenueDataItem {
|
||||
name: string
|
||||
data: number[]
|
||||
}
|
||||
|
||||
/**
|
||||
* 一周的日期标签
|
||||
*/
|
||||
const weekDays = ref(['周一', '周二', '周三', '周四', '周五', '周六', '周日'])
|
||||
|
||||
/**
|
||||
* 总收入数据
|
||||
* 对比线上和线下销售的一周收入情况
|
||||
*/
|
||||
const revenueData = ref<RevenueDataItem[]>([
|
||||
{
|
||||
name: '线上销售',
|
||||
data: [12, 13, 5, 15, 10, 15, 18]
|
||||
},
|
||||
{
|
||||
name: '线下销售',
|
||||
data: [10, 11, 20, 5, 11, 13, 10]
|
||||
}
|
||||
])
|
||||
</script>
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<div class="art-card h-82 p-5 mb-5 max-sm:mb-4">
|
||||
<div class="art-card-header">
|
||||
<div class="title">
|
||||
<h4>访客洞察</h4>
|
||||
</div>
|
||||
</div>
|
||||
<ArtLineChart
|
||||
height="calc(100% - 30px)"
|
||||
:data="chartData"
|
||||
:xAxisData="xAxisData"
|
||||
:showLegend="true"
|
||||
:showAxisLabel="true"
|
||||
:showAxisLine="false"
|
||||
:showSplitLine="true"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { LineDataItem } from '@/types/component/chart'
|
||||
|
||||
/**
|
||||
* X 轴数据配置
|
||||
* 表示一年的月份(1-12月)
|
||||
*/
|
||||
const xAxisData = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']
|
||||
|
||||
/**
|
||||
* 访客洞察图表数据
|
||||
* 对比老客户和新客户的全年访问趋势
|
||||
*/
|
||||
const chartData = computed<LineDataItem[]>(() => [
|
||||
{
|
||||
name: '老客户',
|
||||
data: [280, 350, 300, 250, 230, 210, 240, 280, 320, 350, 300, 200]
|
||||
},
|
||||
{
|
||||
name: '新客户',
|
||||
data: [260, 200, 150, 130, 180, 270, 340, 380, 300, 220, 170, 130]
|
||||
}
|
||||
])
|
||||
</script>
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<div class="art-card h-82 p-5 mb-5 max-sm:mb-4">
|
||||
<div class="art-card-header">
|
||||
<div class="title">
|
||||
<h4>业务量与服务水平</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ArtBarChart
|
||||
class="mt-6"
|
||||
height="14.3rem"
|
||||
:data="volumeServiceData"
|
||||
:xAxisData="serviceCategories"
|
||||
:showLegend="true"
|
||||
:showAxisLine="false"
|
||||
:stack="true"
|
||||
barWidth="22%"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
interface VolumeServiceDataItem {
|
||||
name: string
|
||||
data: number[]
|
||||
stack: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务类别数据
|
||||
* 不同产品的分类标签
|
||||
*/
|
||||
const serviceCategories = ref(['产品A', '产品B', '产品C', '产品D', '产品E'])
|
||||
|
||||
/**
|
||||
* 业务量与服务量数据
|
||||
* 展示各产品的业务量和服务量对比,使用堆叠柱状图展示
|
||||
*/
|
||||
const volumeServiceData = ref<VolumeServiceDataItem[]>([
|
||||
{
|
||||
name: '业务量',
|
||||
data: [20, 25, 30, 35, 40],
|
||||
stack: 'total'
|
||||
},
|
||||
{
|
||||
name: '服务量',
|
||||
data: [30, 35, 40, 45, 50],
|
||||
stack: 'total'
|
||||
}
|
||||
])
|
||||
</script>
|
||||
Reference in New Issue
Block a user