明树Git Lab
Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
J
jt_front
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
jt_front
Commits
7ffc99c8
Commit
7ffc99c8
authored
Dec 08, 2025
by
zfp1
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update
parent
33cec7e4
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
172 additions
and
120 deletions
+172
-120
commonForm.vue
src/components/common/commonForm.vue
+22
-25
commonTable.vue
src/components/common/commonTable.vue
+7
-1
addProject.vue
src/views/managePage/addProject.vue
+2
-2
roleManage.vue
src/views/systemManage/roleManage.vue
+94
-49
userManage.vue
src/views/systemManage/userManage.vue
+46
-42
window.js
src/window.js
+1
-1
No files found.
src/components/common/commonForm.vue
View file @
7ffc99c8
...
...
@@ -278,8 +278,8 @@
:data=
"item.data"
:props=
"
item.props || {
label: '
label
',
value: '
value
',
label: '
name
',
value: '
id
',
children: 'children',
}
"
...
...
@@ -391,13 +391,8 @@
/>
</el-form-item>
</el-col>
</el-row>
<!-- 表单操作按钮 -->
<el-form-item
v-if=
"config.showButtons !== false"
class=
"form-buttons"
>
<el-button
v-if=
"config.showReset !== false"
@
click=
"handleReset"
>
{{ config.resetText || "重置" }}
</el-button>
<el-button
v-if=
"config.showSubmit !== false"
type=
"primary"
...
...
@@ -416,6 +411,8 @@
{{ btn.text }}
</el-button>
</el-form-item>
</el-row>
</el-form>
</div>
</template>
...
...
src/components/common/commonTable.vue
View file @
7ffc99c8
...
...
@@ -2,7 +2,9 @@
<div
class=
"common-table"
>
<div
class=
"table-header"
v-if=
"showHeader"
>
<div
class=
"header-left"
>
<slot
name=
"header-left"
>
<h3
v-if=
"title"
>
{{
title
}}
</h3>
</slot>
</div>
<div
class=
"header-right"
>
<slot
name=
"header-actions"
></slot>
...
...
@@ -524,6 +526,10 @@ const handleNextClick = (val) => {
margin-bottom: 16px;
.header-left {
flex: 1; /* 占满剩余空间 */
display: flex;
align-items: center;
gap: 12px;
h3 {
margin: 0;
font-size: 18px;
...
...
src/views/managePage/addProject.vue
View file @
7ffc99c8
...
...
@@ -7,8 +7,8 @@
<div
class=
"add-project-header"
>
<div
class=
"header-left"
></div>
<div
class=
"header-right"
>
<el-button
type=
"default"
v-if=
"formData.projectLzType === 1"
@
click=
"backClick"
>
返回
</el-button>
<el-button
type=
"primary"
v-if=
"formData.projectLzType === 1"
@
click=
"saveClick('save')"
>
保存
</el-button>
<el-button
type=
"default"
@
click=
"backClick"
>
返回
</el-button>
<el-button
type=
"primary"
v-if=
"formData.projectLzType === 1
|| !formData.projectLzType
"
@
click=
"saveClick('save')"
>
保存
</el-button>
<el-button
type=
"primary"
v-if=
"formData.projectLzType === 1"
@
click=
"saveClick('submit')"
>
发起立项填报
</el-button>
</div>
</div>
...
...
src/views/systemManage/roleManage.vue
View file @
7ffc99c8
<
template
>
<div
class=
"user-manage"
v-loading=
"loading"
>
<div
class=
"search-form"
>
<commonForm
v-model=
"searchForm"
:config=
"searchConfig"
:items=
"searchItems"
@
submit=
"handleSearch"
@
reset=
"handleReset"
/>
</div>
<!-- search form moved into table header to align with 新增 button -->
<div
class=
"table-container"
>
<common-table
:autoHeight=
"true"
...
...
@@ -19,13 +11,22 @@
:total=
"total"
:current-page=
"currentPage"
:page-size=
"pageSize"
title=
"
角色管理
"
title=
""
:border=
"true"
@
size-change=
"handleSizeChange"
@
current-page-change=
"handleCurrentPageChange"
>
<template
#
header-actions
>
<template
#
header-left
>
<div
style=
"display:flex;align-items:center;gap:12px;"
>
<commonForm
v-model=
"searchForm"
:config=
"searchConfig"
:items=
"searchItems"
@
submit=
"handleSearch"
@
reset=
"handleReset"
/>
<el-button
type=
"primary"
@
click=
"handleAdd"
>
新增
</el-button>
</div>
</
template
>
<
template
#
operations=
"{ row, index }"
>
<el-button
type=
"text"
size=
"small"
@
click=
"handleEdit(row, index)"
>
...
...
@@ -52,7 +53,21 @@
:rules=
"formRules"
@
submit=
"handleFormSubmit"
@
reset=
"handleFormReset"
>
<
template
#
menus
>
<el-tree
:data=
"treeData"
node-key=
"id"
:props=
"
{
label: 'name',
children: 'children'
}"
show-checkbox
@check="hanldeSubmit"
ref="treeRef"
/>
</
template
>
</commonForm>
</el-dialog>
<!-- <el-dialog v-model="menuVisible" title="菜单配置">
<el-tree
...
...
@@ -74,7 +89,7 @@
</template>
<
script
setup
>
import
{
ref
,
reactive
,
onMounted
,
getCurrentInstance
,
computed
}
from
"vue"
;
import
{
ref
,
reactive
,
onMounted
,
getCurrentInstance
,
computed
,
nextTick
}
from
"vue"
;
import
{
ElMessage
,
ElMessageBox
}
from
"element-plus"
;
import
{
Plus
,
Edit
,
Delete
}
from
"@element-plus/icons-vue"
;
import
commonForm
from
"@/components/common/commonForm.vue"
;
...
...
@@ -84,16 +99,16 @@ import { da } from "element-plus/es/locales.mjs";
const
{
proxy
}
=
getCurrentInstance
();
const
loading
=
ref
(
false
);
const
treeData
=
ref
([]);
const
tree
=
ref
(
null
);
const
tree
Ref
=
ref
(
null
);
// 数据转换函数
const
convertToTreeData
=
(
apiData
)
=>
{
return
apiData
.
map
((
item
)
=>
({
value
:
item
.
id
.
toString
(),
label
:
item
.
name
,
children
:
item
.
children
?
convertToTreeData
(
item
.
children
)
:
[],
}));
};
//
const convertToTreeData = (apiData) => {
//
return apiData.map((item) => ({
//
value: item.id.toString(),
//
label: item.name,
//
children: item.children ? convertToTreeData(item.children) : [],
//
}));
//
};
// 查询表单数据
const
searchForm
=
ref
({
...
...
@@ -115,7 +130,7 @@ const searchItems = [
{
type
:
"input"
,
prop
:
"name"
,
label
:
"
角色名称:
"
,
label
:
""
,
placeholder
:
"请输入角色名称"
,
clearable
:
true
,
span
:
8
,
...
...
@@ -135,6 +150,11 @@ const tableColumns = [
label
:
"角色名称"
,
minWidth
:
100
,
},
{
prop
:
"key"
,
label
:
"角色标识"
,
minWidth
:
100
,
},
{
prop
:
"createdAt"
,
label
:
"创建时间"
,
...
...
@@ -164,6 +184,7 @@ const editIndex = ref(-1);
// 用户表单数据
const
roleForm
=
ref
({
name
:
""
,
key
:
""
,
menus
:
[],
});
...
...
@@ -187,19 +208,19 @@ const formItems = computed(() => [
rules
:
[{
required
:
true
,
message
:
"请输入角色名称"
,
trigger
:
"blur"
}],
},
{
type
:
"tree"
,
type
:
"input"
,
prop
:
"key"
,
label
:
"角色标识"
,
placeholder
:
"请输入角色英文标识"
,
span
:
24
,
required
:
true
,
rules
:
[{
required
:
true
,
message
:
"请输入角色英文标识"
,
trigger
:
"blur"
}],
},
{
type
:
"slot"
,
prop
:
"menus"
,
slotName
:
"menus"
,
label
:
"菜单配置"
,
placeholder
:
"请选择菜单配置"
,
data
:
treeData
.
value
,
clearable
:
true
,
filterable
:
true
,
checkStrictly
:
true
,
renderAfterExpand
:
false
,
showCheckbox
:
false
,
multiple
:
true
,
collapseTags
:
true
,
maxCollapseTags
:
2
,
span
:
24
,
},
]);
...
...
@@ -242,11 +263,16 @@ const handleNodeClick = (data, node, element) => {
// 新增用户
const
handleAdd
=
()
=>
{
isEdit
.
value
=
false
;
dialogTitle
.
value
=
"新增
用户
"
;
dialogTitle
.
value
=
"新增
角色
"
;
roleForm
.
value
=
{
name
:
""
,
key
:
""
,
menus
:
[],
};
// 清空树的已选项
if
(
treeRef
.
value
&&
treeRef
.
value
.
setCheckedKeys
)
{
treeRef
.
value
.
setCheckedKeys
([]);
}
dialogVisible
.
value
=
true
;
};
let
currentID
=
ref
();
...
...
@@ -254,7 +280,7 @@ let currentRow = ref();
// 编辑
const
handleEdit
=
(
row
,
index
)
=>
{
isEdit
.
value
=
true
;
dialogTitle
.
value
=
"编辑
用户
"
;
dialogTitle
.
value
=
"编辑
角色
"
;
editIndex
.
value
=
index
;
currentRow
.
value
=
row
;
proxy
.
$post
({
...
...
@@ -263,6 +289,16 @@ const handleEdit = (row, index) => {
callback
:
(
data
)
=>
{
roleForm
.
value
=
{
...
data
};
currentID
.
value
=
data
.
id
;
// 如果返回了已选菜单,延后到下一个 DOM 更新周期再设置树的选中项(确保 tree 已渲染)
if
(
data
.
menus
&&
treeRef
.
value
&&
treeRef
.
value
.
setCheckedKeys
)
{
nextTick
(()
=>
{
try
{
treeRef
.
value
.
setCheckedKeys
(
data
.
menus
);
}
catch
(
e
)
{
console
.
warn
(
'setCheckedKeys failed:'
,
e
);
}
});
}
},
error
:
(
err
)
=>
{
ElMessage
.
error
(
"编辑失败:"
,
err
);
...
...
@@ -296,12 +332,14 @@ const handleDelete = async (row, index) => {
};
const
handleFormSubmit
=
(
formData
)
=>
{
// 在提交前确保同步树的选中项到 roleForm
hanldeSubmit
();
if
(
isEdit
.
value
)
{
// 编辑用户
// 编辑用户
- 以 roleForm.value 为准,附带 id
const
updateUser
=
{
...
formData
,
...
roleForm
.
value
,
id
:
currentID
.
value
,
menus
:
Array
.
isArray
(
formData
.
menus
)
?
formData
.
menus
:
[],
};
proxy
.
$post
({
url
:
"/api/user/role/updateRole"
,
...
...
@@ -316,9 +354,9 @@ const handleFormSubmit = (formData) => {
},
});
}
else
{
// 新增角色
// 新增角色
- 以 roleForm.value 为准,包含 menus
const
newUser
=
{
...
formData
,
...
roleForm
.
value
,
};
proxy
.
$post
({
url
:
"/api/user/role/createRole"
,
...
...
@@ -344,18 +382,25 @@ const handleDialogClose = () => {
};
const
hanldeSubmit
=
()
=>
{
// 获取当前复选框选中的节点信息
const
checkedNodes
=
tree
.
value
?.
getCheckedNodes
();
const
halfCheckedNodes
=
tree
.
value
?.
getHalfCheckedNodes
();
// 使用 treeRef 获取当前勾选节点
const
treeInst
=
treeRef
.
value
;
if
(
!
treeInst
)
return
;
const
checkedNodes
=
treeInst
.
getCheckedNodes
?
treeInst
.
getCheckedNodes
()
:
[];
const
halfCheckedNodes
=
treeInst
.
getHalfCheckedNodes
?
treeInst
.
getHalfCheckedNodes
()
:
[];
// 获取选中节点的ID
const
checkedIds
=
checkedNodes
?
checkedNodes
.
map
((
node
)
=>
node
.
id
)
:
[];
const
halfCheckedIds
=
halfCheckedNodes
?
halfCheckedNodes
.
map
((
node
)
=>
node
.
id
)
:
[];
// 合并所有选中的节点ID(完全选中和半选中的)
const
allSelectedIds
=
[...
checkedIds
,
...
halfCheckedIds
];
const
allSelectedIds
=
Array
.
from
(
new
Set
([...
checkedIds
,
...
halfCheckedIds
]));
// 把选中的菜单 id 写回表单数据,供提交使用
roleForm
.
value
.
menus
=
allSelectedIds
;
return
allSelectedIds
;
};
// 表格数据
const
loadTableData
=
()
=>
{
...
...
@@ -381,13 +426,13 @@ const loadTableData = () => {
const
handleTreeData
=
()
=>
{
proxy
.
$post
({
url
:
"/api/user/
depart/treeDepart
"
,
url
:
"/api/user/
menu/treeMenu
"
,
data
:
{
page
:
currentPage
.
value
,
pageSize
:
pageSize
.
value
,
},
callback
:
(
data
)
=>
{
treeData
.
value
=
convertToTreeData
(
data
)
;
treeData
.
value
=
data
;
},
error
:
(
err
)
=>
{
ElMessage
.
error
(
"加载数据失败"
);
...
...
src/views/systemManage/userManage.vue
View file @
7ffc99c8
<
template
>
<div
class=
"user-manage"
v-loading=
"loading"
>
<div
class=
"search-form"
>
<
!--
<
div
class=
"search-form"
>
<commonForm
v-model=
"searchForm"
:config=
"searchConfig"
...
...
@@ -8,7 +8,7 @@
@
submit=
"handleSearch"
@
reset=
"handleReset"
/>
</div>
</div>
-->
<div
class=
"table-container"
>
<common-table
:autoHeight=
"true"
...
...
@@ -19,11 +19,20 @@
:total=
"total"
:current-page=
"currentPage"
:page-size=
"pageSize"
title=
"
用户管理
"
title=
""
:border=
"true"
@
size-change=
"handleSizeChange"
@
current-page-change=
"handleCurrentPageChange"
>
<template
#
header-left
>
<commonForm
v-model=
"searchForm"
:config=
"searchConfig"
:items=
"searchItems"
@
submit=
"handleSearch"
@
reset=
"handleReset"
/>
</
template
>
<
template
#
header-actions
>
<el-button
type=
"primary"
@
click=
"handleAdd"
>
<!--
<el-icon><Plus
/></el-icon>
-->
...
...
@@ -83,13 +92,13 @@ const loading = ref(false);
// 数据转换函数
const
convertToTreeData
=
(
apiData
)
=>
{
return
apiData
.
map
((
item
)
=>
({
value
:
item
.
id
.
toString
(),
label
:
item
.
name
,
children
:
item
.
children
?
convertToTreeData
(
item
.
children
)
:
[],
}));
};
//
const convertToTreeData = (apiData) => {
//
return apiData.map((item) => ({
//
value: item.id.toString(),
//
label: item.name,
//
children: item.children ? convertToTreeData(item.children) : [],
//
}));
//
};
// 查询表单数据
const
searchForm
=
ref
({
...
...
@@ -111,19 +120,11 @@ const searchItems = [
{
type
:
"input"
,
prop
:
"name"
,
label
:
"用户姓名:"
,
placeholder
:
"请输入用户姓名"
,
clearable
:
true
,
span
:
8
,
},
{
type
:
"input"
,
prop
:
"mobile"
,
label
:
"手机号码:"
,
placeholder
:
"请输入手机号码"
,
label
:
""
,
placeholder
:
"请输入关键字查询"
,
clearable
:
true
,
span
:
8
,
}
,
span
:
12
,
}
];
// 表格数据
...
...
@@ -140,6 +141,11 @@ const tableColumns = [
minWidth
:
100
,
showOverflowTooltip
:
true
,
},
{
prop
:
"mobile"
,
label
:
"手机号码"
,
minWidth
:
100
,
},
{
prop
:
"departs"
,
label
:
"所属部门"
,
...
...
@@ -158,11 +164,6 @@ const tableColumns = [
minWidth
:
100
,
showOverflowTooltip
:
true
,
},
{
prop
:
"mobile"
,
label
:
"手机号码"
,
minWidth
:
100
,
},
{
prop
:
"createdAt"
,
label
:
"创建时间"
,
...
...
@@ -216,7 +217,8 @@ const loadDepartmentData = () => {
url
:
"/api/user/depart/treeDepart"
,
data
:
{},
callback
:
(
data
)
=>
{
departmentData
.
value
=
convertToTreeData
(
data
);
// departmentData.value = convertToTreeData(data);
departmentData
.
value
=
data
;
},
error
:
(
err
)
=>
{},
});
...
...
@@ -228,7 +230,7 @@ const loadPositionsData = () => {
url
:
"/api/user/position/listPosition"
,
data
:
{},
callback
:
(
data
)
=>
{
positionsData
.
value
=
convertToTreeData
(
data
.
rows
)
;
positionsData
.
value
=
data
.
rows
;
},
error
:
(
err
)
=>
{},
});
...
...
@@ -243,7 +245,7 @@ const loadRolesData = () => {
pageSize
:
10
,
},
callback
:
(
data
)
=>
{
rolesData
.
value
=
convertToTreeData
(
data
.
rows
)
;
rolesData
.
value
=
data
.
rows
;
},
error
:
(
err
)
=>
{},
});
...
...
@@ -257,7 +259,7 @@ const formItems = computed(() => [
label
:
"用户姓名"
,
placeholder
:
"请输入用户姓名"
,
// required: true,
span
:
12
,
span
:
24
,
// rules: [{ required: true, message: "请输入用户姓名", trigger: "blur" }],
},
{
...
...
@@ -269,12 +271,12 @@ const formItems = computed(() => [
clearable
:
true
,
filterable
:
true
,
checkStrictly
:
true
,
renderAfterExpand
:
fals
e
,
renderAfterExpand
:
tru
e
,
showCheckbox
:
false
,
multiple
:
tru
e
,
multiple
:
fals
e
,
collapseTags
:
true
,
maxCollapseTags
:
2
,
span
:
12
,
span
:
24
,
},
{
type
:
"tree"
,
...
...
@@ -290,7 +292,7 @@ const formItems = computed(() => [
multiple
:
true
,
collapseTags
:
true
,
maxCollapseTags
:
2
,
span
:
12
,
span
:
24
,
},
{
type
:
"tree"
,
...
...
@@ -306,23 +308,23 @@ const formItems = computed(() => [
multiple
:
true
,
collapseTags
:
true
,
maxCollapseTags
:
2
,
span
:
12
,
span
:
24
,
},
{
type
:
"input"
,
prop
:
"mobile"
,
label
:
"手机号码"
,
placeholder
:
"请输入手机号码"
,
span
:
12
,
span
:
24
,
},
{
type
:
"radio"
,
prop
:
"enable"
,
label
:
"状态"
,
span
:
12
,
span
:
24
,
options
:
[
{
label
:
"启用"
,
value
:
"0"
},
{
label
:
"停用"
,
value
:
"1"
},
{
label
:
"启用"
,
value
:
0
},
{
label
:
"停用"
,
value
:
1
},
],
},
]);
...
...
@@ -529,7 +531,7 @@ onMounted(() => {
<
style
scoped
lang=
"less"
>
.user-manage {
padding:
20
px;
padding:
8px 8px 20px 8
px;
background: rgba(157, 188, 218, 0.1);
height: 100%;
display: flex;
...
...
@@ -548,8 +550,10 @@ onMounted(() => {
.table-container {
background: rgba(255, 255, 255, 0.9);
border-radius: 8px;
padding:
20
px;
padding:
12
px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
padding-left: 0px;
padding-top: 2px;
}
}
</
style
>
src/window.js
View file @
7ffc99c8
export
default
{
baseUrl
:
"http://
10.40.8.9
:3000"
baseUrl
:
"http://
localhost
:3000"
};
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment