From 0e08a1fef80e15bd434a2b17e603711e782878d5 Mon Sep 17 00:00:00 2001
From: huangdeliang <huangdeliang@skieer.com>
Date: Mon, 31 May 2021 19:34:04 +0800
Subject: [PATCH 1/2] =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=90=8E=E5=8F=B0?=
 =?UTF-8?q?=E5=89=8D=E7=AB=AF=E6=90=AD=E5=BB=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .DS_Store                                     | Bin 6148 -> 6148 bytes
 .../mapper/custom/SysServicesTopicMapper.xml  |  22 +-
 stdiet-ui/src/api/custom/message.js           |   4 +-
 stdiet-ui/src/store/getters.js                |   6 +-
 stdiet-ui/src/store/modules/message.js        |  60 +++-
 stdiet-ui/src/views/custom/message/index.vue  |   2 +-
 .../views/custom/message/messageBrowser.vue   |  45 ---
 .../custom/message/messageBrowser/Comment.vue |  94 ++++++
 .../custom/message/messageBrowser/index.vue   | 276 ++++++++++++++++++
 9 files changed, 439 insertions(+), 70 deletions(-)
 delete mode 100644 stdiet-ui/src/views/custom/message/messageBrowser.vue
 create mode 100644 stdiet-ui/src/views/custom/message/messageBrowser/Comment.vue
 create mode 100644 stdiet-ui/src/views/custom/message/messageBrowser/index.vue

