Commit a5adf7e1 authored by chenqikuai's avatar chenqikuai

store

parent 6fd2685f
<template>
<div
class="item flex items-center justify-center ml-4"
:class="{ 'select-item': selected }"
>{{ value }}</div>
</template>
<script setup lang="ts">
import { PropType } from "@vue/runtime-core";
const props = defineProps({
selected: {
required: true,
type: Boolean,
},
value: {
required: true,
type: String as PropType<string>,
}
})
</script>
<style>
.item {
width: 100px;
height: 35px;
background: #f5f6f9;
border-radius: 20px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #1b1f37;
}
.select-item {
background: #3e4faf;
color: #ffffff;
}
</style>
\ No newline at end of file
<template>
<div class="ChatOption bg-white flex items-center">
<div
v-for="item in props.list"
:key="item.name"
class="item flex items-center justify-center ml-4"
:class="{ 'select-item': props.selected === item.id }"
@click="props.setSelected && props.setSelected(item.id)"
>{{ item.name }}</div>
<slot></slot>
</div>
</template>
<script lang="ts" setup>
import { PropType } from "vue";
const props = defineProps({
list: {
type: Array as PropType<{ name: string, id: number }[]>,
},
selected: {
type: Number,
},
setSelected: {
type: Function,
requied: true
},
});
</script>
<style lang="less" scoped>
.ChatOption {
......
<template>
<div>
<van-popup v-model:show="show" round teleport="body" :style="{ width: '90%', top: '80%' }" @click-overlay="hide">
<div class="text-center py-4" @click="handleClickCall">
<icon
name="icon-a-dianhua"
color="#3E4FAF"
size="17"
class="inline-block pr-3 align-text-bottom"
/>
<span class="text-app-blue text-sm align-middle font-semibold">呼叫{{ phone }}</span>
</div>
</van-popup>
<van-popup
<van-popup
v-model:show="show"
round
teleport="body"
:style="{ width: '90%', top: '80%' }"
@click-overlay="hide"
>
<div class="text-center py-4" @click="handleClickCall">
<icon
name="icon-a-dianhua"
color="#3E4FAF"
size="17"
class="inline-block pr-3 align-text-bottom"
/>
<span class="text-app-blue text-sm align-middle font-semibold">呼叫{{ phone }}</span>
</div>
</van-popup>
<van-popup
v-model:show="show"
round
:style="{ width: '90%', margin: '60px auto 0px auto', top: '80%' }"
......@@ -28,7 +34,7 @@
</template>
<script lang="ts" setup>
import Vue, { ComponentInternalInstance, getCurrentInstance } from 'vue'
import Vue, { getCurrentInstance } from 'vue'
import jsBridge from "@/utils/jsBridge2"
const { ctx } = getCurrentInstance() as any
......
export const TRANSFER_HUMAN_1 = '客服经理已接入会话,我们预计3分钟内联系您'
export const TRANSFER_HUMAN_2 = '客户已接入会话,请尽快联系客户'
\ No newline at end of file
......@@ -146,7 +146,7 @@ class MessageStore {
}
// 多媒体类的消息(语音、图片、视频)上传阿里云 OSS,取得 url,发送 url
if (type !== ChatMessageTypes.Text && type !== ChatMessageTypes.Card && type !== ChatMessageTypes.FOO) {
if (type !== ChatMessageTypes.Text && type !== ChatMessageTypes.Card) {
// 特殊情况处理:当发送微信和支付宝收款方式时,由于是直接从后端拿到的图片外链,所以直接发送
if (!content.rawMessage) {
if (
......
export interface iNotifyMsg {
staffMsg: string
userMsg: string
}
......@@ -7,6 +7,6 @@ export enum ChatMessageTypes {
Video = 4,
File = 5,
Card = 6,
Alert = 7,
robot = 100,
FOO = 9,
}
......@@ -53,3 +53,52 @@ export const getDisplayNamesFromAddress = async (
return msg?.user_name || msg?.phone
})
}
export const getMsgFromAddress = async (
addressList: string[],
): Promise<any[]> => {
/* 数据库查 有结果拿 没结果网上查且存 */
const user = getUserMsg()
let foundList = [] as any[]
let notFoundList = [] as any[]
if (user?.role === eRole.user) {
const ret = await ContactPersonService.getInstance().findByList(addressList)
foundList = ret.foundList
notFoundList = ret.notFoundList
} else if (user?.role === eRole.staff) {
const ret = await UserInfoDBService.getInstance().findByList(addressList)
foundList = ret.foundList
notFoundList = ret.notFoundList
}
const fullList = (foundList as unknown) as any
if (notFoundList.length !== 0) {
if (user?.role === eRole.user) {
const ret = await UserService.getInstance().staffInfo({
addrs: notFoundList,
})
if (ret.code === 200) {
const theoseNotFoundList = ret.data.item
ContactPersonService.getInstance().save(theoseNotFoundList)
fullList.push(...theoseNotFoundList)
}
} else if (user?.role === eRole.staff) {
const ret = await UserService.getInstance().userInfo({
addrs: notFoundList,
})
if (ret.code === 200) {
const theoseNotFoundList = ret.data
UserInfoDBService.getInstance().save(theoseNotFoundList)
fullList.push(...theoseNotFoundList)
}
}
}
return addressList.map((item) => {
const msg = fullList.find((i: any) => i?.addr === item)
return msg;
})
}
......@@ -37,7 +37,6 @@ enum MsgType {
Card = 6;
Alert = 7;
Forward = 8;
FOO = 9;
}
message CommonMsg {
......@@ -133,6 +132,7 @@ enum AlertType {
UpdateGroupMutedAlert = 5;
UpdateGroupMemberMutedAlert = 6;
UpdateGroupOwnerAlert = 7;
CommonMsg = 8;
}
message AlertUpdateGroupName {
......
......@@ -44,8 +44,6 @@ export default (data: Uint8Array): DecodedMessage | null => {
case 6:
content = CardMsg.toObject(CardMsg.decode(commonMsg.msg || new Uint8Array()))
break
case 9:
content = TextMsg.toObject(TextMsg.decode(commonMsg.msg || new Uint8Array()))
default:
throw '解码消息时发现未知的消息类型:' + commonMsg.msgType
}
......
......@@ -55,11 +55,6 @@ export default (msg: ChatMessageEncoderArgs): Uint8Array => {
account: (msg.msg as dtalk.proto.CardMsg).account,
}).finish()
break
case ChatMessageTypes.FOO:
content = dtalk.proto.TextMsg.encode({
content: (msg.msg as dtalk.proto.ITextMsg).content,
}).finish()
break
default:
throw '未知的消息类型:' + msg.msgType
}
......
......@@ -220,8 +220,7 @@ export namespace dtalk {
File = 5,
Card = 6,
Alert = 7,
Forward = 8,
FOO = 9
Forward = 8
}
/** Properties of a CommonMsg. */
......@@ -1661,7 +1660,8 @@ export namespace dtalk {
DeleteGroupAlert = 4,
UpdateGroupMutedAlert = 5,
UpdateGroupMemberMutedAlert = 6,
UpdateGroupOwnerAlert = 7
UpdateGroupOwnerAlert = 7,
CommonMsg = 8
}
/** Properties of an AlertUpdateGroupName. */
......@@ -2462,6 +2462,102 @@ export namespace dtalk {
public toJSON(): { [k: string]: any };
}
/** Properties of an AlertCommonMsg. */
interface IAlertCommonMsg {
/** AlertCommonMsg user */
user?: (string|null);
/** AlertCommonMsg staff */
staff?: (string|null);
}
/** Represents an AlertCommonMsg. */
class AlertCommonMsg implements IAlertCommonMsg {
/**
* Constructs a new AlertCommonMsg.
* @param [properties] Properties to set
*/
constructor(properties?: dtalk.proto.IAlertCommonMsg);
/** AlertCommonMsg user. */
public user: string;
/** AlertCommonMsg staff. */
public staff: string;
/**
* Creates a new AlertCommonMsg instance using the specified properties.
* @param [properties] Properties to set
* @returns AlertCommonMsg instance
*/
public static create(properties?: dtalk.proto.IAlertCommonMsg): dtalk.proto.AlertCommonMsg;
/**
* Encodes the specified AlertCommonMsg message. Does not implicitly {@link dtalk.proto.AlertCommonMsg.verify|verify} messages.
* @param message AlertCommonMsg message or plain object to encode
* @param [writer] Writer to encode to
* @returns Writer
*/
public static encode(message: dtalk.proto.IAlertCommonMsg, writer?: $protobuf.Writer): $protobuf.Writer;
/**
* Encodes the specified AlertCommonMsg message, length delimited. Does not implicitly {@link dtalk.proto.AlertCommonMsg.verify|verify} messages.
* @param message AlertCommonMsg message or plain object to encode
* @param [writer] Writer to encode to
* @returns Writer
*/
public static encodeDelimited(message: dtalk.proto.IAlertCommonMsg, writer?: $protobuf.Writer): $protobuf.Writer;
/**
* Decodes an AlertCommonMsg message from the specified reader or buffer.
* @param reader Reader or buffer to decode from
* @param [length] Message length if known beforehand
* @returns AlertCommonMsg
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): dtalk.proto.AlertCommonMsg;
/**
* Decodes an AlertCommonMsg message from the specified reader or buffer, length delimited.
* @param reader Reader or buffer to decode from
* @returns AlertCommonMsg
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): dtalk.proto.AlertCommonMsg;
/**
* Verifies an AlertCommonMsg message.
* @param message Plain object to verify
* @returns `null` if valid, otherwise the reason why it is not
*/
public static verify(message: { [k: string]: any }): (string|null);
/**
* Creates an AlertCommonMsg message from a plain object. Also converts values to their respective internal types.
* @param object Plain object
* @returns AlertCommonMsg
*/
public static fromObject(object: { [k: string]: any }): dtalk.proto.AlertCommonMsg;
/**
* Creates a plain object from an AlertCommonMsg message. Also converts values to other types if specified.
* @param message AlertCommonMsg
* @param [options] Conversion options
* @returns Plain object
*/
public static toObject(message: dtalk.proto.AlertCommonMsg, options?: $protobuf.IConversionOptions): { [k: string]: any };
/**
* Converts this AlertCommonMsg to JSON.
* @returns JSON object
*/
public toJSON(): { [k: string]: any };
}
/** Properties of a NotifyMsg. */
interface INotifyMsg {
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -10,11 +10,21 @@
<div class="flex flex-col flex-grow overflow-hidden" style="flex-basis: 0px">
<ChatContentVue />
<ServiceRating :setSelectedRate="handleSelect" :selected="selected" v-if="showServiceRating" />
<ChatOption
:selected="selectedChatOption"
:setSelected="handleSelectChatOption"
:list="optionList"
/>
<ChatOption>
<ChatOptionItemVue
v-if="isUser"
:selected="questionSelected"
@click="handleClickQuestionOption"
value="常用问题"
/>
<ChatOptionItemVue
v-if="isUser"
:selected="serviceSelected"
:value="serviceShowValue"
@click="handleClickService"
/>
<ChatOptionItemVue :selected="false" value="电话联系" @click="handleClickCall" />
</ChatOption>
<ChatInputVue />
<CommonUseSentence
class="transition-all h-0"
......@@ -24,6 +34,7 @@
:list="sentenceList"
/>
</div>
<ShowCall :show="showCall" :phone="callPhone" @hidden="showCall = false" />
</div>
</template>
......@@ -41,7 +52,13 @@ import { v4 as uuidv4 } from 'uuid'
import { ChatMessageTypes } from "@/types/chatMessageTypes";
import { useRoute } from "vue-router";
import { queryFaqAnswer, queryFaqList } from "@/service/FaqService";
import { getDisplayNamesFromAddress } from "@/utils/displayName";
import { getDisplayNamesFromAddress, getMsgFromAddress } from "@/utils/displayName";
import { MessageContent } from "@/types/chat-message";
import { TRANSFER_HUMAN_1, TRANSFER_HUMAN_2 } from "@/config/chat";
import ChatOptionItemVue from "@/components/ChatOptions/ChatOptionItem.vue";
import ShowCall from "@/components/showCall/index.vue"
import { getUserMsg } from "@/utils/userMsg";
import { eRole } from "@/types/roleType";
export default defineComponent({
......@@ -51,14 +68,63 @@ export default defineComponent({
NavBar,
ServiceRating: defineAsyncComponent(() => import(/* webpackChunkName: 'serviceRating' */ "@/components/ServiceRating/index.vue")),
ChatOption: defineAsyncComponent(() => import(/* webpackChunkName: 'ChatOption' */"@/components/ChatOptions/index.vue")),
CommonUseSentence: defineAsyncComponent(() => import(/* webpackChunkName: 'CommonUseSentence' */"@/components/CommonUseSentence/index.vue"))
CommonUseSentence: defineAsyncComponent(() => import(/* webpackChunkName: 'CommonUseSentence' */"@/components/CommonUseSentence/index.vue")),
ChatOptionItemVue,
ShowCall
},
setup() {
const questionSelected = ref(false)
const handleClickQuestionOption = () => {
questionSelected.value = !questionSelected.value
}
watch(questionSelected, () => {
setShowSentences(questionSelected.value)
sentensesLoading.value = true;
questionSelected.value && queryFaqList().then(ret => {
if (ret.code === 200) {
sentenceList.value = ret.data.question;
}
sentensesLoading.value = false;
})
})
const serviceSelected = ref(false);
const serviceShowValue = ref('人工服务')
const handleClickService = () => {
const sendChatMessage = (payload: {
type: ChatMessageTypes;
content: MessageContent;
}) => {
messageStore.sendMessage({ type: payload.type, content: payload.content, target: route.query.targetId as string });
};
if (serviceShowValue.value === '人工服务') {
sendChatMessage({
type: ChatMessageTypes.Card,
content: {
bank: TRANSFER_HUMAN_1,
name: TRANSFER_HUMAN_2,
account: '',
} as MessageContent
})
serviceShowValue.value = '结束服务'
} else if (serviceShowValue.value === '结束服务') {
serviceShowValue.value = '人工服务'
sendChatMessage({
type: ChatMessageTypes.Card,
content: {
bank: '本次服务已结束',
name: '本次服务已结束',
account: '',
} as MessageContent
})
// showServiceRating.value = true;
}
}
const initError = ref(false);
const showServiceRating = ref(false);
const selected = ref("");
const selectedChatOption = ref(NaN);
const showShortSentences = ref(false);
const route = useRoute()
......@@ -67,38 +133,16 @@ export default defineComponent({
const sentenceList = ref<any[]>([])
const sentensesLoading = ref(false)
const optionList = [
{ name: '常用问题', id: 1 },
{ name: '人工服务', id: 2 },
{ name: '电话咨询', id: 3 },
];
const setShowSentences = (show: boolean) =>
(showShortSentences.value = show);
const handleSelect = (select: string) => (selected.value = select);
const handleSelectChatOption = (select: number) => {
selectedChatOption.value = select
};
watch(selectedChatOption, () => {
if (selectedChatOption.value === 1) {
setShowSentences(true)
sentensesLoading.value = true;
queryFaqList().then(ret => {
if (ret.code === 200) {
sentenceList.value = ret.data.question;
}
sentensesLoading.value = false;
})
setShowSentences(true)
} else {
setShowSentences(false)
}
if (selectedChatOption.value === 3) {
}
})
const handleClickCall = () => {
showCall.value = true;
}
const useSentence = (content: string) => {
/* 问 */
......@@ -153,6 +197,15 @@ export default defineComponent({
onMounted(async () => {
const list = await getDisplayNamesFromAddress([target])
title.value = list[0];
const ret = await getMsgFromAddress([target])
callPhone.value = ret[0].phone;
})
const showCall = ref(false)
const callPhone = ref('')
const isUser = computed(() => {
return getUserMsg()?.role === eRole.user
})
......@@ -162,13 +215,19 @@ export default defineComponent({
handleSelect,
showServiceRating,
showShortSentences,
selectedChatOption,
handleSelectChatOption,
useSentence,
sentenceList,
optionList,
sentensesLoading,
title
title,
questionSelected,
handleClickQuestionOption,
serviceSelected,
serviceShowValue,
handleClickService,
handleClickCall,
showCall,
callPhone,
isUser
};
},
});
......
<template>
<div>
<div v-if="!hideDatetime" class="text-xs text-gray-400 text-center pb-2 pt-4">{{ time }}</div>
<!-- 卡片消息 -->
<ChatContentMessageCardVue
v-if="type === 6"
:from-myself="fromMyself"
:content="content"
></ChatContentMessageCardVue>
<div
class="flex items-start flex-nowrap w-screen py-1.5"
:class="{ 'flex-row-reverse': fromMyself }"
>
<!-- 头像 -->
<q-avatar class="mx-4 min-w-chat-msg-avatar w-chat-msg-avatar h-chat-msg-avatar !rounded-md">
<q-avatar class="mx-4 min-w-chat-msg-avatar w-chat-msg-avatar h-chat-msg-avatar !rounded-md" v-if="type !== 6">
<img :src="default_avatar_url" />
</q-avatar>
......@@ -53,13 +59,7 @@
:uploadProgress="uploadProgress"
/>-->
<!-- 卡片消息 -->
<ChatContentMessageCardVue
v-else-if="type === 6"
:from-myself="fromMyself"
:content="content"
/>
<!-- 消息状态 -->
<div class="w-10 self-stretch flex flex-row justify-center items-center">
<!-- 发送失败 -->
......
<template>
<div :class="fromMyself ? 'bg-secondary' : 'bg-white'" class="w-full h-24 rounded-md font-medium">
<div class="py-3 px-3 flex items-center enable-touch">
<q-icon :name="'img:' + iconUrl" size="28px" class="mr-1" /> {{ content.bank }}
</div>
<div class="pb-3 px-2 flex flex-nowrap justify-between text-base break-all enable-touch">
<div>{{ content.name }}</div>
<div>{{ content.account }}</div>
</div>
<div class="w-full rounded-md font-medium flex items-center">
<div class="flex-grow border-b mr-1 ml-2"></div>
<div class="text-center" v-if="isUser">{{ content?.bank }}</div>
<div class="text-center" v-else>{{ content?.name }}</div>
<div class="flex-grow border-b ml-1 mr-2"></div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { defineComponent, PropType } from 'vue'
import iconUrl from '@/assets/message_bank_card.png'
import { getUserMsg } from '@/utils/userMsg'
import { eRole } from '@/types/roleType'
export default defineComponent({
props: { fromMyself: Boolean, content: Object },
props: {
fromMyself: Boolean,
content: Object as PropType<{ bank: string, name: string, account: string }>
},
setup() {
return { iconUrl }
const isUser = getUserMsg()?.role === eRole.user
return { iconUrl, isUser }
},
})
</script>
......@@ -6,9 +6,7 @@
@click="inputType === 1 ? (inputType = 2) : (inputType = 1)"
class="w-7 h-7 mx-2.5 text-center select-none focus:outline-none"
>
<i v-if="inputType === 1" class="iconfont text-primary text-xl"
>&#xe604;</i
>
<i v-if="inputType === 1" class="iconfont text-primary text-xl">&#xe604;</i>
<i v-else class="iconfont text-primary text-xl">&#xe60d;</i>
</button>
......@@ -20,7 +18,7 @@
/>
<!-- 没有输入文字,显示 `加号` 按钮 -->
<!-- v-if="!inputText" -->
<!-- v-if="!inputText" -->
<button
v-if="false"
@click="showMenu ? (showMenu = false) : (showMenu = true)"
......@@ -31,30 +29,14 @@
<!-- 有输入文字,显示 `发送` 按钮 -->
<button
v-else
@click="inputText.trim().length !== 0 &&sendChatMessage({ type: 9, content: { content: inputText } })"
class="
mx-2.5
px-4
py-1.5
flex
items-center
rounded-md
text-center
select-none
focus:outline-none
text-app-white
"
@click="inputText.trim().length !== 0 && sendChatMessage({ type: 1, content: { content: inputText } })"
class="mx-2.5 px-4 py-1.5 flex items-center rounded-md text-center select-none focus:outline-none text-app-white"
style="background: rgb(7, 193, 99)"
>
发送
</button>
>发送</button>
</div>
<!-- input menu -->
<div
v-show="showMenu"
class="min-h-input-menu flex items-center px-8 text-sm text-subtle"
>
<div v-show="showMenu" class="min-h-input-menu flex items-center px-8 text-sm text-subtle">
<ChatInputAlbumVue />
<!-- <ChatInputCameraVue /> -->
</div>
......@@ -104,7 +86,7 @@ export default defineComponent({
type: ChatMessageTypes;
content: MessageContent;
}) => {
messageStore.sendMessage({type: payload.type, content: payload.content, target: route.query.targetId as string});
messageStore.sendMessage({ type: payload.type, content: payload.content, target: route.query.targetId as string });
textInputStore.clearTextMessage();
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment