296 lines
8.3 KiB
Vue
296 lines
8.3 KiB
Vue
<template>
|
||
<div class="crm-sales-report-page">
|
||
<!-- 时间筛选区域(根页面保留,统一管理查询参数) -->
|
||
<div class="date-filter-container">
|
||
<el-form :model="dateQuery" inline class="date-form">
|
||
<el-form-item label="统计时间" prop="dateRange">
|
||
<el-date-picker
|
||
v-model="dateQuery.dateRange"
|
||
type="daterange"
|
||
range-separator="至"
|
||
start-placeholder="开始日期"
|
||
end-placeholder="结束日期"
|
||
format="yyyy-MM-dd"
|
||
value-format="yyyy-MM-dd"
|
||
clearable
|
||
></el-date-picker>
|
||
</el-form-item>
|
||
<el-form-item>
|
||
<el-button type="primary" icon="el-icon-search" @click="queryAllData">查询</el-button>
|
||
<el-button icon="el-icon-refresh" @click="resetDateRange">重置</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
</div>
|
||
|
||
<!-- 1. 销售汇总指标卡组件 -->
|
||
<SalesReportSummaryCard
|
||
:summary-data="summaryData"
|
||
:loading="summaryLoading"
|
||
:format-amount="formatAmount"
|
||
/>
|
||
|
||
<!-- 2. 三个ECharts图表组件(布局由根页面控制) -->
|
||
<div class="echarts-container">
|
||
<el-row :gutter="20">
|
||
<!-- 销售员统计图表 -->
|
||
<el-col :span="8">
|
||
<SalesmanChart :salesman-stat-list="salesmanStatList" />
|
||
</el-col>
|
||
<!-- 客户等级统计图表 -->
|
||
<el-col :span="8">
|
||
<CustomerLevelChart
|
||
:customer-level-stat-list="customerLevelStatList"
|
||
:customer-level-dict="dict.type.customer_level"
|
||
/>
|
||
</el-col>
|
||
<!-- 行业统计图表 -->
|
||
<el-col :span="8">
|
||
<IndustryChart :industry-stat-list="industryStatList" />
|
||
</el-col>
|
||
</el-row>
|
||
</div>
|
||
|
||
<!-- 3. 订单明细组件 -->
|
||
<SalesReportOrderDetail
|
||
:order-detail-list="orderDetailList"
|
||
:page-params="pageParams"
|
||
:total="total"
|
||
:loading="orderLoading"
|
||
:format-amount="formatAmount"
|
||
:format-date="formatDate"
|
||
@size-change="handleSizeChange"
|
||
@current-change="handleCurrentChange"
|
||
@export-order="exportOrderDetails"
|
||
@selection-change="handleSelectionChange"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
// 导入子组件
|
||
import SalesReportSummaryCard from "./SalesReportSummaryCard.vue";
|
||
import SalesmanChart from "./SalesmanChart.vue";
|
||
import CustomerLevelChart from "./CustomerLevelChart.vue";
|
||
import IndustryChart from "./IndustryChart.vue";
|
||
import SalesReportOrderDetail from "./SalesReportOrderDetail.vue";
|
||
|
||
// 导入API函数
|
||
import {
|
||
getSummary,
|
||
getOrderDetails,
|
||
getSalesmanStats,
|
||
getCustomerLevelStats,
|
||
getIndustryStats,
|
||
exportOrderDetails as apiExportOrderDetails
|
||
} from "@/api/crm/report";
|
||
|
||
export default {
|
||
name: "CrmSalesReport",
|
||
dicts: ['customer_level'],
|
||
components: {
|
||
SalesReportSummaryCard,
|
||
SalesmanChart,
|
||
CustomerLevelChart,
|
||
IndustryChart,
|
||
SalesReportOrderDetail
|
||
},
|
||
data() {
|
||
return {
|
||
// 时间查询参数
|
||
dateQuery: {
|
||
dateRange: []
|
||
},
|
||
// 分页参数
|
||
pageParams: {
|
||
pageNum: 1,
|
||
pageSize: 10
|
||
},
|
||
// 汇总数据
|
||
summaryData: {},
|
||
// 订单明细数据
|
||
orderDetailList: [],
|
||
// 总条数
|
||
total: 0,
|
||
// 图表数据(传递给对应图表组件)
|
||
salesmanStatList: [],
|
||
customerLevelStatList: [],
|
||
industryStatList: [],
|
||
// 加载状态
|
||
summaryLoading: false,
|
||
orderLoading: false,
|
||
// 表格勾选数据
|
||
multipleSelection: []
|
||
};
|
||
},
|
||
created() {
|
||
// 初始化默认时间
|
||
this.initDefaultDateRange();
|
||
// 页面加载查询所有数据
|
||
this.queryAllData();
|
||
},
|
||
methods: {
|
||
// 初始化默认时间范围:当月第一天到今天
|
||
initDefaultDateRange() {
|
||
const now = new Date();
|
||
const monthFirstDay = new Date(now.getFullYear(), now.getMonth(), 1);
|
||
const firstDayStr = this.formatToDateStr(monthFirstDay);
|
||
const todayStr = this.formatToDateStr(now);
|
||
this.dateQuery.dateRange = [firstDayStr, todayStr];
|
||
},
|
||
// 日期对象格式化为yyyy-MM-dd字符串
|
||
formatToDateStr(date) {
|
||
const year = date.getFullYear();
|
||
const month = (date.getMonth() + 1).toString().padStart(2, "0");
|
||
const day = date.getDate().toString().padStart(2, "0");
|
||
return `${year}-${month}-${day}`;
|
||
},
|
||
// 格式化金额
|
||
formatAmount(amount) {
|
||
if (!amount) {
|
||
return "0.00";
|
||
}
|
||
return Number(amount).toFixed(2);
|
||
},
|
||
// 格式化日期
|
||
formatDate(timestamp) {
|
||
if (!timestamp) return "-";
|
||
return timestamp;
|
||
},
|
||
// 重置日期范围
|
||
resetDateRange() {
|
||
this.initDefaultDateRange();
|
||
this.queryAllData();
|
||
},
|
||
// 统一查询所有数据
|
||
queryAllData() {
|
||
this.loadSummaryData();
|
||
this.loadChartData();
|
||
this.loadOrderDetailData();
|
||
},
|
||
// 组装公共查询参数
|
||
getCommonParams(needPage = false) {
|
||
const params = {};
|
||
if (this.dateQuery.dateRange && this.dateQuery.dateRange.length === 2) {
|
||
params.startTime = this.dateQuery.dateRange[0];
|
||
params.endTime = this.dateQuery.dateRange[1];
|
||
}
|
||
if (needPage) {
|
||
params.pageNum = this.pageParams.pageNum;
|
||
params.pageSize = this.pageParams.pageSize;
|
||
}
|
||
return params;
|
||
},
|
||
// 加载销售汇总数据
|
||
loadSummaryData() {
|
||
this.summaryLoading = true;
|
||
const params = this.getCommonParams();
|
||
getSummary(params)
|
||
.then((res) => {
|
||
if (res.code === 200) {
|
||
this.summaryData = res.data || {};
|
||
}
|
||
})
|
||
.finally(() => {
|
||
this.summaryLoading = false;
|
||
});
|
||
},
|
||
// 加载图表数据
|
||
loadChartData() {
|
||
const params = this.getCommonParams();
|
||
// 并行加载三个图表数据
|
||
Promise.all([
|
||
getSalesmanStats(params),
|
||
getCustomerLevelStats(params),
|
||
getIndustryStats(params)
|
||
])
|
||
.then(([salesmanRes, customerRes, industryRes]) => {
|
||
if (salesmanRes.code === 200) {
|
||
this.salesmanStatList = salesmanRes.data || [];
|
||
}
|
||
if (customerRes.code === 200) {
|
||
this.customerLevelStatList = customerRes.data || [];
|
||
}
|
||
if (industryRes.code === 200) {
|
||
this.industryStatList = industryRes.data || [];
|
||
}
|
||
});
|
||
},
|
||
// 加载订单明细数据
|
||
loadOrderDetailData() {
|
||
this.orderLoading = true;
|
||
const params = this.getCommonParams(true);
|
||
getOrderDetails(params)
|
||
.then((res) => {
|
||
if (res.code === 200) {
|
||
this.orderDetailList = res.rows || [];
|
||
this.total = res.total || 0;
|
||
}
|
||
})
|
||
.finally(() => {
|
||
this.orderLoading = false;
|
||
});
|
||
},
|
||
// 分页大小改变
|
||
handleSizeChange(val) {
|
||
this.pageParams.pageSize = val;
|
||
this.loadOrderDetailData();
|
||
},
|
||
// 当前页改变
|
||
handleCurrentChange(val) {
|
||
this.pageParams.pageNum = val;
|
||
this.loadOrderDetailData();
|
||
},
|
||
// 表格勾选事件
|
||
handleSelectionChange(val) {
|
||
this.multipleSelection = val;
|
||
},
|
||
// 导出订单明细
|
||
exportOrderDetails() {
|
||
const params = this.getCommonParams();
|
||
apiExportOrderDetails(params).then((res) => {
|
||
this.handleExportBlob(res, "销售报表订单明细.xlsx");
|
||
});
|
||
},
|
||
// 处理blob文件导出
|
||
handleExportBlob(res, fileName) {
|
||
const blob = new Blob([res], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
|
||
const url = window.URL.createObjectURL(blob);
|
||
const a = document.createElement("a");
|
||
a.href = url;
|
||
a.download = fileName;
|
||
document.body.appendChild(a);
|
||
a.click();
|
||
window.URL.revokeObjectURL(url);
|
||
document.body.removeChild(a);
|
||
this.$message.success("导出成功!");
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
.crm-sales-report-page {
|
||
padding: 20px;
|
||
background-color: #f5f7fa;
|
||
min-height: calc(100vh - 120px);
|
||
}
|
||
|
||
/* 时间筛选区域样式 */
|
||
.date-filter-container {
|
||
background-color: #fff;
|
||
padding: 20px;
|
||
border-radius: 4px;
|
||
margin-bottom: 20px;
|
||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.04);
|
||
}
|
||
|
||
.date-form {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
/* 图表容器布局样式 */
|
||
.echarts-container {
|
||
margin-bottom: 20px;
|
||
}
|
||
</style> |