build / build (push) Successful in 2m53s
- 系统部门:卡片网格改为表格(序号/部门名称/上级/人员/状态),层级用缩进+折叠表达; 去掉新增、排序与操作列,只保留启停与「包含子组」 - 人员列:memberCount + memberNames 前 3 个姓名 + N,Tooltip 展示完整预览, 点击弹窗分页查看全部(/api/sysuser/List?groupId=,不传 withSub 只看直属) - 自定义部门:卡片改表格(序号/名称/人员/状态/操作),行拖动排序沿用 customDeptSort, 分类列表支持拖动(customDeptCategorySort),原有新增/编辑/删除/成员/上下移保留 - DeptCard.vue、CustomDeptCard.vue 标记为已废弃(无引用,可安全删除)
201 lines
4.7 KiB
Vue
201 lines
4.7 KiB
Vue
<!-- 自定义部门卡片(已被 CustomDeptPanel.vue 的表格取代,2026-10-23)。保留文件仅作参考,无任何引用,可安全删除。 -->
|
||
<template>
|
||
<article class="cdept-card" :class="{ 'is-off': !dept.enabled }">
|
||
<div class="row-1">
|
||
<span class="status-dot" :class="{ 'is-off': !dept.enabled }"></span>
|
||
<h3 class="card-name" :title="dept.name">{{ dept.name }}</h3>
|
||
<span class="sw" :class="{ 'is-off': !dept.enabled }" :title="dept.enabled ? '点击停用' : '点击启用'"
|
||
@click="emit('toggle', dept)"></span>
|
||
</div>
|
||
<div class="row-2">
|
||
<span class="sub">{{ memberText }}</span>
|
||
<span class="ops">
|
||
<i class="op" :class="{ 'is-disabled': !canMoveUp }" title="上移" @click="emit('moveUp')">↑</i>
|
||
<i class="op" :class="{ 'is-disabled': !canMoveDown }" title="下移" @click="emit('moveDown')">↓</i>
|
||
<a class="link" @click="emit('members', dept)">成员</a>
|
||
<a class="link" @click="emit('edit', dept)">编辑</a>
|
||
<a class="link danger" @click="emit('remove', dept)">删除</a>
|
||
</span>
|
||
</div>
|
||
</article>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
import { computed } from "vue";
|
||
import type { CustomDepartmentVo } from "@/api/globals";
|
||
|
||
/**
|
||
* CUSTOM 部门卡片:与 SYSTEM 的 DeptCard 同款外观,但字段来自 ub_custom_department。
|
||
* 停用在管理端照常可见(灰态),软删的部门由后端列表过滤、不会走到这里。
|
||
*/
|
||
const props = defineProps<{
|
||
dept: CustomDepartmentVo;
|
||
canMoveUp?: boolean;
|
||
canMoveDown?: boolean;
|
||
}>();
|
||
|
||
const emit = defineEmits<{
|
||
(e: "toggle", dept: CustomDepartmentVo): void;
|
||
(e: "edit", dept: CustomDepartmentVo): void;
|
||
(e: "remove", dept: CustomDepartmentVo): void;
|
||
(e: "members", dept: CustomDepartmentVo): void;
|
||
(e: "moveUp"): void;
|
||
(e: "moveDown"): void;
|
||
}>();
|
||
|
||
const memberText = computed(() => {
|
||
const count = Number(props.dept?.memberCount ?? 0);
|
||
if (!props.dept?.enabled) return count ? `已停用 · ${count} 人` : "已停用 · 无成员";
|
||
return count ? `${count} 人` : "无成员(可先建部门再配人)";
|
||
});
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.cdept-card {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 9px;
|
||
padding: 13px 14px;
|
||
background: var(--panel, #fff);
|
||
border: 1px solid var(--line, #e9edf5);
|
||
border-radius: var(--r, 10px);
|
||
box-shadow: 0 1px 2px rgba(30, 38, 53, .03);
|
||
transition: border-color .15s, box-shadow .15s;
|
||
}
|
||
|
||
.cdept-card:hover {
|
||
border-color: #dbe2fb;
|
||
box-shadow: 0 6px 18px rgba(30, 38, 53, .07);
|
||
}
|
||
|
||
.cdept-card.is-off {
|
||
background: #fbfcfd;
|
||
border-style: dashed;
|
||
}
|
||
|
||
.row-1 {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.status-dot {
|
||
flex: 0 0 6px;
|
||
width: 6px;
|
||
height: 6px;
|
||
border-radius: 50%;
|
||
background: var(--green, #20a162);
|
||
}
|
||
|
||
.status-dot.is-off {
|
||
background: #cbd2df;
|
||
}
|
||
|
||
.card-name {
|
||
flex: 1;
|
||
min-width: 0;
|
||
margin: 0;
|
||
font-size: 15px;
|
||
font-weight: 600;
|
||
line-height: 1.4;
|
||
color: var(--text, #1e2635);
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.cdept-card.is-off .card-name {
|
||
color: var(--text-3, #98a1b2);
|
||
}
|
||
|
||
.row-2 {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
min-height: 26px;
|
||
margin-top: auto;
|
||
padding-top: 9px;
|
||
border-top: 1px dashed var(--line-2, #f0f3f9);
|
||
font-size: 12px;
|
||
color: var(--text-3, #98a1b2);
|
||
}
|
||
|
||
.row-2 .sub {
|
||
flex: 1;
|
||
min-width: 0;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.ops {
|
||
flex: 0 0 auto;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.link {
|
||
color: var(--brand, #577afb);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.link.danger {
|
||
color: #e54545;
|
||
}
|
||
|
||
.op {
|
||
font-style: normal;
|
||
font-size: 12px;
|
||
line-height: 18px;
|
||
width: 18px;
|
||
text-align: center;
|
||
border-radius: 4px;
|
||
color: var(--text-2, #5a6478);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.op:hover {
|
||
background: #e8ecfa;
|
||
color: var(--brand, #577afb);
|
||
}
|
||
|
||
.op.is-disabled {
|
||
color: #d3d9e6;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
/* 启停开关(与 SYSTEM 卡片同一套视觉) */
|
||
.sw {
|
||
position: relative;
|
||
flex: 0 0 auto;
|
||
width: 36px;
|
||
height: 20px;
|
||
border-radius: 10px;
|
||
background: var(--brand, #577afb);
|
||
cursor: pointer;
|
||
transition: background .15s;
|
||
}
|
||
|
||
.sw::after {
|
||
content: '';
|
||
position: absolute;
|
||
top: 2px;
|
||
left: 18px;
|
||
width: 16px;
|
||
height: 16px;
|
||
border-radius: 50%;
|
||
background: #fff;
|
||
box-shadow: 0 1px 3px rgba(30, 38, 53, .22);
|
||
transition: left .15s;
|
||
}
|
||
|
||
.sw.is-off {
|
||
background: #d3d9e6;
|
||
}
|
||
|
||
.sw.is-off::after {
|
||
left: 2px;
|
||
}
|
||
</style>
|