Prechádzať zdrojové kódy

Merge remote-tracking branch 'origin/master'

yusm 1 mesiac pred
rodič
commit
dc4a99d349

+ 76 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/biReport/cusTotalAnalysis/api.ts

@@ -0,0 +1,76 @@
+import { post, get } from '@/utils/request';
+import { dayjs } from 'element-plus';
+
+export type RequestProps = {
+  startDate?: string;
+  endDate?: string;
+  exportType?: 0 | 1;
+  userId?: number;
+  departmentId?: number;
+};
+
+export async function getOverallData(payload?: RequestProps): Promise<any> {
+  return await post('/report/getCustomerTotalCount', payload);
+}
+
+export async function getConversionData(payload?: RequestProps): Promise<any> {
+  return await post('/report/getCustomerTransferRate', payload);
+}
+
+export async function getDepartmentData(): Promise<any> {
+  return await get('/department/normalList');
+}
+
+export async function getStaffData(): Promise<any> {
+  return await get('/user/getSimpleActiveUserList');
+}
+
+export async function exportFile(payload: RequestProps, type: number): Promise<any> {
+  return await post(
+    type === 0 ? '/report/exportCustomerTotalCount' : '/report/exportCustomerTransferRate',
+    payload
+  );
+}
+
+export const dateCollections = [
+  {
+    name: '当日',
+    start_time: dayjs().startOf('date').format('YYYY-MM-DD HH:mm:ss'),
+    end_time: dayjs().endOf('date').format('YYYY-MM-DD HH:mm:ss')
+  },
+  {
+    name: '昨日',
+    start_time: dayjs().startOf('date').subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss'),
+    end_time: dayjs().endOf('date').subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss')
+  },
+  {
+    name: '本周',
+    start_time: dayjs().startOf('week').add(1, 'day').format('YYYY-MM-DD HH:mm:ss'),
+    end_time: dayjs().endOf('week').add(1, 'day').format('YYYY-MM-DD HH:mm:ss')
+  },
+  {
+    name: '上周',
+    start_time: dayjs().add(-1, 'week').startOf('week').add(1, 'day').format('YYYY-MM-DD HH:mm:ss'),
+    end_time: dayjs().add(-1, 'week').endOf('week').add(1, 'day').format('YYYY-MM-DD HH:mm:ss')
+  },
+  {
+    name: '本月',
+    start_time: dayjs().startOf('month').format('YYYY-MM-DD HH:mm:ss'),
+    end_time: dayjs().endOf('month').format('YYYY-MM-DD HH:mm:ss')
+  },
+  {
+    name: '上月',
+    start_time: dayjs().add(-1, 'month').startOf('month').format('YYYY-MM-DD HH:mm:ss'),
+    end_time: dayjs().add(-1, 'month').endOf('month').format('YYYY-MM-DD HH:mm:ss')
+  },
+  {
+    name: '本季度',
+    start_time: dayjs().month(0).format('YYYY-MM-DD HH:mm:ss'),
+    end_time: dayjs().month(2).endOf('month').format('YYYY-MM-DD HH:mm:ss')
+  },
+  {
+    name: '上季度',
+    start_time: dayjs().add(-1, 'year').month(9).format('YYYY-MM-DD HH:mm:ss'),
+    end_time: dayjs().add(-1, 'year').month(11).endOf('month').format('YYYY-MM-DD HH:mm:ss')
+  }
+];

+ 202 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/biReport/cusTotalAnalysis/index.vue

