Files
klp-oa/klp-ui/src/views/crm/report/index.vue

296 lines
8.3 KiB
Vue
Raw Normal View History

<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>