fix(platform-admin): 中文化账户参数校验提示
This commit is contained in:
@@ -5,6 +5,17 @@ export const tokenStorageKey = 'token';
|
|||||||
|
|
||||||
export type PageResult<T> = { total: number; list: T[] };
|
export type PageResult<T> = { total: number; list: T[] };
|
||||||
|
|
||||||
|
// 将后端 SDK 的通用英文错误转换为面向用户的中文提示。
|
||||||
|
const API_ERROR_MESSAGES: Record<string, string> = {
|
||||||
|
'Invalid Argument': '请求参数不正确,请检查填写内容',
|
||||||
|
};
|
||||||
|
|
||||||
|
// 优先保留后端提供的具体中文信息,仅翻译已知的通用英文错误。
|
||||||
|
function localizeApiErrorMessage(message?: string) {
|
||||||
|
if (!message) return '请求失败';
|
||||||
|
return API_ERROR_MESSAGES[message.trim()] ?? message;
|
||||||
|
}
|
||||||
|
|
||||||
export async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
export async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
||||||
const token = localStorage.getItem(tokenStorageKey);
|
const token = localStorage.getItem(tokenStorageKey);
|
||||||
let response: Response;
|
let response: Response;
|
||||||
@@ -21,6 +32,8 @@ export async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
|||||||
throw new Error('无法连接服务器,请确认服务已启动');
|
throw new Error('无法连接服务器,请确认服务已启动');
|
||||||
}
|
}
|
||||||
const payload = (await response.json()) as { code?: number; message?: string; details?: T };
|
const payload = (await response.json()) as { code?: number; message?: string; details?: T };
|
||||||
if (!response.ok || payload.code !== 0) throw new Error(payload.message || '请求失败');
|
if (!response.ok || payload.code !== 0) {
|
||||||
|
throw new Error(localizeApiErrorMessage(payload.message));
|
||||||
|
}
|
||||||
return payload.details as T;
|
return payload.details as T;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -241,6 +241,7 @@
|
|||||||
<a-select v-else-if="field.type === 'identity' || field.type === 'identity-list'" v-model="actionForm[field.key]" :multiple="field.type === 'identity-list'" allow-search :loading="relationLoading[field.relation ?? '']" @search="(value: string) => searchRelation(field.relation, value)">
|
<a-select v-else-if="field.type === 'identity' || field.type === 'identity-list'" v-model="actionForm[field.key]" :multiple="field.type === 'identity-list'" allow-search :loading="relationLoading[field.relation ?? '']" @search="(value: string) => searchRelation(field.relation, value)">
|
||||||
<a-option v-for="option in relationOptions[field.relation ?? ''] ?? []" :key="String(option.identity)" :value="String(option.identity)">{{ optionLabel(option) }}</a-option>
|
<a-option v-for="option in relationOptions[field.relation ?? ''] ?? []" :key="String(option.identity)" :value="String(option.identity)">{{ optionLabel(option) }}</a-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
|
<a-input-password v-else-if="field.type === 'password'" v-model="actionForm[field.key]" />
|
||||||
<a-input v-else v-model="actionForm[field.key]" />
|
<a-input v-else v-model="actionForm[field.key]" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
@@ -310,6 +311,22 @@ const roleOptions = ref<PlatformRole[]>([]);
|
|||||||
const relationOptions = reactive<Record<string, Row[]>>({});
|
const relationOptions = reactive<Record<string, Row[]>>({});
|
||||||
const relationLoading = reactive<Record<string, boolean>>({});
|
const relationLoading = reactive<Record<string, boolean>>({});
|
||||||
const relationSearchTimers = new Map<string, ReturnType<typeof setTimeout>>();
|
const relationSearchTimers = new Map<string, ReturnType<typeof setTimeout>>();
|
||||||
|
// 账户密码规则与后端 AccountPasswordMinLength 保持一致。
|
||||||
|
const ACCOUNT_PASSWORD_MIN_LENGTH = 6;
|
||||||
|
const ACCOUNT_PASSWORD_LENGTH_MESSAGE = '密码长度不能少于6个字符';
|
||||||
|
|
||||||
|
// 检查当前表单中的密码字段,按 Unicode 字符数与后端规则对齐。
|
||||||
|
function hasInvalidPassword(
|
||||||
|
fields: ResourceField[],
|
||||||
|
values: Record<string, any>,
|
||||||
|
) {
|
||||||
|
return fields.some(
|
||||||
|
(field) =>
|
||||||
|
field.type === 'password' &&
|
||||||
|
!isMissingField(values[field.key]) &&
|
||||||
|
Array.from(String(values[field.key])).length < ACCOUNT_PASSWORD_MIN_LENGTH,
|
||||||
|
);
|
||||||
|
}
|
||||||
const managedOwnerIdentity = computed(() =>
|
const managedOwnerIdentity = computed(() =>
|
||||||
typeof route.query.owner_identity === 'string' ? route.query.owner_identity : '',
|
typeof route.query.owner_identity === 'string' ? route.query.owner_identity : '',
|
||||||
);
|
);
|
||||||
@@ -683,6 +700,13 @@ async function saveAccount() {
|
|||||||
Message.warning('请填写用户名和密码');
|
Message.warning('请填写用户名和密码');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
!accountEditingIdentity.value &&
|
||||||
|
Array.from(String(accountForm.password ?? '')).length < ACCOUNT_PASSWORD_MIN_LENGTH
|
||||||
|
) {
|
||||||
|
Message.warning(ACCOUNT_PASSWORD_LENGTH_MESSAGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
accountSaving.value = true;
|
accountSaving.value = true;
|
||||||
try {
|
try {
|
||||||
const payload: Record<string, unknown> = {
|
const payload: Record<string, unknown> = {
|
||||||
@@ -873,6 +897,10 @@ async function submitDetailAction() {
|
|||||||
Message.warning('请填写必填字段');
|
Message.warning('请填写必填字段');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (hasInvalidPassword(action.fields ?? [], actionForm)) {
|
||||||
|
Message.warning(ACCOUNT_PASSWORD_LENGTH_MESSAGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
await executeDetailAction(action);
|
await executeDetailAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -912,6 +940,10 @@ async function save() {
|
|||||||
Message.warning('请填写必填字段');
|
Message.warning('请填写必填字段');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (hasInvalidPassword(formFields.value, form)) {
|
||||||
|
Message.warning(ACCOUNT_PASSWORD_LENGTH_MESSAGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
saving.value = true;
|
saving.value = true;
|
||||||
try {
|
try {
|
||||||
const payload = buildResourcePayload(
|
const payload = buildResourcePayload(
|
||||||
|
|||||||
Reference in New Issue
Block a user