viewAI.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. <template src="./viewAI.html">
  2. </template>
  3. <script>
  4. const util = require('@/utils/util.js').default;
  5. import {
  6. MessageBox
  7. } from 'mint-ui';
  8. import {
  9. Indicator
  10. } from 'mint-ui';
  11. import {
  12. Toast
  13. } from 'mint-ui';
  14. import lottie from "lottie-web"; //lottie
  15. // import commonMethod from '@/common/commonMethod.js';
  16. // import touchHandle from '@/mixins/touchHandle.js';
  17. // import requestConfig from '@/static/lib/requestConfig';
  18. export default {
  19. data: function() {
  20. return {
  21. leftList: [],
  22. rightList: [],
  23. musicList: [], //音乐列表
  24. dataList: [],
  25. tabIndex: 0, //当前选中的tab序号
  26. selectIndex: -1,
  27. peopleIndex: -1,
  28. petIndex: -1,
  29. musicIndex: -1,
  30. specialIndex: 0,
  31. specialList:[
  32. {
  33. id:1,
  34. url:'https://dm.static.elab-plus.com/miniProgram/lottieJson/gold.json',
  35. title:'金光闪闪',
  36. },
  37. {
  38. id:2,
  39. url:'https://dm.static.elab-plus.com/miniProgram/lottieJson/fireworks.json',
  40. title:'烟花',
  41. },
  42. {
  43. id:3,
  44. url:'https://dm.static.elab-plus.com/miniProgram/lottieJson/coloreRibbon.json',
  45. title:'彩带',
  46. },
  47. ],
  48. hasRedBox:false, //是否添加了红包
  49. limit:20,
  50. videoId:'', //上传视频的id
  51. videoUrl:'', //处理好的视频地址
  52. progress:0, //进度条
  53. ktProgress:0, //抠图进度条
  54. showPersonView:false, //是否显示个人形象提示弹窗
  55. showPopView:false, //是否显示确认取消框
  56. uploadStatus:0, //视频处理的状态 0 未开始,1 上传中,2绿幕抠图中-服务端处理中,3处理成功 4 处理失败
  57. count:0, //结果请求次数
  58. timeOut:90000, //超时时间
  59. outTimer:null, //延时处理对象
  60. timer:null, //轮询对象
  61. widthHeight:'', //用户上传视频尺寸
  62. stopFlag:false, //停止上传动作
  63. cancelTokenSource:null, //取消上传的操作对象
  64. }
  65. },
  66. props: {
  67. },
  68. // mixins: [touchHandle],
  69. async mounted() {
  70. // await this.getCityHouseList();
  71. console.warn("***viewAI***")
  72. Indicator.open('加载中...');
  73. this.getDatalist(0);
  74. this.getDatalist(1);
  75. this.getDatalist(3);
  76. },
  77. computed: {
  78. userId() {
  79. return this.$store.state.userId;
  80. },
  81. },
  82. // 页面被展示时执行
  83. onPageShow: function() {
  84. },
  85. //页面被隐藏时执行
  86. onPageHide: function() {
  87. // console.warn("***detached-hide***")
  88. },
  89. methods: {
  90. format(percentage) {
  91. let text = "上传中";
  92. if(this.uploadStatus==1){
  93. text = "上传中";
  94. }else if(this.uploadStatus==2){
  95. text = "抠图中";
  96. }
  97. return `${text}\n${percentage}%`;
  98. },
  99. resolveIndex(index) {
  100. this.selectIndex = index || 0;
  101. },
  102. specialChange(index) {
  103. if (this.specialIndex == index) {
  104. return false;
  105. }
  106. this.specialIndex = index;
  107. this.$nextTick(() => {
  108. // 播放lottie动画
  109. lottie.destroy("markLoading");
  110. var element = document.getElementById("special-img");
  111. this.anim = lottie.loadAnimation({
  112. container: element,
  113. name: "markLoading",
  114. renderer: "svg",
  115. loop: true,
  116. autoplay: true,
  117. path: this.specialList[this.specialIndex].url, //动画json
  118. });
  119. });
  120. },
  121. tabChange(index) {
  122. if (this.tabIndex == index) {
  123. return false;
  124. }
  125. if (this.$parent.repeatFlag == true) {
  126. Toast({
  127. message: '加载中...请稍后再试',
  128. });
  129. return false
  130. }
  131. this.tabIndex = index;
  132. this.$emit("tabChange", this.tabIndex); //通知页面,户型大类发生了变更
  133. if(this.tabIndex==2 && this.specialIndex>-1){
  134. this.$nextTick(() => {
  135. // 播放lottie动画
  136. lottie.destroy("markLoading");
  137. var element = document.getElementById("special-img");
  138. this.anim = lottie.loadAnimation({
  139. container: element,
  140. name: "markLoading",
  141. renderer: "svg",
  142. loop: true,
  143. autoplay: true,
  144. path: this.specialList[this.specialIndex].url, //动画json
  145. });
  146. });
  147. }
  148. },
  149. initStatus(){
  150. this.progress = 0;
  151. this.ktProgress = 0;
  152. this.count = 0;
  153. this.videoUrl = '';
  154. this.widthHeight = '';
  155. this.leftList[0].icon = '';
  156. this.leftList[0].url = '';
  157. this.uploadStatus = 0;//处理完毕
  158. },
  159. uploadImgObj(e,form,type=1){
  160. this.stopFlag = false;//上传开始时,开启上传
  161. if(type==2){
  162. this.initStatus();//重置上传状态到初始值
  163. }
  164. this.uploadStatus = 0;
  165. this.peopleIndex = 0; //选中第一个
  166. //上传图片
  167. var file = e.target.files[0];
  168. var fileSize = file.size / 1024 / 1024;
  169. if (!/\.(MP4|mp4)$/.test(e.target.value)) {
  170. this.$message.warning('文件片类型必须是MP4');
  171. var videoForm = document.getElementById(form); //获取表单对象
  172. videoForm && videoForm.reset(); // 重置表单
  173. return false
  174. }
  175. if (fileSize > this.limit) {
  176. this.$message.warning('您的上传的视频过大,请低于' + this.limit + 'MB');
  177. var videoForm = document.getElementById(form); //获取表单对象
  178. videoForm && videoForm.reset(); // 重置表单
  179. return false
  180. }
  181. if (file.name.length > 100) {
  182. this.$message.warning('文件名过长,请不要超过100个字符');
  183. var videoForm = document.getElementById(form); //获取表单对象
  184. videoForm && videoForm.reset(); // 重置表单
  185. return false;
  186. }
  187. let reader = new FileReader();
  188. reader.onload = (event) => {
  189. let video = document.createElement('video');
  190. video.onloadedmetadata = (event) => {
  191. let duration = video.duration;
  192. let width = video.videoWidth;
  193. let height = video.videoHeight;
  194. // this.videoWidth = width;
  195. // this.videoHeight = height;
  196. console.warn('视频时长:', duration,this.stopFlag);
  197. console.warn('视频尺寸:x:', width, 'y:', height);
  198. if (duration > 20) {
  199. this.$message.warning('您的上传的视频过长,请低于20s');
  200. var videoForm = document.getElementById(form); //获取表单对象
  201. videoForm && videoForm.reset(); // 重置表单
  202. return false
  203. }else{
  204. if(!this.stopFlag){
  205. var item = {};
  206. item.file = file;
  207. console.warn("***uploadImgObj***",file)
  208. this.uploadMaterielFile(item, form); //正常上传图片
  209. }
  210. }
  211. };
  212. video.src = event.target.result;
  213. };
  214. reader.readAsDataURL(file);
  215. },
  216. //视频上传进度处理
  217. uploadProgress(e){
  218. this.progress = Math.round((e.loaded / e.total) * 100);//loaded已经加载的
  219. console.warn("***uploadProgress***",this.progress)
  220. },
  221. //显示弹窗提示框
  222. showPopViewHandle(){
  223. this.showPopView = true;//弹出确认框;
  224. },
  225. //取消上传
  226. cancel(cancelTokenSource){
  227. this.cancelTokenSource = cancelTokenSource;
  228. console.warn("***取消上传函数定义***")
  229. },
  230. //停止上传
  231. stopUpload(){
  232. this.showPopView = false;//弹出确认框;
  233. this.stopFlag = true;//停止上传标志打开
  234. if(this.uploadStatus == 1){
  235. this.cancelTokenSource.cancel('上传已取消');//通知取消上传
  236. }
  237. else if(this.uploadStatus==2 || this.uploadStatus==3){//绿幕抠图中 或者已经完成
  238. let data = {
  239. userId:this.userId,
  240. brandId: $config.brandId,
  241. processStatus:'canceled',
  242. virtualNo:this.videoId,
  243. }
  244. requestConfig('addUserVirtural', data);//停止该绿幕视频的使用
  245. this.initStatus();//还原初始状态
  246. }
  247. let data = {
  248. url:'https://dm.static.elab-plus.com/miniProgram/silhouette1.mp4',
  249. value:'个人形象',
  250. width:'',
  251. height:'',
  252. }
  253. this.aiPeopleChange(data, 'canel')
  254. this.peopleIndex = -1;
  255. },
  256. //获取用户上传的个人形象
  257. async getUserVirtural() {
  258. let data = {
  259. userId:this.userId,
  260. brandId: $config.brandId,
  261. processStatus:'completed',
  262. }
  263. let res = await requestConfig('getUserVirtural', data);//停止该绿幕视频的使用
  264. if (res.success && res.list && res.list[0]) {
  265. let data = res.list[res.list.length - 1];//获取最新的一个用户的个人形象数据
  266. this.leftList[0].icon = data.virtualBg;
  267. this.leftList[0].url = data.virtualUrl;
  268. this.videoUrl = data.virtualUrl;
  269. if(data.widthHeight){
  270. this.leftList[0].width = data.widthHeight.split('x')[0];
  271. this.leftList[0].height = data.widthHeight.split('x')[1];
  272. }
  273. }
  274. },
  275. async uploadMaterielFile(item, form) {
  276. if(this.stopFlag){
  277. return false;
  278. }
  279. var self = this;
  280. let formData = new FormData();
  281. formData.append('file', item.file);
  282. formData.append('brandId', $config.brandId);
  283. formData.append('userId', this.userId);
  284. console.warn("***uploadMaterielFile***");
  285. this.uploadStatus = 1;//上传中
  286. this.showPersonView = false;
  287. this.addSilhouette();//添加剪影视频
  288. let res = await requestConfig('robust_video', formData, true, false,'post',this.uploadProgress,this.cancel)
  289. if (axios.isCancel(res)) {//取消上传处理
  290. this.initStatus();//还原初始状态
  291. }else if (res.success && res.single) {
  292. this.videoId = res.single;//根据Id查询结果
  293. this.startInterval();//开始轮询获取结果
  294. }
  295. var videoForm = document.getElementById(form); //获取表单对象
  296. videoForm && videoForm.reset(); // 重置表单
  297. },
  298. async getVideoUrl() {
  299. if(this.stopFlag){
  300. this.stopInterval();
  301. }
  302. if(!this.videoId){
  303. Toast({
  304. message: '请先上传视频',
  305. });
  306. return false;
  307. }
  308. this.count = this.count + 1;
  309. let res = await requestConfig('get_result', {id:this.videoId,userId:this.userId}, true, false,'get')
  310. if(this.stopFlag){
  311. this.stopInterval();
  312. }
  313. if (res.success && res.single) {
  314. this.resultHandle(res.single)
  315. }else{
  316. this.videoUrl = "https://test.static.elab-plus.com/digital_human/f4c16cffae9711ee9853845cf3fb2826.mp4";//视频地址
  317. this.leftList[0].icon = this.videoUrl + "?vframe/jpg/offset/0";
  318. this.leftList[0].url = this.videoUrl;
  319. this.uploadStatus = 4;//处理失败
  320. }
  321. },
  322. //添加剪影视频
  323. addSilhouette(){
  324. let data = {
  325. url:'https://dm.static.elab-plus.com/miniProgram/silhouette1.mp4',
  326. value:'个人形象',
  327. width:'',
  328. height:'',
  329. }
  330. this.aiPeopleChange(data, 'add')
  331. },
  332. //添加用户绿幕视频
  333. addRealVideo(){
  334. let data = {
  335. url:this.videoUrl,
  336. value:'个人形象',
  337. width:this.widthHeight.split('x')[0],
  338. height:this.widthHeight.split('x')[1],
  339. }
  340. this.aiPeopleChange(data, 'add')
  341. },
  342. //上传结果处理
  343. resultHandle(single){
  344. if(!single){
  345. return false;
  346. }
  347. if(single.status=='completed' && single.output){//有结果
  348. this.ktProgress = 100;//抠图进度100%
  349. this.videoUrl = single.output;//视频地址
  350. // this.leftList[0].icon = this.videoUrl + "?vframe/jpg/offset/5";
  351. this.widthHeight = single.widthHeight; //"856x480"
  352. this.leftList[0].icon = single.virtualBg;
  353. this.leftList[0].url = this.videoUrl;
  354. this.leftList[0].width = single.widthHeight.split('x')[0],
  355. this.leftList[0].height = single.widthHeight.split('x')[1],
  356. this.uploadStatus = 3;//处理完毕
  357. this.stopInterval();//停止轮询
  358. this.addRealVideo();
  359. }else{//没有结果
  360. let progress = single.progress;
  361. progress = progress.replace(this.videoId + ':','');
  362. let index = progress.indexOf("|");
  363. progress = progress.substr(0,index);
  364. console.warn("***抠图进度条***",progress);
  365. this.ktProgress = parseFloat(progress);//提取出来的进度条
  366. if(this.ktProgress>99){
  367. this.ktProgress = 99;
  368. }
  369. }
  370. },
  371. //开始生成AI图的轮询,每隔1s轮询一次
  372. startInterval() {
  373. if(this.timer){
  374. return false;
  375. }
  376. let self = this;
  377. this.count = 0;//轮询次数
  378. this.uploadStatus = 2;//绿幕抠图中
  379. this.getVideoUrl();//获取结果
  380. this.timer = setInterval(()=>{
  381. this.getVideoUrl();//获取结果
  382. },1000);//1秒轮询一次
  383. this.setOutTimer();//设置超时逻辑
  384. },
  385. //设置一个超时逻辑,到底指定时间后停止轮询,当前是90s
  386. setOutTimer() {
  387. var self = this;
  388. if (this.outTimer) {
  389. clearTimeout(this.outTimer)
  390. this.outTimer = null
  391. }
  392. this.outTimer = setTimeout(function() {
  393. if(!self.videoUrl){//没有结果
  394. MessageBox.confirm('',{
  395. title: '提示',
  396. message: '当前AI使用火爆,请继续尝试?',
  397. showCancelButton: true,
  398. confirmButtonText:'继续尝试',
  399. cancelButtonText:'取消等待',
  400. }).then(action => {
  401. console.warn("***MessageBox-action***",action)
  402. if(action == 'confirm'){
  403. // self.confirmHandle(1);
  404. }
  405. }).catch(err=>{
  406. console.warn("***MessageBox-err***",err)
  407. if(err == 'cancel'){
  408. // self.cancelHandle();
  409. }
  410. });
  411. // MessageBox.confirm('确定执行此操作?')
  412. }
  413. self.stopInterval();//停止轮询
  414. }, this.timeOut);
  415. },
  416. //停止轮询
  417. stopInterval() {
  418. if (this.timer) {
  419. clearInterval(this.timer);
  420. this.timer = null;
  421. }
  422. if (this.outTimer) {
  423. clearTimeout(this.outTimer)
  424. this.outTimer = null
  425. }
  426. // this.uploadStatus = 0;//回到初始上传状态
  427. },
  428. showMask(){
  429. this.showPersonView = true;
  430. console.warn("***showMask***",this.showPersonView)
  431. },
  432. //AI数字人切换
  433. selectAction(selItem, index) {
  434. console.log('点击动作111:', selItem, index,this.leftList)
  435. if (this.tabIndex == 0) {
  436. if(!this.leftList[index].url){
  437. return false
  438. }
  439. if (this.peopleIndex == index) { //取消选中
  440. this.aiPeopleChange(this.leftList[this.peopleIndex], 'canel')
  441. this.peopleIndex = -1;
  442. return false
  443. }
  444. } else if (this.tabIndex == 1) {
  445. if (this.petIndex == index) { //取消选中
  446. this.aiPeopleChange(this.rightList[this.petIndex], 'canel')
  447. this.petIndex = -1;
  448. return false
  449. }
  450. } else if (this.tabIndex == 3) {
  451. if (this.musicIndex == index) { //取消选中
  452. this.aiPeopleChange(this.musicList[this.musicIndex], 'canel')
  453. this.musicIndex = -1;
  454. return false
  455. }
  456. }
  457. if (this.$parent.repeatFlag == true) {
  458. Toast({
  459. message: '加载中...请稍后再试',
  460. });
  461. return false
  462. }
  463. if (this.tabIndex == 0) {
  464. this.peopleIndex = index;
  465. this.aiPeopleChange(this.leftList[this.peopleIndex], 'add')
  466. } else if (this.tabIndex == 1) {
  467. this.petIndex = index;
  468. this.aiPeopleChange(this.rightList[this.petIndex], 'add')
  469. } else if (this.tabIndex == 3) {
  470. this.musicIndex = index;
  471. this.aiPeopleChange(this.musicList[this.musicIndex], 'add')
  472. }
  473. },
  474. // 获取瀑布流数据
  475. async getDatalist(type) {
  476. let typeName = "Virtual_Human";
  477. if (type == 0) {
  478. typeName = "Virtual_Human";
  479. } else if (type == 1) {
  480. typeName = "Virtual_Pet";
  481. } else if (type == 3) {
  482. typeName = "Virtual_Music";
  483. Indicator.close();
  484. }
  485. var parmas = {
  486. "type": typeName,
  487. // "brandId": $config.brandId,
  488. }
  489. let res = await requestConfig('queryEnumList', parmas)
  490. this.selectIndex = 0;
  491. if (res && res.success && res.list) {
  492. let list = res.list;
  493. if (type == 0) {
  494. this.leftList.push({
  495. icon:'',
  496. userUpload:true,
  497. value:'',
  498. url:'',
  499. width:'',
  500. height:'',
  501. })
  502. this.leftList = this.leftList.concat(list);
  503. this.getUserVirtural();
  504. } else if (type == 1) {
  505. this.rightList = list;
  506. } else if (type == 3) {
  507. this.musicList = list;
  508. }
  509. }
  510. },
  511. catchTouchMove: function() {
  512. return false;
  513. },
  514. // hideOrShowActor(type){
  515. // this.$emit('hideOrShowActor',type);//隐藏所有视角
  516. // },
  517. addRedBox(){//添加红包
  518. this.$emit("redBox",'add');
  519. this.hasRedBox = true;
  520. },
  521. removeRedBox(){//去除红包
  522. this.$emit("redBox",'canel');
  523. this.hasRedBox = false;
  524. },
  525. setRedBox(){
  526. this.$emit("setRedBox");
  527. },
  528. //AI数字人切换
  529. aiPeopleChange(item, type) {
  530. this.$emit("aiPeopleChange", item, type, this.tabIndex); //通知页面,AI数字人切换了
  531. },
  532. //发布全景
  533. mynavigateFuc(e) {
  534. if (e) {
  535. if(this.hasRedBox){
  536. if(!this.$parent.redBoxData.count){
  537. Toast({
  538. message: '请输入红包个数!',
  539. });
  540. return false;
  541. }
  542. if(!this.$parent.redBoxData.money){
  543. Toast({
  544. message: '请输入充值金额!',
  545. });
  546. return false;
  547. }
  548. }
  549. if(this.peopleIndex==0 && (this.uploadStatus ==1 || this.uploadStatus ==2)){
  550. Toast({
  551. message: '请在个人形象上传完成后发布!',
  552. });
  553. return false;
  554. }
  555. let param = {
  556. type: 'CLK', //埋点类型
  557. clkId: 'clk_2cmina_23121301', //点击ID
  558. clkName: 'webgl_public_clk', //点击前往的页面名称
  559. clkParams: {
  560. locusName: "720发布",
  561. }
  562. };
  563. util.trackRequest(param);
  564. let _ps = this.$parent.getPosition();
  565. if (window.__wxjs_environment === 'miniprogram') {
  566. let url = '/extraPackage/pages/aiPublishPage/aiPublishPage?houseId=' + (this.$route.query.houseId || '')
  567. url += '&bgUrl=' + encodeURIComponent(this.$parent.bgUrl)
  568. if(this.peopleIndex>-1){
  569. let people = {
  570. url:this.leftList[this.peopleIndex].url,
  571. ath:_ps.peopleAth,
  572. atv:_ps.peopleAtv,
  573. width:this.leftList[this.peopleIndex].width || '',
  574. height:this.leftList[this.peopleIndex].height || '',
  575. scale:this.$parent.peopleScale,
  576. userUpload:this.peopleIndex==0?true:false,//是否使用了个人形象
  577. }
  578. url += '&AIPeople=' + encodeURIComponent(JSON.stringify(people))
  579. }
  580. if(this.petIndex>-1){
  581. let pet = {
  582. url:this.rightList[this.petIndex].url,
  583. ath:_ps.petAth,
  584. atv:_ps.petAtv,
  585. scale:this.$parent.petScale,
  586. }
  587. url += '&AIPet=' + encodeURIComponent(JSON.stringify(pet))
  588. }
  589. if(this.musicIndex>-1){
  590. let music = {
  591. url:this.musicList[this.musicIndex].url,
  592. title:this.musicList[this.musicIndex].value
  593. };
  594. url += '&bgMusic=' + encodeURIComponent(JSON.stringify(music))
  595. }
  596. if(this.hasRedBox){
  597. let redBox = {
  598. url:'https://dm.static.elab-plus.com/miniProgram/redbox.mp4',
  599. ath:_ps.redBoxAth,
  600. atv:_ps.redBoxAtv,
  601. scale:1,
  602. lottieIndex:this.specialIndex,
  603. count:this.$parent.redBoxData.count,
  604. money:this.$parent.redBoxData.money,
  605. message:this.$parent.redBoxData.message,
  606. }
  607. url += '&redBox=' + encodeURIComponent(JSON.stringify(redBox))
  608. }
  609. console.warn("data:", _ps, url)
  610. wx.miniProgram.navigateTo({
  611. url: url
  612. })
  613. } else {
  614. console.warn("data:", _ps)
  615. Toast({
  616. message: '敬请期待',
  617. });
  618. }
  619. }
  620. },
  621. }
  622. }
  623. </script>
  624. <style lang="scss" scoped>
  625. @import "./viewAI.scss";
  626. /* @import "@/common/css/common.css"; */
  627. </style>