panhui před 4 roky
rodič
revize
4a0a497a8b

+ 82 - 17
src/components/ChatInfo.vue

@@ -1,25 +1,36 @@
 <template>
-    <div class="chat" :class="{ alignRight: isMine }">
-        <van-image round width="36" height="36" fit="cover" />
-        <div class="chat-content">
-            <div class="chat-text" v-if="contentType === 'text'">
-                {{ info.info }}
+    <div class="chat-box">
+        <div class="time" v-if="info.time">{{ info.time }}</div>
+
+        <div class="product" v-if="contentType === 'LINK'">
+            <product-info :info="productInfo" :showBtn="false"></product-info>
+        </div>
+
+        <div v-else class="chat" :class="{ alignRight: isMine }">
+            <van-image :src="sendUserInfo.avatar" round width="36" height="36" fit="cover" />
+            <div class="chat-content">
+                <div class="chat-text" v-if="contentType === 'TEXT'">
+                    {{ info.info }}
+                </div>
+                <van-image
+                    @click="preview(info.info)"
+                    class="chat-img"
+                    width="190"
+                    height="190"
+                    fit="heightFix"
+                    :src="info.info"
+                    v-else-if="contentType === 'IMAGE'"
+                />
             </div>
-            <van-image
-                @click="preview()"
-                class="chat-img"
-                width="190"
-                height="190"
-                fit="heightFix"
-                v-else-if="contentType === 'image'"
-            />
         </div>
     </div>
 </template>
 
 <script>
