660 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			660 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | |
|   <ai-list class="Statistics">
 | |
|     <template #left>
 | |
|       <ai-tree-menu
 | |
|         title="应报到单位名单"
 | |
|         searchPlaceholder="请输入单位..."
 | |
|         @search="onSearch"
 | |
|       >
 | |
|         <ai-party-tree
 | |
|           :filter-node-method="filterNode"
 | |
|           ref="tree"
 | |
|           :instance="instance"
 | |
|           :root="user.info.organizationId"
 | |
|           :current-node-key="selected.id"
 | |
|           @select="handleNodeClick"
 | |
|         />
 | |
|       </ai-tree-menu>
 | |
|     </template>
 | |
|     <template slot="content">
 | |
|       <div class="top">
 | |
|         <header>近12个月党员活动参与情况统计</header>
 | |
|         <div class="month" id="month"></div>
 | |
|       </div>
 | |
|       <div class="middle">
 | |
|         <header>
 | |
|           <el-date-picker
 | |
|             v-model="selectMonth"
 | |
|             type="month"
 | |
|             @change="typeScale()"
 | |
|             size="mini"
 | |
|             :clearable="false"
 | |
|             value-format="yyyy-MM-dd"
 | |
|             placeholder="选择年月"
 | |
|           >
 | |
|           </el-date-picker>
 | |
|         </header>
 | |
|         <div class="content">
 | |
|           <div class="middle-left">
 | |
|             <ul>
 | |
|               <li>
 | |
|                 <p>应报到党员人数</p>
 | |
|                 <div class="num">
 | |
|                   <span>{{ numObj.party_num }}</span>
 | |
|                   <span>人</span>
 | |
|                 </div>
 | |
|               </li>
 | |
|               <li>
 | |
|                 <p>本月报名活动人数</p>
 | |
|                 <div class="num">
 | |
|                   <span>{{ numObj.registered_num }}</span>
 | |
|                   <span>人</span>
 | |
|                 </div>
 | |
|               </li>
 | |
|               <li>
 | |
|                 <p>实际参与活动人数</p>
 | |
|                 <div class="num">
 | |
|                   <span>{{ numObj.actual_num }}</span>
 | |
|                   <span>人</span>
 | |
|                 </div>
 | |
|               </li>
 | |
|               <li>
 | |
|                 <p>活动实际参与率</p>
 | |
|                 <div class="num">
 | |
|                   <span>{{ numObj.proportion }}</span>
 | |
|                 </div>
 | |
|               </li>
 | |
|             </ul>
 | |
|           </div>
 | |
|           <div class="middle-right" id="middle-right"></div>
 | |
|         </div>
 | |
|       </div>
 | |
|       <div class="bottom">
 | |
|         <header>
 | |
|           <ul>
 | |
|             <li
 | |
|               v-for="(e, index) in table"
 | |
|               :key="index"
 | |
|               @click="handleClick(e, index)"
 | |
|               :class="{ activeNav: e.id == activeId }"
 | |
|             >
 | |
|               {{ e.label }}
 | |
|             </li>
 | |
|             <span ref="border"></span>
 | |
|           </ul>
 | |
|         </header>
 | |
|         <ai-search-bar>
 | |
|           <template #left>
 | |
|             <el-date-picker
 | |
|               v-model="searchObj.ymd"
 | |
|               type="month"
 | |
|               @change="(page.current = 1), searchList()"
 | |
|               size="small"
 | |
|               :clearable="false"
 | |
|               value-format="yyyy-MM-01"
 | |
|               placeholder="选择年月"
 | |
|             >
 | |
|             </el-date-picker>
 | |
|             <el-button
 | |
|               icon="iconfont iconExported"
 | |
|               size="mini"
 | |
|               style="margin-left: 8px"
 | |
|               @click="outPut()"
 | |
|               :disabled="!Boolean(tableData.length)"
 | |
|               >导出
 | |
|             </el-button>
 | |
|           </template>
 | |
|           <template #right>
 | |
|             <el-input
 | |
|               v-model="searchObj.name"
 | |
|               size="small"
 | |
|               placeholder="请输入姓名"
 | |
|               clearable
 | |
|               @change="(page.current = 1), searchList()"
 | |
|               suffix-icon="iconfont iconSearch"
 | |
|             />
 | |
|           </template>
 | |
|         </ai-search-bar>
 | |
|         <ai-table
 | |
|           :dict="dict"
 | |
|           :tableData="tableData"
 | |
|           :col-configs="colConfigs"
 | |
|           :total="page.total"
 | |
|           style="margin-top: 6px"
 | |
|           :current.sync="page.current"
 | |
