index.vue 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. <script lang="ts" setup>
  2. import { ref, onMounted, watch, reactive } from "vue";
  3. import {
  4. type RequestProps,
  5. getOverallData,
  6. exportFile,
  7. dateCollections
  8. } from './api';
  9. import { downloadFile } from '@/utils/tools';
  10. import { dealWithTranslation } from '@/utils/translationProcessing';
  11. import personnelSearch from '@/components/translationComponent/personnelSearch/personnelSearch.vue';
  12. import treeSelect from '@/components/translationComponent/treeSelect/treeSelect.vue';
  13. import Echarts from '@/components/ReEcharts/index.vue';
  14. import { EChartsOption } from 'echarts';
  15. import { useStore } from '@/store/index';
  16. import { storeToRefs } from 'pinia';
  17. const { userInfo } = storeToRefs(useStore());
  18. const isLoading = ref(false);
  19. const dataSource = ref([]);
  20. const form = reactive({ type: 1, date: undefined, member: '' });
  21. const chartOptions: EChartsOption = reactive({
  22. grid: { bottom: 30 },
  23. legend: {},
  24. tooltip: {},
  25. toolbox: {
  26. show: true,
  27. feature: {
  28. magicType: {
  29. show: true,
  30. type: ['line', 'bar'] // 允许切换的图表类型
  31. },
  32. restore: { show: true } // 还原按钮
  33. }
  34. },
  35. dataset: {
  36. dimensions: [],
  37. source: []
  38. },
  39. xAxis: { type: 'category' },
  40. yAxis: {},
  41. series: []
  42. });
  43. const dateOptions = [
  44. { label: '今天', value: '1' },
  45. { label: '昨天', value: '2' },
  46. { label: '本周', value: '3' },
  47. { label: '上周', value: '4' },
  48. { label: '本月', value: '5' },
  49. { label: '上月', value: '6' },
  50. { label: '本季度', value: '7' },
  51. { label: '上季度', value: '8' }
  52. ];
  53. const exportLoading = ref(false);
  54. const seachLoading = ref(false);
  55. const onSubmit = async (isExport?: boolean) => {
  56. const payload = {
  57. startDate: form.date && dateCollections[form.date - 1].start_time,
  58. endDate: form.date && dateCollections[form.date - 1].end_time,
  59. exportType: form.type,
  60. userId: form.type === 1 ? form.member : undefined,
  61. departmentId: form.type === 1 ? undefined : form.member
  62. } as RequestProps;
  63. if (isExport) {
  64. exportLoading.value = true;
  65. const { data } = await exportFile(payload, 0);
  66. await downloadFile(data, data?.split('/')?.[2] || '客户表');
  67. exportLoading.value = false;
  68. return;
  69. }
  70. queryOverall(payload);
  71. };
  72. const queryOverall = async (payload?: RequestProps) => {
  73. isLoading.value = true;
  74. seachLoading.value = true
  75. const { data = [] } = await getOverallData(payload);
  76. isLoading.value = false;
  77. dataSource.value = data.map((d: any) => ({
  78. dealRate: d.dealRate * 100,
  79. customerDeal: d.customerDeal,
  80. customertotal: d.customertotal,
  81. name: form.type === 1 ? d.name : d.departmentName
  82. }));
  83. seachLoading.value = false
  84. const sourceData = data.map((d: any) => {
  85. const base = {
  86. name: form.type === 1 ? d.name : d.departmentName,
  87. ['成交客户数']: d.customerDeal,
  88. ['新增客户数']: d.customertotal
  89. };
  90. if (form.type === 0) {
  91. base['客户总数'] = d.earlierCusTotal;
  92. }
  93. return base;
  94. });
  95. const sourceDataTypes = sourceData.map((item: any) => ({
  96. type: form.type === 1 ? 'userName' : 'departmentName',
  97. id: item.name
  98. }));
  99. chartOptions.series = [
  100. { type: 'bar', barWidth: 40, color: '#ffba6d' },
  101. { type: 'bar', barWidth: 40, color: '#3f95c2' }
  102. ];
  103. if (form.type === 0) {
  104. chartOptions.series.push({ type: 'bar', barWidth: 40, color: '#6dc8e1' }); // 只有按部门时才显示客户总数的柱状图
  105. }
  106. if (userInfo && userInfo.value.userNameNeedTranslate == 1) {
  107. dealWithTranslation(sourceDataTypes, sourceData).then((res: any) => {
  108. chartOptions.dataset.dimensions = ['name', '成交客户数', '新增客户数'];
  109. if (form.type === 0) {
  110. chartOptions.dataset.dimensions.push('客户总数'); // 只有按部门时才加入
  111. }
  112. chartOptions.dataset.source = res;
  113. chartOptions.legend = {};
  114. });
  115. return;
  116. }
  117. chartOptions.dataset.dimensions = ['name', '成交客户数', '新增客户数'];
  118. if (form.type === 0) {
  119. chartOptions.dataset.dimensions.push('客户总数');
  120. }
  121. chartOptions.dataset.source = sourceData;
  122. chartOptions.legend = {};
  123. };
  124. onMounted(() => {
  125. onSubmit(false);
  126. });
  127. </script>
  128. <template>
  129. <div class="w-full h-full p-5 bg-white flex flex-col">
  130. <div class="flex justify-between">
  131. <div class="flex items-center">
  132. <div class="flex items-center mr-8">
  133. <div class="mr-3 text-[14px]">时间</div>
  134. <el-select clearable v-model="form.date" style="width: 112px">
  135. <el-option v-for="date in dateOptions" :key="date.value" :label="date.label" :value="date.value" />
  136. </el-select>
  137. </div>
  138. <div class="flex items-center mr-8">
  139. <div class="mr-3 text-[14px]">分类</div>
  140. <el-select v-model="form.type" @change="form.member = ''" style="width: 112px">
  141. <el-option label="按部门" :value="0" />
  142. <el-option label="按员工" :value="1" />
  143. </el-select>
  144. </div>
  145. <div class="flex items-center mr-8">
  146. <div class="mr-3 text-[14px]">{{ form.type == 1 ? '员工' : '部门' }}</div>
  147. <template v-if="form.type == 1">
  148. <personnel-search v-model="form.member" :size="''" placeholder="选择员工" width="240px"></personnel-search>
  149. </template>
  150. <template v-if="form.type == 0">
  151. <tree-select v-model="form.member" :size="''" checkStrictly placeholder="选择部门" width="240px"></tree-select>
  152. </template>
  153. </div>
  154. <div class="flex items-center mr-8">
  155. <el-button type="primary" @click="onSubmit(false)" :loading="seachLoading">搜索</el-button>
  156. </div>
  157. </div>
  158. <el-button type="primary" @click="onSubmit(true)" :loading="exportLoading">导出</el-button>
  159. </div>
  160. <div class="flex-1 py-4">
  161. <Echarts :option="chartOptions"></Echarts>
  162. </div>
  163. <div class="h-[40vh]">
  164. <el-table :data="dataSource" style="height: 100%" v-loading="seachLoading">
  165. <el-table-column prop="name" label="名称" align="center">
  166. <template #default="scope">
  167. <TextTranslation translationTypes="userName" :translationValue="scope.row.name"></TextTranslation>
  168. </template>
  169. </el-table-column>
  170. <el-table-column prop="customertotal" label="新增客户数" align="center" />
  171. <el-table-column prop="customerDeal" label="成交客户数" align="center" />
  172. <el-table-column prop="dealRate" label="客户成交率(%)" align="center" >
  173. <template #default="scope">
  174. {{ scope.row?.dealRate.toFixed(0) }}
  175. </template>
  176. </el-table-column>
  177. </el-table>
  178. </div>
  179. </div>
  180. </template>
  181. <style lang="scss" scoped>
  182. </style>