Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
H
hr-admin-view
Project
Project
Details
Activity
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
anjia-hr
hr-admin-view
Commits
d9cb58ab
Commit
d9cb58ab
authored
Dec 15, 2025
by
刘斌
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 增加编制计划初版
parent
ec6e2c90
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
2330 additions
and
0 deletions
+2330
-0
staffingPlanData.ts
apps/web-antd/src/api/hr/staffingPlanData.ts
+345
-0
staffingPlanRecords.ts
apps/web-antd/src/api/hr/staffingPlanRecords.ts
+77
-0
hr.ts
apps/web-antd/src/router/routes/modules/hr.ts
+25
-0
data.ts
apps/web-antd/src/views/hr/staffingPlanData/data.ts
+664
-0
form.vue
apps/web-antd/src/views/hr/staffingPlanData/form.vue
+453
-0
list.vue
apps/web-antd/src/views/hr/staffingPlanData/list.vue
+255
-0
staffing-import-modal.vue
...d/src/views/hr/staffingPlanData/staffing-import-modal.vue
+124
-0
data.ts
apps/web-antd/src/views/hr/staffingPlanRecords/data.ts
+101
-0
list.vue
apps/web-antd/src/views/hr/staffingPlanRecords/list.vue
+148
-0
modal.vue
apps/web-antd/src/views/hr/staffingPlanRecords/modal.vue
+138
-0
No files found.
apps/web-antd/src/api/hr/staffingPlanData.ts
0 → 100644
View file @
d9cb58ab
import
type
{
BaseModel
,
PageQuery
}
from
'#/api/baseModel'
;
import
{
commonExport
}
from
'#/api/helper'
;
import
{
requestClient
}
from
'#/api/request'
;
export
namespace
StaffingPlanDataApi
{
export
interface
StaffingPlanData
extends
BaseModel
{
/**
* 板块
*/
plate
?:
string
;
/**
* 一级部门
*/
firstLevelDepartment
?:
string
;
/**
* 二级部门
*/
secondLevelDepartment
?:
string
;
/**
* 三级部门
*/
thirdLevelDepartment
?:
string
;
/**
* 部门ID
*/
deptId
?:
number
;
/**
* 主岗位
*/
position
?:
string
;
/**
* 上一年编制
*/
lastYearStaffing
?:
number
;
/**
* 今年编制
*/
thisYearStaffing
?:
number
;
/**
* 下一年编制
*/
nextYearStaffing
?:
number
;
/**
* 1月正式工计划
*/
m1FormalPlan
?:
number
;
/**
* 1月正式工实际
*/
m1FormalActual
?:
string
;
/**
* 1月兼职计划
*/
m1PartPlan
?:
number
;
/**
* 1月兼职实际
*/
m1PartActual
?:
string
;
/**
* 2月正式工计划
*/
m2FormalPlan
?:
number
;
/**
* 2月正式工实际
*/
m2FormalActual
?:
string
;
/**
* 2月兼职计划
*/
m2PartPlan
?:
number
;
/**
* 2月兼职实际
*/
m2PartActual
?:
string
;
/**
* 3月正式工计划
*/
m3FormalPlan
?:
number
;
/**
* 3月正式工实际
*/
m3FormalActual
?:
string
;
/**
* 3月兼职计划
*/
m3PartPlan
?:
number
;
/**
* 3月兼职实际
*/
m3PartActual
?:
string
;
/**
* 4月正式工计划
*/
m4FormalPlan
?:
number
;
/**
* 4月正式工实际
*/
m4FormalActual
?:
string
;
/**
* 4月兼职计划
*/
m4PartPlan
?:
number
;
/**
* 4月兼职实际
*/
m4PartActual
?:
string
;
/**
* 5月正式工计划
*/
m5FormalPlan
?:
number
;
/**
* 5月正式工实际
*/
m5FormalActual
?:
string
;
/**
* 5月兼职计划
*/
m5PartPlan
?:
number
;
/**
* 5月兼职实际
*/
m5PartActual
?:
string
;
/**
* 6月正式工计划
*/
m6FormalPlan
?:
number
;
/**
* 6月正式工实际
*/
m6FormalActual
?:
string
;
/**
* 6月兼职计划
*/
m6PartPlan
?:
number
;
/**
* 6月兼职实际
*/
m6PartActual
?:
string
;
/**
* 7月正式工计划
*/
m7FormalPlan
?:
number
;
/**
* 7月正式工实际
*/
m7FormalActual
?:
string
;
/**
* 7月兼职计划
*/
m7PartPlan
?:
number
;
/**
* 7月兼职实际
*/
m7PartActual
?:
string
;
/**
* 8月正式工计划
*/
m8FormalPlan
?:
number
;
/**
* 8月正式工实际
*/
m8FormalActual
?:
string
;
/**
* 8月兼职计划
*/
m8PartPlan
?:
number
;
/**
* 8月兼职实际
*/
m8PartActual
?:
string
;
/**
* 9月正式工计划
*/
m9FormalPlan
?:
number
;
/**
* 9月正式工实际
*/
m9FormalActual
?:
string
;
/**
* 9月兼职计划
*/
m9PartPlan
?:
number
;
/**
* 9月兼职实际
*/
m9PartActual
?:
string
;
/**
* 10月正式工计划
*/
m10FormalPlan
?:
number
;
/**
* 10月正式工实际
*/
m10FormalActual
?:
string
;
/**
* 10月兼职计划
*/
m10PartPlan
?:
number
;
/**
* 10月兼职实际
*/
m10PartActual
?:
string
;
/**
* 11月正式工计划
*/
m11FormalPlan
?:
number
;
/**
* 11月正式工实际
*/
m11FormalActual
?:
string
;
/**
* 11月兼职计划
*/
m11PartPlan
?:
number
;
/**
* 11月兼职实际
*/
m11PartActual
?:
string
;
/**
* 12月正式工计划
*/
m12FormalPlan
?:
number
;
/**
* 12月正式工实际
*/
m12FormalActual
?:
string
;
/**
* 12月兼职计划
*/
m12PartPlan
?:
number
;
/**
* 12月兼职实际
*/
m12PartActual
?:
string
;
/**
* 合计行
*/
summary
?:
string
;
/**
* 备注
*/
remark
?:
string
;
}
}
/**
* 查询编制规划记录明细列表
* @param params
* @returns {*} page
*/
export
function
apiPage
(
params
:
PageQuery
)
{
return
requestClient
.
get
(
'/employee/staffingPlanData/page'
,
{
params
});
}
/**
* 查询编制规划记录明细详细
* @param id
*/
export
function
apiDetail
(
id
:
number
)
{
return
requestClient
.
get
(
`/employee/staffingPlanData/
${
id
}
`
);
}
/**
* 新增编制规划记录明细
* @param data
*/
export
function
apiAdd
(
data
:
StaffingPlanDataApi
.
StaffingPlanData
)
{
return
requestClient
.
post
(
'/employee/staffingPlanData'
,
data
);
}
/**
* 修改编制规划记录明细
* @param data
*/
export
function
apiUpdate
(
data
:
StaffingPlanDataApi
.
StaffingPlanData
[])
{
return
requestClient
.
put
(
'/employee/staffingPlanData'
,
data
);
}
/**
* 删除编制规划记录明细
* @param id
*/
export
function
apiDelete
(
id
:
Array
<
number
>
|
number
)
{
return
requestClient
.
delete
(
`/employee/staffingPlanData/
${
id
}
`
);
}
/**
* 导出编制规划记录明细
* @param params
*/
export
function
apiExport
(
id
:
number
)
{
return
commonExport
(
`/employee/staffingPlanData/export/
${
id
}
`
,
{});
}
/**
* 下载用户导入模板
* @returns blob
*/
export
function
downloadImportTemplate
()
{
return
commonExport
(
'/employee/staffingPlanData/importTemplate'
,
{});
}
/**
* 从excel导入培训信息
* @param file
* @returns void
*/
export
function
staffingPlanDataImportData
(
recordId
:
number
,
file
:
Blob
)
{
return
requestClient
.
post
<
{
errMessage
:
string
;
success
:
boolean
}
>
(
`/employee/staffingPlanData/import/
${
recordId
}
`
,
{
file
},
{
headers
:
{
'Content-Type'
:
'multipart/form-data;charset=UTF-8'
,
},
isTransformResponse
:
false
,
responseReturn
:
'body'
,
timeout
:
300
_000
,
},
);
}
apps/web-antd/src/api/hr/staffingPlanRecords.ts
0 → 100644
View file @
d9cb58ab
import
type
{
BaseModel
,
PageQuery
}
from
'#/api/baseModel'
;
import
{
commonExport
}
from
'#/api/helper'
;
import
{
requestClient
}
from
'#/api/request'
;
export
namespace
StaffingPlanRecordsApi
{
export
interface
StaffingPlanRecords
extends
BaseModel
{
/**
* 记录时间
*/
recordDate
?:
string
;
/**
* 上一年标题
*/
lastYearTitle
?:
string
;
/**
* 今年标题
*/
currentYearTitle
?:
string
;
/**
* 明年标题
*/
nextYearTitle
?:
string
;
/**
* 是否已初始化
*/
initFlag
?:
string
;
/**
* 备注
*/
remark
?:
string
;
}
}
/**
* 查询编制规划记录列表
* @param params
* @returns {*} page
*/
export
function
apiPage
(
params
:
PageQuery
)
{
return
requestClient
.
get
(
'/employee/staffingPlanRecords/page'
,
{
params
});
}
/**
* 查询编制规划记录详细
* @param id
*/
export
function
apiDetail
(
id
:
number
)
{
return
requestClient
.
get
(
`/employee/staffingPlanRecords/
${
id
}
`
);
}
/**
* 新增编制规划记录
* @param data
*/
export
function
apiAdd
(
data
:
StaffingPlanRecordsApi
.
StaffingPlanRecords
)
{
return
requestClient
.
post
(
'/employee/staffingPlanRecords'
,
data
);
}
/**
* 修改编制规划记录
* @param data
*/
export
function
apiUpdate
(
data
:
StaffingPlanRecordsApi
.
StaffingPlanRecords
)
{
return
requestClient
.
put
(
'/employee/staffingPlanRecords'
,
data
);
}
/**
* 删除编制规划记录
* @param id
*/
export
function
apiDelete
(
id
:
Array
<
number
>
|
number
)
{
return
requestClient
.
delete
(
`/employee/staffingPlanRecords/
${
id
}
`
);
}
/**
* 导出编制规划记录
* @param params
*/
export
function
apiExport
(
params
:
PageQuery
)
{
return
commonExport
(
'/employee/staffingPlanRecords/export'
,
params
);
}
apps/web-antd/src/router/routes/modules/hr.ts
View file @
d9cb58ab
...
...
@@ -168,6 +168,31 @@ const routes: RouteRecordRaw[] = [
componentPath
:
'#/views/hr/employeeStatusAnalysis/list.vue'
,
},
},
{
path
:
'/hr/report/staffingPlanRecords/records'
,
name
:
'StaffingPlanRecordsList'
,
component
:
()
=>
import
(
'#/views/hr/staffingPlanRecords/list.vue'
),
meta
:
{
title
:
'编制规划记录'
,
icon
:
'arcticons:one-hand-operation'
,
keepAlive
:
true
,
permission
:
[
'dashboard'
],
componentPath
:
'#/views/hr/staffingPlanRecords/list.vue'
,
},
},
{
path
:
'/hr/report/staffingPlan/data/:recordId'
,
component
:
()
=>
import
(
'#/views/hr/staffingPlanData/list.vue'
),
name
:
'StaffingPlanDataList'
,
meta
:
{
title
:
'编制明细'
,
icon
:
'mingcute:department-line'
,
keepAlive
:
true
,
hideInMenu
:
true
,
permission
:
[
'dashboard'
],
componentPath
:
'#/views/hr/staffingPlanData/list.vue'
,
},
},
],
},
{
...
...
apps/web-antd/src/views/hr/staffingPlanData/data.ts
0 → 100644
View file @
d9cb58ab
This diff is collapsed.
Click to expand it.
apps/web-antd/src/views/hr/staffingPlanData/form.vue
0 → 100644
View file @
d9cb58ab
<
script
lang=
"ts"
setup
>
import
type
{
VbenFormSchema
}
from
'#/adapter/form'
;
import
type
{
StaffingPlanDataApi
}
from
'#/api/hr/staffingPlanData'
;
import
{
computed
,
ref
}
from
'vue'
;
import
{
useVbenDrawer
}
from
'@vben/common-ui'
;
import
{
useVbenForm
}
from
'#/adapter/form'
;
import
{
apiAdd
,
apiUpdate
}
from
'#/api/hr/staffingPlanData'
;
import
{
defaultFormValueGetter
,
useBeforeCloseDiff
}
from
'#/utils/popup'
;
const
emit
=
defineEmits
<
{
success
:
[];
}
>
();
const
isUpdate
=
ref
(
false
);
const
formSchema
:
VbenFormSchema
[]
=
[
{
component
:
'Input'
,
dependencies
:
{
show
:
()
=>
false
,
triggerFields
:
[
''
],
},
fieldName
:
'id'
,
label
:
'id'
,
},
{
component
:
'Input'
,
fieldName
:
'plate'
,
label
:
'板块'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'firstLevelDepartment'
,
label
:
'一级部门'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'secondLevelDepartment'
,
label
:
'二级部门'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'thirdLevelDepartment'
,
label
:
'三级部门'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'deptId'
,
label
:
'部门ID'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'position'
,
label
:
'主岗位'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'lastYearStaffing'
,
label
:
'上一年编制'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'thisYearStaffing'
,
label
:
'今年编制'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'nextYearStaffing'
,
label
:
'下一年编制'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm1FormalPlan'
,
label
:
'1月正式工计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm1FormalActual'
,
label
:
'1月正式工实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm1PartPlan'
,
label
:
'1月兼职计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm1PartActual'
,
label
:
'1月兼职实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm2FormalPlan'
,
label
:
'2月正式工计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm2FormalActual'
,
label
:
'2月正式工实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm2PartPlan'
,
label
:
'2月兼职计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm2PartActual'
,
label
:
'2月兼职实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm3FormalPlan'
,
label
:
'3月正式工计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm3FormalActual'
,
label
:
'3月正式工实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm3PartPlan'
,
label
:
'3月兼职计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm3PartActual'
,
label
:
'3月兼职实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm4FormalPlan'
,
label
:
'4月正式工计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm4FormalActual'
,
label
:
'4月正式工实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm4PartPlan'
,
label
:
'4月兼职计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm4PartActual'
,
label
:
'4月兼职实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm5FormalPlan'
,
label
:
'5月正式工计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm5FormalActual'
,
label
:
'5月正式工实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm5PartPlan'
,
label
:
'5月兼职计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm5PartActual'
,
label
:
'5月兼职实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm6FormalPlan'
,
label
:
'6月正式工计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm6FormalActual'
,
label
:
'6月正式工实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm6PartPlan'
,
label
:
'6月兼职计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm6PartActual'
,
label
:
'6月兼职实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm7FormalPlan'
,
label
:
'7月正式工计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm7FormalActual'
,
label
:
'7月正式工实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm7PartPlan'
,
label
:
'7月兼职计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm7PartActual'
,
label
:
'7月兼职实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm8FormalPlan'
,
label
:
'8月正式工计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm8FormalActual'
,
label
:
'8月正式工实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm8PartPlan'
,
label
:
'8月兼职计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm8PartActual'
,
label
:
'8月兼职实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm9FormalPlan'
,
label
:
'9月正式工计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm9FormalActual'
,
label
:
'9月正式工实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm9PartPlan'
,
label
:
'9月兼职计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm9PartActual'
,
label
:
'9月兼职实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm10FormalPlan'
,
label
:
'10月正式工计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm10FormalActual'
,
label
:
'10月正式工实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm10PartPlan'
,
label
:
'10月兼职计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm10PartActual'
,
label
:
'10月兼职实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm11FormalPlan'
,
label
:
'11月正式工计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm11FormalActual'
,
label
:
'11月正式工实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm11PartPlan'
,
label
:
'11月兼职计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm11PartActual'
,
label
:
'11月兼职实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm12FormalPlan'
,
label
:
'12月正式工计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm12FormalActual'
,
label
:
'12月正式工实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm12PartPlan'
,
label
:
'12月兼职计划'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'm12PartActual'
,
label
:
'12月兼职实际'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'summary'
,
label
:
'合计行'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'remark'
,
label
:
'备注'
,
rules
:
'required'
,
},
];
const
[
BasicForm
,
formApi
]
=
useVbenForm
({
commonConfig
:
{
componentProps
:
{
class
:
'w-full'
,
},
formItemClass
:
'col-span-2'
,
labelWidth
:
90
,
},
schema
:
formSchema
,
showDefaultActions
:
false
,
wrapperClass
:
'grid-cols-2'
,
});
const
{
onBeforeClose
,
markInitialized
,
resetInitialized
}
=
useBeforeCloseDiff
(
{
initializedGetter
:
defaultFormValueGetter
(
formApi
),
currentGetter
:
defaultFormValueGetter
(
formApi
),
},
);
const
[
Drawer
,
drawerApi
]
=
useVbenDrawer
({
onBeforeClose
,
onClosed
:
handleClosed
,
onConfirm
:
onSubmit
,
async
onOpenChange
(
isOpen
)
{
if
(
!
isOpen
)
{
return
null
;
}
const
data
=
drawerApi
.
getData
<
StaffingPlanDataApi
.
StaffingPlanData
>
();
isUpdate
.
value
=
!!
data
?.
id
;
if
(
isUpdate
.
value
)
{
await
formApi
.
setValues
(
data
);
}
else
{
formApi
.
resetForm
();
}
await
markInitialized
();
},
});
async
function
onSubmit
()
{
const
{
valid
}
=
await
formApi
.
validate
();
if
(
valid
)
{
drawerApi
.
lock
();
const
data
=
await
formApi
.
getValues
<
StaffingPlanDataApi
.
StaffingPlanData
>
();
try
{
await
(
isUpdate
.
value
?
apiUpdate
(
data
)
:
apiAdd
(
data
));
resetInitialized
();
emit
(
'success'
);
drawerApi
.
close
();
}
finally
{
drawerApi
.
unlock
();
}
}
}
async
function
handleClosed
()
{
await
formApi
.
resetForm
();
resetInitialized
();
}
const
getDrawerTitle
=
computed
(()
=>
isUpdate
.
value
?
'修改编制规划记录明细'
:
'新增编制规划记录明细'
,
);
</
script
>
<
template
>
<Drawer
class=
"w-full max-w-[800px]"
:title=
"getDrawerTitle"
>
<BasicForm
class=
"mx-4"
/>
</Drawer>
</
template
>
apps/web-antd/src/views/hr/staffingPlanData/list.vue
0 → 100644
View file @
d9cb58ab
<
script
lang=
"ts"
setup
>
import
type
{
VxeTableGridOptions
}
from
'#/adapter/vxe-table'
;
import
type
{
StaffingPlanDataApi
}
from
'#/api/hr/staffingPlanData'
;
import
{
onMounted
,
reactive
,
ref
,
watch
}
from
'vue'
;
import
{
useRoute
}
from
'vue-router'
;
import
{
Page
,
useVbenModal
}
from
'@vben/common-ui'
;
import
{
Plus
}
from
'@vben/icons'
;
import
{
ExportOutlined
,
SaveOutlined
}
from
'@ant-design/icons-vue'
;
import
{
Button
,
message
,
Space
}
from
'ant-design-vue'
;
import
{
useVbenVxeGrid
}
from
'#/adapter/vxe-table'
;
import
{
apiExport
,
apiPage
,
apiUpdate
}
from
'#/api/hr/staffingPlanData'
;
import
{
apiDetail
as
recordInfo
}
from
'#/api/hr/staffingPlanRecords'
;
import
{
commonDownloadExcel
}
from
'#/utils/file/download'
;
import
{
useColumns
}
from
'./data'
;
import
staffingImportModal
from
'./staffing-import-modal.vue'
;
// import Form from './form.vue';
const
route
=
useRoute
();
const
recordId
=
route
.
params
.
recordId
?
Number
(
route
.
params
.
recordId
)
:
0
;
const
initFlagRef
=
ref
(
'N'
);
const
staffingRecords
=
reactive
({
lastYearTitle
:
''
,
currentYearTitle
:
''
,
nextYearTitle
:
''
,
});
watch
(
()
=>
staffingRecords
,
()
=>
{
const
cols
=
useColumns
(
staffingRecords
)
as
any
;
gridApi
.
grid
?.
reloadColumn
?.(
cols
);
},
{
deep
:
true
},
);
onMounted
(
async
()
=>
{
const
records
=
await
recordInfo
(
recordId
);
initFlagRef
.
value
=
records
.
initFlag
;
staffingRecords
.
lastYearTitle
=
records
.
lastYearTitle
;
staffingRecords
.
currentYearTitle
=
records
.
currentYearTitle
;
staffingRecords
.
nextYearTitle
=
records
.
nextYearTitle
;
});
/**
* 导入
*/
const
[
StaffingImportModal
,
staffingImportModalApi
]
=
useVbenModal
({
connectedComponent
:
staffingImportModal
,
});
function
handleImport
()
{
staffingImportModalApi
.
setData
({
recordId
}).
open
();
}
// const formOptions: VbenFormProps = {
// commonConfig: {
// labelWidth: 80,
// componentProps: {
// allowClear: true,
// },
// },
// schema: querySchema,
// wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
// };
// const [FormDrawer, formDrawerApi] = useVbenDrawer({
// connectedComponent: Form,
// });
const
[
Grid
,
gridApi
]
=
useVbenVxeGrid
({
// formOptions,
gridOptions
:
{
columns
:
useColumns
(
staffingRecords
)
as
any
,
height
:
'auto'
,
keepSource
:
true
,
pagerConfig
:
{
enabled
:
true
,
pageSize
:
20
,
},
editConfig
:
{
mode
:
'cell'
,
trigger
:
'click'
,
// activeMethod({ row }) {
// return !row.summary;
// },
// beforeEditMethod({ row }) {
// // name 为 'x' 开头的列禁止编辑
// console.log('[row]', row);
// return true;
// },
},
proxyConfig
:
{
ajax
:
{
query
:
async
({
page
},
formValues
=
{})
=>
{
return
await
apiPage
({
pageNo
:
page
.
currentPage
,
pageSize
:
page
.
pageSize
,
recordId
,
...
formValues
,
});
},
},
},
border
:
true
,
columnConfig
:
{
resizable
:
false
,
},
showCustomHeader
:
true
,
spanMethod
({
row
,
column
})
{
if
(
row
.
summary
===
'Y'
)
{
const
mergeFields
=
[
'plate'
,
'firstLevelDepartment'
,
'secondLevelDepartment'
,
'thirdLevelDepartment'
,
];
if
(
mergeFields
.
includes
(
column
.
field
as
string
))
{
if
(
column
.
field
===
'plate'
)
{
return
{
rowspan
:
1
,
colspan
:
4
}
as
any
;
}
return
{
rowspan
:
0
,
colspan
:
0
}
as
any
;
}
}
return
undefined
as
any
;
},
rowClassName
:
({
row
})
=>
{
if
(
row
.
summary
===
'Y'
)
{
return
row
.
plate
===
'片区合计'
?
'bg-red-500 text-white'
:
'bg-red-100'
;
}
return
''
;
},
mergeHeaderCells
:
[
{
row
:
0
,
col
:
0
,
rowspan
:
2
,
colspan
:
1
},
{
row
:
0
,
col
:
1
,
rowspan
:
2
,
colspan
:
1
},
{
row
:
0
,
col
:
2
,
rowspan
:
2
,
colspan
:
1
},
{
row
:
0
,
col
:
3
,
rowspan
:
2
,
colspan
:
1
},
{
row
:
0
,
col
:
4
,
rowspan
:
2
,
colspan
:
1
},
{
row
:
0
,
col
:
5
,
rowspan
:
2
,
colspan
:
1
},
{
row
:
0
,
col
:
6
,
rowspan
:
2
,
colspan
:
1
},
{
row
:
0
,
col
:
7
,
rowspan
:
2
,
colspan
:
1
},
{
row
:
0
,
col
:
8
,
rowspan
:
1
,
colspan
:
48
},
{
row
:
0
,
col
:
56
,
rowspan
:
2
,
colspan
:
1
},
],
rowConfig
:
{
keyField
:
'id'
,
// 高亮当前行
isCurrent
:
false
,
},
}
as
VxeTableGridOptions
,
});
// function onActionClick({
// code,
// row,
// }: OnActionClickParams
<
StaffingPlanDataApi
.
StaffingPlanData
>
)
{
// switch (code) {
// case 'delete': {
// onDelete(row);
// break;
// }
// case 'edit': {
// onEdit(row);
// break;
// }
// default: {
// break;
// }
// }
// }
async
function
onEdit
()
{
const
full
=
(
await
gridApi
.
grid
?.
getUpdateRecords
())
as
StaffingPlanDataApi
.
StaffingPlanData
[];
if
(
full
&&
full
.
length
>
0
)
{
await
apiUpdate
(
full
);
message
.
success
(
'已保存编制计划'
);
}
else
{
message
.
error
(
'无修改,请检查'
);
}
}
function
onRefresh
()
{
gridApi
.
query
();
initFlagRef
.
value
=
'Y'
;
}
// function onDelete(row: StaffingPlanDataApi.StaffingPlanData) {
// const hideLoading = message.loading({
// content: `正在删除${row.name}...`,
// duration: 0,
// key: 'action_process_msg',
// });
// apiDelete(row.id || 0)
// .then(() => {
// message.success({
// content: `${row.name}删除成功`,
// key: 'action_process_msg',
// });
// onRefresh();
// })
// .catch(() => {
// hideLoading();
// });
// }
function
handleDownloadExcel
()
{
commonDownloadExcel
(
apiExport
,
'编制规划记录明细'
,
recordId
);
}
</
script
>
<
template
>
<Page
auto-content-height
>
<!--
<FormDrawer
@
success=
"onRefresh"
/>
-->
<StaffingImportModal
@
reload=
"onRefresh"
/>
<Grid
table-title=
"编制规划记录明细列表"
>
<template
#
toolbar-tools
>
<Space>
<Button
type=
"primary"
ghost
v-access:code=
"['employee:staffingPlanData:edit']"
@
click=
"onEdit"
>
<template
#
icon
>
<SaveOutlined
/>
</
template
>
保存修改
</Button>
<Button
type=
"primary"
danger
v-access:code=
"['employee:staffingPlanData:export']"
@
click=
"handleDownloadExcel"
>
<
template
#
icon
>
<ExportOutlined
/>
</
template
>
导出
</Button>
<Button
v-access:code=
"['employee:staffingPlanData:add']"
v-if=
"initFlagRef === 'N'"
type=
"primary"
@
click=
"handleImport"
>
<Plus
class=
"size-5"
/>
导入明细
</Button>
</Space>
</template>
</Grid>
</Page>
</template>
apps/web-antd/src/views/hr/staffingPlanData/staffing-import-modal.vue
0 → 100644
View file @
d9cb58ab
<
script
setup
lang=
"ts"
>
import
type
{
UploadFile
}
from
'ant-design-vue/es/upload/interface'
;
import
{
h
,
ref
,
unref
}
from
'vue'
;
import
{
useVbenModal
}
from
'@vben/common-ui'
;
import
{
ExcelIcon
,
InBoxIcon
}
from
'@vben/icons'
;
import
{
Button
,
Modal
,
Upload
}
from
'ant-design-vue'
;
import
{
downloadImportTemplate
,
staffingPlanDataImportData
,
}
from
'#/api/hr/staffingPlanData'
;
import
{
commonDownloadExcel
}
from
'#/utils/file/download'
;
const
emit
=
defineEmits
<
{
reload
:
[]
}
>
();
const
UploadDragger
=
Upload
.
Dragger
;
const
recordIdRef
=
ref
(
0
);
const
[
BasicModal
,
modalApi
]
=
useVbenModal
({
onCancel
:
handleCancel
,
onConfirm
:
handleSubmit
,
onOpenChange
:
async
(
isOpen
)
=>
{
if
(
!
isOpen
)
{
return
null
;
}
const
{
recordId
}
=
modalApi
.
getData
()
as
{
recordId
:
number
};
recordIdRef
.
value
=
recordId
;
},
});
const
fileList
=
ref
<
UploadFile
[]
>
([]);
// const checked = ref(false);
async
function
handleSubmit
()
{
try
{
modalApi
.
modalLoading
(
true
);
if
(
fileList
.
value
.
length
!==
1
)
{
handleCancel
();
return
;
}
// const data = {
// file: fileList.value[0]!.originFileObj as Blob,
// updateSupport: unref(checked),
// };
const
{
success
,
errMessage
}
=
await
staffingPlanDataImportData
(
unref
(
recordIdRef
),
fileList
.
value
[
0
]
!
.
originFileObj
as
Blob
,
);
let
modal
=
Modal
.
success
;
if
(
success
)
{
emit
(
'reload'
);
}
else
{
modal
=
Modal
.
error
;
}
handleCancel
();
modal
({
content
:
h
(
'div'
,
{
class
:
'max-h-[260px] overflow-y-auto'
,
innerHTML
:
errMessage
,
// 后台已经处理xss问题
}),
title
:
'提示'
,
});
}
catch
(
error
)
{
console
.
warn
(
error
);
modalApi
.
close
();
}
finally
{
modalApi
.
modalLoading
(
false
);
}
}
function
handleCancel
()
{
modalApi
.
close
();
fileList
.
value
=
[];
// checked.value = false;
}
</
script
>
<
template
>
<BasicModal
:close-on-click-modal=
"false"
:fullscreen-button=
"false"
title=
"编制计划导入"
>
<!-- z-index不设置会遮挡模板下载loading -->
<!-- 手动处理 而不是放入文件就上传 -->
<UploadDragger
v-model:file-list=
"fileList"
:before-upload=
"() => false"
:max-count=
"1"
:show-upload-list=
"true"
accept=
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
>
<p
class=
"ant-upload-drag-icon flex items-center justify-center"
>
<InBoxIcon
class=
"text-primary size-[48px]"
/>
</p>
<p
class=
"ant-upload-text"
>
点击或者拖拽到此处上传文件
</p>
</UploadDragger>
<div
class=
"mt-2 flex flex-col gap-2"
>
<div
class=
"flex items-center gap-2"
>
<span>
允许导入xlsx, xls文件
</span>
<Button
type=
"link"
@
click=
"
commonDownloadExcel(downloadImportTemplate, '编制计划导入模板')
"
>
<div
class=
"flex items-center gap-[4px]"
>
<ExcelIcon
/>
<span>
下载模板
</span>
</div>
</Button>
</div>
<!--
<div
class=
"flex items-center gap-2"
>
<span
:class=
"
{ 'text-red-500': checked }">
是否更新/覆盖已存在的用户数据
</span>
<Switch
v-model:checked=
"checked"
/>
</div>
-->
</div>
</BasicModal>
</
template
>
apps/web-antd/src/views/hr/staffingPlanRecords/data.ts
0 → 100644
View file @
d9cb58ab
import
type
{
VbenFormSchema
}
from
'#/adapter/form'
;
import
type
{
OnActionClickFn
,
VxeTableGridOptions
}
from
'#/adapter/vxe-table'
;
import
type
{
StaffingPlanRecordsApi
}
from
'#/api/hr/staffingPlanRecords'
;
export
const
querySchema
:
VbenFormSchema
[]
=
[
{
component
:
'DatePicker'
,
componentProps
:
{
picker
:
'year'
,
format
:
'YYYY'
,
valueFormat
:
'YYYY'
,
},
fieldName
:
'recordDate'
,
label
:
'记录时间'
,
},
// {
// component: 'Input',
// fieldName: 'lastYearTitle',
// label: '上一年标题',
// },
// {
// component: 'Input',
// fieldName: 'currentYearTitle',
// label: '今年标题',
// },
// {
// component: 'Input',
// fieldName: 'nextYearTitle',
// label: '明年标题',
// },
// {
// component: 'Input',
// fieldName: 'initFlag',
// label: '是否已初始化',
// },
];
export
function
useColumns
(
onActionClick
:
OnActionClickFn
<
StaffingPlanRecordsApi
.
StaffingPlanRecords
>
,
):
VxeTableGridOptions
<
StaffingPlanRecordsApi
.
StaffingPlanRecords
>
[
'columns'
]
{
return
[
{
title
:
'记录时间'
,
field
:
'recordDate'
,
// formatter: 'formatDateTime',
},
// {
// title: '上一年标题',
// field: 'lastYearTitle',
// },
// {
// title: '今年标题',
// field: 'currentYearTitle',
// },
// {
// title: '明年标题',
// field: 'nextYearTitle',
// },
// {
// title: '是否已初始化',
// field: 'initFlag',
// },
{
title
:
'备注'
,
field
:
'remark'
,
},
{
align
:
'right'
,
cellRender
:
{
attrs
:
{
nameField
:
'recordDate'
,
nameTitle
:
'编制规划记录'
,
onClick
:
onActionClick
,
},
name
:
'CellOperation'
,
options
:
[
{
text
:
'明细'
,
code
:
'detail'
,
accessCode
:
[
'employee:staffingPlanRecords:edit'
],
},
// 明细数据
{
code
:
'edit'
,
accessCode
:
[
'employee:staffingPlanRecords:edit'
],
},
// 默认的编辑按钮
{
code
:
'delete'
,
accessCode
:
[
'employee:staffingPlanRecords:remove'
],
},
// 默认的删除按钮
],
},
field
:
'action'
,
fixed
:
'right'
,
headerAlign
:
'center'
,
resizable
:
false
,
showOverflow
:
false
,
title
:
'操作'
,
width
:
'auto'
,
},
];
}
apps/web-antd/src/views/hr/staffingPlanRecords/list.vue
0 → 100644
View file @
d9cb58ab
<
script
lang=
"ts"
setup
>
import
type
{
VbenFormProps
}
from
'@vben/common-ui'
;
import
type
{
OnActionClickParams
,
VxeTableGridOptions
,
}
from
'#/adapter/vxe-table'
;
import
type
{
StaffingPlanRecordsApi
}
from
'#/api/hr/staffingPlanRecords'
;
import
{
useRouter
}
from
'vue-router'
;
import
{
Page
,
useVbenModal
}
from
'@vben/common-ui'
;
import
{
Plus
}
from
'@vben/icons'
;
import
{
Button
,
message
,
Space
}
from
'ant-design-vue'
;
import
{
useVbenVxeGrid
}
from
'#/adapter/vxe-table'
;
import
{
apiDelete
,
apiPage
}
from
'#/api/hr/staffingPlanRecords'
;
import
{
querySchema
,
useColumns
}
from
'./data'
;
import
staffingPlanRecordModal
from
'./modal.vue'
;
const
formOptions
:
VbenFormProps
=
{
commonConfig
:
{
labelWidth
:
80
,
componentProps
:
{
allowClear
:
true
,
},
},
schema
:
querySchema
,
wrapperClass
:
'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4'
,
};
const
[
StaffingPlanRecordModal
,
modalApi
]
=
useVbenModal
({
connectedComponent
:
staffingPlanRecordModal
,
});
const
[
Grid
,
gridApi
]
=
useVbenVxeGrid
({
formOptions
,
gridOptions
:
{
columns
:
useColumns
(
onActionClick
),
height
:
'auto'
,
keepSource
:
true
,
pagerConfig
:
{
enabled
:
true
,
},
proxyConfig
:
{
ajax
:
{
query
:
async
({
page
},
formValues
=
{})
=>
{
return
await
apiPage
({
pageNo
:
page
.
currentPage
,
pageSize
:
page
.
pageSize
,
...
formValues
,
});
},
},
},
rowConfig
:
{
keyField
:
'id'
,
// 高亮当前行
isCurrent
:
true
,
},
}
as
VxeTableGridOptions
,
});
function
onActionClick
({
code
,
row
,
}:
OnActionClickParams
<
StaffingPlanRecordsApi
.
StaffingPlanRecords
>
)
{
switch
(
code
)
{
case
'delete'
:
{
onDelete
(
row
);
break
;
}
case
'detail'
:
{
onRecordData
(
row
);
break
;
}
case
'edit'
:
{
onEdit
(
row
);
break
;
}
default
:
{
break
;
}
}
}
function
onRefresh
()
{
gridApi
.
query
();
}
function
onEdit
(
row
:
StaffingPlanRecordsApi
.
StaffingPlanRecords
)
{
modalApi
.
setData
(
row
).
open
();
}
function
onCreate
()
{
modalApi
.
setData
({}).
open
();
}
function
onDelete
(
row
:
StaffingPlanRecordsApi
.
StaffingPlanRecords
)
{
const
hideLoading
=
message
.
loading
({
content
:
`正在删除
${
row
.
recordDate
}
...`
,
duration
:
0
,
key
:
'action_process_msg'
,
});
apiDelete
(
row
.
id
||
0
)
.
then
(()
=>
{
message
.
success
({
content
:
`
${
row
.
recordDate
}
删除成功`
,
key
:
'action_process_msg'
,
});
onRefresh
();
})
.
catch
(()
=>
{
hideLoading
();
});
}
const
router
=
useRouter
();
function
onRecordData
(
record
:
StaffingPlanRecordsApi
.
StaffingPlanRecords
)
{
router
.
push
(
`/hr/report/staffingPlan/data/
${
record
.
id
}
`
);
}
// function handleDownloadExcel() {
// commonDownloadExcel(apiExport, '编制规划记录', gridApi.formApi.form.values);
// }
</
script
>
<
template
>
<Page
auto-content-height
>
<StaffingPlanRecordModal
@
success=
"onRefresh"
/>
<Grid
table-title=
"编制规划记录列表"
>
<template
#
toolbar-tools
>
<Space>
<!--
<Button
v-access:code=
"['employee:staffingPlanRecords:export']"
@
click=
"handleDownloadExcel"
>
导出
</Button>
-->
<Button
v-access:code=
"['employee:staffingPlanRecords:add']"
type=
"primary"
@
click=
"onCreate"
>
<Plus
class=
"size-5"
/>
新增
</Button>
</Space>
</
template
>
</Grid>
</Page>
</template>
apps/web-antd/src/views/hr/staffingPlanRecords/modal.vue
0 → 100644
View file @
d9cb58ab
<
script
lang=
"ts"
setup
>
import
type
{
VbenFormSchema
}
from
'#/adapter/form'
;
import
type
{
StaffingPlanRecordsApi
}
from
'#/api/hr/staffingPlanRecords'
;
import
{
computed
,
ref
}
from
'vue'
;
import
{
useVbenModal
}
from
'@vben/common-ui'
;
import
{
getVxePopupContainer
}
from
'@vben/utils'
;
import
{
useVbenForm
}
from
'#/adapter/form'
;
import
{
apiAdd
,
apiUpdate
}
from
'#/api/hr/staffingPlanRecords'
;
import
{
defaultFormValueGetter
,
useBeforeCloseDiff
}
from
'#/utils/popup'
;
const
emit
=
defineEmits
<
{
success
:
[];
}
>
();
const
formData
=
ref
<
StaffingPlanRecordsApi
.
StaffingPlanRecords
>
();
const
formSchema
:
VbenFormSchema
[]
=
[
{
component
:
'DatePicker'
,
componentProps
:
{
picker
:
'year'
,
format
:
'YYYY'
,
valueFormat
:
'YYYY'
,
getVxePopupContainer
,
},
fieldName
:
'recordDate'
,
label
:
'记录时间'
,
rules
:
'required'
,
},
// {
// component: 'Input',
// fieldName: 'lastYearTitle',
// label: '上一年标题',
// rules: 'required',
// },
// {
// component: 'Input',
// fieldName: 'currentYearTitle',
// label: '今年标题',
// rules: 'required',
// },
// {
// component: 'Input',
// fieldName: 'nextYearTitle',
// label: '明年标题',
// rules: 'required',
// },
// {
// component: 'Input',
// fieldName: 'initFlag',
// label: '是否已初始化',
// rules: 'required',
// },
{
component
:
'Input'
,
fieldName
:
'remark'
,
label
:
'备注'
,
// rules: 'required',
},
];
const
[
BasicForm
,
formApi
]
=
useVbenForm
({
commonConfig
:
{
componentProps
:
{
class
:
'w-full'
,
},
formItemClass
:
'col-span-2'
,
labelWidth
:
90
,
},
schema
:
formSchema
,
showDefaultActions
:
false
,
wrapperClass
:
'grid-cols-2'
,
});
const
{
onBeforeClose
,
markInitialized
,
resetInitialized
}
=
useBeforeCloseDiff
(
{
initializedGetter
:
defaultFormValueGetter
(
formApi
),
currentGetter
:
defaultFormValueGetter
(
formApi
),
},
);
const
[
BasicModal
,
modalApi
]
=
useVbenModal
({
fullscreenButton
:
false
,
onBeforeClose
,
onClosed
:
handleClosed
,
onConfirm
:
onSubmit
,
onOpenChange
:
async
(
isOpen
)
=>
{
if
(
!
isOpen
)
{
return
null
;
}
modalApi
.
modalLoading
(
true
);
const
data
=
modalApi
.
getData
<
StaffingPlanRecordsApi
.
StaffingPlanRecords
>
();
if
(
data
)
{
formData
.
value
=
data
;
await
formApi
.
setValues
(
formData
.
value
);
}
await
markInitialized
();
modalApi
.
modalLoading
(
false
);
},
});
async
function
onSubmit
()
{
const
{
valid
}
=
await
formApi
.
validate
();
if
(
valid
)
{
modalApi
.
lock
();
const
data
=
await
formApi
.
getValues
<
StaffingPlanRecordsApi
.
StaffingPlanRecords
>
();
try
{
await
(
formData
.
value
?.
id
?
apiUpdate
({
id
:
formData
.
value
.
id
,
...
data
})
:
apiAdd
(
data
));
resetInitialized
();
emit
(
'success'
);
modalApi
.
close
();
}
finally
{
modalApi
.
unlock
();
}
}
}
async
function
handleClosed
()
{
await
formApi
.
resetForm
();
resetInitialized
();
}
const
getModalTitle
=
computed
(()
=>
formData
.
value
?.
id
?
'修改编制规划记录'
:
'新增编制规划记录'
,
);
</
script
>
<
template
>
<BasicModal
:title=
"getModalTitle"
>
<BasicForm
class=
"mx-4"
/>
</BasicModal>
</
template
>
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