result.vue 28 KB

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