diff --git a/app/Http/Controllers/Api/DialogController.php b/app/Http/Controllers/Api/DialogController.php
index b28c825fb..8c6322017 100755
--- a/app/Http/Controllers/Api/DialogController.php
+++ b/app/Http/Controllers/Api/DialogController.php
@@ -218,7 +218,7 @@ class DialogController extends AbstractController
$user->task_dialog_id = $dialog->id;
$user->save();
}
- //去掉标记未读
+ // 去掉标记未读
$isMarkDialogUser = WebSocketDialogUser::whereDialogId($dialog->id)->whereUserid($user->userid)->whereMarkUnread(1)->first();
if ($isMarkDialogUser) {
$isMarkDialogUser->mark_unread = 0;
diff --git a/app/Models/WebSocketDialogMsg.php b/app/Models/WebSocketDialogMsg.php
index 2c2013b95..d9b5236db 100644
--- a/app/Models/WebSocketDialogMsg.php
+++ b/app/Models/WebSocketDialogMsg.php
@@ -27,6 +27,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* @property \Illuminate\Support\Carbon|null $updated_at
* @property \Illuminate\Support\Carbon|null $deleted_at
* @property-read int|mixed $percentage
+ * @property-read \App\Models\WebSocketDialogMsg|null $reply_data
* @property-read \App\Models\WebSocketDialog|null $webSocketDialog
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg newQuery()
@@ -55,6 +56,7 @@ class WebSocketDialogMsg extends AbstractModel
protected $appends = [
'percentage',
+ 'reply_data',
];
protected $hidden = [
@@ -81,6 +83,21 @@ class WebSocketDialogMsg extends AbstractModel
return $this->appendattrs['percentage'];
}
+ /**
+ * 回复消息详情
+ * @return WebSocketDialogMsg|null
+ */
+ public function getReplyDataAttribute()
+ {
+ if (!isset($this->appendattrs['reply_data'])) {
+ $this->appendattrs['reply_data'] = null;
+ if ($this->reply_id > 0) {
+ $this->appendattrs['reply_data'] = self::find($this->reply_id, ['id', 'userid', 'type', 'msg'])?->cancelAppend() ?: null;
+ }
+ }
+ return $this->appendattrs['reply_data'];
+ }
+
/**
* 消息格式化
* @param $value
diff --git a/package.json b/package.json
index 6b203d410..ab0071a6d 100644
--- a/package.json
+++ b/package.json
@@ -54,7 +54,7 @@
"vue-resize-observer": "^2.0.16",
"vue-router": "^3.5.3",
"vue-template-compiler": "^2.6.14",
- "vue-virtual-scroll-list": "^2.3.3",
+ "vue-virtual-scroll-list-hi": "^2.3.3-3",
"vuedraggable": "^2.24.3",
"vuex": "^3.6.2",
"webpack": "^5.69.1",
diff --git a/resources/assets/js/pages/manage/components/ChatInput/index.vue b/resources/assets/js/pages/manage/components/ChatInput/index.vue
index 991005620..f4f3cc0b0 100755
--- a/resources/assets/js/pages/manage/components/ChatInput/index.vue
+++ b/resources/assets/js/pages/manage/components/ChatInput/index.vue
@@ -277,7 +277,7 @@ export default {
}
},
computed: {
- ...mapState(['dialogInputCache', 'cacheProjects', 'cacheTasks', 'cacheUserBasic', 'dialogMsgs', 'dialogReplys']),
+ ...mapState(['dialogInputCache', 'cacheProjects', 'cacheTasks', 'cacheUserBasic', 'dialogMsgs']),
isEnterSend() {
if (typeof this.enterSend === "boolean") {
@@ -351,15 +351,7 @@ export default {
replyData() {
const {replyId} = this;
if (replyId > 0) {
- let data = this.dialogMsgs.find(item => item.id === replyId)
- if (data) {
- return data;
- }
- data = this.dialogReplys.find(item => item.id === replyId)
- if (data) {
- return data;
- }
- this.$store.dispatch("getDialogReply", replyId)
+ return this.dialogMsgs.find(item => item.id === replyId)
}
return null;
}
diff --git a/resources/assets/js/pages/manage/components/DialogView.vue b/resources/assets/js/pages/manage/components/DialogView.vue
index 8668fd06b..cb84e0639 100644
--- a/resources/assets/js/pages/manage/components/DialogView.vue
+++ b/resources/assets/js/pages/manage/components/DialogView.vue
@@ -10,9 +10,9 @@
:class="headClass"
v-longpress="{callback: handleLongpress, delay: 300}">
-
-
-
{{formatMsgDesc(replyData)}}
+
+
+
{{formatMsgDesc(msgData.reply_data)}}
@@ -172,7 +172,7 @@ export default {
},
computed: {
- ...mapState(['loads', 'dialogMsgs', 'dialogReplys', 'audioPlaying', 'windowActive']),
+ ...mapState(['loads', 'audioPlaying', 'windowActive']),
isLoading() {
if (!this.msgData.created_at) {
@@ -183,12 +183,12 @@ export default {
},
viewClass() {
- const {msgData, replyData, operateAction, operateEnter} = this;
+ const {msgData, operateAction, operateEnter} = this;
const array = [];
if (msgData.type) {
array.push(msgData.type)
}
- if (replyData) {
+ if (msgData.reply_data) {
array.push('reply-view')
}
if (operateAction) {
@@ -237,22 +237,6 @@ export default {
}
}
return classArray;
- },
-
- replyData() {
- const {reply_id} = this.msgData;
- if (reply_id > 0) {
- let data = this.dialogMsgs.find(item => item.id === reply_id)
- if (data) {
- return data;
- }
- data = this.dialogReplys.find(item => item.id === reply_id)
- if (data) {
- return data;
- }
- this.$store.dispatch("getDialogReply", reply_id)
- }
- return null;
}
},
@@ -390,7 +374,7 @@ export default {
viewReply() {
this.$emit("on-view-reply", {
msg_id: this.msgData.id,
- reply_id: this.replyData.id
+ reply_id: this.msgData.reply_id
})
},
diff --git a/resources/assets/js/pages/manage/components/DialogWrapper.vue b/resources/assets/js/pages/manage/components/DialogWrapper.vue
index e8434ed59..09a6183b6 100644
--- a/resources/assets/js/pages/manage/components/DialogWrapper.vue
+++ b/resources/assets/js/pages/manage/components/DialogWrapper.vue
@@ -81,6 +81,7 @@
:estimate-size="78"
:keeps="70"
@scroll="onScroll"
+ @range="onRange"
@totop="onNextPage"
@on-longpress="onLongpress"
@@ -263,7 +264,7 @@ import DrawerOverlay from "../../../components/DrawerOverlay";
import DialogGroupInfo from "./DialogGroupInfo";
import ChatInput from "./ChatInput";
-import VirtualList from 'vue-virtual-scroll-list'
+import VirtualList from 'vue-virtual-scroll-list-hi'
import {Store} from "le5le-store";
import {textImagesInfo} from "../../../functions/utils";
@@ -325,10 +326,11 @@ export default {
operateEmojis: ['👌', '🤝', '🤔', '👍', '👎', '👏', '✋', '✅', '❌', '❤️', '❓'],
recordState: '',
- wrapperStart: 0,
+ wrapperStart: {},
- scrollBalance: 0,
- scrollMoreLoad: false,
+ scrollTail: 0,
+ preventMoreLoad: false,
+ preventToBottom: false,
replyId: 0,
replyActiveIndex: -1,
@@ -434,7 +436,7 @@ export default {
if (this.msgNew > 0 && this.allMsgs.length > 0) {
return 'newmsg'
}
- if (this.scrollBalance > 50) {
+ if (this.scrollTail > 50) {
return 'goto'
}
return null
@@ -509,25 +511,27 @@ export default {
},
allMsgList(newList, oldList) {
- const {balance} = this.scrollInfo();
+ const {tail} = this.scrollInfo();
this.allMsgs = newList;
//
- if (!this.windowActive || (balance > 10 && oldList.length > 0)) {
+ if (!this.windowActive || (tail > 10 && oldList.length > 0)) {
const lastId = oldList[oldList.length - 1].id
const tmpList = newList.filter(item => item.id && item.id > lastId)
this.msgNew += tmpList.length
} else {
- requestAnimationFrame(this.onToBottom)
+ if (!this.preventToBottom) {
+ requestAnimationFrame(this.onToBottom)
+ }
}
},
windowScrollY(val) {
if ($A.isIos()) {
- const {balance} = this.scrollInfo();
+ const {tail} = this.scrollInfo();
this.navStyle = {
marginTop: val + 'px'
}
- if (balance <= 10) {
+ if (tail <= 10) {
requestAnimationFrame(this.onToBottom)
}
}
@@ -537,6 +541,12 @@ export default {
if (val) {
this.operateVisible = false;
}
+ },
+
+ replyActiveIndex(index) {
+ if (index > -1) {
+ setTimeout(_ => this.replyActiveIndex = -1, 800)
+ }
}
},
@@ -711,7 +721,7 @@ export default {
}
if (this.wrapperStart.clientY > e.touches[0].clientY) {
// 向上滑动
- if (this.wrapperStart.balance === 0) {
+ if (this.wrapperStart.tail === 0) {
e.preventDefault();
}
} else {
@@ -796,8 +806,39 @@ export default {
onToBottom() {
this.msgNew = 0;
- if (this.isReady) {
- this.$refs.scroller?.scrollToBottom();
+ const scroller = this.$refs.scroller;
+ if (scroller) {
+ scroller.scrollToBottom();
+ requestAnimationFrame(_ => scroller.scrollToBottom()) // 确保滚动到
+ }
+ },
+
+ onToIndex(index, addOffset) {
+ const scroller = this.$refs.scroller;
+ if (scroller) {
+ scroller.scrollToIndex(index, addOffset);
+ requestAnimationFrame(_ => scroller.scrollToIndex(index, addOffset)) // 确保滚动到
+ }
+ },
+
+ onToOffset(offset) {
+ const scroller = this.$refs.scroller;
+ if (scroller) {
+ scroller.scrollToOffset(offset);
+ setTimeout(_ => scroller.scrollToOffset(offset), 10) // 预防出现白屏的情况
+ }
+ },
+
+ scrollInfo() {
+ const scroller = this.$refs.scroller;
+ if (scroller) {
+ return scroller.scrollInfo();
+ } else {
+ return {
+ offset: 0,
+ scale: 0,
+ tail: 0
+ }
}
},
@@ -838,15 +879,11 @@ export default {
const previousSize = typeof previousValue === "object" ? previousValue.size : scroller.getSize(previousValue)
return {size: previousSize + scroller.getSize(currentId)}
})
- let size = this.$refs.scroller.getOffset() + offset.size;
+ let size = scroller.getOffset() + offset.size;
if (this.nextPage === 0) {
size -= 36
}
- scroller.scrollToOffset(size);
- setTimeout(_ => {
- // 预防出现白屏的情况
- scroller.scrollToOffset(size);
- }, 1)
+ this.onToOffset(size);
});
}).catch(() => {})
},
@@ -906,52 +943,34 @@ export default {
}
},
- scrollInfo() {
- const scroller = this.$refs.scroller
- if (!scroller) {
- return {
- scale: 0, //已滚动比例
- offset: 0, //滚动的距离
- balance: 0, //与底部距离
- }
- }
- let clientSize = scroller.getClientSize();
- let offset = scroller.getOffset();
- let scrollSize = scroller.getScrollSize();
- return {
- scale: offset / (scrollSize - clientSize),
- offset: offset,
- balance: scrollSize - clientSize - offset,
+ onScroll() {
+ this.operateVisible = false;
+ //
+ const {tail} = this.scrollInfo();
+ this.scrollTail = tail;
+ if (this.scrollTail <= 10) {
+ this.msgNew = 0;
}
},
- onScroll(evt, range) {
- this.operateVisible = false;
- this.__onScroll && clearTimeout(this.__onScroll);
- this.__onScroll = setTimeout(_ => {
- const {balance} = this.scrollInfo();
- this.scrollBalance = balance;
- if (this.scrollBalance <= 10) {
- this.msgNew = 0;
+ onRange(range) {
+ if (this.preventMoreLoad) {
+ return
+ }
+ let tmpPage = 0;
+ for (let i = range.start; i <= range.end; i++) {
+ if (tmpPage - parseInt(this.allMsgs[i]._page) > 1) {
+ this.preventMoreLoad = true
+ this.$store.dispatch("getDialogMoreMsgs", {
+ dialog_id: this.dialogId,
+ page: tmpPage - 1
+ }).finally(_ => {
+ this.preventMoreLoad = false
+ })
+ break;
}
- //
- if (!this.scrollMoreLoad) {
- let tmpPage = 0;
- for (let i = range.start; i <= range.end; i++) {
- if (tmpPage - parseInt(this.allMsgs[i]._page) > 1) {
- this.scrollMoreLoad = true
- this.$store.dispatch("getDialogMoreMsgs", {
- dialog_id: this.dialogId,
- page: tmpPage - 1
- }).finally(_ => {
- this.scrollMoreLoad = false
- })
- break;
- }
- tmpPage = parseInt(this.allMsgs[i]._page);
- }
- }
- }, 100)
+ tmpPage = parseInt(this.allMsgs[i]._page);
+ }
},
onBack() {
@@ -1081,40 +1100,29 @@ export default {
if (this.operateVisible) {
return
}
- const toIndex = (index) => {
- this.$refs.scroller?.scrollToIndex(index)
- requestAnimationFrame(_ => {
- this.replyActiveIndex = index
- setTimeout(_ => {
- this.replyActiveIndex = -1
- }, 800)
- })
+ const runToIndex = (index) => {
+ this.onToIndex(index, -100)
+ requestAnimationFrame(_ => this.replyActiveIndex = index)
}
const index = this.allMsgs.findIndex(item => item.id === data.reply_id)
if (index > -1) {
- toIndex(index)
+ runToIndex(index)
} else {
this.$store.dispatch("setLoad", {
key: `msg-${data.msg_id}`,
delay: 600
})
+ this.preventToBottom = true;
this.$store.dispatch("getDialogMoreMsgs", {
dialog_id: this.dialogId,
position_id: data.reply_id
- }).then(_ => {
- let i = 0;
- let inter = setInterval(_ => {
- i++
- const index = this.allMsgs.findIndex(item => item.id === data.reply_id)
- if (i > 10 || index > -1) {
- clearInterval(inter)
- if (index > -1) {
- toIndex(index)
- }
- }
- }, 100)
}).finally(_ => {
+ const index = this.allMsgs.findIndex(item => item.id === data.reply_id)
+ if (index > -1) {
+ runToIndex(index)
+ }
this.$store.dispatch("cancelLoad", `msg-${data.msg_id}`)
+ this.preventToBottom = false;
})
}
},
diff --git a/resources/assets/js/store/actions.js b/resources/assets/js/store/actions.js
index 4908cc012..e62e286fc 100644
--- a/resources/assets/js/store/actions.js
+++ b/resources/assets/js/store/actions.js
@@ -2151,25 +2151,6 @@ export default {
})
},
- /**
- * 获取回复消息
- * @param state
- * @param dispatch
- * @param msg_id
- */
- getDialogReply({state, dispatch}, msg_id) {
- dispatch("call", {
- url: 'dialog/msg/one',
- data: {
- msg_id: msg_id,
- },
- }).then(({data}) => {
- state.dialogReplys.push(data)
- }).catch(e => {
- console.warn(e);
- });
- },
-
/**
* 获取会话消息
* @param state
diff --git a/resources/assets/js/store/state.js b/resources/assets/js/store/state.js
index 015114b78..f5786c4dc 100644
--- a/resources/assets/js/store/state.js
+++ b/resources/assets/js/store/state.js
@@ -72,7 +72,6 @@ const stateData = {
dialogId: 0,
dialogIns: [],
dialogMsgs: [],
- dialogReplys: [],
dialogInputCache: $A.getStorageArray("cacheDialogInput"),
dialogMsgTransfer: {time: 0},