125 lines
4.4 KiB
TypeScript
125 lines
4.4 KiB
TypeScript
import { Ref } from 'vue';
|
|
import { List as TenantList } from '@/api/imTenant';
|
|
import { useUserStore } from '@/store/modules/user';
|
|
import type { FormSchema } from '@/components/Form';
|
|
|
|
export interface ImTenantOption {
|
|
label: string;
|
|
value: number;
|
|
code?: string;
|
|
name?: string;
|
|
}
|
|
|
|
export function formatImTenantLabel(item: any): string {
|
|
const code = item?.code || item?.tenantCode || '';
|
|
const name = item?.name || item?.tenantName || '当前商户';
|
|
return code ? `${name} (${code})` : name;
|
|
}
|
|
|
|
export function getDefaultTenantValue(options: any[]) {
|
|
const defaultTenant = options.find(
|
|
(item) => item.code === 'default' || String(item.label || '').includes('(default)')
|
|
);
|
|
return defaultTenant?.value || options.find((item) => Number(item.value) > 0)?.value || 0;
|
|
}
|
|
|
|
export async function loadImTenantOptions(
|
|
target: Ref<ImTenantOption[]>,
|
|
params: Record<string, any> = { page: 1, perPage: 100 }
|
|
) {
|
|
const boundTenantId = getBoundTenantId();
|
|
|
|
// 登录用户已绑定商户租户:仅返回自己商户选项(与后端 resolveImAdminScope 强制范围一致)
|
|
if (boundTenantId > 0) {
|
|
const info = readCurrentUserInfo();
|
|
try {
|
|
const res = await TenantList(params);
|
|
target.value = (res?.list || []).map(toTenantOption);
|
|
} catch {
|
|
const tenant = { id: boundTenantId, name: info?.tenantName, code: info?.tenantCode };
|
|
target.value = [toTenantOption(tenant)];
|
|
}
|
|
return target.value;
|
|
}
|
|
|
|
// 平台账号:加载全部商户;失败时保留旧选项,避免页面初始化被单个请求失败打断
|
|
try {
|
|
const res = await TenantList(params);
|
|
target.value = (res?.list || []).map(toTenantOption);
|
|
} catch (err) {
|
|
console.error('loadImTenantOptions failed:', err);
|
|
}
|
|
return target.value;
|
|
}
|
|
|
|
// 登录用户绑定的商户租户ID(按绑定租户判定,与后端 resolveImAdminScope 的范围逻辑一致)
|
|
export function getBoundTenantId(): number {
|
|
const userInfo = readCurrentUserInfo();
|
|
return Number(userInfo?.tenantId || userInfo?.tenantID || 0);
|
|
}
|
|
|
|
// 登录用户是否为商户绑定账号(true=下拉框只显示并锁定自己商户)
|
|
export function isTenantBound(): boolean {
|
|
return getBoundTenantId() > 0;
|
|
}
|
|
|
|
// 商户绑定账号:锁定搜索表单中的商户下拉项(仅一项、不可清除、不可更改)
|
|
export function lockTenantSchema(schema?: FormSchema) {
|
|
if (!schema || !isTenantBound()) return;
|
|
const props: any = (schema.componentProps = schema.componentProps || {});
|
|
props.disabled = true;
|
|
props.clearable = false;
|
|
}
|
|
|
|
/**
|
|
* 统一搜索重置回调:BasicForm 的 resetFields 会把包括 tenantId 在内的全部搜索字段清空,
|
|
* 随后的自动查询因缺商户条件命中前端空列表 guard(或被后端以「请选择IM租户」拒绝)。
|
|
* 此工厂返回的回调在 reset 之后把商户下拉回填为当前选项列表的第一项
|
|
* (商户绑定账号=自己商户;平台账号=全部商户列表第一项),再触发查询——
|
|
* 与各页面初始加载(onMounted 默认选中第一项)的行为保持一致。
|
|
*
|
|
* setFieldsValueFn 必须传页面 useForm() 解构出的 setFieldsValue(与 onMounted 同一通道),
|
|
* 不要用模板 ref 上的实例方法(可靠性不足)。
|
|
*/
|
|
export function imSearchReset(
|
|
setFieldsValueFn: (values: Record<string, any>) => Promise<void> | void,
|
|
tenantOptions: Ref<ImTenantOption[]>,
|
|
reload: () => unknown,
|
|
) {
|
|
return async () => {
|
|
const first = Number(tenantOptions.value[0]?.value || 0);
|
|
if (first > 0) {
|
|
await setFieldsValueFn({ tenantId: first });
|
|
}
|
|
await reload();
|
|
};
|
|
}
|
|
|
|
function toTenantOption(item: any): ImTenantOption {
|
|
return {
|
|
label: formatImTenantLabel(item),
|
|
value: Number(item.id),
|
|
code: item.code,
|
|
name: item.name,
|
|
};
|
|
}
|
|
|
|
function readCurrentUserInfo() {
|
|
const userStore = useUserStore();
|
|
return { ...readTokenUserInfo(userStore.getToken), ...(userStore.getUserInfo as any) };
|
|
}
|
|
|
|
function readTokenUserInfo(token: string) {
|
|
try {
|
|
const payload = token.split('.')[1];
|
|
if (!payload) return {};
|
|
const normalized = payload.replace(/-/g, '+').replace(/_/g, '/');
|
|
const padded = normalized.padEnd(Math.ceil(normalized.length / 4) * 4, '=');
|
|
const binary = window.atob(padded);
|
|
const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
|
|
return JSON.parse(new TextDecoder().decode(bytes));
|
|
} catch {
|
|
return {};
|
|
}
|
|
}
|