zhuangyunsheng před 1 rokem
rodič
revize
257d8d511e

+ 9 - 13
src/components/ReplyCard/detail.vue

@@ -1,7 +1,8 @@
 <template>
     <div class="reply-item-dialog">
-        <el-dialog v-model="visible" :title="`${childrenCount}条回复`" width="680" @closed="$emit('closed')">
-            <reply-tree ref="replyTree" @updateCount="childrenCount = $event" @closeDialog="visible = false"></reply-tree>
+        <el-dialog v-model="visible" :title="`${replyData.childrenCount}条回复`" width="680" @closed="$emit('closed')">
+            <reply-tree :currentReply="replyData" @updateCount="replyData.childrenCount = $event" @closeDialog="visible = false"></reply-tree>
+            <el-divider>没有更多内容了</el-divider>
         </el-dialog>
     </div>
 </template>
@@ -19,18 +20,17 @@ export default {
         return {
             visible: false,
 
-            childrenCount: 0
+            replyData: {
+                childrenCount: 0
+            }
         }
     },
 
     methods: {
-        open() {
+        open(data) {
             this.visible = true;
+            this.replyData = Object.assign({}, data);
             return this;
-        },
-
-        setData(data) {
-            nextTick(() => this.$refs.replyTree.setData(data));
         }
     }
 }
