|
|
@@ -0,0 +1,218 @@
|
|
|
+<template>
|
|
|
+ <div style="background:#F5F7FA" @scroll="scroll">
|
|
|
+ <nav-bar @click-left="$router.go(-1)" :title="title">
|
|
|
+ <div slot="right">全部已读</div>
|
|
|
+ </nav-bar>
|
|
|
+ <div class="list" v-if="userInfo && userInfo.id">
|
|
|
+ <template v-for="item in reverseMessages">
|
|
|
+ <div
|
|
|
+ class="message-item"
|
|
|
+ :class="{ rtl: item.userId === userInfo.id }"
|
|
|
+ v-if="item.type === 'TEXT' && item.userId === userInfo.id"
|
|
|
+ :key="item.id"
|
|
|
+ >
|
|
|
+ <img class="avatar" :src="(userInfo || {}).avatar" />
|
|
|
+ <div class="msg-content">{{ item.content }}</div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="message-item"
|
|
|
+ :class="{ rtl: item.userId === userInfo.id }"
|
|
|
+ v-else-if="item.type === 'TEXT'"
|
|
|
+ :key="item.id"
|
|
|
+ >
|
|
|
+ <img class="avatar" :src="conversation.icon" />
|
|
|
+ <div class="msg-content">{{ item.content }}</div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <div class="bottom-holder"></div>
|
|
|
+ <div class="bottom-wrapper">
|
|
|
+ <div class="bottom">
|
|
|
+ <input placeholder="请输入您要回复的内容" v-model="content" @keyup.enter="send" />
|
|
|
+ <div class="btn-send" @click="send">发送</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script>
|
|
|
+import { mapState } from 'vuex';
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ title: '',
|
|
|
+ messages: [],
|
|
|
+ conversation: {},
|
|
|
+ page: 0,
|
|
|
+ last: false,
|
|
|
+ loading: false,
|
|
|
+ content: '',
|
|
|
+ lastTop: 0,
|
|
|
+ scrollBottom: 0
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ ...mapState(['userInfo']),
|
|
|
+ reverseMessages() {
|
|
|
+ return [...this.messages].reverse();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ this.title = this.$route.query.title;
|
|
|
+ this.getData();
|
|
|
+ this.$http.get(`/conversation/get/${this.$route.query.conversationId}`).then(res => {
|
|
|
+ this.conversation = res;
|
|
|
+ setTimeout(() => {
|
|
|
+ this.scrollToBottom();
|
|
|
+ }, 100);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.scrollToBottom();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ getData() {
|
|
|
+ this.loading = true;
|
|
|
+ this.$http
|
|
|
+ .get('/message/all', {
|
|
|
+ sessionId: this.$route.query.sessionId,
|
|
|
+ page: this.page
|
|
|
+ })
|
|
|
+ .then(res => {
|
|
|
+ // res.content[0].content = '嗯嗯,我对贵公司的产品简直不要太喜欢,算我穷尽我的词汇也无法真实表达我的感受';
|
|
|
+ // res.content[2].userId = 1;
|
|
|
+ if (res.first) {
|
|
|
+ this.messages = [];
|
|
|
+ }
|
|
|
+ this.messages = this.messages.concat(res.content);
|
|
|
+ this.last = res.last;
|
|
|
+ this.loading = false;
|
|
|
+ if (this.scrollBottom) {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.$el.scrollTop =
|
|
|
+ this.$el.scrollHeight - this.$el.getBoundingClientRect().height - this.scrollBottom;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch(e => {
|
|
|
+ this.loading = false;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ send() {
|
|
|
+ if (!this.content) return;
|
|
|
+ let data = {
|
|
|
+ sessionId: this.$route.query.sessionId,
|
|
|
+ toUserId: this.conversation.toUserId,
|
|
|
+ type: 'TEXT',
|
|
|
+ content: this.content
|
|
|
+ };
|
|
|
+ this.$http.post('/message/send', data).then(res => {
|
|
|
+ this.messages.unshift({ ...data, userId: this.userInfo.id });
|
|
|
+ this.content = '';
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.scrollToBottom();
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ scrollToBottom() {
|
|
|
+ let el = document.querySelector('#root');
|
|
|
+ el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' });
|
|
|
+ },
|
|
|
+ scroll(e) {
|
|
|
+ let top = e.target.scrollTop;
|
|
|
+ if (top < this.lastTop && top < 30 && !this.last && !this.loading) {
|
|
|
+ console.log('scroll top');
|
|
|
+ this.page++;
|
|
|
+ this.getData();
|
|
|
+ }
|
|
|
+ this.lastTop = top;
|
|
|
+ this.scrollBottom = this.$el.scrollHeight - this.$el.scrollTop - this.$el.getBoundingClientRect().height;
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+<style lang="less" scoped>
|
|
|
+/deep/ .nav-bar-right {
|
|
|
+ word-break: keep-all;
|
|
|
+ font-size: 14px;
|
|
|
+ color: @text3;
|
|
|
+ &:active {
|
|
|
+ color: fade(@text3, 60%);
|
|
|
+ }
|
|
|
+}
|
|
|
+.message-item {
|
|
|
+ .flex();
|
|
|
+ padding: 10px 16px 0 16px;
|
|
|
+ align-items: flex-start;
|
|
|
+ .avatar {
|
|
|
+ width: 36px;
|
|
|
+ height: 36px;
|
|
|
+ min-width: 36px;
|
|
|
+ border-radius: 18px;
|
|
|
+ object-fit: cover;
|
|
|
+ }
|
|
|
+ .msg-content {
|
|
|
+ font-size: 15px;
|
|
|
+ line-height: 24px;
|
|
|
+ padding: 12px;
|
|
|
+ color: black;
|
|
|
+ background: white;
|
|
|
+ border-radius: 0px 16px 16px 16px;
|
|
|
+ margin-left: 8px;
|
|
|
+ margin-right: 10px;
|
|
|
+ }
|
|
|
+ &.rtl {
|
|
|
+ direction: rtl;
|
|
|
+ .msg-content {
|
|
|
+ margin-left: 10px;
|
|
|
+ margin-right: 8px;
|
|
|
+ border-radius: 16px 0px 16px 16px;
|
|
|
+ background: @prim;
|
|
|
+ color: white;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.bottom-holder {
|
|
|
+ height: calc(76px + var(--safe-bottom));
|
|
|
+}
|
|
|
+.bottom-wrapper {
|
|
|
+ position: fixed;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ padding-bottom: var(--safe-bottom);
|
|
|
+ background: white;
|
|
|
+}
|
|
|
+.bottom {
|
|
|
+ height: 56px;
|
|
|
+ .flex();
|
|
|
+ padding: 0 16px;
|
|
|
+ input {
|
|
|
+ height: 40px;
|
|
|
+ border: 1px solid @bg;
|
|
|
+ border-radius: 4px;
|
|
|
+ flex-grow: 1;
|
|
|
+ font-size: 15px;
|
|
|
+ padding: 0 10px;
|
|
|
+ &::-webkit-input-placeholder {
|
|
|
+ color: @text4;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .btn-send {
|
|
|
+ width: 64px;
|
|
|
+ height: 40px;
|
|
|
+ border-radius: 4px;
|
|
|
+ background: @prim;
|
|
|
+ color: white;
|
|
|
+ font-size: 14px;
|
|
|
+ .flex();
|
|
|
+ justify-content: center;
|
|
|
+ margin-left: 8px;
|
|
|
+ user-select: none;
|
|
|
+ &:active {
|
|
|
+ background: shade(@prim, 20%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|