configLaunchList.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  1. <style scoped lang="scss">
  2. ::v-deep .ant-drawer-header{
  3. border-bottom: 0px;
  4. }
  5. </style>
  6. <template>
  7. <div class="toutiaoBatch">
  8. <div class="toolbox-automate-rules-create-content_title">
  9. <h3>账户配置信息</h3>
  10. <a-button type='primary' @click="goNewConfigInfo" class="goNewConfigInfo">新建配置信息</a-button>
  11. </div>
  12. <div class="topOptions">
  13. <div >
  14. <Treeselect :appId.sync="accountId" :multiple="false" request="2,4" ref="treeSelect" style="margin-bottom:8px;width:600px " />
  15. </div>
  16. <span class="optionBtn">
  17. <a-button type='primary' @click="search" class="searchBtn">查询</a-button>
  18. </span>
  19. </div>
  20. <div class="tableArea">
  21. <!-- <div class="tableOption" v-if="selectedRowKeys.length">
  22. :row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
  23. </div> -->
  24. <div class="table">
  25. <a-table
  26. :columns="columns"
  27. :data-source="data"
  28. bordered
  29. :pagination="ipagination"
  30. :loading="loading"
  31. @change="sort"
  32. >
  33. <span slot="status" slot-scope="text,record">
  34. <a-spin :spinning="record.spin" size="small" >
  35. <div class="spin-content">
  36. <a-switch size="default" :checked='text==1' @change="switchChange(text,record)"/>
  37. </div>
  38. </a-spin>
  39. </span>
  40. <span slot="openProgramCreate" slot-scope="text,record">
  41. <a-spin :spinning="record.openProgramCreateSpin" size="small" >
  42. <div class="spin-content">
  43. <a-switch size="default" :checked='text==1' @change="openProgramCreateSwitchChange(text,record)"/>
  44. </div>
  45. </a-spin>
  46. </span>
  47. <span slot="cpaType" slot-scope="text,record">
  48. {{record.cpaBid.includes('/')?'阶梯出价':record.cpaBid.includes('-')?"随机出价":"统一出价"}}
  49. </span>
  50. <div slot="cpaBid" slot-scope="text,record">
  51. <!-- {{
  52. text==0?record.roiRatio:
  53. text.includes('/')? text.split
  54. }} -->
  55. <span v-if="text===0">{{record.roiRatio}}</span>
  56. <span v-else-if="text.includes('/')">
  57. <!-- {{text.split('/')}} -->
  58. <span v-for="(item,index) in text.split('/')">
  59. {{item/1000+(index === text.split('/').length-1?'':'/')}}
  60. </span>
  61. </span>
  62. <span v-else-if="text.includes('-')">
  63. <!-- {{text.split('/')}} -->
  64. <span v-for="(item,index) in text.split('-')">
  65. {{item/1000+(index === text.split('-').length-1?'':'-')}}
  66. </span>
  67. </span>
  68. <span v-else>{{text/1000}}</span>
  69. </div>
  70. <span slot="ocpxActionType" slot-scope="text">
  71. {{text|ocpxActionType}}
  72. </span>
  73. <span slot="authName" slot-scope="text">
  74. <!-- <a href="javascript:;" >{{text}}</a> -->
  75. {{text || '-'}}
  76. </span>
  77. <span slot="time" slot-scope="text,record">
  78. {{record.startTime}}至{{record.endTime}}
  79. </span>
  80. <span slot="operator" slot-scope="text,record">
  81. <a href="javascript:;" @click="goPlanList(record)">编辑</a>
  82. <a-divider type="vertical" />
  83. <!-- <a href="javascript:;" @click="deleteRecord(record)">删除</a>
  84. <a-divider type="vertical" /> -->
  85. <a-popover v-model="record.visible" trigger="click" placement="topLeft" @visibleChange='visibleChange'>
  86. <span slot="title">出价</span>
  87. <template slot="content" style="width:300px;">
  88. <div style="margin:5px 0 0">
  89. <span ><a-input-number :min="0" v-model="newBid" :step="0.1" placeholder="请输入出价" size="small" style='margin-right:20px;width:120px' /></span>
  90. <p style="color:red;font-size:12px;height:16px;padding:5px 0">{{bidErrorMessage}}</p>
  91. </div>
  92. <div>
  93. <a-button type='default' @click="bidChangeCancel(record)" size='small' style='margin-right:10px'>取消</a-button>
  94. <a-button type='primary' @click="bidChangeOk(record)" size='small' class="ok">修改</a-button>
  95. </div>
  96. </template>
  97. <a href="javascript:;" type='primary' @click="()=>{record.visible=true}">修改出价</a>
  98. </a-popover>
  99. <!-- <a-divider type="vertical" />
  100. -->
  101. <a-divider type="vertical" />
  102. <a-dropdown>
  103. <a class="ant-dropdown-link" @click="e => e.preventDefault()">
  104. 更多
  105. </a>
  106. <a-menu slot="overlay">
  107. <a-menu-item>
  108. <a @click="goExplore(record)">加速探索</a>
  109. </a-menu-item>
  110. <a-menu-item>
  111. <a-popover v-model="record.show" trigger="click" placement="topRight" @visibleChange='visibleChange'>
  112. <div slot="content">
  113. <span style='font-weight:700;margin-right:15px;font-size:15px'>修改后重提</span>
  114. <a-radio-group v-model="examineAgainType" >
  115. <a-radio :value="1">修改广告语</a-radio>
  116. <a-radio :value="0">修改封面</a-radio>
  117. </a-radio-group>
  118. <a-button type='default' @click="examineAgainCancel(record)" size='small' style='margin-right:10px'>取消</a-button>
  119. <a-button type='primary' @click="examineAgainOk(record)" size='small' class="ok">重提</a-button>
  120. </div>
  121. <a href="javascript:;" type='primary' @click="()=>{record.show=true}">一键重提</a>
  122. </a-popover>
  123. </a-menu-item>
  124. <a-menu-item>
  125. <a href="javascript:;" @click="deleteRecord(record)">删除</a>
  126. </a-menu-item>
  127. </a-menu>
  128. </a-dropdown>
  129. </span>
  130. <!-- <span slot="action" slot-scope="text,record">
  131. <a @click="goExplore(record)">加速探索</a>
  132. </span> -->
  133. </a-table>
  134. </div>
  135. </div>
  136. <configLaunchExploreDrawer
  137. :exploreVisible.sync="exploreVisible"
  138. :exploreKey.sync="exploreKey"
  139. ref="exploreDrawer" />
  140. </div>
  141. </template>
  142. <script>
  143. import moment from 'moment';
  144. import { getAction, postAction, downFile, downFilePost,deleteAction } from '@/api/manage';
  145. // import { JeecgListMixin } from '@/mixins/ipagination'
  146. // import editableCell from './editableCell'
  147. import Treeselect from '@/views/modules/Statistics/components/Treeselect.vue'
  148. import configLaunchExploreDrawer from './components/configLaunchExploreDrawer.vue'
  149. import qs from 'qs'
  150. import { mapActions, mapGetters } from 'vuex'
  151. let typeValue='预算'
  152. const strategyColumns = [
  153. {
  154. title: '开关',
  155. dataIndex: 'status',
  156. key: 'status',
  157. align: 'center',
  158. scopedSlots: { customRender: 'status' },
  159. width:110,
  160. },
  161. {
  162. title: '所属账户名称',
  163. dataIndex: 'authName',
  164. key: 'authName',
  165. align: 'center',
  166. scopedSlots: { customRender: 'authName' },
  167. width:200,
  168. },
  169. {
  170. title: '所属账户ID',
  171. dataIndex: 'accountId',
  172. key: 'accountId',
  173. align: 'center',
  174. scopedSlots: { customRender: 'accountId' },
  175. },
  176. {
  177. title: '创建时间',
  178. dataIndex: 'createTime',
  179. key: 'createTime',
  180. align: 'center',
  181. scopedSlots: { customRender: 'createTime' },
  182. },
  183. {
  184. title: '转化目标',
  185. dataIndex: 'ocpxActionType',
  186. align: 'center',
  187. scopedSlots: { customRender: 'ocpxActionType' },
  188. // sorter:() => {}
  189. },
  190. {
  191. title: '出价类型',
  192. dataIndex: 'cpaType',
  193. align: 'center',
  194. scopedSlots: { customRender: 'cpaType' },
  195. // sorter:() => {}
  196. },
  197. {
  198. title: '出价',
  199. dataIndex: 'cpaBid',
  200. align: 'center',
  201. scopedSlots: { customRender: 'cpaBid' },
  202. // sorter:() => {}
  203. },
  204. // {
  205. // title: '是否开启程序化创建',
  206. // dataIndex: 'openProgramCreate',
  207. // align: 'center',
  208. // scopedSlots: { customRender: 'openProgramCreate' },
  209. // sorter:() => {},
  210. // width:180,
  211. // },
  212. {
  213. title: '操作',
  214. dataIndex: 'operator',
  215. key: 'operator',
  216. align: 'center',
  217. scopedSlots: { customRender: 'operator' },
  218. },
  219. // {
  220. // title: '探索工具',
  221. // dataIndex: 'action',
  222. // key: 'action',
  223. // align: 'center',
  224. // scopedSlots: { customRender: 'action' },
  225. // fixed:'right',
  226. // width:150,
  227. // },
  228. ];
  229. const publicColumns = [
  230. ]
  231. export default {
  232. name:'strategy-list',
  233. components: {
  234. // editableCell,
  235. Treeselect,
  236. configLaunchExploreDrawer
  237. },
  238. // mixins: [JeecgListMixin],
  239. data() {
  240. return {
  241. exploreAccountId:"",
  242. exploreVisible:false,
  243. exploreKey:'',
  244. targetVisible:false,
  245. selectedRecord:{},
  246. bidErrorMessage:'',
  247. examineAgainType:1,
  248. newBid:undefined,
  249. examineAgain:false,
  250. accountId:[],
  251. accountList:[],
  252. strategyState:undefined,
  253. strategyName:'',
  254. strategyId:undefined,
  255. scrollX:1400,
  256. ipagination: {
  257. current: 1,
  258. pageSize: 10,
  259. // pageSizeOptions: ['10', '20', '30'],
  260. showTotal: (total, range) => {
  261. return range[0] + "-" + range[1] + " 共" + total + "条"
  262. },
  263. showQuickJumper: true,
  264. showSizeChanger:true,
  265. pageSizeOptions: ['10', '30', '50'],
  266. total: 0,
  267. onChange: (current, pageSize) => {
  268. // 切换分页时的回调,
  269. // 当在页面定义change事件时,切记要把此处的事件清除,因为这两个事件重叠了,可能到时候会导致一些莫名的bug
  270. this.ipagination.current = current;
  271. this.ipagination.pageSize= pageSize;
  272. }
  273. },
  274. spinning:false,
  275. moment,
  276. optionId:'',//input输入的id或关键词
  277. selectDisable:true,
  278. optValue:undefined,//操作设置的值 删除 暂停 开启
  279. visible: false,//出价里的弹出框
  280. //主页的表格
  281. data:[],
  282. columns:[...strategyColumns,...publicColumns],
  283. selectedRowKeys:[],
  284. loading:false,
  285. editID:0,
  286. url: {
  287. list:'/ctop/aiKuaishouAdvertiserStrategy/list',
  288. delete:'/ctop/aiKuaishouAdvertiserStrategy/delete',
  289. },
  290. xiugaiData:[],//存分别修改时候的数组
  291. }
  292. },
  293. computed: {
  294. hasSelected() {
  295. return this.selectedRowKeys.length > 0;
  296. },
  297. },
  298. methods: {
  299. ...mapGetters(['userInfo']),
  300. goExplore(item) {
  301. this.exploreVisible = true
  302. this.exploreKey = '1'
  303. this.exploreAccountId = item.accountId
  304. this.$refs.exploreDrawer.getData(item.accountId)
  305. },
  306. //状态改变
  307. switchChange(text,record){
  308. // this.spinning=true;
  309. console.log(text,record)
  310. record.spin=true;
  311. let status=text==1?0:1;
  312. getAction(`/ctop/aiKuaishouAdvertiserStrategy/oprateStatus`,{
  313. id:record.id,
  314. status
  315. }).then((res)=>{
  316. record.spin=false;
  317. if(res.success){
  318. this.getStrategyList()
  319. this.$message.success(res.message)
  320. }else{
  321. this.$message.error(res.message)
  322. }
  323. })
  324. },
  325. //是否开启程序化创意状态改变
  326. openProgramCreateSwitchChange(text,record){
  327. // this.spinning=true;
  328. console.log(text,record)
  329. record.openProgramCreateSpin=true;
  330. let status=text==1?0:1;
  331. getAction(`/ctop/aiKuaishouAdvertiserStrategy/oprateCreativeStatus`,{
  332. id:record.id,
  333. status
  334. }).then((res)=>{
  335. record.openProgramCreateSpin=false;
  336. if(res.success){
  337. this.getStrategyList()
  338. this.$message.success(res.message)
  339. }else{
  340. this.$message.error(res.message)
  341. }
  342. })
  343. },
  344. examineAgainMethod(record){
  345. console.log(record)
  346. this.examineAgain=true;
  347. this.selectedRecord=record
  348. },
  349. visibleChange(){
  350. this.bidErrorMessage='';
  351. this.examineAgainType=1;
  352. this.newBid=undefined;
  353. },
  354. bidChangeCancel(record){
  355. record.visible=false;
  356. this.newBid=undefined;
  357. this.bidErrorMessage=''
  358. },
  359. bidChangeOk(record){
  360. if(this.newBid){
  361. record.visible=false;
  362. postAction('/ai/batchUpdate/updateGroupBid',{
  363. accountId:record.accountId,
  364. bid:this.newBid*1000
  365. }).then(res=>{
  366. console.log(res)
  367. if(res.code==0){
  368. this.$message.success(res.message)
  369. this.newBid=undefined;
  370. this.getStrategyList()
  371. }
  372. })
  373. }else{
  374. this.bidErrorMessage='请正确填写出价'
  375. // this.$message.error('请正确填写出价')
  376. }
  377. },
  378. examineAgainCancel(record){
  379. record.show=false;
  380. this.examineAgainType=1
  381. },
  382. examineAgainOk(record){
  383. record.show=false;
  384. postAction('/kuaishou/creative/again',{
  385. accountId:record.accountId,
  386. updateType:this.examineAgainType
  387. }).then(res=>{
  388. console.log(res);
  389. if(res.code==0){
  390. this.$message.success('正在重提中,您可稍后查看结果')
  391. }else{
  392. this.$message.success(res.message)
  393. }
  394. this.examineAgainType=1
  395. })
  396. },
  397. onSelectChange(selectedRowKeys) {
  398. console.log('selectedRowKeys changed: ', selectedRowKeys);
  399. this.selectedRowKeys = selectedRowKeys;
  400. },
  401. goNewConfigInfo(){
  402. this.$router.push('/autoLaunch/configLaunchInfo')
  403. },
  404. goPlanList(record){
  405. console.log(record)
  406. this.$parent.currentStrategyId=record.id;
  407. this.$router.push(`/autoLaunch/configLaunchInfo?id=${record.id}`)
  408. },
  409. deleteRecord(record){
  410. let that = this
  411. this.$confirm({
  412. title: '删除提示',
  413. content: '是否删除该账户配置信息?',
  414. onOk() {
  415. that.loading=true
  416. deleteAction(that.url.delete,{
  417. id:record.id
  418. }).then(res=>{
  419. that.loading=false
  420. if(res.success){
  421. that.$message.success(res.message);
  422. that.getStrategyList()
  423. }else{
  424. that.$message.success(res.message);
  425. }
  426. })
  427. }
  428. });
  429. },
  430. filterOption(input, option) {
  431. return (
  432. option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
  433. );
  434. },
  435. //查询按钮事件
  436. search(){
  437. this.ipagination.current=1;
  438. this.getStrategyList()
  439. },
  440. //点击分页
  441. sort(pagination, filters, sorter, { currentDataSource }){
  442. console.log(pagination)
  443. this.ipagination.current=pagination.current;
  444. this.ipagination.pageSize=pagination.pageSize;
  445. this.getStrategyList()
  446. },
  447. getStrategyList(){
  448. this.loading = true
  449. console.log(this.accountId)
  450. getAction(this.url.list,{
  451. strategyId:this.strategyId==undefined?null:this.strategyId,
  452. accountId:this.accountId,
  453. pageNo:this.ipagination.current,
  454. pageSize:this.ipagination.pageSize,
  455. userId:this.userInfo().id
  456. }).then((res)=>{
  457. this.data=[]
  458. console.log(res)
  459. this.loading = false
  460. if(res.success){
  461. this.ipagination.total = res.result.total
  462. res.result.list.forEach((item)=>{
  463. item.key=item.id;
  464. item.show=false;
  465. item.visible=false;
  466. item.spin=false;
  467. item.openProgramCreateSpin=false;
  468. })
  469. this.data = res.result.list;
  470. this.selectedRowKeys=[];
  471. }
  472. })
  473. },
  474. },
  475. mounted() {
  476. this.getStrategyList()
  477. },
  478. activated() {
  479. this.getStrategyList()
  480. },
  481. beforeDestroy() {
  482. },
  483. filters: {
  484. toPercentage(val) {
  485. if(val){
  486. if(typeof val != 'string'){
  487. return (val * 100).toFixed(2) + '%'
  488. }else{
  489. return val
  490. }
  491. }else if(typeof val =='string'){
  492. return val
  493. }
  494. else{
  495. return 0
  496. }
  497. },
  498. //保留两位小数并且变成货币格式
  499. decimalsHandle(val){
  500. if(val && typeof val !='string'){
  501. if(val>=0){
  502. val=parseFloat(val).toFixed(2);
  503. let numberStr = val.toString()
  504. let str = numberStr.split('.')
  505. let str0=str[0].split('').reverse();
  506. for (let i = 0; i < str0.length; i++) {
  507. if ((i + 1) % 4 === 0) {
  508. str0.splice(i, 0, ',')
  509. }
  510. }
  511. str0.reverse()
  512. let handleResult = ''
  513. for (let j = 0; j < str0.length; j++) {
  514. handleResult += str0[j]
  515. }
  516. return handleResult+'.'+str[1]
  517. }else{
  518. val=parseFloat(val).toFixed(2);
  519. let numberStr = val.toString()
  520. let str = numberStr.split('.')
  521. let str0=str[0].substr(1).split('').reverse();
  522. for (let i = 0; i < str0.length; i++) {
  523. if ((i + 1) % 4 === 0) {
  524. str0.splice(i, 0, ',')
  525. }
  526. }
  527. str0.reverse()
  528. let handleResult = ''
  529. for (let j = 0; j < str0.length; j++) {
  530. handleResult += str0[j]
  531. }
  532. return '-'+handleResult+'.'+str[1]
  533. }
  534. }else if(typeof val =='string'){
  535. return val
  536. }
  537. else{
  538. return 0
  539. }
  540. },
  541. //变成货币格式
  542. formatCurrency(val){
  543. if((val||val==0)&& typeof val !='string'){
  544. let numberStr = val.toString()
  545. let str = numberStr.split('').reverse()
  546. for (let i = 0; i < str.length; i++) {
  547. if ((i + 1) % 4 === 0) {
  548. str.splice(i, 0, ',')
  549. }
  550. }
  551. str.reverse()
  552. let handleResult = ''
  553. for (let j = 0; j < str.length; j++) {
  554. handleResult += str[j]
  555. }
  556. return handleResult
  557. }else if(typeof val =='string'){
  558. return val
  559. }
  560. else{
  561. return '-'
  562. }
  563. },
  564. }
  565. }
  566. </script>
  567. <style lang="scss">
  568. #closeIcon{
  569. color: #0E74D2;
  570. }
  571. .toutiaoBatch{
  572. .ant-tag .anticon-close {
  573. color: #1890ff;
  574. }
  575. .ant-tag .anticon-close:hover{
  576. color: rgba(0, 0, 0, 0.85);
  577. }
  578. }
  579. #batchModal{
  580. .rules,.totalPrice{
  581. font-weight: 600;
  582. }
  583. .selectePlan{
  584. font-size: 14px;
  585. font-weight: 700;
  586. color: #333;
  587. padding: 20px 0;
  588. }
  589. .totalPrice{
  590. margin-left: 20px;
  591. }
  592. .modifyTable{
  593. margin-top: 20px;
  594. width: 100%;
  595. height: 400px;
  596. overflow: auto;
  597. font-weight: 600;
  598. }
  599. }
  600. #copyModal{
  601. .ant-modal-header{
  602. text-align: center;
  603. }
  604. .copyTip{
  605. font-size: 12px;
  606. color: #999;
  607. }
  608. .copyName{
  609. width: 118px;
  610. display: inline-block;
  611. text-align: right;
  612. .copyKeyStart{
  613. color: red;
  614. }
  615. }
  616. // font-weight: 600;
  617. }
  618. </style>
  619. <style lang="scss" scoped>
  620. .toutiaoBatch{
  621. .breadcrumb{
  622. height: 22px;
  623. font-size: 12px;
  624. font-family: PingFangSC-Regular, PingFang SC;
  625. font-weight: 400;
  626. color: #000000;
  627. line-height: 22px;
  628. }
  629. background-color: #fff;
  630. padding: 10px 20px;
  631. position: relative;
  632. width: 100%;
  633. .OptinItem{
  634. display: inline-block;
  635. margin-right: 15px;
  636. margin-top: 15px;
  637. .ok{
  638. margin-right: 15px;
  639. }
  640. }
  641. .OptinItem:first-child{
  642. margin-right: 10px;
  643. }
  644. .topOptions{
  645. padding: 15px 0;
  646. display: flex;
  647. justify-content: space-between;
  648. .topOpt{
  649. width: 100%;
  650. margin-bottom: 10px;
  651. }
  652. }
  653. .optionBtn{
  654. // display: inline-block;
  655. float: right;
  656. // .searchBtn{
  657. // margin-right: 10px;
  658. // }
  659. }
  660. .tableArea{
  661. .tableOption{
  662. padding: 20px 0;
  663. }
  664. }
  665. .toolbox-automate-rules-create-content_title {
  666. background-color: #fff;
  667. display: flex;
  668. flex-flow: row nowrap;
  669. justify-content: flex-start;
  670. align-items: center;
  671. margin-bottom: 28px;
  672. position: relative;
  673. h3 {
  674. font-size: 22px;
  675. margin: 0;
  676. font-weight: 400;
  677. height: 30px;
  678. line-height: 30px;
  679. }
  680. .goNewConfigInfo{
  681. position: absolute;
  682. right: 0;
  683. top: 4px;
  684. }
  685. }
  686. }
  687. </style>