fix(components): 菜单管理调整

This commit is contained in:
2026-03-27 14:03:42 +08:00
parent 120a5b4dfd
commit ca3d697941
9 changed files with 11075 additions and 103 deletions

View File

@@ -346,10 +346,6 @@ const pageResourceOptions = pageResourceItems.map(item => ({
const selectedPageResource = computed(() => pageResourceMap.get(model.value.pageResourcePath) ?? null);
const displayRoutePath = computed(() => {
if (selectedPageResource.value) {
return selectedPageResource.value.path;
}
return joinRoutePaths(currentParentFullPath.value, model.value.path);
});
@@ -357,14 +353,6 @@ const hasCompatibleViewRouteData = computed(() =>
Boolean(getNullableText(model.value.component) && getNullableText(model.value.path))
);
const isSelectedPageResourceCompatible = computed(() => {
if (!selectedPageResource.value) {
return false;
}
return Boolean(getRelativeRoutePath(selectedPageResource.value.path, currentParentFullPath.value));
});
const rules = computed(() => {
const pathRule: RuleFormItem = {
message: $t('page.system.menu.form.path'),
@@ -403,11 +391,6 @@ const rules = computed(() => {
return;
}
if (!isSelectedPageResourceCompatible.value) {
callback(new Error($t('page.system.menu.form.pageResourceParentMismatch')));
return;
}
callback();
}
};
@@ -569,14 +552,16 @@ const parentTreeOptions = computed<ParentTreeOption[]>(() => {
];
});
function filterParentTreeNode(value: string, data: ParentTreeOption) {
function filterParentTreeNode(value: string, data: { label?: string }) {
const keyword = value.trim().toLowerCase();
if (!keyword) {
return true;
}
return data.label.toLowerCase().includes(keyword);
return String(data.label ?? '')
.toLowerCase()
.includes(keyword);
}
function closeModal() {
@@ -642,7 +627,13 @@ function syncViewRouteFields() {
return;
}
model.value.path = getRelativeRoutePath(pageResource.path, currentParentFullPath.value);
const nextRelativePath =
getRelativeRoutePath(pageResource.path, currentParentFullPath.value) ||
normalizeRoutePart(model.value.path) ||
normalizeRoutePart(pageResource.path).split('/').filter(Boolean).at(-1) ||
'';
model.value.path = nextRelativePath;
model.value.component = pageResource.component;
model.value.componentName = pageResource.name;
model.value.routePropsJson = stringifyRouteProps(pageResource.props as Record<string, unknown> | null);
@@ -867,8 +858,11 @@ watch(
watch(
() => model.value.parentId,
() => {
async () => {
syncCurrentRouteFields();
await nextTick();
clearFormValidation();
}
);

View File

@@ -100,7 +100,10 @@ watch(visible, async value => {
:scrollbar="false"
@confirm="handleSubmit"
>
<ElForm ref="formRef" :model="model" :rules="rules" label-position="top">
<ElForm ref="formRef" :model="model" :rules="rules" label-position="top" autocomplete="off">
<input class="business-form-autofill-guard" type="text" name="fake-username" autocomplete="username" />
<input class="business-form-autofill-guard" type="password" name="fake-password" autocomplete="new-password" />
<ElRow :gutter="16">
<ElCol :span="24">
<ElFormItem :label="$t('page.system.user.userName')">
@@ -109,14 +112,22 @@ watch(visible, async value => {
</ElCol>
<ElCol :span="24">
<ElFormItem :label="$t('page.system.user.newPassword')" prop="password">
<ElInput v-model="model.password" show-password :placeholder="$t('page.system.user.form.newPassword')" />
<ElInput
v-model="model.password"
name="system-user-reset-password"
show-password
autocomplete="new-password"
:placeholder="$t('page.system.user.form.newPassword')"
/>
</ElFormItem>
</ElCol>
<ElCol :span="24">
<ElFormItem :label="$t('page.system.user.confirmPassword')" prop="confirmPassword">
<ElInput
v-model="model.confirmPassword"
name="system-user-reset-confirm-password"
show-password
autocomplete="new-password"
:placeholder="$t('page.system.user.form.confirmPassword')"
/>
</ElFormItem>
@@ -125,3 +136,19 @@ watch(visible, async value => {
</ElForm>
</BusinessFormDialog>
</template>
<style scoped>
.business-form-autofill-guard {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
opacity: 0;
pointer-events: none;
}
</style>

View File

@@ -29,12 +29,13 @@ const model = defineModel<Api.SystemManage.UserSearchParams>('model', { required
<TableSearchPanel
:model="model"
:disabled="disabled"
:action-col-lg="8"
:action-col-md="8"
:action-col-lg="24"
:action-col-md="24"
:action-col-sm="24"
@reset="$emit('reset')"
@search="$emit('search')"
>
<ElCol :lg="8" :md="8" :sm="12">
<ElCol :lg="6" :md="8" :sm="12">
<ElFormItem :label="$t('page.system.user.userName')" prop="username">
<ElInput
v-model="model.username"
@@ -44,7 +45,7 @@ const model = defineModel<Api.SystemManage.UserSearchParams>('model', { required
/>
</ElFormItem>
</ElCol>
<ElCol :lg="8" :md="8" :sm="12">
<ElCol :lg="6" :md="8" :sm="12">
<ElFormItem :label="$t('page.system.user.userPhone')" prop="mobile">
<ElInput
v-model="model.mobile"
@@ -54,7 +55,7 @@ const model = defineModel<Api.SystemManage.UserSearchParams>('model', { required
/>
</ElFormItem>
</ElCol>
<ElCol :lg="8" :md="8" :sm="12">
<ElCol :lg="6" :md="8" :sm="12">
<ElFormItem :label="$t('page.system.user.userStatus')" prop="status">
<ElSelect
v-model="model.status"
@@ -71,21 +72,18 @@ const model = defineModel<Api.SystemManage.UserSearchParams>('model', { required
</ElSelect>
</ElFormItem>
</ElCol>
<template #extra>
<ElCol :lg="8" :md="8" :sm="12">
<ElFormItem :label="$t('page.system.user.userRole')" prop="roleId">
<ElSelect
v-model="model.roleId"
clearable
filterable
:disabled="disabled"
:placeholder="$t('page.system.user.form.userRole')"
>
<ElOption v-for="item in roleOptions" :key="item.id" :label="item.name" :value="item.id" />
</ElSelect>
</ElFormItem>
</ElCol>
</template>
<ElCol :lg="6" :md="8" :sm="12">
<ElFormItem :label="$t('page.system.user.userRole')" prop="roleId">
<ElSelect
v-model="model.roleId"
clearable
filterable
:disabled="disabled"
:placeholder="$t('page.system.user.form.userRole')"
>
<ElOption v-for="item in roleOptions" :key="item.id" :label="item.name" :value="item.id" />
</ElSelect>
</ElFormItem>
</ElCol>
</TableSearchPanel>
</template>