feat(admin+api+player): 站内信手动发送、媒体库选择与发送记录详情
新增管理员手动发送站内信(三语富文本),支持发送记录查看与删除;修复全站「从媒体库选择」因分类过滤导致列表为空的问题;玩家端支持渲染管理员自定义消息;并优化后台列表页双层卡片布局。
This commit is contained in:
@@ -7,6 +7,7 @@ import GoldSpinner from './GoldSpinner.vue';
|
||||
import ConfirmDialog from './ConfirmDialog.vue';
|
||||
import { useAuthStore } from '../stores/auth';
|
||||
import { usePlayerMessages, type DepositMessagePayload, type PlayerMessage } from '../composables/usePlayerMessages';
|
||||
import { stripHtml } from '../utils/html';
|
||||
|
||||
const router = useRouter();
|
||||
const { t, locale } = useI18n();
|
||||
@@ -44,7 +45,8 @@ function messagePreview(item: PlayerMessage) {
|
||||
const deposit = item.payload as DepositMessagePayload | null;
|
||||
if (deposit?.orderNo) return deposit.orderNo;
|
||||
}
|
||||
return item.body.length > 80 ? `${item.body.slice(0, 80)}…` : item.body;
|
||||
const plain = stripHtml(item.body);
|
||||
return plain.length > 80 ? `${plain.slice(0, 80)}…` : plain;
|
||||
}
|
||||
|
||||
function openDetail(id: string) {
|
||||
|
||||
@@ -5,7 +5,8 @@ export type PlayerMessageType =
|
||||
| 'DEPOSIT_APPROVED'
|
||||
| 'DEPOSIT_REJECTED'
|
||||
| 'BANNER_PROMO'
|
||||
| 'ANNOUNCEMENT_PROMO';
|
||||
| 'ANNOUNCEMENT_PROMO'
|
||||
| 'ADMIN_CUSTOM';
|
||||
|
||||
export type DepositMessagePayload = {
|
||||
depositOrderId?: string;
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useI18n } from 'vue-i18n';
|
||||
import { formatLocalMatchDateTime } from '@thebet365/shared';
|
||||
import GoldSpinner from '../components/GoldSpinner.vue';
|
||||
import ConfirmDialog from '../components/ConfirmDialog.vue';
|
||||
import { sanitizeAnnouncementHtml } from '../utils/html';
|
||||
import { formatMoney } from '../utils/localeDisplay';
|
||||
import {
|
||||
usePlayerMessages,
|
||||
@@ -174,7 +175,12 @@ watch(messageId, () => {
|
||||
</span>
|
||||
<p v-if="message.createdAt" class="detail-date">{{ formatDate(message.createdAt) }}</p>
|
||||
<h2 class="detail-title">{{ messageTitle(message) }}</h2>
|
||||
<p class="detail-body">{{ messageBody(message) }}</p>
|
||||
<div
|
||||
v-if="message.type === 'ADMIN_CUSTOM'"
|
||||
class="detail-body rich-body"
|
||||
v-html="sanitizeAnnouncementHtml(message.body)"
|
||||
/>
|
||||
<p v-else class="detail-body">{{ messageBody(message) }}</p>
|
||||
|
||||
<div
|
||||
v-if="message.type === 'DEPOSIT_REJECTED' && depositPayload?.rejectReason?.trim()"
|
||||
@@ -323,6 +329,32 @@ watch(messageId, () => {
|
||||
color: #d0d0d0;
|
||||
}
|
||||
|
||||
.rich-body :deep(p) {
|
||||
margin: 0 0 12px;
|
||||
}
|
||||
|
||||
.rich-body :deep(p:last-child) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.rich-body :deep(img) {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
margin: 12px 0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.rich-body :deep(ul),
|
||||
.rich-body :deep(ol) {
|
||||
margin: 0 0 12px;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.rich-body :deep(a) {
|
||||
color: var(--gold);
|
||||
}
|
||||
|
||||
.reason-box {
|
||||
margin-top: 18px;
|
||||
padding: 14px;
|
||||
|
||||
Reference in New Issue
Block a user