+import ProductInfo from './ProductInfo.vue';
 export default {
     name: 'ChatInfo',
+    components: { ProductInfo },
     props: {
         info: {
             type: Object,
@@ -29,20 +40,53 @@ export default {
         },
         contentType: {
             type: String,
-            default: 'text'
+            default: 'TEXT'
         },
         isMine: {
             type: Boolean,
             default: false
         }
+    },
+    computed: {
+        sendUser() {
+            return this.info.sendUser || null;
+        },
+        sendUserInfo() {
+            if (this.sendUser) {
+                if (this.sendUser.store && !this.isMine) {
+                    return {
+                        name: this.sendUser.store.storeName,
+                        avatar: this.sendUser.store.logo
+                    };
+                } else {
+                    return {
+                        name: this.sendUser.nickname,
+                        avatar: this.sendUser.avatar
+                    };
+                }
+            } else {
+                return {};
+            }
+        },
+        productInfo() {
+            if (this.contentType === 'LINK') {
+                return JSON.parse(this.info.info);
+            } else {
+                return {};
+            }
+        }
     }
 };
 </script>
 
 <style lang="less" scoped>
+.chat-box {
+    padding-top: 30px;
+}
 .chat {
-    margin-top: 30px;
+    // margin-top: 30px;
     .flex();
+    align-items: flex-start;
     &.alignRight {
         flex-direction: row-reverse;
         .chat-content {
@@ -78,22 +122,43 @@ export default {
     }
 }
 
+.product {
+    background-color: #fff;
+    padding: 15px;
+    border-radius: 12px;
+    // margin-top: 30px;
+}
+
 /deep/.chat {
     .chat-img {
         .van-image {
-            border-radius: 2px 12px 12px 12px;
+            .van-image__img {
+                border-radius: 12px 0px 12px 12px;
+            }
             overflow: hidden;
         }
     }
     &.alignRight {
         .chat-img {
             .van-image {
-                border-radius: 12px 0px 12px 12px;
+                .van-image__img {
+                    border-radius: 12px 0px 12px 12px;
+                }
+                display: flex;
+                justify-content: flex-end;
             }
         }
     }
 }
 
+.time {
+    font-size: 12px;
+    color: #878d99;
+    line-height: 17px;
+    text-align: center;
+    padding-bottom: 10px;
+}
+
 /deep/ .van-image {
     --image-placeholder-background-color: #fff;
 }

+ 18 - 2
src/components/NewsInfo.vue

@@ -12,7 +12,7 @@
                 {{ otherUserInfo.name }}
             </div>
             <span class="time">{{ time }}</span>
-            <div class="text2">{{ lastMsg.info }}</div>
+            <div class="text2">{{ text }}</div>
         </div>
     </div>
 </template>
@@ -20,6 +20,11 @@
 <script>
 import { mapState } from 'vuex';
 import dayjs from 'dayjs';
+import * as relativeTime from 'dayjs/plugin/relativeTime';
+import 'dayjs/locale/zh-cn';
+dayjs.locale('zh-cn');
+dayjs.extend(relativeTime);
+
 export default {
     name: 'NewsInfo',
     props: {
@@ -60,9 +65,20 @@ export default {
         lastMsg() {
             return this.info.lastMsg || { createdAt: '' };
         },
+        text() {
+            if (this.lastMsg.messageType === 'TEXT') {
+                return this.lastMsg.info;
+            } else if (this.lastMsg.messageType === 'IMAGE') {
+                return '图片...';
+            } else if (this.lastMsg.messageType === 'LINK') {
+                let product = JSON.parse(this.lastMsg.info);
+                return product.caseName;
+            }
+            return '';
+        },
         time() {
             if (this.lastMsg.createdAt) {
-                return dayjs().fromNow();
+                return dayjs(this.lastMsg.createdAt).fromNow();
             } else {
                 return '';
             }

+ 90 - 17
src/pages/chat.vue

@@ -1,28 +1,41 @@
 <config>
 {
-    "navigationBarTitleText":'光之城-卡牌',
+    "navigationBarTitleText":'',
     "backgroundColor":"#F5F7FA"
 }
 </config>
 <template>
     <div class="page">
-        <div class="chat-list" @click="showAttach = false">
-            <!-- <div class="product">
-                <product-info :showBtn="false"></product-info>
-            </div> -->
+        <div
+            id="chat-list"
+            class="chat-list"
+            @click="showAttach = false"
+            :style="{ paddingBottom: `calc(${100 + attachHeight}px + env(safe-area-inset-bottom))` }"
+        >
             <chat-info
                 v-for="(item, index) in list"
                 :key="index"
                 :info="item"
                 :isMine="userInfo && item.sendId === userInfo.id"
+                :contentType="item.messageType"
             ></chat-info>
+
+            <div class="loading" v-if="loading">
+                <van-loading size="24px">加载中...</van-loading>
+            </div>
             <!-- <chat-info isMine></chat-info>
             <chat-info isMine contentType="image"></chat-info> -->
         </div>
 
         <div class="bottom-box">
             <div class="input-box">
-                <van-field :boder="false" placeholder="请输入需要咨询的问题" :value="message" />
+                <van-field
+                    :boder="false"
+                    placeholder="请输入需要咨询的问题"
+                    :value="message"
+                    @input="message = $event.detail"
+                    @confirm="confirm"
+                />
 
                 <img src="/native/svgs/icon_liaotian_biaoqing.svg" alt="" class="icon" />
                 <img
@@ -43,8 +56,12 @@
 
 <script>
 import ChatInfo from '@/components/ChatInfo';
-import ProductInfo from '@/components/ProductInfo';
 import { mapState } from 'vuex';
+import dayjs from 'dayjs';
+import * as calendar from 'dayjs/plugin/calendar';
+import 'dayjs/locale/zh-cn';
+dayjs.locale('zh-cn');
+dayjs.extend(calendar);
 export default {
     name: 'Chat',
     components: {
@@ -56,11 +73,20 @@ export default {
             showAttach: false,
             topicInfo: null,
             list: [],
-            toUserId: 0
+            toUserId: 0,
+            loading: true,
+            timeFormat: {
+                sameDay: 'A hh:mm', // The same day ( Today at 2:30 AM )
+                nextDay: '[明天]', // The next day ( Tomorrow at 2:30 AM )
+                nextWeek: 'dddd', // The next week ( Sunday at 2:30 AM )
+                lastDay: 'MM/DD HH:mm', // The day before ( Yesterday at 2:30 AM )
+                lastWeek: 'MM/DD HH:mm', // Last week ( Last Monday at 2:30 AM )
+                sameElse: 'YYYY/MM/DD' // Everything else ( 7/10/2011 )
+            }
         };
     },
     computed: {
-        ...mapState(['userInfo']),
+        ...mapState(['userInfo', 'systemInfo']),
         attachHeight() {
             return this.showAttach ? 114 : 0;
         }
@@ -77,33 +103,79 @@ export default {
     },
     methods: {
         loginMethods() {
+            console.log(this.$mp.options.toUserId);
+            let eventChannel = this.$mp.page.getOpenerEventChannel();
+
             this.$http
                 .post('/topic/newTopic', {
-                    targetId: this.toUserId
+                    targetId: this.$mp.options.toUserId
                 })
                 .then(res => {
                     this.topicInfo = res;
                     return this.getList();
                 })
                 .then(() => {
-                    // this.newMessage('欢迎管理本店,小店客服会尽快为您提供服务。', false, 'TEXT', true);
+                    if (eventChannel && eventChannel.on) {
+                        eventChannel.on('productInfo', data => {
+                            this.newMessage(JSON.stringify(data), true, 'LINK');
+                            setTimeout(() => {
+                                this.newMessage('欢迎光临本店,小店客服会尽快为您提供服务。', false, 'TEXT', false);
+                            }, 1000);
+                        });
+                    }
                 });
         },
         sendImg() {
             this.choosePhoto().then(res => {
                 console.log(res);
+                this.newMessage(res, true, 'IMAGE');
             });
         },
         getList() {
+            this.loading = true;
             return this.$http
                 .get('/message/findTopicMessages', {
                     topicId: this.topicInfo.id
                 })
                 .then(res => {
-                    this.list = res;
+                    this.loading = false;
+                    this.list = res.map((item, index) => {
+                        let time = '';
+                        if (index == 0) {
+                            time = dayjs(item.createdAt).calendar(null, this.timeFormat);
+                        } else {
+                            const date1 = dayjs(item.createdAt);
+                            if (date1.diff(res[index - 1].createdAt, 'minute') > 5) {
+                                time = dayjs(item.createdAt).calendar(null, this.timeFormat);
+                            }
+                        }
+                        return {
+                            ...item,
+                            time: time
+                        };
+                    });
+                    this.$nextTick(() => {
+                        setTimeout(() => {
+                            wx.createSelectorQuery()
+                                .select('#chat-list')
+                                .boundingClientRect(rect => {
+                                    wx.pageScrollTo({
+                                        scrollTop: rect.height + 100
+                                    });
+                                })
+                                .exec();
+                        }, 100);
+                    });
+                    this.$http.post('/message/allRead', {
+                        topicId: this.topicInfo.id
+                    });
                     return Promise.resolve();
                 });
         },
+        confirm(e) {
+            this.newMessage(e.detail);
+            this.message = '';
+        },
         newMessage(info, isSend = true, messageType = 'TEXT', beenRead = false) {
             let data = {
                 topicId: this.topicInfo.id,
@@ -133,11 +205,6 @@ page {
     padding: 10px 20px 100px;
 }
 
-.product {
-    background-color: #fff;
-    padding: 15px;
-    border-radius: 12px;
-}
 .bottom-box {
     .bottom();
     background-color: #fff;
@@ -201,4 +268,10 @@ page {
         }
     }
 }
+
+.loading {
+    padding: 20px;
+    .flex();
+    justify-content: center;
+}
 </style>

+ 12 - 2
src/pages/details.vue

@@ -72,10 +72,9 @@
             ></card-case>
             <div class="box-footer-con">
                 <div class="box-footer-left">
-                    <div class="contact">
+                    <div class="contact" @click="goChat">
                         <img src="../static/imgs/icon_kefu@3x.png" alt="" />
                         <p>客服</p>
-                        <button open-type="contact" />
                     </div>
                     <div class="box-follow" :class="{ active: isCollection }" @click="collect">
                         <van-icon
@@ -164,6 +163,17 @@ export default {
                 this.caseId = this.$mp.options.id;
                 this.checkCollect();
             }
+        },
+        goChat() {
+            this.checkLogin().then(() => {
+                wx.navigateTo({
+                    url: `/pages/chat?toUserId=${this.storeInfo.userId}&toName=${this.storeInfo.storeName}`,
+                    success: res => {
+                        // success
+                        res.eventChannel.emit('productInfo', this.cardCaseInfo);
+                    }
+                });
+            });
         }
     },
     onShow() {

+ 18 - 5
src/pages/news.vue

@@ -7,7 +7,7 @@
 <template>
     <div>
         <block v-for="item in list" :key="item.id">
-            <news-info :info="item"></news-info>
+            <news-info :info="item" :dot="item.unread"></news-info>
         </block>
 
         <!-- 
@@ -15,6 +15,7 @@
         <news-info></news-info> -->
 
         <van-empty
+            v-if="empty"
             image="https://ticket-exchange.oss-cn-hangzhou.aliyuncs.com/wechat/kong_png_xiaoxiliebiao.png"
             description="你还没有任何消息哦~"
         >
@@ -31,14 +32,26 @@ export default {
     },
     data() {
         return {
-            list: []
+            list: [],
+            empty: true
         };
     },
+    onShow() {
+        this.loginMethods();
+    },
     methods: {
         loginMethods() {
-            this.$http.get('/topic/getMyTopicList').then(res => {
-                this.list = res;
-            });
+            if (this.isLogin) {
+                this.empty = false;
+                this.showLoading();
+                this.$http.get('/topic/getMyTopicList').then(res => {
+                    this.list = res;
+                    this.hideLoading();
+                    if (res.length === 0) {
+                        this.empty = true;
+                    }
+                });
+            }
         }
     }
 };