You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

1115 lines
30 KiB

<!-- 客服 -->
<template>
<view class="chat-wrap">
<!-- 标题栏 -->
<shopro-navbar
:background="{
backgroundImage: 'linear-gradient(45deg, #9000ff, #5e00ff)',
color: '#FFF'
}"
backIconColor="#fff"
>
<view class="u-flex u-col-bottom head-box" slot="content">
<view class="head-title u-m-r-20">{{ navTitle.split(',')[0] }}</view>
<view v-show="navTitle.split(',')[1] === '在线'" class="u-flex u-col-center">
<view class="iconfont icon-yuandianxiao text-green head-icon"></view>
<view class="head-state">在线</view>
</view>
<view v-show="navTitle.split(',')[1] === '离线'" class="u-flex u-col-center">
<view class="iconfont icon-yuandianxiao text-gray head-icon"></view>
<view class="head-state">离线</view>
</view>
</view>
</shopro-navbar>
<!-- 提示 -->
<u-notice-bar
:autoplay="true"
close-icon
@close="closeNotice"
:show="showNotice"
:type="noticeType"
:list="noticeList"
:volumeIcon="true"
:isCircular="true"
></u-notice-bar>
<scroll-view class="scroll-box" scroll-y="true" :scroll-with-animation="false" :enable-back-to-top="true" :show-scrollbar="false" :scroll-into-view="scrollInto">
<u-loadmore v-if="logmsgList.length" :status="logStatus" :loadText="loadText" icon-type="circle" @loadmore="logLoadmore" />
<view class="cu-chat">
<block v-for="(chat, index) in chatList" :key="index">
<!-- 系统消息-->
<view class="cu-info" v-if="chat.type === 'system'">{{ chat.msg }}</view>
<view class="cu-info" v-if="showTime(chat.date, index) && chat.type !== 'system' && chat.type !== 'template'">{{ $u.timeFrom(chat.date) }}</view>
<view class="" v-if="chat.type !== 'system' && chat.type !== 'template'">
<!-- 自己 -->
<view class="cu-item" :class="{ self: chat.identify === 'user' }">
<view
v-if="chat.identify !== 'user'"
class="cu-avatar round"
:style="'background-image:url(' + (chat.server_avatar ? chat.server_avatar : $IMG_URL + '/imgs/chat/default-chat-avatar.png') + ')'"
></view>
<view class="main">
<!-- 消息 -->
<view class="content " style="max-width: 480rpx;" :class="chat.identify !== 'user' ? 'bg-white' : ' bg-gradual-purple'" v-if="chat.type === 'text'">
<u-parse :html="chat.msg"></u-parse>
</view>
<!-- 订单 -->
<view class="content " v-if="chat.type === 'order'" @tap="jump('/pages/order/detail', { id: chat.msg.id })">
<view class="order-chat">
<view class="order-code u-m-b-20">订单号:{{ chat.msg.order_sn }}</view>
<view class="goods-card u-flex u-col-center">
<view class="img-wrap"><image class="goods-img" :src="chat.msg.image" mode=""></image></view>
<view class="u-flex-col u-row-between card-right">
<view class="goods-title u-ellipsis-2">{{ chat.msg.title }}</view>
<view class="u-flex u-col-center price-box">
<view class="goods-price">{{ chat.msg.price }}</view>
<text class="goods-state u-m-l-10">{{ chat.msg.status_name }}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 商品 -->
<view class="content " v-if="chat.type === 'goods'" @tap="jump('/pages/goods/detail', { id: chat.msg.id })">
<view class="goods-card u-flex u-col-center">
<view class="img-wrap"><image class="goods-img" :src="chat.msg.image" mode=""></image></view>
<view class="u-flex-col u-row-between card-right">
<view class="goods-title u-ellipsis-2">{{ chat.msg.title }}</view>
<view class="u-flex u-row-between price-box">
<view class="goods-price">{{ chat.msg.price }}</view>
<text></text>
</view>
</view>
</view>
</view>
</view>
<view v-if="chat.identify === 'user'" class="cu-avatar round" :style="'background-image:url(' + userInfo.avatar + ')'"></view>
</view>
</view>
<!-- 模板消息 -->
<view class="template-box u-m-y-20" v-if="chat.type === 'template'">
<view class="template-title">猜你想问</view>
<view class="template-item" v-for="item in templateList" :key="item.id" @tap="onQuestion(item)">* {{ item.title }}</view>
</view>
</block>
</view>
<view class="scroll-bottom" style="height: 330rpx;" id="scrollBottom"></view>
</scroll-view>
<!-- 底部功能栏,输入栏 -->
<view class="cu-bar foot input u-flex-col">
<!-- 输入栏 -->
<view class="cu-bar u-flex-1" style="width: 100%;">
<view class="input-wrap u-flex-1 u-flex u-col-center u-m-r-20 u-p-l-20">
<input
class="input"
v-model="msgText"
placeholder-style="font-size:26rpx;color:#999"
placeholder="请输入您想咨询的问题~"
type="text"
confirm-type="发送"
:focus="false"
maxlength="300"
cursor-spacing="10"
@focus="InputFocus"
@blur="InputBlur"
@input="onInput"
@confirm="onSend"
/>
<view class="action u-p-10" @tap="selEmoji"><text class="iconfont icon-biaoqing text-grey"></text></view>
</view>
<button v-if="isFocus" class="u-reset-button send-btn shadow" @tap.stop="onSend">发送</button>
<button v-else class="u-reset-button more-btn" @tap.stop="onTools">
<view class="action" style="margin-right: 0;"><text class="iconfont icon-tianjia text-grey" :class="{ 'tools-active': showTools }"></text></view>
</button>
</view>
<!-- 工具栏 -->
<view class="tools-box u-flex" style="width: 100%;" v-if="showTools">
<u-upload
:showProgress="false"
:showUploadList="false"
@on-uploaded="uploadSuccess"
@on-change="uploadChange"
:action="`${EMOJI_BASE_URL}/api/common/upload`"
:header="{token: token}"
maxCount="9"
:customBtn="true"
:show-tips="false"
class="u-flex-1 tools-item"
>
<view class="tools-item u-flex-1" slot="addBtn">
<image class="item-img" :src="$IMG_URL + '/imgs/chat/imgs_icon.png'" mode=""></image>
<text class="item-title">图片</text>
</view>
</u-upload>
<view class="tools-item u-flex-1" @tap="onToolItem('goods')">
<image class="item-img" :src="$IMG_URL + '/imgs/chat/goods_icon.png'" mode=""></image>
<text class="item-title">商品</text>
</view>
<view class="tools-item u-flex-1" @tap="onToolItem('order')">
<image class="item-img" :src="$IMG_URL + '/imgs/chat/order_icon.png'" mode=""></image>
<text class="item-title">订单</text>
</view>
</view>
<!-- 表情栏 -->
<view class="emoji-box" v-if="showEmoji">
<swiper
class="emoji-swiper"
:indicator-dots="true"
circular
indicator-active-color="#7063D2"
indicator-color="rgba(235, 231, 255, 1)"
:autoplay="false"
:interval="3000"
:duration="1000"
>
<swiper-item v-for="(memoji, index) in newEmojiList" :key="index">
<view class="swiper-item u-flex u-col-center">
<view class="emoji-img" v-for="(memo, mindex) in memoji" :key="memo.file" @tap="onEmoji(memo)">
<image class="emoji-img" :src="`${EMOJI_BASE_URL}/assets/addons/shopro/img/emoji/${memo.file}`" mode=""></image>
</view>
</view>
</swiper-item>
</swiper>
</view>
</view>
<!-- 商品/订单 -->
<view class="cu-bar log-box foot input u-flex-col" v-if="showLogBox">
<view class="log-head u-flex u-row-between">
<view class="title-box">{{ logTitle }}</view>
<button class="u-reset-button close-btn" @tap="closeToolsItem"><text class="u-iconfont uicon-close-circle-fill" style="#e0e0e0;font-size: 36rpx;"></text></button>
</view>
<view class="log-content">
<scroll-view class="card-scroll-box" scroll-y="true" :scroll-with-animation="true" :show-scrollbar="false" @scrolltolower="loadMore">
<!-- 订单 -->
<view class="log-item" v-for="(item, index) in orderList" :key="index" @tap="onOrderCard(item)" v-if="cardType === 'order'">
<view class="code-box u-flex u-row-between">
<view class="code-text">订单号:{{ item.order_sn }}</view>
<view class="date-text">{{ $u.timeFormat(item.createtime, 'mm-dd hh:MM') }}</view>
</view>
<view class="u-flex log-card">
<view class="img-wrap"><image class="goods-img" :src="item.item[0].goods_image" mode=""></image></view>
<view class="u-flex-col card-right">
<view class="goods-title u-ellipsis-2">{{ item.item[0].goods_title }}</view>
<view class="num-box">数量:{{ item.item[0].goods_num }}</view>
<view class="u-flex u-row-between price-box">
<view class="goods-price">{{ item.item[0].goods_price }}</view>
<text class="goods-state">{{ item.status_name }}</text>
</view>
</view>
</view>
</view>
<!-- 商品 -->
<view class="log-item" v-for="(item, index) in viewList" :key="index" @tap="onViewCard(item)" v-if="cardType === 'goods'">
<view class="u-flex log-card">
<view class="img-wrap"><image class="goods-img" :src="item.goods.image" mode=""></image></view>
<view class="u-flex-col u-row-between card-right">
<view class="goods-title u-ellipsis-2">{{ item.goods.title }}</view>
<view class="num-box">{{ item.goods.subtitle }}</view>
<view class="u-flex u-row-between price-box">
<view class="goods-price">{{ item.goods.price }}</view>
<text class="goods-state"></text>
</view>
</view>
</view>
</view>
<u-loadmore height="80rpx" :status="loadStatus" icon-type="flower" color="#ccc" />
</scroll-view>
</view>
</view>
<!-- 遮罩 -->
<view class="cu-modal" @tap="onMask" :class="{ show: showTools || showEmoji }" style="z-index: 1000;"></view>
</view>
</template>
<script>
import Socket from './chat.js';
import { BASE_URL, API_URL } from '@/env.js';
import { mapMutations, mapActions, mapState, mapGetters } from 'vuex';
export default {
data() {
return {
socket: null, //socket服务
InputBottom: 0,
isPageHide: false,
HTTP_API_URL: API_URL,
EMOJI_BASE_URL: BASE_URL,
navTitle: '连接中...', //标题栏
scrollInto: '', //scrollBottom
lastId: '', //加载历史聊天记录用
logmsgList: [], //历史消息
templateList: [], //模板问题。
emojiList: [], //表情包
newEmojiList: [], //分层后的表情数据
loadText: {
loadmore: '点击加载更多',
loading: '正在加载,请喝杯茶...',
nomore: '我也是有底线的'
},
logStatus: 'loadmore',
cardType: '', //卡片分类
currentPage: 1,
lastPage: 1,
chatList: [
// identify: 'customer_service', // 用户发送的为 user; 客服发送的为 customer_service
// type: 'text', //message:用户消息类型; message_list:请求消息列表
// msg: message.message,
// date: this.$u.timeFormat(message.createtime, 'yyyy年mm月dd日 hh时MM分')
],
msgText: '', //输入框内容
showNotice: true, //滚动提示
noticeType: 'warning',
showTools: false, //工具栏显示
showLogBox: false, //商品订单栏
showEmoji: false, //表情显示
logTitle: '', //;栏目标题
toolsList: [
//工具栏列表
{
id: 'imgs',
image: this.$IMG_URL + '/imgs/chat/imgs_icon.png',
title: '图片'
},
{
id: 'goods',
image: this.$IMG_URL + '/imgs/chat/goods_icon.png',
title: '商品'
},
{
id: 'order',
image: this.$IMG_URL + '/imgs/chat/order_icon.png',
title: '订单'
},
{
id: 'file',
image: this.$IMG_URL + '/imgs/chat/file_icon.png',
title: '文件'
}
],
noticeList: [], //跑马灯提示。
// 订单商品,分页。
loadStatus: 'loadmore', //loadmore-加载前的状态,loading-加载中的状态,nomore-没有更多的状态
orderList: [],
viewList: [],
orderCurrentPage: 1,
viewCurrentPage: 1,
orderTotalPage: 1,
viewTotalPage: 1,
token: uni.getStorageSync('token')
};
},
computed: {
...mapGetters(['userInfo']),
isFocus() {
//检测输入框是否有信息
let isMsg = false;
this.msgText ? (isMsg = true) : (isMsg = false);
return isMsg;
},
isClose() {
if (this.socket) {
return this.socket.isClose;
}
}
},
created() {
this.init();
},
onShow() {
// #ifdef MP-WEIXIN
this.init();
this.isPageHide = true;
// #endif
},
onHide() {
// #ifdef MP-WEIXIN
if (this.isPageHide) {
this.socket.close();
}
// #endif
uni.hideKeyboard();
},
beforeDestroy() {
this.socket.close();
},
methods: {
init() {
let that = this;
that.$http('common.chat').then(res => {
if (res.code == 1) {
that.noticeList.push(res.data.config.basic.notice);
that.templateList = res.data.question;
that.emojiList = res.data.emoji;
that.newEmojiList = this.sortData(res.data.emoji, 30);
that.socket = new Socket(
{
ping: 20000,
is_ssl: res.data.config.system.is_ssl,
gateway_port: res.data.config.system.gateway_port,
ssl_type: res.data.config.system.ssl_type
},
msg => {
that.parseMsgStatus(msg.data); //监听消息
}
);
}
});
},
// 数据分层
sortData(oArr, length) {
let arr = [];
let minArr = [];
oArr.forEach(c => {
if (minArr.length === length) {
minArr = [];
}
if (minArr.length === 0) {
arr.push(minArr);
}
minArr.push(c);
});
return arr;
},
// 时间显示
showTime(timestamp, index) {
timestamp = parseInt(timestamp);
// 判断用户输入的时间戳是秒还是毫秒,一般前端js获取的时间戳是毫秒(13位),后端传过来的为秒(10位)
if (timestamp.toString().length == 10) timestamp *= 1000;
let timer = new Date().getTime() - timestamp;
timer = parseInt(timer / 1000);
if (index % 6 == 0 && timer >= 300) {
return true;
}
},
jump(path, parmas) {
this.$Router.push({
path: path,
query: parmas
});
},
// 解析链接状态
parseMsgStatus(msgStr) {
let obj = JSON.parse(msgStr);
let chatName = '客服';
if (obj.data?.customer_service) {
chatName = obj.data.customer_service.name ? `客服-${obj.data.customer_service.name}` : '客服';
}
if (obj.code === 1) {
switch (obj.type) {
case 'init':
uni.setStorageSync('chatSessionId', obj.data.session_id);
this.chatLog().then(this.pushChat('', 'template'));
this.goBottom();
break;
case 'waiting':
this.navTitle = '暂无客服在线';
this.pushChat(obj.data.message.message, 'system');
break;
case 'access':
this.navTitle = `${chatName},在线`;
this.pushChat(obj.data.message.message, 'system');
break;
case 'customer_service_online':
this.navTitle = `${chatName},在线`;
break;
case 'customer_service_offline':
this.navTitle = `${chatName},离线`;
break;
case 'message':
this.chatList.push(this.parseMsg(obj.data.message, obj.data.message.identify));
this.goBottom();
uni.vibrateLong();
break;
case 'message_list':
let msgList = obj.data.message_list.data;
this.logmsgList = obj.data.message_list.data;
this.lastId = msgList[0]?.id;
this.lastPage = obj.data.message_list.last_page;
msgList.forEach(item => {
this.chatList.unshift(this.parseMsg(item, item.identify));
});
break;
default:
}
} else {
this.$u.toast('连接错误,正在重试~');
}
},
// 解析消息类型,接受数据时才用,发送数据时不用。
parseMsg(message, identify) {
let obj = null;
switch (message.message_type) {
case 'system':
obj = {
identify: 'customer_service', // 用户发送的为 user; 客服发送的为 customer_service
type: 'system', //message:用户消息类型; message_list:请求消息列表
msg: message.message
};
break;
case 'image':
obj = {
identify: message.sender_identify, // 用户发送的为 user; 客服发送的为 customer_service
type: 'text', //message:用户消息类型; message_list:请求消息列表
msg: `<img class="chat-img" src="${message.message}"/>`,
server_avatar: identify?.avatar,
date: message.createtime
};
break;
case 'goods':
obj = {
identify: message.sender_identify, // 用户发送的为 user; 客服发送的为 customer_service
type: message.message_type, //message:用户消息类型; message_list:请求消息列表
msg: JSON.parse(message.message),
server_avatar: identify?.avatar,
date: message.createtime
};
break;
case 'order':
obj = {
identify: message.sender_identify, // 用户发送的为 user; 客服发送的为 customer_service
type: message.message_type, //message:用户消息类型; message_list:请求消息列表
msg: JSON.parse(message.message),
server_avatar: identify?.avatar,
date: message.createtime
};
break;
case 'text':
obj = {
identify: message.sender_identify, // 用户发送的为 user; 客服发送的为 customer_service
type: message.message_type, //message:用户消息类型; message_list:请求消息列表
msg: this.replaceEmoji(message.message),
server_avatar: identify?.avatar,
date: message.createtime
};
break;
default:
break;
}
return obj;
},
// 获取历史聊天记录
async chatLog() {
let msg = {
identify: 'user', // 用户发送的为 user; 客服发送的为 customer_service
type: 'message_list', //message:用户消息类型; message_list:请求消息列表
data: {
// 额外参数,分页页码,分页条数等
page: this.currentPage, //默认
last_id: this.lastId //第一页第一条的Id
}
};
this.logStatus = 'loading';
let strMsg = JSON.stringify(msg);
let res = await this.socket.send(strMsg);
if (res && res.errMsg === 'sendSocketMessage:ok') {
setTimeout(() => {
this.logStatus = 'loadmore';
}, 300);
}
},
// 获取焦点
InputFocus(e) {
this.onMask();
},
// 失去焦点
InputBlur(e) {
this.InputBottom = 0;
},
// 输入
onInput(e) {},
// 滚动到顶部
logLoadmore() {
if (this.currentPage < this.lastPage) {
this.currentPage += 1;
this.chatLog();
} else {
this.logStatus = 'nomore';
}
},
// 点击工具栏开关
onTools() {
if (this.isClose) {
this.$u.toast('您已掉线!请返回重试');
this.noticeType = 'error';
this.noticeList = ['您已掉线!请返回重试'];
return;
}
this.showEmoji = false;
this.showTools = !this.showTools;
},
// 工具栏功能项
onToolItem(type) {
this.orderList = [];
this.viewList = [];
this.orderCurrentPage = 1;
this.viewCurrentPage = 1;
this.orderTotalPage = 1;
this.viewTotalPage = 1;
this.cardType = type;
let map = new Map();
map.set('order', () => {
this.logTitle = '我的订单';
this.showLogBox = true;
this.getOrderList();
});
map.set('goods', () => {
this.logTitle = '我的浏览';
this.showLogBox = true;
this.getbrowseList();
});
map.set('imgs', this.chooseImg);
map.get(type)();
},
// 点击商品卡片
onViewCard(goods) {
let goodsData = {
id: goods.goods.id,
title: goods.goods.title,
price: goods.goods.price,
image: goods.goods.image
};
let goodsStr = JSON.stringify(goodsData);
this.sendWs(goodsStr, 'goods');
this.pushChat(goodsData, 'goods');
this.onMask();
},
onOrderCard(order) {
let orderData = {
id: order.id,
title: order.item[0].goods_title,
price: order.item[0].goods_price,
num: order.item[0].goods_num,
order_sn: order.order_sn,
image: order.item[0].goods_image,
status_name: order.status_name
};
let orderStr = JSON.stringify(orderData);
this.sendWs(orderStr, 'order');
this.pushChat(orderData, 'order');
this.onMask();
},
// 关闭工具栏项
closeToolsItem() {
this.showLogBox = false;
},
// 选择表情
selEmoji() {
this.showTools = false;
this.showLogBox = false;
this.showEmoji = !this.showEmoji;
},
// 点击表情
onEmoji(item) {
this.msgText += item.name;
},
// 点击遮罩
onMask() {
this.showTools = false;
this.showLogBox = false;
this.showEmoji = false;
},
//关闭滚动提示
closeNotice() {
this.showNotice = false;
},
// 滚动底部
goBottom() {
let timeout = null;
this.scrollInto = '';
clearTimeout(timeout);
timeout = setTimeout(() => {
this.scrollInto = 'scrollBottom';
}, 300);
},
// 发送图片
uploadSuccess(list) {
list.forEach(item => {
this.sendWs(item.response.data.url, 'image');
this.pushChat(`<img class="chat-img" src="${item.response.data.fullurl}"/>`);
this.onMask();
});
},
uploadChange(e) {
// console.log('上传回调', e);
},
// 发送问题
async onQuestion(question) {
this.pushChat(question.title);
let msg = {
identify: 'user', // 用户发送的为 user; 客服发送的为 customer_service
type: 'message', //message:用户消息类型; message_list:请求消息列表
message: {
// 发送的消息 type 为 message 的时候必填
message_type: 'text', // 消息类型 text image 等
message: question.title // 消息内容 文本,或者图片地址,或者商品 json 对象
},
data: {
question_id: question.id
}
};
let strMsg = JSON.stringify(msg);
let res = await this.socket.send(strMsg);
},
// 发送消息
onSend() {
if (this.msgText) {
this.sendWs(this.msgText);
this.pushChat(this.msgText);
this.msgText = '';
}
this.showEmoji && this.onMask();
},
// 发送服务数据
async sendWs(data, type = 'text') {
let msg = {
identify: 'user', // 用户发送的为 user; 客服发送的为 customer_service
type: 'message', //message:用户消息类型; message_list:请求消息列表
message: {
// 发送的消息 type 为 message 的时候必填
message_type: type, // 消息类型 text image 等
message: data // 消息内容 文本,或者图片地址,或者商品 json 对象
}
};
let strMsg = JSON.stringify(msg);
let res = await this.socket.send(strMsg);
},
// 发送本地数据。
pushChat(data, type = 'text') {
if (this.isClose) {
this.$u.toast('您已掉线!请返回重试');
this.noticeType = 'error';
this.noticeList = ['您已掉线!请返回重试'];
return;
}
this.chatList.push({
identify: 'user',
type: type,
msg: this.replaceEmoji(data),
date: new Date().getTime()
});
this.goBottom();
},
// 表情地址
selEmojiFile(name) {
for (let index in this.emojiList) {
if (this.emojiList[index].name === name) {
return this.emojiList[index].file;
}
}
return false;
},
// 替换表情
replaceEmoji(data) {
let newData = data;
if (typeof newData !== 'object') {
let reg = /\[(.+?)\]/g; // [] 中括号
let zhEmojiName = newData.match(reg);
if (zhEmojiName) {
zhEmojiName.forEach(item => {
let emojiFile = this.selEmojiFile(item);
newData = newData.replace(
item,
`<img class="chat-img" style="width:50rpx;height:50rpx;margin:0 6rpx" src="${this.EMOJI_BASE_URL}/assets/addons/shopro/img/emoji/${emojiFile}"/>`
);
});
}
}
return newData;
},
// 加载更多
loadMore() {
if (this.cardType === 'goods') {
if (this.viewCurrentPage < this.viewTotalPage) {
this.viewCurrentPage += 1;
this.getbrowseList();
}
}
if (this.cardType === 'order') {
if (this.orderCurrentPage < this.orderTotalPage) {
this.orderCurrentPage += 1;
this.getOrderList();
}
}
},
// 订单列表
getOrderList() {
let that = this;
that.isLoading = true;
that.loadStatus = 'loading';
that.$http('order.index', {
type: 'all',
page: that.orderCurrentPage
}).then(res => {
that.isLoading = false;
if (res.code === 1) {
that.orderList = [...that.orderList, ...res.data.data];
that.orderTotalPage = res.data.last_page;
that.loadStatus = that.orderCurrentPage < res.data.last_page ? 'loadmore' : 'nomore';
}
});
},
// 历史记录
getbrowseList() {
let that = this;
that.loadStatus = 'loading';
that.$http('user.viewList', {
page: that.viewCurrentPage
}).then(res => {
if (res.code === 1) {
that.viewList = [...that.viewList, ...res.data.data];
that.viewTotalPage = res.data.last_page;
that.loadStatus = that.viewCurrentPage < res.data.last_page ? 'loadmore' : 'nomore';
}
});
}
}
};
</script>
<style lang="scss">
@import './chat.scss';
// 重置样式
page {
overflow: hidden;
}
.cu-avatar {
border: 1rpx solid #eeeeee;
}
// 标题栏
.head-box {
.head-title {
font-size: 38rpx;
line-height: 38rpx;
white-space: nowrap;
}
.head-icon {
font-size: 34rpx;
line-height: 38rpx;
}
.text-green {
color: $u-type-success-dark;
}
.text-gray {
color: $u-type-error;
}
.head-state {
font-size: 28rpx;
line-height: 38rpx;
}
}
// 模板消息
.template-box {
width: 690rpx;
background: #ffffff;
border-radius: 10rpx;
margin: 0 auto;
padding: 20rpx 24rpx;
.template-title {
font-size: 26rpx;
font-weight: bold;
color: #333333;
line-height: 36rpx;
margin-bottom: 20rpx;
}
.template-item {
font-size: 24rpx;
font-weight: 500;
color: #603fff;
line-height: 46rpx;
}
}
// 聊天框
.chat-wrap {
height: 100%;
overflow: hidden;
.scroll-box {
height: 100%;
}
.cu-chat {
.cu-info {
border-radius: 26rpx;
background: rgba(#000, 0.1);
padding: 6rpx 20rpx;
}
.main {
margin: 0 20rpx;
max-width: calc(100% - 80px);
}
.cu-item > .main .content {
&::after {
width: 0;
height: 0;
}
&::before {
width: 0;
height: 0;
}
}
}
}
// 底部
.foot {
padding: 0 20rpx;
.input-wrap {
background: #f2f2f2;
border-radius: 32rpx;
flex: 1;
height: 60rpx;
.input {
width: 100%;
}
}
.send-btn {
padding: 0;
width: 110rpx;
line-height: 64rpx;
background: linear-gradient(90deg, #a36fff, #5336ff);
border-radius: 32rpx;
color: #fff;
}
.more-btn {
padding: 0;
background: none;
.icon-tianjia {
font-size: 44rpx;
background: linear-gradient(90deg, #a36fff, #5336ff);
-webkit-background-clip: text;
color: transparent;
transition: all linear 0.2s;
}
.tools-active {
transform: rotate(45deg);
transition: all linear 0.2s;
}
}
}
// 工具栏
.tools-box {
background-color: #fff;
height: 310rpx;
border-top: 1rpx solid #f6f6f6;
transition: all 0.3s ease-in-out 0s;
.tools-item {
align-items: center;
justify-content: center;
display: flex;
flex-direction: column;
.item-img {
width: 70rpx;
height: 70rpx;
margin-bottom: 30rpx;
}
.item-tile {
font-size: 24rpx;
font-weight: 500;
color: #333333;
}
}
}
// 商品卡片
.goods-card {
width: 100%;
.goods-img {
width: 116rpx;
height: 116rpx;
margin-right: 20rpx;
}
.card-right {
width: 330rpx;
height: 116rpx;
.goods-title {
width: 330rpx;
font-size: 26rpx;
font-weight: 500;
color: #333333;
line-height: 32rpx;
text-align: left;
}
.price-box {
width: 100%;
.goods-price {
font-size: 26rpx;
font-weight: 500;
color: #ff3000;
&::before {
content: '¥';
font-size: 20rpx;
}
}
.goods-state {
font-size: 24rpx;
font-weight: 500;
color: #603fff;
}
}
}
}
// 订单卡片样式
.order-chat {
width: 100%;
.order-code {
font-size: 24rpx;
width: 100%;
font-weight: 400;
color: #999999;
border-bottom: 1rpx solid rgba(#dfdfdf, 0.5);
padding: 0 0rpx 10rpx;
}
}
// 订单商品记录
.log-box {
width: 750rpx;
height: 600rpx;
background: #f2f2f2;
border-radius: 20rpx 20rpx 0px 0px;
display: flex;
flex-direction: column;
.log-head {
box-sizing: border-box;
width: 750rpx;
height: 94rpx;
background: #ffffff;
border-radius: 20rpx 20rpx 0px 0px;
padding: 0 26rpx;
.title-box {
font-size: 30rpx;
font-weight: 500;
color: #333333;
line-height: 90rpx;
border-bottom: 4rpx solid #7063d2;
}
.close-btn {
padding: 0;
background: none;
}
}
.log-content {
flex: 1;
height: 100%;
width: 100%;
overflow: hidden;
background: #f2f2f2;
.card-scroll-box {
height: 100%;
width: 100%;
background: #f2f2f2;
}
.log-item {
width: 690rpx;
margin: 20rpx;
background-color: #fff;
border-radius: 20rpx;
.code-box {
border-bottom: 1rpx solid rgba(#dfdfdf, 0.5);
height: 76rpx;
padding: 0 20rpx;
.code-text,
.date-text {
font-size: 24rpx;
font-weight: 400;
color: #999999;
}
}
.log-card {
padding: 30rpx 20rpx;
}
.goods-img {
width: 140rpx;
height: 140rpx;
margin-right: 20rpx;
}
.card-right {
width: 500rpx;
height: 140rpx;
.goods-title {
font-size: 26rpx;
font-weight: 500;
color: #333333;
line-height: 32rpx;
text-align: left;
width: 500rpx;
}
.num-box {
font-size: 24rpx;
font-weight: 400;
color: #999999;
text-align: left;
width: 100%;
}
.price-box {
width: 100%;
.goods-price {
font-size: 26rpx;
font-weight: 500;
color: #333333;
&::before {
content: '¥';
font-size: 20rpx;
}
}
.goods-state {
font-size: 24rpx;
font-weight: 500;
color: #603fff;
}
}
}
}
}
}
// 表情栏
.emoji-box {
width: 100%;
background-color: #fff;
height: 310rpx;
border-top: 1rpx solid #f6f6f6;
transition: all 0.3s ease-in-out 0s;
padding: 20rpx 0;
.emoji-swiper {
height: 280rpx;
.swiper-item {
flex-wrap: wrap;
}
}
.emoji-img {
width: 50rpx;
height: 50rpx;
display: inline-block;
margin: 10rpx;
}
}
</style>