feat: 初次提交我的项目代码
This commit is contained in:
634
pages/mall/consumer/messages.uvue
Normal file
634
pages/mall/consumer/messages.uvue
Normal file
@@ -0,0 +1,634 @@
|
||||
<!-- pages/mall/consumer/messages.uvue -->
|
||||
<template>
|
||||
<view class="messages-page">
|
||||
<!-- 顶部标题栏 -->
|
||||
<view class="messages-header">
|
||||
<text class="header-title">消息</text>
|
||||
<view class="header-actions">
|
||||
<text class="action-icon" @click="clearAllUnread">📝</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 消息分类标签 -->
|
||||
<view class="message-tabs">
|
||||
<view
|
||||
v-for="tab in messageTabs"
|
||||
:key="tab.id"
|
||||
:class="['tab-item', { active: activeTab === tab.id }]"
|
||||
@click="switchTab(tab.id)"
|
||||
>
|
||||
<text class="tab-name">{{ tab.name }}</text>
|
||||
<text v-if="tab.unread > 0" class="tab-badge">{{ tab.unread }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 消息列表 -->
|
||||
<scroll-view
|
||||
scroll-y
|
||||
class="messages-content"
|
||||
refresher-enabled
|
||||
:refresher-triggered="refreshing"
|
||||
@refresherrefresh="onRefresh"
|
||||
>
|
||||
<!-- 系统通知 -->
|
||||
<view v-if="activeTab === 'system'" class="message-section">
|
||||
<view
|
||||
v-for="message in systemMessages"
|
||||
:key="message.id"
|
||||
:class="['message-item', { unread: !message.read }]"
|
||||
@click="viewSystemMessage(message)"
|
||||
>
|
||||
<view class="message-icon-wrapper">
|
||||
<text class="message-icon">📢</text>
|
||||
</view>
|
||||
<view class="message-content">
|
||||
<view class="message-header">
|
||||
<text class="message-title">{{ message.title }}</text>
|
||||
<text class="message-time">{{ message.time }}</text>
|
||||
</view>
|
||||
<text class="message-preview">{{ message.content }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 订单消息 -->
|
||||
<view v-if="activeTab === 'order'" class="message-section">
|
||||
<view
|
||||
v-for="message in orderMessages"
|
||||
:key="message.id"
|
||||
:class="['message-item', { unread: !message.read }]"
|
||||
@click="viewOrderMessage(message)"
|
||||
>
|
||||
<view class="message-icon-wrapper">
|
||||
<text class="message-icon">📦</text>
|
||||
</view>
|
||||
<view class="message-content">
|
||||
<view class="message-header">
|
||||
<text class="message-title">{{ message.title }}</text>
|
||||
<text class="message-time">{{ message.time }}</text>
|
||||
</view>
|
||||
<text class="message-preview">{{ message.content }}</text>
|
||||
<text class="order-info" v-if="message.order_no">订单号: {{ message.order_no }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 客服消息 -->
|
||||
<view v-if="activeTab === 'service'" class="message-section">
|
||||
<view
|
||||
v-for="message in serviceMessages"
|
||||
:key="message.id"
|
||||
:class="['message-item', { unread: !message.read }]"
|
||||
@click="startCustomerService(message)"
|
||||
>
|
||||
<view class="message-icon-wrapper">
|
||||
<image
|
||||
v-if="message.avatar"
|
||||
class="message-avatar"
|
||||
:src="message.avatar"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<text v-else class="message-icon">💁</text>
|
||||
</view>
|
||||
<view class="message-content">
|
||||
<view class="message-header">
|
||||
<text class="message-title">{{ message.title }}</text>
|
||||
<text class="message-time">{{ message.time }}</text>
|
||||
</view>
|
||||
<text class="message-preview">{{ message.content }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 优惠活动 -->
|
||||
<view v-if="activeTab === 'promo'" class="message-section">
|
||||
<view
|
||||
v-for="message in promoMessages"
|
||||
:key="message.id"
|
||||
:class="['message-item', { unread: !message.read }]"
|
||||
@click="viewPromoMessage(message)"
|
||||
>
|
||||
<view class="message-icon-wrapper">
|
||||
<text class="message-icon">🎁</text>
|
||||
</view>
|
||||
<view class="message-content">
|
||||
<view class="message-header">
|
||||
<text class="message-title">{{ message.title }}</text>
|
||||
<text class="message-time">{{ message.time }}</text>
|
||||
</view>
|
||||
<text class="message-preview">{{ message.content }}</text>
|
||||
<view v-if="message.coupon" class="coupon-tag">
|
||||
<text class="coupon-text">{{ message.coupon }}优惠券</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view v-if="!loading && currentMessages.length === 0" class="empty-messages">
|
||||
<text class="empty-icon">💬</text>
|
||||
<text class="empty-title">暂无消息</text>
|
||||
<text class="empty-desc">暂时没有新消息</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 底部固定按钮 -->
|
||||
<view class="floating-action">
|
||||
<button class="action-button" @click="contactCustomerService">
|
||||
<text class="button-icon">💁</text>
|
||||
<text class="button-text">联系客服</text>
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
|
||||
// 响应式数据
|
||||
const activeTab = ref<string>('system')
|
||||
const refreshing = ref<boolean>(false)
|
||||
const loading = ref<boolean>(false)
|
||||
const unreadCount = ref<number>(5)
|
||||
|
||||
// 消息分类标签
|
||||
const messageTabs = reactive([
|
||||
{ id: 'system', name: '系统通知', unread: 3 },
|
||||
{ id: 'order', name: '订单消息', unread: 2 },
|
||||
{ id: 'service', name: '客服消息', unread: 0 },
|
||||
{ id: 'promo', name: '优惠活动', unread: 1 }
|
||||
])
|
||||
|
||||
// Mock 系统通知数据
|
||||
const systemMessages = reactive([
|
||||
{
|
||||
id: 'sys001',
|
||||
title: '系统维护通知',
|
||||
content: '平台将于今晚23:00-01:00进行系统维护,届时部分功能可能无法使用。',
|
||||
time: '2023-11-23 15:30',
|
||||
read: false,
|
||||
type: 'system'
|
||||
},
|
||||
{
|
||||
id: 'sys002',
|
||||
title: '隐私政策更新',
|
||||
content: '我们已更新隐私政策,请查阅相关条款。',
|
||||
time: '2023-11-22 10:15',
|
||||
read: true,
|
||||
type: 'system'
|
||||
},
|
||||
{
|
||||
id: 'sys003',
|
||||
title: '账户安全提醒',
|
||||
content: '检测到您的账户在异地登录,如果不是您本人操作,请及时修改密码。',
|
||||
time: '2023-11-21 18:45',
|
||||
read: false,
|
||||
type: 'system'
|
||||
}
|
||||
])
|
||||
|
||||
// Mock 订单消息数据
|
||||
const orderMessages = reactive([
|
||||
{
|
||||
id: 'order001',
|
||||
title: '订单发货通知',
|
||||
content: '您的订单202311230001已发货,点击查看物流信息。',
|
||||
time: '2023-11-23 14:20',
|
||||
read: false,
|
||||
type: 'order',
|
||||
order_no: '202311230001'
|
||||
},
|
||||
{
|
||||
id: 'order002',
|
||||
title: '订单支付成功',
|
||||
content: '您的订单202311220001支付成功,商家正在备货中。',
|
||||
time: '2023-11-22 09:30',
|
||||
read: false,
|
||||
type: 'order',
|
||||
order_no: '202311220001'
|
||||
},
|
||||
{
|
||||
id: 'order003',
|
||||
title: '订单确认收货',
|
||||
content: '您的订单202311210001已完成,期待您的评价。',
|
||||
time: '2023-11-21 16:15',
|
||||
read: true,
|
||||
type: 'order',
|
||||
order_no: '202311210001'
|
||||
}
|
||||
])
|
||||
|
||||
// Mock 客服消息数据
|
||||
const serviceMessages = reactive([
|
||||
{
|
||||
id: 'service001',
|
||||
title: '在线客服',
|
||||
content: '您好,有什么可以帮助您的吗?',
|
||||
time: '2023-11-23 10:05',
|
||||
read: true,
|
||||
type: 'service',
|
||||
avatar: 'https://picsum.photos/50/50?random=1'
|
||||
},
|
||||
{
|
||||
id: 'service002',
|
||||
title: '售后客服',
|
||||
content: '关于您申请的退款,已处理完成。',
|
||||
time: '2023-11-22 15:20',
|
||||
read: true,
|
||||
type: 'service',
|
||||
avatar: 'https://picsum.photos/50/50?random=2'
|
||||
}
|
||||
])
|
||||
|
||||
// Mock 优惠活动数据
|
||||
const promoMessages = reactive([
|
||||
{
|
||||
id: 'promo001',
|
||||
title: '新人专享券',
|
||||
content: '您有一张新人专享优惠券已到账,有效期3天。',
|
||||
time: '2023-11-23 08:00',
|
||||
read: false,
|
||||
type: 'promo',
|
||||
coupon: '50元'
|
||||
},
|
||||
{
|
||||
id: 'promo002',
|
||||
title: '双11大促',
|
||||
content: '双11狂欢购物节,全场满300减50。',
|
||||
time: '2023-11-22 12:30',
|
||||
read: true,
|
||||
type: 'promo',
|
||||
coupon: '满300减50'
|
||||
}
|
||||
])
|
||||
|
||||
// 计算当前显示的消息
|
||||
const currentMessages = computed(() => {
|
||||
switch (activeTab.value) {
|
||||
case 'system': return systemMessages
|
||||
case 'order': return orderMessages
|
||||
case 'service': return serviceMessages
|
||||
case 'promo': return promoMessages
|
||||
default: return []
|
||||
}
|
||||
})
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
loadMessages()
|
||||
})
|
||||
|
||||
// 加载消息
|
||||
const loadMessages = () => {
|
||||
loading.value = true
|
||||
setTimeout(() => {
|
||||
// 这里应该调用API获取消息数据
|
||||
loading.value = false
|
||||
}, 800)
|
||||
}
|
||||
|
||||
// 切换标签
|
||||
const switchTab = (tabId: string) => {
|
||||
activeTab.value = tabId
|
||||
}
|
||||
|
||||
// 查看系统消息
|
||||
const viewSystemMessage = (message: any) => {
|
||||
message.read = true
|
||||
uni.navigateTo({
|
||||
url: `/pages/mall/consumer/message-detail?id=${message.id}&type=system`
|
||||
})
|
||||
}
|
||||
|
||||
// 查看订单消息
|
||||
const viewOrderMessage = (message: any) => {
|
||||
message.read = true
|
||||
uni.navigateTo({
|
||||
url: `/pages/mall/consumer/order-detail?id=${message.order_no}`
|
||||
})
|
||||
}
|
||||
|
||||
// 联系客服
|
||||
const startCustomerService = (message: any) => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/consumer/chat'
|
||||
})
|
||||
}
|
||||
|
||||
// 查看优惠活动
|
||||
const viewPromoMessage = (message: any) => {
|
||||
message.read = true
|
||||
uni.navigateTo({
|
||||
url: `/pages/mall/consumer/coupons`
|
||||
})
|
||||
}
|
||||
|
||||
// 联系客服
|
||||
const contactCustomerService = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/consumer/chat'
|
||||
})
|
||||
}
|
||||
|
||||
// 清除所有未读
|
||||
const clearAllUnread = () => {
|
||||
uni.showModal({
|
||||
title: '确认操作',
|
||||
content: '确定要标记所有消息为已读吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 标记所有消息为已读
|
||||
systemMessages.forEach(msg => msg.read = true)
|
||||
orderMessages.forEach(msg => msg.read = true)
|
||||
serviceMessages.forEach(msg => msg.read = true)
|
||||
promoMessages.forEach(msg => msg.read = true)
|
||||
|
||||
// 更新标签未读数
|
||||
messageTabs.forEach(tab => tab.unread = 0)
|
||||
|
||||
uni.showToast({
|
||||
title: '已标记所有消息为已读',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 下拉刷新
|
||||
const onRefresh = () => {
|
||||
refreshing.value = true
|
||||
setTimeout(() => {
|
||||
loadMessages()
|
||||
refreshing.value = false
|
||||
uni.showToast({
|
||||
title: '刷新成功',
|
||||
icon: 'success'
|
||||
})
|
||||
}, 1000)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.messages-page {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* 头部 */
|
||||
.messages-header {
|
||||
background-color: white;
|
||||
padding: 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.header-actions .action-icon {
|
||||
font-size: 20px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* 消息分类标签 */
|
||||
.message-tabs {
|
||||
background-color: white;
|
||||
display: flex;
|
||||
padding: 0 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
padding: 15px 5px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
border-bottom: 2px solid transparent;
|
||||
}
|
||||
|
||||
.tab-item.active {
|
||||
color: #ff5000;
|
||||
border-bottom-color: #ff5000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tab-name {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.tab-badge {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
background-color: #ff5000;
|
||||
color: white;
|
||||
font-size: 10px;
|
||||
padding: 2px 6px;
|
||||
border-radius: 10px;
|
||||
min-width: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 消息内容区 */
|
||||
.messages-content {
|
||||
flex: 1;
|
||||
padding-bottom: 80px; /* 为底部按钮留出空间 */
|
||||
}
|
||||
|
||||
/* 消息项 */
|
||||
.message-section {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.message-item {
|
||||
background-color: white;
|
||||
border-radius: 10px;
|
||||
padding: 15px;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.message-item.unread {
|
||||
background-color: #fff8f6;
|
||||
border-left: 3px solid #ff5000;
|
||||
}
|
||||
|
||||
.message-icon-wrapper {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 25px;
|
||||
background-color: #f5f5f5;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 15px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.message-icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.message-avatar {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 25px;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.message-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.message-title {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
flex: 1;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.message-time {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.message-preview {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 8px;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.order-info {
|
||||
font-size: 12px;
|
||||
color: #ff5000;
|
||||
background-color: #fff0e8;
|
||||
padding: 3px 8px;
|
||||
border-radius: 4px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.coupon-tag {
|
||||
display: inline-block;
|
||||
background-color: #ff5000;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 12px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.coupon-text {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty-messages {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 80px 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 80px;
|
||||
color: #ddd;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.empty-title {
|
||||
font-size: 18px;
|
||||
color: #666;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.empty-desc {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 底部浮动按钮 */
|
||||
.floating-action {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
background: linear-gradient(135deg, #ff5000, #ff9500);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 25px;
|
||||
padding: 12px 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-shadow: 0 4px 12px rgba(255, 80, 0, 0.3);
|
||||
}
|
||||
|
||||
.button-icon {
|
||||
font-size: 18px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.button-text {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 响应式适配 */
|
||||
@media screen and (max-width: 320px) {
|
||||
.tab-name {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.message-title {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.message-preview {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 415px) {
|
||||
.message-item {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.message-icon-wrapper {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 30px;
|
||||
}
|
||||
|
||||
.message-icon {
|
||||
font-size: 28px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user