2 Commits 36c45917ca ... 93f23efdc8

Autore SHA1 Messaggio Data
  cldu 93f23efdc8 月份筛选调整 1 settimana fa
  cldu 735b3f661f 业务收入金额统计表增加到款统计 1 settimana fa

+ 23 - 0
src/api/financialStatistics.js

@@ -108,9 +108,32 @@ export function setServiceAmount(data) {
  * @param data.list_param - 统计类型: 0-月度; 1-季度; 2-半年度;3-年度;4-月度累计
  * @param data.company_type - 客户类型 0全部 1新客户 2老客户
  * @param data.seller_ids - 销售ids
+ * @param data.income_type - 收入类型 0开票收入 1到款收入
  * @returns 
  */
  export function getIncomeChartData(data) {
+    return request({
+        url:'/census/invoice_payment/income/chart_list',
+        method:'get',
+        params:data,
+        responseType:data.is_export==1?'blob':'text',
+    })
+   }
+// 业务收入详情表格
+ /**
+ * 获取业务收入金额
+ * @param data.start_date - 开始时间
+ * @param data.end_date - 结束时间
+ * @param data.is_export - 是否是导出 0-否 1-是
+ * @param data.list_param - 统计类型: 0-月度; 1-季度; 2-半年度;3-年度;4-月度累计
+ * @param data.company_type - 客户类型 0全部 1新客户 2老客户
+ * @param data.seller_ids - 销售ids
+ * @param data.income_type - 收入类型 0开票收入 1到款收入
+ * @param data.keyword - 客户名称搜索
+ * @param data.sort_type - 排序
+ * @returns 
+ */
+ export function getIncomeDetailData(data) {
     return request({
         url:'/census/invoice_payment/income/list',
         method:'get',

+ 240 - 43
src/views/financialStatistics/businessIncome.vue

@@ -1,18 +1,70 @@
 <script setup>
   import {downloadByFlow} from '@/utils/common-methods'
   import {getSellerTeamList} from '@/api/crm'
-  import {getIncomeChartData} from '@/api/financialStatistics'
+  import {getIncomeChartData,getIncomeDetailData} from '@/api/financialStatistics'
   import chart from '@/components/echart/index.vue'
   import {baseOptions} from '@/components/echart/baseOptions'
   import {getSimpleServiceList} from '@/api/financialMana'
+  import { Search } from '@element-plus/icons-vue'
 
   const basicOptions=baseOptions()
-
+  
+  const statisticalMethod=[{label:'开票统计',value:0},{label:'到款统计',value:1}]
   const dimensionArray=[{label:'月度',tag:0},{label:'季度',tag:1},{label:'半年度',tag:2},{label:'年度',tag:3},{label:'月度累计',tag:4}]
   const customerTypeArray=[{label:'全部',value:0},{label:'新客户',value:1},{label:'老客户',value:2},{label:'未续约',value:3}]
   const sellerArray=ref(null)
+  const detailData = ref([])
+  const tableRef = ref(null)
+
+  const toolTipText = computed(() => {
+    return searchParams.income_type == 0 ?
+     (searchParams.company_type == 3 ? `未续约收入金额:当期未续约收入金额=去年同期总收入金额(新客户+老客户)-当期老客户收入金额<br />移动平均值:未续约收入金额的移动平均值,移动间隔长度为3个月<br />注:该处的收入金额为开票金额。`
+                                     : `业务收入金额:此处指开票金额,含已开票已到款、已开票未到款、未开票已到款<br />同比值:今年同期/去年同期-1`
+     ) :
+     (searchParams.company_type == 3 ? `未续约收入金额:当期未续约收入金额=去年同期总收入金额(新客户+老客户)-当期老客户收入金额<br />移动平均值:未续约收入金额的移动平均值,移动间隔长度为3个月<br />注:该处的收入金额为到款金额。`
+                                     : `业务收入金额:此处指到款金额,含已开票已到款、未开票已到款<br />同比值:今年同期/去年同期-1`
+     );
+  })
+
+  const detailColumns = computed(() => {
+      return [{
+        label: '客户名称',
+        key: 'company_name',
+        minwidthsty: '206px',
+      },{
+        label: '是否新客户',
+        key: 'contract_type',
+        minwidthsty: '100px',
+      },{
+        label: searchParams.income_type?'到款日期':'开票日期',
+        key: 'invoice_time',
+        minwidthsty: '140px',
+        sortable:'custom',
+      },{
+        label: searchParams.income_type?'到款金额':'开票金额',
+        key: 'origin_amount',
+        minwidthsty: '140px',
+      },{
+        label: searchParams.income_type?'到款单位':'开票单位',
+        key: 'unit_name',
+        minwidthsty: '120px',
+      },{
+        label: searchParams.income_type?'到款金额(换算后)':'开票金额(换算后)',
+        key: 'amount',
+        minwidthsty: '140px',
+      },{
+        label: '销售',
+        key: 'seller_name',
+        minwidthsty: '140px',
+      },{
+        label: '套餐',
+        key: 'services_name',
+        minwidthsty: '182px',
+      }]
+  })
 
   const searchParams=reactive({
+    income_type:0,
     list_param:0,
     company_type:0,
     start_date:'',
@@ -23,10 +75,18 @@
     // 不是后端所需要的值,用于axios的请求拦截器,具体请看@/utils/request.js文件
     takeLastRequestResult:true
   })
+  const detailParams = reactive({
+    page_size:10,
+    current:1,
+    keyword:'',
+    sort_type:'',//排序
+  })
+  const detailTotal = ref(0)
   // 加载状态
   const loading=reactive({
     list:true,
-    export:false
+    export:false,
+    detail:false
   })
   const chartOptions=ref(basicOptions)
   
@@ -38,7 +98,7 @@
       searchParams.start_date = value[0]
       searchParams.end_date=value[1]
     }
-    getList()
+    changeChartDetail()
   })
 
   const sellersCheckList=ref(null)
@@ -48,7 +108,7 @@
     }else{
       searchParams.seller_ids = value.join(',')
     }
-    getList()
+    changeChartDetail()
   })
 
   const getSellerData=()=>{
@@ -169,9 +229,26 @@
     })
   }
 
+  //获取数据详情列表
+  const getDetailList = () => {
+    if(searchParams.company_type == 3) { //未续约
+      detailData.value = [];
+      detailParams.keyword = '';
+      detailParams.sort_type = '';
+      return
+    };
+    loading.detail=true;
+    getIncomeDetailData({...searchParams,...detailParams}).then(res=>{
+      loading.detail=false;
+      if(res.code != 200) return;
+      detailData.value = res.data.list || [];
+      detailTotal.value = res.data.page?.total || 0;
+    }).catch(err=>{loading.detail=false;})
+  }
+
   const exportData=()=>{
     loading.export=true
-    getIncomeChartData({...searchParams,is_export:1}).then(res=>{
+    getIncomeDetailData({...searchParams,...detailParams,is_export:1}).then(res=>{
       downloadByFlow(res,'xlxs','业务收入金额统计')
     }).finally(()=>{
       loading.export=false
@@ -188,25 +265,67 @@
   // 选择套餐改变
   const serviceTypeChange=(value)=>{
     searchParams.service_types=value.join(',')
-    getList()
+    changeChartDetail()
+  }
+  //初始化detailParams
+  const initDetailParams = () => {
+     detailParams.current = 1;
+     detailParams.keyword = '';
+     detailParams.sort_type = '';
+     tableRef.value?.clearSort();
+  };
+  //更新数据
+  const changeChartDetail = () => {
+     initDetailParams()
+     getList();
+     getDetailList();
+  }
+  //切换统计种类
+  const changeStatisticalMethod = () => {
+    changeChartDetail()
+  }
+  //表格客户名称搜索
+  const handleSearch = () => {
+     changePageNo(1);
+  };
+  //表格切换page_size
+  const changePageSize = (pageSize) => {
+     detailParams.page_size = pageSize;
+     getDetailList();
+  }
+  //表格切换current
+  const changePageNo = (pageNo) => {
+    detailParams.current = pageNo;
+    getDetailList()
+  }
+  //表格排序
+  const sortChange = ({order}) => {
+     detailParams.sort_type = order? order=="descending"?"desc":"asc" :""
+     getDetailList();
   }
 
   initOptions()
   getSellerData()
   getList()
+  getDetailList()
   getServiceListFun()
 </script>
 
 <template>
     <div class="business-income-container" id="business-income-container">
+      <el-radio-group v-model="searchParams.income_type" size="large"
+        style="margin: 0 0 30px 0;">
+        <el-radio-button v-for="item in statisticalMethod" :key="item.value" class="title-dimension-radio" @change="changeStatisticalMethod"
+        :label="item.value" >{{ item.label }}</el-radio-button>
+      </el-radio-group>
       <div class="business-income-top">
         <div class="business-income-search-zone">
-          <el-radio-group v-model="searchParams.list_param" size="large" @change="getList"
+          <el-radio-group v-model="searchParams.list_param" size="large" @change="changeChartDetail"
           style="margin: 0 30px 8px 0;">
             <el-radio-button v-for="item in dimensionArray" :key="item.tag" class="dimension-radio"
             :label="item.tag" >{{ item.label }}</el-radio-button>
           </el-radio-group>
-          <el-radio-group v-model="searchParams.company_type" size="large" @change="getList"
+          <el-radio-group v-model="searchParams.company_type" size="large" @change="changeChartDetail"
           style="margin: 0 30px 8px 0;">
             <el-radio-button v-for="item in customerTypeArray" :key="item.value" class="dimension-radio"
             :label="item.value" >{{ item.label }}</el-radio-button>
@@ -218,30 +337,74 @@
           <el-cascader :options="serviceTypeArray" style="width: 240px;margin-bottom: 8px;margin-right: 30px;"
             @change="serviceTypeChange" placeholder="请选择套餐" clearable collapse-tags :show-all-levels="false"
             :props="{multiple:true,label:'title',value:'service_template_id',children:'children',emitPath:false}"></el-cascader>
-          <el-date-picker v-model="invoiceTime" type="monthrange"
+          <el-date-picker v-model="invoiceTime" type="monthrange" unlink-panels
           start-placeholder="开始日期" end-placeholder="结束日期" style="max-width: 238px;margin:0 30px 8px 0;"
           value-format="YYYY-MM"></el-date-picker>
         </div>
-        <el-button @click="exportData" type="primary" size="large" style="width: 118px;" :loading="loading.export"
-        v-if="searchParams.company_type!=3">导出数据</el-button>
       </div>
-      <div class="business-income-chart" v-loading="loading.list" element-loading-text="图表加载中……">
-        <chart :options="chartOptions" style="width: 75%;height: 80%;"/>
-        <el-tooltip placement="top-end">
-          <span class="notRenewed-legend-hint" v-show="searchParams.company_type==3">
-            <el-icon size="16px" style="margin-right:4px ;">
-              <svg-icon name="svgIcon-common-infoReverse" color="var(--themeColor)"></svg-icon>
-            </el-icon>
-            <span>图例说明</span>
-          </span>
-          <template #content>
-            <div>
-              未续约收入金额:当期未续约收入金额=去年同期总收入金额(新客户+老客户)-当期老客户收入金额
-              <br />
-              移动平均值:未续约收入金额的移动平均值,移动间隔长度3个月。
+      <div class="chart-detail-wrap">
+        <div class="business-income-chart" v-loading="loading.list" element-loading-text="图表加载中……">
+          <chart :options="chartOptions" style="width: 75%;height: 80%;"/>
+          <el-tooltip placement="top-end">
+            <span class="notRenewed-legend-hint">
+              <el-icon size="16px" style="margin-right:4px ;">
+                <svg-icon name="svgIcon-common-infoReverse" color="var(--themeColor)"></svg-icon>
+              </el-icon>
+              <span>图例说明</span>
+            </span>
+            <template #content>
+              <div v-html="toolTipText"></div>
+            </template>
+          </el-tooltip>
+        </div>
+        <div class="business-income-detail" v-if="searchParams.company_type!=3" v-loading="loading.detail" element-loading-text="数据加载中……">
+            <div class="detail-title">
+              <div class="title-text">数据详情</div>
+              <div style="display: flex;align-items: center;">
+                <el-input 
+                 v-model="detailParams.keyword" 
+                 style="width: 240px;margin-right: 25px;" 
+                 placeholder="请输入客户名称" 
+                 :prefix-icon="Search"
+                 @input="handleSearch"
+                 clearable/>
+                <el-button @click="exportData" type="primary" size="large" style="width: 118px;" :loading="loading.export"
+                 v-if="searchParams.company_type!=3">导出数据</el-button>
+              </div>
             </div>
-          </template>
-        </el-tooltip>
+            <el-table :data="detailData" border style="width: 100%;margin-top: 20px;" max-height="600px" @sort-change="sortChange" ref="tableRef">
+              <el-table-column
+                v-for="item in detailColumns"
+                :key="item.label"
+                :label="item.label"
+                :width="item.widthsty"
+                :min-width="item.minwidthsty"
+                show-overflow-tooltip
+                :sortable="item.sortable || false"
+                :prop="item.key"
+              >
+              <template #header>
+                  <el-tooltip 
+                  :content="searchParams.income_type == 0 ? `开票金额:已开票已到款、已开票未到款、未开票已到款<br/>注:未开票已到款的也算作开票金额进行统计。` : `到款金额:已开票已到款、未开票已到款`" 
+                  placement="top" 
+                  v-if="item.key == 'origin_amount'"
+                  raw-content>
+                      <span style="display: inline-flex;align-items: center;">{{ item.label }}
+                          <svg-Icon name="svgIcon-financial-info" size="18" style="margin-left: 5px;color: white;" />
+                      </span>
+                  </el-tooltip>
+                  <span v-else>{{ item.label }}</span>
+              </template>
+              <template #default="{row}">
+                <span v-if="item.key == 'contract_type'">{{ row.contract_type==0?'/':row.contract_type==1?'是':'否' }}</span>
+                <span v-else>{{ row[item.key] }}</span>
+              </template>
+              </el-table-column>
+            </el-table>
+            <m-page :pageSize="detailParams.page_size" :page_no="detailParams.current" 
+            style="display: flex;justify-content: flex-end;margin-top: 30px;" 
+            :total="detailTotal" @handleCurrentChange="changePageNo" @handleSizeChange="changePageSize"/>
+        </div>
       </div>
     </div>
 </template>
@@ -259,25 +422,43 @@
         flex-wrap: wrap;
       }
     }
-    .business-income-chart{
+    .chart-detail-wrap{
+      width: 100%;
       border: 1px solid #DCDFE6;
       background-color: white;
-      height: calc(100vh - 190px);
-      padding: 20px 30px;
-      box-sizing: border-box;
-      display: flex;
-      justify-content: center;
-      align-items: center;
-      position: relative;
-      .notRenewed-legend-hint{
-        position: absolute;
-        right: 30px;
-        top: 20px;
-        cursor: pointer;
-        font-size: 14px;
-        color: $themeColor;
+      .business-income-chart{
+        width: 100%;
+        height: calc(100vh - 280px);
+        padding: 0 30px;
+        box-sizing: border-box;
         display: flex;
+        justify-content: center;
         align-items: center;
+        position: relative;
+        .notRenewed-legend-hint{
+          position: absolute;
+          right: 30px;
+          top: 20px;
+          cursor: pointer;
+          font-size: 14px;
+          color: $themeColor;
+          display: flex;
+          align-items: center;
+        }
+      }
+      .business-income-detail{
+        box-sizing: border-box;
+        padding: 0 30px 40px;
+        .detail-title{
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          .title-text{
+            font-size: 14px;
+            font-weight: 400;
+            color: #333333;
+          }
+        }
       }
     }
 
@@ -285,6 +466,17 @@
 </style>
 <style lang="scss">
   #business-income-container{
+    .title-dimension-radio{
+      span{
+        box-sizing: border-box;
+        border: 1px solid #AB9523;
+        font-size: 16px;
+        display: inline-block;
+        color: #AB9523;
+        padding: 12px 30px;
+        font-weight: 500;
+      }
+    }
     .dimension-radio{
       span{
         display: inline-block;
@@ -297,5 +489,10 @@
         color:white
       }
     }
+    .business-income-detail{
+      .el-table td.el-table__cell, .el-table th.el-table__cell.is-leaf{
+        height: 50px;
+      }
+    }
   }
 </style>