setProjectConvert.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. <template>
  2. <div class="newPlan">
  3. <div class="moduler">
  4. <div v-if="projectInfo.length>0">
  5. <span style="margin-right:8px"> 项目:<strong>{{projectInfo[0].name||''}}</strong></span>
  6. <span style="margin-right:8px"> 推广目的:<strong>{{projectInfo[0].landingType=='APP'?'应用推广':'销售线索收集'||''}}</strong></span>
  7. <span style="margin-right:8px"> 投放媒体:<strong>{{projectInfo[0].deliveryRange=="DEFAULT"?'默认':'穿山甲'||''}}</strong></span>
  8. <span style="margin-right:8px"> 投放方式:
  9. <strong v-if="projectInfo[0].adTarget=='CPA'">优先成本</strong>
  10. <strong v-if="projectInfo[0].adTarget=='COST'">优先跑量</strong>
  11. <strong v-if="projectInfo[0].adTarget=='PUSH'">激进抢量</strong>
  12. </span>
  13. </div>
  14. </div>
  15. <div class="moduler">
  16. <a-form :form="form">
  17. <div class="moduler-title">投放链接</div>
  18. <div class="ad-range">
  19. <div class="row-item" v-if="projectInfo.length>0&&projectInfo[0].landingType=='APP'" >
  20. <div class="hint-item"></div>
  21. <div class="label-item">
  22. <div class="text-item">下载方式</div>
  23. <div class="required-item"></div>
  24. </div>
  25. <div class="input-item">
  26. <a-form-item>
  27. <a-radio-group
  28. v-decorator="['downloadType',{ initialValue:'DOWNLOAD_URL' }]"
  29. @change="downloadTypeChange">
  30. <a-radio-button value="DOWNLOAD_URL">下载链接</a-radio-button>
  31. <a-radio-button value="EXTERNAL_URL">落地页</a-radio-button>
  32. </a-radio-group>
  33. </a-form-item>
  34. </div>
  35. </div>
  36. <div class="row-item">
  37. <div class="hint-item"></div>
  38. <div class="label-item">
  39. <div class="text-item">投放平台</div>
  40. <div class="required-item"></div>
  41. </div>
  42. <div class="input-item">
  43. <a-form-item>
  44. <a-radio-group v-decorator="['appType', { initialValue:'APP_IOS' }]" @change="appTypeChange">
  45. <a-radio-button value="" v-if="getFormData('downloadType')=='EXTERNAL_URL' || (projectInfo.length>0&&projectInfo[0].landingType=='LINK')">不限</a-radio-button>
  46. <a-radio-button value="APP_IOS">IOS</a-radio-button>
  47. <a-radio-button value="APP_ANDROID">安卓</a-radio-button>
  48. </a-radio-group>
  49. </a-form-item>
  50. </div>
  51. </div>
  52. <div class="row-item">
  53. <div class="hint-item"></div>
  54. <div class="label-item">
  55. <div class="text-item">链接地址</div>
  56. <div class="required-item"></div>
  57. </div>
  58. <div class="input-item">
  59. <a-form-item>
  60. <a-input v-decorator="['url', {rules:validationRules.url}]" @change="UrlChange" />
  61. </a-form-item>
  62. </div>
  63. </div>
  64. <div class="row-item" v-if="getFormData('downloadType')=='DOWNLOAD_URL'&&getFormData('appType')=='APP_ANDROID'">
  65. <div class="hint-item"></div>
  66. <div class="label-item">
  67. <div class="text-item">应用包名</div>
  68. <div class="required-item"></div>
  69. </div>
  70. <div class="input-item">
  71. <a-form-item>
  72. <a-input v-decorator="['adlabPackage', {rules:validationRules.name}]" :disabled="true" />
  73. </a-form-item>
  74. </div>
  75. </div>
  76. <div class="row-item" v-if="getFormData('downloadType')=='DOWNLOAD_URL'&&getFormData('appType')=='APP_ANDROID'">
  77. <div class="hint-item"></div>
  78. <div class="label-item">
  79. <div class="text-item">应用下载详情页</div>
  80. <div class="required-item"></div>
  81. </div>
  82. <div class="input-item">
  83. <a-form-item>
  84. <a-input v-decorator="['webUrl', {rules:validationRules.url}]" />
  85. </a-form-item>
  86. </div>
  87. </div>
  88. <div class="row-item" v-show="getFormData('downloadType')=='EXTERNAL_URL'">
  89. <div class="hint-item"></div>
  90. <div class="label-item">
  91. <div class="text-item">直达链接</div>
  92. <div class="required-item"></div>
  93. </div>
  94. <div class="input-item">
  95. <a-form-item>
  96. <a-radio-group v-decorator="['useOpenUrl', { initialValue:'NO' }]" @change="useOpenUrlChange">
  97. <a-radio-button value="NO">不启用</a-radio-button>
  98. <a-radio-button value="YES">启用</a-radio-button>
  99. </a-radio-group>
  100. </a-form-item>
  101. </div>
  102. </div>
  103. <div class="row-item" v-show="getFormData('downloadType')=='EXTERNAL_URL'&&getFormData('useOpenUrl')=='YES'">
  104. <div class="hint-item"></div>
  105. <div class="label-item">
  106. <div class="text-item">跳转APP链接</div>
  107. <div class="required-item"></div>
  108. </div>
  109. <div class="input-item">
  110. <a-form-item>
  111. <a-input v-decorator="['openUrl']" />
  112. </a-form-item>
  113. </div>
  114. </div>
  115. <div class="row-item">
  116. <div class="hint-item"></div>
  117. <div class="label-item">
  118. <div class="text-item">转化目标</div>
  119. <div class="required-item"></div>
  120. </div>
  121. <div class="input-item" >
  122. <a-form-item style="margin-bottom:15px" v-for="(item,index) in LHKaccountInfo" :key="index">
  123. <a-radio-button
  124. value="SelectConversionTarget"
  125. @click="SelectConversionTarget(item,index)"
  126. :disabled="!IsURL(getFormData('url'))"
  127. v-show="showIndex<=index"
  128. >选择转化目标</a-radio-button>
  129. <a-select style="width: 335px" v-show="showIndex>index" @change="APIChange($event,index)">
  130. <a-select-option v-for="item in currentConvertTypes[index]" :key="item.convertId" :value='item.convertId'>
  131. {{item.external_name}}
  132. </a-select-option>
  133. </a-select>
  134. <span style="margin-left:20px">账户:{{item.title}} </span>
  135. </a-form-item>
  136. </div>
  137. </div>
  138. </div>
  139. </a-form>
  140. </div>
  141. <!-- 当前账户 -->
  142. <div class="moduler">
  143. <div class="adName">
  144. <span>当前账户:</span>
  145. <div class="nameList">
  146. <strong v-for="item in LHKaccountInfo" :key="item.value" class="item">{{item.title+'('+item.value+')'}}</strong>
  147. </div>
  148. </div>
  149. </div>
  150. <!-- 操作 -->
  151. <div class="moduler">
  152. <!-- <div class="moduler-title">计划名称</div> -->
  153. <div class="opt">
  154. <a-button type="default" style="margin-right:15px" @click="goBack">取消</a-button>
  155. <a-button type="primary" @click="goNext" :loading="goNextloading">下一步</a-button>
  156. </div>
  157. </div>
  158. <!-- 投放链接 -->
  159. <div class="infoModal">
  160. <a-modal v-model="visible" title="提示" @ok="handleOk" :keyboard='false' :maskClosable='false'>
  161. <ul>
  162. <li v-for="(item,index) in errorInfo" :key="index">
  163. <span>账户{{LHKaccountInfo[index].title}}:</span>{{item.message || '设置转化信息成功'}}
  164. </li>
  165. </ul>
  166. <template slot="footer">
  167. <a-button key="back" @click="handleCancel">
  168. 返回本页
  169. </a-button>
  170. <a-button key="submit" type="primary" @click="handleOk">
  171. 下一步
  172. </a-button>
  173. </template>
  174. </a-modal>
  175. </div>
  176. </div>
  177. </template>
  178. <script>
  179. import moment from 'moment'
  180. import { getAction, postAction, downFile, downFilePost } from '@/api/manage'
  181. import qs from 'qs'
  182. var str = ""
  183. for (let i = 0; i < 7*48; i++) {
  184. str+='0'
  185. }
  186. export default {
  187. components: {
  188. // selectCheckAll,
  189. // newDirectedPackage,
  190. },
  191. data() {
  192. return {
  193. projectInfo:[],
  194. LHKaccountInfo:[],
  195. form: this.$form.createForm(this),
  196. showIndex:0,
  197. goNextloading:false,
  198. goPlanShowloading:false,
  199. dateRange: [moment(), moment()],
  200. visible:false,
  201. errorInfo:[],
  202. validationRules: {
  203. url: [
  204. {
  205. required: true,
  206. validator: this.validateURL,
  207. },
  208. ],
  209. name:[{
  210. required: true,
  211. validator: this.validateName,
  212. }],
  213. bid:[{
  214. required: true,
  215. message:'出价信息必须填写',
  216. // validator: this.validateBid,
  217. }],
  218. roi:[{
  219. required: true,
  220. message:'ROI系数必须填写',
  221. // validator: this.validateBid,
  222. }],
  223. },
  224. currentConvertTypes:[],
  225. convertIds:[],
  226. convertInfo:[],
  227. }
  228. },
  229. watch: {
  230. },
  231. methods: {
  232. callback(val) {
  233. console.log(val);
  234. },
  235. // 链接地址改变
  236. UrlChange(e){
  237. console.log(e.target.value);
  238. if(this.IsURL(e.target.value)&&this.getFormData('appType')=='APP_ANDROID'&&this.projectInfo[0].landingType=='APP'){
  239. postAction('/ctop/queryTool/parseInstallPackage',qs.stringify({
  240. installUrl:e.target.value,
  241. appType:this.getFormData('appType')
  242. })).then(res=>{
  243. console.log(res)
  244. if(res.success){
  245. this.form.setFieldsValue({
  246. adlabPackage:res.result.package
  247. })
  248. }else{
  249. this.$message.error(res.message)
  250. }
  251. })
  252. }
  253. },
  254. handleOk(e) {
  255. this.visible=false;
  256. // this.$router.push('/LaunchHousekeeper/setProjectDirectional')
  257. this.$router.push({path:'/LaunchHousekeeper/setProjectDirectional'})
  258. },
  259. handleCancel(e) {
  260. this.visible = false;
  261. },
  262. // 直达链接是否启用
  263. useOpenUrlChange(){
  264. this.form.setFieldsValue({
  265. openUrl:''
  266. })
  267. },
  268. // 下载方式改变
  269. downloadTypeChange(val){
  270. console.log(val)
  271. this.showIndex=0;
  272. if(val.target.value=="EXTERNAL_URL"){
  273. this.form.setFieldsValue({
  274. appType:'',
  275. url:'',
  276. adlabPackage:'',
  277. webUrl:'',
  278. })
  279. }else{
  280. this.form.setFieldsValue({
  281. appType:'APP_IOS',
  282. url:'',
  283. adlabPackage:'',
  284. useOpenUrl:'NO',
  285. openUrl:'',
  286. })
  287. }
  288. },
  289. // 投放平台改变
  290. appTypeChange(val){
  291. this.showIndex=0;
  292. if(val.target.value=="APP_IOS"){
  293. this.form.setFieldsValue({
  294. url:'',
  295. adlabPackage:'',
  296. webUrl:'',
  297. })
  298. }else{
  299. this.form.setFieldsValue({
  300. url:'',
  301. })
  302. }
  303. },
  304. // 转化目标显示
  305. SelectConversionTarget(item,index) {
  306. let downloadType=this.getFormData('downloadType');
  307. let adlabPackage=this.getFormData('adlabPackage');
  308. let appType=this.getFormData('appType');
  309. let downloadUrl='';
  310. let externalUrl='';
  311. if(downloadType=='DOWNLOAD_URL'){
  312. downloadUrl=this.getFormData('url');
  313. externalUrl='';
  314. }else{
  315. externalUrl=this.getFormData('url');
  316. downloadUrl='';
  317. }
  318. if(downloadType=='DOWNLOAD_URL'&&appType=='APP_ANDROID'){
  319. if(adlabPackage){
  320. postAction('/ctop/queryTool/queryConvert',qs.stringify({
  321. accountId:this.LHKaccountInfo[index].value,
  322. landingType:this.projectInfo[index].landingType,
  323. downloadType,
  324. downloadUrl,
  325. externalUrl,
  326. toutiaoPackage:adlabPackage,
  327. appType,
  328. })).then(res=>{
  329. console.log(res)
  330. if(res.success){
  331. this.showIndex=index+1
  332. this.currentConvertTypes[index]=[];
  333. res.result.data.forEach(ele=>{
  334. if(ele.external_actions.length>0){
  335. ele.external_actions.forEach(element=>{
  336. if(element.deep_external_action){
  337. element.deep_external_action.forEach(i=>{
  338. this.currentConvertTypes[index].push(i)
  339. })
  340. }else{
  341. this.currentConvertTypes[index].push(element)
  342. }
  343. })
  344. }
  345. })
  346. }else{
  347. this.$message.error('网络异常,数据获取失败')
  348. }
  349. })
  350. }else{
  351. this.$message.error('请先输入应用包名称!')
  352. }
  353. }else{
  354. postAction('/ctop/queryTool/queryConvert',qs.stringify({
  355. accountId:this.LHKaccountInfo[index].value,
  356. landingType:this.projectInfo[index].landingType,
  357. downloadType,
  358. downloadUrl,
  359. externalUrl,
  360. toutiaoPackage:adlabPackage,
  361. appType,
  362. })).then(res=>{
  363. console.log(res);
  364. if(res.success){
  365. this.showIndex=index+1;
  366. this.currentConvertTypes[index]=[];
  367. res.result.data.forEach(ele=>{
  368. if(ele.external_actions.length>0){
  369. ele.external_actions.forEach(element=>{
  370. if(element.deep_external_action){
  371. element.deep_external_action.forEach(i=>{
  372. this.currentConvertTypes[index].push(i)
  373. })
  374. }else{
  375. this.currentConvertTypes[index].push(element)
  376. }
  377. })
  378. }
  379. })
  380. }else{
  381. this.$message.error('网络异常,数据获取失败')
  382. }
  383. })
  384. }
  385. },
  386. // 转化目标改变
  387. APIChange(val,index,item){
  388. console.log(val,index,item);
  389. this.convertIds[index]={
  390. accountId:this.LHKaccountInfo[index].value,
  391. convertId:val,
  392. }
  393. // this.convertInfo[index]={
  394. // accountId:this.LHKaccountInfo[index].value,
  395. // ...item
  396. // }
  397. },
  398. //获取表单的某一个属性值
  399. getFormData(className) {
  400. return this.form.getFieldValue(className)
  401. },
  402. dateChange(date, dateString) {
  403. // console.log(date,dateString)
  404. this.form.getFieldDecorator('startTime')
  405. this.form.getFieldDecorator('endTime')
  406. this.form.setFieldsValue({
  407. startTime: date[0].format('YYYY-MM-DD HH:mm'),
  408. endTime: date[1].format('YYYY-MM-DD HH:mm'),
  409. })
  410. },
  411. // 验证网址
  412. IsURL(res) {
  413. // var strRegex = /^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/|www\.)(([A-Za-z0-9-~]+)\.)+([A-Za-z0-9-~\/])+$/
  414. var strRegex = /^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(([A-Za-z0-9-~]+)\.)+([A-Za-z0-9-~\/])+(.+[A-Za-z0-9-~\/])+$/
  415. var re = new RegExp(strRegex)
  416. // console.log(re.test(res))
  417. if (re.test(res)) {
  418. return true
  419. } else {
  420. return false
  421. }
  422. },
  423. validateURL(rule, value, callback) {
  424. // console.log(rule, value, callback);
  425. if (this.IsURL(value)) {
  426. callback()
  427. } else if (value && !this.IsURL(value)) {
  428. callback('链接地址无法访问,请正确输入')
  429. } else {
  430. callback('链接必须填写')
  431. }
  432. },
  433. validateName(rule, value, callback){
  434. // console.log(rule, value, callback);
  435. if (value) {
  436. callback()
  437. } else {
  438. callback('应用包名称必须填写')
  439. }
  440. },
  441. validateBid(rule, value, callback){
  442. // console.log(rule, value, callback);
  443. if (value) {
  444. callback()
  445. } else {
  446. callback('出价必须填写')
  447. }
  448. },
  449. goBack() {
  450. this.$router.replace('/modules/LaunchHousekeeper/LaunchHousekeeperList')
  451. this.$bus.$emit('remove', '/LaunchHousekeeper/setProjectConvert')
  452. },
  453. // 保存并新建创意
  454. goNext() {
  455. this.$nextTick(()=>{
  456. this.form.validateFields((err, values) => {
  457. if (!err) {
  458. console.log('Received values of form: ', values)
  459. this.goNextloading=true;
  460. let params=[];
  461. params=this.convertIds.map((item,index)=>{
  462. return {
  463. ...item,
  464. ...values,
  465. ...this.projectInfo[index]
  466. }
  467. })
  468. console.log(params)
  469. postAction('/adlab/Project/setConvert', params).then((res) => {
  470. console.log(res)
  471. if (res.success) {
  472. this.goNextloading=false;
  473. if(res.result){
  474. this.errorInfo=res.result;
  475. this.visible=true;
  476. let projectInfo=[]
  477. res.result.forEach(item=>{
  478. if(item.code==0){
  479. projectInfo.push(item)
  480. }
  481. })
  482. sessionStorage.setItem('projectInfo',JSON.stringify(projectInfo))
  483. }
  484. } else {
  485. this.goNextloading=false;
  486. this.$message.error(res.message)
  487. }
  488. })
  489. }else{
  490. this.$message.error('请正确填写必填项目')
  491. }
  492. })
  493. })
  494. },
  495. },
  496. destroyed() {
  497. sessionStorage.setItem('convertInfo',JSON.stringify(this.convertInfo))
  498. },
  499. mounted() {
  500. this.$bus.$emit('remove', '/LaunchHousekeeper/newProject')
  501. let projectInfo=sessionStorage.getItem('projectInfo');
  502. if(projectInfo){
  503. this.projectInfo=JSON.parse(projectInfo)
  504. }
  505. let LHKaccountInfo=sessionStorage.getItem('LHKaccountInfo');
  506. if(LHKaccountInfo){
  507. this.LHKaccountInfo=JSON.parse(LHKaccountInfo)
  508. }
  509. },
  510. }
  511. </script>
  512. <style lang="scss">
  513. .newPlan{
  514. .ant-btn-danger {
  515. background-color: #ff4d4f !important;
  516. }
  517. }
  518. .ant-tooltip-inner,
  519. .ant-tooltip,
  520. .ant-tooltip-arrow::before {
  521. background-color: #fff;
  522. color: #333;
  523. }
  524. .ant-tooltip-inner {
  525. span {
  526. display: block;
  527. }
  528. }
  529. .ant-tooltip {
  530. max-width: 450px;
  531. }
  532. .newPlan {
  533. .ant-radio-button-wrapper {
  534. min-width: 80px;
  535. text-align: center;
  536. }
  537. .ant-form-item {
  538. -webkit-box-sizing: border-box;
  539. box-sizing: border-box;
  540. margin: 0;
  541. padding: 0;
  542. color: rgba(0, 0, 0, 0.65);
  543. font-size: 14px;
  544. font-variant: tabular-nums;
  545. line-height: 1.5;
  546. list-style: none;
  547. -webkit-font-feature-settings: 'tnum';
  548. font-feature-settings: 'tnum';
  549. vertical-align: top;
  550. }
  551. .directedBody {
  552. .ant-form-item {
  553. margin-bottom: 20px;
  554. }
  555. }
  556. }
  557. </style>
  558. <style lang="scss" scoped>
  559. .newPlan {
  560. font-family: PingFangSC-Regular, tahoma, arial, 'Hiragino Sans GB', 'Microsoft yahei', sans-serif;
  561. color: #333;
  562. ul,
  563. li {
  564. margin: 0;
  565. padding: 0;
  566. }
  567. .moduler {
  568. background: #fff;
  569. margin-bottom: 16px;
  570. position: relative;
  571. padding: 32px 24px 48px 32px;
  572. border-radius: 4px;
  573. box-shadow: 0px 1px 6px 0px rgba(0, 0, 0, 0.05);
  574. .moduler-title {
  575. display: flex;
  576. align-items: center;
  577. font-size: 22px;
  578. margin-bottom: 20px;
  579. }
  580. .row-item {
  581. display: flex;
  582. justify-content: flex-start;
  583. align-items: center;
  584. margin-bottom: 32px;
  585. }
  586. .row-item:last-of-type {
  587. margin-bottom: 0;
  588. }
  589. .row-item .hint-item {
  590. width: 24px;
  591. min-width: 24px;
  592. align-self: flex-start;
  593. line-height: 20px;
  594. height: 20px;
  595. margin-top: 5px;
  596. }
  597. .row-item .label-item {
  598. position: relative;
  599. align-items: flex-start;
  600. align-self: flex-start;
  601. line-height: 20px;
  602. height: 20px;
  603. margin-top: 7px;
  604. width: 80px;
  605. min-width: 80px;
  606. .text-item {
  607. font-size: 14px;
  608. width: 60px;
  609. }
  610. }
  611. .row-item .required-item {
  612. width: 4px;
  613. height: 4px;
  614. border-radius: 2px;
  615. background: #f45858;
  616. position: absolute;
  617. right: 10px;
  618. top: 50%;
  619. transform: translateY(-50%);
  620. }
  621. .row-item .input-item {
  622. min-width: 480px;
  623. position: relative;
  624. // height: 35px;
  625. .tip {
  626. font-size: 12px;
  627. color: tomato;
  628. }
  629. }
  630. .adName{
  631. display: flex;
  632. .nameList{
  633. width: 90%;
  634. }
  635. .item{
  636. display: inline-block;
  637. width: 30%;
  638. margin-left: 15px;
  639. margin-bottom: 10px;
  640. }
  641. }
  642. }
  643. .opt {
  644. text-align: right;
  645. }
  646. }
  647. </style>