Browse Source

Merge branch 'V1.1.7'

朱鑫波 4 years ago
parent
commit
866f8addbc

File diff suppressed because it is too large
+ 19777 - 0
package-lock.json


BIN
src/assets/down.png


BIN
src/assets/up.png


+ 3 - 3
src/utils/request.js

@@ -16,8 +16,8 @@ else if (process.env.NODE_ENV == 'debug') {
 else if (process.env.NODE_ENV == 'production') { 
   
   // axios.defaults.baseURL = 'http://192.168.1.251/jeecg-boot';
-  // axios.defaults.baseURL = 'http://139.186.165.84:8806/jeecg-boot';     
-  axios.defaults.baseURL = 'http://api.tjyourong.com.cn/jeecg-boot';
+  axios.defaults.baseURL = 'http://139.186.165.84:8806/jeecg-boot';     
+  // axios.defaults.baseURL = 'http://api.tjyourong.com.cn/jeecg-boot';
 }
 const service = axios.create({
 //   baseURL: '/jeecg-boot', // api base_url
@@ -100,7 +100,7 @@ service.interceptors.request.use(config => {
       ...config.params
     }
   }
-  return config
+  return config 
 }, (error) => {
   return Promise.reject(error)
 })

+ 1 - 0
src/views/modules/Statistics/materialReport/marterialDetail.vue

@@ -209,6 +209,7 @@
               color: rgba(0, 0, 0, 0.85);
               font-weight: bold;
               font-size: 16px;
+               
               line-height: 1.5;
             "
           >

+ 36 - 13
src/views/modules/Statistics/videoStatics/KSvideoStatics.vue

@@ -5,20 +5,25 @@
         <Treeselect  :appId.sync="appId" request="2,4"   style="display: inline-block;position: relative;margin-left: 0px;"/>
     </div>
     <div class="timeDiv">
-      <div style='display:flex;align-items: center;'>
-        <span>时间范围:</span>
-        <span  @click="opendate">
-          <DatePicker :openOptions='openOptions'  :parentDate='dateValue' left='-100px'></DatePicker>
-        </span> 
-        <span style="margin-left:15px">设计负责人:</span> 
-        <span  >
+      <div style='display:flex;align-items: center;flex-wrap:wrap;'>
+        <div style="dispaly:inline-block;margin-bottom:15px;"> 
+          <span>时间范围:</span>
+          <span style="display: inline-block;"  @click="opendate">
+            <DatePicker :openOptions='openOptions'  :parentDate='dateValue' left='-100px'></DatePicker>
+          </span>
+        </div>
+        <div style="dispaly:inline-block;margin-bottom:15px;">
+        <span style="margin-left:15px;">设计负责人:</span> 
+        <span>
             <!-- <a-input placeholder="请输入剪辑的名字" v-model="clip" style="width:140px"  /> -->
             <a-select v-model="leaderId" style="width: 140px" allowClear  show-search :filter-option="filterOption">
               <a-select-option v-for="item in designList" :key="item.userId" :value='item.userId'>
                 {{item.companyName +'_'+item.userName  }}
               </a-select-option>
             </a-select>
-        </span>         
+        </span>   
+        </div>      
+        <div style="dispaly:inline-block;margin-bottom:15px;">
         <span style="margin-left:15px">剪辑:</span> 
         <span  >
             <!-- <a-input placeholder="请输入剪辑的名字" v-model="clip" style="width:140px"  /> -->
@@ -27,7 +32,9 @@
                 {{item.companyName +'_'+item.userName  }}
               </a-select-option>
             </a-select>
-        </span>         
+        </span>     
+        </div>    
+        <div style="dispaly:inline-block;margin-bottom:15px;">
         <span style="margin-left:15px">拍摄:</span> 
         <span  >
             <!-- <a-input placeholder="请输入拍摄的名字" v-model="shot" style="width:140px" /> -->
@@ -36,7 +43,9 @@
                 {{item.companyName +'_'+item.userName  }}
               </a-select-option>
             </a-select>
-        </span>         
+        </span>   
+        </div>      
+        <div style="dispaly:inline-block;margin-bottom:15px;">
         <span style="margin-left:15px">编导:</span> 
         <span  >
             <!-- <a-input placeholder="请输入编导的名字" v-model="plan" style="width:140px"  /> -->
@@ -45,7 +54,18 @@
                  {{item.companyName +'_'+item.userName  }}
               </a-select-option>
             </a-select>
-        </span>         
+        </span>     
+        </div>
+        <div style="dispaly:inline-block;margin-bottom:15px;">
+        <span style="margin-left:15px">素材渠道:</span> 
+        <span>
+            <!-- <a-input placeholder="请输入编导的名字" v-model="plan" style="width:140px"  /> -->
+            <a-select v-model="material" style="width: 140px" allowClear>
+              <a-select-option value="0">内部</a-select-option>
+              <a-select-option value="1">素造</a-select-option>
+            </a-select>
+        </span>    
+        </div> 
       </div>
       <a-button type="primary" @click="searchRes" :loading='searchLoading'>查询</a-button>
     </div>
@@ -504,6 +524,7 @@ let detailColumn=[
 export default {
   data() {
     return {
+      material: '',
       searchLoading:false,
 
       designList:[],
@@ -744,7 +765,8 @@ export default {
         clipId:this.clip?this.clip:'',
         shotId:this.shot?this.shot:'',
         planId:this.plan?this.plan:'',
-        leaderId:this.leaderId?this.leaderId:''
+        leaderId:this.leaderId?this.leaderId:'',
+        channelType: this.material ? Number(this.material) : ''
       }).then(res => {
         let resArr = []
         this.data=[];
@@ -792,7 +814,8 @@ export default {
         clipId:this.clip?this.clip:'',
         shotId:this.shot?this.shot:'',
         planId:this.plan?this.plan:'',
-        leaderId:this.leaderId?this.leaderId:''
+        leaderId:this.leaderId?this.leaderId:'',
+        channelType: this.material ? Number(this.material) : ''
       }).then(res => {
         this.exportLoading=false;
         let blob = new Blob([res], {

+ 418 - 76
src/views/modules/autoLaunch/configLaunchInfo.vue

@@ -70,10 +70,72 @@
                 </div>
                 <div class="input-item">
                 <a-form-item>                
-                    <a-input v-decorator="['campaignName',{ rules: [{ required: true, message: '请填写计划的命名规则' }] }]"  allow-clear />
+                    <a-input v-decorator="['campaignName',{ rules: [{ required: true, message: '请填写计划的命名规则' }] }]"  allow-clear  id="campaignName"/>
                 </a-form-item>
                 </div>
             </div>  
+            <!-- <div class="row-item">
+                <div class="hint-item"> </div>
+                <div class="label-item">
+                <div class="text-item"></div>
+                </div>
+                <div class="input-item">
+                <a-form-item>                
+                   <a-tag color="#2db7f5" @click="getChangeAll('定向包', 'form', 'campaignName')"
+                >+定向包</a-tag
+              >
+              <a-tag color="#2db7f5" @click="getChangeAll('应用包名', 'form', 'campaignName')"
+                >+应用包名</a-tag
+              >
+              <a-tag color="#2db7f5" @click="getChangeAll('自定义', 'form', 'campaignName')"
+                >+自定义</a-tag
+              >
+                </a-form-item>
+                </div>
+            </div>   -->
+                        
+            <div class="row-item">
+                <div class="hint-item"> </div>
+                <div class="label-item">
+                <div class="text-item">广告计划单日预算</div>
+                <div class="required-item"></div>
+                </div>
+                <div class="input-item">
+                <a-form-item>                
+                <a-radio-group v-model="budgetType">
+                    <a-radio-button value="1">不限</a-radio-button>
+                    <a-radio-button value="2">统一预算</a-radio-button>
+                </a-radio-group>
+                </a-form-item>
+                </div>
+            </div>  
+
+            <div class="row-item" v-if="budgetType == '2'">
+                <div class="hint-item"> </div>
+                <div class="label-item">
+                <div class="text-item"></div>
+                <div class="required-item"></div>
+                </div>
+                <div class="input-item">
+                <a-form-item>                
+                    <a-input-number
+                        v-decorator="[
+                        'campaignDayBudget',
+                        {
+                            rules: [{ required: true, message: '不小于500, 不超过100000000,仅支持输入自然数' }],
+                        },
+                        ]"
+                        :min="500"
+                        :precision="0"
+                        :max="100000000"
+                        style="width: 100%"
+                        placeholder="不小于500, 不超过100000000,仅支持输入自然数"
+                    />
+                </a-form-item>
+                </div>
+            </div>  
+
+
             <div class="row-item">
                 <div class="hint-item"> </div>
                 <div class="label-item">
@@ -82,10 +144,76 @@
                 </div>
                 <div class="input-item">
                 <a-form-item>                
-                    <a-input v-decorator="['groupName',{ rules: [{ required: true, message: '请填写组的命名规则' }] }]"  allow-clear />
+                    <a-input v-decorator="['groupName',{ rules: [{ required: true, message: '请填写组的命名规则' }] }]"  allow-clear id="groupName"/>
+                </a-form-item>
+                </div>
+            </div>  
+            <div class="row-item">
+                <div class="hint-item"> </div>
+                <div class="label-item">
+                <div class="text-item"></div>
+                </div>
+                <div class="input-item">
+                <a-form-item>                
+                   <!-- <a-tag color="#2db7f5" @click="getChangeAll('定向包', 'form', 'groupName')"
+                >+定向包</a-tag
+              > -->
+              <!-- <a-tag color="#2db7f5" @click="getChangeAll('日期', 'form', 'groupName')">+日期</a-tag>
+              <a-tag color="#2db7f5" @click="getChangeAll('标号', 'form', 'groupName')">+标号</a-tag> -->
+              <!-- <a-tag color="#2db7f5" @click="getChangeAll('应用包名', 'form', 'groupName')"
+                >+应用包名</a-tag
+              > -->
+               <a-tag color="#2db7f5" @click="getChangeAll('创意制作方式', 'form', 'groupName')"
+                >+创意制作方式</a-tag
+              >
+               <a-tag color="#2db7f5" @click="getChangeAll('广告位置', 'form', 'groupName')"
+                >+广告位置</a-tag
+              >
+               <a-tag color="#2db7f5" @click="getChangeAll('自定义', 'form', 'groupName')"
+                >+自定义</a-tag
+              >
                 </a-form-item>
                 </div>
             </div>  
+            <div class="row-item">
+                <div class="hint-item"> </div>
+                <div class="label-item">
+                <div class="text-item">广告组单日预算</div>
+                <div class="required-item"></div>
+                </div>
+                <div class="input-item">
+                <a-form-item>                
+                    <a-radio-group v-model="dayBudgetType">
+                        <a-radio-button value="1">不限</a-radio-button>
+                        <a-radio-button value="2">统一预算</a-radio-button>
+                    </a-radio-group>
+                </a-form-item>
+                </div>
+            </div>
+            <div class="row-item" v-if="dayBudgetType=='2'">
+                <div class="hint-item"> </div>
+                <div class="label-item">
+                <div class="text-item"></div>
+                <div class="required-item"></div>
+                </div>
+                <div class="input-item">
+                <a-form-item>                
+                    <a-input-number
+                        v-decorator="[
+                        'unitDayBudget',
+                        {
+                            rules: [{ required: true, message: '不小于500, 不超过100000000,仅支持输入自然数' }],
+                        },
+                        ]"
+                        style="width: 100%"
+                        placeholder="不小于500, 不超过100000000,仅支持输入自然数"
+                        :min="500"
+                        :precision="0"
+                    />
+                </a-form-item>
+                </div>
+            </div>
+
             
         </div>
         <div class="moduler">
@@ -220,16 +348,16 @@
         </div>
         <div class="moduler">
             <div class="moduler-title">用户定向
-            <div style="margin-left:30px;position:relative;top:-2px">
+            <!-- <div style="margin-left:30px;position:relative;top:-2px">
                 <a-radio-group v-model="useDirectional" @change="useDirectionalChange">
                     <a-radio :value="1">
                         不使用定向
                     </a-radio>
-                    <!-- <a-radio :value="0">
+                    <a-radio :value="0">
                         使用定向包
-                    </a-radio> -->
+                    </a-radio>
                 </a-radio-group>
-            </div>
+            </div> -->
             </div>
             <div class="ad-range" v-if="useDirectional==1">
                     <div class="row-item">
@@ -284,7 +412,7 @@
                         </div>
                         <div class="input-item">
                             <a-form-item>
-                                <radioCheck :checkArr='ageArr' @getSonValue='getAgeSelect'   />
+                                <radioCheck v-model="agesRange"  :options="ageArr" @change='getAgeSelect'   />
                             </a-form-item>
                         </div>
                     </div>
@@ -303,12 +431,12 @@
                                 </a-radio-group>
                             </a-form-item>
 
-                            <!-- <div style="margin-top:24px"  v-if="getFormData('platformOs')!=0">
+                            <div style="margin-top:24px"  v-if="getFormData('platformOs')!=0">
                                 <div v-if="getFormData('platformOs')==1">
                                     <a-form-item>
                                     <a-radio-group v-decorator="['androidOsv',{initialValue: 3,}]">
                                         <a-radio :value="3">不限</a-radio>
-                                        <a-radio :value="4">4X+</a-radio>
+                                        <a-radio :value="4">4x+</a-radio>
                                         <a-radio :value="5">5x+</a-radio>
                                         <a-radio :value="6">6x+</a-radio>
                                         <a-radio :value="7">7x+</a-radio>
@@ -319,7 +447,7 @@
                                     <a-form-item>
                                     <a-radio-group  v-decorator="['iosOsv',{initialValue: 6,}]">
                                         <a-radio :value="6">不限</a-radio>
-                                        <a-radio :value="7">7X+</a-radio>
+                                        <a-radio :value="7">7x+</a-radio>
                                         <a-radio :value="8">8x+</a-radio>
                                         <a-radio :value="9">9x+</a-radio>
                                         <a-radio :value="10">10x+</a-radio>
@@ -327,10 +455,10 @@
                                     </a-form-item>
                                 </div>
                                 
-                            </div> -->
+                            </div>
                         </div>
                     </div>
-                    <!-- <div class="row-item" v-if="getFormData('platformOs')!=2">
+                    <div class="row-item" v-if="getFormData('platformOs')!=2">
                         <div class="hint-item"></div>
                         <div class="label-item">
                         <div class="text-item">设备品牌</div>
@@ -349,6 +477,7 @@
                             <div class="inventory-tags-lists-name"><strong>品牌名称</strong></div>
                             </div>
                             <div class="inventory-tags-lists-container" >
+                                <a-form-item>
                                 <a-checkbox-group
                                     v-decorator="['deviceBrand', { rules: [{ required: true, message: '请选择设备品牌' }] }]"
                                 >
@@ -364,11 +493,55 @@
                                 <a-checkbox :value="10" style="margin-bottom: 8px">其他</a-checkbox>
                                 <a-checkbox :value="11" v-if="getFormData('platformOs') == 0" style="margin-bottom: 8px">苹果</a-checkbox>
                                 </a-checkbox-group>
+                                 </a-form-item>
                             </div>
                         </div>                  
                         
                         </div>
-                    </div> -->
+                    </div>
+                    <div class="row-item">
+                        <div class="hint-item"></div>
+                        <div class="label-item">
+                        <div class="text-item">设备价格</div>
+                        <div class="required-item"></div>
+                        </div>
+                        <div class="input-item">
+                        <a-form-item>
+                            <a-radio-group v-model="devicePrice">
+                                <a-radio-button :value="0">不限</a-radio-button>
+                                <a-radio-button :value="1">选择价格</a-radio-button>                      
+                            </a-radio-group>
+                        </a-form-item>
+                        <div style="width: 400px; margin-top: 24px;" class="inventoryTypes" v-if="devicePrice==1">
+                            <div class="inventory-tags-lists-header" style="padding-left:15px">
+                                
+                            <div class="inventory-tags-lists-name"><strong>价格区间</strong></div>
+                            </div>
+                            <div class="inventory-tags-lists-container" >
+                                 <a-form-item>
+                                <a-checkbox-group
+                                v-decorator="['devicePrice', { rules: [{ required: true, message: '请选择设备价格' }] }]"
+                                style="width: 120%"
+                                >
+                                <a-checkbox :value="1" style="margin-bottom: 8px">1500以下</a-checkbox>
+                                <a-checkbox :value="2" style="margin-bottom: 8px">1501~2000</a-checkbox>
+                                <a-checkbox :value="3" style="margin-bottom: 8px">2001~2500</a-checkbox>
+                                <a-checkbox :value="4" style="margin-bottom: 8px">2501~3000</a-checkbox>
+                                <a-checkbox :value="5" style="margin-left: 0; margin-bottom: 8px">3001~3500</a-checkbox>
+                                <a-checkbox :value="6" style="margin-bottom: 8px">3501~4000</a-checkbox>
+                                <a-checkbox :value="7" style="margin-bottom: 8px">4001~4500</a-checkbox>
+                                <a-checkbox :value="8" style="margin-bottom: 8px">4501~5000</a-checkbox>
+                                <a-checkbox :value="9" style="margin-left: 0; margin-bottom: 8px">5001~5500</a-checkbox>
+                                <a-checkbox :value="10" style="margin-bottom: 8px">5500以上</a-checkbox>
+                                </a-checkbox-group>
+                                 </a-form-item>
+                            </div>
+                        </div>                  
+                        
+                        </div>
+                    </div>
+
+
                     <div class="row-item">
                         <div class="hint-item"></div>
                             <div class="label-item">
@@ -758,6 +931,25 @@
         <div class="moduler">
             <div class="moduler-title">创意信息</div>
                 <div class="ad-range">
+
+
+
+                    <div class="row-item">
+                        <div class="hint-item"></div>
+                        <div class="label-item">
+                        <div class="text-item">创意制作方式</div>
+                        <div class="required-item"></div>
+                        </div>
+                        <div class="input-item">
+                        <a-form-item>
+                            <a-radio-group v-decorator="['openProgramCreate', { initialValue:2 }]" @change="adposition=1;checkedList=[];checkAll=false">
+                                <a-radio-button :value='2'>不限</a-radio-button>
+                                <a-radio-button :value="0">自定义</a-radio-button>                            
+                                <a-radio-button :value="1">程序化</a-radio-button>                            
+                            </a-radio-group>
+                        </a-form-item>                       
+                        </div>
+                    </div>
                     <div class="row-item">
                         <div class="hint-item"></div>
                         <div class="label-item">
@@ -768,7 +960,8 @@
                         <a-form-item>
                             <a-radio-group v-model="adposition" @change="adpositionChange">
                                 <a-radio-button :value='1'>优选广告位</a-radio-button>
-                                <a-radio-button value="inventoryTypes">按媒体指定位置</a-radio-button>                            
+                                <a-radio-button value="inventoryTypes">按媒体指定位置</a-radio-button>    
+                                <a-radio-button :value='5' :disabled="getData('openProgramCreate')==1">联盟广告</a-radio-button>
                             </a-radio-group>
                         </a-form-item>
                         <div style="width: 400px; margin-top: 24px;" class="inventoryTypes" v-show="adposition=='inventoryTypes'">
@@ -778,28 +971,60 @@
                             <div class="inventory-tags-lists-name"><strong>APP名称</strong></div>
                             </div>
                             <div class="inventory-tags-lists-container">
-                                <a-checkbox-group v-model="checkedList" :options="plainOptions" @change="onChange" />
+                                <a-checkbox-group v-model="checkedList" @change="onChange" >
+
+                                    <a-checkbox :value="item.value" v-for="(item,index) in plainOptions" :key="index" :disabled="item.value==3&&getData('openProgramCreate')==1">
+                                        {{item.label}}
+                                    </a-checkbox>
+
+                                </a-checkbox-group>
                             </div>
                         </div>
                         
                         </div>
                     </div>
-                    <div class="row-item">
+
+
+
+                    <div class="row-item" v-if="getData('openProgramCreate')!=1">
                         <div class="hint-item"></div>
                         <div class="label-item">
-                        <div class="text-item">创意制作方式</div>
+                        <div class="text-item">自定义组上限</div>
                         <div class="required-item"></div>
                         </div>
                         <div class="input-item">
                         <a-form-item>
-                            <a-radio-group v-decorator="['openProgramCreate', { initialValue:2 }]">
-                                <a-radio-button :value='2'>不限</a-radio-button>
-                                <a-radio-button :value="0">自定义</a-radio-button>                            
-                                <a-radio-button :value="1">程序化</a-radio-button>                            
-                            </a-radio-group>
+                            <a-input-number
+                                v-model="customUnitCnt"
+                                style="width: 100%"
+                                placeholder="仅支持输入自然数"
+                                :max="customUnitCntMax"
+                                :precision="0"
+                            />
+                        </a-form-item>                       
+                        </div>
+                    </div>
+
+
+                    <div class="row-item" v-if="getData('openProgramCreate')!=0">
+                        <div class="hint-item"></div>
+                        <div class="label-item">
+                        <div class="text-item">程序化组上限</div>
+                        <div class="required-item"></div>
+                        </div>
+                        <div class="input-item">
+                        <a-form-item>
+                            <a-input-number
+                                v-model="programUnitCnt"
+                                style="width: 100%"
+                                placeholder="仅支持输入自然数"
+                                :max="60"
+                                :precision="0"
+                            />
                         </a-form-item>                       
                         </div>
                     </div>
+
                     <div class="row-item">
                         <div class="hint-item"></div>
                         <div class="label-item">
@@ -891,7 +1116,7 @@
                     <div class="row-item" v-if="getFormData('generalTrack')==1">
                         <div class="hint-item"></div>
                         <div class="label-item">
-                        <div class="text-item">点击监测链接</div>
+                        <div class="text-item">第三方点击监测链接</div>
                         </div>
                         <div class="input-item">
                         <a-form-item>
@@ -903,7 +1128,7 @@
                     <div class="row-item" v-if="getFormData('generalTrack')==1">
                         <div class="hint-item"></div>
                         <div class="label-item">
-                        <div class="text-item">开始播放监测链接</div>
+                        <div class="text-item">第三方开始播放监测链接</div>
                         <!-- <div class="required-item"></div> -->
                         </div>
                         <div class="input-item">
@@ -915,7 +1140,7 @@
                     <div class="row-item" v-if="whiteList.actionbar_click_url_switch==1&&getFormData('generalTrack')==1">
                         <div class="hint-item"></div>
                         <div class="label-item">
-                        <div class="text-item">点击按钮监测链接</div>
+                        <div class="text-item">第三方actionBar监测链接</div>
                         <!-- <div class="required-item"></div> -->
                         </div>
                         <div class="input-item">
@@ -1022,7 +1247,8 @@
                                     :max="15"
                                     :step="1"
                                     :min='1'
-                                    v-decorator="['imageCnt',{ initialValue:1, rules: [{ required: true, message: '请填写关联封面数' }] } ]"
+                                    v-decorator="['imageCnt',{ initialValue:5, rules: [{ required: true, message: '请填写关联封面数' }] } ]"
+                                    @change="setImageCnt"
                                 />
                           </a-form-item>
                                 
@@ -1165,7 +1391,8 @@ import { TreeSelect } from 'ant-design-vue';
 import qs from 'qs'
 const SHOW_PARENT = TreeSelect.SHOW_PARENT;
 // import selectCheckAll from './toutiaoTime'
-import radioCheck from './components/radioCheck';
+// import radioCheck from './components/radioCheck';
+import radioCheck from '@/components/formComponents/checkBoxGroup'
 import linkMultiSelect from './components/linkMultiSelect'
 import singleLayersSelecte from './components/singleLayerSelecte'
 import scheduleTime from '@/components/formComponents/toutiaoTime'
@@ -1180,35 +1407,30 @@ for (let i = 0; i < 7*24; i++) {
 
 let ageArr=[
     {
-        value:'',
-        title:'不限',
-        checked:false,
+        value:1,
+        label:'不限',
        
     },
     {
         value:18,
-        title:'	18-23岁',
-         checked:false,
+        label:'	18-23岁'
     },
     {
         value:24,
-        title:'24-30岁',
-         checked:false,
+        label:'24-30岁',
     },
     {
         value:31,
-        title:'31-40岁',
-        checked:false,
+        label:'31-40岁',
     },
     {
         value:41,
-        title:'41-49岁',
-        checked:false,
+        label:'41-49岁',
     },
     {
         value:50,
-        title:'50岁+',
-        checked:false,
+        label:'50岁+',
+        
     },
 ]
 
@@ -1279,10 +1501,7 @@ const plainOptions = [
       value: 3,
       label: '视频播放页广告'
     },
-    {
-      value: 5,
-      label: '联盟广告'
-    },
+    
 ];
 
 export default {
@@ -1297,8 +1516,14 @@ export default {
     },
     data() {
         return {
+            programUnitCnt:60,
+            customUnitCnt:400,
+            customUnitCntMax:400,
+            budgetType:'1',
+            dayBudgetType:'1',
             clickTrackUrlTip:false,
-            // deviceBrand:0,
+            deviceBrand:0,
+            devicePrice:0,
             tongbuLoading:false,
             refreshPopulationLoading:false,
             noAreaBreak:false,
@@ -1371,7 +1596,7 @@ export default {
             regionValue:'NONE',
             ageArr,//受众年龄
             region:[],
-            agesRange:[],
+            agesRange:[1],
             regionCityListUrl:'/kuaishou/batch/getRegion',
             regionCountyListUrl:'/kuaishou/batch/getRegion',
 
@@ -1525,9 +1750,12 @@ export default {
             },
     },
     methods: {
+        setImageCnt(e){
+            this.customUnitCntMax = Math.floor(2000/e)
+        },
         platformOsChange(e){
             //console.log(e);
-            // this.deviceBrand=0;
+            this.deviceBrand=0;
             this.sysType=e.target.value;
             this.sysTypeChange(e)
         },
@@ -1601,7 +1829,22 @@ export default {
             })
         },
         descriptionchange(e){
-            this.description=e.target.value
+            if(this.getData('description')){
+                this.$nextTick(()=>{
+                    this.form.setFieldsValue({
+                        description: this.getData('description').replace(/\s/g,'')
+                    })
+                })
+            }else{
+                this.$nextTick(()=>{
+                    this.form.setFieldsValue({
+                        description: undefined
+                    })
+                })
+            }
+            this.description=e.target.value.replace(/\s/g,'')
+
+           
         },
 
         //获取表单的某一个属性值
@@ -1831,7 +2074,15 @@ export default {
             onCheckAllChange(e) {
                 let valueOption = [];
                 this.plainOptions.forEach((item) => {
-                valueOption.push(item.value)
+                    if(this.getData('openProgramCreate')==1){
+                        if(item.value!=3){
+                            valueOption.push(item.value)
+                        }
+                        
+                    }else{
+                        valueOption.push(item.value)
+                    }
+                
                 })
                 Object.assign(this, {
                 checkedList: e.target.checked ? valueOption : [],
@@ -1899,13 +2150,21 @@ export default {
                 this.region=val;
             },
             //获取选中的年龄段
-            getAgeSelect(val){
-                // //console.log(val)
-                if(val.length==1&&val[0]==""){
-                    this.agesRange=[]
-                }else{
-                    this.agesRange=val;
+            getAgeSelect(data){
+
+                if (data.length > 1 && data.findIndex((item) => item == 1) == 0) {
+                    data.splice(data.findIndex((item) => item == 1),1)
+                } else if (data.length > 1 && data.findIndex((item) => item == 1) == data.length - 1) {
+                    data.splice(0, data.length - 1)
+                } else if (data.length == 0) {
+                    data.push(1)
                 }
+                // //console.log(val)
+                // if(val.length==1&&val[0]==""){
+                //     this.agesRange=[]
+                // }else{
+                //     this.agesRange=val;
+                // }
                 
             },
             //获取智能放量定向的值
@@ -2004,7 +2263,8 @@ export default {
   
             this.form.validateFields((err, values) => {
                 //console.log(values) 
-                if (!err) {                   
+                if (!err) {     
+                    console.log(values)              
                     this.goNextloading=true;
                     if(this.district!='NONE'){
                         values.district=this.district
@@ -2036,7 +2296,7 @@ export default {
                     // }
                     values.appIdArray=values.appId instanceof Array?JSON.stringify(values.appId):JSON.stringify([values.appId])
                     values.appId=undefined;
-                    values.agesRange=JSON.stringify(this.agesRange)
+                    values.agesRange=this.agesRange[0]==1?JSON.stringify([]):JSON.stringify(this.agesRange)
                     values.region=JSON.stringify(this.region);
                     
                     values.convertId=this.convertId==''?undefined:this.convertId;
@@ -2083,10 +2343,8 @@ export default {
                          values.creativeCategory=undefined
                     }
                     
-                    // if(this.deviceBrand==0){
-                        
-                    // }
-                    // values.deviceBrand=this.deviceBrand==0?'[0]':JSON.stringify(values.deviceBrand)
+                    values.deviceBrand=this.deviceBrand==0?'[]':JSON.stringify(values.deviceBrand)
+                    values.devicePrice=this.devicePrice==0?'[]':JSON.stringify(values.devicePrice)
                     values.accountId = this.accountId
                    
                     values.creativeTag=values.creativeTag?JSON.stringify(values.creativeTag):undefined
@@ -2095,6 +2353,18 @@ export default {
                     values.noGenderBreak=this.noGenderBreak?1:0
                     values.noAgeBreak=this.noAgeBreak?1:0
 
+                    values.campaignDayBudget = this.budgetType =='1'?0: values.campaignDayBudget*1000
+                    values.unitDayBudget = this.dayBudgetType =='1'?0: values.unitDayBudget*1000
+                    if(this.getData('openProgramCreate')==0){
+                        values.customUnitCnt = this.customUnitCnt
+                    }else if(this.getData('openProgramCreate')==1){
+                        values.programUnitCnt = this.programUnitCnt
+                    }else{
+                        values.customUnitCnt = this.customUnitCnt
+                        values.programUnitCnt = this.programUnitCnt
+                    }
+                    
+                    
                     //console.log('Received values of form: ', values)
                     let url=''
                     if(this.editRecordId){
@@ -2278,6 +2548,8 @@ export default {
                 this.actionBarTextList = res.result
             }
             })
+
+            
         },
 
         // 获取创意分类创意标签白名单
@@ -2353,10 +2625,20 @@ export default {
                         }
                     }
                     
-                    // if(res.result.deviceBrand){
+                    
                         
-                    //     this.deviceBrand=res.result.deviceBrand.indexOf(0)>-1?0:1;
-                    // }
+                    this.deviceBrand=res.result.deviceBrand?JSON.parse(res.result.deviceBrand).length>0?1:0:0;
+                    
+                    
+                    this.devicePrice=res.result.devicePrice?JSON.parse(res.result.devicePrice).length>0?1:0:0
+                    
+
+                    this.budgetType = res.result.campaignDayBudget?res.result.campaignDayBudget>0?'2':'1':'1'
+                    this.dayBudgetType = res.result.unitDayBudget?res.result.unitDayBudget>0?'2':'1':'1'
+                    this.customUnitCnt = res.result.customUnitCnt
+                    this.programUnitCnt = res.result.programUnitCnt
+                    this.customUnitCntMax = Math.floor(2000/res.result.imageCnt)
+
                     setTimeout(()=>{                       
                         this.form.setFieldsValue({
                              ...res.result,
@@ -2365,9 +2647,21 @@ export default {
                             isOpen:res.result.isOpen?res.result.isOpen:0,
                             cpaBid:res.result.cpaBid/1000,
                             appId:res.singleAppid?JSON.parse(res.result.appIdArray)[0]:JSON.parse(res.result.appIdArray),
-                            // deviceBrand:res.result.deviceBrand?JSON.parse(res.result.deviceBrand):[],
+                            deviceBrand:res.result.deviceBrand?JSON.parse(res.result.deviceBrand):[],
+                            devicePrice:res.result.devicePrice?JSON.parse(res.result.devicePrice):[],
+                           
+                            campaignDayBudget:res.result.campaignDayBudget?res.result.campaignDayBudget/1000:null,
+                            unitDayBudget:res.result.unitDayBudget?res.result.unitDayBudget/1000:null
+                           
                         })
                     },0)
+                    setTimeout(()=>{
+                         this.form.setFieldsValue({
+                             androidOsv:res.result.androidOsv?res.result.androidOsv:3,
+                            iosOsv:res.result.iosOsv?res.result.iosOsv:6,
+                        })
+                        
+                    },100)
                     if((res.result.ocpxActionType == 180 || res.result.ocpxActionType == 53) && this.groupTypeData.deepConversionTypes&&this.groupTypeData.deepConversionTypes.length > 0){
                         // //console.log(1)
                         setTimeout(()=>{
@@ -2390,19 +2684,22 @@ export default {
                     this.ageArr=[];
                     this.ageArr=JSON.parse(JSON.stringify(ageArr))
                     
-                    let agesRange=res.result.agesRange?JSON.parse(res.result.agesRange):[]
-                    if(agesRange.length>0){
-                        agesRange.forEach((item,index)=>{                   
-                            this.ageArr.forEach((ele)=>{
-                                if(ele.value==item){
-                                    ele.checked=true;
-                                }
-                            })                   
-                        });
-                    }
+                    this.agesRange=res.result.agesRange?JSON.parse(res.result.agesRange).length>0?JSON.parse(res.result.agesRange):[1]:[1]
+                    // if(agesRange.length>0){
+                    //     agesRange.forEach((item,index)=>{                   
+                    //         this.ageArr.forEach((ele)=>{
+                    //             if(ele.value==item){
+                    //                 ele.checked=true;
+                    //             }
+                    //         })                   
+                    //     });
+                    // }
                     let sceneId=res.result.sceneId?JSON.parse(res.result.sceneId):[]
                     if(sceneId.length==1&&sceneId[0]==1){
                         this.adposition=1
+                    }else if(sceneId.length==1&&sceneId[0]==5){
+                        this.adposition=5
+                        
                     }else{
                         this.adposition='inventoryTypes';
                         this.checkedList=sceneId
@@ -2489,7 +2786,52 @@ export default {
         clickTrackUrlBlur(){
             // //console.log('blur')
             this.clickTrackUrlTip=false;
-        }
+        },
+        getChangeAll(type, form, field) {
+            var node = document.getElementById(field)
+            var v = '-{{' + type + '}}-'
+            if (document.selection) {
+                //IE
+                node.focus()
+                var sel = document.selection.createRange()
+                sel.text = v
+                sel.select()
+                if (field == 'campaignName') {
+                this[form].setFieldsValue({ campaignName: sel.text })
+                } else if (field == 'groupName') {
+                this[form].setFieldsValue({ groupName: sel.text })
+                }
+            } else if (node.selectionStart || node.selectionStart == '0') {
+                //MOZILLA/GOOGLE
+                var startPos = node.selectionStart
+                var endPos = node.selectionEnd
+                var restoreTop = node.scrollTop
+                node.value = node.value.substring(0, startPos) + v + node.value.substring(endPos, node.value.length)
+                if (restoreTop > 0) {
+                node.scrollTop = restoreTop
+                }
+                if (field == 'campaignName') {
+                this[form].setFieldsValue({ campaignName: node.value })
+                } else if (field == 'groupName') {
+                this[form].setFieldsValue({ groupName: node.value })
+                }
+                node.focus()
+                node.selectionStart = startPos + v.length
+                node.selectionEnd = startPos + v.length
+                // this.campaignName = node.value
+            } else {
+                //OTHER
+                node.value += v
+                // console.log(node.value)
+                if (field == 'campaignName') {
+                this[form].setFieldsValue({ campaignName: node.value })
+                } else if (field == 'groupName') {
+                this[form].setFieldsValue({ groupName: node.value })
+                }
+                node.focus()
+                // this.campaignName = node.value
+            }
+        },
     },
     created() {
         if(this.$route){

+ 64 - 0
src/views/modules/crowd-control/components/tree-select/tree-select.less

@@ -0,0 +1,64 @@
+
+.tree-select-content {
+    .input-search {
+        width: 240px;
+        margin: 10px 0 10px 0;
+    }
+    .tree-select-class {
+        display: flex;
+        justify-content: space-between;
+        .class-left-header {
+            height: 50px;
+            line-height: 50px;
+            background-color: #ccc;
+            text-indent: 10px;
+        }
+        .select-class-left {
+            width: 60%;
+            height: 400px;
+            border: 1px solid #ccc;
+            .class-left-content {
+                overflow-y: auto;
+                height: 340px;
+            }
+            .example {
+                text-align: center;
+                line-height: 200px;
+            }
+        }
+        .select-class-right {
+            width: 35%;
+            height: 400px;
+            border: 1px solid #ccc;
+            .class-left-content {
+                padding: 0 10px;
+                height: 348px;
+                overflow-y: auto;
+                .apply-right-tree {
+                    display: flex;
+                    justify-content: space-between;
+                    align-items: baseline;
+                    .left-content-p {
+                        display: inline-block;
+                        width: 85%;
+                        height: 25px;
+                        line-height: 25px;
+                        margin: 0;
+                        overflow: hidden;
+                        text-overflow: ellipsis;
+                        white-space: nowrap;
+                    }
+                    .delete-type-class {
+                        color: #1890ff;
+                        cursor: pointer;
+                    }
+                }
+            }
+            .no-data-class {
+                height: 340px;
+                line-height: 340px;
+                text-align: center;
+            }
+        }
+    }
+}

+ 238 - 0
src/views/modules/crowd-control/components/tree-select/tree-select.vue

@@ -0,0 +1,238 @@
+<template>
+    <div class="tree-select-content">
+        <a-input-search class="input-search" placeholder="请输入账户名或ID" @change="onChange" />
+        <div class="tree-select-class">
+            <div class="select-class-left">
+                <div class="class-left-header">选择分享的账户名称</div>
+                <div class="class-left-content">
+                    <template>
+                        <a-tree
+                            v-model="checkedKeys"
+                            checkable
+                            :expanded-keys="expandedKeys"
+                            :auto-expand-parent="autoExpandParent"
+                            :selected-keys="selectedKeys"
+                            :tree-data="treeData"
+                            @check="onCheck"
+                            @expand="onExpand"
+                        />
+                    </template>
+                    <div class="example">
+                        <a-spin :spinning="spinning"/>
+                        <span v-if="leftTreeNoData">暂无数据</span>
+                    </div>
+                </div>
+            </div>
+            <div class="select-class-right">
+                <div class="class-left-header">
+                    已选 ({{ applyTypeOption.length ? applyTypeOption.length : 0}}/100)
+                    <a-popover placement="topRight">
+                        <template slot="content">
+                            <p>1、输入账户超出推送范围,请检查是否同主体账户</p>
+                            <p>2、有效账户将不会重复推送,请登录该账户查看使用</p>
+                        </template>
+                        <span><a-icon type="question-circle" /></span>
+                    </a-popover>
+                </div>
+                <div v-if="applyTypeOption.length" class="class-left-content">
+                    <div class="apply-right-tree" v-for="item in applyTypeOption" :key="item.key">
+                        <p class="left-content-p">
+                            <a-tooltip placement="left">
+                                <template slot="title">
+                                    <span>{{ item.title }}</span>
+                                </template>
+                                {{ item.title }}
+                            </a-tooltip>
+                        </p>
+                        <a-icon type="delete" class="delete-type-class" @click="handleDelTree(item)" />
+                    </div>
+                </div>
+                <div v-else class="no-data-class">暂无数据</div>
+            </div>
+        </div>
+    </div>
+</template>
+<script>
+import {mapGetters} from 'vuex';
+import {postAction} from '@/api/manage';
+
+export default {
+    name: 'tree-select',
+    data() {
+        return {
+            expandedKeys: [],
+            autoExpandParent: true,
+            checkedKeys: [],
+            selectedKeys: [],
+            treeData: [],
+            updateTreeData: [],
+            applyTypeOption: [],
+            selectRightData: new Set(),
+            spinning: true,
+            leftTreeNoData: false
+        };
+    },
+    mounted() {
+        this.getAccountId();
+    },
+    methods: {
+        ...mapGetters(['userInfo']),
+        getAccountId() {
+            postAction('/ctop/projectMember/participateListByMediaId', {
+                userId: this.userInfo().id,
+                type: 'kuaishou'
+            }).then(result => {
+                if (result.result.length) {
+                    this.spinning = false;
+                    this.treeData = result.result.map(item => {
+                        return {
+                            key: item.projectId + 'projectId',
+                            title: item.projectName + '\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0' + item.advertiserName,
+                            children: item.accountList
+                            ? item.accountList.map(i => {
+                                return {
+                                    key: i.accountId,
+                                    title:
+                                    (i.userName.length === 2
+                                        ? i.userName + '\xa0\xa0\xa0\xa0\xa0'
+                                        : i.userName.length === 3
+                                        ? i.userName + '\xa0\xa0\xa0\xa0'
+                                        : i.userName)
+                                        + '\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0'
+                                        + i.accountId
+                                        + '\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0'
+                                        + i.authName
+                                };
+                            }) : []
+                        };
+                    });
+                    this.updateTreeData = [...this.treeData];
+                }
+                else {
+                    this.spinning = false;
+                    this.leftTreeNoData = true;
+                }
+            });
+        },
+        handleDelTree(list) {
+            const defaultTypeOption = JSON.parse(JSON.stringify(this.applyTypeOption));
+            const defaultCheckKey = JSON.parse(JSON.stringify(this.checkedKeys));
+            const len = defaultTypeOption.length;
+            const keysLen = defaultCheckKey.length;
+            for(let i = len - 1; i >= 0; i--) {
+                if(defaultTypeOption[i].key === list.key) {
+                    defaultTypeOption.splice(i, 1);
+                }
+            }
+            this.applyTypeOption = defaultTypeOption;
+            this.selectRightData = new Set(defaultTypeOption);
+            for(let i = keysLen - 1; i >= 0; i--) {
+                if(defaultCheckKey[i] === list.key) {
+                    defaultCheckKey.splice(i, 1);
+                }
+            }
+            const txt = this.handleDelFindId(this.treeData, list.key);
+            const lastIndex = defaultCheckKey.findIndex(item => item === txt);
+            defaultCheckKey.splice(lastIndex, 1);
+            this.checkedKeys = defaultCheckKey;
+        },
+        onChange(e) {
+            const value = e.target.value;
+            this.treeData = value !== '' ? this.getNewTreeData(this.updateTreeData, value) : [...this.updateTreeData];
+            if (!this.treeData.length) {
+                this.spinning = false;
+                this.leftTreeNoData = true;
+            }
+            else {
+                this.leftTreeNoData = false;
+            }
+        },
+        handleDelFindId(treeData, value) {
+            if (!treeData) {
+                return null;
+            }
+            let node = null;
+            let children = null;
+            let text = '';
+            for (let i = 0; i < treeData.length; i++) {
+                node = treeData[i];
+                if (node.children) {
+                    children = node.children;
+                    text = node.key;
+                    for (let j = 0; j < children.length; j++) {
+                        if (children[j].key === value) {
+                            return text;
+                        }
+                    }
+                }
+            }
+        },
+        // 根据关键词查询所有相关的tree节点
+        getNewTreeData(treeData, value) {
+            if (!treeData) {
+                return null;
+            }
+            let newTreeData = new Array();
+            let node = null;
+            let children = null;
+            let text = '';
+            for (let i = 0; i < treeData.length; i++) { // 多个根节点开始遍历
+                node = treeData[i];
+                if (node.children) {
+                    children = node.children;
+                }
+                text = node.title;
+                if (text.indexOf(value) > -1) {
+                    newTreeData.push(node);
+                    continue;
+                }
+                else {
+                    if (children) {
+                        let newNodes = this.getNewTreeData(node.children, value);
+                        if (newNodes.length > 0) {
+                            node.children = newNodes;
+                            newTreeData.push(node);
+                        }
+                    }
+                }
+
+            }
+            return newTreeData;
+        },
+        onExpand(expandedKeys) {
+            this.expandedKeys = expandedKeys;
+            this.autoExpandParent = false;
+        },
+        onCheck(checkedKeys) {
+            this.nodes(this.treeData, checkedKeys);
+            this.applyTypeOption = [...this.selectRightData];
+            const changeSelectData = [...this.selectRightData].map(item => item.key);
+            if (this.applyTypeOption.length > 100) {
+                const lastOptionKey = this.applyTypeOption[99].key;
+                const lastIndex = changeSelectData.findIndex(item => item === lastOptionKey);
+                this.checkedKeys = changeSelectData.slice(0, lastIndex + 1);
+                this.applyTypeOption = [...this.selectRightData].slice(0, 100);
+            }
+            this.$emit('applyType', this.applyTypeOption);
+        },
+        nodes(data, checkedKeys) {
+            data.forEach(item => {
+                if (item.children) {
+                    this.nodes(item.children, checkedKeys);
+                }
+                else {
+                    if (checkedKeys.indexOf(item.key) !== -1) {
+                        this.selectRightData.add(item);
+                    }
+                    else {
+                        this.selectRightData.delete(item);
+                    }
+                }
+            });
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+    @import 'tree-select';
+</style>

+ 216 - 0
src/views/modules/crowd-control/crowd-control-service.js

@@ -0,0 +1,216 @@
+/**
+ * @file 人群包管理基础服务
+ * @author jiayufei(jiayufei@c-top.com.cn)
+ */
+
+class AppMarketService {
+    constructor() {}
+
+    // 相关账户的table列表
+    setAcountColumns() {
+        return [
+            {
+                title: '项目名称',
+                dataIndex: 'accountName',
+                width: '35%'
+            },
+            {
+                title: '所属项目',
+                dataIndex: 'projectName',
+                width: '35%'
+            },
+            {
+                title: '人群包数量',
+                dataIndex: 'count',
+                width: '20%'
+            }
+        ]
+    }
+
+    // 原因的table列表
+    setCauseColumns() {
+        return [
+            {
+                title: '项目名称',
+                dataIndex: 'projectName',
+                width: '30%'
+            },
+            {
+                title: '账户名称',
+                dataIndex: 'accountName',
+                width: '30%'
+            },
+            {
+                title: '原因',
+                dataIndex: 'message',
+                width: '40%'
+            }
+        ]
+    }
+
+    // 相关项目的table列表
+    setDepColumns() {
+        return [
+            {
+                title: '项目名称',
+                dataIndex: 'projectName',
+                width: '40%'
+            },
+            {
+                title: '账户数量',
+                dataIndex: 'accountCount',
+                width: '20%'
+            },
+            {
+                title: '人群包数量',
+                dataIndex: 'count',
+                width: '20%'
+            }
+        ]
+    }
+
+    // 状态枚举
+    setStatusTasks() {
+        return [
+            {
+                label: 0,
+                value: '计算中'
+            },
+            {
+                label: 1,
+                value: '已生效'
+            },
+            {
+                label: 3,
+                value: '推送中'
+            },
+            {
+                label: 4,
+                value: '已推送'
+            },
+            {
+                label: 5,
+                value: '计算失败'
+            },
+            {
+                label: 6,
+                value: '推送失败'
+            },
+            {
+                label: 7,
+                value: '已失效'
+            }
+        ]
+    }
+
+    // 上传人去报的校验规则
+    setPersonRules() {
+        return {
+            name: [
+                {required: true, message: '人群包名称不能为空', trigger: 'blur'},
+                {min: 1, max: 20, message: '人群包名称不能超过20个字符', trigger: 'blur'}
+            ],
+            resource: [
+                {required: true, message: '请选择匹配类型', trigger: 'change'}
+            ]
+        }
+    }
+
+    // 人群包类型枚举值
+    setPopulationTypeTasks() {
+        return [
+            {
+                label: 1,
+                value: '上传人群'
+            }, {
+                label: 2,
+                value: '广告人群'
+            }, {
+                label: 3,
+                value: '主题专区'
+            }, {
+                label: 4,
+                value: '逻辑规则'
+            }, {
+                label: 5,
+                value: '人群扩展'
+            }, {
+                label: 6,
+                value: '平台制定'
+            }, {
+                label: 7,
+                value: '定制付费'
+            }, {
+                label: 8,
+                value: '网红粉丝类别'
+            }, {
+                label: 9,
+                value: '内容付费行为'
+            }, {
+                label: 10,
+                value: '移动应用安装'
+            }, {
+                label: 11,
+                value: '快手使用活跃度'
+            }, {
+                label: 12,
+                value: '行业分类'
+            }, {
+                label: 13,
+                value: '商业兴趣'
+            }, {
+                label: 14,
+                value: '固话标签'
+            }, {
+                label: 15,
+                value: '行业偏好'
+            }, {
+                label: 16,
+                value: '第三方标签'
+            }, {
+                label: 17,
+                value: '产品关键词'
+            }, {
+                label: 19,
+                value: '应用渗透率'
+            }, {
+                label: 22,
+                value: '指定网红'
+            }, {
+                label: 23,
+                value: '行业分类'
+            }
+        ]
+    }
+
+    // 匹配类型枚举值
+    setMateTypeTasks() {
+        return [
+            {
+                label: 1,
+                value: 'IMEI'
+            }, {
+                label: 2,
+                value: 'IDFA'
+            }, {
+                label: 3,
+                value: 'IMEI_MD5'
+            }, {
+                label: 4,
+                value: 'IDFA_MD5'
+            }, {
+                label: 5,
+                value: '手机号-MD5'
+            }, {
+                label: 7,
+                value: 'OAID'
+            }, {
+                label: 8,
+                value: 'OAID_MD5'
+            }
+        ]
+    }
+
+}
+
+export default new AppMarketService();

+ 102 - 0
src/views/modules/crowd-control/crowd-control.less

@@ -0,0 +1,102 @@
+.crowd-control-content {
+    background: #fff;
+    height: calc(100vh - 137px);
+    padding: 20px;
+    overflow-y: auto;
+    .control-con-header {
+        margin-bottom: 20px;
+        position: relative;
+        /deep/ .ant-form-inline .ant-form-item > .ant-form-item-control-wrapper, .ant-form-inline .ant-form-item > .ant-form-item-label {
+            width: 200px !important;
+        }
+        .reset-class {
+            margin-right: 10px !important;
+        }
+        .upload-person {
+            position: absolute;
+            right: 10px;
+            top: 0;
+        }
+    }
+    .cause-text-class {
+        cursor: pointer;
+    }
+    .pagin-table-class {
+        display: flex;
+        justify-content: flex-end;
+        margin-top: 20px;
+    }
+    .acount-search-class {
+        width: 200% !important;
+    }
+    .grid-form-type {
+        margin-left: 210px;
+    }
+}
+/deep/ .push-modal {
+    width: 600px !important;
+    .acount-title {
+        display: flex;
+        font-size: 14px;
+        height: 40px;
+        line-height: 40px;
+        .acount-title-left {
+            margin-right: 20px;
+            width: 100px;
+        }
+    }
+    .push-plate {
+        margin-bottom: 20px;
+    }
+}
+.person-modal {
+    width: 500px;
+    /deep/ .ant-form-item {
+        display: flex;
+    }
+    /deep/ .ant-form-item-label {
+        width: 20%;
+    }
+    /deep/ .ant-form-item-control-wrapper {
+        width: 80%;
+    }
+    .acount-search-class {
+        width: 100% !important;
+    }
+    .upload-txt-rules {
+        margin-top: 10px;
+        margin-bottom: 10px;
+        line-height: 1.5;
+    }
+    /deep/ .ant-radio-group {
+        line-height: 30px;
+    }
+}
+/deep/ .cause-modal {
+    width: 600px !important;
+    .cause-modal-table-class {
+        height: 500px;
+        overflow-y: auto;
+    }
+    .pagin-table-class {
+        display: flex;
+        justify-content: flex-end;
+        margin-top: 20px;
+    }
+}
+/deep/ .relax-modal {
+    width: 600px !important;
+    .acount-title {
+        display: flex;
+        font-size: 14px;
+        height: 40px;
+        line-height: 40px;
+        .acount-title-left {
+            margin-right: 20px;
+            width: 100px;
+        }
+    }
+    .push-plate {
+        margin-bottom: 20px;
+    }
+}

+ 619 - 0
src/views/modules/crowd-control/crowd-control.vue

@@ -0,0 +1,619 @@
+<template>
+    <div class="crowd-control-content">
+        <div class="control-con-header">
+            <a-form
+                class="grid-form" layout="inline"
+                :form="form"
+                hide-required-mark
+                @submit="handleQueryList"
+            >
+                <a-row class="grid-form-options">
+                    <a-form-item
+                        class="grid-form-item"
+                        label="名称"
+                        :colon="false"
+                    >
+                        <a-input
+                            v-decorator="['name']" type="text"
+                            placeholder="请输入"
+                        />
+                    </a-form-item>
+                    <a-form-item
+                        class="grid-form-item" label="账户"
+                        :colon="false"
+                    >
+                        <acount-search class="acount-search-class" :appId.sync="acountId" :multiple="false"></acount-search>
+                    </a-form-item>
+                    <a-form-item
+                        class="grid-form-item grid-form-type" label="状态"
+                        :colon="false"
+                    >
+                        <a-select
+                            v-decorator="['status']"
+                            placeholder="请选择"
+                            allow-clear
+                        >
+                            <a-select-option v-for="item in statusTasks" :key="item.label">
+                                {{ item.value }}
+                            </a-select-option>
+                        </a-select>
+                    </a-form-item>
+                    <a-form-item class="form-handle-btn">
+                        <a-button type="default" class="reset-class" @click="handleResetForm">重置</a-button>
+                        <a-button type="primary" html-type="submit">查询</a-button>
+                    </a-form-item>
+                </a-row>
+            </a-form>
+            <a-button type="primary" class="upload-person" @click="handleUploadPerson">
+                上传人群包
+            </a-button>
+        </div>
+        <div class="control-con-table">
+            <a-table
+                ref="table"
+                size="middle"
+                bordered
+                :columns="columns"
+                :dataSource="dataSource"
+                :pagination="false"
+            >
+                <span slot="action" slot-scope="text, record">
+                    <a @click="handleEdit(record)">推送</a>
+                    <a-divider type="vertical" />
+                    <a @click="handleDelete(record)">删除</a>
+                </span>
+                <span slot="cause" slot-scope="text, record">
+                    <a class="cause-text-class" @click="handleCause(record)">失败原因</a>
+                </span>
+                <span slot="depRelax" slot-scope="text, record">
+                    <a @click="handleAcountRelax('dep', record)">{{ text }}</a>
+                </span>
+                <span slot="acountRelax" slot-scope="text, record">
+                    <a @click="handleAcountRelax('acount', record)">{{ text }}</a>
+                </span>
+            </a-table>
+            <a-pagination
+                class="pagin-table-class"
+                :total="totalAll"
+                :show-total="total => `共 ${totalAll} 条`"
+                size="small"
+                show-size-changer
+                show-quick-jumper
+                @change="onShowSizeChange"
+                @showSizeChange="onShowSizeChange"
+            />
+        </div>
+        <a-modal
+            v-if="personVisible"
+            title="上传人群包"
+            class="person-modal"
+            :visible="personVisible"
+            :confirm-loading="confirmLoading"
+            @ok="handleOk"
+            @cancel="handleCancel"
+        >
+            <div>
+                <a-form-model
+                    ref="ruleForm"
+                    :model="personForm"
+                    :rules="personRules"
+                    :label-col="labelCol"
+                    :wrapper-col="wrapperCol"
+                >
+                    <a-form-model-item label="匹配类型" prop="resource">
+                        <a-radio-group v-model="personForm.resource">
+                            <a-radio v-for="item in mateTypeTasks" :key="item.label" :value="item.label">{{ item.value }}</a-radio>
+                        </a-radio-group>
+                    </a-form-model-item>
+                    <a-form-model-item ref="name" label="人群包名称" prop="name">
+                        <a-input
+                            v-model="personForm.name"
+                            placeholder="请输入人群包名称"
+                        />
+                    </a-form-model-item>
+                    <a-form-model-item label="选择账户">
+                        <acount-search class="acount-search-class" :appId.sync="uploadAcountIds" :multiple="false"></acount-search>
+                    </a-form-model-item>
+                    <a-form-model-item label="上传人群包">
+                        <a-upload
+                            name="file"
+                            :file-list="fileList"
+                            :before-upload="beforeUpload"
+                            @change="handleChange"
+                        >
+                            <a-button><a-icon type="upload" />文件上传</a-button>
+                        </a-upload>
+                        <p class="upload-txt-rules">1、文件格式:支持上传*.txt(utf-8)文本;也支持将单个/多个*.txt文件经过Zip格式压缩上传</p>
+                        <p class="upload-txt-rules">2、文件大小:单个文件大小不能超过1G</p>
+                        <p class="upload-txt-rules">3、内容编排:每行一条记录</p>
+                    </a-form-model-item>
+                </a-form-model>
+            </div>
+        </a-modal>
+        <a-modal
+            title="推送账户"
+            v-if="pushVisible"
+            :visible="pushVisible"
+            :confirm-loading="pushConfirmLoading"
+            dialog-class="push-modal"
+            @ok="handlePushSure"
+            @cancel="handlePushCancel"
+        >
+            <div>
+                <div class="acount-title">
+                    <div class="acount-title-left">已选人群包</div>
+                    <div class="acount-title-right">{{ tableSelectList.orientationName }} (ID: {{ tableSelectList.id }})</div>
+                </div>
+                <div class="acount-title push-plate">
+                    <div class="acount-title-left">推送平台</div>
+                    <div class="acount-title-right">
+                        <a-radio-group default-value="a" button-style="solid">
+                            <a-radio-button value="a">效果</a-radio-button>
+                            <a-radio-button value="b" disabled>品牌</a-radio-button>
+                        </a-radio-group>
+                    </div>
+                </div>
+                <tree-select @applyType="handleApplyType"></tree-select>
+            </div>
+        </a-modal>
+        <a-modal
+            title="相关项目"
+            v-if="causeVisible"
+            :visible="causeVisible"
+            :confirm-loading="causeConfirmLoading"
+            :footer="null"
+            dialog-class="cause-modal"
+            @cancel="handleCauseCancel"
+        >
+            <div>
+                <div class="cause-modal-table-class">
+                    <a-table :columns="causeColumns" :data-source="causeData" bordered :pagination="false"></a-table>
+                </div>
+                <a-pagination
+                    class="pagin-table-class"
+                    :total="totalAllCause"
+                    size="small"
+                    @change="handleCauseSizeChange"
+                />
+            </div>
+        </a-modal>   
+        <a-modal
+            title="相关项目"
+            v-if="relaxVisible"
+            :visible="relaxVisible"
+            :confirm-loading="relaxConfirmLoading"
+            :footer="null"
+            dialog-class="relax-modal"
+            @cancel="handleRelaxCancel"
+        >
+            <div>
+                <div class="acount-title">
+                    <div class="acount-title-left">人群包名称</div>
+                    <div class="acount-title-right">{{ acountRelaxDetail.orientationName }}</div>
+                </div>
+                <div class="acount-title push-plate">
+                    <div class="acount-title-left">目标账户</div>
+                    <div class="acount-title-right">{{ acountRelaxDetail.accountName }}</div>
+                </div>
+                <template v-if="relaxStatus === 'dep'">
+                    <a-table :columns="depColumns" :data-source="depData" bordered>
+                    </a-table>
+                </template>
+                <template v-if="relaxStatus === 'acount'">
+                    <a-table :columns="acountColumns" :data-source="acountData" bordered></a-table>
+                </template>
+            </div>
+        </a-modal>
+    </div>
+</template>
+<script>
+import TreeSelect from './components/tree-select/tree-select';
+import {getAction, postAction} from '@/api/manage';
+import AcountSearch from '@/views/modules/Statistics/components/Treeselect.vue';
+import AppMarketService from './crowd-control-service';
+
+let COS = require('cos-js-sdk-v5');
+let cos = new COS({
+    SecretId: 'AKIDE6IpMi8fJQRCg1iuWzFajjRs43kbbets',
+    SecretKey: 'tXzuwMfplTTK3c9GFUyETilasvQfePu9'
+});
+export default {
+    name: 'crowd-control',
+    components: {
+        TreeSelect,
+        AcountSearch
+    },
+    data() {
+        let that = this;
+        return {
+            totalAllCause: 0,
+            acountId: undefined, // 搜索的账户ID
+            uploadAcountIds: '',
+            totalAll: 10,
+            finallyRightTree: [],
+            fileList: [],
+            relaxVisible: false,
+            relaxConfirmLoading: false,
+            pushVisible: false,
+            pushConfirmLoading: false,
+            causeVisible: false,
+            causeConfirmLoading: false,
+            labelCol: {span: 4},
+            wrapperCol: {span: 14},
+            personVisible: false,
+            confirmLoading: false,
+            mateTypeTasks: AppMarketService.setMateTypeTasks(), // 匹配类型
+            populationTypeTasks: AppMarketService.setPopulationTypeTasks(), // 人群包类型
+            statusTasks: AppMarketService.setStatusTasks(), // 状态枚举
+            relaxStatus: '',
+            causeData: [], // 原因的table列表数据,
+            depData: [], // 相关项目的table列表数据,
+            acountData: [], // 相关账户的table列表数据,
+            acountColumns: AppMarketService.setAcountColumns(), // 相关账户的table列表
+            depColumns: AppMarketService.setDepColumns(), // 相关项目的table列表
+            causeColumns: AppMarketService.setCauseColumns(), // 原因的table列表
+            dataSource: [],
+            columns: [
+                {
+                    title: '人群包名称',
+                    align: 'center',
+                    width: 200,
+                    ellipsis: true,
+                    dataIndex: 'orientationName'
+                },
+                {
+                    title: '人群包类型',
+                    align: 'center',
+                    dataIndex: 'populationType',
+                    customRender(t) {
+                        return t ? that.populationTypeTasks.find(item => item.label === Number(t)).value : '-';
+                    }
+                },
+                {
+                    title: '匹配类型',
+                    align: 'center',
+                    dataIndex: 'typeStr'
+                },
+                {
+                    title: '上传时间',
+                    dataIndex: 'statDate',
+                    align: 'center'
+                },
+                {
+                    title: '覆盖数量',
+                    dataIndex: 'coverNum',
+                    align: 'center'
+                },
+                {
+                    title: '状态',
+                    dataIndex: 'statusStr',
+                    align: 'center'
+                },
+                {
+                    title: '原因',
+                    dataIndex: '',
+                    align: 'center',
+                    scopedSlots: {customRender: 'cause'}
+                },
+                {
+                    title: '目标账户',
+                    dataIndex: 'accountName',
+                    align: 'center',
+                    ellipsis: true
+                },
+                {
+                    title: '相关项目',
+                    dataIndex: 'projectCount',
+                    align: 'center',
+                    scopedSlots: {customRender: 'depRelax'}
+                },
+                {
+                    title: '相关账户',
+                    dataIndex: 'accountCount',
+                    align: 'center',
+                    scopedSlots: {customRender: 'acountRelax'}
+                },
+                {
+                    title: '操作',
+                    dataIndex: 'action',
+                    align: 'center',
+                    scopedSlots: {customRender: 'action'}
+                }
+            ],
+            personForm: {
+                name: '',
+                resource: ''
+            },
+            personRules: AppMarketService.setPersonRules(), // 上传人群包表单校验规则
+            tablePag: {
+                page: 1,
+                size: 10
+            },
+            // table 原因的分页
+            causePag: {
+                page: 1,
+                size: 10
+            },
+            tableSelectList: {},
+            acountRelaxDetail: {},
+            causeDetailData: {}
+        };
+    },
+    created() {
+        this.form = this.$form.createForm(this);
+    },
+    mounted() {
+        this.handleGetTableList({});
+    },
+    methods: {
+        onShowSizeChange(current, pageSize) {
+            const paramsData = this.form.getFieldsValue();
+            this.tablePag = {
+                page: current,
+                size: pageSize
+            };
+            this.handleGetTableList(paramsData);
+        },
+        handleCauseSizeChange(current, pageSize) {
+            this.causePag = {
+                page: current,
+                size: pageSize
+            };
+            this.handleCauseTableData();
+        },
+        handleGetTableList(data) {
+            const paramsData = {
+                orientationName: data.name,
+                accountName: this.acountId,
+                status: data.status,
+                pageNo: this.tablePag.page,
+                pageSize: this.tablePag.size
+            };
+            getAction('/kuaishouCrowdPack/queryPageList', paramsData).then(result => {
+                if (result.code === 200) {
+                    this.dataSource = result.result.list || [];
+                    this.totalAll = result.result.total || 0;
+                }
+                else {
+                    this.$message.error(result.message);
+                }
+            }).catch(error => {
+                console.log(error, 'eeee');
+            });
+        },
+        handleDelete(data) {
+            this.$confirm({
+                title: '删除提示',
+                content: '确定要删除这一条吗?',
+                onOk() {
+                    getAction('/kuaishouCrowdPack/delete', {id: data.id}).then(result => {
+                        if (result.code === 200) {
+                            this.handleGetTableList({});
+                        }
+                        else {
+                            this.$message.error(result.message);
+                        }
+                    }).catch(error => {
+                        console.log(error, 'eeee');
+                    });
+                }
+            });
+        },
+        handleAcountRelaxTable() {
+            const paramsData = {
+                signature: this.acountRelaxDetail.signature,
+                accountId: this.acountRelaxDetail.accountId,
+                type: this.relaxStatus === 'dep' ? 1 : 2
+            };
+            getAction('/kuaishouCrowdPack/queryRel', paramsData).then(result => {
+                if (result.code === 200) {
+                    if (this.relaxStatus === 'dep') {
+                        this.depData = result.result.list;
+                    }
+                    else if (this.relaxStatus === 'acount') {
+                        this.acountData = result.result.list;
+                    }
+                }
+                else {
+                    this.$message.error(result.message);
+                }
+            }).catch(error => {
+                console.log(error, 'eeee');
+            });
+        },
+        handleAcountRelax(txt, recd) {
+            if (txt === 'dep') {
+                this.relaxStatus = 'dep';
+            }
+            else if (txt === 'acount') {
+                this.relaxStatus = 'acount';
+            }
+            this.acountRelaxDetail = recd;
+            this.handleAcountRelaxTable();
+            this.relaxVisible = true;
+        },
+        handleRelaxCancel() {
+            this.relaxVisible = false;
+        },
+        handleCause(list) {
+            this.causeVisible = true;
+            this.causeDetailData = list;
+            this.handleCauseTableData();
+        },
+        handleCauseTableData() {
+            const paramsData = {
+                signature: this.causeDetailData.signature,
+                pageNo: this.causePag.page,
+                pageSize: this.causePag.size
+            };
+            getAction('/kuaishouCrowdPack/queryFailReason', paramsData).then(result => {
+                if (result.code === 200) {
+                    this.causeData = result.result.list || [];
+                    this.totalAllCause = result.result.total || 0;
+                }
+                else {
+                    this.$message.error(result.message);
+                }
+            }).catch(error => {
+                console.log(error, 'eeee');
+            });
+        },
+        handleApplyType(list) {
+            this.finallyRightTree = list;
+        },
+        handleEdit(val) {
+            this.tableSelectList = val;
+            this.pushVisible = true;
+        },
+        handleCauseCancel() {
+            this.causeVisible = false;
+        },
+        handlePushSure() {
+            const paramsData = {
+                accountIds: this.finallyRightTree.map(item => item.key),
+                orientationId: this.tableSelectList.orientationId,
+                accountId: this.tableSelectList.accountId
+            };
+            postAction('/kuaishouCrowdPack/accountPush', paramsData).then(result => {
+                if (result.code === 200) {
+                    this.pushVisible = false;
+                    this.handleGetTableList({});
+                }
+                else {
+                    this.$message.error(result.message);
+                }
+            }).catch(error => {
+                console.log(error, 'eeeeeee');
+            });
+        },
+        handlePushCancel() {
+            this.pushVisible = false;
+        },
+        beforeUpload(file) {
+            const isZip = file.type.includes('zip') || file.type.includes('text');
+            const fileOvesize = file.size > (1024 * 1024 * 1024);
+            if (!isZip) {
+                this.fileList = [];
+                this.$message.error('只能上传zip格式的文件或者txt文件');
+                return false;
+            }
+            if (fileOvesize) {
+                this.$message.error('文件大小不能超过1G');
+                return;
+            }
+            this.cosUpload(file);
+        },
+        handleChange(info) {
+            this.fileList = info.fileList;
+        },
+        cosUpload(file) {
+            let that = this;
+            let date = new Date();
+            let y = date.getFullYear();
+            let MM = date.getMonth() + 1;
+            MM = MM < 10 ? '0' + MM : MM;
+            let d = date.getDate();
+            d = d < 10 ? '0' + d : d;
+            let timeElse = new Date().getTime();
+            let arr = file.name.split('.');
+            let str = '';
+            for (let i = 0; i < arr.length; i++) {
+                if (i === arr.length - 1) {
+                }
+                else {
+                    if (i === arr.length - 2) {
+                        str += arr[i];
+                    }
+                    else {
+                        str += arr[i] + '.';
+                    }
+                }
+            }
+            cos.putObject(
+                {
+                    Bucket: 'media-1301855440',
+                    Region: 'ap-chongqing',
+                    // 存储桶所在地域,必须字段
+                    Key: that.uploadType + '/' + y + '-' + MM + '-' + d + '/' + str + '-' + timeElse + '.' + arr[arr.length - 1],
+                    StorageClass: 'STANDARD',
+                    Body: file // 上传文件对象
+                },
+                function (err, data) {
+                    if (err) {
+                        that.$message.error('上传失败!!!' + err);
+                        return;
+                    }
+                    that.loadingElse = false;
+                    that.fileList.push({
+                        uid: file.name,
+                        name: file.name,
+                        status: 'done',
+                        url: '//' + data.Location
+                    });
+                    if (that.fileList.length > 1) {
+                        that.fileList = that.fileList.slice(-1);
+                    }
+                }
+            );
+        },
+        handleQueryList(event) {
+            event.preventDefault();
+            const paramsData = this.form.getFieldsValue();
+            this.handleGetTableList(paramsData);
+        },
+        handleResetForm() {
+            this.form.resetFields();
+            this.acountId = undefined;
+            this.handleGetTableList({});
+        },
+        handleUploadPerson() {
+            this.personVisible = true;
+        },
+        handleOk() {
+            this.$refs.ruleForm.validate(valid => {
+                if (valid) {
+                    if (!this.uploadAcountIds) {
+                        this.$message.error('请选择账户');
+                        return;
+                    }
+                    if (!this.fileList.length) {
+                        this.$message.error('请上传文件');
+                        return;
+                    }
+                    this.handleUploadRuleForm();
+                }
+                else {
+                    return false;
+                }
+            });
+        },
+        handleUploadRuleForm() {
+            const paramsData = {
+                type: this.personForm.resource,
+                orientationName: this.personForm.name,
+                accountId: this.uploadAcountIds,
+                url: this.fileList[0].url
+            };
+            postAction('/kuaishouCrowdPack/uploadCrowdPack', paramsData).then(result => {
+                if (result.code === 200) {
+                    this.personVisible = false;
+                    this.handleGetTableList({});
+                }
+                else {
+                    this.$message.error(result.message);
+                }
+            }).catch(error => {
+                console.log(error, 'eeee');
+            });
+        },
+        handleCancel() {
+            this.personVisible = false;
+            this.$refs.ruleForm.resetFields();
+            this.uploadAcountIds = '';
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+    @import "crowd-control";
+</style>

+ 1 - 1
src/views/modules/stockWatch/accountPage.vue

@@ -1159,7 +1159,7 @@ const columns=[
                     option.xAxis[0].data=data.xData?data.xData.yesterday:[]
                     option.xAxis[1].data=data.xData?data.xData.today:[]
                    
-                }
+                } 
                 option.series[0].name=data.yData?data.yData.yesterday.name:''
                 option.series[1].name=data.yData?data.yData.today.name:''
                 option.series[0].data=data.yData?data.yData.yesterday.data:[]

+ 3 - 0
src/views/modules/stockWatch/keep-market.less

@@ -0,0 +1,3 @@
+.keep-market-content {
+    
+}

+ 27 - 0
src/views/modules/stockWatch/keep-market.vue

@@ -0,0 +1,27 @@
+<template>
+    <div class="keep-market-content"></div>
+</template>
+<script>
+export default {
+    name: 'keep-market',
+    data() {
+        return {
+            rotureType: 'person'
+        };
+    },
+    mounted() {
+        if (this.rotureType === 'person') {
+            this.$router.push('/modules/stockWatch/modules/keep-person/keep-person');
+        }
+        else if (this.rotureType === 'manage') {
+            this.$router.push('/modules/stockWatch/modules/keep-manage/keep-manage');
+        }
+    },
+    methods: {
+
+    }
+};
+</script>
+<style lang="less" scoped>
+    @import "keep-market";
+</style>

+ 109 - 0
src/views/modules/stockWatch/modules/custom-columns/custom-columns.less

@@ -0,0 +1,109 @@
+/deep/ .custom-columns-modal {
+    width: 800px !important;
+    .custom-modal-content {
+        .input-search {
+            width: 200px;
+            margin: 10px 0 10px 0;
+        }
+        .class-left-header {
+            height: 50px;
+            line-height: 50px;
+            background-color: #ccc;
+            padding: 0 10px;
+            display: flex;
+            justify-content: space-between;
+        }
+        .active {
+            background: #ccc;
+            color:cyan;
+            cursor: pointer;
+        }
+        .modal-content-table {
+            display: flex;
+            justify-content: space-between;
+            .select-class-left {
+                width: 65%;
+                height: 400px;
+                border: 1px solid #ccc;
+                .class-left-main {
+                    display: flex;
+                    .left-main-left {
+                        width: 140px;
+                        border-right: 1px solid #ccc;
+                        .main-left-select {
+                            height: 40px;
+                            line-height: 40px;
+                            text-align: center;
+                        }
+                    }
+                    .left-main-right {
+                        width: 100%;
+                        height: 348px;
+                        overflow-y: auto;
+                        padding: 10px;
+                        .main-right-class {
+                            height: 200px;
+                            .check-box-p {
+                                height: 20px;
+                                line-height: 20px;
+                            }
+                            .check-box-select-muster {
+                                .check-box-class {
+                                    display: inline-block;
+                                    width: 50%;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            .select-class-right {
+                width: 30%;
+                height: 400px;
+                border: 1px solid #ccc;
+                .class-left-content {
+                    padding: 0 10px;
+                    height: 348px;
+                    overflow-y: auto;
+                    .apply-right-tree {
+                        display: flex;
+                        justify-content: space-between;
+                        align-items: baseline;
+                        .left-content-p {
+                            display: inline-block;
+                            width: 85%;
+                            height: 25px;
+                            line-height: 25px;
+                            margin: 0;
+                            overflow: hidden;
+                            text-overflow: ellipsis;
+                            white-space: nowrap;
+                        }
+                        .delete-type-class {
+                            color: #1890ff;
+                            cursor: pointer;
+                        }
+                    }
+                }
+                .no-data-class {
+                    height: 340px;
+                    line-height: 340px;
+                    text-align: center;
+                }
+            }
+        }
+    }
+    // .acount-title {
+    //     display: flex;
+    //     font-size: 14px;
+    //     height: 40px;
+    //     line-height: 40px;
+    //     .acount-title-left {
+    //         margin-right: 20px;
+    //         width: 100px;
+    //     }
+    // }
+    // .push-plate {
+    //     margin-bottom: 20px;
+    // }
+}

+ 154 - 0
src/views/modules/stockWatch/modules/custom-columns/custom-columns.vue

@@ -0,0 +1,154 @@
+<template>
+    <a-modal
+        title="自定义列表"
+        :visible="visible"
+        dialog-class="custom-columns-modal"
+        @ok="handleOk"
+        @cancel="handleCancel"
+    >
+        <div class="custom-modal-content">
+            <a-input-search class="input-search" placeholder="请输入指标名称" @change="onChange" />
+            <div class="modal-content-table">
+                <div class="select-class-left">
+                    <div class="class-left-header">可添加的列</div>
+                    <div class="class-left-main">
+                        <div class="left-main-left">
+                            <div
+                                class="main-left-select"
+                                v-for="(item, index) in selectLeftList"
+                                :key="index"
+                                :class="{active: cur === index}"
+                                @click="handleSelectNum(index)"
+                            >
+                                {{item}}
+                            </div>
+                        </div>
+                        <div class="left-main-right">
+                            <div v-show="isConNumOne" class="main-right-class">
+                                <p class="check-box-p">展示数据</p>
+                                <div class="check-box-select-muster">
+                                    <a-checkbox-group @change="handleChangeBox">
+                                        <span
+                                            class="check-box-class"
+                                            v-for="(item, index) in selectCheckboxData"
+                                            :key="index"
+                                        >
+                                            <a-checkbox :value="item">{{ item }}</a-checkbox>
+                                        </span>
+                                    </a-checkbox-group>
+                                </div>
+                            </div>
+                            <div v-show="isConNumTwo" class="main-right-class">内容二</div>
+                            <div v-show="isConNumThree" class="main-right-class">内容三</div>
+                            <div v-show="isConNumFour" class="main-right-class">内容四</div>
+                        </div>
+                    </div>
+                </div>
+                <div class="select-class-right">
+                    <div class="class-left-header">
+                        <span>已选100个</span>
+                        <span><a @click="handleClearAll">清空全部</a></span>
+                    </div>
+                    <div v-if="applyTypeOption.length" class="class-left-content">
+                        <div class="apply-right-tree" v-for="(item, index) in applyTypeOption" :key="index">
+                            <p class="left-content-p">
+                                <a-tooltip placement="left">
+                                    <template slot="title">
+                                        <span>{{ item }}</span>
+                                    </template>
+                                    {{ item }}
+                                </a-tooltip>
+                            </p>
+                            <a-icon type="delete" class="delete-type-class" @click="handleDelTree(item)" />
+                        </div>
+                    </div>
+                    <div v-else class="no-data-class">暂无数据</div>
+                </div>
+            </div>
+        </div>
+    </a-modal>
+</template>
+<script>
+export default {
+    name: 'custom-columns',
+    props: {
+        // treeData: {
+        //     type: Array,
+        //     default: () => []
+        // },
+        // searchValue: {
+        //     type: String,
+        //     default: ''
+        // },
+        visible: {
+            type: Boolean,
+            default: false
+        }
+    },
+    data() {
+        return {
+            selectCheckboxData: ['花费', '封面曝光数', '行为数', '举报书', '拉黑数', '评论数'],
+            selectLeftList: ['111', '222', '333', '444'],
+            cur: 0,
+            isConNumOne: true,
+            isConNumTwo: true,
+            isConNumThree: true,
+            isConNumFour: true,
+            applyTypeOption: []
+        };
+    },
+    methods: {
+        handleDelTree(item) {
+            console.log(item, 'item');
+            this.applyTypeOption = [];
+        },
+        handleChangeBox(val) {
+            console.log(val, 'checkboc111');
+            this.applyTypeOption = val;
+        },
+        handleSelectNum(index) {
+            this.cur = index;
+            if (index === 0) {
+                this.isConNumOne = true;
+                this.isConNumTwo = true;
+                this.isConNumThree = true;
+                this.isConNumFour = true;
+            }
+            else if (index === 1) {
+                this.isConNumOne = false;
+                this.isConNumTwo = true;
+                this.isConNumThree = true;
+                this.isConNumFour = true;
+            }
+            else if (index === 2) {
+                this.isConNumOne = false;
+                this.isConNumTwo = false;
+                this.isConNumThree = true;
+                this.isConNumFour = true;
+            }
+            else if (index === 3) {
+                this.isConNumOne = false;
+                this.isConNumTwo = false;
+                this.isConNumThree = false;
+                this.isConNumFour = true;
+            }
+        },
+        handleOk() {
+            console.log('这个是确定按钮');
+        },
+        handleCancel() {
+            console.log('这个是取消按钮');
+            this.$emit('cancelClick', false);
+        },
+        onChange(e) {
+            console.log(e.target.value, '---------');
+        },
+        handleClearAll() {
+            console.log('清空全部按钮事件');
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+    @import "custom-columns";
+</style>

+ 3 - 0
src/views/modules/stockWatch/modules/keep-manage/keep-manage.less

@@ -0,0 +1,3 @@
+.keep-manage-content {
+    
+}

+ 13 - 0
src/views/modules/stockWatch/modules/keep-manage/keep-manage.vue

@@ -0,0 +1,13 @@
+<template>
+    <div class="keep-manage-content">
+        这个是运营经理的页面
+    </div>
+</template>
+<script>
+export default {
+    name: 'keep-manage'
+};
+</script>
+<style lang="less" scoped>
+    @import "keep-manage";
+</style>

+ 102 - 0
src/views/modules/stockWatch/modules/keep-person/keep-person.less

@@ -0,0 +1,102 @@
+.keep-person-main {
+    .keep-person-header {
+        display: flex;
+        justify-content: space-between;
+        height: 120px;
+        background: #fff;
+        margin-bottom: 15px;
+        .person-header-left {
+            display: flex;
+            align-items: center;
+            .header-left-img {
+                margin-left: 20px;
+                margin-right: 20px;
+                width: 60px;
+                height:60px;
+                img {
+                    width: 100%;
+                }
+            }
+            .header-left-title {
+                height: 50px;
+                line-height: 50px;
+                font-size: 20px;
+                .left-title-radio {
+                    margin-left: 30px;
+                    color: #1afa29;
+                    .title-radio-img {
+                        width: 25px;
+                        height: 25px;
+                        margin-bottom: 5px;
+                        margin-right: 5px;
+                    }
+                }
+                .left-title-radio-down {
+                    margin-left: 30px;
+                    color: #d81e06;
+                    .title-radio-img {
+                        width: 25px;
+                        height: 25px;
+                        margin-bottom: 5px;
+                        margin-right: 5px;
+                    }
+                }
+            }
+        }
+        .person-header-right {
+            display: flex;
+            align-items: center;
+            text-align: center;
+            margin-right: 20px;
+            .header-right-msg {
+                font-size: 20px;
+                margin-right: 60px;
+                .right-msg-class {
+                    height: 50px;
+                    line-height: 50px;
+                    .title-radio-img {
+                        width: 25px;
+                        height: 25px;
+                        margin-bottom: 5px;
+                        margin-right: 5px;
+                    }
+                    .msg-ranking {
+                        font-size: 30px;
+                    }
+                }
+                .msg-class-up {
+                    color: #1afa29;
+                }
+                .msg-class-down {
+                    color: #d81e06;
+                }
+            }
+        }
+    }
+    .keep-person-content {
+        .person-content-title {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            height: 60px;
+            background: #fff;
+            padding: 0 20px;
+            .content-title-acount {
+                font-size: 20px;
+            }
+            .content-title-checkout {
+                .title-checkout-custom {
+                    cursor: pointer;
+                }
+                .title-checkout-time {
+                    margin-left: 20px;
+                }
+            }
+        }
+        .pagin-table-class {
+            display: flex;
+            justify-content: flex-end;
+            margin-top: 20px;
+        }
+    }
+}

+ 140 - 0
src/views/modules/stockWatch/modules/keep-person/keep-person.vue

@@ -0,0 +1,140 @@
+<template>
+    <div class="keep-person-main">
+        <div class="keep-person-header">
+            <div class="person-header-left">
+                <div class="header-left-img"><img src="@/assets/daiban.png" alt=""></div>
+                <div>
+                    <div class="header-left-title">早安,antdesign,祝你开心每一天</div>
+                    <div class="header-left-title">
+                        <span>今日消耗:</span>
+                        <span>1000000</span>
+                        <span class="left-title-radio"><img class="title-radio-img" src="@/assets/up.png" alt="">10.765%</span>
+                        <!-- <span class="left-title-radio-down"><img class="title-radio-img" src="@/assets/down.png" alt="">10.765%</span> -->
+                    </div>
+                </div>
+            </div>
+            <div class="person-header-right">
+                <div class="header-right-msg">
+                    <div class="right-msg-class">周消耗环比</div>
+                    <div class="right-msg-class msg-class-up"><img class="title-radio-img" src="@/assets/up.png" alt="">23.98%</div>
+                    <!-- <div class="right-msg-class msg-class-down"><img class="title-radio-img" src="@/assets/down.png" alt="">23.98%</div> -->
+                </div>
+                <div class="header-right-msg">
+                    <div class="right-msg-class">本周消耗</div>
+                    <div class="right-msg-class">4356345635</div>
+                </div>
+                <div class="header-right-msg">
+                    <div class="right-msg-class">上周消耗</div>
+                    <div class="right-msg-class">45654567567</div>
+                </div>
+                <div class="header-right-msg">
+                    <div class="right-msg-class">团队内排名</div>
+                    <div class="right-msg-class"><span class="msg-ranking">8</span> / 24</div>
+                </div>
+            </div>
+        </div>
+        <div class="keep-person-content">
+            <div class="person-content-title">
+                <div class="content-title-acount">账户列表</div>
+                <div class="content-title-checkout">
+                    <span class="title-checkout-custom"><a @click="handleCustomClick">自定义列</a></span>
+                    <span class="title-checkout-time"><a-date-picker @change="handleDataPicker" /></span>
+                </div>
+            </div>
+            <a-table
+                ref="table"
+                size="middle"
+                bordered
+                :columns="columns"
+                :dataSource="dataSource"
+                :pagination="false"
+            >
+                <span slot="action" slot-scope="text, record">
+                    <a @click="handleEdit(record)">推送</a>
+                    <a-divider type="vertical" />
+                    <a @click="handleDelete(record)">删除</a>
+                </span>
+                <span slot="cause" slot-scope="text, record">
+                    <a class="cause-text-class" @click="handleCause(record)">{{ text }}</a>
+                </span>
+                <span slot="depRelax" slot-scope="text, record">
+                    <a @click="handleAcountRelax('dep', record)">{{ text }}</a>
+                </span>
+                <span slot="acountRelax" slot-scope="text, record">
+                    <a @click="handleAcountRelax('acount', record)">{{ text }}</a>
+                </span>
+            </a-table>
+            <a-pagination
+                class="pagin-table-class"
+                :total="totalAll"
+                :show-total="total => `共 ${totalAll} 条`"
+                size="small"
+                show-size-changer
+                show-quick-jumper
+                @change="onShowSizeChange"
+                @showSizeChange="onShowSizeChange"
+            />
+        </div>
+        <custom-columns :visible="isCustomVisible" @cancelClick="handleCancelClick"></custom-columns>
+    </div>
+</template>
+<script>
+import CustomColumns from '../custom-columns/custom-columns';
+export default {
+    name: 'keep-person',
+    components: {
+        CustomColumns
+    },
+    data() {
+        return {
+            isCustomVisible: false,
+            totalAll: 100,
+            dataSource: [],
+            columns: [
+                {
+                    title: '人群包名称',
+                    width: 200,
+                    ellipsis: true,
+                    dataIndex: 'orientationName'
+                },
+                {
+                    title: '人群包类型',
+                    align: 'center',
+                    dataIndex: 'populationType'
+                },
+                {
+                    title: '匹配类型',
+                    align: 'center',
+                    dataIndex: 'typeStr'
+                },
+                {
+                    title: '上传时间',
+                    dataIndex: 'statDate',
+                    align: 'center'
+                }
+            ]
+        };
+    },
+    methods: {
+        handleDataPicker(date, dateString) {
+            console.log(date, dateString, '-------');
+        },
+        handleCustomClick () {
+            console.log('这个是自定义列的点击事件');
+            this.isCustomVisible = true;
+        },
+        onShowSizeChange(current, pageSize) {
+            console.log(current, pageSize, 'current, pageSize');
+        },
+        handleCauseSizeChange(current, pageSize) {
+            console.log(current, pageSize, 'size-size');
+        },
+        handleCancelClick(status) {
+            this.isCustomVisible = status;
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+    @import "keep-person";
+</style>

+ 1 - 1
vue.config.js

@@ -84,7 +84,7 @@ module.exports = {
         // target: 'https://trac.tjyourong.com.cn', //请求本地 需要jeecg-boot后台项目
         // target: 'http://39.106.184.70:8088/', //请求本地 需要jeecg-boot后台项目
         //  target: 'http://adsp.tjyourong.com.cn/', //请求本地 需要jeecg-boot后台项目
-        // target: 'http://192.168.1.251/', //请求本地 需要jeecg-boot后台项目
+        // target: 'http://192.168.1.251/', //请求本地 需要jeecg-boot后台项目 
         // target:'http://118.24.244.213:8804',
       //  target:'http://139.186.165.84:8806', //测试