✨ feat(im): 继续优化频道的各种代码(v3)
parent
2442a01e48
commit
94e5fc00ac
|
|
@ -18,6 +18,13 @@ export const getManagerChannelMaterialPage = (params: PageParam) => {
|
||||||
return request.get({ url: '/im/manager/channel-material/page', params })
|
return request.get({ url: '/im/manager/channel-material/page', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获得指定频道下的素材精简列表
|
||||||
|
export const getSimpleManagerChannelMaterialList = (channelId: number) => {
|
||||||
|
return request.get({
|
||||||
|
url: '/im/manager/channel-material/simple-list?channelId=' + channelId
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 获得素材详情
|
// 获得素材详情
|
||||||
export const getManagerChannelMaterial = (id: number) => {
|
export const getManagerChannelMaterial = (id: number) => {
|
||||||
return request.get({ url: '/im/manager/channel-material/get?id=' + id })
|
return request.get({ url: '/im/manager/channel-material/get?id=' + id })
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,26 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="material-card" @click="onClick">
|
<!-- 公众号会话内(大卡片:封面 + 标题 + 摘要) -->
|
||||||
|
<div v-if="isChannelView" class="material-card" @click="onClick">
|
||||||
<div class="title">{{ payload.title || '(无标题)' }}</div>
|
<div class="title">{{ payload.title || '(无标题)' }}</div>
|
||||||
<img v-if="payload.coverUrl" class="cover" :src="payload.coverUrl" />
|
<img v-if="payload.coverUrl" class="cover" :src="payload.coverUrl" />
|
||||||
<div v-if="payload.summary" class="summary">{{ payload.summary }}</div>
|
<div v-if="payload.summary" class="summary">{{ payload.summary }}</div>
|
||||||
<span class="link">{{ payload.url ? '外链' : '查看详情' }}</span>
|
<span class="link">{{ payload.url ? '外链' : '查看详情' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 私聊 / 群聊里被转发的素材(紧凑卡片:标题左 + 小封面右 + 底部频道标识) -->
|
||||||
|
<!-- TODO @AI:转发后的消息,无法点击打开; -->
|
||||||
|
<div v-else class="material-card-forward" @click="onClick">
|
||||||
|
<div class="forward-body">
|
||||||
|
<div class="forward-title">{{ payload.title || '(无标题)' }}</div>
|
||||||
|
<img v-if="payload.coverUrl" class="forward-cover" :src="payload.coverUrl" />
|
||||||
|
</div>
|
||||||
|
<div class="forward-footer">
|
||||||
|
<Icon icon="ep:promotion" :size="12" />
|
||||||
|
<span>频道消息</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- TODO @ai:需要注释下; -->
|
||||||
<Dialog
|
<Dialog
|
||||||
v-model="detailVisible"
|
v-model="detailVisible"
|
||||||
:title="payload.title || '详情'"
|
:title="payload.title || '详情'"
|
||||||
|
|
@ -23,8 +38,11 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import type { PropType } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
|
import Icon from '@/components/Icon/src/Icon.vue'
|
||||||
import { getChannelMaterial } from '@/api/im/channel/material'
|
import { getChannelMaterial } from '@/api/im/channel/material'
|
||||||
import { parseMessage, type MaterialMessage } from '@/views/im/utils/message'
|
import { parseMessage, type MaterialMessage } from '@/views/im/utils/message'
|
||||||
|
import { useConversationStore } from '@/views/im/home/store/conversationStore'
|
||||||
|
import { ImConversationType } from '@/views/im/utils/constants'
|
||||||
|
|
||||||
interface MessageInfo {
|
interface MessageInfo {
|
||||||
materialId?: number
|
materialId?: number
|
||||||
|
|
@ -35,6 +53,13 @@ const props = defineProps({
|
||||||
message: { type: Object as PropType<MessageInfo>, required: true }
|
message: { type: Object as PropType<MessageInfo>, required: true }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const conversationStore = useConversationStore()
|
||||||
|
|
||||||
|
/** 当前是否在公众号 / 频道会话里:决定走大卡片还是紧凑转发卡片 */
|
||||||
|
const isChannelView = computed(
|
||||||
|
() => conversationStore.activeConversation?.type === ImConversationType.CHANNEL
|
||||||
|
)
|
||||||
|
|
||||||
/** 反序列化 content JSON 为 payload 对象 */
|
/** 反序列化 content JSON 为 payload 对象 */
|
||||||
const payload = computed<MaterialMessage>(
|
const payload = computed<MaterialMessage>(
|
||||||
() => parseMessage<MaterialMessage>(props.message.content) ?? {}
|
() => parseMessage<MaterialMessage>(props.message.content) ?? {}
|
||||||
|
|
@ -69,6 +94,8 @@ const onClick = async () => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
/* 公众号会话内大卡片:占父容器全宽,封面 + 标题 + 摘要纵向铺开 */
|
||||||
|
/** TODO @AI:有没可能 unocss 尽量替代掉; */
|
||||||
.material-card {
|
.material-card {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
@ -124,6 +151,62 @@ const onClick = async () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 私聊 / 群聊转发紧凑卡片:标题左 + 小封面右 + 底部频道标识 */
|
||||||
|
.material-card-forward {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 280px;
|
||||||
|
padding: 10px 12px 8px;
|
||||||
|
background: var(--el-bg-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid var(--el-border-color-lighter);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: box-shadow 0.15s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.forward-body {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
.forward-title {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1.4;
|
||||||
|
color: var(--el-text-color-primary);
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forward-cover {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: var(--el-fill-color-light);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.forward-footer {
|
||||||
|
margin-top: 8px;
|
||||||
|
padding-top: 6px;
|
||||||
|
border-top: 1px solid var(--el-border-color-lighter);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--el-text-color-secondary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.material-detail-body {
|
.material-detail-body {
|
||||||
max-width: 720px;
|
max-width: 720px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,13 @@
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="编码" align="center" prop="code" width="160" show-overflow-tooltip />
|
<el-table-column label="编码" align="center" prop="code" width="160" show-overflow-tooltip />
|
||||||
<el-table-column label="名称" align="center" prop="name" min-width="120" show-overflow-tooltip />
|
<el-table-column
|
||||||
|
label="名称"
|
||||||
|
align="center"
|
||||||
|
prop="name"
|
||||||
|
min-width="120"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
<el-table-column label="排序" align="center" prop="sort" width="80" />
|
<el-table-column label="排序" align="center" prop="sort" width="80" />
|
||||||
<el-table-column label="状态" align="center" prop="status" width="80">
|
<el-table-column label="状态" align="center" prop="status" width="80">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
|
|
@ -111,7 +117,6 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
// TOOD @AI:注释风格,对齐 system user index
|
|
||||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||||
import { dateFormatter } from '@/utils/formatTime'
|
import { dateFormatter } from '@/utils/formatTime'
|
||||||
import * as ChannelApi from '@/api/im/manager/channel'
|
import * as ChannelApi from '@/api/im/manager/channel'
|
||||||
|
|
@ -119,12 +124,12 @@ import ChannelForm from './ChannelForm.vue'
|
||||||
|
|
||||||
defineOptions({ name: 'ImChannel' })
|
defineOptions({ name: 'ImChannel' })
|
||||||
|
|
||||||
const message = useMessage()
|
const message = useMessage() // 消息弹窗
|
||||||
const { t } = useI18n()
|
const { t } = useI18n() // 国际化
|
||||||
|
|
||||||
const loading = ref(true)
|
const loading = ref(true) // 列表的加载中
|
||||||
const total = ref(0)
|
const total = ref(0) // 列表的总页数
|
||||||
const list = ref<ChannelApi.ImManagerChannelVO[]>([])
|
const list = ref<ChannelApi.ImManagerChannelVO[]>([]) // 列表的数据
|
||||||
const queryParams = reactive({
|
const queryParams = reactive({
|
||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
|
|
@ -132,7 +137,7 @@ const queryParams = reactive({
|
||||||
name: undefined as string | undefined,
|
name: undefined as string | undefined,
|
||||||
status: undefined as number | undefined
|
status: undefined as number | undefined
|
||||||
})
|
})
|
||||||
const queryFormRef = ref()
|
const queryFormRef = ref() // 搜索的表单
|
||||||
|
|
||||||
/** 查询频道分页 */
|
/** 查询频道分页 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
|
|
@ -176,6 +181,7 @@ const handleDelete = async (id: number) => {
|
||||||
await getList()
|
await getList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 初始化 **/
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList()
|
getList()
|
||||||
})
|
})
|
||||||
|
|
@ -8,10 +8,14 @@
|
||||||
v-loading="formLoading"
|
v-loading="formLoading"
|
||||||
>
|
>
|
||||||
<el-form-item label="所属频道" prop="channelId">
|
<el-form-item label="所属频道" prop="channelId">
|
||||||
<!-- TODO @AI:使用 channelselect 组件 -->
|
<ChannelSelect v-model="formData.channelId" placeholder="请选择频道" />
|
||||||
<el-select v-model="formData.channelId" placeholder="请选择频道" class="!w-full">
|
</el-form-item>
|
||||||
<el-option v-for="c in props.channelList" :key="c.id" :label="c.name" :value="c.id" />
|
<!-- TODO @AI:是不是内容类型,在考虑优化下。1)富文本;2)外链;更简介;注意,需要插入到字典里; -->
|
||||||
</el-select>
|
<el-form-item label="内容类型" prop="type">
|
||||||
|
<el-radio-group v-model="formData.type">
|
||||||
|
<el-radio :value="1">站内富文本</el-radio>
|
||||||
|
<el-radio :value="2">外链</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="标题" prop="title">
|
<el-form-item label="标题" prop="title">
|
||||||
<el-input v-model="formData.title" placeholder="图文标题" maxlength="128" show-word-limit />
|
<el-input v-model="formData.title" placeholder="图文标题" maxlength="128" show-word-limit />
|
||||||
|
|
@ -29,14 +33,8 @@
|
||||||
show-word-limit
|
show-word-limit
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- TODO @AI:需要增加 type; -->
|
<!-- 内容类型为「站内富文本」时展示 content 富文本输入;「外链」时展示 url 输入 -->
|
||||||
<el-form-item label="跳转链接" prop="url">
|
<el-form-item v-if="formData.type === 1" label="正文" prop="content">
|
||||||
<el-input
|
|
||||||
v-model="formData.url"
|
|
||||||
placeholder="为空走站内详情页渲染 content;非空则跳此链接"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="正文" prop="content">
|
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.content"
|
v-model="formData.content"
|
||||||
placeholder="富文本 HTML"
|
placeholder="富文本 HTML"
|
||||||
|
|
@ -44,6 +42,9 @@
|
||||||
:rows="8"
|
:rows="8"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item v-else label="跳转链接" prop="url">
|
||||||
|
<el-input v-model="formData.url" placeholder="https://example.com/..." />
|
||||||
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||||
|
|
@ -53,26 +54,22 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
// TODO @AI:补充一些注释,对齐 system user form;
|
|
||||||
import * as MaterialApi from '@/api/im/manager/channel/material'
|
import * as MaterialApi from '@/api/im/manager/channel/material'
|
||||||
import type { ImManagerChannelVO } from '@/api/im/manager/channel'
|
import ChannelSelect from '../list/components/ChannelSelect.vue'
|
||||||
|
|
||||||
defineOptions({ name: 'ImChannelMaterialForm' })
|
defineOptions({ name: 'ImChannelMaterialForm' })
|
||||||
|
|
||||||
const props = defineProps<{ channelList: ImManagerChannelVO[] }>()
|
const { t } = useI18n() // 国际化
|
||||||
|
const message = useMessage() // 消息弹窗
|
||||||
|
|
||||||
const { t } = useI18n()
|
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||||
const message = useMessage()
|
const dialogTitle = ref('') // 弹窗的标题
|
||||||
|
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||||||
const dialogVisible = ref(false)
|
const formType = ref('') // 表单的类型:create - 新增;update - 修改
|
||||||
const dialogTitle = ref('')
|
|
||||||
const formLoading = ref(false)
|
|
||||||
const formType = ref('')
|
|
||||||
const formData = ref({
|
const formData = ref({
|
||||||
id: undefined as number | undefined,
|
id: undefined as number | undefined,
|
||||||
channelId: undefined as number | undefined,
|
channelId: undefined as number | undefined,
|
||||||
// TODO @AI:不是这种 type;是 1 为外链;2 为图文;
|
type: 1, // 内容类型;1 站内富文本 2 外链;参见 ImChannelMaterialTypeEnum
|
||||||
type: 125, // MATERIAL
|
|
||||||
title: '',
|
title: '',
|
||||||
coverUrl: '',
|
coverUrl: '',
|
||||||
summary: '',
|
summary: '',
|
||||||
|
|
@ -81,15 +78,18 @@ const formData = ref({
|
||||||
})
|
})
|
||||||
const formRules = reactive({
|
const formRules = reactive({
|
||||||
channelId: [{ required: true, message: '所属频道不能为空', trigger: 'change' }],
|
channelId: [{ required: true, message: '所属频道不能为空', trigger: 'change' }],
|
||||||
|
type: [{ required: true, message: '内容类型不能为空', trigger: 'change' }],
|
||||||
title: [{ required: true, message: '标题不能为空', trigger: 'blur' }]
|
title: [{ required: true, message: '标题不能为空', trigger: 'blur' }]
|
||||||
})
|
})
|
||||||
const formRef = ref()
|
const formRef = ref() // 表单 Ref
|
||||||
|
|
||||||
|
/** 打开弹窗 */
|
||||||
const open = async (type: string, id?: number) => {
|
const open = async (type: string, id?: number) => {
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
dialogTitle.value = t('action.' + type)
|
dialogTitle.value = t('action.' + type)
|
||||||
formType.value = type
|
formType.value = type
|
||||||
resetForm()
|
resetForm()
|
||||||
|
// 修改时回填数据
|
||||||
if (id) {
|
if (id) {
|
||||||
formLoading.value = true
|
formLoading.value = true
|
||||||
try {
|
try {
|
||||||
|
|
@ -99,10 +99,11 @@ const open = async (type: string, id?: number) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defineExpose({ open })
|
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||||
|
|
||||||
const emit = defineEmits(['success'])
|
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
||||||
|
|
||||||
|
/** 提交表单 */
|
||||||
const submitForm = async () => {
|
const submitForm = async () => {
|
||||||
await formRef.value.validate()
|
await formRef.value.validate()
|
||||||
formLoading.value = true
|
formLoading.value = true
|
||||||
|
|
@ -122,11 +123,12 @@ const submitForm = async () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 重置表单 */
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
formData.value = {
|
formData.value = {
|
||||||
id: undefined,
|
id: undefined,
|
||||||
channelId: undefined,
|
channelId: undefined,
|
||||||
type: 125,
|
type: 1,
|
||||||
title: '',
|
title: '',
|
||||||
coverUrl: '',
|
coverUrl: '',
|
||||||
summary: '',
|
summary: '',
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,7 @@
|
||||||
label-width="68px"
|
label-width="68px"
|
||||||
>
|
>
|
||||||
<el-form-item label="频道" prop="channelId">
|
<el-form-item label="频道" prop="channelId">
|
||||||
<el-select v-model="queryParams.channelId" placeholder="全部" clearable class="!w-200px">
|
<ChannelSelect v-model="queryParams.channelId" placeholder="全部" clearable class="!w-200px" />
|
||||||
<el-option v-for="c in channelList" :key="c.id" :label="c.name" :value="c.id" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="标题" prop="title">
|
<el-form-item label="标题" prop="title">
|
||||||
<el-input
|
<el-input
|
||||||
|
|
@ -108,33 +106,32 @@
|
||||||
/>
|
/>
|
||||||
</ContentWrap>
|
</ContentWrap>
|
||||||
|
|
||||||
<ChannelMaterialForm ref="formRef" :channel-list="channelList" @success="getList" />
|
<ChannelMaterialForm ref="formRef" @success="getList" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
// TOOD @AI:注释风格,对齐 system user index
|
|
||||||
import { dateFormatter } from '@/utils/formatTime'
|
import { dateFormatter } from '@/utils/formatTime'
|
||||||
import * as MaterialApi from '@/api/im/manager/channel/material'
|
import * as MaterialApi from '@/api/im/manager/channel/material'
|
||||||
import * as ChannelApi from '@/api/im/manager/channel'
|
import ChannelSelect from '../list/components/ChannelSelect.vue'
|
||||||
import ChannelMaterialForm from './ChannelMaterialForm.vue'
|
import ChannelMaterialForm from './ChannelMaterialForm.vue'
|
||||||
|
|
||||||
defineOptions({ name: 'ImChannelMaterial' })
|
defineOptions({ name: 'ImChannelMaterial' })
|
||||||
|
|
||||||
const message = useMessage()
|
const message = useMessage() // 消息弹窗
|
||||||
const { t } = useI18n()
|
const { t } = useI18n() // 国际化
|
||||||
|
|
||||||
const loading = ref(true)
|
const loading = ref(true) // 列表的加载中
|
||||||
const total = ref(0)
|
const total = ref(0) // 列表的总页数
|
||||||
const list = ref<MaterialApi.ImManagerChannelMaterialVO[]>([])
|
const list = ref<MaterialApi.ImManagerChannelMaterialVO[]>([]) // 列表的数据
|
||||||
const channelList = ref<ChannelApi.ImManagerChannelVO[]>([])
|
|
||||||
const queryParams = reactive({
|
const queryParams = reactive({
|
||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
channelId: undefined as number | undefined,
|
channelId: undefined as number | undefined,
|
||||||
title: undefined as string | undefined
|
title: undefined as string | undefined
|
||||||
})
|
})
|
||||||
const queryFormRef = ref()
|
const queryFormRef = ref() // 搜索的表单
|
||||||
|
|
||||||
|
/** 查询素材分页 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
|
|
@ -146,21 +143,25 @@ const getList = async () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 搜索 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.pageNo = 1
|
queryParams.pageNo = 1
|
||||||
getList()
|
getList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 重置 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value.resetFields()
|
queryFormRef.value.resetFields()
|
||||||
handleQuery()
|
handleQuery()
|
||||||
}
|
}
|
||||||
|
|
||||||
const formRef = ref()
|
/** 打开新增 / 编辑弹窗 */
|
||||||
|
const formRef = ref() // 表单 Ref
|
||||||
const openForm = (type: string, id?: number) => {
|
const openForm = (type: string, id?: number) => {
|
||||||
formRef.value.open(type, id)
|
formRef.value.open(type, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 删除 */
|
||||||
const handleDelete = async (id: number) => {
|
const handleDelete = async (id: number) => {
|
||||||
try {
|
try {
|
||||||
await message.delConfirm()
|
await message.delConfirm()
|
||||||
|
|
@ -172,9 +173,8 @@ const handleDelete = async (id: number) => {
|
||||||
await getList()
|
await getList()
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
/** 初始化 */
|
||||||
// TOOD @AI:注释风格,ChannelApi 列表,让 channel/components 抽个组件,复用一下;
|
onMounted(() => {
|
||||||
channelList.value = await ChannelApi.getEnabledChannelList()
|
|
||||||
getList()
|
getList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,7 @@
|
||||||
label-width="68px"
|
label-width="68px"
|
||||||
>
|
>
|
||||||
<el-form-item label="频道" prop="channelId">
|
<el-form-item label="频道" prop="channelId">
|
||||||
<el-select v-model="queryParams.channelId" placeholder="全部" clearable class="!w-200px">
|
<ChannelSelect v-model="queryParams.channelId" placeholder="全部" clearable class="!w-200px" />
|
||||||
<el-option v-for="c in channelList" :key="c.id" :label="c.name" :value="c.id" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="发送时间" prop="sendTime">
|
<el-form-item label="发送时间" prop="sendTime">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
|
|
@ -88,33 +86,32 @@
|
||||||
/>
|
/>
|
||||||
</ContentWrap>
|
</ContentWrap>
|
||||||
|
|
||||||
<ChannelMessageSendForm ref="sendFormRef" :channel-list="channelList" @success="getList" />
|
<ChannelMessageSendForm ref="sendFormRef" @success="getList" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
// TODO @AI:补充一些注释,对齐 system user index;
|
|
||||||
import { dateFormatter } from '@/utils/formatTime'
|
import { dateFormatter } from '@/utils/formatTime'
|
||||||
import * as MessageApi from '@/api/im/manager/channel/message'
|
import * as MessageApi from '@/api/im/manager/channel/message'
|
||||||
import * as ChannelApi from '@/api/im/manager/channel'
|
import ChannelSelect from '../list/components/ChannelSelect.vue'
|
||||||
import ChannelMessageSendForm from './ChannelMessageSendForm.vue'
|
import ChannelMessageSendForm from './ChannelMessageSendForm.vue'
|
||||||
|
|
||||||
defineOptions({ name: 'ImChannelMessage' })
|
defineOptions({ name: 'ImChannelMessage' })
|
||||||
|
|
||||||
const message = useMessage()
|
const message = useMessage() // 消息弹窗
|
||||||
const { t } = useI18n()
|
const { t } = useI18n() // 国际化
|
||||||
|
|
||||||
const loading = ref(true)
|
const loading = ref(true) // 列表的加载中
|
||||||
const total = ref(0)
|
const total = ref(0) // 列表的总页数
|
||||||
const list = ref<MessageApi.ImManagerChannelMessageVO[]>([])
|
const list = ref<MessageApi.ImManagerChannelMessageVO[]>([]) // 列表的数据
|
||||||
const channelList = ref<ChannelApi.ImManagerChannelVO[]>([])
|
|
||||||
const queryParams = reactive({
|
const queryParams = reactive({
|
||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
channelId: undefined as number | undefined,
|
channelId: undefined as number | undefined,
|
||||||
sendTime: [] as string[]
|
sendTime: [] as string[]
|
||||||
})
|
})
|
||||||
const queryFormRef = ref()
|
const queryFormRef = ref() // 搜索的表单
|
||||||
|
|
||||||
|
/** 查询消息分页 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
|
|
@ -126,21 +123,25 @@ const getList = async () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 搜索 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.pageNo = 1
|
queryParams.pageNo = 1
|
||||||
getList()
|
getList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 重置 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value.resetFields()
|
queryFormRef.value.resetFields()
|
||||||
handleQuery()
|
handleQuery()
|
||||||
}
|
}
|
||||||
|
|
||||||
const sendFormRef = ref()
|
/** 打开「立即推送」弹窗 */
|
||||||
|
const sendFormRef = ref() // 推送弹窗 Ref
|
||||||
const openSendForm = () => {
|
const openSendForm = () => {
|
||||||
sendFormRef.value.open()
|
sendFormRef.value.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 删除 */
|
||||||
const handleDelete = async (id: number) => {
|
const handleDelete = async (id: number) => {
|
||||||
try {
|
try {
|
||||||
await message.delConfirm()
|
await message.delConfirm()
|
||||||
|
|
@ -152,8 +153,7 @@ const handleDelete = async (id: number) => {
|
||||||
await getList()
|
await getList()
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(() => {
|
||||||
channelList.value = await ChannelApi.getEnabledChannelList()
|
|
||||||
getList()
|
getList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue