Przeglądaj źródła

Merge branch 'master' into xqc_9

bding 1 rok temu
rodzic
commit
8705ed62f5

+ 3 - 2
src/api/api.js

@@ -22,7 +22,7 @@ import { departInterence, videoInterence ,InteractionInterence,enAuthInterence}
 import { dataMainInterface } from './modules/statisticApi';
 
 //crm
-import { customInterence ,equityContacts} from './modules/crmApi';
+import { customInterence ,equityContacts ,xClassCustomApi} from './modules/crmApi';
 
 //合同
 import { contractInterface } from './modules/contractApi';
@@ -114,7 +114,8 @@ export {
   businessTripInterence,
   reportVarietyENInterence,
   businessCustomInterence,
-  assistanceDocInterence
+  assistanceDocInterence,
+  xClassCustomApi
 };
 
 //老接口 研报 ppt等

+ 33 - 1
src/api/modules/crmApi.js

@@ -1275,4 +1275,36 @@ const customAllInterence = {
     },
 }
 
-export { customInterence,customAllInterence, equityContacts,etaTrialInterence};
+/* X类客户评分 */
+const xClassCustomApi = {
+  //模板 列表
+  enterScoreDetail:(params)=>{
+      return http.get("/cygx/enterScore/detail",params)
+  },
+   //添加/ 更新录分
+   enterScoreUpdate:(params)=>{
+    return http.post("/cygx/enterScore/update",params)
+  },  
+  // X试用类客户检索
+  enterScoreSearchlist:(params)=>{
+      return http.get("/cygx/enterScore/company/searchlist",params)
+  },
+  // 录分列表接口
+  enterScoreList:(params)=>{
+    return http.get("/cygx/enterScore/list",params)
+  },
+  // 录分列表接口
+  enterScoreDelete:(params)=>{
+    return http.post("/cygx/enterScore/delete",params)
+  },  
+  // 评分总览接口
+  enterScoreScoreOverview:(params)=>{
+    return http.get("/cygx/enterScore/scoreOverview",params)
+  }, 
+  // 排名总览接口
+  enterScoreRankingOverview:(params)=>{
+    return http.get("/cygx/enterScore/rankingOverview",params)
+  }, 
+}
+
+export { customInterence,customAllInterence, equityContacts,etaTrialInterence,xClassCustomApi};

+ 26 - 0
src/routes/modules/customRoutes.js

@@ -437,6 +437,32 @@ export default [
         name:"海外客户路演",
         component: () => import('@/views/custom_manage/overseasList/overseasCustomRoadshow.vue'),
         hidden: false
+      },
+      {
+        path:'XClassCustomPoints',
+        name:"X类客户派点",
+        component: () => import('@/views/custom_manage/points/XClassCustom.vue'),
+        hidden: false
+      },
+      {
+        path:'AddNewEntries',
+        name:"新增录分",
+        component: () => import('@/views/custom_manage/points/AddNewEntries.vue'),
+        hidden: false,
+        meta:{
+          pathFrom: "XClassCustomPoints",
+          pathName: "X类客户派点",
+        }
+      },
+      {
+        path:'EditNewEntries',
+        name:"查看明细",
+        component: () => import('@/views/custom_manage/points/AddNewEntries.vue'),
+        hidden: false,
+        meta:{
+          pathFrom: "XClassCustomPoints",
+          pathName: "X类客户派点",
+        }
       }
     ],
   },

+ 45 - 33
src/views/contract_manage/components/allocationNumber.vue

@@ -7,37 +7,31 @@
           <el-button style="margin-top: 20px" type="primary" size="mini" @click="averageaAllocation">平均分配</el-button>
         </div>
 
-        <p>
-          1)单行业套餐只能在对应行业内部分配研究员贡献百分比<br />
-          2)多行业套餐先在行业间分配百分比(最低不低于平均值的一半),再分配到个人<br />
-          3)允许总额20%以内的负分<br />
-          4)转正后一个季度内可以提交和修改
-          <br />
-        </p>
+        <div>
+          <p v-for="(item, index) in textualList" :key="item.text">{{ index + 1 }}{{ item.text }}</p>
+        </div>
       </div>
       <div class="content-box">
         <div v-for="item in listArr" :key="item.ChartPermissionName">
-          <div class="industry-ul">
-            <span :class="['industry-name', item.ChartPermissionId == '31' && 'name-yanxuan', item.ChartPermissionId == '52' && 'points-name']">{{ item.ChartPermissionName }}</span>
-            <template v-if="item.ChartPermissionId != '31' && item.ChartPermissionId != '52'">
-              <el-input :min="-100" :max="100" type="number" v-model="item.Proportion" size="small" @input="restrictInput(item)" style="width: 76px; margin: 0 5px 0 8px">
+          <div :class="['industry-ul', item.ChartPermissionName.includes('研选') && 'ul-yanxuan']">
+            <span :class="['industry-name', item.ChartPermissionName.includes('研选') && 'name-yanxuan']">{{ item.ChartPermissionName }}</span>
+            <template>
+              <el-input :min="-100" :max="100" type="number" v-model="item.Proportion" size="small" @input="restrictInput(item)" style="width: 80px; margin: 0 5px 0 8px">
                 <div class="per_cent_" slot="suffix">%</div>
               </el-input>
               <p style="width: 38px">{{ roundedResult(item) }}</p>
             </template>
-            <p style="width: 38px; height: 32px; line-height: 32px; text-align: center" v-else>{{ item.Money }}</p>
           </div>
-          <div v-for="study in item.List" :key="study.RealName" class="industry-ul">
-            <span :class="['study-name', item.ChartPermissionId == '31' && 'name-yanxuan', item.ChartPermissionId == '52' && 'points-name']">{{ study.RealName }}</span>
-            <template v-if="!study.RealName.includes('研选')">
+          <div v-for="study in item.List" :key="study.RealName" :class="['industry-ul', item.ChartPermissionName.includes('研选') && 'ul-yanxuan']">
+            <span :class="['study-name', item.ChartPermissionName.includes('研选') && 'name-yanxuan']">{{ study.RealName }}</span>
+            <template>
               <el-input :min="-100" :max="100" type="number" v-model="study.Proportion" size="small" style="width: 76px; margin: 0 5px 0 8px">
                 <div class="per_cent_" slot="suffix">%</div>
               </el-input>
               <p style="width: 38px">{{ roundedResult(study) }}</p>
             </template>
-            <p style="width: 38px; height: 32px; line-height: 32px; text-align: center" v-else>{{ study.Money }}</p>
           </div>
-          <div class="all-item" v-if="item.ChartPermissionId != '31' && item.ChartPermissionId != '52'">
+          <div class="all-item">
             <span> {{ allPerCentHandler(item) == 0 ? "" : `总占比:` }}</span>
             <span> {{ allPerCentHandler(item) == 0 ? "" : `${allPerCentHandler(item)}` }}</span>
           </div>
@@ -72,9 +66,32 @@ export default {
       listArr: [],
       allNum: 0,
       TotalPointsContent: "",
+      isXClass: false,
     };
   },
