diff --git a/src/api/boe/userbasic.js b/src/api/boe/userbasic.js
index 918bdf3f..2ed576ba 100644
--- a/src/api/boe/userbasic.js
+++ b/src/api/boe/userbasic.js
@@ -46,6 +46,14 @@ const getUserInfoById = function(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
* 【当前代码中未查询到】获取当前用户受众信息
@@ -103,14 +111,6 @@ const getUsersByIds = function(ids) {
return ajax.postJson(baseURL,'/user/getUserMessageToDai',ids);
}
-/**
- * 根据关键字检索用户(创建人下拉)
- * @param {string} keyword
- */
-const selectUser = function(keyword = '') {
- return ajax.postJson(baseURL,'/user/selectuser',{ keyword });
-}
-
export default {
userParentOrg,
findOrgsByKeyword,
@@ -125,5 +125,5 @@ export default {
getUsersByIds,
updateUser,
logout,
- selectUser
+ getAllOrgTree
}
diff --git a/src/components/signup/SignupModal.vue b/src/components/signup/SignupModal.vue
index 1295a05d..50888b86 100644
--- a/src/components/signup/SignupModal.vue
+++ b/src/components/signup/SignupModal.vue
@@ -77,7 +77,14 @@
重置
-
@@ -573,13 +580,25 @@ export default {
this.stuSelectRows = this.stuSelectRows.filter(
(i) => (i.id || i.userId) !== (item.id || item.userId)
);
+ // 同步左侧快速选人表格的勾选状态
+ this.$nextTick(() => {
+ this.syncStuTableSelection();
+ });
},
removeOrg(item) {
this.deptList = this.deptList.filter((i) => i.id !== item.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) {
this.auditSelectRows = this.auditSelectRows.filter((i) => i.id !== item.id);
+ // 同步左侧受众表格的勾选状态
+ this.$nextTick(() => {
+ this.syncAudienceTableSelection();
+ });
},
submitAuth() {
if (this.type === 2) {
diff --git a/src/views/course/ManageListRemote.vue b/src/views/course/ManageListRemote.vue
index e9a2cbcf..3271fd2d 100644
--- a/src/views/course/ManageListRemote.vue
+++ b/src/views/course/ManageListRemote.vue
@@ -100,9 +100,12 @@
placeholder="资源归属"
clearable
:props="resOwnerCascaderProps"
+ :options="resOwnerOptions"
:show-all-levels="false"
@change="handleResOwnerChange"
@input.native="limitResOwnerInput"
+ @clear="handleResOwnerClear"
+ @visible-change="handleResOwnerVisibleChange"
filterable
:filter-method="resOwnerFilterMethod"
>
@@ -227,7 +230,7 @@
{{ scope.row.openCourse == 1 ? '是' : '否' }}
-
+
{{ scope.row.orgName }}
@@ -464,14 +467,23 @@ export default {
computed: {
...mapGetters(['resOwnerMap', 'sysTypeMap', 'userInfo', 'identity']),
resOwnerCascaderProps() {
+ // 搜索模式:关闭懒加载,直接使用全量 options
+ if (this.resOwnerSearchMode) {
+ return {
+ value: 'id',
+ label: 'name',
+ children: 'children',
+ checkStrictly: true, // 允许选择任意一级选项
+ };
+ }
+ // 非搜索模式:开启前端“伪懒加载”,数据从本地缓存树中按需取
return {
value: 'id',
label: 'name',
children: 'children',
lazy: true,
- lazyLoad: this.loadResOwnerNode,
- leaf: 'leaf',
- checkStrictly: true // 允许选择任意一级选项
+ lazyLoad: this.loadResOwnerNodeFromCache,
+ checkStrictly: true, // 允许选择任意一级选项
};
},
// 动态计算“授课教师”列的最小宽度,避免固定 260px
@@ -496,7 +508,11 @@ export default {
sysTypeList: [],
resOwnerListMap: [],
resOwnerSelected: [],
- resOwnerCascaderOptions: [],
+ // 资源归属全量树 & 级联选项
+ resOwnerTreeAll: [],
+ resOwnerOptions: [],
+ // 资源归属搜索模式开关(有关键字时为 true)
+ resOwnerSearchMode: false,
showSetTopFeature: false,
page: {
pageIndex: 1,//第几页
@@ -628,6 +644,8 @@ export default {
//已经加载tree的情况下,不需要再单独的加载一次
this.loadResOwners();
this.loadSysTypes();
+ // 加载资源归属全量树,供级联和搜索使用
+ this.loadAllResOwnerTree();
document.querySelector('#app').style.overflowX = 'hidden';
this.applyAppScrollbarStyle();
@@ -838,8 +856,36 @@ export default {
if (event && event.target && event.target.value !== limited) {
event.target.value = limited;
}
- if (this.$refs.resOwnerCascader) {
- this.$refs.resOwnerCascader.inputValue = limited;
+ const keyword = (limited || '').trim();
+ // 根据是否有关键字切换搜索模式
+ 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) {
@@ -1460,59 +1506,49 @@ export default {
sessionStorage.setItem('courseDetail', JSON.stringify(row));
this.$router.push({ path: '/iframe/course/coursemanage-remote' });
},
- async loadResOwnerNode(node, resolve) {
- const { level } = node;
- let parentId = '';
-
- if (level === 0) {
- // 第一层:获取根节点
- try {
- const res = await apiUserbasic.findOrgsByKeyword('');
- if (res && res.result) {
- const nodes = res.result.map(item => ({
- id: item.id,
- name: item.name,
- hrbpId: item.hrbpId,
- leaf: false, // 懒加载模式下,先假设所有节点都可能有子节点
- children: [] // 空数组表示需要懒加载
- }));
- resolve(nodes);
- } else {
- resolve([]);
- }
- } catch (error) {
- console.error('加载资源归属失败:', error);
- resolve([]);
+ // 前端“伪懒加载”:根据本地全量机构树按需返回子节点
+ // 为了让 el-cascader 的 loading 动画有可见效果,这里故意加入一个很小的延时再 resolve
+ async loadResOwnerNodeFromCache(node, resolve) {
+ try {
+ const delayResolve = (nodes) => {
+ // 适当延时 150ms,让 loading 动画可见,但又不会让用户感觉明显卡顿
+ setTimeout(() => resolve(nodes), 150);
+ };
+
+ // 根节点(level === 0):返回所有一级机构
+ if (node.level === 0) {
+ return delayResolve(this.resOwnerTreeAll || []);
}
- } else {
- // 子节点:根据父节点ID加载
- parentId = node.value || (node.data && node.data.id);
- if (!parentId) {
- resolve([]);
- return;
+
+ // 其他层级:根据当前节点 id 在树中查找对应节点,再返回其 children
+ const currentId = node.value || (node.data && node.data.id);
+ if (!currentId) {
+ return delayResolve([]);
}
- 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: [] // 空数组表示需要懒加载
- }));
+
+ const findNodeById = (list = [], id) => {
+ 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;
}
- resolve(treeList);
- } else {
- // 如果没有子节点,返回空数组,级联选择器会自动将其视为叶子节点
- resolve([]);
}
- } catch (error) {
- console.error('加载资源归属子节点失败:', error);
- resolve([]);
+ return null;
+ };
+
+ const target = findNodeById(this.resOwnerTreeAll || [], currentId);
+ if (target && Array.isArray(target.children)) {
+ delayResolve(target.children);
+ } else {
+ delayResolve([]);
}
+ } catch (e) {
+ console.error('本地懒加载资源归属节点失败:', e);
+ resolve([]);
}
},
handleResOwnerChange(value) {
@@ -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() {
this.courseChooseShow = true;
},