Commit 21c718f9 authored by xhx's avatar xhx

退出

parents 661790e3 98c80ac9
<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> <template>
<div class="ChatOption bg-white flex items-center"> <div class="ChatOption bg-white flex items-center">
<div <slot></slot>
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>
</div> </div>
</template> </template>
<script lang="ts" setup> <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> </script>
<style lang="less" scoped> <style lang="less" scoped>
.ChatOption { .ChatOption {
......
<template> <template>
<van-swipe class="my-swipe" indicator-color="#3E4FAF"> <Skeleton :row="3" :loading="skeLoading">
<van-swipe class="my-swipe" indicator-color="#3E4FAF" style="margin-top:20px">
<van-swipe-item <van-swipe-item
class="flex justify-center swpiItem" class="flex justify-center swpiItem"
v-for="item in hotProductList" v-for="item in state.hotProductList"
:key="item.value" :key="item.value"
> >
<Skeleton :row="3" :loading="skeLoading">
<LoanHotCard <LoanHotCard
:inst_name="item.inst_name" :inst_name="item.inst_name"
:product_name="item.product_name" :product_name="item.product_name"
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
:max_amount="item.max_amount" :max_amount="item.max_amount"
:uuid="item.uuid" :uuid="item.uuid"
/> />
</Skeleton>
</van-swipe-item> </van-swipe-item>
</van-swipe> </van-swipe>
</Skeleton>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from "vue"; import { ref } from "vue";
...@@ -28,7 +28,7 @@ import { ...@@ -28,7 +28,7 @@ import {
import { onMounted, PropType, reactive, watch } from "@vue/runtime-core"; import { onMounted, PropType, reactive, watch } from "@vue/runtime-core";
import { eLoanMode } from "@/views/withMenu/Loan/types"; import { eLoanMode } from "@/views/withMenu/Loan/types";
import { hotProduct } from "./type"; import { hotProduct } from "./type";
import { Skeleton} from "vant" import { Skeleton } from "vant";
const props = defineProps({ const props = defineProps({
loanMode: { loanMode: {
...@@ -37,45 +37,44 @@ const props = defineProps({ ...@@ -37,45 +37,44 @@ const props = defineProps({
}, },
}); });
let skeLoading = ref(false) let skeLoading = ref(true);
let hotProductList: Array<hotProduct> = reactive([]); let state = reactive({hotProductList: [] as Array<hotProduct>})
watch(props,(newV,oldV)=>{ watch(props, (newV, oldV) => {
console.log(props.loanMode); state.hotProductList = [];
hotProductList=[] fetchList();
fetchList() });
})
onMounted(() => { onMounted(() => {
fetchList() fetchList();
}); });
const fetchList = ()=>{ const fetchList = () => {
skeLoading.value = true skeLoading.value = true;
queryLoanProductList({ queryLoanProductList({
limit: 3, limit: 3,
loan_type: props.loanMode!, loan_type: props.loanMode!,
offset: 0, offset: 0,
}).then((ret) => { }).then((ret) => {
if (ret.code === 200) { if (ret.code === 200) {
skeLoading.value = false skeLoading.value = false;
ret.data.uuid.map((uuid) => { ret.data.uuid.map((uuid) => {
queryLoanProductInfo({ uuid }).then((ret) => { queryLoanProductInfo({ uuid }).then((ret) => {
const { rate_lower, max_amount, max_date, inst_name, product_name } = const { rate_lower, max_amount, max_date, inst_name, product_name } =
ret.data; ret.data;
hotProductList.push({ state.hotProductList.push({
rate_lower, rate_lower,
max_amount, max_amount,
max_date, max_date,
inst_name, inst_name,
product_name, product_name,
uuid uuid,
}); });
}); });
}); });
} }
}); });
} };
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
name="icon-kefu" name="icon-kefu"
class="absolute left-11" class="absolute left-11"
size="18" size="18"
@click="$router.push({name:'Chat'})"
:color="iconColor" :color="iconColor"
/> />
<icon <icon
......
<template> <template>
<div> <div>
<van-popup v-model:show="show" round teleport="body" :style="{ width: '90%', top: '80%' }" @click-overlay="hide"> <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"> <div class="text-center py-4" @click="handleClickCall">
<icon <icon
name="icon-a-dianhua" name="icon-a-dianhua"
...@@ -28,7 +34,7 @@ ...@@ -28,7 +34,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import Vue, { ComponentInternalInstance, getCurrentInstance } from 'vue' import Vue, { getCurrentInstance } from 'vue'
import jsBridge from "@/utils/jsBridge2" import jsBridge from "@/utils/jsBridge2"
const { ctx } = getCurrentInstance() as any const { ctx } = getCurrentInstance() as any
......
export const TRANSFER_HUMAN_1 = '客服经理已接入会话,我们预计3分钟内联系您'
export const TRANSFER_HUMAN_2 = '客户已接入会话,请尽快联系客户'
export const CONST_START_CHAT = {
user: { id: '1', value: '客服经理已接入会话,我们预计3分钟内联系您' },
staff: { id: '2', value: '客户已接入会话,请尽快联系客户' },
}
export const CONST_END_CHAT = {
user: { id: '3', value: '会话已结束' },
staff: { id: '4', value: '会话已结束' },
}
export const CHAT_CONST_LIST = [CONST_START_CHAT, CONST_END_CHAT]
import { DisplayMessage } from '@/store/messagesStore' import { DisplayMessage } from '@/store/messagesStore'
import { ChatMessageTypes } from '@/types/chatMessageTypes'
import { eRole } from '@/types/roleType'
import ChatDataService from '@/utils/ChatDataService'
import { import {
getMasterIdFromDisplayMsg, getMasterIdFromDisplayMsg,
getTargetIdFromDisplayMsg, getTargetIdFromDisplayMsg,
} from '@/utils/chatutils' } from '@/utils/chatutils'
import { getUserMsg } from '@/utils/userMsg'
import { iChatListCard, MyAppDatabase } from './index' import { iChatListCard, MyAppDatabase } from './index'
export default class ChatListCardDB extends MyAppDatabase { export default class ChatListCardDB extends MyAppDatabase {
...@@ -72,7 +76,17 @@ export default class ChatListCardDB extends MyAppDatabase { ...@@ -72,7 +76,17 @@ export default class ChatListCardDB extends MyAppDatabase {
}) })
.first() .first()
const content = msg.content?.content || '[新消息]' let content: string
if (msg.type === ChatMessageTypes.Card) {
content =
ChatDataService.getInstance().extractCommonMsgContentFromMsg(
msg,
getUserMsg()?.role as eRole,
) || ''
} else {
content = msg.content?.content || '[新消息]'
}
const unreadMsgCount = cardItem?.unreadMsgCount || 0 const unreadMsgCount = cardItem?.unreadMsgCount || 0
this.updateCard( this.updateCard(
...@@ -90,13 +104,14 @@ export default class ChatListCardDB extends MyAppDatabase { ...@@ -90,13 +104,14 @@ export default class ChatListCardDB extends MyAppDatabase {
const content = data.msg.content?.content || '[新消息]' const content = data.msg.content?.content || '[新消息]'
const masterId = getMasterIdFromDisplayMsg(data.msg) const masterId = getMasterIdFromDisplayMsg(data.msg)
const targetId = getTargetIdFromDisplayMsg(data.msg) const targetId = getTargetIdFromDisplayMsg(data.msg)
console.log(data.msg, "in addNewCard"); console.log(data.msg, 'in addNewCard')
this.saveCard({ this.saveCard({
masterId, masterId,
targetId: targetId, targetId: targetId,
unreadMsgCount: data.isChattingWithTargetId ? 0 : 1, unreadMsgCount: data.isChattingWithTargetId ? 0 : 1,
content, content,
inChat: false,
}) })
} }
...@@ -109,4 +124,24 @@ export default class ChatListCardDB extends MyAppDatabase { ...@@ -109,4 +124,24 @@ export default class ChatListCardDB extends MyAppDatabase {
item.unreadMsgCount = 0 item.unreadMsgCount = 0
}) })
} }
setChatStatus(masterId: string, targetId: string, isChat: boolean) {
return this.chatListCard
.filter((item) => {
return item.targetId === targetId && item.masterId === masterId
})
.modify((item) => {
item.inChat = isChat
})
}
async getChatStatus(masterId: string, targetId: string) {
const ret = await this.chatListCard
.filter((item) => {
return item.targetId === targetId && item.masterId === masterId
})
.first()
return ret?.inChat
}
} }
...@@ -11,6 +11,7 @@ export interface iChatListCard { ...@@ -11,6 +11,7 @@ export interface iChatListCard {
targetId: string targetId: string
unreadMsgCount: number unreadMsgCount: number
content: string content: string
inChat: boolean // 会话状态,会话中?
} }
export class MyAppDatabase extends Dexie { export class MyAppDatabase extends Dexie {
...@@ -25,12 +26,11 @@ export class MyAppDatabase extends Dexie { ...@@ -25,12 +26,11 @@ export class MyAppDatabase extends Dexie {
this.version(1.2).stores({ this.version(1.2).stores({
chatMessage: chatMessage:
'++id, content, from, uuid, state, uploadProgress, type, datetime, hideDatetime, logid, masterId, readed', '++id, content, from, uuid, state, uploadProgress, type, datetime, hideDatetime, logid, masterId, readed',
chatListCard: '++id, masterId, targetId, unreadMsgCount, content', chatListCard: '++id, masterId, targetId, unreadMsgCount, content, inChat',
contactPerson: '++id, addr, bank, phone, user_name', contactPerson: '++id, addr, bank, phone, user_name',
userInfo: '++id, created_at, phone, remark, user_name, uuid, addr', userInfo: '++id, created_at, phone, remark, user_name, uuid, addr',
}) })
this.chatMessage = this.table('chatMessage') this.chatMessage = this.table('chatMessage')
this.chatListCard = this.table('chatListCard') this.chatListCard = this.table('chatListCard')
this.contactPerson = this.table('contactPerson') this.contactPerson = this.table('contactPerson')
......
...@@ -2,6 +2,8 @@ import baseAxios from '../index' ...@@ -2,6 +2,8 @@ import baseAxios from '../index'
import { eLoanMode } from '@/views/withMenu/Loan/types' import { eLoanMode } from '@/views/withMenu/Loan/types'
import { iLoanProdcutItem } from "./type" import { iLoanProdcutItem } from "./type"
const prefix = '/loan/query'
export function queryLoanProductList(data: { export function queryLoanProductList(data: {
limit: number, limit: number,
loan_type:eLoanMode loan_type:eLoanMode
...@@ -12,7 +14,7 @@ export function queryLoanProductList(data: { ...@@ -12,7 +14,7 @@ export function queryLoanProductList(data: {
uuid: string[], uuid: string[],
total: number total: number
}>({ }>({
url: '/loan/query/list', url: prefix+'/list',
method: 'POST', method: 'POST',
data data
}) })
...@@ -20,7 +22,7 @@ export function queryLoanProductList(data: { ...@@ -20,7 +22,7 @@ export function queryLoanProductList(data: {
export function queryLoanProductInfo(data: { uuid: string }) { export function queryLoanProductInfo(data: { uuid: string }) {
return baseAxios<iLoanProdcutItem>({ return baseAxios<iLoanProdcutItem>({
url: '/loan/query/info', url: prefix+'/info',
method: 'GET', method: 'GET',
params: data params: data
}) })
...@@ -54,11 +56,22 @@ export function queryDirectLoanReq(data: { ...@@ -54,11 +56,22 @@ export function queryDirectLoanReq(data: {
items: iLoanProdcutItem[] items: iLoanProdcutItem[]
total: number total: number
}>({ }>({
url: '/loan/query/direct/list', url: prefix+'/direct/list',
method: 'POST', method: 'POST',
data, data,
}) })
} }
export function queryLimit() {
return baseAxios<{
en_max_amount:string,
en_rate_lower:string,
max_amount:string,
}>({
url: prefix+'/max_limit',
method: 'GET',
})
}
...@@ -4,10 +4,7 @@ ...@@ -4,10 +4,7 @@
import { MessageContent } from '@/types/chat-message' import { MessageContent } from '@/types/chat-message'
import { reactive, Ref, ref } from '@vue/reactivity' import { reactive, Ref, ref } from '@vue/reactivity'
import { import { target as __target, getFromId } from '@/store/appCallerStore'
target as __target,
getFromId
} from '@/store/appCallerStore'
import { ChatMessageTypes } from '@/types/chatMessageTypes' import { ChatMessageTypes } from '@/types/chatMessageTypes'
import encodeChatMessage from '@/utils/fzm-message-protocol-chat/encodeChatMessage' import encodeChatMessage from '@/utils/fzm-message-protocol-chat/encodeChatMessage'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
...@@ -26,6 +23,8 @@ import { ...@@ -26,6 +23,8 @@ import {
getTargetIdFromDisplayMsg, getTargetIdFromDisplayMsg,
} from '@/utils/chatutils' } from '@/utils/chatutils'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import ChatListCardDB from '@/db/ChatListCardDB'
import { CONST_END_CHAT, CONST_START_CHAT } from '@/config/chat'
/** 多媒体消息的上传进度 */ /** 多媒体消息的上传进度 */
export interface UploadProgress { export interface UploadProgress {
...@@ -116,7 +115,6 @@ class MessageStore { ...@@ -116,7 +115,6 @@ class MessageStore {
target: string target: string
uuid?: string uuid?: string
}) { }) {
const _uuid = uuid || uuidv4() const _uuid = uuid || uuidv4()
/** 聊天界面显示的消息 */ /** 聊天界面显示的消息 */
...@@ -189,17 +187,17 @@ class MessageStore { ...@@ -189,17 +187,17 @@ class MessageStore {
} }
// 文本类消息,不需要上传 OSS,直接发送 // 文本类消息,不需要上传 OSS,直接发送
else { else {
ChatDBService.getInstance().handleEveryReceive({ ChatDBService.getInstance().handleEveryReceive({
msg: message, msg: message,
masterId: getMasterIdFromDisplayMsg(message), masterId: getMasterIdFromDisplayMsg(message),
isChattingWithTargetId: isChattingWith( isChattingWithTargetId: isChattingWith(
getMasterIdFromDisplayMsg(message), getMasterIdFromDisplayMsg(message),
getTargetIdFromDisplayMsg(message), getTargetIdFromDisplayMsg(message),
target target,
), ),
}) }).then(()=>{
this.send(type, content, _uuid, message, target as string) this.send(type, content, _uuid, message, target as string)
})
} }
} }
...@@ -228,11 +226,8 @@ class MessageStore { ...@@ -228,11 +226,8 @@ class MessageStore {
// hideDatetime: false, // hideDatetime: false,
// logid: record.log_id, // logid: record.log_id,
// } // }
// if (this.isMessageDuplicated(message)) return // if (this.isMessageDuplicated(message)) return
// this.messages.unshift(message) // this.messages.unshift(message)
// // 新插入的消息和下面那条消息比较时间,小于两分钟就隐藏下面那条消息的时间 // // 新插入的消息和下面那条消息比较时间,小于两分钟就隐藏下面那条消息的时间
// const underMessage = this.messages[1] // const underMessage = this.messages[1]
// if (underMessage) { // if (underMessage) {
...@@ -307,6 +302,23 @@ class MessageStore { ...@@ -307,6 +302,23 @@ class MessageStore {
}, },
{ state: message.state }, { state: message.state },
) )
if (type === ChatMessageTypes.Card) {
if (content.bank === CONST_START_CHAT.user.id)
ChatListCardDB.getInstance().setChatStatus(
getFromId() as string,
target,
true,
)
else if (content.bank === CONST_END_CHAT.user.id) {
ChatListCardDB.getInstance().setChatStatus(
getFromId() as string,
target,
false,
)
}
}
/* 存数据库...... */ /* 存数据库...... */
}) })
.catch(() => { .catch(() => {
......
export interface iNotifyMsg {
staffMsg: string
userMsg: string
}
...@@ -7,5 +7,6 @@ export enum ChatMessageTypes { ...@@ -7,5 +7,6 @@ export enum ChatMessageTypes {
Video = 4, Video = 4,
File = 5, File = 5,
Card = 6, Card = 6,
Alert = 7,
robot = 100, robot = 100,
} }
import { CHAT_CONST_LIST } from '@/config/chat'
import { DisplayMessage } from '@/store/messagesStore'
import { eRole } from '@/types/roleType'
export default class ChatDataService {
static instance: ChatDataService
static getInstance() {
if (!ChatDataService.instance)
ChatDataService.instance = new ChatDataService()
return ChatDataService.instance
}
extractCommonMsgContentFromMsg(msg: DisplayMessage, role: eRole) {
const userId = msg.content.bank
const CONST = CHAT_CONST_LIST.find((i) => i.user.id === userId)
return eRole.user === role ? CONST?.user.value : CONST?.staff.value
}
}
...@@ -53,3 +53,52 @@ export const getDisplayNamesFromAddress = async ( ...@@ -53,3 +53,52 @@ export const getDisplayNamesFromAddress = async (
return msg?.user_name || msg?.phone 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;
})
}
...@@ -132,6 +132,7 @@ enum AlertType { ...@@ -132,6 +132,7 @@ enum AlertType {
UpdateGroupMutedAlert = 5; UpdateGroupMutedAlert = 5;
UpdateGroupMemberMutedAlert = 6; UpdateGroupMemberMutedAlert = 6;
UpdateGroupOwnerAlert = 7; UpdateGroupOwnerAlert = 7;
CommonMsg = 8;
} }
message AlertUpdateGroupName { message AlertUpdateGroupName {
......
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.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -531,5 +531,15 @@ jsBridge.prototype.bridge_quitApp = function (params, success) { ...@@ -531,5 +531,15 @@ jsBridge.prototype.bridge_quitApp = function (params, success) {
} }
} }
/* 去直播 */
jsBridge.prototype.bridge_live = function (params, success) {
if (this.curApp == ANDROID) {
dsBridge.call('bridge_live', params, success)
}
else if (this.curApp == IOS) {
this.callHandler('bridge_live', params, success)
}
}
export default jsBridge; export default jsBridge;
...@@ -10,12 +10,22 @@ ...@@ -10,12 +10,22 @@
<div class="flex flex-col flex-grow overflow-hidden" style="flex-basis: 0px"> <div class="flex flex-col flex-grow overflow-hidden" style="flex-basis: 0px">
<ChatContentVue /> <ChatContentVue />
<ServiceRating :setSelectedRate="handleSelect" :selected="selected" v-if="showServiceRating" /> <ServiceRating :setSelectedRate="handleSelect" :selected="selected" v-if="showServiceRating" />
<ChatOption <ChatOption>
:selected="selectedChatOption" <ChatOptionItemVue
:setSelected="handleSelectChatOption" v-if="isUser"
:list="optionList" :selected="questionSelected"
@click="handleClickQuestionOption"
value="常用问题"
/> />
<ChatInputVue /> <ChatOptionItemVue
v-if="isUser"
:selected="serviceSelected"
:value="serviceShowValue"
@click="handleClickService"
/>
<ChatOptionItemVue :selected="false" value="电话联系" @click="handleClickCall" />
</ChatOption>
<ChatInputVue :serviceShowValue="serviceShowValue"/>
<CommonUseSentence <CommonUseSentence
class="transition-all h-0" class="transition-all h-0"
:class="{ 'h-40': showShortSentences }" :class="{ 'h-40': showShortSentences }"
...@@ -24,6 +34,7 @@ ...@@ -24,6 +34,7 @@
:list="sentenceList" :list="sentenceList"
/> />
</div> </div>
<ShowCall :show="showCall" :phone="callPhone" @hidden="showCall = false" />
</div> </div>
</template> </template>
...@@ -41,7 +52,13 @@ import { v4 as uuidv4 } from 'uuid' ...@@ -41,7 +52,13 @@ import { v4 as uuidv4 } from 'uuid'
import { ChatMessageTypes } from "@/types/chatMessageTypes"; import { ChatMessageTypes } from "@/types/chatMessageTypes";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { queryFaqAnswer, queryFaqList } from "@/service/FaqService"; import { queryFaqAnswer, queryFaqList } from "@/service/FaqService";
import { getDisplayNamesFromAddress } from "@/utils/displayName"; import { getDisplayNamesFromAddress, getMsgFromAddress } from "@/utils/displayName";
import { MessageContent } from "@/types/chat-message";
import { CONST_END_CHAT, CONST_START_CHAT } 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({ export default defineComponent({
...@@ -51,14 +68,69 @@ export default defineComponent({ ...@@ -51,14 +68,69 @@ export default defineComponent({
NavBar, NavBar,
ServiceRating: defineAsyncComponent(() => import(/* webpackChunkName: 'serviceRating' */ "@/components/ServiceRating/index.vue")), ServiceRating: defineAsyncComponent(() => import(/* webpackChunkName: 'serviceRating' */ "@/components/ServiceRating/index.vue")),
ChatOption: defineAsyncComponent(() => import(/* webpackChunkName: 'ChatOption' */"@/components/ChatOptions/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() { 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: CONST_START_CHAT.user.id,
name: CONST_START_CHAT.staff.id,
account: '',
} as MessageContent
})
serviceShowValue.value = '结束服务'
} else if (serviceShowValue.value === '结束服务') {
serviceShowValue.value = '人工服务'
sendChatMessage({
type: ChatMessageTypes.Card,
content: {
bank: CONST_END_CHAT.user.id,
name: CONST_END_CHAT.staff.id,
account: '',
} as MessageContent
})
// showServiceRating.value = true;
}
}
onMounted(async () => {
const inChat = await ChatListCardDB.getInstance().getChatStatus(getFromId() as string, target)
serviceShowValue.value = inChat ? '结束服务' : '人工服务'
})
const initError = ref(false); const initError = ref(false);
const showServiceRating = ref(false); const showServiceRating = ref(false);
const selected = ref(""); const selected = ref("");
const selectedChatOption = ref(NaN);
const showShortSentences = ref(false); const showShortSentences = ref(false);
const route = useRoute() const route = useRoute()
...@@ -67,38 +139,16 @@ export default defineComponent({ ...@@ -67,38 +139,16 @@ export default defineComponent({
const sentenceList = ref<any[]>([]) const sentenceList = ref<any[]>([])
const sentensesLoading = ref(false) const sentensesLoading = ref(false)
const optionList = [
{ name: '常用问题', id: 1 },
{ name: '人工服务', id: 2 },
{ name: '电话咨询', id: 3 },
];
const setShowSentences = (show: boolean) => const setShowSentences = (show: boolean) =>
(showShortSentences.value = show); (showShortSentences.value = show);
const handleSelect = (select: string) => (selected.value = select); 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) => { const useSentence = (content: string) => {
/* 问 */ /* 问 */
...@@ -153,6 +203,15 @@ export default defineComponent({ ...@@ -153,6 +203,15 @@ export default defineComponent({
onMounted(async () => { onMounted(async () => {
const list = await getDisplayNamesFromAddress([target]) const list = await getDisplayNamesFromAddress([target])
title.value = list[0]; 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 +221,19 @@ export default defineComponent({ ...@@ -162,13 +221,19 @@ export default defineComponent({
handleSelect, handleSelect,
showServiceRating, showServiceRating,
showShortSentences, showShortSentences,
selectedChatOption,
handleSelectChatOption,
useSentence, useSentence,
sentenceList, sentenceList,
optionList,
sentensesLoading, sentensesLoading,
title title,
questionSelected,
handleClickQuestionOption,
serviceSelected,
serviceShowValue,
handleClickService,
handleClickCall,
showCall,
callPhone,
isUser
}; };
}, },
}); });
......
<template> <template>
<div> <div>
<div v-if="!hideDatetime" class="text-xs text-gray-400 text-center pb-2 pt-4">{{ time }}</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 <div
class="flex items-start flex-nowrap w-screen py-1.5" class="flex items-start flex-nowrap w-screen py-1.5"
:class="{ 'flex-row-reverse': fromMyself }" :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" /> <img :src="default_avatar_url" />
</q-avatar> </q-avatar>
...@@ -53,12 +59,6 @@ ...@@ -53,12 +59,6 @@
:uploadProgress="uploadProgress" :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"> <div class="w-10 self-stretch flex flex-row justify-center items-center">
......
<template> <template>
<div :class="fromMyself ? 'bg-secondary' : 'bg-white'" class="w-full h-24 rounded-md font-medium"> <div class="w-full rounded-md font-medium flex items-center">
<div class="py-3 px-3 flex items-center enable-touch"> <div class="flex-grow border-b mr-1 ml-2"></div>
<q-icon :name="'img:' + iconUrl" size="28px" class="mr-1" /> {{ content.bank }} <div class="text-center" v-if="isUser">{{ sentence?.user.value }}</div>
</div> <div class="text-center" v-else>{{ sentence?.staff.value }}</div>
<div class="pb-3 px-2 flex flex-nowrap justify-between text-base break-all enable-touch"> <div class="flex-grow border-b ml-1 mr-2"></div>
<div>{{ content.name }}</div>
<div>{{ content.account }}</div>
</div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue' import { defineComponent, PropType } from 'vue'
import iconUrl from '@/assets/message_bank_card.png' import iconUrl from '@/assets/message_bank_card.png'
import { getUserMsg } from '@/utils/userMsg'
import { eRole } from '@/types/roleType'
import { CHAT_CONST_LIST } from '@/config/chat'
export default defineComponent({
props: { fromMyself: Boolean, content: Object },
setup() { export default defineComponent({
return { iconUrl } props: {
fromMyself: Boolean,
content: {
required: true,
type: Object as PropType<{ bank: string, name: string, account: string }>,
}
},
setup(props) {
const isUser = getUserMsg()?.role === eRole.user
const sentence = CHAT_CONST_LIST.find(i => i.user.id === props?.content.bank)
return { iconUrl, isUser, sentence, CHAT_CONST_LIST }
}, },
}) })
</script> </script>
...@@ -6,15 +6,13 @@ ...@@ -6,15 +6,13 @@
@click="inputType === 1 ? (inputType = 2) : (inputType = 1)" @click="inputType === 1 ? (inputType = 2) : (inputType = 1)"
class="w-7 h-7 mx-2.5 text-center select-none focus:outline-none" 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" <i v-if="inputType === 1" class="iconfont text-primary text-xl">&#xe604;</i>
>&#xe604;</i
>
<i v-else class="iconfont text-primary text-xl">&#xe60d;</i> <i v-else class="iconfont text-primary text-xl">&#xe60d;</i>
</button> </button>
<ChatInputTextVue <ChatInputTextVue
v-if="inputType === 1" v-if="inputType === 1"
@send="sendChatMessage" @send="handleSend"
@click="showMenu = false" @click="showMenu = false"
class="pl-5" class="pl-5"
/> />
...@@ -31,30 +29,14 @@ ...@@ -31,30 +29,14 @@
<!-- 有输入文字,显示 `发送` 按钮 --> <!-- 有输入文字,显示 `发送` 按钮 -->
<button <button
v-else v-else
@click="inputText.trim().length !== 0 &&sendChatMessage({ type: 1, content: { content: inputText } })" @click="inputText.trim().length !== 0 && handleSend()"
class=" class="mx-2.5 px-4 py-1.5 flex items-center rounded-md text-center select-none focus:outline-none text-app-white"
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)" style="background: rgb(7, 193, 99)"
> >发送</button>
发送
</button>
</div> </div>
<!-- input menu --> <!-- input menu -->
<div <div v-show="showMenu" class="min-h-input-menu flex items-center px-8 text-sm text-subtle">
v-show="showMenu"
class="min-h-input-menu flex items-center px-8 text-sm text-subtle"
>
<ChatInputAlbumVue /> <ChatInputAlbumVue />
<!-- <ChatInputCameraVue /> --> <!-- <ChatInputCameraVue /> -->
</div> </div>
...@@ -69,13 +51,16 @@ import { MessageContent } from "@/types/chat-message"; ...@@ -69,13 +51,16 @@ import { MessageContent } from "@/types/chat-message";
import ChatInputTextVue from "./ChatInputText.vue"; import ChatInputTextVue from "./ChatInputText.vue";
import ChatInputAlbumVue from "./ChatInputAlbum.vue"; import ChatInputAlbumVue from "./ChatInputAlbum.vue";
import ChatInputCameraVue from "./ChatInputCamera.vue"; import ChatInputCameraVue from "./ChatInputCamera.vue";
import { target } from "@/store/appCallerStore"; import { getFromId, target } from "@/store/appCallerStore";
// import { from } from "@/store/appCallerStore";
import { textInputStore } from "@/store/textInputStore"; import { textInputStore } from "@/store/textInputStore";
import { v4 as uuidv4 } from 'uuid'
import Icon from "@/components/common/Icon.vue"; import Icon from "@/components/common/Icon.vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
export default defineComponent({ export default defineComponent({
props: {
serviceShowValue: String,
},
components: { components: {
ChatInputTextVue, ChatInputTextVue,
ChatInputAlbumVue, ChatInputAlbumVue,
...@@ -83,7 +68,7 @@ export default defineComponent({ ...@@ -83,7 +68,7 @@ export default defineComponent({
Icon, Icon,
}, },
setup() { setup(props) {
const route = useRoute(); const route = useRoute();
const enum InputType { const enum InputType {
text = 1, text = 1,
...@@ -104,7 +89,7 @@ export default defineComponent({ ...@@ -104,7 +89,7 @@ export default defineComponent({
type: ChatMessageTypes; type: ChatMessageTypes;
content: MessageContent; 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(); textInputStore.clearTextMessage();
}; };
...@@ -126,11 +111,33 @@ export default defineComponent({ ...@@ -126,11 +111,33 @@ export default defineComponent({
// } // }
// }) // })
const handleSend = () => {
console.log('handle send');
if (props.serviceShowValue === "人工服务") {
messageStore.displayNewMessage({
content: {
content: inputText.value
},
from: getFromId() as string,
target: target,
uuid: uuidv4(),
state: 'success',
datetime: new Date().getTime(),
type: ChatMessageTypes.robot,
})
textInputStore.clearTextMessage();
} else {
sendChatMessage({ type: 1, content: { content: inputText.value } })
}
}
return { return {
inputType, inputType,
inputText, inputText,
showMenu, showMenu,
sendChatMessage, sendChatMessage,
handleSend
// showReceiptInput, // showReceiptInput,
}; };
}, },
......
...@@ -11,6 +11,9 @@ import { useRoute } from "vue-router"; ...@@ -11,6 +11,9 @@ import { useRoute } from "vue-router";
import { queryLoanProductInfo } from "@/service/LoanProductService/index" import { queryLoanProductInfo } from "@/service/LoanProductService/index"
import { iLoanProdcutItem,eGuaranteeType } from "@/service/LoanProductService/type" import { iLoanProdcutItem,eGuaranteeType } from "@/service/LoanProductService/type"
import { filterGuaranteeType } from "@/utils/guarantee-type" import { filterGuaranteeType } from "@/utils/guarantee-type"
import { Skeleton } from "vant"
import { iNearbyOutLet } from "@/service/AddressService/types"
import AddressService from "@/service/AddressService"
function isInViewPort(element: HTMLElement, barHeight: number) { function isInViewPort(element: HTMLElement, barHeight: number) {
const viewWidth = window.innerWidth || document.documentElement.clientWidth; const viewWidth = window.innerWidth || document.documentElement.clientWidth;
...@@ -30,6 +33,7 @@ export default defineComponent({ ...@@ -30,6 +33,7 @@ export default defineComponent({
LoanDetailDescribe, LoanDetailDescribe,
Branch, Branch,
Transition, Transition,
Skeleton
}, },
setup() { setup() {
const applyEl = ref(); const applyEl = ref();
...@@ -50,6 +54,24 @@ export default defineComponent({ ...@@ -50,6 +54,24 @@ export default defineComponent({
const apply_to= ref('') const apply_to= ref('')
const apply_cond= ref('') const apply_cond= ref('')
const submit_cond= ref('') const submit_cond= ref('')
const state = reactive({
outletList: [] as iNearbyOutLet[],
loading: false,
})
const fetchBranch = async () =>
{
state.loading = true;
const ret = await AddressService.getInstance().getNearby({
bank_code: Number(process.env.VUE_APP_BANK_CODE),
number: 1,
})
if (ret.code === 200) {
state.outletList = ret.data;
console.log(state.outletList[0]);
}
state.loading = false;
}
onMounted(() => { onMounted(() => {
uuid.value = useRoute().params.uuid as string uuid.value = useRoute().params.uuid as string
...@@ -72,6 +94,8 @@ export default defineComponent({ ...@@ -72,6 +94,8 @@ export default defineComponent({
apply_cond.value = productItem.apply_cond apply_cond.value = productItem.apply_cond
submit_cond.value = productItem.submit_cond submit_cond.value = productItem.submit_cond
} }
fetchBranch()
}) })
const barEle = document.querySelector(".theBar"); const barEle = document.querySelector(".theBar");
...@@ -203,8 +227,24 @@ export default defineComponent({ ...@@ -203,8 +227,24 @@ export default defineComponent({
</div> </div>
</div> </div>
<LoanDetailDescribe class=" mt-5" products={products.value} features={features.value} apply_to={apply_to.value} apply_cond={apply_cond.value} submit_cond={submit_cond.value}/> <LoanDetailDescribe class=" mt-5" products={products.value} features={features.value} apply_to={apply_to.value} apply_cond={apply_cond.value} submit_cond={submit_cond.value}/>
<div class="title mx-5 mt-5">营业网点</div> <div class="title mx-5 mt-5" >营业网点</div>
<Branch class=" mx-5 mt-2.5 mb-4" /> <Skeleton loading={state.loading} row={4} class="mt-2">
{ state.outletList[0]&&(
<branch
class="my-3 mx-5"
name={state.outletList[0].name}
distance={state.outletList[0].distance}
is_normal_work={state.outletList[0].is_normal_work}
latitude={state.outletList[0].latitude}
location={state.outletList[0].location}
longitude={state.outletList[0].longitude}
opening_hours={state.outletList[0].opening_hours}
weekend_status={state.outletList[0].weekend_status}
outlet_id={state.outletList[0].outlet_id}
/>
)
}
</Skeleton>
</div> </div>
<div class="h-12"></div> <div class="h-12"></div>
<transition name="fade" mode="out-in"> <transition name="fade" mode="out-in">
......
...@@ -4,20 +4,9 @@ ...@@ -4,20 +4,9 @@
v-for="app in appList" v-for="app in appList"
:key="app.name" :key="app.name"
class="w-1/4 mb-5 text-center" class="w-1/4 mb-5 text-center"
@click="$router.push({ name: app.routerName })" @click="app.cb && app.cb() || $router.push({ name: app.routerName })"
>
<div
class="
w-16
h-16
bg-white
app-container
mx-auto
flex
items-center
justify-center
"
> >
<div class="w-16 h-16 bg-white app-container mx-auto flex items-center justify-center">
<Icon :name="app.icon" :color="app.color" size="25" /> <Icon :name="app.icon" :color="app.color" size="25" />
</div> </div>
<div class="mt-2.5 app-name">{{ app.name }}</div> <div class="mt-2.5 app-name">{{ app.name }}</div>
......
import Bridge from "@/utils/jsBridge2"
export default [ export default [
{ {
name: '贷款服务', name: '贷款服务',
...@@ -38,6 +40,9 @@ export default [ ...@@ -38,6 +40,9 @@ export default [
name: '精彩直播', name: '精彩直播',
icon: 'icon-jingcaizhibo', icon: 'icon-jingcaizhibo',
color: '#0FCBA5', color: '#0FCBA5',
cb(){
new Bridge().bridge_live()
},
}, },
{ {
name: '消息中心', name: '消息中心',
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
</span> </span>
</div> </div>
<span class="word27">¥</span> <span class="word27">¥</span>
<span class="txt14">1,000,000</span> <span class="txt14">{{ limit.max_amount }}</span>
</div> </div>
</div> </div>
<div class="outer55" v-else-if="eLoanMode.company === mode"> <div class="outer55" v-else-if="eLoanMode.company === mode">
...@@ -48,10 +48,10 @@ ...@@ -48,10 +48,10 @@
</div> </div>
<div class="outer7 flex-row"> <div class="outer7 flex-row">
<span class="info15">¥</span> <span class="info15">¥</span>
<span class="txt10">1,000,000</span> <span class="txt10">{{ limit.en_max_amount }}</span>
</div> </div>
<div class="outer8 flex-row"> <div class="outer8 flex-row">
<span class="word33">年利率最低4.35%</span> <span class="word33">年利率最低{{ limit.en_rate_lower }}%</span>
<div class="main22 flex-col"></div> <div class="main22 flex-col"></div>
<span class="word34">分秒必批</span> <span class="word34">分秒必批</span>
<div class="main22 flex-col"></div> <div class="main22 flex-col"></div>
...@@ -65,11 +65,12 @@ ...@@ -65,11 +65,12 @@
<!-- 非热门贷款 --> <!-- 非热门贷款 -->
<GroupTitle <GroupTitle
title="贷款精选" title="贷款精选"
v-if="state.allProductList"
@seeMore="$router.push({ name: 'LoanList', params: { mode: mode } })" @seeMore="$router.push({ name: 'LoanList', params: { mode: mode } })"
/> />
<Skeleton :row="3" :loading="skeLoading"> <Skeleton :row="3" :loading="skeLoading" style="margin-top: 20px" v-if="state.allProductList">
<LoanCard <LoanCard
v-for="item in allProductList" v-for="item in state.allProductList"
:key="item.value" :key="item.value"
:max_amount="item.max_amount" :max_amount="item.max_amount"
:product_name="item.product_name" :product_name="item.product_name"
...@@ -115,7 +116,7 @@ ...@@ -115,7 +116,7 @@
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { defineComponent, ref } from "vue"; import { defineComponent, ref, toRefs } from "vue";
import { eLoanMode } from "./types"; import { eLoanMode } from "./types";
import LoanHotCard from "@/components/Loan/LoanHotCard/index.vue"; import LoanHotCard from "@/components/Loan/LoanHotCard/index.vue";
import LoanHotSwipe from "@/components/Loan/LoanHotSwipe/index.vue"; import LoanHotSwipe from "@/components/Loan/LoanHotSwipe/index.vue";
...@@ -131,6 +132,7 @@ import { Skeleton } from "vant"; ...@@ -131,6 +132,7 @@ import { Skeleton } from "vant";
import { import {
queryLoanProductList, queryLoanProductList,
queryLoanProductInfo, queryLoanProductInfo,
queryLimit,
} from "@/service/LoanProductService"; } from "@/service/LoanProductService";
const mode = ref(eLoanMode.personal); const mode = ref(eLoanMode.personal);
...@@ -138,12 +140,19 @@ let skeLoading = ref(false); ...@@ -138,12 +140,19 @@ let skeLoading = ref(false);
const setMode = (v: eLoanMode) => { const setMode = (v: eLoanMode) => {
mode.value = v; mode.value = v;
}; };
let allProductList: Array<simpleItemInfo> = reactive([]); let state = reactive({ allProductList: [] as Array<simpleItemInfo> });
const src = ref(""); const src = ref("");
const uuid = ref(""); const uuid = ref("");
const hotNews = ref([]) const hotNews = ref([]);
const limit = reactive({
en_max_amount: "",
en_rate_lower: "",
max_amount: "",
state: false,
});
watch(mode, () => { watch(mode, () => {
allProductList = []; state.allProductList = [];
fetchList(); fetchList();
}); });
...@@ -154,7 +163,7 @@ const getNews = () => { ...@@ -154,7 +163,7 @@ const getNews = () => {
}).then((res: any) => { }).then((res: any) => {
hotNews.value = res.data.items; hotNews.value = res.data.items;
}); });
} };
const fetchActivityList = () => { const fetchActivityList = () => {
skeLoading.value = true; skeLoading.value = true;
...@@ -181,7 +190,7 @@ const fetchList = () => { ...@@ -181,7 +190,7 @@ const fetchList = () => {
queryLoanProductInfo({ uuid }).then((ret) => { queryLoanProductInfo({ uuid }).then((ret) => {
const { max_amount, inst_name, uuid, features, product_name } = const { max_amount, inst_name, uuid, features, product_name } =
ret.data; ret.data;
allProductList.push({ state.allProductList.push({
max_amount, max_amount,
product_name, product_name,
features, features,
...@@ -193,7 +202,25 @@ const fetchList = () => { ...@@ -193,7 +202,25 @@ const fetchList = () => {
} }
}); });
}; };
const formatLimit = (limit: string): string => {
return Number(limit + "0000").toLocaleString();
};
const fetchLimit = () => {
limit.state = true;
queryLimit().then((ret) => {
if (ret.code == 200) {
const data = ret.data;
limit.max_amount = formatLimit(data.max_amount);
limit.en_max_amount = formatLimit(data.en_max_amount);
limit.en_rate_lower = data.en_rate_lower;
}
});
};
onMounted(() => { onMounted(() => {
fetchLimit();
fetchList(); fetchList();
fetchActivityList(); fetchActivityList();
getNews(); getNews();
......
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