diff --git a/.DS_Store b/.DS_Store
index 20c255b4c0208f1c6c70c5b04b3dd52fbaef6a68..d343bcd39fd6f5467ffeb3453751438201595a32 100644
GIT binary patch
delta 61
zcmZoMXfc@J&&aVcU^gQp$7UX;WsLHi48;s33@Hqm45>g`m!Xs)vn;qMFDE}Qoq>UY
Paq~uIGnUQl9Dn%%?J^Ju

delta 32
ocmZoMXfc@J&&a+pU^gQp`(_@dWsIAzFdMT>Y*5<F&heKY0H@*#KL7v#

diff --git a/stdiet-custom/src/main/resources/mapper/custom/SysServicesTopicMapper.xml b/stdiet-custom/src/main/resources/mapper/custom/SysServicesTopicMapper.xml
index 947d75729..688494714 100644
--- a/stdiet-custom/src/main/resources/mapper/custom/SysServicesTopicMapper.xml
+++ b/stdiet-custom/src/main/resources/mapper/custom/SysServicesTopicMapper.xml
@@ -9,11 +9,13 @@
         <result column="topic_id" property="topicId"/>
         <result column="topic_type" property="topicType"/>
         <result column="content" property="content"/>
-        <result column="name" property="name"/>
+        <result column="uid" property="uid"/>
+        <result column="role" property="role"/>
         <result column="read" property="read"/>
         <result column="img" property="img" typeHandler="com.stdiet.custom.typehandler.ArrayJsonHandler"/>
         <result column="create_time" property="createTime"/>
         <result column="update_time" property="updateTime"/>
+        <association column="{uid=uid,role=role}" property="name" select="selectUserInfo"/>
     </resultMap>
 
 
@@ -21,21 +23,9 @@
     <select id="selectSysServicesTopicByUserIdAndRole" parameterType="SysServicesTopic"
             resultMap="SysServicesTopicResult">
         SELECT * FROM (
-        SELECT * FROM sys_services_topic_status WHERE role = #{role} AND uid = #{uid}
+        SELECT topic_id, id, `read`, create_time, update_time, 'customer' AS role FROM sys_services_topic_status WHERE role = #{role} AND uid = #{uid}
         ) AS status
         LEFT JOIN sys_services_topic USING(topic_id)
-        <choose>
-            <when test="role == 'customer'">
-                LEFT JOIN (
-                SELECT name, id AS uid FROM sys_customer WHERE id = #{uid}
-                ) AS customer ON status.uid = customer.uid
-            </when>
-            <otherwise>
-                LEFT JOIN (
-                SELECT user_id AS uid, nick_name AS name FROM sys_user WHERE user_id = #{uid}
-                ) AS user ON status.uid = user.uid
-            </otherwise>
-        </choose>
         ORDER BY `read` ASC, update_time DESC
     </select>
 
@@ -92,10 +82,12 @@
 
     <select id="selectServicesTopicCommentByTopicId" resultMap="ServicesTopicCommentResult">
         select * from sys_services_topic_comment where topic_id = #{topic_id}
+        order by create_time asc
     </select>
 
     <select id="selectServicesTopicCommentReplyByCommentId" resultMap="ServicesTopicCommentReplyResult">
-        select * from sys_services_topic_reply where comment_id = #{id} order by create_time asc
+        select * from sys_services_topic_reply where comment_id = #{id}
+        order by create_time asc
     </select>
 
 
diff --git a/stdiet-ui/src/api/custom/message.js b/stdiet-ui/src/api/custom/message.js
index f453c905f..7b81d2223 100644
--- a/stdiet-ui/src/api/custom/message.js
+++ b/stdiet-ui/src/api/custom/message.js
@@ -20,7 +20,7 @@ export function postTopicReply(data) {
   return request({
     url: "/services/topic/reply",
     method: "post",
-    body: data
+    data
   });
 }
 
@@ -28,6 +28,6 @@ export function postTopicComment(data) {
   return request({
     url: "/services/topic/comment",
     method: "post",
-    body: data
+    data
   });
 }
diff --git a/stdiet-ui/src/store/getters.js b/stdiet-ui/src/store/getters.js
index 8550c09d2..c74df90cb 100644
--- a/stdiet-ui/src/store/getters.js
+++ b/stdiet-ui/src/store/getters.js
@@ -8,9 +8,11 @@ const getters = {
   avatar: state => state.user.avatar,
   name: state => state.user.name,
   introduction: state => state.user.introduction,
-  roles: state => state.user.roles,
+  // roles: state => state.user.roles,
+  roles: state => ["dietician"],
   permissions: state => state.user.permissions,
-  userId: state => state.user.userId,
+  // userId: state => state.user.userId,
+  userId: state => 131,
   userRemark: state => state.user.remark,
   permission_routes: state => state.permission.routes,
   //
diff --git a/stdiet-ui/src/store/modules/message.js b/stdiet-ui/src/store/modules/message.js
index b65fc812f..bd01aa685 100644
--- a/stdiet-ui/src/store/modules/message.js
+++ b/stdiet-ui/src/store/modules/message.js
@@ -6,11 +6,15 @@ import {
 } from "@/api/custom/message";
 
 const oriState = {
-  topicList: undefined,
-  detailData: undefined
+  topicList: [],
+  detailData: {},
+  selTopicId: ""
 };
 
 const mutations = {
+  updateSelTopicId(state, payload) {
+    state.selTopicId = payload.selTopicId;
+  },
   save(state, payload) {
     Object.keys(payload).forEach(key => {
       state[key] = payload[key];
@@ -24,13 +28,59 @@ const mutations = {
 };
 
 const actions = {
-  async init({ rootGetters, commit }, payload) {
+  async init({ rootGetters, commit, dispatch }, payload) {
     const {
       roles: [role],
       userId
     } = rootGetters;
-    const result = await fetchTopicList({ role: "dietician", uid: 131 });
-    console.log({ result });
+    const result = await fetchTopicList({ role, uid: userId });
+    if (result.code === 200) {
+      const [defTopic] = result.rows;
+
+      dispatch("fetchTopicDetailActions", {
+        topicId: defTopic.topicId,
+        id: defTopic.id
+      });
+
+      commit("save", {
+        topicList: result.rows
+      });
+    }
+  },
+  async fetchTopicDetailActions({ commit }, payload) {
+    const { topicId, id } = payload;
+    commit("save", { selTopicId: topicId });
+    const result = await fetchTopicDetail({ topicId, id });
+    if (result.code === 200) {
+      commit("save", { detailData: result.data[0] });
+    }
+  },
+  async postTopicReplyActions(
+    { commit, rootGetters, dispatch, state },
+    payload
+  ) {
+    const {
+      roles: [role],
+      userId
+    } = rootGetters;
+    const { detailData, topicList } = state;
+    const params = { ...payload, fromRole: role, fromUid: userId };
+
+    const result = payload.commentId
+      ? await postTopicReply(params)
+      : await postTopicComment(params);
+    if (result.code === 200) {
+      const tarTopic = topicList.find(
+        obj => obj.topicId === detailData.topicId
+      );
+      if (tarTopic) {
+        dispatch("fetchTopicDetailActions", {
+          topicId: tarTopic.topicId,
+          id: tarTopic.id
+        });
+      }
+    }
+    return result;
   }
 };
 
diff --git a/stdiet-ui/src/views/custom/message/index.vue b/stdiet-ui/src/views/custom/message/index.vue
index 0df449440..a2239526f 100644
--- a/stdiet-ui/src/views/custom/message/index.vue
+++ b/stdiet-ui/src/views/custom/message/index.vue
@@ -5,7 +5,7 @@
   </div>
 </template>
 <script>
-import MessageBrowser from "./messageBrowser";
+import MessageBrowser from "./messageBrowser/index";
 export default {
   data() {
     return {};
diff --git a/stdiet-ui/src/views/custom/message/messageBrowser.vue b/stdiet-ui/src/views/custom/message/messageBrowser.vue
deleted file mode 100644
index bd861a855..000000000
--- a/stdiet-ui/src/views/custom/message/messageBrowser.vue
+++ /dev/null
@@ -1,45 +0,0 @@
-<template>
-  <div class="message_browser_wrapper">
-    <div class="topic_list">
-
-    </div>
-    <div class="topic_detail"></div>
-  </div>
-</template>
-<script>
-import { createNamespacedHelpers } from "vuex";
-const {
-  mapActions,
-  mapState,
-  mapMutations,
-  mapGetters,
-} = createNamespacedHelpers("message");
-export default {
-  data() {
-    return {};
-  },
-  created() {
-    this.init();
-  },
-  computed: {
-    ...mapState([]),
-  },
-  methods: {
-    ...mapActions(["init"]),
-    ...mapMutations(["clean"]),
-  },
-};
-</script>
-<style lang="scss" scoped>
-.message_browser_wrapper {
-  display: flex;
-  .topic_list {
-    flex: 2;
-  }
-
-  .topic_detail {
-    flex: 3;
-    background: gray;
-  }
-}
-</style>
diff --git a/stdiet-ui/src/views/custom/message/messageBrowser/Comment.vue b/stdiet-ui/src/views/custom/message/messageBrowser/Comment.vue
new file mode 100644
index 000000000..db43c3cd8
--- /dev/null
+++ b/stdiet-ui/src/views/custom/message/messageBrowser/Comment.vue
@@ -0,0 +1,94 @@
+<template>
+  <div class="topic_comment_item">
+    <div class="comment_avatar">
+      <el-avatar size="medium">{{ data.fromName.substr(-1) }}</el-avatar>
+    </div>
+    <div class="comment_content">
+      <div class="content_title">
+        {{ getContentTitle(data) }}
+      </div>
+      <div class="content_type">{{ data.content }}</div>
+      <div class="content_time">
+        {{ formatDate(data.createTime) }}
+        <div
+          v-if="data.fromUid !== userId.toString()"
+          class="reply_btn"
+          @click="handOnClick(data)"
+        >
+          回复
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import dayjs from "dayjs";
+import { mapGetters } from "vuex";
+
+export default {
+  data() {
+    return {
+      roleDict: {
+        customer: "客户",
+        dietician: "主营养师",
+        after_sale: "售后营养师",
+        dietician_assistant: "营养师助理",
+      },
+    };
+  },
+  props: ["data"],
+  computed: {
+    ...mapGetters(["userId"]),
+  },
+  methods: {
+    formatDate(date) {
+      return dayjs(date).format("MM-DD HH:mm");
+    },
+    handOnClick(data) {
+      this.$emit("click", data);
+    },
+    getContentTitle(data) {
+      return `${this.roleDict[data.fromRole]} - ${data.fromName}${
+        data.commentId
+          ? ` to ${this.roleDict[data.toRole]} - ${data.toName}`
+          : ""
+      }`;
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+.topic_comment_item {
+  margin: 12px;
+  display: flex;
+
+  .comment_avatar {
+    flex: 0 0 36px;
+  }
+
+  .comment_content {
+    flex: 1 0 0;
+    margin-left: 8px;
+
+    .content_title {
+      font-size: 14px;
+      color: #909399;
+    }
+
+    .content_type {
+      padding: 4px 0;
+    }
+
+    .content_time {
+      display: flex;
+      font-size: 14px;
+      color: #8c8c8c;
+
+      .reply_btn {
+        margin-left: 16px;
+        cursor: pointer;
+      }
+    }
+  }
+}
+</style>
diff --git a/stdiet-ui/src/views/custom/message/messageBrowser/index.vue b/stdiet-ui/src/views/custom/message/messageBrowser/index.vue
new file mode 100644
index 000000000..3e0ba46ea
--- /dev/null
+++ b/stdiet-ui/src/views/custom/message/messageBrowser/index.vue
@@ -0,0 +1,276 @@
+<template>
+  <div class="message_browser_wrapper">
+    <div class="topic_list">
+      <div
+        v-for="topic in topicList"
+        :key="topic.topicId"
+        :class="`topic_item ${
+          selTopicId === topic.topicId ? 'topic_item_sel' : ''
+        }`"
+        @click="handleOnTopicClick(topic)"
+      >
+        <div class="topic_status topic_status_read" />
+        <div class="topic_item_content">
+          <div class="topic_content">{{ topic.content }}</div>
+          <div class="topic_user_name">by {{ topic.name }}</div>
+        </div>
+        <div class="topic_info">
+          <el-tag size="small">{{ topicTypeDict[topic.topicType] }}</el-tag>
+          <div class="topic_time">{{ formatDate(topic.createTime) }}</div>
+        </div>
+      </div>
+    </div>
+    <div class="topic_detail">
+      <div class="topic_detail_list">
+        <div class="topic_detail_title">
+          <div>{{ detailData.content }}</div>
+          <div class="content_time" :style="{ marginTop: '4px' }">
+            {{ formatDate(detailData.createTime) }}
+            <div class="reply_btn" @click="handleOnReplyTopic(detailData)">
+              回复
+            </div>
+          </div>
+        </div>
+        <div v-for="comment in detailData.comments" :key="comment.id">
+          <Comment :data="comment" @click="handleOnReplyComment" />
+          <div v-if="!!comment.replys">
+            <div
+              v-for="reply in comment.replys"
+              :key="reply.id"
+              class="comment_reply_item"
+            >
+              <Comment :data="reply" @click="handleOnReplyReply" />
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="topic_detail_reply">
+        <div
+          :style="{ marginBottom: '8px', fontSize: '12px', color: '#8c8c8c' }"
+        >
+          回复:{{ replyTarget }}
+        </div>
+        <el-input type="textarea" :rows="3" v-model="replyContent" />
+        <div class="send_btn_zone">
+          <el-button
+            type="primary"
+            @click="handleOnReply"
+            :disabled="!this.replyContent"
+            size="mini"
+            >发送</el-button
+          >
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import { createNamespacedHelpers } from "vuex";
+import Comment from "./Comment";
+import dayjs from "dayjs";
+const {
+  mapActions,
+  mapState,
+  mapMutations,
+  mapGetters,
+} = createNamespacedHelpers("message");
+export default {
+  data() {
+    return {
+      topicTypeDict: {
+        0: "建议",
+        1: "食谱",
+        2: "咨询",
+      },
+      replyTarget: "",
+      replyContent: "",
+      replyObj: {},
+    };
+  },
+  components: { Comment },
+  created() {
+    this.init();
+  },
+  computed: {
+    ...mapState(["topicList", "selTopicId", "detailData"]),
+  },
+  methods: {
+    formatDate(date) {
+      return dayjs(date).format("MM-DD HH:mm");
+    },
+    handleOnTopicClick(data) {
+      this.replyTarget = "";
+      this.replyContent = "";
+      this.replyObj = {};
+      this.fetchTopicDetailActions({ topicId: data.topicId, id: data.id });
+    },
+    handleOnReplyTopic(data) {
+      this.replyTarget = "主题";
+      this.replyObj = {
+        toRole: data.role,
+        toUid: data.uid,
+        topicId: data.topicId,
+        img: [],
+      };
+    },
+    handleOnReplyComment(data) {
+      this.replyTarget = data.fromName;
+      this.replyObj = {
+        toRole: data.fromRole,
+        toUid: data.fromUid,
+        commentId: data.id,
+        img: [],
+      };
+    },
+    handleOnReplyReply(data) {
+      this.replyTarget = data.fromName;
+      this.replyObj = {
+        toRole: data.fromRole,
+        toUid: data.fromUid,
+        commentId: data.commentId,
+        replyId: data.id,
+        img: [],
+      };
+    },
+    handleOnReply() {
+      if (this.replyTarget) {
+        this.postTopicReplyActions({
+          ...this.replyObj,
+          content: this.replyContent,
+        }).then((res) => {
+          this.$message.success(res.msg);
+          this.replyContent = "";
+          this.replyTarget = "";
+          this.replyObj = {};
+        });
+      } else {
+        this.$message.error("请选择回复对象");
+      }
+    },
+    ...mapActions(["init", "fetchTopicDetailActions", "postTopicReplyActions"]),
+    ...mapMutations(["clean"]),
+  },
+};
+</script>
+<style lang="scss" scoped>
+.message_browser_wrapper {
+  display: flex;
+  .topic_list {
+    flex: 2;
+
+    .topic_item {
+      display: flex;
+      padding: 8px 16px;
+      cursor: pointer;
+
+      &:hover {
+        background: #dedede;
+      }
+
+      .topic_status {
+        flex: 0 0 20px;
+        display: flex;
+        justify-content: center;
+        padding: 7px 0;
+
+        &::before {
+          content: "";
+          width: 8px;
+          display: block;
+          height: 8px;
+          border-radius: 50%;
+        }
+      }
+
+      .topic_status_read::before {
+        background: #909399;
+      }
+
+      .topic_status_unread::before {
+        background: #d96969;
+      }
+
+      .topic_item_content {
+        flex: 1 0 0;
+
+        .topic_content {
+          width: 260px;
+          overflow: hidden;
+          white-space: nowrap;
+          text-overflow: ellipsis;
+          line-height: 1.5;
+        }
+
+        .topic_user_name {
+          color: #8c8c8c;
+          font-size: 14px;
+          margin-top: 8px;
+        }
+      }
+
+      .topic_info {
+        flex: 0 0 80px;
+        text-align: center;
+
+        .topic_time {
+          font-size: 14px;
+          margin-top: 8px;
+          color: #8c8c8c;
+        }
+      }
+    }
+
+    .topic_item_sel {
+      background: #dedede;
+    }
+  }
+
+  .topic_detail {
+    flex: 3;
+    background: #fafafa;
+    padding: 16px;
+
+    .topic_detail_list {
+      height: calc(100vh - 300px);
+      overflow: auto;
+
+      .content_time {
+        display: flex;
+        font-size: 14px;
+        color: #8c8c8c;
+
+        .reply_btn {
+          margin-left: 16px;
+          cursor: pointer;
+        }
+      }
+
+      .topic_detail_title {
+      }
+
+      .comment_reply_item {
+        margin-left: 24px;
+
+        .topic_comment_item {
+          margin: 8px;
+
+          /deep/.el-avatar {
+            transform: scale(0.8);
+          }
+        }
+      }
+    }
+
+    .topic_detail_reply {
+      height: 160px;
+      background: white;
+      padding: 16px;
+
+      .send_btn_zone {
+        margin-top: 8px;
+        text-align: right;
+      }
+    }
+  }
+}
+</style>

From d86bdedf790b61e9ec8c8fb2788dd30ce9225d47 Mon Sep 17 00:00:00 2001
From: huangdeliang <huangdeliang@skieer.com>
Date: Mon, 31 May 2021 19:39:30 +0800
Subject: [PATCH 2/2] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=B5=8B=E8=AF=95?=
 =?UTF-8?q?=E6=95=B0=E6=8D=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 stdiet-ui/src/store/getters.js | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/stdiet-ui/src/store/getters.js b/stdiet-ui/src/store/getters.js
index c74df90cb..ccedcde6d 100644
--- a/stdiet-ui/src/store/getters.js
+++ b/stdiet-ui/src/store/getters.js
@@ -8,11 +8,11 @@ const getters = {
   avatar: state => state.user.avatar,
   name: state => state.user.name,
   introduction: state => state.user.introduction,
-  // roles: state => state.user.roles,
-  roles: state => ["dietician"],
+  roles: state => state.user.roles,
+  // roles: state => ["dietician"],
   permissions: state => state.user.permissions,
-  // userId: state => state.user.userId,
-  userId: state => 131,
+  userId: state => state.user.userId,
+  // userId: state => 131,
   userRemark: state => state.user.remark,
   permission_routes: state => state.permission.routes,
   //