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>
<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>
<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
class="flex justify-center swpiItem"
v-for="item in hotProductList"
v-for="item in state.hotProductList"
:key="item.value"
>
<Skeleton :row="3" :loading="skeLoading">
<LoanHotCard
:inst_name="item.inst_name"
:product_name="item.product_name"
......@@ -14,9 +14,9 @@
:max_amount="item.max_amount"
:uuid="item.uuid"
/>
</Skeleton>
</van-swipe-item>
</van-swipe>
</Skeleton>
</template>
<script lang="ts" setup>
import { ref } from "vue";
......@@ -28,7 +28,7 @@ import {
import { onMounted, PropType, reactive, watch } from "@vue/runtime-core";
import { eLoanMode } from "@/views/withMenu/Loan/types";
import { hotProduct } from "./type";
import { Skeleton} from "vant"
import { Skeleton } from "vant";
const props = defineProps({
loanMode: {
......@@ -37,45 +37,44 @@ const props = defineProps({
},
});
let skeLoading = ref(false)
let hotProductList: Array<hotProduct> = reactive([]);
let skeLoading = ref(true);
let state = reactive({hotProductList: [] as Array<hotProduct>})
watch(props,(newV,oldV)=>{
console.log(props.loanMode);
hotProductList=[]
fetchList()
})
watch(props, (newV, oldV) => {
state.hotProductList = [];
fetchList();
});
onMounted(() => {
fetchList()
fetchList();
});
const fetchList = ()=>{
skeLoading.value = true
const fetchList = () => {
skeLoading.value = true;
queryLoanProductList({
limit: 3,
loan_type: props.loanMode!,
offset: 0,
}).then((ret) => {
if (ret.code === 200) {
skeLoading.value = false
skeLoading.value = false;
ret.data.uuid.map((uuid) => {
queryLoanProductInfo({ uuid }).then((ret) => {
const { rate_lower, max_amount, max_date, inst_name, product_name } =
ret.data;
hotProductList.push({
state.hotProductList.push({
rate_lower,
max_amount,
max_date,
inst_name,
product_name,
uuid
uuid,
});
});
});
}
});
}
};
</script>
<style lang="less" scoped>
......
......@@ -18,6 +18,7 @@
name="icon-kefu"
class="absolute left-11"
size="18"
@click="$router.push({name:'Chat'})"
:color="iconColor"
/>
<icon
......
<template>
<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">
<icon
name="icon-a-dianhua"
......@@ -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 = '客户已接入会话,请尽快联系客户'
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 { ChatMessageTypes } from '@/types/chatMessageTypes'
import { eRole } from '@/types/roleType'
import ChatDataService from '@/utils/ChatDataService'
import {
getMasterIdFromDisplayMsg,
getTargetIdFromDisplayMsg,
} from '@/utils/chatutils'
import { getUserMsg } from '@/utils/userMsg'
import { iChatListCard, MyAppDatabase } from './index'
export default class ChatListCardDB extends MyAppDatabase {
......@@ -72,7 +76,17 @@ export default class ChatListCardDB extends MyAppDatabase {
})
.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
this.updateCard(
......@@ -90,13 +104,14 @@ export default class ChatListCardDB extends MyAppDatabase {
const content = data.msg.content?.content || '[新消息]'
const masterId = getMasterIdFromDisplayMsg(data.msg)
const targetId = getTargetIdFromDisplayMsg(data.msg)
console.log(data.msg, "in addNewCard");
console.log(data.msg, 'in addNewCard')
this.saveCard({
masterId,
targetId: targetId,
unreadMsgCount: data.isChattingWithTargetId ? 0 : 1,
content,
inChat: false,
})
}
......@@ -109,4 +124,24 @@ export default class ChatListCardDB extends MyAppDatabase {
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 {
targetId: string
unreadMsgCount: number
content: string
inChat: boolean // 会话状态,会话中?
}
export class MyAppDatabase extends Dexie {
......@@ -25,12 +26,11 @@ export class MyAppDatabase extends Dexie {
this.version(1.2).stores({
chatMessage:
'++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',
userInfo: '++id, created_at, phone, remark, user_name, uuid, addr',
})
this.chatMessage = this.table('chatMessage')
this.chatListCard = this.table('chatListCard')
this.contactPerson = this.table('contactPerson')
......
......@@ -2,6 +2,8 @@ import baseAxios from '../index'
import { eLoanMode } from '@/views/withMenu/Loan/types'
import { iLoanProdcutItem } from "./type"
const prefix = '/loan/query'
export function queryLoanProductList(data: {
limit: number,
loan_type:eLoanMode
......@@ -12,7 +14,7 @@ export function queryLoanProductList(data: {
uuid: string[],
total: number
}>({
url: '/loan/query/list',
url: prefix+'/list',
method: 'POST',
data
})
......@@ -20,7 +22,7 @@ export function queryLoanProductList(data: {
export function queryLoanProductInfo(data: { uuid: string }) {
return baseAxios<iLoanProdcutItem>({
url: '/loan/query/info',
url: prefix+'/info',
method: 'GET',
params: data
})
......@@ -54,11 +56,22 @@ export function queryDirectLoanReq(data: {
items: iLoanProdcutItem[]
total: number
}>({
url: '/loan/query/direct/list',
url: prefix+'/direct/list',
method: 'POST',
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 @@
import { MessageContent } from '@/types/chat-message'
import { reactive, Ref, ref } from '@vue/reactivity'
import {
target as __target,
getFromId
} from '@/store/appCallerStore'
import { target as __target, getFromId } from '@/store/appCallerStore'
import { ChatMessageTypes } from '@/types/chatMessageTypes'
import encodeChatMessage from '@/utils/fzm-message-protocol-chat/encodeChatMessage'
import { v4 as uuidv4 } from 'uuid'
......@@ -26,6 +23,8 @@ import {
getTargetIdFromDisplayMsg,
} from '@/utils/chatutils'
import { useRoute } from 'vue-router'
import ChatListCardDB from '@/db/ChatListCardDB'
import { CONST_END_CHAT, CONST_START_CHAT } from '@/config/chat'
/** 多媒体消息的上传进度 */
export interface UploadProgress {
......@@ -116,7 +115,6 @@ class MessageStore {
target: string
uuid?: string
}) {
const _uuid = uuid || uuidv4()
/** 聊天界面显示的消息 */
......@@ -189,17 +187,17 @@ class MessageStore {
}
// 文本类消息,不需要上传 OSS,直接发送
else {
ChatDBService.getInstance().handleEveryReceive({
msg: message,
masterId: getMasterIdFromDisplayMsg(message),
isChattingWithTargetId: isChattingWith(
getMasterIdFromDisplayMsg(message),
getTargetIdFromDisplayMsg(message),
target
target,
),
})
}).then(()=>{
this.send(type, content, _uuid, message, target as string)
})
}
}
......@@ -228,11 +226,8 @@ class MessageStore {
// hideDatetime: false,
// logid: record.log_id,
// }
// if (this.isMessageDuplicated(message)) return
// this.messages.unshift(message)
// // 新插入的消息和下面那条消息比较时间,小于两分钟就隐藏下面那条消息的时间
// const underMessage = this.messages[1]
// if (underMessage) {
......@@ -307,6 +302,23 @@ class MessageStore {
},
{ 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(() => {
......
export interface iNotifyMsg {
staffMsg: string
userMsg: string
}
......@@ -7,5 +7,6 @@ export enum ChatMessageTypes {
Video = 4,
File = 5,
Card = 6,
Alert = 7,
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 (
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 {
UpdateGroupMutedAlert = 5;
UpdateGroupMemberMutedAlert = 6;
UpdateGroupOwnerAlert = 7;
CommonMsg = 8;
}
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.
......@@ -3365,6 +3365,7 @@ export const dtalk = $root.dtalk = (() => {
case 5:
case 6:
case 7:
case 8:
break;
}
if (message.body != null && message.hasOwnProperty("body"))
......@@ -3418,6 +3419,10 @@ export const dtalk = $root.dtalk = (() => {
case 7:
message.type = 7;
break;
case "CommonMsg":
case 8:
message.type = 8;
break;
}
if (object.body != null)
if (typeof object.body === "string")
......@@ -3990,6 +3995,7 @@ export const dtalk = $root.dtalk = (() => {
* @property {number} UpdateGroupMutedAlert=5 UpdateGroupMutedAlert value
* @property {number} UpdateGroupMemberMutedAlert=6 UpdateGroupMemberMutedAlert value
* @property {number} UpdateGroupOwnerAlert=7 UpdateGroupOwnerAlert value
* @property {number} CommonMsg=8 CommonMsg value
*/
proto.AlertType = (function() {
const valuesById = {}, values = Object.create(valuesById);
......@@ -4001,6 +4007,7 @@ export const dtalk = $root.dtalk = (() => {
values[valuesById[5] = "UpdateGroupMutedAlert"] = 5;
values[valuesById[6] = "UpdateGroupMemberMutedAlert"] = 6;
values[valuesById[7] = "UpdateGroupOwnerAlert"] = 7;
values[valuesById[8] = "CommonMsg"] = 8;
return values;
})();
......@@ -5970,6 +5977,216 @@ export const dtalk = $root.dtalk = (() => {
return AlertUpdateGroupOwner;
})();
proto.AlertCommonMsg = (function() {
/**
* Properties of an AlertCommonMsg.
* @memberof dtalk.proto
* @interface IAlertCommonMsg
* @property {string|null} [user] AlertCommonMsg user
* @property {string|null} [staff] AlertCommonMsg staff
*/
/**
* Constructs a new AlertCommonMsg.
* @memberof dtalk.proto
* @classdesc Represents an AlertCommonMsg.
* @implements IAlertCommonMsg
* @constructor
* @param {dtalk.proto.IAlertCommonMsg=} [properties] Properties to set
*/
function AlertCommonMsg(properties) {
if (properties)
for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null)
this[keys[i]] = properties[keys[i]];
}
/**
* AlertCommonMsg user.
* @member {string} user
* @memberof dtalk.proto.AlertCommonMsg
* @instance
*/
AlertCommonMsg.prototype.user = "";
/**
* AlertCommonMsg staff.
* @member {string} staff
* @memberof dtalk.proto.AlertCommonMsg
* @instance
*/
AlertCommonMsg.prototype.staff = "";
/**
* Creates a new AlertCommonMsg instance using the specified properties.
* @function create
* @memberof dtalk.proto.AlertCommonMsg
* @static
* @param {dtalk.proto.IAlertCommonMsg=} [properties] Properties to set
* @returns {dtalk.proto.AlertCommonMsg} AlertCommonMsg instance
*/
AlertCommonMsg.create = function create(properties) {
return new AlertCommonMsg(properties);
};
/**
* Encodes the specified AlertCommonMsg message. Does not implicitly {@link dtalk.proto.AlertCommonMsg.verify|verify} messages.
* @function encode
* @memberof dtalk.proto.AlertCommonMsg
* @static
* @param {dtalk.proto.IAlertCommonMsg} message AlertCommonMsg message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
AlertCommonMsg.encode = function encode(message, writer) {
if (!writer)
writer = $Writer.create();
if (message.user != null && Object.hasOwnProperty.call(message, "user"))
writer.uint32(/* id 1, wireType 2 =*/10).string(message.user);
if (message.staff != null && Object.hasOwnProperty.call(message, "staff"))
writer.uint32(/* id 2, wireType 2 =*/18).string(message.staff);
return writer;
};
/**
* Encodes the specified AlertCommonMsg message, length delimited. Does not implicitly {@link dtalk.proto.AlertCommonMsg.verify|verify} messages.
* @function encodeDelimited
* @memberof dtalk.proto.AlertCommonMsg
* @static
* @param {dtalk.proto.IAlertCommonMsg} message AlertCommonMsg message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
AlertCommonMsg.encodeDelimited = function encodeDelimited(message, writer) {
return this.encode(message, writer).ldelim();
};
/**
* Decodes an AlertCommonMsg message from the specified reader or buffer.
* @function decode
* @memberof dtalk.proto.AlertCommonMsg
* @static
* @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
* @param {number} [length] Message length if known beforehand
* @returns {dtalk.proto.AlertCommonMsg} AlertCommonMsg
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
AlertCommonMsg.decode = function decode(reader, length) {
if (!(reader instanceof $Reader))
reader = $Reader.create(reader);
let end = length === undefined ? reader.len : reader.pos + length, message = new $root.dtalk.proto.AlertCommonMsg();
while (reader.pos < end) {
let tag = reader.uint32();
switch (tag >>> 3) {
case 1:
message.user = reader.string();
break;
case 2:
message.staff = reader.string();
break;
default:
reader.skipType(tag & 7);
break;
}
}
return message;
};
/**
* Decodes an AlertCommonMsg message from the specified reader or buffer, length delimited.
* @function decodeDelimited
* @memberof dtalk.proto.AlertCommonMsg
* @static
* @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
* @returns {dtalk.proto.AlertCommonMsg} AlertCommonMsg
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
AlertCommonMsg.decodeDelimited = function decodeDelimited(reader) {
if (!(reader instanceof $Reader))
reader = new $Reader(reader);
return this.decode(reader, reader.uint32());
};
/**
* Verifies an AlertCommonMsg message.
* @function verify
* @memberof dtalk.proto.AlertCommonMsg
* @static
* @param {Object.<string,*>} message Plain object to verify
* @returns {string|null} `null` if valid, otherwise the reason why it is not
*/
AlertCommonMsg.verify = function verify(message) {
if (typeof message !== "object" || message === null)
return "object expected";
if (message.user != null && message.hasOwnProperty("user"))
if (!$util.isString(message.user))
return "user: string expected";
if (message.staff != null && message.hasOwnProperty("staff"))
if (!$util.isString(message.staff))
return "staff: string expected";
return null;
};
/**
* Creates an AlertCommonMsg message from a plain object. Also converts values to their respective internal types.
* @function fromObject
* @memberof dtalk.proto.AlertCommonMsg
* @static
* @param {Object.<string,*>} object Plain object
* @returns {dtalk.proto.AlertCommonMsg} AlertCommonMsg
*/
AlertCommonMsg.fromObject = function fromObject(object) {
if (object instanceof $root.dtalk.proto.AlertCommonMsg)
return object;
let message = new $root.dtalk.proto.AlertCommonMsg();
if (object.user != null)
message.user = String(object.user);
if (object.staff != null)
message.staff = String(object.staff);
return message;
};
/**
* Creates a plain object from an AlertCommonMsg message. Also converts values to other types if specified.
* @function toObject
* @memberof dtalk.proto.AlertCommonMsg
* @static
* @param {dtalk.proto.AlertCommonMsg} message AlertCommonMsg
* @param {$protobuf.IConversionOptions} [options] Conversion options
* @returns {Object.<string,*>} Plain object
*/
AlertCommonMsg.toObject = function toObject(message, options) {
if (!options)
options = {};
let object = {};
if (options.defaults) {
object.user = "";
object.staff = "";
}
if (message.user != null && message.hasOwnProperty("user"))
object.user = message.user;
if (message.staff != null && message.hasOwnProperty("staff"))
object.staff = message.staff;
return object;
};
/**
* Converts this AlertCommonMsg to JSON.
* @function toJSON
* @memberof dtalk.proto.AlertCommonMsg
* @instance
* @returns {Object.<string,*>} JSON object
*/
AlertCommonMsg.prototype.toJSON = function toJSON() {
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
};
return AlertCommonMsg;
})();
proto.NotifyMsg = (function() {
/**
......
......@@ -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;
......@@ -10,12 +10,22 @@
<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="常用问题"
/>
<ChatInputVue />
<ChatOptionItemVue
v-if="isUser"
:selected="serviceSelected"
:value="serviceShowValue"
@click="handleClickService"
/>
<ChatOptionItemVue :selected="false" value="电话联系" @click="handleClickCall" />
</ChatOption>
<ChatInputVue :serviceShowValue="serviceShowValue"/>
<CommonUseSentence
class="transition-all h-0"
:class="{ 'h-40': showShortSentences }"
......@@ -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 { 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({
......@@ -51,14 +68,69 @@ 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: 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 showServiceRating = ref(false);
const selected = ref("");
const selectedChatOption = ref(NaN);
const showShortSentences = ref(false);
const route = useRoute()
......@@ -67,38 +139,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 +203,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 +221,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,12 +59,6 @@
: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">{{ sentence?.user.value }}</div>
<div class="text-center" v-else>{{ sentence?.staff.value }}</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'
import { CHAT_CONST_LIST } from '@/config/chat'
export default defineComponent({
props: { fromMyself: Boolean, content: Object },
setup() {
return { iconUrl }
export default defineComponent({
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>
......@@ -6,15 +6,13 @@
@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>
<ChatInputTextVue
v-if="inputType === 1"
@send="sendChatMessage"
@send="handleSend"
@click="showMenu = false"
class="pl-5"
/>
......@@ -31,30 +29,14 @@
<!-- 有输入文字,显示 `发送` 按钮 -->
<button
v-else
@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
"
@click="inputText.trim().length !== 0 && handleSend()"
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>
......@@ -69,13 +51,16 @@ import { MessageContent } from "@/types/chat-message";
import ChatInputTextVue from "./ChatInputText.vue";
import ChatInputAlbumVue from "./ChatInputAlbum.vue";
import ChatInputCameraVue from "./ChatInputCamera.vue";
import { target } from "@/store/appCallerStore";
// import { from } from "@/store/appCallerStore";
import { getFromId, target } from "@/store/appCallerStore";
import { textInputStore } from "@/store/textInputStore";
import { v4 as uuidv4 } from 'uuid'
import Icon from "@/components/common/Icon.vue";
import { useRoute } from "vue-router";
export default defineComponent({
props: {
serviceShowValue: String,
},
components: {
ChatInputTextVue,
ChatInputAlbumVue,
......@@ -83,7 +68,7 @@ export default defineComponent({
Icon,
},
setup() {
setup(props) {
const route = useRoute();
const enum InputType {
text = 1,
......@@ -104,7 +89,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();
};
......@@ -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 {
inputType,
inputText,
showMenu,
sendChatMessage,
handleSend
// showReceiptInput,
};
},
......
......@@ -11,6 +11,9 @@ import { useRoute } from "vue-router";
import { queryLoanProductInfo } from "@/service/LoanProductService/index"
import { iLoanProdcutItem,eGuaranteeType } from "@/service/LoanProductService/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) {
const viewWidth = window.innerWidth || document.documentElement.clientWidth;
......@@ -30,6 +33,7 @@ export default defineComponent({
LoanDetailDescribe,
Branch,
Transition,
Skeleton
},
setup() {
const applyEl = ref();
......@@ -50,6 +54,24 @@ export default defineComponent({
const apply_to= ref('')
const apply_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(() => {
uuid.value = useRoute().params.uuid as string
......@@ -72,6 +94,8 @@ export default defineComponent({
apply_cond.value = productItem.apply_cond
submit_cond.value = productItem.submit_cond
}
fetchBranch()
})
const barEle = document.querySelector(".theBar");
......@@ -203,8 +227,24 @@ export default defineComponent({
</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}/>
<div class="title mx-5 mt-5">营业网点</div>
<Branch class=" mx-5 mt-2.5 mb-4" />
<div class="title mx-5 mt-5" >营业网点</div>
<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 class="h-12"></div>
<transition name="fade" mode="out-in">
......
......@@ -4,20 +4,9 @@
v-for="app in appList"
:key="app.name"
class="w-1/4 mb-5 text-center"
@click="$router.push({ name: app.routerName })"
>
<div
class="
w-16
h-16
bg-white
app-container
mx-auto
flex
items-center
justify-center
"
@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">
<Icon :name="app.icon" :color="app.color" size="25" />
</div>
<div class="mt-2.5 app-name">{{ app.name }}</div>
......
import Bridge from "@/utils/jsBridge2"
export default [
{
name: '贷款服务',
......@@ -38,6 +40,9 @@ export default [
name: '精彩直播',
icon: 'icon-jingcaizhibo',
color: '#0FCBA5',
cb(){
new Bridge().bridge_live()
},
},
{
name: '消息中心',
......
......@@ -38,7 +38,7 @@
</span>
</div>
<span class="word27">¥</span>
<span class="txt14">1,000,000</span>
<span class="txt14">{{ limit.max_amount }}</span>
</div>
</div>
<div class="outer55" v-else-if="eLoanMode.company === mode">
......@@ -48,10 +48,10 @@
</div>
<div class="outer7 flex-row">
<span class="info15">¥</span>
<span class="txt10">1,000,000</span>
<span class="txt10">{{ limit.en_max_amount }}</span>
</div>
<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>
<span class="word34">分秒必批</span>
<div class="main22 flex-col"></div>
......@@ -65,11 +65,12 @@
<!-- 非热门贷款 -->
<GroupTitle
title="贷款精选"
v-if="state.allProductList"
@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
v-for="item in allProductList"
v-for="item in state.allProductList"
:key="item.value"
:max_amount="item.max_amount"
:product_name="item.product_name"
......@@ -115,7 +116,7 @@
</div>
</template>
<script lang="ts" setup>
import { defineComponent, ref } from "vue";
import { defineComponent, ref, toRefs } from "vue";
import { eLoanMode } from "./types";
import LoanHotCard from "@/components/Loan/LoanHotCard/index.vue";
import LoanHotSwipe from "@/components/Loan/LoanHotSwipe/index.vue";
......@@ -131,6 +132,7 @@ import { Skeleton } from "vant";
import {
queryLoanProductList,
queryLoanProductInfo,
queryLimit,
} from "@/service/LoanProductService";
const mode = ref(eLoanMode.personal);
......@@ -138,12 +140,19 @@ let skeLoading = ref(false);
const setMode = (v: eLoanMode) => {
mode.value = v;
};
let allProductList: Array<simpleItemInfo> = reactive([]);
let state = reactive({ allProductList: [] as Array<simpleItemInfo> });
const src = 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, () => {
allProductList = [];
state.allProductList = [];
fetchList();
});
......@@ -154,7 +163,7 @@ const getNews = () => {
}).then((res: any) => {
hotNews.value = res.data.items;
});
}
};
const fetchActivityList = () => {
skeLoading.value = true;
......@@ -181,7 +190,7 @@ const fetchList = () => {
queryLoanProductInfo({ uuid }).then((ret) => {
const { max_amount, inst_name, uuid, features, product_name } =
ret.data;
allProductList.push({
state.allProductList.push({
max_amount,
product_name,
features,
......@@ -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(() => {
fetchLimit();
fetchList();
fetchActivityList();
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