fix(wot-ui): 修复 v2 升级后部门和角色下拉不显示

Cascader/SelectPicker 在 v2 中不再自带触发单元格,拆分为 wd-form-item 触发 + 选择器弹出模式
This commit is contained in:
Ray.Hao
2026-06-04 13:55:55 +08:00
parent f97a10c71f
commit a422f9f962
5 changed files with 81 additions and 82 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "youlai-app",
"version": "1.0.0",
"version": "1.0.1",
"scripts": {
"dev:app": "uni -p app",
"dev:app-android": "uni -p app-android",

View File

@@ -44,15 +44,11 @@
{{ formData.id ? "编辑部门" : "新增部门" }}
</view>
<wd-form ref="formRef" :model="formData" :schema="rules">
<wd-form-item prop="parentId" title="上级部门" required>
<wd-cascader
v-model="parentSelected"
:columns="parentColumns"
:column-change="handleParentColumnChange"
:display-format="displayParentFormat"
@confirm="handleParentConfirm"
/>
</wd-form-item>
<!-- 上级部门选择触发交 wd-form-item选择器只负责弹出 -->
<wd-form-item title="上级部门" prop="parentId" required is-link
:value="parentLabel" placeholder="请选择上级部门" @click="showParentPicker = true" />
<wd-cascader v-model="parentSelected" v-model:visible="showParentPicker" :options="parentOptions"
:lazy-load="handleParentLazyLoad" :display-format="displayParentFormat" @confirm="handleParentConfirm" />
<wd-form-item prop="name" title="部门名称" required>
<wd-input v-model="formData.name" placeholder="请输入部门名称" />
</wd-form-item>
@@ -60,7 +56,7 @@
<wd-input v-model="formData.code" placeholder="请输入部门编号" />
</wd-form-item>
<wd-form-item prop="sort" title="排序">
<wd-input-number v-model="formData.sort" :min="0" />
<wd-input-number v-model="formData.sort!" :min="0" />
</wd-form-item>
<wd-form-item prop="status" title="状态">
<wd-switch v-model="formData.status" :active-value="1" :inactive-value="0" />
@@ -140,9 +136,10 @@ function transformDeptToTree(dept: DeptItem): any {
}
// 上级部门选择器
const showParentPicker = ref(false);
const parentSelected = ref<(string | number)[]>([]);
const parentColumns = ref<OptionType[][]>([]);
const parentOptions = ref<OptionType[]>([]);
const parentLabel = ref("");
// 格式化上级部门展示
const displayParentFormat = (selectedItems: OptionType[]) => {
@@ -168,8 +165,8 @@ function findDeptPath(data: OptionType[], targetId: string, path: string[] = [])
return null;
}
// 上级部门列变化
const handleParentColumnChange = ({ selectedItem, resolve, finish }: any) => {
// v2 Cascader 懒加载
const handleParentLazyLoad = ({ selectedItem, resolve, finish }: any) => {
if (String(selectedItem?.value) === "0") {
finish();
return;
@@ -183,9 +180,10 @@ const handleParentColumnChange = ({ selectedItem, resolve, finish }: any) => {
};
// 上级部门确认选择
const handleParentConfirm = ({ value }: any) => {
const handleParentConfirm = ({ value, selectedItems }: any) => {
parentSelected.value = value;
formData.parentId = Number(value[value.length - 1]) || 0;
parentLabel.value = selectedItems.map((item: any) => item.label).join("/");
};
const rules = toFormSchema({
@@ -267,12 +265,11 @@ async function openDeptDialog(dept?: DeptItem) {
formRef.value?.reset();
Object.assign(formData, initialFormData);
parentSelected.value = [];
parentLabel.value = "";
dialog.visible = true;
const data = await DeptAPI.getOptions();
parentOptions.value = data;
const firstColumn: OptionType[] = [{ value: "0", label: "顶级部门" }, ...data];
parentColumns.value = [firstColumn];
parentOptions.value = [{ value: "0", label: "顶级部门" }, ...data];
if (dept) {
formData.id = dept.id;
@@ -283,16 +280,6 @@ async function openDeptDialog(dept?: DeptItem) {
const path = findDeptPath(data, String(form.parentId));
if (path) {
parentSelected.value = path;
const columns: OptionType[][] = [firstColumn];
let currentLevel = data;
for (let i = 0; i < path.length - 1; i++) {
const found = currentLevel.find((item: any) => String(item.value) === path[i]);
if (found && found.children) {
columns.push(found.children);
currentLevel = found.children;
}
}
parentColumns.value = columns;
} else {
parentSelected.value = [String(form.parentId)];
}

View File

@@ -34,10 +34,11 @@
</view>
<scroll-view scroll-y class="max-h-60vh">
<wd-form ref="formRef" :model="formData" :schema="rules">
<wd-form-item prop="parentId" title="上级菜单" required>
<wd-cascader v-model="parentSelected" :columns="parentColumns" :column-change="handleParentColumnChange"
:display-format="displayParentFormat" @confirm="handleParentConfirm" />
</wd-form-item>
<!-- 上级菜单选择触发交 wd-form-item选择器只负责弹出 -->
<wd-form-item title="上级菜单" prop="parentId" required is-link
:value="parentLabel" placeholder="请选择上级菜单" @click="showParentPicker = true" />
<wd-cascader v-model="parentSelected" v-model:visible="showParentPicker" :options="parentOptions"
:lazy-load="handleParentLazyLoad" :display-format="displayParentFormat" @confirm="handleParentConfirm" />
<wd-form-item prop="name" title="菜单名称" required>
<wd-input v-model="formData.name" placeholder="请输入菜单名称" />
</wd-form-item>
@@ -167,9 +168,10 @@
}
// 上级菜单选择器
const showParentPicker = ref(false);
const parentSelected = ref<(string | number)[]>([]);
const parentColumns = ref<OptionType[][]>([]);
const parentOptions = ref<OptionType[]>([]);
const parentLabel = ref("");
const displayParentFormat = (selectedItems: Record<string, any>[]) => {
if (!selectedItems || selectedItems.length === 0) return "";
@@ -197,7 +199,8 @@
return null;
}
const handleParentColumnChange = ({ selectedItem, resolve, finish }: any) => {
// v2 Cascader 懒加载
const handleParentLazyLoad = ({ selectedItem, resolve, finish }: any) => {
if (String(selectedItem?.value) === "0") {
finish();
return;
@@ -210,9 +213,10 @@
}
};
const handleParentConfirm = ({ value }: any) => {
const handleParentConfirm = ({ value, selectedItems }: any) => {
parentSelected.value = value;
formData.parentId = String(value[value.length - 1]) || "0";
parentLabel.value = selectedItems.map((item: any) => item.label).join("/");
};
const rules = toFormSchema({
@@ -289,12 +293,11 @@
formRef.value?.reset();
Object.assign(formData, initialFormData);
parentSelected.value = [];
parentLabel.value = "";
dialog.visible = true;
const data = await MenuAPI.getOptions(true);
parentOptions.value = data;
const firstColumn: OptionType[] = [{ value: "0", label: "顶级菜单" }, ...data];
parentColumns.value = [firstColumn];
parentOptions.value = [{ value: "0", label: "顶级菜单" }, ...data];
if (menu) {
formData.id = menu.id;
@@ -305,18 +308,6 @@
const path = findMenuPath(data, String(form.parentId));
if (path) {
parentSelected.value = path;
const columns: OptionType[][] = [firstColumn];
let currentLevel = data;
for (let i = 0; i < path.length - 1; i++) {
const found = currentLevel.find((item: any) => String(item.value) === String(path[i]));
if (found && found.children && found.children.length > 0) {
columns.push(found.children);
currentLevel = found.children;
} else {
break;
}
}
parentColumns.value = columns;
} else {
parentSelected.value = [String(form.parentId)];
}

View File

@@ -58,9 +58,11 @@
<wd-form-item prop="code" title="角色编码" required>
<wd-input v-model="formData.code" placeholder="请输入角色编码" />
</wd-form-item>
<wd-form-item prop="dataScope" title="数据权限" required>
<wd-select-picker v-model="formData.dataScope" :columns="dataScopeOptions" />
</wd-form-item>
<!-- 数据权限选择触发交 wd-form-item选择器只负责弹出 -->
<wd-form-item title="数据权限" prop="dataScope" required is-link
:value="dataScopeLabel" placeholder="请选择数据权限" @click="showDataScopePicker = true" />
<wd-select-picker v-model="formData.dataScope" v-model:visible="showDataScopePicker"
:columns="dataScopeOptions" @confirm="handleDataScopeConfirm" />
<wd-form-item prop="status" title="状态">
<wd-switch v-model="formData.status" :active-value="1" :inactive-value="0" />
</wd-form-item>
@@ -124,6 +126,18 @@
const formData = reactive<RoleForm>({ ...initialFormData });
// 数据权限选择器状态
const showDataScopePicker = ref(false);
const dataScopeLabel = computed(() => {
const opt = dataScopeOptions.value.find((o) => o.value === formData.dataScope);
return opt?.label || "";
});
// 数据权限确认
const handleDataScopeConfirm = () => {
// label 由 computed 自动计算
};
const dataScopeOptions = ref<Record<string, any>[]>([
{ label: "全部数据", value: 1 },
{ label: "部门及子部门数据", value: 2 },

View File

@@ -85,13 +85,17 @@
<wd-form-item prop="nickname" title="昵称" required>
<wd-input v-model="formData.nickname" placeholder="请输入昵称" />
</wd-form-item>
<wd-form-item prop="deptId" title="部门" required>
<wd-cascader v-model="deptSelected" :columns="deptColumns" :column-change="handleDeptColumnChange"
:display-format="displayDeptFormat" @confirm="handleDeptConfirm" />
</wd-form-item>
<wd-form-item prop="roleIds" title="角色" required>
<wd-select-picker v-model="formData.roleIds" :columns="roleOptions" />
</wd-form-item>
<!-- 部门选择触发交 wd-form-item选择器只负责弹出 -->
<wd-form-item title="部门" prop="deptId" required is-link
:value="deptLabel" placeholder="请选择部门" @click="showDeptPicker = true" />
<wd-cascader v-model="deptSelected" v-model:visible="showDeptPicker" :options="deptOptions"
:lazy-load="handleDeptLazyLoad" :display-format="displayDeptFormat" @confirm="handleDeptConfirm" />
<!-- 角色选择触发交 wd-form-item选择器只负责弹出 -->
<wd-form-item title="角色" prop="roleIds" required is-link
:value="roleLabel" placeholder="请选择角色" @click="showRolePicker = true" />
<wd-select-picker v-model="formData.roleIds" v-model:visible="showRolePicker" :columns="roleOptions"
@confirm="handleRoleConfirm" />
<wd-form-item prop="mobile" title="手机号">
<wd-input v-model="formData.mobile" placeholder="请输入手机号" />
</wd-form-item>
@@ -186,9 +190,14 @@
const roleOptions = ref<Record<string, any>[]>([]);
const deptOptions = ref<OptionType[]>([]);
// 部门多列选择器数据
// 部门选择器状态
const showDeptPicker = ref(false);
const deptSelected = ref<(string | number)[]>([]);
const deptColumns = ref<Record<string, any>[][]>([]);
const deptLabel = ref("");
// 角色选择器状态
const showRolePicker = ref(false);
const roleLabel = ref("");
// 格式化部门展示
const displayDeptFormat = (selectedItems: Record<string, any>[]) => {
@@ -210,8 +219,8 @@
return null;
}
// 部门列变化(动态加载子部门)
const handleDeptColumnChange = ({ selectedItem, resolve, finish }: any) => {
// v2 Cascader 懒加载
const handleDeptLazyLoad = ({ selectedItem, resolve, finish }: any) => {
const children = selectedItem.children;
if (children && children.length > 0) {
resolve(children);
@@ -223,8 +232,13 @@
// 部门确认选择
const handleDeptConfirm = ({ value, selectedItems }: any) => {
deptSelected.value = value;
// 取最后一个选中的部门ID
formData.deptId = value[value.length - 1];
deptLabel.value = selectedItems.map((item: any) => item.label).join("/");
};
// 角色确认选择
const handleRoleConfirm = ({ selectedItems }: any) => {
roleLabel.value = selectedItems.map((item: any) => item.label).join("、");
};
const rules = toFormSchema({
@@ -297,6 +311,8 @@
formRef.value?.reset();
Object.assign(formData, initialFormData);
deptSelected.value = [];
deptLabel.value = "";
roleLabel.value = "";
dialog.visible = true;
roleOptions.value = await RoleAPI.getOptions();
const deptData = await DeptAPI.getOptions();
@@ -306,31 +322,22 @@
formData.id = id;
const data = await UserAPI.getFormData(id);
Object.assign(formData, data, { id });
// 编辑时回显部门选择(需要完整路径和预加载所有层级数据)
// 编辑时回显部门
if (data.deptId) {
const path = findDeptPath(deptData, String(data.deptId));
if (path) {
deptSelected.value = path;
// 预加载所有层级的 columns
const columns: any[] = [deptData];
let currentLevel = deptData;
for (let i = 0; i < path.length - 1; i++) {
const found = currentLevel.find((item: any) => item.value === path[i]);
if (found && found.children) {
columns.push(found.children);
currentLevel = found.children;
}
}
deptColumns.value = columns;
} else {
deptSelected.value = [String(data.deptId)];
deptColumns.value = [deptData];
}
} else {
deptColumns.value = [deptData];
}
} else {
deptColumns.value = [deptData];
// 回显角色
if (data.roleIds && data.roleIds.length > 0) {
const names = roleOptions.value
.filter((r: any) => data.roleIds.includes(r.value))
.map((r: any) => r.label);
roleLabel.value = names.join("、");
}
}
}