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
535cbc70
Commit
535cbc70
authored
Dec 09, 2025
by
刘斌
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 增加培训,面试,人力成本
parent
3dad53ac
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
2135 additions
and
33 deletions
+2135
-33
interviewProfile.ts
apps/web-antd/src/api/hr/interviewProfile.ts
+139
-0
laborCost.ts
apps/web-antd/src/api/hr/laborCost.ts
+71
-0
training.ts
apps/web-antd/src/api/hr/training.ts
+128
-0
hr.ts
apps/web-antd/src/router/routes/modules/hr.ts
+36
-0
data.ts
apps/web-antd/src/views/hr/changeAnalysis/data.ts
+33
-5
list.vue
apps/web-antd/src/views/hr/changeAnalysis/list.vue
+10
-13
dict-enum.ts
apps/web-antd/src/views/hr/dict-enum.ts
+2
-0
data.ts
apps/web-antd/src/views/hr/employeeInfo/data.ts
+1
-1
data.ts
apps/web-antd/src/views/hr/interviewProfile/data.ts
+178
-0
form.vue
apps/web-antd/src/views/hr/interviewProfile/form.vue
+197
-0
interview-import-modal.vue
.../src/views/hr/interviewProfile/interview-import-modal.vue
+115
-0
list.vue
apps/web-antd/src/views/hr/interviewProfile/list.vue
+166
-0
data.ts
apps/web-antd/src/views/hr/laborCost/data.ts
+74
-0
form.vue
apps/web-antd/src/views/hr/laborCost/form.vue
+126
-0
list.vue
apps/web-antd/src/views/hr/laborCost/list.vue
+145
-0
modal.vue
apps/web-antd/src/views/hr/laborCost/modal.vue
+117
-0
data.ts
apps/web-antd/src/views/hr/phoneBook/data.ts
+7
-7
data.ts
apps/web-antd/src/views/hr/training/data.ts
+132
-0
form.vue
apps/web-antd/src/views/hr/training/form.vue
+164
-0
list.vue
apps/web-antd/src/views/hr/training/list.vue
+166
-0
training-import-modal.vue
.../web-antd/src/views/hr/training/training-import-modal.vue
+112
-0
data.ts
apps/web-antd/src/views/workflow/hrFlow/data.ts
+16
-7
No files found.
apps/web-antd/src/api/hr/interviewProfile.ts
0 → 100644
View file @
535cbc70
import
type
{
BaseModel
,
PageQuery
}
from
'#/api/baseModel'
;
import
{
commonExport
}
from
'#/api/helper'
;
import
{
requestClient
}
from
'#/api/request'
;
export
namespace
InterviewProfileApi
{
export
interface
InterviewProfile
extends
BaseModel
{
/**
* 员工信息ID
*/
employeeId
?:
number
;
/**
* 招揽岗位
*/
jobPosition
?:
string
;
/**
* 姓名
*/
name
?:
string
;
/**
* 性别
*/
gender
?:
string
;
/**
* 身份证号
*/
idCardNumber
?:
number
;
/**
* 学历
*/
education
?:
string
;
/**
* 院校
*/
school
?:
string
;
/**
* 专业
*/
major
?:
string
;
/**
* 联系方式
*/
phoneNumber
?:
string
;
/**
* 标杆企业
*/
benchmarkEnterprise
?:
string
;
/**
* 面试时间
*/
interviewDate
?:
string
;
/**
* 面试情况
*/
interviewSituation
?:
string
;
/**
* 面试结果
*/
interviewResult
?:
string
;
/**
* 备注
*/
remark
?:
string
;
}
}
/**
* 查询面试档案列表
* @param params
* @returns {*} page
*/
export
function
apiPage
(
params
:
PageQuery
)
{
return
requestClient
.
get
(
'/employee/interviewProfile/page'
,
{
params
});
}
/**
* 查询面试档案详细
* @param id
*/
export
function
apiDetail
(
id
:
number
)
{
return
requestClient
.
get
(
`/employee/interviewProfile/
${
id
}
`
);
}
/**
* 新增面试档案
* @param data
*/
export
function
apiAdd
(
data
:
InterviewProfileApi
.
InterviewProfile
)
{
return
requestClient
.
post
(
'/employee/interviewProfile'
,
data
);
}
/**
* 修改面试档案
* @param data
*/
export
function
apiUpdate
(
data
:
InterviewProfileApi
.
InterviewProfile
)
{
return
requestClient
.
put
(
'/employee/interviewProfile'
,
data
);
}
/**
* 删除面试档案
* @param id
*/
export
function
apiDelete
(
id
:
Array
<
number
>
|
number
)
{
return
requestClient
.
delete
(
`/employee/interviewProfile/
${
id
}
`
);
}
/**
* 导出面试档案
* @param params
*/
export
function
apiExport
(
params
:
PageQuery
)
{
return
commonExport
(
'/employee/interviewProfile/export'
,
params
);
}
/**
* 下载用户导入模板
* @returns blob
*/
export
function
downloadImportTemplate
()
{
return
commonExport
(
'/employee/interviewProfile/importTemplate'
,
{});
}
/**
* 从excel导入面试信息
* @param file
* @returns void
*/
export
function
interviewProfileImportData
(
file
:
Blob
)
{
return
requestClient
.
post
<
{
errMessage
:
string
;
success
:
boolean
}
>
(
'/employee/interviewProfile/import'
,
{
file
},
{
headers
:
{
'Content-Type'
:
'multipart/form-data;charset=UTF-8'
,
},
isTransformResponse
:
false
,
responseReturn
:
'body'
,
timeout
:
300
_000
,
},
);
}
apps/web-antd/src/api/hr/laborCost.ts
0 → 100644
View file @
535cbc70
import
type
{
BaseModel
,
PageQuery
}
from
'#/api/baseModel'
;
import
{
commonExport
}
from
'#/api/helper'
;
import
{
requestClient
}
from
'#/api/request'
;
export
namespace
LaborCostApi
{
export
interface
LaborCost
extends
BaseModel
{
/**
* 记录时间
*/
recordDate
?:
string
;
/**
* 文件ID
*/
ossId
?:
number
;
/**
* 文件Key
*/
fileKey
?:
string
;
/**
* 备注
*/
remark
?:
string
;
}
}
/**
* 查询人工成本档案列表
* @param params
* @returns {*} page
*/
export
function
apiPage
(
params
:
PageQuery
)
{
return
requestClient
.
get
(
'/employee/laborCost/page'
,
{
params
});
}
/**
* 查询人工成本档案详细
* @param id
*/
export
function
apiDetail
(
id
:
number
)
{
return
requestClient
.
get
(
`/employee/laborCost/
${
id
}
`
);
}
/**
* 新增人工成本档案
* @param data
*/
export
function
apiAdd
(
data
:
LaborCostApi
.
LaborCost
)
{
return
requestClient
.
post
(
'/employee/laborCost'
,
data
);
}
/**
* 修改人工成本档案
* @param data
*/
export
function
apiUpdate
(
data
:
LaborCostApi
.
LaborCost
)
{
return
requestClient
.
put
(
'/employee/laborCost'
,
data
);
}
/**
* 删除人工成本档案
* @param id
*/
export
function
apiDelete
(
id
:
Array
<
number
>
|
number
)
{
return
requestClient
.
delete
(
`/employee/laborCost/
${
id
}
`
);
}
/**
* 导出人工成本档案
* @param params
*/
export
function
apiExport
(
params
:
PageQuery
)
{
return
commonExport
(
'/employee/laborCost/export'
,
params
);
}
apps/web-antd/src/api/hr/training.ts
0 → 100644
View file @
535cbc70
import
type
{
BaseModel
,
PageQuery
}
from
'#/api/baseModel'
;
import
{
commonExport
}
from
'#/api/helper'
;
import
{
requestClient
}
from
'#/api/request'
;
export
namespace
TrainingApi
{
export
interface
Training
extends
BaseModel
{
/**
* 员工信息ID
*/
employeeId
?:
number
;
/**
* 姓名
*/
name
?:
string
;
/**
* 身份证号
*/
idCardNumber
?:
string
;
/**
* 培训课程
*/
trainingCourse
?:
string
;
/**
* 培训机构
*/
trainingInstitution
?:
string
;
/**
* 培训讲师
*/
trainer
?:
string
;
/**
* 参训时间
*/
trainingTime
?:
string
;
/**
* 服务期
*/
serviceEndDate
?:
string
;
/**
* 服务年限
*/
serviceYears
?:
string
;
/**
* 培训金额
*/
trainingAmount
?:
number
;
/**
* 备注
*/
remark
?:
string
;
}
}
/**
* 查询员工培训档案列表
* @param params
* @returns {*} page
*/
export
function
apiPage
(
params
:
PageQuery
)
{
return
requestClient
.
get
(
'/employee/training/page'
,
{
params
});
}
/**
* 查询员工培训档案详细
* @param id
*/
export
function
apiDetail
(
id
:
number
)
{
return
requestClient
.
get
(
`/employee/training/
${
id
}
`
);
}
/**
* 新增员工培训档案
* @param data
*/
export
function
apiAdd
(
data
:
TrainingApi
.
Training
)
{
return
requestClient
.
post
(
'/employee/training'
,
data
);
}
/**
* 修改员工培训档案
* @param data
*/
export
function
apiUpdate
(
data
:
TrainingApi
.
Training
)
{
return
requestClient
.
put
(
'/employee/training'
,
data
);
}
/**
* 删除员工培训档案
* @param id
*/
export
function
apiDelete
(
id
:
Array
<
number
>
|
number
)
{
return
requestClient
.
delete
(
`/employee/training/
${
id
}
`
);
}
/**
* 导出员工培训档案
* @param params
*/
export
function
apiExport
(
params
:
PageQuery
)
{
return
commonExport
(
'/employee/training/export'
,
params
);
}
/**
* 下载用户导入模板
* @returns blob
*/
export
function
downloadImportTemplate
()
{
return
commonExport
(
'/employee/training/importTemplate'
,
{});
}
/**
* 从excel导入培训信息
* @param file
* @returns void
*/
export
function
trainingImportData
(
file
:
Blob
)
{
return
requestClient
.
post
<
{
errMessage
:
string
;
success
:
boolean
}
>
(
'/employee/training/import'
,
{
file
},
{
headers
:
{
'Content-Type'
:
'multipart/form-data;charset=UTF-8'
,
},
isTransformResponse
:
false
,
responseReturn
:
'body'
,
timeout
:
300
_000
,
},
);
}
apps/web-antd/src/router/routes/modules/hr.ts
View file @
535cbc70
...
...
@@ -85,6 +85,42 @@ const routes: RouteRecordRaw[] = [
componentPath
:
'#/views/hr/changeLog/list.vue'
,
},
},
{
path
:
'/hr/training/list'
,
name
:
'EmployeeTrainingList'
,
component
:
()
=>
import
(
'#/views/hr/training/list.vue'
),
meta
:
{
title
:
'员工培训档案'
,
icon
:
'streamline-plump:contact-phonebook'
,
keepAlive
:
true
,
permission
:
[
'dashboard'
],
componentPath
:
'#/views/hr/training/list.vue'
,
},
},
{
path
:
'/hr/interviewProfile/list'
,
name
:
'InterviewProfileList'
,
component
:
()
=>
import
(
'#/views/hr/interviewProfile/list.vue'
),
meta
:
{
title
:
'面试档案'
,
icon
:
'streamline-plump:contact-phonebook'
,
keepAlive
:
true
,
permission
:
[
'dashboard'
],
componentPath
:
'#/views/hr/interviewProfile/list.vue'
,
},
},
{
path
:
'/hr/laborCost/list'
,
name
:
'EmployeeLaborCostList'
,
component
:
()
=>
import
(
'#/views/hr/laborCost/list.vue'
),
meta
:
{
title
:
'人工成本档案'
,
icon
:
'streamline-plump:contact-phonebook'
,
keepAlive
:
true
,
permission
:
[
'dashboard'
],
componentPath
:
'#/views/hr/laborCost/list.vue'
,
},
},
{
path
:
'/hr/report'
,
name
:
'HrReport'
,
...
...
apps/web-antd/src/views/hr/changeAnalysis/data.ts
View file @
535cbc70
...
...
@@ -163,7 +163,21 @@ export function useColumns(): VxeTableGridOptions<ChangeAnalysisApi.ChangeAnalys
},
{
title
:
'被动离职'
,
field
:
'passiveResignation'
,
headerAlign
:
'center'
,
children
:
[
{
title
:
'试用期内(6个月)'
,
field
:
'passiveProbationPeriod'
,
},
{
title
:
'优化'
,
field
:
'passiveLayoff'
,
},
],
},
{
title
:
'退休'
,
field
:
'retirement'
,
},
{
title
:
'总离职'
,
...
...
@@ -185,22 +199,36 @@ export function useColumns(): VxeTableGridOptions<ChangeAnalysisApi.ChangeAnalys
headerAlign
:
'center'
,
children
:
[
{
title
:
'试用期内
离职率
'
,
title
:
'试用期内
(6个月)
'
,
field
:
'probationResignationRate'
,
},
{
title
:
'入职3年内
离职率
'
,
title
:
'入职3年内'
,
field
:
'within3YearsResignationRate'
,
},
{
title
:
'入职3年以上
离职率
'
,
title
:
'入职3年以上'
,
field
:
'over3YearsResignationRate'
,
},
],
},
{
title
:
'被动离职率'
,
field
:
'passiveResignationRate'
,
headerAlign
:
'center'
,
children
:
[
{
title
:
'试用期内(6个月)'
,
field
:
'passiveProbationPeriodRate'
,
},
{
title
:
'优化'
,
field
:
'passiveLayoffRate'
,
},
],
},
{
title
:
'退休'
,
field
:
'retirementRate'
,
},
{
title
:
'总离职率'
,
...
...
apps/web-antd/src/views/hr/changeAnalysis/list.vue
View file @
535cbc70
...
...
@@ -67,20 +67,17 @@ const [Grid, gridApi] = useVbenVxeGrid({
{
row
:
0
,
col
:
2
,
rowspan
:
3
,
colspan
:
1
},
{
row
:
0
,
col
:
3
,
rowspan
:
3
,
colspan
:
1
},
{
row
:
0
,
col
:
4
,
rowspan
:
2
,
colspan
:
2
},
{
row
:
2
,
col
:
4
,
rowspan
:
1
,
colspan
:
1
},
{
row
:
2
,
col
:
5
,
rowspan
:
1
,
colspan
:
1
},
{
row
:
0
,
col
:
6
,
rowspan
:
1
,
colspan
:
5
},
{
row
:
0
,
col
:
6
,
rowspan
:
1
,
colspan
:
7
},
{
row
:
1
,
col
:
6
,
rowspan
:
1
,
colspan
:
3
},
{
row
:
2
,
col
:
6
,
rowspan
:
1
,
colspan
:
1
},
{
row
:
2
,
col
:
7
,
rowspan
:
1
,
colspan
:
1
},
{
row
:
2
,
col
:
8
,
rowspan
:
1
,
colspan
:
1
},
{
row
:
1
,
col
:
9
,
rowspan
:
2
,
colspan
:
1
},
{
row
:
1
,
col
:
10
,
rowspan
:
2
,
colspan
:
1
},
{
row
:
0
,
col
:
11
,
rowspan
:
3
,
colspan
:
1
},
{
row
:
0
,
col
:
12
,
rowspan
:
1
,
colspan
:
5
},
{
row
:
1
,
col
:
12
,
rowspan
:
1
,
colspan
:
3
},
{
row
:
1
,
col
:
15
,
rowspan
:
2
,
colspan
:
1
},
{
row
:
1
,
col
:
16
,
rowspan
:
2
,
colspan
:
1
},
{
row
:
1
,
col
:
9
,
rowspan
:
1
,
colspan
:
2
},
{
row
:
1
,
col
:
11
,
rowspan
:
2
,
colspan
:
1
},
{
row
:
1
,
col
:
12
,
rowspan
:
2
,
colspan
:
1
},
{
row
:
0
,
col
:
13
,
rowspan
:
3
,
colspan
:
1
},
{
row
:
0
,
col
:
14
,
rowspan
:
1
,
colspan
:
7
},
{
row
:
1
,
col
:
14
,
rowspan
:
1
,
colspan
:
3
},
{
row
:
1
,
col
:
17
,
rowspan
:
1
,
colspan
:
2
},
{
row
:
1
,
col
:
19
,
rowspan
:
2
,
colspan
:
1
},
{
row
:
1
,
col
:
20
,
rowspan
:
2
,
colspan
:
1
},
],
rowConfig
:
{
keyField
:
'plate'
,
...
...
apps/web-antd/src/views/hr/dict-enum.ts
View file @
535cbc70
...
...
@@ -17,6 +17,8 @@ export const HrDictEnum = {
HR_CHANGE_LOG_TYPE
:
'hr_change_log_type'
,
// 员工离职类型
HR_RESIGNATION_CATEGORY
:
'hr_resignation_category'
,
// 员工离职类别
HR_COST_TYPE
:
'hr_cost_type'
,
// 员工成本费用细分
HR_APPLY_TYPE
:
'hr_apply_type'
,
// 员工审批类型
HR_INTERVIEW_RESULT
:
'hr_interview_result'
,
// 员工审批类型
// SYS_JOB_TYPE: 'sys_job_type', // 定时任务类型
// SYS_JOB_STATUS: 'sys_job_status', // 定时任务状态
// SYS_OSS_ACCESS_POLICY: 'oss_access_policy', // oss权限桶类型
...
...
apps/web-antd/src/views/hr/employeeInfo/data.ts
View file @
535cbc70
...
...
@@ -318,7 +318,7 @@ export function useColumns(): VxeTableGridOptions<EmployeeInfoApi.Employee>['col
},
{
title
:
'性别'
,
field
:
'gender'
,
field
:
'gender
Name
'
,
width
:
80
,
},
{
...
...
apps/web-antd/src/views/hr/interviewProfile/data.ts
0 → 100644
View file @
535cbc70
import
type
{
VbenFormSchema
}
from
'#/adapter/form'
;
import
type
{
OnActionClickFn
,
VxeTableGridOptions
}
from
'#/adapter/vxe-table'
;
import
type
{
InterviewProfileApi
}
from
'#/api/hr/interviewProfile'
;
import
{
getDictOptions
,
getTagDicts
}
from
'#/utils/dict'
;
import
{
HrDictEnum
}
from
'../dict-enum'
;
export
const
querySchema
:
VbenFormSchema
[]
=
[
// {
// component: 'Input',
// fieldName: 'employeeId',
// label: '员工信息ID',
// },
{
component
:
'Input'
,
fieldName
:
'jobPosition'
,
label
:
'招揽岗位'
,
},
{
component
:
'Input'
,
fieldName
:
'name'
,
label
:
'姓名'
,
},
// {
// component: 'Input',
// fieldName: 'gender',
// label: '性别',
// },
{
component
:
'Input'
,
fieldName
:
'idCardNumber'
,
label
:
'身份证号'
,
},
{
component
:
'Input'
,
fieldName
:
'education'
,
label
:
'学历'
,
},
{
component
:
'Input'
,
fieldName
:
'school'
,
label
:
'院校'
,
},
{
component
:
'Input'
,
fieldName
:
'major'
,
label
:
'专业'
,
},
{
component
:
'Input'
,
fieldName
:
'phoneNumber'
,
label
:
'联系方式'
,
},
{
component
:
'Input'
,
fieldName
:
'benchmarkEnterprise'
,
label
:
'标杆企业'
,
},
{
component
:
'DatePicker'
,
fieldName
:
'interviewDate'
,
label
:
'面试时间'
,
},
{
component
:
'Input'
,
fieldName
:
'interviewSituation'
,
label
:
'面试情况'
,
},
{
component
:
'Select'
,
componentProps
:
{
options
:
getDictOptions
(
HrDictEnum
.
HR_INTERVIEW_RESULT
),
},
fieldName
:
'interviewResult'
,
label
:
'面试结果'
,
},
];
export
function
useColumns
(
onActionClick
:
OnActionClickFn
<
InterviewProfileApi
.
InterviewProfile
>
,
):
VxeTableGridOptions
<
InterviewProfileApi
.
InterviewProfile
>
[
'columns'
]
{
return
[
// {
// title: '员工信息ID',
// field: 'employeeId',
// },
{
title
:
'招揽岗位'
,
field
:
'jobPosition'
,
},
{
title
:
'姓名'
,
field
:
'name'
,
},
{
title
:
'性别'
,
field
:
'gender'
,
cellRender
:
{
name
:
'CellTag'
,
options
:
[
getTagDicts
(
HrDictEnum
.
HR_USER_SEX
)],
},
},
{
title
:
'身份证号'
,
field
:
'idCardNumber'
,
},
{
title
:
'学历'
,
field
:
'education'
,
},
{
title
:
'标杆企业'
,
field
:
'benchmarkEnterprise'
,
},
{
title
:
'院校'
,
field
:
'school'
,
},
{
title
:
'专业'
,
field
:
'major'
,
},
{
title
:
'联系方式'
,
field
:
'phoneNumber'
,
},
{
title
:
'面试时间'
,
field
:
'interviewDate'
,
formatter
:
'formatDateTime'
,
},
{
title
:
'面试情况'
,
field
:
'interviewSituation'
,
},
{
title
:
'面试结果'
,
field
:
'interviewResult'
,
cellRender
:
{
name
:
'CellTag'
,
options
:
[
getTagDicts
(
HrDictEnum
.
HR_INTERVIEW_RESULT
)],
},
},
// {
// title: '备注',
// field: 'remark',
// },
{
align
:
'right'
,
cellRender
:
{
attrs
:
{
nameField
:
'name'
,
nameTitle
:
'姓名'
,
onClick
:
onActionClick
,
},
name
:
'CellOperation'
,
options
:
[
{
code
:
'edit'
,
accessCode
:
[
'employee:interviewProfile:edit'
],
},
// 默认的编辑按钮
{
code
:
'delete'
,
accessCode
:
[
'employee:interviewProfile:remove'
],
},
// 默认的删除按钮
],
},
field
:
'action'
,
fixed
:
'right'
,
headerAlign
:
'center'
,
resizable
:
false
,
showOverflow
:
false
,
title
:
'操作'
,
width
:
'auto'
,
},
];
}
apps/web-antd/src/views/hr/interviewProfile/form.vue
0 → 100644
View file @
535cbc70
<
script
lang=
"ts"
setup
>
import
type
{
VbenFormSchema
}
from
'#/adapter/form'
;
import
type
{
InterviewProfileApi
}
from
'#/api/hr/interviewProfile'
;
import
{
computed
,
ref
}
from
'vue'
;
import
{
useVbenDrawer
}
from
'@vben/common-ui'
;
import
{
getVxePopupContainer
}
from
'@vben/utils'
;
import
{
useVbenForm
}
from
'#/adapter/form'
;
import
{
apiAdd
,
apiUpdate
}
from
'#/api/hr/interviewProfile'
;
import
{
getDictOptions
}
from
'#/utils/dict'
;
import
{
defaultFormValueGetter
,
useBeforeCloseDiff
}
from
'#/utils/popup'
;
import
{
HrDictEnum
}
from
'../dict-enum'
;
const
emit
=
defineEmits
<
{
success
:
[];
}
>
();
const
isUpdate
=
ref
(
false
);
const
formSchema
:
VbenFormSchema
[]
=
[
{
component
:
'Input'
,
dependencies
:
{
show
:
()
=>
false
,
triggerFields
:
[
''
],
},
fieldName
:
'id'
,
label
:
'id'
,
},
// {
// component: 'Input',
// fieldName: 'employeeId',
// label: '员工信息ID',
// rules: 'required',
// },
{
component
:
'Input'
,
fieldName
:
'jobPosition'
,
label
:
'招揽岗位'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'name'
,
label
:
'姓名'
,
rules
:
'required'
,
},
{
component
:
'RadioGroup'
,
componentProps
:
{
buttonStyle
:
'solid'
,
optionType
:
'button'
,
options
:
getDictOptions
(
HrDictEnum
.
HR_USER_SEX
),
},
defaultValue
:
'1'
,
fieldName
:
'gender'
,
label
:
'性别'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'idCardNumber'
,
label
:
'身份证号'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'education'
,
label
:
'学历'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'benchmarkEnterprise'
,
label
:
'标杆企业'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'school'
,
label
:
'院校'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'major'
,
label
:
'专业'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'phoneNumber'
,
label
:
'联系方式'
,
rules
:
'required'
,
},
{
component
:
'DatePicker'
,
fieldName
:
'interviewDate'
,
label
:
'面试时间'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'interviewSituation'
,
label
:
'面试情况'
,
rules
:
'required'
,
},
{
component
:
'Select'
,
componentProps
:
{
getVxePopupContainer
,
options
:
getDictOptions
(
HrDictEnum
.
HR_INTERVIEW_RESULT
),
},
fieldName
:
'interviewResult'
,
label
:
'面试结果'
,
rules
:
'selectRequired'
,
},
{
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
<
InterviewProfileApi
.
InterviewProfile
>
();
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
<
InterviewProfileApi
.
InterviewProfile
>
();
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/interviewProfile/interview-import-modal.vue
0 → 100644
View file @
535cbc70
<
script
setup
lang=
"ts"
>
import
type
{
UploadFile
}
from
'ant-design-vue/es/upload/interface'
;
import
{
h
,
ref
}
from
'vue'
;
import
{
useVbenModal
}
from
'@vben/common-ui'
;
import
{
ExcelIcon
,
InBoxIcon
}
from
'@vben/icons'
;
import
{
Button
,
Modal
,
Upload
}
from
'ant-design-vue'
;
import
{
downloadImportTemplate
,
interviewProfileImportData
,
}
from
'#/api/hr/interviewProfile'
;
import
{
commonDownloadExcel
}
from
'#/utils/file/download'
;
const
emit
=
defineEmits
<
{
reload
:
[]
}
>
();
const
UploadDragger
=
Upload
.
Dragger
;
const
[
BasicModal
,
modalApi
]
=
useVbenModal
({
onCancel
:
handleCancel
,
onConfirm
:
handleSubmit
,
});
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
interviewProfileImportData
(
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/interviewProfile/list.vue
0 → 100644
View file @
535cbc70
<
script
lang=
"ts"
setup
>
import
type
{
VbenFormProps
}
from
'@vben/common-ui'
;
import
type
{
OnActionClickParams
,
VxeTableGridOptions
,
}
from
'#/adapter/vxe-table'
;
import
type
{
InterviewProfileApi
}
from
'#/api/hr/interviewProfile'
;
import
{
Page
,
useVbenDrawer
,
useVbenModal
}
from
'@vben/common-ui'
;
import
{
Plus
}
from
'@vben/icons'
;
import
{
ExportOutlined
,
UploadOutlined
}
from
'@ant-design/icons-vue'
;
import
{
Button
,
message
,
Space
}
from
'ant-design-vue'
;
import
{
useVbenVxeGrid
}
from
'#/adapter/vxe-table'
;
import
{
apiDelete
,
apiExport
,
apiPage
}
from
'#/api/hr/interviewProfile'
;
import
{
commonDownloadExcel
}
from
'#/utils/file/download'
;
import
{
querySchema
,
useColumns
}
from
'./data'
;
import
Form
from
'./form.vue'
;
import
interviewImportModal
from
'./interview-import-modal.vue'
;
/**
* 导入
*/
const
[
InterviewImportModal
,
interviewImportModalApi
]
=
useVbenModal
({
connectedComponent
:
interviewImportModal
,
});
function
handleImport
()
{
interviewImportModalApi
.
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
(
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
<
InterviewProfileApi
.
InterviewProfile
>
)
{
switch
(
code
)
{
case
'delete'
:
{
onDelete
(
row
);
break
;
}
case
'edit'
:
{
onEdit
(
row
);
break
;
}
default
:
{
break
;
}
}
}
function
onRefresh
()
{
gridApi
.
query
();
}
function
onEdit
(
row
:
InterviewProfileApi
.
InterviewProfile
)
{
formDrawerApi
.
setData
(
row
).
open
();
}
function
onCreate
()
{
formDrawerApi
.
setData
({}).
open
();
}
function
onDelete
(
row
:
InterviewProfileApi
.
InterviewProfile
)
{
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
,
'面试档案'
,
gridApi
.
formApi
.
form
.
values
);
}
</
script
>
<
template
>
<Page
auto-content-height
>
<FormDrawer
@
success=
"onRefresh"
/>
<Grid
table-title=
"面试档案列表"
>
<template
#
toolbar-tools
>
<Space>
<Button
type=
"primary"
ghost
v-access:code=
"['employee:interviewProfile:export']"
@
click
.
stop=
"handleDownloadExcel"
>
<template
#
icon
>
<ExportOutlined
/>
</
template
>
导出
</Button>
<Button
v-access:code=
"['employee:interviewProfile:import']"
@
click=
"handleImport"
>
<
template
#
icon
>
<UploadOutlined
/>
</
template
>
导入
</Button>
<Button
v-access:code=
"['employee:interviewProfile:add']"
type=
"primary"
@
click=
"onCreate"
>
<Plus
class=
"size-5"
/>
新增
</Button>
</Space>
</template>
</Grid>
<InterviewImportModal
@
reload=
"onRefresh"
/>
</Page>
</template>
apps/web-antd/src/views/hr/laborCost/data.ts
0 → 100644
View file @
535cbc70
import
type
{
VbenFormSchema
}
from
'#/adapter/form'
;
import
type
{
OnActionClickFn
,
VxeTableGridOptions
}
from
'#/adapter/vxe-table'
;
import
type
{
LaborCostApi
}
from
'#/api/hr/laborCost'
;
export
const
querySchema
:
VbenFormSchema
[]
=
[
{
component
:
'DatePicker'
,
fieldName
:
'recordDate'
,
label
:
'记录时间'
,
},
// {
// component: 'Input',
// fieldName: 'ossId',
// label: '文件ID',
// },
// {
// component: 'Input',
// fieldName: 'fileKey',
// label: '文件Key',
// },
];
export
function
useColumns
(
onActionClick
:
OnActionClickFn
<
LaborCostApi
.
LaborCost
>
,
):
VxeTableGridOptions
<
LaborCostApi
.
LaborCost
>
[
'columns'
]
{
return
[
{
title
:
'记录时间'
,
field
:
'recordDate'
,
formatter
:
'formatDate'
,
},
// {
// title: '文件ID',
// field: 'ossId',
// },
// {
// title: '文件Key',
// field: 'fileKey',
// },
{
title
:
'备注'
,
field
:
'remark'
,
},
{
align
:
'right'
,
cellRender
:
{
attrs
:
{
nameField
:
'recordDate'
,
nameTitle
:
'人工成本档案'
,
onClick
:
onActionClick
,
},
name
:
'CellOperation'
,
options
:
[
{
code
:
'edit'
,
accessCode
:
[
'employee:laborCost:edit'
],
name
:
'查看'
,
},
// 默认的编辑按钮
{
code
:
'delete'
,
accessCode
:
[
'employee:laborCost:remove'
],
},
// 默认的删除按钮
],
},
field
:
'action'
,
fixed
:
'right'
,
headerAlign
:
'center'
,
resizable
:
false
,
showOverflow
:
false
,
title
:
'操作'
,
width
:
'auto'
,
},
];
}
apps/web-antd/src/views/hr/laborCost/form.vue
0 → 100644
View file @
535cbc70
<
script
lang=
"ts"
setup
>
import
type
{
VbenFormSchema
}
from
'#/adapter/form'
;
import
type
{
LaborCostApi
}
from
'#/api/hr/laborCost'
;
import
{
computed
,
ref
}
from
'vue'
;
import
{
useVbenDrawer
}
from
'@vben/common-ui'
;
import
{
useVbenForm
}
from
'#/adapter/form'
;
import
{
apiAdd
,
apiUpdate
}
from
'#/api/hr/laborCost'
;
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
:
'DatePicker'
,
fieldName
:
'recordDate'
,
label
:
'记录时间'
,
rules
:
'required'
,
},
{
component
:
'FileUpload'
,
componentProps
:
{
maxCount
:
1
,
},
fieldName
:
'ossId'
,
formItemClass
:
'items-start'
,
label
:
'文件'
,
rules
:
'required'
,
},
// {
// component: 'Input',
// fieldName: 'fileKey',
// label: '文件Key',
// rules: 'required',
// },
{
component
:
'Textarea'
,
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
<
LaborCostApi
.
LaborCost
>
();
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
<
LaborCostApi
.
LaborCost
>
();
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/laborCost/list.vue
0 → 100644
View file @
535cbc70
<
script
lang=
"ts"
setup
>
import
type
{
VbenFormProps
}
from
'@vben/common-ui'
;
import
type
{
OnActionClickParams
,
VxeTableGridOptions
,
}
from
'#/adapter/vxe-table'
;
import
type
{
LaborCostApi
}
from
'#/api/hr/laborCost'
;
import
{
Page
,
useVbenDrawer
,
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
,
apiExport
,
apiPage
}
from
'#/api/hr/laborCost'
;
import
{
commonDownloadExcel
}
from
'#/utils/file/download'
;
import
{
querySchema
,
useColumns
}
from
'./data'
;
import
Form
from
'./form.vue'
;
import
previewModal
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
[
PreviewModal
,
previewModalApi
]
=
useVbenModal
({
connectedComponent
:
previewModal
,
});
const
[
FormDrawer
,
formDrawerApi
]
=
useVbenDrawer
({
connectedComponent
:
Form
,
});
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
<
LaborCostApi
.
LaborCost
>
)
{
switch
(
code
)
{
case
'delete'
:
{
onDelete
(
row
);
break
;
}
case
'edit'
:
{
onEdit
(
row
);
break
;
}
default
:
{
break
;
}
}
}
function
onRefresh
()
{
gridApi
.
query
();
}
function
onEdit
(
row
:
LaborCostApi
.
LaborCost
)
{
previewModalApi
.
setData
({
ossId
:
row
.
ossId
}).
open
();
}
function
onCreate
()
{
formDrawerApi
.
setData
({}).
open
();
}
function
onDelete
(
row
:
LaborCostApi
.
LaborCost
)
{
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
();
});
}
function
handleDownloadExcel
()
{
commonDownloadExcel
(
apiExport
,
'人工成本档案'
,
gridApi
.
formApi
.
form
.
values
);
}
</
script
>
<
template
>
<Page
auto-content-height
>
<FormDrawer
@
success=
"onRefresh"
/>
<Grid
table-title=
"人工成本档案列表"
>
<template
#
toolbar-tools
>
<Space>
<Button
v-access:code=
"['employee:laborCost:export']"
@
click=
"handleDownloadExcel"
>
导出
</Button>
<Button
v-access:code=
"['employee:laborCost:add']"
type=
"primary"
@
click=
"onCreate"
>
<Plus
class=
"size-5"
/>
新增
</Button>
</Space>
</
template
>
</Grid>
<PreviewModal
/>
</Page>
</template>
apps/web-antd/src/views/hr/laborCost/modal.vue
0 → 100644
View file @
535cbc70
<
script
lang=
"ts"
setup
>
import
{
ref
}
from
'vue'
;
import
{
useVbenModal
}
from
'@vben/common-ui'
;
import
{
ossInfo
}
from
'#/api/system/oss'
;
import
{
urlToBase64
}
from
'../../../utils/file/base64Conver'
;
// const emit = defineEmits
<
{
// success: [];
// }>();
// const formData = ref
<
LaborCostApi
.
LaborCost
>
();
// const formSchema: VbenFormSchema[] = [
// {
// component: 'DatePicker',
// fieldName: 'recordDate',
// label: '记录时间',
// rules: 'required',
// },
// {
// component: 'Input',
// fieldName: 'ossId',
// label: '文件ID',
// rules: 'required',
// },
// {
// component: 'Input',
// fieldName: 'fileKey',
// label: '文件Key',
// 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
url
=
ref
(
''
);
const
[
BasicModal
,
modalApi
]
=
useVbenModal
({
fullscreenButton
:
true
,
// onClosed: handleClosed,
onConfirm
:
onSubmit
,
onOpenChange
:
async
(
isOpen
)
=>
{
if
(
!
isOpen
)
{
return
null
;
}
modalApi
.
modalLoading
(
true
);
const
{
ossId
}
=
modalApi
.
getData
()
as
{
ossId
:
number
};
if
(
ossId
)
{
const
resp
=
await
ossInfo
(
ossId
);
const
ossData
=
resp
[
0
];
url
.
value
=
`http://172.16.200.110:8012/onlinePreview?url=
${
encodeURIComponent
(
urlToBase64
(
ossData
.
url
))}
`
;
// console.log('[url.value]', url.value);
// formData.value = data;
// await formApi.setValues(formData.value);
}
// await markInitialized();
modalApi
.
modalLoading
(
false
);
},
});
async
function
onSubmit
()
{
modalApi
.
close
();
// const { valid } = await formApi.validate();
// if (valid) {
// modalApi.lock();
// const data = await formApi.getValues
<
LaborCostApi
.
LaborCost
>
();
// 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();
// }
// class="size-full"
</
script
>
<
template
>
<BasicModal
class=
"h-[950px] w-[1100px]"
title=
"文件预览"
>
<iframe
:src=
"url"
class=
"h-[900px] w-full rounded-[6px] border"
></iframe>
</BasicModal>
</
template
>
apps/web-antd/src/views/hr/phoneBook/data.ts
View file @
535cbc70
...
...
@@ -83,7 +83,7 @@ export function useColumns(): VxeTableGridOptions<PhoneBookApi.PhoneBook>['colum
// field: 'deptId',
// },
{
title
:
'
主
岗位'
,
title
:
'岗位'
,
field
:
'position'
,
},
{
...
...
@@ -91,17 +91,17 @@ export function useColumns(): VxeTableGridOptions<PhoneBookApi.PhoneBook>['colum
field
:
'name'
,
},
{
title
:
'手机号码'
,
field
:
'phoneNumber'
,
},
{
title
:
'办公电话'
,
title
:
'电话'
,
field
:
'officePhone'
,
},
{
title
:
'
短
线'
,
title
:
'
内
线'
,
field
:
'shortLine'
,
},
{
title
:
'手机'
,
field
:
'phoneNumber'
,
},
{
title
:
'备注'
,
field
:
'remarks'
,
...
...
apps/web-antd/src/views/hr/training/data.ts
0 → 100644
View file @
535cbc70
import
type
{
VbenFormSchema
}
from
'#/adapter/form'
;
import
type
{
OnActionClickFn
,
VxeTableGridOptions
}
from
'#/adapter/vxe-table'
;
import
type
{
TrainingApi
}
from
'#/api/hr/training'
;
export
const
querySchema
:
VbenFormSchema
[]
=
[
// {
// component: 'Input',
// fieldName: 'employeeId',
// label: '员工信息ID',
// },
{
component
:
'Input'
,
fieldName
:
'name'
,
label
:
'姓名'
,
},
{
component
:
'Input'
,
fieldName
:
'trainingCourse'
,
label
:
'培训课程'
,
},
{
component
:
'Input'
,
fieldName
:
'trainingInstitution'
,
label
:
'培训机构'
,
},
{
component
:
'Input'
,
fieldName
:
'trainer'
,
label
:
'培训讲师'
,
},
{
component
:
'DatePicker'
,
fieldName
:
'trainingTime'
,
label
:
'参训时间'
,
},
{
component
:
'DatePicker'
,
fieldName
:
'serviceEndDate'
,
label
:
'服务期'
,
},
{
component
:
'Input'
,
fieldName
:
'serviceYears'
,
label
:
'服务年限'
,
},
{
component
:
'Input'
,
fieldName
:
'trainingAmount'
,
label
:
'培训金额'
,
},
];
export
function
useColumns
(
onActionClick
:
OnActionClickFn
<
TrainingApi
.
Training
>
,
):
VxeTableGridOptions
<
TrainingApi
.
Training
>
[
'columns'
]
{
return
[
// {
// title: '员工信息ID',
// field: 'employeeId',
// },
{
title
:
'姓名'
,
field
:
'name'
,
},
{
title
:
'身份证号'
,
field
:
'idCardNumber'
,
},
{
title
:
'培训课程'
,
field
:
'trainingCourse'
,
},
{
title
:
'培训机构'
,
field
:
'trainingInstitution'
,
},
{
title
:
'培训讲师'
,
field
:
'trainer'
,
},
{
title
:
'参训时间'
,
field
:
'trainingTime'
,
formatter
:
'formatDate'
,
},
{
title
:
'服务期'
,
field
:
'serviceEndDate'
,
formatter
:
'formatDate'
,
},
{
title
:
'服务年限'
,
field
:
'serviceYears'
,
},
{
title
:
'培训金额'
,
field
:
'trainingAmount'
,
},
{
title
:
'备注'
,
field
:
'remark'
,
},
{
align
:
'right'
,
cellRender
:
{
attrs
:
{
nameField
:
'name'
,
nameTitle
:
'员工培训档案'
,
onClick
:
onActionClick
,
},
name
:
'CellOperation'
,
options
:
[
{
code
:
'edit'
,
accessCode
:
[
'employee:training:edit'
],
},
// 默认的编辑按钮
{
code
:
'delete'
,
accessCode
:
[
'employee:training:remove'
],
},
// 默认的删除按钮
],
},
field
:
'action'
,
fixed
:
'right'
,
headerAlign
:
'center'
,
resizable
:
false
,
showOverflow
:
false
,
title
:
'操作'
,
width
:
'auto'
,
},
];
}
apps/web-antd/src/views/hr/training/form.vue
0 → 100644
View file @
535cbc70
<
script
lang=
"ts"
setup
>
import
type
{
VbenFormSchema
}
from
'#/adapter/form'
;
import
type
{
TrainingApi
}
from
'#/api/hr/training'
;
import
{
computed
,
ref
}
from
'vue'
;
import
{
useVbenDrawer
}
from
'@vben/common-ui'
;
import
{
useVbenForm
}
from
'#/adapter/form'
;
import
{
apiAdd
,
apiUpdate
}
from
'#/api/hr/training'
;
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: 'employeeId',
// label: '员工信息ID',
// rules: 'required',
// },
{
component
:
'Input'
,
fieldName
:
'name'
,
label
:
'姓名'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'idCardNumber'
,
label
:
'身份证号'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'trainingCourse'
,
label
:
'培训课程'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'trainingInstitution'
,
label
:
'培训机构'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'trainer'
,
label
:
'培训讲师'
,
// rules: 'required',
},
{
component
:
'DatePicker'
,
fieldName
:
'trainingTime'
,
label
:
'参训时间'
,
rules
:
'required'
,
},
{
component
:
'DatePicker'
,
fieldName
:
'serviceEndDate'
,
label
:
'服务期'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'serviceYears'
,
label
:
'服务年限'
,
rules
:
'required'
,
},
{
component
:
'Input'
,
fieldName
:
'trainingAmount'
,
label
:
'培训金额'
,
rules
:
'required'
,
},
{
component
:
'Textarea'
,
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
<
TrainingApi
.
Training
>
();
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
<
TrainingApi
.
Training
>
();
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/training/list.vue
0 → 100644
View file @
535cbc70
<
script
lang=
"ts"
setup
>
import
type
{
VbenFormProps
}
from
'@vben/common-ui'
;
import
type
{
OnActionClickParams
,
VxeTableGridOptions
,
}
from
'#/adapter/vxe-table'
;
import
type
{
TrainingApi
}
from
'#/api/hr/training'
;
import
{
Page
,
useVbenDrawer
,
useVbenModal
}
from
'@vben/common-ui'
;
import
{
Plus
}
from
'@vben/icons'
;
import
{
ExportOutlined
,
UploadOutlined
}
from
'@ant-design/icons-vue'
;
import
{
Button
,
message
,
Space
}
from
'ant-design-vue'
;
import
{
useVbenVxeGrid
}
from
'#/adapter/vxe-table'
;
import
{
apiDelete
,
apiExport
,
apiPage
}
from
'#/api/hr/training'
;
import
{
commonDownloadExcel
}
from
'#/utils/file/download'
;
import
{
querySchema
,
useColumns
}
from
'./data'
;
import
Form
from
'./form.vue'
;
import
trainingImportModal
from
'./training-import-modal.vue'
;
/**
* 导入
*/
const
[
TrainingImportModal
,
trainingImportModalApi
]
=
useVbenModal
({
connectedComponent
:
trainingImportModal
,
});
function
handleImport
()
{
trainingImportModalApi
.
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
(
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
<
TrainingApi
.
Training
>
)
{
switch
(
code
)
{
case
'delete'
:
{
onDelete
(
row
);
break
;
}
case
'edit'
:
{
onEdit
(
row
);
break
;
}
default
:
{
break
;
}
}
}
function
onRefresh
()
{
gridApi
.
query
();
}
function
onEdit
(
row
:
TrainingApi
.
Training
)
{
formDrawerApi
.
setData
(
row
).
open
();
}
function
onCreate
()
{
formDrawerApi
.
setData
({}).
open
();
}
function
onDelete
(
row
:
TrainingApi
.
Training
)
{
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
,
'员工培训档案'
,
gridApi
.
formApi
.
form
.
values
);
}
</
script
>
<
template
>
<Page
auto-content-height
>
<FormDrawer
@
success=
"onRefresh"
/>
<Grid
table-title=
"员工培训档案列表"
>
<template
#
toolbar-tools
>
<Space>
<Button
type=
"primary"
ghost
v-access:code=
"['employee:training:export']"
@
click
.
stop=
"handleDownloadExcel"
>
<template
#
icon
>
<ExportOutlined
/>
</
template
>
导出
</Button>
<Button
v-access:code=
"['employee:training:import']"
@
click=
"handleImport"
>
<
template
#
icon
>
<UploadOutlined
/>
</
template
>
导入
</Button>
<Button
v-access:code=
"['employee:training:add']"
type=
"primary"
@
click=
"onCreate"
>
<Plus
class=
"size-5"
/>
新增
</Button>
</Space>
</template>
</Grid>
<TrainingImportModal
@
reload=
"onRefresh"
/>
</Page>
</template>
apps/web-antd/src/views/hr/training/training-import-modal.vue
0 → 100644
View file @
535cbc70
<
script
setup
lang=
"ts"
>
import
type
{
UploadFile
}
from
'ant-design-vue/es/upload/interface'
;
import
{
h
,
ref
}
from
'vue'
;
import
{
useVbenModal
}
from
'@vben/common-ui'
;
import
{
ExcelIcon
,
InBoxIcon
}
from
'@vben/icons'
;
import
{
Button
,
Modal
,
Upload
}
from
'ant-design-vue'
;
import
{
downloadImportTemplate
,
trainingImportData
}
from
'#/api/hr/training'
;
import
{
commonDownloadExcel
}
from
'#/utils/file/download'
;
const
emit
=
defineEmits
<
{
reload
:
[]
}
>
();
const
UploadDragger
=
Upload
.
Dragger
;
const
[
BasicModal
,
modalApi
]
=
useVbenModal
({
onCancel
:
handleCancel
,
onConfirm
:
handleSubmit
,
});
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
trainingImportData
(
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/workflow/hrFlow/data.ts
View file @
535cbc70
...
...
@@ -4,7 +4,9 @@ import type { EmployeeFlowApi } from '#/api/hr/employeeFlow';
import
{
DictEnum
}
from
'@vben/constants'
;
import
{
getTagDicts
}
from
'#/utils/dict'
;
import
{
getDictOptions
,
getTagDicts
}
from
'#/utils/dict'
;
import
{
HrDictEnum
}
from
'../../hr/dict-enum'
;
export
const
flowTypeOptions
=
[
{
label
:
'入职'
,
value
:
'1'
},
...
...
@@ -24,7 +26,7 @@ export const querySchema: VbenFormSchema[] = [
{
component
:
'Select'
,
componentProps
:
{
options
:
flowTypeOptions
,
options
:
getDictOptions
(
HrDictEnum
.
HR_APPLY_TYPE
)
,
},
fieldName
:
'flowType'
,
label
:
'审批类型'
,
...
...
@@ -51,12 +53,19 @@ export function useColumns(): VxeTableGridOptions<EmployeeFlowApi.EmployeeFlow>[
{
title
:
'审批类型'
,
field
:
'flowType'
,
cellRender
:
{
name
:
'CellTag'
,
options
:
flowTypeOptions
},
cellRender
:
{
name
:
'CellTag'
,
options
:
[
getTagDicts
(
HrDictEnum
.
HR_APPLY_TYPE
)],
},
},
{
title
:
'员工姓名'
,
field
:
'name'
,
},
{
title
:
'员工部门'
,
field
:
'deptName'
,
},
// {
// title: '员工信息ID',
// field: 'employeeId',
// },
// {
// title: '开始时间',
// field: 'startDate',
...
...
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