mirror of
https://codeup.aliyun.com/67762337eccfc218f6110e0e/vue/learning-system-portal.git
synced 2025-12-18 23:36:44 +08:00
feat: 新增获取全量机构树的API,优化SignupModal和ManageListRemote组件的组织树交互逻辑
This commit is contained in:
@@ -46,6 +46,14 @@ const getUserInfoById = function(id) {
|
|||||||
return ajax.postJson(baseURL,'/user/list',{id});
|
return ajax.postJson(baseURL,'/user/list',{id});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取全量机构树
|
||||||
|
* GET /userbasic/organization/all/tree
|
||||||
|
*/
|
||||||
|
const getAllOrgTree = function () {
|
||||||
|
return ajax.get(baseURL, '/organization/all/tree');
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://u-pre.boe.com/userbasic/audience/userAudiences
|
* https://u-pre.boe.com/userbasic/audience/userAudiences
|
||||||
* 【当前代码中未查询到】获取当前用户受众信息
|
* 【当前代码中未查询到】获取当前用户受众信息
|
||||||
@@ -103,14 +111,6 @@ const getUsersByIds = function(ids) {
|
|||||||
return ajax.postJson(baseURL,'/user/getUserMessageToDai',ids);
|
return ajax.postJson(baseURL,'/user/getUserMessageToDai',ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据关键字检索用户(创建人下拉)
|
|
||||||
* @param {string} keyword
|
|
||||||
*/
|
|
||||||
const selectUser = function(keyword = '') {
|
|
||||||
return ajax.postJson(baseURL,'/user/selectuser',{ keyword });
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
userParentOrg,
|
userParentOrg,
|
||||||
findOrgsByKeyword,
|
findOrgsByKeyword,
|
||||||
@@ -125,5 +125,5 @@ export default {
|
|||||||
getUsersByIds,
|
getUsersByIds,
|
||||||
updateUser,
|
updateUser,
|
||||||
logout,
|
logout,
|
||||||
selectUser
|
getAllOrgTree
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,14 @@
|
|||||||
</el-button>
|
</el-button>
|
||||||
<el-button size="small" @click="resetOrg">重置</el-button>
|
<el-button size="small" @click="resetOrg">重置</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-tree class="org-tree" show-checkbox node-key="id" :data="orgList" :props="orgTreeProps" lazy
|
<el-tree
|
||||||
|
ref="orgTree"
|
||||||
|
class="org-tree"
|
||||||
|
show-checkbox
|
||||||
|
node-key="id"
|
||||||
|
:data="orgList"
|
||||||
|
:props="orgTreeProps"
|
||||||
|
lazy
|
||||||
:load="loadOrgNodeFull" @check-change="onOrgCheckChange" :default-checked-keys="selectedOrgKeys" />
|
:load="loadOrgNodeFull" @check-change="onOrgCheckChange" :default-checked-keys="selectedOrgKeys" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
@@ -573,13 +580,25 @@ export default {
|
|||||||
this.stuSelectRows = this.stuSelectRows.filter(
|
this.stuSelectRows = this.stuSelectRows.filter(
|
||||||
(i) => (i.id || i.userId) !== (item.id || item.userId)
|
(i) => (i.id || i.userId) !== (item.id || item.userId)
|
||||||
);
|
);
|
||||||
|
// 同步左侧快速选人表格的勾选状态
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.syncStuTableSelection();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
removeOrg(item) {
|
removeOrg(item) {
|
||||||
this.deptList = this.deptList.filter((i) => i.id !== item.id);
|
this.deptList = this.deptList.filter((i) => i.id !== item.id);
|
||||||
this.selectedOrgKeys = this.deptList.map((d) => d.id);
|
this.selectedOrgKeys = this.deptList.map((d) => d.id);
|
||||||
|
// 同步左侧组织树的勾选状态
|
||||||
|
if (this.$refs.orgTree && this.$refs.orgTree.setCheckedKeys) {
|
||||||
|
this.$refs.orgTree.setCheckedKeys(this.selectedOrgKeys);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
removeAudience(item) {
|
removeAudience(item) {
|
||||||
this.auditSelectRows = this.auditSelectRows.filter((i) => i.id !== item.id);
|
this.auditSelectRows = this.auditSelectRows.filter((i) => i.id !== item.id);
|
||||||
|
// 同步左侧受众表格的勾选状态
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.syncAudienceTableSelection();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
submitAuth() {
|
submitAuth() {
|
||||||
if (this.type === 2) {
|
if (this.type === 2) {
|
||||||
|
|||||||
@@ -100,9 +100,12 @@
|
|||||||
placeholder="资源归属"
|
placeholder="资源归属"
|
||||||
clearable
|
clearable
|
||||||
:props="resOwnerCascaderProps"
|
:props="resOwnerCascaderProps"
|
||||||
|
:options="resOwnerOptions"
|
||||||
:show-all-levels="false"
|
:show-all-levels="false"
|
||||||
@change="handleResOwnerChange"
|
@change="handleResOwnerChange"
|
||||||
@input.native="limitResOwnerInput"
|
@input.native="limitResOwnerInput"
|
||||||
|
@clear="handleResOwnerClear"
|
||||||
|
@visible-change="handleResOwnerVisibleChange"
|
||||||
filterable
|
filterable
|
||||||
:filter-method="resOwnerFilterMethod"
|
:filter-method="resOwnerFilterMethod"
|
||||||
></el-cascader>
|
></el-cascader>
|
||||||
@@ -227,7 +230,7 @@
|
|||||||
<span class="common-cell common-cell-right">{{ scope.row.openCourse == 1 ? '是' : '否' }}</span>
|
<span class="common-cell common-cell-right">{{ scope.row.openCourse == 1 ? '是' : '否' }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="资源归属" prop="orgName" min-width="220" align="center" sortable="custom">
|
<el-table-column label="资源归属" prop="orgName" min-width="220" align="center" sortable="custom" show-overflow-tooltip>
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-tooltip :content="scope.row.orgFullName || scope.row.orgName" placement="top" effect="dark">
|
<el-tooltip :content="scope.row.orgFullName || scope.row.orgName" placement="top" effect="dark">
|
||||||
<span class="common-cell common-cell-right">{{ scope.row.orgName }}</span>
|
<span class="common-cell common-cell-right">{{ scope.row.orgName }}</span>
|
||||||
@@ -464,14 +467,23 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['resOwnerMap', 'sysTypeMap', 'userInfo', 'identity']),
|
...mapGetters(['resOwnerMap', 'sysTypeMap', 'userInfo', 'identity']),
|
||||||
resOwnerCascaderProps() {
|
resOwnerCascaderProps() {
|
||||||
|
// 搜索模式:关闭懒加载,直接使用全量 options
|
||||||
|
if (this.resOwnerSearchMode) {
|
||||||
|
return {
|
||||||
|
value: 'id',
|
||||||
|
label: 'name',
|
||||||
|
children: 'children',
|
||||||
|
checkStrictly: true, // 允许选择任意一级选项
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// 非搜索模式:开启前端“伪懒加载”,数据从本地缓存树中按需取
|
||||||
return {
|
return {
|
||||||
value: 'id',
|
value: 'id',
|
||||||
label: 'name',
|
label: 'name',
|
||||||
children: 'children',
|
children: 'children',
|
||||||
lazy: true,
|
lazy: true,
|
||||||
lazyLoad: this.loadResOwnerNode,
|
lazyLoad: this.loadResOwnerNodeFromCache,
|
||||||
leaf: 'leaf',
|
checkStrictly: true, // 允许选择任意一级选项
|
||||||
checkStrictly: true // 允许选择任意一级选项
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
// 动态计算“授课教师”列的最小宽度,避免固定 260px
|
// 动态计算“授课教师”列的最小宽度,避免固定 260px
|
||||||
@@ -496,7 +508,11 @@ export default {
|
|||||||
sysTypeList: [],
|
sysTypeList: [],
|
||||||
resOwnerListMap: [],
|
resOwnerListMap: [],
|
||||||
resOwnerSelected: [],
|
resOwnerSelected: [],
|
||||||
resOwnerCascaderOptions: [],
|
// 资源归属全量树 & 级联选项
|
||||||
|
resOwnerTreeAll: [],
|
||||||
|
resOwnerOptions: [],
|
||||||
|
// 资源归属搜索模式开关(有关键字时为 true)
|
||||||
|
resOwnerSearchMode: false,
|
||||||
showSetTopFeature: false,
|
showSetTopFeature: false,
|
||||||
page: {
|
page: {
|
||||||
pageIndex: 1,//第几页
|
pageIndex: 1,//第几页
|
||||||
@@ -628,6 +644,8 @@ export default {
|
|||||||
//已经加载tree的情况下,不需要再单独的加载一次
|
//已经加载tree的情况下,不需要再单独的加载一次
|
||||||
this.loadResOwners();
|
this.loadResOwners();
|
||||||
this.loadSysTypes();
|
this.loadSysTypes();
|
||||||
|
// 加载资源归属全量树,供级联和搜索使用
|
||||||
|
this.loadAllResOwnerTree();
|
||||||
document.querySelector('#app').style.overflowX = 'hidden';
|
document.querySelector('#app').style.overflowX = 'hidden';
|
||||||
this.applyAppScrollbarStyle();
|
this.applyAppScrollbarStyle();
|
||||||
|
|
||||||
@@ -838,8 +856,36 @@ export default {
|
|||||||
if (event && event.target && event.target.value !== limited) {
|
if (event && event.target && event.target.value !== limited) {
|
||||||
event.target.value = limited;
|
event.target.value = limited;
|
||||||
}
|
}
|
||||||
if (this.$refs.resOwnerCascader) {
|
const keyword = (limited || '').trim();
|
||||||
this.$refs.resOwnerCascader.inputValue = limited;
|
// 根据是否有关键字切换搜索模式
|
||||||
|
this.resOwnerSearchMode = !!keyword;
|
||||||
|
if (this.resOwnerSearchMode) {
|
||||||
|
// 搜索模式:使用全量树作为 options,交给 filter-method 过滤
|
||||||
|
this.resOwnerOptions = this.resOwnerTreeAll;
|
||||||
|
} else {
|
||||||
|
// 非搜索模式:清空 options,交给 lazyLoad 从缓存树按需“懒加载”
|
||||||
|
this.resOwnerOptions = [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 清空选择时,恢复到懒加载模式
|
||||||
|
handleResOwnerClear() {
|
||||||
|
this.resOwnerSearchMode = false;
|
||||||
|
this.resOwnerOptions = [];
|
||||||
|
// 清空输入框的文字,避免残留关键字
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.$refs.resOwnerCascader && this.$refs.resOwnerCascader.inputValue !== undefined) {
|
||||||
|
this.$refs.resOwnerCascader.inputValue = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 下拉面板打开时,如果当前没有关键字,也确保是懒加载模式
|
||||||
|
handleResOwnerVisibleChange(visible) {
|
||||||
|
if (!visible) return;
|
||||||
|
// 如果没有关键字,就强制回到懒加载模式
|
||||||
|
const keyword = (this.$refs.resOwnerCascader && this.$refs.resOwnerCascader.inputValue) || '';
|
||||||
|
if (!keyword) {
|
||||||
|
this.resOwnerSearchMode = false;
|
||||||
|
this.resOwnerOptions = [];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
resOwnerFilterMethod(node, keyword) {
|
resOwnerFilterMethod(node, keyword) {
|
||||||
@@ -1460,60 +1506,50 @@ export default {
|
|||||||
sessionStorage.setItem('courseDetail', JSON.stringify(row));
|
sessionStorage.setItem('courseDetail', JSON.stringify(row));
|
||||||
this.$router.push({ path: '/iframe/course/coursemanage-remote' });
|
this.$router.push({ path: '/iframe/course/coursemanage-remote' });
|
||||||
},
|
},
|
||||||
async loadResOwnerNode(node, resolve) {
|
// 前端“伪懒加载”:根据本地全量机构树按需返回子节点
|
||||||
const { level } = node;
|
// 为了让 el-cascader 的 loading 动画有可见效果,这里故意加入一个很小的延时再 resolve
|
||||||
let parentId = '';
|
async loadResOwnerNodeFromCache(node, resolve) {
|
||||||
|
try {
|
||||||
|
const delayResolve = (nodes) => {
|
||||||
|
// 适当延时 150ms,让 loading 动画可见,但又不会让用户感觉明显卡顿
|
||||||
|
setTimeout(() => resolve(nodes), 150);
|
||||||
|
};
|
||||||
|
|
||||||
if (level === 0) {
|
// 根节点(level === 0):返回所有一级机构
|
||||||
// 第一层:获取根节点
|
if (node.level === 0) {
|
||||||
try {
|
return delayResolve(this.resOwnerTreeAll || []);
|
||||||
const res = await apiUserbasic.findOrgsByKeyword('');
|
}
|
||||||
if (res && res.result) {
|
|
||||||
const nodes = res.result.map(item => ({
|
// 其他层级:根据当前节点 id 在树中查找对应节点,再返回其 children
|
||||||
id: item.id,
|
const currentId = node.value || (node.data && node.data.id);
|
||||||
name: item.name,
|
if (!currentId) {
|
||||||
hrbpId: item.hrbpId,
|
return delayResolve([]);
|
||||||
leaf: false, // 懒加载模式下,先假设所有节点都可能有子节点
|
}
|
||||||
children: [] // 空数组表示需要懒加载
|
|
||||||
}));
|
const findNodeById = (list = [], id) => {
|
||||||
resolve(nodes);
|
for (let i = 0; i < list.length; i++) {
|
||||||
|
const item = list[i];
|
||||||
|
if (item.id === id) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
if (Array.isArray(item.children) && item.children.length > 0) {
|
||||||
|
const found = findNodeById(item.children, id);
|
||||||
|
if (found) return found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const target = findNodeById(this.resOwnerTreeAll || [], currentId);
|
||||||
|
if (target && Array.isArray(target.children)) {
|
||||||
|
delayResolve(target.children);
|
||||||
} else {
|
} else {
|
||||||
|
delayResolve([]);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('本地懒加载资源归属节点失败:', e);
|
||||||
resolve([]);
|
resolve([]);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
|
||||||
console.error('加载资源归属失败:', error);
|
|
||||||
resolve([]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 子节点:根据父节点ID加载
|
|
||||||
parentId = node.value || (node.data && node.data.id);
|
|
||||||
if (!parentId) {
|
|
||||||
resolve([]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const res = await apiUserbasic.getOrgInfo(parentId);
|
|
||||||
if (res && res.status === 200 && res.result) {
|
|
||||||
let treeList = [];
|
|
||||||
if (res.result.directChildList && res.result.directChildList.length > 0) {
|
|
||||||
treeList = res.result.directChildList.map(item => ({
|
|
||||||
id: item.id,
|
|
||||||
name: item.name,
|
|
||||||
hrbpId: item.hrbpId,
|
|
||||||
leaf: false, // 懒加载模式下,先假设所有节点都可能有子节点
|
|
||||||
children: [] // 空数组表示需要懒加载
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
resolve(treeList);
|
|
||||||
} else {
|
|
||||||
// 如果没有子节点,返回空数组,级联选择器会自动将其视为叶子节点
|
|
||||||
resolve([]);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('加载资源归属子节点失败:', error);
|
|
||||||
resolve([]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
handleResOwnerChange(value) {
|
handleResOwnerChange(value) {
|
||||||
if (!value || value.length === 0) {
|
if (!value || value.length === 0) {
|
||||||
@@ -1536,6 +1572,39 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
// 将后端机构节点转换为级联组件所需结构
|
||||||
|
mapOrgToCascaderNode(node = {}) {
|
||||||
|
const children = Array.isArray(node.childList)
|
||||||
|
? node.childList.map(child => this.mapOrgToCascaderNode(child))
|
||||||
|
: [];
|
||||||
|
return {
|
||||||
|
id: node.organizationId,
|
||||||
|
name: node.orgName,
|
||||||
|
children,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
// 加载资源归属全量机构树
|
||||||
|
async loadAllResOwnerTree() {
|
||||||
|
try {
|
||||||
|
const res = await apiUserbasic.getAllOrgTree();
|
||||||
|
if (res && res.status === 200 && res.result && Array.isArray(res.result.orgTreeList)) {
|
||||||
|
this.resOwnerTreeAll = res.result.orgTreeList.map(item => this.mapOrgToCascaderNode(item));
|
||||||
|
// 默认进入非搜索模式,由懒加载从本地树按需返回节点
|
||||||
|
this.resOwnerOptions = [];
|
||||||
|
} else if (res && res.result && Array.isArray(res.result.orgTreeList)) {
|
||||||
|
// 兼容没有 status 字段但有 result 的情况
|
||||||
|
this.resOwnerTreeAll = res.result.orgTreeList.map(item => this.mapOrgToCascaderNode(item));
|
||||||
|
this.resOwnerOptions = [];
|
||||||
|
} else {
|
||||||
|
this.resOwnerTreeAll = [];
|
||||||
|
this.resOwnerOptions = [];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载资源归属全量树失败:', error);
|
||||||
|
this.resOwnerTreeAll = [];
|
||||||
|
this.resOwnerOptions = [];
|
||||||
|
}
|
||||||
|
},
|
||||||
showChooseCourse() {
|
showChooseCourse() {
|
||||||
this.courseChooseShow = true;
|
this.courseChooseShow = true;
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user