@@ -51,16 +51,12 @@ export default {
     .el-card__body {
       margin-left: 10px;
       padding: 0;
-
-      .no-p-b {
-        padding-bottom: 0;
-      }
     }
   }
 
   .el-divider {
     margin-top: 40px;
-    border-color: var(--el-border-color-light);
+    border-color: var(--el-border-color-lighter);
 
     .el-divider__text {
       padding: 0 60px;

+ 70 - 210
src/components/ReplyCard/index.vue

@@ -1,5 +1,5 @@
 <template>
-    <el-card shadow="never" :class="total > 0 && 'reply-card'">
+    <el-card :class="['reply-card', total > 0 && 'header-has-border']" shadow="never">
         <template #header>
             <el-button type="primary" link @click="showInput = !showInput">留言
                 <template #icon><el-icon size="16"><tjm-icon-mdi-comment-text-outline /></el-icon></template>
@@ -11,77 +11,36 @@
             </div>
         </template>
 
-        <el-form v-loading="loading">
-            <template v-for="(item, index) in replyData" :key="item.id">
-                <div class="reply-item">
-                    <el-form-item :label="`${item.createName}:`">{{ item.messageContent }}</el-form-item>
-                    <el-form-item class="reply-date-item" :label="formatDate(item.createTime)">
-                        <div class="handle-button-group">
-                            <el-tooltip content="删除" placement="top">
-                                <el-button v-if="item.createId == loginUser" icon="delete" circle @click="reply_del(item)"></el-button>
-                            </el-tooltip>
-                            <el-tooltip content="留言" placement="top">
-                                <el-button circle @click="reply_add(item)">
-                                    <template #icon><tjm-icon-mdi-comment-text-outline /></template>
-                                </el-button>
-                            </el-tooltip>
-                        </div>
-                    </el-form-item>
-                </div>
-                <div class="reply-item__children">
-                    <div class="reply-item" v-for="child in replyChildren[index]" :key="child.id">
-                        <el-form-item>
-                            <template #label>{{ child.createName }}:
-                                <template v-if="child.replyId"><span>回复@</span>{{ child.replyName }}:</template>
-                            </template>
-                            {{ child.messageContent }}
-                        </el-form-item>
-                        <el-form-item class="reply-date-item" :label="formatDate(child.createTime)">
-                            <div class="handle-button-group">
-                                <el-tooltip content="删除" placement="top">
-                                    <el-button v-if="child.createId == loginUser" icon="delete" circle @click="reply_del(child)"></el-button>
-                                </el-tooltip>
-                                <el-tooltip content="留言" placement="top">
-                                    <el-button circle @click="reply_add(child)">
-                                        <template #icon><tjm-icon-mdi-comment-text-outline /></template>
-                                    </el-button>
-                                </el-tooltip>
-                            </div>
-                        </el-form-item>
-                    </div>
-                    <el-button v-if="item.childrenCount > replyChildrenCount" class="text-reverse" type="primary" link @click="reply_children(item)">共{{ item.childrenCount }}条回复
-                        <template #icon><el-icon size="22"><tjm-icon-mdi-menu-down /></el-icon></template>
-                    </el-button>
-                </div>
-            </template>
-        </el-form>
-
-        <template v-if="total > replyCount">
-            <el-divider></el-divider>
-            <el-button class="text-reverse" type="primary" link>查看全部{{ allTotal }}条留言
-                <template #icon><arrow-right /></template>
-            </el-button>
-        </template>
-        <template v-else>
-            <el-divider v-if="total">已加载全部留言</el-divider>
+        <template v-for="(item, index) in replyData" v-bind:key="index">
+            <reply-tree :currentReply="item" :pageSize="replyChildrenCount" @closeDialog="reloadTree">
+                <!-- 回复详情 -->
+                <el-button class="text-reverse" type="primary" link @click="reply_detail(item)">共{{ item.childrenCount }}条回复
+                    <template #icon><el-icon size="22"><tjm-icon-mdi-menu-down /></el-icon></template>
+                </el-button>
+            </reply-tree>
         </template>
+        
+        <div class="reply-card__footer">
+            <template v-if="total > replyCount">
+                <el-divider></el-divider>
+                <el-button class="text-reverse" type="primary" icon="arrow-right" link>查看全部11条留言</el-button>
+            </template>
+            <template v-else><el-divider v-if="total">已加载全部留言</el-divider></template>
+        </div>
     </el-card>
 
-    <reply-detail v-if="dialog.detail" ref="replyDetail" :refId="refId" :refType="refType" @success="reloadChildrenTree" @closed="dialog.detail = false"></reply-detail>
-    <reply-child-detail v-if="dialog.child" ref="replyChildDetail" @closed="reloadTree(), dialog.child = false"></reply-child-detail>
+    <reply-detail v-if="dialog" ref="replyDetail" @closed="reloadTree(), dialog = false"></reply-detail>
 </template>
 
 <script>
-import moment from "moment";
 import API from "@/api/policy/message";
-import replyDetail from "./dialog.vue";
-import replyChildDetail from "./detail.vue";
-import { useUserStore } from "@/store/user";
+import replyTree from "@/components/ReplyCard/tree/index.vue";
+import replyDetail from "@/components/ReplyCard/detail.vue";
 
 export default {
     components: {
-        replyDetail,
-        replyChildDetail
+        replyTree,
+        replyDetail
     },
     props: {
         refId: { type: String, default: "" },
@@ -93,7 +52,6 @@ export default {
     data() {
         return {
             loading: false,
-            loginUser: useUserStore().userInfo.id,
             params: {
                 page: 1,
                 size: this.replyCount,
@@ -103,22 +61,12 @@ export default {
             },
             total: 0,
             replyData: [],
-            replyChildren: [],
 
             showInput: false,
             isSaving: false,
             messageContent: null,
 
-            dialog: {
-                detail: false,
-                child: false
-            }
-        }
-    },
-
-    computed: {
-        allTotal() {
-            return this.total + (this.replyChildren.length && this.replyChildren.map(c => c.length).reduce((p, v) => p + v) || 0);
+            dialog: false
         }
     },
 
@@ -127,10 +75,6 @@ export default {
     },
 
     methods: {
-        formatDate(value) {
-            return value && moment(value).format("YY-MM-DD HH:mm") || "";
-        },
-
         reloadTree() {
             this.loading = true;
             API.get(this.params).then(res => {
@@ -138,28 +82,10 @@ export default {
                 if (res.code === 200) {
                     this.replyData = res.data.records;
                     this.total = res.data.total;
-                    this.reloadChildrenTree();
                 } else ElMessage.error(res.msg);
             }).catch(() => this.loading = false);
         },
 
-        reloadChildrenTree(parentId) {
-            let promiseArray = [];
-            if (parentId) {
-                const reply_i = this.replyData.findIndex(c => c.id == parentId);
-                this.replyData[reply_i].childrenCount++;
-
-                promiseArray = this.replyData.map(_ => []);
-                promiseArray[reply_i] = API.get({ ...this.params, size: this.replyChildrenCount, parentId });
-            } else this.replyData.forEach(item => promiseArray.push(API.get({ ...this.params, size: this.replyChildrenCount, parentId: item.id })));
-
-            Promise.all(promiseArray).then(res => {
-                this.replyChildren = res.map(r => r.code == 200 && r.data.records || []);
-            }).catch(() => {
-                this.replyChildren = [];
-            });
-        },
-
         submit() {
             if (this.refId && this.refType) {
                 const data = {
@@ -181,29 +107,9 @@ export default {
             }
         },
 
-        reply_add(data) {
-            this.dialog.detail = true;
-            nextTick(() => this.$refs.replyDetail.open().setData(data));
-        },
-
-        reply_del(data) {
-            ElMessageBox.confirm("是否确认删除?", "删除警告", {
-                type: "warning",
-                confirmButtonText: "确定",
-                cancelButtonText: "取消"
-            }).then(() => {
-                API.del({ ids: data.id }).then(res => {
-                    if (res.code == 200) {
-                        ElMessage.success("操作成功");
-                        this.reloadTree();
-                    } else ElMessage.error(res.msg);
-                });
-            }).catch(() => ElMessage.success("已取消"));
-        },
-
-        reply_children(data) {
-            this.dialog.child = true;
-            nextTick(() => this.$refs.replyChildDetail.open().setData(data));
+        reply_detail(data) {
+            this.dialog = true;
+            nextTick(() => this.$refs.replyDetail.open(data));
         }
     }
 }
@@ -216,21 +122,21 @@ export default {
 
   :deep([class*='el-icon'] + span) {
     margin-left: 0;
-    margin-right: 6px;
     font-size: 13px;
   }
 }
 
-.el-card {
+.reply-card {
+  --el-card-border-color: var(--el-border-color-lighter);
   margin-bottom: 25px;
   border-top: none;
-  border-radius: 0 0 var(--el-card-border-radius) var(--el-card-border-radius);
+  border-radius: 0;
 
   :deep(.el-card__header) {
     display: flex;
     flex-direction: column;
     align-items: center;
-    border-bottom: 0;
+    border-bottom: none;
     padding: calc(var(--el-card-padding) / 2) var(--el-card-padding);
 
     .reply-form {
@@ -247,108 +153,62 @@ export default {
     }
   }
 
-  :deep(.el-card__body) {
+  > :deep(.el-card__body) {
     padding: 0;
 
-    .el-divider {
-      margin: calc(var(--el-card-padding) / 2) 0;
-      border-color: var(--el-border-color-light);
-
-      .el-divider__text {
-        color: var(--el-text-color-disabled);
-      }
-    }
-  }
-}
+    .el-card {
+      border: none;
+      border-radius: 0;
 
-.reply-card :deep(.el-card__body) {
-  display: flex;
-  flex-direction: column;
-  padding: calc(var(--el-card-padding) / 2) var(--el-card-padding);
-  padding-top: 0;
+      .el-card__body {
+        margin-left: 10px;
+        padding: 0;
 
-  .el-form {
-    flex-basis: 100%;
-    padding: calc(var(--el-card-padding) / 2) 10% 0;
-    border-top: 1px solid var(--el-card-border-color);
-
-    .el-form-item {
-      align-items: baseline;
-      margin-bottom: 0;
-      padding: 0 6px;
-      border-radius: 4px 4px 0 0;
-
-      .el-form-item__label {
-        height: fit-content;
-        line-height: 22px;
-        font-size: 13px;
-        color: var(--el-color-primary);
-      }
-
-      .el-form-item__content {
-        height: fit-content;
-        line-height: 22px;
-        font-size: 13px;
-        color: var(--el-text-color-regular);
+        .text-reverse {
+          margin-bottom: 10px;
+          padding: calc(9px / 2) 0 calc(9px / 2) 9px;
+          border: none;
+          border-left: 1px solid var(--el-border-color-lighter);
+          border-radius: 0;
+        }
       }
     }
+  }
 
-    .reply-date-item {
-      margin-bottom: 6px;
-      align-items: center;
-      border-radius: 0 0 4px 4px;
-
-      .el-form-item__label {
-        color: var(--el-text-color-placeholder);
-      }
-
-      .el-form-item__content {
-        justify-content: flex-end;
-
-        .handle-button-group {
-          display: none;
+  .reply-card__footer {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    height: fit-content;
 
-          .el-button {
-            width: 20px;
-            height: 20px;
-            padding: 0;
-            background-color: transparent;
-            border: none;
+    .el-divider {
+      margin: 10px 0;
+      border-color: var(--el-card-border-color);
 
-            &:hover {
-              background-color: var(--el-color-primary-light-8);
-            }
-          }
-        }
+      :deep(.el-divider__text) {
+        padding: 0 60px;
+        color: var(--el-text-color-disabled);
       }
     }
+  }
+}
 
-    .reply-item:hover .el-form-item {
-      background: var(--el-color-primary-light-9);
+.header-has-border.reply-card > :deep {
+  .el-card__header {
+    position: relative;
 
-      .el-form-item__content .handle-button-group {
-        display: inline-flex;
-      }
+    &::after {
+      content: '';
+      position: absolute;
+      bottom: 0;
+      width: 80%;
+      height: 1px;
+      background: var(--el-card-border-color);
     }
+  }
 
-    .reply-item__children {
-      margin-bottom: 6px;
-      margin-left: 6px;
-      padding-left: 1px;
-      border-left: 1px solid var(--el-card-border-color);
-
-      .el-form-item__label span {
-        color: var(--el-text-color-regular);
-      }
-
-      .reply-item:last-child .reply-date-item {
-        margin-bottom: 0;
-      }
-
-      .text-reverse {
-        margin-left: 3px;
-      }
-    }
+  .el-card__body {
+    padding: calc(var(--el-card-padding) / 2) 10%;
   }
 }
 </style>

+ 27 - 22
src/components/ReplyCard/tree/index.vue

@@ -1,12 +1,17 @@
 <template>
-    <reply-item :replyItem="replyData" @success="reloadChildren" @closeDialog="$emit('closeDialog')"></reply-item>
+    <reply-item :replyItem="replyData" :isLastItem="replyData.childrenCount == 0" @success="reloadChildren" @closeDialog="$emit('closeDialog')"></reply-item>
 
-    <el-card v-loading="loading" shadow="never">
+    <el-card class="reply-children-card" v-loading="loading" shadow="never">
         <template v-for="(item, index) in replyData.children" v-bind:key="index">
-            <reply-item :class="index == replyData.childrenCount - 1 && 'no-p-b'" :replyItem="item" @success="reloadChildren"></reply-item>
+            <reply-item :replyItem="item" :isLastItem="index == replyData.childrenCount - 1" @success="reloadChildren"></reply-item>
+        </template>
+        
+        <!-- 回复详情 -->
+        <template v-if="replyData.childrenCount > replyData.children.length">
+            <slot></slot>
         </template>
-        <el-divider>没有更多内容了</el-divider>
     </el-card>
+
 </template>
 
 <script>
@@ -16,7 +21,11 @@ import replyItem from "@/components/ReplyCard/tree/item.vue";
 export default {
     emits: ["updateCount", "closeDialog"],
     components: {
-        replyItem
+        replyItem,
+    },
+    props: {
+        pageSize: { type: Number, defult: 999 },
+        currentReply: { type: Object, defult: () => {} }
     },
     
     data() {
@@ -37,8 +46,18 @@ export default {
         }
     },
 
+    watch: {
+        currentReply(value) {
+            this.init(this.currentReply);
+        }
+    },
+
+    mounted() {
+        this.init(this.currentReply);
+    },
+
     methods: {
-        setData(data) {
+        init(data) {
             for (const key in this.replyData) {
                 if (key == "children") this.replyData[key] = [];
                 else this.replyData[key] = data[key];
@@ -49,7 +68,7 @@ export default {
 
         reloadChildren() {
             this.loading = true;
-            API.get({ page: 1, size: 999, parentId: this.replyData.id, refId: this.replyData.refId, refType: this.replyData.refType }).then(res => {
+            API.get({ page: 1, size: this.pageSize, parentId: this.replyData.id, refId: this.replyData.refId, refType: this.replyData.refType }).then(res => {
                 this.loading = false;
                 if (res.code === 200) {
                     this.replyData["childrenCount"] = res.data.total;
@@ -63,27 +82,13 @@ export default {
 </script>
 
 <style lang="scss" scoped>
-.el-card {
+.reply-children-card {
   border: none;
   border-radius: 0;
 
   .el-card__body {
     margin-left: 10px;
     padding: 0;
-
-    .no-p-b {
-      padding-bottom: 0;
-    }
-  }
-}
-
-.el-divider {
-  margin-top: 40px;
-  border-color: var(--el-border-color-light);
-
-  .el-divider__text {
-    padding: 0 60px;
-    color: var(--el-text-color-disabled);
   }
 }
 </style>

+ 9 - 3
src/components/ReplyCard/tree/item.vue

@@ -1,5 +1,5 @@
 <template>
-    <el-form :class="['reply-item', replyItem.parentId == 0 && 'no-b-l']">
+    <el-form :class="['reply-item', replyItem.parentId == 0 && 'no-b-l', isLastItem && 'no-p-b']">
         <div class="reply-item__content">
             <el-form-item>
                 <template #label>{{ replyItem.createName }}<span>:</span>
@@ -37,7 +37,8 @@ export default {
         replyDetail
     },
     props: {
-        replyItem: { type: Object, default: () => {} }
+        replyItem: { type: Object, default: () => {} },
+        isLastItem: { type: Boolean, default: false }
     },
 
     data() {
@@ -95,7 +96,7 @@ export default {
   align-items: center;
   padding-left: 10px;
   padding-bottom: 10px;
-  border-left: 1px solid var(--el-border-color-light);
+  border-left: 1px solid var(--el-border-color-lighter);
 
   .reply-item__content {
     flex: 1;
@@ -153,4 +154,9 @@ export default {
 .no-b-l {
   border-left: none;
 }
+
+.no-p-b {
+  margin-bottom: 10px;
+  padding-bottom: 0;
+}
 </style>