|           :size.sync="page.size"
 | |
|           @getList="searchList"
 | |
|         >
 | |
|         </ai-table>
 | |
|       </div>
 | |
|     </template>
 | |
|   </ai-list>
 | |
| </template>
 | |
| 
 | |
| <script>
 | |
| import { mapState } from "vuex";
 | |
| import * as echarts from "echarts";
 | |
| 
 | |
| export default {
 | |
|   name: "Statistics",
 | |
|   props: {
 | |
|     instance: Function,
 | |
|     dict: Object,
 | |
|     permissions: Function,
 | |
|   },
 | |
|   data() {
 | |
|     return {
 | |
|       filterText: "",
 | |
|       defaultArr: "",
 | |
|       partyOrgId: "", //当前选中的id
 | |
|       data12: {},
 | |
|       selectMonth: "",
 | |
|       activeId: "0",
 | |
|       numObj: {},
 | |
|       searchObj: {
 | |
|         name: "",
 | |
|         listType: "0",
 | |
|         ymd: "",
 | |
|       },
 | |
|       tableData: [],
 | |
|       page: {
 | |
|         size: 5,
 | |
|         current: 1,
 | |
|         total: 0,
 | |
|       },
 | |
|       selected: {},
 | |
|       colConfigs: [
 | |
|         { prop: "name", label: "姓名", align: "center" },
 | |
|         { prop: "sex", label: "性别", align: "center", dict: "sex" },
 | |
|         { prop: "partyOrg", label: "所属组织", align: "center" },
 | |
|         { prop: "signupCount", label: "报名次数", align: "center", width: 150 },
 | |
|         { prop: "partakeCount", label: "参与次数", align: "center", width: 150 },
 | |
|       ],
 | |
|     };
 | |
|   },
 | |
|   watch: {
 | |
|     filterText(val) {
 | |
|       this.$refs.tree.filter(val);
 | |
|     },
 | |
|   },
 | |
|   computed: {
 | |
|     ...mapState(["user"]),
 | |
|     table() {
 | |
|       return [
 | |
|         { label: "党员活动记录", id: "0" },
 | |
|         { label: "未参与活动名单", id: "1" },
 | |
|       ];
 | |
|     },
 | |
|     defaultProps() {
 | |
|       return {
 | |
|         children: "children",
 | |
|         label: "label",
 | |
|       };
 | |
|     },
 | |
|     orgTree() {
 | |
|       return this.$refs.tree?.$refs?.partyTree;
 | |
|     },
 | |
|   },
 | |
|   methods: {
 | |
|     handleNodeClick(data) {
 | |
|       this.selected = data;
 | |
|       this.partyOrgId = data.id;
 | |
|       this.activeId = "0";
 | |
|       this.searchObj.name = "";
 | |
|       this.searchObj.listType = "0";
 | |
|       this.$nextTick(() => {
 | |
|         this.month12();
 | |
|         this.typeScale();
 | |
|         this.searchList();
 | |
|       });
 | |
|     },
 | |
|     filterNode(value, data) {
 | |
|       if (!value) return true;
 | |
|       return data.name.indexOf(value) !== -1;
 | |
|     },
 | |
|     month12() {
 | |
|       this.instance
 | |
|         .post("/app/apppartyreport/trend", null, {
 | |
|           params: {
 | |
|             partyOrgId: this.partyOrgId,
 | |
|           },
 | |
|         })
 | |
|         .then((res) => {
 | |
|           if (res.code == 0) {
 | |
|             this.data12 = res.data;
 | |
|             this.showMonth12(res.data);
 | |
|           }
 | |
|         });
 | |
|     },
 | |
|     typeScale() {
 | |
|       this.instance
 | |
|         .post("/app/apppartyreport/type-scale", null, {
 | |
|           params: {
 | |
|             partyOrgId: this.partyOrgId,
 | |
|             ymd: this.selectMonth,
 | |
|           },
 | |
|         })
 | |
|         .then((res) => {
 | |
|           if (res.code == 0) {
 | |
|             this.numObj = res.data;
 | |
|             this.showPartyScale();
 | |
|           }
 | |
|         });
 | |
|     },
 | |
|     handleClick(e, index) {
 | |
|       this.activeId = e.id;
 | |
|       this.searchObj.listType = e.id;
 | |
|       this.searchObj.name = "";
 | |
|       this.page.current = 1;
 | |
|       this.page.size = 5;
 | |
|       this.searchList();
 | |
|       this.$refs.border.style.left = index * 160 + "px";
 | |
|     },
 | |
|     searchList() {
 | |
|       this.instance
 | |
|         .post(`/app/apppartyreport/list-signup`, null, {
 | |
|           params: {
 | |
|             ...this.searchObj,
 | |
|             partyOrgId: this.partyOrgId,
 | |
|             ...this.page,
 | |
|           },
 | |
|         })
 | |
|         .then((res) => {
 | |
|           if (res?.data) {
 | |
|             this.tableData = res.data.records;
 | |
|             this.page.total = res.data.total;
 | |
|           }
 | |
|         });
 | |
|     },
 | |
|     outPut() {
 | |
|       this.instance
 | |
|         .post("/app/apppartyreport/export-signup", null, {
 | |
|           responseType: "blob",
 | |
|           params: {
 | |
|             partyOrgId: this.partyOrgId,
 | |
|             ...this.searchObj,
 | |
|           },
 | |
|         })
 | |
|         .then((res) => {
 | |
|           const link = document.createElement("a");
 | |
|           let blob = new Blob([res], { type: "application/vnd.ms-excel" });
 | |
|           link.style.display = "none";
 | |
|           link.href = URL.createObjectURL(blob);
 | |
|           let fileName = "";
 | |
|           this.activeId == 0
 | |
|             ? (fileName = "党员活动记录")
 | |
|             : (fileName = "未参与活动名单");
 | |
|           link.setAttribute("download", fileName + ".xls");
 | |
|           document.body.appendChild(link);
 | |
|           link.click();
 | |
|           document.body.removeChild(link);
 | |
|         });
 | |
|     },
 | |
|     showMonth12(data) {
 | |
|       let myChart2 = echarts.init(document.getElementById("month"));
 | |
|       let months = [];
 | |
|       let arr1 = [];
 | |
|       let arr2 = [];
 | |
|       let arr3 = [];
 | |
|       data.forEach((e) => {
 | |
|         months.push(e.cycle);
 | |
|         arr1.push(e.partyNum);
 | |
|         arr2.push(e.registeredNumrc);
 | |
|         arr3.push(e.actualNumrc);
 | |
|       });
 | |
|       let option = {
 | |
|         tooltip: {
 | |
|           trigger: "axis",
 | |
|           axisPointer: {
 | |
|             type: "cross",
 | |
|             label: {
 | |
|               backgroundColor: "#6a7985",
 | |
|             },
 | |
|           },
 | |
|         },
 | |
|         dataset: {
 | |
|           source: [
 | |
|             ["product", ...months],
 | |
|             ["应报到党员人次", ...arr1],
 | |
|             ["报名活动人次", ...arr2],
 | |
|             ["实际参与活动人次", ...arr3],
 | |
|           ],
 | |
|         },
 | |
|         legend: {
 | |
|           data: ["应报到党员人次", "报名活动人次", "实际参与活动人次"],
 | |
|         },
 | |
|         toolbox: {
 | |
|           feature: {
 | |
|             saveAsImage: {},
 | |
|           },
 | |
|         },
 | |
|         grid: {
 | |
|           left: "3%",
 | |
|           right: "4%",
 | |
|           bottom: "3%",
 | |
|           containLabel: true,
 | |
|         },
 | |
|         xAxis: {
 | |
|           boundaryGap: false,
 | |
|           type: "category",
 | |
|         },
 | |
|         yAxis: { gridIndex: 0 },
 | |
| 
 | |
|         series: [
 | |
|           { type: "line", smooth: true, seriesLayoutBy: "row" },
 | |
|           { type: "line", smooth: true, seriesLayoutBy: "row" },
 | |
|           { type: "line", smooth: true, seriesLayoutBy: "row" },
 | |
|         ],
 | |
|       };
 | |
| 
 | |
|       myChart2.setOption(option);
 | |
| 
 | |
|       window.onresize = function () {
 | |
|         myChart2.resize();
 | |
|       };
 | |
|     },
 | |
|     showPartyScale() {
 | |
|       let myChart = echarts.init(document.getElementById("middle-right"));
 | |
|       let legendData = [];
 | |
|       let seriesData = [];
 | |
|       if (JSON.stringify(this.numObj.reportTypeMap) != "[]") {
 | |
|         this.numObj.reportTypeMap.forEach((e) => {
 | |
|           legendData.push(
 | |
|             this.dict.getLabel("partyReportSignupReportType", e.report_type)
 | |
|           );
 | |
|           seriesData.push({
 | |
|             value: e.count,
 | |
|             name: this.dict.getLabel(
 | |
|               "partyReportSignupReportType",
 | |
|               e.report_type
 | |
|             ),
 | |
|           });
 | |
|         });
 | |
|       } else {
 | |
|         legendData = [
 | |
|           "居住地社区报到服务",
 | |
|           "单位联系社区报到服务",
 | |
|           "其他社区报到服务",
 | |
|         ];
 | |
|         seriesData = [
 | |
|           { value: 0, name: "居住地社区报到服务" },
 | |
|           { value: 0, name: "单位联系社区报到服务" },
 | |
|           { value: 0, name: "其他社区报到服务" },
 | |
|         ];
 | |
|       }
 | |
|       let option = {
 | |
|         backgroundColor: "rgba(249,249,249,1)",
 | |
| 
 | |
|         title: {
 | |
|           text: "党员报到类型比例",
 | |
|           x: "left",
 | |
|         },
 | |
| 
 | |
|         tooltip: {
 | |
|           trigger: "item",
 | |
|           formatter: "{a} <br/>{b} : {c} ({d}%)",
 | |
|         },
 | |
|         legend: {
 | |
|           orient: "vertical",
 | |
|           right: 50,
 | |
|           top: 70,
 | |
|           bottom: 20,
 | |
|           width: "auto",
 | |
|           data: legendData,
 | |
|         },
 | |
|         series: [
 | |
|           {
 | |
|             name: "党员报到类型比例",
 | |
|             type: "pie",
 | |
|             radius: ["45%", "75%"],
 | |
|             center: ["30%", "55%"],
 | |
|             avoidLabelOverlap: false,
 | |
|             label: {
 | |
|               position: "inside",
 | |
|               formatter: "{d}%",
 | |
|             },
 | |
| 
 | |
|             data: seriesData,
 | |
|             itemStyle: {
 | |
|               normal: {
 | |
|                 color: function (params) {
 | |
|                   //自定义颜色
 | |
|                   var colorList = [
 | |
|                     "#4B87FE",
 | |
|                     "#FFAA44",
 | |
|                     "#FF4466",
 | |
|                     "#FFAA44",
 | |
|                     "#2EA222",
 | |
|                   ];
 | |
|                   return colorList[params.dataIndex];
 | |
|                 },
 | |
|               },
 | |
|             },
 | |
|           },
 | |
|         ],
 | |
|       };
 | |
|       myChart.setOption(option);
 | |
|       window.onresize = function () {
 | |
|         myChart.resize();
 | |
|       };
 | |
|     },
 | |
|     getNowDate() {
 | |
|       let mydate = new Date();
 | |
|       let mymonth = mydate.getMonth() + 1;
 | |
|       mymonth < 10 ? (mymonth = `0${mymonth}`) : mymonth;
 | |
|       let year = mydate.getFullYear();
 | |
|       return `${year}-${mymonth}-01`;
 | |
|     },
 | |
| 
 | |
|     onSearch(v) {
 | |
|       this.orgTree.filter(v);
 | |
|     },
 | |
|   },
 | |
|   mounted() {
 | |
|     this.partyOrgId = this.user.info.organizationId;
 | |
|     this.dict.load("partyReportSignupReportType", "sex");
 | |
|     this.selectMonth = this.getNowDate();
 | |
|     this.searchObj.ymd = this.getNowDate();
 | |
|     this.$nextTick(() => {
 | |
|       this.month12();
 | |
|       this.typeScale();
 | |
|       this.searchList();
 | |
|     });
 | |
|   },
 | |
| };
 | |
