|
|
@@ -1,147 +1,375 @@
|
|
|
<template>
|
|
|
<div class="app-container home">
|
|
|
- <!-- <el-divider /> -->
|
|
|
- <div class="index-style">
|
|
|
- <div class="typewriter-container">
|
|
|
- <span v-for="(char, index) in 'welcome!'" :key="index" :style="{ animationDelay: `${index * 0.5}s` }" class="typewriter-char">{{
|
|
|
- char
|
|
|
- }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <!-- 统计卡片 -->
|
|
|
+ <el-row :gutter="20" class="panel-group">
|
|
|
+ <el-col :span="6" class="card-panel-col">
|
|
|
+ <el-card shadow="hover" class="box-card">
|
|
|
+ <div class="card-header">
|
|
|
+ <span>伙伴商总数</span>
|
|
|
+ <el-tag type="primary" effect="light" size="small">实时</el-tag>
|
|
|
+ </div>
|
|
|
+ <div class="card-body">
|
|
|
+ <h2 class="num">1,250</h2>
|
|
|
+ <div class="bottom">
|
|
|
+ <span class="text-up">较上月 + 5% ↑</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6" class="card-panel-col">
|
|
|
+ <el-card shadow="hover" class="box-card">
|
|
|
+ <div class="card-header">
|
|
|
+ <span>本月新增入驻</span>
|
|
|
+ <el-tag type="success" effect="light" size="small">月度</el-tag>
|
|
|
+ </div>
|
|
|
+ <div class="card-body">
|
|
|
+ <h2 class="num">120</h2>
|
|
|
+ <div class="bottom">
|
|
|
+ <span class="text-up">较上月 + 12% ↑</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6" class="card-panel-col">
|
|
|
+ <el-card shadow="hover" class="box-card">
|
|
|
+ <div class="card-header">
|
|
|
+ <span>待处理审批</span>
|
|
|
+ <el-tag type="warning" effect="light" size="small">待办</el-tag>
|
|
|
+ </div>
|
|
|
+ <div class="card-body">
|
|
|
+ <h2 class="num" style="color: #e6a23c;">15</h2>
|
|
|
+ <div class="bottom">
|
|
|
+ <span style="color: #909399">需及时处理审批事项</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6" class="card-panel-col">
|
|
|
+ <el-card shadow="hover" class="box-card">
|
|
|
+ <div class="card-header">
|
|
|
+ <span>合作中项目数</span>
|
|
|
+ <el-tag type="info" effect="light" size="small">业务</el-tag>
|
|
|
+ </div>
|
|
|
+ <div class="card-body">
|
|
|
+ <h2 class="num">340</h2>
|
|
|
+ <div class="bottom">
|
|
|
+ <span class="text-down">较上月 - 2% ↓</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <!-- 图表 -->
|
|
|
+ <el-row :gutter="20" class="chart-group">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-card shadow="hover">
|
|
|
+ <template #header>
|
|
|
+ <div class="clearfix">
|
|
|
+ <span>近半年新增伙伴商趋势</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <div ref="lineChartRef" style="height: 350px"></div>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-card shadow="hover">
|
|
|
+ <template #header>
|
|
|
+ <div class="clearfix">
|
|
|
+ <span>伙伴商评级分布</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <div ref="pieChartRef" style="height: 350px"></div>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <!-- 列表 -->
|
|
|
+ <el-row :gutter="20" class="list-group">
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-card shadow="hover">
|
|
|
+ <template #header>
|
|
|
+ <div class="clearfix">
|
|
|
+ <span>最新入驻伙伴商审批列表</span>
|
|
|
+ <el-button style="float: right; padding: 3px 0" type="primary" link>查看更多</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <el-table :data="partnerList" style="width: 100%" :header-cell-style="{background:'#f8f8f9',color:'#606266'}">
|
|
|
+ <el-table-column type="index" label="序号" width="60" align="center" />
|
|
|
+ <el-table-column prop="companyName" label="伙伴商名称" min-width="200" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="contact" label="联系人" width="120" />
|
|
|
+ <el-table-column prop="phone" label="联系电话" width="150" />
|
|
|
+ <el-table-column prop="level" label="申请评级" width="120" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-tag :type="getLevelType(scope.row.level)">
|
|
|
+ {{ scope.row.level }}
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="status" label="审批状态" width="120" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-tag :type="scope.row.status === '已通过' ? 'success' : scope.row.status === '待审批' ? 'warning' : 'danger'">
|
|
|
+ {{ scope.row.status }}
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="joinTime" label="申请时间" width="160" />
|
|
|
+ <el-table-column label="操作" width="120" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-button type="primary" link size="small" v-if="scope.row.status === '待审批'">审批</el-button>
|
|
|
+ <el-button type="info" link size="small" v-else>查看</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup name="Index" lang="ts">
|
|
|
-const goTarget = (url: string) => {
|
|
|
- window.open(url, '__blank');
|
|
|
-};
|
|
|
-</script>
|
|
|
+import { ref, onMounted, onBeforeUnmount, nextTick, markRaw } from 'vue';
|
|
|
+import * as echarts from 'echarts';
|
|
|
|
|
|
-<style lang="scss" scoped>
|
|
|
-.home {
|
|
|
- blockquote {
|
|
|
- padding: 10px 20px;
|
|
|
- margin: 0 0 20px;
|
|
|
- font-size: 17.5px;
|
|
|
- border-left: 5px solid #eee;
|
|
|
+const lineChartRef = ref<HTMLElement | null>(null);
|
|
|
+const pieChartRef = ref<HTMLElement | null>(null);
|
|
|
+
|
|
|
+let lineChart: echarts.ECharts | null = null;
|
|
|
+let pieChart: echarts.ECharts | null = null;
|
|
|
+
|
|
|
+// 表格数据
|
|
|
+const partnerList = ref([
|
|
|
+ { companyName: '上海星瑞科技有限公司', contact: '张伟', phone: '138****8000', level: '战略伙伴', status: '待审批', joinTime: '2023-11-05 10:23:00' },
|
|
|
+ { companyName: '北京云创集团有限公司', contact: '李娜', phone: '139****5678', level: '核心伙伴', status: '已通过', joinTime: '2023-11-04 15:45:12' },
|
|
|
+ { companyName: '深圳速达物流中心', contact: '王强', phone: '137****9999', level: '普通伙伴', status: '已通过', joinTime: '2023-11-02 09:12:30' },
|
|
|
+ { companyName: '广州联智网络股份有限公司', contact: '陈静', phone: '136****6666', level: '核心伙伴', status: '已驳回', joinTime: '2023-10-30 14:20:00' },
|
|
|
+ { companyName: '杭州数智信息技术有限公司', contact: '刘洋', phone: '135****8888', level: '战略伙伴', status: '已通过', joinTime: '2023-10-28 11:10:45' },
|
|
|
+]);
|
|
|
+
|
|
|
+const getLevelType = (level: string) => {
|
|
|
+ switch (level) {
|
|
|
+ case '战略伙伴': return 'danger';
|
|
|
+ case '核心伙伴': return 'warning';
|
|
|
+ case '普通伙伴': return 'info';
|
|
|
+ default: return 'primary';
|
|
|
}
|
|
|
- hr {
|
|
|
- margin-top: 20px;
|
|
|
- margin-bottom: 20px;
|
|
|
- border: 0;
|
|
|
- border-top: 1px solid #eee;
|
|
|
+};
|
|
|
+
|
|
|
+const initLineChart = () => {
|
|
|
+ if (lineChartRef.value) {
|
|
|
+ lineChart = markRaw(echarts.init(lineChartRef.value));
|
|
|
+ const option = {
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'axis'
|
|
|
+ },
|
|
|
+ grid: {
|
|
|
+ left: '3%',
|
|
|
+ right: '4%',
|
|
|
+ bottom: '3%',
|
|
|
+ containLabel: true
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: 'category',
|
|
|
+ boundaryGap: false,
|
|
|
+ data: ['5月', '6月', '7月', '8月', '9月', '10月']
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: 'value',
|
|
|
+ splitLine: {
|
|
|
+ lineStyle: {
|
|
|
+ type: 'dashed'
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '新增伙伴商',
|
|
|
+ type: 'line',
|
|
|
+ smooth: true,
|
|
|
+ areaStyle: {
|
|
|
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
+ { offset: 0, color: 'rgba(64,158,255,0.6)' },
|
|
|
+ { offset: 1, color: 'rgba(64,158,255,0.1)' }
|
|
|
+ ])
|
|
|
+ },
|
|
|
+ itemStyle: {
|
|
|
+ color: '#409EFF'
|
|
|
+ },
|
|
|
+ data: [20, 32, 25, 45, 60, 55]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+ lineChart.setOption(option);
|
|
|
}
|
|
|
- .col-item {
|
|
|
- margin-bottom: 20px;
|
|
|
+};
|
|
|
+
|
|
|
+const initPieChart = () => {
|
|
|
+ if (pieChartRef.value) {
|
|
|
+ pieChart = markRaw(echarts.init(pieChartRef.value));
|
|
|
+ const option = {
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'item',
|
|
|
+ formatter: '{a} <br/>{b} : {c}家 ({d}%)'
|
|
|
+ },
|
|
|
+ legend: {
|
|
|
+ bottom: '0%',
|
|
|
+ left: 'center',
|
|
|
+ itemWidth: 10,
|
|
|
+ itemHeight: 10,
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '伙伴商评级',
|
|
|
+ type: 'pie',
|
|
|
+ radius: ['45%', '70%'],
|
|
|
+ center: ['50%', '45%'],
|
|
|
+ avoidLabelOverlap: false,
|
|
|
+ itemStyle: {
|
|
|
+ borderRadius: 8,
|
|
|
+ borderColor: '#fff',
|
|
|
+ borderWidth: 2
|
|
|
+ },
|
|
|
+ label: {
|
|
|
+ show: false,
|
|
|
+ position: 'center'
|
|
|
+ },
|
|
|
+ emphasis: {
|
|
|
+ label: {
|
|
|
+ show: true,
|
|
|
+ fontSize: '18',
|
|
|
+ fontWeight: 'bold'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ labelLine: {
|
|
|
+ show: false
|
|
|
+ },
|
|
|
+ data: [
|
|
|
+ { value: 1048, name: '普通伙伴', itemStyle: { color: '#909399' } },
|
|
|
+ { value: 735, name: '核心伙伴', itemStyle: { color: '#E6A23C' } },
|
|
|
+ { value: 580, name: '战略伙伴', itemStyle: { color: '#F56C6C' } },
|
|
|
+ { value: 484, name: '认证伙伴', itemStyle: { color: '#409EFF' } },
|
|
|
+ { value: 300, name: '观察期伙伴', itemStyle: { color: '#C0C4CC' } }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+ pieChart.setOption(option);
|
|
|
}
|
|
|
+};
|
|
|
|
|
|
- ul {
|
|
|
- padding: 0;
|
|
|
- margin: 0;
|
|
|
+const handleResize = () => {
|
|
|
+ if (lineChart) {
|
|
|
+ lineChart.resize();
|
|
|
+ }
|
|
|
+ if (pieChart) {
|
|
|
+ pieChart.resize();
|
|
|
}
|
|
|
+};
|
|
|
|
|
|
- font-family: 'open sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
|
|
- font-size: 13px;
|
|
|
- color: #676a6c;
|
|
|
- overflow-x: hidden;
|
|
|
+onMounted(() => {
|
|
|
+ nextTick(() => {
|
|
|
+ initLineChart();
|
|
|
+ initPieChart();
|
|
|
+ window.addEventListener('resize', handleResize);
|
|
|
+ });
|
|
|
+});
|
|
|
|
|
|
- ul {
|
|
|
- list-style-type: none;
|
|
|
+onBeforeUnmount(() => {
|
|
|
+ window.removeEventListener('resize', handleResize);
|
|
|
+ if (lineChart) {
|
|
|
+ lineChart.dispose();
|
|
|
}
|
|
|
-
|
|
|
- h4 {
|
|
|
- margin-top: 0px;
|
|
|
+ if (pieChart) {
|
|
|
+ pieChart.dispose();
|
|
|
}
|
|
|
+});
|
|
|
+</script>
|
|
|
|
|
|
- h2 {
|
|
|
- margin-top: 10px;
|
|
|
- font-size: 26px;
|
|
|
- font-weight: 100;
|
|
|
- }
|
|
|
+<style lang="scss" scoped>
|
|
|
+.app-container {
|
|
|
+ padding: 20px;
|
|
|
+ background-color: #f0f2f5;
|
|
|
+ min-height: calc(100vh - 84px);
|
|
|
+}
|
|
|
|
|
|
- p {
|
|
|
- margin-top: 10px;
|
|
|
+.panel-group {
|
|
|
+ margin-bottom: 20px;
|
|
|
+}
|
|
|
|
|
|
- b {
|
|
|
- font-weight: 700;
|
|
|
- }
|
|
|
+.box-card {
|
|
|
+ border: none;
|
|
|
+ border-radius: 8px;
|
|
|
+
|
|
|
+ .card-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ color: #606266;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 500;
|
|
|
}
|
|
|
|
|
|
- .update-log {
|
|
|
- ol {
|
|
|
- display: block;
|
|
|
- list-style-type: decimal;
|
|
|
- margin-block-start: 1em;
|
|
|
- margin-block-end: 1em;
|
|
|
- margin-inline-start: 0;
|
|
|
- margin-inline-end: 0;
|
|
|
- padding-inline-start: 40px;
|
|
|
+ .card-body {
|
|
|
+ margin-top: 15px;
|
|
|
+
|
|
|
+ .num {
|
|
|
+ font-size: 30px;
|
|
|
+ font-weight: bold;
|
|
|
+ margin: 0;
|
|
|
+ color: #303133;
|
|
|
}
|
|
|
- }
|
|
|
- .index-style {
|
|
|
- font-size: 48px;
|
|
|
- font-weight: bold;
|
|
|
- letter-spacing: 15px;
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- align-items: center;
|
|
|
- height: 300px;
|
|
|
- background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
|
|
- border-radius: 10px;
|
|
|
- box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
- .typewriter-container {
|
|
|
+ .bottom {
|
|
|
+ margin-top: 15px;
|
|
|
+ font-size: 13px;
|
|
|
display: flex;
|
|
|
- }
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ .text-up {
|
|
|
+ color: #f56c6c;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ font-weight: 500;
|
|
|
+ }
|
|
|
|
|
|
- .typewriter-char {
|
|
|
- opacity: 0;
|
|
|
- transform: translateY(20px) rotate(-5deg);
|
|
|
- animation:
|
|
|
- typewriter-animation 0.8s ease forwards,
|
|
|
- pulse 2s ease-in-out infinite 1s;
|
|
|
- color: #2d8cf0;
|
|
|
- text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
|
|
|
- transition: color 0.3s ease;
|
|
|
-
|
|
|
- &:hover {
|
|
|
- color: #f06292;
|
|
|
- transform: scale(1.1);
|
|
|
- animation-play-state: paused;
|
|
|
+ .text-down {
|
|
|
+ color: #67c23a;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ font-weight: 500;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- @keyframes typewriter-animation {
|
|
|
- 0% {
|
|
|
- opacity: 0;
|
|
|
- transform: translateY(20px) rotate(-5deg);
|
|
|
- }
|
|
|
- 50% {
|
|
|
- opacity: 0.5;
|
|
|
- transform: translateY(10px) rotate(-2deg);
|
|
|
- }
|
|
|
- 100% {
|
|
|
- opacity: 1;
|
|
|
- transform: translateY(0) rotate(0deg);
|
|
|
- }
|
|
|
+.chart-group {
|
|
|
+ margin-bottom: 20px;
|
|
|
+
|
|
|
+ .el-card {
|
|
|
+ border: none;
|
|
|
+ border-radius: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .clearfix {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #303133;
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- @keyframes pulse {
|
|
|
- 0% {
|
|
|
- text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
|
|
|
- transform: scale(1);
|
|
|
- }
|
|
|
- 50% {
|
|
|
- text-shadow:
|
|
|
- 0 0 15px rgba(45, 140, 240, 0.8),
|
|
|
- 0 0 30px rgba(45, 140, 240, 0.4);
|
|
|
- transform: scale(1.05);
|
|
|
- }
|
|
|
- 100% {
|
|
|
- text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
|
|
|
- transform: scale(1);
|
|
|
- }
|
|
|
+.list-group {
|
|
|
+ .el-card {
|
|
|
+ border: none;
|
|
|
+ border-radius: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .clearfix {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #303133;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
}
|
|
|
}
|
|
|
</style>
|