customerService.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859
  1. <template>
  2. <view class="customer-service-page">
  3. <!-- 顶部栏 -->
  4. <!-- 顶部导航栏 -->
  5. <view class="custom-navbar">
  6. <view class="navbar-left">
  7. <text class="fa fa-angle-left" @click="goBack"></text>
  8. <view class="navbar-title one-omit">
  9. 时间是一种解药时间是一种解药时间是一种解药时间是一种解药时间是一种解药
  10. </view>
  11. </view>
  12. <view class="navbar-right" @click="toggleDropdown">
  13. <image src="@/static/icon/more2.png" style="width: 64rpx; height: 64rpx; margin-top: 15rpx"
  14. mode="widthFix"></image>
  15. <view class="dropdown-menu" v-if="showDropdown">
  16. <view class="dropdown-item" @tap="handleOption('report')">举报内容</view>
  17. </view>
  18. </view>
  19. </view>
  20. <!-- 聊天内容区 -->
  21. <scroll-view class="cs-chat-list" :scroll-y="true" :scroll-with-animation="true"
  22. :scroll-into-view="scrollToView" :style="{
  23. paddingBottom: (keyboardHeight ? keyboardHeight + 100 : 100) + 'rpx',
  24. }">
  25. <view v-for="(msg, idx) in chatList" :key="msg.id">
  26. <view v-if="shouldShowTime(idx)" class="cs-time-bar">
  27. <view class="cs-time-inner">{{ formatTime(msg.time) }}</view>
  28. </view>
  29. <template v-if="msg.type === 'orderCard'">
  30. <view class="cs-msg-order-card-box">
  31. <image class="order-card-avatar" :src="msg.avatar" />
  32. <view class="cs-msg-order-card">
  33. <image class="order-card-img" :src="msg.order.img" mode="aspectFill" />
  34. <view class="order-card-info">
  35. <view class="order-card-title">{{ msg.order.title }}</view>
  36. <view class="order-card-row">
  37. <text class="order-card-label">订单编号</text>
  38. <text class="order-card-value">{{ msg.order.orderNo }}</text>
  39. </view>
  40. <view class="order-card-row">
  41. <text class="order-card-label">下单时间</text>
  42. <text class="order-card-value">{{
  43. msg.order.orderTime
  44. }}</text>
  45. </view>
  46. <view class="order-card-btn-box">
  47. <button class="order-card-btn">查看详情</button>
  48. </view>
  49. </view>
  50. </view>
  51. </view>
  52. </template>
  53. <template v-else>
  54. <view :id="'msg-' + msg.id" :class="[
  55. 'cs-msg-item',
  56. msg.type === 'user' ? 'cs-msg-self' : 'cs-msg-other',
  57. ]">
  58. <image class="cs-avatar" :src="msg.avatar" />
  59. <view class="cs-msg-bubble">{{ msg.content }}</view>
  60. </view>
  61. </template>
  62. </view>
  63. <view style="height: 200rpx; width: 100%"></view>
  64. <view :id="'bottom-anchor'"></view>
  65. <view v-if="adShow" :style="{ height: orderCardHeight + 'rpx' }"></view>
  66. </scroll-view>
  67. <!-- 底部输入栏 -->
  68. <view class="cs-input-bar" :style="{ bottom: keyboardHeight + 'rpx' }">
  69. <!-- 广告条 -->
  70. <view class="order-card" v-if="adShow">
  71. <view class="order-card-header">
  72. <image class="order-card-img" src="/static/crowdFunding/top-img.png" mode="aspectFill" />
  73. <view class="order-card-info">
  74. <view class="order-card-title one-omit">【Woh】灯塔 塔罗牌 治愈风泛伟特系</view>
  75. <view class="order-card-btn-box">
  76. <button class="order-card-btn" @click="sendOrderCardMsg()">
  77. 发给客服
  78. </button>
  79. </view>
  80. </view>
  81. <image class="order-card-close" @click="closeOrderCard" src="@/static/icon/wd_icon_guanbi.png"
  82. mode="widthFix"></image>
  83. </view>
  84. <view class="order-card-row">
  85. <text class="order-card-label">订单编号</text>
  86. <text class="order-card-value">12201544521215415415415</text>
  87. </view>
  88. <view class="order-card-row">
  89. <text class="order-card-label">下单时间</text>
  90. <text class="order-card-value">2025-05-27 09:35:30</text>
  91. </view>
  92. </view>
  93. <view class="cs-input-area">
  94. <textarea class="cs-textarea" v-model="inputValue" placeholder="在这里输入新消息" :focus="inputFocused"
  95. :adjust-position="false" @focus="onInputFocus" @blur="onInputBlur"
  96. @keyboardheightchange="onKeyboardHeightChange" maxlength="300" auto-height
  97. :style="{ 'max-height': '120rpx', 'overflow-y': 'auto' }"></textarea>
  98. <view class="emoji-trigger" @tap="toggleEmojiPanel">
  99. <text class="fa fa-smile-o"></text>
  100. </view>
  101. <view class="send_btn" @tap="sendMsg">发送</view>
  102. </view>
  103. </view>
  104. <view class="emoji-panel" :class="{ show: showEmojiPanel }" v-if="showEmojiPanel">
  105. <view class="emoji-grid">
  106. <view class="emoji-item" v-for="(emoji, index) in emojiList" :key="index" @tap="selectEmoji(emoji)">
  107. {{ emoji }}
  108. </view>
  109. </view>
  110. </view>
  111. </view>
  112. </template>
  113. <script>
  114. export default {
  115. data() {
  116. return {
  117. chatList: [
  118. {
  119. id: 1,
  120. content: "哈哈哈哈哈哈哈哈红红火火恍恍惚惚",
  121. type: "customerService",
  122. avatar: "/static/home/avator.png",
  123. time: "2025-05-21 20:01",
  124. },
  125. {
  126. id: 2,
  127. content: "哈哈哈哈哈哈哈哈红红火火恍恍惚惚",
  128. type: "customerService",
  129. avatar: "/static/home/avator.png",
  130. time: "2025-05-21 20:05",
  131. },
  132. {
  133. id: 3,
  134. content: "你好请问可以怎么帮助你",
  135. type: "user",
  136. avatar: "/static/makedetail/characterProfilePicture.png",
  137. time: "2025-05-21 20:10",
  138. },
  139. {
  140. id: 4,
  141. content:
  142. "哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚",
  143. type: "user",
  144. avatar: "/static/makedetail/characterProfilePicture.png",
  145. time: "2025-05-21 20:10",
  146. },
  147. {
  148. id: 5,
  149. content: "哈哈哈哈哈哈哈哈红红火火恍恍惚惚",
  150. type: "customerService",
  151. avatar: "/static/home/avator.png",
  152. time: "2025-05-21 20:01",
  153. },
  154. {
  155. id: 6,
  156. content: "哈哈哈哈哈哈哈哈红红火火恍恍惚惚",
  157. type: "customerService",
  158. avatar: "/static/home/avator.png",
  159. time: "2025-05-21 20:05",
  160. },
  161. {
  162. id: 7,
  163. content: "哈哈哈哈哈哈哈哈红红火火恍恍惚惚",
  164. type: "customerService",
  165. avatar: "/static/home/avator.png",
  166. time: "2025-05-21 20:01",
  167. },
  168. {
  169. id: 8,
  170. content:
  171. "哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈红红火火恍恍惚惚",
  172. type: "customerService",
  173. avatar: "/static/home/avator.png",
  174. time: "2025-05-21 20:05",
  175. },
  176. {
  177. id: 9,
  178. content: "你好请问可以怎么帮助你",
  179. type: "user",
  180. avatar: "/static/makedetail/characterProfilePicture.png",
  181. time: "2025-05-21 21:10",
  182. },
  183. {
  184. id: 13,
  185. content: "你好请问可以怎么帮助你",
  186. type: "user",
  187. avatar: "/static/makedetail/characterProfilePicture.png",
  188. time: "2025-05-21 20:10",
  189. },
  190. {
  191. id: 10,
  192. content: "哈哈哈哈哈哈哈哈红红火火恍恍惚惚",
  193. type: "customerService",
  194. avatar: "/static/home/avator.png",
  195. time: "2025-05-21 20:01",
  196. },
  197. {
  198. id: 11,
  199. content: "哈哈哈哈哈哈哈哈红红火火恍恍惚惚",
  200. type: "customerService",
  201. avatar: "/static/home/avator.png",
  202. time: "2025-05-21 23:05",
  203. },
  204. ],
  205. inputValue: "",
  206. pollTimer: null,
  207. scrollToView: "bottom-anchor",
  208. adShow: true,
  209. keyboardHeight: 0,
  210. inputFocused: false,
  211. orderCardHeight: 260, // rpx,实际高度可根据广告条内容微调
  212. showEmojiPanel: false,
  213. showDropdown: false, // 控制下拉菜单显示状态
  214. emojiList: ["😀", "😁", "😂", "🤣", "😃", "😄", "😅", "😆", "😉", "😊", "😋", "😎", "😍", "😘", "🥰", "😗", "😙", "😚", "🙂", "🤗", "🤩", "🤔", "🤨", "😐", "😑", "😶", "🙄", "😏", "😣", "😥", "😮", "🤐", "😯", "😪", "😫", "🥱", "😴", "😌", "😛", "😜", "😝", "🤤", "😒", "😓", "😔", "😕", "🙃", "🤑", "😲", "☹️", "🙁", "😖", "😞", "😟", "😤", "😢", "😭", "😦", "😧", "😨", "😩", "🤯", "😬", "😰", "😱", "🥵", "🥶", "😳", "🤪", "😵", "😡", "😠", "🤬", "😷", "🤒", "🤕", "🤢", "🤮", "🥴", "😇", "🥳", "🥺", "🤠", "😈", "👿", "👹", "👺", "💀", "👻", "👽", "🤖", "💩", "😺", "😸", "😹", "😻", "😼", "😽", "🙀", "😿", "😾", "🙈", "🙉", "🙊", "💋", "💌", "💘", "💝", "💖", "💗", "💓", "💞", "💕", "💟", "❣️", "💔", "❤️", "🧡", "💛", "💚", "💙", "💜", "🤎", "🖤", "🤍", "💯", "💢", "💥", "💫", "💦", "💨", "🕳️", "💣", "💬", "👋", "🤚", "🖐️", "✋", "🖖", "👌", "🤏", "✌️", "🤞", "🤟", "🤘", "🤙", "👈", "👉", "👆", "🖕", "👇", "☝️", "👍", "👎", "✊", "👊", "🤛", "🤜", "👏", "🙌", "👐", "🤲", "🙏", "✍️", "💅", "🤳", "💪", "🦾", "🦵", "🦶", "👂", "👃", "🧠", "🦷", "🦴", "👀", "👁️", "👅", "👄",
  215. ],
  216. };
  217. },
  218. onShow() {
  219. this.startPolling();
  220. },
  221. onHide() {
  222. this.clearPolling();
  223. },
  224. onUnload() {
  225. this.clearPolling();
  226. },
  227. methods: {
  228. goBack() {
  229. uni.navigateBack();
  230. },
  231. // 轮询获取消息
  232. startPolling() {
  233. this.clearPolling();
  234. this.pollTimer = setInterval(this.fetchMessages, 30000);
  235. this.fetchMessages();
  236. },
  237. clearPolling() {
  238. if (this.pollTimer) {
  239. clearInterval(this.pollTimer);
  240. this.pollTimer = null;
  241. }
  242. },
  243. fetchMessages() {
  244. // TODO: 替换为实际接口获取消息的接口
  245. // uni.request({ ... })
  246. // 假设新消息加入chatList
  247. // this.chatList.push(...)
  248. // 滚动到底部
  249. this.$nextTick(() => {
  250. this.scrollToView = "bottom-anchor";
  251. });
  252. },
  253. sendMsg() {
  254. if (!this.inputValue.trim()) return;
  255. this.chatList.push({
  256. id: Date.now(),
  257. content: this.inputValue,
  258. type: "user",
  259. avatar: "/static/avatar/cs2.png",
  260. });
  261. this.inputValue = "";
  262. this.$nextTick(() => {
  263. this.scrollToView = "bottom-anchor";
  264. });
  265. // TODO: 发送消息到后端接口
  266. },
  267. closeOrderCard() {
  268. this.adShow = false;
  269. },
  270. shouldShowTime(idx) {
  271. if (idx === 0) return true;
  272. // 找到上一个显示时间条的消息
  273. let lastShowIdx = -1;
  274. for (let i = idx - 1; i >= 0; i--) {
  275. if (this.shouldShowTime(i)) {
  276. lastShowIdx = i;
  277. break;
  278. }
  279. }
  280. if (lastShowIdx === -1) return true;
  281. const curTime = new Date(
  282. this.chatList[idx].time.replace(/-/g, "/")
  283. ).getTime();
  284. const lastTime = new Date(
  285. this.chatList[lastShowIdx].time.replace(/-/g, "/")
  286. ).getTime();
  287. // 20分钟 = 20*60*1000 毫秒
  288. return curTime - lastTime > 20 * 60 * 1000;
  289. },
  290. formatTime(timeStr) {
  291. // 例:'2025-05-21 20:01' => '05月21日 20:01'
  292. if (!timeStr) return "";
  293. const d = new Date(timeStr.replace(/-/g, "/"));
  294. const MM = String(d.getMonth() + 1).padStart(2, "0");
  295. const DD = String(d.getDate()).padStart(2, "0");
  296. const hhmm = timeStr.slice(11, 16);
  297. return `${MM}月${DD}日 ${hhmm}`;
  298. },
  299. onInputFocus(e) {
  300. this.inputFocused = true;
  301. },
  302. onInputBlur(e) {
  303. this.inputFocused = false;
  304. this.keyboardHeight = 0;
  305. },
  306. px2rpx(px) {
  307. // 以750设计稿为例,1rpx = 屏幕宽度/750
  308. const screenWidth = uni.getSystemInfoSync().windowWidth;
  309. return (px * 750) / screenWidth;
  310. },
  311. onKeyboardHeightChange(e) {
  312. let pxHeight = e.detail ? e.detail.height : e.height || 0;
  313. // #ifdef H5 || APP-PLUS
  314. this.keyboardHeight = this.px2rpx(pxHeight);
  315. // #endif
  316. // #ifdef MP-WEIXIN
  317. this.keyboardHeight = pxHeight; // 小程序下直接用rpx
  318. // #endif
  319. },
  320. toggleEmojiPanel() {
  321. this.inputFocused = false;
  322. setTimeout(() => {
  323. this.showEmojiPanel = !this.showEmojiPanel;
  324. }, 100);
  325. },
  326. selectEmoji(emoji) {
  327. this.inputValue += emoji;
  328. this.showEmojiPanel = false;
  329. },
  330. sendOrderCardMsg() {
  331. this.chatList.push({
  332. id: Date.now(),
  333. type: "orderCard",
  334. avatar: "/static/makedetail/characterProfilePicture.png", // 用户头像
  335. order: {
  336. img: "/static/crowdFunding/top-img.png",
  337. title: "【Woh】灯塔 塔罗牌 治愈风泛伟特系",
  338. orderNo: "12201544521215415415415",
  339. orderTime: "2025-05-27 09:35:30",
  340. },
  341. time: this.getNowTime(),
  342. });
  343. this.$nextTick(() => {
  344. this.closeOrderCard();
  345. setTimeout(() => {
  346. this.scrollToView = "bottom-anchor";
  347. }, 1000);
  348. });
  349. },
  350. getNowTime() {
  351. const d = new Date();
  352. const pad = (n) => (n < 10 ? "0" + n : n);
  353. return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(
  354. d.getDate()
  355. )} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
  356. },
  357. // 切换下拉菜单显示状态
  358. toggleDropdown() {
  359. this.showDropdown = !this.showDropdown;
  360. },
  361. // 处理下拉菜单选项点击
  362. handleOption(type) {
  363. this.showDropdown = false;
  364. switch (type) {
  365. case 'report':
  366. uni.navigateTo({
  367. url: '/pages/my/feedback?isReportContent=true'
  368. });
  369. break;
  370. }
  371. },
  372. },
  373. };
  374. </script>
  375. <style lang="scss">
  376. .customer-service-page {
  377. min-height: 100vh;
  378. background: #f2f6f2;
  379. display: flex;
  380. flex-direction: column;
  381. position: relative;
  382. .custom-navbar {
  383. display: flex;
  384. flex-direction: row;
  385. align-items: center;
  386. justify-content: space-between;
  387. height: 90rpx;
  388. padding: 0 20rpx;
  389. padding-top: var(--status-bar-height);
  390. background-color: #ffffff;
  391. position: sticky;
  392. top: 0;
  393. height: calc(90rpx + var(--status-bar-height));
  394. z-index: 100;
  395. .navbar-left {
  396. height: 80rpx;
  397. display: flex;
  398. align-items: center;
  399. justify-content: center;
  400. .fa-angle-left {
  401. font-size: 48rpx;
  402. color: #333;
  403. }
  404. .navbar-title {
  405. max-width: 450rpx;
  406. font-family: "PingFang SC-Bold";
  407. font-weight: 400;
  408. font-size: 32rpx;
  409. color: #1f1f1f;
  410. padding-left: 20rpx;
  411. }
  412. }
  413. .navbar-right {
  414. width: 80rpx;
  415. height: 80rpx;
  416. display: flex;
  417. justify-content: center;
  418. align-items: center;
  419. .fa-ellipsis-h {
  420. font-size: 36rpx;
  421. color: #333;
  422. }
  423. }
  424. }
  425. .cs-chat-list {
  426. flex: 1;
  427. padding: 24rpx 0 0 0;
  428. overflow-y: auto;
  429. background: #f6f7f9;
  430. .cs-msg-item {
  431. display: flex;
  432. // align-items: flex-end;
  433. margin-bottom: 18rpx;
  434. padding: 0 24rpx;
  435. &.cs-msg-other {
  436. flex-direction: row;
  437. .cs-avatar {
  438. margin-right: 12rpx;
  439. }
  440. .cs-msg-bubble {
  441. background: #fff;
  442. color: #1f1f1f;
  443. border-top-left-radius: 0;
  444. border-top-right-radius: 12rpx;
  445. border-bottom-left-radius: 12rpx;
  446. border-bottom-right-radius: 12rpx;
  447. }
  448. }
  449. &.cs-msg-self {
  450. flex-direction: row-reverse;
  451. .cs-avatar {
  452. margin-left: 12rpx;
  453. }
  454. .cs-msg-bubble {
  455. background: #e6f6d9;
  456. color: #1f1f1f;
  457. border-top-right-radius: 0;
  458. border-top-left-radius: 12rpx;
  459. border-bottom-left-radius: 12rpx;
  460. border-bottom-right-radius: 12rpx;
  461. }
  462. }
  463. .cs-avatar {
  464. width: 64rpx;
  465. height: 64rpx;
  466. border-radius: 50%;
  467. }
  468. .cs-msg-bubble {
  469. max-width: 70vw;
  470. min-height: 40rpx;
  471. font-size: 28rpx;
  472. padding: 18rpx 24rpx;
  473. word-break: break-all;
  474. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
  475. margin-bottom: 2rpx;
  476. display: flex;
  477. align-items: center;
  478. }
  479. }
  480. .cs-time-bar {
  481. display: flex;
  482. justify-content: center;
  483. align-items: center;
  484. margin: 18rpx 0 12rpx 0;
  485. .cs-time-inner {
  486. background: #fff;
  487. color: #b2b2b2;
  488. font-size: 24rpx;
  489. border-radius: 16rpx;
  490. padding: 8rpx 24rpx;
  491. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
  492. display: inline-block;
  493. }
  494. }
  495. }
  496. .order-card {
  497. background: #fff;
  498. border-radius: 20rpx;
  499. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
  500. padding: 24rpx 24rpx 18rpx 24rpx;
  501. margin: 24rpx;
  502. position: absolute;
  503. top: -280rpx;
  504. font-size: 28rpx;
  505. width: 670rpx;
  506. .order-card-header {
  507. display: flex;
  508. align-items: flex-start;
  509. position: relative;
  510. .order-card-img {
  511. width: 100rpx;
  512. height: 100rpx;
  513. border-radius: 12rpx;
  514. margin-right: 18rpx;
  515. flex-shrink: 0;
  516. }
  517. .order-card-info {
  518. flex: 1;
  519. display: flex;
  520. flex-direction: column;
  521. justify-content: flex-start;
  522. .order-card-title {
  523. font-size: 30rpx;
  524. color: #1f1f1f;
  525. font-weight: 500;
  526. margin-bottom: 18rpx;
  527. margin-top: 2rpx;
  528. line-height: 1.3;
  529. max-width: 450rpx;
  530. }
  531. .order-card-btn-box {
  532. display: flex;
  533. align-items: center;
  534. justify-content: flex-end;
  535. .order-card-btn {
  536. font-family: "PingFang SC-Bold";
  537. font-weight: 400;
  538. font-size: 24rpx;
  539. color: #acf934;
  540. background: #1f1f1f;
  541. border-radius: 128rpx;
  542. padding: 8rpx 14rpx;
  543. line-height: 1.2;
  544. margin: 0;
  545. }
  546. }
  547. }
  548. .order-card-close {
  549. position: absolute;
  550. right: -10rpx;
  551. top: -10rpx;
  552. font-size: 36rpx;
  553. color: #1f1f1f;
  554. background: #fff;
  555. border-radius: 50%;
  556. width: 34rpx;
  557. height: 34rpx;
  558. display: flex;
  559. align-items: center;
  560. justify-content: center;
  561. z-index: 2;
  562. }
  563. }
  564. .order-card-row {
  565. display: flex;
  566. align-items: center;
  567. margin-top: 12rpx;
  568. .order-card-label {
  569. color: #b2b2b2;
  570. font-size: 26rpx;
  571. width: 140rpx;
  572. flex-shrink: 0;
  573. }
  574. .order-card-value {
  575. color: #1f1f1f;
  576. font-size: 26rpx;
  577. margin-left: 12rpx;
  578. word-break: break-all;
  579. }
  580. }
  581. }
  582. .cs-input-bar {
  583. display: flex;
  584. align-items: center;
  585. background: #fff;
  586. padding: 12rpx 16rpx;
  587. border-top: 1rpx solid #ededed;
  588. position: fixed;
  589. left: 0;
  590. right: 0;
  591. bottom: 0;
  592. z-index: 10;
  593. .cs-input-area {
  594. display: flex;
  595. align-items: flex-end;
  596. background: #fff;
  597. border-radius: 32rpx;
  598. padding: 8rpx 12rpx;
  599. flex: 1;
  600. .cs-textarea {
  601. flex: 1;
  602. min-height: 64rpx;
  603. max-height: 120rpx;
  604. overflow-y: auto;
  605. border: none;
  606. font-size: 28rpx;
  607. background: #f6f7f9;
  608. border-radius: 24rpx;
  609. padding: 12rpx 20rpx;
  610. resize: none;
  611. }
  612. .emoji-trigger {
  613. margin: 0 12rpx;
  614. font-size: 36rpx;
  615. color: #999;
  616. display: flex;
  617. align-items: center;
  618. }
  619. .send_btn {
  620. background: #a6e22e;
  621. color: #fff;
  622. border-radius: 32rpx;
  623. font-size: 28rpx;
  624. padding: 0 32rpx;
  625. height: 64rpx;
  626. line-height: 64rpx;
  627. margin-left: 8rpx;
  628. }
  629. }
  630. }
  631. .emoji-panel {
  632. position: fixed;
  633. left: 0;
  634. right: 0;
  635. bottom: 0;
  636. max-height: 50vh;
  637. width: 100vw;
  638. background: #fff;
  639. padding: 12rpx 0 0 0;
  640. border-top: 1rpx solid #ededed;
  641. z-index: 1000;
  642. box-shadow: 0 -4rpx 24rpx rgba(0, 0, 0, 0.08);
  643. overflow-y: auto;
  644. transform: translateY(100%);
  645. transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  646. border-top: 20rpx solid #fff;
  647. &.show {
  648. transform: translateY(0);
  649. }
  650. .emoji-grid {
  651. display: flex;
  652. flex-wrap: wrap;
  653. justify-content: center;
  654. padding-bottom: 24rpx;
  655. .emoji-item {
  656. width: 60rpx;
  657. height: 60rpx;
  658. display: flex;
  659. align-items: center;
  660. justify-content: center;
  661. font-size: 36rpx;
  662. color: #333;
  663. margin: 8rpx;
  664. border-radius: 8rpx;
  665. padding: 8rpx;
  666. }
  667. }
  668. }
  669. .cs-msg-order-card-box {
  670. display: flex;
  671. flex-direction: row-reverse;
  672. .order-card-avatar {
  673. width: 64rpx;
  674. height: 64rpx;
  675. border-radius: 50%;
  676. margin-left: 12rpx;
  677. margin-right: 24rpx;
  678. }
  679. .cs-msg-order-card {
  680. position: relative;
  681. display: flex;
  682. flex-direction: row;
  683. align-items: flex-start;
  684. background: #fff;
  685. border-radius: 20rpx;
  686. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
  687. padding: 24rpx 24rpx 18rpx 24rpx;
  688. margin: 24rpx 0 0 0;
  689. width: 600rpx;
  690. min-height: 160rpx;
  691. .order-card-img {
  692. width: 100rpx;
  693. height: 100rpx;
  694. border-radius: 12rpx;
  695. margin-right: 18rpx;
  696. flex-shrink: 0;
  697. }
  698. .order-card-info {
  699. flex: 1;
  700. display: flex;
  701. flex-direction: column;
  702. justify-content: flex-start;
  703. .order-card-title {
  704. font-size: 30rpx;
  705. color: #1f1f1f;
  706. font-weight: 500;
  707. margin-bottom: 18rpx;
  708. margin-top: 2rpx;
  709. line-height: 1.3;
  710. max-width: 350rpx;
  711. word-break: break-all;
  712. }
  713. .order-card-btn-box {
  714. display: flex;
  715. align-items: center;
  716. justify-content: flex-end;
  717. margin-top: 12rpx;
  718. .order-card-btn {
  719. font-family: "PingFang SC-Bold";
  720. font-weight: 400;
  721. font-size: 24rpx;
  722. color: #1f1f1f;
  723. background: #acf934;
  724. border-radius: 128rpx;
  725. padding: 8rpx 24rpx;
  726. line-height: 1.2;
  727. margin: 0;
  728. }
  729. }
  730. }
  731. .order-card-row {
  732. display: flex;
  733. align-items: center;
  734. margin-top: 8rpx;
  735. .order-card-label {
  736. color: #b2b2b2;
  737. font-size: 26rpx;
  738. width: 140rpx;
  739. flex-shrink: 0;
  740. }
  741. .order-card-value {
  742. color: #1f1f1f;
  743. font-size: 26rpx;
  744. margin-left: 12rpx;
  745. word-break: break-all;
  746. }
  747. }
  748. }
  749. }
  750. .dropdown-menu {
  751. position: absolute;
  752. top: calc(100% + 10rpx);
  753. right: 20rpx;
  754. background-color: #ffffff;
  755. border-radius: 20rpx;
  756. padding: 0;
  757. width: 200rpx;
  758. box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
  759. z-index: 100;
  760. transform-origin: top right;
  761. animation: dropdownAnimation 0.2s ease-out;
  762. overflow: hidden;
  763. .dropdown-item {
  764. padding: 24rpx 0;
  765. color: #333333;
  766. font-size: 28rpx;
  767. position: relative;
  768. text-align: center;
  769. &:not(:last-child)::after {
  770. content: '';
  771. position: absolute;
  772. left: 0;
  773. right: 0;
  774. bottom: 0;
  775. height: 1rpx;
  776. background-color: #EEEEEE;
  777. }
  778. &:active {
  779. background-color: #f8f8f8;
  780. }
  781. }
  782. }
  783. @keyframes dropdownAnimation {
  784. 0% {
  785. opacity: 0;
  786. transform: scale(0.95) translateY(-5rpx);
  787. }
  788. 100% {
  789. opacity: 1;
  790. transform: scale(1) translateY(0);
  791. }
  792. }
  793. }
  794. </style>