GeneratePlan.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. <template>
  2. <div class="generate-plan-page AI-Design-container">
  3. <!-- 导航栏 -->
  4. <div class="header">
  5. <van-nav-bar title="生成方案" left-arrow @click-left="returnPage" @click-right="toHome">
  6. <template #right>
  7. <van-icon name="wap-home-o" color="#333" size="26" />
  8. </template>
  9. </van-nav-bar>
  10. </div>
  11. <div>
  12. <!-- 已生成方案区域 -->
  13. <div class="generated-section">
  14. <div class="generated-header">
  15. <div class="generated-title">已生成</div>
  16. <div>
  17. <div class="scheme-info"><span class="orgin-color">{{ stoneColors }}</span>{{
  18. planParams.F_ColorCard
  19. }}</div>
  20. <span class="gray-color">|</span>
  21. <div class="scheme-process"><span class="orgin-color">{{ planParams.F_DeepGrooveTech }}</span>工艺
  22. </div>
  23. </div>
  24. <van-tag color="#FF8D1A" class="ai-tag">AI效果图</van-tag>
  25. </div>
  26. <!-- 效果图 -->
  27. <div class="scheme-image">
  28. <img :src="planParams.BaseUrl + planParams.F_ResultSmallFilePath" alt="房屋效果图"
  29. @click="imgClick(imageUrl)" />
  30. </div>
  31. <!-- 推荐方案区域 -->
  32. <div class="recommend-scheme">
  33. <h3 class="recommend-title">推荐方案</h3>
  34. <section class="recommend-scheme-section">
  35. <!-- 施工面积 -->
  36. <div class="construction-area">
  37. <h3>施工面积</h3>
  38. <div class="construction-info">
  39. <span>主色</span>
  40. <div @click="openAreaPopup">
  41. <span class="area-value">{{ mainArea }} </span>
  42. <van-icon name="arrow" size="12" />
  43. </div>
  44. </div>
  45. </div>
  46. <!-- 工序 -->
  47. <div class="custom-table">
  48. <div class="table-header">
  49. <div class="table-cell text-left" style="flex:0.95;">工序</div>
  50. <div class="table-cell text-left" style="flex:1.7;">别墅之星系列</div>
  51. <div class="table-cell text-right" style="flex:0.35;">使用量</div>
  52. </div>
  53. <div class="table-row" v-for="(item, index) in processData" :key="index">
  54. <div class="table-cell text-left" style="flex:0.95;"><span class="gray">{{ index + 1 }}
  55. </span>{{
  56. item.F_ProcedureName }}</div>
  57. <div class="table-cell text-left" style="flex:1.7;">{{ item.F_ProductName }}</div>
  58. <div class="table-cell text-right" style="flex:0.35;">{{ item.usage }}<span
  59. class="gray">{{
  60. item.F_OrderUnit }}</span>
  61. </div>
  62. </div>
  63. </div>
  64. <!-- 预计工期 -->
  65. <div class="construction-period custom-table">
  66. <h5>预计工期<div>
  67. <span class="orgin-color">2人配合</span>
  68. 施工一栋<span class="orgin-color">300㎡</span>房子
  69. </div>
  70. </h5>
  71. <div class="table-row" v-for="(item, index) in processData" :key="index">
  72. <div class="table-cell text-left" style="flex:2.4;"><span class="gray">{{ index + 1 }}
  73. </span>{{ item.F_ProcedureName }}</div>
  74. <div class="table-cell text-right" style="flex:0.6;">{{ item.F_ConstructionPeriod
  75. }}<span class="gray">天</span>
  76. </div>
  77. </div>
  78. </div>
  79. </section>
  80. <!-- 提示语 -->
  81. <div class="notice-bar">
  82. <span>该方案能有效还原意向效果</span>,快去看看吧~
  83. </div>
  84. <!-- 确认按钮 -->
  85. <van-button class="confirm-btn" color="#E87838" block @click="confirmScheme">
  86. 确认方案 去下单
  87. </van-button>
  88. </div>
  89. </div>
  90. </div>
  91. <!-- 面积输入弹窗 -->
  92. <van-popup v-model="areaPopupShow" round position="bottom" :style="{ height: '150px', width: '100%' }"
  93. class="area-popup">
  94. <!-- 弹窗内容容器:Flex垂直布局,高度100% -->
  95. <div class="popup-content">
  96. <h3 class="popup-title">面积</h3>
  97. <div class="popup-c">
  98. <p class="popup-desc">请输入主色施工面积</p>
  99. <van-field ref="areaField" type="tel" @input="onNativeInput" class="custom-field"
  100. v-model="inputArea" placeholder="输入面积㎡" :maxlength="maxLength" @keyup.enter="confirmInput"
  101. @blur="confirmInput" />
  102. </div>
  103. </div>
  104. </van-popup>
  105. </div>
  106. </template>
  107. <script lang="ts">
  108. import Vue from 'vue';
  109. import { Component, Ref } from 'vue-property-decorator';
  110. import { getWecomType, toLBHome, toXiaoChengxu, getWxconfig, getWecomTypeName } from '@/utils/index';
  111. import { Tag, Field, ImagePreview } from 'vant';
  112. import { GetProductInfo, GetDictList, AddTrackEvent, GetOrderAddress } from "@/api/indexAI";
  113. Vue.use(Tag)
  114. @Component({
  115. components: {}
  116. })
  117. export default class GeneratePlan extends Vue {
  118. @Ref('areaField') private areaField!: Field;
  119. // 工序数据(与原表格数据一致)
  120. private processData = [];
  121. private maxLength = 10;//面积最长位数
  122. // 主色面积
  123. private mainArea = '300';
  124. // 面积输入弹窗显示状态
  125. private areaPopupShow = false;
  126. // 输入的面积
  127. private inputArea = '';
  128. private planParams = {};
  129. // 数字键盘显示状态(核心:控制键盘自动弹出)
  130. private showKeyboard = false;
  131. private imageUrl = ''; // 替换为实际图片路径
  132. private stoneColors = '';
  133. created() {
  134. }
  135. activated() {
  136. this.initialize();
  137. this.getPicList();
  138. let planParams = sessionStorage.getItem("planParams");
  139. if (planParams) {
  140. this.planParams = JSON.parse(planParams)
  141. const high_Definition_img = this.planParams.F_ResultFilePath || this.planParams.F_ResultlargeFilePath || this.planParams.F_ResultSmallFilePath;
  142. this.imageUrl = this.planParams.BaseUrl + high_Definition_img;
  143. this.GetProductInfoFn()
  144. }
  145. }
  146. private initialize() {
  147. this.processData = [];
  148. this.mainArea = '300';
  149. this.areaPopupShow = false;
  150. this.inputArea = '';
  151. this.planParams = {};
  152. this.showKeyboard = false;
  153. }
  154. // 推荐方案
  155. private GetProductInfoFn() {
  156. let that = this;
  157. const formData = new FormData();
  158. formData.append('colorCard', that.planParams.F_ColorCard);
  159. formData.append('deepGrooveTech', that.planParams.F_DeepGrooveTech);
  160. GetProductInfo(formData).then(response => {
  161. if (response.StatusCode == 200 && response.Data.length > 0) {
  162. let resData = that.processResData(response.Data, that.mainArea);
  163. that.processData = resData;
  164. } else {
  165. that.$toast(`${response.Info}`);
  166. }
  167. })
  168. }
  169. //获取电子色卡
  170. private getPicList() {
  171. let that = this;
  172. const formData = new FormData();
  173. // formData.append('WXuserid', userInfo.loginName);
  174. formData.append('baseType', 0);//必填 0外墙 1内墙
  175. const agentFrom = window.localStorage.getItem('agentFromAI');
  176. const wecomType = getWecomType(agentFrom);
  177. formData.append('wecomType', wecomType);
  178. GetDictList(formData).then(response => {
  179. if (response.StatusCode == 200) {
  180. if (response.Data && response.Data.dict) {
  181. // 仿石漆电子色卡选项
  182. let stoneColors_option = response.Data.dict.ColorCard;
  183. const targetItem = stoneColors_option.find(item => item.value === that.planParams.F_ColorCard);
  184. that.stoneColors = targetItem ? targetItem.text : '';
  185. }
  186. }
  187. });
  188. }
  189. // 处理数据的函数
  190. private processResData(data, area) {
  191. return data.map(item => {
  192. // 计算usage值:inputArea * F_UsagePerSqM / F_PackagingQuantity
  193. const usageValue = area * item.F_UsagePerSqM / item.F_PackagingQuantity;
  194. // 向上取整
  195. const usage = Math.ceil(usageValue);
  196. return {
  197. ...item,
  198. usage: usage // 新增的使用量属性
  199. };
  200. });
  201. }
  202. // 打开面积输入弹窗
  203. private openAreaPopup() {
  204. this.inputArea = this.mainArea;
  205. this.areaPopupShow = true;
  206. this.showKeyboard = true; // 显示数字键盘
  207. this.$nextTick(() => {
  208. // 输入框自动获取焦点(可选,增强交互)
  209. (this.areaField as any).focus();
  210. });
  211. }
  212. // 监听原生输入,限制最多10位
  213. private onNativeInput(value: string) {
  214. // 过滤非数字字符
  215. const pureNum = value.replace(/\D/g, '');
  216. // 长度校验
  217. if (pureNum.length > this.maxLength) {
  218. this.inputArea = pureNum.slice(0, this.maxLength);
  219. this.$toast(`最多只能输入${this.maxLength}位数字`);
  220. } else {
  221. this.inputArea = pureNum;
  222. }
  223. }
  224. // 确认输入(弹窗外的确认方案按钮可调用)
  225. private confirmInput() {
  226. const areaNum = Number(this.inputArea);
  227. if (!isNaN(areaNum) && areaNum > 0) {
  228. this.mainArea = this.inputArea;
  229. this.areaPopupShow = false;
  230. this.processData = this.processResData(this.processData, this.mainArea);
  231. } else {
  232. this.$toast('请输入主色施工面积');
  233. }
  234. }
  235. // 确认方案
  236. private confirmScheme() {
  237. let that = this;
  238. if (Number(this.mainArea) > 0) {
  239. const formData = new FormData();
  240. formData.append('eventname', '确认方案去下单');//事件名称
  241. formData.append('eventtype', 'click');//事件类型
  242. formData.append('menupath', '外墙质感/结果页/确认AI设计/确认方案去下单');//完整菜单路径
  243. const eventdataObj = {
  244. wecomType: getWecomTypeName(window.localStorage.getItem('agentFromAI')),
  245. F_ColorCard: that.planParams.F_ColorCard,
  246. F_DeepGrooveTech: that.planParams.F_DeepGrooveTech,
  247. F_UserArea: that.mainArea,
  248. F_ID: that.planParams.F_ID
  249. };
  250. formData.append('eventdata', JSON.stringify(eventdataObj));//事件数据
  251. AddTrackEvent(formData)//埋点
  252. // 获取确认下单地址
  253. GetOrderAddress().then((res) => {
  254. if (res.StatusCode == 200 && res.Data) {
  255. window.location.href = res.Data;
  256. } else {
  257. if (res && res.Info) {
  258. this.$toast(res.Info)
  259. } else {
  260. this.$toast("系统未知错误,请反馈给管理员.")
  261. }
  262. }
  263. })
  264. } else {
  265. this.$toast('请输入有效的主色施工面积');
  266. }
  267. }
  268. imgClick(url) {
  269. ImagePreview([url]);
  270. }
  271. returnPage() {
  272. this.$router.back();
  273. }
  274. toHome() {
  275. toLBHome()
  276. }
  277. }
  278. </script>
  279. <style scoped lang="scss">
  280. .generate-plan-page {
  281. background-color: #f5f5f5;
  282. min-height: 100vh;
  283. flex-direction: column;
  284. padding-bottom: 20px;
  285. .orgin-color {
  286. color: rgba(255, 141, 26, 1);
  287. }
  288. .generated-section {
  289. padding: 0 14px;
  290. .generated-header {
  291. margin-bottom: 4px;
  292. .generated-title {
  293. font-size: 22px;
  294. font-weight: 600;
  295. margin-right: 10px;
  296. line-height: 34px;
  297. padding-top: 5px;
  298. }
  299. .gray-color {
  300. height: 14px;
  301. color: rgb(166, 166, 166);
  302. display: inline-block;
  303. overflow: hidden;
  304. margin: 0 4px;
  305. }
  306. .scheme-info,
  307. .scheme-process {
  308. font-size: 12px;
  309. color: #000;
  310. display: inline-block;
  311. }
  312. .ai-tag {
  313. border-radius: 4px;
  314. margin: 5px 0 3px;
  315. padding: 1.5px 4px;
  316. }
  317. }
  318. .scheme-image {
  319. display: flex;
  320. justify-content: center;
  321. align-items: center;
  322. margin-bottom: 15px;
  323. img {
  324. // width: 60%;
  325. width: 100%;
  326. height: auto;
  327. border-radius: 8px;
  328. }
  329. }
  330. .recommend-scheme {
  331. // background-color: #fff;
  332. border-radius: 8px;
  333. // padding: 15px 10px;
  334. border-bottom: 1px solid rgba(229, 230, 235, 1);
  335. .recommend-title {
  336. font-size: 22px;
  337. font-weight: 600;
  338. margin-right: 10px;
  339. line-height: 34px;
  340. padding-top: 5px;
  341. margin-bottom: 10px;
  342. }
  343. .recommend-scheme-section {
  344. padding: 10px 6px;
  345. border-radius: 8px;
  346. background-color: rgba(248, 248, 248, 1);
  347. // background-color:#fff;
  348. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  349. }
  350. // 自定义表格样式
  351. .custom-table {
  352. padding: 10px 0;
  353. // background-color: #fff;
  354. width: 100%;
  355. border-radius: 4px;
  356. overflow: hidden;
  357. // border: 1px solid #ddd;
  358. border-bottom: 1px solid rgba(229, 230, 235, 1);
  359. .table-header {
  360. display: flex;
  361. // background-color: #f8f8f8;
  362. font-weight: 600;
  363. .table-cell {
  364. flex: 1;
  365. // padding: 10px;
  366. // text-align: center;
  367. font-size: 15px;
  368. white-space: nowrap;
  369. // border-right: 1px solid #eee;
  370. &:last-child {
  371. border-right: none;
  372. }
  373. }
  374. }
  375. .gray {
  376. color: rgba(128, 128, 128, 1);
  377. }
  378. .table-row {
  379. display: flex;
  380. // border-bottom: 1px solid #eee;
  381. align-items: stretch;
  382. &:last-child {
  383. border-bottom: none;
  384. }
  385. .table-cell {
  386. padding: 2px 0;
  387. // display: flex;
  388. // align-items: center;
  389. // justify-content: center;
  390. flex: 1;
  391. // padding: 10px;
  392. // text-align: center;
  393. font-size: 12px;
  394. color: #000;
  395. word-break: break-all; // 文字换行
  396. // border-right: 1px solid #eee;
  397. &:last-child {
  398. border-right: none;
  399. }
  400. }
  401. }
  402. .text-left {
  403. text-align: left;
  404. }
  405. .text-right {
  406. text-align: right;
  407. }
  408. }
  409. .construction-period {
  410. border-bottom: none !important;
  411. h5 {
  412. font-size: 16px;
  413. font-weight: 600;
  414. padding-bottom: 10px;
  415. div {
  416. display: inline-block;
  417. font-size: 12px;
  418. margin-left: 10px;
  419. font-weight: 400;
  420. span {
  421. font-size: 12px;
  422. }
  423. }
  424. }
  425. }
  426. .construction-area {
  427. padding: 0 0 10px;
  428. border-bottom: 1px solid rgba(229, 230, 235, 1);
  429. .area-value {
  430. color: #e55b2a;
  431. font-weight: bold;
  432. font-size: 16px;
  433. }
  434. h3 {
  435. font-size: 16px;
  436. font-weight: 600;
  437. }
  438. .construction-info {
  439. display: flex;
  440. justify-content: space-between;
  441. align-items: center;
  442. margin-top: 10px;
  443. font-size: 12px;
  444. }
  445. }
  446. .notice-bar {
  447. height: 30px;
  448. margin: 10px 0 0;
  449. padding-bottom: 22px;
  450. position: relative;
  451. bottom: -22px;
  452. border-radius: 14px 14px 0 0;
  453. line-height: 30px;
  454. color: #000000;
  455. font-size: 12px;
  456. background: linear-gradient(180deg, #F6F2B5 0%, #F9F3D8 100%);
  457. span {
  458. padding-left: 15px;
  459. color: #FF8D1A;
  460. font-weight: bold;
  461. }
  462. }
  463. .confirm-btn {
  464. padding: 16px;
  465. background-color: #E96337;
  466. border: none;
  467. border-radius: 30px;
  468. color: white;
  469. font-weight: 600;
  470. cursor: pointer;
  471. transition: all 0.2s ease;
  472. text-align: center;
  473. min-width: 90%;
  474. }
  475. }
  476. }
  477. // 弹窗样式
  478. .area-popup {
  479. padding: 0;
  480. box-sizing: border-box;
  481. .popup-content {
  482. padding: 15px;
  483. box-sizing: border-box;
  484. .popup-title {
  485. font-size: 20px;
  486. font-weight: bold;
  487. margin-bottom: 5px;
  488. }
  489. .popup-c {
  490. display: flex;
  491. flex-direction: column;
  492. align-items: center;
  493. }
  494. .popup-desc {
  495. color: #000;
  496. margin-bottom: 5px;
  497. }
  498. .custom-field {
  499. width: 150px;
  500. margin: 0px auto;
  501. text-align: center;
  502. ::v-deep input {
  503. caret-color: #e55b2a;
  504. outline: none;
  505. pointer-events: auto;
  506. text-align: center;
  507. font-size: 18px;
  508. color: #e55b2a;
  509. font-weight: bold;
  510. }
  511. }
  512. }
  513. }
  514. }
  515. </style>