Files
im_manager/web/src/views/imFile/model.ts
T
Austin 0596599db9 feat: add tenant bound restriction for IM dashboard and management pages
1. extract isTenantBound utility from user store logic
2. add disabled state to tenant select components across all IM pages
3. update policy tenant options logic to hide global option for bound tenants
4. add backend scope validation for IM admin operations
2026-09-22 11:34:40 +08:00

160 lines
4.4 KiB
TypeScript

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 { isTenantBound, loadImTenantOptions } from '@/views/imTenantOptions';
const dict = useDictStore();
export const tenantOptions = ref<any[]>([]);
export class State {
public tenantId = 0;
public tenantName = '';
public id = 0;
public createdAt = '';
public updatedAt = '';
public userId = 0;
public status = 0;
public mimeType = '';
public size = 0;
public etag = '';
public location = '';
public purpose = '';
public linkCount = 0;
public firstTopic = '';
public firstMsgId = 0;
public firstLinkAt = '';
public links: any[] = [];
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),
disabled: isTenantBound(),
placeholder: '请选择商户',
},
},
{
field: 'fileId',
component: 'NInput',
label: '文件ID',
componentProps: { placeholder: '请输入文件ID' },
},
{
field: 'userId',
component: 'NInput',
label: '上传用户',
componentProps: { placeholder: '请输入上传用户ID' },
},
{
field: 'status',
component: 'NSelect',
label: '状态',
componentProps: {
clearable: true,
options: dict.getOption('ImFileStatusOptions'),
placeholder: '请选择状态',
},
},
// 用途暂不开放,后续需要时恢复
// {
// field: 'purpose',
// component: 'NSelect',
// label: '用途',
// componentProps: {
// clearable: true,
// options: dict.getOption('ImFilePurposeOptions'),
// placeholder: '请选择用途',
// },
// },
{
field: 'mimeType',
component: 'NInput',
label: 'MIME',
componentProps: { placeholder: '请输入MIME类型' },
},
{
field: 'topic',
component: 'NInput',
label: 'Topic',
componentProps: { placeholder: '请输入关联Topic' },
},
{
field: 'updatedAt',
component: 'NDatePicker',
label: '更新时间',
componentProps: {
type: 'datetimerange',
clearable: true,
shortcuts: defRangeShortcuts(),
},
},
]);
export const columns = [
{ title: '文件ID', key: 'id', align: 'left', width: 180 },
{
title: '状态',
key: 'status',
align: 'left',
width: 110,
render(row: State) {
return dict.getLabel('ImFileStatusOptions', row.status);
},
},
// 用途暂不开放,后续需要时恢复
// {
// title: '用途',
// key: 'purpose',
// align: 'left',
// width: 120,
// render(row: State) {
// return dict.getLabel('ImFilePurposeOptions', row.purpose) || row.purpose;
// },
// },
{ title: '上传用户', key: 'userId', align: 'left', width: 120 },
{ title: 'MIME', key: 'mimeType', align: 'left', width: 180 },
{ title: '大小', key: 'size', align: 'left', width: 110 },
{ title: '引用数', key: 'linkCount', align: 'left', width: 90 },
{ title: '首个Topic', key: 'firstTopic', align: 'left', width: 180 },
{ title: '首个消息', key: 'firstMsgId', align: 'left', width: 110 },
{ title: '位置', key: 'location', align: 'left', width: 260 },
{ title: '创建时间', key: 'createdAt', align: 'left', width: 180 },
{ title: '更新时间', key: 'updatedAt', align: 'left', width: 180 },
];
export const linkColumns = [
{ title: 'ID', key: 'id', align: 'left', width: 90 },
{ title: '消息ID', key: 'msgId', align: 'left', width: 100 },
{ title: 'Topic', key: 'topic', align: 'left', width: 180 },
{ title: '用户ID', key: 'userId', align: 'left', width: 120 },
{ title: '创建时间', key: 'createdAt', align: 'left', width: 180 },
];
export function loadOptions() {
dict.loadOptions(['ImFileStatusOptions', 'ImFilePurposeOptions']);
}
export async function loadTenantOptions() {
return loadImTenantOptions(tenantOptions, { page: 1, perPage: 20 });
}