| </script>
 | |
| 
 | |
| <style lang="scss" scoped>
 | |
| .Statistics {
 | |
|   width: 100%;
 | |
|   height: 100%;
 | |
|   padding: 16px;
 | |
|   box-sizing: border-box;
 | |
|   overflow: auto;
 | |
| 
 | |
|   .top {
 | |
|     width: 100%;
 | |
|     height: 288px;
 | |
|     background-color: #fff;
 | |
|     border-radius: 4px;
 | |
|     padding: 16px 12px;
 | |
|     box-sizing: border-box;
 | |
| 
 | |
|     header {
 | |
|       color: #333333;
 | |
|       padding: 0 16px;
 | |
|       box-sizing: border-box;
 | |
|       height: 47px;
 | |
|       font-size: 16px;
 | |
|       font-weight: bold;
 | |
|       line-height: 47px;
 | |
|       background: rgba(255, 255, 255, 1);
 | |
|       border-bottom: 1px solid #eee;
 | |
|     }
 | |
| 
 | |
|     .month {
 | |
|       width: 100%;
 | |
|       padding: 16px;
 | |
|       box-sizing: border-box;
 | |
|       height: calc(100% - 47px);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   .middle {
 | |
|     width: 100%;
 | |
|     height: 346px;
 | |
|     margin-top: 16px;
 | |
|     background-color: #fff;
 | |
|     border-radius: 4px;
 | |
|     padding: 16px 12px;
 | |
|     box-sizing: border-box;
 | |
| 
 | |
|     header {
 | |
|       padding: 0 16px;
 | |
|       box-sizing: border-box;
 | |
|       height: 48px;
 | |
|       display: flex;
 | |
|       align-items: center;
 | |
|     }
 | |
| 
 | |
|     .content {
 | |
|       width: 100%;
 | |
|       padding: 16px;
 | |
|       box-sizing: border-box;
 | |
|       height: calc(100% - 48px);
 | |
| 
 | |
|       .middle-left {
 | |
|         width: 50%;
 | |
|         height: 100%;
 | |
|         float: left;
 | |
| 
 | |
|         ul {
 | |
|           overflow: hidden;
 | |
|           width: 95%;
 | |
|           height: 100%;
 | |
|           display: flex;
 | |
|           flex-wrap: wrap;
 | |
| 
 | |
|           li {
 | |
|             width: 48%;
 | |
|             height: 112px;
 | |
|             padding: 8px;
 | |
|             box-sizing: border-box;
 | |
|             background: rgba(249, 249, 249, 1);
 | |
|             border-radius: 2px;
 | |
|             margin-bottom: 16px;
 | |
|             margin-left: 4%;
 | |
| 
 | |
|             &:nth-of-type(2n - 1) {
 | |
|               margin-left: 0;
 | |
|             }
 | |
| 
 | |
|             p {
 | |
|               color: #333333;
 | |
|               font-size: 16px;
 | |
|               height: 32px;
 | |
|               font-weight: bold;
 | |
|             }
 | |
| 
 | |
|             .num {
 | |
|               height: 80px;
 | |
|               line-height: 60px;
 | |
| 
 | |
|               span:nth-of-type(1) {
 | |
|                 color: #2266ff;
 | |
|                 font-size: 32px;
 | |
|               }
 | |
| 
 | |
|               span:nth-of-type(2) {
 | |
|                 font-size: 16px;
 | |
|                 color: rgba(153, 153, 153, 1);
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       .middle-right {
 | |
|         width: 50%;
 | |
|         height: 100%;
 | |
|         float: left;
 | |
|         padding: 4px;
 | |
|         box-sizing: border-box;
 | |
|         background: rgba(249, 249, 249, 1);
 | |
|         border-radius: 2px;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   .bottom {
 | |
|     width: 100%;
 | |
|     height: 464px;
 | |
|     margin-top: 16px;
 | |
|     background-color: #fff;
 | |
|     border-radius: 4px;
 | |
|     padding: 16px 12px;
 | |
|     box-sizing: border-box;
 | |
| 
 | |
|     header {
 | |
|       width: 100%;
 | |
|       height: 56px;
 | |
|       padding: 0 16px;
 | |
|       box-sizing: border-box;
 | |
|       border-bottom: 1px solid rgb(241, 237, 237);
 | |
|       margin-bottom: 16px;
 | |
| 
 | |
|       ul {
 | |
|         width: 100%;
 | |
|         height: 100%;
 | |
|         position: relative;
 | |
| 
 | |
|         li {
 | |
|           width: 160px;
 | |
|           height: 56px;
 | |
|           line-height: 56px;
 | |
|           float: left;
 | |
|           text-align: center;
 | |
|           font-size: 16px;
 | |
|           color: #333333;
 | |
|           position: relative;
 | |
|           transition: opacity 1s;
 | |
|           cursor: pointer;
 | |
|           opacity: 0.7;
 | |
| 
 | |
|           &:hover {
 | |
|             color: rgba(34, 102, 255, 1);
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         .activeNav {
 | |
|           opacity: 1;
 | |
|           font-weight: bold;
 | |
|           color: rgba(34, 102, 255, 1);
 | |
|         }
 | |
| 
 | |
|         span {
 | |
|           width: 160px;
 | |
|           height: 3px;
 | |
|           display: block;
 | |
|           background-color: rgba(34, 102, 255, 1);
 | |
|           transition: left 0.5s;
 | |
|           position: absolute;
 | |
|           bottom: 0;
 | |
|           left: 0;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   ::v-deep .el-col-24 {
 | |
|     width: auto;
 | |
|   }
 | |
|   ::v-deep  .ai-list__content--right-wrapper {
 | |
|     background-color: none!important;
 | |
|     padding: 0!important;
 | |
|   }
 | |
|   ::v-deep .el-tree .is-current>.el-tree-node__content {
 | |
|     min-width: 100%!important;
 | |
|   }
 | |
| }
 | |
| </style> |