diff --git a/packages/base/src/page/Transit/index.test.tsx b/packages/base/src/page/Transit/index.test.tsx
index e405dc92eb..c74b400dbe 100644
--- a/packages/base/src/page/Transit/index.test.tsx
+++ b/packages/base/src/page/Transit/index.test.tsx
@@ -38,6 +38,21 @@ describe('Transit Component', () => {
console.error = originOutputError;
});
+ it('should wait until user info is fetched before resolving project', () => {
+ mockUseCurrentUser({
+ isUserInfoFetched: false,
+ bindProjects: []
+ });
+ mockExtractQueries.mockReturnValue({
+ from: 'cloudbeaver',
+ to: 'create_workflow',
+ project_name: 'default',
+ compression_data: 'data'
+ });
+ superRender();
+ expect(mockNavigate).not.toHaveBeenCalled();
+ });
+
it('should navigate to / when required parameters are missing', () => {
mockExtractQueries.mockReturnValue({
from: 'cloudbeaver'
diff --git a/packages/base/src/page/Transit/index.tsx b/packages/base/src/page/Transit/index.tsx
index 2b9e70bcb8..4b280d0b35 100644
--- a/packages/base/src/page/Transit/index.tsx
+++ b/packages/base/src/page/Transit/index.tsx
@@ -42,7 +42,7 @@ const TARGET_DATA = (
const Transit: React.FC = () => {
const navigate = useTypedNavigate();
- const { bindProjects } = useCurrentUser();
+ const { bindProjects, isUserInfoFetched } = useCurrentUser();
const extractQueries = useTypedQuery();
useEffect(() => {
const searchParams = extractQueries(ROUTE_PATHS.BASE.TRANSIT.index);
@@ -51,6 +51,9 @@ const Transit: React.FC = () => {
const compressionData = searchParams?.compression_data;
const projectName = searchParams?.project_name;
const workflowId = searchParams?.workflow_id;
+ if (!isUserInfoFetched) {
+ return;
+ }
if (!from || !to) {
console.error(`Missing required parameters!\n from=${from}\n to=${to}\n`);
navigate(ROUTE_PATHS.BASE.HOME, {
@@ -85,9 +88,15 @@ const Transit: React.FC = () => {
return;
}
if (compressionData) {
- navigate(`${path}?from=${from}&compression_data=${compressionData}`, {
- replace: true
- });
+ // useTypedQuery / URLSearchParams 已解码;再拼 URL 必须重新编码,否则 + 变空格破坏预填
+ navigate(
+ `${path}?from=${encodeURIComponent(
+ from
+ )}&compression_data=${encodeURIComponent(compressionData)}`,
+ {
+ replace: true
+ }
+ );
} else {
navigate(path, {
replace: true
@@ -99,7 +108,7 @@ const Transit: React.FC = () => {
replace: true
});
}
- }, [bindProjects, navigate, extractQueries]);
+ }, [bindProjects, isUserInfoFetched, navigate, extractQueries]);
return ;
};
export default Transit;
diff --git a/packages/dms-kit/src/utils/Common.ts b/packages/dms-kit/src/utils/Common.ts
index f5e737b7c2..51592817ae 100644
--- a/packages/dms-kit/src/utils/Common.ts
+++ b/packages/dms-kit/src/utils/Common.ts
@@ -84,26 +84,64 @@ export type GetErrorMessageParams =
| string
| AxiosResponse
| ISwaggerLoseRequireParamsRes;
+
+const BUSINESS_ERROR_I18N_KEYS: Record = {
+ 'privilege_apply.no_assignee': 'privilegeApply.create.errors.noAssignee',
+ 'privilege_apply.account_mismatch':
+ 'privilegeApply.create.errors.accountMismatch',
+ 'privilege_apply.invalid_argument':
+ 'privilegeApply.create.errors.invalidArgument',
+ 'privilege_apply.duplicate_open':
+ 'privilegeApply.create.errors.duplicateOpen',
+ 'privilege_apply.invalid_account_name':
+ 'privilegeApply.create.errors.invalidAccountName',
+ 'privilege_apply.forbidden': 'privilegeApply.detail.errors.forbidden'
+};
+
+const BUSINESS_ERROR_FALLBACK_ZH: Record = {
+ 'privilege_apply.no_assignee': '请先配置提权审批人后再提交(未落单)',
+ 'privilege_apply.account_mismatch':
+ '当前连库账号已变更,请回到工作台刷新后重新申请',
+ 'privilege_apply.invalid_argument': '请完善必填项后重试',
+ 'privilege_apply.duplicate_open':
+ '该数据源已有进行中的提权申请,请等待处理完成后再提交',
+ 'privilege_apply.invalid_account_name':
+ '新账号名不合法:仅支持字母开头,字母、数字、下划线、连字符与点,最长 32 字符',
+ 'privilege_apply.forbidden': '没有账号管理权限,无法审批该提权申请'
+};
+
+const mapBusinessErrorMessage = (message: string): string => {
+ const i18nKey = BUSINESS_ERROR_I18N_KEYS[message];
+ if (!i18nKey) {
+ return message;
+ }
+ const translated = i18n.t(i18nKey);
+ if (translated && translated !== i18nKey) {
+ return translated;
+ }
+ return BUSINESS_ERROR_FALLBACK_ZH[message] || message;
+};
+
export const getErrorMessage = (error: GetErrorMessageParams): string => {
if (typeof error === 'string') {
- return error;
+ return mapBusinessErrorMessage(error);
}
if (error instanceof Error || 'code' in error) {
- return error.message;
+ return mapBusinessErrorMessage(error.message);
}
if (error.data) {
if (typeof error.data?.message === 'string') {
- return error.data.message;
+ return mapBusinessErrorMessage(error.data.message);
}
if (typeof error.data?.msg === 'string') {
- return error.data.msg;
+ return mapBusinessErrorMessage(error.data.msg);
}
if (typeof error.data === 'string') {
- return error.data;
+ return mapBusinessErrorMessage(error.data);
}
return JSON.stringify(error.data);