feat: add IM admin P1 operations

This commit is contained in:
richjohnrambo
2026-08-21 17:25:19 +08:00
parent 77b19a8157
commit c89e35d0e0
35 changed files with 2587 additions and 53 deletions
+81
View File
@@ -0,0 +1,81 @@
<template>
<div>
<div class="n-layout-page-header">
<n-card :bordered="false" title="IM任务看板" />
</div>
<n-card :bordered="false" class="proCard">
<BasicForm
ref="searchFormRef"
@register="register"
@submit="reloadTable"
@reset="handleReset"
@keyup.enter="reloadTable"
/>
<BasicTable
ref="actionRef"
:columns="columns"
:request="loadDataTable"
:row-key="(row) => row.tenantId"
:scroll-x="scrollX"
:resizeHeightOffset="-10000"
/>
</n-card>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted, ref } from 'vue';
import { useMessage } from 'naive-ui';
import { BasicForm, useForm } from '@/components/Form/index';
import { BasicTable } from '@/components/Table';
import { useUserStore } from '@/store/modules/user';
import { List } from '@/api/imTaskDashboard';
import { columns, loadOptions, loadTenantOptions, schemas, tenantOptions } from './model';
import { adaTableScrollX } from '@/utils/hotgo';
const message = useMessage();
const userStore = useUserStore();
const isPlatformAdmin = computed(() => userStore.isCompanyDept);
const actionRef = ref();
const searchFormRef = ref<any>({});
const tenantSchema = schemas.value.find((item) => item.field === 'tenantId');
if (tenantSchema) {
tenantSchema.ifShow = () => isPlatformAdmin.value;
}
const scrollX = computed(() => adaTableScrollX(columns, 0));
const [register, { setFieldsValue }] = useForm({
gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' },
labelWidth: 90,
schemas,
});
const loadDataTable = async (res) => {
const params = { ...searchFormRef.value?.formModel, ...res };
return await List(params);
};
function reloadTable() {
actionRef.value?.reload();
}
async function handleReset() {
await setFieldsValue({});
reloadTable();
}
onMounted(async () => {
loadOptions();
if (isPlatformAdmin.value) {
await loadTenantOptions();
if (tenantOptions.value.length === 0) {
message.warning('暂无可用租户');
}
}
reloadTable();
});
</script>
<style lang="less" scoped></style>
+88
View File
@@ -0,0 +1,88 @@
import { computed, ref } from 'vue';
import { FormSchema } from '@/components/Form';
import { useDictStore } from '@/store/modules/dict';
import { List as TenantList } from '@/api/imTenant';
const dict = useDictStore();
export const tenantOptions = ref<any[]>([]);
export class State {
public tenantId = 0;
public tenantName = '';
public tenantCode = '';
public tenantState = '';
public dbStatus = '';
public status = '';
public outboxPendingCount = 0;
public outboxFailedCount = 0;
public groupOutboxPending = 0;
public groupOutboxFailed = 0;
public orphanFileCount = 0;
public deletedFileCount = 0;
public lastOutboxCreatedAt = '';
public lastGroupEventAt = '';
public lastFileUpdatedAt = '';
public recommendedNextAction = '';
}
export const schemas = ref<FormSchema[]>([
{
field: 'tenantId',
component: 'NSelect',
label: '租户',
componentProps: {
clearable: true,
options: computed(() => tenantOptions.value),
placeholder: '请选择租户',
},
},
{
field: 'status',
component: 'NSelect',
label: '状态',
componentProps: {
clearable: true,
options: computed(() => dict.getOptions('ImTaskDashboardStatusOptions')),
placeholder: '请选择状态',
},
},
]);
export const columns = [
{ title: '租户', key: 'tenantName', align: 'left', width: 160 },
{ title: '企业码', key: 'tenantCode', align: 'left', width: 120 },
{
title: '状态',
key: 'status',
align: 'left',
width: 110,
render(row: State) {
return dict.getLabel('ImTaskDashboardStatusOptions', row.status);
},
},
{ title: 'DB', key: 'dbStatus', align: 'left', width: 90 },
{ title: '业务待投递', key: 'outboxPendingCount', align: 'left', width: 110 },
{ title: '业务失败', key: 'outboxFailedCount', align: 'left', width: 100 },
{ title: '群待投递', key: 'groupOutboxPending', align: 'left', width: 100 },
{ title: '群失败', key: 'groupOutboxFailed', align: 'left', width: 90 },
{ title: '孤儿文件', key: 'orphanFileCount', align: 'left', width: 100 },
{ title: '待物理清理', key: 'deletedFileCount', align: 'left', width: 110 },
{ title: '建议动作', key: 'recommendedNextAction', align: 'left', width: 220 },
{ title: '最新业务事件', key: 'lastOutboxCreatedAt', align: 'left', width: 180 },
{ title: '最新群事件', key: 'lastGroupEventAt', align: 'left', width: 180 },
{ title: '最新文件更新', key: 'lastFileUpdatedAt', align: 'left', width: 180 },
];
export function loadOptions() {
dict.loadOptions(['ImTaskDashboardStatusOptions']);
}
export async function loadTenantOptions() {
const res = await TenantList({ page: 1, perPage: 100 });
tenantOptions.value = (res?.list || []).map((item) => ({
label: `${item.name}(${item.code})`,
value: item.id,
}));
return tenantOptions.value;
}