|
@@ -0,0 +1,911 @@
|
|
|
+<template>
|
|
|
+ <div class="content">
|
|
|
+ <div class="bck">
|
|
|
+ <el-form :inline="true" :model="queryForm">
|
|
|
+ <!-- <el-form-item label="">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="queryForm.aa"
|
|
|
+ type="month"
|
|
|
+ placeholder="月份"
|
|
|
+ @change="onQuery"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="">
|
|
|
+ <el-radio-group v-model="queryForm.bb" size="large" @change="onQuery">
|
|
|
+ <el-radio-button label="本日" />
|
|
|
+ <el-radio-button label="本周" />
|
|
|
+ <el-radio-button label="本月" />
|
|
|
+ <el-radio-button label="今年" />
|
|
|
+ <el-radio-button label="其他" />
|
|
|
+ </el-radio-group>
|
|
|
+ </el-form-item> -->
|
|
|
+ <el-form-item>
|
|
|
+ <el-date-picker
|
|
|
+ v-model="queryForm.timeArr"
|
|
|
+ type="daterange"
|
|
|
+ unlink-panels
|
|
|
+ range-separator="-"
|
|
|
+ start-placeholder="开始日期"
|
|
|
+ end-placeholder="结束日期"
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
+ @change="onQuery"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" @click="onQuery">搜索</el-button>
|
|
|
+ <el-button type="defualt" @click="onReset">重置</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ <div class="world" style="margin: 20px 0px">
|
|
|
+ <div ref="worldChart" style="height: 400px; width: 50%"></div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="bck statistics"
|
|
|
+ style="margin-top: 10px"
|
|
|
+ v-loading="statisticsLoading"
|
|
|
+ >
|
|
|
+ <div class="stat-warp">
|
|
|
+ <ul>
|
|
|
+ <li class="theme1">
|
|
|
+ <div class="num">
|
|
|
+ {{ moneyFormat(allData.salesStatisticsData.amount, 2) }}
|
|
|
+ </div>
|
|
|
+ <div class="label">销售额(¥)</div>
|
|
|
+ <div class="icon-box">
|
|
|
+ <i class="icon iconfont icon-iconx_caiwgl"></i>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ <li class="theme2">
|
|
|
+ <div class="num">
|
|
|
+ {{ allData.salesStatisticsData.contractCount }}
|
|
|
+ </div>
|
|
|
+ <div class="label">订单(单)</div>
|
|
|
+ <div class="icon-box">
|
|
|
+ <i class="icon iconfont icon-iconm_fukgl"></i>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ <li class="theme3">
|
|
|
+ <div class="num">
|
|
|
+ {{ allData.salesStatisticsData.customerCount }}
|
|
|
+ </div>
|
|
|
+ <div class="label">下单客户数(人)</div>
|
|
|
+ <div class="icon-box">
|
|
|
+ <i class="icon iconfont icon-iconm_unread"></i>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="bck scatter"
|
|
|
+ style="margin-top: 10px"
|
|
|
+ v-loading="scatterLoading"
|
|
|
+ >
|
|
|
+ <el-row>
|
|
|
+ <el-col :span="8">
|
|
|
+ <TitleInfo :content="titleList[0]"></TitleInfo>
|
|
|
+ <div ref="echartDom" style="height: 40vh"></div>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="16">
|
|
|
+ <byTable
|
|
|
+ :hideSearch="true"
|
|
|
+ :tableHeight="tableHeight"
|
|
|
+ :source="sourceList.scatterData"
|
|
|
+ :pagination="sourceList.scatterPagination"
|
|
|
+ :config="scatterConfig"
|
|
|
+ :loading="scatterLoading"
|
|
|
+ highlight-current-row
|
|
|
+ :hidePagination="true"
|
|
|
+ :selectConfig="[]"
|
|
|
+ >
|
|
|
+ <template #flag="{ item }">
|
|
|
+ <div>
|
|
|
+ <div>
|
|
|
+ <svg class="icon" aria-hidden="true">
|
|
|
+ <use :xlink:href="'#' + item.countryIcon"></use>
|
|
|
+ </svg>
|
|
|
+
|
|
|
+ {{ item.countryName }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </byTable>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ <div style="margin-top: 10px">
|
|
|
+ <el-row>
|
|
|
+ <el-col :span="12" class="bck" v-loading="salesLoading">
|
|
|
+ <TitleInfo :content="titleList[1]"></TitleInfo>
|
|
|
+ <div ref="echartDomOne" style="height: 30vh"></div>
|
|
|
+ <div style="margin-top: 10px">
|
|
|
+ <byTable
|
|
|
+ :hideSearch="true"
|
|
|
+ :tableHeight="300"
|
|
|
+ :source="sourceList.salesData"
|
|
|
+ :pagination="sourceList.salesPagination"
|
|
|
+ :config="salesConfig"
|
|
|
+ :loading="salesLoading"
|
|
|
+ highlight-current-row
|
|
|
+ :selectConfig="[]"
|
|
|
+ >
|
|
|
+ </byTable>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12" style="padding-left: 10px">
|
|
|
+ <div class="bck" v-loading="salesmanSalesLoading">
|
|
|
+ <TitleInfo :content="titleList[2]"></TitleInfo>
|
|
|
+ <div ref="echartDomTwo" style="height: 30vh"></div>
|
|
|
+ <div style="margin-top: 10px">
|
|
|
+ <byTable
|
|
|
+ :hideSearch="true"
|
|
|
+ :tableHeight="300"
|
|
|
+ :source="sourceList.salesmanSalesData"
|
|
|
+ :pagination="sourceList.salesmanSalesPagination"
|
|
|
+ :config="salesmanSalesConfig"
|
|
|
+ :loading="salesmanSalesLoading"
|
|
|
+ highlight-current-row
|
|
|
+ :selectConfig="[]"
|
|
|
+ >
|
|
|
+ </byTable>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div style="margin-top: 10px">
|
|
|
+ <el-row>
|
|
|
+ <el-col :span="12" class="bck" v-loading="productSalesLoading">
|
|
|
+ <TitleInfo :content="titleList[3]"></TitleInfo>
|
|
|
+ <div ref="echartDomThree" style="height: 30vh"></div>
|
|
|
+ <div style="margin-top: 10px">
|
|
|
+ <byTable
|
|
|
+ :hideSearch="true"
|
|
|
+ :tableHeight="300"
|
|
|
+ :source="sourceList.productSalesVolumeData"
|
|
|
+ :pagination="sourceList.productSalesVolumePagination"
|
|
|
+ :config="productSalesConfig"
|
|
|
+ :loading="productSalesLoading"
|
|
|
+ highlight-current-row
|
|
|
+ :selectConfig="[]"
|
|
|
+ >
|
|
|
+ </byTable>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12" style="padding-left: 10px">
|
|
|
+ <div class="bck" v-loading="productSalesOneLoading">
|
|
|
+ <TitleInfo :content="titleList[4]"></TitleInfo>
|
|
|
+ <div ref="echartDomFour" style="height: 30vh"></div>
|
|
|
+ <div style="margin-top: 10px">
|
|
|
+ <byTable
|
|
|
+ :hideSearch="true"
|
|
|
+ :tableHeight="300"
|
|
|
+ :source="sourceList.productSalesVolumeOneData"
|
|
|
+ :pagination="sourceList.productSalesVolumeOnePagination"
|
|
|
+ :config="productSalesOneConfig"
|
|
|
+ :loading="productSalesOneLoading"
|
|
|
+ highlight-current-row
|
|
|
+ :selectConfig="[]"
|
|
|
+ >
|
|
|
+ </byTable>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import * as echarts from "echarts";
|
|
|
+// import "echarts-gl";
|
|
|
+// import "../../../world.js";
|
|
|
+
|
|
|
+import byTable from "@/components/byTable/index";
|
|
|
+import TitleInfo from "@/components/TitleInfo/index.vue";
|
|
|
+const titleList = [
|
|
|
+ "销售分布",
|
|
|
+ "客户分类",
|
|
|
+ "业务员销售趋势",
|
|
|
+ "商品销售额",
|
|
|
+ "商品销量",
|
|
|
+];
|
|
|
+const { proxy } = getCurrentInstance();
|
|
|
+
|
|
|
+const statisticsLoading = ref(false);
|
|
|
+const scatterLoading = ref(false);
|
|
|
+const salesLoading = ref(false);
|
|
|
+const salesmanSalesLoading = ref(false);
|
|
|
+const productSalesLoading = ref(false);
|
|
|
+const productSalesOneLoading = ref(false);
|
|
|
+
|
|
|
+const queryForm = reactive({
|
|
|
+ beginTime: "",
|
|
|
+ endTime: "",
|
|
|
+ timeArr: "",
|
|
|
+});
|
|
|
+const sourceList = ref({
|
|
|
+ scatterData: [],
|
|
|
+ scatterPagination: {
|
|
|
+ total: 0,
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ },
|
|
|
+ salesData: [],
|
|
|
+ salesPagination: {
|
|
|
+ total: 0,
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ },
|
|
|
+ salesmanSalesData: [],
|
|
|
+ salesmanSalesPagination: {
|
|
|
+ total: 0,
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ },
|
|
|
+ productSalesVolumeData: [],
|
|
|
+ productSalesVolumePagination: {
|
|
|
+ total: 0,
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ },
|
|
|
+ productSalesVolumeOneData: [],
|
|
|
+ productSalesVolumeOnePagination: {
|
|
|
+ total: 0,
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ },
|
|
|
+});
|
|
|
+
|
|
|
+const allData = reactive({
|
|
|
+ salesStatisticsData: {},
|
|
|
+});
|
|
|
+//图表
|
|
|
+const echartDom = ref(null);
|
|
|
+const echartDomOne = ref(null);
|
|
|
+const echartDomTwo = ref(null);
|
|
|
+const echartDomThree = ref(null);
|
|
|
+const echartDomFour = ref(null);
|
|
|
+const worldChart = ref(null);
|
|
|
+let myChart = null;
|
|
|
+let myChartOne = null;
|
|
|
+let myChartTwo = null;
|
|
|
+let myChartThree = null;
|
|
|
+let myChartFour = null;
|
|
|
+let myWorldChart = null;
|
|
|
+
|
|
|
+const optionOne = reactive({
|
|
|
+ data: {
|
|
|
+ tooltip: {
|
|
|
+ trigger: "item",
|
|
|
+ },
|
|
|
+ legend: {
|
|
|
+ bottom: "0%",
|
|
|
+ left: "center",
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: "销售分析",
|
|
|
+ type: "pie",
|
|
|
+ radius: ["30%", "70%"],
|
|
|
+ avoidLabelOverlap: false,
|
|
|
+ itemStyle: {
|
|
|
+ borderRadius: 10,
|
|
|
+ borderColor: "#fff",
|
|
|
+ borderWidth: 2,
|
|
|
+ },
|
|
|
+ label: {
|
|
|
+ show: false,
|
|
|
+ position: "center",
|
|
|
+ },
|
|
|
+ emphasis: {
|
|
|
+ label: {
|
|
|
+ show: true,
|
|
|
+ fontSize: 20,
|
|
|
+ fontWeight: "bold",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ labelLine: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ data: [
|
|
|
+ { value: 1048, name: "Search Engine" },
|
|
|
+ { value: 735, name: "Direct" },
|
|
|
+ { value: 580, name: "Email" },
|
|
|
+ { value: 484, name: "Union Ads" },
|
|
|
+ { value: 300, name: "Video Ads" },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+});
|
|
|
+const optionTwo = reactive({
|
|
|
+ data: {
|
|
|
+ tooltip: {
|
|
|
+ trigger: "axis",
|
|
|
+ axisPointer: {
|
|
|
+ type: "shadow",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ grid: {
|
|
|
+ left: "1%",
|
|
|
+ right: "1%",
|
|
|
+ bottom: "1%",
|
|
|
+ top: "10%",
|
|
|
+ containLabel: true,
|
|
|
+ },
|
|
|
+ xAxis: [
|
|
|
+ {
|
|
|
+ type: "category",
|
|
|
+ data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
|
|
|
+ axisTick: {
|
|
|
+ alignWithLabel: true,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ yAxis: [
|
|
|
+ {
|
|
|
+ type: "value",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: "名称",
|
|
|
+ type: "bar",
|
|
|
+ barWidth: "25%",
|
|
|
+ data: [10, 52, 200, 334, 390, 330, 220],
|
|
|
+ itemStyle: {
|
|
|
+ color: "#0084FF",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+});
|
|
|
+const worldOption = ref({
|
|
|
+ backgroundColor: "#fff",
|
|
|
+ geo: {
|
|
|
+ map: "world",
|
|
|
+ roam: false,
|
|
|
+ label: {
|
|
|
+ emphasis: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ silent: true,
|
|
|
+ itemStyle: {
|
|
|
+ normal: {
|
|
|
+ areaColor: "#323c48",
|
|
|
+ },
|
|
|
+ emphasis: {
|
|
|
+ areaColor: "#2a333d",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ zoom: 1.2,
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: "弱",
|
|
|
+ type: "scatterGL",
|
|
|
+ progressive: 1e6,
|
|
|
+ coordinateSystem: "geo",
|
|
|
+ symbolSize: 2.3,
|
|
|
+ zoomScale: 0.002,
|
|
|
+ blendMode: "lighter",
|
|
|
+ large: true,
|
|
|
+ itemStyle: {
|
|
|
+ color: "#940819",
|
|
|
+ },
|
|
|
+ postEffect: {
|
|
|
+ enable: true,
|
|
|
+ },
|
|
|
+ silent: true,
|
|
|
+ dimensions: ["lng", "lat"],
|
|
|
+ data: new Float32Array(),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+});
|
|
|
+const scatterConfig = computed(() => {
|
|
|
+ return [
|
|
|
+ {
|
|
|
+ type: "index",
|
|
|
+ attrs: {
|
|
|
+ label: "序列",
|
|
|
+ width: 80,
|
|
|
+ align: "center",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ attrs: {
|
|
|
+ label: "国旗",
|
|
|
+ slot: "flag",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ attrs: {
|
|
|
+ label: "订单量(单)",
|
|
|
+ prop: "count",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ attrs: {
|
|
|
+ label: "交易金额(¥)",
|
|
|
+ prop: "amount",
|
|
|
+ },
|
|
|
+ render(amount) {
|
|
|
+ return proxy.moneyFormat(amount, 2);
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ];
|
|
|
+});
|
|
|
+const salesConfig = computed(() => {
|
|
|
+ return [
|
|
|
+ {
|
|
|
+ type: "index",
|
|
|
+ attrs: {
|
|
|
+ label: "序列",
|
|
|
+ width: 80,
|
|
|
+ align: "center",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ attrs: {
|
|
|
+ label: "客户",
|
|
|
+ prop: "corporationName",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ attrs: {
|
|
|
+ label: "销售额(¥)",
|
|
|
+ prop: "amount",
|
|
|
+ },
|
|
|
+ render(amount) {
|
|
|
+ return proxy.moneyFormat(amount, 2);
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ];
|
|
|
+});
|
|
|
+const salesmanSalesConfig = computed(() => {
|
|
|
+ return [
|
|
|
+ {
|
|
|
+ type: "index",
|
|
|
+ attrs: {
|
|
|
+ label: "序列",
|
|
|
+ width: 80,
|
|
|
+ align: "center",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ attrs: {
|
|
|
+ label: "业务员",
|
|
|
+ prop: "userName",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ attrs: {
|
|
|
+ label: "销售额(¥)",
|
|
|
+ prop: "amount",
|
|
|
+ },
|
|
|
+ render(amount) {
|
|
|
+ return proxy.moneyFormat(amount, 2);
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ];
|
|
|
+});
|
|
|
+const productSalesConfig = computed(() => {
|
|
|
+ return [
|
|
|
+ {
|
|
|
+ type: "index",
|
|
|
+ attrs: {
|
|
|
+ label: "序列",
|
|
|
+ width: 80,
|
|
|
+ align: "center",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ attrs: {
|
|
|
+ label: "商品名称",
|
|
|
+ prop: "productName",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ attrs: {
|
|
|
+ label: "销售额(¥)",
|
|
|
+ prop: "amount",
|
|
|
+ },
|
|
|
+ render(amount) {
|
|
|
+ return proxy.moneyFormat(amount, 2);
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ];
|
|
|
+});
|
|
|
+const tableHeight = computed(() => {
|
|
|
+ return (document.documentElement.clientHeight / 10) * 4;
|
|
|
+});
|
|
|
+
|
|
|
+const productSalesOneConfig = computed(() => {
|
|
|
+ return [
|
|
|
+ {
|
|
|
+ type: "index",
|
|
|
+ attrs: {
|
|
|
+ label: "序列",
|
|
|
+ width: 80,
|
|
|
+ align: "center",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ attrs: {
|
|
|
+ label: "商品名称",
|
|
|
+ prop: "productName",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ attrs: {
|
|
|
+ label: "销售量(个)",
|
|
|
+ prop: "quantity",
|
|
|
+ },
|
|
|
+ render(quantity) {
|
|
|
+ return proxy.moneyFormat(quantity, 2);
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ];
|
|
|
+});
|
|
|
+const getData = () => {
|
|
|
+ statisticsLoading.value = true;
|
|
|
+ scatterLoading.value = true;
|
|
|
+ salesLoading.value = true;
|
|
|
+ salesmanSalesLoading.value = true;
|
|
|
+ productSalesLoading.value = true;
|
|
|
+ productSalesOneLoading.value = true;
|
|
|
+ proxy.post("/contract/salesStatistics", queryForm).then((res) => {
|
|
|
+ allData.salesStatisticsData = res;
|
|
|
+ setTimeout(() => {
|
|
|
+ statisticsLoading.value = false;
|
|
|
+ }, 200);
|
|
|
+ });
|
|
|
+ proxy.post("/contract/countrySalesStatistics", queryForm).then((res) => {
|
|
|
+ sourceList.value.scatterData = res;
|
|
|
+ //根据amount字段从大到小
|
|
|
+ res.sort((a, b) => b.amount - a.amount);
|
|
|
+ //截取前十条
|
|
|
+ if (res.length > 10) res = res.slice(0, 10);
|
|
|
+
|
|
|
+ optionOne.data.series[0].data = res.map((x) => ({
|
|
|
+ value: x.amount,
|
|
|
+ name: x.countryName,
|
|
|
+ }));
|
|
|
+ myChart.setOption(optionOne.data);
|
|
|
+ setTimeout(() => {
|
|
|
+ scatterLoading.value = false;
|
|
|
+ }, 200);
|
|
|
+ });
|
|
|
+
|
|
|
+ proxy.post("/contract/customSalesStatistics", queryForm).then((res) => {
|
|
|
+ sourceList.value.salesData = res;
|
|
|
+ const option = { ...optionTwo };
|
|
|
+ option.data.xAxis[0].data = res.map((x) => x.corporationName);
|
|
|
+ option.data.series[0].data = res.map((x) => x.amount);
|
|
|
+ option.data.series[0].name = "销售额(¥)";
|
|
|
+ myChartOne.setOption(option.data);
|
|
|
+ setTimeout(() => {
|
|
|
+ salesLoading.value = false;
|
|
|
+ }, 200);
|
|
|
+ });
|
|
|
+
|
|
|
+ proxy.post("/contract/salesmanSalesStatistics", queryForm).then((res) => {
|
|
|
+ sourceList.value.salesmanSalesData = res;
|
|
|
+ const option = { ...optionTwo };
|
|
|
+ option.data.xAxis[0].data = res.map((x) => x.userName);
|
|
|
+ option.data.series[0].data = res.map((x) => x.amount);
|
|
|
+ option.data.series[0].name = "销售额(¥)";
|
|
|
+ myChartTwo.setOption(option.data);
|
|
|
+ setTimeout(() => {
|
|
|
+ salesmanSalesLoading.value = false;
|
|
|
+ }, 200);
|
|
|
+ });
|
|
|
+
|
|
|
+ proxy.post("/contract/productSalesStatistics", queryForm).then((res) => {
|
|
|
+ sourceList.value.productSalesVolumeData = res;
|
|
|
+ const option = { ...optionTwo };
|
|
|
+ option.data.xAxis[0].data = res.map((x) => x.productName);
|
|
|
+ option.data.series[0].data = res.map((x) => x.amount);
|
|
|
+ option.data.series[0].name = "销售额(¥)";
|
|
|
+ myChartThree.setOption(option.data);
|
|
|
+ setTimeout(() => {
|
|
|
+ productSalesLoading.value = false;
|
|
|
+ }, 200);
|
|
|
+ });
|
|
|
+
|
|
|
+ proxy.post("/contract/salesVolumeStatistics", queryForm).then((res) => {
|
|
|
+ sourceList.value.productSalesVolumeOneData = res;
|
|
|
+ const option = { ...optionTwo };
|
|
|
+ option.data.xAxis[0].data = res.map((x) => x.productName);
|
|
|
+ option.data.series[0].data = res.map((x) => x.quantity);
|
|
|
+ option.data.series[0].name = "销售量(个)";
|
|
|
+ myChartFour.setOption(option.data);
|
|
|
+ setTimeout(() => {
|
|
|
+ productSalesOneLoading.value = false;
|
|
|
+ }, 200);
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const onQuery = () => {
|
|
|
+ if (queryForm.timeArr.length > 1) {
|
|
|
+ queryForm.beginTime = queryForm.timeArr[0];
|
|
|
+ queryForm.endTime = queryForm.timeArr[1];
|
|
|
+ } else {
|
|
|
+ queryForm.beginTime = "";
|
|
|
+ queryForm.endTime = "";
|
|
|
+ }
|
|
|
+ getData();
|
|
|
+};
|
|
|
+
|
|
|
+const onReset = () => {
|
|
|
+ queryForm.timeArr = [];
|
|
|
+ onQuery();
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ myChart = echarts.init(echartDom.value);
|
|
|
+ window.addEventListener("resize", () => {
|
|
|
+ myChart.resize();
|
|
|
+ });
|
|
|
+ // 客户分类柱状图
|
|
|
+ myChartOne = echarts.init(echartDomOne.value);
|
|
|
+ window.addEventListener("resize", () => {
|
|
|
+ myChartOne.resize();
|
|
|
+ });
|
|
|
+ // 业务员销售趋势柱状图
|
|
|
+ myChartTwo = echarts.init(echartDomTwo.value);
|
|
|
+ window.addEventListener("resize", () => {
|
|
|
+ myChartTwo.resize();
|
|
|
+ });
|
|
|
+ //商品销售额柱状图
|
|
|
+ myChartThree = echarts.init(echartDomThree.value);
|
|
|
+ window.addEventListener("resize", () => {
|
|
|
+ myChartThree.resize();
|
|
|
+ });
|
|
|
+ // 商品销量柱状图
|
|
|
+ myChartFour = echarts.init(echartDomFour.value);
|
|
|
+ window.addEventListener("resize", () => {
|
|
|
+ myChartFour.resize();
|
|
|
+ });
|
|
|
+ // 世界图表
|
|
|
+ myWorldChart = echarts.init(worldChart.value);
|
|
|
+ // myWorldChart.setOption(worldOption.value);
|
|
|
+ window.addEventListener("resize", () => {
|
|
|
+ myWorldChart.resize();
|
|
|
+ });
|
|
|
+
|
|
|
+ let endData = new Date();
|
|
|
+ let beginDate = new Date();
|
|
|
+ beginDate.setMonth(0);
|
|
|
+ beginDate.setDate(1);
|
|
|
+ queryForm.timeArr = [
|
|
|
+ proxy.parseTime(beginDate, "{y}-{m}-{d}"),
|
|
|
+ proxy.parseTime(endData, "{y}-{m}-{d}"),
|
|
|
+ ];
|
|
|
+ onQuery();
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.content {
|
|
|
+ margin: 20px;
|
|
|
+}
|
|
|
+:deep(.el-form-item) {
|
|
|
+ margin-bottom: 0px;
|
|
|
+}
|
|
|
+.bck {
|
|
|
+ background-color: #fff;
|
|
|
+ padding: 15px;
|
|
|
+}
|
|
|
+.statistics {
|
|
|
+ display: flex;
|
|
|
+ // justify-content: space-around;
|
|
|
+ .item {
|
|
|
+ border-radius: 10px;
|
|
|
+ margin-right: 20px;
|
|
|
+ width: 13vw;
|
|
|
+ height: 70px;
|
|
|
+ padding: 10px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ .left_ {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: space-around;
|
|
|
+ .money {
|
|
|
+ font-weight: 700;
|
|
|
+ color: #333333;
|
|
|
+ font-size: 15px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .right_ {
|
|
|
+ .icon {
|
|
|
+ img {
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ margin-top: 6px;
|
|
|
+ }
|
|
|
+ width: 34px;
|
|
|
+ height: 34px;
|
|
|
+ margin-top: 10px;
|
|
|
+ border-radius: 8px;
|
|
|
+ background-color: #ffffff;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 34px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .first {
|
|
|
+ background: linear-gradient(#c7e3fe, #dfecff);
|
|
|
+ }
|
|
|
+ .two {
|
|
|
+ background: linear-gradient(#eae8fb, #ded9ff);
|
|
|
+ }
|
|
|
+ .three {
|
|
|
+ background: linear-gradient(#fcf1e4, #fce5ca);
|
|
|
+ }
|
|
|
+ .four {
|
|
|
+ background: linear-gradient(#e2fbe8, #e2fbe8);
|
|
|
+ }
|
|
|
+ .five {
|
|
|
+ background: linear-gradient(#ffebe9, #ffebe9);
|
|
|
+ }
|
|
|
+}
|
|
|
+.stat-warp {
|
|
|
+ background: #fff;
|
|
|
+ padding: 20px;
|
|
|
+ overflow: hidden;
|
|
|
+ position: relative;
|
|
|
+ border-radius: 5px;
|
|
|
+
|
|
|
+ .title {
|
|
|
+ height: 60px;
|
|
|
+ select {
|
|
|
+ height: 60px;
|
|
|
+ border: none;
|
|
|
+ outline: none;
|
|
|
+ -webkit-appearance: none;
|
|
|
+ appearance: none;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: bold;
|
|
|
+ background: url("@/assets/images/sanjiao.png") no-repeat right center;
|
|
|
+ padding-right: 20px;
|
|
|
+ }
|
|
|
+ div {
|
|
|
+ height: 60px;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: bold;
|
|
|
+ line-height: 60px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ul {
|
|
|
+ padding: 0;
|
|
|
+ overflow: hidden;
|
|
|
+ margin: 0;
|
|
|
+ li {
|
|
|
+ list-style: none;
|
|
|
+ min-width: 285px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ margin-right: 20px;
|
|
|
+ background: linear-gradient(360deg, #c7e3fe 0%, #dfecff 100%);
|
|
|
+ float: left;
|
|
|
+ overflow: hidden;
|
|
|
+ padding: 20px;
|
|
|
+ color: #333333;
|
|
|
+ position: relative;
|
|
|
+ border-radius: 10px;
|
|
|
+ cursor: pointer;
|
|
|
+ .label {
|
|
|
+ font-size: 14px;
|
|
|
+ margin-top: 10px;
|
|
|
+ }
|
|
|
+ .label::before {
|
|
|
+ // width: 10px;
|
|
|
+ // height: 10px;
|
|
|
+ // content: '';
|
|
|
+ // border-radius: 50%;
|
|
|
+ // background: #0084ff;
|
|
|
+ // display: inline-block;
|
|
|
+ // margin-right: 10px;
|
|
|
+ }
|
|
|
+ .num {
|
|
|
+ font-size: 24px;
|
|
|
+ font-weight: bold;
|
|
|
+ }
|
|
|
+ .icon-box {
|
|
|
+ position: absolute;
|
|
|
+ height: 40px;
|
|
|
+ width: 40px;
|
|
|
+ right: 20px;
|
|
|
+ top: 20px;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 10px;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 40px;
|
|
|
+ i {
|
|
|
+ font-size: 20px;
|
|
|
+ color: #0084ff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //#F5F3FF #9E64ED
|
|
|
+ .theme2 {
|
|
|
+ background: linear-gradient(180deg, #eae8fb 0%, #ded9ff 100%);
|
|
|
+ .label::before {
|
|
|
+ background: #7566f0;
|
|
|
+ }
|
|
|
+ .icon-box i {
|
|
|
+ color: #7566f0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //#FFF1E1 #FF9315
|
|
|
+ .theme3 {
|
|
|
+ background: #fff1e1;
|
|
|
+ .label::before {
|
|
|
+ background: #ff9315;
|
|
|
+ }
|
|
|
+ .icon-box i {
|
|
|
+ color: #ff9315;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //#E2FBE8 #39C55A
|
|
|
+ .theme4 {
|
|
|
+ background: #e2fbe8;
|
|
|
+ .label::before {
|
|
|
+ background: #39c55a;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .theme5 {
|
|
|
+ background: #ffebe9;
|
|
|
+ .label::before {
|
|
|
+ background: #f94539;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .theme6 {
|
|
|
+ background: #e4f9f9;
|
|
|
+ .label::before {
|
|
|
+ background: #53cbcb;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .multi-data {
|
|
|
+ .label::before {
|
|
|
+ display: none;
|
|
|
+ }
|
|
|
+ .label {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #333;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ }
|
|
|
+ .num-warp {
|
|
|
+ overflow: hidden;
|
|
|
+ .num-box {
|
|
|
+ float: left;
|
|
|
+ min-width: 80px;
|
|
|
+ margin-right: 20px;
|
|
|
+ .num-small {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: bold;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ }
|
|
|
+ .label-small {
|
|
|
+ color: #666;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+// .scatter {
|
|
|
+// display: flex;
|
|
|
+// }
|
|
|
+.public {
|
|
|
+ display: flex;
|
|
|
+}
|
|
|
+</style>
|