-  computed: {},
+  computed: {
+    textualList() {
+      let items = [
+        {
+          text: ")单行业套餐只能在对应行业内部分配研究员贡献百分比",
+        },
+        {
+          text: ")多行业套餐先在行业间分配百分比(最低不低于平均值的一半),再分配到个人",
+        },
+        {
+          text: ")允许总额20%以内的负分",
+        },
+        {
+          text: ")转正后一个季度内可以提交和修改",
+        },
+      ];
+      if (this.isXClass) {
+        return items.filter((item, index) => index == 0 || index == 3);
+      } else {
+        return items;
+      }
+    },
+  },
   watch: {
     allocationVisible: {
       handler(newVal) {
@@ -138,27 +155,19 @@ export default {
       if (res.Ret === 200) {
         this.allNum = res.Data.Money;
         this.listArr = res.Data.List;
+        this.isXClass = res.Data.IsXClass;
         this.TotalPointsContent = res.Data.TotalPointsContent;
       }
     },
     // 平均分配
     averageaAllocation() {
-      let isName = [];
-      this.listArr.forEach((item) => {
-        if (!item.ChartPermissionName.includes("研选")) {
-          isName.push(true);
-        }
-      });
-      let num = 100 / isName.length;
+      let num = (100 / this.listArr.length).toFixed(2);
+      console.log(num);
       this.listArr.forEach((item) => {
-        if (item.ChartPermissionName != "研选订阅" && item.ChartPermissionName != "研选扣点包") {
-          item.Proportion = num;
-        }
-        let childrenNum = num / item.List.length;
+        item.Proportion = num;
+        let childrenNum = (num / item.List.length).toFixed(2);
         item.List.forEach((key) => {
-          if (key.RealName != "研选订阅" && key.RealName != "研选扣点包") {
-            key.Proportion = childrenNum;
-          }
+          key.Proportion = childrenNum;
         });
       });
     },
@@ -181,7 +190,7 @@ export default {
       display: flex;
       align-items: center;
       margin: 30px 0;
-      width: 180px;
+      width: 188px;
       color: #333;
       margin-right: 25px;
       .per_cent_ {
@@ -224,6 +233,9 @@ export default {
   .points-name {
     width: 80px !important;
   }
+  .ul-yanxuan {
+    width: 220px !important;
+  }
   /* 取消[type='number']的input的上下箭头 */
   input::-webkit-inner-spin-button {
     -webkit-appearance: none !important;

+ 9 - 1
src/views/custom_manage/approvalTurn.vue

@@ -14,7 +14,7 @@
 							<span>合同类型: {{contractInfo.ContractType}}</span>
 						</li>
 						<li>
-							<span style="min-width:450px;marginRight:260px;display:inline-block;">合同期限:{{contractInfo.StartDate}}-{{contractInfo.EndDate}}({{contractInfo.StartDate|formateYear(contractInfo.EndDate)}})</span>
+							<span style="min-width:450px;marginRight:260px;display:inline-block;">合同期限:{{ContractTermTxt}}</span>
 							<span>合同金额:{{contractInfo.Money}}元</span>
 						</li>
 						<li>
@@ -267,6 +267,14 @@ export default {
 		}
 		this.getCompanyInfo()
 	},
+	computed:{
+		ContractTermTxt(){
+			let date = `${this.contractInfo.StartDate}-${this.contractInfo.EndDate}`;
+			let calculation = CalculationDate(this.contractInfo.StartDate,this.contractInfo.EndDate);
+			let str = this.contractInfo.Quarter ? this.contractInfo.Quarter + `(${date})` : date + `(${calculation})`;
+			return str
+		}
+	},
 }
 </script>
 <style lang='scss'>

+ 1 - 1
src/views/custom_manage/approvalUpdate.vue

@@ -12,7 +12,7 @@
 						<span>合同类型:{{contractInfo.ContractType}}</span><span class="contract_type_hint">{{contractInfo.SourceTag}}</span>
 					</li>
 					<li>
-						<span style="min-width:320px;marginRight:260px;display:inline-block;">合同期限:{{contractInfo.StartDate}}-{{contractInfo.EndDate}}({{diff_time}}年期)</span>
+						<span style="min-width:320px;marginRight:260px;display:inline-block;">合同期限:{{contractInfo.Quarter}}{{contractInfo.StartDate}}-{{contractInfo.EndDate}}({{diff_time}}年期)</span>
 						<span>合同金额:{{contractInfo.Money}}元</span>
 					</li>
 					<li>

+ 42 - 13
src/views/custom_manage/customList/applyTurn.vue

@@ -66,7 +66,7 @@
 									<i class="el-icon-info"></i>
 							</el-tooltip>
 						</el-form-item>
-						<el-form-item label="合同期限" prop="term" style="marginRight:60px;">
+						<el-form-item label="合同期限" prop="term" style="marginRight:60px;" :rules="{ required: true, message: '合同期限不能为空', trigger: 'blur' }" v-if="!isXClassCustom">
 							<i style="color:#f00;fontSize:20px;position:absolute;left:-90px;top:10%;">*</i>
 							<el-date-picker
 							v-model="formData.term"
@@ -79,6 +79,19 @@
 							style="width:400px;">
 							</el-date-picker>
 						</el-form-item>
+						<el-form-item label="合同期限" prop="term" :rules="{ required: true, message: '合同期限不能为空', trigger: 'change' }" style="marginRight:60px;" v-if="isXClassCustom">
+							<i style="color:#f00;fontSize:20px;position:absolute;left:-90px;top:10%;">*</i>
+							<div class="quarters-content">
+								<el-checkbox-group v-model="selectedQuarters" @input="checkboxInputHandler">
+									<el-checkbox v-for="quarter in quarters" :key="quarter.value" :label="quarter.label" :disabled="isDisabled(quarter)" >
+										{{ quarter.label }}
+									</el-checkbox>
+								</el-checkbox-group>
+								<div v-if="selectedQuarters.length > 0" class="quarters-text">
+										{{ selectedDateRange }}
+								</div>
+							</div>
+						</el-form-item>
 						<el-form-item label="合同金额" prop="amount" style="marginRight:60px;">
 							<i style="color:#f00;fontSize:20px;position:absolute;left:-90px;top:10%;">*</i>
 							<el-input 
@@ -119,13 +132,13 @@
 								<i style="color:#f00;fontSize:20px;position:absolute;left:-15px;top:10%;">*</i>
 								权限设置
 							</label>
-							<template  v-if="companyInfo.CompanyType=='权益' ||isRoleType== '权益'">
+							<template  v-if="(companyInfo.CompanyType=='权益' || isRoleType== '权益') && !isXClassCustom" >
 								<raiPermissionbox ref="raiPermissionboxRef" v-for="item in authList" :key="item.ClassifyName" :data="item" :formData="formData"
 								:hasNoChild="hasNoChild"></raiPermissionbox>
 							</template>
 							<ul class="menu_lists" style="width:100%" v-else>
 								<li v-for="item in authList" :key="item.ClassifyName" class="menu_item">
-									<el-checkbox v-if="item.ClassifyName !== '权益'" :indeterminate="item.isIndeterminate" v-model="item.checkAll" :disabled="setSelectVarietyDisabled(item)" @change="handleCheckAll(item)" style="marginRight:30px;fontWeight:bold;minWidth:90px;">{{item.ClassifyName+':'}}</el-checkbox>
+									<el-checkbox  :indeterminate="item.isIndeterminate" v-model="item.checkAll" :disabled="setSelectVarietyDisabled(item)" @change="handleCheckAll(item)" style="marginRight:30px;fontWeight:bold;minWidth:90px;">{{item.ClassifyName+':'}}</el-checkbox>
 									<el-checkbox-group v-model="item.CheckList" @change="handleChecked(item)">
 										<el-checkbox v-for="list in item.Items" :label="list.ChartPermissionId" :key="list.ChartPermissionId" class="list_item" :disabled="list.IsPublic==1  || list.disabled">{{list.PermissionName}}</el-checkbox>
 									</el-checkbox-group>
@@ -179,10 +192,16 @@ import pdf from 'vue-pdf'
 import {CalculationDate} from '@/utils/CalculationDate'
 import JurisdictionCheck from '../compontents/jurisdictionCheck.vue';
 import raiPermissionbox from './components/raiPermissionbox'
-
+import quartersMixin from './mixins/quartersMixin'
 export default {
 	name:'',
+	mixins:[quartersMixin],
 	components: {imgPreview,pdf ,JurisdictionCheck,raiPermissionbox},
+	computed:{
+		isXClassCustom(){
+			return	this.companyInfo.Status.includes('永续') || this.companyInfo.Status.includes('X类试用')
+		}
+	},
 	data () {
 		return {
 			companyInfo:JSON.parse(sessionStorage.getItem('companyInfo')) || {},//客户基本信息
@@ -200,9 +219,6 @@ export default {
 			hasNoChild:false, // 医药、消费、科技、智造是否没有主客观
 			authList:[],//权限列表
 			formRule:{
-				term:[
-					{ required: true, message: '合同期限不能为空', trigger: 'blur' },
-				],
 				amount:[
 					{ required: true, message: '合同金额不能为空', trigger: 'blur' },
 					{ type: 'number', message: '合同金额必须为数字'}
@@ -254,9 +270,10 @@ export default {
 						setmeal:res.Data.Item.PackageType,
 						qyBigServeCheck:res.Data.Item.RaiPackageType
 					}
+					this.selectedQuarters = res.Data.Item.Quarter.split(',')
 					let newArr = [];
 					/* 处理权限列表 */
-					if(this.companyInfo.CompanyType == '权益' || this.isRoleType== '权益') {
+					if((this.companyInfo.CompanyType == '权益' || this.isRoleType== '权益') && !this.isXClassCustom ) {
 						res.Data.Item.PermissionList[0].Items.map(item => {
 							item.disabled=item.isIndeterminate=false								
 							if(item.ChartPermissionId==22 && (!item.Child)) this.hasNoChild=true
@@ -295,11 +312,12 @@ export default {
 		/* 获取基本权限信息 */
 		getAuthBasic() {
 			customInterence.authList({
-				IsShowYanXuanKouDian:true
+				IsShowYanXuanKouDian:true,
+				CompanyStatus:this.companyInfo.Status 
 			}).then(res => {
 				let newArr = [];
 				if(res.Ret === 200) {
-					if(this.companyInfo.CompanyType == '权益' || this.isRoleType== '权益') {
+					if((this.companyInfo.CompanyType == '权益' || this.isRoleType== '权益') && !this.isXClassCustom) {
 						res.Data.List[0].Items.map(item => {
 							item.disabled=item.isIndeterminate=false								
 							if(item.ChartPermissionId==22 && (!item.Child)) this.hasNoChild=true
@@ -355,7 +373,7 @@ export default {
 					let checkArr = [];
 					let checkArrName = [];
 					let hasMinusSignVal = 0
-					if(this.companyInfo.CompanyType==='权益' || this.isRoleType== '权益'){
+					if((this.companyInfo.CompanyType==='权益' || this.isRoleType== '权益') && !this.isXClassCustom){
 					 	hasMinusSignVal = this.$refs.raiPermissionboxRef[0].minus_sign_val;		
 						this.authList.forEach(item => {
 								if(item.CheckList.length) {
@@ -578,7 +596,10 @@ export default {
 				})
 				this.$message.warning('请勾选品种')
 			}
-		}
+		},
+	checkboxInputHandler(){
+		this.formData.term = this.selectedQuarters ? [this.selectedDateRange.split(" ~ ")[0],this.selectedDateRange.split(" ~ ")[1]]:[]
+	}
 	
 	},
 	created() {},
@@ -673,6 +694,14 @@ export default {
 			}
 		}
 	}
-
+	.quarters-content {
+		position: relative;
+		.quarters-text {
+			position: absolute;
+			left: 0;
+			top: 20px;
+			color: #f00;
+		}
+	}
 }
 </style>

+ 1 - 2
src/views/custom_manage/customList/components/raiPermissionbox.vue

@@ -51,7 +51,7 @@
             </el-checkbox>
           </div>
         </el-checkbox-group>
-        <div class="rai-checkbox-notice-box">
+        <div class="rai-checkbox-notice-box" v-if="data.ItemsUp.length>0">
           <span class="rai-checkbox-notice" v-if="formData.qyBigServeCheck">
             同时包含{{formData.qyBigServeCheck==2?"10":"16"}}次专项调研</span>
           <p class="rai-checkbox-notice" v-if="equityGroupDisabled(data.CheckList)">同时包含升级行业各5次专项调研</p>
@@ -85,7 +85,6 @@
       }
     },
     created(){
-      console.log(this.data);
       // 回显
       if(this.data.CheckList && this.data.CheckList.length>0){
         this.data.Items.map(item =>{

+ 98 - 0
src/views/custom_manage/customList/mixins/quartersMixin.js

@@ -0,0 +1,98 @@
+export default {
+  data() {
+    return {
+      selectedQuarters: [],
+      quarters: this.generateQuarters(),
+      showAlert: true,
+    };
+  },
+  computed: {
+    selectedDateRange() {
+      if (this.selectedQuarters.length) {
+        const sortedQuarters = [...this.selectedQuarters].sort();
+        const startDate = this.quarterToDateRange(sortedQuarters[0]).split(" ~ ")[0];
+        const endDate = this.quarterToDateRange(sortedQuarters[this.selectedQuarters.length - 1]).split(" ~ ")[1];
+        return `${startDate} ~ ${endDate}`;
+      }
+      return "";
+    },
+  },
+  methods: {
+    generateQuarters() {
+      const currentDate = new Date();
+      const currentYear = currentDate.getFullYear();
+      let currentQuarter = Math.floor(currentDate.getMonth() / 3) + 1;
+
+      let quarters = [];
+
+      for (let i = 3; i >= 0; i--) {
+        // 包括当前季度和前三个季度
+        let year = currentYear;
+        let quarter = currentQuarter - i;
+
+        while (quarter <= 0) {
+          year--; // 上一年
+          quarter += 4; // 季度数增加
+        }
+
+        quarters.push({
+          label: `${year}Q${quarter}`,
+          value: `${year}Q${quarter}`,
+        });
+      }
+
+      return quarters;
+    },
+
+    isDisabled(quarter) {
+      if (this.selectedQuarters.length === 0) return false;
+      const sortedSelected = [...this.selectedQuarters].sort();
+      const firstIndex = this.quarters.findIndex((q) => q.value === sortedSelected[0]);
+      const lastIndex = this.quarters.findIndex((q) => q.value === sortedSelected[sortedSelected.length - 1]);
+
+      const currentIndex = this.quarters.findIndex((q) => q.value === quarter.value);
+
+      return currentIndex < firstIndex - 1 || currentIndex > lastIndex + 1;
+    },
+
+    quarterToDateRange(quarterLabel) {
+      const [year, q] = quarterLabel.split("Q");
+
+      switch (parseInt(q)) {
+        case 1:
+          return `${year}-01-01 ~ ${year}-03-31`;
+        case 2:
+          return `${year}-04-01 ~ ${year}-06-30`;
+        case 3:
+          return `${year}-07-01 ~ ${year}-09-30`;
+        case 4:
+          return `${year}-10-01 ~ ${year}-12-31`;
+      }
+    },
+    isConsecutiveSelection() {
+      const sortedSelectedIndexes = this.selectedQuarters.map((sq) => this.quarters.findIndex((aq) => aq.value === sq)).sort((a, b) => a - b);
+      for (let i = 0; i < sortedSelectedIndexes.length - 1; i++) {
+        if (sortedSelectedIndexes[i + 1] - sortedSelectedIndexes[i] !== 1) {
+          return false;
+        }
+      }
+
+      return true;
+    },
+  },
+
+  watch: {
+    selectedQuarters(newValue, oldValue) {
+      if (!newValue.length) return;
+      if (!this.isConsecutiveSelection() && this.showAlert) {
+        this.showAlert = false;
+        this.selectedQuarters.pop();
+        this.$message.error("只能选择相邻的季度");
+        this.$nextTick(() => {
+          this.selectedQuarters.pop();
+          this.showAlert = true;
+        });
+      }
+    },
+  },
+};

+ 437 - 0
src/views/custom_manage/points/AddNewEntries.vue

@@ -0,0 +1,437 @@
+<template>
+  <div class="container add-new-entries">
+    <div class="container-top">
+      <span>客户名称</span>
+      <el-autocomplete v-model="companyName" :fetch-suggestions="querySearchAsync" style="width: 220px; margin: 0 20px" @select="selectCompanyChange" placeholder="请输入客户名称"></el-autocomplete>
+
+      <div class="quarters-content">
+        <el-checkbox-group v-model="selectedQuarters">
+          <el-checkbox v-for="quarter in quarters" :key="quarter.value" :label="quarter.label" :disabled="isDisabled(quarter)">
+            {{ quarter.label }}
+          </el-checkbox>
+        </el-checkbox-group>
+      </div>
+    </div>
+    <div v-if="Object.keys(EnterScoreObj).length > 0">
+      <div class="tabs-box">
+        <span v-for="item in listTitle" :key="item.value" @click="tabsBoxBtn(item)" :class="item.value == tabsPitchon ? 'pitch' : ''">{{ item.lable }}</span>
+      </div>
+      <template>
+        <p class="class-text">
+          权益研究员 <span style="font-weight: 600">{{ allPerCentNumble(raiDataHandler(), "rai") }}</span>
+          <span v-if="tabsPitchon == 2 && allPerCentNumble(raiDataHandler(), 'rai')">%</span>
+        </p>
+        <div class="content-box">
+          <div v-for="item in raiDataHandler()" :key="item.EnterScoreId">
+            <div :class="['industry-ul']">
+              <span :class="['industry-name']">{{ item.ChartPermissionName }}</span>
+              <span style="margin: 0 5px 0 8px; font-weight: 600">{{ allPerCentHandlerRai(item) }}</span>
+              <span v-if="tabsPitchon == 2 && item.Proportion">%</span>
+            </div>
+            <div v-for="study in item.List" :key="study.RealName" :class="['industry-ul']">
+              <span :class="['study-name']">{{ study.RealName }}</span>
+              <template>
+                <el-input :min="-100" :max="100" type="number" v-model="study.Proportion" size="small" @input="formatDecimal(study)" style="width: 76px; margin: 0 5px 0 8px"> </el-input>
+              </template>
+              <span v-if="tabsPitchon == 2">%</span>
+            </div>
+          </div>
+        </div>
+      </template>
+      <template>
+        <p class="class-text">
+          FICC研究员 <span style="font-weight: 600">{{ allPerCentNumble(FICCDataHandler(), "ficc") }}</span>
+          <span v-if="tabsPitchon == 2 && allPerCentNumble(FICCDataHandler(), 'ficc')">%</span>
+        </p>
+        <div class="content-box">
+          <div v-for="item in FICCDataHandler()" :key="item.EnterScoreId">
+            <div :class="['industry-ul']">
+              <span :class="['industry-name']">{{ item.ChartPermissionName }}</span>
+              <span style="margin: 0 5px 0 8px; font-weight: 600">{{ allPerCentHandlerFICC(item) }}</span>
+              <span v-if="tabsPitchon == 2 && item.Proportion">%</span>
+            </div>
+            <div v-for="study in item.List" :key="study.RealName" :class="['industry-ul']">
+              <span :class="['study-name']">{{ study.RealName }}</span>
+              <template>
+                <el-input :min="-100" :max="100" type="number" v-model="study.Proportion" size="small" @input="formatDecimal(study)" style="width: 76px; margin: 0 5px 0 8px"> </el-input>
+              </template>
+              <span v-if="tabsPitchon == 2">%</span>
+            </div>
+          </div>
+        </div>
+      </template>
+      <div class="division-line"></div>
+      <div class="content-box">
+        <div v-for="item in ProuDataHandler()" :key="item.GroupName">
+          <div :class="['industry-ul']">
+            <span :class="['industry-name']">{{ item.GroupName }}</span>
+            <el-input :min="-100" :max="100" type="number" v-model="item.Proportion" @input="formatDecimal(item)" size="small" style="width: 76px; margin: 0 5px 0 8px"> </el-input>
+            <span v-if="tabsPitchon == 2">%</span>
+          </div>
+        </div>
+      </div>
+      <div class="division-line"></div>
+      <div class="bottom-box">
+        排名
+        <el-input type="text" v-model="rankingValue" style="width: 110px; margin: 0 50px 0 8px" placeholder="请输入排名"> </el-input>
+        合并打分
+        <el-radio-group v-model="radioScoring" style="margin: 0 60px 0 8px">
+          <el-radio :label="0">否</el-radio>
+          <el-radio :label="1">是</el-radio>
+        </el-radio-group>
+        <template v-if="radioScoring == 1">
+          券商名称
+          <el-input type="text" v-model="brokerName" placeholder="请输入合并打分的券商名称" style="width: 230px; margin: 0 50px 0 8px"> </el-input>
+          合并占比
+          <el-input type="text" v-model="mergeProportion" placeholder="占比值" style="width: 76px; margin: 0 5px 0 8px"> </el-input>%
+        </template>
+      </div>
+      <p class="total-num" v-if="Object.keys(EnterScoreObj).length > 0">
+        当前合计总分:{{ TotalScoreHandler(ProuDataHandler()) }}
+        <span v-if="tabsPitchon == 2">%</span>
+      </p>
+      <div style="display: flex; justify-content: center">
+        <el-button type="primary" style="margin-right: 20px" @click="preserveHandler">{{ $route.query.id ? "修改并保存" : "保存" }}</el-button>
+        <el-button type="primary" plain @click="goBackHandler">取消</el-button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import quartersMixin from "../customList/mixins/quartersMixin";
+import { xClassCustomApi, raiInterface } from "@/api/api.js";
+
+export default {
+  name: "",
+  components: {},
+  mixins: [quartersMixin],
+  props: {},
+  data() {
+    return {
+      listTitle: [
+        {
+          lable: "按评分录入",
+          value: 1,
+        },
+        {
+          lable: "按比例录入",
+          value: 2,
+        },
+      ],
+      tabsPitchon: 1, //tabs 默认选中
+      tmeplateObj: {},
+      EnterScoreObj: {},
+      PercentageObj: {},
+      rankingValue: "", // 排名
+      radioScoring: 0, // 合并打分
+      brokerName: "", //券商名称
+      mergeProportion: "",
+      querySearchList: [],
+      companyName: "",
+      companyId: 0,
+      totalScoreNumber: 0,
+    };
+  },
+  computed: {},
+  watch: {
+    companyName: {
+      handler(newVal) {
+        if (!this.companyName) {
+          this.companyId = 0;
+        }
+      },
+    },
+  },
+  created() {},
+  mounted() {
+    this.$route.query.id ? this.getCompanyDetail() : this.getDataTemplate();
+  },
+  methods: {
+    // 头部的点击事件
+    tabsBoxBtn(item) {
+      if (this.tabsPitchon == item.value) return;
+      this.tabsPitchon = item.value;
+      this.raiDataHandler();
+      this.FICCDataHandler();
+      this.ProuDataHandler();
+    },
+
+    /** */
+    /** */
+    allPerCentHandlerRai(item) {
+      return this.allPerCentHandler(item);
+    },
+    allPerCentHandlerFICC(item) {
+      return this.allPerCentHandler(item);
+    },
+    //数量的总和
+    allPerCentHandler(item) {
+      let num = 0;
+      item && item.List.forEach((key) => (num = num + +key.Proportion));
+      item.Proportion = Number(num.toFixed(2));
+      return num == 0 ? "" : num.toFixed(2);
+    },
+    /** */
+    /** */
+
+    // 处理小数点
+    formatDecimal(key) {
+      let value = key.Proportion;
+      if (value === "") return; // 如果为空则不处理
+      // 先清除非数字和多余的小数点
+      value = value
+        .replace(/[^\d.]/g, "")
+        .replace(/\.{2,}/g, ".")
+        .replace(".", "$#$")
+        .replace(/\./g, "")
+        .replace("$#$", ".");
+
+      // 限制只能输入两位小数
+      const decimalRegex = /^(\d+\.?\d{0,2})/;
+      const match = value.match(decimalRegex);
+
+      if (match) {
+        key.Proportion = match[1];
+        this.restrictInput(key);
+      } else {
+        key.Proportion = 0; // 如果不匹配正则,则清空输入框
+      }
+    },
+    // 输入框的限制
+    restrictInput(item) {
+      if (item.Proportion) if (item.Proportion > 100) return (item.Proportion = 100);
+      if (item.Proportion < -100) return (item.Proportion = -100);
+    },
+    // 切换了录入 权益
+    raiDataHandler() {
+      return this.tabsPitchon == 1 ? this.EnterScoreObj.ListRai : this.PercentageObj.ListRai;
+    },
+    // 切换了录入 FICC
+    FICCDataHandler() {
+      return this.tabsPitchon == 1 ? this.EnterScoreObj.ListFicc : this.PercentageObj.ListFicc;
+    },
+    // 切换了录入 分组
+    ProuDataHandler() {
+      return this.tabsPitchon == 1 ? this.EnterScoreObj.ListGroup : this.PercentageObj.ListGroup;
+    },
+
+    /** */
+    /** */
+    // 总和
+    allPerCentNumble(item, type) {
+      let num = 0;
+      item.forEach((item) => (num += item.Proportion));
+      type === "rai" ? (this.tmeplateObj.RaiProportionTotal = Number(num.toFixed(2))) : (this.tmeplateObj.FiccProportionTotal = Number(num.toFixed(2)));
+      return num == 0 ? "" : num.toFixed(2);
+    },
+    TotalScoreHandler(item) {
+      let num = 0;
+      item && item.forEach((item) => (num += Number(item.Proportion)));
+      this.totalScoreNumber = Number((num + this.tmeplateObj.RaiProportionTotal + this.tmeplateObj.FiccProportionTotal).toFixed(2));
+      return this.totalScoreNumber;
+    },
+    /** */
+    /** */
+
+    // 获取模板
+    async getDataTemplate() {
+      const res = await xClassCustomApi.enterScoreDetail();
+      if (res.Ret === 200) {
+        this.tmeplateObj = res.Data;
+        this.EnterScoreObj = res.Data.EnterScoreObj;
+        this.PercentageObj = res.Data.PercentageObj;
+      }
+    },
+
+    // 保存
+    async preserveHandler() {
+      let StartDate = this.selectedDateRange ? this.selectedDateRange.split(" ~ ")[0] : "";
+      let EndDate = this.selectedDateRange ? this.selectedDateRange.split(" ~ ")[1] : "";
+      let ListGroup = this.ProuDataHandler().map((item) => {
+        return {
+          ...item,
+          Proportion: Number(item.Proportion),
+        };
+      });
+      let ListRai = this.raiDataHandler().map((item) => ({
+        ...item,
+        List: item.List.map((subItem) => ({
+          ...subItem,
+          Proportion: Number(subItem.Proportion),
+        })),
+      }));
+      let ListFicc = this.FICCDataHandler().map((item) => ({
+        ...item,
+        List: item.List.map((subItem) => ({
+          ...subItem,
+          Proportion: Number(subItem.Proportion),
+        })),
+      }));
+      let params = {
+        EnterScoreId: this.$route.query.id ? +this.$route.query.id : 0, //录分ID,等于0新增,大于0 修改
+        CompanyId: this.companyId,
+        CompanyName: this.companyName,
+        Quarter: this.selectedQuarters,
+        StartDate,
+        EndDate,
+        EnterScoreType: this.tabsPitchon,
+        RaiProportionTotal: this.tmeplateObj.RaiProportionTotal,
+        FiccProportionTotal: this.tmeplateObj.FiccProportionTotal,
+        ListRai,
+        ListFicc,
+        ListGroup,
+        Ranking: this.rankingValue,
+        IsMergeScoring: this.radioScoring,
+        SecuritiesFirmsName: this.brokerName,
+        MergeProportion: this.mergeProportion ? +this.mergeProportion : 0,
+        ProportionTotal: this.totalScoreNumber,
+      };
+      if (!params.CompanyName || !params.CompanyId) return this.$message.error("请输入客户名称");
+      if (!params.Quarter.length) return this.$message.error("请选择季度");
+      const res = await xClassCustomApi.enterScoreUpdate(params);
+      if (res.Ret === 200) {
+        this.$message.success(res.Msg);
+        this.$router.back();
+      }
+    },
+    //  获取详情
+    async getCompanyDetail() {
+      const res = await xClassCustomApi.enterScoreDetail({
+        EnterScoreId: +this.$route.query.id,
+      });
+      if (res.Ret === 200) {
+        this.tmeplateObj = res.Data;
+        this.EnterScoreObj = res.Data.EnterScoreObj;
+        this.PercentageObj = res.Data.PercentageObj;
+        this.rankingValue = res.Data.Ranking;
+        this.radioScoring = res.Data.IsMergeScoring;
+        this.brokerName = res.Data.SecuritiesFirmsName;
+        this.mergeProportion = res.Data.MergeProportion;
+        this.selectedQuarters = res.Data.Quarter;
+        this.companyId = res.Data.CompanyId;
+        this.companyName = res.Data.CompanyName;
+        this.tabsPitchon = res.Data.EnterScoreType;
+      }
+    },
+    //
+    async querySearchAsync(query, cb) {
+      cb([]);
+      if (query) {
+        const res = await xClassCustomApi.enterScoreSearchlist({ KeyWord: query });
+        if (res.Ret === 200) {
+          this.querySearchList = res.Data.List.map((_) => {
+            return {
+              ..._,
+              value: _.CompanyName,
+            };
+          });
+          cb(this.querySearchList);
+        }
+      }
+    },
+    // 选择后客户名称的id
+    selectCompanyChange(value) {
+      this.companyId = value.CompanyId;
+    },
+    // 返回事件
+    goBackHandler() {
+      this.$router.back();
+    },
+  },
+};
+</script>
+<style scoped lang="scss">
+.add-new-entries {
+  .container-top {
+    display: flex;
+    align-items: center;
+  }
+  .class-text {
+    margin-top: 20px;
+    width: 100%;
+    height: 38px;
+    line-height: 32px;
+    padding-left: 20px;
+    background-color: #ebeef5;
+  }
+  .tabs-box {
+    margin-top: 20px;
+    span {
+      display: inline-block;
+      padding: 9px 24px;
+      background-color: #e9f4ff;
+      border: 1px solid #b3d8ff;
+      border-radius: 4px;
+      margin-right: 30px;
+      color: #409eff;
+      cursor: pointer;
+    }
+    .pitch {
+      background-color: #409eff;
+      border: none;
+      color: #fff;
+    }
+  }
+  .content-box {
+    width: 100%;
+    overflow: hidden;
+    overflow-x: auto;
+    display: flex;
+    .industry-ul {
+      display: flex;
+      align-items: center;
+      margin: 10px 0;
+      width: 188px;
+      color: #333;
+      margin-right: 25px;
+      .per_cent_ {
+        line-height: 32px;
+      }
+      .industry-name {
+        flex-shrink: 0;
+        font-weight: 800;
+        font-size: 16px;
+        line-height: 22px;
+      }
+      .study-name {
+        width: 58px;
+        flex-shrink: 0;
+        font-size: 14px;
+        line-height: 22px;
+      }
+      p {
+        color: #9999;
+        font-size: 14px;
+      }
+    }
+  }
+  .division-line {
+    width: 100%;
+    border: 1px dashed #dcdfe6;
+    margin: 30px 0 20px;
+  }
+  .bottom-box {
+    display: flex;
+    align-items: center;
+  }
+
+  .total-num {
+    margin: 30px 0 20px 0;
+    padding-left: 460px;
+  }
+}
+</style>
+<style>
+/* 针对于 Chrome、Safari 等 Webkit 内核浏览器 */
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+  -webkit-appearance: none;
+  margin: 0;
+}
+
+/* 针对 Firefox 浏览器 */
+input[type="number"] {
+  -moz-appearance: textfield;
+}
+</style>

+ 231 - 0
src/views/custom_manage/points/EntryRecords.vue

@@ -0,0 +1,231 @@
+<template>
+  <div class="container entry-records-points">
+    <div>
+      <el-autocomplete
+        v-model="companyName"
+        :fetch-suggestions="querySearchAsync"
+        style="width: 220px; margin-right: 20px"
+        @select="selectCompanyChange"
+        clearable
+        placeholder="请输入公司名称"
+        @clear="clearCompanyHandleSearch"
+      >
+        <i slot="prefix" class="el-input__icon el-icon-search"></i>
+      </el-autocomplete>
+      <el-cascader
+        v-model="sales"
+        placeholder="请选择销售"
+        style="width: 200px; margin-right: 20px"
+        :options="salesArr"
+        :props="defaultSalesProps"
+        :show-all-levels="false"
+        collapse-tags
+        clearable
+        filterable
+        @change="companyHandleSearch"
+      >
+      </el-cascader>
+      <el-button type="primary" @click="$router.push('AddNewEntries')"> 新增</el-button>
+      <a :href="exportUser" download>
+        <el-button type="primary" style="width: 80px;margin-left:15px">导出</el-button>
+      </a>
+    </div>
+
+    <div style="margin-top: 20px">
+      <el-table :data="tableData" style="width: 100%" border>
+        <el-table-column align="center" prop="CompanyName" label="客户名称"> </el-table-column>
+        <el-table-column align="center" prop="SellerName" label="销售" width="100"> </el-table-column>
+        <el-table-column align="center" prop="Quarter" label="季度" width="180">
+          <template slot-scope="{ row }">
+            <span>{{ row.Quarter.join(",") }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column align="center" prop="ProportionTotal" label="总分" width="100">
+          <template slot-scope="{ row }">
+            <span>{{ row.ProportionTotal }}{{ row.EnterScoreType == 2 ? "%" : "" }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column align="center" prop="Ranking" label="排名" width="100"> </el-table-column>
+        <el-table-column align="center" prop="IsMergeScoring" label="合并打分" width="80">
+          <template slot-scope="{ row }">
+            <span>{{ row.IsMergeScoring == 1 ? "是" : "否" }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column align="center" prop="SecuritiesFirmsName" label="券商名称"> </el-table-column>
+        <el-table-column align="center" prop="CreateTime" label="首次录入时间" width="180"> </el-table-column>
+        <el-table-column align="center" prop="ModifyTime" label="最近更新时间" width="180"> </el-table-column>
+        <el-table-column align="center" prop="name" label="操作" width="180">
+          <template slot-scope="{ row }">
+            <span class="editsty" @click="lookHandler(row)">查看明细</span>
+            <span class="deletesty" @click="deleteHandle(row)">删除</span>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+  </div>
+</template>
+
+<script>
+import { customInterence, xClassCustomApi } from "@/api/api.js";
+export default {
+  name: "EntryRecords",
+  props: {
+    searchVal: {
+      type: String,
+      default: "",
+    },
+  },
+  computed: {
+    exportUser() {
+      let baseUrl = process.env.API_ROOT + "/cygx/enterScore/list";
+      let token = localStorage.getItem("auth") || "";
+      let salesArr = [];
+      if (this.sales.length) {
+        salesArr = this.sales.map((item) => {
+          return item[item.length - 1];
+        });
+      }
+      let paramStr = "";
+      let params = {
+        PageSize: this.pageSize,
+        CurrentIndex: this.page_no,
+        KeyWord: this.companyName,
+        AdminId: salesArr.join(","),
+        IsExport: true,
+      };
+      for (let key in params) {
+        paramStr = `${paramStr}&${key}=${params[key]}`;
+      }
+      return `${baseUrl}?${token}${paramStr}`;
+    },
+  },
+  data() {
+    return {
+      page_no: 1,
+      pageSize: 10,
+      total: 1,
+      tableData: [],
+      companyName: "",
+      sales: "",
+      salesArr: [], //销售
+      defaultSalesProps: {
+        multiple: true,
+        label: "RealName",
+        children: "ChildrenList",
+        value: "AdminId",
+      }, //销售级联配置
+    };
+  },
+  watch: {
+    searchVal() {
+      this.getDataList();
+    },
+  },
+  mounted() {
+    this.getSale();
+    this.getDataList();
+  },
+  methods: {
+    // 公司名称
+    companyHandleSearch(value) {
+      this.page_no = 1;
+      this.getDataList();
+    },
+    /* 获取销售 */
+    getSale() {
+      let status = 0;
+      if (this.act_status == "流失") {
+        status = 1;
+      }
+      customInterence.getSale({ Status: status }).then((res) => {
+        if (res.Ret === 200) {
+          this.salesArr = res.Data.List;
+        }
+      });
+    },
+    // 获取列表信息
+    async getDataList() {
+      let salesArr = [];
+      if (this.sales.length) {
+        salesArr = this.sales.map((item) => {
+          return item[item.length - 1];
+        });
+      }
+      const res = await xClassCustomApi.enterScoreList({
+        PageSize: this.pageSize,
+        CurrentIndex: this.page_no,
+        KeyWord: this.companyName,
+        AdminId: salesArr.join(","),
+      });
+      if (res.Ret === 200) {
+        this.total = res.Data.Paging.Totals;
+        this.tableData = res.Data.List;
+      }
+    },
+    // 删除
+    deleteHandle(item) {
+      this.$confirm("是否删除?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(async () => {
+          const res = await xClassCustomApi.enterScoreDelete({
+            EnterScoreId: item.EnterScoreId,
+          });
+          if (res.Ret === 200) {
+            this.$message({
+              type: "success",
+              message: "删除成功!",
+            });
+            this.getDataList();
+          }
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除",
+          });
+        });
+    },
+    // 查看
+    lookHandler(item) {
+      this.$router.push({
+        path: "/EditNewEntries",
+        query: { id: item.EnterScoreId },
+      });
+    },
+    //
+    async querySearchAsync(query, cb) {
+      cb([]);
+      if (query) {
+        const res = await xClassCustomApi.enterScoreSearchlist({ KeyWord: query });
+        if (res.Ret === 200) {
+          this.querySearchList = res.Data.List.map((_) => {
+            return {
+              ..._,
+              value: _.CompanyName,
+            };
+          });
+          cb(this.querySearchList);
+        }
+      }
+    },
+    // 选择后客户名称的id
+    selectCompanyChange(value) {
+      this.companyId = value.CompanyId;
+      this.page_no = 1;
+      this.getDataList();
+    },
+    clearCompanyHandleSearch() {
+      this.companyId = "";
+      this.page_no = 1;
+      this.getDataList();
+    },
+  },
+};
+</script>
+<style scoped lang="scss">
+// .entry-records-points {
+// }
+</style>

+ 211 - 0
src/views/custom_manage/points/RankingOverview.vue

@@ -0,0 +1,211 @@
+<template>
+  <div class="container ranking-overview-content">
+    <div class="select-box">
+      <el-cascader
+        v-model="sales"
+        placeholder="请选择销售"
+        style="width: 220px"
+        :options="salesArr"
+        :props="defaultSalesProps"
+        :show-all-levels="false"
+        collapse-tags
+        clearable
+        filterable
+        @change="changeHandle"
+      >
+      </el-cascader>
+      <el-select style="width: 220px; margin: 0 20px" v-model="valueLocation" multiple placeholder="请选择城市" @change="changeHandle">
+        <el-option v-for="item in locationOptions" :key="item.name" :label="item.name" :value="item.name"> </el-option>
+      </el-select>
+      <a :href="exportUser" download>
+        <el-button type="primary" style="width: 80px">导出</el-button>
+      </a>
+    </div>
+    <div class="table-cont">
+      <template v-if="tableTheadColumns.length">
+        <table class="thead-sticky thead-box">
+          <thead>
+            <tr>
+              <td class="'head-column'"></td>
+              <td v-for="item in tableTheadColumns" :key="item" :class="['head-column']">
+                {{ item.CompanyName }}
+              </td>
+            </tr>
+          </thead>
+          <tbody v-for="(item, index) in datalist" :key="index">
+            <tr>
+              <td class="thead-rs">{{ item.Quarter }}</td>
+              <td v-for="key in item.ProportionListText" :key="key">{{ key }}</td>
+            </tr>
+          </tbody>
+        </table>
+        <template v-if="!datalist.length"> <div class="not-text">暂无数据</div> </template>
+      </template>
+      <template v-else> <div class="not-text">暂无数据</div> </template>
+    </div>
+  </div>
+</template>
+
+<script>
+import { customInterence, xClassCustomApi } from "@/api/api.js";
+
+export default {
+  name: "",
+  components: {},
+  props: {},
+  data() {
+    return {
+      sales: "",
+      salesArr: [], //销售
+      defaultSalesProps: {
+        multiple: true,
+        label: "RealName",
+        children: "ChildrenList",
+        value: "AdminId",
+      }, //销售级联配置
+      valueLocation: [], //地址
+      tableTheadColumns: [],
+      datalist: [],
+      listGroup: [],
+      locationOptions: [{ name: "北京市" }, { name: "上海市" }, { name: "深圳市" }],
+    };
+  },
+  computed: {
+    exportUser() {
+      let baseUrl = process.env.API_ROOT + "/cygx/enterScore/rankingOverview";
+      let token = localStorage.getItem("auth") || "";
+      let paramStr = "";
+      let params = this.paramsHandler();
+      params.IsExport = true;
+      for (let key in params) {
+        paramStr = `${paramStr}&${key}=${params[key]}`;
+      }
+      return `${baseUrl}?${token}${paramStr}`;
+    },
+  },
+  watch: {},
+  created() {},
+  mounted() {
+    this.getSale();
+    this.getDataList();
+  },
+  methods: {
+    /* 获取销售 */
+    getSale() {
+      let status = 0;
+      if (this.act_status == "流失") {
+        status = 1;
+      }
+      customInterence.getSale({ Status: status }).then((res) => {
+        if (res.Ret === 200) {
+          this.salesArr = res.Data.List;
+        }
+      });
+    },
+    async getDataList() {
+      let params = this.paramsHandler();
+      const res = await xClassCustomApi.enterScoreRankingOverview(params);
+      if (res.Ret === 200) {
+        this.tableTheadColumns = res.Data.ListCompany || [];
+        this.datalist = res.Data.ListQuarterDate || [];
+      }
+    },
+    // 处理数据, 获取数据
+    paramsHandler() {
+      let salesArr = [];
+      if (this.sales.length) {
+        salesArr = this.sales.map((item) => {
+          return item[item.length - 1];
+        });
+      }
+      let params = {
+        City: this.valueLocation.join(","),
+        AdminId: salesArr.join(","),
+      };
+      return params;
+    },
+    changeHandle() {
+      this.getDataList();
+    },
+  },
+};
+</script>
+<style scoped lang="scss">
+.ranking-overview-content {
+  .select-box {
+    display: flex;
+  }
+
+  .top-select {
+    display: flex;
+    justify-content: space-between;
+  }
+  .select-box {
+    display: flex;
+    margin-bottom: 30px;
+  }
+  .table-cont {
+    overflow: auto;
+    max-height: calc(100vh - 400px);
+    table {
+      font-size: 14px;
+      color: #666;
+      thead {
+        position: sticky;
+        top: 0;
+        left: 0;
+        border-left: 1px solid #dcdfe6;
+        border-right: 1px solid #dcdfe6;
+        td,
+        th {
+          min-width: 100px;
+          word-break: break-all;
+          border: 1px solid #dcdfe6;
+          outline-color: #dcdfe6;
+          outline-style: solid;
+          outline-width: 0.5px;
+        }
+      }
+      td,
+      th {
+        min-width: 100px;
+        word-break: break-all;
+        border: 1px solid #dcdfe6;
+        height: 45px;
+        text-align: center;
+        background-color: #fff;
+      }
+
+      .head-column {
+        background-color: #f0f2f5;
+      }
+
+      .data-cell {
+        color: #409eff;
+        cursor: pointer;
+      }
+
+      .thead-sticky {
+        position: sticky;
+        top: 0;
+      }
+    }
+    .content-ul {
+      .association {
+        color: #409eff;
+        cursor: pointer;
+      }
+    }
+  }
+  .not-text {
+    height: 300px;
+    line-height: 300px;
+    text-align: center;
+  }
+  .thead-box {
+    position: sticky;
+    top: 0;
+    z-index: 9;
+  }
+}
+</style>

+ 258 - 0
src/views/custom_manage/points/RatingOverview.vue

@@ -0,0 +1,258 @@
+<template>
+  <div class="container rating-overview-content">
+    <div class="top-select">
+      <div class="select-box">
+        <el-date-picker style="width: 220px" v-model="yearValue" value-format="yyyy" type="year" placeholder="请选择年份" :clearable="false" @change="changeHandle"> </el-date-picker>
+        <el-select style="width: 220px; margin: 0 20px" v-model="selectedQuarter" placeholder="请选择季度" @change="changeHandle">
+          <el-option v-for="item in quarterOptions" :key="item.label" :label="item.label" :value="item.value"> </el-option>
+        </el-select>
+        <el-input style="width: 220px" placeholder="请输入券商名称" prefix-icon="el-icon-search" v-model="brokerName" @input="inputHandle"> </el-input>
+        <el-select style="width: 220px; margin: 0 20px" v-model="valueLocation" multiple placeholder="请选择城市" @change="changeHandle">
+          <el-option v-for="item in locationOptions" :key="item.name" :label="item.name" :value="item.name"> </el-option>
+        </el-select>
+        <a :href="exportUser" download>
+          <el-button type="primary" style="width: 80px">导出</el-button>
+        </a>
+      </div>
+      <div>
+        <el-button @click="enterScoreType = !enterScoreType" type="primary">{{ enterScoreType ? "原始值显示" : "百分比显示" }} </el-button>
+      </div>
+    </div>
+
+    <div class="table-cont">
+      <template v-if="tableTheadColumns.length">
+        <table class="thead-sticky thead-box">
+          <thead>
+            <tr>
+              <td class="'head-column'"></td>
+              <td v-for="item in tableTheadColumns" :key="item" :class="['head-column']">
+                {{ item.CompanyName }}
+              </td>
+            </tr>
+          </thead>
+          <tbody v-for="(item, index) in datalist" :key="index">
+            <tr>
+              <td class="thead-rs">{{ item.ChartPermissionName }}</td>
+              <td v-for="key in item.ProportionListText" :key="key">{{ key }}</td>
+            </tr>
+            <tr v-for="rs in item.List" :key="rs.RealName" class="content-ul">
+              <td>{{ rs.RealName }}</td>
+              <td v-for="pr in rs.ProportionListText" :key="pr">{{ pr }}</td>
+            </tr>
+          </tbody>
+          <tbody v-for="(item, index) in listGroup" :key="index">
+            <tr>
+              <td class="thead-rs">{{ item.GroupName }}</td>
+              <td v-for="key in item.ProportionListText" :key="key">{{ key }}</td>
+            </tr>
+          </tbody>
+        </table>
+        <template v-if="!datalist.length && !listGroup.length"> <div class="not-text">暂无数据</div> </template>
+      </template>
+      <template v-else> <div class="not-text">暂无数据</div> </template>
+    </div>
+  </div>
+</template>
+
+<script>
+import { customInterence, xClassCustomApi } from "@/api/api.js";
+
+export default {
+  name: "",
+  components: {},
+  props: {},
+  data() {
+    return {
+      yearValue: new Date().getFullYear().toString(), // 年份
+      selectedQuarter: [], // 季度
+      quarterOptions: [
+        {
+          label: "Q1",
+          value: ["01-01", "03-31"],
+        },
+        {
+          label: "Q2",
+          value: ["04-01", "06-30"],
+        },
+        {
+          label: "Q3",
+          value: ["07-01", "09-30"],
+        },
+        {
+          label: "Q4",
+          value: ["10-01", "12-31"],
+        },
+      ],
+      brokerName: "", // 券商名
+      valueLocation: [], //地址
+      tableTheadColumns: [],
+      datalist: [],
+      listGroup: [],
+      enterScoreType: false,
+      locationOptions: [{ name: "北京市" }, { name: "上海市" }, { name: "深圳市" }],
+    };
+  },
+  computed: {
+    exportUser() {
+      let baseUrl = process.env.API_ROOT + "/cygx/enterScore/scoreOverview";
+      let token = localStorage.getItem("auth") || "";
+      const cityArr = [];
+      let paramStr = "";
+      let params = this.paramsHandler();
+      params.IsExport = true;
+      for (let key in params) {
+        paramStr = `${paramStr}&${key}=${params[key]}`;
+      }
+      return `${baseUrl}?${token}${paramStr}`;
+    },
+  },
+  watch: {
+    enterScoreType: {
+      handler() {
+        this.getDataList();
+      },
+    },
+  },
+  mounted() {
+    this.setDefaultQuarter();
+
+    this.getDataList();
+  },
+  methods: {
+    setDefaultQuarter() {
+      const currentDate = new Date();
+      const month = currentDate.getMonth() + 1; // 获取当前月份(0-11,所以加1)
+
+      let currentQuarterIndex;
+      if (month >= 1 && month <= 3) {
+        // Q1
+        currentQuarterIndex = 0;
+      } else if (month >= 4 && month <= 6) {
+        // Q2
+        currentQuarterIndex = 1;
+      } else if (month >= 7 && month <= 9) {
+        // Q3
+        currentQuarterIndex = 2;
+      } else if (month >= 10 && month <= 12) {
+        // Q4
+        currentQuarterIndex = 3;
+      }
+
+      // 获取上一个季度索引
+      const previousQuarterIndex = currentQuarterIndex === 0 ? this.quarterOptions.length - 1 : currentQuarterIndex - 1;
+
+      // 设置v-model绑定的值为上一个季度的value数组
+      this.selectedQuarter = this.quarterOptions[previousQuarterIndex].value;
+    },
+
+    getPreviousYear(currentYear, currentQuarter) {
+      // 如果当前季度是第一个季度,则上个季度应该是去年的最后一个季度
+      return currentQuarter === "Q1" ? currentYear - 1 : currentYear;
+    },
+    changeHandle() {
+      this.getDataList();
+    },
+    inputHandle: _.debounce(async function () {
+      this.getDataList();
+    }, 500),
+    async getDataList() {
+      this.tableTheadColumns = [];
+      this.datalist = [];
+      this.listGroup = [];
+      let params = this.paramsHandler();
+      const res = await xClassCustomApi.enterScoreScoreOverview(params);
+      if (res.Ret === 200) {
+        this.tableTheadColumns = res.Data.ListCompany || [];
+        this.datalist = res.Data.ListPermission || [];
+        this.listGroup = res.Data.ListGroup || [];
+      }
+    },
+    // 处理数据, 获取数据
+    paramsHandler() {
+      let params = {
+        StartDate: this.yearValue + "-" + this.selectedQuarter[0],
+        EndDate: this.yearValue + "-" + this.selectedQuarter[1],
+        KeyWord: this.brokerName,
+        City: this.valueLocation.join(","),
+        EnterScoreType: this.enterScoreType ? 2 : 1,
+      };
+      return params;
+    },
+  },
+};
+</script>
+<style scoped lang="scss">
+.rating-overview-content {
+  .top-select {
+    display: flex;
+    justify-content: space-between;
+  }
+  .select-box {
+    display: flex;
+    margin-bottom: 30px;
+  }
+  .table-cont {
+    max-height: calc(100vh - 400px);
+    overflow: auto;
+    table {
+      font-size: 14px;
+      color: #666;
+      thead {
+        position: sticky;
+        top: 0;
+        left: 0;
+        border-left: 1px solid #dcdfe6;
+        border-right: 1px solid #dcdfe6;
+        td,
+        th {
+          min-width: 100px;
+          word-break: break-all;
+          border: 1px solid #dcdfe6;
+          outline-color: #dcdfe6;
+          outline-style: solid;
+          outline-width: 0.5px;
+        }
+      }
+      td,
+      th {
+        min-width: 100px;
+        word-break: break-all;
+        border: 1px solid #dcdfe6;
+        height: 45px;
+        text-align: center;
+        background-color: #fff;
+      }
+
+      .head-column {
+        background-color: #f0f2f5;
+      }
+
+      .data-cell {
+        color: #409eff;
+        cursor: pointer;
+      }
+
+      .thead-sticky {
+        position: sticky;
+        top: 0;
+      }
+    }
+    .content-ul {
+      .association {
+        color: #409eff;
+        cursor: pointer;
+      }
+    }
+  }
+  .not-text {
+    height: 300px;
+    line-height: 300px;
+    text-align: center;
+  }
+  .thead-box {
+    position: sticky;
+    top: 0;
+    z-index: 9;
+  }
+}
+</style>

+ 85 - 0
src/views/custom_manage/points/XClassCustom.vue

@@ -0,0 +1,85 @@
+<template>
+  <div class="container x-class-custom-content">
+    <el-card>
+      <div class="top-card-box">
+        <div class="tabs-box">
+          <span v-for="item in listTitle" :key="item.value" @click="tabsBoxBtn(item)" :class="item.value == tabsPitchon ? 'pitch' : ''">{{ item.lable }}</span>
+        </div>
+      </div>
+    </el-card>
+    <el-card style="margin-top: 20px">
+      <EntryRecords v-if="tabsPitchon == 1" />
+      <RatingOverview v-if="tabsPitchon == 2" />
+      <RankingOverview v-if="tabsPitchon == 3" />
+    </el-card>
+  </div>
+</template>
+
+<script>
+import EntryRecords from "./EntryRecords.vue"; // 录分
+import RatingOverview from "./RatingOverview.vue"; // 评分
+import RankingOverview from "./RankingOverview.vue"; // 排名
+export default {
+  name: "",
+  components: { EntryRecords, RatingOverview, RankingOverview },
+  props: {},
+  data() {
+    return {
+      listTitle: [
+        {
+          lable: "录分记录",
+          value: "1",
+        },
+        {
+          lable: "评分总览",
+          value: "2",
+        },
+        {
+          lable: "排名总览",
+          value: "3",
+        },
+      ],
+      tabsPitchon: 1, //tabs 默认选中
+    };
+  },
+  computed: {},
+  watch: {},
+  created() {},
+  mounted() {},
+  methods: {
+    // 头部的点击事件
+    tabsBoxBtn(item) {
+      this.tabsPitchon = item.value;
+    },
+    // 输入框搜索事件
+    handleSearch() {
+      // this.$refs.recordRefs
+    },
+  },
+};
+</script>
+<style scoped lang="scss">
+.x-class-custom-content {
+  .top-card-box {
+    display: flex;
+    justify-content: space-between;
+    .tabs-box {
+      span {
+        display: inline-block;
+        padding: 9px 24px;
+        background-color: #e9f4ff;
+        border: 1px solid #b3d8ff;
+        border-radius: 4px;
+        margin-right: 30px;
+        color: #409eff;
+        cursor: pointer;
+      }
+      .pitch {
+        background-color: #409eff;
+        border: none;
+        color: #fff;
+      }
+    }
+  }
+}
+</style>

+ 11 - 8
src/views/rai_manage/activityManage/activityManage.vue

@@ -7,11 +7,11 @@
         <div class="tabs-box">
           <span v-for="(item, index) in listTitle" :key="item.ChartPermissionId" @click="tabsBoxBtn(item, index)" :class="index == tabsPitchon ? 'pitch' : ''">{{ item.PermissionName }}</span>
         </div>
-        <div style="display: flex;align-items: center">
-          <el-upload style="height:40px" ref="imgUpload" action="#" :http-request="handleUploadImg" :show-file-list="false" accept="image/*">
-            <el-button style="height:40px" type="primary">识图建会</el-button>
+        <div style="display: flex; align-items: center">
+          <el-upload style="height: 40px" ref="imgUpload" action="#" :http-request="handleUploadImg" :show-file-list="false" accept="image/*">
+            <el-button style="height: 40px" type="primary">识图建会</el-button>
           </el-upload>
-          <el-button style="margin-left: 20px;height:40px" type="primary" @click="$router.push(!isResearch ? '/addActivity' : '/addPurchaserActivity')">添加活动</el-button>
+          <el-button style="margin-left: 20px; height: 40px" type="primary" @click="$router.push(!isResearch ? '/addActivity' : '/addPurchaserActivity')">添加活动</el-button>
         </div>
       </div>
     </el-card>
@@ -45,7 +45,7 @@
       <el-table :data="dataList" style="width: 100%" border>
         <el-table-column align="center" label="活动名称" min-width="285">
           <template slot-scope="{ row }">
-            <span class="editsty" @click="titleBtnClick(row.ActivityId)">{{ row.ActivityName }}</span>
+            <span :class="row.PublishStatus == 3 ? 'grey-color' : 'editsty'" @click="titleBtnClick(row.ActivityId)">{{ row.ActivityName }}</span>
           </template>
         </el-table-column>
         <el-table-column prop="ChartPermissionName" align="center" label="行业" min-width="90"></el-table-column>
@@ -65,10 +65,10 @@
           <template slot-scope="{ row }">
             <div class="operate-box">
               <p v-if="row.PublishStatus == 0 && tabsPitchon == 0" class="editsty" @click="operationBtn(row.ActivityId, '发布')">发布</p>
-              <p v-if="row.PublishStatus == 3" class="editsty" @click="operationBtn(row.ActivityId, '重新发布')">重新发布</p>
+              <p v-if="row.PublishStatus == 3" class="grey-color" @click="operationBtn(row.ActivityId, '重新发布')">重新发布</p>
               <p v-if="row.PublishStatus == 1" class="editsty" @click="operationBtn(row.ActivityId, '取消发布')">取消发布</p>
               &nbsp;&nbsp;
-              <p class="editsty" @click="editBtn(row.ActivityId, row.PublishStatus)">编辑</p>
+              <p :class="row.PublishStatus == 3 ? 'grey-color' : 'editsty'" @click="editBtn(row.ActivityId, row.PublishStatus)">编辑</p>
               &nbsp;&nbsp;
               <p class="deletesty" v-if="row.PublishStatus == 0 && tabsPitchon == 0" @click="operationBtn(row.ActivityId, '删除')">删除</p>
               <p class="editsty" v-if="row.IsShowSigninButton" @click="handleDownLoadImg(row)">下载签到码</p>
@@ -439,9 +439,12 @@ export default {
       flex-shrink: 0;
     }
   }
-  .el-upload  {
+  .el-upload {
     height: 40px !important;
     min-height: 40px !important;
   }
+  .grey-color {
+    cursor: pointer;
+  }
 }
 </style>

+ 16 - 20
src/views/rai_manage/activityManage/applyManage.vue

@@ -37,14 +37,8 @@
           <el-button type="primary" @click="sendMessage">发送模板消息</el-button>
         </div>
         <div>
-          <el-select placeholder="行业" clearable v-model="industry" @change="conditionChange" style="margin-bottom: 20px"
-          v-if="!isResearch">
-            <el-option
-              v-for="item in chartPermissionList"
-              :label="item.PermissionName"
-              :key="item.ChartPermissionId"
-              :value="item.ChartPermissionId"
-            ></el-option>
+          <el-select placeholder="行业" clearable v-model="industry" @change="conditionChange" style="margin-bottom: 20px" v-if="!isResearch">
+            <el-option v-for="item in chartPermissionList" :label="item.PermissionName" :key="item.ChartPermissionId" :value="item.ChartPermissionId"></el-option>
           </el-select>
           <el-select placeholder="活动类型" clearable @focus="activityType" v-model="cactivityTypeVal" @change="conditionChange" style="margin-bottom: 20px">
             <el-option v-for="item in cactivityTypeList" :label="item.ActivityTypeName" :key="item.ActivityTypeId" :value="item.ActivityTypeId"></el-option>
@@ -81,7 +75,7 @@
               <span v-if="row.SignupFailPeopleNum == 0">--</span>
               <span v-else class="editsty" @click="particularsBtn('报名失败详情', row.ActivityId)">{{ row.SignupFailPeopleNum }}</span>
             </div>
-            <span v-else @click="handleRowClick(row, item.key)" :style="handleRowStyle(item.key)">{{ handleRowContent(row, item.key) }}</span>
+            <span v-else @click="handleRowClick(row, item.key)" :style="handleRowStyle(item.key, row)">{{ handleRowContent(row, item.key) }}</span>
           </template>
         </el-table-column>
       </el-table>
@@ -118,7 +112,7 @@ import ParticularsDialog from "../components/apply/particularsDialog.vue";
 import AtcParticulars from "../components/atcParticulars.vue";
 import GenerationAsk from "../components/generationAsk.vue";
 import SummaryRemind from "../components/apply/summaryRemind.vue";
-import { ListTitle , purchaserListTitle , TableApplyColums, StatusSelect, PublishSelect } from "../components/apply/applyTableColums";
+import { ListTitle, purchaserListTitle, TableApplyColums, StatusSelect, PublishSelect } from "../components/apply/applyTableColums";
 import TemplateMessage from "../components/apply/templateMessage.vue";
 export default {
   name: "",
@@ -166,11 +160,11 @@ export default {
   },
   computed: {
     // 弘则 研选 是否是研选
-    isResearch(){
-      return this.$route.path.indexOf("purchaser")!=-1?true:false
+    isResearch() {
+      return this.$route.path.indexOf("purchaser") != -1 ? true : false;
     },
     listTitle() {
-      return !this.isResearch?ListTitle:purchaserListTitle;
+      return !this.isResearch ? ListTitle : purchaserListTitle;
     },
     statusSelect() {
       return StatusSelect;
@@ -187,7 +181,7 @@ export default {
       this.page_no = 1;
       this.init();
       this.getsDataList();
-    }
+    },
   },
   created() {},
   mounted() {
@@ -225,7 +219,7 @@ export default {
           ActivityTypeId: this.cactivityTypeVal,
           ActiveState: this.cactivityStatus,
           PublishStatus: this.publishStatus ? Number(this.publishStatus) : 2,
-          IsResearch:this.isResearch
+          IsResearch: this.isResearch,
         })
         .then((res) => {
           if (res.Ret !== 200) return;
@@ -315,7 +309,7 @@ export default {
     },
     //获取行业
     chartPermission() {
-      raiInterface.chartPermission({IsHideResearch:!this.isResearch}).then((res) => {
+      raiInterface.chartPermission({ IsHideResearch: !this.isResearch }).then((res) => {
         if (res.Ret === 200) {
           this.chartPermissionList = res.Data.List;
         }
@@ -372,9 +366,11 @@ export default {
       }
     },
     /* 表格行的样式 */
-    handleRowStyle(key) {
-      let isStyle = ["ActivityName", "SignupPeopleNum", "AppointmentPeopleNum", "AskNum"];
-      return isStyle.includes(key) ? "color: #409eff; cursor: pointer" : "";
+    handleRowStyle(key, row) {
+      if (["ActivityName", "SignupPeopleNum", "AppointmentPeopleNum", "AskNum"].includes(key)) {
+        return row.PublishStatus == 3 ? "cursor: pointer" : "color: #409eff; cursor: pointer";
+      }
+      return "";
     },
     /* 表格行的点击事件 */
     handleRowClick(row, key) {
@@ -403,7 +399,7 @@ export default {
         let status = row[key] == 1 ? "未开始" : row[key] == 2 ? "进行中" : "已结束";
         return status;
       } else if (key == "PublishStatus") {
-        let status = row["PublishStatus"] == 1 ? "已发布" : row["PublishStatus"] == 2 ?"未发布":"已取消";
+        let status = row["PublishStatus"] == 1 ? "已发布" : row["PublishStatus"] == 2 ? "未发布" : "已取消";
         return status;
       } else {
         return row[key];