客服:组件初步抽离

pull/56/head
puhui999 2024-06-07 11:29:01 +08:00
parent 561529b01e
commit 3355f5e853
5 changed files with 314 additions and 230 deletions

View File

@ -86,7 +86,8 @@
], ],
"subPackages": [{ "subPackages": [{
"root": "pages/goods", "root": "pages/goods",
"pages": [{ "pages": [
{
"path": "index", "path": "index",
"style": { "style": {
"navigationBarTitleText": "商品详情" "navigationBarTitleText": "商品详情"
@ -150,7 +151,8 @@
}, },
{ {
"root": "pages/order", "root": "pages/order",
"pages": [{ "pages": [
{
"path": "detail", "path": "detail",
"style": { "style": {
"navigationBarTitleText": "订单详情" "navigationBarTitleText": "订单详情"
@ -249,7 +251,8 @@
}, },
{ {
"root": "pages/user", "root": "pages/user",
"pages": [{ "pages": [
{
"path": "info", "path": "info",
"style": { "style": {
"navigationBarTitleText": "我的信息" "navigationBarTitleText": "我的信息"
@ -335,7 +338,8 @@
}, },
{ {
"root": "pages/commission", "root": "pages/commission",
"pages": [{ "pages": [
{
"path": "index", "path": "index",
"style": { "style": {
"navigationBarTitleText": "分销" "navigationBarTitleText": "分销"
@ -432,7 +436,8 @@
}, },
{ {
"root": "pages/app", "root": "pages/app",
"pages": [{ "pages": [
{
"path": "sign", "path": "sign",
"style": { "style": {
"navigationBarTitleText": "签到中心" "navigationBarTitleText": "签到中心"
@ -447,7 +452,8 @@
}, },
{ {
"root": "pages/public", "root": "pages/public",
"pages": [{ "pages": [
{
"path": "setting", "path": "setting",
"style": { "style": {
"navigationBarTitleText": "系统设置" "navigationBarTitleText": "系统设置"
@ -496,7 +502,8 @@
}, },
{ {
"root": "pages/coupon", "root": "pages/coupon",
"pages": [{ "pages": [
{
"path": "list", "path": "list",
"style": { "style": {
"navigationBarTitleText": "领券中心" "navigationBarTitleText": "领券中心"
@ -538,7 +545,8 @@
}, },
{ {
"root": "pages/pay", "root": "pages/pay",
"pages": [{ "pages": [
{
"path": "index", "path": "index",
"style": { "style": {
"navigationBarTitleText": "收银台" "navigationBarTitleText": "收银台"
@ -578,7 +586,8 @@
}, },
{ {
"root": "pages/activity", "root": "pages/activity",
"pages": [{ "pages": [
{
"path": "groupon/detail", "path": "groupon/detail",
"style": { "style": {
"navigationBarTitleText": "拼团详情" "navigationBarTitleText": "拼团详情"

View File

@ -0,0 +1,102 @@
<template>
<view class="send-wrap ss-flex">
<view class="left ss-flex ss-flex-1">
<uni-easyinput
class="ss-flex-1 ss-p-l-22"
:inputBorder="false"
:clearable="false"
v-model="message"
placeholder="请输入你要咨询的问题"
></uni-easyinput>
</view>
<text class="sicon-basic bq" @tap.stop="onTools('emoji')"></text>
<text
v-if="!message"
class="sicon-edit"
:class="{ 'is-active': toolsMode === 'tools' }"
@tap.stop="onTools('tools')"
></text>
<button v-if="message" class="ss-reset-button send-btn" @tap="sendMessage">
发送
</button>
</view>
</template>
<script setup>
import { computed } from 'vue';
/**
* 消息发送组件
*/
const props = defineProps({
//
modelValue: {
type: String,
default: '',
},
//
toolsMode: {
type: String,
default: '',
},
});
const emits = defineEmits(['update:modelValue', 'onTools', 'sendMessage']);
const message = computed({
get() {
return props.modelValue;
},
set(newValue) {
emits(`update:modelValue`, newValue);
}
});
//
function onTools(mode) {
emits('onTools', mode);
}
//
function sendMessage() {
emits('sendMessage');
}
</script>
<style scoped lang="scss">
.send-wrap {
padding: 18rpx 20rpx;
background: #fff;
.left {
height: 64rpx;
border-radius: 32rpx;
background: var(--ui-BG-1);
}
.bq {
font-size: 50rpx;
margin-left: 10rpx;
}
.sicon-edit {
font-size: 50rpx;
margin-left: 10rpx;
transform: rotate(0deg);
transition: all linear 0.2s;
&.is-active {
transform: rotate(45deg);
}
}
.send-btn {
width: 100rpx;
height: 60rpx;
line-height: 60rpx;
border-radius: 30rpx;
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
font-size: 26rpx;
color: #fff;
margin-left: 11rpx;
}
}
</style>

View File

@ -0,0 +1,166 @@
<template>
<su-popup
:show="showTools"
@close="handleClose"
>
<view class="ss-modal-box ss-flex-col">
<slot></slot>
<view class="content ss-flex ss-flex-1">
<template v-if="toolsMode === 'emoji'">
<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="emoji in emojiPage" :key="emoji">
<view class="ss-flex ss-flex-wrap">
<image
v-for="item in emoji" :key="item"
class="emoji-img"
:src="sheep.$url.cdn(`/static/img/chat/emoji/${item.file}`)"
@tap="onEmoji(item)"
>
</image>
</view>
</swiper-item>
</swiper>
</template>
<template v-else>
<view class="image">
<s-uploader
file-mediatype="image"
:imageStyles="{ width: 50, height: 50, border: false }"
@select="imageSelect({ type: 'image', data: $event })"
>
<image
class="icon"
:src="sheep.$url.static('/static/img/shop/chat/image.png')"
mode="aspectFill"
></image>
</s-uploader>
<view>图片</view>
</view>
<view class="goods" @tap="onShowSelect('goods')">
<image
class="icon"
:src="sheep.$url.static('/static/img/shop/chat/goods.png')"
mode="aspectFill"
></image>
<view>商品</view>
</view>
<view class="order" @tap="onShowSelect('order')">
<image
class="icon"
:src="sheep.$url.static('/static/img/shop/chat/order.png')"
mode="aspectFill"
></image>
<view>订单</view>
</view>
</template>
</view>
</view>
</su-popup>
</template>
<script setup>
/**
* 聊天工具
*/
import { emojiPage } from '@/pages/chat/emoji';
import sheep from '@/sheep';
const props = defineProps({
//
toolsMode: {
type: String,
default: '',
},
//
showTools: {
type: Boolean,
default: () => false,
},
});
const emits = defineEmits(['onEmoji', 'imageSelect', 'onShowSelect', 'close']);
//
function handleClose() {
emits('close');
}
//
function onEmoji(emoji) {
emits('onEmoji', emoji);
}
//
function imageSelect(val) {
emits('imageSelect', val);
}
//
function onShowSelect(mode) {
emits('onShowSelect', mode);
}
</script>
<style scoped lang="scss">
.content {
width: 100%;
align-content: space-around;
border-top: 1px solid #dfdfdf;
padding: 20rpx 0 0;
.emoji-swiper {
width: 100%;
height: 280rpx;
padding: 0 20rpx;
.emoji-img {
width: 50rpx;
height: 50rpx;
display: inline-block;
margin: 10rpx;
}
}
.image,
.goods,
.order {
width: 33.3%;
height: 280rpx;
text-align: center;
font-size: 24rpx;
color: #333;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.icon {
width: 50rpx;
height: 50rpx;
margin-bottom: 21rpx;
}
}
:deep() {
.uni-file-picker__container {
justify-content: center;
}
.file-picker__box {
display: none;
&:last-of-type {
display: flex;
}
}
}
}
</style>

View File

@ -159,119 +159,13 @@
</scroll-view> </scroll-view>
</view> </view>
<su-fixed bottom> <su-fixed bottom>
<view class="send-wrap ss-flex"> <message-input v-model="chat.msg" @on-tools="onTools" @send-message="onSendMessage"></message-input>
<view class="left ss-flex ss-flex-1">
<uni-easyinput
class="ss-flex-1 ss-p-l-22"
:inputBorder="false"
:clearable="false"
v-model="chat.msg"
placeholder="请输入你要咨询的问题"
></uni-easyinput>
</view>
<text class="sicon-basic bq" @tap.stop="onTools('emoji')"></text>
<text
v-if="!chat.msg"
class="sicon-edit"
:class="{ 'is-active': chat.toolsMode == 'tools' }"
@tap.stop="onTools('tools')"
></text>
<button v-if="chat.msg" class="ss-reset-button send-btn" @tap="onSendMessage">
发送
</button>
</view>
</su-fixed> </su-fixed>
<su-popup <!-- 聊天工具 -->
:show="chat.showTools" <tools-popup :show-tools="chat.showTools" :tools-mode="chat.toolsMode" @close="handleToolsClose"
@close=" @on-emoji="onEmoji" @image-select="onSelect" @on-show-select="onShowSelect">
chat.showTools = false; <message-input v-model="chat.msg" @on-tools="onTools" @send-message="onSendMessage"></message-input>
chat.toolsMode = ''; </tools-popup>
"
>
<view class="ss-modal-box ss-flex-col">
<view class="send-wrap ss-flex">
<view class="left ss-flex ss-flex-1">
<uni-easyinput
class="ss-flex-1 ss-p-l-22"
:inputBorder="false"
:clearable="false"
v-model="chat.msg"
placeholder="请输入你要咨询的问题"
></uni-easyinput>
</view>
<text class="sicon-basic bq" @tap.stop="onTools('emoji')"></text>
<text></text>
<text
v-if="!chat.msg"
class="sicon-edit"
:class="{ 'is-active': chat.toolsMode == 'tools' }"
@tap.stop="onTools('tools')"
></text>
<button v-if="chat.msg" class="ss-reset-button send-btn" @tap="onSendMessage">
发送
</button>
</view>
<view class="content ss-flex ss-flex-1">
<template v-if="chat.toolsMode == 'emoji'">
<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="emoji in emojiPage" :key="emoji">
<view class="ss-flex ss-flex-wrap">
<template v-for="item in emoji" :key="item">
<image
class="emoji-img"
:src="sheep.$url.cdn(`/static/img/chat/emoji/${item.file}`)"
@tap="onEmoji(item)"
>
</image>
</template>
</view>
</swiper-item>
</swiper>
</template>
<template v-else>
<view class="image">
<s-uploader
file-mediatype="image"
:imageStyles="{ width: 50, height: 50, border: false }"
@select="onSelect({ type: 'image', data: $event })"
>
<image
class="icon"
:src="sheep.$url.static('/static/img/shop/chat/image.png')"
mode="aspectFill"
></image>
</s-uploader>
<view>图片</view>
</view>
<view class="goods" @tap="onShowSelect('goods')">
<image
class="icon"
:src="sheep.$url.static('/static/img/shop/chat/goods.png')"
mode="aspectFill"
></image>
<view>商品</view>
</view>
<view class="order" @tap="onShowSelect('order')">
<image
class="icon"
:src="sheep.$url.static('/static/img/shop/chat/order.png')"
mode="aspectFill"
></image>
<view>订单</view>
</view>
</template>
</view>
</view>
</su-popup>
<SelectPopup <SelectPopup
:mode="chat.selectMode" :mode="chat.selectMode"
@ -286,10 +180,12 @@
import sheep from '@/sheep'; import sheep from '@/sheep';
import { computed, reactive, toRefs } from 'vue'; import { computed, reactive, toRefs } from 'vue';
import { onLoad } from '@dcloudio/uni-app'; import { onLoad } from '@dcloudio/uni-app';
import { emojiList, emojiPage } from './emoji.js'; import { emojiList } from './emoji.js';
import SelectPopup from './components/select-popup.vue'; import SelectPopup from './components/select-popup.vue';
import GoodsItem from './components/goods.vue'; import GoodsItem from './components/goods.vue';
import OrderItem from './components/order.vue'; import OrderItem from './components/order.vue';
import MessageInput from './components/messageInput.vue';
import ToolsPopup from './components/toolsPopup.vue';
import { useChatWebSocket } from './socket'; import { useChatWebSocket } from './socket';
const { const {
@ -372,12 +268,23 @@
}, },
}); });
//======================= =======================
function handleToolsClose() {
chat.showTools = false;
chat.toolsMode = '';
}
function onEmoji(item) {
chat.msg += item.name;
}
// //
function onTools(mode) { function onTools(mode) {
if (!socketState.value.isConnect) { // if (!socketState.value.isConnect) {
sheep.$helper.toast(socketState.value.tip || '您已掉线!请返回重试'); // sheep.$helper.toast(socketState.value.tip || '线');
return; // return;
} // }
if (!chat.toolsMode || chat.toolsMode === mode) { if (!chat.toolsMode || chat.toolsMode === mode) {
chat.showTools = !chat.showTools; chat.showTools = !chat.showTools;
@ -523,10 +430,6 @@
// scrollBottom(); // scrollBottom();
} }
function onEmoji(item) {
chat.msg += item.name;
}
function selEmojiFile(name) { function selEmojiFile(name) {
for (let index in emojiList) { for (let index in emojiList) {
if (emojiList[index].name === name) { if (emojiList[index].name === name) {
@ -761,98 +664,6 @@
height: 120rpx; height: 120rpx;
} }
} }
.send-wrap {
padding: 18rpx 20rpx;
background: #fff;
.left {
height: 64rpx;
border-radius: 32rpx;
background: var(--ui-BG-1);
}
.bq {
font-size: 50rpx;
margin-left: 10rpx;
}
.sicon-edit {
font-size: 50rpx;
margin-left: 10rpx;
transform: rotate(0deg);
transition: all linear 0.2s;
&.is-active {
transform: rotate(45deg);
}
}
.send-btn {
width: 100rpx;
height: 60rpx;
line-height: 60rpx;
border-radius: 30rpx;
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
font-size: 26rpx;
color: #fff;
margin-left: 11rpx;
}
}
}
.content {
width: 100%;
align-content: space-around;
border-top: 1px solid #dfdfdf;
padding: 20rpx 0 0;
.emoji-swiper {
width: 100%;
height: 280rpx;
padding: 0 20rpx;
.emoji-img {
width: 50rpx;
height: 50rpx;
display: inline-block;
margin: 10rpx;
}
}
.image,
.goods,
.order {
width: 33.3%;
height: 280rpx;
text-align: center;
font-size: 24rpx;
color: #333;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.icon {
width: 50rpx;
height: 50rpx;
margin-bottom: 21rpx;
}
}
:deep() {
.uni-file-picker__container {
justify-content: center;
}
.file-picker__box {
display: none;
&:last-of-type {
display: flex;
}
}
}
} }
</style> </style>
<style> <style>
@ -861,6 +672,7 @@
height: 24px; height: 24px;
margin: 0 3px; margin: 0 3px;
} }
.full-img { .full-img {
object-fit: cover; object-fit: cover;
width: 100px; width: 100px;

View File

@ -304,12 +304,7 @@ export function useChatWebSocket(socketConfig) {
// 用户id,获取token // 用户id,获取token
const getUserToken = async (id) => { const getUserToken = async (id) => {
const res = await chat.unifiedToken(); return uni.getStorageSync('token');
if (res.error === 0) {
uni.setStorageSync('socketUserToken', res.data.token);
// SocketIo && SocketIo.connected && socketLogin(res.data.token)
}
return res;
}; };
// 用户登录 // 用户登录