This commit is contained in:
xiezhijun 2021-06-08 18:52:27 +08:00
commit 06a7323a65
17 changed files with 657 additions and 113 deletions

View File

@ -20,10 +20,16 @@ public class SysServiceTopicController extends BaseController {
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo list(SysServicesTopic topic) { public TableDataInfo list(SysServicesTopic topic) {
startPage(); return getDataTable(servicesTopicService.selectTopicListByUid(topic));
return getDataTable(servicesTopicService.selectSysServicesTopicByUserIdAndRole(topic));
} }
@GetMapping("/customers")
public TableDataInfo customers(SysServicesTopic topic) {
startPage();
return getDataTable(servicesTopicService.selectCustomerListByUserIdAndRole(topic));
}
// @PutMapping("/update/status") // @PutMapping("/update/status")
// public AjaxResult status(@RequestBody SysServicesQuestion sysServicesQuestion) { // public AjaxResult status(@RequestBody SysServicesQuestion sysServicesQuestion) {
// return toAjax(sysServicesQuestionService.updateSysServicesQuestionStatus(sysServicesQuestion)); // return toAjax(sysServicesQuestionService.updateSysServicesQuestionStatus(sysServicesQuestion));

View File

@ -2,8 +2,8 @@ package com.stdiet.web.controller.custom;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.stdiet.common.core.controller.BaseController; import com.stdiet.common.core.controller.BaseController;
import com.stdiet.custom.utils.WsUtils;
import com.stdiet.custom.server.WebSocketServer; import com.stdiet.custom.server.WebSocketServer;
import com.stdiet.custom.utils.WsUtils;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
@ -38,16 +38,16 @@ public class WebSocketController extends BaseController {
} }
// @Scheduled(fixedRate = 30000) @Scheduled(fixedRate = 1800000)
// public void boardCast() { public void boardCast() {
// try { try {
// JSONObject heartBeat = new JSONObject(); JSONObject heartBeat = new JSONObject();
// heartBeat.put("type", WsUtils.WS_TYPE_HEART_BEAT); heartBeat.put("type", WsUtils.WS_TYPE_SYSTEM_MESSAGE_CLEAN);
// heartBeat.put("msg", "ping"); heartBeat.put("msg", "clean");
//
// WebSocketServer.sendInfo(heartBeat.toJSONString(), null); WebSocketServer.sendInfo(heartBeat.toJSONString(), null);
// } catch (IOException e) { } catch (IOException e) {
// e.printStackTrace(); e.printStackTrace();
// } }
// } }
} }

View File

@ -71,18 +71,26 @@ public class SysCustomer extends BaseEntity
/** 主营养师 */ /** 主营养师 */
@Excel(name = "主营养师") @Excel(name = "主营养师")
private String dietitianName;
private Long mainDietitian; private Long mainDietitian;
/** 营养师助理 */ /** 营养师助理 */
@Excel(name = "营养师助理") @Excel(name = "营养师助理")
private String assDietitianName;
private Long assistantDietitian; private Long assistantDietitian;
/** 售后营养师 */ /** 售后营养师 */
@Excel(name = "售后营养师") @Excel(name = "售后营养师")
private String afterDietitianName;
private Long afterDietitian; private Long afterDietitian;
/** 销售人员 */ /** 销售人员 */
@Excel(name = "销售人员") @Excel(name = "销售人员")
private String salesName;
private Long salesman; private Long salesman;
/** 负责人 */ /** 负责人 */

View File

@ -7,6 +7,8 @@ import java.util.List;
public interface SysServicesTopicMapper { public interface SysServicesTopicMapper {
List<SysServicesTopic> selectSysServicesTopicByUserIdAndRole(SysServicesTopic topic); List<SysServicesTopic> selectSysServicesTopicByUserIdAndRole(SysServicesTopic topic);
List<SysServicesTopic> selectCustomerListByUserIdAndRole(SysServicesTopic topic);
int insertSysServicesTopic(SysServicesTopic topic); int insertSysServicesTopic(SysServicesTopic topic);
int insertSysServicesTopicStatus(List<SysServicesTopic> topics); int insertSysServicesTopicStatus(List<SysServicesTopic> topics);
@ -20,4 +22,6 @@ public interface SysServicesTopicMapper {
List<SysServicesTopic> selectSysServicesTopicSessionByTopicId(String topicId); List<SysServicesTopic> selectSysServicesTopicSessionByTopicId(String topicId);
List<SysServicesTopic> selectUnreadTopicCount(List<SysServicesTopic> topics); List<SysServicesTopic> selectUnreadTopicCount(List<SysServicesTopic> topics);
List<SysServicesTopic> selectTopicListByUid(SysServicesTopic topic);
} }

View File

@ -27,7 +27,7 @@ public class WebSocketServer {
//private static ConcurrentHashMap<String,WebSocketServer> websocketList = new ConcurrentHashMap<>(); //private static ConcurrentHashMap<String,WebSocketServer> websocketList = new ConcurrentHashMap<>();
// 与某个客户端的连接会话需要通过它来给客户端发送数据 // 与某个客户端的连接会话需要通过它来给客户端发送数据
private Session session; private Session session;
// 接收sid // 接收sidw
private String sid = ""; private String sid = "";
public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() { public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() {

View File

@ -8,6 +8,8 @@ public interface ISysServicesTopicService {
List<SysServicesTopic> selectSysServicesTopicByUserIdAndRole(SysServicesTopic topic); List<SysServicesTopic> selectSysServicesTopicByUserIdAndRole(SysServicesTopic topic);
List<SysServicesTopic> selectCustomerListByUserIdAndRole(SysServicesTopic topic);
SysServicesTopic insertSysServicesTopic(SysServicesTopic topic); SysServicesTopic insertSysServicesTopic(SysServicesTopic topic);
int updateSysServicesTopicStatus(SysServicesTopic topic); int updateSysServicesTopicStatus(SysServicesTopic topic);
@ -19,4 +21,6 @@ public interface ISysServicesTopicService {
List<SysServicesTopic> selectSysServicesTopicSessionByTopicId(String topicId); List<SysServicesTopic> selectSysServicesTopicSessionByTopicId(String topicId);
List<SysServicesTopic> selectUnreadTopicCount(List<SysServicesTopic> topic); List<SysServicesTopic> selectUnreadTopicCount(List<SysServicesTopic> topic);
List<SysServicesTopic> selectTopicListByUid(SysServicesTopic topic);
} }

View File

@ -30,6 +30,10 @@ public class SysServicesTopicServiceImp implements ISysServicesTopicService {
return servicesTopicMapper.selectSysServicesTopicByUserIdAndRole(topic); return servicesTopicMapper.selectSysServicesTopicByUserIdAndRole(topic);
} }
@Override
public List<SysServicesTopic> selectCustomerListByUserIdAndRole(SysServicesTopic topic) {
return servicesTopicMapper.selectCustomerListByUserIdAndRole(topic);
}
@Override @Override
public SysServicesTopic insertSysServicesTopic(SysServicesTopic topic) { public SysServicesTopic insertSysServicesTopic(SysServicesTopic topic) {
@ -187,4 +191,9 @@ public class SysServicesTopicServiceImp implements ISysServicesTopicService {
public List<SysServicesTopic> selectUnreadTopicCount(List<SysServicesTopic> statusList) { public List<SysServicesTopic> selectUnreadTopicCount(List<SysServicesTopic> statusList) {
return servicesTopicMapper.selectUnreadTopicCount(statusList); return servicesTopicMapper.selectUnreadTopicCount(statusList);
} }
@Override
public List<SysServicesTopic> selectTopicListByUid(SysServicesTopic topic) {
return servicesTopicMapper.selectTopicListByUid(topic);
}
} }

View File

@ -6,6 +6,8 @@ public class WsUtils {
public static final String WS_TYPE_SYSTEM_MESSAGE = "WS_TYPE_SYSTEM_MESSAGE"; public static final String WS_TYPE_SYSTEM_MESSAGE = "WS_TYPE_SYSTEM_MESSAGE";
public static final String WS_TYPE_SYSTEM_MESSAGE_CLEAN = "WS_TYPE_SYSTEM_MESSAGE_CLEAN";
public static final String WS_TYPE_MESSAGE_COUNT = "WS_TYPE_MESSAGE_COUNT"; public static final String WS_TYPE_MESSAGE_COUNT = "WS_TYPE_MESSAGE_COUNT";
public static final String WS_TYPE_NEW_CUSTOMER_REPLY = "WS_TYPE_NEW_CUSTOMER_REPLY"; public static final String WS_TYPE_NEW_CUSTOMER_REPLY = "WS_TYPE_NEW_CUSTOMER_REPLY";

View File

@ -5,38 +5,50 @@
<mapper namespace="com.stdiet.custom.mapper.SysCustomerMapper"> <mapper namespace="com.stdiet.custom.mapper.SysCustomerMapper">
<resultMap type="SysCustomer" id="SysCustomerResult"> <resultMap type="SysCustomer" id="SysCustomerResult">
<result property="id" column="id" /> <result property="id" column="id"/>
<result property="name" column="name" /> <result property="name" column="name"/>
<result property="phone" column="phone" /> <result property="phone" column="phone"/>
<result property="email" column="email" /> <result property="email" column="email"/>
<result property="address" column="address" /> <result property="address" column="address"/>
<result property="payDate" column="pay_date" /> <result property="payDate" column="pay_date"/>
<result property="startDate" column="start_date" /> <result property="startDate" column="start_date"/>
<result property="fansTime" column="fans_time" /> <result property="fansTime" column="fans_time"/>
<result property="fansChannel" column="fans_channel" /> <result property="fansChannel" column="fans_channel"/>
<result property="purchaseNum" column="purchase_num" /> <result property="purchaseNum" column="purchase_num"/>
<result property="payTotal" column="pay_total" /> <result property="payTotal" column="pay_total"/>
<result property="mainDietitian" column="main_dietitian" /> <result property="chargePerson" column="charge_person"/>
<result property="assistantDietitian" column="assistant_dietitian" /> <result property="followStatus" column="follow_status"/>
<result property="afterDietitian" column="after_dietitian" /> <result property="createTime" column="create_time"/>
<result property="salesman" column="salesman" /> <result property="createBy" column="create_by"/>
<result property="chargePerson" column="charge_person" /> <result property="updateTime" column="update_time"/>
<result property="followStatus" column="follow_status" /> <result property="updateBy" column="update_by"/>
<result property="createTime" column="create_time" /> <result property="channelId" column="channel_id"/>
<result property="createBy" column="create_by" />
<result property="updateTime" column="update_time" /> <result property="mainDietitian" column="main_dietitian"/>
<result property="updateBy" column="update_by" /> <result property="assistantDietitian" column="assistant_dietitian"/>
<result property="channelId" column="channel_id" /> <result property="afterDietitian" column="after_dietitian"/>
<result property="salesman" column="salesman"/>
<association property="dietitianName" column="{id=main_dietitian}" select="selectUserName"/>
<association property="assDietitianName" column="{id=assistant_dietitian}" select="selectUserName"/>
<association property="afterDietitianName" column="{id=after_dietitian}" select="selectUserName"/>
<association property="salesName" column="{id=salesman}" select="selectUserName"/>
</resultMap> </resultMap>
<select id="selectUserName" parameterType="java.util.Map" resultType="String">
select nick_name from sys_user where user_id = #{id}
</select>
<sql id="selectSysCustomerVo"> <sql id="selectSysCustomerVo">
select id, name, phone, email, fans_time, fans_channel, address, pay_date, start_date, purchase_num, pay_total, main_dietitian, assistant_dietitian, after_dietitian, salesman, charge_person, follow_status, create_time, create_by, update_time, update_by, channel_id from sys_customer select id, name, phone, email, fans_time, fans_channel, address, pay_date, start_date, purchase_num, pay_total, main_dietitian, assistant_dietitian, after_dietitian, salesman, charge_person, follow_status, create_time, create_by, update_time, update_by, channel_id from sys_customer
</sql> </sql>
<select id="selectSysCustomerList" parameterType="SysCustomer" resultMap="SysCustomerResult"> <select id="selectSysCustomerList" parameterType="SysCustomer" resultMap="SysCustomerResult">
select select
sc.id, sc.name, sc.phone, sc.email, sc.fans_time, sc.fans_channel, sc.address, sc.pay_date, sc.start_date, sc.purchase_num, sc.pay_total, sc.main_dietitian, sc.id, sc.name, sc.phone, sc.email, sc.fans_time, sc.fans_channel, sc.address, sc.pay_date, sc.start_date,
sc.assistant_dietitian, sc.after_dietitian, sc.salesman, sc.charge_person, sc.follow_status, sc.create_time,sc.channel_id sc.purchase_num, sc.pay_total, sc.main_dietitian,
sc.assistant_dietitian, sc.after_dietitian, sc.salesman, sc.charge_person, sc.follow_status,
sc.create_time,sc.channel_id
from sys_customer sc from sys_customer sc
left join sys_customer_healthy as sch left join sys_customer_healthy as sch
on sch.customer_id = sc.id and sch.del_flag = 0 on sch.customer_id = sc.id and sch.del_flag = 0
@ -44,16 +56,18 @@
<if test="name != null and name != ''"> <if test="name != null and name != ''">
and (sc.name like concat('%', #{name}, '%') or sc.phone like concat('%', #{name}, '%')) and (sc.name like concat('%', #{name}, '%') or sc.phone like concat('%', #{name}, '%'))
</if> </if>
<if test="mainDietitian != null and mainDietitian != ''"> and sc.main_dietitian = #{mainDietitian}</if> <if test="mainDietitian != null and mainDietitian != ''">and sc.main_dietitian = #{mainDietitian}</if>
<if test="mainDietitian == 0"> and (isnull(sc.main_dietitian) or sc.main_dietitian=0)</if> <if test="mainDietitian == 0">and (isnull(sc.main_dietitian) or sc.main_dietitian=0)</if>
<if test="salesman != null and salesman != ''"> and sc.salesman = #{salesman}</if> <if test="salesman != null and salesman != ''">and sc.salesman = #{salesman}</if>
<if test="salesman == 0"> and (isnull(sc.salesman) or sc.salesman=0)</if> <if test="salesman == 0">and (isnull(sc.salesman) or sc.salesman=0)</if>
<if test="afterDietitian != null and afterDietitian != ''"> and sc.after_dietitian = #{afterDietitian}</if> <if test="afterDietitian != null and afterDietitian != ''">and sc.after_dietitian = #{afterDietitian}</if>
<if test="afterDietitian == 0"> and (isnull(sc.after_dietitian) or sc.after_dietitian=0)</if> <if test="afterDietitian == 0">and (isnull(sc.after_dietitian) or sc.after_dietitian=0)</if>
<if test="assistantDietitian != null and assistantDietitian != ''"> and sc.assistant_dietitian = #{assistantDietitian}</if> <if test="assistantDietitian != null and assistantDietitian != ''">and sc.assistant_dietitian =
<if test="assistantDietitian == 0"> and (isnull(sc.assistant_dietitian) or sc.assistant_dietitian=0)</if> #{assistantDietitian}
<if test="fansChannel != null "> and sc.fans_channel = #{fansChannel}</if> </if>
<if test="channelId != null "> and sc.channel_id = #{channelId}</if> <if test="assistantDietitian == 0">and (isnull(sc.assistant_dietitian) or sc.assistant_dietitian=0)</if>
<if test="fansChannel != null ">and sc.fans_channel = #{fansChannel}</if>
<if test="channelId != null ">and sc.channel_id = #{channelId}</if>
<if test="channels != null"> <if test="channels != null">
and sc.channel_id in and sc.channel_id in
<foreach collection="channels" item="cn" separator="," open="(" close=")"> <foreach collection="channels" item="cn" separator="," open="(" close=")">

View File

@ -16,8 +16,57 @@
<result column="create_time" property="createTime"/> <result column="create_time" property="createTime"/>
<result column="update_time" property="updateTime"/> <result column="update_time" property="updateTime"/>
<association column="{uid=uid,role=role}" property="name" select="selectUserInfo"/> <association column="{uid=uid,role=role}" property="name" select="selectUserInfo"/>
<association property="avatar" column="{uid=uid,role=role}" select="selectUserAvatar"/>
</resultMap> </resultMap>
<select id="selectCustomerListByUserIdAndRole" parameterType="SysServicesTopic" resultMap="SysServicesTopicResult">
SELECT DISTINCT(uid)AS uid, MAX(update_time) AS update_time, MIN(create_time) AS create_time, MIN(`read`) AS
`read`, role FROM (
SELECT * FROM (
SELECT topic_id, `read`, create_time, update_time, 'customer' AS role FROM sys_services_topic_status
<choose>
<when test="role == 'admin' or role == 'manager' or role == 'admin-dev'">
WHERE role = 'dietician'
</when>
<otherwise>
WHERE role = #{role} AND uid = #{uid}
</otherwise>
</choose>
) AS status
LEFT JOIN (SELECT topic_id, uid, del_flag FROM sys_services_topic ) AS topic USING(topic_id)
WHERE del_flag = 0
ORDER BY `read` ASC, update_time DESC
) AS userList GROUP BY uid
</select>
<select id="selectTopicListByUid" parameterType="SysServicesTopic" resultMap="SysServicesTopicResult">
SELECT * FROM(
SELECT topic_id, topic_type, content, uid, img, 'customer' AS role FROM sys_services_topic
WHERE uid = #{fromUid} AND del_flag = 0
) AS topic
LEFT JOIN (SELECT topic_id, create_time, update_time, `read`,
<choose>
<when test="role == 'admin' or role == 'manager' or role == 'admin-dev'">
'0' AS id
</when>
<otherwise>
id
</otherwise>
</choose>
FROM sys_services_topic_status
<choose>
<when test="role == 'admin' or role == 'manager' or role == 'admin-dev'">
WHERE role = 'dietician'
</when>
<otherwise>
WHERE role = #{role} AND uid = #{uid}
</otherwise>
</choose>
) AS state
USING(topic_id)
ORDER BY `read` ASC, update_time DESC
</select>
<!-- 根据userId和角色查询问题列表--> <!-- 根据userId和角色查询问题列表-->
<select id="selectSysServicesTopicByUserIdAndRole" parameterType="SysServicesTopic" <select id="selectSysServicesTopicByUserIdAndRole" parameterType="SysServicesTopic"
@ -36,8 +85,6 @@
ORDER BY `read` ASC, update_time DESC ORDER BY `read` ASC, update_time DESC
</otherwise> </otherwise>
</choose> </choose>
</select> </select>
<!-- 查询主题--> <!-- 查询主题-->

View File

@ -1,5 +1,13 @@
import request from "@/utils/request"; import request from "@/utils/request";
export function fetchCustomerList(query) {
return request({
url: "/services/topic/customers",
method: "get",
params: query
});
}
export function fetchTopicList(query) { export function fetchTopicList(query) {
return request({ return request({
url: "/services/topic/list", url: "/services/topic/list",

View File

@ -192,7 +192,7 @@ export default {
}, },
methods: { methods: {
showDrawer(data) { showDrawer(data) {
// console.log(data); console.log(data);
this.data = data; this.data = data;
if (!this.data) { if (!this.data) {
return; return;

View File

@ -1,7 +1,15 @@
import { getCustomerPhysicalSignsByCusId } from "@/api/custom/customer"; import {
getCustomerPhysicalSignsByCusId,
getCustomer
} from "@/api/custom/customer";
import { dealHealthy } from "@/utils/healthyData"; import { dealHealthy } from "@/utils/healthyData";
import {
listRecipesPlanByCusId,
updateRecipesPlan
} from "@/api/custom/recipesPlan";
import { import {
fetchCustomerList,
fetchTopicList, fetchTopicList,
postTopicReply, postTopicReply,
fetchTopicDetail, fetchTopicDetail,
@ -10,13 +18,26 @@ import {
const oriState = { const oriState = {
pageNum: 1, pageNum: 1,
cusLoading: false,
customerList: [],
selCusId: "",
//
topicList: [], topicList: [],
detailData: {}, topicLoading: false,
selTopicId: "", selTopicId: "",
//
detailData: {},
detailLoading: false,
//
healthyData: {}, healthyData: {},
healthDataLoading: false, healthDataLoading: false,
healthyDataType: 0, healthyDataType: 0,
avoidFoodIds: [] avoidFoodIds: [],
//
customerData: {},
//
planList: [],
planListLoading: false
}; };
const mutations = { const mutations = {
@ -37,50 +58,93 @@ const mutations = {
const actions = { const actions = {
async init({ dispatch }, payload) { async init({ dispatch }, payload) {
dispatch("fetchTopicListApi", {}); dispatch("fetchCustomerListActions", {});
}, },
async fetchTopicListApi({ dispatch, commit, rootGetters, state }, payload) {
const { async fetchCustomerListActions(
roles: [role], { dispatch, commit, rootGetters, state },
userId payload
} = rootGetters; ) {
const { detailData, pageNum, topicList } = state; // prettier-ignore
const result = await fetchTopicList({ const { roles: [role], userId } = rootGetters;
const { customerList, pageNum } = state;
commit("save", { cusLoading: true });
const result = await fetchCustomerList({
role, role,
uid: userId, uid: userId,
pageSize: 20, pageSize: 20,
pageNum pageNum
}); });
if (result.code === 200) { let mPageNum = pageNum,
if (!detailData.topicId) { mCustomerList = customerList;
// 默认展示第一个 if (result.code === 200 && result.rows.length) {
const [defTopic] = result.rows; //
dispatch("fetchTopicDetailActions", { if (!customerList.length) {
topicId: defTopic.topicId, const [defCustomer] = result.rows;
id: defTopic.id, dispatch("fetchTopicListApi", { fromUid: defCustomer.uid });
uid: defTopic.uid
});
}
if (result.rows.length) {
commit("save", {
pageNum: pageNum + 1,
topicList: [...topicList, ...result.rows]
});
} }
//
mPageNum += 1;
mCustomerList = [...customerList, ...result.rows];
} }
commit("save", {
pageNum: mPageNum,
cusLoading: false,
customerList: mCustomerList
});
},
async fetchTopicListApi({ dispatch, commit, rootGetters, state }, payload) {
// prettier-ignore
const { roles: [role], userId } = rootGetters;
const { fromUid } = payload;
commit("save", { selCusId: fromUid, topicLoading: true });
const result = await fetchTopicList({
role,
uid: userId,
fromUid
});
let mTopicList = [];
if (result.code === 200 && result.rows.length) {
// 默认展示第一个
const [defTopic] = result.rows;
dispatch("fetchTopicDetailActions", {
topicId: defTopic.topicId,
id: defTopic.id,
uid: defTopic.uid
});
mTopicList = result.rows;
}
commit("save", {
topicList: mTopicList,
topicLoading: false
});
}, },
async fetchTopicDetailActions({ commit, dispatch, state }, payload) { async fetchTopicDetailActions({ commit, dispatch, state }, payload) {
const { topicId, id, uid } = payload; const { topicId, id = 0, uid } = payload;
const { healthyData } = state; const { healthyData, planList, customerData } = state;
commit("save", { selTopicId: topicId }); commit("save", { selTopicId: topicId, detailLoading: true });
// 客户信息 // 客户信息
if (healthyData.customerId !== parseInt(uid)) { if (healthyData.customerId !== parseInt(uid)) {
dispatch("getHealthyData", { cusId: uid, callback: payload.callback }); dispatch("getHealthyData", { cusId: uid, callback: payload.callback });
} }
// 食谱计划
if (!planList.length || planList[0].cusId !== parseInt(uid)) {
dispatch("getRecipesPlanActions", { cusId: uid });
}
// 客户档案
if (customerData.id !== parseInt(uid)) {
dispatch("getCustomerFileActions", { cusId: uid });
}
// //
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] }); commit("save", { detailData: result.data[0], detailLoading: false });
}
},
async getCustomerFileActions({ commit }, payload) {
const result = await getCustomer(payload.cusId);
if (result.code === 200) {
commit("save", { customerData: result.data });
} }
}, },
async postTopicReplyActions( async postTopicReplyActions(
@ -130,13 +194,39 @@ const actions = {
obj => obj.id obj => obj.id
); );
} }
} else {
throw new Error(healthyDataResult.msg);
} }
commit("save", { commit("save", {
healthDataLoading: false, healthDataLoading: false,
...newState ...newState
}); });
},
async getRecipesPlanActions({ commit }, payload) {
commit("save", { planListLoading: true, planList: [] });
const result = await listRecipesPlanByCusId(payload.cusId);
let planList = [];
if (result.code === 200) {
planList = result.data;
}
commit("save", {
planList,
planListLoading: false
});
},
async updateRecipesPlanActions({ commit, state }, payload) {
const { id, sendFlag, callback } = payload;
const { planList } = state;
const result = await updateRecipesPlan({ id, sendFlag });
if (result.code === 200) {
callback && callback("success", result.msg);
const newPlanList = JSON.parse(JSON.stringify(planList));
const tarPlan = newPlanList.find(obj => obj.id === id);
if (tarPlan) {
tarPlan.sendFlag = sendFlag;
}
commit("save", {
planList: newPlanList
});
}
} }
}; };

View File

@ -1,8 +1,8 @@
<template> <template>
<div class="topic_comment_item" @click="handOnClick(data)"> <div class="topic_comment_item" @click="handOnClick(data)">
<div class="comment_avatar"> <div class="comment_avatar">
<el-avatar size="medium" :src="data.fromAvatar || ''">{{ <el-avatar size="medium" :src="data.fromAvatar">{{
data.fromName.substr(-1) data.fromName && data.fromName.substr(-1)
}}</el-avatar> }}</el-avatar>
</div> </div>
<div class="comment_content"> <div class="comment_content">
@ -31,6 +31,7 @@ export default {
dietician: "主任营养师", dietician: "主任营养师",
after_sale: "售后营养师", after_sale: "售后营养师",
dietician_assistant: "营养师助理", dietician_assistant: "营养师助理",
manager: "总经理",
}, },
}; };
}, },

View File

@ -1,6 +1,25 @@
<template> <template>
<div class="message_browser_wrapper"> <div class="message_browser_wrapper">
<div class="topic_list" @scroll="handleOnScroll"> <div class="customers_list" @scroll="handleOnScroll" v-loading="cusLoading">
<div v-if="customerList && customerList.length">
<div
v-for="customer in customerList"
:key="customer.uid"
:class="`customer_item ${
customer.uid === selCusId ? 'customer_item_sel' : ''
}`"
@click="handleOnCustomerClick(customer)"
>
<el-avatar size="medium" :src="customer.avatar">
{{ customer.name && customer.name.substr(-1) }}
</el-avatar>
<span class="customer_name">
{{ customer.name }}
</span>
</div>
</div>
</div>
<div class="topic_list" v-loading="topicLoading">
<div v-if="topicList && topicList.length"> <div v-if="topicList && topicList.length">
<div <div
v-for="topic in topicList" v-for="topic in topicList"
@ -29,7 +48,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"> <div class="topic_detail" v-loading="detailLoading">
<div class="topic_detail_list"> <div class="topic_detail_list">
<div <div
class="topic_detail_title" class="topic_detail_title"
@ -125,7 +144,16 @@ export default {
window.removeEventListener("message", this.handleOnMessage); window.removeEventListener("message", this.handleOnMessage);
}, },
computed: { computed: {
...mapState(["topicList", "selTopicId", "detailData"]), ...mapState([
"cusLoading",
"topicLoading",
"detailLoading",
"topicList",
"selCusId",
"selTopicId",
"detailData",
"customerList",
]),
}, },
methods: { methods: {
handleOnScroll({ target }) { handleOnScroll({ target }) {
@ -133,7 +161,7 @@ export default {
target.clientHeight + parseInt(target.scrollTop) === target.clientHeight + parseInt(target.scrollTop) ===
target.scrollHeight target.scrollHeight
) { ) {
this.fetchTopicListApi(); this.fetchCustomerListActions();
} }
}, },
handleOnMessage({ data }) { handleOnMessage({ data }) {
@ -181,6 +209,14 @@ export default {
formatDate(date) { formatDate(date) {
return dayjs(date).format("MM-DD HH:mm"); return dayjs(date).format("MM-DD HH:mm");
}, },
handleOnCustomerClick(data) {
if (this.selCusId !== data.uid) {
this.replyTarget = "";
this.replyContent = "";
this.replyObj = {};
this.fetchTopicListApi({ fromUid: data.uid });
}
},
handleOnTopicClick(data) { handleOnTopicClick(data) {
if (data.topicId !== this.selTopicId) { if (data.topicId !== this.selTopicId) {
this.replyTarget = ""; this.replyTarget = "";
@ -242,6 +278,7 @@ export default {
"fetchTopicDetailActions", "fetchTopicDetailActions",
"postTopicReplyActions", "postTopicReplyActions",
"fetchTopicListApi", "fetchTopicListApi",
"fetchCustomerListActions",
]), ]),
...mapMutations(["clean", "save"]), ...mapMutations(["clean", "save"]),
...globalMapActions(["updateUnreadCount"]), ...globalMapActions(["updateUnreadCount"]),
@ -251,13 +288,40 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.message_browser_wrapper { .message_browser_wrapper {
display: flex; display: flex;
.customers_list {
flex: 1;
overflow: auto;
border-right: 1px solid #f0f0f0;
.customer_item {
padding: 8px 12px;
cursor: pointer;
display: flex;
align-items: center;
&:hover {
background: #dedede;
}
.customer_name {
margin-left: 8px;
}
}
.customer_item_sel {
background: #f0f0f0;
}
}
.topic_list { .topic_list {
flex: 2; flex: 2;
overflow: auto; overflow: auto;
border-right: 1px solid #f0f0f0;
.topic_item { .topic_item {
display: flex; display: flex;
padding: 8px 16px; padding: 8px 12px;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
@ -318,7 +382,7 @@ export default {
} }
.topic_item_sel { .topic_item_sel {
background: #dedede; background: #f0f0f0;
} }
.topic_list_empty { .topic_list_empty {
@ -353,6 +417,13 @@ export default {
.topic_detail_title { .topic_detail_title {
display: flex; display: flex;
cursor: pointer; cursor: pointer;
& > :nth-child(1) {
flex: 0 0 40px;
}
& > :nth-child(2) {
flex: 1 0 0;
}
} }
.comment_reply_item { .comment_reply_item {

View File

@ -1,38 +1,98 @@
<template> <template>
<div v-loading="healthDataLoading"> <el-tabs v-model="activeName" class="message_userinfo_wrapper">
<HealthyView <el-tab-pane label="客户信息" name="health">
dev <div
:data="healthyDataType === 0 ? healthyData : {}" v-loading="healthDataLoading"
v-show="healthyDataType === 0" :style="{ height: getTabContentHeight(), overflow: 'auto' }"
/> >
<BodySignView <HealthyView
dev dev
:data="healthyDataType === 1 ? healthyData : {}" :data="healthyDataType === 0 ? healthyData : {}"
v-show="healthyDataType === 1" v-show="healthyDataType === 0"
/> />
</div> <BodySignView
dev
:data="healthyDataType === 1 ? healthyData : {}"
v-show="healthyDataType === 1"
/>
<div v-if="customerData.id" class="customer_service_info">
<div class="info_item">
<span>主任营养师</span>
<span>
{{ customerData.dietitianName || "无" }}
</span>
</div>
<div class="info_item">
<span>营养师助理</span>
<span>{{ customerData.assDietitianName || "无" }}</span>
</div>
<div class="info_item">
<span>售后营养师</span>
<span>{{ customerData.afterDietitianName || "无" }}</span>
</div>
</div>
</div>
</el-tab-pane>
<el-tab-pane label="食谱计划" name="plan">
<div :style="{ height: getTabContentHeight(), overflow: 'auto' }">
<RecipesPlan />
</div>
</el-tab-pane>
</el-tabs>
</template> </template>
<script> <script>
import { createNamespacedHelpers } from "vuex"; import { createNamespacedHelpers } from "vuex";
import HealthyView from "@/components/HealthyView"; import HealthyView from "@/components/HealthyView";
import BodySignView from "@/components/BodySignView"; import BodySignView from "@/components/BodySignView";
const { import RecipesPlan from "./recipesPlan";
mapActions, const { mapActions, mapState, mapMutations, mapGetters } =
mapState, createNamespacedHelpers("message");
mapMutations,
mapGetters,
} = createNamespacedHelpers("message");
export default { export default {
name: "SignUserInfo", name: "SignUserInfo",
components: { components: {
HealthyView, HealthyView,
BodySignView, BodySignView,
RecipesPlan,
}, },
data() { data() {
return {}; return {
activeName: "health",
};
},
methods: {
getTabContentHeight() {
const tabPanelElm = document.querySelector(".el-tabs");
if (tabPanelElm) {
return `${tabPanelElm.clientHeight - 68}px`;
}
return "";
},
}, },
computed: { computed: {
...mapState(["healthyData", "healthyDataType", "healthDataLoading"]), ...mapState([
"healthyData",
"healthyDataType",
"healthDataLoading",
"customerData",
]),
}, },
}; };
</script> </script>
<style lang="scss" scoped>
.message_userinfo_wrapper {
.customer_service_info {
position: absolute;
right: 30%;
top: 68px;
.info_item {
margin-bottom: 10px;
font-size: 14px;
& > span:nth-child(1) {
color: #8c8c8c;
}
}
}
}
</style>

View File

@ -0,0 +1,220 @@
<template>
<div class="recipes_plan_wrapper">
<div class="header">
<section>
<el-button
v-if="cusOutId"
type="primary"
icon="el-icon-share"
size="mini"
class="copyBtn"
:data-clipboard-text="copyValue"
@click="handleOnRecipesLinkClick"
>食谱链接
</el-button>
<el-popover
placement="top"
trigger="click"
v-if="cusOutId"
style="margin: 0 12px"
>
<VueQr :text="copyValue" :logoSrc="logo" :size="256" />
<el-button
slot="reference"
size="mini"
icon="el-icon-picture-outline"
type="primary"
@click="handleCopy(scope.row.path)"
>二维码</el-button
>
</el-popover>
<!-- <el-button icon="el-icon-view" size="mini" @click="handleInnerOpen"
>查看暂停记录
</el-button> -->
</section>
<section>
<el-button
icon="el-icon-refresh"
size="mini"
@click="getRecipesPlanActions({ cusId })"
circle
/>
</section>
</div>
<el-table :data="planList" v-loading="planListLoading">
<el-table-column label="审核状态" align="center">
<template slot-scope="scope">
<el-tag :type="getReviewType(scope.row.reviewStatus)">
{{ getReviewStatusName(scope.row.reviewStatus) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="计划" align="center" width="130">
<template slot-scope="scope">
{{ `${scope.row.startNumDay}${scope.row.endNumDay}` }}
</template>
</el-table-column>
<el-table-column label="日期" align="center" width="200">
<template slot-scope="scope">
{{ `${scope.row.startDate}${scope.row.endDate}` }}
</template>
</el-table-column>
<el-table-column label="订阅情况" align="center">
<template slot-scope="scope">
<el-tag :type="scope.row.subscribed ? 'success' : 'danger'">
{{ scope.row.subscribed ? "已订阅" : "未订阅" }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="发送" align="center">
<template slot-scope="scope">
<el-switch
v-model="!!scope.row.sendFlag"
@change="(val) => handleOnSendChange(val, scope.row)"
/>
</template>
</el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button
type="text"
:icon="
scope.row.recipesId ? 'el-icon-edit' : 'el-icon-edit-outline'
"
@click="handleOnRecipesEditClick(scope.row)"
>
{{ `${scope.row.recipesId ? "编辑" : "制作"}` }}
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 暂停记录抽屉 -->
<!-- <PlanPauseDrawer ref="planPauseRef" /> -->
</div>
</template>
<script>
import Clipboard from "clipboard";
import { createNamespacedHelpers } from "vuex";
const { mapActions, mapState, mapMutations, mapGetters } =
createNamespacedHelpers("message");
// import PlanPauseDrawer from "./PlanPauseDrawer";
import VueQr from "vue-qr";
const logo = require("@/assets/logo/logo_b.png");
export default {
name: "RecipesPlanDrawer",
components: {
// PlanPauseDrawer,
VueQr,
},
data() {
return {
logo,
title: "",
cusOutId: "",
copyValue: "",
cusId: "",
};
},
watch: {
planList(val, newVal) {
console.log({ val, newVal });
this.cusOutId = val.reduce((str, cur) => {
if (!str && cur.recipesId && cur.reviewStatus === 2) {
str = cur.outId;
this.cusId = cur.cusId;
}
return str;
}, "");
if (this.cusOutId) {
this.copyValue =
window.location.origin.replace("manage", "sign") +
"/recipes/detail/" +
this.cusOutId;
}
},
},
computed: {
...mapState(["planList", "planListLoading", "healthyData"]),
},
methods: {
getReviewStatusName(status) {
switch (status) {
case 1:
return "未审核";
case 2:
return "已审核";
case 3:
return "制作中";
case 0:
default:
return "未制作";
}
},
getReviewType(status) {
switch (status) {
case 1:
return "danger";
case 2:
return "success";
case 3:
return "";
case 0:
default:
return "info";
}
},
// handleInnerOpen() {
// this.$refs["planPauseRef"].showDrawer(this.data);
// this.innerVisible = true;
// this.innerTitle = `${this.data.name}`;
// },
handleOnRecipesLinkClick() {
new Clipboard(".copyBtn");
this.$message({
message: "拷贝成功",
type: "success",
});
},
handleOnRecipesEditClick(data) {
window.open(
"/recipes/build/" + this.healthyData.name + "/" + data.id,
"_blank"
);
},
handleOnSendChange(val, data) {
console.log({ val, data });
const { id } = data;
if (data.reviewStatus === 2) {
this.updateRecipesPlanActions({
id,
sendFlag: val ? 1 : 0,
callback: (type, msg) => {
this.$message[type](msg);
},
});
} else {
this.$message.error("未审核的食谱不能发送");
}
},
...mapActions(["getRecipesPlanActions", "updateRecipesPlanActions"]),
},
};
</script>
<style lang="scss" scoped>
/deep/ :focus {
outline: 0;
}
.recipes_plan_wrapper {
// height: calc(100vh - 77px);
.header {
margin-bottom: 8px;
display: flex;
align-items: center;
justify-content: space-between;
}
}
</style>