Initial commit of akmon project
This commit is contained in:
850
pages/msg/compose.uvue
Normal file
850
pages/msg/compose.uvue
Normal file
@@ -0,0 +1,850 @@
|
||||
<template>
|
||||
<view class="compose-page">
|
||||
<!-- 导航栏 -->
|
||||
<view class="nav-bar">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-text">取消</text>
|
||||
</view>
|
||||
<view class="nav-center">
|
||||
<text class="nav-title">{{ pageTitle }}</text>
|
||||
</view>
|
||||
<view class="nav-right" @click="sendMessage">
|
||||
<text class="nav-text" :class="{ 'disabled': !canSend }">发送</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 表单内容 -->
|
||||
<scroll-view class="form-content">
|
||||
<!-- 消息类型选择 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-text">消息类型</text>
|
||||
</view>
|
||||
<picker-view class="type-picker" :value="[typeIndex]" @change="onTypeChange">
|
||||
<picker-view-column>
|
||||
<view v-for="(type, index) in messageTypes" :key="type.id">
|
||||
<text class="picker-text">{{ type.name }}</text>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
</picker-view>
|
||||
</view>
|
||||
|
||||
<!-- 接收者选择 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-text">发送给</text>
|
||||
</view>
|
||||
<view class="receiver-input">
|
||||
<input
|
||||
class="input-field"
|
||||
type="text"
|
||||
placeholder="输入接收者ID或选择群组"
|
||||
:value="formData.receiverId"
|
||||
/>
|
||||
<view class="select-btn" @click="selectReceiver">
|
||||
<text class="btn-text">选择</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 消息标题 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-text">标题 (可选)</text>
|
||||
</view>
|
||||
<input
|
||||
class="title-input"
|
||||
type="text"
|
||||
placeholder="请输入消息标题"
|
||||
:value="formData.title"
|
||||
maxlength="200"
|
||||
/>
|
||||
<view class="char-count">
|
||||
<text class="count-text">{{ formData.title.length }}/200</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 消息内容 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-text">内容 *</text>
|
||||
</view>
|
||||
<textarea
|
||||
class="content-textarea"
|
||||
placeholder="请输入消息内容"
|
||||
:value="formData.content"
|
||||
maxlength="5000"
|
||||
:auto-height="true"
|
||||
/>
|
||||
<view class="char-count">
|
||||
<text class="count-text">{{ formData.content.length }}/5000</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 消息选项 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-text">消息选项</text>
|
||||
</view>
|
||||
|
||||
<!-- 优先级设置 -->
|
||||
<view class="option-item">
|
||||
<text class="option-label">优先级</text>
|
||||
<picker-view class="priority-picker" :value="[priorityIndex]" @change="onPriorityChange">
|
||||
<picker-view-column>
|
||||
<view v-for="(priority, index) in priorityOptions" :key="index">
|
||||
<text class="picker-text">{{ priority.label }}</text>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
</picker-view>
|
||||
</view>
|
||||
|
||||
<!-- 紧急标记 -->
|
||||
<view class="option-item">
|
||||
<text class="option-label">紧急消息</text>
|
||||
<switch :value="formData.isUrgent" />
|
||||
</view>
|
||||
|
||||
<!-- 推送通知 -->
|
||||
<view class="option-item">
|
||||
<text class="option-label">推送通知</text>
|
||||
<switch :value="formData.pushNotification" />
|
||||
</view>
|
||||
|
||||
<!-- 邮件通知 -->
|
||||
<view class="option-item">
|
||||
<text class="option-label">邮件通知</text>
|
||||
<switch :value="formData.emailNotification" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 定时发送 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-text">定时发送</text>
|
||||
</view>
|
||||
<view class="option-item">
|
||||
<text class="option-label">启用定时发送</text>
|
||||
<switch :value="formData.enableSchedule" @change="onScheduleToggle" />
|
||||
</view>
|
||||
<view class="schedule-time" v-if="formData.enableSchedule">
|
||||
<picker-date
|
||||
:value="scheduleDate"
|
||||
@change="onScheduleDateChange"
|
||||
></picker-date>
|
||||
<picker-time
|
||||
:value="scheduleTime"
|
||||
@change="onScheduleTimeChange"
|
||||
></picker-time>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 过期时间 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-text">过期时间</text>
|
||||
</view>
|
||||
<view class="option-item">
|
||||
<text class="option-label">设置过期时间</text>
|
||||
<switch :value="formData.enableExpiry" @change="onExpiryToggle" />
|
||||
</view>
|
||||
<view class="expiry-time" v-if="formData.enableExpiry">
|
||||
<picker-date
|
||||
:value="expiryDate"
|
||||
@change="onExpiryDateChange"
|
||||
></picker-date>
|
||||
<picker-time
|
||||
:value="expiryTime"
|
||||
@change="onExpiryTimeChange"
|
||||
></picker-time>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 原消息引用 (回复/转发时显示) -->
|
||||
<view class="form-section" v-if="originalMessage !== null">
|
||||
<view class="section-title">
|
||||
<text class="title-text">{{ isReply ? '回复消息' : '转发消息' }}</text>
|
||||
</view>
|
||||
<view class="original-message">
|
||||
<view class="original-header">
|
||||
<text class="original-sender">{{ originalMessage?.sender_name ?? '未知发送者' }}</text>
|
||||
<text class="original-time">{{ originalMessage?.created_at!=null ? formatTime(new Date(originalMessage!!.created_at!!)) : '' }}</text>
|
||||
</view>
|
||||
<view class="original-content">
|
||||
<text class="original-text">{{ getMessageSummary(originalMessage?.content ?? '', 100) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 接收者选择弹窗 -->
|
||||
<view class="receiver-modal" v-if="showReceiverModal" @click="hideReceiverModal">
|
||||
<view class="modal-content" @click.stop>
|
||||
<view class="modal-header">
|
||||
<text class="modal-title">选择接收者</text>
|
||||
<view class="modal-close" @click="hideReceiverModal">
|
||||
<text class="close-icon">×</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="modal-body">
|
||||
<view class="receiver-type-tabs">
|
||||
<view
|
||||
class="tab-item"
|
||||
:class="{ 'active': receiverTab === 'user' }"
|
||||
@click="switchReceiverTab('user')"
|
||||
>
|
||||
<text class="tab-text">用户</text>
|
||||
</view>
|
||||
<view
|
||||
class="tab-item"
|
||||
:class="{ 'active': receiverTab === 'group' }"
|
||||
@click="switchReceiverTab('group')"
|
||||
>
|
||||
<text class="tab-text">群组</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view class="receiver-list">
|
||||
<view
|
||||
class="receiver-item"
|
||||
v-for="receiver in receiverList"
|
||||
:key="receiver.id"
|
||||
@click="selectReceiverItem(receiver)"
|
||||
>
|
||||
<view class="receiver-info">
|
||||
<text class="receiver-name">{{ receiver.name }}</text>
|
||||
<text class="receiver-desc">{{ receiver.description }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { MsgDataServiceReal } from '@/utils/msgDataServiceReal.uts'
|
||||
import { MsgUtils } from '@/utils/msgUtils.uts'
|
||||
import supa from '@/components/supadb/aksupainstance.uts'
|
||||
import {
|
||||
Message,
|
||||
MessageType,
|
||||
SendMessageParams
|
||||
} from '@/utils/msgTypes.uts'
|
||||
|
||||
// 页面参数
|
||||
const replyToId = ref<string>('')
|
||||
const forwardId = ref<string>('')
|
||||
|
||||
// 响应式数据
|
||||
const messageTypes = ref<Array<MessageType>>([])
|
||||
const originalMessage = ref<Message | null>(null)
|
||||
const loading = ref<boolean>(false)
|
||||
const showReceiverModal = ref<boolean>(false)
|
||||
const receiverTab = ref<string>('user')
|
||||
const receiverList = ref<Array<MessageType>>([])
|
||||
|
||||
// 表单数据类型声明,兼容 UTS Android 类型推断
|
||||
type FormData = {
|
||||
messageTypeId: string
|
||||
receiverId: string
|
||||
title: string
|
||||
content: string
|
||||
priority: number
|
||||
isUrgent: boolean
|
||||
pushNotification: boolean
|
||||
emailNotification: boolean
|
||||
enableSchedule: boolean
|
||||
enableExpiry: boolean
|
||||
}
|
||||
const formData = ref({
|
||||
messageTypeId: '',
|
||||
receiverId: '',
|
||||
title: '',
|
||||
content: '',
|
||||
priority: 0,
|
||||
isUrgent: false,
|
||||
pushNotification: true,
|
||||
emailNotification: false,
|
||||
enableSchedule: false,
|
||||
enableExpiry: false
|
||||
} as FormData)
|
||||
|
||||
// UI状态
|
||||
const typeIndex = ref<number>(0)
|
||||
const priorityIndex = ref<number>(1)
|
||||
const scheduleDate = ref<string>('')
|
||||
const scheduleTime = ref<string>('')
|
||||
const expiryDate = ref<string>('')
|
||||
const expiryTime = ref<string>('')
|
||||
|
||||
// 优先级选项
|
||||
const priorityOptions = [
|
||||
{ label: '低优先级', value: 10 },
|
||||
{ label: '普通', value: 50 },
|
||||
{ label: '重要', value: 70 },
|
||||
{ label: '紧急', value: 90 }
|
||||
]
|
||||
const isReply = computed(() => {
|
||||
return replyToId.value !== ''
|
||||
})
|
||||
// 计算属性
|
||||
const pageTitle = computed(() => {
|
||||
if (originalMessage.value !== null) {
|
||||
return isReply.value ? '回复消息' : '转发消息'
|
||||
}
|
||||
return '写消息'
|
||||
})
|
||||
|
||||
|
||||
|
||||
const canSend = computed(() => {
|
||||
return formData.value.content.trim() !== '' && formData.value.messageTypeId !== ''
|
||||
})
|
||||
|
||||
// 日期/时间格式化函数,放在顶部,确保所有调用前可用
|
||||
function formatDate(date: Date): string {
|
||||
const y = date.getFullYear()
|
||||
const m = (date.getMonth() + 1).toString().padStart(2, '0')
|
||||
const d = date.getDate().toString().padStart(2, '0')
|
||||
return y + '-' + m + '-' + d
|
||||
}
|
||||
function formatTime(date: Date): string {
|
||||
const h = date.getHours().toString().padStart(2, '0')
|
||||
const min = date.getMinutes().toString().padStart(2, '0')
|
||||
return h + ':' + min
|
||||
}
|
||||
|
||||
// 加载消息类型
|
||||
async function loadMessageTypes(): Promise<void> {
|
||||
const response = await MsgDataServiceReal.getMessageTypes()
|
||||
if (response.data !== null) {
|
||||
if (Array.isArray(response.data)) {
|
||||
const dataArray = response.data as Array<any>
|
||||
const types: Array<MessageType> = []
|
||||
for (let i = 0; i < dataArray.length; i++) {
|
||||
types.push(dataArray[i] as MessageType)
|
||||
}
|
||||
messageTypes.value = types
|
||||
} else {
|
||||
messageTypes.value = []
|
||||
}
|
||||
} else {
|
||||
messageTypes.value = []
|
||||
}
|
||||
if (messageTypes.value.length > 0) {
|
||||
formData.value.messageTypeId = messageTypes.value[0].id
|
||||
}
|
||||
}
|
||||
|
||||
// 加载原消息
|
||||
async function loadOriginalMessage(): Promise<void> {
|
||||
const messageId = replyToId.value !== '' ? replyToId.value : forwardId.value
|
||||
if (messageId === '') return
|
||||
const response = await MsgDataServiceReal.getMessageById(messageId)
|
||||
if (response.data !== null) {
|
||||
originalMessage.value = (response.data ?? null) as Message | null
|
||||
// 预填充表单数据
|
||||
const msg = originalMessage.value
|
||||
if (isReply.value) {
|
||||
formData.value.title = `回复: ${(msg != null && typeof msg.title === 'string') ? msg.title : ''}`
|
||||
formData.value.receiverId = (msg != null && typeof msg.sender_id === 'string') ? (msg.sender_id as string) : ''
|
||||
} else {
|
||||
formData.value.title = `转发: ${(msg != null && typeof msg.title === 'string') ? msg.title : ''}`
|
||||
formData.value.content = `转发消息:\n\n${(msg != null && typeof msg.content === 'string') ? msg.content : ''}`
|
||||
}
|
||||
}
|
||||
}
|
||||
// 工具函数
|
||||
function goBack(): void {
|
||||
uni.navigateBack()
|
||||
}
|
||||
|
||||
// 事件处理
|
||||
function onTypeChange(event: UniPickerViewChangeEvent): void {
|
||||
const index = event.detail.value[0]
|
||||
typeIndex.value = index
|
||||
|
||||
if (index < messageTypes.value.length) {
|
||||
formData.value.messageTypeId = messageTypes.value[index].id
|
||||
}
|
||||
}
|
||||
|
||||
function onPriorityChange(event: UniPickerViewChangeEvent): void {
|
||||
const index = event.detail.value[0]
|
||||
priorityIndex.value = index
|
||||
|
||||
if (index < priorityOptions.length) {
|
||||
formData.value.priority = parseInt(priorityOptions[index].value.toString())
|
||||
}
|
||||
}
|
||||
function hideReceiverModal(): void {
|
||||
showReceiverModal.value = false
|
||||
}
|
||||
|
||||
function onScheduleToggle(): void {
|
||||
if (formData.value.enableSchedule) {
|
||||
const now = new Date()
|
||||
scheduleDate.value = formatDate(now)
|
||||
scheduleTime.value = formatTime(now)
|
||||
}
|
||||
}
|
||||
|
||||
function onExpiryToggle(): void {
|
||||
if (formData.value.enableExpiry) {
|
||||
const tomorrow = new Date()
|
||||
tomorrow.setDate(tomorrow.getDate() + 1)
|
||||
expiryDate.value = formatDate(tomorrow)
|
||||
expiryTime.value = formatTime(tomorrow)
|
||||
}
|
||||
}
|
||||
|
||||
function onScheduleDateChange(date: string): void {
|
||||
scheduleDate.value = date
|
||||
}
|
||||
|
||||
function onScheduleTimeChange(time: string): void {
|
||||
scheduleTime.value = time
|
||||
}
|
||||
|
||||
function onExpiryDateChange(date: string): void {
|
||||
expiryDate.value = date
|
||||
}
|
||||
|
||||
function onExpiryTimeChange(time: string): void {
|
||||
expiryTime.value = time
|
||||
}
|
||||
|
||||
function loadReceiverList(): void {
|
||||
// 这里应该根据receiverTab加载用户或群组列表
|
||||
receiverList.value = []
|
||||
}
|
||||
|
||||
function selectReceiverItem(receiver:MessageType): void {
|
||||
formData.value.receiverId = receiver.id
|
||||
hideReceiverModal()
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
async function sendMessage(): Promise<void> {
|
||||
if (!canSend.value) return
|
||||
|
||||
// 验证表单
|
||||
const validationError = MsgUtils.validateSendParams(formData.value.title, formData.value.content)
|
||||
if (validationError !== null) {
|
||||
uni.showToast({
|
||||
title: validationError,
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
|
||||
try {
|
||||
const params: SendMessageParams = {
|
||||
message_type_id: formData.value.messageTypeId,
|
||||
receiver_type: 'user', // 根据实际选择确定
|
||||
receiver_id: formData.value.receiverId === '' ? null : formData.value.receiverId,
|
||||
title: formData.value.title === '' ? null : formData.value.title,
|
||||
content: formData.value.content,
|
||||
priority: formData.value.priority,
|
||||
is_urgent: formData.value.isUrgent,
|
||||
push_notification: formData.value.pushNotification,
|
||||
email_notification: formData.value.emailNotification
|
||||
}
|
||||
|
||||
// 设置定时发送
|
||||
if (formData.value.enableSchedule && scheduleDate.value !== '' && scheduleTime.value !== '') {
|
||||
params.scheduled_at = `${scheduleDate.value} ${scheduleTime.value}`
|
||||
}
|
||||
|
||||
// 设置过期时间
|
||||
if (formData.value.enableExpiry && expiryDate.value !== '' && expiryTime.value !== '') {
|
||||
params.expires_at = `${expiryDate.value} ${expiryTime.value}`
|
||||
}
|
||||
|
||||
const response = await MsgDataServiceReal.sendMessage(params)
|
||||
|
||||
let isSuccess = false
|
||||
if ( response.status >= 200 && response.status < 300) {
|
||||
isSuccess = true
|
||||
}
|
||||
if (isSuccess) {
|
||||
uni.showToast({
|
||||
title: '发送成功',
|
||||
icon: 'success'
|
||||
})
|
||||
setTimeout(() => {
|
||||
goBack()
|
||||
}, 1500)
|
||||
} else {
|
||||
let errMsg = response.error?.message ?? '发送失败'
|
||||
uni.showToast({
|
||||
title: errMsg,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: '发送失败',
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 接收者选择
|
||||
function selectReceiver(): void {
|
||||
showReceiverModal.value = true
|
||||
loadReceiverList()
|
||||
}
|
||||
|
||||
|
||||
function switchReceiverTab(tab: string): void {
|
||||
receiverTab.value = tab
|
||||
loadReceiverList()
|
||||
}
|
||||
|
||||
|
||||
function getMessageSummary(content: string | null, maxLength: number): string {
|
||||
return MsgUtils.getMessageSummary(content, maxLength)
|
||||
}
|
||||
|
||||
// 初始化数据
|
||||
async function loadInitialData(): Promise<void> {
|
||||
await loadMessageTypes()
|
||||
|
||||
if (replyToId.value !== '' || forwardId.value !== '') {
|
||||
await loadOriginalMessage()
|
||||
}
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
onLoad((options: OnLoadOptions) => {
|
||||
if (options["replyTo"] !== null) {
|
||||
const val = options.getString("replyTo")
|
||||
if (val !== null) {
|
||||
replyToId.value = val
|
||||
}
|
||||
}
|
||||
if (options["forward"] !== null) {
|
||||
const val = options.getString("forward")
|
||||
if (val !== null) {
|
||||
forwardId.value = val
|
||||
}
|
||||
}
|
||||
loadInitialData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.compose-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.nav-bar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 44px;
|
||||
padding: 0 16px;
|
||||
background-color: #ffffff;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.nav-left, .nav-right {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.nav-center {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav-text {
|
||||
font-size: 16px;
|
||||
color: #007AFF;
|
||||
}
|
||||
|
||||
.nav-text.disabled {
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.form-content {
|
||||
flex: 1;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
background-color: #ffffff;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.title-text {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.type-picker, .priority-picker {
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.picker-text {
|
||||
font-size: 16px;
|
||||
color: #333333;
|
||||
text-align: center;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
.receiver-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.input-field {
|
||||
flex: 1;
|
||||
height: 40px;
|
||||
padding: 0 12px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 6px;
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.select-btn {
|
||||
margin-left: 12px;
|
||||
padding: 0 16px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: #2196F3;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.btn-text {
|
||||
color: #ffffff;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.title-input {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
padding: 0 12px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 6px;
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.content-textarea {
|
||||
width: 100%;
|
||||
min-height: 120px;
|
||||
padding: 12px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 6px;
|
||||
background-color: #f8f8f8;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.char-count {
|
||||
margin-top: 8px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.count-text {
|
||||
font-size: 12px;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.option-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.option-label {
|
||||
font-size: 16px;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.schedule-time, .expiry-time {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.original-message {
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 6px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.original-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.original-sender {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.original-time {
|
||||
font-size: 12px;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.original-content {
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.original-text {
|
||||
font-size: 14px;
|
||||
color: #666666;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.receiver-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: #ffffff;
|
||||
border-radius: 12px;
|
||||
width: 90%;
|
||||
max-width: 400px;
|
||||
max-height: 80%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16px 20px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
font-size: 24px;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.receiver-type-tabs {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
height: 44px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tab-item.active {
|
||||
border-bottom: 2px solid #2196F3;
|
||||
}
|
||||
|
||||
.tab-text {
|
||||
font-size: 16px;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.tab-item.active .tab-text {
|
||||
color: #2196F3;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.receiver-list {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.receiver-item {
|
||||
padding: 16px 20px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.receiver-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.receiver-name {
|
||||
font-size: 16px;
|
||||
color: #333333;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.receiver-desc {
|
||||
font-size: 14px;
|
||||
color: #999999;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user