zhuxinbo 5 سال پیش
والد
کامیت
25652a10a3
3فایلهای تغییر یافته به همراه1622 افزوده شده و 3 حذف شده
  1. 871 0
      src/views/modules/BatchCreate/TouTiaoBatch.vue
  2. 748 0
      src/views/modules/BatchCreate/crowedPackage.vue
  3. 3 3
      vue.config.js

+ 871 - 0
src/views/modules/BatchCreate/TouTiaoBatch.vue

@@ -0,0 +1,871 @@
+<template>
+    <div class="toutiaoBatch">
+        <keep-alive>  
+        <div class="tabs">
+            <a-tabs v-model="tabkey" @change="callback">
+                <a-tab-pane key="group" tab="广告组">                
+                </a-tab-pane>
+                <a-tab-pane key="plan" tab="广告计划">              
+                </a-tab-pane>
+                <a-tab-pane key="idea" tab="广告创意">               
+                </a-tab-pane>
+                <a-button type='primary' slot="tabBarExtraContent" @click="goBatch">
+                   + 头条批量创建
+                </a-button>
+            </a-tabs>
+        </div>
+        </keep-alive>
+        <div class="topOptions">
+            <span class="OptinItem">
+                <a-select  style="width: 120px" @change="statusChange" placeholder="请选择状态">    
+                    <a-select-option value="open" >
+                        开
+                    </a-select-option>
+                    <a-select-option value="close">
+                        关
+                    </a-select-option>
+                </a-select>
+            </span>
+            <span class="OptinItem">           
+                <a-input-search  placeholder="请选择媒体账户" style="width: 200px" v-model="account" />
+            </span>
+            <span class="OptinItem">
+                <a-date-picker @change="dateChange" />
+            </span>
+            <span class="OptinItem">
+                <a-input-search placeholder="请输入ID或名称关键词" v-model="optionId" style="width: 200px" @search="onSearch" />
+            </span>
+            <span class="optionBtn">
+                <a-button type='primary' @click="search" class="searchBtn">查询</a-button>
+                <a-button type='default' @click="reset">重置</a-button>
+            </span>
+        </div>
+        <div class="tableArea">
+            <div class="tableOption">
+                <span class="OptinItem">                    
+                    <a-tooltip>
+                        <template slot="title" :getPopupContainer='getPopupContainer'>
+                        点我就可以批量启动、暂停、删除你的选择哦~
+                        </template>
+                        <a-button type="link" @click="changeSelectStatus">批量操作</a-button>
+                    </a-tooltip>
+                </span>
+                <span class="OptinItem">
+                    <a-select  style="width: 120px" @change="optChange" placeholder="" :disabled='selectDisable'>    
+                        <a-select-option value="open" >
+                            启动
+                        </a-select-option>
+                        <a-select-option value="pause">
+                            暂停
+                        </a-select-option>
+                        <a-select-option value="delete">
+                            删除
+                        </a-select-option>
+                    </a-select>
+                </span>
+                 <span class="OptinItem">
+                    <a-popconfirm
+                        title="确定要删除选择的内容吗?"
+                        ok-text="删除"
+                        cancel-text="取消"
+                        @confirm="confirm"
+                        @cancel="cancel"
+                        v-if="optValue=='delete'"
+                    >
+                        <a-button type='primary' @click="isOkHandle" class="ok">确定</a-button>
+                    </a-popconfirm>
+                    <a-button type='primary' @click="isOkHandle" class="ok" v-else>确定</a-button>
+
+
+                    <a-popover v-model="visible" trigger="click" >
+                        <div slot="content">
+                            <span style='font-weight:700;margin-right:15px;font-size:15px'>预算</span>
+                            <a-radio-group v-model="radioValue" @change="radioChange">
+                                <a-radio value="unlimit">不限</a-radio>
+                                <a-radio value="dayBudget">日预算</a-radio>                                
+                            </a-radio-group>
+                            <span v-show="radioValue=='dayBudget'">预计金额: <a-input-number :min="0" v-model="dayBudgetValue" :step="0.1" @change="budgetChange" size="small" style='margin-right:20px' /></span>
+                            <a-button type='default' @click="showPricecancel"  style='margin-right:10px'>取消</a-button>
+                            <a-button type='primary' @click="showPriceOk"  class="ok">保存</a-button>
+                        </div>
+                        
+                        <a-button type='default'  v-if="tabkey=='group'" class="ok">更改预算</a-button>
+                    </a-popover>
+                    <a-button type='default' @click="changebudget" v-if="tabkey=='plan'" class="ok">更改预算</a-button>
+                    <a-button type='default' @click="changeofferPrice" v-show="tabkey=='plan'">更改出价</a-button>
+                    
+                 </span>
+                <span class="optionBtn">                    
+                    <a-button type='primary' @click="reset">自定义列</a-button>
+                </span>
+            </div>
+            <div class="table">
+                <a-table 
+                :columns="columns" 
+                :data-source="data" 
+                :row-selection="rowSelection" 
+                bordered
+                >
+                    <template slot="campaignName" slot-scope="text,record">                                       
+                        <editableCell :text="text" slotName='campaignName' @change="onCellChange(record.key, 'campaignName', $event)" />                       
+                    </template>
+                    <span slot="groupBudget" slot-scope="text,record">
+                       <editableCell :text="text" slotName='groupBudget' @change="onCellChange(record.key, 'groupBudget', $event)" /> 
+                    </span>
+                    <span slot="status" slot-scope="text,record">
+                        <a-switch size="default" :checked=text  @change="switchChange(text,record)"/>
+                    </span>
+                    <span slot="options" slot-scope="record">
+                        <a href="javascript:;" style="margin-right:10px">编辑</a>
+                        <a href="javascript:;" v-if="tabkey=='plan'" @click="copyPlan(record)">复制</a>
+                        <a href="javascript:;" v-if="tabkey=='idea'">预览</a>
+                    </span>
+                    <span slot="parentGroup" slot-scope="text,record">
+                        <a href="javascript:;" >{{text}}</a>
+                    </span>
+                    <span slot="parentPlan" slot-scope="text,record">
+                        <a href="javascript:;" >{{text}}</a>
+                    </span>
+                </a-table>
+            </div>
+        </div>
+        <!-- 出价的模态框 -->
+        <div class="batchModal">        
+            <a-modal v-model="offerPriceVisiable" :title="'批量修改'+ModalTitle" @ok="handleOk" width='55%'  >
+                <div id="batchModal">
+
+                <div class="selectePlan">已选{{}}个广告计划</div>
+                <div class="modifyRules">
+                    <span class="rules">修改规则:</span>
+                    <a-radio-group v-model="modifyRulesValue" @change="modifyRulesChange">
+                        <a-radio-button value="total">
+                            统一修改
+                        </a-radio-button>
+                        <a-radio-button value="separately">
+                            分别修改
+                        </a-radio-button>
+                    </a-radio-group>
+                    <span class="totalPrice" v-if="modifyRulesValue=='total'"><span>{{ModalTitle=='出价'?'出价':'总预算'}}</span>
+                        :
+                        <a-input-number :min="0" v-model="inputValue" :step="0.1" @change="budgetChange" size="small"  /> 元
+                    </span>
+                </div>
+                <div class="modifyTable">
+                        <a-table
+                        :columns="modifyTableCol"
+                        :data-source="modifyTableData"
+                        bordered
+                        tableLayout="auto"
+                        :pagination="false"
+                        :loading='modifyTableloading'
+                        style="word-break: break-all;"
+                    >
+                        <span slot="changeBudget" slot-scope="">
+                            <span v-if="ModalTitle=='出价'">oCPM</span>
+                            <span v-else>{{modifyRulesValue=='total'?'总预算':'日预算'}}</span>
+                            :<a-input-number :min="0" v-model="inputValue" :step="0.1" @change="budgetChange"  size="small" :disabled="modifyRulesValue=='total'" /> 元
+                        </span>
+                        <span slot="currentCost" slot-scope="currentCost">{{ currentCost | decimalsHandle }}</span>
+                        <span slot="currentBudget" slot-scope="text"> 
+                            <span v-if="ModalTitle=='出价'">oCPM: {{text | decimalsHandle}}</span>
+                            <span v-else>日预算:{{  text | decimalsHandle }}</span>
+                        </span>
+                    </a-table>
+                </div>
+            
+                </div>
+            </a-modal>
+        </div>
+
+        <!-- 复制计划的弹出框 -->
+        <a-modal v-model="copyPlanVisiable" title="复制计划" @ok="copyPlanOk"  :maskClosable='false'>
+            <div id="copyModal">
+            <p class="copyTip">复制说明:适用于批量复制多个广告计划,默认同事复制所属创意。此类型不直接跨广告投放账号复制,且只能复制完成后逐一修改</p>
+            <p style="font-weight:700;font-size:15px">被复制广告计划:<span>{{}}</span></p>
+            <p><span class="copyName"><b class="copyKeyStart">*</b> 复制个数:</span> 
+                <a-input-number :min="1" :max="10" v-model="copyNum" style="width:250px" />
+                
+            </p>
+            <p><span class="copyName"><b class="copyKeyStart">*</b>复制到广告组:</span> 
+                <a-select size="default" default-value="a1" style="width: 250px" v-model="copyGroup" >
+                <a-select-option v-for="i in 25" :key="(i + 9).toString(36) + i">
+                    {{ (i + 9).toString(36) + i }}
+                </a-select-option>
+                </a-select>
+            </p>           
+            </div>
+        </a-modal>
+    </div>
+</template>
+
+<script>
+import moment from 'moment';
+import { getAction, postAction, downFile, downFilePost } from '@/api/manage';
+import editableCell from './editableCell'
+let typeValue='预算'
+let modifyTableCol=[
+    {
+        title: '广告计划',
+        dataIndex: 'advertisingPlan',
+        align: 'center',
+    },
+    {
+        title: '当前消耗',
+        dataIndex: 'currentCost',
+        align: 'center',
+        scopedSlots: { customRender: 'currentCost' },
+    },
+    {
+        title: '当前'+typeValue,
+        dataIndex: 'currentBudget',
+        align: 'center',
+        scopedSlots: { customRender: 'currentBudget' },
+    },
+    {
+        title: '统一修改'+typeValue,
+        dataIndex: 'changeBudget',
+        align: 'center',
+        scopedSlots: { customRender: 'changeBudget' },
+        
+    },
+]
+
+const columns = [
+  {
+    title: '状态',
+    dataIndex: 'status',
+    key: 'status',
+    align: 'center',
+    scopedSlots: { customRender: 'status' }
+  },
+  {
+    title: '广告组名称',
+    dataIndex: 'campaignName',
+    key: 'campaignName',
+    align: 'center',
+    width:450,
+    scopedSlots: { customRender: 'campaignName' }
+  },
+  {
+    title: '广告组ID',
+    dataIndex: 'advantageID',    
+    key: 'advantageID',
+    align: 'center',
+  },
+  {
+    title: '推广目的',
+    dataIndex: 'promotionPurpose',    
+    key: 'promotionPurpose',
+    align: 'center',
+  },
+  {
+    title: '组预算(元)',
+    dataIndex: 'groupBudget',    
+    key: 'groupBudget',
+    align: 'center',
+    width:250,
+    scopedSlots: { customRender: 'groupBudget' }
+  },
+  {
+    title: '创建时间',
+    dataIndex: 'creatTime',    
+    key: 'creatTime',
+    align: 'center',
+    scopedSlots: { customRender: 'creatTime' }
+  },
+];
+const planColumns = [
+  {
+    title: '状态',
+    dataIndex: 'status',
+    key: 'status',
+    align: 'center',
+    scopedSlots: { customRender: 'status' }
+  },
+  {
+    title: '操作',
+    dataIndex: 'options',
+    key: 'options',
+    align: 'center',
+    scopedSlots: { customRender: 'options' }
+  },
+  {
+    title: '计划名称',
+    dataIndex: 'planName',
+    key: 'planName',
+    align: 'center',
+    width:300,
+    scopedSlots: { customRender: 'planName' }
+  },
+  {
+    title: '计划ID',
+    dataIndex: 'planID',    
+    key: 'planID',
+    align: 'center',
+  },
+  {
+    title: '账户',
+    dataIndex: 'accountName',    
+    key: 'promotionPurpose',
+    align: 'center',
+  },
+  {
+    title: '计划预算(元)',
+    dataIndex: 'planBudget',    
+    key: 'planBudget',
+    align: 'center',
+    width:150,
+    scopedSlots: { customRender: 'planBudget' }
+  },
+  {
+    title: '出价(元)',
+    dataIndex: 'planoffer',    
+    key: 'planoffer',
+    align: 'center',
+    width:150,
+    scopedSlots: { customRender: 'planoffer' }
+  },
+  {
+    title: '投放方式',
+    dataIndex: 'Launchmode',    
+    key: 'Launchmode',
+    align: 'center',
+    scopedSlots: { customRender: 'Launchmode' }
+  },
+  {
+    title: '投放时间',
+    dataIndex: 'LaunchTime',    
+    key: 'LaunchTime',
+    align: 'center',
+    scopedSlots: { customRender: 'LaunchTime' }
+  },
+  {
+    title: '所属广告组',
+    dataIndex: 'parentGroup',    
+    key: 'parentGroup',
+    align: 'center',
+    scopedSlots: { customRender: 'parentGroup' }
+  },
+];
+const ideaColumns = [
+  {
+    title: '状态',
+    dataIndex: 'status',
+    key: 'status',
+    align: 'center',
+    scopedSlots: { customRender: 'status' }
+  },
+  {
+    title: '操作',
+    dataIndex: 'options',
+    key: 'options',
+    align: 'center',
+    scopedSlots: { customRender: 'options' }
+  }, 
+  {
+    title: '创意ID',
+    dataIndex: 'ideaID',    
+    key: 'ideID',
+    align: 'center',
+  },
+  {
+    title: '广告创意',
+    dataIndex: 'ideID',    
+    key: 'ideaID',
+    align: 'center',
+  },
+  {
+    title: '创意方式',
+    dataIndex: 'iaID',    
+    key: 'idaID',
+    align: 'center',
+  },
+  {
+    title: '账户',
+    dataIndex: 'accountName',    
+    key: 'promotionPurpose',
+    align: 'center',
+  },
+ 
+  
+  {
+    title: '投放时间',
+    dataIndex: 'LaunchTime',    
+    key: 'LaunchTime',
+    align: 'center',
+    scopedSlots: { customRender: 'LaunchTime' }
+  },
+  {
+    title: '投放位置',
+    dataIndex: 'LaunchPosition',    
+    key: 'LaunchPosition',
+    align: 'center',
+    scopedSlots: { customRender: 'LaunchPosition' }
+  },
+  {
+    title: '所属计划',
+    dataIndex: 'parentPlan',    
+    key: 'parentPlan',
+    align: 'center',
+    scopedSlots: { customRender: 'parentPlan' }
+  },
+  {
+    title: '所属广告组',
+    dataIndex: 'parentGroup',    
+    key: 'parentGroup',
+    align: 'center',
+    scopedSlots: { customRender: 'parentGroup' }
+  },
+];
+
+
+
+let data=[
+    {
+        status:true,
+        campaignName:'有缘有相聚',
+        advantageID:28856,
+        promotionPurpose:'-',
+        groupBudget:12563,
+        creatTime:'2020-01-03',
+        key:28856
+    },
+    {
+        status:false,
+        campaignName:'有缘有相聚',
+        advantageID:27856,
+        promotionPurpose:'-',
+        groupBudget:'不限',
+        key:27856,
+        creatTime:'2020-03-03'
+    },
+    {
+        status:true,
+        campaignName:'有缘有相聚',
+        advantageID:24856,
+        promotionPurpose:'-',
+        groupBudget:14563,
+        creatTime:'2020-04-03',
+        key:24856,
+    },
+]
+
+
+export default {
+    components: {
+        editableCell,
+    },
+    data() {
+        return {
+            account:'',//媒体账号
+            optionId:'',//input输入的id或关键词
+            dateValue:'',//日期选择框选择的事件--我赋值的是dateString
+            tabkey:'group',//tab选中的页
+            selectDisable:true,
+            optValue:'',//操作设置的值 删除 暂停 开启
+            visible: false,//出价里的弹出框
+            radioValue:'unlimit',//出价的单选默认值
+            dayBudgetValue:0,//日预算的默认值
+            offerPriceVisiable:false,//修改出价的弹出框显示与否
+            modifyRulesValue:'total',//修改出价里的radio默认值
+            ModalTitle:'出价',//模态框的标题
+            inputValue:'',//模态框里统一修改时的金额
+            //主页的表格
+            data:[],
+            columns,
+            selectedRowKeys:[],
+            rowSelection:{
+                onChange: (selectedRowKeys, selectedRows) => {
+                    console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
+                    console.log(selectedRowKeys);
+                    this.selectedRowKeys=selectedRowKeys;
+                },
+                onSelect: (record, selected, selectedRows) => {
+                    console.log(record, selected, selectedRows);
+                    
+                },
+                onSelectAll: (selected, selectedRows, changeRows) => {
+                    console.log(selected, selectedRows, changeRows);
+                    
+                },
+            },
+            editID:0,
+            //批量修改里的表格
+            typeValue,
+            modifyTableData:[
+                {
+                    advertisingPlan:'王者荣耀',
+                    currentCost:826595312,
+                    currentBudget:10000,
+                    changeBudget:''
+                }
+            ],
+            modifyTableCol,
+            modifyTableloading:false,
+            
+            
+            //复制计划
+            copyPlanVisiable:false,
+            copyRecord:null,
+            copyNum:1,//复制个数
+            copyGroup:'',
+        }
+    },
+    
+    methods: {
+        //tab切换页的函数
+        callback(key) {
+            console.log(key);
+            if(key=='plan'){
+                this.columns=planColumns
+            }else if(key=='group'){
+                this.columns=columns
+            }else if(key=='idea'){
+                this.columns=ideaColumns
+            }
+        },
+        //跳转到批量页面
+        goBatch(){
+
+        },
+        //状态改变
+        statusChange(value){          
+            console.log(value);
+
+        },
+        //日期改变
+        dateChange(date, dateString) {
+            console.log(date, dateString);
+        },
+        //输入框查询事件
+        onSearch(value){
+            console.log('input--'+value);
+        },
+        //查询按钮事件
+        search(){
+
+        },
+        //重置按钮事件
+        reset(){
+
+        },
+        //状态改变
+        switchChange(text,record){
+            // console.log(`a-switch to ${checked}`);
+            console.log(text,record);
+            record.status=!text;
+            console.log(this.data)
+        },
+
+
+        //改变批量操作的按钮
+        changeSelectStatus(){
+            this.selectDisable=false;
+        },
+        //批量操作下的启动 删除 暂停
+        optChange(value){
+            console.log(value)
+            this.optValue=value;
+        },
+        //批量操作的确定按钮
+        isOkHandle(){
+            this.selectDisable=true;
+            if(this.optValue){
+                if(this.optValue=='pause'){
+                    if(this.selectedRowKeys.length>0){
+                        this.selectedRowKeys.forEach((item,index)=>{
+                            this.data.forEach((ele)=>{
+                                if(ele.key==item){
+                                    ele.status=false;
+                                }
+                            })
+                            
+                        })
+                    }
+                }else if(this.optValue=='open'){
+                   if(this.selectedRowKeys.length>0){
+                        this.selectedRowKeys.forEach((item,index)=>{
+                           this.data.forEach((ele)=>{
+                                if(ele.key==item){
+                                    ele.status=true;
+                                }
+                            })
+                        })
+                    }
+                }
+                console.log(this.data)
+            }
+            
+        },
+        //确定删除
+        confirm(e) {
+            console.log(e);
+                if(this.optValue=='delete'){
+                    if(this.selectedRowKeys.length>0){
+
+                        this.selectedRowKeys.forEach((item,index)=>{
+                            this.data.splice(item,1)
+                        })
+                    }
+                }
+            this.$message.success('删除成功');
+
+        },
+        //取消删除
+        cancel(e) {
+            console.log(e);
+            // this.$message.error('删除成功');
+        },
+        //预算里 取消按钮点击
+        showPricecancel() {
+            // console.log(111);
+            this.visible = false;
+            this.dayBudgetValue=0
+            this.radioValue='unlimit'
+        },
+        showPriceOk(){
+            this.visible = false;
+        },
+        //单选按钮改变事件
+        radioChange(e) {
+            console.log('radio checked', e.target.value,this.radioValue);
+        },
+        budgetChange(){
+            console.log(this.inputValue)
+        },
+        //广告计划下的预算
+        changebudget(){
+            this.offerPriceVisiable=true;
+            this.ModalTitle='预算'
+            typeValue='预算'
+        },
+        //修改出价
+        changeofferPrice(){
+            this.offerPriceVisiable=true;
+            this.ModalTitle='出价'
+            typeValue='出价';
+            this.modifyTableCol[2].title='出价';
+            
+            this.modifyTableCol[3].title='统一修改出价';
+            
+        },
+        handleOk(e) {
+            console.log(e);
+            this.offerPriceVisiable = false;
+        },
+        //修改规则的改变
+        modifyRulesChange(e){
+            if(e.target.value=='total'){
+                this.inputValue=''
+            }else{
+                this.inputValue=10000
+            }
+        },
+        //更改文字提示的父节点
+        getPopupContainer(){
+            console.log(this);
+            return this.$el
+        },
+
+        //点击修改广告名
+        // changecampaignName(text,record){
+        //     console.log(text,record)
+        // },
+        
+        onCellChange(key, dataIndex, value) {
+            console.log(key, dataIndex, value)
+            const dataSource = [...this.data];
+            const target = dataSource.find(item => item.key === key);
+            if (target) {                              
+                target[dataIndex] = value;
+                    this.data = dataSource;       
+            }
+            console.log(this.data)
+        },
+
+
+        //复制广告计划
+        copyPlan(record){
+            this.copyRecord=record;
+            this.copyPlanVisiable=true;
+        },
+
+        copyPlanOk(e) {
+            this.copyPlanVisiable = false;
+            console.log(this.copyNum,'---',this.copyGroup)
+        },
+    },
+    mounted() {
+        console.log(this);
+        this.data=data;
+    },
+    filters: {
+        toPercentage(val) {
+            if(val){
+                if(typeof val != 'string'){
+                    return (val * 100).toFixed(2) + '%'
+                }else{
+                    return val
+                }
+            }else if(typeof val =='string'){
+                    return val
+                }
+            else{
+                return 0
+            }    
+        },
+        //保留两位小数并且变成货币格式
+        decimalsHandle(val){
+            
+            if(val && typeof val !='string'){
+                if(val>=0){
+                    val=parseFloat(val).toFixed(2);
+                    let numberStr = val.toString()
+                    let str = numberStr.split('.')
+                    
+                    let str0=str[0].split('').reverse();
+                    for (let i = 0; i < str0.length; i++) {
+                        if ((i + 1) % 4 === 0) {
+                            str0.splice(i, 0, ',')
+                        }
+                    }
+                    str0.reverse()
+                    let handleResult = ''
+                    for (let j = 0; j < str0.length; j++) {
+                        handleResult += str0[j]
+                    }
+                    
+                    return handleResult+'.'+str[1]
+                }else{
+                    val=parseFloat(val).toFixed(2);
+                    let numberStr = val.toString()
+                    let str = numberStr.split('.')
+                    
+                    let str0=str[0].substr(1).split('').reverse();
+                    for (let i = 0; i < str0.length; i++) {
+                        if ((i + 1) % 4 === 0) {
+                            str0.splice(i, 0, ',')
+                        }
+                    }
+                    str0.reverse()
+                    let handleResult = ''
+                    for (let j = 0; j < str0.length; j++) {
+                        handleResult += str0[j]
+                    }
+                    
+                    return '-'+handleResult+'.'+str[1]
+                }
+                
+            }else if(typeof val =='string'){
+                return val
+            }
+            else{
+                return 0
+            }           
+        },
+        //变成货币格式
+        formatCurrency(val){
+            if((val||val==0)&& typeof val !='string'){
+                let numberStr = val.toString()
+                let str = numberStr.split('').reverse()
+                for (let i = 0; i < str.length; i++) {
+                    if ((i + 1) % 4 === 0) {
+                    str.splice(i, 0, ',')
+                    }
+                }
+                str.reverse()
+                let handleResult = ''
+                for (let j = 0; j < str.length; j++) {
+                    handleResult += str[j]
+                }
+                return handleResult
+            }else if(typeof val =='string'){
+                    return val
+            }
+            else{
+                return '-'
+            }
+            
+        }
+    }
+}
+</script>
+<style lang="scss">
+     .ant-tooltip-inner,.ant-tooltip,.ant-tooltip-arrow::before{
+        background-color: #fff;
+        color: #333;
+    }
+    #batchModal{
+        .rules,.totalPrice{
+            font-weight: 600;
+        }
+
+        .selectePlan{        
+            font-size: 14px;
+            font-weight: 700;
+            color: #333;
+            padding: 20px 0;
+        }
+        .totalPrice{
+            margin-left: 20px;
+        }
+        .modifyTable{
+            margin-top: 20px;
+            width: 100%;
+            height: 400px;
+            overflow: auto;
+            font-weight: 600;
+        }
+    }
+    #copyModal{
+        .ant-modal-header{
+            text-align: center;
+        }
+        .copyTip{
+            font-size: 12px;
+            color: #999;
+        }
+        .copyName{
+            width: 118px;
+            display: inline-block;
+            text-align: right;
+            .copyKeyStart{
+                color: red;
+            }
+        }
+        // font-weight: 600;
+    }
+</style>
+<style lang="scss" scoped>
+.toutiaoBatch{
+    background-color: #fff;
+    padding: 10px 20px;
+    position: relative;
+    width: 100%;
+    .OptinItem{
+        display: inline-block;
+        margin-right: 15px;
+        .ok{
+            margin-right: 15px;
+        }
+    }
+    .topOptions{
+        padding: 15px 0;
+    }
+    .optionBtn{
+        // display: inline-block;
+        float: right;
+        .searchBtn{
+            margin-right: 10px;
+        }
+    }
+    .tableArea{
+        .tableOption{
+            padding: 20px 0;
+        }
+    }
+    
+    
+}
+
+</style>

