637 lines
16 KiB
Vue
637 lines
16 KiB
Vue
<template>
|
||
<div class="app-container home">
|
||
<!-- 公司标题栏 -->
|
||
<div class="company-header">
|
||
<div class="company-title">
|
||
<i class="el-icon-office-building"></i>
|
||
<h1>西安华府人家装饰工程有限公司</h1>
|
||
<p class="company-subtitle">专业装饰工程服务管理平台</p>
|
||
</div>
|
||
<div class="company-stats">
|
||
<div class="stat-item">
|
||
<div class="stat-number">{{ stats.orderCount }}</div>
|
||
<div class="stat-label">订单总数</div>
|
||
</div>
|
||
<div class="stat-item">
|
||
<div class="stat-number">{{ stats.serviceCount }}</div>
|
||
<div class="stat-label">服务项目</div>
|
||
</div>
|
||
<div class="stat-item">
|
||
<div class="stat-number">{{ stats.materialCount }}</div>
|
||
<div class="stat-label">材料类型</div>
|
||
</div>
|
||
<div class="stat-item">
|
||
<div class="stat-number">{{ stats.userCount }}</div>
|
||
<div class="stat-label">用户总数</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 业务概览 -->
|
||
<el-row :gutter="20" class="business-overview">
|
||
<el-col :span="8">
|
||
<el-card class="overview-card order-overview">
|
||
<div slot="header" class="card-header">
|
||
<i class="el-icon-document-checked"></i>
|
||
<span>订单管理</span>
|
||
</div>
|
||
<div class="card-content">
|
||
<div class="feature-list">
|
||
<div class="feature-item">
|
||
<i class="el-icon-circle-check"></i>
|
||
<span>智能派单系统</span>
|
||
</div>
|
||
<div class="feature-item">
|
||
<i class="el-icon-time"></i>
|
||
<span>服务进度跟踪</span>
|
||
</div>
|
||
<div class="feature-item">
|
||
<i class="el-icon-money"></i>
|
||
<span>费用结算管理</span>
|
||
</div>
|
||
<div class="feature-item">
|
||
<i class="el-icon-phone"></i>
|
||
<span>客户沟通记录</span>
|
||
</div>
|
||
</div>
|
||
<div class="action-btn">
|
||
<el-button type="primary" @click="goToPage('/system/Order/index')">
|
||
<i class="el-icon-right"></i>
|
||
进入订单管理
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
</el-card>
|
||
</el-col>
|
||
|
||
<el-col :span="8">
|
||
<el-card class="overview-card service-overview">
|
||
<div slot="header" class="card-header">
|
||
<i class="el-icon-setting"></i>
|
||
<span>服务项目</span>
|
||
</div>
|
||
<div class="card-content">
|
||
<div class="feature-list">
|
||
<div class="feature-item">
|
||
<i class="el-icon-tools"></i>
|
||
<span>工艺分类管理</span>
|
||
</div>
|
||
<div class="feature-item">
|
||
<i class="el-icon-goods"></i>
|
||
<span>服务内容配置</span>
|
||
</div>
|
||
<div class="feature-item">
|
||
<i class="el-icon-price-tag"></i>
|
||
<span>报价模板设置</span>
|
||
</div>
|
||
<div class="feature-item">
|
||
<i class="el-icon-collection-tag"></i>
|
||
<span>材料分类管理</span>
|
||
</div>
|
||
</div>
|
||
<div class="action-btn">
|
||
<el-button type="success" @click="goToPage('/system/ServiceGoods/index')">
|
||
<i class="el-icon-right"></i>
|
||
管理服务项目
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
</el-card>
|
||
</el-col>
|
||
|
||
<el-col :span="8">
|
||
<el-card class="overview-card quote-overview">
|
||
<div slot="header" class="card-header">
|
||
<i class="el-icon-document"></i>
|
||
<span>报价系统</span>
|
||
</div>
|
||
<div class="card-content">
|
||
<div class="feature-list">
|
||
<div class="feature-item">
|
||
<i class="el-icon-edit-outline"></i>
|
||
<span>快速生成报价</span>
|
||
</div>
|
||
<div class="feature-item">
|
||
<i class="el-icon-coin"></i>
|
||
<span>成本核算分析</span>
|
||
</div>
|
||
<div class="feature-item">
|
||
<i class="el-icon-data-analysis"></i>
|
||
<span>价格趋势分析</span>
|
||
</div>
|
||
<div class="feature-item">
|
||
<i class="el-icon-printer"></i>
|
||
<span>报价单据打印</span>
|
||
</div>
|
||
</div>
|
||
<div class="action-btn">
|
||
<el-button type="warning" @click="goToPage('/system/QuoteMaterial/index')">
|
||
<i class="el-icon-right"></i>
|
||
进入报价管理
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
</el-card>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<!-- 数据统计图表 -->
|
||
<el-row :gutter="20" class="charts-section">
|
||
<el-col :span="24">
|
||
<el-card class="chart-card">
|
||
<div slot="header" class="card-header">
|
||
<i class="el-icon-pie-chart"></i>
|
||
<span>订单状态分布</span>
|
||
</div>
|
||
<div class="chart-container" ref="orderChart"></div>
|
||
</el-card>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<!-- 快捷操作 -->
|
||
<el-row :gutter="20" class="quick-actions">
|
||
<el-col :span="24">
|
||
<el-card class="action-card">
|
||
<div slot="header" class="card-header">
|
||
<i class="el-icon-connection"></i>
|
||
<span>快捷操作</span>
|
||
</div>
|
||
<div class="quick-buttons">
|
||
<el-button-group>
|
||
<el-button type="primary" icon="el-icon-plus" @click="goToPage('/system/Order/index')">新建订单</el-button>
|
||
<el-button type="success" icon="el-icon-edit" @click="goToPage('/system/ServiceGoods/index')">添加服务</el-button>
|
||
<el-button type="warning" icon="el-icon-document-add" @click="goToPage('/system/QuoteMaterial/index')">创建报价</el-button>
|
||
<el-button type="info" icon="el-icon-user-solid" @click="goToPage('/system/users/index')">管理用户</el-button>
|
||
</el-button-group>
|
||
</div>
|
||
</el-card>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<!-- 系统信息 -->
|
||
<el-row :gutter="20" class="system-info">
|
||
<el-col :span="12">
|
||
<el-card class="info-card">
|
||
<div slot="header" class="card-header">
|
||
<i class="el-icon-info"></i>
|
||
<span>系统信息</span>
|
||
</div>
|
||
<div class="info-content">
|
||
<div class="info-item">
|
||
<span class="info-label">系统版本:</span>
|
||
<span class="info-value">v{{ version }}</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-label">服务状态:</span>
|
||
<el-tag type="success" size="small">运行正常</el-tag>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-label">最后更新:</span>
|
||
<span class="info-value">{{ new Date().toLocaleDateString() }}</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-label">数据库:</span>
|
||
<span class="info-value">MySQL 8.0</span>
|
||
</div>
|
||
</div>
|
||
</el-card>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-card class="info-card">
|
||
<div slot="header" class="card-header">
|
||
<i class="el-icon-cpu"></i>
|
||
<span>技术架构</span>
|
||
</div>
|
||
<div class="tech-stack">
|
||
<div class="tech-group">
|
||
<h4>后端技术</h4>
|
||
<div class="tech-tags">
|
||
<el-tag size="small">Spring Boot</el-tag>
|
||
<el-tag size="small">Spring Security</el-tag>
|
||
<el-tag size="small">MyBatis</el-tag>
|
||
<el-tag size="small">MySQL</el-tag>
|
||
</div>
|
||
</div>
|
||
<div class="tech-group">
|
||
<h4>前端技术</h4>
|
||
<div class="tech-tags">
|
||
<el-tag size="small" type="success">Vue.js</el-tag>
|
||
<el-tag size="small" type="success">Element UI</el-tag>
|
||
<el-tag size="small" type="success">Axios</el-tag>
|
||
<el-tag size="small" type="success">ECharts</el-tag>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</el-card>
|
||
</el-col>
|
||
</el-row>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { getVersion } from "@/api/system/index"
|
||
import { listOrder } from "@/api/system/Order"
|
||
import { listServiceGoods } from "@/api/system/ServiceGoods"
|
||
import { listQuoteMaterial } from "@/api/system/QuoteMaterial"
|
||
import { listUser } from "@/api/system/user"
|
||
import * as echarts from 'echarts'
|
||
|
||
export default {
|
||
name: "Index",
|
||
data() {
|
||
return {
|
||
// 版本号
|
||
version: "3.8.9",
|
||
// 统计数据
|
||
stats: {
|
||
orderCount: 0,
|
||
serviceCount: 0,
|
||
materialCount: 0,
|
||
userCount: 0
|
||
}
|
||
};
|
||
},
|
||
created() {
|
||
this.getVersion();
|
||
this.loadStats();
|
||
},
|
||
mounted() {
|
||
this.$nextTick(() => {
|
||
this.initCharts();
|
||
});
|
||
},
|
||
methods: {
|
||
getVersion() {
|
||
getVersion().then(response => {
|
||
this.version = response.data;
|
||
}).catch(() => {
|
||
// 如果接口不存在,使用默认版本号
|
||
});
|
||
},
|
||
// 加载统计数据
|
||
async loadStats() {
|
||
try {
|
||
// 加载订单数量
|
||
const orderRes = await listOrder({});
|
||
this.stats.orderCount = orderRes.total || 0;
|
||
|
||
// 加载服务项目数量
|
||
const serviceRes = await listServiceGoods({});
|
||
this.stats.serviceCount = serviceRes.total || 0;
|
||
|
||
// 加载材料数量
|
||
const materialRes = await listQuoteMaterial({});
|
||
this.stats.materialCount = materialRes.total || 0;
|
||
|
||
// 加载用户数量
|
||
const userRes = await listUser({});
|
||
this.stats.userCount = userRes.total || 0;
|
||
} catch (error) {
|
||
console.error('加载统计数据失败:', error);
|
||
// 设置默认数据
|
||
this.stats = {
|
||
orderCount: 156,
|
||
serviceCount: 23,
|
||
materialCount: 45,
|
||
userCount: 89
|
||
};
|
||
}
|
||
},
|
||
// 初始化图表
|
||
initCharts() {
|
||
this.initOrderChart();
|
||
},
|
||
// 订单状态分布图
|
||
initOrderChart() {
|
||
const chartDom = this.$refs.orderChart;
|
||
if (!chartDom) return;
|
||
|
||
const myChart = echarts.init(chartDom);
|
||
const option = {
|
||
title: {
|
||
text: '订单状态分布',
|
||
left: 'center',
|
||
textStyle: {
|
||
fontSize: 14,
|
||
color: '#666'
|
||
}
|
||
},
|
||
tooltip: {
|
||
trigger: 'item',
|
||
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||
},
|
||
legend: {
|
||
bottom: '5%',
|
||
left: 'center'
|
||
},
|
||
series: [
|
||
{
|
||
name: '订单状态',
|
||
type: 'pie',
|
||
radius: ['40%', '70%'],
|
||
center: ['50%', '50%'],
|
||
data: [
|
||
{ value: 45, name: '待派单', itemStyle: { color: '#409EFF' } },
|
||
{ value: 32, name: '进行中', itemStyle: { color: '#67C23A' } },
|
||
{ value: 23, name: '已完成', itemStyle: { color: '#E6A23C' } },
|
||
{ value: 12, name: '已取消', itemStyle: { color: '#F56C6C' } }
|
||
],
|
||
emphasis: {
|
||
itemStyle: {
|
||
shadowBlur: 10,
|
||
shadowOffsetX: 0,
|
||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||
}
|
||
}
|
||
}
|
||
]
|
||
};
|
||
myChart.setOption(option);
|
||
},
|
||
// 页面跳转
|
||
goToPage(path) {
|
||
this.$router.push(path);
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.home {
|
||
padding: 20px;
|
||
background: #f5f7fa;
|
||
min-height: calc(100vh - 84px);
|
||
}
|
||
|
||
.company-header {
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
color: white;
|
||
padding: 40px;
|
||
border-radius: 15px;
|
||
margin-bottom: 30px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
|
||
|
||
.company-title {
|
||
flex: 1;
|
||
|
||
i {
|
||
font-size: 32px;
|
||
margin-right: 15px;
|
||
vertical-align: middle;
|
||
}
|
||
|
||
h1 {
|
||
display: inline-block;
|
||
margin: 0;
|
||
font-size: 28px;
|
||
font-weight: 300;
|
||
vertical-align: middle;
|
||
}
|
||
|
||
.company-subtitle {
|
||
margin: 10px 0 0 47px;
|
||
opacity: 0.9;
|
||
font-size: 16px;
|
||
}
|
||
}
|
||
|
||
.company-stats {
|
||
display: flex;
|
||
gap: 40px;
|
||
|
||
.stat-item {
|
||
text-align: center;
|
||
|
||
.stat-number {
|
||
font-size: 32px;
|
||
font-weight: bold;
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 14px;
|
||
opacity: 0.8;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.business-overview {
|
||
margin-bottom: 30px;
|
||
|
||
.overview-card {
|
||
height: 280px;
|
||
border-radius: 15px;
|
||
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
|
||
transition: transform 0.3s ease;
|
||
|
||
&:hover {
|
||
transform: translateY(-5px);
|
||
}
|
||
|
||
.card-header {
|
||
display: flex;
|
||
align-items: center;
|
||
font-weight: 600;
|
||
font-size: 16px;
|
||
|
||
i {
|
||
margin-right: 8px;
|
||
font-size: 18px;
|
||
}
|
||
}
|
||
|
||
.card-content {
|
||
height: 200px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.feature-list {
|
||
flex: 1;
|
||
|
||
.feature-item {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 15px;
|
||
|
||
i {
|
||
margin-right: 10px;
|
||
color: #409EFF;
|
||
font-size: 16px;
|
||
}
|
||
|
||
span {
|
||
color: #666;
|
||
}
|
||
}
|
||
}
|
||
|
||
.action-btn {
|
||
text-align: center;
|
||
|
||
.el-button {
|
||
width: 140px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.order-overview .card-header i { color: #409EFF; }
|
||
.service-overview .card-header i { color: #67C23A; }
|
||
.quote-overview .card-header i { color: #E6A23C; }
|
||
}
|
||
|
||
.charts-section {
|
||
margin-bottom: 30px;
|
||
|
||
.chart-card {
|
||
border-radius: 15px;
|
||
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
|
||
|
||
.card-header {
|
||
display: flex;
|
||
align-items: center;
|
||
font-weight: 600;
|
||
font-size: 16px;
|
||
|
||
i {
|
||
margin-right: 8px;
|
||
font-size: 18px;
|
||
color: #409EFF;
|
||
}
|
||
}
|
||
|
||
.chart-container {
|
||
height: 300px;
|
||
width: 100%;
|
||
}
|
||
}
|
||
}
|
||
|
||
.quick-actions {
|
||
margin-bottom: 30px;
|
||
|
||
.action-card {
|
||
border-radius: 15px;
|
||
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
|
||
|
||
.card-header {
|
||
display: flex;
|
||
align-items: center;
|
||
font-weight: 600;
|
||
font-size: 16px;
|
||
|
||
i {
|
||
margin-right: 8px;
|
||
font-size: 18px;
|
||
color: #409EFF;
|
||
}
|
||
}
|
||
|
||
.quick-buttons {
|
||
text-align: center;
|
||
padding: 20px 0;
|
||
|
||
.el-button {
|
||
margin: 0 10px;
|
||
padding: 12px 20px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.system-info {
|
||
.info-card {
|
||
border-radius: 15px;
|
||
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
|
||
|
||
.card-header {
|
||
display: flex;
|
||
align-items: center;
|
||
font-weight: 600;
|
||
font-size: 16px;
|
||
|
||
i {
|
||
margin-right: 8px;
|
||
font-size: 18px;
|
||
color: #409EFF;
|
||
}
|
||
}
|
||
|
||
.info-content {
|
||
.info-item {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 15px;
|
||
|
||
.info-label {
|
||
color: #666;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.info-value {
|
||
color: #333;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
}
|
||
|
||
.tech-stack {
|
||
.tech-group {
|
||
margin-bottom: 20px;
|
||
|
||
h4 {
|
||
margin: 0 0 10px 0;
|
||
color: #666;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.tech-tags {
|
||
.el-tag {
|
||
margin-right: 8px;
|
||
margin-bottom: 5px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 响应式设计
|
||
@media (max-width: 768px) {
|
||
.company-header {
|
||
flex-direction: column;
|
||
text-align: center;
|
||
|
||
.company-stats {
|
||
margin-top: 20px;
|
||
gap: 20px;
|
||
}
|
||
}
|
||
|
||
.business-overview {
|
||
.el-col {
|
||
margin-bottom: 20px;
|
||
}
|
||
}
|
||
|
||
.quick-buttons {
|
||
.el-button-group {
|
||
display: flex;
|
||
flex-direction: column;
|
||
|
||
.el-button {
|
||
margin: 5px 0 !important;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style>
|
||
|