feat: add tenant-aware IM management console

This commit is contained in:
richjohnrambo
2026-08-19 00:31:09 +08:00
parent 642b7ec5da
commit 89ba6bcff8
126 changed files with 11941 additions and 339 deletions
+215
View File
@@ -0,0 +1,215 @@
import { computed, ref } from 'vue';
import { cloneDeep } from 'lodash-es';
import { FormSchema } from '@/components/Form';
import { defRangeShortcuts } from '@/utils/dateUtil';
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; // 租户ID
public tenantName = ''; // 租户名称
public userId = ''; // 用户ID
public username = ''; // 登录账号
public phone = ''; // 手机号
public nickname = ''; // 昵称
public publicAccount = ''; // 公开账号
public gender = ''; // 性别
public region = ''; // 地区
public state = 0; // 账号状态
public authVersion = 0; // 认证版本
public passwordUpdatedAt = ''; // 密码更新时间
public authNames = ''; // 登录标识
public credentials = ''; // 凭证
public lastSeen = ''; // 最后在线时间
public userAgent = ''; // 客户端
public createdAt = ''; // 创建时间
public updatedAt = ''; // 修改时间
public signature = ''; // 个性签名
public avatarFileId = ''; // 头像文件ID
public birthDate = ''; // 出生日期
public profileJson = ''; // Tinode Public资料
public trustedJson = ''; // Tinode Trusted资料
public accessJson = ''; // 访问权限
public profileVersion = 0; // 资料版本
constructor(state?: Partial<State>) {
if (state) {
Object.assign(this, state);
}
}
}
export function newState(state: State | Record<string, any> | null): State {
if (state !== null) {
if (state instanceof State) {
return cloneDeep(state);
}
return new State(state);
}
return new State();
}
// 表格搜索表单
export const schemas = ref<FormSchema[]>([
{
field: 'tenantId',
component: 'NSelect',
label: '租户',
componentProps: {
clearable: false,
options: computed(() => tenantOptions.value),
placeholder: '请选择租户',
},
},
{
field: 'userId',
component: 'NInput',
label: '用户ID',
componentProps: {
placeholder: '请输入用户ID',
},
},
{
field: 'nickname',
component: 'NInput',
label: '昵称',
componentProps: {
placeholder: '请输入昵称',
},
},
{
field: 'authName',
component: 'NInput',
label: '登录标识',
componentProps: {
placeholder: '请输入登录名/手机号/邮箱',
},
},
{
field: 'state',
component: 'NSelect',
label: '状态',
componentProps: {
clearable: true,
options: computed(() => dict.getOptions('ImUserStateOptions')),
placeholder: '请选择状态',
},
},
{
field: 'createdAt',
component: 'NDatePicker',
label: '创建时间',
componentProps: {
type: 'datetimerange',
clearable: true,
shortcuts: defRangeShortcuts(),
},
},
{
field: 'lastSeen',
component: 'NDatePicker',
label: '最后在线',
componentProps: {
type: 'datetimerange',
clearable: true,
shortcuts: defRangeShortcuts(),
},
},
]);
// 表格列
export const columns = [
{
title: '用户ID',
key: 'userId',
align: 'left',
width: 120,
},
{
title: '昵称',
key: 'nickname',
align: 'left',
width: 160,
},
{
title: '登录账号',
key: 'username',
align: 'left',
width: 180,
},
{
title: '手机号',
key: 'phone',
align: 'left',
width: 180,
},
{
title: '公开账号',
key: 'publicAccount',
align: 'left',
width: 150,
},
{
title: '状态',
key: 'state',
align: 'left',
width: 110,
render(row: State) {
return dict.getLabel('ImUserStateOptions', row.state);
},
},
{
title: '登录标识',
key: 'authNames',
align: 'left',
width: 240,
},
{
title: '凭证',
key: 'credentials',
align: 'left',
width: 220,
},
{
title: '最后在线',
key: 'lastSeen',
align: 'left',
width: 180,
},
{
title: '客户端',
key: 'userAgent',
align: 'left',
width: 240,
},
{
title: '创建时间',
key: 'createdAt',
align: 'left',
width: 180,
},
{
title: '修改时间',
key: 'updatedAt',
align: 'left',
width: 180,
},
];
// 加载字典数据选项
export function loadOptions() {
dict.loadOptions(['ImUserStateOptions']);
}
export async function loadTenantOptions() {
const res = await TenantList({ page: 1, perPage: 20 });
tenantOptions.value = (res?.list || []).map((item) => ({
label: `${item.name}(${item.code})`,
value: item.id,
}));
return tenantOptions.value;
}