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

im
YunaiV 2026-05-19 17:18:48 +08:00
parent b6d123ac72
commit bfd407d75b
6 changed files with 160 additions and 17 deletions

View File

@ -51,8 +51,8 @@ export const getAllUser = () => {
* @param id
* @returns
*/
export const getDeptUser = (id: number): Promise<UserVO[]> => {
return request.get({ url: '/system/user/simple-list?id=' + id })
export const getDeptUser = (deptId: number): Promise<UserVO[]> => {
return request.get({ url: '/system/user/simple-list?deptId=' + deptId })
}
// 查询用户详情

View File

@ -29,21 +29,9 @@ import {
MESSAGE_PRIVATE_READ_ENABLED
} from '../../utils/config'
import { useUserStore } from '@/store/modules/user'
import { useChannelStore } from '../store/channelStore'
import { buildChannelConversationStub } from '../../utils/channel'
import type { Message } from '../types'
/** 构建频道会话描述;优先从 channelStore 取真实 name / avatar缺失时退化为占位 */
// TODO @AI这个可以抽到 channel.ts 搞个工具类么?类似 user.ts 获取名字这种。
export const buildChannelConversationStub = (channelId: number) => {
const channel = useChannelStore().getChannel(channelId)
return {
type: ImConversationType.CHANNEL,
targetId: channelId,
name: channel?.name || `频道 ${channelId}`,
avatar: channel?.avatar || ''
}
}
/**
* 线
*

View File

@ -30,7 +30,7 @@ import {
import { readPrivateMessages as apiReadPrivateMessages } from '@/api/im/message/private'
import { readGroupMessages as apiReadGroupMessages } from '@/api/im/message/group'
import type { ImChannelMessageRespVO } from '@/api/im/message/channel'
import { buildChannelConversationStub } from '../composables/useMessagePuller'
import { buildChannelConversationStub } from '../../utils/channel'
import type {
WebSocketFrame,
ImPrivateMessageDTO,

View File

@ -0,0 +1,138 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="720">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
v-loading="formLoading"
>
<el-form-item label="所属频道" prop="channelId">
<!-- TODO @AI使用 channelselect 组件 -->
<el-select v-model="formData.channelId" placeholder="请选择频道" class="!w-full">
<el-option v-for="c in props.channelList" :key="c.id" :label="c.name" :value="c.id" />
</el-select>
</el-form-item>
<el-form-item label="标题" prop="title">
<el-input v-model="formData.title" placeholder="图文标题" maxlength="128" show-word-limit />
</el-form-item>
<el-form-item label="封面图" prop="coverUrl">
<el-input v-model="formData.coverUrl" placeholder="封面图 URL" />
</el-form-item>
<el-form-item label="摘要" prop="summary">
<el-input
v-model="formData.summary"
placeholder="一句话摘要"
type="textarea"
:rows="2"
maxlength="255"
show-word-limit
/>
</el-form-item>
<!-- TODO @AI需要增加 type -->
<el-form-item label="跳转链接" prop="url">
<el-input
v-model="formData.url"
placeholder="为空走站内详情页渲染 content非空则跳此链接"
/>
</el-form-item>
<el-form-item label="正文" prop="content">
<el-input
v-model="formData.content"
placeholder="富文本 HTML"
type="textarea"
:rows="8"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</template>
<script lang="ts" setup>
// TODO @AI system user form
import * as MaterialApi from '@/api/im/manager/channel/material'
import type { ImManagerChannelVO } from '@/api/im/manager/channel'
defineOptions({ name: 'ImChannelMaterialForm' })
const props = defineProps<{ channelList: ImManagerChannelVO[] }>()
const { t } = useI18n()
const message = useMessage()
const dialogVisible = ref(false)
const dialogTitle = ref('')
const formLoading = ref(false)
const formType = ref('')
const formData = ref({
id: undefined as number | undefined,
channelId: undefined as number | undefined,
// TODO @AI type 1 2
type: 125, // MATERIAL
title: '',
coverUrl: '',
summary: '',
content: '',
url: ''
})
const formRules = reactive({
channelId: [{ required: true, message: '所属频道不能为空', trigger: 'change' }],
title: [{ required: true, message: '标题不能为空', trigger: 'blur' }]
})
const formRef = ref()
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
if (id) {
formLoading.value = true
try {
formData.value = await MaterialApi.getManagerChannelMaterial(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open })
const emit = defineEmits(['success'])
const submitForm = async () => {
await formRef.value.validate()
formLoading.value = true
try {
const data = formData.value as MaterialApi.ImManagerChannelMaterialVO
if (formType.value === 'create') {
await MaterialApi.createManagerChannelMaterial(data)
message.success(t('common.createSuccess'))
} else {
await MaterialApi.updateManagerChannelMaterial(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
emit('success')
} finally {
formLoading.value = false
}
}
const resetForm = () => {
formData.value = {
id: undefined,
channelId: undefined,
type: 125,
title: '',
coverUrl: '',
summary: '',
content: '',
url: ''
}
formRef.value?.resetFields()
}
</script>

View File

@ -0,0 +1,18 @@
import { useChannelStore } from '../home/store/channelStore'
import { ImConversationType } from './constants'
/**
* type / targetId / name / avatar
*
* channelStore / 退 N
* utils/channel.ts useMessagePuller / websocketStore utils/user.ts
*/
export const buildChannelConversationStub = (channelId: number) => {
const channel = useChannelStore().getChannel(channelId)
return {
type: ImConversationType.CHANNEL,
targetId: channelId,
name: channel?.name || `频道 ${channelId}`,
avatar: channel?.avatar || ''
}
}

View File

@ -307,7 +307,6 @@ export interface FaceMessage extends Quotable {
/** 合并转发的单条内嵌消息快照(对齐后端 MergeMessage.Item */
export interface MergeMessageItem {
// TODO @AI是不是把 messageId 改成 id和原本的更统一一点
/** 原消息编号;仅做溯源标识 */
messageId: number
/** 发送人编号 */