@@ -0,0 +1,202 @@
+<script lang="ts" setup>
+import { ref, onMounted, watch, reactive } from "vue";
+import {
+  type RequestProps,
+  getOverallData,
+  exportFile,
+  dateCollections
+} from './api';
+import { downloadFile } from '@/utils/tools';
+import { dealWithTranslation } from '@/utils/translationProcessing';
+import personnelSearch from '@/components/translationComponent/personnelSearch/personnelSearch.vue';
+import treeSelect from '@/components/translationComponent/treeSelect/treeSelect.vue';
+import Echarts from '@/components/ReEcharts/index.vue';
+import { EChartsOption } from 'echarts';
+import { useStore } from '@/store/index';
+import { storeToRefs } from 'pinia';
+
+const { userInfo } = storeToRefs(useStore());
+const isLoading = ref(false);
+const dataSource = ref([]);
+const form = reactive({ type: 1, date: undefined, member: '' });
+const chartOptions: EChartsOption = reactive({
+  grid: { bottom: 30 },
+  legend: {},
+  tooltip: {},
+  toolbox: {
+    show: true,
+    feature: {
+      magicType: {
+        show: true,
+        type: ['line', 'bar'] // 允许切换的图表类型
+      },
+      restore: { show: true } // 还原按钮
+    }
+  },
+  dataset: {
+    dimensions: [],
+    source: []
+  },
+  xAxis: { type: 'category' },
+  yAxis: {},
+  series: []
+});
+
+const dateOptions = [
+  { label: '今天', value: '1' },
+  { label: '昨天', value: '2' },
+  { label: '本周', value: '3' },
+  { label: '上周', value: '4' },
+  { label: '本月', value: '5' },
+  { label: '上月', value: '6' },
+  { label: '本季度', value: '7' },
+  { label: '上季度', value: '8' }
+];
+const exportLoading = ref(false);
+const seachLoading = ref(false);
+
+const onSubmit = async (isExport?: boolean) => {
+  const payload = {
+    startDate: form.date && dateCollections[form.date - 1].start_time,
+    endDate: form.date && dateCollections[form.date - 1].end_time,
+    exportType: form.type,
+    userId: form.type === 1 ? form.member : undefined,
+    departmentId: form.type === 1 ? undefined : form.member
+  } as RequestProps;
+
+  if (isExport) {
+    exportLoading.value = true;
+    const { data } = await exportFile(payload, 0);
+    await downloadFile(data, data?.split('/')?.[2] || '客户表');
+    exportLoading.value = false;
+    return;
+  }
+  queryOverall(payload);
+};
+
+const queryOverall = async (payload?: RequestProps) => {
+  isLoading.value = true;
+  seachLoading.value = true
+  const { data = [] } = await getOverallData(payload);
+  isLoading.value = false;
+  dataSource.value = data.map((d: any) => ({
+    dealRate: d.dealRate * 100,
+    customerDeal: d.customerDeal,
+    customertotal: d.customertotal,
+    name: form.type === 1 ? d.name : d.departmentName
+  }));
+  seachLoading.value = false
+
+  const sourceData = data.map((d: any) => {
+    const base = {
+      name: form.type === 1 ? d.name : d.departmentName,
+      ['成交客户数']: d.customerDeal,
+      ['新增客户数']: d.customertotal
+    };
+    
+    if (form.type === 0) {
+      base['客户总数'] = d.earlierCusTotal;
+    }
+
+    return base;
+  });
+
+  const sourceDataTypes = sourceData.map((item: any) => ({
+    type: form.type === 1 ? 'userName' : 'departmentName',
+    id: item.name
+  }));
+
+  chartOptions.series = [
+    { type: 'bar', barWidth: 40, color: '#ffba6d' },
+    { type: 'bar', barWidth: 40, color: '#3f95c2' }
+  ];
+
+  if (form.type === 0) {
+    chartOptions.series.push({ type: 'bar', barWidth: 40, color: '#6dc8e1' }); // 只有按部门时才显示客户总数的柱状图
+  }
+
+  if (userInfo && userInfo.value.userNameNeedTranslate == 1) {
+    dealWithTranslation(sourceDataTypes, sourceData).then((res: any) => {
+      chartOptions.dataset.dimensions = ['name', '成交客户数', '新增客户数'];
+      if (form.type === 0) {
+        chartOptions.dataset.dimensions.push('客户总数'); // 只有按部门时才加入
+      }
+      chartOptions.dataset.source = res;
+      chartOptions.legend = {};
+    });
+    return;
+  }
+
+  chartOptions.dataset.dimensions = ['name', '成交客户数', '新增客户数'];
+  if (form.type === 0) {
+    chartOptions.dataset.dimensions.push('客户总数');
+  }
+  chartOptions.dataset.source = sourceData;
+  chartOptions.legend = {};
+};
+
+onMounted(() => {
+  onSubmit(false);
+});
+</script>
+
+
+<template>
+  <div class="w-full h-full p-5 bg-white flex flex-col">
+    <div class="flex justify-between">
+      <div class="flex items-center">
+        <div class="flex items-center mr-8">
+          <div class="mr-3 text-[14px]">时间</div>
+          <el-select clearable v-model="form.date" style="width: 112px">
+            <el-option v-for="date in dateOptions" :key="date.value" :label="date.label" :value="date.value" />
+          </el-select>
+        </div>
+
+        <div class="flex items-center mr-8">
+          <div class="mr-3 text-[14px]">分类</div>
+          <el-select v-model="form.type" @change="form.member = ''" style="width: 112px">
+            <el-option label="按部门" :value="0" />
+            <el-option label="按员工" :value="1" />
+          </el-select>
+        </div>
+
+        <div class="flex items-center mr-8">
+          <div class="mr-3 text-[14px]">{{ form.type == 1 ? '员工' : '部门' }}</div>
+          <template v-if="form.type == 1">
+            <personnel-search v-model="form.member" :size="''" placeholder="选择员工" width="240px"></personnel-search>
+          </template>
+          <template v-if="form.type == 0">
+            <tree-select v-model="form.member" :size="''" checkStrictly placeholder="选择部门" width="240px"></tree-select>
+          </template>
+        </div>
+
+        <div class="flex items-center mr-8">
+          <el-button type="primary" @click="onSubmit(false)" :loading="seachLoading">搜索</el-button>
+        </div>
+      </div>
+      <el-button type="primary" @click="onSubmit(true)" :loading="exportLoading">导出</el-button>
+    </div>
+    <div class="flex-1 py-4">
+      <Echarts :option="chartOptions"></Echarts>
+    </div>
+    <div class="h-[40vh]">
+      <el-table :data="dataSource" style="height: 100%" v-loading="seachLoading">
+        <el-table-column prop="name" label="名称" align="center">
+          <template #default="scope">
+            <TextTranslation translationTypes="userName" :translationValue="scope.row.name"></TextTranslation>
+          </template>
+        </el-table-column>
+        <el-table-column prop="customertotal" label="新增客户数" align="center" />
+        <el-table-column prop="customerDeal" label="成交客户数" align="center" />
+        <el-table-column prop="dealRate" label="客户成交率(%)" align="center" >
+          <template #default="scope">
+            {{ scope.row?.dealRate.toFixed(0) }}
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+</style>

