Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
psa-web
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
高滢
psa-web
Commits
e1d65834
Commit
e1d65834
authored
Mar 10, 2025
by
wangjiancheng
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat:项目管理列表
parent
95da1fbf
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
195 additions
and
52 deletions
+195
-52
add.vue
src/views/project/add.vue
+13
-9
index.vue
src/views/project/index.vue
+182
-43
No files found.
src/views/project/add.vue
View file @
e1d65834
...
...
@@ -91,6 +91,7 @@
size=
"large"
multiple
filterable
v-hasPermi=
"['project-manager']"
style=
"width: 100%;"
>
<el-option
...
...
@@ -114,19 +115,19 @@
<el-form-item
label=
"项目附件"
>
<el-upload
list-type=
"text"
v-model:file-list=
"form.
file
List"
v-model:file-list=
"form.
projectAnnex
List"
action=
"https://jsonplaceholder.typicode.com/posts/"
:on-preview=
"handlePreview"
:on-remove=
"handleRemove"
:before-remove=
"beforeRemove"
:file-list=
"form.
file
List"
:file-list=
"form.
projectAnnex
List"
:on-exceed=
"handleExceed"
:auto-upload=
"false"
:on-success=
"handleSuccess"
>
<el-button
size=
"large"
type=
"text"
>
<img
src=
"../../assets/icons/common/upl.png"
height=
"16"
width=
"16"
alt=
"上传"
/>
点击上传
点击上传
附件
</el-button>
</el-upload>
</el-form-item>
...
...
@@ -138,6 +139,7 @@
placeholder=
"请选择项目回款笔数"
@
change=
"updateRepaymentInputs"
size=
"large"
clearable
>
<el-option
v-for=
"num in 10"
...
...
@@ -147,13 +149,13 @@
></el-option>
</el-select>
</el-form-item>
<el-form
:model=
"form"
:rules=
"rules"
label-width=
"1
40
px"
>
<el-form
:model=
"form"
:rules=
"rules"
label-width=
"1
58
px"
>
<div
v-for=
"(item, index) in form.repaymentDetails"
:key=
"index"
>
<!-- 回款比例 -->
<el-form-item
:label=
"'第 ' + (index + 1) + ' 笔'"
>
<el-form-item
:label=
"'第 ' + (index + 1) + ' 笔
回款百分比
'"
>
<el-input
v-model=
"item.repaymentPercentage"
placeholder=
"请输入回款
比例
"
placeholder=
"请输入回款
百分比
"
@
blur=
"checkPercentage(item.repaymentPercentage, index)"
>
<template
#
suffix
>
...
...
@@ -162,7 +164,7 @@
</el-input>
</el-form-item>
<!-- 回款条件 -->
<el-form-item
label=
"回款前置条件
"
>
<el-form-item
:label=
"'第 ' + (index + 1) + ' 笔回款前置条件'
"
>
<el-input
type=
"textarea"
:autosize=
"{ minRows: 3, maxRows: 20 }"
...
...
@@ -208,7 +210,7 @@ const form = reactive({
projectCost
:
''
,
projectDescribe
:
''
,
projectStatus
:
''
,
file
List
:
[],
projectAnnex
List
:
[],
repaymentCount
:
null
,
repaymentDetails
:
[],
draft
:
''
,
...
...
@@ -244,6 +246,8 @@ const rules = ref({
],
})
// 获取用户列表
const
getUserList
=
()
=>
{
listUser
().
then
(
response
=>
{
headOptions
.
value
=
response
.
rows
.
map
(
item
=>
{
...
...
@@ -318,7 +322,7 @@ const resetForm = () => {
form
.
projectCost
=
''
form
.
projectDescribe
=
''
form
.
projectStatus
=
''
form
.
file
List
=
[]
form
.
projectAnnex
List
=
[]
form
.
repaymentCount
=
''
form
.
repaymentDetails
=
[]
form
.
draft
=
''
...
...
src/views/project/index.vue
View file @
e1d65834
...
...
@@ -9,21 +9,36 @@
placeholder=
"请输入项目名称"
clearable
@
keyup
.
enter=
"handleQuery"
style=
"width: 220px"
/>
</el-form-item>
<el-form-item
label=
"项目经理"
prop=
"projectManagerId"
>
<el-input
<!--
<el-input
v-model=
"queryParams.projectManagerId"
placeholder=
"请输入项目经理"
clearable
@
keyup
.
enter=
"handleQuery"
/>
style=
"width: 220px"
/>
-->
<el-select
v-model=
"queryParams.projectManagerId"
placeholder=
"请选择项目经理"
style=
"width: 220px"
clearable
>
<el-option
v-for=
"dict in managerOptions"
:key=
"dict.value"
:label=
"dict.label"
:value=
"dict.value"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"项目状态"
prop=
"projectStatus"
>
<el-select
v-model=
"queryParams.projectStatus"
placeholder=
"请选择项目状态"
style=
"width:
193
px"
style=
"width:
220
px"
clearable
>
<el-option
...
...
@@ -35,32 +50,68 @@
</el-select>
</el-form-item>
<!-- 操作按钮 -->
<el-form-item
style=
"padding-left: 9%"
>
<el-button
icon=
"Refresh"
@
click=
"resetQuery"
class=
"el-button-defalut"
>
重置
</el-button>
<el-button
type=
"primary"
icon=
"Search"
@
click=
"handleQuery"
class=
"el-button-primary"
>
查询
</el-button>
<el-button
size=
"large"
type=
"text"
@
click=
"toggleSearch"
>
{{
isExpanded
?
' 收起'
:
' 展开'
}}
<el-icon
class=
"el-icon--right"
>
<arrow-down
/>
</el-icon>
<el-form-item
style=
"padding-left: 5.4%"
>
<el-button
@
click=
"resetQuery"
class=
"el-button-defalut"
>
<template
#
icon
>
<img
src=
"../../assets/icons/common/reset.png"
height=
"25"
width=
"24"
/>
</
template
>
重置
</el-button>
<el-button
type=
"primary"
@
click=
"handleQuery"
class=
"el-button-primary"
>
<
template
#
icon
>
<img
src=
"../../assets/icons/common/search.png"
height=
"24"
width=
"24"
/>
</
template
>
查询
</el-button>
<el-button
size=
"large"
icon=
"ArrowDown"
type=
"text"
v-show=
"!isExpanded"
@
click=
"toggleSearch"
>
展开
</el-button>
<el-button
size=
"large"
type=
"text"
icon=
"ArrowUp"
v-show=
"isExpanded"
@
click=
"toggleSearch"
>
收起
</el-button>
</el-form-item>
<!-- 可折叠的查询条件 -->
<transition>
<div
v-if=
"isExpanded"
>
<el-form-item
label=
"事业部负责人"
prop=
"departmentLeaderId"
>
<el-input
<!--
<el-input
v-model="queryParams.departmentLeaderId"
placeholder="请输入事业部负责人"
clearable
@keyup.enter="handleQuery"
/>
style="width: 220px"
/>-->
<el-select
v-model=
"queryParams.departmentLeaderId"
placeholder=
"请选择事业部负责人"
style=
"width: 220px"
clearable
>
<el-option
v-for=
"dict in headOptions"
:key=
"dict.value"
:label=
"dict.label"
:value=
"dict.value"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"项目类型"
prop=
"projectType"
>
<el-select
v-model=
"queryParams.projectType"
placeholder=
"请选择项目类型"
style=
"width:
193
px"
style=
"width:
220
px"
clearable
>
<el-option
...
...
@@ -78,7 +129,7 @@
<div
class=
"contentTable"
>
<div
style=
"padding-left: 8px ;margin-bottom: 20px"
>
<span
class=
"bold-text"
style=
"border-bottom: 3px solid #0062FF;"
>
项目列表
</span>
<span
style=
"padding-left:
79
%"
>
<span
style=
"padding-left:
80
%"
>
<el-button
class=
"el-button-primary-pain"
plain
...
...
@@ -86,26 +137,39 @@
@
click=
"handleAdd"
v-hasPermi=
"['system:project:add']"
>
项目立项
</el-button>
<el-button
type=
"text"
plain
@
click=
"handleDraft"
v-hasPermi=
"['system:project:draft']"
><img
src=
"../../assets/icons/common/rightone.png"
height=
"30"
width=
"30"
/></el-button>
<el-button
type=
"text"
plain
@
click=
"handleExport"
v-hasPermi=
"['system:project:export']"
><img
src=
"../../assets/icons/common/print.png"
height=
"30"
width=
"30"
/></el-button>
<el-tooltip
content=
"草稿箱"
placement=
"top"
>
<el-button
type=
"text"
plain
@
click=
"handleDraft"
v-hasPermi=
"['system:project:draft']"
><img
src=
"../../assets/icons/common/rightone.png"
height=
"38"
width=
"38"
/>
</el-button>
</el-tooltip>
<el-tooltip
content=
"导出"
placement=
"top"
>
<el-button
type=
"text"
plain
@
click=
"handleExport"
v-hasPermi=
"['system:project:export']"
><img
src=
"../../assets/icons/common/print.png"
height=
"38"
width=
"38"
/>
</el-button>
</el-tooltip>
</span>
</div>
<el-table
v-loading=
"loading"
:data=
"projectList"
border
style=
"width: 100%"
>
<el-table-column
type=
"selection"
width=
"40"
align=
"right"
/>
<div>
<el-alert
v-if=
"emptyMemberCount > 0"
:title=
"`您有 ${emptyMemberCount} 个项目需添加成员`"
type=
"warning"
show-icon
/>
</div>
<el-table
v-loading=
"loading"
:data=
"sortedProjectList"
border
style=
"width: 100%"
:row-class-name=
"tableRowClassName"
>
<el-table-column
type=
"selection"
width=
"56"
align=
"center"
/>
<el-table-column
label=
"项目编号"
align=
"center"
prop=
"projectNumber"
min-width=
"150"
/>
<el-table-column
label=
"项目名称"
align=
"center"
prop=
"projectName"
min-width=
"120"
show-overflow-tooltip
/>
<el-table-column
label=
"项目类型"
align=
"center"
prop=
"projectType"
min-width=
"120"
>
<el-table-column
label=
"项目类型"
align=
"center"
prop=
"projectType"
min-width=
"120"
sortable
>
<
template
#
default=
"scope"
>
<dict-tag
:options=
"project_type"
:value=
"scope.row.projectType"
/>
</
template
>
...
...
@@ -120,7 +184,7 @@
<
span
>
{{
parseTime
(
scope
.
row
.
endDate
,
'{y
}
/{m
}
/{d
}
'
)
}}
<
/span
>
<
/template
>
<
/el-table-column
>
<
el
-
table
-
column
label
=
"事业部负责人"
align
=
"center"
prop
=
"departmentLeaderName"
min
-
width
=
"1
30"
/>
<
el
-
table
-
column
label
=
"事业部负责人"
align
=
"center"
prop
=
"departmentLeaderName"
min
-
width
=
"1
50"
sortable
/>
<
el
-
table
-
column
label
=
"项目经理"
align
=
"center"
prop
=
"projectManagerName"
min
-
width
=
"120"
/>
<
el
-
table
-
column
label
=
"项目成本(元)"
align
=
"center"
prop
=
"projectCost"
min
-
width
=
"120"
/>
<
el
-
table
-
column
label
=
"项目状态"
align
=
"center"
prop
=
"projectStatus"
min
-
width
=
"120"
>
...
...
@@ -136,6 +200,12 @@
<
el
-
button
type
=
"text"
>
查看详情
<
/el-button
>
<
/template
>
<
el
-
table
:
data
=
"scope.row.repaymentDetails"
border
style
=
"width: 100%"
>
<!--
项目回款笔数
-->
<
el
-
table
-
column
label
=
"回款笔数"
align
=
"center"
>
<
template
#
default
=
"scope"
>
第
{{
scope
.
$index
+
1
}}
笔
<
/template
>
<
/el-table-column
>
<
el
-
table
-
column
label
=
"回款百分比"
align
=
"center"
prop
=
"repaymentPercentage"
>
<
template
#
default
=
"scope"
>
{{
scope
.
row
.
repaymentPercentage
}}
%
...
...
@@ -160,20 +230,27 @@
<
span
>
{{
parseTime
(
scope
.
row
.
updateDate
,
'{y
}
/{m
}
/{d
}
'
)
||
'-'
}}
<
/span
>
<
/template
>
<
/el-table-column
>
<
el
-
table
-
column
label
=
"操作"
align
=
"center"
class
-
name
=
"small-padding fixed-width"
fixed
=
"right"
width
=
"17
0"
>
<
el
-
table
-
column
label
=
"操作"
align
=
"center"
class
-
name
=
"small-padding fixed-width"
fixed
=
"right"
min
-
width
=
"20
0"
>
<
template
#
default
=
"scope"
>
<
el
-
button
link
type
=
"text"
@
click
=
"handleUpdate(scope.row)"
v
-
hasPermi
=
"['system:project:edit']"
>
<
img
src
=
"../../assets/icons/common/edit.png"
height
=
"20"
width
=
"20"
/><
/el-button
>
<
el
-
button
link
type
=
"text"
@
click
=
"handleView(scope.row)"
v
-
hasPermi
=
"['system:project:view']"
>
<
img
src
=
"../../assets/icons/common/check.png"
height
=
"20"
width
=
"20"
/><
/el-button
>
<
el
-
button
link
type
=
"text"
@
click
=
"handleDelete(scope.row)"
v
-
hasPermi
=
"['system:project:logicRemove']"
>
<
img
src
=
"../../assets/icons/common/delete.png"
height
=
"20"
width
=
"20"
/><
/el-button
>
<
el
-
button
link
type
=
"text"
@
click
=
"handleDelete(scope.row)"
>
<
img
src
=
"../../assets/icons/common/send.png"
height
=
"20"
width
=
"20"
/><
/el-button
>
<
el
-
tooltip
content
=
"编辑"
placement
=
"top"
>
<
el
-
button
link
type
=
"text"
@
click
=
"handleUpdate(scope.row)"
v
-
hasPermi
=
"['system:project:edit']"
>
<
img
src
=
"../../assets/icons/common/edit.png"
height
=
"32"
width
=
"32"
/>
<
/el-button
>
<
/el-tooltip
>
<
el
-
tooltip
content
=
"详情"
placement
=
"top"
>
<
el
-
button
link
type
=
"text"
@
click
=
"handleView(scope.row)"
v
-
hasPermi
=
"['system:project:view']"
>
<
img
src
=
"../../assets/icons/common/check.png"
height
=
"32"
width
=
"32"
/>
<
/el-button
>
<
/el-tooltip
>
<
el
-
tooltip
content
=
"删除"
placement
=
"top"
>
<
el
-
button
link
type
=
"text"
@
click
=
"handleDelete(scope.row)"
v
-
hasPermi
=
"['system:project:logicRemove']"
>
<
img
src
=
"../../assets/icons/common/delete.png"
height
=
"32"
width
=
"32"
/>
<
/el-button
>
<
/el-tooltip
>
<
/template
>
<
/el-table-column
>
<
/el-table
>
<
div
style
=
"padding-right: 300px;margin-top: 1px
"
>
<
div
class
=
"pagination-containerA
"
>
<
pagination
v
-
show
=
"total>0"
:
total
=
"total"
...
...
@@ -188,7 +265,7 @@
<
script
setup
name
=
"Project"
>
import
{
listProject
,
logicRemove
}
from
"../../api/project/project.js"
;
import
{
ArrowDown
}
from
"@element-plus/icons-vue
"
;
import
{
listUser
}
from
"../../api/system/user.js
"
;
const
{
proxy
}
=
getCurrentInstance
();
const
{
project_status
,
project_type
}
=
proxy
.
useDict
(
'project_status'
,
'project_type'
);
...
...
@@ -201,6 +278,8 @@ const multiple = ref(true);
const
total
=
ref
(
0
);
// 定义是否展开的状态
const
isExpanded
=
ref
(
false
);
const
headOptions
=
ref
([]);
const
managerOptions
=
ref
([]);
const
data
=
reactive
({
form
:
{
}
,
...
...
@@ -228,6 +307,32 @@ function getList() {
}
);
}
// 获取用户列表
const
getUserList
=
()
=>
{
listUser
().
then
(
response
=>
{
headOptions
.
value
=
response
.
rows
.
map
(
item
=>
{
return
{
value
:
item
.
userId
,
label
:
item
.
nickName
}
}
)
managerOptions
.
value
=
response
.
rows
.
map
(
item
=>
{
return
{
value
:
item
.
userId
,
label
:
item
.
nickName
}
}
)
}
)
}
// 排序后的项目列表,将成员为空的项目放在前面
const
sortedProjectList
=
computed
(()
=>
[...
projectList
.
value
].
sort
((
a
,
b
)
=>
{
const
aEmpty
=
!
a
.
projectMemberNames
||
a
.
projectMemberNames
.
trim
()
===
""
;
const
bEmpty
=
!
b
.
projectMemberNames
||
b
.
projectMemberNames
.
trim
()
===
""
;
return
aEmpty
===
bEmpty
?
0
:
aEmpty
?
-
1
:
1
;
}
)
);
/** 搜索按钮操作 */
function
handleQuery
()
{
queryParams
.
value
.
pageNum
=
1
;
...
...
@@ -265,6 +370,18 @@ function handleDraft() {
proxy
.
$router
.
push
({
path
:
'/project/opera/draft'
}
);
}
// 是否有成员
const
tableRowClassName
=
({
row
}
)
=>
{
if
(
!
row
.
projectMemberNames
||
row
.
projectMemberNames
.
trim
()
===
""
)
{
return
'error-row'
;
}
return
''
;
}
// 计算成员为空的项目数量
const
emptyMemberCount
=
computed
(()
=>
projectList
.
value
.
filter
(
item
=>
!
item
.
projectMemberNames
||
item
.
projectMemberNames
.
trim
()
===
""
).
length
);
/** 逻辑删除按钮操作 */
function
handleDelete
(
row
)
{
const
_ids
=
row
.
id
||
ids
.
value
;
...
...
@@ -284,6 +401,7 @@ function handleExport() {
}
getList
();
getUserList
()
<
/script
>
<
style
scoped
lang
=
"scss"
>
.
bold
-
text
{
...
...
@@ -296,4 +414,25 @@ getList();
letter
-
spacing
:
0
;
line
-
height
:
15
px
;
}
// 表格的标头
:
deep
(.
el
-
table
th
.
el
-
table__cell
)
{
line
-
height
:
35
px
;
//height: 56px;
background
:
#
F6F8FC
!
important
;
}
/* 设置当member字段为空时的行背景色 */
:
deep
.
el
-
table
.
error
-
row
{
--
el
-
table
-
tr
-
bg
-
color
:
var
(
--
el
-
color
-
warning
-
light
-
9
);
}
.
pagination
-
containerA
{
//display: flex;
//justify-content: center; /* 水平居中 */
padding
-
right
:
43
%
;
}
.
el
-
alert
{
margin
:
23
px
0
23
px
;
}
<
/style
>
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