feat(im): 继续优化频道的各种代码(v2)

im
YunaiV 2026-05-19 17:48:35 +08:00
parent bfd407d75b
commit 2442a01e48
3 changed files with 39 additions and 115 deletions

View File

@ -36,7 +36,6 @@ export const deleteManagerChannel = (id: number) => {
} }
// 获得启用的频道精简列表(表单选择用) // 获得启用的频道精简列表(表单选择用)
// TODO @AI改成 simplelist 命名上? export const getSimpleChannelList = () => {
export const getEnabledChannelList = () => {
return request.get<ImManagerChannelVO[]>({ url: '/im/manager/channel/simple-list' }) return request.get<ImManagerChannelVO[]>({ url: '/im/manager/channel/simple-list' })
} }

View File

@ -1,5 +1,4 @@
<template> <template>
<!-- TODO @AI要不使用 model 组件弹窗用户允许手动弹窗 -->
<div class="material-card" @click="onClick"> <div 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" />
@ -7,37 +6,23 @@
<span class="link">{{ payload.url ? '外链' : '查看详情' }}</span> <span class="link">{{ payload.url ? '外链' : '查看详情' }}</span>
</div> </div>
<!-- 全屏文章详情仿微信公众号文章打开 --> <Dialog
<el-dialog
v-model="detailVisible" v-model="detailVisible"
:show-close="false" :title="payload.title || '详情'"
fullscreen fullscreen
append-to-body
destroy-on-close destroy-on-close
class="material-detail-dialog"
> >
<template #header> <div v-loading="detailLoading" class="material-detail-body">
<div class="detail-header">
<button class="back-btn" @click="detailVisible = false">
<Icon icon="ant-design:close-outlined" :size="18" />
</button>
<span class="detail-title">{{ payload.title || '详情' }}</span>
<span class="placeholder"></span>
</div>
</template>
<div v-loading="detailLoading" class="detail-body">
<div class="article-title">{{ payload.title || '' }}</div> <div class="article-title">{{ payload.title || '' }}</div>
<div v-if="detailHtml" class="article-content" v-html="detailHtml"></div> <div v-if="detailHtml" class="article-content" v-dompurify-html="detailHtml"></div>
<div v-else-if="!detailLoading" class="article-empty">暂无正文</div> <div v-else-if="!detailLoading" class="article-empty">暂无正文</div>
</div> </div>
</el-dialog> </Dialog>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import { ElDialog } from 'element-plus'
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'
@ -62,7 +47,8 @@ const detailHtml = ref('')
/** 点击行为url 非空跳外链;为空则按 materialId 拉富文本正文,全屏 dialog 渲染 */ /** 点击行为url 非空跳外链;为空则按 materialId 拉富文本正文,全屏 dialog 渲染 */
const onClick = async () => { const onClick = async () => {
if (payload.value.url) { if (payload.value.url) {
window.open(payload.value.url, '_blank') // noopener,noreferrer window.opener / referrer
window.open(payload.value.url, '_blank', 'noopener,noreferrer')
return return
} }
if (!props.message.materialId) { if (!props.message.materialId) {
@ -137,107 +123,46 @@ const onClick = async () => {
color: var(--el-color-primary); color: var(--el-color-primary);
} }
} }
</style>
<style lang="scss"> .material-detail-body {
/* 全屏文章详情样式(非 scopedel-dialog 全屏后 header / body 在 teleport 子树) */ max-width: 720px;
.material-detail-dialog { margin: 0 auto;
.el-dialog__header { padding: 24px 20px 80px;
margin: 0;
padding: 0; .article-title {
border-bottom: 1px solid var(--el-border-color-lighter); font-size: 22px;
font-weight: 600;
line-height: 1.4;
color: var(--el-text-color-primary);
margin-bottom: 20px;
} }
.el-dialog__body { .article-content {
padding: 0; font-size: 15px;
} line-height: 1.75;
color: var(--el-text-color-primary);
.detail-header { :deep(img) {
display: flex; max-width: 100%;
align-items: center; height: auto;
height: 52px;
padding: 0 12px;
background: var(--el-bg-color);
.back-btn {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
border: none;
border-radius: 50%;
cursor: pointer;
color: var(--el-text-color-primary);
&:hover {
background: var(--el-fill-color-light);
}
} }
.detail-title { :deep(p) {
flex: 1; margin: 12px 0;
text-align: center;
font-size: 15px;
font-weight: 500;
color: var(--el-text-color-primary);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
} }
.placeholder { :deep(h1),
width: 36px; :deep(h2),
} :deep(h3) {
} margin: 20px 0 12px;
.detail-body {
max-width: 720px;
margin: 0 auto;
padding: 24px 20px 80px;
min-height: calc(100vh - 52px);
.article-title {
font-size: 22px;
font-weight: 600; font-weight: 600;
line-height: 1.4;
color: var(--el-text-color-primary);
margin-bottom: 20px;
} }
}
.article-content { .article-empty {
font-size: 15px; text-align: center;
line-height: 1.75; color: var(--el-text-color-secondary);
color: var(--el-text-color-primary); margin-top: 80px;
:deep(img),
img {
max-width: 100%;
height: auto;
}
:deep(p),
p {
margin: 12px 0;
}
:deep(h1),
:deep(h2),
:deep(h3),
h1,
h2,
h3 {
margin: 20px 0 12px;
font-weight: 600;
}
}
.article-empty {
text-align: center;
color: var(--el-text-color-secondary);
margin-top: 80px;
}
} }
} }
</style> </style>

View File

@ -1,6 +1,6 @@
import { defineStore, acceptHMRUpdate } from 'pinia' import { defineStore, acceptHMRUpdate } from 'pinia'
import { store } from '@/store' import { store } from '@/store'
import { getEnabledChannelList, type ImManagerChannelVO } from '@/api/im/manager/channel' import { getSimpleChannelList, type ImManagerChannelVO } from '@/api/im/manager/channel'
import { useConversationStore } from './conversationStore' import { useConversationStore } from './conversationStore'
import { ImConversationType } from '../../utils/constants' import { ImConversationType } from '../../utils/constants'
import { getCurrentUserId, imStorage, setQuietly, StorageKeys } from '../../utils/storage' import { getCurrentUserId, imStorage, setQuietly, StorageKeys } from '../../utils/storage'
@ -62,7 +62,7 @@ export const useChannelStore = defineStore('imChannelStore', {
return return
} }
try { try {
this.channels = (await getEnabledChannelList()) || [] this.channels = (await getSimpleChannelList()) || []
this.loaded = true this.loaded = true
this.syncConversationMetadata() this.syncConversationMetadata()
this.saveChannels() this.saveChannels()