+ 748 - 0
src/views/modules/BatchCreate/crowedPackage.vue

@@ -0,0 +1,748 @@
+<template>
+    <div class="crowedPackage">
+        <div class="optHeader">
+            <div class="top">
+                <span class="optItem">  
+                <a-tree-select
+                    v-model="treeValue"
+                    show-search
+                    style="width: 600px;height:30px"
+                    :dropdownMatchSelectWidth='true'
+                    :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"              
+                    tree-checkable
+                    searchPlaceholder='请输入账户关键字搜索'
+                    :show-checked-strategy="SHOW_PARENT"
+                    placeholder="请选择账户或搜索账户关键字"
+                    treeNodeFilterProp="title"
+                    :allowClear="true"
+                    @change="treeChange"
+                    @search="treeSearch"
+                    @select="treeSelect"                        
+                    :maxTagCount='1'    
+                    :tree-data="treeData"
+                    :filterOption='filterOption'
+                >
+                </a-tree-select>
+                </span>
+                <span class="optItem">
+                    <a-date-picker v-model="dateValue" @change="dateChange" />
+                </span>
+
+            </div>
+            <div class="bottom">
+                <div class="optItem">
+                    <a-select size="default" placeholder='覆盖数量' v-model="coverageQuantity" style="width: 200px" @change="coverChange">
+                        <a-select-option v-for="i in 25" :key="(i + 9).toString(36) + i">
+                            {{ (i + 9).toString(36) + i }}
+                        </a-select-option>
+                    </a-select>
+                </div>
+                <div class="optItem">
+                    <a-select size="default" placeholder='类别' v-model="category" style="width: 200px" @change="categoryChange">
+                        <a-select-option value='' > 
+                            全部
+                        </a-select-option>
+                        <a-select-option v-for="(item,index) in categoryArr" :key="index" :value='item.value' > 
+                            {{ item.title }}
+                        </a-select-option>
+                    </a-select>
+                </div>
+                <div class="optItem">
+                    <a-input-search placeholder="按名称搜索" v-model="nameSearch" style="width: 200px" @search="onSearch" />
+                </div>
+                <div class="optionBtn">
+                     <a-button class="search" type='primary' @click="search">查询</a-button>
+                     <a-button class="search" type='link' @click="clearAll">清空全部</a-button>
+                </div>
+            </div>
+        </div>
+        <div class="tableBOX">
+            <div class="tableOpt">
+                <a-button class="search" type='primary' @click="updatePackage">上传人群包</a-button>
+                <a-button class="search" type='primary' @click="synchro">同步</a-button>
+                <a-select size="default" placeholder='批量操作' v-model="batchValue" style="width: 200px" @change="batchChange">
+                    
+                    <a-select-option  value='push'>
+                        推送
+                    </a-select-option>
+                    <a-select-option  value='delete'>
+                        删除
+                    </a-select-option>
+                </a-select>
+                <a-button class="addCol" type='primary' @click="search">自定义列</a-button>
+            </div>
+            <div class="tableArea">
+                <a-table 
+                :columns="columns" 
+                :data-source="dataSource" 
+                :row-selection="rowSelection" 
+                bordered
+                >
+                    <template slot="campaignName" slot-scope="text,record">                                       
+                        <editableCell :text="text" slotName='campaignName' @change="onCellChange(record.key, 'campaignName', $event)" />                       
+                    </template>
+                    <span slot="groupBudget" slot-scope="text,record">
+                       <editableCell :text="text" slotName='groupBudget' @change="onCellChange(record.key, 'groupBudget', $event)" /> 
+                    </span>
+                    <span slot="status" slot-scope="text,record">
+                        <span v-if="record.status">
+                            <span style='color:#33CC33'>可用</span>
+                            <span style="display:block">推送完成</span> 
+                        </span>
+                        <span v-else>
+                            <span style='color:#CC3333'>不可用</span>
+                            <span style="display:block">推送失败</span> 
+                        </span>                
+                    </span>
+                    <span slot="operation" slot-scope="text,record">
+                        <a href="javascript:;" style="margin-right:10px">推送</a>
+                        <a-popconfirm
+                            v-if="dataSource.length"
+                            title="确定要删除吗?"
+                            @confirm="() => onDelete(record.key)"
+                        >
+                            <a href="javascript:;">删除</a>
+                        </a-popconfirm>
+                        
+                        
+                    </span>
+                    <span slot="parentGroup" slot-scope="text">
+                        <a href="javascript:;" >{{text}}</a>
+                    </span>
+                    <span slot="parentPlan" slot-scope="text">
+                        <a href="javascript:;" >{{text}}</a>
+                    </span>
+                    <span slot="cost" slot-scope="cost">       
+                        {{cost | formatCurrency }}
+                    </span>
+                </a-table>
+            </div>
+        </div>
+        <!-- 上传人群包的界面 -->
+        <a-modal v-model="updatePackageVisiable"  @ok="updatePackageOk" width="750px"  okText='上传'>
+            <div id="updatePackageOk">
+
+            <p class="title">上传人群包</p>
+            <div class="updatePackagebody" >
+                <p class="item">
+                    <span class="desc">匹配类型 <span class="redCircular"></span></span>
+                    <a-select size="default" placeholder='请选择匹配类型'  v-model="matchValue" style="width: 400px" @change="matchChange">
+                        <a-select-option v-for="i in 25" :key="(i + 9).toString(36) + i">
+                            {{ (i + 9).toString(36) + i }}
+                        </a-select-option>
+                    </a-select>
+                    <span class="tips">大部分是15位数字,如123456789012345(电信是14位)</span>
+                </p>
+                <p class="item">
+                    <span class="desc">人群包名称 <span class="redCircular"></span></span>
+                    <a-input placeholder="请输入人群包名称" v-model="crowedName" style="width: 400px" />
+                </p>
+                <p class="item">
+                    <span class="desc">类型匹配 <span class="Circular"></span></span>
+                    <a-radio-group name="radioGroup" v-model="typeMatch">
+                        <a-radio :value="1">
+                            设备号匹配
+                        </a-radio>
+                        <a-radio :value="2">
+                            uid匹配
+                        </a-radio>
+                    </a-radio-group>
+                    <span class="tips">
+                        <span class="tipsinfo">设备号匹配:定向/排除时直接按照设备号圈选,数据相对量少而精确</span>
+                        <span class="tipsinfo">UID匹配:定向/排除时圈选在该设备上登录的全部UID数据,数据相对量多而广泛</span>
+                    </span>
+                </p>
+                <p class="item">
+                    <span class="desc">人群分组 <span class="redCircular"></span></span>
+                    <span class="crowedGroup">
+                        <a-input-group compact >
+                            <a-input style="width: 290px" placeholder='请输入内容' v-model="populationGroup"/>
+                            <a-button type='default' @click="showGroupPage">选择已有<a-icon type="down" /></a-button>
+                        </a-input-group>
+                        <div class="crowedGroupPage" v-show="showcrowedPackage">
+                            <ul @click.stop="selectgroupName">
+                                <li class="crowedGroupPageItem">系统推荐</li>
+                                <li class="crowedGroupPageItem">哈哈哈</li>
+                                <li class="crowedGroupPageItem">嘿嘿</li>
+                                <li class="crowedGroupPageItem">魏志佳编辑</li>
+                                <li class="crowedGroupPageItem">1</li>
+                                <li class="crowedGroupPageItem">1</li>                               
+                            </ul>
+                        </div>
+                    </span>                                       
+                </p>
+                <p class="item">
+                    <span class="desc">上传文件 <span class="redCircular"></span></span>
+                    <a-upload action="https://www.mocky.io/v2/5cc8019d300000980a055e76" directory>
+                        <a-button> <a-icon type="upload" /> 点击上传ZIP包 </a-button>
+                    </a-upload>
+                    <span class="tips">
+                        <span class="tipsTitle">文件格式说明</span>
+                        <span class="tipsinfo">1.安卓和IOS设备号,imei小写后MD5加密,IDFA大写后MD5加密,32位MD5均可</span>
+                        <span class="tipsinfo">2.上传文件内,每行一个号码,号码数量不多于3千万</span>
+                        <span class="tipsinfo">3.文件类型为单个或多个txt文件经过zip格式压缩得到,压缩后大小不超过1G</span>
+                        <span class="tipsinfo">4.上传过程中需要一定的格式校验时间,请耐心等待</span>
+                    </span>
+                </p>
+            </div>
+            
+            </div>
+        </a-modal>
+    </div>
+</template>
+
+<script>
+import moment from 'moment';
+import { getAction, postAction, downFile, downFilePost } from '@/api/manage';
+import editableCell from './editableCell'
+import { TreeSelect } from 'ant-design-vue';
+const SHOW_PARENT = TreeSelect.SHOW_PARENT;
+
+
+const columns = [
+  {
+    title: '名称',
+    dataIndex: 'userName',
+    align: 'center',
+    key:'userName',
+    scopedSlots: { customRender: 'userName' }
+  },
+  {
+    title: '类别',
+    dataIndex: 'department',
+    align: 'center', 
+    key: 'department',
+    scopedSlots: { customRender: 'department' }
+  },
+  {
+    title: '创建时间',
+    dataIndex: 'roleName',
+    align: 'center',
+    
+    key: 'roleName',
+    scopedSlots: { customRender: 'roleName' }
+  },
+  
+  {
+    title: '全部覆盖人数',
+    dataIndex: 'cost',
+    align: 'center',
+    scopedSlots: { customRender: 'cost' },
+    sorter:()=>{}
+  },
+  {
+    title: '账户名称',
+    dataIndex: 'accountName',
+    align: 'center',
+    scopedSlots: { customRender: 'accountName' },
+    
+  },
+  {
+    title: '状态',
+    dataIndex: 'status',
+    align: 'center',
+    scopedSlots: { customRender: 'status' },
+    
+  },
+            
+  {
+    title: '操作',
+    dataIndex: 'operation',
+    align: 'center',
+    scopedSlots: { customRender: 'operation' },
+    
+  }
+]
+
+const categoryArr=[
+    {
+        title:'规则',
+        value:'guize',
+        key:'guize'
+    },
+    {
+        title:'运算',
+        value:'yunsuan',
+        key:'yuansuan'
+    },
+    {
+        title:'上传',
+        value:'update',
+        key:'update'
+    },
+    {
+        title:'扩展',
+        value:'extend',
+        key:'extend'
+    },
+    {
+        title:'API',
+        value:'API',
+        key:'API'
+    },
+    {
+        title:'付费',
+        value:'pay',
+        key:'pay'
+    },
+    {
+        title:'主题人群',
+        value:'crowd',
+        key:'crowd'
+    },
+]
+export default {
+    components: {
+        editableCell,
+    },
+    data() {
+        return {
+            //treeselect的参数
+            
+            treeData: [],
+            SHOW_PARENT,
+            accountId:[],
+            
+             //主页的表格
+            dataSource:[
+                {
+                    userName:'人群纠错包1',
+                    department:'运算',
+                    roleName:'2020-6-10',
+                    cost:16897546322,
+                    accountName:'伊对-01',
+                    status:true,
+                    key:0
+                },
+                {
+                    userName:'人群纠错包2',
+                    department:'运算',
+                    roleName:'2020-6-10',
+                    cost:16897322,
+                    accountName:'伊对-02',
+                    status:false,
+                    key:1
+                },
+                {
+                    userName:'人群纠错包3',
+                    department:'运算',
+                    roleName:'2020-6-10',
+                    cost:16322,
+                    accountName:'伊对-03',
+                    status:true,
+                    key:2
+                },
+            ],
+            categoryArr,
+            columns,
+            selectedRowKeys:[],
+            rowSelection:{
+                onChange: (selectedRowKeys, selectedRows) => {
+                    console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
+                    console.log(selectedRowKeys);
+                    this.selectedRowKeys=selectedRowKeys;
+                },
+                onSelect: (record, selected, selectedRows) => {
+                    console.log(record, selected, selectedRows);
+                    
+                },
+                onSelectAll: (selected, selectedRows, changeRows) => {
+                    console.log(selected, selectedRows, changeRows);
+                    
+                },
+            },
+            editID:0,
+            //查询条件
+            treeValue: [],
+            coverageQuantity:undefined,
+            category:undefined,
+            dateValue:null,//日期选择器
+            nameSearch:undefined,
+            batchValue:undefined, //批量操作的选中值
+
+            updatePackageVisiable:false,//上传人群包的弹出框
+            matchValue:undefined, //上传人群包的匹配框
+            crowedName:undefined,//上传人群包名称
+            typeMatch:2,//类型匹配
+            showcrowedPackage:false,
+            populationGroup:undefined,//上传人群包---人群分组
+        }
+    },
+    methods: {
+        //项目改变后的事件
+        treeChange(val) {
+            // console.log(this.treeData)
+            console.log(val)
+            this.accountId = [];
+            //选择一个后禁用其他
+            if(val.length==1){
+                if(val[0]*1){
+                    let selectindex=0
+                    this.treeData.forEach((ele,index)=>{                   
+                        if(ele.children){
+                            ele.children.map((item,ind)=>{
+                                    if(item.value==val[0]){
+                                        selectindex=index;
+                                        
+                                    }
+                            })
+                        }                   
+                    });
+                    console.log(selectindex)
+                    if(selectindex ||selectindex==0){
+                        this.treeData.forEach((ele,index)=>{
+                            if(index!=selectindex){
+                                ele.disableCheckbox = true;
+                                if(ele.children){
+                                    ele.children.map((item,ind)=>{
+                                        item.disableCheckbox = true;
+                                    })
+                                }
+                            }
+                        })
+                    }
+                    
+                }else{
+                    //  console.log(1)
+                    this.treeData.forEach((ele,index)=>{
+                            if(ele.value!=val[0]){
+                                ele.disableCheckbox = true;
+                                
+                                if(ele.children){
+                                    ele.children.forEach((item,ind)=>{
+                                        item.disableCheckbox = true;
+                                    })
+                                }
+                            }
+                            
+                    })
+                }
+               
+            }
+
+            if(val.length==0){
+                this.treeData.forEach((ele,index)=>{              
+                        ele.disableCheckbox = false;
+                        this.mediaId=ele.mediaId;
+                        if(ele.children){
+                            ele.children.forEach((item,ind)=>{
+                                item.disableCheckbox = false;
+                            })
+                        }
+                    
+                });
+               
+            }
+            if(val){
+                val.forEach((ele,index)=>{
+                if(ele*1){
+                    this.accountId.push(ele.value)
+                }else{              
+                    let projectArr=this.treeData.filter((item)=>{
+                        return item.value==ele
+                    });
+                    console.log(projectArr)
+                    projectArr[0].children.forEach((element)=>{
+                        this.accountId.push(element.value)
+                    })
+                }
+                })       
+            }
+            
+            console.log(this.accountId)
+        },
+        treeSearch(){
+            console.log(arguments);
+        },
+        treeSelect(){
+            // console.log(arguments);
+            // this.treeValue=arguments[0].value
+        },
+        coverChange(){
+
+        },
+        categoryChange(){
+
+        },
+        //日期改变
+        dateChange(date, dateString) {
+            console.log(date, dateString);
+            this.dateValue=date;
+        },
+        //按名字搜索
+        onSearch(value) {
+            console.log(value);
+        },
+        //批量操作
+        batchChange(val){
+            console.log(val)
+            this.batchValue=val
+        },
+        //查询按钮
+        search(){
+
+        },
+        //清空全部
+        clearAll(){
+            this.treeValue=[];
+            this.coverageQuantity=undefined;
+            this.category=undefined;
+            this.dateValue=null;//日期选择器
+            this.nameSearch=undefined;
+            this.batchValue=undefined; //批量操作的选中值
+        },
+        //表格里的删除按钮
+        onDelete(key) {
+            console.log(key)
+            const dataSource = [...this.dataSource];
+            this.dataSource = dataSource.filter(item => item.key !== key);
+
+        },
+        //上传人群包
+        updatePackage(){
+            this.updatePackageVisiable=true;
+        },
+        //同步人群包
+        synchro(){
+
+        },
+        updatePackageOk(){
+            this.updatePackageVisiable = false;
+        },
+        //匹配类型
+        matchChange(val){
+            console.log(val)
+        },
+        //上传人群包--选择已有的人群分组
+        showGroupPage(){
+            this.showcrowedPackage=!this.showcrowedPackage
+        },
+        //人群分组选中事件
+        selectgroupName(e){
+            // console.log(e)
+            this.populationGroup=e.target.innerText;
+            this.showcrowedPackage=!this.showcrowedPackage
+        },
+ 
+        filterOption(input, option){
+            console.log(input, option)
+            return (
+                option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                );
+        },
+    },
+    filters: {
+        toPercentage(val) {
+            if(val){
+                if(typeof val != 'string'){
+                    return (val * 100).toFixed(2) + '%'
+                }else{
+                    return val
+                }
+            }else if(typeof val =='string'){
+                    return val
+                }
+            else{
+                return 0
+            }    
+        },
+        //保留两位小数并且变成货币格式
+        decimalsHandle(val){
+            
+            if(val && typeof val !='string'){
+                if(val>=0){
+                    val=parseFloat(val).toFixed(2);
+                    let numberStr = val.toString()
+                    let str = numberStr.split('.')
+                    
+                    let str0=str[0].split('').reverse();
+                    for (let i = 0; i < str0.length; i++) {
+                        if ((i + 1) % 4 === 0) {
+                            str0.splice(i, 0, ',')
+                        }
+                    }
+                    str0.reverse()
+                    let handleResult = ''
+                    for (let j = 0; j < str0.length; j++) {
+                        handleResult += str0[j]
+                    }
+                    
+                    return handleResult+'.'+str[1]
+                }else{
+                    val=parseFloat(val).toFixed(2);
+                    let numberStr = val.toString()
+                    let str = numberStr.split('.')
+                    
+                    let str0=str[0].substr(1).split('').reverse();
+                    for (let i = 0; i < str0.length; i++) {
+                        if ((i + 1) % 4 === 0) {
+                            str0.splice(i, 0, ',')
+                        }
+                    }
+                    str0.reverse()
+                    let handleResult = ''
+                    for (let j = 0; j < str0.length; j++) {
+                        handleResult += str0[j]
+                    }
+                    
+                    return '-'+handleResult+'.'+str[1]
+                }
+                
+            }else if(typeof val =='string'){
+                return val
+            }
+            else{
+                return 0
+            }           
+        },
+        //变成货币格式
+        formatCurrency(val){
+            if((val||val==0)&& typeof val !='string'){
+                let numberStr = val.toString()
+                let str = numberStr.split('').reverse()
+                for (let i = 0; i < str.length; i++) {
+                    if ((i + 1) % 4 === 0) {
+                    str.splice(i, 0, ',')
+                    }
+                }
+                str.reverse()
+                let handleResult = ''
+                for (let j = 0; j < str.length; j++) {
+                    handleResult += str[j]
+                }
+                return handleResult
+            }else if(typeof val =='string'){
+                    return val
+            }
+            else{
+                return '-'
+            }
+            
+        }
+    }
+}
+</script>
+<style lang="scss">
+    #updatePackageOk{
+        .title{
+            font-size: 18px;
+            font-weight: 700;
+        }
+        .desc{
+            width: 100px;
+            display: inline-block;
+            text-align: right;
+            margin-right: 10px;
+            .redCircular,.Circular{
+                display: inline-block;
+                margin-left: 5px;
+                width: 5px;
+                height: 5px;
+                border-radius: 50%;
+                background-color: red;
+                position: relative;
+                top: -2px;
+            }
+            .Circular{
+                background-color: transparent;
+            }
+        }
+        .updatePackagebody{
+            .crowedGroup{
+                display: inline-block;
+                width: 500px;
+                position: relative;
+                .crowedGroupPage{
+                    position: absolute;
+                    width: 400px;
+                    height: 250px;
+                    top: 32px;
+                    left: 0;
+                    background-color: #fff;
+                    border: 1px solid #ddd;
+                    border-top: null;
+                    border-radius: 0  0 10px 10px ;
+                    overflow:auto;
+                    z-index: 3;
+                    ul{
+                        padding: 0;
+                        margin: 0em;
+                    }
+                    .crowedGroupPageItem{
+                        height: 30px;
+                        line-height: 30px;
+                        padding: 0 15px;
+                        list-style: none;
+                        
+                    }
+                    .crowedGroupPageItem:hover{
+                        background-color: rgba(0,0,0,.2);
+                    }
+                }
+            }
+            .tips{
+                display: block;
+                font-size: 12px;
+                color: #999;
+                margin-left: 110px;
+                margin-top: 10px;
+                .tipsinfo{
+                    display: block;
+                    margin-bottom: 6px;
+                }
+                .tipsTitle{
+                    display: block;
+                    color: #777;
+                }
+            }
+        }
+
+    }
+</style>
+<style lang="scss" scoped>
+.crowedPackage{
+    
+    .optHeader{
+        margin: 15px 0;
+        padding: 15px 15px;
+        background: #fff;
+        .optItem{
+            display: inline-block;
+            margin-right: 15px;
+            .ok{
+                margin-right: 15px;
+            }
+        }
+        .top{
+            margin-bottom: 15px;
+        }
+        .optionBtn{
+        // display: inline-block;
+            float: right;
+            .searchBtn{
+                margin-right: 10px;
+            }
+        }
+    }
+    .optHeader:hover{
+        box-shadow: 0 0 15px rgba(0,0,0,.2);
+        border-radius: 10px;
+    }
+    .tableBOX{
+        background: #fff;
+        padding: 15px 15px;
+        .tableOpt{
+            margin-bottom: 10px;
+            .search{
+                margin-right: 15px;
+            }
+            .addCol{
+                float:right;
+
+            }
+        }
+        
+    }
+
+}
+</style>

