|
|
@@ -0,0 +1,297 @@
|
|
|
+<template>
|
|
|
+ <div class="reply-container">
|
|
|
+ <el-divider content-position="left">沟通记录</el-divider>
|
|
|
+ <div
|
|
|
+ class="message-container"
|
|
|
+ @scroll="handleScroll"
|
|
|
+ >
|
|
|
+ <div v-if="loadingHistory" class="loading-history">加载历史消息中...</div>
|
|
|
+
|
|
|
+ <div v-if="noMoreHistory" class="no-more-history">已加载全部历史消息</div>
|
|
|
+
|
|
|
+ <div
|
|
|
+ v-for="msg in messageList"
|
|
|
+ :key="msg.id"
|
|
|
+ :class="['message-item',
|
|
|
+ msg.sender === 'user' ? 'message-user-left' :
|
|
|
+ msg.sender === 'store' ? 'message-store-left' :
|
|
|
+ 'message-system-right'
|
|
|
+]"
|
|
|
+ >
|
|
|
+ <div class="sender">
|
|
|
+ <span style="font-size: 13px;font-weight: bold;">{{ msg.sender === 'user' ? '用户' : msg.sender === 'store' ? '店铺' : '平台' }}</span>
|
|
|
+ <span class="time">{{ msg.time }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="content">{{ msg.content }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-divider content-position="left">消息回复</el-divider>
|
|
|
+ <div class="reply-area">
|
|
|
+ <el-input
|
|
|
+ v-model="replyContent"
|
|
|
+ :rows="3"
|
|
|
+ class="reply-input"
|
|
|
+ placeholder="请输入回复内容..."
|
|
|
+ type="textarea"
|
|
|
+ @keyup.enter.native="sendReply"
|
|
|
+ ></el-input>
|
|
|
+ <el-button
|
|
|
+ class="send-btn"
|
|
|
+ type="primary"
|
|
|
+ @click="sendReply"
|
|
|
+ >
|
|
|
+ 发 送
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+
|
|
|
+<script>
|
|
|
+import { listComplaintMsg,addComplaintMsg } from '@/api/user/complaintMsg'
|
|
|
+
|
|
|
+export default ({
|
|
|
+ name: 'Reply',
|
|
|
+ props: {
|
|
|
+ complaintId: {
|
|
|
+ type: [String, Number],
|
|
|
+ required: true
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ messageList: [],
|
|
|
+ replyContent: '',
|
|
|
+ nextId: 1,
|
|
|
+
|
|
|
+ // 分页参数
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 5,
|
|
|
+ total: 0,
|
|
|
+ loadingHistory: false,
|
|
|
+ noMoreHistory: false,
|
|
|
+ initialLoaded: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ sendReply() {
|
|
|
+ const content = this.replyContent.trim()
|
|
|
+ if (!content) return
|
|
|
+ //请求消息发送接口
|
|
|
+ addComplaintMsg({
|
|
|
+ complaintId: this.complaintId,
|
|
|
+ content: content,
|
|
|
+ }).then(response => {
|
|
|
+ this.messageList.push({
|
|
|
+ id: this.nextId++,
|
|
|
+ sender: 'system',
|
|
|
+ content,
|
|
|
+ time: this.getFormattedTime()
|
|
|
+ })
|
|
|
+ this.replyContent = ''
|
|
|
+ this.scrollToBottom()
|
|
|
+ })
|
|
|
+ },
|
|
|
+ getFormattedTime() {
|
|
|
+ const now = new Date()
|
|
|
+ const year = now.getFullYear()
|
|
|
+ const month = (now.getMonth() + 1).toString().padStart(2, '0')
|
|
|
+ const day = now.getDate().toString().padStart(2, '0')
|
|
|
+ const hours = now.getHours().toString().padStart(2, '0')
|
|
|
+ const minutes = now.getMinutes().toString().padStart(2, '0')
|
|
|
+ return `${year}-${month}-${day} ${hours}:${minutes}`
|
|
|
+ },
|
|
|
+
|
|
|
+ handleScroll(e) {
|
|
|
+ const scrollTop = e.target.scrollTop
|
|
|
+ if (scrollTop <= 10 && !this.loadingHistory && !this.noMoreHistory) {
|
|
|
+ this.loadHistoryMessages()
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ loadHistoryMessages() {
|
|
|
+ if (this.loadingHistory || this.noMoreHistory) {
|
|
|
+ return Promise.resolve()
|
|
|
+ }
|
|
|
+
|
|
|
+ this.loadingHistory = true
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ listComplaintMsg({
|
|
|
+ pageNum: this.pageNum,
|
|
|
+ pageSize: this.pageSize,
|
|
|
+ complaintId: this.complaintId
|
|
|
+ }).then(response => {
|
|
|
+ if (!response) {
|
|
|
+ this.$message.error('接口响应异常,请重试')
|
|
|
+ resolve()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (response.code === 200) {
|
|
|
+ const { rows = [], total = 0 } = response
|
|
|
+ this.total = total
|
|
|
+
|
|
|
+ const formattedList = rows.map(msg => ({
|
|
|
+ id: msg.id || this.nextId++,
|
|
|
+ sender: msg.sendType === 1 ? 'user' : msg.sendType === 2 ? 'system' : 'store',
|
|
|
+ content: msg.content || '(无内容)',
|
|
|
+ time: msg.createTime || this.getFormattedTime()
|
|
|
+ })).reverse()
|
|
|
+
|
|
|
+ if (this.pageNum === 1) {
|
|
|
+ this.messageList = formattedList
|
|
|
+ } else {
|
|
|
+ this.messageList.unshift(...formattedList)
|
|
|
+ }
|
|
|
+
|
|
|
+ if (total === 0 || this.pageNum * this.pageSize >= total) {
|
|
|
+ this.noMoreHistory = true
|
|
|
+ } else {
|
|
|
+ this.pageNum++
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.$message.error(`加载失败:${response.msg || '未知错误'}`)
|
|
|
+ }
|
|
|
+ resolve()
|
|
|
+ }).catch(error => {
|
|
|
+ console.error('请求历史消息失败:', error)
|
|
|
+ this.$message.error('网络异常或接口请求失败,请检查网络后重试')
|
|
|
+ reject(error)
|
|
|
+ }).finally(() => {
|
|
|
+ this.loadingHistory = false
|
|
|
+ this.initialLoaded = true
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ scrollToBottom() {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ const messageContainer = document.querySelector('.message-container')
|
|
|
+ if (messageContainer) {
|
|
|
+ messageContainer.scrollTop = messageContainer.scrollHeight
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.loadHistoryMessages().then(() => {
|
|
|
+ this.scrollToBottom()
|
|
|
+ })
|
|
|
+ }
|
|
|
+})
|
|
|
+</script>
|
|
|
+<style scoped>
|
|
|
+.reply-container {
|
|
|
+ padding: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.message-container {
|
|
|
+ border: 1px solid #e6e6e6;
|
|
|
+ width: 100%;
|
|
|
+ height: 300px;
|
|
|
+ overflow-y: auto;
|
|
|
+ padding: 15px;
|
|
|
+ border-radius: 4px;
|
|
|
+ margin-bottom: 15px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ background: #fff;
|
|
|
+ transform: translateZ(0);
|
|
|
+}
|
|
|
+
|
|
|
+.no-message {
|
|
|
+ text-align: center;
|
|
|
+ color: #999;
|
|
|
+ font-size: 14px;
|
|
|
+ padding: 50px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.loading-history {
|
|
|
+ text-align: center;
|
|
|
+ color: #666;
|
|
|
+ font-size: 12px;
|
|
|
+ padding: 8px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.no-more-history {
|
|
|
+ text-align: center;
|
|
|
+ color: #999;
|
|
|
+ font-size: 12px;
|
|
|
+ padding: 8px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.message-item {
|
|
|
+ margin: 0 0 15px 0;
|
|
|
+ max-width: 80%;
|
|
|
+}
|
|
|
+
|
|
|
+.message-user-left .content {
|
|
|
+ background-color: #e4e4e4;
|
|
|
+ color: #333;
|
|
|
+ border-radius: 6px;
|
|
|
+}
|
|
|
+
|
|
|
+.message-store-left .content {
|
|
|
+ background-color: #448e17;
|
|
|
+ color: white;
|
|
|
+ border-radius: 6px;
|
|
|
+}
|
|
|
+
|
|
|
+.message-system-right .content {
|
|
|
+ background-color: #0f64b5;
|
|
|
+ color: white;
|
|
|
+ border-radius: 6px;
|
|
|
+}
|
|
|
+
|
|
|
+.sender {
|
|
|
+ font-size: 12px;
|
|
|
+ margin-bottom: 5px;
|
|
|
+ color: #888;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+}
|
|
|
+
|
|
|
+.time {
|
|
|
+ font-size: 11px;
|
|
|
+}
|
|
|
+
|
|
|
+.content {
|
|
|
+ padding: 8px 12px;
|
|
|
+ border-radius: 6px;
|
|
|
+ line-height: 1.5;
|
|
|
+ word-break: break-all;
|
|
|
+}
|
|
|
+
|
|
|
+.reply-area {
|
|
|
+ border: 1px solid #e6e6e6;
|
|
|
+ padding: 15px;
|
|
|
+ border-radius: 4px;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.reply-input {
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.send-btn {
|
|
|
+ margin-top: 20px;
|
|
|
+ float: right;
|
|
|
+}
|
|
|
+
|
|
|
+.message-container::-webkit-scrollbar {
|
|
|
+ width: 5px;
|
|
|
+ height: 5px;
|
|
|
+}
|
|
|
+
|
|
|
+.message-container::-webkit-scrollbar-track {
|
|
|
+ background: transparent;
|
|
|
+}
|
|
|
+
|
|
|
+.message-container::-webkit-scrollbar-thumb {
|
|
|
+ background: #e0e0e0;
|
|
|
+ border-radius: 3px;
|
|
|
+}
|
|
|
+
|
|
|
+.message-container::-webkit-scrollbar-thumb:hover {
|
|
|
+ background: #ccc;
|
|
|
+}
|
|
|
+</style>
|