chat.vue 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097
  1. <template>
  2. <view class="chat-box" :style="colorStyle">
  3. <!-- #ifdef MP -->
  4. <!-- <view class="head-box">
  5. <view class="system-head" :style="{ height: sysHead }"></view>
  6. <view class="title-hd">
  7. <view class="iconfont icon-fanhui" @click="goBack"></view>
  8. <view>{{ titleName }}</view>
  9. </view>
  10. </view> -->
  11. <!-- #endif -->
  12. <view class="broadcast-details_order">
  13. <!-- 商品信息 -->
  14. <view class="broadcast-details_box" v-if="productId && productInfo.id">
  15. <view class="broadcast_details_img">
  16. <image class="goods-img" :src="productInfo.image" />
  17. </view>
  18. <view class="broadcast_details_picBox">
  19. <view
  20. class="broadcast_details_tit"
  21. v-text="productInfo.store_name"
  22. ></view>
  23. <view class="acea-row row-between">
  24. <view class="broadcast_details_pic">
  25. {{ $t(`¥`) }}{{ productInfo.price }}
  26. <text
  27. class="broadcast_details_pic_num"
  28. v-if="productInfo.ot_price"
  29. >{{ $t(`¥`) }}{{ productInfo.ot_price }}</text
  30. >
  31. </view>
  32. <view class="broadcast_details_btn" @click="sendProduct">{{
  33. $t(`发送客服`)
  34. }}</view>
  35. </view>
  36. </view>
  37. </view>
  38. <!-- 订单信息 -->
  39. <view class="broadcast_box" v-if="orderId && orderInfo.id">
  40. <view class="broadcast-details_num broadcast_num">
  41. <text>{{ $t(`订单号`) }}:{{ orderInfo.order_id }}</text>
  42. <text>{{ orderInfo.add_time_y }} {{ orderInfo.add_time_h }}</text>
  43. </view>
  44. <view class="broadcast-details_box">
  45. <view class="broadcast_details_img">
  46. <image
  47. class="goods-img"
  48. :src="orderInfo.cartInfo[0].productInfo.image"
  49. />
  50. <view class="broadcast_details_model">
  51. {{ orderInfo.cartInfo ? orderInfo.cartInfo.length : 0
  52. }}{{ $t(`件商品`) }}
  53. </view>
  54. </view>
  55. <view class="broadcast_details_picBox">
  56. <view class="broadcast_details_tit">{{
  57. orderInfo.cartInfo[0].productInfo.store_name
  58. }}</view>
  59. <view class="acea-row row-between">
  60. <view class="broadcast_details_pic">
  61. {{ $t(`¥`) }}{{ orderInfo.cartInfo[0].productInfo.price }}
  62. <text class="broadcast_details_pic_num"
  63. >{{ $t(`¥`) }}{{ orderInfo.cartInfo[0].costPrice }}</text
  64. >
  65. </view>
  66. <view class="broadcast_details_btn" @click="sendOrder">{{
  67. $t(`发送客服`)
  68. }}</view>
  69. </view>
  70. </view>
  71. </view>
  72. </view>
  73. </view>
  74. <view class="chat-scroll-box">
  75. <scroll-view
  76. scroll-y="true"
  77. style="height: 100%"
  78. :scroll-top="scrollTop"
  79. @scrolltoupper="scrollToTop"
  80. >
  81. <Loading :loaded="status" :loading="loading"></Loading>
  82. <view id="box" class="chat" ref="chat">
  83. <view
  84. v-for="(item, index) in records"
  85. :key="index"
  86. :id="`msg-${item.id}`"
  87. >
  88. <view class="day-box" v-if="item.show">{{ item._add_time }}</view>
  89. <view class="chat-item" :class="{ 'right-box': item.uid == myUid }">
  90. <image class="avatar" :src="item.avatar" mode=""></image>
  91. <!-- 消息 -->
  92. <view
  93. class="msg-box"
  94. v-if="item.msn_type <= 2"
  95. v-html="item.msn"
  96. ></view>
  97. <!-- 图片 -->
  98. <view class="img-box" v-if="item.msn_type == 3">
  99. <image
  100. :src="item.msn"
  101. mode="widthFix"
  102. @tap="previewImage(item.msn)"
  103. ></image>
  104. </view>
  105. <!-- 商品 -->
  106. <view
  107. class="product-box"
  108. v-if="item.msn_type == 5"
  109. @click="goProduct(item)"
  110. >
  111. <image :src="item.productInfo.image" mode="widthFix"></image>
  112. <view class="info">
  113. <view class="price">
  114. <text>{{ $t(`¥`) }}</text>
  115. {{ item.productInfo.price }}
  116. </view>
  117. <view class="name line2">{{
  118. item.productInfo.store_name
  119. }}</view>
  120. </view>
  121. </view>
  122. <!-- 订单 -->
  123. <view
  124. class="order-box"
  125. v-if="item.msn_type == 6 && item.orderInfo"
  126. @click="goOrder(item)"
  127. >
  128. <view class="title"
  129. >{{ $t(`订单号`) }}: {{ item.orderInfo.order_id }}</view
  130. >
  131. <view class="info">
  132. <image
  133. :src="item.orderInfo.cartInfo[0].productInfo.image"
  134. ></image>
  135. <view class="product-info">
  136. <view class="name line2"
  137. >{{ item.orderInfo.cartInfo[0].productInfo.store_name }}
  138. </view>
  139. <view class="price">
  140. {{ $t(`¥`)
  141. }}{{ item.orderInfo.cartInfo[0].productInfo.price }}
  142. </view>
  143. </view>
  144. </view>
  145. </view>
  146. </view>
  147. </view>
  148. </view>
  149. </scroll-view>
  150. </view>
  151. <view class="footer-box">
  152. <view class="words" @click="uploadImg"
  153. ><text class="iconfont icon-tupian"></text
  154. ></view>
  155. <view class="input-box">
  156. <input
  157. type="text"
  158. :placeholder="$t(`请输入内容`)"
  159. v-model="con"
  160. confirm-type="send"
  161. @confirm="sendText"
  162. />
  163. <text
  164. class="iconfont icon-fasong"
  165. @click="sendText"
  166. :class="{ isSend: isSend }"
  167. ></text>
  168. </view>
  169. <view class="emoji" @click="isSwiper = !isSwiper"
  170. ><span class="iconfont icon-biaoqing"></span
  171. ></view>
  172. </view>
  173. <!-- 表情 -->
  174. <view class="banner slider-banner" v-if="isSwiper">
  175. <swiper
  176. class="swiper-wrapper"
  177. :autoplay="autoplay"
  178. :circular="circular"
  179. :interval="interval"
  180. :duration="duration"
  181. v-if="emojiGroup.length > 0"
  182. >
  183. <block v-for="(emojiList, index) in emojiGroup" :key="index">
  184. <swiper-item
  185. ><i
  186. class="em"
  187. :class="emoji"
  188. :style="'background-image:url(' + httpUrl + ')'"
  189. v-for="emoji in emojiList"
  190. :key="emoji"
  191. @click="addEmoji(emoji)"
  192. ></i
  193. ></swiper-item>
  194. </block>
  195. </swiper>
  196. </view>
  197. <canvas
  198. canvas-id="canvas"
  199. v-if="canvasStatus"
  200. :style="{
  201. width: canvasWidth + 'px',
  202. height: canvasHeight + 'px',
  203. position: 'absolute',
  204. left: '-100000px',
  205. top: '-100000px',
  206. }"
  207. ></canvas>
  208. </view>
  209. </template>
  210. <script>
  211. const app = getApp();
  212. import { getChatRecord } from "@/api/user";
  213. import { getProductDetail } from "@/api/store";
  214. import { getOrderDetail } from "@/api/order";
  215. let statusBarHeight = uni.getWindowInfo().statusBarHeight + "px";
  216. import Socket from "@/libs/new_chat";
  217. const chunk = function (arr, num) {
  218. num = num * 1 || 1;
  219. var ret = [];
  220. arr.forEach(function (item, i) {
  221. if (i % num === 0) {
  222. ret.push([]);
  223. }
  224. ret[ret.length - 1].push(item);
  225. });
  226. return ret;
  227. };
  228. import emojiList from "@/utils/emoji";
  229. import Loading from "@/components/Loading";
  230. import colors from "@/mixins/color";
  231. import { HTTP_REQUEST_URL } from "@/config/app.js";
  232. export default {
  233. name: "adminChat_index",
  234. data() {
  235. return {
  236. status: false,
  237. loading: false,
  238. sysHead: statusBarHeight,
  239. isTool: false,
  240. isSwiper: false,
  241. isWords: false,
  242. autoplay: false,
  243. circular: true,
  244. interval: 3000,
  245. duration: 500,
  246. emojiGroup: chunk(emojiList, 21),
  247. wordsList: [],
  248. con: "",
  249. toUid: 0,
  250. limit: 15,
  251. upperId: 0,
  252. chatList: [],
  253. kefuInfo: {},
  254. scrollTop: 0,
  255. active: true,
  256. isScroll: true,
  257. oldHeight: 0,
  258. myUid: 0,
  259. productId: 0,
  260. productInfo: {},
  261. orderId: 0,
  262. page: 1,
  263. orderInfo: {},
  264. uidTo: 0,
  265. titleName: "",
  266. chatStatus: false,
  267. userType: 0,
  268. canvasWidth: "",
  269. canvasHeight: "",
  270. canvasStatus: false,
  271. httpUrl: "",
  272. };
  273. },
  274. mixins: [colors],
  275. components: {
  276. Loading,
  277. },
  278. computed: {
  279. isSend() {
  280. if (this.con.length == 0) {
  281. return false;
  282. } else {
  283. return true;
  284. }
  285. },
  286. records() {
  287. return this.chatList.map((item, index) => {
  288. if (index) {
  289. if (item.add_time - this.chatList[index - 1].add_time >= 300) {
  290. item.show = true;
  291. } else {
  292. item.show = false;
  293. }
  294. } else {
  295. item.show = true;
  296. }
  297. return item;
  298. });
  299. },
  300. },
  301. onLoad(options) {
  302. uni.showLoading({
  303. title: this.$t(`客服连接中`),
  304. });
  305. this.myUid = this.$store.state.app.uid;
  306. this.toUid = options.to_uid;
  307. this.productId = parseInt(options.productId) || 0;
  308. this.orderId = options.orderId || 0;
  309. this.userType = options.type;
  310. this.getproductInfo();
  311. this.getOrderInfo();
  312. },
  313. onUnload() {
  314. this.$socket.onClose();
  315. uni.$off();
  316. },
  317. onReady() {
  318. this.httpUrl = `${HTTP_REQUEST_URL}/statics/images/look.png`;
  319. // #ifdef H5
  320. let dom = document.querySelector(".chat-box");
  321. dom.style.height = window.innerHeight + "px";
  322. // #endif
  323. let initSocket = () => {
  324. if (app.globalData.isWsOpen) {
  325. this.$socket.send({
  326. data: {
  327. token: this.$store.state.app.token,
  328. //#ifdef MP || APP-PLUS
  329. form_type: 2,
  330. //#endif
  331. //#ifdef H5
  332. form_type: this.$wechat.isWeixin() ? 1 : 3,
  333. //#endif
  334. },
  335. type: "login",
  336. });
  337. this.getChatList();
  338. } else {
  339. let form_type;
  340. //#ifdef MP || APP-PLUS
  341. form_type = 2;
  342. //#endif
  343. //#ifdef H5
  344. form_type = this.$wechat.isWeixin() ? 1 : 3;
  345. //#endif
  346. this.$socket.onStart(this.$store.state.app.token, form_type);
  347. }
  348. uni.$once("socketOpen", () => {
  349. // 登录
  350. this.$socket.send({
  351. data: this.$store.state.app.token,
  352. //#ifdef MP || APP-PLUS
  353. form_type: 2,
  354. //#endif
  355. //#ifdef H5
  356. form_type: this.$wechat.isWeixin() ? 1 : 3,
  357. //#endif
  358. type: "login",
  359. });
  360. this.$nextTick((e) => {
  361. this.getChatList();
  362. });
  363. });
  364. };
  365. initSocket();
  366. // 初始化
  367. // 监听客服转接
  368. uni.$on("to_transfer", (data) => {
  369. this.toUid = data.toUid;
  370. this.$socket.send({
  371. data: {
  372. id: this.toUid,
  373. },
  374. type: "to_chat",
  375. });
  376. this.chatList.forEach((el) => {
  377. if (el.uid != this.myUid) {
  378. el.avatar = data.avatar;
  379. }
  380. });
  381. });
  382. // 超时了
  383. uni.$once("timeout", () => {
  384. uni.showLoading({
  385. title: "重连中",
  386. mask: true,
  387. });
  388. this.chatList = [];
  389. initSocket();
  390. });
  391. // 链接成功
  392. uni.$once("success", () => {
  393. this.$socket.init();
  394. });
  395. // 消息接收
  396. uni.$on(["reply", "chat"], (data) => {
  397. if (data.msn_type == 1) {
  398. data.msn = this.replace_em(data.msn);
  399. }
  400. data._add_time = data._add_time.substring(0, data._add_time.length - 3);
  401. this.chatList.push(data);
  402. this.$nextTick(() => {
  403. this.height();
  404. });
  405. });
  406. uni.$on("socket_error", () => {
  407. this.$util.Tips({
  408. title: this.$t(`连接失败`),
  409. });
  410. });
  411. uni.$on("err_tip", (e) => {
  412. this.$util.Tips({
  413. title: e.msg,
  414. });
  415. });
  416. uni.$on("online", (data) => {
  417. if (data.online == 0) {
  418. uni.showModal({
  419. title: this.$t(`提示`),
  420. content: this.$t(`客服已下线,是否需要反馈?`),
  421. success: function (res) {
  422. if (res.confirm) {
  423. uni.redirectTo({
  424. url: "/pages/columnGoods/HotNewGoods/feedback",
  425. });
  426. } else if (res.cancel) {
  427. }
  428. },
  429. });
  430. }
  431. });
  432. this.$nextTick(() => {
  433. this.height();
  434. });
  435. },
  436. methods: {
  437. previewImage(n) {
  438. uni.previewImage({
  439. urls: [n],
  440. });
  441. },
  442. // 返回
  443. goBack() {
  444. uni.navigateBack();
  445. },
  446. // 商品信息
  447. getproductInfo() {
  448. let that = this;
  449. if (!this.productId) return;
  450. getProductDetail(this.productId).then((res) => {
  451. that.productInfo = res.data.storeInfo;
  452. });
  453. },
  454. // 商品信息
  455. goProduct(item) {
  456. uni.navigateTo({
  457. url: `/pages/goods_details/index?id=${item.msn}`,
  458. });
  459. },
  460. // 订单详情
  461. goOrder(item) {
  462. if (this.userType) {
  463. uni.navigateTo({
  464. url: `/pages/admin/orderDetail/index?id=${item.msn}`,
  465. });
  466. } else {
  467. uni.navigateTo({
  468. url: `/pages/goods/order_details/index?order_id=${item.msn}`,
  469. });
  470. }
  471. },
  472. // 订单消息
  473. getOrderInfo() {
  474. if (!this.orderId) return;
  475. getOrderDetail(this.orderId).then((res) => {
  476. this.orderInfo = res.data;
  477. if (this.orderInfo.add_time_h) {
  478. this.orderInfo.add_time_h = this.orderInfo.add_time_h.substring(
  479. 0,
  480. this.orderInfo.add_time_h.lastIndexOf(":")
  481. );
  482. }
  483. if (this.orderInfo.cartInfo.length) {
  484. this.cartInfo = this.orderInfo.cartInfo[0];
  485. }
  486. });
  487. },
  488. // 表情点击
  489. addEmoji(item) {
  490. let val = `[${item}]`;
  491. this.con += val;
  492. },
  493. // 聊天表情转换
  494. replace_em(str) {
  495. str = str.replace(
  496. /\[([^\[\]]+)\]/g,
  497. "<span class='em $1' style='background-image:url(" +
  498. this.httpUrl +
  499. ")'></span>"
  500. );
  501. return str;
  502. },
  503. // 获取聊天列表
  504. getChatList() {
  505. let self = this;
  506. getChatRecord({
  507. limit: this.limit,
  508. uidTo: this.uidTo,
  509. toUid: this.toUid,
  510. })
  511. .then((res) => {
  512. let selector = "";
  513. if (res.data.serviceList.length) {
  514. if (this.uidTo == 0) {
  515. selector = `#msg-${
  516. res.data.serviceList[res.data.serviceList.length - 1].id
  517. }`;
  518. } else {
  519. selector = `#msg-${
  520. this.chatList.length ? this.chatList[0].id : 0
  521. }`;
  522. }
  523. }
  524. let arr = [];
  525. var sH = 0;
  526. uni.hideLoading();
  527. uni.setNavigationBarTitle({
  528. title: res.data.nickname,
  529. });
  530. this.titleName = res.data.nickname;
  531. this.toUid = res.data.uid;
  532. res.data.serviceList.forEach((el) => {
  533. el._add_time = el._add_time.substring(0, el._add_time.length - 3);
  534. if (el.msn_type == 1 || el.msn_type == 2) {
  535. el.msn = this.replace_em(el.msn);
  536. }
  537. });
  538. this.loading = false;
  539. this.chatList = [...res.data.serviceList, ...this.chatList];
  540. this.$nextTick(() => {
  541. if (this.chatList.length) {
  542. this.setPageScrollTo(selector);
  543. this.isScroll = res.data.serviceList.length >= this.limit;
  544. }
  545. });
  546. this.$socket.send({
  547. data: {
  548. id: this.toUid,
  549. },
  550. type: "to_chat",
  551. });
  552. })
  553. .catch((error) => {
  554. uni.hideLoading();
  555. this.$util.Tips({
  556. title: error,
  557. });
  558. this.loading = false;
  559. this.isScroll = false;
  560. uni.redirectTo({
  561. url: "/pages/columnGoods/HotNewGoods/feedback",
  562. });
  563. });
  564. },
  565. // 设置页面滚动位置
  566. setPageScrollTo(selector) {
  567. let view = uni.createSelectorQuery().in(this).select(selector);
  568. view
  569. .boundingClientRect((res) => {
  570. this.scrollTop = res ? parseFloat(res.top) - 60 : 0;
  571. })
  572. .exec();
  573. },
  574. // 发送消息
  575. sendText() {
  576. if (!this.isSend) {
  577. return this.$util.Tips({
  578. title: this.$t(`请输入内容`),
  579. });
  580. }
  581. this.sendMsg(this.con, 1);
  582. this.con = "";
  583. },
  584. // ws发送
  585. sendMsg(msn, type) {
  586. this.$socket.send({
  587. data: {
  588. msn,
  589. type,
  590. to_uid: this.toUid,
  591. },
  592. //#ifdef MP || APP-PLUS
  593. form_type: 2,
  594. //#endif
  595. //#ifdef H5
  596. form_type: this.$wechat.isWeixin() ? 1 : 3,
  597. //#endif
  598. type: "chat",
  599. });
  600. },
  601. uploadImg() {
  602. let self = this;
  603. self.canvasStatus = true;
  604. self.$util.uploadImageChange(
  605. "upload/image",
  606. function (res) {
  607. if (res.status == 200) {
  608. self.sendMsg(res.data.url, 3);
  609. }
  610. },
  611. (res) => {
  612. this.canvasStatus = false;
  613. },
  614. (res) => {
  615. this.canvasWidth = res.w;
  616. this.canvasHeight = res.h;
  617. }
  618. );
  619. },
  620. // 发送商品
  621. sendProduct() {
  622. this.sendMsg(this.productId, 5);
  623. this.productId = 0;
  624. this.productInfo = {};
  625. },
  626. // 发送订单
  627. sendOrder() {
  628. this.sendMsg(this.orderId, 6);
  629. this.orderId = 0;
  630. this.orderInfo = {};
  631. },
  632. // 滚动到底部
  633. height() {
  634. let self = this;
  635. var scrollTop = 0;
  636. let info = uni.createSelectorQuery().select(".chat");
  637. setTimeout((res) => {
  638. info
  639. .boundingClientRect(function (data) {
  640. //data - 各种参数
  641. scrollTop = data.height;
  642. if (self.active) {
  643. self.scrollTop = parseInt(scrollTop) + 500;
  644. } else {
  645. self.scrollTop = parseInt(scrollTop) + 100;
  646. }
  647. })
  648. .exec();
  649. }, 200);
  650. },
  651. // 滚动到顶部
  652. scrollToTop() {
  653. let self = this;
  654. if (this.isScroll) {
  655. this.loading = true;
  656. this.uidTo = this.chatList.length ? this.chatList[0].id : 0;
  657. this.isScroll = false;
  658. setTimeout((res) => {
  659. this.getChatList();
  660. }, 800);
  661. }
  662. },
  663. },
  664. };
  665. </script>
  666. <style>
  667. /* #ifdef MP || APP-PLUS || H5 */
  668. page,
  669. uni-page-body,
  670. html,
  671. body {
  672. height: 100%;
  673. }
  674. /* #endif */
  675. </style>
  676. <style lang="scss">
  677. .chat-box {
  678. display: flex;
  679. flex-direction: column;
  680. height: 100%;
  681. background: #f0f1f2;
  682. /* #ifdef H5 */
  683. height: 100vh;
  684. /* #endif */
  685. .head-box {
  686. /* #ifdef H5 */
  687. height: 86rpx;
  688. /* #endif */
  689. background: linear-gradient(85deg, $kf-star 0%, $kf-end 100%);
  690. .title-hd {
  691. display: flex;
  692. align-items: center;
  693. justify-content: center;
  694. position: relative;
  695. height: 43px;
  696. padding: 0 30rpx;
  697. color: #fff;
  698. .icon-fanhui {
  699. position: absolute;
  700. left: 30rpx;
  701. top: 50%;
  702. transform: translateY(-50%);
  703. }
  704. .icon-gengduo2 {
  705. /* #ifdef MP */
  706. position: absolute;
  707. right: 210rpx;
  708. top: 50%;
  709. transform: translateY(-50%);
  710. /* #endif */
  711. }
  712. }
  713. }
  714. .scroll-box {
  715. flex: 1;
  716. }
  717. .footer-box {
  718. display: flex;
  719. align-items: center;
  720. color: rgba(0, 0, 0, 0.8);
  721. background: #f7f7f7;
  722. /* #ifdef APP-PLUS */
  723. padding: 0 30rpx;
  724. height: 70rpx;
  725. height: (70rpx + constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
  726. height: calc(70rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
  727. /* #endif */
  728. /* #ifndef APP-PLUS */
  729. padding: 0 30rpx 15rpx 30rpx;
  730. height: 115rpx;
  731. /* #endif */
  732. .words .icon-tupian {
  733. font-size: 50rpx;
  734. }
  735. .input-box {
  736. display: flex;
  737. align-items: center;
  738. flex: 1;
  739. height: 64rpx;
  740. padding-right: 5rpx;
  741. margin-left: 18rpx;
  742. background-color: #fff;
  743. border-radius: 32rpx;
  744. input {
  745. flex: 1;
  746. padding-left: 20rpx;
  747. height: 100%;
  748. font-size: 28rpx;
  749. font-weight: normal;
  750. }
  751. .icon-fasong {
  752. font-size: 50rpx;
  753. color: #ccc;
  754. font-weight: normal;
  755. }
  756. .isSend {
  757. color: $kf-theme;
  758. }
  759. }
  760. .emoji .icon-biaoqing {
  761. margin-left: 18rpx;
  762. font-size: 50rpx;
  763. }
  764. .more .icon-gengduozhankai {
  765. margin-left: 18rpx;
  766. font-size: 50rpx;
  767. }
  768. }
  769. }
  770. .tool-wrapper {
  771. display: flex;
  772. justify-content: space-between;
  773. padding: 45rpx 60rpx;
  774. background: #fff;
  775. font-size: 24rpx;
  776. .tool-item {
  777. text-align: center;
  778. image {
  779. width: 104rpx;
  780. height: 104rpx;
  781. }
  782. }
  783. }
  784. .slider-banner {
  785. background: #fff;
  786. padding-bottom: 0rpx;
  787. padding-bottom: calc(constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
  788. padding-bottom: calc(env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
  789. }
  790. .words-mask {
  791. z-index: 50;
  792. position: fixed;
  793. left: 0;
  794. top: 0;
  795. right: 0;
  796. bottom: 0;
  797. background: rgba(0, 0, 0, 0.5);
  798. .content {
  799. position: absolute;
  800. left: 0;
  801. right: 0;
  802. top: 114rpx;
  803. bottom: 0;
  804. display: flex;
  805. flex-direction: column;
  806. padding: 0 30rpx;
  807. background: #fff;
  808. border-radius: 6rpx 6rpx 0px 0px;
  809. .title-box {
  810. position: relative;
  811. height: 125rpx;
  812. line-height: 125rpx;
  813. text-align: center;
  814. font-size: 32rpx;
  815. .icon-cha1 {
  816. position: absolute;
  817. right: 0;
  818. top: 50%;
  819. transform: translateY(-50%);
  820. }
  821. }
  822. .scroll-box {
  823. flex: 1;
  824. overflow: hidden;
  825. .msg-item {
  826. padding: 25rpx 0;
  827. border-bottom: 1px solid #eceff8;
  828. }
  829. }
  830. }
  831. }
  832. .chat-scroll-box {
  833. flex: 1;
  834. padding: 30rpx 30rpx 0;
  835. overflow: hidden;
  836. .chat-item {
  837. display: flex;
  838. margin-bottom: 36rpx;
  839. -webkit-user-select: auto;
  840. .avatar {
  841. width: 80rpx;
  842. height: 80rpx;
  843. border-radius: 50%;
  844. }
  845. .msg-box {
  846. display: flex;
  847. align-items: center;
  848. max-width: 452rpx;
  849. margin-left: 22rpx;
  850. padding: 10rpx 24rpx;
  851. background: #fff;
  852. border-radius: 14rpx;
  853. word-break: break-all;
  854. -webkit-user-select: auto;
  855. }
  856. .img-box {
  857. width: 270rpx;
  858. margin-left: 22rpx;
  859. image {
  860. width: 270rpx;
  861. }
  862. }
  863. .product-box {
  864. width: 452rpx;
  865. margin-left: 22rpx;
  866. background-color: #fff;
  867. border-radius: 14rpx;
  868. overflow: hidden;
  869. image {
  870. width: 452rpx;
  871. }
  872. .info {
  873. padding: 16rpx 26rpx;
  874. .price {
  875. font-size: 36rpx;
  876. color: var(--view-priceColor);
  877. text {
  878. font-size: 28rpx;
  879. }
  880. }
  881. }
  882. }
  883. .order-box {
  884. width: 452rpx;
  885. margin-left: 22rpx;
  886. background-color: #fff;
  887. border-radius: 14rpx;
  888. .title {
  889. padding: 15rpx 20rpx;
  890. font-size: 26rpx;
  891. color: #282828;
  892. border-bottom: 1px solid #eceff8;
  893. }
  894. .info {
  895. display: flex;
  896. padding: 20rpx;
  897. image {
  898. width: 124rpx;
  899. height: 124rpx;
  900. border-radius: 6rpx;
  901. }
  902. .product-info {
  903. flex: 1;
  904. display: flex;
  905. flex-direction: column;
  906. justify-content: space-between;
  907. margin-left: 16rpx;
  908. .name {
  909. font-size: 26rpx;
  910. }
  911. .price {
  912. font-size: 30rpx;
  913. color: var(--view-priceColor);
  914. }
  915. }
  916. }
  917. }
  918. &.right-box {
  919. flex-direction: row-reverse;
  920. .msg-box {
  921. margin-left: 0;
  922. margin-right: 22rpx;
  923. background-color: #9cec60;
  924. }
  925. .img-box {
  926. margin-left: 0;
  927. margin-right: 22rpx;
  928. }
  929. .product-box {
  930. margin-left: 0;
  931. margin-right: 22rpx;
  932. }
  933. .order-box {
  934. margin-left: 0;
  935. margin-right: 22rpx;
  936. }
  937. }
  938. .em {
  939. margin: 0;
  940. }
  941. }
  942. }
  943. .broadcast-details_box {
  944. display: flex;
  945. background: #fff;
  946. border-radius: 6px;
  947. padding: 24rpx;
  948. }
  949. .broadcast_details_img {
  950. width: 140rpx;
  951. height: 140rpx;
  952. border-radius: 8px;
  953. overflow: hidden;
  954. position: relative;
  955. }
  956. .broadcast_details_img .goods-img {
  957. width: 100%;
  958. height: 100%;
  959. }
  960. .broadcast_details_picBox {
  961. width: 75%;
  962. margin-left: 24rpx;
  963. }
  964. .broadcast_details_tit {
  965. font-size: 28rpx;
  966. color: #333333;
  967. height: 85rpx;
  968. font-weight: 800;
  969. line-height: 40rpx;
  970. overflow: hidden;
  971. text-overflow: ellipsis;
  972. display: -webkit-box;
  973. -webkit-line-clamp: 2;
  974. -webkit-box-orient: vertical;
  975. text-align: left !important;
  976. }
  977. .broadcast_details_pic {
  978. font-size: 36rpx;
  979. color: var(--view-priceColor);
  980. text-align: left;
  981. }
  982. .broadcast_details_pic_num {
  983. text-decoration: line-through;
  984. font-size: 28rpx;
  985. color: rgba(0, 0, 0, 0.5);
  986. margin-left: 0.1rem;
  987. }
  988. .broadcast_details_btn {
  989. width: 130rpx;
  990. height: 50rpx;
  991. background: var(--view-theme);
  992. opacity: 1;
  993. border-radius: 125rpx;
  994. color: #fff;
  995. font-size: 24rpx;
  996. text-align: center;
  997. line-height: 50rpx;
  998. }
  999. .broadcast-details_num {
  1000. width: 100%;
  1001. height: 80rpx;
  1002. line-height: 80rpx;
  1003. color: #000000;
  1004. font-size: 26rpx;
  1005. display: flex;
  1006. justify-content: space-between;
  1007. background: #fff;
  1008. border-bottom: 1px dashed rgba(0, 0, 0, 0.2);
  1009. padding: 0 24rpx;
  1010. }
  1011. .day-box {
  1012. font-size: 24rpx;
  1013. color: #999;
  1014. text-align: center;
  1015. margin-bottom: 36rpx;
  1016. }
  1017. </style>
  1018. <style>
  1019. .em {
  1020. display: inline-block;
  1021. width: 50rpx;
  1022. height: 50rpx;
  1023. margin: 40rpx 0 0 50rpx;
  1024. }
  1025. .emoji-outer {
  1026. position: absolute;
  1027. right: 50rpx;
  1028. bottom: 30rpx;
  1029. width: 50rpx;
  1030. height: 50rpx;
  1031. }
  1032. </style>