Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
E
EMS
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
hejie
EMS
Commits
af5ff054
提交
af5ff054
authored
4月 21, 2025
作者:
詹银鑫
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: 添加部门管理菜单和内容并联调列表展示接口
上级
cebb93cf
隐藏空白字符变更
内嵌
并排
正在显示
7 个修改的文件
包含
596 行增加
和
17 行删除
+596
-17
system.ts
src/api/system.ts
+16
-1
form.vue
src/views/systems/dep/form.vue
+139
-0
hooks.ts
src/views/systems/dep/hooks.ts
+39
-0
index.vue
src/views/systems/dep/index.vue
+164
-16
hook.tsx
src/views/systems/dep/utils/hook.tsx
+185
-0
rule.ts
src/views/systems/dep/utils/rule.ts
+37
-0
types.ts
src/views/systems/dep/utils/types.ts
+16
-0
没有找到文件。
src/api/system.ts
浏览文件 @
af5ff054
...
...
@@ -44,9 +44,24 @@ export const getMenuList = (data?: object) => {
return
http
.
request
<
Result
>
(
"post"
,
"/menu"
,
{
data
});
};
// {
// name: "杭州总公司",
// parentId: 0,
// id: 100,
// sort: 0,
// phone: "15888888888",
// principal: faker.person.firstName(),
// email: faker.internet.email(),
// status: 1, // 状态 1 启用 0 停用
// type: 1, // 1 公司 2 分公司 3 部门
// createTime: 1605456000000,
// remark: "这里是备注信息这里是备注信息这里是备注信息这里是备注信息"
// },
/** 获取系统管理-部门管理列表 */
export
const
getDeptList
=
(
data
?:
object
)
=>
{
return
http
.
request
<
Result
>
(
"post"
,
"/dept"
,
{
data
});
return
http
.
request
<
Result
>
(
"post"
,
"/api/depart/get-depart-list-by-page"
,
{
data
});
};
/** 获取系统监控-在线用户列表 */
...
...
src/views/systems/dep/form.vue
0 → 100644
浏览文件 @
af5ff054
<
script
setup
lang=
"ts"
>
import
{
ref
}
from
"vue"
;
import
ReCol
from
"@/components/ReCol"
;
import
{
formRules
}
from
"./utils/rule"
;
import
{
FormProps
}
from
"./utils/types"
;
import
{
usePublicHooks
}
from
"./hooks"
;
const
props
=
withDefaults
(
defineProps
<
FormProps
>
(),
{
formInline
:
()
=>
({
higherDeptOptions
:
[],
parentId
:
0
,
name
:
""
,
principal
:
""
,
phone
:
""
,
email
:
""
,
sort
:
0
,
status
:
1
,
remark
:
""
})
});
const
ruleFormRef
=
ref
();
const
{
switchStyle
}
=
usePublicHooks
();
const
newFormInline
=
ref
(
props
.
formInline
);
function
getRef
()
{
return
ruleFormRef
.
value
;
}
defineExpose
({
getRef
});
</
script
>
<
template
>
<el-form
ref=
"ruleFormRef"
:model=
"newFormInline"
:rules=
"formRules"
label-width=
"82px"
>
<el-row
:gutter=
"30"
>
<re-col>
<el-form-item
label=
"上级部门"
>
<el-cascader
v-model=
"newFormInline.parentId"
class=
"w-full"
:options=
"newFormInline.higherDeptOptions"
:props=
"
{
value: 'id',
label: 'name',
emitPath: false,
checkStrictly: true
}"
clearable
filterable
placeholder="请选择上级部门"
>
<template
#
default=
"
{ node, data }">
<span>
{{
data
.
name
}}
</span>
<span
v-if=
"!node.isLeaf"
>
(
{{
data
.
children
.
length
}}
)
</span>
</
template
>
</el-cascader>
</el-form-item>
</re-col>
<re-col
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"部门名称"
prop=
"name"
>
<el-input
v-model=
"newFormInline.name"
clearable
placeholder=
"请输入部门名称"
/>
</el-form-item>
</re-col>
<re-col
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"部门负责人"
>
<el-input
v-model=
"newFormInline.principal"
clearable
placeholder=
"请输入部门负责人"
/>
</el-form-item>
</re-col>
<re-col
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"手机号"
prop=
"phone"
>
<el-input
v-model=
"newFormInline.phone"
clearable
placeholder=
"请输入手机号"
/>
</el-form-item>
</re-col>
<re-col
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"邮箱"
prop=
"email"
>
<el-input
v-model=
"newFormInline.email"
clearable
placeholder=
"请输入邮箱"
/>
</el-form-item>
</re-col>
<re-col
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"排序"
>
<el-input-number
v-model=
"newFormInline.sort"
class=
"w-full!"
:min=
"0"
:max=
"9999"
controls-position=
"right"
/>
</el-form-item>
</re-col>
<re-col
:value=
"12"
:xs=
"24"
:sm=
"24"
>
<el-form-item
label=
"部门状态"
>
<el-switch
v-model=
"newFormInline.status"
inline-prompt
:active-value=
"1"
:inactive-value=
"0"
active-text=
"启用"
inactive-text=
"停用"
:style=
"switchStyle"
/>
</el-form-item>
</re-col>
<re-col>
<el-form-item
label=
"备注"
>
<el-input
v-model=
"newFormInline.remark"
placeholder=
"请输入备注信息"
type=
"textarea"
/>
</el-form-item>
</re-col>
</el-row>
</el-form>
</template>
src/views/systems/dep/hooks.ts
0 → 100644
浏览文件 @
af5ff054
// 抽离可公用的工具函数等用于系统管理页面逻辑
import
{
computed
}
from
"vue"
;
import
{
useDark
}
from
"@pureadmin/utils"
;
export
function
usePublicHooks
()
{
const
{
isDark
}
=
useDark
();
const
switchStyle
=
computed
(()
=>
{
return
{
"--el-switch-on-color"
:
"#6abe39"
,
"--el-switch-off-color"
:
"#e84749"
};
});
const
tagStyle
=
computed
(()
=>
{
return
(
status
:
number
)
=>
{
return
status
===
1
?
{
"--el-tag-text-color"
:
isDark
.
value
?
"#6abe39"
:
"#389e0d"
,
"--el-tag-bg-color"
:
isDark
.
value
?
"#172412"
:
"#f6ffed"
,
"--el-tag-border-color"
:
isDark
.
value
?
"#274a17"
:
"#b7eb8f"
}
:
{
"--el-tag-text-color"
:
isDark
.
value
?
"#e84749"
:
"#cf1322"
,
"--el-tag-bg-color"
:
isDark
.
value
?
"#2b1316"
:
"#fff1f0"
,
"--el-tag-border-color"
:
isDark
.
value
?
"#58191c"
:
"#ffa39e"
};
};
});
return
{
/** 当前网页是否为`dark`模式 */
isDark
,
/** 表现更鲜明的`el-switch`组件 */
switchStyle
,
/** 表现更鲜明的`el-tag`组件 */
tagStyle
};
}
src/views/systems/dep/index.vue
浏览文件 @
af5ff054
<
template
>
<div
class=
"systems"
>
<h2>
Systems
</h2>
<slot
/>
</div>
</
template
>
<
script
setup
lang=
"ts"
>
// 组件逻辑部分
import
{
ref
}
from
"vue"
;
import
{
useDept
}
from
"./utils/hook"
;
import
{
PureTableBar
}
from
"@/components/RePureTableBar"
;
import
{
useRenderIcon
}
from
"@/components/ReIcon/src/hooks"
;
const
count
=
ref
(
0
);
import
Delete
from
"~icons/ep/delete"
;
import
EditPen
from
"~icons/ep/edit-pen"
;
import
Refresh
from
"~icons/ep/refresh"
;
import
AddFill
from
"~icons/ri/add-circle-line"
;
const
increment
=
()
=>
{
count
.
value
++
;
};
defineOptions
({
name
:
"SystemDept"
});
const
formRef
=
ref
();
const
tableRef
=
ref
();
const
{
form
,
loading
,
columns
,
dataList
,
onSearch
,
resetForm
,
openDialog
,
handleDelete
,
handleSelectionChange
}
=
useDept
();
function
onFullscreen
()
{
// 重置表格高度
tableRef
.
value
.
setAdaptive
();
}
</
script
>
<
style
scoped
lang=
"scss"
>
.systems
{
padding
:
20px
;
border
:
1px
solid
#ccc
;
<
template
>
<div
class=
"main"
>
<el-form
ref=
"formRef"
:inline=
"true"
:model=
"form"
class=
"search-form bg-bg_color w-full pl-8 pt-[12px] overflow-auto"
>
<el-form-item
label=
"部门名称:"
prop=
"name"
>
<el-input
v-model=
"form.name"
placeholder=
"请输入部门名称"
clearable
class=
"w-[180px]!"
/>
</el-form-item>
<el-form-item
label=
"状态:"
prop=
"status"
>
<el-select
v-model=
"form.status"
placeholder=
"请选择状态"
clearable
class=
"w-[180px]!"
>
<el-option
label=
"启用"
:value=
"1"
/>
<el-option
label=
"停用"
:value=
"0"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button
type=
"primary"
:icon=
"useRenderIcon('ri/search-line')"
:loading=
"loading"
@
click=
"onSearch"
>
搜索
</el-button>
<el-button
:icon=
"useRenderIcon(Refresh)"
@
click=
"resetForm(formRef)"
>
重置
</el-button>
</el-form-item>
</el-form>
<PureTableBar
title=
"部门管理(仅演示,操作后不生效)"
:columns=
"columns"
:tableRef=
"tableRef?.getTableRef()"
@
refresh=
"onSearch"
@
fullscreen=
"onFullscreen"
>
<template
#
buttons
>
<el-button
type=
"primary"
:icon=
"useRenderIcon(AddFill)"
@
click=
"openDialog()"
>
新增部门
</el-button>
</
template
>
<
template
v-slot=
"{ size, dynamicColumns }"
>
<pure-table
ref=
"tableRef"
adaptive
:adaptiveConfig=
"
{ offsetBottom: 45 }"
align-whole="center"
row-key="id"
showOverflowTooltip
table-layout="auto"
default-expand-all
:loading="loading"
:size="size"
:data="dataList"
:columns="dynamicColumns"
:header-cell-style="{
background: 'var(--el-fill-color-light)',
color: 'var(--el-text-color-primary)'
}"
@selection-change="handleSelectionChange"
>
<template
#
operation=
"
{ row }">
<el-button
class=
"reset-margin"
link
type=
"primary"
:size=
"size"
:icon=
"useRenderIcon(EditPen)"
@
click=
"openDialog('修改', row)"
>
修改
</el-button>
<el-button
class=
"reset-margin"
link
type=
"primary"
:size=
"size"
:icon=
"useRenderIcon(AddFill)"
@
click=
"openDialog('新增',
{ parentId: row.id } as any)"
>
新增
</el-button>
<el-popconfirm
:title=
"`是否确认删除部门名称为$
{row.name}的这条数据`"
@confirm="handleDelete(row)"
>
<template
#
reference
>
<el-button
class=
"reset-margin"
link
type=
"primary"
:size=
"size"
:icon=
"useRenderIcon(Delete)"
>
删除
</el-button>
</
template
>
</el-popconfirm>
</template>
</pure-table>
</template>
</PureTableBar>
</div>
</template>
<
style
lang=
"scss"
scoped
>
:deep
(
.el-table__inner-wrapper
::before
)
{
height
:
0
;
}
.main-content
{
margin
:
24px
24px
0
!
important
;
}
.search-form
{
:deep
(
.el-form-item
)
{
margin-bottom
:
12px
;
}
}
</
style
>
src/views/systems/dep/utils/hook.tsx
0 → 100644
浏览文件 @
af5ff054
import
dayjs
from
"dayjs"
;
import
editForm
from
"../form.vue"
;
import
{
handleTree
}
from
"@/utils/tree"
;
import
{
message
}
from
"@/utils/message"
;
import
{
getDeptList
}
from
"@/api/system"
;
import
{
usePublicHooks
}
from
"../hooks"
;
import
{
addDialog
}
from
"@/components/ReDialog"
;
import
{
reactive
,
ref
,
onMounted
,
h
}
from
"vue"
;
import
type
{
FormItemProps
}
from
"../utils/types"
;
import
{
cloneDeep
,
isAllEmpty
,
deviceDetection
}
from
"@pureadmin/utils"
;
// import { cloneDeep, deviceDetection } from "@pureadmin/utils";
export
function
useDept
()
{
const
form
=
reactive
({
name
:
""
,
status
:
null
});
const
formRef
=
ref
();
const
dataList
=
ref
([]);
const
loading
=
ref
(
true
);
const
{
tagStyle
}
=
usePublicHooks
();
const
columns
:
TableColumnList
=
[
{
label
:
"部门名称"
,
prop
:
"name"
,
width
:
180
,
align
:
"left"
},
{
label
:
"排序"
,
prop
:
"sort"
,
minWidth
:
70
},
{
label
:
"状态"
,
prop
:
"status"
,
minWidth
:
100
,
cellRenderer
:
({
row
,
props
})
=>
(
<
el
-
tag
size=
{
props
.
size
}
style=
{
tagStyle
.
value
(
row
.
status
)
}
>
{
row
.
status
===
1
?
"启用"
:
"停用"
}
</
el
-
tag
>
)
},
{
label
:
"创建时间"
,
minWidth
:
200
,
prop
:
"createTime"
,
formatter
:
({
createTime
})
=>
dayjs
(
createTime
).
format
(
"YYYY-MM-DD HH:mm:ss"
)
},
{
label
:
"备注"
,
prop
:
"remark"
,
minWidth
:
320
},
{
label
:
"操作"
,
fixed
:
"right"
,
width
:
210
,
slot
:
"operation"
}
];
function
handleSelectionChange
(
val
)
{
console
.
log
(
"handleSelectionChange"
,
val
);
}
function
resetForm
(
formEl
)
{
if
(
!
formEl
)
return
;
formEl
.
resetFields
();
onSearch
();
}
async
function
onSearch
()
{
// loading.value = true;
const
params
=
{
pageNum
:
1
,
pageSize
:
10
};
const
{
data
}
=
await
getDeptList
(
params
);
// 这里是返回一维数组结构,前端自行处理成树结构,返回格式要求:唯一id加父节点parentId,parentId取父节点id
console
.
log
(
"data"
,
data
);
let
newData
=
(
data
as
any
).
records
;
if
(
!
isAllEmpty
(
form
.
name
))
{
// 前端搜索部门名称
newData
=
newData
.
filter
(
item
=>
item
.
name
.
includes
(
form
.
name
));
}
if
(
!
isAllEmpty
(
form
.
status
))
{
// 前端搜索状态
newData
=
newData
.
filter
(
item
=>
item
.
status
===
form
.
status
);
}
dataList
.
value
=
handleTree
(
newData
);
// 处理成树结构
console
.
log
(
"dataList"
,
dataList
.
value
);
setTimeout
(()
=>
{
loading
.
value
=
false
;
},
500
);
}
function
formatHigherDeptOptions
(
treeList
)
{
// 根据返回数据的status字段值判断追加是否禁用disabled字段,返回处理后的树结构,用于上级部门级联选择器的展示(实际开发中也是如此,不可能前端需要的每个字段后端都会返回,这时需要前端自行根据后端返回的某些字段做逻辑处理)
if
(
!
treeList
||
!
treeList
.
length
)
return
;
const
newTreeList
=
[];
for
(
let
i
=
0
;
i
<
treeList
.
length
;
i
++
)
{
treeList
[
i
].
disabled
=
treeList
[
i
].
status
===
0
?
true
:
false
;
formatHigherDeptOptions
(
treeList
[
i
].
children
);
newTreeList
.
push
(
treeList
[
i
]);
}
return
newTreeList
;
}
function
openDialog
(
title
=
"新增"
,
row
?:
FormItemProps
)
{
addDialog
({
title
:
`
${
title
}
部门`
,
props
:
{
formInline
:
{
higherDeptOptions
:
formatHigherDeptOptions
(
cloneDeep
(
dataList
.
value
)),
parentId
:
row
?.
parentId
??
0
,
name
:
row
?.
name
??
""
,
principal
:
row
?.
principal
??
""
,
phone
:
row
?.
phone
??
""
,
email
:
row
?.
email
??
""
,
sort
:
row
?.
sort
??
0
,
status
:
row
?.
status
??
1
,
remark
:
row
?.
remark
??
""
}
},
width
:
"40%"
,
draggable
:
true
,
fullscreen
:
deviceDetection
(),
fullscreenIcon
:
true
,
closeOnClickModal
:
false
,
contentRenderer
:
()
=>
h
(
editForm
,
{
ref
:
formRef
,
formInline
:
null
}),
beforeSure
:
(
done
,
{
options
})
=>
{
const
FormRef
=
formRef
.
value
.
getRef
();
const
curData
=
options
.
props
.
formInline
as
FormItemProps
;
function
chores
()
{
message
(
`您
${
title
}
了部门名称为
${
curData
.
name
}
的这条数据`
,
{
type
:
"success"
});
done
();
// 关闭弹框
onSearch
();
// 刷新表格数据
}
FormRef
.
validate
(
valid
=>
{
if
(
valid
)
{
console
.
log
(
"curData"
,
curData
);
// 表单规则校验通过
if
(
title
===
"新增"
)
{
// 实际开发先调用新增接口,再进行下面操作
chores
();
}
else
{
// 实际开发先调用修改接口,再进行下面操作
chores
();
}
}
});
}
});
}
function
handleDelete
(
row
)
{
message
(
`您删除了部门名称为
${
row
.
name
}
的这条数据`
,
{
type
:
"success"
});
onSearch
();
}
onMounted
(()
=>
{
onSearch
();
});
return
{
form
,
loading
,
columns
,
dataList
,
/** 搜索 */
onSearch
,
/** 重置 */
resetForm
,
/** 新增、修改部门 */
openDialog
,
/** 删除部门 */
handleDelete
,
handleSelectionChange
};
}
src/views/systems/dep/utils/rule.ts
0 → 100644
浏览文件 @
af5ff054
import
{
reactive
}
from
"vue"
;
import
type
{
FormRules
}
from
"element-plus"
;
import
{
isPhone
,
isEmail
}
from
"@pureadmin/utils"
;
/** 自定义表单规则校验 */
export
const
formRules
=
reactive
(
<
FormRules
>
{
name
:
[{
required
:
true
,
message
:
"部门名称为必填项"
,
trigger
:
"blur"
}],
phone
:
[
{
validator
:
(
rule
,
value
,
callback
)
=>
{
if
(
value
===
""
)
{
callback
();
}
else
if
(
!
isPhone
(
value
))
{
callback
(
new
Error
(
"请输入正确的手机号码格式"
));
}
else
{
callback
();
}
},
trigger
:
"blur"
// trigger: "click" // 如果想在点击确定按钮时触发这个校验,trigger 设置成 click 即可
}
],
email
:
[
{
validator
:
(
rule
,
value
,
callback
)
=>
{
if
(
value
===
""
)
{
callback
();
}
else
if
(
!
isEmail
(
value
))
{
callback
(
new
Error
(
"请输入正确的邮箱格式"
));
}
else
{
callback
();
}
},
trigger
:
"blur"
}
]
});
src/views/systems/dep/utils/types.ts
0 → 100644
浏览文件 @
af5ff054
interface
FormItemProps
{
higherDeptOptions
:
Record
<
string
,
unknown
>
[];
parentId
:
number
;
name
:
string
;
principal
:
string
;
phone
:
string
|
number
;
email
:
string
;
sort
:
number
;
status
:
number
;
remark
:
string
;
}
interface
FormProps
{
formInline
:
FormItemProps
;
}
export
type
{
FormItemProps
,
FormProps
};
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论