result.vue 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. <template>
  2. <div class="resout-container AI-Design-container">
  3. <div class="header">
  4. <van-nav-bar title="生成结果" left-arrow @click-left="returnPage" @click-right="toHome">
  5. <template #right>
  6. <van-icon name="wap-home-o" color="#333" size="26" />
  7. </template>
  8. </van-nav-bar>
  9. </div>
  10. <div class="container">
  11. <!-- 历史生图 -->
  12. <div class="history-section padded-lr-20" v-if="wallType === 'outside' || wallType === 'inside'">
  13. <div class="history-header" @click="viewHistory">
  14. <van-icon name="clock-o" color="#EC8868" />
  15. <span>历史生图</span>
  16. <span v-if="!readState" class="badge-dot"></span>
  17. </div>
  18. </div>
  19. <!-- 房屋效果图 -->
  20. <div class="image-container">
  21. <div v-if="imageUrl" class="comparisonWrapper">
  22. <div class="imgbox-t">
  23. <div>
  24. <p class="tit">原图</p>
  25. </div>
  26. <div>
  27. <p class="tit">AI效果图</p>
  28. </div>
  29. </div>
  30. <div class="imgbox-b">
  31. <div class="image-wrapper" @click="imgClick(UserFilePathUrl)">
  32. <img :src="UserFilePathUrl" alt="房屋效果图" class="house-image" @error="handleImageError" />
  33. <div v-on="{
  34. 'click.stop': imgHasErr ? () => reloadImage('userFile') : () => { }
  35. }"></div>
  36. </div>
  37. <div class="image-wrapper" @click="imgClick(imageUrl)">
  38. <img :src="imageUrlSmall" alt="房屋效果图" class="house-image" @error="handleImageError" />
  39. <div v-on="{
  40. 'click.stop': imgHasErr ? () => reloadImage('imageSmall') : () => { }
  41. }"></div>
  42. </div>
  43. </div>
  44. </div>
  45. <div v-else class="loading-state">
  46. <img v-if="StateCode != 3 && StateCode != 4" src="@/assets/AIDesign/loding.gif" style="width: 100px;">
  47. <p class="loading-text">{{ type || StateCode ? (StateCode == 3 ? '生成失败' : (StateCode == 4 ?
  48. '生成失败,\n' + StateInfo :
  49. '正在为您加速生成中,先喝杯茶吧~\n退出本页不影响生成')) : '加载中...' }}</p>
  50. </div>
  51. </div>
  52. <!-- 功能按钮组 -->
  53. <!-- 外墙 -->
  54. <div class="button-group-outside" v-if="wallType === 'outside' || wallType === 'inside'">
  55. <button class="action-button-big flex-center" @click="handleAIfun"
  56. v-if="agentFrom === 'stoneLikePaint' && allRes && allRes.F_DesignStyle != 'CHANGE_COLOR' && StateCode == 2 && wallType === 'outside'">
  57. <img src="@/assets/AIDesign/file-excel-line.png" class="icon" />
  58. <div>
  59. <div class="title">确认AI设计</div>
  60. <div class="text">生成解决方案</div>
  61. </div>
  62. </button>
  63. <div class="flex-between">
  64. <button class="action-button-middle flex-center" :disabled="regenerateDisable"
  65. :class="regenerateDisable == true ? 'save-button-disabled' : ''" @click="regenerate">
  66. <img src="@/assets/AIDesign/resetIcon.png" class="icon" />
  67. <div>
  68. <div class="title">重新生成</div>
  69. <div class="text">再来一次也不错</div>
  70. </div>
  71. </button>
  72. <!-- :class="projectDisableFlag == true ? 'save-button-disabled' : ''" :disabled="projectDisableFlag"-->
  73. <button class="action-button-middle flex-center" @click="manualDesign"
  74. v-if="showArtificial && StateCode == 2 && !projectDisableFlag && wallType === 'outside'">
  75. <img src="@/assets/AIDesign/bsIcon.png" class="iconbig" />
  76. <div>
  77. <div class="title">转人工设计
  78. </div>
  79. <div class="text">别墅之星小程序</div>
  80. </div>
  81. </button>
  82. </div>
  83. </div>
  84. <!-- 内墙 -->
  85. <!--<div class="button-group" v-if="wallType === 'inside'">-->
  86. <!--<button class="action-button" :disabled="regenerateDisable"-->
  87. <!--:class="regenerateDisable == true ? 'save-button-disabled' : ''" @click="regenerate">-->
  88. <!--<van-icon class="icon" name="replay" />-->
  89. <!--<span class="text">重新生成</span>-->
  90. <!--</button>-->
  91. <!--<button class="action-button" @click="viewHistory">-->
  92. <!--<van-icon class="icon" name="clock-o" />-->
  93. <!--<span class="text">历史生图</span>-->
  94. <!--<span v-if="!readState" class="badge-dot"></span>-->
  95. <!--</button>-->
  96. <!--</div>-->
  97. </div>
  98. </div>
  99. </template>
  100. <script lang="ts">
  101. import { ImagePreview, Dialog } from 'vant';
  102. import { Component, Vue } from "vue-property-decorator";
  103. import { GetEntity, GetReadState, UpdateReadState, insideGetEntity, insideGetReadState, insideUpdateReadState, GetProjectlist, GetDictList, AddTrackEvent } from "@/api/indexAI";
  104. import { getWecomType, toLBHome, toXiaoChengxu, getWxconfig, getWecomTypeName, checkAndSaveUserWecomType } from '@/utils/index';
  105. import axios from "axios";
  106. declare let wx: any;
  107. @Component
  108. export default class extends Vue {
  109. private readState = true;
  110. // 数据属性
  111. // private imageUrl = require('@/assets/AIDesign/house-image.jpg'); // 替换为实际图片路径
  112. private imageUrl = ''; // 替换为实际图片路径
  113. private imageUrlSmall = '';
  114. private UserFilePathUrl = '';//用户原图
  115. private pollingTimer: number | null = null; // 轮询定时器引用
  116. private timer = null;
  117. private StateCode = null;
  118. private projectId = null;
  119. private regenerateDisable = true;
  120. private StateInfo = '';
  121. private type = '';
  122. private wallType = '';
  123. private F_OutsideType = null;
  124. private defaultImg = require('@/assets/AIDesign/imgErrIcon.jpg'); // 替换为实际图片路径
  125. private imgHasErr = false;
  126. // 处理内外墙api
  127. private GetEntityToApi = {
  128. outside: GetEntity,
  129. inside: insideGetEntity
  130. };
  131. private GetReadStateToApi = {
  132. outside: GetReadState,
  133. inside: insideGetReadState
  134. };
  135. private UpdateReadStateToApi = {
  136. outside: UpdateReadState,
  137. inside: insideUpdateReadState
  138. };
  139. private designPageApi = {
  140. outside: '/AIDesign/design',
  141. inside: '/AIDesign/insideDesign'
  142. };
  143. private designTimer = {
  144. outside: 30000,
  145. inside: 20000
  146. };
  147. private showArtificial = false;
  148. private agentFrom = window.localStorage.getItem('agentFromAI');
  149. private outsideDesignCount = 0;//项目下设计已用数量-接口获取
  150. private isNeedProjectFlag = true;//是否需要项目-接口获取
  151. private projectDisableFlag = true;//转人工不可点击
  152. private serviceCodeArray = [];
  153. private allRes = null;
  154. created() {
  155. getWxconfig();
  156. if (window.localStorage.getItem('agentFromAI') === 'stoneLikePaint') {
  157. this.getServiceCode();
  158. }
  159. checkAndSaveUserWecomType();
  160. }
  161. activated() {
  162. this.initialize();
  163. this.wallType = this.$route.query.wallType || 'outside';
  164. const userInfo: any = JSON.parse(window.localStorage.getItem("userInfoV1")!);
  165. const customerCode = userInfo && userInfo.sysUserExt ? userInfo.sysUserExt.customerCode : '';
  166. const salesLevel = userInfo && userInfo.sysUserExt ? userInfo.sysUserExt.salesLevel : '';
  167. // 外墙-服务商随身邦
  168. if (this.agentFrom === 'stoneLikePaint' && this.wallType === 'outside') {
  169. this.getIsNeedProjectFlag();
  170. this.showArtificial = true;
  171. }
  172. // 和部分经销商展示转人工
  173. // else if(customerCode && (salesLevel === 'customer_level' || salesLevel === 'reseller_level')){
  174. // this.showArtificial = true;
  175. // }
  176. // 从经销商随身邦进入的,显示转人工按钮,没有次数限制
  177. if ((this.agentFrom === 'ssb' || this.agentFrom === 'dg') && this.wallType === 'outside') {
  178. this.showArtificial = true;
  179. this.projectDisableFlag = false;
  180. }
  181. this.type = window.localStorage.getItem('type');
  182. this.GetReadStateFn();
  183. this.GetEntityDataFirst()
  184. }
  185. // 离开页面时清除定时器
  186. deactivated() {
  187. // console.log('resule页面销毁1')
  188. window.localStorage.removeItem('type');
  189. clearInterval(this.pollingTimer);
  190. clearTimeout(this.timer);
  191. this.pollingTimer = null;
  192. this.timer = null;
  193. }
  194. initialize() {
  195. clearInterval(this.pollingTimer);
  196. clearTimeout(this.timer);
  197. this.readState = true;
  198. this.imageUrl = ''; // 替换为实际图片路径
  199. this.imageUrlSmall = '';
  200. this.UserFilePathUrl = '';//用户原图
  201. this.pollingTimer = null; // 轮询定时器引用
  202. this.timer = null;
  203. this.StateCode = null;
  204. this.projectId = null;
  205. this.regenerateDisable = true;
  206. this.StateInfo = '';
  207. this.type = '';
  208. this.wallType = '';
  209. this.outsideDesignCount = 0;
  210. this.isNeedProjectFlag = true;
  211. this.projectDisableFlag = true;
  212. this.showArtificial = false;
  213. this.allRes = null;
  214. this.imgHasErr = false;
  215. }
  216. // 图片加载失败处理(私有方法)
  217. private handleImageError(e) {
  218. const imgElement = e.target as HTMLImageElement;
  219. // 降级显示默认占位图
  220. imgElement.src = this.defaultImg;
  221. imgElement.onerror = null;
  222. this.imgHasErr = true;
  223. }
  224. private reloadImage(imgType: 'userFile' | 'imageSmall') {
  225. let that = this;
  226. if (that.allRes && that.imgHasErr) {
  227. if (imgType === 'userFile') {
  228. if (that.allRes.F_UserFilePath) {
  229. that.UserFilePathUrl = that.allRes.BaseUrl + that.allRes.F_UserFilePath;
  230. that.imgHasErr = false;
  231. }
  232. } else {
  233. let high_Definition_img = that.allRes.F_ResultFilePath || that.allRes.F_ResultlargeFilePath || that.allRes.F_ResultSmallFilePath;
  234. if (high_Definition_img) {
  235. that.imageUrl = that.allRes.BaseUrl + high_Definition_img;
  236. that.imageUrlSmall = that.allRes.BaseUrl + that.allRes.F_ResultSmallFilePath;
  237. that.imgHasErr = false;
  238. }
  239. }
  240. }
  241. }
  242. // 是否关联了项目
  243. getIsNeedProjectFlag() {
  244. let that = this;
  245. const formData = new FormData();
  246. // const userInfo: any = JSON.parse(window.localStorage.getItem("userInfoV1")!);
  247. // let roleIdArray = [];
  248. // if (userInfo.roles.length > 0) {
  249. // userInfo.roles.forEach(item => {
  250. // roleIdArray.push(item.roleId);
  251. // })
  252. // }
  253. // formData.append('roleIds', roleIdArray.join(','));
  254. // formData.append('WXuserid', userInfo.loginName);
  255. formData.append('baseType', 0);//0外墙--这里只用查询外墙
  256. // const agentFrom = window.localStorage.getItem('agentFromAI');
  257. // const wecomType = getWecomType(agentFrom);
  258. // formData.append('wecomType', 5);
  259. GetDictList(formData).then(response => {
  260. if (response.StatusCode == 200) {
  261. if (that.serviceCodeArray.length == 0) {
  262. that.isNeedProjectFlag = false; //是否需要项目
  263. } else {
  264. that.isNeedProjectFlag = response.Data.isNeedProject;
  265. }
  266. }
  267. })
  268. }
  269. private getServiceCode() {
  270. let that = this;
  271. const userInfo: any = JSON.parse(window.localStorage.getItem("userInfoV1")!);
  272. let serviceCodeArray = [];
  273. // if (userInfo && userInfo.loginTypeList && userInfo.loginTypeList.length > 0) {
  274. // userInfo.loginTypeList.forEach(item => {
  275. // if (item.shopType == 'stoneLikePaint') {
  276. // item.shopList.forEach(childItem => {
  277. // serviceCodeArray.push(childItem.shop_code);
  278. // })
  279. // }
  280. // })
  281. // }
  282. if (userInfo && userInfo.ServiceCode) {
  283. serviceCodeArray = userInfo.ServiceCode.split(',').map(item => item.trim()).filter(item => item !== '');
  284. }
  285. that.serviceCodeArray = serviceCodeArray;
  286. }
  287. GetReadStateFn() {
  288. const formData = new FormData();
  289. // const userInfo: any = JSON.parse(window.localStorage.getItem("userInfoV1")!);
  290. // formData.append('WXuserid', userInfo.loginName);
  291. if (this.wallType === 'outside') {
  292. const outsideType_val = this.F_OutsideType || 0;
  293. formData.append('outsideType', outsideType_val);
  294. }
  295. this.GetReadStateToApi[this.wallType](formData).then(response => {
  296. if (response.StatusCode == 200) {
  297. this.readState = response.Data.readState;
  298. }
  299. });
  300. }
  301. UpdateReadStateFn() {
  302. const formData = new FormData();
  303. // const userInfo: any = JSON.parse(window.localStorage.getItem("userInfoV1")!);
  304. // formData.append('WXuserid', userInfo.loginName);
  305. const outsideType_val = this.F_OutsideType || 0;
  306. formData.append('outsideType', outsideType_val);
  307. this.UpdateReadStateToApi[this.wallType](formData).then(response => { });
  308. }
  309. returnPage() {
  310. this.$router.push({ path: this.designPageApi[this.wallType] });
  311. // this.$router.back();
  312. }
  313. toHome() {
  314. toLBHome()
  315. }
  316. imgClick(url) {
  317. ImagePreview([url]);
  318. }
  319. private startPolling(): void {
  320. // 立即执行一次检查
  321. this.GetEntityData();
  322. // 设置定时器每秒执行一次检查
  323. this.pollingTimer = window.setInterval(() => {
  324. if (!this.imageUrl) {
  325. if (this.StateCode == 3 || this.StateCode == 4) {
  326. clearInterval(this.pollingTimer);
  327. this.pollingTimer = null;
  328. } else {
  329. this.GetEntityData();
  330. }
  331. } else {
  332. // 当 imageUrl 有值时,清除定时器
  333. if (this.pollingTimer) {
  334. clearInterval(this.pollingTimer);
  335. this.pollingTimer = null;
  336. }
  337. }
  338. }, 3000);
  339. }
  340. //进入页面首次调用获取状态
  341. GetEntityDataFirst() {
  342. let that = this;
  343. const F_ID = this.$route.query.F_id || "";
  344. const formData = new FormData();
  345. formData.append('F_id', F_ID);
  346. this.GetEntityToApi[this.wallType](formData).then(response => {
  347. // console.log(response);
  348. if (response.StatusCode == 200) {
  349. if (response.Data == null) {
  350. that.regenerateDisable = true;
  351. if (that.timer) {
  352. clearTimeout(that.timer);
  353. that.timer = null;
  354. }
  355. that.timer = setTimeout(() => {
  356. that.startPolling();
  357. }, that.designTimer[that.wallType]);
  358. } else {
  359. this.allRes = response.Data;
  360. this.StateCode = response.Data.StateCode;
  361. this.StateInfo = response.Data.Description;
  362. this.projectId = response.Data.ProjectID;
  363. this.F_OutsideType = response.Data.F_OutsideType;
  364. let DesignCount = response.Data.DesignCount || 0;
  365. // 外墙-服务商随身邦
  366. if (this.agentFrom === 'stoneLikePaint' && this.wallType === 'outside') {
  367. if (that.isNeedProjectFlag) {
  368. if (DesignCount >= 3) {
  369. that.projectDisableFlag = false;//有项目判断>=3出现
  370. }
  371. } else {
  372. that.projectDisableFlag = false;//没有项目就可点击
  373. }
  374. }
  375. if (response.Data.F_ResultFilePath || response.Data.F_ResultlargeFilePath) {
  376. const high_Definition_img = response.Data.F_ResultFilePath || response.Data.F_ResultlargeFilePath || response.Data.F_ResultSmallFilePath;
  377. that.imageUrl = response.Data.BaseUrl + high_Definition_img;
  378. that.imageUrlSmall = response.Data.BaseUrl + response.Data.F_ResultSmallFilePath;
  379. that.UserFilePathUrl = response.Data.BaseUrl + response.Data.F_UserFilePath;
  380. }
  381. if (response.Data.StateCode == 1) {
  382. let createTime = new Date(response.Data.CreateDate);
  383. let currentTime = new Date().getTime();
  384. if (currentTime - createTime > that.designTimer[that.wallType]) {
  385. that.startPolling();
  386. } else {
  387. if (that.timer) {
  388. clearTimeout(that.timer);
  389. that.timer = null;
  390. }
  391. that.timer = setTimeout(() => {
  392. that.startPolling();
  393. }, currentTime - createTime);
  394. }
  395. } else {
  396. if (response.Data.StateCode == 2 || response.Data.StateCode == 3 || response.Data.StateCode == 4) {
  397. that.regenerateDisable = false;
  398. } else {
  399. that.regenerateDisable = true;
  400. }
  401. }
  402. }
  403. } else {
  404. this.$toast.fail(response.Info);
  405. }
  406. })
  407. }
  408. GetEntityData() {
  409. let that = this;
  410. const F_ID = this.$route.query.F_id || "";
  411. const formData = new FormData();
  412. formData.append('F_id', F_ID);
  413. this.GetEntityToApi[this.wallType](formData).then(response => {
  414. // console.log(response);
  415. if (response.StatusCode == 200) {
  416. if (response.Data) {
  417. this.allRes = response.Data;
  418. this.StateCode = response.Data.StateCode;
  419. this.StateInfo = response.Data.Description;
  420. this.F_OutsideType = response.Data.F_OutsideType;
  421. this.projectId = response.Data.ProjectID;
  422. let DesignCount = response.Data.DesignCount || 0;
  423. // 外墙-服务商随身邦
  424. if (this.agentFrom === 'stoneLikePaint' && this.wallType === 'outside') {
  425. if (that.isNeedProjectFlag) {
  426. if (DesignCount >= 3) {
  427. that.projectDisableFlag = false;//有项目判断>=3出现
  428. }
  429. } else {
  430. that.projectDisableFlag = false;//没有项目就可点击
  431. }
  432. }
  433. if (response.Data.F_ResultFilePath || response.Data.F_ResultlargeFilePath) {
  434. const high_Definition_img = response.Data.F_ResultFilePath || response.Data.F_ResultlargeFilePath || response.Data.F_ResultlargeFilePath;
  435. that.imageUrl = response.Data.BaseUrl + high_Definition_img;
  436. that.imageUrlSmall = response.Data.BaseUrl + response.Data.F_ResultSmallFilePath;
  437. that.UserFilePathUrl = response.Data.BaseUrl + response.Data.F_UserFilePath;
  438. }
  439. if (response.Data.StateCode == 2 || response.Data.StateCode == 3 || response.Data.StateCode == 4) {
  440. that.regenerateDisable = false;
  441. } else {
  442. that.regenerateDisable = true;
  443. }
  444. } else {
  445. that.regenerateDisable = true;
  446. }
  447. } else {
  448. this.$toast.fail(response.Info);
  449. }
  450. })
  451. }
  452. // 下载图片并保存到相册
  453. downloadAndSaveImage() {
  454. const that = this;
  455. const imageUrl = this.imageUrl;
  456. wx.ready(function () {
  457. // 1. 下载OSS图片到本地临时路径
  458. wx.downloadFile({
  459. url: imageUrl,
  460. success: (downloadRes) => {
  461. // 检查下载是否成功(临时文件路径存在)
  462. if (downloadRes.statusCode === 200 && downloadRes.tempFilePath) {
  463. // 2. 保存图片到相册
  464. wx.saveImageToPhotosAlbum({
  465. filePath: downloadRes.tempFilePath,
  466. success: () => {
  467. // 提示用户
  468. that.$toast.success('图片已成功保存到相册');
  469. },
  470. fail: (saveErr) => {
  471. console.error('保存图片失败', saveErr);
  472. that.$toast.fail('保存失败,请重试');
  473. }
  474. });
  475. } else {
  476. console.error('图片下载失败', downloadRes);
  477. that.$toast.fail('图片下载失败,请检查URL');
  478. }
  479. },
  480. fail: (downloadErr) => {
  481. console.error('下载请求失败', downloadErr);
  482. that.$toast.fail('下载图片失败,请重试');
  483. }
  484. });
  485. });
  486. }
  487. // 方法
  488. private saveImage(): void {
  489. if (!this.imageUrl) {
  490. this.$toast.fail('图片尚未生成完成');
  491. return;
  492. }
  493. // // 创建一个临时的下载链接
  494. // const link = document.createElement('a');
  495. // link.href = this.imageUrl;
  496. // link.download = `ai-design-${new Date().getTime()}.png`;
  497. // link.style.display = 'none';
  498. // // 将链接添加到页面并触发点击事件
  499. // document.body.appendChild(link);
  500. // link.click();
  501. // // 清理DOM元素
  502. // document.body.removeChild(link);
  503. fetch(this.imageUrl).then(response => response.blob()).then(blob => {
  504. const blobUrl = URL.createObjectURL(blob);
  505. // 创建一个临时的下载链接
  506. const link = document.createElement('a');
  507. link.href = blobUrl;
  508. link.download = `ai-design-${new Date().getTime()}.png`;
  509. link.style.display = 'none';
  510. // 将链接添加到页面并触发点击事件
  511. document.body.appendChild(link);
  512. link.click();
  513. // 清理DOM元素
  514. document.body.removeChild(link);
  515. // 释放Blob URL
  516. URL.revokeObjectURL(blobUrl);
  517. // this.$toast.success('图片保存成功');
  518. }).catch(error => {
  519. console.error('图片下载失败:', error);
  520. this.$toast.fail('图片下载失败');
  521. });
  522. }
  523. private regenerate(): void {
  524. // console.log('重新生成');
  525. let that = this;
  526. // 实现重新生成逻辑
  527. const F_ID = this.$route.query.F_id || "";
  528. let projectId = this.allRes.WecomType == 2 && that.projectId ? that.projectId : null;
  529. this.$router.push({
  530. path: this.designPageApi[this.wallType],
  531. query: {
  532. F_id: F_ID,
  533. projectId
  534. }
  535. });
  536. }
  537. private viewHistory(): void {
  538. this.UpdateReadStateFn();
  539. // console.log('查看历史生成');
  540. // 实现查看历史生成逻辑
  541. this.$router.push({ path: '/AIDesign/history', query: { wallType: this.wallType } });
  542. }
  543. private manualDesign(): void {
  544. let that = this;
  545. const formData = new FormData();
  546. formData.append('eventname', '转人工设计');//事件名称
  547. formData.append('eventtype', 'click');//事件类型
  548. formData.append('menupath', '外墙质感/结果页/转人工设计');//完整菜单路径
  549. const eventdataObj = {
  550. wecomType: getWecomTypeName(window.localStorage.getItem('agentFromAI')),
  551. };
  552. formData.append('eventdata', JSON.stringify(eventdataObj));//事件数据
  553. AddTrackEvent(formData)//埋点
  554. // 实现转人工设计逻辑
  555. toXiaoChengxu(`${process.env.VUE_APP_BASE_DISID6}`);
  556. }
  557. private handleAIfun() {
  558. const formData = new FormData();
  559. formData.append('eventname', '确认AI设计');//事件名称
  560. formData.append('eventtype', 'click');//事件类型
  561. formData.append('menupath', '外墙质感/结果页/确认AI设计');//完整菜单路径
  562. const eventdataObj = {
  563. wecomType: getWecomTypeName(window.localStorage.getItem('agentFromAI')),
  564. };
  565. formData.append('eventdata', JSON.stringify(eventdataObj));//事件数据
  566. AddTrackEvent(formData)//埋点
  567. let allRes = JSON.stringify(this.allRes);
  568. sessionStorage.setItem("planParams", allRes);
  569. this.$router.push({ path: '/AIDesign/GeneratePlan' });
  570. }
  571. }
  572. </script>
  573. <style scoped lang="scss">
  574. .resout-container {
  575. background-color: #f8f9fa;
  576. min-height: 100vh;
  577. flex-direction: column;
  578. }
  579. .header {
  580. /*height: 50px;*/
  581. /*line-height: 50px;*/
  582. /*text-align: center;*/
  583. /*background: #fff;*/
  584. border-bottom: 1px solid #f8f8f8;
  585. .van-nav-bar__title {
  586. font-size: 20px;
  587. color: #333;
  588. }
  589. .van-icon {
  590. font-size: 20px;
  591. color: #333 !important;
  592. }
  593. }
  594. .container {
  595. padding: 0 20px;
  596. .history-section {
  597. margin: 20px 0;
  598. .history-header {
  599. display: flex;
  600. align-items: center;
  601. gap: 12px;
  602. padding: 12px 16px;
  603. background-color: #ffffff;
  604. border-radius: 18px;
  605. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
  606. border: 1px solid #e9ecef;
  607. /* margin-bottom: 10px; */
  608. }
  609. .icon-clock {
  610. font-size: 12px;
  611. margin-right: 8px;
  612. }
  613. .history-header span {
  614. font-weight: 500;
  615. color: #EC8868;
  616. }
  617. .history-header .badge-dot {
  618. width: 5px;
  619. height: 5px;
  620. background-color: #ff4d4f;
  621. border-radius: 50%;
  622. }
  623. }
  624. }
  625. .image-container {
  626. position: relative;
  627. width: 100%;
  628. border-radius: 10px;
  629. overflow: hidden;
  630. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  631. .comparisonWrapper {
  632. display: flex;
  633. flex-direction: column;
  634. padding: 35px 6px;
  635. .imgbox-t {
  636. display: flex;
  637. justify-content: space-between;
  638. align-items: center;
  639. >div {
  640. .tit {
  641. width: fit-content;
  642. padding: 0 5px;
  643. height: 17px;
  644. line-height: 17px;
  645. border-radius: 4px;
  646. font-size: 10px;
  647. }
  648. }
  649. >div:first-child {
  650. width: 36%;
  651. .tit {
  652. background: rgba(204, 204, 204, 1);
  653. }
  654. }
  655. >div:last-child {
  656. width: 58%;
  657. .tit {
  658. color: #fff;
  659. background: #FF8D1A;
  660. }
  661. }
  662. }
  663. .imgbox-b {
  664. display: flex;
  665. justify-content: space-between;
  666. align-items: center;
  667. >div:first-child {
  668. width: 36%;
  669. }
  670. >div:last-child {
  671. width: 58%;
  672. }
  673. .image-wrapper {
  674. position: relative;
  675. width: 100%;
  676. margin: 5px 0;
  677. display: flex;
  678. align-items: center;
  679. justify-content: flex-start;
  680. .house-image {
  681. border-radius: 10px;
  682. display: block;
  683. width: 100%;
  684. height: auto;
  685. }
  686. .house-image+div {
  687. position: absolute;
  688. top: 0;
  689. left: 0;
  690. width: 100%;
  691. height: 100%;
  692. background: transparent;
  693. z-index: 2;
  694. }
  695. }
  696. }
  697. }
  698. }
  699. .loading-state {
  700. position: relative;
  701. width: 100%;
  702. height: 300px;
  703. display: flex;
  704. flex-direction: column;
  705. align-items: center;
  706. justify-content: center;
  707. color: #666;
  708. text-align: center;
  709. // background-color: rgba(0, 0, 0, 0.7);
  710. background-image: url('../../assets/AIDesign/bg.png');
  711. background-size: 100% 100%;
  712. /* 添加半透明黑色背景 */
  713. // border-radius: 16px;
  714. /* 圆角边框 */
  715. }
  716. .loading-text {
  717. margin-top: 10px;
  718. font-size: 14px;
  719. color: white;
  720. white-space: pre-line
  721. /* 文字颜色改为白色以提高对比度 */
  722. }
  723. .address-info {
  724. position: absolute;
  725. bottom: 10px;
  726. left: 10px;
  727. right: 10px;
  728. background-color: rgba(0, 0, 0, 0.5);
  729. color: white;
  730. padding: 8px;
  731. border-radius: 8px;
  732. font-size: 14px;
  733. text-align: center;
  734. }
  735. .project-name {
  736. margin: 0;
  737. font-weight: bold;
  738. }
  739. .address {
  740. margin: 4px 0 0;
  741. font-size: 12px;
  742. }
  743. .save-button {
  744. width: 100%;
  745. padding: 16px;
  746. margin-top: 20px;
  747. background-color: #E96337;
  748. color: white;
  749. border: none;
  750. border-radius: 12px;
  751. font-size: 16px;
  752. font-weight: bold;
  753. cursor: pointer;
  754. transition: background-color 0.3s ease;
  755. }
  756. .save-button-disabled {
  757. background-color: #cccccc !important;
  758. cursor: not-allowed !important;
  759. color: white !important;
  760. }
  761. /* .save-button:hover {
  762. background-color: #e04a1d;
  763. } */
  764. .button-group-outside {
  765. .flex-center {
  766. display: flex;
  767. align-items: center;
  768. justify-content: center;
  769. border: none;
  770. margin-top: 10px;
  771. }
  772. .flex-between {
  773. display: flex;
  774. align-items: center;
  775. border: none;
  776. }
  777. .title {
  778. font-size: 16px;
  779. color: rgb(23, 23, 23);
  780. font-weight: 600;
  781. line-height: 16px;
  782. }
  783. .text {
  784. font-size: 12px;
  785. color: rgb(134, 144, 156);
  786. line-height: 12px;
  787. margin-top: 5px;
  788. }
  789. .icon {
  790. width: 28px;
  791. height: auto;
  792. margin-right: 10px;
  793. }
  794. .iconbig {
  795. width: 48px;
  796. height: auto;
  797. margin-right: 5px;
  798. }
  799. .action-button-big {
  800. width: 100%;
  801. height: 72px;
  802. text-align: center;
  803. border-radius: 8px;
  804. background: rgba(248, 243, 204, 1);
  805. }
  806. .action-button-middle {
  807. width: 48%;
  808. height: 72px;
  809. border-radius: 8px;
  810. background: rgba(240, 240, 240, 1);
  811. margin: 8px 1%;
  812. }
  813. .action-button-small {
  814. width: fit-content;
  815. margin: 10px auto;
  816. text-align: center;
  817. text-decoration: underline;
  818. font-size: 14px;
  819. line-height: 18px;
  820. .text {
  821. font-size: 14px;
  822. color: rgb(23, 23, 23);
  823. }
  824. }
  825. }
  826. .button-group {
  827. margin-top: 20px;
  828. .action-button {
  829. width: 100%;
  830. padding: 14px;
  831. margin-bottom: 12px;
  832. background-color: white;
  833. border: 1px solid #e0e0e0;
  834. border-radius: 12px;
  835. font-size: 15px;
  836. color: #333;
  837. cursor: pointer;
  838. display: flex;
  839. align-items: center;
  840. justify-content: flex-start;
  841. transition: background-color 0.3s ease;
  842. }
  843. .action-button:hover {
  844. background-color: #f5f5f5;
  845. }
  846. .badge-dot {
  847. margin-left: 10px;
  848. width: 5px;
  849. height: 5px;
  850. background-color: #ff4d4f;
  851. border-radius: 50%;
  852. }
  853. .icon {
  854. margin-right: 10px;
  855. font-size: 18px;
  856. }
  857. .text {
  858. font-weight: 500;
  859. }
  860. }
  861. .van-nav-bar__title {
  862. font-size: 20px;
  863. color: #333;
  864. }
  865. </style>