123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- <template>
- <div class="data-summary-container">
- <el-card>
- <div style="display: flex">
- <div class="data-summary-top">
- <span :class="['button-sty', { act: monthType === item.label }]" v-for="item in monthLabel" @click="toggleMonth(item.label)" :key="item.label">
- {{ item.label }}
- </span>
- </div>
- <date-picker v-model="timeRange" type="year" range value-type="format" placeholder="开始至结束" :editable="false" @change="dateChange" :disabled-date="disabledDate" @pick="onPick" clearable />
- </div>
- </el-card>
- <div class="dataReport-main">
- <!-- 合同类型帅选项 -->
- <div style="display: flex; flex-wrap: wrap">
- <div class="data-summary-top">
- <span :class="['button-sty btn-filter', { act: selectedFilters.includes(item) }]" v-for="(fields, item) in filterOptions" @click="toggleFilter(item)" :key="item">
- {{ item }}
- </span>
- </div>
- <el-cascader
- v-model="pathfinderSales"
- :options="salesArrRai"
- :props="salesArrProps"
- clearable
- @change="salesChangeHandedl"
- placeholder="选择开拓组销售"
- :disabled="serviceGroupSalesAct.length"
- style="margin-right: 20px"
- ></el-cascader>
- <el-cascader
- v-model="serviceGroupSalesAct"
- :options="serviceGroupSales"
- :props="salesArrProps"
- clearable
- @change="salesChangeHandedl"
- placeholder="选择服务组销售"
- :disabled="pathfinderSales.length"
- ></el-cascader>
- <div class="switch-box">
- <span>开拓组</span>
- <el-switch v-model="pathfinderSwitch" :disabled="isSwitchDisabled" @change="salesChangeHandedl"></el-switch>
- <span>服务组</span>
- <el-switch v-model="serviceGroupSwitch" :disabled="isSwitchDisabled" @change="salesChangeHandedl"></el-switch>
- </div>
- </div>
- <!-- 数据表格 -->
- <el-table :data="flattenedData" border style="width: 100%; margin-top: 20px" :span-method="mergeRows">
- <!-- DataType 作为合并行 -->
- <el-table-column prop="DataType" label="" align="center" width="120px" />
- <!-- 销售姓名 -->
- <el-table-column prop="SellerName" label="销售姓名" align="center" width="150px" />
- <el-table-column v-for="col in dynamicColumns" :key="col.key" :prop="col.key" align="center">
- <template slot="header" slot-scope="{ row }">
- <el-tooltip :content="col.tooltip" placement="top">
- <div style="display: inline-flex; align-items: center">
- <span style="margin-right: 4px">{{ col.label }}</span>
- <i class="el-icon-info" style="color: #333333" />
- </div>
- </el-tooltip>
- </template>
- <template slot-scope="{ row }">
- <span class="editsty" @click="handlerRowClick(row, col.key)">{{ row[col.key] }}</span>
- </template>
- </el-table-column>
- </el-table>
- </div>
- <DataSummary :visible.sync="showDlg" :title="titleDlg" :columns="columnsDlg" :dataItem="dataItem" />
- </div>
- </template>
- <script>
- import { dataMainInterface } from "@/api/api.js";
- import DataSummary from "./components/DataSummary.vue";
- import { tableConfigs, tableDlgTitle } from "./configdata.js";
- export default {
- components: { DataSummary },
- data() {
- const currentYear = new Date().getFullYear() + "";
- return {
- timeRange: [currentYear, currentYear],
- timePick: "",
- monthType: "季度",
- monthLabel: [
- {
- label: "季度",
- },
- {
- label: "半年度",
- },
- {
- label: "年度",
- },
- ],
- // 筛选项映射的表头字段(新增后端 key)
- filterOptions: {
- 新签: [
- { label: "新增试用", key: "AddTrialCount", tooltip: "新增试用客户的时间,包含在所选时间段内的客户数(包括新建和领取流失)" },
- { label: "新签合同(金额/数量)", key: "NewContractData", tooltip: "起始时间在所选时间段内的新签合同(第一份合同起始时间一年内的再次签约仍属于新签合同)" },
- ],
- 续约: [
- { label: "到期合同(金额/数量)", key: "ExpiredContractData", tooltip: "结束时间在所选时间段内的合用" },
- { label: "续约合同(金额/数量)", key: "RenewedContractData", tooltip: "起始时间在所选时间段内的续约合同(第一份合同起始时间一年以后的再次签约均属于续约合同)" },
- { label: "续约率(金额/数量)", key: "RenewalRateData", tooltip: "续约合同/到期合同" },
- { label: "确认不续约合同(金额/数量)", key: "ConfirmedNoRenewalContractData", tooltip: "已确认不续约的到期合同" },
- { label: "确认不续约率(金额/数量)", key: "ConfirmNonRenewalRateData", tooltip: "确认不续约合同(剔除非业务不续约)/到期合同" },
- { label: "签约客户数量", key: "SignedClientCount", tooltip: "新签和续约的客户数" },
- { label: "客单价", key: "AverageRevenueCount", tooltip: "新签合同和续约合同的总金额/签约客户数量" },
- ],
- 收入: [
- { label: "开票金额", key: "InvoiceAmountCount", tooltip: "财务系统中已经登记开票的金额" },
- { label: "到款金额", key: "PaymentReceivedCount", tooltip: "财务系统中已经登记到账的金额" },
- { label: "未到款比例", key: "UnpaidRatioCount", tooltip: "开票金额-到款金额 / 开票金额" },
- { label: "新客开票", key: "NewCustomerInvoicingCount", tooltip: "财务系统中已经登记开票的新签合同金额" },
- { label: "新客到款", key: "NewCustomerPaymentsReceivedCount", tooltip: "财务系统中已经登记开票的新签合同金额" },
- ],
- },
- selectedFilters: ["新签", "续约", "收入"], // 用户选择的筛选项
- // 示例数据(与后端返回的 key 对应)
- tableData: [],
- // 扁平化后的数据
- flattenedData: [],
- showDlg: false,
- titleDlg: "",
- columnsDlg: [],
- salesArrRai: [], //开拓者销售
- pathfinderSales: [], //选中的开拓者销售
- salesArrProps: {
- multiple: true,
- value: "AdminId",
- label: "RealName",
- children: "ChildrenList",
- },
- serviceGroupSales: [], //服务组销售
- serviceGroupSalesAct: [], //选中的服务组销售
- pathfinderSwitch: false, //开拓者开关
- serviceGroupSwitch: false, //服务组开关
- dataItem: {}, //数据项
- };
- },
- methods: {
- /* 选择时间后的处理 */
- dateChange() {
- this.$nextTick(() => {
- if (this.timeRange.length) this.timePick = this.timeRange[0];
- this.getDataList();
- });
- },
- // 处理结束年份变化的逻辑
- disabledDate(time) {
- if (this.timePick) {
- const minTime = +this.timePick;
- const maxTime = +this.timePick + 4; // 结束年份最大为开始年份限制5年 +4
- return this.$moment(time).format("YYYY") < minTime || this.$moment(time).format("YYYY") > maxTime;
- }
- },
- // 选了时间的事件
- onPick(date) {
- this.timePick = this.$moment(date).format("YYYY");
- },
- // 获取表格数据
- async getDataList() {
- let AdminId = this.pathfinderSales.map((item) => item[item.length - 1]).join(",");
- let ServiceAdminId = this.serviceGroupSalesAct.map((item) => item[item.length - 1]).join(",");
- let params = {
- StartYear: this.timeRange[0],
- EndYear: this.timeRange[1],
- DataType: this.monthType,
- AdminId,
- ServiceAdminId,
- DevelopButton: this.pathfinderSwitch,
- ServerButton: this.serviceGroupSwitch,
- };
- const res = await dataMainInterface.getRaiDataSummary(params);
- this.tableData = res.Data.List;
- this.flattenedData = this.tableData.flatMap((item) => item.DataList.map((row) => ({ ...row, DataType: item.DataType })));
- },
- // 处理合并行
- mergeRows({ row, column, rowIndex, columnIndex }) {
- if (columnIndex === 0) {
- // 只合并 DataType (第1列)
- const currentType = row.DataType;
- const prevType = rowIndex > 0 ? this.flattenedData[rowIndex - 1].DataType : null;
- if (rowIndex === 0 || currentType !== prevType) {
- // 计算 rowspan(找到相同 DataType 的总行数)
- const rowspan = this.flattenedData.filter((item) => item.DataType === currentType).length;
- return { rowspan, colspan: 1 };
- } else {
- return { rowspan: 0, colspan: 0 };
- }
- }
- },
- // 点击表格
- handlerRowClick(row, key) {
- console.log(row);
-
- this.showDlg = true;
- this.dataItem = row;
- this.titleDlg = tableDlgTitle[key];
- this.columnsDlg = tableConfigs[key];
- },
- // 点击头部筛选项
- toggleMonth(key) {
- if (this.monthType !== key) {
- this.monthType = key;
- this.getDataList();
- }
- },
- // 点击了标签
- toggleFilter(item) {
- if (this.selectedFilters.includes(item)) {
- let index = this.selectedFilters.findIndex((key) => key === item);
- this.selectedFilters.splice(index, 1);
- } else {
- this.selectedFilters.push(item);
- }
- this.getDataList();
- },
- /* 获取权益销售 */
- getSaleRai() {
- dataMainInterface.getListRaiSellerServer().then((res) => {
- if (res.Ret === 200) {
- this.salesArrRai = res.Data.List;
- this.serviceGroupSales = res.Data.ListServer;
- }
- });
- },
- salesChangeHandedl() {
- this.getDataList();
- },
- },
- computed: {
- // 计算动态表头
- dynamicColumns() {
- let columns = [];
- this.selectedFilters.forEach((key) => {
- if (this.filterOptions[key]) {
- this.filterOptions[key].forEach((field) => {
- columns.push({ label: field.label, key: field.key, tooltip: field.tooltip });
- });
- }
- });
- return columns;
- },
- // 开关选择是否禁用
- isSwitchDisabled() {
- return this.pathfinderSales.length || this.serviceGroupSalesAct.length;
- },
- },
- mounted() {
- this.getDataList();
- this.getSaleRai();
- },
- };
- </script>
- <style scoped lang="scss">
- .data-summary-container {
- .data-summary-top {
- box-sizing: border-box;
- height: 40px;
- border: #dcdfe6 1px solid;
- border-radius: 4px;
- margin-right: 20px;
- overflow: hidden;
- }
- .button-sty {
- display: inline-block;
- text-align: center;
- line-height: 40px;
- width: 120px;
- height: 40px;
- cursor: pointer;
- &:nth-child(2) {
- border-left: 1px solid #dcdfe6;
- border-right: 1px solid #dcdfe6;
- }
- }
- .act {
- background-color: #409eff !important;
- color: #fff !important;
- }
- .dataReport-main {
- padding: 20px 20px 80px;
- background: #fff;
- margin-top: 20px;
- border: 1px solid #ececec;
- border-radius: 4px;
- box-shadow: 0 3px 6px rgba(0, 0, 0, 0.05);
- .btn-filter {
- background-color: #eaf3fe;
- color: #333;
- }
- .switch-box {
- display: flex;
- align-items: center;
- span {
- flex-shrink: 0;
- display: inline-block;
- margin: 0 10px 0 20px;
- }
- }
- }
- }
- .dete-partition {
- display: inline-block;
- margin: 0 10px;
- }
- </style>
|