| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- <template>
- <view class="message-row-wrap">
- <view v-if="showDateLabel" class="date-separator">
- <view class="date-line-cell">
- <view class="date-line" />
- </view>
- <view class="date-text-wrap">
- <text class="date-text">{{ dateLabel }}</text>
- </view>
- <view class="date-line-cell">
- <view class="date-line" />
- </view>
- </view>
- <view
- :id="'msg-' + (msg.id || msg.tempId)"
- class="message-row"
- >
- <!-- 左侧:应用头像 -->
- <view class="side-left">
- <view class="avatar-box">
- <SystemAvatar
- :name="appName"
- :size="64"
- unit="rpx"
- />
- </view>
- </view>
- <!-- 中间:通知卡片(绿色标题 + 白底正文 + 蓝色按钮) -->
- <view class="bubble notify-card">
- <!-- 顶部绿色标题条 -->
- <view class="notify-header">
- <text class="notify-header-text">
- {{ msg.title || statusText }}
- </text>
- </view>
- <!-- 中间白底正文 -->
- <view class="notify-body">
- <text v-if="msg.content" class="notify-content">
- {{ msg.content }}
- </text>
- </view>
- <!-- 底部蓝色按钮 -->
- <view v-if="msg.actionText || msg.actionUrl" class="notify-footer">
- <view class="notify-btn" @click="onOpenNotificationUrl">
- <text class="notify-btn-text">{{ msg.actionText || '打开应用' }}</text>
- </view>
- </view>
- </view>
- <!-- 右侧:占位,保持对齐 -->
- <view class="side-right placeholder" />
- </view>
- <view class="time-row">
- <text class="bubble-time">{{ timeText }}</text>
- </view>
- </view>
- </template>
- <script setup>
- import { computed } from 'vue'
- import SystemAvatar from '../SystemAvatar.vue'
- const props = defineProps({
- msg: {
- type: Object,
- required: true
- },
- senderName: {
- type: String,
- default: ''
- },
- showDateLabel: {
- type: Boolean,
- default: false
- }
- })
- const emit = defineEmits(['open-notification-url'])
- const appName = computed(() => props.msg.appName || props.msg.app_name || props.senderName || '系统通知')
- const dateLabel = computed(() => {
- const t = props.msg.createdAt || props.msg.created_at
- if (!t) return ''
- const d = new Date(t)
- return (d.getMonth() + 1) + '月' + d.getDate() + '日'
- })
- const timeText = computed(() => {
- const t = props.msg.createdAt || props.msg.created_at
- if (!t) return ''
- const d = new Date(t)
- const h = d.getHours()
- const m = String(d.getMinutes()).padStart(2, '0')
- const month = d.getMonth() + 1
- const day = d.getDate()
- return month + '月' + day + '日 ' + h + ':' + m
- })
- const statusText = computed(() => {
- return props.msg.statusText || '应用审批通过,已发布成功'
- })
- function onOpenNotificationUrl() {
- emit('open-notification-url', props.msg)
- }
- </script>
- <style scoped>
- .message-row-wrap {
- width: 100%;
- margin-bottom: 28rpx;
- }
- .date-separator {
- display: flex;
- flex-direction: row;
- align-items: center;
- width: 100%;
- box-sizing: border-box;
- margin-bottom: 24rpx;
- }
- .date-line-cell {
- flex: 1 1 0%;
- min-width: 0;
- display: flex;
- align-items: center;
- }
- .date-line {
- width: 100%;
- height: 1rpx;
- background: rgba(148, 163, 184, 0.4);
- }
- .date-text-wrap {
- flex: 0 0 auto;
- max-width: 100%;
- margin: 0 20rpx;
- }
- .date-text {
- font-size: 24rpx;
- color: #9ca3af;
- padding: 6rpx 16rpx;
- border-radius: 999rpx;
- background: rgba(15, 23, 42, 0.04);
- }
- .message-row {
- display: flex;
- align-items: flex-start;
- justify-content: center;
- padding: 0 24rpx;
- gap: 12rpx;
- }
- .side-left {
- flex-shrink: 0;
- width: 72rpx;
- display: flex;
- justify-content: center;
- align-items: flex-start;
- }
- .side-right {
- flex-shrink: 0;
- width: 72rpx;
- display: flex;
- justify-content: center;
- align-items: flex-start;
- }
- .avatar-box {
- width: 64rpx;
- height: 64rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .bubble {
- width: 560rpx;
- max-width: calc(100% - 72rpx - 72rpx - 12rpx - 12rpx);
- min-width: 88rpx;
- border-radius: 18rpx;
- box-shadow: 0 4rpx 10rpx rgba(15, 23, 42, 0.06);
- background-color: #ffffff;
- overflow: hidden;
- flex-shrink: 1;
- }
- .notify-card {
- padding: 0;
- }
- .notify-header {
- background-color: #bbf7d0;
- padding: 16rpx 20rpx;
- }
- .notify-header-text {
- font-size: 26rpx;
- color: #166534;
- font-weight: 600;
- }
- .notify-body {
- padding: 20rpx 20rpx 8rpx;
- }
- .notify-content {
- font-size: 26rpx;
- color: #111827;
- line-height: 1.5;
- }
- .notify-footer {
- padding: 12rpx 20rpx 20rpx;
- }
- .notify-btn {
- width: 100%;
- height: 72rpx;
- border-radius: 12rpx;
- border-width: 2rpx;
- border-style: solid;
- border-color: #1677ff;
- background-color: #ffffff;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .notify-btn-text {
- font-size: 28rpx;
- color: #1677ff;
- }
- .time-row {
- margin-top: 6rpx;
- display: flex;
- justify-content: center;
- }
- .bubble-time {
- font-size: 22rpx;
- color: #9ca3af;
- }
- </style>
|