smartTab.html 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport"
  7. content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no, viewport-fit=cover" />
  8. <title>微分AI</title>
  9. <!--引入 element-ui 的样式,-->
  10. <link rel="stylesheet"
  11. href="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1742018383195/element-ui.css">
  12. <!-- 必须先引入vue, 后使用element-ui -->
  13. <script
  14. src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1742017957144/vue.js"></script>
  15. <!-- 引入element 的组件库-->
  16. <script
  17. src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1742017747738/element-ui.js"></script>
  18. <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
  19. <script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script>
  20. <!-- <script src="js/vconsole.min.js"></script>
  21. <script>
  22. var vConsole = new window.VConsole();
  23. </script> -->
  24. </head>
  25. <style>
  26. body {
  27. margin: 0;
  28. padding: 0;
  29. }
  30. .box {
  31. width: 100vw;
  32. height: auto;
  33. box-sizing: border-box;
  34. background: #FAFAFA;
  35. }
  36. .page6 {
  37. width: 100vw;
  38. box-sizing: border-box;
  39. }
  40. .tab_list {
  41. width: 100%;
  42. height: 50px;
  43. background: #FAFCFF;
  44. position: absolute;
  45. top: 90px;
  46. border-radius: 15px 15px 0 0;
  47. display: flex;
  48. padding-top: 15px;
  49. padding-left: 15px;
  50. box-sizing: border-box;
  51. }
  52. .tab_item {
  53. font-weight: 500;
  54. font-size: 16px;
  55. color: #222222;
  56. line-height: 24px;
  57. margin-right: 40px;
  58. display: flex;
  59. align-items: center;
  60. flex-direction: column;
  61. }
  62. .tab_item img {
  63. width: 12px;
  64. }
  65. .show_active {
  66. color: #1677FF;
  67. }
  68. .smart_reply {
  69. width: 100%;
  70. height: calc(100vh - 120px);
  71. box-sizing: border-box;
  72. background: linear-gradient( 180deg, #FAFCFF 0%, #FAFAFA 100%);
  73. padding: 25px 15px 60px 15px;
  74. overflow-y: auto;
  75. display: flex;
  76. flex-direction: column;
  77. justify-content: space-between;
  78. }
  79. .smart_see {
  80. width: 100%;
  81. height: calc(100vh - 140px);
  82. box-sizing: border-box;
  83. background: linear-gradient( 180deg, #FAFCFF 0%, #FAFAFA 100%);
  84. padding: 25px 15px 85px 15px;
  85. overflow-y: auto;
  86. }
  87. .smart_form {
  88. padding: 15px;
  89. background: #FFFFFF;
  90. border-radius: 10px;
  91. margin-bottom: 15px;
  92. }
  93. .intent_car {
  94. padding: 15px;
  95. background: #FFFFFF;
  96. border-radius: 10px;
  97. font-weight: 400;
  98. font-size: 14px;
  99. color: #666666;
  100. }
  101. .intent {
  102. font-weight: 500;
  103. font-size: 16px;
  104. color: #1677FF;
  105. padding: 8px 12px 8px 10px;
  106. background: #FFFFFF;
  107. border-radius: 5px;
  108. border: 1px solid #1677FF;
  109. width: fit-content;
  110. margin-top: 15px;
  111. }
  112. .sync_btn {
  113. background: #1677FF;
  114. border-radius: 20px;
  115. font-weight: 500;
  116. font-size: 16px;
  117. color: #FFFFFF;
  118. text-align: center;
  119. padding: 15px 96px;
  120. position: fixed;
  121. bottom: 34px;
  122. margin: 0 20px;
  123. }
  124. .item_lable {
  125. display: flex;
  126. align-items: center;
  127. justify-content: space-between;
  128. font-weight: 400;
  129. font-size: 14px;
  130. color: #666666;
  131. margin-bottom: 10px;
  132. }
  133. .edit_btn {
  134. color: #1677FF;
  135. }
  136. .el-input__inner{
  137. border-top: none;
  138. border-left: none;
  139. border-right: none;
  140. border-bottom: 1px solid #F4F3FD;
  141. padding: 0;
  142. margin-bottom: 10px;
  143. border-radius: 0;
  144. background-color: #FFFFFF !important;
  145. }
  146. .el-textarea__inner{
  147. border: none;
  148. padding: 0;
  149. border-radius: 10px;
  150. padding: 10px;
  151. }
  152. .client_msg {
  153. width: 100%;
  154. height: 120px;
  155. background: url('./img/smart_bg.png');
  156. background-size: 100% 120px;
  157. background-repeat: no-repeat;
  158. position: relative;
  159. padding-top: 20px;
  160. padding-left: 20px;
  161. box-sizing: border-box;
  162. }
  163. .client_wx {
  164. display: flex;
  165. align-items: center;
  166. }
  167. .client_wx img {
  168. width: 56px;
  169. height: 56px;
  170. border-radius: 10px ;
  171. margin-right: 12px;
  172. }
  173. .wx_msg {
  174. display: flex;
  175. flex-direction: column;
  176. align-items: flex-start;
  177. justify-content: center;
  178. font-weight: 500;
  179. color: #FFFFFF;
  180. }
  181. .wx_name {
  182. font-size: 16px;
  183. padding-bottom: 5px;
  184. }
  185. .wx_tag {
  186. font-size: 10px;
  187. }
  188. .loading_text {
  189. font-size: 14px;
  190. color: #999999;
  191. padding-top: 90px;
  192. text-align: center;
  193. }
  194. .input_style {
  195. display: flex;
  196. align-items: center;
  197. position: fixed;
  198. bottom: 10px;
  199. }
  200. .smart_input {
  201. width: 288px;
  202. margin-right: 15px;
  203. }
  204. .smart_input .el-input__inner {
  205. height: 50px;
  206. border: none;
  207. padding: 15px;
  208. background: #F6F6F7;
  209. border-radius: 20px;
  210. font-size: 14px;
  211. line-height: 20px;
  212. margin-bottom: 0;
  213. }
  214. .send_btn {
  215. width: 42px;
  216. height: 42px;
  217. }
  218. .reply_content {
  219. background: #F0F4FA;
  220. border-radius: 10px;
  221. font-size: 14px;
  222. color: #222222;
  223. line-height: 28px;
  224. padding: 15px;
  225. margin-bottom: 7px;
  226. }
  227. .reply_title {
  228. color: #1677FF;
  229. }
  230. .copy_div {
  231. display: flex;
  232. align-items: center;
  233. justify-content: flex-end;
  234. border-top: 1px solid #CCD8E8;
  235. font-size: 14px;
  236. color: #1677FF;
  237. line-height: 20px;
  238. padding-top: 13px;
  239. margin-top: 15px;
  240. }
  241. .copy_div img {
  242. width: 14px;
  243. height: 14px;
  244. margin-right: 8px;
  245. }
  246. .send_msg {
  247. font-size: 14px;
  248. color: #222222;
  249. padding: 12px 10px 12px 15px;
  250. background: #FFFFFF;
  251. display: flex;
  252. align-items: center;
  253. width: fit-content;
  254. margin-bottom: 10px;
  255. }
  256. .msg_list {
  257. font-size: 12px;
  258. color: #222222;
  259. padding: 12px 10px 12px 15px;
  260. background: #FFFFFF;
  261. display: flex;
  262. align-items: center;
  263. width: fit-content;
  264. margin-bottom: 10px;
  265. }
  266. .msg_list img {
  267. width: 16px;
  268. height: 16px;
  269. margin-left: 8px;
  270. }
  271. </style>
  272. <body>
  273. <div id="box" class="box">
  274. <div class="page6">
  275. <div class="client_msg">
  276. <div class="client_wx">
  277. <img :src="clientData.avatar" />
  278. <div class="wx_msg">
  279. <div class="wx_name">{{clientData.name}}</div>
  280. <div class="wx_tag">@微信</div>
  281. </div>
  282. </div>
  283. </div>
  284. <div class="tab_list">
  285. <div class="tab_item" @click="handleClick('first')">
  286. <div :class="activeName === 'first' ? 'show_active' : ''">智能回复</div>
  287. <img src="./img/tab_line.png" v-show="activeName ==='first'" />
  288. </div>
  289. <div class="tab_item" @click="handleClick('second')">
  290. <div :class="activeName === 'second' ? 'show_active' : ''">智能洞察</div>
  291. <img src="./img/tab_line.png" v-show="activeName ==='second'" />
  292. </div>
  293. </div>
  294. <div class="smart_reply" v-if="activeName ==='first'">
  295. <div class="loading_text" v-if="!lastMsgData.length && !replyData.problem">暂无新提问或正在同步中…</div>
  296. <div>
  297. <div class="send_msg" v-if="replyData.problem">
  298. <span>{{replyData.problem}}</span>
  299. </div>
  300. <div class="reply_content" v-if="loading || replyData.reply">
  301. <div class="reply_title">智能回复:</div>
  302. <div>{{loading ? '思考中...' : replyData.reply}}</div>
  303. <div class="copy_div" @click="handleCopy(replyData.reply)">
  304. <img src="./img/copy_icon2.png" alt="">
  305. <span>复制</span>
  306. </div>
  307. </div>
  308. </div>
  309. <div>
  310. <div class="msg_list" v-for="(item, index) in lastMsgData" :key="index" @click="sendMsg(item)">
  311. <span>{{item.content}}</span>
  312. <img src="./img/msg_icon.png" alt="">
  313. </div>
  314. </div>
  315. <div class="input_style">
  316. <el-input class="smart_input" placeholder="请输入您的问题" v-model="problem">
  317. </el-input>
  318. <img class="send_btn" src="./img/send_btn2.png" @click="sendMsg('')"></img>
  319. </div>
  320. </div>
  321. <div class="smart_see" v-if="activeName === 'second'">
  322. <div class="smart_form">
  323. <div class="item_lable">
  324. <div>手机号</div>
  325. <div class="edit_btn" @click="handleSave(1, disabled1)">{{disabled1 ? '编辑' : '确定'}}</div>
  326. </div>
  327. <el-input v-model="insightData.phone" type="number" :readonly="disabled1" placeholder="请输入内容"></el-input>
  328. <div class="item_lable">
  329. <div>地区</div>
  330. <div class="edit_btn" @click="handleSave(2, disabled2)">{{disabled2 ? '编辑' : '确定'}}</div>
  331. </div>
  332. <el-cascader v-model="areaData" :options="transformedData" style="width: 100%;" :disabled="disabled2"
  333. @change="handleInfoCity">
  334. </el-cascader>
  335. <div class="item_lable">
  336. <div>详细地址</div>
  337. <div class="edit_btn" @click="handleSave(3, disabled3)">{{disabled3 ? '编辑' : '确定'}}</div>
  338. </div>
  339. <el-input type="textarea" :autosize="{ minRows: 3 }" placeholder="暂无" v-model="insightData.address" :disabled="disabled3">
  340. </el-input>
  341. </div>
  342. <div class="intent_car">
  343. <div>意向车型</div>
  344. <div class="intent" v-if="insightData.intent">{{insightData.intent}}</div>
  345. </div>
  346. <div class="sync_btn" @click="handleSync">同步到用户画像</div>
  347. </div>
  348. </div>
  349. </div>
  350. </body>
  351. <script>
  352. new Vue({
  353. el: '#box',
  354. data() {
  355. return {
  356. httpUrl: '',
  357. bId: null,
  358. env: '',
  359. memberId: null,
  360. externalUserId: null,
  361. activeName: 'first',
  362. clientData: {
  363. avatar: '',
  364. name: '',
  365. },
  366. lastMsgData: [],
  367. problem: '',
  368. replyData: {
  369. messageId: '',
  370. problem: '',
  371. reply: '',
  372. },
  373. timer: null,
  374. secondTimer: null,
  375. loading: false,
  376. disabled1: true,
  377. disabled2: true,
  378. disabled3: true,
  379. insightData: {
  380. phone: '',
  381. province: '',
  382. city: '',
  383. address: '',
  384. intent: '',
  385. },
  386. transformedData: [],
  387. areaData: [],
  388. }
  389. },
  390. created() {
  391. this.bId = this.getQueryParam('bId')
  392. this.env = this.getQueryParam('env')
  393. if (!this.env || this.env === 'prod') {
  394. this.httpUrl = 'https://wlapi.wefanbot.com'
  395. } else {
  396. this.httpUrl = 'http://test.wefanbot.com:18993'
  397. }
  398. if (this.getQueryParam('memberId')) {
  399. // 已授权
  400. this.memberId = this.getQueryParam('memberId')
  401. if (this.getQueryParam('externalUserId')) {
  402. this.externalUserId = this.getQueryParam('externalUserId')
  403. this.getClientExt()
  404. this.getLastMsg()
  405. // 设置定时器:每60秒刷新一次
  406. this.timer = setInterval(() => {
  407. this.getLastMsg()
  408. }, 5 * 1000)
  409. this.insight()
  410. this.secondTimer = setInterval(() => {
  411. this.insight()
  412. }, 5 * 1000)
  413. this.getCityLevel()
  414. } else {
  415. this.getQyWxSign()
  416. }
  417. } else {
  418. // 授权
  419. this.getAuth()
  420. }
  421. // this.memberId = "woU17nDAAAfzP9lzjd-G8iwCiveKR8GA"
  422. // this.externalUserId = "wmU17nDAAALFy-xUBJDwHbB5CsjzeY_g"
  423. // this.getClientExt()
  424. // this.getLastMsg()
  425. // // 设置定时器:每60秒刷新一次
  426. // this.timer = setInterval(() => {
  427. // this.getLastMsg()
  428. // }, 60 * 1000)
  429. // this.getCityLevel()
  430. },
  431. methods: {
  432. getAuth() {
  433. fetch(this.httpUrl + `/p/insuite/p/getRedirectUri?env=${this.env}&bId=${this.bId}`)
  434. .then(res => {
  435. return res.json()
  436. }).then(result => {
  437. let { data, code, msg } = result
  438. if (code === 1) {
  439. window.location.replace(data)
  440. } else {
  441. this.$message({
  442. message: msg,
  443. type: 'warning'
  444. })
  445. }
  446. })
  447. },
  448. getQyWxSign() {
  449. fetch(this.httpUrl + '/scrm/v1/wxcp-corp/p/getAgentConfig', {
  450. method: 'post',
  451. body: JSON.stringify({
  452. bId: this.bId,
  453. url: window.location.href,
  454. }),
  455. headers: {
  456. 'Content-Type': 'application/json'
  457. }
  458. }).then(res => {
  459. return res.json()
  460. }).then(result => {
  461. let { data, code, msg } = result
  462. if (code === 1) {
  463. let that = this
  464. wx.agentConfig({
  465. corpid: data.corpid,
  466. agentid: data.agentId,
  467. timestamp: data.timestamp, // 必填,生成签名的时间戳
  468. nonceStr: data.nonceStr, // 必填,生成签名的随机串
  469. signature: data.agentSignature, // 必填,签名,见附录1
  470. jsApiList: ['getCurExternalContact'], // 必填,需要使用的JS接口列表
  471. success: function (res) {
  472. // 回调
  473. // 此处直接在注入回调中调用了获取当前外部联系人userId的接口,注意此接口是从聊天框的工具栏进入才能获取
  474. wx.invoke('getCurExternalContact', {
  475. }, function (res) {
  476. if (res.err_msg == "getCurExternalContact:ok") {
  477. console.log('invoke成功:', res.userId);
  478. that.externalUserId = res.userId
  479. that.getClientExt()
  480. that.getLastMsg()
  481. // 设置定时器:每60秒刷新一次
  482. that.timer = setInterval(() => {
  483. that.getLastMsg()
  484. }, 5 * 1000)
  485. that.insight()
  486. that.secondTimer = setInterval(() => {
  487. that.insight()
  488. }, 5 * 1000)
  489. that.getCityLevel()
  490. } else {
  491. //错误处理
  492. console.log('invoke失败:', res)
  493. }
  494. });
  495. },
  496. fail: function (res) {
  497. if (res.errMsg.indexOf('function not exist') > -1) {
  498. alert('版本过低请升级');
  499. }
  500. },
  501. complete: function (res) {
  502. // 回调
  503. console.log('complete1', res);
  504. }
  505. });
  506. } else {
  507. this.$message({
  508. message: msg,
  509. type: 'warning'
  510. })
  511. }
  512. })
  513. },
  514. handleClick(tabName) {
  515. this.activeName = tabName
  516. if (tabName === 'second') {
  517. this.insight()
  518. }
  519. },
  520. // 获取客户画像
  521. getClientExt() {
  522. fetch(this.httpUrl + '/scrm/v1/wxcp-client/p/h5clientInfo', {
  523. method: 'post',
  524. body: JSON.stringify({
  525. bid: this.bId,
  526. externalUserId: this.externalUserId,
  527. }),
  528. headers: {
  529. 'Content-Type': 'application/json'
  530. }
  531. }).then(res => {
  532. return res.json()
  533. }).then(result => {
  534. let { data, code, msg } = result
  535. if (code === 1) {
  536. this.clientData = data
  537. } else {
  538. this.$message({
  539. message: msg,
  540. type: 'warning'
  541. })
  542. }
  543. })
  544. },
  545. // 获取智能回复提示
  546. getLastMsg() {
  547. fetch(this.httpUrl + '/scrm/v1/wxcp-message/p/getLastMessagesByH5', {
  548. method: 'post',
  549. body: JSON.stringify({
  550. bid: this.bId,
  551. externalUserId: this.externalUserId,
  552. memberId: this.memberId,
  553. }),
  554. headers: {
  555. 'Content-Type': 'application/json'
  556. }
  557. }).then(res => {
  558. return res.json()
  559. }).then(result => {
  560. let { data, code, msg } = result
  561. if (code === 1) {
  562. this.lastMsgData = data
  563. } else {
  564. this.$message({
  565. message: msg,
  566. type: 'warning'
  567. })
  568. }
  569. })
  570. },
  571. sendMsg(item) {
  572. if (!item.id && !this.problem) {
  573. this.$message({
  574. message: '请输入内容',
  575. type: 'warning'
  576. })
  577. return
  578. }
  579. this.replyData.problem = item.id ? item.content : this.problem
  580. this.loading = true
  581. fetch(this.httpUrl + '/scrm/v1/tenancy-ai/p/h5AiReply', {
  582. method: 'post',
  583. body: JSON.stringify({
  584. bid: this.bId,
  585. externalUserId: this.externalUserId,
  586. memberId: this.memberId,
  587. endMsgId: item.id,
  588. problem: item.id ? '' : this.problem,
  589. }),
  590. headers: {
  591. 'Content-Type': 'application/json'
  592. }
  593. }).then(res => {
  594. return res.json()
  595. }).then(result => {
  596. let { data, code, msg } = result
  597. if (code === 1) {
  598. this.replyData = {
  599. messageId: item.id,
  600. problem: item.id ? item.content : data.problem,
  601. reply: '',
  602. }
  603. this.titleWriter(data.reply)
  604. } else {
  605. this.$message({
  606. message: msg,
  607. type: 'warning'
  608. })
  609. }
  610. }).finally(() => {
  611. this.problem = ''
  612. this.loading = false
  613. })
  614. },
  615. titleWriter (str) {
  616. let that = this
  617. let i = 0;
  618. let timer = setInterval(function () {
  619. that.replyData.reply += str.charAt(i)
  620. i++;
  621. if (i >= str.length) {
  622. clearInterval(timer);
  623. }
  624. }, 50);
  625. },
  626. // 客户洞察
  627. insight () {
  628. if (!this.externalUserId) {
  629. return
  630. }
  631. fetch(this.httpUrl + '/scrm/v1/wxcp-chat-tool/p/h5Insight', {
  632. method: 'post',
  633. body: JSON.stringify({
  634. bid: this.bId,
  635. externalUserId: this.externalUserId,
  636. memberId: this.memberId,
  637. }),
  638. headers: {
  639. 'Content-Type': 'application/json'
  640. }
  641. }).then(res => {
  642. return res.json()
  643. }).then(result => {
  644. let { data, code, msg } = result
  645. if (code === 1) {
  646. this.insightData = data
  647. this.areaData = [data.province, data.city]
  648. } else {
  649. this.$message({
  650. message: msg,
  651. type: 'warning'
  652. })
  653. }
  654. })
  655. },
  656. handleSave (num, status) {
  657. if (num === 1) {
  658. if (this.insightData.phone && this.insightData.phone.length !== 11) {
  659. this.$message({
  660. message: '请输入正确的手机号',
  661. type: 'warning'
  662. })
  663. return
  664. }
  665. this.disabled1 = !status
  666. if (status) {
  667. return
  668. }
  669. } else if (num === 2) {
  670. this.disabled2 = !status
  671. if (status) {
  672. return
  673. }
  674. } else if (num === 3) {
  675. this.disabled3 = !status
  676. if (status) {
  677. return
  678. }
  679. }
  680. fetch(this.httpUrl + '/scrm/v1/wxcp-chat-tool/p/update2Insight', {
  681. method: 'post',
  682. body: JSON.stringify({
  683. bid: this.bId,
  684. externalUserId: this.externalUserId,
  685. memberId: this.memberId,
  686. ...this.insightData
  687. }),
  688. headers: {
  689. 'Content-Type': 'application/json'
  690. }
  691. }).then(res => {
  692. return res.json()
  693. }).then(result => {
  694. let { data, code, msg } = result
  695. if (code === 1) {
  696. this.$message({
  697. message: '保存成功',
  698. type: 'success'
  699. })
  700. } else {
  701. this.$message({
  702. message: msg,
  703. type: 'warning'
  704. })
  705. }
  706. })
  707. },
  708. handleSync () {
  709. fetch(this.httpUrl + '/scrm/v1/wxcp-chat-tool/p/sync2Ext', {
  710. method: 'post',
  711. body: JSON.stringify({
  712. bid: this.bId,
  713. externalUserId: this.externalUserId,
  714. memberId: this.memberId,
  715. ...this.insightData
  716. }),
  717. headers: {
  718. 'Content-Type': 'application/json'
  719. }
  720. }).then(res => {
  721. return res.json()
  722. }).then(result => {
  723. let { data, code, msg } = result
  724. if (code === 1) {
  725. this.$message({
  726. message: '同步成功',
  727. type: 'success'
  728. })
  729. } else {
  730. this.$message({
  731. message: msg,
  732. type: 'warning'
  733. })
  734. }
  735. }).finally(() => {
  736. this.disabled1 = true
  737. this.disabled2 = true
  738. this.disabled3 = true
  739. })
  740. },
  741. // 获取城市数据
  742. getCityLevel() {
  743. fetch('https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/1000/1720161853377/pc-code.json')
  744. .then(res => {
  745. return res.json()
  746. }).then(result => {
  747. this.transformedData = this.transformData(result)
  748. })
  749. },
  750. handleInfoCity(value) {
  751. this.insightData.province = value[0]
  752. this.insightData.city = value[1]
  753. },
  754. // 省市数据做转换
  755. transformData(data) {
  756. return data.map(item => {
  757. // 创建一个新对象,避免直接修改原始对象
  758. const newItem = { ...item };
  759. // 重命名 text 为 label
  760. if (newItem.text) {
  761. newItem.label = newItem.text;
  762. newItem.value = newItem.text;
  763. delete newItem.text;
  764. }
  765. // 如果存在 children 数组,则递归处理每个子项
  766. if (newItem.children && Array.isArray(newItem.children)) {
  767. newItem.children = this.transformData(newItem.children);
  768. }
  769. return newItem;
  770. })
  771. },
  772. // 截取url中的数据
  773. getQueryParam(paramName) {
  774. // 获取当前URL的查询字符串部分
  775. const queryString = window.location.search;
  776. // 创建一个URLSearchParams对象
  777. const urlParams = new URLSearchParams(queryString);
  778. // 返回指定参数的值,如果不存在则返回null
  779. return urlParams.get(paramName);
  780. },
  781. // 检测是否iOS端
  782. iosAgent() {
  783. return navigator.userAgent.match(/(iPhone|iPod|iPad);?/i);
  784. },
  785. // 复制文本函数,微信端,需要在用户触发 Click 事件里面才能执行成功
  786. handleCopy(message) {
  787. if (this.iosAgent()) {
  788. let inputObj = document.createElement("input");
  789. inputObj.value = message;
  790. document.body.appendChild(inputObj);
  791. inputObj.select();
  792. inputObj.setSelectionRange(0, inputObj.value.length);
  793. this.execCommand('Copy');
  794. document.body.removeChild(inputObj);
  795. } else {
  796. let domObj = document.createElement("span");
  797. domObj.innerHTML = message;
  798. document.body.appendChild(domObj);
  799. let selection = window.getSelection();
  800. let range = document.createRange();
  801. range.selectNodeContents(domObj);
  802. selection.removeAllRanges();
  803. selection.addRange(range);
  804. this.execCommand('Copy');
  805. document.body.removeChild(domObj);
  806. }
  807. },
  808. // 执行浏览器命令 Copy 顺便输出一下日志,如果在移动端推荐写个方法展示日志或者用alert(msg)也行。
  809. execCommand(action) {
  810. let is = document.execCommand(action);
  811. if (is) {
  812. this.$message({
  813. message: '复制成功',
  814. type: 'success'
  815. })
  816. } else {
  817. this.$message({
  818. message: '复制失败',
  819. type: 'error'
  820. })
  821. }
  822. },
  823. }
  824. })
  825. </script>
  826. </html>