+ 3 - 3
vue.config.js

@@ -65,15 +65,15 @@ module.exports = {
        },*/
       '/jeecg-boot': {
        
-        target: 'http://192.168.1.90:8080', //请求本地 需要jeecg-boot后台项目  蒙蒙
+        // target: 'http://192.168.1.90:8080', //请求本地 需要jeecg-boot后台项目  蒙蒙
        
-        target: 'http://192.168.1.72:8088', //请求本地 需要jeecg-boot后台项目  英豪
+        // target: 'http://192.168.1.72:8088', //请求本地 需要jeecg-boot后台项目  英豪
        
         // target: 'http://192.168.2.115:8080', //请求本地 需要jeecg-boot后台项目  祚云
         // target: 'http://192.168.1.94:8804', //请求本地 需要jeecg-boot后台项目  孙震
         // target: 'http://192.168.1.51:8088', //请求本地 需要jeecg-boot后台项目  毕洁泉
         // target: 'http://192.168.1.165:8848', //请求本地 需要jeecg-boot后台项目  毕洁泉
-        // target: 'http://api.tjyourong.com.cn', //请求本地 需要jeecg-boot后台项目 
+        target: 'http://api.tjyourong.com.cn', //请求本地 需要jeecg-boot后台项目 
         // target: 'https://trac.tjyourong.com.cn', //请求本地 需要jeecg-boot后台项目 
         // target: 'http://192.168.1.251:8088', //请求本地 需要jeecg-boot后台项目 
         // target: 'http://adsp.tjyourong.com.cn/', //请求本地 需要jeecg-boot后台项目