- 系统部门:自写 table 换成 iView Table(border + 表头灰底 + 行 hover), 层级仍用名称列缩进 + 折叠;状态改为可点击的边框 Tag(已启用/已停用) - 标题行:去掉 SYSTEM / CUSTOM 英文,「包含子组」移到来源切换左侧并整体右对齐, 切换视图时标签位置不再左右跳动 - 自定义部门:同样换 iView Table;表格内不再拖行,改为「排序管理」按钮 + 弹框拖动, 保存后按新顺序提交 customDeptSort;操作列保留 编辑/成员/删除 - 修正 Tag 上的 @click.native(Vue 3 已移除 .native)
This commit is contained in:
+139
-187
@@ -18,17 +18,19 @@
|
||||
<Option v-for="s in schoolOptions" :key="s.id" :value="s.id">{{ s.name }}</Option>
|
||||
</Select>
|
||||
<!-- 来源切换:只切右侧管理视图,学校上下文共用,不改底层组织树 -->
|
||||
<div class="source-tabs ml-auto">
|
||||
<span class="source-tab" :class="{ 'is-active': source === 'SYSTEM' }"
|
||||
@click="source = 'SYSTEM'">系统部门 SYSTEM</span>
|
||||
<span class="source-tab" :class="{ 'is-active': source === 'CUSTOM' }"
|
||||
@click="source = 'CUSTOM'">自定义部门 CUSTOM</span>
|
||||
<div class="title-tail">
|
||||
<span v-if="source === 'SYSTEM'" class="inc-ctrl" title="打开后列出该校下所有层级的部门"
|
||||
@click="toggleInclude">
|
||||
<span class="inc-label">包含子组</span>
|
||||
<i class="sw-mini" :class="{ 'is-on': includeOn }"></i>
|
||||
</span>
|
||||
<div class="source-tabs">
|
||||
<span class="source-tab" :class="{ 'is-active': source === 'SYSTEM' }"
|
||||
@click="source = 'SYSTEM'">系统部门</span>
|
||||
<span class="source-tab" :class="{ 'is-active': source === 'CUSTOM' }"
|
||||
@click="source = 'CUSTOM'">自定义部门</span>
|
||||
</div>
|
||||
</div>
|
||||
<span v-if="source === 'SYSTEM'" class="inc-ctrl" title="打开后列出该校下所有层级的部门"
|
||||
@click="toggleInclude">
|
||||
<span class="inc-label">包含子组</span>
|
||||
<i class="sw-mini" :class="{ 'is-on': includeOn }"></i>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<template v-if="source === 'SYSTEM'">
|
||||
@@ -47,50 +49,30 @@
|
||||
|
||||
<template v-else>
|
||||
<div class="row-sum">{{ deptRows.length }} 个一级部门 · 共 {{ flatRows.length }} 行</div>
|
||||
<table class="dept-table">
|
||||
<colgroup>
|
||||
<col style="width: 58px" />
|
||||
<col />
|
||||
<col style="width: 120px" />
|
||||
<col style="width: 268px" />
|
||||
<col style="width: 74px" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="ta-c">序号</th>
|
||||
<th>部门名称</th>
|
||||
<th>上级</th>
|
||||
<th>人员</th>
|
||||
<th class="ta-c">状态</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="row in flatRows" :key="row.id" :class="{ 'is-off': row.status === 1 }">
|
||||
<td class="ta-c dim">{{ row.no }}</td>
|
||||
<td>
|
||||
<span class="nmcell" :style="{ paddingLeft: row.level * 20 + 'px' }">
|
||||
<i v-if="row.kidCount" class="tw" @click="toggleRow(row.id)">{{ row.open ? '▾' : '▸' }}</i>
|
||||
<i v-else class="tw blank"></i>
|
||||
<span class="nm" :class="{ root: row.level === 0 }" :title="row.name">{{ row.name }}</span>
|
||||
<span v-if="row.kidCount" class="cnt">{{ row.kidCount }} 个下级</span>
|
||||
<span v-if="row.isStudent" class="cnt grey">学生组</span>
|
||||
</span>
|
||||
</td>
|
||||
<td class="dim" :title="row.parentName">{{ row.parentName }}</td>
|
||||
<td>
|
||||
<Tooltip v-if="row.memberCount" placement="top" max-width="360"
|
||||
:content="memberTip(row)">
|
||||
<span class="mem-cell" @click="openMembers(row)">{{ memberText(row) }}</span>
|
||||
</Tooltip>
|
||||
<span v-else class="dim">无成员</span>
|
||||
</td>
|
||||
<td class="ta-c">
|
||||
<i class="sw" :class="{ 'is-on': row.status !== 1 }"
|
||||
:title="row.status === 1 ? '启用' : '停用'" @click="onToggle(row.raw)"></i>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<Table class="dept-itable" border :columns="sysColumns" :data="flatRows"
|
||||
:row-class-name="rowClassName" :loading="false" no-data-text="暂无部门">
|
||||
<template #name="{ row }">
|
||||
<span class="nmcell" :style="{ paddingLeft: row.level * 20 + 'px' }">
|
||||
<i v-if="row.kidCount" class="tw" @click.stop="toggleRow(row.id)">{{ row.open ? '▾' : '▸' }}</i>
|
||||
<i v-else class="tw blank"></i>
|
||||
<span class="nm" :class="{ root: row.level === 0 }" :title="row.name">{{ row.name }}</span>
|
||||
<span v-if="row.kidCount" class="cnt">{{ row.kidCount }} 个下级</span>
|
||||
<span v-if="row.isStudent" class="cnt grey">学生组</span>
|
||||
</span>
|
||||
</template>
|
||||
<template #members="{ row }">
|
||||
<Tooltip v-if="row.memberCount" placement="top" max-width="360" :content="memberTip(row)">
|
||||
<span class="mem-cell" @click="openMembers(row)">{{ memberText(row) }}</span>
|
||||
</Tooltip>
|
||||
<span v-else class="dim">无成员</span>
|
||||
</template>
|
||||
<template #status="{ row }">
|
||||
<Tag type="border" :color="row.status === 1 ? 'error' : 'success'" class="sta-tag"
|
||||
:title="row.status === 1 ? '点击启用' : '点击停用'" @click="onToggle(row.raw)">
|
||||
{{ row.status === 1 ? '已停用' : '已启用' }}
|
||||
</Tag>
|
||||
</template>
|
||||
</Table>
|
||||
<div class="table-foot">共 {{ flatRows.length }} 个部门</div>
|
||||
</template>
|
||||
</template>
|
||||
@@ -240,6 +222,19 @@ const flatRows = computed<DeptRow[]>(() => {
|
||||
return out;
|
||||
});
|
||||
|
||||
/** iView Table 列定义:层级用「部门名称」列的缩进 + 折叠表达,不用 Table 自带树(避免样式不可控) */
|
||||
const sysColumns: any[] = [
|
||||
{ title: "序号", type: "index", width: 80, align: "center" },
|
||||
{ title: "部门名称", slot: "name", minWidth: 300 },
|
||||
{ title: "上级", key: "parentName", width: 160 },
|
||||
{ title: "人员", slot: "members", minWidth: 320 },
|
||||
{ title: "状态", slot: "status", width: 120, align: "center" },
|
||||
];
|
||||
/** 停用行整行灰化 */
|
||||
function rowClassName(row: any) {
|
||||
return row?.status === 1 ? "is-off" : "";
|
||||
}
|
||||
|
||||
/** 人员列:前 3 个姓名 + 剩余数;无姓名时退回「N 人」 */
|
||||
function memberText(row: DeptRow) {
|
||||
if (!row.memberNames.length) return `${row.memberCount} 人`;
|
||||
@@ -477,6 +472,14 @@ async function loadSchoolScope() {
|
||||
color: var(--text, #1e2635);
|
||||
}
|
||||
|
||||
/* 标题行右侧:包含子组 + 来源切换,整体右对齐;「包含子组」放左边,切视图时 tab 位置不跳 */
|
||||
.title-tail {
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.school-select {
|
||||
width: 180px;
|
||||
}
|
||||
@@ -570,7 +573,7 @@ async function loadSchoolScope() {
|
||||
}
|
||||
}
|
||||
|
||||
/* ================= 部门表格 ================= */
|
||||
/* ================= 部门表格(iView Table) ================= */
|
||||
.row-sum {
|
||||
flex: 0 0 auto;
|
||||
margin-bottom: 8px;
|
||||
@@ -578,147 +581,96 @@ async function loadSchoolScope() {
|
||||
color: var(--text-3, #98a1b2);
|
||||
}
|
||||
|
||||
.dept-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed;
|
||||
font-size: 12.5px;
|
||||
color: var(--text, #1e2635);
|
||||
|
||||
th {
|
||||
height: 40px;
|
||||
padding: 0 12px;
|
||||
background: #f7f8fa;
|
||||
border-bottom: 1px solid var(--line, #e9edf5);
|
||||
color: var(--text-2, #5a6478);
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
/* 表格本体外观全部交给 iView:只补单元格内部的排版细节 */
|
||||
.dept-itable {
|
||||
:deep(.ivu-table-cell) {
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
}
|
||||
|
||||
td {
|
||||
height: 46px;
|
||||
padding: 0 12px;
|
||||
border-bottom: 1px solid var(--line, #e9edf5);
|
||||
vertical-align: middle;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
tbody tr:hover td {
|
||||
background: #fafbfe;
|
||||
}
|
||||
|
||||
tbody tr.is-off td {
|
||||
:deep(.ivu-table-row.is-off td) {
|
||||
background: #fcfcfd;
|
||||
}
|
||||
|
||||
.ta-c {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dim {
|
||||
color: var(--text-3, #98a1b2);
|
||||
font-size: 11.5px;
|
||||
}
|
||||
|
||||
.nmcell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.tw {
|
||||
flex: 0 0 auto;
|
||||
width: 14px;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
font-size: 9px;
|
||||
color: #aeb6c2;
|
||||
cursor: pointer;
|
||||
|
||||
&.blank {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.nm {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
&.root {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
tr.is-off .nm {
|
||||
color: var(--text-3, #98a1b2);
|
||||
}
|
||||
|
||||
.cnt {
|
||||
flex: 0 0 auto;
|
||||
padding: 0 5px;
|
||||
line-height: 16px;
|
||||
border-radius: 4px;
|
||||
background: #f1f3f7;
|
||||
color: #8a94a6;
|
||||
font-size: 10.5px;
|
||||
|
||||
&.grey {
|
||||
background: #f6f7fa;
|
||||
color: #a3adbd;
|
||||
}
|
||||
}
|
||||
|
||||
.mem-cell {
|
||||
cursor: pointer;
|
||||
color: var(--text-2, #5a6478);
|
||||
border-bottom: 1px dashed transparent;
|
||||
|
||||
&:hover {
|
||||
color: var(--brand, #577afb);
|
||||
border-bottom-color: #c9d4f7;
|
||||
}
|
||||
}
|
||||
|
||||
/* 胶囊开关(与小组件管理同款比例) */
|
||||
.sw {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 30px;
|
||||
height: 17px;
|
||||
border-radius: 9px;
|
||||
background: #d5d8de;
|
||||
cursor: pointer;
|
||||
transition: background .18s;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, .2);
|
||||
transition: left .18s;
|
||||
}
|
||||
|
||||
&.is-on {
|
||||
background: var(--brand, #577afb);
|
||||
|
||||
&::after {
|
||||
left: 15px;
|
||||
}
|
||||
}
|
||||
:deep(.ivu-table-row.is-off:hover td) {
|
||||
background: #f8f9fb;
|
||||
}
|
||||
}
|
||||
|
||||
.nmcell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.nmcell .tw {
|
||||
flex: 0 0 auto;
|
||||
width: 14px;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
font-size: 9px;
|
||||
color: #aeb6c2;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.nmcell .tw.blank {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.nmcell .nm {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nmcell .nm.root {
|
||||
font-weight: 600;
|
||||
color: var(--text, #1e2635);
|
||||
}
|
||||
|
||||
.nmcell .cnt {
|
||||
flex: 0 0 auto;
|
||||
padding: 0 5px;
|
||||
line-height: 16px;
|
||||
border-radius: 4px;
|
||||
background: #f1f3f7;
|
||||
color: #8a94a6;
|
||||
font-size: 10.5px;
|
||||
}
|
||||
|
||||
.nmcell .cnt.grey {
|
||||
background: #f6f7fa;
|
||||
color: #a3adbd;
|
||||
}
|
||||
|
||||
.mem-cell {
|
||||
cursor: pointer;
|
||||
color: var(--text-2, #5a6478);
|
||||
border-bottom: 1px dashed transparent;
|
||||
}
|
||||
|
||||
.mem-cell:hover {
|
||||
color: var(--brand, #577afb);
|
||||
border-bottom-color: #c9d4f7;
|
||||
}
|
||||
|
||||
.dim {
|
||||
color: var(--text-3, #98a1b2);
|
||||
font-size: 11.5px;
|
||||
}
|
||||
|
||||
/* 状态标签可点:hover 给一点反馈,暗示能切换 */
|
||||
.sta-tag {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sta-tag:hover {
|
||||
opacity: .82;
|
||||
}
|
||||
|
||||
|
||||
.table-foot {
|
||||
flex: 0 0 auto;
|
||||
padding: 10px 2px;
|
||||
|
||||
Reference in New Issue
Block a user