Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
J
jilinzhongdianrenqun-web
概览
Overview
Details
Activity
Cycle Analytics
版本库
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
问题
0
Issues
0
列表
Board
标记
里程碑
合并请求
0
Merge Requests
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
Snippets
成员
Members
Collapse sidebar
Close sidebar
活动
图像
聊天
创建新问题
作业
提交
Issue Boards
Open sidebar
吴超
jilinzhongdianrenqun-web
Commits
30a96ce8
Commit
30a96ce8
authored
Dec 30, 2025
by
yubin
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
https://code.palacesun.com/wuchao/jilinzhongdianrenqun-web
parents
a91a89c2
0bef0175
显示空白字符变更
内嵌
并排
正在显示
14 个修改的文件
包含
1861 行增加
和
170 行删除
+1861
-170
src/api/key-dm-inbound.js
+9
-0
src/api/key-dm-inventory.js
+9
-0
src/api/key-dm-user.js
+3
-2
src/api/key-dm.js
+74
-0
src/router/group/key-person.js
+8
-0
src/view/key-person/key_dm_conf/chartAnalysis.vue
+471
-0
src/view/key-person/key_dm_conf/index.vue
+219
-53
src/view/key-person/key_dm_inventory/inbound.vue
+394
-43
src/view/key-person/key_dm_inventory/index.vue
+421
-21
src/view/key-person/key_dm_inventory/stats.vue
+60
-16
src/view/key-person/key_dm_leave/index.vue
+13
-18
src/view/key-person/key_dm_user/index.vue
+25
-7
src/view/key-person/key_dm_user/userMultiSelector.vue
+8
-10
src/view/key-person/key_dm_user/userSelector.vue
+147
-0
没有找到文件。
src/api/key-dm-inbound.js
View file @
30a96ce8
...
...
@@ -71,3 +71,12 @@ export const getInboundById = (param) => {
data
:
param
})
}
// 归还详情
export
const
getPendingReturnById
=
(
param
)
=>
{
return
axios
.
request
({
url
:
'/api/ac/jilinsscgsdp/keyDmInbound/getPendingReturnById'
,
method
:
'post'
,
data
:
param
})
}
src/api/key-dm-inventory.js
View file @
30a96ce8
...
...
@@ -18,6 +18,15 @@ export const getPendingBorrowList = (param) => {
})
}
// 获取历史列表
export
const
getHistoryBorrowList
=
(
param
)
=>
{
return
axios
.
request
({
url
:
'/api/keyDmBorrow/selectHistoryList'
,
method
:
'post'
,
data
:
param
})
}
// 保存申请(含明细)
export
const
saveBorrowApplication
=
(
param
)
=>
{
return
axios
.
request
({
...
...
src/api/key-dm-user.js
View file @
30a96ce8
...
...
@@ -47,8 +47,9 @@ export const dmUserOffice = (param) => {
export
const
getUserTypeList
=
(
param
)
=>
{
return
axios
.
request
({
url
:
'/api/ac/jilinsscgsdp/keyDmUserCategory/selectList'
url
:
'/api/ac/jilinsscgsdp/keyDmUserCategory/selectList'
,
method
:
'post'
,
data
:
param
})
}
// 获取人员多选器列表(所有在职人员)
...
...
src/api/key-dm.js
View file @
30a96ce8
...
...
@@ -167,3 +167,77 @@ export const getWorkloadDetails = (param) => {
data
:
param
})
}
// ===== 图表分析 =====
// 汇总统计数据
export
const
getSummaryStats
=
()
=>
{
return
axios
.
request
({
url
:
'/api/ac/jilinsscgsdp/keyDmUserCategory/getSummaryStats'
,
method
:
'post'
})
}
// 请假类型统计
export
const
getLeaveTypeStats
=
()
=>
{
return
axios
.
request
({
url
:
'/api/ac/jilinsscgsdp/keyDmUserCategory/getLeaveTypeStats'
,
method
:
'post'
})
}
// 人员请假统计
export
const
getLeaveUserStats
=
()
=>
{
return
axios
.
request
({
url
:
'/api/ac/jilinsscgsdp/keyDmUserCategory/getLeaveUserStats'
,
method
:
'post'
})
}
// 用品领用统计
export
const
getMaterialUsageStats
=
()
=>
{
return
axios
.
request
({
url
:
'/api/ac/jilinsscgsdp/keyDmUserCategory/getMaterialUsageStats'
,
method
:
'post'
})
}
// 库存预警列表
export
const
getStockWarningList
=
()
=>
{
return
axios
.
request
({
url
:
'/api/ac/jilinsscgsdp/keyDmUserCategory/getStockWarningList'
,
method
:
'post'
})
}
// ===== 部门管理 =====
export
const
getOrgList
=
(
param
)
=>
{
return
axios
.
request
({
url
:
'/api/ac/jilinsscgsdp/keyDmUserCategory/selectOrgList'
,
method
:
'post'
,
data
:
param
})
}
export
const
saveOrg
=
(
param
)
=>
{
return
axios
.
request
({
url
:
'/api/ac/jilinsscgsdp/keyDmUserCategory/saveOrg'
,
method
:
'post'
,
data
:
param
})
}
export
const
deleteOrg
=
(
param
)
=>
{
return
axios
.
request
({
url
:
'/api/ac/jilinsscgsdp/keyDmUserCategory/deleteOrg'
,
method
:
'post'
,
data
:
param
})
}
export
const
assignUsersToOrg
=
(
param
)
=>
{
return
axios
.
request
({
url
:
'/api/ac/jilinsscgsdp/keyDmUserCategory/assignUsersToOrg'
,
method
:
'post'
,
data
:
param
})
}
src/router/group/key-person.js
View file @
30a96ce8
...
...
@@ -254,5 +254,13 @@ export default [
title
:
'日常管理统计'
},
component
:
()
=>
import
(
'@/view/key-person/key_dm_inventory/stats'
)
},
{
path
:
'/key-person/dmChartAnalysis'
,
name
:
'dmChartAnalysis'
,
meta
:
{
title
:
'日常数据统计分析'
},
component
:
()
=>
import
(
'@/view/key-person/key_dm_conf/chartAnalysis'
)
}
]
src/view/key-person/key_dm_conf/chartAnalysis.vue
0 → 100644
View file @
30a96ce8
<
template
>
<div
class=
"chart-analysis-wrapper"
>
<!-- 第一行:统计标签 -->
<div
class=
"header-container"
>
<div
class=
"title-wrapper"
>
<div
class=
"title-bar"
></div>
<h3
class=
"title-text"
>
数据概览
</h3>
</div>
</div>
<Row
class=
"statistics-bar"
>
<Col
span=
"8"
>
<div
class=
"statistics-item leave-count"
>
<div
class=
"stat-icon"
>
<Icon
type=
"ios-calendar-outline"
size=
"32"
/>
</div>
<div
class=
"stat-content"
>
<div
class=
"stat-title"
>
请假申请次数
</div>
<div
class=
"stat-number"
>
{{
summaryData
.
leaveCount
}}
</div>
<div
class=
"stat-unit"
>
次
</div>
</div>
</div>
</Col>
<Col
span=
"8"
>
<div
class=
"statistics-item borrow-count"
>
<div
class=
"stat-icon"
>
<Icon
type=
"ios-paper-outline"
size=
"32"
/>
</div>
<div
class=
"stat-content"
>
<div
class=
"stat-title"
>
办公用品申领次数
</div>
<div
class=
"stat-number"
>
{{
summaryData
.
borrowCount
}}
</div>
<div
class=
"stat-unit"
>
次
</div>
</div>
</div>
</Col>
<Col
span=
"8"
>
<div
class=
"statistics-item inbound-count"
>
<div
class=
"stat-icon"
>
<Icon
type=
"ios-archive-outline"
size=
"32"
/>
</div>
<div
class=
"stat-content"
>
<div
class=
"stat-title"
>
办公用品入库次数
</div>
<div
class=
"stat-number"
>
{{
summaryData
.
inboundCount
}}
</div>
<div
class=
"stat-unit"
>
次
</div>
</div>
</div>
</Col>
</Row>
<!-- 第二行:请假相关图表 -->
<div
class=
"header-container"
>
<div
class=
"title-wrapper"
>
<div
class=
"title-bar"
></div>
<h3
class=
"title-text"
>
请假数据分析
</h3>
</div>
</div>
<Row
:gutter=
"16"
>
<Col
span=
"10"
>
<Card>
<div
class=
"chart-title"
>
请假类型占比
</div>
<div
ref=
"leaveTypeChart"
class=
"chart-container"
></div>
</Card>
</Col>
<Col
span=
"14"
>
<Card>
<div
class=
"chart-title"
>
月度各人员请假次数
</div>
<div
ref=
"leaveUserChart"
class=
"chart-container"
></div>
</Card>
</Col>
</Row>
<!-- 第三行:办公用品相关图表和表格 -->
<div
class=
"header-container"
>
<div
class=
"title-wrapper"
>
<div
class=
"title-bar"
></div>
<h3
class=
"title-text"
>
办公用品数据分析
</h3>
</div>
</div>
<Row
:gutter=
"16"
>
<Col
span=
"10"
>
<Card>
<div
class=
"chart-title"
>
月度各用品领用量
</div>
<div
ref=
"materialUsageChart"
class=
"chart-container"
></div>
</Card>
</Col>
<Col
span=
"14"
>
<Card
class=
"stock-warning-card"
>
<div
class=
"chart-title"
>
库存预警信息
</div>
<div
class=
"table-container"
>
<Table
:data=
"stockWarningData"
:columns=
"stockWarningColumns"
size=
"small"
border
:height=
"chartHeight"
>
<template
slot=
"threshold"
slot-scope=
"
{ row }">
<span>
{{
row
.
min_stock
}}
-
{{
row
.
max_stock
}}
</span>
</
template
>
<
template
slot=
"status"
slot-scope=
"{ row }"
>
<Tag
:color=
"row.status === 'low' ? 'red' : 'orange'"
>
{{
row
.
status
===
'low'
?
'库存不足'
:
'库存过高'
}}
</Tag>
</
template
>
</Table>
</div>
</Card>
</Col>
</Row>
</div>
</template>
<
script
>
import
*
as
echarts
from
'echarts'
import
{
getSummaryStats
,
getLeaveTypeStats
,
getLeaveUserStats
,
getMaterialUsageStats
,
getStockWarningList
}
from
'@/api/key-dm'
export
default
{
name
:
'chart-analysis'
,
data
()
{
return
{
summaryData
:
{
leaveCount
:
0
,
borrowCount
:
0
,
inboundCount
:
0
},
leaveTypeChart
:
null
,
leaveUserChart
:
null
,
materialUsageChart
:
null
,
chartHeight
:
240
,
stockWarningData
:
[],
stockWarningColumns
:
[
{
title
:
'用品名称'
,
key
:
'material_name'
,
align
:
'center'
,
minWidth
:
50
},
{
title
:
'现有数量'
,
key
:
'available_quantity'
,
align
:
'center'
,
minWidth
:
50
},
{
title
:
'阙值范围'
,
slot
:
'threshold'
,
align
:
'center'
,
minWidth
:
50
},
{
title
:
'状态'
,
slot
:
'status'
,
align
:
'center'
,
minWidth
:
50
}
]
}
},
mounted
()
{
this
.
loadData
()
},
beforeDestroy
()
{
if
(
this
.
leaveTypeChart
)
{
this
.
leaveTypeChart
.
dispose
()
}
if
(
this
.
leaveUserChart
)
{
this
.
leaveUserChart
.
dispose
()
}
if
(
this
.
materialUsageChart
)
{
this
.
materialUsageChart
.
dispose
()
}
},
methods
:
{
loadData
()
{
this
.
loadSummaryStats
()
this
.
loadLeaveTypeStats
()
this
.
loadLeaveUserStats
()
this
.
loadMaterialUsageStats
()
this
.
loadStockWarningList
()
},
loadSummaryStats
()
{
getSummaryStats
().
then
(
ret
=>
{
if
(
ret
.
data
&&
ret
.
data
.
errcode
===
0
)
{
this
.
summaryData
=
ret
.
data
.
data
||
this
.
summaryData
}
}).
catch
(()
=>
{
this
.
$Message
.
error
(
'获取统计数据失败'
)
})
},
loadLeaveTypeStats
()
{
getLeaveTypeStats
().
then
(
ret
=>
{
if
(
ret
.
data
&&
ret
.
data
.
errcode
===
0
)
{
this
.
initLeaveTypeChart
(
ret
.
data
.
data
||
[])
}
}).
catch
(()
=>
{
this
.
$Message
.
error
(
'获取请假类型统计失败'
)
})
},
loadLeaveUserStats
()
{
getLeaveUserStats
().
then
(
ret
=>
{
if
(
ret
.
data
&&
ret
.
data
.
errcode
===
0
)
{
this
.
initLeaveUserChart
(
ret
.
data
.
data
||
[])
}
}).
catch
(()
=>
{
this
.
$Message
.
error
(
'获取人员请假统计失败'
)
})
},
loadMaterialUsageStats
()
{
getMaterialUsageStats
().
then
(
ret
=>
{
if
(
ret
.
data
&&
ret
.
data
.
errcode
===
0
)
{
this
.
initMaterialUsageChart
(
ret
.
data
.
data
||
[])
}
}).
catch
(()
=>
{
this
.
$Message
.
error
(
'获取用品领用统计失败'
)
})
},
loadStockWarningList
()
{
getStockWarningList
().
then
(
ret
=>
{
if
(
ret
.
data
&&
ret
.
data
.
errcode
===
0
)
{
this
.
stockWarningData
=
ret
.
data
.
data
||
[]
}
}).
catch
(()
=>
{
this
.
$Message
.
error
(
'获取库存预警数据失败'
)
})
},
initLeaveTypeChart
(
data
)
{
this
.
$nextTick
(()
=>
{
const
chartDom
=
this
.
$refs
.
leaveTypeChart
if
(
!
chartDom
)
return
this
.
leaveTypeChart
=
echarts
.
init
(
chartDom
)
const
colors
=
[
'#73c0de'
,
'#3ba272'
,
'#fc8452'
,
'#9a60b4'
,
'#ea7ccc'
,
'#91cc75'
,
'#fac858'
,
'#ee6666'
]
const
option
=
{
tooltip
:
{
trigger
:
'item'
,
formatter
:
'{a} <br/>{b}: {c} ({d}%)'
},
legend
:
{
orient
:
'vertical'
,
left
:
'left'
,
textStyle
:
{
fontSize
:
12
}
},
color
:
colors
,
series
:
[
{
name
:
'请假类型'
,
type
:
'pie'
,
radius
:
[
'50%'
,
'70%'
],
avoidLabelOverlap
:
false
,
label
:
{
show
:
true
,
position
:
'outside'
,
formatter
:
'{b}: {c}'
,
fontSize
:
12
},
emphasis
:
{
label
:
{
show
:
true
,
fontSize
:
'16'
,
fontWeight
:
'bold'
}
},
labelLine
:
{
show
:
true
,
length
:
10
,
length2
:
10
},
data
:
data
.
map
((
item
,
index
)
=>
({
value
:
item
.
count
,
name
:
item
.
type_name
,
itemStyle
:
{
color
:
colors
[
index
%
colors
.
length
]
}
}))
}
]
}
this
.
leaveTypeChart
.
setOption
(
option
)
})
},
initLeaveUserChart
(
data
)
{
this
.
$nextTick
(()
=>
{
const
chartDom
=
this
.
$refs
.
leaveUserChart
if
(
!
chartDom
)
return
this
.
leaveUserChart
=
echarts
.
init
(
chartDom
)
const
option
=
{
tooltip
:
{
trigger
:
'axis'
,
axisPointer
:
{
type
:
'shadow'
}
},
grid
:
{
left
:
'3%'
,
right
:
'4%'
,
bottom
:
'3%'
,
containLabel
:
true
},
xAxis
:
{
type
:
'category'
,
data
:
data
.
map
(
item
=>
item
.
user_name
),
axisLabel
:
{
rotate
:
45
}
},
yAxis
:
{
type
:
'value'
},
series
:
[
{
name
:
'请假次数'
,
type
:
'bar'
,
data
:
data
.
map
(
item
=>
item
.
leave_count
),
itemStyle
:
{
color
:
'#409EFF'
}
}
]
}
this
.
leaveUserChart
.
setOption
(
option
)
})
},
initMaterialUsageChart
(
data
)
{
this
.
$nextTick
(()
=>
{
const
chartDom
=
this
.
$refs
.
materialUsageChart
if
(
!
chartDom
)
return
this
.
materialUsageChart
=
echarts
.
init
(
chartDom
)
const
colors
=
[
'#73c0de'
,
'#3ba272'
,
'#fc8452'
,
'#9a60b4'
,
'#ea7ccc'
,
'#91cc75'
,
'#fac858'
,
'#ee6666'
]
const
option
=
{
tooltip
:
{
trigger
:
'item'
,
formatter
:
'{a} <br/>{b}: {c} ({d}%)'
},
legend
:
{
orient
:
'vertical'
,
left
:
'left'
,
textStyle
:
{
fontSize
:
12
}
},
color
:
colors
,
series
:
[
{
name
:
'领用量'
,
type
:
'pie'
,
radius
:
[
'50%'
,
'70%'
],
avoidLabelOverlap
:
false
,
label
:
{
show
:
true
,
position
:
'outside'
,
formatter
:
'{b}: {c}'
,
fontSize
:
12
},
emphasis
:
{
label
:
{
show
:
true
,
fontSize
:
'16'
,
fontWeight
:
'bold'
}
},
labelLine
:
{
show
:
true
,
length
:
10
,
length2
:
10
},
data
:
data
.
map
((
item
,
index
)
=>
({
value
:
item
.
total_quantity
,
name
:
item
.
material_name
,
itemStyle
:
{
color
:
colors
[
index
%
colors
.
length
]
}
}))
}
]
}
this
.
materialUsageChart
.
setOption
(
option
)
})
}
}
}
</
script
>
<
style
scoped
>
.chart-analysis-wrapper
{
padding
:
20px
;
}
.header-container
{
margin
:
20px
0
10px
0
;
}
.title-wrapper
{
display
:
flex
;
align-items
:
center
;
}
.title-bar
{
width
:
4px
;
height
:
20px
;
background-color
:
#409EFF
;
margin-right
:
10px
;
}
.title-text
{
margin
:
0
;
font-size
:
18px
;
font-weight
:
600
;
color
:
#333
;
}
.statistics-bar
{
margin-bottom
:
20px
;
}
.statistics-item
{
display
:
flex
;
align-items
:
center
;
padding
:
20px
;
background
:
linear-gradient
(
135deg
,
#667eea
0%
,
#764ba2
100%
);
border-radius
:
8px
;
margin
:
0
10px
;
box-shadow
:
0
4px
6px
rgba
(
0
,
0
,
0
,
0.1
);
}
.statistics-item.leave-count
{
background
:
linear-gradient
(
135deg
,
#f093fb
0%
,
#f5576c
100%
);
}
.statistics-item.borrow-count
{
background
:
linear-gradient
(
135deg
,
#4facfe
0%
,
#00f2fe
100%
);
}
.statistics-item.inbound-count
{
background
:
linear-gradient
(
135deg
,
#43e97b
0%
,
#38f9d7
100%
);
}
.stat-icon
{
color
:
white
;
margin-right
:
20px
;
}
.stat-content
{
flex
:
1
;
}
.stat-title
{
font-size
:
14px
;
color
:
rgba
(
255
,
255
,
255
,
0.8
);
margin-bottom
:
8px
;
}
.stat-number
{
font-size
:
36px
;
font-weight
:
bold
;
color
:
white
;
margin-bottom
:
4px
;
display
:
inline
;
}
.stat-unit
{
font-size
:
16px
;
color
:
rgba
(
255
,
255
,
255
,
0.8
);
display
:
inline
;
}
.chart-container
{
width
:
100%
;
height
:
240px
;
}
.chart-title
{
font-size
:
16px
;
font-weight
:
600
;
margin-bottom
:
16px
;
text-align
:
center
;
}
.stock-warning-card
{
height
:
315px
;
display
:
flex
;
flex-direction
:
column
;
}
.table-container
{
flex
:
1
;
overflow
:
hidden
;
}
</
style
>
src/view/key-person/key_dm_conf/index.vue
View file @
30a96ce8
...
...
@@ -9,17 +9,51 @@
</
template
>
</Table>
</TabPane>
<!-- 部门管理 -->
<TabPane
label=
"部门管理"
name=
"org"
>
<div
class=
"search-div"
>
<Row
type=
"flex"
:gutter=
"16"
>
<Col
span=
"12"
>
<span>
部门名称:
</span>
<Input
v-model=
"filters.org.org_name"
placeholder=
"请输入"
style=
"width: 200px"
/>
</Col>
<Col
span=
"12"
class=
"text-right"
>
<Button
type=
"primary"
class=
"mr10"
@
click=
"handleSearch('org')"
>
搜索
</Button>
<Button
type=
"primary"
class=
"mr10"
@
click=
"handleReset('org')"
>
重置
</Button>
<Button
type=
"primary"
@
click=
"openAddModal('org')"
>
新增
</Button>
</Col>
</Row>
</div>
<Table
border
:loading=
"loading.org"
:columns=
"orgColumns"
:data=
"tables.org"
>
<
template
slot=
"action"
slot-scope=
"{ row }"
>
<Button
size=
"small"
type=
"primary"
class=
"mr5"
@
click=
"openEditModal('org', row)"
>
修改
</Button>
<Button
size=
"small"
type=
"info"
class=
"mr5"
@
click=
"openUserAssignModal(row)"
>
人员划分
</Button>
<Poptip
confirm
title=
"确认删除?"
transfer
@
on-ok=
"handleDelete('org', row)"
>
<Button
size=
"small"
type=
"error"
>
删除
</Button>
</Poptip>
</
template
>
</Table>
<Page
class=
"page_style"
:total=
"pagers.org.totalRecord"
:current=
"pagers.org.pageNo"
:page-size=
"pagers.org.pageSize"
show-total
show-sizer
@
on-change=
"pageChange('org', $event)"
@
on-page-size-change=
"sizeChange('org', $event)"
/>
</TabPane>
<!-- 假种管理 -->
<TabPane
label=
"假种管理"
name=
"leaveType"
>
<div
class=
"search-div"
>
<Row
type=
"flex"
:gutter=
"16"
>
<Col
span=
"6"
>
<span>
类型名称:
</span>
<Input
v-model=
"filters.leaveType.type_name"
placeholder=
"请输入"
style=
"width: 70%"
/>
</Col>
<Col
span=
"6"
>
<Col
span=
"12"
>
<span>
类型编码:
</span>
<Input
v-model=
"filters.leaveType.type_code"
placeholder=
"请输入"
style=
"width: 70%"
/>
<Input
v-model=
"filters.leaveType.type_code"
placeholder=
"请输入"
style=
"width: 200px"
class=
"mr10"
/>
<span>
类型名称:
</span>
<Input
v-model=
"filters.leaveType.type_name"
placeholder=
"请输入"
style=
"width: 200px"
/>
</Col>
<Col
span=
"12"
class=
"text-right"
>
<Button
type=
"primary"
class=
"mr10"
@
click=
"handleSearch('leaveType')"
>
搜索
</Button>
...
...
@@ -52,13 +86,11 @@
<TabPane
label=
"办公用品分类管理"
name=
"materialCategory"
>
<div
class=
"search-div"
>
<Row
type=
"flex"
:gutter=
"16"
>
<Col
span=
"6"
>
<span>
分类名称:
</span>
<Input
v-model=
"filters.materialCategory.category_name"
placeholder=
"请输入"
style=
"width: 70%"
/>
</Col>
<Col
span=
"6"
>
<Col
span=
"12"
>
<span>
分类编码:
</span>
<Input
v-model=
"filters.materialCategory.category_code"
placeholder=
"请输入"
style=
"width: 70%"
/>
<Input
v-model=
"filters.materialCategory.category_code"
placeholder=
"请输入"
style=
"width: 200px"
class=
"mr10"
/>
<span>
分类名称:
</span>
<Input
v-model=
"filters.materialCategory.category_name"
placeholder=
"请输入"
style=
"width: 200px"
/>
</Col>
<Col
span=
"12"
class=
"text-right"
>
<Button
type=
"primary"
class=
"mr10"
@
click=
"handleSearch('materialCategory')"
>
搜索
</Button>
...
...
@@ -91,19 +123,15 @@
<TabPane
label=
"办公用品管理"
name=
"material"
>
<div
class=
"search-div"
>
<Row
type=
"flex"
:gutter=
"16"
>
<Col
span=
"6"
>
<span>
名称:
</span>
<Input
v-model=
"filters.material.material_name"
placeholder=
"请输入"
style=
"width: 70%"
/>
</Col>
<Col
span=
"6"
>
<span>
编码:
</span>
<Input
v-model=
"filters.material.material_code"
placeholder=
"请输入"
style=
"width: 70%"
/>
</Col>
<Col
span=
"6"
>
<Col
span=
"18"
>
<span>
分类:
</span>
<Select
v-model=
"filters.material.category_id"
clearable
style=
"width:
70%
"
>
<Select
v-model=
"filters.material.category_id"
clearable
style=
"width:
200px"
class=
"mr10
"
>
<Option
v-for=
"cat in materialCategoryOptions"
:key=
"cat.id"
:value=
"cat.id"
>
{{ cat.category_name }}
</Option>
</Select>
<span>
编码:
</span>
<Input
v-model=
"filters.material.material_code"
placeholder=
"请输入"
style=
"width: 200px"
class=
"mr10"
/>
<span>
名称:
</span>
<Input
v-model=
"filters.material.material_name"
placeholder=
"请输入"
style=
"width: 200px"
/>
</Col>
<Col
span=
"6"
class=
"text-right"
>
<Button
type=
"primary"
class=
"mr10"
@
click=
"handleSearch('material')"
>
搜索
</Button>
...
...
@@ -180,27 +208,12 @@
<Input
type=
"textarea"
:rows=
"3"
v-model=
"modals.leaveType.form.remark"
placeholder=
"请输入类型描述"
/>
</FormItem>
<Row
:gutter=
"16"
>
<Col
span=
"12"
>
<FormItem
label=
"基准天数"
prop=
"base_days"
>
<InputNumber
v-model=
"modals.leaveType.form.base_days"
:min=
"0"
:precision=
"2"
style=
"width: 100%"
/>
</FormItem>
</Col>
<Col
span=
"12"
>
<!-- <Col span="12">
<FormItem label="年度上限" prop="max_days_per_year">
<InputNumber v-model="modals.leaveType.form.max_days_per_year" :min="0" :precision="2" style="width: 100%" />
</FormItem>
</Col>
</Row>
<Row
:gutter=
"16"
>
<Col
span=
"12"
>
<FormItem
label=
"需要审批"
>
<Select
v-model=
"modals.leaveType.form.need_approval"
style=
"width: 100%"
>
<Option
:value=
"1"
>
需要
</Option>
<Option
:value=
"0"
>
不需要
</Option>
</Select>
</FormItem>
</Col>
<Col
span=
"12"
>
</Col> -->
<Col
span=
"24"
>
<FormItem
label=
"排序号"
prop=
"order_no"
>
<InputNumber
v-model=
"modals.leaveType.form.order_no"
:min=
"0"
style=
"width: 100%"
/>
</FormItem>
...
...
@@ -356,9 +369,55 @@
</div>
</Modal>
<!-- 部门管理弹窗 -->
<Modal
v-model=
"modals.org.visible"
:title=
"modals.org.isEdit ? '修改部门' : '新增部门'"
width=
"600"
:mask-closable=
"false"
>
<Form
:label-width=
"120"
:model=
"modals.org.form"
:rules=
"modals.org.rules"
ref=
"orgForm"
>
<!-- <FormItem label="部门编码" prop="org_code">
<Input v-model="modals.org.form.org_code" placeholder="请输入部门编码" />
</FormItem> -->
<FormItem
label=
"部门名称"
prop=
"org_name"
>
<Input
v-model=
"modals.org.form.org_name"
placeholder=
"请输入部门名称"
/>
</FormItem>
<!-- <FormItem label="所属机构编码" prop="source_org">
<Input v-model="modals.org.form.source_org" placeholder="请输入所属机构编码" />
</FormItem> -->
<FormItem
label=
"部门描述"
prop=
"remark"
>
<Input
type=
"textarea"
:rows=
"3"
v-model=
"modals.org.form.remark"
placeholder=
"请输入部门描述"
/>
</FormItem>
<FormItem
label=
"排序号"
prop=
"order_no"
>
<InputNumber
v-model=
"modals.org.form.order_no"
:min=
"0"
style=
"width: 100%"
/>
</FormItem>
</Form>
<div
slot=
"footer"
>
<Button
@
click=
"modals.org.visible = false"
>
取消
</Button>
<Button
type=
"primary"
:loading=
"modals.org.saving"
@
click=
"handleSave('org')"
>
保存
</Button>
</div>
</Modal>
<!-- 人员划分弹窗 -->
<Modal
v-model=
"userAssignModal.visible"
title=
"人员划分"
width=
"800"
:mask-closable=
"false"
>
<div
style=
"margin-bottom: 16px;"
>
<span
style=
"font-weight: bold;"
>
部门:
</span>
{{ userAssignModal.orgName }}
</div>
<div
style=
"margin-bottom: 16px;"
>
<span
style=
"font-weight: bold;"
>
已划分人员:
</span>
<div
style=
"margin-top: 8px;"
>
<Tag
v-for=
"user in userAssignModal.selectedUsers"
:key=
"user.user_id"
closable
@
on-close=
"removeAssignedUser(user)"
>
{{ user.user_name }}
</Tag>
</div>
</div>
<div
slot=
"footer"
>
<Button
@
click=
"userAssignModal.visible = false"
>
取消
</Button>
<Button
type=
"primary"
@
click=
"addUsersToOrg"
>
添加人员
</Button>
<Button
type=
"primary"
:loading=
"userAssignModal.saving"
@
click=
"saveUserAssignment"
>
保存
</Button>
</div>
</Modal>
<!-- 人员选择器 -->
<UserMultiSelector
v-model=
"userSelectorVisible"
:round=
"userRound"
@
on-ok=
"handleUserSelectorOk"
@
cancel=
"userSelectorVisible = false"
/>
...
...
@@ -379,7 +438,11 @@ import {
importMaterial
,
getPermissionConfigList
,
savePermissionUsers
,
getUserDmPermissionList
getUserDmPermissionList
,
getOrgList
,
saveOrg
,
deleteOrg
,
assignUsersToOrg
}
from
'@/api/key-dm'
import
axios
from
'axios'
import
UserMultiSelector
from
'@/view/key-person/key_dm_user/userMultiSelector.vue'
...
...
@@ -393,25 +456,29 @@ export default {
filters
:
{
leaveType
:
{
type_name
:
''
,
type_code
:
''
},
materialCategory
:
{
category_name
:
''
,
category_code
:
''
},
material
:
{
material_name
:
''
,
material_code
:
''
,
category_id
:
''
}
material
:
{
material_name
:
''
,
material_code
:
''
,
category_id
:
''
},
org
:
{
org_name
:
''
,
org_code
:
''
}
},
tables
:
{
permissionConfig
:
[],
leaveType
:
[],
materialCategory
:
[],
material
:
[]
material
:
[],
org
:
[]
},
loading
:
{
permissionConfig
:
false
,
leaveType
:
false
,
materialCategory
:
false
,
material
:
false
material
:
false
,
org
:
false
},
pagers
:
{
permissionConfig
:
{
pageNo
:
1
,
pageSize
:
10
,
totalRecord
:
0
},
leaveType
:
{
pageNo
:
1
,
pageSize
:
10
,
totalRecord
:
0
},
materialCategory
:
{
pageNo
:
1
,
pageSize
:
10
,
totalRecord
:
0
},
material
:
{
pageNo
:
1
,
pageSize
:
10
,
totalRecord
:
0
}
material
:
{
pageNo
:
1
,
pageSize
:
10
,
totalRecord
:
0
},
org
:
{
pageNo
:
1
,
pageSize
:
10
,
totalRecord
:
0
}
},
modals
:
{
leaveType
:
{
...
...
@@ -473,6 +540,23 @@ export default {
category_id
:
[{
required
:
true
,
message
:
'请选择分类'
,
trigger
:
'change'
}],
material_name
:
[{
required
:
true
,
message
:
'请输入物料名称'
,
trigger
:
'blur'
}]
}
},
org
:
{
visible
:
false
,
isEdit
:
false
,
saving
:
false
,
form
:
{
id
:
''
,
source_org
:
''
,
org_code
:
''
,
org_name
:
''
,
remark
:
''
,
order_no
:
0
},
rules
:
{
// org_code: [{ required: true, message: '请输入部门编码', trigger: 'blur' }],
org_name
:
[{
required
:
true
,
message
:
'请输入部门名称'
,
trigger
:
'blur'
}]
}
}
},
userConfigModal
:
{
...
...
@@ -482,6 +566,13 @@ export default {
permissionName
:
''
,
selectedUsers
:
[]
},
userAssignModal
:
{
visible
:
false
,
saving
:
false
,
orgId
:
''
,
orgName
:
''
,
selectedUsers
:
[]
},
userSelectorVisible
:
false
,
importShow
:
false
,
impBtnDisabled
:
false
,
...
...
@@ -490,8 +581,8 @@ export default {
{
type
:
'index'
,
title
:
'序号'
,
width
:
60
,
align
:
'center'
},
{
title
:
'类型编码'
,
key
:
'type_code'
,
align
:
'center'
},
{
title
:
'类型名称'
,
key
:
'type_name'
,
align
:
'center'
},
{
title
:
'基准天数'
,
key
:
'base_days'
,
align
:
'center'
,
width
:
100
},
{
title
:
'需要审批'
,
key
:
'need_approval'
,
align
:
'center'
,
width
:
100
,
render
:
(
h
,
{
row
})
=>
h
(
'span'
,
row
.
need_approval
===
1
?
'需要'
:
'不需要'
)
},
//
{ title: '基准天数', key: 'base_days', align: 'center', width: 100 },
//
{ title: '需要审批', key: 'need_approval', align: 'center', width: 100, render: (h, { row }) => h('span', row.need_approval === 1 ? '需要' : '不需要') },
{
title
:
'排序号'
,
key
:
'order_no'
,
align
:
'center'
,
width
:
100
},
{
title
:
'操作'
,
slot
:
'action'
,
align
:
'center'
,
width
:
180
,
fixed
:
'right'
}
],
...
...
@@ -528,12 +619,23 @@ export default {
{
title
:
'配置人员'
,
key
:
'user_names'
,
align
:
'center'
,
minWidth
:
300
},
{
title
:
'操作'
,
slot
:
'action'
,
align
:
'center'
,
width
:
120
,
fixed
:
'right'
}
],
orgColumns
:
[
{
type
:
'index'
,
title
:
'序号'
,
width
:
60
,
align
:
'center'
},
// { title: '部门编码', key: 'org_code', align: 'center' },
{
title
:
'部门名称'
,
key
:
'org_name'
,
align
:
'center'
},
// { title: '所属机构编码', key: 'source_org', align: 'center' },
{
title
:
'部门人员'
,
key
:
'user_names'
,
align
:
'center'
},
{
title
:
'描述'
,
key
:
'remark'
,
align
:
'center'
},
{
title
:
'排序号'
,
key
:
'order_no'
,
align
:
'center'
,
width
:
100
},
{
title
:
'操作'
,
slot
:
'action'
,
align
:
'center'
,
width
:
200
,
fixed
:
'right'
}
],
power
:
{
leave_approval
:
false
,
// 请假审核
leave_view
:
false
,
// 请假查询(统计)
supply_approval
:
false
,
// 用品申领审核
supply_view
:
false
// 用品查询(统计)
}
},
userRound
:
'1'
}
},
created
()
{
...
...
@@ -572,7 +674,8 @@ export default {
permissionConfig
:
()
=>
Promise
.
resolve
({
data
:
{
errcode
:
0
,
data
:
[]
}
}),
leaveType
:
getLeaveTypeList
,
materialCategory
:
getMaterialCategoryList
,
material
:
getMaterialList
material
:
getMaterialList
,
org
:
getOrgList
}
const
api
=
apiMap
[
tab
]
if
(
!
api
)
return
...
...
@@ -597,7 +700,8 @@ export default {
permissionConfig
:
()
=>
({}),
leaveType
:
()
=>
({
type_name
:
''
,
type_code
:
''
}),
materialCategory
:
()
=>
({
category_name
:
''
,
category_code
:
''
}),
material
:
()
=>
({
material_name
:
''
,
material_code
:
''
,
category_id
:
''
})
material
:
()
=>
({
material_name
:
''
,
material_code
:
''
,
category_id
:
''
}),
org
:
()
=>
({
org_name
:
''
,
org_code
:
''
})
}
this
.
filters
[
tab
]
=
resetMap
[
tab
]()
this
.
pagers
[
tab
].
pageNo
=
1
...
...
@@ -662,6 +766,14 @@ export default {
can_borrow
:
1
,
material_desc
:
''
,
order_no
:
0
},
org
:
{
id
:
''
,
source_org
:
''
,
org_code
:
''
,
org_name
:
''
,
remark
:
''
,
order_no
:
0
}
}
return
JSON
.
parse
(
JSON
.
stringify
(
defaults
[
tab
]))
...
...
@@ -676,7 +788,8 @@ export default {
const
saveApiMap
=
{
leaveType
:
saveLeaveType
,
materialCategory
:
saveMaterialCategory
,
material
:
saveMaterial
material
:
saveMaterial
,
org
:
saveOrg
}
const
api
=
saveApiMap
[
tab
]
api
(
modal
.
form
).
then
(
ret
=>
{
...
...
@@ -698,7 +811,8 @@ export default {
const
deleteApiMap
=
{
leaveType
:
deleteLeaveType
,
materialCategory
:
deleteMaterialCategory
,
material
:
deleteMaterial
material
:
deleteMaterial
,
org
:
deleteOrg
}
const
api
=
deleteApiMap
[
tab
]
api
({
id
:
row
.
id
}).
then
(
ret
=>
{
...
...
@@ -748,10 +862,12 @@ export default {
console
.
log
(
'this.userConfigModal'
,
this
.
userConfigModal
)
},
addUsers
()
{
this
.
userRound
=
'1'
this
.
userSelectorVisible
=
true
},
handleUserSelectorOk
(
selectedUsers
)
{
// 将新选择的用户添加到已选用户列表中,避免重复
if
(
this
.
userConfigModal
.
visible
)
{
// 权限配置弹窗
const
existingIds
=
this
.
userConfigModal
.
selectedUsers
.
map
(
u
=>
u
.
user_id
)
const
newUsers
=
selectedUsers
.
filter
(
u
=>
!
existingIds
.
includes
(
u
.
id
)).
map
(
u
=>
({
user_id
:
u
.
id
,
...
...
@@ -759,6 +875,16 @@ export default {
gh
:
u
.
gh
}))
this
.
userConfigModal
.
selectedUsers
=
[...
this
.
userConfigModal
.
selectedUsers
,
...
newUsers
]
}
else
if
(
this
.
userAssignModal
.
visible
)
{
// 人员划分弹窗
const
existingIds
=
this
.
userAssignModal
.
selectedUsers
.
map
(
u
=>
u
.
user_id
)
const
newUsers
=
selectedUsers
.
filter
(
u
=>
!
existingIds
.
includes
(
u
.
id
)).
map
(
u
=>
({
user_id
:
u
.
id
,
user_name
:
u
.
name
,
gh
:
u
.
gh
}))
this
.
userAssignModal
.
selectedUsers
=
[...
this
.
userAssignModal
.
selectedUsers
,
...
newUsers
]
}
this
.
userSelectorVisible
=
false
},
removeUser
(
user
)
{
...
...
@@ -876,6 +1002,46 @@ export default {
const
areaId
=
info
.
area_id
||
''
if
(
areaId
&&
areaId
.
startsWith
(
'2201'
))
return
true
return
false
},
openUserAssignModal
(
row
)
{
this
.
userAssignModal
.
visible
=
true
this
.
userAssignModal
.
orgId
=
row
.
id
this
.
userAssignModal
.
orgName
=
row
.
org_name
this
.
userAssignModal
.
selectedUsers
=
row
.
user_names
?
(
JSON
.
parse
(
row
.
users
)
||
[])
:
[]
// 加载该部门已分配的人员
// this.loadOrgAssignedUsers(row.id)
},
// loadOrgAssignedUsers (orgId) {
// getOrgList({ pageNo: 1, pageSize: 1000, params: { id: orgId } }).then(ret => {
// if (ret.data && ret.data.errcode === 0) {
// const data = ret.data.data || {}
// // 这里可以根据实际需求调整如何获取已分配的人员
// // 暂时设置为空,后续根据实际业务逻辑调整
// }
// })
// },
addUsersToOrg
()
{
this
.
userRound
=
'2'
this
.
userSelectorVisible
=
true
},
removeAssignedUser
(
user
)
{
this
.
userAssignModal
.
selectedUsers
=
this
.
userAssignModal
.
selectedUsers
.
filter
(
u
=>
u
.
user_id
!==
user
.
user_id
)
},
saveUserAssignment
()
{
this
.
userAssignModal
.
saving
=
true
const
userIds
=
this
.
userAssignModal
.
selectedUsers
.
map
(
u
=>
u
.
user_id
)
assignUsersToOrg
({
org_id
:
this
.
userAssignModal
.
orgId
,
user_ids
:
userIds
}).
then
(
ret
=>
{
if
(
ret
.
data
&&
ret
.
data
.
errcode
===
0
)
{
this
.
fetchList
(
"org"
)
this
.
$Message
.
success
(
'保存成功'
)
this
.
userAssignModal
.
visible
=
false
}
else
{
this
.
$Notice
.
error
({
title
:
'保存失败'
,
desc
:
ret
.
data
&&
ret
.
data
.
errmsg
})
}
}).
finally
(()
=>
{
})
}
}
}
...
...
src/view/key-person/key_dm_inventory/inbound.vue
View file @
30a96ce8
...
...
@@ -4,26 +4,77 @@
<TabPane
label=
"办公用品入库"
name=
"inbound"
>
<div
class=
"search-div"
>
<Row
type=
"flex"
:gutter=
"16"
>
<Col
span=
"8"
>
<Input
v-model=
"filters.inbound.inbound_no"
placeholder=
"单号/批次号"
style=
"width:60%"
/>
<Button
type=
"primary"
class=
"mr10"
@
click=
"handleSearch('inbound')"
>
搜索
</Button>
<Button
@
click=
"handleReset('inbound')"
>
重置
</Button>
<Col
span=
"20"
>
<div
class=
"search-form"
>
<Form
:inline=
"true"
:model=
"filters.return"
class=
"form-inline"
>
<FormItem
label=
"入库单号:"
class=
"form-item"
>
<Input
v-model=
"filters.inbound.inbound_no"
placeholder=
"请输入入库单号:"
class=
"form-input"
/>
</FormItem>
<FormItem
label=
"批次号:"
class=
"form-item"
>
<Input
v-model=
"filters.inbound.batch_no"
placeholder=
"请输入批次号:"
class=
"form-input"
/>
</FormItem>
<FormItem
label=
"入库日期"
class=
"form-item"
>
<DatePicker
v-model=
"inboundDateRange"
type=
"daterange"
range-separator=
"至"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
format=
"yyyy-MM-dd"
value-format=
"yyyy-MM-dd"
clearable
/>
</FormItem>
<FormItem
label=
"入库类型:"
class=
"form-item"
>
<Select
v-model=
"filters.inbound.inbound_type"
placeholder=
"请选择入库类型"
class=
"form-input"
>
<Option
:value=
'1'
>
手工入库
</Option>
<Option
:value=
'2'
>
归还入库
</Option>
</Select>
</FormItem>
<FormItem
label=
"入库类型:"
class=
"form-item"
>
<Select
v-model=
"filters.inbound.inbound_status"
placeholder=
"请选择入库类型"
class=
"form-input"
>
<Option
:value=
'0'
>
待入库
</Option>
<Option
:value=
'1'
>
已入库
</Option>
</Select>
</FormItem>
<FormItem
class=
"form-item-actions"
>
<Button
type=
"primary"
@
click=
"handleSearch('inbound')"
>
搜索
</Button>
<Button
@
click=
"handleReset('inbound')"
style=
"margin-left: 8px;"
>
重置
</Button>
</FormItem>
</Form>
</div>
</Col>
<Col
span=
"
16
"
class=
"text-right"
>
<Col
span=
"
4
"
class=
"text-right"
>
<Button
type=
"success"
@
click=
"openInboundModal"
>
新增入库
</Button>
</Col>
</Row>
</div>
<Table
:data=
"tables.inbound"
:loading=
"loading.inbound"
:columns=
"inboundColumns"
border
>
<template
slot=
"action"
slot-scope=
"
{ row }">
<Poptip
confirm
title=
"确认执行入库?"
transfer
@
on-ok=
"doInbound(row)"
v-if=
"row.inbound_status === 0"
>
<Button
size=
"small"
type=
"success"
>
入库
</Button>
</Poptip>
<Button
size=
"small"
@
click=
"openDetail(row)"
>
详细
</Button>
<Button
size=
"small"
type=
"primary"
@
click=
"openEdit(row)"
v-if=
"canEdit(row)"
>
修改
</Button>
<Poptip
confirm
title=
"确认删除?"
transfer
@
on-ok=
"deleteInbound(row)"
>
<Button
size=
"small"
type=
"error"
>
删除
</Button>
</Poptip>
<Poptip
confirm
title=
"确认执行入库?"
transfer
@
on-ok=
"doInbound(row)"
v-if=
"row.inbound_status===0"
>
<Button
size=
"small"
type=
"success"
>
入库
</Button>
</Poptip>
</
template
>
</Table>
<Page
class=
"page_style"
:total=
"pagers.inbound.totalRecord"
:current=
"pagers.inbound.pageNo"
:page-size=
"pagers.inbound.pageSize"
...
...
@@ -34,9 +85,28 @@
<div
class=
"search-div"
>
<Row
type=
"flex"
:gutter=
"16"
>
<Col
span=
"10"
>
<Input
v-model=
"filters.return.key"
placeholder=
"申请单号/申请人"
style=
"width:60%"
/>
<Button
type=
"primary"
class=
"mr10"
@
click=
"handleSearch('return')"
>
搜索
</Button>
<Button
@
click=
"handleReset('return')"
>
重置
</Button>
<div
class=
"search-form"
>
<Form
:inline=
"true"
:model=
"filters.return"
class=
"form-inline"
>
<FormItem
label=
"申请单号:"
class=
"form-item"
>
<Input
v-model=
"filters.return.application_no"
placeholder=
"请输入申请单号"
class=
"form-input"
/>
</FormItem>
<FormItem
label=
"申请人:"
class=
"form-item"
>
<Input
v-model=
"filters.return.applicant_name"
placeholder=
"请输入申请人"
class=
"form-input"
/>
</FormItem>
<FormItem
class=
"form-item-actions"
>
<Button
type=
"primary"
@
click=
"handleSearch('return')"
>
搜索
</Button>
<Button
@
click=
"handleReset('return')"
style=
"margin-left: 8px;"
>
重置
</Button>
</FormItem>
</Form>
</div>
</Col>
</Row>
</div>
...
...
@@ -73,7 +143,13 @@
<Input
v-model=
"inboundModal.form.batch_no"
/>
</FormItem>
<FormItem
label=
"入库日期"
>
<DatePicker
v-model=
"inboundModal.form.inbound_date"
type=
"date"
/>
<DatePicker
v-model=
"inboundModal.form.inbound_date"
type=
"date"
format=
"yyyy-MM-dd"
value-format=
"yyyy-MM-dd"
placeholder=
"请选择入库日期"
/>
</FormItem>
<FormItem
label=
"存放位置"
>
<Input
v-model=
"inboundModal.form.storage_location"
/>
...
...
@@ -136,17 +212,42 @@ import {
getPendingReturnList
,
processReturn
,
getInventoryList
,
getInboundById
getInboundById
,
getPendingReturnById
}
from
'@/api/key-dm-inbound'
import
MaterialSelector
from
'@/view/key-person/key_dm_conf/materialSelector.vue'
import
{
normalizeVisitTimeValue
}
from
'@/view/key-person/key_dm_conf/dates.js'
export
default
{
name
:
'key-dm-inbound-index'
,
components
:
{
MaterialSelector
},
data
()
{
return
{
// 时间范围数组
inboundDateRange
:
null
,
// 入库状态映射字典
inboundTypeMap
:
{
'1'
:
'手工'
,
'2'
:
'归还'
},
inboundStatusMap
:
{
'0'
:
'待入库'
,
'1'
:
'已入库'
},
opTypeMap
:
{
'1'
:
'入库'
,
'2'
:
'出库'
},
issueStatusType
:
{
'0'
:
'待发放'
,
'1'
:
'已发放'
},
activeTab
:
'inbound'
,
filters
:
{
inbound
:
{
inbound_no
:
''
},
return
:
{
key
:
''
},
inventory
:
{
material_name
:
''
}
},
filters
:
{
inbound
:
{
inbound_no
:
null
,
batch_no
:
null
,
startDate
:
null
,
endDate
:
null
,
inbound_type
:
null
,
inbound_status
:
null
},
return
:
{
application_no
:
''
,
applicant_name
:
''
},
inventory
:
{
material_name
:
''
}
},
tables
:
{
inbound
:
[],
return
:
[],
inventory
:
[]
},
pagers
:
{
inbound
:
{
pageNo
:
1
,
pageSize
:
10
,
totalRecord
:
0
},
return
:
{
pageNo
:
1
,
pageSize
:
10
,
totalRecord
:
0
},
inventory
:
{
pageNo
:
1
,
pageSize
:
10
,
totalRecord
:
0
}
},
loading
:
{
inbound
:
false
,
return
:
false
,
inventory
:
false
},
...
...
@@ -154,9 +255,30 @@ export default {
{
type
:
'index'
,
title
:
'序号'
,
width
:
60
,
align
:
'center'
},
{
title
:
'入库单号'
,
key
:
'inbound_no'
,
align
:
'center'
},
{
title
:
'批次号'
,
key
:
'batch_no'
,
align
:
'center'
},
{
title
:
'入库日期'
,
key
:
'inbound_date'
,
align
:
'center'
},
{
title
:
'类型'
,
key
:
'inbound_type'
,
align
:
'center'
},
{
title
:
'状态'
,
key
:
'inbound_status'
,
align
:
'center'
},
{
title
:
'入库日期'
,
key
:
'inbound_date'
,
align
:
'center'
,
render
:
(
h
,
{
row
})
=>
{
return
h
(
'span'
,
this
.
formatDate
(
row
.
inbound_date
)
||
row
.
inbound_date
||
''
)
}
},
{
title
:
'类型'
,
key
:
'inbound_type'
,
align
:
'center'
,
render
:
(
h
,
{
row
})
=>
{
return
h
(
'span'
,
this
.
inboundTypeMap
[
row
.
inbound_type
]
||
row
.
inbound_type
||
'-'
)
}
},
{
title
:
'状态'
,
key
:
'inbound_status'
,
align
:
'center'
,
render
:
(
h
,
{
row
})
=>
{
return
h
(
'span'
,
this
.
inboundStatusMap
[
row
.
inbound_status
]
||
row
.
inbound_status
||
'-'
)
}
},
{
title
:
'操作'
,
slot
:
'action'
,
width
:
360
,
align
:
'center'
}
],
returnColumns
:
[
...
...
@@ -164,7 +286,14 @@ export default {
{
title
:
'申请单号'
,
key
:
'application_no'
,
align
:
'center'
},
{
title
:
'申请人'
,
key
:
'applicant_name'
,
align
:
'center'
},
{
title
:
'部门'
,
key
:
'department_name'
,
align
:
'center'
},
{
title
:
'发放状态'
,
key
:
'issue_status'
,
align
:
'center'
},
{
title
:
'发放状态'
,
key
:
'issue_status'
,
align
:
'center'
,
render
:
(
h
,
{
row
})
=>
{
return
h
(
'span'
,
this
.
issueStatusType
[
row
.
issue_status
]
||
row
.
issue_status
||
'-'
)
}
},
{
title
:
'操作'
,
slot
:
'action'
,
width
:
140
,
align
:
'center'
}
],
inventoryColumns
:
[
...
...
@@ -172,8 +301,16 @@ export default {
{
title
:
'物料编码'
,
key
:
'material_code'
,
align
:
'center'
},
{
title
:
'物料名称'
,
key
:
'material_name'
,
align
:
'center'
},
{
title
:
'总量'
,
key
:
'total_quantity'
,
align
:
'center'
},
{
title
:
'可用'
,
key
:
'available_quantity'
,
align
:
'center'
},
{
title
:
'借出'
,
key
:
'borrowed_quantity'
,
align
:
'center'
}
{
title
:
'可用'
,
key
:
'available_quantity'
,
align
:
'center'
,
render
:
(
h
,
{
row
})
=>
{
return
h
(
'span'
,
(
row
.
total_quantity
-
row
.
borrowed_quantity
-
row
.
damaged_quantity
)
||
0
)
}
},
{
title
:
'借出'
,
key
:
'borrowed_quantity'
,
align
:
'center'
},
{
title
:
'损坏'
,
key
:
'damaged_quantity'
,
align
:
'center'
}
],
// 模态窗口内表格列定义
inboundDetailColumns
:
[
...
...
@@ -192,13 +329,18 @@ export default {
},
style
:
{
width
:
'100px'
},
on
:
{
input
:
(
val
)
=>
{
params
.
row
.
inbound_quantity
=
val
||
0
params
.
row
.
total_amount
=
((
params
.
row
.
inbound_quantity
||
0
)
*
(
params
.
row
.
unit_price
||
0
)).
toFixed
(
2
)
'on-change'
:
(
val
)
=>
{
// 使用Vue.set确保响应式更新
this
.
$set
(
this
.
inboundModal
.
details
[
params
.
index
],
'inbound_quantity'
,
Number
(
val
)
||
0
)
// 计算并更新总金额
const
quantity
=
Number
(
val
)
||
0
const
unitPrice
=
this
.
inboundModal
.
details
[
params
.
index
].
unit_price
||
0
this
.
$set
(
this
.
inboundModal
.
details
[
params
.
index
],
'total_amount'
,
(
quantity
*
unitPrice
).
toFixed
(
2
))
}
}
})
}
},
}
},
{
title
:
'单价'
,
key
:
'unit_price'
,
minWidth
:
120
,
...
...
@@ -211,20 +353,30 @@ export default {
},
style
:
{
width
:
'100px'
},
on
:
{
input
:
(
val
)
=>
{
params
.
row
.
unit_price
=
val
||
0
params
.
row
.
total_amount
=
((
params
.
row
.
inbound_quantity
||
0
)
*
(
params
.
row
.
unit_price
||
0
)).
toFixed
(
2
)
'on-change'
:
(
val
)
=>
{
// 使用Vue.set确保响应式更新
this
.
$set
(
this
.
inboundModal
.
details
[
params
.
index
],
'unit_price'
,
Number
(
val
)
||
0
)
// 计算并更新总金额
const
quantity
=
this
.
inboundModal
.
details
[
params
.
index
].
inbound_quantity
||
0
const
unitPrice
=
Number
(
val
)
||
0
this
.
$set
(
this
.
inboundModal
.
details
[
params
.
index
],
'total_amount'
,
(
quantity
*
unitPrice
).
toFixed
(
2
))
}
}
})
}
},
{
title
:
'总金额'
,
}
},
{
title
:
'总金额'
,
key
:
'total_amount'
,
minWidth
:
120
,
render
:
(
h
,
params
)
=>
{
const
amount
=
((
params
.
row
.
inbound_quantity
||
0
)
*
(
params
.
row
.
unit_price
||
0
)).
toFixed
(
2
)
return
h
(
'span'
,
amount
)
}
}
const
quantity
=
Number
(
params
.
row
.
inbound_quantity
)
||
0
const
unitPrice
=
Number
(
params
.
row
.
unit_price
)
||
0
const
total
=
(
quantity
*
unitPrice
).
toFixed
(
2
)
this
.
$set
(
params
.
row
,
'total_amount'
,
total
)
return
h
(
'span'
,
total
)
}
}
],
returnDetailColumns
:
[
{
title
:
'物料名称'
,
key
:
'material_name'
},
...
...
@@ -238,9 +390,32 @@ export default {
{
title
:
'单价'
,
key
:
'unit_price'
}
],
detailLogsColumns
:
[
{
title
:
'操作类型'
,
key
:
'op_type'
},
{
title
:
'物料名称'
,
key
:
'material_name'
},
{
title
:
'操作类型'
,
key
:
'op_type'
,
render
:
(
h
,
{
row
})
=>
{
return
h
(
'span'
,
this
.
opTypeMap
[
row
.
op_type
]
||
row
.
op_type
||
'-'
)
}
},
{
title
:
'数量'
,
key
:
'quantity'
},
{
title
:
'时间'
,
key
:
'create_time'
}
{
title
:
'操作人'
,
key
:
'userName'
,
render
:
(
h
,
{
row
})
=>
{
return
h
(
'span'
,
row
.
userName
||
row
.
create_by
||
'-'
)
}
},
{
title
:
'时间'
,
key
:
'create_time'
,
render
:
(
h
,
{
row
})
=>
{
return
h
(
'span'
,
this
.
formatDateTime
(
row
.
create_time
)
||
row
.
create_time
||
'-'
)
}
}
],
// 选择器控制与已选明细
showMaterialSelector
:
false
,
...
...
@@ -250,8 +425,27 @@ export default {
detailModal
:
{
visible
:
false
,
loading
:
false
,
data
:
{},
details
:
[],
logs
:
[]
}
}
},
watch
:
{
inboundDateRange
(
newVal
)
{
if
(
newVal
&&
Array
.
isArray
(
newVal
))
{
this
.
filters
.
inbound
.
startDate
=
normalizeVisitTimeValue
(
newVal
[
0
])
this
.
filters
.
inbound
.
endDate
=
normalizeVisitTimeValue
(
newVal
[
1
])
}
else
{
this
.
filters
.
inbound
.
startDate
=
null
this
.
filters
.
inbound
.
endDate
=
null
}
}
},
created
()
{
this
.
fetchList
(
'inbound'
)
},
methods
:
{
// 获取当天日期,格式为 yyyy-MM-dd
getTodayDate
()
{
const
today
=
new
Date
()
const
year
=
today
.
getFullYear
()
const
month
=
String
(
today
.
getMonth
()
+
1
).
padStart
(
2
,
'0'
)
const
day
=
String
(
today
.
getDate
()).
padStart
(
2
,
'0'
)
return
`
${
year
}
-
${
month
}
-
${
day
}
`
},
handleTabChange
(
name
)
{
this
.
activeTab
=
name
if
(
name
===
'return'
)
this
.
fetchList
(
'return'
)
...
...
@@ -270,14 +464,17 @@ export default {
}
else
this
.
$Notice
.
error
({
title
:
'查询失败'
,
desc
:
ret
.
data
&&
ret
.
data
.
errmsg
})
}).
finally
(()
=>
{
this
.
loading
[
tab
]
=
false
})
},
handleSearch
(
tab
)
{
(
this
.
pagers
[
tab
]
||
{}).
pageNo
=
1
;
this
.
fetchList
(
tab
)
},
handleReset
(
tab
)
{
this
.
filters
[
tab
]
=
{};
(
this
.
pagers
[
tab
]
||
{}).
pageNo
=
1
;
this
.
fetchList
(
tab
)
},
handleSearch
(
tab
)
{
(
this
.
pagers
[
tab
]
||
{}).
pageNo
=
1
this
.
fetchList
(
tab
)
},
handleReset
(
tab
)
{
this
.
inboundDateRange
=
null
;
this
.
filters
[
tab
]
=
{};
(
this
.
pagers
[
tab
]
||
{}).
pageNo
=
1
;
this
.
fetchList
(
tab
)
},
pageChange
(
tab
,
pageNo
)
{
(
this
.
pagers
[
tab
]
||
{}).
pageNo
=
pageNo
;
this
.
fetchList
(
tab
)
},
sizeChange
(
tab
,
size
)
{
(
this
.
pagers
[
tab
]
||
{}).
pageSize
=
size
;
(
this
.
pagers
[
tab
]
||
{}).
pageNo
=
1
;
this
.
fetchList
(
tab
)
},
openInboundModal
()
{
this
.
inboundModal
.
isEdit
=
false
this
.
inboundModal
.
form
=
{
inbound_no
:
''
,
batch_no
:
''
,
inbound_date
:
''
,
inbound_type
:
1
,
storage_location
:
''
,
remark
:
''
}
this
.
inboundModal
.
form
=
{
inbound_no
:
''
,
batch_no
:
''
,
inbound_date
:
this
.
getTodayDate
()
,
inbound_type
:
1
,
storage_location
:
''
,
remark
:
''
}
this
.
inboundModal
.
details
=
[]
this
.
inboundModal
.
visible
=
true
},
...
...
@@ -285,6 +482,7 @@ export default {
this
.
inboundSelectedDetails
=
list
||
[]
},
handleInboundMaterialSelectorOk
(
selectedRows
)
{
console
.
log
(
'选择的物料信息'
+
selectedRows
)
if
(
!
Array
.
isArray
(
selectedRows
)
||
selectedRows
.
length
===
0
)
{
this
.
$Message
.
warning
(
'未选择物料'
)
return
...
...
@@ -296,6 +494,7 @@ export default {
exist
.
inbound_quantity
=
Number
(
exist
.
inbound_quantity
||
0
)
+
1
}
else
{
this
.
inboundModal
.
details
.
push
({
material_id
:
sel
.
id
,
material_code
:
sel
.
material_code
,
material_name
:
sel
.
material_name
,
inbound_quantity
:
0
,
...
...
@@ -306,6 +505,32 @@ export default {
})
this
.
showMaterialSelector
=
false
},
// 转换时间戳为yyyy-MM-dd
formatDate
(
timestamp
)
{
if
(
!
timestamp
||
isNaN
(
Number
(
timestamp
)))
return
''
const
d
=
new
Date
(
Number
(
timestamp
))
return
`
${
d
.
getFullYear
()}
-
${
String
(
d
.
getMonth
()
+
1
).
padStart
(
2
,
'0'
)}
-
${
String
(
d
.
getDate
()).
padStart
(
2
,
'0'
)}
`
},
// 转换时间戳为yyyy-MM-dd hh-mm-ss
formatDateTime
(
timestamp
)
{
// 空值/非数字处理:返回空字符串
if
(
!
timestamp
||
isNaN
(
Number
(
timestamp
)))
return
''
const
d
=
new
Date
(
Number
(
timestamp
))
// 年
const
year
=
d
.
getFullYear
()
// 月(补0)
const
month
=
String
(
d
.
getMonth
()
+
1
).
padStart
(
2
,
'0'
)
// 日(补0)
const
day
=
String
(
d
.
getDate
()).
padStart
(
2
,
'0'
)
// 时(24小时制,补0)
const
hour
=
String
(
d
.
getHours
()).
padStart
(
2
,
'0'
)
// 分(补0)
const
minute
=
String
(
d
.
getMinutes
()).
padStart
(
2
,
'0'
)
// 秒(补0)
const
second
=
String
(
d
.
getSeconds
()).
padStart
(
2
,
'0'
)
// 拼接为 yyyy-MM-dd HH:mm:ss
return
`
${
year
}
-
${
month
}
-
${
day
}
${
hour
}
:
${
minute
}
:
${
second
}
`
},
deleteSelectedInboundDetails
()
{
if
(
!
this
.
inboundSelectedDetails
||
this
.
inboundSelectedDetails
.
length
===
0
)
{
this
.
$Message
.
warning
(
'请先选择要删除的明细行'
)
...
...
@@ -320,25 +545,87 @@ export default {
getInboundById
({
id
:
row
.
id
}).
then
(
ret
=>
{
if
(
ret
.
data
&&
ret
.
data
.
errcode
===
0
)
{
this
.
inboundModal
.
form
=
ret
.
data
.
data
||
{}
if
(
this
.
inboundModal
.
form
.
inbound_date
)
{
this
.
inboundModal
.
form
.
inbound_date
=
this
.
formatDate
(
this
.
inboundModal
.
form
.
inbound_date
)
||
''
}
else
{
this
.
inboundModal
.
form
.
inbound_date
=
this
.
getTodayDate
()
}
this
.
inboundModal
.
details
=
ret
.
data
.
data
.
details
||
[]
}
})
this
.
inboundModal
.
visible
=
true
},
saveInbound
()
{
// 1. 验证明细数据
this
.
inboundModal
.
saving
=
true
saveInbound
(
Object
.
assign
({},
this
.
inboundModal
.
form
,
{
details
:
this
.
inboundModal
.
details
})).
then
(
ret
=>
{
if
(
ret
.
data
&&
ret
.
data
.
errcode
===
0
)
{
this
.
$Message
.
success
(
'保存成功'
);
this
.
inboundModal
.
visible
=
false
;
this
.
fetchList
(
'inbound'
)
}
else
this
.
$Notice
.
error
({
title
:
'保存失败'
,
desc
:
ret
.
data
&&
ret
.
data
.
errmsg
})
}).
finally
(()
=>
{
this
.
inboundModal
.
saving
=
false
})
// 1. 验证主表必填项
const
{
inbound_no
,
batch_no
,
inbound_date
}
=
this
.
inboundModal
.
form
if
(
!
inbound_no
||
!
batch_no
||
!
inbound_date
)
{
this
.
$Message
.
warning
(
'入库单号、批次号、入库日期为必填项'
)
this
.
inboundModal
.
saving
=
false
return
}
// 2. 验证明细数据
const
invalidDetails
=
this
.
inboundModal
.
details
.
filter
(
detail
=>
{
return
!
detail
.
inbound_quantity
||
detail
.
inbound_quantity
<=
0
})
if
(
invalidDetails
.
length
>
0
)
{
this
.
$Message
.
warning
(
'请填写有效的入库数量(必须大于0)'
)
this
.
inboundModal
.
saving
=
false
return
}
// 2. 转换数据类型
const
details
=
this
.
inboundModal
.
details
.
map
(
detail
=>
{
return
{
material_id
:
detail
.
material_id
,
material_code
:
detail
.
material_code
,
material_name
:
detail
.
material_name
,
inbound_quantity
:
Number
(
detail
.
inbound_quantity
)
||
0
,
unit_price
:
Number
(
detail
.
unit_price
)
||
0
,
total_amount
:
Number
(
detail
.
total_amount
)
||
0
}
})
// 3. 发送请求
const
payload
=
{
...
this
.
inboundModal
.
form
,
details
:
details
}
console
.
log
(
'发送的数据:'
,
payload
)
// 添加日志,查看发送的数据
saveInbound
(
payload
).
then
(
ret
=>
{
if
(
ret
.
data
&&
ret
.
data
.
errcode
===
0
)
{
this
.
$Message
.
success
(
'保存成功'
)
this
.
inboundModal
.
visible
=
false
this
.
fetchList
(
'inbound'
)
}
else
{
this
.
$Notice
.
error
({
title
:
'保存失败'
,
desc
:
ret
.
data
&
ret
.
data
.
errmsg
||
'未知错误'
})
}
}).
catch
(
error
=>
{
console
.
error
(
'保存出错:'
,
error
)
this
.
$Notice
.
error
({
title
:
'保存出错'
,
desc
:
error
.
message
})
}).
finally
(()
=>
{
this
.
inboundModal
.
saving
=
false
})
},
canEdit
(
row
)
{
return
row
.
inbound_status
===
0
},
deleteInbound
(
row
)
{
deleteInbound
({
id
:
row
.
id
}).
then
(
ret
=>
{
if
(
ret
.
data
&&
ret
.
data
.
errcode
===
0
)
{
this
.
$Message
.
success
(
'删除成功'
);
this
.
fetchList
(
'inbound'
)
}
else
this
.
$Notice
.
error
({
title
:
'删除失败'
,
desc
:
ret
.
data
&&
ret
.
data
.
errmsg
})
})
},
doInbound
(
row
)
{
doInbound
({
id
:
row
.
id
}).
then
(
ret
=>
{
if
(
ret
.
data
&&
ret
.
data
.
errcode
===
0
)
{
this
.
$Message
.
success
(
'入库成功'
);
this
.
fetchList
(
'inbound'
);
this
.
fetchList
(
'inventory'
)
}
else
this
.
$Notice
.
error
({
title
:
'入库失败'
,
desc
:
ret
.
data
&&
ret
.
data
.
errmsg
})
})
},
doInbound
(
row
)
{
doInbound
({
id
:
row
.
id
}).
then
(
ret
=>
{
if
(
ret
.
data
&&
ret
.
data
.
errcode
===
0
)
{
this
.
$Message
.
success
(
'入库成功'
)
this
.
fetchList
(
'inbound'
)
this
.
fetchList
(
'inventory'
)
}
else
{
this
.
$Notice
.
error
({
title
:
'入库失败'
,
desc
:
ret
.
data
&&
ret
.
data
.
errmsg
})
}
})
},
openReturnModal
(
row
)
{
this
.
returnModal
.
record
=
Object
.
assign
({},
row
)
this
.
returnModal
.
details
=
[]
get
Inbound
ById
({
id
:
row
.
id
}).
then
(
ret
=>
{
get
PendingReturn
ById
({
id
:
row
.
id
}).
then
(
ret
=>
{
if
(
ret
.
data
&&
ret
.
data
.
errcode
===
0
)
this
.
returnModal
.
details
=
ret
.
data
.
data
.
details
||
[]
})
this
.
returnModal
.
visible
=
true
...
...
@@ -355,6 +642,7 @@ export default {
this
.
detailModal
.
loading
=
true
getInboundById
({
id
:
row
.
id
}).
then
(
ret
=>
{
if
(
ret
.
data
&&
ret
.
data
.
errcode
===
0
)
{
console
.
log
(
ret
.
data
)
this
.
detailModal
.
data
=
ret
.
data
.
data
||
{}
this
.
detailModal
.
details
=
ret
.
data
.
data
.
details
||
[]
this
.
detailModal
.
logs
=
ret
.
data
.
data
.
logs
||
[]
...
...
@@ -372,4 +660,67 @@ export default {
.text-right
{
text-align
:
right
;
}
.page_style
{
margin-top
:
12px
;
text-align
:
right
;
}
.mt8
{
margin-top
:
8px
;
}
/* 搜索区域外层盒:统一间距+背景 */
.search-container
{
padding
:
16px
;
background
:
#fff
;
border-radius
:
4px
;
margin-bottom
:
16px
;
}
/* 行容器:垂直居中+间距 */
.search-row
{
margin
:
0
!important
;
}
/* 内联表单:消除默认间距 */
.form-inline
{
display
:
flex
;
align-items
:
center
;
flex-wrap
:
wrap
;
margin
:
0
;
}
/* 表单项:统一间距+对齐 */
.form-item
{
margin
:
0
8px
0
0
!important
;
display
:
flex
;
align-items
:
center
;
}
/* 输入框/下拉框:统一宽度 */
.form-input
{
width
:
180px
!important
;
}
/* 按钮组:单独样式 */
.form-item-actions
{
margin-left
:
16px
!important
;
}
/* 右侧操作列:居右+内边距 */
.action-col
{
text-align
:
right
;
padding-right
:
16px
;
}
/* 响应式适配:小屏幕自动换行 */
@media
(
max-width
:
768px
)
{
.form-inline
{
flex-direction
:
column
;
align-items
:
flex-start
;
}
.form-item
{
margin
:
8px
0
!important
;
width
:
100%
;
}
.form-input
{
width
:
100%
!important
;
}
.action-col
{
text-align
:
left
;
padding
:
16px
0
0
0
;
}
}
</
style
>
src/view/key-person/key_dm_inventory/index.vue
View file @
30a96ce8
...
...
@@ -4,12 +4,44 @@
<TabPane
label=
"办公用品申领"
name=
"apply"
>
<div
class=
"search-div"
>
<Row
type=
"flex"
:gutter=
"16"
>
<Col
span=
"10"
>
<Input
v-model=
"filters.apply.applicant_name"
placeholder=
"姓名/工号"
style=
"width:60%"
/>
<Button
type=
"primary"
class=
"mr10"
@
click=
"handleSearch('apply')"
>
搜索
</Button>
<Button
@
click=
"handleReset('apply')"
>
重置
</Button>
<Col
span=
"20"
>
<div
class=
"search-form"
>
<Form
:inline=
"true"
:model=
"filters.apply"
class=
"form-inline"
>
<FormItem
label=
"申请单号:"
class=
"form-item"
>
<Input
v-model=
"filters.apply.application_no"
placeholder=
"请输入申请单号"
class=
"form-input"
/>
</FormItem>
<FormItem
label=
"申请人:"
class=
"form-item"
>
<Input
v-model=
"filters.apply.applicant_name"
placeholder=
"请输入申请人"
class=
"form-input"
/>
</FormItem>
<FormItem
label=
"审批状态:"
class=
"form-item"
>
<Select
v-model=
"filters.apply.approval_status"
placeholder=
"请选择审批状态"
class=
"form-input"
>
<Option
:value=
'0'
>
待提交
</Option>
<Option
:value=
'1'
>
审核中
</Option>
<Option
:value=
'9'
>
审核通过
</Option>
<Option
:value=
'-1'
>
驳回
</Option>
</Select>
</FormItem>
<FormItem
class=
"form-item-actions"
>
<Button
type=
"primary"
@
click=
"handleSearch('apply')"
>
搜索
</Button>
<Button
@
click=
"handleReset('apply')"
style=
"margin-left: 8px;"
>
重置
</Button>
</FormItem>
</Form>
</div>
</Col>
<Col
span=
"14"
class=
"text-right"
>
<!-- 右侧操作按钮区:固定居右 -->
<Col
span=
"4"
class=
"action-col"
>
<Button
type=
"success"
@
click=
"openApplyModal"
>
申请
</Button>
</Col>
</Row>
...
...
@@ -40,6 +72,47 @@
</TabPane>
<TabPane
label=
"办公用品审核历史查询"
name=
"history"
>
<div
class=
"search-div"
>
<Row
type=
"flex"
:gutter=
"16"
>
<Col
span=
"24"
>
<div
class=
"search-form"
>
<Form
:inline=
"true"
:model=
"filters.history"
class=
"form-inline"
>
<FormItem
label=
"申请单号:"
class=
"form-item"
>
<Input
v-model=
"filters.history.application_no"
placeholder=
"请输入申请单号"
class=
"form-input"
/>
</FormItem>
<FormItem
label=
"申请人:"
class=
"form-item"
>
<Input
v-model=
"filters.history.applicant_name"
placeholder=
"请输入申请人"
class=
"form-input"
/>
</FormItem>
<FormItem
label=
"审批状态:"
class=
"form-item"
>
<Select
v-model=
"filters.history.approval_status"
placeholder=
"请选择审批状态"
class=
"form-input"
>
<Option
:value=
"0"
>
待提交
</Option>
<Option
:value=
"1"
>
审核中
</Option>
<Option
:value=
"9"
>
审核通过
</Option>
<Option
:value=
"-1"
>
驳回
</Option>
</Select>
</FormItem>
<FormItem
class=
"form-item-actions"
>
<Button
type=
"primary"
@
click=
"handleSearch('history')"
>
搜索
</Button>
<Button
@
click=
"handleReset('history')"
style=
"margin-left: 8px;"
>
重置
</Button>
</FormItem>
</Form>
</div>
</Col>
</Row>
</div>
<Table
:data=
"tables.history"
:loading=
"loading.history"
:columns=
"historyColumns"
border
>
<
template
slot=
"action"
slot-scope=
"{ row }"
>
<Button
size=
"small"
@
click=
"openDetail(row)"
>
详细
</Button>
...
...
@@ -63,7 +136,13 @@
<Input
v-model=
"applyModal.form.borrow_purpose"
/>
</FormItem>
<FormItem
label=
"预计归还日期"
>
<DatePicker
v-model=
"applyModal.form.expected_return_date"
type=
"date"
/>
<DatePicker
v-model=
"applyModal.form.expected_return_date"
type=
"date"
format=
"yyyy-MM-dd"
value-format=
"yyyy-MM-dd"
placeholder=
"请选择预计归还日期"
/>
</FormItem>
<h4>
申请明细
</h4>
...
...
@@ -107,6 +186,7 @@
<div
v-else
>
<Row
:gutter=
"16"
><Col
span=
"12"
><p><strong>
申请人:
</strong>
{{ detailModal.data.applicant_name }}
</p></Col><Col
span=
"12"
><p><strong>
部门:
</strong>
{{ detailModal.data.department_name }}
</p></Col></Row>
<Row
class=
"mt8"
><Col
span=
"24"
><p><strong>
领用用途:
</strong>
{{ detailModal.data.borrow_purpose }}
</p></Col></Row>
<Row
class=
"mt8"
><Col
span=
"24"
><p><strong>
预计归还日期:
</strong>
{{ formatDate(detailModal.data.expected_return_date) }}
</p></Col></Row>
<Row
class=
"mt8"
><Col
span=
"24"
><h4>
明细
</h4></Col></Row>
<Table
:data=
"detailModal.details"
:columns=
"detailDetailColumns"
size=
"small"
border
/>
<Row
class=
"mt8"
><Col
span=
"24"
><h4>
审批记录
</h4></Col></Row>
...
...
@@ -135,8 +215,17 @@ export default {
components
:
{
MaterialSelector
},
data
()
{
return
{
// 申请弹窗中的可编辑行状态
editingRowIndex
:
-
1
,
editingCellField
:
''
,
// 审批状态映射字典
approvalStatusMap
:
{
'0'
:
'待提交'
,
'1'
:
'审核中'
,
'9'
:
'审核通过'
,
'-1'
:
'驳回'
},
opTypeMap
:
{
'1'
:
'入库'
,
'2'
:
'出库'
},
activeTab
:
'apply'
,
filters
:
{
apply
:
{
applicant_name
:
''
}
},
filters
:
{
apply
:
{
application_no
:
''
,
applicant_name
:
''
,
approval_status
:
null
},
history
:
{
application_no
:
''
,
applicant_name
:
''
,
approval_status
:
null
}
},
tables
:
{
apply
:
[],
pending
:
[],
history
:
[]
},
pagers
:
{
apply
:
{
pageNo
:
1
,
pageSize
:
10
,
totalRecord
:
0
},
pending
:
{
pageNo
:
1
,
pageSize
:
10
,
totalRecord
:
0
},
history
:
{
pageNo
:
1
,
pageSize
:
10
,
totalRecord
:
0
}
},
loading
:
{
apply
:
false
,
pending
:
false
,
history
:
false
},
...
...
@@ -145,10 +234,41 @@ export default {
{
title
:
'申请单号'
,
key
:
'application_no'
,
align
:
'center'
},
{
title
:
'申请人'
,
key
:
'applicant_name'
,
align
:
'center'
},
{
title
:
'部门'
,
key
:
'department_name'
,
align
:
'center'
},
{
title
:
'请假类型'
,
key
:
'borrow_purpose'
,
align
:
'center'
},
{
title
:
'起止时间'
,
key
:
'start_time'
,
align
:
'center'
},
{
title
:
'时长'
,
key
:
'duration'
,
align
:
'center'
},
{
title
:
'状态'
,
key
:
'approval_status'
,
align
:
'center'
},
{
title
:
'审评用途'
,
key
:
'borrow_purpose'
,
align
:
'center'
},
{
title
:
'起止时间'
,
key
:
'start_time'
,
align
:
'center'
,
width
:
'300px'
,
render
:
(
h
,
{
row
})
=>
{
return
h
(
'span'
,
(
this
.
formatDateTime
(
row
.
create_time
)
||
row
.
create_time
||
'-'
)
+
'--'
+
(
this
.
formatDateTime
(
row
.
approval_time
)
||
row
.
approval_time
||
'-'
))
}
},
{
title
:
'时长'
,
key
:
'duration'
,
align
:
'center'
,
render
:
(
h
,
{
row
})
=>
{
const
createTime
=
Number
(
row
.
create_time
)
||
0
const
approvalTime
=
Number
(
row
.
approval_time
)
||
0
let
duration
=
null
if
(
createTime
!==
0
&&
approvalTime
!==
0
)
{
const
diffMs
=
Math
.
abs
(
approvalTime
-
createTime
)
duration
=
this
.
formatDuration
(
diffMs
)
}
else
{
duration
=
this
.
formatDuration
(
''
)
}
return
h
(
'span'
,
duration
)
}
},
{
title
:
'状态'
,
key
:
'approval_status'
,
align
:
'center'
,
render
:
(
h
,
{
row
})
=>
{
return
h
(
'span'
,
this
.
approvalStatusMap
[
row
.
approval_status
+
''
]
||
row
.
approval_status
||
'-'
)
}
},
{
title
:
'操作'
,
slot
:
'action'
,
align
:
'center'
,
width
:
320
}
],
pendingColumns
:
[
...
...
@@ -156,15 +276,36 @@ export default {
{
title
:
'申请单号'
,
key
:
'application_no'
,
align
:
'center'
},
{
title
:
'申请人'
,
key
:
'applicant_name'
,
align
:
'center'
},
{
title
:
'部门'
,
key
:
'department_name'
,
align
:
'center'
},
{
title
:
'提交时间'
,
key
:
'submit_time'
,
align
:
'center'
},
{
title
:
'提交时间'
,
key
:
'submit_time'
,
align
:
'center'
,
render
:
(
h
,
{
row
})
=>
{
return
h
(
'span'
,
this
.
formatDate
(
row
.
submit_time
)
||
row
.
submit_time
||
'-'
)
}
},
{
title
:
'操作'
,
slot
:
'action'
,
width
:
120
,
align
:
'center'
}
],
historyColumns
:
[
{
type
:
'index'
,
title
:
'序号'
,
width
:
60
,
align
:
'center'
},
{
title
:
'申请单号'
,
key
:
'application_no'
,
align
:
'center'
},
{
title
:
'申请人'
,
key
:
'applicant_name'
,
align
:
'center'
},
{
title
:
'状态'
,
key
:
'approval_status'
,
align
:
'center'
},
{
title
:
'审批完成时间'
,
key
:
'approval_complete_time'
,
align
:
'center'
},
{
title
:
'状态'
,
key
:
'approval_status'
,
align
:
'center'
,
render
:
(
h
,
{
row
})
=>
{
return
h
(
'span'
,
this
.
approvalStatusMap
[
row
.
approval_status
+
''
]
||
row
.
approval_status
||
'-'
)
}
},
{
title
:
'审批完成时间'
,
key
:
'approval_time'
,
align
:
'center'
,
render
:
(
h
,
{
row
})
=>
{
return
h
(
'span'
,
this
.
formatDateTime
(
row
.
approval_time
)
||
row
.
approval_time
||
'-'
)
}
},
{
title
:
'操作'
,
slot
:
'action'
,
width
:
100
,
align
:
'center'
}
],
// 模态窗口内表格列定义
...
...
@@ -172,7 +313,77 @@ export default {
{
type
:
'selection'
,
width
:
60
},
{
title
:
'物料编码'
,
key
:
'material_code'
},
{
title
:
'物料名称'
,
key
:
'material_name'
},
{
title
:
'申请数量'
,
key
:
'apply_quantity'
},
{
title
:
'申请数量'
,
key
:
'apply_quantity'
,
render
:
(
h
,
{
row
,
column
,
index
})
=>
{
// 如果当前行是编辑状态,显示输入框
if
(
this
.
editingRowIndex
===
index
&&
this
.
editingCellField
===
'apply_quantity'
)
{
return
h
(
'InputNumber'
,
{
props
:
{
value
:
row
.
apply_quantity
,
min
:
1
,
max
:
row
.
available_quantity
||
9999
,
precision
:
0
},
style
:
{
width
:
'100%'
},
on
:
{
input
:
(
value
)
=>
{
// 更新数据
this
.
applyModal
.
details
[
index
].
apply_quantity
=
value
},
'on-blur'
:
()
=>
{
// 失去焦点时退出编辑模式
this
.
editingRowIndex
=
-
1
this
.
editingCellField
=
''
},
'on-keyup'
:
(
event
)
=>
{
// 按回车键保存并退出编辑
if
(
event
.
keyCode
===
13
)
{
this
.
editingRowIndex
=
-
1
this
.
editingCellField
=
''
}
}
}
})
}
else
{
// 非编辑状态,显示文本和编辑图标
return
h
(
'div'
,
{
style
:
{
display
:
'flex'
,
justifyContent
:
'space-between'
,
alignItems
:
'center'
,
cursor
:
'pointer'
,
padding
:
'0 8px'
},
on
:
{
click
:
()
=>
{
// 点击进入编辑模式
this
.
editingRowIndex
=
index
this
.
editingCellField
=
'apply_quantity'
// 下一个tick聚焦到输入框
this
.
$nextTick
(()
=>
{
const
input
=
document
.
querySelector
(
`.ivu-table-cell-with-input input`
)
if
(
input
)
input
.
focus
()
})
}
}
},
[
h
(
'span'
,
row
.
apply_quantity
||
0
),
h
(
'Icon'
,
{
props
:
{
type
:
'md-create'
,
size
:
14
},
style
:
{
color
:
'#2d8cf0'
,
marginLeft
:
'8px'
}
})
])
}
}
},
{
title
:
'单位'
,
key
:
'unit'
},
{
title
:
'备注'
,
key
:
'issue_remark'
}
],
...
...
@@ -190,21 +401,108 @@ export default {
{
title
:
'已归还'
,
key
:
'returned_quantity'
}
],
detailLogsColumns
:
[
{
title
:
'操作类型'
,
key
:
'op_type'
},
{
title
:
'物料名称'
,
key
:
'material_name'
},
{
title
:
'操作类型'
,
key
:
'op_type'
,
render
:
(
h
,
{
row
})
=>
{
return
h
(
'span'
,
this
.
opTypeMap
[
row
.
op_type
]
||
row
.
op_type
||
'-'
)
}
},
{
title
:
'数量'
,
key
:
'quantity'
},
{
title
:
'时间'
,
key
:
'create_time'
},
{
title
:
'时间'
,
key
:
'create_time'
,
width
:
'150px'
,
render
:
(
h
,
{
row
})
=>
{
return
h
(
'span'
,
this
.
formatDateTime
(
row
.
create_time
)
||
row
.
create_time
||
'-'
)
}
},
{
title
:
'操作人'
,
key
:
'create_by'
}
],
// 选择器控制与已选明细
showMaterialSelector
:
false
,
applySelectedDetails
:
[],
applyModal
:
{
visible
:
false
,
isEdit
:
false
,
saving
:
false
,
form
:
{},
details
:
[]
},
applyModal
:
{
visible
:
false
,
isEdit
:
false
,
saving
:
false
,
form
:
{},
details
:
[]
,
isEditing
:
false
},
approveModal
:
{
visible
:
false
,
record
:
{},
details
:
[],
opinion
:
''
,
submitting
:
false
},
detailModal
:
{
visible
:
false
,
loading
:
false
,
data
:
{},
details
:
[],
logs
:
[]
}
}
},
created
()
{
this
.
fetchList
(
'apply'
)
},
methods
:
{
// 获取当天日期,格式为 yyyy-MM-dd
getTodayDate
()
{
const
today
=
new
Date
()
const
year
=
today
.
getFullYear
()
const
month
=
String
(
today
.
getMonth
()
+
1
).
padStart
(
2
,
'0'
)
const
day
=
String
(
today
.
getDate
()).
padStart
(
2
,
'0'
)
return
`
${
year
}
-
${
month
}
-
${
day
}
`
},
// 格式化毫秒差值为易读的时长
formatDuration
(
diffMs
)
{
// 无有效差值时返回兜底值
if
(
diffMs
<=
0
)
return
'--'
// 时间单位换算(毫秒)
const
oneSecond
=
1000
const
oneMinute
=
oneSecond
*
60
const
oneHour
=
oneMinute
*
60
const
oneDay
=
oneHour
*
24
// 计算各单位的数值
const
days
=
Math
.
floor
(
diffMs
/
oneDay
)
const
hours
=
Math
.
floor
((
diffMs
%
oneDay
)
/
oneHour
)
const
minutes
=
Math
.
floor
((
diffMs
%
oneHour
)
/
oneMinute
)
const
seconds
=
Math
.
floor
((
diffMs
%
oneMinute
)
/
oneSecond
)
// 拼接时长字符串(按需显示非零单位,避免冗余)
let
duration
=
''
if
(
days
>
0
)
duration
+=
`
${
days
}
天`
if
(
hours
>
0
||
duration
)
duration
+=
`
${
hours
}
时`
if
(
minutes
>
0
||
duration
)
duration
+=
`
${
minutes
}
分`
duration
+=
`
${
seconds
}
秒`
return
duration
},
// 处理单元格点击编辑
handleCellEdit
(
row
,
column
,
index
,
field
)
{
if
(
field
===
'apply_quantity'
)
{
this
.
editingRowIndex
=
index
this
.
editingCellField
=
field
// 下一个tick聚焦到输入框
this
.
$nextTick
(()
=>
{
const
input
=
document
.
querySelector
(
`.ivu-table-cell-with-input input`
)
if
(
input
)
input
.
focus
()
})
}
},
// 添加方法:退出编辑模式
exitEditMode
()
{
this
.
editingRowIndex
=
-
1
this
.
editingCellField
=
''
},
// 转换时间戳为yyyy-MM-dd
formatDate
(
timestamp
)
{
if
(
!
timestamp
||
isNaN
(
Number
(
timestamp
)))
return
''
const
d
=
new
Date
(
Number
(
timestamp
))
return
`
${
d
.
getFullYear
()}
-
${
String
(
d
.
getMonth
()
+
1
).
padStart
(
2
,
'0'
)}
-
${
String
(
d
.
getDate
()).
padStart
(
2
,
'0'
)}
`
},
// 转换时间戳为yyyy-MM-dd hh-mm-ss
formatDateTime
(
timestamp
)
{
// 空值/非数字处理:返回空字符串
if
(
!
timestamp
||
isNaN
(
Number
(
timestamp
)))
return
''
const
d
=
new
Date
(
Number
(
timestamp
))
// 年
const
year
=
d
.
getFullYear
()
// 月(补0)
const
month
=
String
(
d
.
getMonth
()
+
1
).
padStart
(
2
,
'0'
)
// 日(补0)
const
day
=
String
(
d
.
getDate
()).
padStart
(
2
,
'0'
)
// 时(24小时制,补0)
const
hour
=
String
(
d
.
getHours
()).
padStart
(
2
,
'0'
)
// 分(补0)
const
minute
=
String
(
d
.
getMinutes
()).
padStart
(
2
,
'0'
)
// 秒(补0)
const
second
=
String
(
d
.
getSeconds
()).
padStart
(
2
,
'0'
)
// 拼接为 yyyy-MM-dd HH:mm:ss
return
`
${
year
}
-
${
month
}
-
${
day
}
${
hour
}
:
${
minute
}
:
${
second
}
`
},
handleTabChange
(
name
)
{
this
.
activeTab
=
name
if
(
name
===
'pending'
)
this
.
fetchList
(
'pending'
)
...
...
@@ -214,7 +512,19 @@ export default {
const
apiMap
=
{
apply
:
getBorrowList
,
pending
:
getPendingBorrowList
,
history
:
getBorrowList
}
const
api
=
apiMap
[
tab
];
if
(
!
api
)
return
this
.
loading
[
tab
]
=
true
const
payload
=
Object
.
assign
({},
this
.
pagers
[
tab
]
||
{},
{
params
:
this
.
filters
[
tab
]
||
{}
})
// 清理空值,防止参数传递问题
const
cleanParams
=
(
obj
)
=>
{
const
cleaned
=
{}
for
(
let
key
in
obj
)
{
const
value
=
obj
[
key
]
if
(
value
!==
null
&&
value
!==
undefined
&&
value
!==
''
)
{
cleaned
[
key
]
=
value
}
}
return
cleaned
}
const
payload
=
Object
.
assign
({},
this
.
pagers
[
tab
]
||
{},
{
params
:
cleanParams
(
this
.
filters
[
tab
]
||
{})
})
console
.
log
(
payload
)
api
(
payload
).
then
(
ret
=>
{
if
(
ret
.
data
&&
ret
.
data
.
errcode
===
0
)
{
const
data
=
ret
.
data
.
data
||
{}
...
...
@@ -223,20 +533,32 @@ export default {
}
else
this
.
$Notice
.
error
({
title
:
'查询失败'
,
desc
:
ret
.
data
&&
ret
.
data
.
errmsg
})
}).
finally
(()
=>
{
this
.
loading
[
tab
]
=
false
})
},
handleSearch
(
tab
)
{
(
this
.
pagers
[
tab
]
||
{}).
pageNo
=
1
;
this
.
fetchList
(
tab
)
},
handleSearch
(
tab
)
{
(
this
.
pagers
[
tab
]
||
{}).
pageNo
=
1
this
.
fetchList
(
tab
)
},
handleReset
(
tab
)
{
this
.
filters
[
tab
]
=
{};
(
this
.
pagers
[
tab
]
||
{}).
pageNo
=
1
;
this
.
fetchList
(
tab
)
},
pageChange
(
tab
,
pageNo
)
{
(
this
.
pagers
[
tab
]
||
{}).
pageNo
=
pageNo
;
this
.
fetchList
(
tab
)
},
sizeChange
(
tab
,
size
)
{
(
this
.
pagers
[
tab
]
||
{}).
pageSize
=
size
;
(
this
.
pagers
[
tab
]
||
{}).
pageNo
=
1
;
this
.
fetchList
(
tab
)
},
openApplyModal
()
{
this
.
applyModal
.
isEdit
=
false
this
.
applyModal
.
form
=
{
applicant_id
:
''
,
applicant_name
:
''
,
department_id
:
''
,
department_name
:
''
,
borrow_purpose
:
''
,
expected_return_date
:
''
,
approval_status
:
0
}
this
.
applyModal
.
form
=
{
applicant_id
:
''
,
applicant_name
:
''
,
department_id
:
''
,
department_name
:
''
,
borrow_purpose
:
''
,
expected_return_date
:
this
.
getTodayDate
()
,
approval_status
:
0
}
this
.
applyModal
.
details
=
[]
this
.
applyModal
.
visible
=
true
this
.
exitEditMode
()
},
openEdit
(
row
)
{
console
.
log
(
row
)
this
.
applyModal
.
isEdit
=
true
this
.
applyModal
.
form
=
Object
.
assign
({},
row
)
// 关键:时间戳转 yyyy-MM-dd 字符串
if
(
this
.
applyModal
.
form
.
expected_return_date
)
{
this
.
applyModal
.
form
.
expected_return_date
=
this
.
formatDate
(
this
.
applyModal
.
form
.
expected_return_date
)
}
else
{
// 空值兜底
this
.
applyModal
.
form
.
expected_return_date
=
this
.
getTodayDate
()
}
// load details from backend when open (simplified)
getBorrowById
({
id
:
row
.
id
}).
then
(
ret
=>
{
if
(
ret
.
data
&&
ret
.
data
.
errcode
===
0
)
{
...
...
@@ -244,6 +566,7 @@ export default {
}
})
this
.
applyModal
.
visible
=
true
this
.
exitEditMode
()
},
onApplyDetailSelectionChange
(
list
)
{
this
.
applySelectedDetails
=
list
||
[]
...
...
@@ -260,6 +583,7 @@ export default {
exist
.
apply_quantity
=
Number
(
exist
.
apply_quantity
||
0
)
+
1
}
else
{
this
.
applyModal
.
details
.
push
({
material_id
:
sel
.
id
,
material_code
:
sel
.
material_code
,
material_name
:
sel
.
material_name
,
apply_quantity
:
1
,
...
...
@@ -281,6 +605,7 @@ export default {
this
.
applySelectedDetails
=
[]
},
saveApplication
()
{
this
.
exitEditMode
()
this
.
applyModal
.
saving
=
true
const
payload
=
Object
.
assign
({},
this
.
applyModal
.
form
,
{
details
:
this
.
applyModal
.
details
})
saveBorrowApplication
(
payload
).
then
(
ret
=>
{
...
...
@@ -346,4 +671,79 @@ export default {
.text-right
{
text-align
:
right
;
}
.page_style
{
margin-top
:
12px
;
text-align
:
right
;
}
.mt8
{
margin-top
:
8px
;
}
/* 搜索区域外层盒:统一间距+背景 */
.search-container
{
padding
:
16px
;
background
:
#fff
;
border-radius
:
4px
;
margin-bottom
:
16px
;
}
/* 行容器:垂直居中+间距 */
.search-row
{
margin
:
0
!important
;
}
/* 内联表单:消除默认间距 */
.form-inline
{
display
:
flex
;
align-items
:
center
;
flex-wrap
:
wrap
;
margin
:
0
;
}
/* 表单项:统一间距+对齐 */
.form-item
{
margin
:
0
8px
0
0
!important
;
display
:
flex
;
align-items
:
center
;
}
/* 输入框/下拉框:统一宽度 */
.form-input
{
width
:
180px
!important
;
}
/* 按钮组:单独样式 */
.form-item-actions
{
margin-left
:
16px
!important
;
}
/* 右侧操作列:居右+内边距 */
.action-col
{
text-align
:
right
;
padding-right
:
16px
;
}
/* 响应式适配:小屏幕自动换行 */
@media
(
max-width
:
768px
)
{
.form-inline
{
flex-direction
:
column
;
align-items
:
flex-start
;
}
.form-item
{
margin
:
8px
0
!important
;
width
:
100%
;
}
.form-input
{
width
:
100%
!important
;
}
.action-col
{
text-align
:
left
;
padding
:
16px
0
0
0
;
}
}
/* 添加一些样式来美化编辑状态 */
.ivu-table-cell
{
position
:
relative
;
}
.edit-icon
{
opacity
:
0
;
transition
:
opacity
0.2s
;
}
.ivu-table-row
:hover
.edit-icon
{
opacity
:
1
;
}
</
style
>
src/view/key-person/key_dm_inventory/stats.vue
View file @
30a96ce8
...
...
@@ -152,8 +152,16 @@ export default {
const
et
=
this
.
workEnd
?
normalizeVisitTimeValue
(
this
.
workEnd
)
:
null
if
(
type
===
'leave'
)
{
this
.
detailModal
.
columns
=
[
{
title
:
'人员'
,
key
:
'user_name'
,
align
:
'center'
},
{
title
:
'开始'
,
key
:
'start_time'
,
align
:
'center'
,
render
:
(
h
,
params
)
=>
{
{
title
:
'人员'
,
key
:
'user_name'
,
align
:
'center'
},
{
title
:
'开始'
,
key
:
'start_time'
,
align
:
'center'
,
render
:
(
h
,
params
)
=>
{
const
time
=
params
.
row
.
start_time
if
(
time
)
{
const
date
=
new
Date
(
time
)
...
...
@@ -166,8 +174,13 @@ export default {
return
h
(
'span'
,
`
${
year
}
-
${
month
}
-
${
day
}
${
hours
}
:
${
minutes
}
:
${
seconds
}
`
)
}
return
h
(
'span'
,
'-'
)
}},
{
title
:
'结束'
,
key
:
'end_time'
,
align
:
'center'
,
render
:
(
h
,
params
)
=>
{
}
},
{
title
:
'结束'
,
key
:
'end_time'
,
align
:
'center'
,
render
:
(
h
,
params
)
=>
{
const
time
=
params
.
row
.
end_time
if
(
time
)
{
const
date
=
new
Date
(
time
)
...
...
@@ -180,9 +193,18 @@ export default {
return
h
(
'span'
,
`
${
year
}
-
${
month
}
-
${
day
}
${
hours
}
:
${
minutes
}
:
${
seconds
}
`
)
}
return
h
(
'span'
,
'-'
)
}},
{
title
:
'时长'
,
key
:
'duration'
,
align
:
'center'
},
{
title
:
'状态'
,
key
:
'status'
,
align
:
'center'
,
render
:
(
h
,
params
)
=>
{
}
},
{
title
:
'时长'
,
key
:
'duration'
,
align
:
'center'
},
{
title
:
'状态'
,
key
:
'status'
,
align
:
'center'
,
render
:
(
h
,
params
)
=>
{
const
status
=
params
.
row
.
status
let
statusText
=
''
switch
(
status
)
{
...
...
@@ -193,14 +215,19 @@ export default {
default
:
statusText
=
status
}
return
h
(
'span'
,
statusText
)
}}
}
}
]
getWorkloadDetails
({
user_id
:
row
.
user_id
,
start
:
st
,
end
:
et
,
type
:
'leave'
}).
then
(
ret
=>
{
if
(
ret
.
data
&&
ret
.
data
.
errcode
===
0
)
{
this
.
detailModal
.
rows
=
ret
.
data
.
data
||
[];
this
.
detailModal
.
visible
=
true
}
else
this
.
$Notice
.
error
({
title
:
'查询失败'
,
desc
:
ret
.
data
&&
ret
.
data
.
errmsg
})
})
}
else
{
this
.
detailModal
.
columns
=
[
{
title
:
'申请时间'
,
key
:
'submit_time'
,
align
:
'center'
,
render
:
(
h
,
params
)
=>
{
{
title
:
'申请时间'
,
key
:
'submit_time'
,
align
:
'center'
,
render
:
(
h
,
params
)
=>
{
const
time
=
params
.
row
.
submit_time
if
(
time
)
{
const
date
=
new
Date
(
time
)
...
...
@@ -213,11 +240,28 @@ export default {
return
h
(
'span'
,
`
${
year
}
-
${
month
}
-
${
day
}
${
hours
}
:
${
minutes
}
:
${
seconds
}
`
)
}
return
h
(
'span'
,
'-'
)
}},
{
title
:
'物料'
,
key
:
'material_name'
,
align
:
'center'
},
{
title
:
'申请数量'
,
key
:
'apply_quantity'
,
align
:
'center'
},
{
title
:
'归还数量'
,
key
:
'returned_quantity'
,
align
:
'center'
},
{
title
:
'状态'
,
key
:
'approval_status'
,
align
:
'center'
,
render
:
(
h
,
params
)
=>
{
}
},
{
title
:
'物料'
,
key
:
'material_name'
,
align
:
'center'
},
{
title
:
'申请数量'
,
key
:
'apply_quantity'
,
align
:
'center'
},
{
title
:
'归还数量'
,
key
:
'returned_quantity'
,
align
:
'center'
},
{
title
:
'状态'
,
key
:
'approval_status'
,
align
:
'center'
,
render
:
(
h
,
params
)
=>
{
const
status
=
params
.
row
.
approval_status
let
statusText
=
''
switch
(
status
)
{
...
...
@@ -228,8 +272,8 @@ export default {
default
:
statusText
=
status
}
return
h
(
'span'
,
statusText
)
}
}
}
}
]
getWorkloadDetails
({
user_id
:
row
.
user_id
,
start
:
st
,
end
:
et
,
type
:
'inventory'
}).
then
(
ret
=>
{
if
(
ret
.
data
&&
ret
.
data
.
errcode
===
0
)
{
this
.
detailModal
.
rows
=
ret
.
data
.
data
||
[];
this
.
detailModal
.
visible
=
true
}
else
this
.
$Notice
.
error
({
title
:
'查询失败'
,
desc
:
ret
.
data
&&
ret
.
data
.
errmsg
})
...
...
src/view/key-person/key_dm_leave/index.vue
View file @
30a96ce8
...
...
@@ -4,22 +4,20 @@
<TabPane
label=
"请假申请"
name=
"apply"
>
<div
class=
"search-div"
>
<Row
type=
"flex"
:gutter=
"16"
class=
"mt8"
>
<Col
span=
"
12
"
>
<Col
span=
"
20
"
>
<span>
开始:
</span>
<DatePicker
v-model=
"filters.apply.start_time"
type=
"date"
placeholder=
"开始日期"
style=
"min-width:110px;margin-right:20px"
/>
<span>
结束:
</span>
<DatePicker
v-model=
"filters.apply.end_time"
type=
"date"
placeholder=
"结束日期"
style=
"min-width:110px;margin-right:20px"
/>
</Col>
<Col
span=
"8"
>
<span>
状态:
</span>
<Select
v-model=
"filters.apply.status"
style=
"width:
60%
"
>
<Select
v-model=
"filters.apply.status"
style=
"width:
150px
"
>
<Option
v-for=
"opt in statusOptions"
:key=
"opt.id"
:value=
"opt.id"
>
{{
opt
.
name
}}
</Option>
</Select>
</Col>
<Col
span=
"4"
class=
"text-right"
>
<Button
type=
"primary"
class=
"mr10"
@
click=
"handleSearch('apply')"
>
搜索
</Button>
<Button
class=
"mr10"
@
click=
"handleReset('apply')"
>
重置
</Button>
<Button
type=
"
success
"
@
click=
"openApplyModal"
>
申请
</Button>
<Button
type=
"primary"
class=
"mr10"
@
click=
"handleReset('apply')"
>
重置
</Button>
<Button
type=
"
primary
"
@
click=
"openApplyModal"
>
申请
</Button>
</Col>
</Row>
</div>
...
...
@@ -58,21 +56,19 @@
<TabPane
label=
"审核历史查询"
name=
"history"
>
<div
class=
"search-div"
>
<Row
type=
"flex"
:gutter=
"16"
align=
"middle"
>
<Col
span=
"
12
"
>
<Col
span=
"
20
"
>
<span>
开始:
</span>
<DatePicker
v-model=
"filters.history.start_time"
type=
"date"
placeholder=
"开始日期"
style=
"min-width:110px;margin-right:20px"
/>
<span>
结束:
</span>
<DatePicker
v-model=
"filters.history.end_time"
type=
"date"
placeholder=
"结束日期"
style=
"min-width:110px;margin-right:20px"
/>
</Col>
<Col
span=
"8"
>
<span>
状态:
</span>
<Select
v-model=
"filters.history.status"
style=
"width:
60%
"
>
<Select
v-model=
"filters.history.status"
style=
"width:
150px"
class=
"mr10
"
>
<Option
v-for=
"opt in statusOptions"
:key=
"opt.id"
:value=
"opt.id"
>
{{ opt.name }}
</Option>
</Select>
</Col>
<Col
span=
"4"
class=
"text-right"
>
<Button
type=
"primary"
class=
"mr10"
@
click=
"handleSearch('history')"
>
搜索
</Button>
<Button
@
click=
"handleReset('history')"
>
重置
</Button>
<Button
type=
"primary"
@
click=
"handleReset('history')"
>
重置
</Button>
</Col>
</Row>
</div>
...
...
@@ -88,21 +84,19 @@
<TabPane
label=
"请假申请查询"
name=
"query"
>
<div
class=
"search-div"
>
<Row
type=
"flex"
:gutter=
"16"
align=
"middle"
>
<Col
span=
"
8
"
>
<Col
span=
"
16
"
>
<span>
开始:
</span>
<DatePicker
v-model=
"filters.query.start_time"
type=
"date"
placeholder=
"开始日期"
style=
"min-width:110px;margin-right:20px"
/>
<span>
结束:
</span>
<DatePicker
v-model=
"filters.query.end_time"
type=
"date"
placeholder=
"结束日期"
style=
"min-width:110px;margin-right:20px"
/>
</Col>
<Col
span=
"8"
>
<span>
状态:
</span>
<Select
v-model=
"filters.query.status"
style=
"width:
60%
"
>
<Select
v-model=
"filters.query.status"
style=
"width:
150px
"
>
<Option
v-for=
"opt in statusOptions"
:key=
"opt.id"
:value=
"opt.id"
>
{{ opt.name }}
</Option>
</Select>
</Col>
<Col
span=
"8"
class=
"text-right"
>
<Button
type=
"primary"
class=
"mr10"
@
click=
"handleSearch('query')"
>
搜索
</Button>
<Button
@
click=
"handleReset('query')"
>
重置
</Button>
<Button
type=
"primary"
@
click=
"handleReset('query')"
>
重置
</Button>
</Col>
</Row>
</div>
...
...
@@ -124,11 +118,11 @@
<span>
结束:
</span>
<DatePicker
v-model=
"statsEnd"
type=
"date"
placeholder=
"结束日期"
style=
"min-width:110px;margin-right:20px"
/>
<span>
部门:
</span>
<Input
v-model=
"statsDept"
placeholder=
"请输入部门名称"
style=
"width:
65%
"
/>
<Input
v-model=
"statsDept"
placeholder=
"请输入部门名称"
style=
"width:
200px
"
/>
</Col>
<Col
span=
"8"
class=
"text-right"
>
<Button
type=
"primary"
class=
"mr10"
@
click=
"loadStats"
>
统计
</Button>
<Button
@
click=
"resetStats"
>
重置
</Button>
<Button
type=
"primary"
@
click=
"resetStats"
>
重置
</Button>
</Col>
</Row>
</div>
...
...
@@ -425,6 +419,7 @@ export default {
if
(
name
===
'pending'
)
this
.
fetchList
(
'pending'
)
if
(
name
===
'history'
)
this
.
fetchList
(
'history'
)
if
(
name
===
'query'
)
this
.
fetchList
(
'query'
)
if
(
name
===
'stats'
)
this
.
loadStats
()
},
fetchList
(
tab
)
{
const
apiMap
=
{
apply
:
getLeaveListByUserId
,
pending
:
getPendingList
,
history
:
getApprovalHistory
,
query
:
getLeaveList
}
...
...
src/view/key-person/key_dm_user/index.vue
View file @
30a96ce8
...
...
@@ -10,11 +10,11 @@
</Col>
-->
<Col
:span=
"12"
class=
"text-left"
>
<span>
姓名:
</span>
<Input
v-model=
"filters.name"
placeholder=
"请输入姓名"
style=
"width:
40%
"
/>
<Input
v-model=
"filters.name"
placeholder=
"请输入姓名"
style=
"width:
200px
"
/>
</Col>
<Col
:span=
"12"
class=
"text-right"
>
<Button
type=
"primary"
class=
"mr10"
@
click=
"handleSearch"
>
搜索
</Button>
<Button
@
click=
"handleReset"
class=
"mr10"
>
重置
</Button>
<Button
type=
"primary"
@
click=
"handleReset"
class=
"mr10"
>
重置
</Button>
<Button
type=
"primary"
class=
"mr10"
@
click=
"handleSync"
>
同步
</Button>
</Col>
</Row>
...
...
@@ -56,10 +56,10 @@
<!--
角色已移除
-->
<!--
<
FormItem
label
=
"归属部门"
>
<
SelectDisplay
v
-
model
=
"editModal.form.office_id"
placeholder
=
"请输入机构"
@
open
=
"openOfficeSelect(editModal.form)"
/>
<
/FormItem
>
<
FormItem
label
=
"直属领导"
>
<
SelectDisplay
v
-
model
=
"editModal.form.leader"
placeholder
=
"只能选择本级或父机构人员"
@
open
=
"openSelectLeader(editModal.form)"
/>
<
/FormItem> --
>
<
FormItem
label
=
"直属领导"
>
<
Input
v
-
model
=
"editModal.form.leader_name"
readonly
placeholder
=
"点击选择直属领导"
@
click
.
native
=
"selectLeader"
style
=
"cursor: pointer"
/>
<
/FormItem
>
<
FormItem
label
=
"是否离职"
>
<
Select
v
-
model
=
"editModal.form.is_leave"
style
=
"width: 160px"
>
<
Option
:
value
=
"0"
>
未离职
<
/Option
>
...
...
@@ -72,16 +72,25 @@
<
Button
type
=
"primary"
:
loading
=
"editModal.saving"
@
click
=
"saveEdit"
>
保存
<
/Button
>
<
/div
>
<
/Modal
>
<!--
人员选择器
-->
<
UserSelector
v
-
model
=
"userSelectorVisible"
permission
=
""
@
on
-
ok
=
"handleLeaderSelected"
@
cancel
=
"userSelectorVisible = false"
/>
<!--
领导与归属部门选择已移除
-->
<
/div
>
<
/template
>
<
script
>
import
{
getDmUserList
,
syncDmUsersByOffice
,
saveDmUser
}
from
'@/api/key-dm-user'
import
UserSelector
from
'./userSelector.vue'
export
default
{
name
:
'key-dm-user-index'
,
components
:
{
}
,
components
:
{
UserSelector
}
,
data
()
{
return
{
officeCode
:
''
,
...
...
@@ -103,7 +112,8 @@ export default {
visible
:
false
,
saving
:
false
,
form
:
{
}
}
}
,
userSelectorVisible
:
false
// leader / office state 已移除
}
}
,
...
...
@@ -188,6 +198,14 @@ export default {
this
.
editModal
.
form
=
copy
this
.
editModal
.
visible
=
true
}
,
selectLeader
()
{
this
.
userSelectorVisible
=
true
}
,
handleLeaderSelected
(
user
)
{
this
.
editModal
.
form
.
leader
=
user
.
id
this
.
editModal
.
form
.
leader_name
=
user
.
name
this
.
userSelectorVisible
=
false
}
,
/* leader / office 相关方法已移除 */
saveEdit
()
{
this
.
$refs
.
editForm
.
validate
(
valid
=>
{
...
...
src/view/key-person/key_dm_user/userMultiSelector.vue
View file @
30a96ce8
...
...
@@ -4,7 +4,7 @@
<Row
type=
"flex"
:gutter=
"16"
align=
"middle"
>
<Col
:span=
"12"
>
<span>
姓名:
</span>
<Input
v-model=
"filters.name"
placeholder=
"请输入姓名"
@
on-enter=
"handleSearch
"
/>
<Input
v-model=
"filters.name"
placeholder=
"请输入姓名"
style=
"width: 200px
"
/>
</Col>
<Col
:span=
"12"
class=
"text-right"
>
<Button
type=
"primary"
class=
"mr10"
@
click=
"handleSearch"
>
搜索
</Button>
...
...
@@ -37,7 +37,9 @@ export default {
name
:
'user-multi-selector'
,
props
:
{
// v-model: value 控制显示
value
:
{
type
:
Boolean
,
default
:
false
}
value
:
{
type
:
Boolean
,
default
:
false
},
// 范围参数1父,本级,下级2本级
round
:
{
type
:
String
,
default
:
'1'
}
},
data
()
{
return
{
...
...
@@ -50,12 +52,12 @@ export default {
confirming
:
false
,
columns
:
[
{
type
:
'selection'
,
width
:
60
,
align
:
'center'
},
{
title
:
'归属部门'
,
key
:
'office_name'
,
align
:
'center'
,
minWidth
:
150
},
{
title
:
'姓名'
,
key
:
'name'
,
align
:
'center'
,
minWidth
:
100
},
{
title
:
'工号'
,
key
:
'gh'
,
align
:
'center'
,
minWidth
:
120
},
{
title
:
'邮箱'
,
key
:
'email'
,
align
:
'center'
,
minWidth
:
150
},
//
{ title: '邮箱', key: 'email', align: 'center', minWidth: 150 },
{
title
:
'电话'
,
key
:
'phone'
,
align
:
'center'
,
minWidth
:
120
},
{
title
:
'手机'
,
key
:
'mobile'
,
align
:
'center'
,
minWidth
:
120
},
{
title
:
'归属部门'
,
key
:
'office_name'
,
align
:
'center'
,
minWidth
:
150
}
{
title
:
'手机'
,
key
:
'mobile'
,
align
:
'center'
,
minWidth
:
120
}
]
}
},
...
...
@@ -78,11 +80,7 @@ export default {
methods
:
{
fetchList
()
{
this
.
loading
=
true
const
payload
=
{
pageNo
:
this
.
pager
.
pageNo
,
pageSize
:
this
.
pager
.
pageSize
,
params
:
this
.
filters
}
const
payload
=
Object
.
assign
({},
{
pageNo
:
this
.
pager
.
pageNo
,
pageSize
:
this
.
pager
.
pageSize
,
round
:
this
.
round
},
this
.
filters
)
getUserMultiSelectorList
(
payload
).
then
(
ret
=>
{
if
(
ret
.
data
&&
ret
.
data
.
errcode
===
0
)
{
const
data
=
ret
.
data
.
data
||
{}
...
...
src/view/key-person/key_dm_user/userSelector.vue
0 → 100644
View file @
30a96ce8
<
template
>
<Modal
v-model=
"visible"
title=
"选择人员"
width=
"900"
:mask-closable=
"false"
>
<div
class=
"search-div"
>
<Row
type=
"flex"
:gutter=
"16"
align=
"middle"
>
<Col
:span=
"12"
>
<span>
姓名:
</span>
<Input
v-model=
"filters.name"
placeholder=
"请输入姓名"
style=
"width: 200px"
/>
</Col>
<Col
:span=
"12"
class=
"text-right"
>
<Button
type=
"primary"
class=
"mr10"
@
click=
"handleSearch"
>
搜索
</Button>
<Button
@
click=
"handleReset"
>
重置
</Button>
</Col>
</Row>
</div>
<Table
:data=
"rows"
:loading=
"loading"
:columns=
"columns"
border
highlight-row
@
on-current-change=
"onCurrentRowChange"
@
on-row-dblclick=
"onRowDblclick"
/>
<Page
class=
"page_style"
:total=
"pager.totalRecord"
:current=
"pager.pageNo"
:page-size=
"pager.pageSize"
show-total
show-sizer
@
on-change=
"pageChange"
@
on-page-size-change=
"sizeChange"
/>
<div
slot=
"footer"
>
<Button
@
click=
"handleCancel"
>
取消
</Button>
<Button
type=
"primary"
:loading=
"confirming"
@
click=
"handleConfirm"
:disabled=
"!selectedRow"
>
确定
</Button>
</div>
</Modal>
</
template
>
<
script
>
import
{
getUserSelectorList
}
from
'@/api/key-dm-user'
export
default
{
name
:
'user-selector'
,
props
:
{
// v-model: value 控制显示
value
:
{
type
:
Boolean
,
default
:
false
},
// 权限参数
permission
:
{
type
:
String
,
default
:
''
}
},
data
()
{
return
{
visibleInternal
:
false
,
filters
:
{
name
:
''
},
rows
:
[],
loading
:
false
,
pager
:
{
pageNo
:
1
,
pageSize
:
10
,
totalRecord
:
0
},
selectedRow
:
null
,
confirming
:
false
,
columns
:
[
{
title
:
'姓名'
,
key
:
'name'
,
align
:
'center'
,
minWidth
:
100
},
{
title
:
'工号'
,
key
:
'gh'
,
align
:
'center'
,
minWidth
:
120
},
{
title
:
'邮箱'
,
key
:
'email'
,
align
:
'center'
,
minWidth
:
150
},
{
title
:
'电话'
,
key
:
'phone'
,
align
:
'center'
,
minWidth
:
120
},
{
title
:
'手机'
,
key
:
'mobile'
,
align
:
'center'
,
minWidth
:
120
},
{
title
:
'归属部门'
,
key
:
'office_name'
,
align
:
'center'
,
minWidth
:
150
},
{
title
:
'人员分类'
,
key
:
'category_names'
,
align
:
'center'
,
minWidth
:
200
}
]
}
},
computed
:
{
visible
:
{
get
()
{
return
this
.
value
},
set
(
v
)
{
this
.
$emit
(
'input'
,
v
)
}
}
},
watch
:
{
visible
(
v
)
{
if
(
v
)
{
this
.
pager
.
pageNo
=
1
this
.
selectedRow
=
null
this
.
filters
.
name
=
''
this
.
fetchList
()
}
}
},
methods
:
{
fetchList
()
{
this
.
loading
=
true
const
payload
=
Object
.
assign
({},
{
pageNo
:
this
.
pager
.
pageNo
,
pageSize
:
this
.
pager
.
pageSize
,
office_code
:
this
.
officeCode
,
permission
:
this
.
permission
},
this
.
filters
)
getUserSelectorList
(
payload
).
then
(
ret
=>
{
if
(
ret
.
data
&&
ret
.
data
.
errcode
===
0
)
{
const
data
=
ret
.
data
.
data
||
{}
this
.
rows
=
data
.
results
||
[]
this
.
pager
.
totalRecord
=
data
.
totalRecord
||
0
}
else
{
this
.
$Notice
.
error
({
title
:
'查询失败'
,
desc
:
ret
.
data
&&
ret
.
data
.
errmsg
})
}
}).
finally
(()
=>
{
this
.
loading
=
false
})
},
handleSearch
()
{
this
.
pager
.
pageNo
=
1
this
.
fetchList
()
},
handleReset
()
{
this
.
filters
=
{
name
:
''
}
this
.
pager
.
pageNo
=
1
this
.
fetchList
()
},
pageChange
(
pageNo
)
{
this
.
pager
.
pageNo
=
pageNo
this
.
fetchList
()
},
sizeChange
(
size
)
{
this
.
pager
.
pageSize
=
size
this
.
pager
.
pageNo
=
1
this
.
fetchList
()
},
onCurrentRowChange
(
currentRow
,
oldCurrentRow
)
{
this
.
selectedRow
=
currentRow
},
onRowDblclick
(
row
,
index
)
{
this
.
selectedRow
=
row
this
.
handleConfirm
()
},
handleCancel
()
{
this
.
$emit
(
'cancel'
)
this
.
$emit
(
'input'
,
false
)
},
handleConfirm
()
{
if
(
!
this
.
selectedRow
)
{
this
.
$Message
.
warning
(
'请先选择人员'
)
return
}
this
.
confirming
=
true
// emit selected user to parent
this
.
$emit
(
'on-ok'
,
this
.
selectedRow
)
this
.
$emit
(
'input'
,
false
)
this
.
confirming
=
false
}
}
}
</
script
>
<
style
scoped
>
.search-div
{
border
:
1px
solid
#dce1e7
;
padding
:
12px
;
margin-bottom
:
12px
;
background-color
:
#f8fbff
;
}
.mr10
{
margin-right
:
10px
;
}
.page_style
{
margin-top
:
12px
;
text-align
:
right
;
}
.text-right
{
text-align
:
right
;
}
</
style
>
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论