Files
learning-system-portal/src/components/signup/SignupModal.vue

896 lines
29 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div v-if="visible">
<el-dialog class="signup-dialog common-course-dialog" :visible="visible" :title="dialogTitle" width="1200px" top="8vh" append-to-body destroy-on-close
@close="handleClose">
<div class="signup-wrap">
<el-tabs v-model="activeTab">
<!-- <el-tab-pane v-if="infoType" label="项目内学员" name="project">
<div class="tab-search">
<span class="label">姓名</span>
<el-input v-model="projectParams.studentName" placeholder="请输入姓名" size="small" clearable class="input" />
<el-button type="primary" size="small" @click="getProjectStu">
搜索
</el-button>
<el-button size="small" @click="resetProjectStu">重置</el-button>
</div>
<el-table height="360" border :data="projectStu.list" style="width: 100%"
@selection-change="onProjectSelectionChange">
<el-table-column type="selection" width="50" />
<el-table-column prop="studentName" label="姓名" width="120" />
<el-table-column prop="studentUserNo" label="工号" width="140" />
<el-table-column prop="studentOrgName" label="归属组织" show-overflow-tooltip />
<el-table-column prop="studentDepartName" label="部门" />
</el-table>
<div class="pager">
<el-pagination background layout="total, prev, pager, next, jumper" :page-size="projectStu.pageSize"
:current-page="projectStu.pageNo" :total="projectStu.total" @current-change="onProjectPageChange" />
</div>
</el-tab-pane> -->
<el-tab-pane label="快速选人" name="quick">
<div class="tab2">
<div class="tab-search">
<span class="label">姓名</span>
<el-input v-model="nameSearch.keyword" placeholder="请输入姓名" size="small" clearable class="input" />
<!-- 点击搜索时认为是一次新的搜索页码应重置为第 1 -->
<el-button type="primary" size="small" @click="onSearchStu(true)">
搜索
</el-button>
<el-button size="small" @click="resetStu">重置</el-button>
</div>
<div class="split">
<div class="left-tree">
<el-tree :data="treeData" :props="treeProps" node-key="id" highlight-current lazy :load="loadOrgNode"
@node-click="onOrgSelect" />
</div>
<div class="table-area">
<el-table
ref="stuTable"
class="use-table"
border
:data="stuTable.list"
@selection-change="onStuSelectionChange"
:row-key="row => row.id || row.userId"
:reserve-selection="true"
>
<el-table-column type="selection" width="50" />
<el-table-column prop="realName" label="姓名" width="120" />
<el-table-column prop="userNo" label="工号" width="120" />
<el-table-column prop="orgName" label="归属组织" min-width="160" show-overflow-tooltip />
<el-table-column prop="departName" label="部门" min-width="140" />
</el-table>
<div class="pager pagination">
<el-pagination background :pager-count="5" layout="total, prev, pager, next, jumper" :page-size="stuTable.pageSize"
:current-page="stuTable.pageNo" :total="stuTable.total" @current-change="onStuPageChange" />
</div>
</div>
</div>
</div>
</el-tab-pane>
<el-tab-pane v-if="!selectStu" label="添加组织" name="org">
<div class="tab-search">
<span class="label">组织:</span>
<el-input v-model="searchOrgName.keyword" placeholder="请输入组织" size="small" clearable class="input"
@change="onOrgKeywordChange" />
<el-button type="primary" size="small" @click="searchOrg">
搜索
</el-button>
<el-button size="small" @click="resetOrg">重置</el-button>
</div>
<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" />
</el-tab-pane>
<el-tab-pane v-if="!selectStu" label="受众关联" name="audience">
<div class="tab-search">
<span class="label">受众名称:</span>
<el-input v-model="audienceName.keyword" placeholder="请输入受众名称" size="small" clearable class="input" />
<el-button type="primary" size="small" @click="searchAudience">
搜索
</el-button>
<el-button size="small" @click="resetAudienceInfo">重置</el-button>
</div>
<el-table
ref="audienceTable"
class="use-table"
border
:data="audienceTable.list"
@selection-change="onAudienceSelectionChange"
:row-key="row => row.id"
:reserve-selection="true"
>
<el-table-column type="selection" width="50" />
<el-table-column prop="audienceName" label="受众名称" min-width="220" />
<el-table-column prop="totalMember" label="总人数" width="100" />
<el-table-column prop="workMember" label="在职人数" width="120" />
</el-table>
<div class="pager pagination">
<el-pagination background :pager-count="5" layout="total, prev, pager, next, jumper" :page-size="audienceTable.pageSize"
:current-page="audienceTable.pageNo" :total="audienceTable.total"
@current-change="onAudiencePageChange" />
</div>
</el-tab-pane>
</el-tabs>
<div class="right1">
<div class="onerow">
<div class="onleft">
<div class="already">已选</div>
</div>
</div>
<div class="selected-area" :style="{ 'max-height': screenHeight - 235 + 'px' }" style="overflow-y: auto">
<div class="selecteds" v-if="infoType">
<div class="person">项目内学员</div>
<div v-for="(item, i) in projectSelectRows" :key="item.id || item.studentId">
<div v-if="i < 11">
<div class="chose">
{{ item.studentName }}
<div class="ch" @click="removeProject(item)"></div>
</div>
</div>
<div v-else>
<div v-if="member">
<div class="chose">
{{ item.studentName }}
<div class="ch" @click="removeProject(item)"></div>
</div>
</div>
</div>
</div>
<div v-if="!member && projectSelectRows.length > 10" class="ifsw">
<div @click="member = !member" class="sw">查看更多></div>
</div>
<div v-if="member && projectSelectRows.length > 10" class="ifsw">
<div @click="member = !member" class="sw">收起&lt;</div>
</div>
</div>
<div class="selecteds">
<div class="person">快速选人</div>
<div v-for="(item, i) in stuSelectRows" :key="item.id || item.userId">
<div v-if="i < 11">
<div class="chose">
{{ item.realName }}
<div class="ch" @click="removeStu(item)"></div>
</div>
</div>
<div v-else>
<div v-if="person">
<div class="chose">
{{ item.realName }}
<div class="ch" @click="removeStu(item)"></div>
</div>
</div>
</div>
</div>
<div v-if="!person && stuSelectRows.length > 10" class="ifsw">
<div @click="person = !person" class="sw">查看更多></div>
</div>
<div v-if="person && stuSelectRows.length > 10" class="ifsw">
<div @click="person = !person" class="sw">收起&lt;</div>
</div>
</div>
<div v-if="!selectStu" class="selecteds">
<div class="dept">添加组织</div>
<div v-for="(item, i) in deptList" :key="item.id">
<div v-if="i < 11">
<div class="chose1">
<div class="span">{{ item.name }}</div>
<div class="ch1" @click="removeOrg(item)" style="cursor: pointer;"></div>
</div>
</div>
<div v-else>
<div v-if="dept">
<div class="chose1">
<div class="span">{{ item.name }}</div>
<div class="ch1" @click="removeOrg(item)"></div>
</div>
</div>
</div>
</div>
<div v-if="!dept && deptList.length > 10" class="ifsw">
<div @click="dept = !dept" class="sw">查看更多></div>
</div>
<div v-if="dept && deptList.length > 10" class="ifsw">
<div @click="dept = !dept" class="sw">收起&lt;</div>
</div>
</div>
<div v-if="!selectStu" class="selecteds">
<div class="group">受众关联</div>
<div v-for="(item, i) in auditSelectRows" :key="item.id">
<div v-if="i < 11">
<div class="chose2">
<div class="span">{{ item.audienceName }}</div>
<div class="ch2" @click="removeAudience(item)"></div>
</div>
</div>
<div v-else>
<div v-if="group">
<div class="chose2">
<div class="span">{{ item.audienceName }}</div>
<div class="ch2" @click="removeAudience(item)"></div>
</div>
</div>
</div>
</div>
<div v-if="!group && auditSelectRows.length > 10" class="ifsw">
<div @click="group = !group" class="sw">查看更多></div>
</div>
<div v-if="group && auditSelectRows.length > 10" class="ifsw">
<div @click="group = !group" class="sw">收起&lt;</div>
</div>
</div>
</div>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="submitAuth">确 定</el-button>
</span>
<el-dialog :visible.sync="stageVisible" title="选择阶段" width="420px" append-to-body center>
<div class="stage-body">
<el-select v-model="stageId" placeholder="选择阶段" filterable style="width:100%">
<el-option v-for="item in stageIds" :key="item.id" :label="item.name || '默认'" :value="item.id" />
</el-select>
<div class="tip">已在其他关卡的学员,不会被添加到该关卡</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="stageVisible = false">取 消</el-button>
<el-button type="primary" @click="handleDialogOk">确 定</el-button>
</span>
</el-dialog>
</el-dialog>
</div>
</template>
<script>
import {
fetchOrgChildren,
fetchOrgList,
fetchProjectStudents,
fetchQuickStudents,
fetchUserAudiences,
saveStu,
} from "@/api/signup/commonStudent";
export default {
name: "SignupModal",
props: {
visible: { type: Boolean, default: false },
mode: { type: String, default: "plain" },
type: Number,
infoType: Number,
infoId: Number,
id: String,
title: { type: String, default: "" },
clear: { type: Boolean, default: false },
selectStu: { type: Boolean, default: false },
selectOne: { type: Boolean, default: false },
stage: { type: Array, default: () => [] },
isGroup: { type: Boolean, default: false },
projectId: { type: Number, default: null },
groupId: { type: Number, default: null },
groupName: { type: String, default: null },
groupMemberCount: { type: Number, default: null },
groupMemberNumber: { type: Number, default: null },
activeKey1: { type: String, default: null },
},
data() {
return {
courseDetail: JSON.parse(sessionStorage.getItem("courseDetail") || "{}"),
activeTab: this.infoType ? "project" : "quick",
stageVisible: false,
stageId: undefined,
projectParams: {
pid: this.infoId,
type: this.infoType,
studentName: "",
},
projectStu: { list: [], pageNo: 1, pageSize: 10, total: 0 },
stuTable: { list: [], pageNo: 1, pageSize: 10, total: 0 },
audienceTable: { list: [], pageNo: 1, pageSize: 10, total: 0 },
treeData: [],
orgList: [],
treeProps: { children: "treeChildList", label: "name" },
orgTreeProps: { children: "directChildList", label: "name" },
nameSearch: { keyword: "", departId: "" },
audienceName: { keyword: "" },
searchOrgName: { keyword: "", pageNo: 1, pageSize: 200 },
projectSelectRows: [],
stuSelectRows: [],
auditSelectRows: [],
deptList: [],
selectedOrgKeys: [],
// 右侧“已选”区域展开/收起控制,与 CommonStudent.vue 保持一致
member: false,
dept: false,
person: false,
group: false,
screenHeight: document.body.clientHeight,
};
},
computed: {
dialogTitle() {
return { 1: "添加学员", 2: "添加学员", 3: "添加学员" }[this.type] || this.title || "添加学员";
},
stageIds() {
return this.stage || [];
},
},
watch: {
visible(val) {
if (val) {
this.initData();
} else {
this.resetState();
}
},
},
mounted() {
if (this.visible) {
this.initData();
}
},
methods: {
// 参考 CommonStudent.vue在关闭弹窗时清空各种选中与搜索条件
resetState() {
this.projectParams.studentName = "";
this.nameSearch = { keyword: "", departId: "" };
this.audienceName = { keyword: "" };
this.searchOrgName = { keyword: "", pageNo: 1, pageSize: 200 };
this.projectSelectRows = [];
this.stuSelectRows = [];
this.auditSelectRows = [];
this.deptList = [];
this.selectedOrgKeys = [];
this.member = false;
this.dept = false;
this.person = false;
this.group = false;
// 清空表格勾选
if (this.$refs.stuTable && this.$refs.stuTable.clearSelection) {
this.$refs.stuTable.clearSelection();
}
if (this.$refs.audienceTable && this.$refs.audienceTable.clearSelection) {
this.$refs.audienceTable.clearSelection();
}
},
initData() {
this.courseDetail = JSON.parse(sessionStorage.getItem("courseDetail") || "{}");
this.projectParams = {
pid: this.infoId,
type: this.infoType,
studentName: "",
};
this.nameSearch = { keyword: "", departId: "" };
this.audienceName = { keyword: "" };
this.searchOrgName = { keyword: "", pageNo: 1, pageSize: 200 };
this.projectSelectRows = [];
this.stuSelectRows = [];
this.auditSelectRows = [];
this.deptList = [];
this.selectedOrgKeys = [];
this.activeTab = this.infoType ? "project" : "quick";
// this.getProjectStu();
this.fetchOrgTree();
this.onSearchStu();
this.searchAudience();
this.searchOrg();
},
handleClose() {
// 通过父组件的 :visible.sync 控制关闭
this.$emit("update:visible", false);
},
getProjectStu() {
fetchProjectStudents({
...this.projectParams,
pageNo: this.projectStu.pageNo,
pageSize: this.projectStu.pageSize,
}).then((res) => {
this.projectStu.list = res.data?.list || [];
this.projectStu.total = res.data?.total || 0;
});
},
onProjectPageChange(page) {
this.projectStu.pageNo = page;
this.getProjectStu();
},
onProjectSelectionChange(list) {
this.projectSelectRows = list;
},
resetProjectStu() {
this.projectParams.studentName = "";
this.getProjectStu();
},
/**
* 获取“快速选人”列表
* @param {Boolean} resetPage 是否重置到第 1 页(新的搜索条件或重置时需要)
*/
onSearchStu(resetPage = false) {
// 当关键字、组织等搜索条件变化或点击“搜索”按钮时,应将页码重置为 1
if (resetPage) {
this.stuTable.pageNo = 1;
}
fetchQuickStudents({
...this.nameSearch,
pageNo: this.stuTable.pageNo,
pageSize: this.stuTable.pageSize,
}).then((res) => {
console.log("res", res);
this.stuTable.list = res.data?.list || [];
this.stuTable.total = res.data?.total || 0;
// 根据右侧已选,恢复当前页的勾选状态
this.$nextTick(() => {
this.syncStuTableSelection();
});
});
},
onStuPageChange(page) {
this.stuTable.pageNo = page;
this.onSearchStu();
},
onStuSelectionChange(list) {
// Element 表格在翻页时会把当前页的 selection 通过 list 传进来
// 为了保留其他页已选,这里做合并而不是直接覆盖
const currentPageIds = this.stuTable.list.map((r) => r.id || r.userId);
// 先保留非当前页的已选
const otherPageSelected = this.stuSelectRows.filter(
(r) => !currentPageIds.includes(r.id || r.userId)
);
const merged = [...otherPageSelected, ...list];
// 根据 id/userId 去重
const seen = new Set();
this.stuSelectRows = merged.filter((r) => {
const key = r.id || r.userId;
if (!key || seen.has(key)) return false;
seen.add(key);
return true;
});
},
resetStu() {
this.nameSearch = { keyword: "", departId: "" };
// 重置时也应从第 1 页重新加载
this.stuTable.pageNo = 1;
this.onSearchStu();
},
fetchOrgTree() {
fetchOrgList({ keyword: "" }).then((res) => {
this.treeData = res.data || res.result || res || [];
});
},
loadOrgNode(node, resolve) {
if (node.level === 0) {
return resolve(this.treeData);
}
fetchOrgChildren({ orgId: node.data.id, keyword: "" }).then((res) => {
resolve(res.data || res.result || res || []);
});
},
onOrgSelect(node) {
this.nameSearch.departId = node.id;
this.onSearchStu();
},
searchOrg() {
fetchOrgList(this.searchOrgName).then((res) => {
this.orgList = res.data || res.result || res || [];
});
},
resetOrg() {
// 重置组织搜索条件并刷新组织树
this.searchOrgName = { keyword: "", pageNo: 1, pageSize: 200 };
this.searchOrg();
},
onOrgKeywordChange() {
this.searchOrg();
},
loadOrgNodeFull(node, resolve) {
if (node.level === 0) {
return resolve(this.orgList);
}
fetchOrgChildren({ orgId: node.data.id, keyword: "" }).then((res) => {
resolve(res.data || res.result || res || []);
});
},
onOrgCheckChange(data, checked) {
if (checked) {
if (!this.deptList.find((d) => d.id === data.id)) {
this.deptList.push(data);
}
} else {
this.deptList = this.deptList.filter((d) => d.id !== data.id);
}
this.selectedOrgKeys = this.deptList.map((d) => d.id);
},
searchAudience() {
fetchUserAudiences({
...this.audienceName,
pageNo: this.audienceTable.pageNo,
pageSize: this.audienceTable.pageSize,
}).then((res) => {
console.log('searchAudience', res);
this.audienceTable.list = res.data?.list || [];
this.audienceTable.total = res.data?.total || 0;
// 根据右侧已选,恢复当前页的受众勾选状态
this.$nextTick(() => {
this.syncAudienceTableSelection();
});
});
},
onAudiencePageChange(page) {
this.audienceTable.pageNo = page;
this.searchAudience();
},
onAudienceSelectionChange(list) {
const currentPageIds = this.audienceTable.list.map((r) => r.id);
const otherPageSelected = this.auditSelectRows.filter(
(r) => !currentPageIds.includes(r.id)
);
const merged = [...otherPageSelected, ...list];
const seen = new Set();
this.auditSelectRows = merged.filter((r) => {
const key = r.id;
if (!key || seen.has(key)) return false;
seen.add(key);
return true;
});
},
// 根据 stuSelectRows 恢复当前页表格里的勾选
syncStuTableSelection() {
if (!this.$refs.stuTable) return;
const table = this.$refs.stuTable;
if (!table.clearSelection || !table.toggleRowSelection) return;
const selectedMap = new Set(
(this.stuSelectRows || []).map((r) => r.id || r.userId)
);
table.clearSelection();
this.stuTable.list.forEach((row) => {
const key = row.id || row.userId;
if (key && selectedMap.has(key)) {
table.toggleRowSelection(row, true);
}
});
},
// 根据 auditSelectRows 恢复当前页受众表格里的勾选
syncAudienceTableSelection() {
if (!this.$refs.audienceTable) return;
const table = this.$refs.audienceTable;
if (!table.clearSelection || !table.toggleRowSelection) return;
const selectedMap = new Set(
(this.auditSelectRows || []).map((r) => r.id)
);
table.clearSelection();
this.audienceTable.list.forEach((row) => {
const key = row.id;
if (key && selectedMap.has(key)) {
table.toggleRowSelection(row, true);
}
});
},
resetAudienceInfo() {
this.audienceName.keyword = "";
this.searchAudience();
},
onOrgSelectChange() { },
removeProject(item) {
this.projectSelectRows = this.projectSelectRows.filter(
(i) => (i.id || i.studentId) !== (item.id || item.studentId)
);
},
removeStu(item) {
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) {
this.stageVisible = true;
} else {
this.handleDialogOk();
}
},
handleDialogOk() {
if (
this.type === 1 &&
this.groupId &&
this.groupMemberCount &&
this.groupMemberNumber &&
this.groupMemberCount < this.groupMemberNumber + this.projectSelectRows.length + this.stuSelectRows.length
) {
return this.$showManageMessage("添加小组学员超过最大值", 'error');
}
saveStu({
targetId: this.courseDetail?.id || this.id,
type: 13,
deptIds: this.deptList.map((e) => e.id),
groupIds: this.auditSelectRows.map((e) => e.id),
studentList: this.stuSelectRows.map((e) => ({id: e.id, realName: e.realName})),
}).then((res) => {
console.log('res', res);
this.$showManageMessage("添加成功", 'success');
this.$emit("confirm");
this.handleClose();
});
},
},
};
</script>
<style lang="scss" scoped>
.signup-dialog ::v-deep .el-dialog__body {
padding-top: 10px;
padding: 10px 20px 30px 20px;
}
::v-deep .el-tabs__nav {
.el-tabs__item {
color: #3b7cff;
}
.el-tabs__active-bar {
// width: 60px !important;
height: 1px;
background-color: #3b7cff;
}
}
.signup-wrap {
display: flex;
gap: 16px;
}
.el-tabs {
flex: 1;
}
.tab-search {
display: flex;
align-items: center;
margin-bottom: 12px;
.label {
margin-right: 8px;
color: #666;
}
.input {
width: 240px;
margin-right: 12px;
}
}
.split {
display: grid;
grid-template-columns: 250px minmax(0, 660px);
gap: 12px;
}
.left-tree {
height: 100%;
border: 1px solid #f0f0f0;
padding: 8px;
overflow: auto;
}
.table-area {
}
.pager {
margin-top: 10px;
text-align: right;
}
.right1 {
border-left: 1px solid #f2f6fe;
margin-left: 20px;
width: 200px;
.selected-area {
&::-webkit-scrollbar-thumb {
border-radius: 4px;
background-color: #4284F7;
}
&::-webkit-scrollbar {
width: 6px;
height: 6px;
background-color:rgba(0, 0, 0, .1);
border-radius: 4px;
}
&::-webkit-scrollbar-thumb {
border-radius: 4px;
background-color: #4284F7
}
}
.onerow {
display: flex;
justify-content: space-between;
align-items: center;
margin-right: 40px;
flex-wrap: wrap;
width: 100%;
.onleft {
display: flex;
text-align: center;
.already {
color: rgba(51, 51, 51, 1);
font-size: 16px;
font-weight: 500;
margin-left: 32px;
white-space: nowrap;
}
}
}
.selecteds {
display: flex;
flex-wrap: wrap;
margin-left: 32px;
.person {
width: 100%;
margin-top: 20px;
border-top: 1px solid #f2f6fe;
}
.chose {
width: 64px;
height: 24px;
margin-top: 25px;
margin-right: 18px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 2px;
border: 1px solid rgba(56, 139, 225, 1);
color: rgba(56, 139, 225, 1);
font-size: 12px;
position: relative;
.ch {
position: absolute;
width: 18px;
height: 18px;
background-image: url(../../assets/images/basicinfo/ch.png);
background-size: 100%;
right: -8px;
top: -8px;
}
}
.ifsw {
display: flex;
align-items: end;
justify-content: center;
color: #4ea6ff;
}
.sw {
display: flex;
align-items: center;
justify-content: center;
text-align: justify;
color: #4ea6ff;
margin-top: 23px;
margin-left: 10px;
cursor: pointer;
}
.dept {
width: 100%;
margin-top: 30px;
border-top: 1px solid #f2f6fe;
}
.chose1 {
height: 24px;
margin-top: 25px;
margin-right: 25px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 2px;
border: 1px solid rgba(56, 139, 225, 1);
color: rgba(56, 139, 225, 1);
font-size: 12px;
position: relative;
.span {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.ch1 {
position: absolute;
width: 18px;
height: 18px;
background-image: url(../../assets/images/basicinfo/ch.png);
background-size: 100%;
right: -8px;
top: -8px;
}
}
.group {
width: 100%;
margin-top: 30px;
border-top: 1px solid #f2f6fe;
}
.chose2 {
height: 24px;
margin-top: 25px;
margin-right: 25px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 2px;
border: 1px solid rgba(56, 139, 225, 1);
color: rgba(56, 139, 225, 1);
font-size: 12px;
position: relative;
.span {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.ch2 {
position: absolute;
width: 18px;
height: 18px;
background-image: url(../../assets/images/basicinfo/ch.png);
background-size: 100%;
right: -8px;
top: -8px;
}
}
}
}
.org-tree {
max-height: 520px;
overflow: auto;
padding: 8px 12px;
border: 1px solid #f0f0f0;
}
.stage-body {
.tip {
margin-top: 12px;
color: #999;
font-size: 12px;
}
}
</style>