diff --git a/app/Http/Controllers/Api/DialogController.php b/app/Http/Controllers/Api/DialogController.php
index 57ca54dba..ffdc7ed7a 100755
--- a/app/Http/Controllers/Api/DialogController.php
+++ b/app/Http/Controllers/Api/DialogController.php
@@ -457,6 +457,15 @@ class DialogController extends AbstractController
->where('web_socket_dialog_msgs.id', '<', $last->id)
->orderByDesc('web_socket_dialog_msgs.id')
->value('id'));
+ //
+ if (empty($position_id)) {
+ $unreadBuilder = WebSocketDialogMsgRead::whereDialogId($dialog_id)->whereUserid($user->userid)->whereReadAt(null)->where('msg_id', '<', $last->id);
+ $unread = $unreadBuilder->count();
+ $data['before'] = [
+ 'unread' => $unread,
+ 'first_id' => $unread > 0 ? intval($unreadBuilder->orderBy('msg_id')->value('msg_id')) : 0,
+ ];
+ }
}
$data['list'] = $list;
$data['time'] = Base::time();
diff --git a/resources/assets/js/pages/manage/components/DialogWrapper.vue b/resources/assets/js/pages/manage/components/DialogWrapper.vue
index 52502dbf3..d22f37e76 100644
--- a/resources/assets/js/pages/manage/components/DialogWrapper.vue
+++ b/resources/assets/js/pages/manage/components/DialogWrapper.vue
@@ -97,6 +97,14 @@
+
+
+
+
+ {{$L(`未读消息${beforeUnread.unread}条`)}}
+
+
+
id === this.dialogId)
+ return before || null
}
},
@@ -2202,6 +2218,25 @@ export default {
}
},
+ goBeforeUnread() {
+ if (!this.beforeUnread || this.beforeLoad) {
+ return;
+ }
+ //
+ this.beforeLoad = true
+ const {first_id} = this.beforeUnread
+ this.$store.dispatch("dialogMsgMark", {
+ dialog_id: this.dialogId,
+ type: 'read'
+ }).then(_ => {
+ this.onPositionId(first_id)
+ }).catch(({msg}) => {
+ $A.modalError(msg)
+ }).finally(_ => {
+ this.beforeLoad = false
+ })
+ },
+
getBase64Image(url) {
return new Promise(resolve => {
let canvas = document.createElement('CANVAS'),
diff --git a/resources/assets/js/pages/manage/messenger.vue b/resources/assets/js/pages/manage/messenger.vue
index 667474e8c..88cab075c 100644
--- a/resources/assets/js/pages/manage/messenger.vue
+++ b/resources/assets/js/pages/manage/messenger.vue
@@ -720,17 +720,12 @@ export default {
},
handleReadClick() {
- this.$store.dispatch("call", {
- url: 'dialog/msg/mark',
- data: {
- dialog_id: this.operateItem.id,
- type: $A.getDialogUnread(this.operateItem, true) > 0 ? 'read' : 'unread'
- },
- }).then(({data}) => {
- this.$store.dispatch("saveDialog", data);
+ this.$store.dispatch("dialogMsgMark", {
+ dialog_id: this.operateItem.id,
+ type: $A.getDialogUnread(this.operateItem, true) > 0 ? 'read' : 'unread'
}).catch(({msg}) => {
- $A.modalError(msg);
- });
+ $A.modalError(msg)
+ })
},
handleSilenceClick() {
diff --git a/resources/assets/js/store/actions.js b/resources/assets/js/store/actions.js
index 142cb761c..9c1156526 100644
--- a/resources/assets/js/store/actions.js
+++ b/resources/assets/js/store/actions.js
@@ -2505,6 +2505,18 @@ export default {
dispatch("saveDialogTodo", resData.todo)
}
//
+ const before = Object.assign({id: data.dialog_id}, resData.before || {});
+ const index = state.dialogBeforeUnreads.findIndex(({id}) => id == data.dialog_id);
+ if (before.unread) {
+ if (index > -1) {
+ state.dialogBeforeUnreads.splice(index, 1, before);
+ } else {
+ state.dialogBeforeUnreads.push(before);
+ }
+ } else if (index > -1) {
+ state.dialogBeforeUnreads.splice(index, 1);
+ }
+ //
dispatch("saveDialogMsg", resData.list)
resolve(result)
}).catch(e => {
@@ -2569,6 +2581,33 @@ export default {
}, 50);
},
+ /**
+ * 标记已读、未读
+ * @param state
+ * @param dispatch
+ * @param data
+ * @returns {Promise}
+ */
+ dialogMsgMark({state, dispatch}, data) {
+ return new Promise((resolve, reject) => {
+ dispatch("call", {
+ url: 'dialog/msg/mark',
+ data,
+ }).then(result => {
+ if (data.type === 'read') {
+ const index = state.dialogBeforeUnreads.findIndex(({id}) => id == data.dialog_id)
+ if (index > -1) {
+ state.dialogBeforeUnreads.splice(index, 1)
+ }
+ }
+ dispatch("saveDialog", result.data)
+ resolve(result)
+ }).catch(e => {
+ reject(e)
+ })
+ })
+ },
+
/** *****************************************************************************************/
/** ************************************* loads *********************************************/
/** *****************************************************************************************/
diff --git a/resources/assets/js/store/state.js b/resources/assets/js/store/state.js
index 61b800500..c2793565f 100644
--- a/resources/assets/js/store/state.js
+++ b/resources/assets/js/store/state.js
@@ -82,6 +82,7 @@ export default {
dialogHistory: [],
dialogInputCache: [],
dialogMsgTransfer: {time: 0},
+ dialogBeforeUnreads: [],
// 文件
fileLists: [],
diff --git a/resources/assets/sass/pages/components/dialog-wrapper.scss b/resources/assets/sass/pages/components/dialog-wrapper.scss
index 6826a7d4b..aa480ef1f 100644
--- a/resources/assets/sass/pages/components/dialog-wrapper.scss
+++ b/resources/assets/sass/pages/components/dialog-wrapper.scss
@@ -1074,6 +1074,30 @@
}
}
+ .dialog-top {
+ position: absolute;
+ top: 78px;
+ left: 0;
+ right: 0;
+ z-index: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ .top-unread {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 6px 12px;
+ border-radius: 4px;
+ box-shadow: 0 2px 8px 0 rgba($primary-text-color, 0.33);
+ background: #fff;
+ cursor: pointer;
+ > i {
+ margin-right: 4px;
+ }
+ }
+ }
+
.dialog-footer {
position: relative;
padding: 0 24px;
@@ -1589,6 +1613,12 @@
}
}
}
+ .dialog-top {
+ top: 68px;
+ &.down {
+ top: 98px;
+ }
+ }
.dialog-footer {
background-color: #f8f8f8;
padding: 8px 10px;