diff --git a/src/config/i18n/locales/en.ts b/src/config/i18n/locales/en.ts
index 5b5dd19c1..21aa68a9e 100644
--- a/src/config/i18n/locales/en.ts
+++ b/src/config/i18n/locales/en.ts
@@ -488,6 +488,9 @@ export default {
defaultValue: 'Default',
enabled: 'Enabled',
nameRequired: 'Command name is required',
+ commandTypeRequired: 'Please select command type',
+ callTypeRequired: 'Please select call type',
+ timeoutRequired: 'Please enter timeout',
codeRequired: 'Command code is required',
paramRequired: 'Command param name, code, direction, and type are required.',
paramNamePattern:
@@ -554,6 +557,8 @@ export default {
type: 'Type',
enabled: 'Enabled',
nameRequired: 'Event name is required',
+ eventTypeRequired: 'Please select event type',
+ eventLevelRequired: 'Please select event level',
codeRequired: 'Event code is required',
paramRequired: 'Event param name, code, and type are required.',
paramNamePattern:
@@ -971,7 +976,9 @@ export default {
userNamePlaceholder: 'Enter user name',
nickNamePlaceholder: 'Enter nickname',
phonePlaceholder: 'Enter phone number',
+ phoneFormat: 'Please enter a valid 11-digit phone number',
emailPlaceholder: 'Enter email',
+ emailFormat: 'Please enter a valid email format',
confirmDelete: 'Are you sure to delete this user? This action cannot be undone!',
assignSaved: 'Role assignment saved',
empty: 'No user data!',
@@ -1067,6 +1074,8 @@ export default {
titleZhPlaceholder: 'Enter Chinese display title',
titleEnPlaceholder: 'Enter English display title',
parentMenuIdPlaceholder: 'Optional, default top-level',
+ menuTypeRequired: 'Please select menu type',
+ menuLevelRequired: 'Please select menu level',
confirmDelete: 'Are you sure to delete this menu? This action cannot be undone!',
empty: 'No menu data!',
},
@@ -1129,6 +1138,7 @@ export default {
modelRequired: 'Model is required',
providerRequired: 'Provider is required',
maxTokensRequired: 'Max tokens is required',
+ temperatureRange: 'Temperature must be between 0.0 and 2.0',
nameRequired: 'Name is required',
baseUrlRequired: 'Base URL is required',
confirmDeleteModel: 'Delete model {name}?',
diff --git a/src/config/i18n/locales/zh.ts b/src/config/i18n/locales/zh.ts
index 1daec7e46..c652783b7 100644
--- a/src/config/i18n/locales/zh.ts
+++ b/src/config/i18n/locales/zh.ts
@@ -487,6 +487,9 @@ export default {
defaultValue: '默认值',
enabled: '启用',
nameRequired: '指令名称不能为空',
+ commandTypeRequired: '请选择指令类型',
+ callTypeRequired: '请选择调用类型',
+ timeoutRequired: '请输入超时时间',
codeRequired: '指令标识不能为空',
paramRequired: '指令参数名称、标识、方向和类型不能为空。',
paramNamePattern: '指令参数名称需2-32位,以字母、数字或中文开头,仅支持字母、数字、中文及-_#@/.|。',
@@ -552,6 +555,8 @@ export default {
type: '类型',
enabled: '启用',
nameRequired: '事件名称不能为空',
+ eventTypeRequired: '请选择事件类型',
+ eventLevelRequired: '请选择事件等级',
codeRequired: '事件标识不能为空',
paramRequired: '事件参数名称、标识和类型不能为空。',
paramNamePattern: '事件参数名称需2-32位,以字母、数字或中文开头,仅支持字母、数字、中文及-_#@/.|。',
@@ -968,7 +973,9 @@ export default {
userNamePlaceholder: '请输入用户名',
nickNamePlaceholder: '请输入昵称',
phonePlaceholder: '请输入手机号',
+ phoneFormat: '请输入正确的11位手机号',
emailPlaceholder: '请输入邮箱',
+ emailFormat: '请输入正确的邮箱格式',
confirmDelete: '是否确定删除该用户? 该操作不可恢复!',
assignSaved: '角色分配已保存',
empty: '暂无用户数据!',
@@ -1064,6 +1071,8 @@ export default {
titleZhPlaceholder: '请输入中文显示名称',
titleEnPlaceholder: '请输入英文显示名称',
parentMenuIdPlaceholder: '选填, 默认顶级菜单',
+ menuTypeRequired: '请选择菜单类型',
+ menuLevelRequired: '请选择菜单层级',
confirmDelete: '是否确定删除该菜单? 该操作不可恢复!',
empty: '暂无菜单数据!',
},
@@ -1126,6 +1135,7 @@ export default {
modelRequired: '模型不能为空',
providerRequired: '供应商不能为空',
maxTokensRequired: '最大词元不能为空',
+ temperatureRange: '温度值需在 0.0~2.0 之间',
nameRequired: '名称不能为空',
baseUrlRequired: 'Base URL 不能为空',
confirmDeleteModel: '是否删除模型 {name}?',
diff --git a/src/utils/formRuleUtil.ts b/src/utils/formRuleUtil.ts
index b9eccae68..dece214ff 100644
--- a/src/utils/formRuleUtil.ts
+++ b/src/utils/formRuleUtil.ts
@@ -17,7 +17,14 @@
import type { FormItemRule } from 'element-plus';
import type { ComposerTranslation } from 'vue-i18n';
-export const NAME_PATTERN = /^[A-Za-z0-9\u4e00-\u9fa5][A-Za-z0-9\u4e00-\u9fa5-_]*$/;
+/** Backend Pattern: ^[A-Za-z0-9\u4e00-\u9fa5][A-Za-z0-9\u4e00-\u9fa5-_#@/.|]{1,31}$ */
+export const NAME_PATTERN = /^[A-Za-z0-9\u4e00-\u9fa5][A-Za-z0-9\u4e00-\u9fa5\-_#@/.|]{1,31}$/;
+/** Backend Pattern: ^[A-Za-z0-9][A-Za-z0-9-_#@/.|]{1,31}$ (no Chinese) */
+export const AUTH_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9\-_#@/.|]{1,31}$/;
+/** Backend Pattern: ^1([3-9])\d{9}$ */
+export const PHONE_PATTERN = /^1([3-9])\d{9}$/;
+/** Backend Pattern: ^[A-Za-z0-9_.-]+@[A-Za-z0-9]+\.[A-Za-z0-9]+$ */
+export const EMAIL_PATTERN = /^[A-Za-z0-9_.\-]+@[A-Za-z0-9]+\.[A-Za-z0-9]+$/;
export const DECIMAL_PATTERN = /^-?(([0-9]*(\.[0-9]{1,3})$)|([0-9]+$))/;
export function nameRules(t: ComposerTranslation, entityName: string): FormItemRule[] {
diff --git a/src/views/settings/agentic/edit/ModelConfigEditForm.vue b/src/views/settings/agentic/edit/ModelConfigEditForm.vue
index 5dddced87..432db5b1b 100644
--- a/src/views/settings/agentic/edit/ModelConfigEditForm.vue
+++ b/src/views/settings/agentic/edit/ModelConfigEditForm.vue
@@ -50,7 +50,7 @@
{{ $t('agentic.capReasoning') }}
-
+
@@ -125,6 +125,15 @@
model: [{ required: true, message: t('settings.agentic.modelRequired'), trigger: 'blur' }],
providerId: [{ required: true, message: t('settings.agentic.providerRequired'), trigger: 'change' }],
maxTokens: [{ required: true, message: t('settings.agentic.maxTokensRequired'), trigger: 'blur' }],
+ temperature: [
+ {
+ type: 'number',
+ min: 0,
+ max: 2,
+ message: t('settings.agentic.temperatureRange'),
+ trigger: 'change',
+ },
+ ],
}));
const show = () => {
diff --git a/src/views/settings/command/edit/CommandEditForm.vue b/src/views/settings/command/edit/CommandEditForm.vue
index da7617e28..6c30674df 100644
--- a/src/views/settings/command/edit/CommandEditForm.vue
+++ b/src/views/settings/command/edit/CommandEditForm.vue
@@ -157,6 +157,7 @@
POINT_TYPE_OPTIONS,
} from '@/config/constant/enums';
import type { CommandForm, CommandParamRecord, CommandRecord } from '@/config/types';
+ import { NAME_PATTERN } from '@/utils/formRuleUtil';
import { failMessage } from '@/utils/notificationUtil';
import {
callTypeValue,
@@ -210,10 +211,15 @@
paramLoading: false,
});
- const PARAM_NAME_RE = /^[A-Za-z0-9一-龥][A-Za-z0-9一-龥\-_#@/.|]{1,31}$/;
-
const rules: FormRules = {
- commandName: [{ required: true, message: t('command.form.nameRequired'), trigger: 'blur' }],
+ commandName: [
+ { required: true, message: t('command.form.nameRequired'), trigger: 'blur' },
+ { min: 2, max: 32, message: t('common.nameLength'), trigger: 'blur' },
+ { pattern: NAME_PATTERN, message: t('common.nameFormat'), trigger: 'blur' },
+ ],
+ commandTypeFlag: [{ required: true, message: t('command.form.commandTypeRequired'), trigger: 'change' }],
+ callTypeFlag: [{ required: true, message: t('command.form.callTypeRequired'), trigger: 'change' }],
+ timeout: [{ required: true, message: t('command.form.timeoutRequired'), trigger: 'blur' }],
};
type RowErrors = { paramName?: string; paramCode?: string };
@@ -227,7 +233,7 @@
const code = String(row.paramCode || '').trim();
if (!name) {
errors.paramName = t('command.form.paramRequired');
- } else if (!PARAM_NAME_RE.test(name)) {
+ } else if (!NAME_PATTERN.test(name)) {
errors.paramName = t('command.form.paramNamePattern');
}
if (!code) {
@@ -301,7 +307,7 @@
failMessage(t('command.form.paramRequired'));
valid = false;
}
- if (item.paramName && !PARAM_NAME_RE.test(item.paramName)) {
+ if (item.paramName && !NAME_PATTERN.test(item.paramName)) {
failMessage(t('command.form.paramNamePattern'));
valid = false;
}
diff --git a/src/views/settings/event/definition/edit/EventEditForm.vue b/src/views/settings/event/definition/edit/EventEditForm.vue
index 797b89359..153af43da 100644
--- a/src/views/settings/event/definition/edit/EventEditForm.vue
+++ b/src/views/settings/event/definition/edit/EventEditForm.vue
@@ -127,6 +127,7 @@
import EnableFlagSegmented from '@/components/segmented/EnableFlagSegmented.vue';
import { EVENT_LEVEL_OPTIONS, EVENT_TYPE_OPTIONS, POINT_TYPE_OPTIONS } from '@/config/constant/enums';
import type { EventForm, EventParamRecord, EventRecord } from '@/config/types';
+ import { NAME_PATTERN } from '@/utils/formRuleUtil';
import { failMessage } from '@/utils/notificationUtil';
import { enableFlagValue, eventLevelValue, eventTypeValue, pointTypeValue } from '@/utils/thingModelFormatUtil';
@@ -172,10 +173,14 @@
paramLoading: false,
});
- const PARAM_NAME_RE = /^[A-Za-z0-9一-龥][A-Za-z0-9一-龥\-_#@/.|]{1,31}$/;
-
const rules: FormRules = {
- eventName: [{ required: true, message: t('eventDefinition.form.nameRequired'), trigger: 'blur' }],
+ eventName: [
+ { required: true, message: t('eventDefinition.form.nameRequired'), trigger: 'blur' },
+ { min: 2, max: 32, message: t('common.nameLength'), trigger: 'blur' },
+ { pattern: NAME_PATTERN, message: t('common.nameFormat'), trigger: 'blur' },
+ ],
+ eventTypeFlag: [{ required: true, message: t('eventDefinition.form.eventTypeRequired'), trigger: 'change' }],
+ eventLevelFlag: [{ required: true, message: t('eventDefinition.form.eventLevelRequired'), trigger: 'change' }],
};
type RowErrors = { paramName?: string; paramCode?: string };
@@ -189,7 +194,7 @@
const code = String(row.paramCode || '').trim();
if (!name) {
errors.paramName = t('eventDefinition.form.paramRequired');
- } else if (!PARAM_NAME_RE.test(name)) {
+ } else if (!NAME_PATTERN.test(name)) {
errors.paramName = t('eventDefinition.form.paramNamePattern');
}
if (!code) {
@@ -256,7 +261,7 @@
failMessage(t('eventDefinition.form.paramRequired'));
valid = false;
}
- if (item.paramName && !PARAM_NAME_RE.test(item.paramName)) {
+ if (item.paramName && !NAME_PATTERN.test(item.paramName)) {
failMessage(t('eventDefinition.form.paramNamePattern'));
valid = false;
}
diff --git a/src/views/settings/group/edit/index.ts b/src/views/settings/group/edit/index.ts
index a65e5eba2..7d2134e0b 100644
--- a/src/views/settings/group/edit/index.ts
+++ b/src/views/settings/group/edit/index.ts
@@ -22,6 +22,7 @@ import { useI18n } from 'vue-i18n';
import EnableFlagSegmented from '@/components/segmented/EnableFlagSegmented.vue';
import { ENTITY_TYPE_OPTIONS } from '@/config/constant/enums';
import type { GroupRecord } from '@/config/types/manager';
+import { NAME_PATTERN } from '@/utils/formRuleUtil';
type FormMode = 'add' | 'edit';
@@ -85,7 +86,11 @@ export default defineComponent({
const rules: FormRules = {
groupTypeFlag: [{ required: true, message: t('settings.common.entityTypePlaceholder'), trigger: 'change' }],
- groupName: [{ required: true, message: t('settings.group.groupNamePlaceholder'), trigger: 'blur' }],
+ groupName: [
+ { required: true, message: t('settings.group.groupNamePlaceholder'), trigger: 'blur' },
+ { min: 2, max: 32, message: t('common.nameLength'), trigger: 'blur' },
+ { pattern: NAME_PATTERN, message: t('common.nameFormat'), trigger: 'blur' },
+ ],
};
const excludedIds = computed(() => {
diff --git a/src/views/settings/label/edit/index.ts b/src/views/settings/label/edit/index.ts
index e6906b21e..3ddb72a7c 100644
--- a/src/views/settings/label/edit/index.ts
+++ b/src/views/settings/label/edit/index.ts
@@ -21,6 +21,7 @@ import { useI18n } from 'vue-i18n';
import EnableFlagSegmented from '@/components/segmented/EnableFlagSegmented.vue';
import { ENTITY_TYPE_OPTIONS } from '@/config/constant/enums';
import type { LabelRecord } from '@/config/types/manager';
+import { NAME_PATTERN } from '@/utils/formRuleUtil';
type FormMode = 'add' | 'edit';
@@ -53,7 +54,11 @@ export default defineComponent({
const rules: FormRules = {
entityTypeFlag: [{ required: true, message: t('settings.common.entityTypePlaceholder'), trigger: 'change' }],
- labelName: [{ required: true, message: t('settings.label.labelNamePlaceholder'), trigger: 'blur' }],
+ labelName: [
+ { required: true, message: t('settings.label.labelNamePlaceholder'), trigger: 'blur' },
+ { min: 2, max: 32, message: t('common.nameLength'), trigger: 'blur' },
+ { pattern: NAME_PATTERN, message: t('common.nameFormat'), trigger: 'blur' },
+ ],
};
const reset = () => {
diff --git a/src/views/settings/menu/edit/index.ts b/src/views/settings/menu/edit/index.ts
index 2202622e5..f6ef431b5 100644
--- a/src/views/settings/menu/edit/index.ts
+++ b/src/views/settings/menu/edit/index.ts
@@ -22,6 +22,7 @@ import { useI18n } from 'vue-i18n';
import EnableFlagSegmented from '@/components/segmented/EnableFlagSegmented.vue';
import { MENU_LEVEL_OPTIONS, MENU_TYPE_OPTIONS } from '@/config/constant/enums';
import { iconMap, iconNames, resolveIcon } from '@/config/constant/icons';
+import { AUTH_NAME_PATTERN } from '@/utils/formRuleUtil';
type FormMode = 'add' | 'edit';
@@ -65,12 +66,17 @@ export default defineComponent({
});
const rules: FormRules = {
- menuName: [{ required: true, message: t('settings.menu.menuNamePlaceholder'), trigger: 'blur' }],
+ menuName: [
+ { required: true, message: t('settings.menu.menuNamePlaceholder'), trigger: 'blur' },
+ { min: 2, max: 32, message: t('common.nameLength'), trigger: 'blur' },
+ { pattern: AUTH_NAME_PATTERN, message: t('common.nameFormat'), trigger: 'blur' },
+ ],
menuCode: [{ required: true, message: t('settings.menu.menuCodePlaceholder'), trigger: 'blur' }],
titleZh: [{ required: true, message: t('settings.menu.titleZhPlaceholder'), trigger: 'blur' }],
titleEn: [{ required: true, message: t('settings.menu.titleEnPlaceholder'), trigger: 'blur' }],
- menuTypeFlag: [{ required: true, trigger: 'change' }],
- menuLevel: [{ required: true, trigger: 'change' }],
+ menuTypeFlag: [{ required: true, message: t('settings.menu.menuTypeRequired'), trigger: 'change' }],
+ menuLevel: [{ required: true, message: t('settings.menu.menuLevelRequired'), trigger: 'change' }],
+ parentMenuId: [{ required: true, message: t('settings.menu.parentMenuIdPlaceholder'), trigger: 'change' }],
};
const parentTreeOptions = computed(() => [{ id: 0, menuName: 'Root', children: props.treeData || [] }]);
diff --git a/src/views/settings/resource/edit/index.ts b/src/views/settings/resource/edit/index.ts
index 08e9329ed..e116ce5e2 100644
--- a/src/views/settings/resource/edit/index.ts
+++ b/src/views/settings/resource/edit/index.ts
@@ -20,6 +20,7 @@ import type { FormInstance, FormRules } from 'element-plus';
import { useI18n } from 'vue-i18n';
import EnableFlagSegmented from '@/components/segmented/EnableFlagSegmented.vue';
+import { AUTH_NAME_PATTERN } from '@/utils/formRuleUtil';
type FormMode = 'add' | 'edit';
@@ -75,7 +76,11 @@ export default defineComponent({
});
const rules: FormRules = {
- resourceName: [{ required: true, message: t('settings.resource.resourceNamePlaceholder'), trigger: 'blur' }],
+ resourceName: [
+ { required: true, message: t('settings.resource.resourceNamePlaceholder'), trigger: 'blur' },
+ { min: 2, max: 32, message: t('common.nameLength'), trigger: 'blur' },
+ { pattern: AUTH_NAME_PATTERN, message: t('common.nameFormat'), trigger: 'blur' },
+ ],
parentResourceId: [
{ required: true, message: t('settings.resource.parentResourceIdPlaceholder'), trigger: 'change' },
],
diff --git a/src/views/settings/role/edit/index.ts b/src/views/settings/role/edit/index.ts
index 62b9173db..a67e0295c 100644
--- a/src/views/settings/role/edit/index.ts
+++ b/src/views/settings/role/edit/index.ts
@@ -20,6 +20,7 @@ import type { FormInstance, FormRules } from 'element-plus';
import { useI18n } from 'vue-i18n';
import EnableFlagSegmented from '@/components/segmented/EnableFlagSegmented.vue';
+import { AUTH_NAME_PATTERN } from '@/utils/formRuleUtil';
type FormMode = 'add' | 'edit';
@@ -56,7 +57,11 @@ export default defineComponent({
});
const rules: FormRules = {
- roleName: [{ required: true, message: t('settings.role.roleNamePlaceholder'), trigger: 'blur' }],
+ roleName: [
+ { required: true, message: t('settings.role.roleNamePlaceholder'), trigger: 'blur' },
+ { min: 2, max: 32, message: t('common.nameLength'), trigger: 'blur' },
+ { pattern: AUTH_NAME_PATTERN, message: t('common.nameFormat'), trigger: 'blur' },
+ ],
parentRoleId: [{ required: true, message: t('settings.role.parentRoleIdPlaceholder'), trigger: 'change' }],
};
diff --git a/src/views/settings/user/edit/index.ts b/src/views/settings/user/edit/index.ts
index 2aa13e4a0..e75e6880a 100644
--- a/src/views/settings/user/edit/index.ts
+++ b/src/views/settings/user/edit/index.ts
@@ -19,6 +19,7 @@ import type { FormInstance, FormRules } from 'element-plus';
import { useI18n } from 'vue-i18n';
import EnableFlagSegmented from '@/components/segmented/EnableFlagSegmented.vue';
+import { AUTH_NAME_PATTERN, EMAIL_PATTERN, NAME_PATTERN, PHONE_PATTERN } from '@/utils/formRuleUtil';
type FormMode = 'add' | 'edit';
@@ -49,8 +50,18 @@ export default defineComponent({
});
const rules: FormRules = {
- userName: [{ required: true, message: t('settings.user.userNamePlaceholder'), trigger: 'blur' }],
- nickName: [{ required: true, message: t('settings.user.nickNamePlaceholder'), trigger: 'blur' }],
+ userName: [
+ { required: true, message: t('settings.user.userNamePlaceholder'), trigger: 'blur' },
+ { min: 2, max: 32, message: t('common.nameLength'), trigger: 'blur' },
+ { pattern: AUTH_NAME_PATTERN, message: t('common.nameFormat'), trigger: 'blur' },
+ ],
+ nickName: [
+ { required: true, message: t('settings.user.nickNamePlaceholder'), trigger: 'blur' },
+ { min: 2, max: 32, message: t('common.nameLength'), trigger: 'blur' },
+ { pattern: NAME_PATTERN, message: t('common.nameFormat'), trigger: 'blur' },
+ ],
+ phone: [{ pattern: PHONE_PATTERN, message: t('settings.user.phoneFormat'), trigger: 'blur' }],
+ email: [{ pattern: EMAIL_PATTERN, message: t('settings.user.emailFormat'), trigger: 'blur' }],
};
const reset = () => {