+ 26 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/biReport/list.ts

@@ -961,6 +961,32 @@ export const dropdownBoxFieldIntegration = [
       { label: "是", value: "1" },
     ],
   },
+  {
+    indicate: "task",
+    fieldName: "pay_type",
+    list: [
+      { label: "未付款", value: "0" },
+      { label: "付款", value: "1" },
+    ],
+  },
+  {
+    indicate: "task",
+    fieldName: "pay_way",
+    list: [
+      { label: "Paynow", value: "0" },
+      { label: "Cash", value: "1" },
+      { label: "Wechat", value: "2" },
+    ],
+  },
+  {
+    indicate: "task",
+    fieldName: "custom_type",
+    list: [
+      { label: "居民住家", value: "0" },
+      { label: "商业区", value: "1" },
+      { label: "其他类型", value: "2" },
+    ],
+  },
   {
     indicate: "task_comment",
     fieldName: "type",

+ 2 - 2
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/corpreport/api.ts

@@ -10,11 +10,11 @@ export type RequestProps = {
 };
 
 export async function getOverallData(payload?: RequestProps): Promise<any> {
-  return await post('report/getCustomerTotalCount', payload);
+  return await post('/report/getCustomerTotalCount', payload);
 }
 
 export async function getConversionData(payload?: RequestProps): Promise<any> {
-  return await post('report/getCustomerTransferRate', payload);
+  return await post('/report/getCustomerTransferRate', payload);
 }
 
 export async function getDepartmentData(): Promise<any> {