chat.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999
  1. <template>
  2. <div class="broadcast-details" :style="'height:'+windowH+'px'">
  3. <view class="hd-wrapper" :class="active === true ? 'on' : ''">
  4. <scroll-view scroll-y="true" style="height: 100%; overflow: hidden;" :scroll-top="scrollTop" scroll-with-animation="true">
  5. <div class="broadcast-details_order">
  6. <div class="broadcast-details_box" v-if="productId && productInfo.id">
  7. <div class="broadcast_details_img">
  8. <img :src="productInfo.image" />
  9. </div>
  10. <div class="broadcast_details_picBox">
  11. <div class="broadcast_details_tit" v-text="productInfo.storeName"></div>
  12. <div class="acea-row row-between">
  13. <div class="broadcast_details_pic">
  14. ¥{{ productInfo.price
  15. }}<span class="broadcast_details_pic_num">¥{{ productInfo.otPrice }}</span>
  16. </div>
  17. <div class="broadcast_details_btn" @click="sendProduct">
  18. 发送客服
  19. </div>
  20. </div>
  21. </div>
  22. </div>
  23. <div class="broadcast_box" v-if="orderId && orderInfo.id">
  24. <div class="broadcast-details_num broadcast_num">
  25. <span>订单号:{{ orderInfo.order_id }}</span>
  26. <span>{{ orderInfo.add_time_y }} {{ orderInfo.add_time_h }}</span>
  27. </div>
  28. <div class="broadcast-details_box">
  29. <div class="broadcast_details_img">
  30. <img :src="cartInfo.productInfo.image" />
  31. <div class="broadcast_details_model">
  32. {{ orderInfo.cartInfo ? orderInfo.cartInfo.length : 0 }}件商品
  33. </div>
  34. </div>
  35. <div class="broadcast_details_picBox">
  36. <div class="broadcast_details_tit">
  37. {{ cartInfo.productInfo.store_name }}
  38. </div>
  39. <div class="acea-row row-between">
  40. <div class="broadcast_details_pic">
  41. ¥{{ cartInfo.productInfo.price
  42. }}<span class="broadcast_details_pic_num">¥{{ cartInfo.productInfo.ot_price }}</span>
  43. </div>
  44. <div class="broadcast_details_btn" @click="sendOrder">
  45. 发送客服
  46. </div>
  47. </div>
  48. </div>
  49. </div>
  50. </div>
  51. </div>
  52. <div class="chat" ref="chat" >
  53. <template v-for="item in history">
  54. <div class="item acea-row row-top" v-if="item.uid === toUid" :key="item.id">
  55. <div class="pictrue"><img :src="item.avatar" /></div>
  56. <div class="text">
  57. <div class="name">{{ item.nickname }}</div>
  58. <div class="acea-row">
  59. <!--商品链接-->
  60. <div v-if="item.msn_type === 6 && item.orderInfo.id">
  61. <router-link class="broadcast-details_num" :to="{
  62. path: '/pages/admin/orderDetail/index?id=' + item.orderInfo.order_id
  63. }">
  64. <span>订单号:{{ item.orderInfo.order_id }}</span>
  65. </router-link>
  66. <div class="conter acea-row row-middle">
  67. <div class="broadcast-details_order noPad" v-for="(val, inx) in item.orderInfo.cartInfo" :key="val.id">
  68. <router-link class="broadcast-details_box noPad" :to="{ path: '/pages/goods_details/index?id=' + val.product_id }" v-if="inx == 0">
  69. <div class="broadcast_details_img">
  70. <img :src="val.productInfo.image" />
  71. <div class="broadcast_details_model">
  72. {{
  73. item.orderInfo.cartInfo
  74. ? item.orderInfo.cartInfo.length
  75. : 0
  76. }}件商品
  77. </div>
  78. </div>
  79. <div class="broadcast_details_picBox noPad">
  80. <div class="broadcast_details_tit" v-text="val.productInfo.store_name"></div>
  81. <div class="broadcast_details_pic">
  82. ¥{{ val.productInfo.price }}
  83. </div>
  84. </div>
  85. </router-link>
  86. </div>
  87. </div>
  88. </div>
  89. <!--商品链接-->
  90. <div class="conter acea-row row-middle" v-if="item.msn_type === 5">
  91. <div class=" noPad">
  92. <router-link class="acea-row row-column-around noPad" v-if="item.productInfo.id" :to="{ path: '/pages/goods_details/index?id=' + item.productInfo.id }">
  93. <div class="broadcast_details_img_no">
  94. <img :src="item.productInfo.image" />
  95. </div>
  96. <div class="broadcast_details_picBox_no noPad">
  97. <div class="broadcast_details_pic">
  98. ¥{{ item.productInfo.price }}
  99. </div>
  100. <div class="broadcast_details_tit_no" v-text="item.productInfo.store_name"></div>
  101. </div>
  102. </router-link>
  103. </div>
  104. </div>
  105. <div class="conter acea-row row-middle" v-if="item.msn_type === 4">
  106. <img src="/static/images/signal2.gif" class="signal" style="margin-right: 0.27rem;" />12’’
  107. </div>
  108. <div class="conter acea-row row-middle" v-if="item.msn_type === 3">
  109. <img :src="item.msn" />
  110. </div>
  111. <div class="conter acea-row row-middle" v-if="item.msn_type === 2">
  112. <i class="em" :class="item.msn"></i>
  113. </div>
  114. <div class="conter acea-row row-middle" v-if="item.msn_type === 1">
  115. {{ item.msn }}
  116. </div>
  117. </div>
  118. </div>
  119. </div>
  120. <div class="item acea-row row-top row-right" v-else :key="item.id">
  121. <div class="text textR">
  122. <div class="name">{{ item.nickname }}</div>
  123. <div class="acea-row ">
  124. <!--商品链接-->
  125. <router-link v-if="item.msn_type === 6 && item.orderInfo.id" :to="{
  126. path: '/pages/admin/orderDetail/index?id=' + item.orderInfo.order_id
  127. }">
  128. <div class="broadcast-details_num">
  129. <span>订单号:{{ item.orderInfo.order_id }}</span>
  130. </div>
  131. <div class="conter acea-row row-middle">
  132. <div class="broadcast-details_order noPad" v-for="(val, inx) in item.orderInfo.cartInfo" :key="val.id">
  133. <div class="broadcast-details_box noPad" v-if="inx == 0">
  134. <div class="broadcast_details_img">
  135. <img :src="val.productInfo.image" />
  136. <div class="broadcast_details_model">
  137. {{
  138. item.orderInfo.cartInfo
  139. ? item.orderInfo.cartInfo.length
  140. : 0
  141. }}件商品
  142. </div>
  143. </div>
  144. <div class="broadcast_details_picBox noPad">
  145. <div class="broadcast_details_tit" v-text="val.productInfo.store_name"></div>
  146. <div class="broadcast_details_pic">
  147. ¥{{ val.productInfo.price }}
  148. </div>
  149. </div>
  150. </div>
  151. </div>
  152. </div>
  153. </router-link>
  154. <!--商品链接-->
  155. <div class="conter acea-row row-middle" v-if="item.msn_type === 5">
  156. <div class=" noPad">
  157. <router-link class="acea-row row-column-around noPad" v-if="item.productInfo.id" :to="{ path: '/pages/goods_details/index?id=' + item.productInfo.id }">
  158. <div class="broadcast_details_img_no">
  159. <img :src="item.productInfo.image" />
  160. </div>
  161. <div class="broadcast_details_picBox_no noPad">
  162. <div class="broadcast_details_pic">
  163. ¥{{ item.productInfo.price }}
  164. </div>
  165. <div class="broadcast_details_tit_no" v-text="item.productInfo.store_name"></div>
  166. </div>
  167. </router-link>
  168. </div>
  169. </div>
  170. <div class="conter acea-row row-middle" v-if="item.msn_type === 3">
  171. <img :src="item.msn" />
  172. </div>
  173. <div class="conter acea-row row-middle" v-if="item.msn_type === 2">
  174. <i class="em" :class="item.msn"></i>
  175. </div>
  176. <div class="conter acea-row row-middle" v-if="item.msn_type === 1">
  177. {{ item.msn }}
  178. </div>
  179. </div>
  180. </div>
  181. <div class="pictrue"><img :src="item.avatar" /></div>
  182. </div>
  183. </template>
  184. </div>
  185. <div :style=" active === true
  186. ? 'height:' + footerConH + 'rem;'
  187. : 'height:' + footerH + 'rem;'
  188. "></div>
  189. </scroll-view>
  190. </view>
  191. <div class="footerCon" :class="active === true ? 'on' : ''" :style="'transform: translate3d(0,' + percent + '%,0);'" ref="footerCon">
  192. <form>
  193. <div class="footer acea-row row-between row-bottom" ref="footer">
  194. <!--<img-->
  195. <!--:src="-->
  196. <!--voice === true-->
  197. <!--? require('@assets/images/keyboard.png')-->
  198. <!--: require('@assets/images/voice.png')-->
  199. <!--"-->
  200. <!--@click="voiceBnt"-->
  201. <!--/>-->
  202. <img @click="uploadImg" src="/static/images/plus.png" />
  203. <img :src="
  204. active === true
  205. ? '/static/images/keyboard.png'
  206. : '/static/images/face.png'
  207. "
  208. @click="emoticon" />
  209. <div class="voice acea-row row-center-wrapper" v-if="voice" @touchstart.prevent="start" @touchmove.prevent="move"
  210. @touchend.prevent="end">
  211. {{ speak }}
  212. </div>
  213. <!-- <p contenteditable="true" class="input" ref="input" v-show="!voice" @keydown="keydown($event)" @keyup="keyup" @focus="focus"></p> -->
  214. <input type="text" placeholder="请输入内容" class="input" ref="input" v-show="!voice" @input="bindInput" @keyup="keyup"
  215. @focus="focus" cursor-spacing="20" v-model="textCon">
  216. <div class="send" :class="sendColor === true ? 'font-color-red' : ''" @click="sendTest">
  217. 发送
  218. </div>
  219. </div>
  220. </form>
  221. <div class="banner slider-banner">
  222. <swiper class="swiper-wrapper" :autoplay="autoplay" :circular="circular" :interval="interval" :duration="duration"
  223. v-if="emojiGroup.length > 0">
  224. <block v-for="(emojiList, index) in emojiGroup" :key="index">
  225. <swiper-item>
  226. <i class="em" :class="emoji" v-for="emoji in emojiList" :key="emoji" @click="addEmoji(emoji)"></i>
  227. <img src="/static/images/del.png" class="emoji-outer" />
  228. </swiper-item>
  229. </block>
  230. <!-- <swiper-slide class="swiper-slide acea-row" v-for="(emojiList, index) in emojiGroup" :key="index">
  231. <i class="em" :class="emoji" v-for="emoji in emojiList" :key="emoji" @click="addEmoji(emoji)"></i>
  232. <img src="/static/images/del.png" class="emoji-outer" />
  233. </swiper-slide>
  234. <div class="swiper-pagination" slot="pagination"></div> -->
  235. </swiper>
  236. </div>
  237. </div>
  238. <div class="recording" v-if="recording">
  239. <img src="/static/images/recording.png" />
  240. </div>
  241. <home></home>
  242. </div>
  243. </template>
  244. <script>
  245. import emojiList from "@/utils/emoji";
  246. import Socket from "@/libs/chat";
  247. import {
  248. getChatRecord
  249. } from "@/api/user";
  250. import {
  251. getProductDetail
  252. } from "@/api/store";
  253. import {
  254. getOrderDetail
  255. } from "@/api/order";
  256. import easyUpload from '@/components/easy-upload/easy-upload.vue'
  257. import {
  258. TOKENNAME,
  259. HTTP_REQUEST_URL
  260. } from '@/config/app.js';
  261. import home from '@/components/home';
  262. const chunk = function(arr, num) {
  263. num = num * 1 || 1;
  264. var ret = [];
  265. arr.forEach(function(item, i) {
  266. if (i % num === 0) {
  267. ret.push([]);
  268. }
  269. ret[ret.length - 1].push(item);
  270. });
  271. return ret;
  272. };
  273. const NAME = "CustomerService";
  274. export default {
  275. name: NAME,
  276. components: {
  277. easyUpload,
  278. home
  279. },
  280. props: {
  281. couponList: {
  282. type: Array,
  283. default: () => []
  284. }
  285. },
  286. data: function() {
  287. return {
  288. url: `${HTTP_REQUEST_URL}/api/upload/image`,
  289. headers: {
  290. "Authori-zation": "Bearer " + this.$store.state.app.token
  291. },
  292. emojiGroup: chunk(emojiList, 20),
  293. active: false,
  294. voice: false,
  295. speak: "按住 说话",
  296. recording: false,
  297. swiperOption: {
  298. pagination: {
  299. el: ".swiper-pagination",
  300. clickable: true
  301. },
  302. speed: 1000,
  303. observer: true,
  304. observeParents: true
  305. },
  306. percent: 0,
  307. footerConH: 0,
  308. footerH: 1.08,
  309. socket: null,
  310. toUid: 0,
  311. page: 1,
  312. limit: 30,
  313. loading: false,
  314. loaded: false,
  315. history: [],
  316. sendColor: false,
  317. sendtxt: "",
  318. productId: 0,
  319. productInfo: {},
  320. orderId: "",
  321. orderInfo: {},
  322. cartInfo: {},
  323. autoplay: false,
  324. circular: true,
  325. interval: 3000,
  326. duration: 500,
  327. upload_max: 2, //图片大小
  328. //上传的图片地址
  329. uploadImages: [],
  330. //展示的图片地址
  331. uploads: [],
  332. // 超出限制数组
  333. exceeded_list: [],
  334. windowH: 0,
  335. isBQ: false,
  336. scrollTop:0 ,//滚动距离
  337. textCon:'' //文字
  338. };
  339. },
  340. watch: {
  341. $route(n) {
  342. if (n.name === NAME) {
  343. if (n.params.productId) this.productId = n.params.productId;
  344. else this.productId = 0;
  345. if (n.query.orderId) this.orderId = n.query.orderId;
  346. else this.orderId = "";
  347. }
  348. }
  349. },
  350. beforeDestroy() {
  351. this.socket && this.socket.close();
  352. },
  353. onLoad(option) {
  354. let self = this
  355. this.toUid = option.uid || 0;
  356. this.productId = parseInt(option.productId) || 0;
  357. this.orderId = option.orderId || ""
  358. uni.getSystemInfo({
  359. success: function(res) {
  360. self.windowH = res.windowHeight
  361. }
  362. })
  363. },
  364. onReady: function() {
  365. this.height();
  366. this.getHistory();
  367. this.getproductInfo();
  368. this.getOrderInfo();
  369. this.socket = new Socket();
  370. this.socket.vm(this);
  371. this.$on(["reply", "chat"], data => {
  372. this.history.push(data);
  373. this.$nextTick(function() {
  374. window.scrollTo(0, document.documentElement.scrollHeight + 999);
  375. });
  376. });
  377. this.$on("socket_error", () => {
  378. this.$dialog.error("连接失败");
  379. });
  380. this.$on("err_tip", data => {
  381. this.$dialog.error(data);
  382. });
  383. this.$on("socket_open", () => {
  384. this.socket.send({
  385. data: {
  386. id: this.toUid
  387. },
  388. type: "to_chat"
  389. });
  390. });
  391. document.addEventListener("scroll", this.scroll, false);
  392. },
  393. destroyed() {
  394. document.removeEventListener("scroll", this.scroll);
  395. },
  396. methods: {
  397. uploadImg() {
  398. let self = this
  399. uni.chooseImage({
  400. count: 1, //默认1
  401. sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
  402. sourceType: ['album', 'camera'], //从相册选择
  403. success: (res) => {
  404. for (let i = 0; i < res.tempFiles.length; i++) {
  405. if (Math.ceil(res.tempFiles[i].size / 1024) < this.upload_max * 1024) {
  406. this.uploads.push(res.tempFiles[i].path)
  407. this.uploadImages.push(res.tempFiles[i].path)
  408. } else {
  409. this.exceeded_list.push(i === 0 ? 1 : i + 1);
  410. uni.showModal({
  411. title: '提示',
  412. content: `第${[...new Set(this.exceeded_list)].join(',')}张图片超出限制${this.upload_max}MB,已过滤`
  413. });
  414. }
  415. }
  416. uni.uploadFile({
  417. url: self.url, //仅为示例,非真实的接口地址
  418. filePath: self.uploadImages[0],
  419. name: 'file',
  420. header: {
  421. "Authori-zation": "Bearer " + self.$store.state.app.token
  422. },
  423. //请求参数
  424. success: (uploadFileRes) => {
  425. let data = JSON.parse(uploadFileRes.data)
  426. self.sendMsg(data.data.url, 3)
  427. }
  428. });
  429. },
  430. fail: (err) => {
  431. uni.showModal({
  432. content: JSON.stringify(err)
  433. });
  434. }
  435. });
  436. },
  437. getOrderInfo() {
  438. if (!this.orderId) return;
  439. getOrderDetail(this.orderId).then(res => {
  440. this.orderInfo = res.data;
  441. if (this.orderInfo.add_time_h) {
  442. this.orderInfo.add_time_h = this.orderInfo.add_time_h.substring(
  443. 0,
  444. this.orderInfo.add_time_h.lastIndexOf(":")
  445. );
  446. }
  447. if (this.orderInfo.cartInfo.length) {
  448. this.cartInfo = this.orderInfo.cartInfo[0];
  449. }
  450. });
  451. },
  452. getproductInfo() {
  453. let that = this;
  454. if (!this.productId) return;
  455. getProductDetail(this.productId).then(res => {
  456. that.productInfo = res.data.storeInfo;
  457. });
  458. },
  459. scroll() {
  460. if (window.scrollY < 300 && !this.loaded && !this.loading)
  461. this.getHistory();
  462. },
  463. imageuploaded(res) {
  464. if (res.status !== 200) return this.$dialog.error(res || "上传图片失败");
  465. this.sendMsg(res.data.url, 3);
  466. },
  467. getHistory() {
  468. if (this.loading || this.loaded) return;
  469. this.loading = true;
  470. getChatRecord(this.toUid, {
  471. page: this.page,
  472. limit: this.limit
  473. })
  474. .then(({
  475. data
  476. }) => {
  477. this.history = data.list.concat(this.history);
  478. if (this.page === 1) {
  479. this.$nextTick(function() {
  480. window.scrollTo(0, document.documentElement.scrollHeight + 999);
  481. this.height();
  482. });
  483. }
  484. this.page++;
  485. this.loading = false;
  486. this.loaded = data.length < this.limit;
  487. })
  488. .catch(err => {
  489. this.$dialog.error(err || "加载失败");
  490. });
  491. },
  492. focus: function() {
  493. this.active = false;
  494. },
  495. keyup: function() {
  496. if (this.$refs.input.innerHTML.length > 0) {
  497. this.sendColor = true;
  498. } else {
  499. this.sendColor = false;
  500. }
  501. },
  502. addEmoji(name) {
  503. this.sendMsg(name, 2);
  504. },
  505. sendMsg(msn, type) {
  506. this.height();
  507. this.socket.send({
  508. data: {
  509. msn,
  510. type,
  511. to_uid: this.toUid
  512. },
  513. type: "chat"
  514. });
  515. },
  516. sendTest() {
  517. this.sendMsg(this.textCon, 1);
  518. this.textCon = ''
  519. this.height();
  520. },
  521. sendProduct() {
  522. this.sendMsg(this.productId, 5);
  523. this.productId = 0;
  524. this.productInfo = {};
  525. },
  526. sendOrder() {
  527. this.sendMsg(this.orderId, 6);
  528. this.orderId = 0;
  529. this.orderInfo = {};
  530. },
  531. bindInput: function(e) {
  532. if(e.detail.value){
  533. this.sendColor = true
  534. }else{
  535. this.sendColor = false
  536. }
  537. this.height();
  538. },
  539. start() {
  540. var that = this;
  541. this.longClick = 0;
  542. this.timeOutEvent = setTimeout(function() {
  543. that.longClick = 1;
  544. }, 500);
  545. that.speak = "松开 结束";
  546. that.recording = true;
  547. },
  548. move() {
  549. clearTimeout(this.timeOutEvent);
  550. this.timeOutEvent = 0;
  551. },
  552. end() {
  553. clearTimeout(this.timeOutEvent);
  554. if (this.timeOutEvent !== 0 && this.longClick === 0) {
  555. //点击
  556. //此处为点击事件----在此处添加跳转详情页
  557. }
  558. this.speak = "按住 说话";
  559. this.recording = false;
  560. return false;
  561. },
  562. voiceBnt: function() {
  563. this.active = false;
  564. if (this.voice === true) {
  565. this.voice = false;
  566. this.$nextTick(function() {
  567. this.$refs.input.focus();
  568. });
  569. } else {
  570. this.voice = true;
  571. }
  572. window.scrollTo(0, document.documentElement.scrollHeight);
  573. this.percent = 0;
  574. this.footerConH = 0;
  575. this.footerH = 0;
  576. this.$nextTick(function() {
  577. this.height();
  578. });
  579. },
  580. emoticon: function() {
  581. this.voice = false;
  582. if (this.active === true) {
  583. this.active = false;
  584. this.isBQ = false
  585. // this.$nextTick(function() {
  586. // this.$refs.input.focus();
  587. // });
  588. } else {
  589. this.active = true;
  590. this.isBQ = true
  591. // this.$nextTick(function() {
  592. // this.$refs.input.blur();
  593. // });
  594. }
  595. this.height();
  596. },
  597. height() {
  598. let scrollTop = 0
  599. let footerConH = this.$refs.footerCon.offsetHeight;
  600. let footerH = this.$refs.footer.offsetHeight;
  601. let scale = 750 / window.screen.availWidth;
  602. this.footerConH = (footerConH * scale) / 100;
  603. this.footerH = (footerH * scale) / 100;
  604. this.percent = ((this.footerConH - this.footerH) / this.footerConH) * 100;
  605. setTimeout(res=>{
  606. let info = uni.createSelectorQuery().select(".chat");
  607. info.boundingClientRect(function(data) { //data - 各种参数
  608. // 获取元素宽度
  609. scrollTop = data.height
  610. }).exec()
  611. if(this.active){
  612. this.scrollTop = scrollTop+500
  613. }else{
  614. this.scrollTop = scrollTop+100
  615. }
  616. },600)
  617. },
  618. }
  619. };
  620. </script>
  621. <style lang="scss">
  622. page {
  623. width: 100%;
  624. height: 100%;
  625. }
  626. /* #ifdef H5 */
  627. @import url("@/plugin/emoji-awesome/css/google.min.css");
  628. /* #endif */
  629. .broadcast_num {
  630. padding: 0 10rpx !important;
  631. }
  632. .noPad {
  633. padding: 0 !important;
  634. margin-bottom: 0 !important;
  635. height: auto !important;
  636. }
  637. .broadcast-details_num {
  638. width: 100%;
  639. height: 80rpx;
  640. line-height: 80rpx;
  641. color: #000000;
  642. font-size: 26rpx;
  643. display: flex;
  644. justify-content: space-between;
  645. background: #fff;
  646. border-bottom: 1px dashed rgba(0, 0, 0, 0.2);
  647. padding: 0 24rpx;
  648. }
  649. .broadcast-details_order {
  650. padding: 15rpx;
  651. }
  652. .broadcast-details_box {
  653. padding: 24rpx;
  654. display: flex;
  655. background: #fff;
  656. border-radius: 6px;
  657. margin-bottom: 24rpx;
  658. }
  659. .broadcast_details_model {
  660. width: 100%;
  661. height: 43rpx;
  662. background: rgba(0, 0, 0, 0.5);
  663. border-radius: 0px 0px 8px 8px;
  664. position: absolute;
  665. z-index: 2;
  666. bottom: 0;
  667. font-size: 22rpx;
  668. color: #fff;
  669. text-align: center;
  670. line-height: 43rpx;
  671. }
  672. .broadcast_details_img {
  673. width: 140rpx;
  674. height: 140rpx;
  675. border-radius: 8px;
  676. overflow: hidden;
  677. position: relative;
  678. }
  679. .broadcast_details_img img {
  680. width: 100%;
  681. height: 100%;
  682. }
  683. .broadcast_details_img_no {
  684. width: 100%;
  685. height: auto;
  686. border-radius: 8px 8px 0px 0px;
  687. overflow: hidden;
  688. margin-bottom: 10rpx;
  689. }
  690. .broadcast_details_picBox_no {
  691. width: 100%;
  692. }
  693. .broadcast_details_img_no img {
  694. width: 100%;
  695. height: 100%;
  696. }
  697. .broadcast_details_tit {
  698. font-size: 28rpx;
  699. color: #333333;
  700. height: 85rpx;
  701. font-weight: 800;
  702. overflow: hidden;
  703. text-overflow: ellipsis;
  704. display: -webkit-box;
  705. -webkit-line-clamp: 2;
  706. -webkit-box-orient: vertical;
  707. text-align: left !important;
  708. }
  709. .broadcast_details_tit_no {
  710. font-size: 28rpx;
  711. color: #333333;
  712. font-weight: 800;
  713. text-align: left;
  714. margin-top: 5rpx;
  715. }
  716. .broadcast_details_picBox {
  717. width: 75%;
  718. margin-left: 24rpx;
  719. }
  720. .broadcast_details_pic {
  721. font-size: 36rpx;
  722. color: $theme-color;
  723. text-align: left;
  724. }
  725. .broadcast_details_pic_num {
  726. text-decoration: line-through;
  727. font-size: 28rpx;
  728. color: rgba(0, 0, 0, 0.5);
  729. margin-left: 0.1rem;
  730. }
  731. .broadcast_details_btn {
  732. width: 160rpx;
  733. height: 50rpx;
  734. background: #e83323;
  735. opacity: 1;
  736. border-radius: 125rpx;
  737. color: #fff;
  738. font-size: 24rpx;
  739. text-align: center;
  740. line-height: 50rpx;
  741. }
  742. .broadcast-details .chat {
  743. padding: 1rpx 23rpx 0 3rpx;
  744. margin-bottom: 3rpx;
  745. }
  746. .broadcast-details .chat .item {
  747. margin-top: 37rpx;
  748. }
  749. .broadcast-details .chat .item .pictrue {
  750. width: 80rpx;
  751. height: 80rpx;
  752. margin-top: 10rpx;
  753. }
  754. .broadcast-details .chat .item .pictrue img {
  755. width: 100%;
  756. height: 100%;
  757. border-radius: 50%;
  758. }
  759. .broadcast-details .chat .item .text {
  760. margin-left: 20rpx;
  761. }
  762. .broadcast-details .chat .item .text.textR {
  763. text-align: right;
  764. margin: 0 20rpx 0 0;
  765. }
  766. .broadcast-details .chat .item .text .name {
  767. font-size: 24rpx;
  768. color: #999;
  769. }
  770. .broadcast-details .chat .item .text .name .return {
  771. color: #509efb;
  772. margin-left: 17rpx;
  773. }
  774. .broadcast-details .chat .item .text.textR .name .return {
  775. margin: 0 0.17rem 0 0;
  776. }
  777. .broadcast-details .chat .item .text .conter {
  778. background-color: #fff;
  779. border-radius: 8rpx;
  780. padding: 16rpx 20rpx;
  781. font-size: 30rpx;
  782. color: #333;
  783. position: relative;
  784. max-width: 496rpx;
  785. margin-top: 2rpx;
  786. }
  787. .broadcast-details .chat .item .text .spot {
  788. width: 15rpx;
  789. height: 15rpx;
  790. background-color: #c00000;
  791. border-radius: 50%;
  792. margin-left: 20rpx;
  793. }
  794. .broadcast-details .chat .item .text .conter:before {
  795. position: absolute;
  796. content: "";
  797. width: 0;
  798. height: 0;
  799. border-bottom: 9rpx solid transparent;
  800. border-right: 14rpx solid #fff;
  801. border-top: 9rpx solid transparent;
  802. left: -14rpx;
  803. top: 25rpx;
  804. }
  805. .broadcast-details .chat .item .text.textR .conter:before {
  806. left: unset;
  807. right: -14rpx;
  808. transform: rotateY(180deg);
  809. }
  810. .broadcast-details .chat .item .text .conter img {
  811. width: 100%;
  812. display: block;
  813. }
  814. .broadcast-details .chat .item .text .conter .signal {
  815. width: 48rpx;
  816. height: 48rpx;
  817. }
  818. .broadcast-details .chat .item .text .conter .signal.signalR {
  819. transform: rotate(180deg);
  820. -ms-transform: rotate(180deg);
  821. -webkit-transform: rotate(180deg);
  822. }
  823. .broadcast-details .footerCon {
  824. height: 100rpx;
  825. width: 100%;
  826. transition: all 0.005s cubic-bezier(0.25, 0.5, 0.5, 0.9);
  827. background-color: #fff;
  828. }
  829. .broadcast-details .footerCon.on {
  830. position: relative;
  831. top: -300rpx;
  832. transform: translate3d(0, 0, 0) !important;
  833. }
  834. .broadcast-details .footerCon .banner .swiper-slide {
  835. flex-wrap: wrap;
  836. -webkit-flex-wrap: wrap;
  837. background-color: #fff;
  838. padding-bottom: 50rpx;
  839. border-top: 1px solid #f5f5f5;
  840. }
  841. .broadcast-details .footerCon .banner .swiper-slide .emoji-outer,
  842. .swiper-slide .em {
  843. display: block;
  844. width: 50rpx;
  845. height: 50rpx;
  846. margin: 40rpx 0 0 50rpx;
  847. }
  848. .broadcast-details .footerCon .banner .swiper-container-horizontal>.swiper-pagination-bullets {
  849. bottom: 10rpx;
  850. }
  851. .broadcast-details .footerCon .slider-banner .swiper-pagination-bullet-active {
  852. background-color: #999;
  853. }
  854. .broadcast-details .recording {
  855. width: 300rpx;
  856. height: 300rpx;
  857. position: fixed;
  858. top: 40%;
  859. left: 50%;
  860. margin-left: -150rpx;
  861. }
  862. .broadcast-details .recording img {
  863. width: 100%;
  864. height: 100%;
  865. }
  866. .broadcast-details .footer {
  867. width: 100%;
  868. background-color: #fff;
  869. padding: 17rpx 26rpx;
  870. }
  871. .broadcast-details .footer img {
  872. width: 61rpx;
  873. height: 60rpx;
  874. display: block;
  875. }
  876. .broadcast-details .footer .input,
  877. .broadcast-details .footer .voice {
  878. width: 440rpx;
  879. border-radius: 10rpx;
  880. background-color: #e5e5e5;
  881. /* padding: 17rpx 30rpx; */
  882. height: 60rpx;
  883. padding-left: 20rpx;
  884. }
  885. .input {}
  886. .broadcast-details .footer .input {
  887. max-height: 150rpx;
  888. overflow-y: auto;
  889. overflow-x: hidden;
  890. }
  891. .broadcast-details .footer .send {
  892. width: 70rpx;
  893. text-align: center;
  894. height: 60rpx;
  895. line-height: 60rpx;
  896. font-weight: bold;
  897. }
  898. .em {
  899. display: inline-block;
  900. width: 50rpx;
  901. height: 50rpx;
  902. margin: 40rpx 0 0 50rpx;
  903. }
  904. .emoji-outer {
  905. position: absolute;
  906. right: 50rpx;
  907. bottom: 30rpx;
  908. width: 50rpx;
  909. height: 50rpx;
  910. }
  911. .broadcast-details {
  912. display: flex;
  913. flex-direction: column;
  914. width: 100%;
  915. overflow: hidden;
  916. .hd-wrapper {
  917. flex: 1;
  918. display: flex;
  919. flex-direction: column;
  920. overflow: hidden;
  921. &.on{
  922. padding-bottom: 300rpx;
  923. }
  924. }
  925. }
  926. </style>