This commit is contained in:
xiezhijun 2021-06-12 18:35:33 +08:00
commit 5f3dee08c2
5 changed files with 143 additions and 37 deletions

View File

@ -2,13 +2,16 @@ package com.stdiet.custom.service.impl;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.stdiet.common.utils.DateUtils; import com.stdiet.common.utils.DateUtils;
import com.stdiet.common.utils.StringUtils;
import com.stdiet.common.utils.uuid.UUID; import com.stdiet.common.utils.uuid.UUID;
import com.stdiet.custom.domain.SysCustomer; import com.stdiet.custom.domain.SysCustomer;
import com.stdiet.custom.domain.SysServicesTopic; import com.stdiet.custom.domain.SysServicesTopic;
import com.stdiet.custom.domain.SysWxUserInfo;
import com.stdiet.custom.mapper.SysCustomerMapper; import com.stdiet.custom.mapper.SysCustomerMapper;
import com.stdiet.custom.mapper.SysServicesTopicMapper; import com.stdiet.custom.mapper.SysServicesTopicMapper;
import com.stdiet.custom.server.WebSocketServer; import com.stdiet.custom.server.WebSocketServer;
import com.stdiet.custom.service.ISysServicesTopicService; import com.stdiet.custom.service.ISysServicesTopicService;
import com.stdiet.custom.service.ISysWxUserInfoService;
import com.stdiet.custom.utils.WsUtils; import com.stdiet.custom.utils.WsUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -25,6 +28,9 @@ public class SysServicesTopicServiceImp implements ISysServicesTopicService {
@Autowired @Autowired
SysCustomerMapper sysCustomerMapper; SysCustomerMapper sysCustomerMapper;
@Autowired
ISysWxUserInfoService iSysWxUserInfoService;
@Override @Override
public List<SysServicesTopic> selectSysServicesTopicByUserIdAndRole(SysServicesTopic topic) { public List<SysServicesTopic> selectSysServicesTopicByUserIdAndRole(SysServicesTopic topic) {
return servicesTopicMapper.selectSysServicesTopicByUserIdAndRole(topic); return servicesTopicMapper.selectSysServicesTopicByUserIdAndRole(topic);
@ -90,10 +96,23 @@ public class SysServicesTopicServiceImp implements ISysServicesTopicService {
dataObj.put("count", counts.get(i).getCount()); dataObj.put("count", counts.get(i).getCount());
dataObj.put("data", topic); dataObj.put("data", topic);
JSONObject userObj = new JSONObject();
SysWxUserInfo userInfo = iSysWxUserInfoService.selectSysWxUserInfoByCusId(Long.parseLong(customerId));
if (!StringUtils.isNull(userInfo)) {
userObj.put("avatar", userInfo.getAvatarUrl());
}
userObj.put("name", customer.getName());
userObj.put("create_time", DateUtils.dateTimeNow("yyyy-MM-dd HH:mm:ss"));
userObj.put("update_time", DateUtils.dateTimeNow("yyyy-MM-dd HH:mm:ss"));
userObj.put("read", 0);
userObj.put("uid", customerId);
userObj.put("role", "customer");
JSONObject msgObj = new JSONObject(); JSONObject msgObj = new JSONObject();
msgObj.put("type", WsUtils.WS_TYPE_MESSAGE_COUNT); msgObj.put("type", WsUtils.WS_TYPE_MESSAGE_COUNT);
msgObj.put("msg", "未读消息数"); msgObj.put("msg", "未读消息数");
msgObj.put("data", dataObj); msgObj.put("data", dataObj);
msgObj.put("customer", userObj);
WebSocketServer.sendInfo(msgObj.toJSONString(), counts.get(i).getUid()); WebSocketServer.sendInfo(msgObj.toJSONString(), counts.get(i).getUid());
} }
} catch (IOException e) { } catch (IOException e) {
@ -156,12 +175,15 @@ public class SysServicesTopicServiceImp implements ISysServicesTopicService {
List<SysServicesTopic> statusList = new ArrayList<>(); List<SysServicesTopic> statusList = new ArrayList<>();
SysServicesTopic dieticianStatus = new SysServicesTopic(); SysServicesTopic dieticianStatus = new SysServicesTopic();
dieticianStatus.setUid(String.valueOf(customer.getMainDietitian())); dieticianStatus.setUid(String.valueOf(customer.getMainDietitian()));
dieticianStatus.setRole("dietician");
statusList.add(dieticianStatus); statusList.add(dieticianStatus);
SysServicesTopic afterSaleStatus = new SysServicesTopic(); SysServicesTopic afterSaleStatus = new SysServicesTopic();
afterSaleStatus.setUid(String.valueOf(customer.getAfterDietitian())); afterSaleStatus.setUid(String.valueOf(customer.getAfterDietitian()));
afterSaleStatus.setRole("after_sale");
statusList.add(afterSaleStatus); statusList.add(afterSaleStatus);
SysServicesTopic dieticianAssistantStatus = new SysServicesTopic(); SysServicesTopic dieticianAssistantStatus = new SysServicesTopic();
dieticianAssistantStatus.setUid(String.valueOf(customer.getAssistantDietitian())); dieticianAssistantStatus.setUid(String.valueOf(customer.getAssistantDietitian()));
dieticianAssistantStatus.setRole("dietician_assistant");
statusList.add(dieticianAssistantStatus); statusList.add(dieticianAssistantStatus);
try { try {
@ -170,6 +192,7 @@ public class SysServicesTopicServiceImp implements ISysServicesTopicService {
JSONObject dataObj = new JSONObject(); JSONObject dataObj = new JSONObject();
dataObj.put("count", counts.get(i).getCount()); dataObj.put("count", counts.get(i).getCount());
dataObj.put("topicId", topic.getTopicId()); dataObj.put("topicId", topic.getTopicId());
dataObj.put("uid", topic.getFromUid());
JSONObject msgObj = new JSONObject(); JSONObject msgObj = new JSONObject();
msgObj.put("type", WsUtils.WS_TYPE_NEW_CUSTOMER_REPLY); msgObj.put("type", WsUtils.WS_TYPE_NEW_CUSTOMER_REPLY);

View File

@ -36,8 +36,8 @@
) AS status ) AS status
LEFT JOIN (SELECT topic_id, uid, del_flag FROM sys_services_topic ) AS topic USING(topic_id) LEFT JOIN (SELECT topic_id, uid, del_flag FROM sys_services_topic ) AS topic USING(topic_id)
WHERE del_flag = 0 WHERE del_flag = 0
ORDER BY `read` ASC, update_time DESC
) AS userList GROUP BY uid ) AS userList GROUP BY uid
ORDER BY `read` ASC, update_time DESC
</select> </select>
<select id="selectTopicListByUid" parameterType="SysServicesTopic" resultMap="SysServicesTopicResult"> <select id="selectTopicListByUid" parameterType="SysServicesTopic" resultMap="SysServicesTopicResult">

View File

@ -96,8 +96,27 @@ const actions = {
async fetchTopicListApi({ dispatch, commit, rootGetters, state }, payload) { async fetchTopicListApi({ dispatch, commit, rootGetters, state }, payload) {
// prettier-ignore // prettier-ignore
const { roles: [role], userId } = rootGetters; const { roles: [role], userId } = rootGetters;
const { customerList } = state;
const { fromUid } = payload; const { fromUid } = payload;
commit("save", { selCusId: fromUid, topicLoading: true }); const newCustomerList = JSON.parse(JSON.stringify(customerList));
const tarIdx = newCustomerList.findIndex(obj => obj.reSort);
if (tarIdx > -1) {
const [tarCustomer] = newCustomerList.splice(tarIdx, 1);
const injectIdx = newCustomerList.findIndex(obj => obj.read == 1);
tarCustomer.reSort = false;
if (injectIdx === -1) {
newCustomerList.splice(newCustomerList.length, 0, tarCustomer);
} else {
newCustomerList.splice(injectIdx, 0, tarCustomer);
}
}
commit("save", {
selCusId: fromUid,
topicLoading: true,
customerList: newCustomerList
});
const result = await fetchTopicList({ const result = await fetchTopicList({
role, role,
uid: userId, uid: userId,
@ -106,12 +125,14 @@ const actions = {
let mTopicList = []; let mTopicList = [];
if (result.code === 200 && result.rows.length) { if (result.code === 200 && result.rows.length) {
// 默认展示第一个 // 默认展示第一个
const [defTopic] = result.rows; setTimeout(() => {
dispatch("fetchTopicDetailActions", { const [defTopic] = result.rows;
topicId: defTopic.topicId, dispatch("fetchTopicDetailActions", {
id: defTopic.id, topicId: defTopic.topicId,
uid: defTopic.uid id: defTopic.id,
}); uid: defTopic.uid
});
}, 100);
mTopicList = result.rows; mTopicList = result.rows;
} }
commit("save", { commit("save", {
@ -121,7 +142,13 @@ const actions = {
}, },
async fetchTopicDetailActions({ commit, dispatch, state }, payload) { async fetchTopicDetailActions({ commit, dispatch, state }, payload) {
const { topicId, id = 0, uid } = payload; const { topicId, id = 0, uid } = payload;
const { healthyData, planList, customerData } = state; const {
healthyData,
planList,
customerData,
topicList,
customerList
} = state;
commit("save", { selTopicId: topicId, detailLoading: true }); commit("save", { selTopicId: topicId, detailLoading: true });
// 客户信息 // 客户信息
if (healthyData.customerId !== parseInt(uid)) { if (healthyData.customerId !== parseInt(uid)) {
@ -138,7 +165,23 @@ const actions = {
// //
const result = await fetchTopicDetail({ topicId, id }); const result = await fetchTopicDetail({ topicId, id });
if (result.code === 200) { if (result.code === 200) {
commit("save", { detailData: result.data[0], detailLoading: false }); // 设置已读
const newTopicList = JSON.parse(JSON.stringify(topicList));
const preState = newTopicList.some(t => t.read == 0);
newTopicList.find(obj => obj.topicId === topicId).read = 1;
const newCutomers = JSON.parse(JSON.stringify(customerList));
const afterState = newTopicList.some(t => t.read == 0);
if (!afterState) {
const tarCustomer = newCutomers.find(cus => cus.uid === uid);
tarCustomer.read = 1;
tarCustomer.reSort = preState;
}
commit("save", {
detailData: result.data[0],
detailLoading: false,
topicList: newTopicList,
customerList: newCutomers
});
} }
}, },
async getCustomerFileActions({ commit }, payload) { async getCustomerFileActions({ commit }, payload) {

View File

@ -1,5 +1,6 @@
<template> <template>
<div class="message_browser_wrapper"> <div class="message_browser_wrapper">
<!-- 客户列表 -->
<div class="customers_list" @scroll="handleOnScroll" v-loading="cusLoading"> <div class="customers_list" @scroll="handleOnScroll" v-loading="cusLoading">
<div v-if="customerList && customerList.length"> <div v-if="customerList && customerList.length">
<div <div
@ -10,7 +11,11 @@
}`" }`"
@click="handleOnCustomerClick(customer)" @click="handleOnCustomerClick(customer)"
> >
<span class="customer_avatar"> <span
:class="`customer_avatar ${
!customer.read ? 'customer_avatar_unread' : ''
}`"
>
<el-avatar size="medium" :src="customer.avatar"> <el-avatar size="medium" :src="customer.avatar">
{{ customer.name && customer.name.substr(-1) }} {{ customer.name && customer.name.substr(-1) }}
</el-avatar> </el-avatar>
@ -21,6 +26,7 @@
</div> </div>
</div> </div>
</div> </div>
<!-- 客户问题列表 -->
<div class="topic_list" v-loading="topicLoading"> <div class="topic_list" v-loading="topicLoading">
<div v-if="topicList && topicList.length"> <div v-if="topicList && topicList.length">
<div <div
@ -49,6 +55,7 @@
</div> </div>
<div v-else class="topic_list_empty">暂无消息</div> <div v-else class="topic_list_empty">暂无消息</div>
</div> </div>
<!-- 问题对话详情列表 -->
<div class="topic_detail" v-loading="detailLoading"> <div class="topic_detail" v-loading="detailLoading">
<div class="topic_detail_list"> <div class="topic_detail_list">
<div <div
@ -136,8 +143,8 @@ export default {
setTimeout(() => { setTimeout(() => {
const itemElm = document.querySelector(".topic_item"); const itemElm = document.querySelector(".topic_item");
if (itemElm) { if (itemElm) {
console.log(itemElm); // console.log(itemElm);
this.itemWidth = itemElm.clientWidth - 32 - 20 - 80; this.itemWidth = itemElm.clientWidth - 24 - 20 - 50 - 4;
} }
}, 100); }, 100);
}, },
@ -167,28 +174,32 @@ export default {
}, },
handleOnMessage({ data }) { handleOnMessage({ data }) {
if (data.type === keys.WS_TYPE_MESSAGE_COUNT) { if (data.type === keys.WS_TYPE_MESSAGE_COUNT) {
const { data: tData } = data.data; const { data: tData, count } = data.data;
const time = dayjs(tData.createTime).format("YYYY-MM-DD HH:mm:ss"); this.updateUnreadCount({
const newTopicList = [ msgUnreadCount: count,
{
id: tData.id,
content: tData.content,
createTime: time,
img: tData.img,
topicId: tData.topicId,
role: "customer",
uid: tData.uid,
updateTime: time,
topicType: tData.topicType,
read: tData.read,
},
...this.topicList,
];
this.save({
topicList: newTopicList,
}); });
if (tData.uid === this.selCusId) {
this.fetchTopicListApi({
fromUid: tData.uid,
});
} else {
const { customer } = data;
//
const newCustomers = JSON.parse(JSON.stringify(this.customerList));
const tarIdx = newCustomers.findIndex((obj) => obj.uid === tData.uid);
if (tarIdx > -1) {
const [tarCustomer] = newCustomers.splice(tarIdx, 1);
tarCustomer.read = 0;
newCustomers.splice(0, 0, tarCustomer);
} else {
newCustomers.splice(0, 0, customer);
}
this.save({
customerList: newCustomers,
});
}
} else if (data.type === keys.WS_TYPE_NEW_CUSTOMER_REPLY) { } else if (data.type === keys.WS_TYPE_NEW_CUSTOMER_REPLY) {
const { count, topicId } = data.data; const { count, topicId, uid } = data.data;
this.updateUnreadCount({ this.updateUnreadCount({
msgUnreadCount: count, msgUnreadCount: count,
}); });
@ -197,13 +208,24 @@ export default {
(obj) => obj.topicId === topicId (obj) => obj.topicId === topicId
); );
if (tarTopic) { if (tarTopic) {
console.log({ tarTopic });
this.fetchTopicDetailActions({ this.fetchTopicDetailActions({
topicId, topicId,
id: tarTopic.id, id: tarTopic.id,
uid: tarTopic.uid, uid: tarTopic.uid,
}); });
} }
} else {
//
const newCustomers = JSON.parse(JSON.stringify(this.customerList));
const tarIdx = newCustomers.findIndex((obj) => obj.uid === uid);
if (tarIdx > -1) {
const [tarCustomer] = newCustomers.splice(tarIdx, 1);
tarCustomer.read = 0;
newCustomers.splice(0, 0, tarCustomer);
this.save({
customerList: newCustomers,
});
}
} }
} }
}, },
@ -300,11 +322,29 @@ export default {
cursor: pointer; cursor: pointer;
display: flex; display: flex;
align-items: center; align-items: center;
position: relative;
&:hover { &:hover {
background: #dedede; background: #dedede;
} }
.customer_avatar {
}
.customer_avatar_unread {
&::after {
content: "";
display: block;
width: 12px;
height: 12px;
border-radius: 50%;
background: #d96969;
position: absolute;
top: 8px;
left: 36px;
}
}
.customer_name { .customer_name {
margin-left: 8px; margin-left: 8px;
overflow: hidden; overflow: hidden;
@ -374,7 +414,7 @@ export default {
} }
.topic_info { .topic_info {
flex: 0 0 80px; flex: 0 0 50px;
text-align: center; text-align: center;
} }
} }

View File

@ -119,7 +119,7 @@ export default {
}, },
watch: { watch: {
planList(val, newVal) { planList(val, newVal) {
console.log({ val, newVal }); // console.log({ val, newVal });
this.cusOutId = val.reduce((str, cur) => { this.cusOutId = val.reduce((str, cur) => {
if (!str && cur.recipesId && cur.reviewStatus === 2) { if (!str && cur.recipesId && cur.reviewStatus === 2) {
str = cur.outId; str = cur.outId;
@ -184,7 +184,7 @@ export default {
); );
}, },
handleOnSendChange(val, data) { handleOnSendChange(val, data) {
console.log({ val, data }); // console.log({ val, data });
const { id } = data; const { id } = data;
if (data.reviewStatus === 2) { if (data.reviewStatus === 2) {
this.updateRecipesPlanActions({ this.updateRecipesPlanActions({