|
|
@ -0,0 +1,504 @@ |
|
|
|
<template> |
|
|
|
<uv-popup ref="popup" mode="bottom" :round="30" |
|
|
|
:safeAreaInsetBottom="false" @close="handleClose"> |
|
|
|
<view class="job-type-picker"> |
|
|
|
<view class="header"> |
|
|
|
<view class="title">选择工种</view> |
|
|
|
<view class="close-btn" @click="close"> |
|
|
|
<uv-icon name="close" size="40rpx"></uv-icon> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
|
|
|
|
<view class="content"> |
|
|
|
<!-- 左侧一级工种列表 --> |
|
|
|
<view class="left-panel"> |
|
|
|
<scroll-view scroll-y class="scroll-view"> |
|
|
|
<!-- 插槽:自定义内容 --> |
|
|
|
<slot name="custom-options"></slot> |
|
|
|
|
|
|
|
<view |
|
|
|
class="job-type-item" |
|
|
|
:class="{ active: selectedParentType && selectedParentType.id === item.id }" |
|
|
|
v-for="item in jobTypeList" |
|
|
|
:key="item.id" |
|
|
|
@click="selectParentType(item)"> |
|
|
|
{{ item.name }} |
|
|
|
</view> |
|
|
|
</scroll-view> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 右侧二三级工种列表 --> |
|
|
|
<view class="right-panel"> |
|
|
|
<scroll-view scroll-y class="scroll-view"> |
|
|
|
<!-- 二级工种 --> |
|
|
|
<template v-if="selectedParentType && !selectedSubType"> |
|
|
|
<!-- 选择整个工种选项 --> |
|
|
|
<view |
|
|
|
v-if="showSelectWholeType" |
|
|
|
class="job-type-item whole-type-item" |
|
|
|
@click="selectWholeParentType"> |
|
|
|
<uv-icon name="checkmark-circle" size="30rpx" color="#3796F8"></uv-icon> |
|
|
|
选择整个{{ selectedParentType.name }} |
|
|
|
</view> |
|
|
|
|
|
|
|
<view |
|
|
|
class="job-type-item" |
|
|
|
:class="{ |
|
|
|
'selected': multiple && isSubTypeSelected(item), |
|
|
|
'active': !multiple && selectedSubType && selectedSubType.id === item.id |
|
|
|
}" |
|
|
|
v-for="item in subTypeList" |
|
|
|
:key="item.id" |
|
|
|
@click="selectSubType(item)"> |
|
|
|
{{ item.name }} |
|
|
|
<uv-icon v-if="multiple && isSubTypeSelected(item)" |
|
|
|
name="checkmark-circle" size="30rpx" color="#3796F8"></uv-icon> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 多选时的确认按钮 --> |
|
|
|
<view v-if="multiple && selectedSubTypes.length > 0" |
|
|
|
class="confirm-btn" @click="confirmMultipleSubTypeSelection"> |
|
|
|
<button class="confirm-button">确认选择工种 ({{ selectedSubTypes.length }})</button> |
|
|
|
</view> |
|
|
|
</template> |
|
|
|
|
|
|
|
<!-- 三级工种 --> |
|
|
|
<template v-if="selectedSubType"> |
|
|
|
<view |
|
|
|
class="job-type-item back-item" |
|
|
|
@click="backToSubType"> |
|
|
|
<uv-icon name="arrow-left" size="30rpx"></uv-icon> |
|
|
|
返回{{ selectedParentType.name }} |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 选择整个子工种选项 --> |
|
|
|
<view |
|
|
|
v-if="showSelectWholeType" |
|
|
|
class="job-type-item whole-type-item" |
|
|
|
@click="selectWholeSubType"> |
|
|
|
<uv-icon name="checkmark-circle" size="30rpx" color="#3796F8"></uv-icon> |
|
|
|
选择整个{{ selectedSubType.name }} |
|
|
|
</view> |
|
|
|
|
|
|
|
<view |
|
|
|
class="job-type-item" |
|
|
|
:class="{ |
|
|
|
'selected': multiple && isDetailTypeSelected(item), |
|
|
|
'active': !multiple && selectedDetailType && selectedDetailType.id === item.id |
|
|
|
}" |
|
|
|
v-for="item in detailTypeList" |
|
|
|
:key="item.id" |
|
|
|
@click="selectDetailType(item)"> |
|
|
|
{{ item.name }} |
|
|
|
<uv-icon v-if="multiple && isDetailTypeSelected(item)" |
|
|
|
name="checkmark-circle" size="30rpx" color="#3796F8"></uv-icon> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 多选时的确认按钮 --> |
|
|
|
<view v-if="multiple && selectedDetailTypes.length > 0" |
|
|
|
class="confirm-btn" @click="confirmMultipleSelection"> |
|
|
|
<button class="confirm-button">确认选择 ({{ selectedDetailTypes.length }})</button> |
|
|
|
</view> |
|
|
|
</template> |
|
|
|
</scroll-view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</uv-popup> |
|
|
|
</template> |
|
|
|
|
|
|
|
<script> |
|
|
|
import { mapState } from 'vuex' |
|
|
|
|
|
|
|
export default { |
|
|
|
name: 'JobTypePicker', |
|
|
|
props: { |
|
|
|
// 是否只选择到二级工种,不选择三级 |
|
|
|
onlySubType: { |
|
|
|
type: Boolean, |
|
|
|
default: false |
|
|
|
}, |
|
|
|
// 是否支持多选 |
|
|
|
multiple: { |
|
|
|
type: Boolean, |
|
|
|
default: false |
|
|
|
}, |
|
|
|
// 是否显示"选择整个工种"选项 |
|
|
|
showSelectWholeType: { |
|
|
|
type: Boolean, |
|
|
|
default: true |
|
|
|
} |
|
|
|
}, |
|
|
|
data() { |
|
|
|
return { |
|
|
|
selectedParentType: null, // 选中的一级工种 |
|
|
|
selectedSubType: null, // 选中的二级工种 |
|
|
|
selectedDetailType: null, // 选中的三级工种 |
|
|
|
selectedSubTypes: [], // 多选时选中的二级工种列表 |
|
|
|
selectedDetailTypes: [], // 多选时选中的三级工种列表 |
|
|
|
subTypeList: [], // 二级工种列表 |
|
|
|
detailTypeList: [], // 三级工种列表 |
|
|
|
} |
|
|
|
}, |
|
|
|
computed: { |
|
|
|
...mapState(['jobTypeList']) |
|
|
|
}, |
|
|
|
methods: { |
|
|
|
// 打开弹窗 |
|
|
|
open() { |
|
|
|
this.$refs.popup.open() |
|
|
|
}, |
|
|
|
|
|
|
|
// 关闭弹窗 |
|
|
|
close() { |
|
|
|
this.$refs.popup.close() |
|
|
|
}, |
|
|
|
|
|
|
|
// 弹窗关闭时重置状态 |
|
|
|
handleClose() { |
|
|
|
this.selectedParentType = null |
|
|
|
this.selectedSubType = null |
|
|
|
this.selectedDetailType = null |
|
|
|
this.selectedSubTypes = [] |
|
|
|
this.selectedDetailTypes = [] |
|
|
|
this.subTypeList = [] |
|
|
|
this.detailTypeList = [] |
|
|
|
}, |
|
|
|
|
|
|
|
// 选择一级工种 |
|
|
|
async selectParentType(parentType) { |
|
|
|
this.selectedParentType = parentType |
|
|
|
this.selectedSubType = null |
|
|
|
this.selectedDetailType = null |
|
|
|
this.detailTypeList = [] |
|
|
|
|
|
|
|
// 获取二级工种列表 |
|
|
|
try { |
|
|
|
this.subTypeList = await this.$store.dispatch('getChildJobTypeList', parentType.id) |
|
|
|
// 如果没有下级工种,直接确认选择 |
|
|
|
if (this.subTypeList.length === 0) { |
|
|
|
this.confirm() |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error('获取二级工种列表失败:', error) |
|
|
|
this.subTypeList = [] |
|
|
|
// 获取失败时也直接确认 |
|
|
|
this.confirm() |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 选择二级工种 |
|
|
|
async selectSubType(subType) { |
|
|
|
if (this.multiple) { |
|
|
|
// 多选模式 |
|
|
|
const index = this.selectedSubTypes.findIndex(item => item.id === subType.id) |
|
|
|
if (index > -1) { |
|
|
|
// 取消选择 |
|
|
|
this.selectedSubTypes.splice(index, 1) |
|
|
|
} else { |
|
|
|
// 添加选择 |
|
|
|
this.selectedSubTypes.push(subType) |
|
|
|
} |
|
|
|
} else { |
|
|
|
// 单选模式 |
|
|
|
this.selectedSubType = subType |
|
|
|
this.selectedDetailType = null |
|
|
|
|
|
|
|
// 如果只选择到二级工种,直接确认 |
|
|
|
if (this.onlySubType) { |
|
|
|
this.confirm() |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 获取三级工种列表 |
|
|
|
try { |
|
|
|
this.detailTypeList = await this.$store.dispatch('getChildJobTypeList', subType.id) |
|
|
|
// 如果没有下级工种,直接确认 |
|
|
|
if (this.detailTypeList.length === 0) { |
|
|
|
this.confirm() |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error('获取三级工种列表失败:', error) |
|
|
|
this.detailTypeList = [] |
|
|
|
// 获取失败时也直接确认 |
|
|
|
this.confirm() |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 选择三级工种 |
|
|
|
selectDetailType(detailType) { |
|
|
|
if (this.multiple) { |
|
|
|
// 多选模式 |
|
|
|
const index = this.selectedDetailTypes.findIndex(item => item.id === detailType.id) |
|
|
|
if (index > -1) { |
|
|
|
// 取消选择 |
|
|
|
this.selectedDetailTypes.splice(index, 1) |
|
|
|
} else { |
|
|
|
// 添加选择 |
|
|
|
this.selectedDetailTypes.push(detailType) |
|
|
|
} |
|
|
|
} else { |
|
|
|
// 单选模式 |
|
|
|
this.selectedDetailType = detailType |
|
|
|
this.confirm() |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 检查二级工种是否被选中(多选模式) |
|
|
|
isSubTypeSelected(subType) { |
|
|
|
return this.selectedSubTypes.some(item => item.id === subType.id) |
|
|
|
}, |
|
|
|
|
|
|
|
// 检查三级工种是否被选中(多选模式) |
|
|
|
isDetailTypeSelected(detailType) { |
|
|
|
return this.selectedDetailTypes.some(item => item.id === detailType.id) |
|
|
|
}, |
|
|
|
|
|
|
|
// 选择整个一级工种 |
|
|
|
selectWholeParentType() { |
|
|
|
this.selectedSubType = null |
|
|
|
this.selectedSubTypes = [] |
|
|
|
this.selectedDetailType = null |
|
|
|
this.selectedDetailTypes = [] |
|
|
|
this.confirm() |
|
|
|
}, |
|
|
|
|
|
|
|
// 选择整个二级工种 |
|
|
|
selectWholeSubType() { |
|
|
|
this.selectedDetailType = null |
|
|
|
this.selectedDetailTypes = [] |
|
|
|
this.confirm() |
|
|
|
}, |
|
|
|
|
|
|
|
// 确认多选二级工种选择 |
|
|
|
confirmMultipleSubTypeSelection() { |
|
|
|
// 直接返回多选二级工种的数据 |
|
|
|
this.confirm() |
|
|
|
}, |
|
|
|
|
|
|
|
// 确认多选选择 |
|
|
|
confirmMultipleSelection() { |
|
|
|
this.confirm() |
|
|
|
}, |
|
|
|
|
|
|
|
// 返回二级工种选择 |
|
|
|
backToSubType() { |
|
|
|
this.selectedSubType = null |
|
|
|
this.selectedDetailType = null |
|
|
|
this.detailTypeList = [] |
|
|
|
}, |
|
|
|
|
|
|
|
// 确认选择 |
|
|
|
confirm() { |
|
|
|
const result = { |
|
|
|
parentType: this.selectedParentType, |
|
|
|
subType: this.selectedSubType, |
|
|
|
detailType: this.selectedDetailType, |
|
|
|
subTypes: this.selectedSubTypes, |
|
|
|
detailTypes: this.selectedDetailTypes |
|
|
|
} |
|
|
|
|
|
|
|
// 生成完整工种文本 |
|
|
|
let fullJobType = '' |
|
|
|
let selectedId = '' // 用于传给后端的ID |
|
|
|
let selectedIds = [] // 多选时的ID数组 |
|
|
|
|
|
|
|
if (this.selectedParentType) { |
|
|
|
fullJobType += this.selectedParentType.name |
|
|
|
} |
|
|
|
|
|
|
|
// 多选二级工种模式 |
|
|
|
if (this.multiple && this.selectedSubTypes.length > 0) { |
|
|
|
const subTypeNames = this.selectedSubTypes.map(item => item.name).join(',') |
|
|
|
fullJobType = subTypeNames |
|
|
|
result.selectedJobType = this.selectedParentType // 多选二级工种时返回一级工种作为选中工种 |
|
|
|
result.selectedSubTypes = this.selectedSubTypes |
|
|
|
// 返回多选二级工种的ID数组 |
|
|
|
selectedIds = this.selectedSubTypes.map(item => item.id) |
|
|
|
result.selectedIds = selectedIds |
|
|
|
} else if (this.selectedSubType) { |
|
|
|
fullJobType += this.selectedSubType.name |
|
|
|
|
|
|
|
// 多选三级工种模式 |
|
|
|
if (this.multiple && this.selectedDetailTypes.length > 0) { |
|
|
|
const detailTypeNames = this.selectedDetailTypes.map(item => item.name).join(',') |
|
|
|
fullJobType += detailTypeNames |
|
|
|
result.selectedJobType = this.selectedSubType // 多选时返回二级工种作为选中工种 |
|
|
|
result.selectedDetailTypes = this.selectedDetailTypes |
|
|
|
// 返回多选三级工种的ID数组 |
|
|
|
selectedIds = this.selectedDetailTypes.map(item => item.id) |
|
|
|
result.selectedIds = selectedIds |
|
|
|
} else if (this.selectedDetailType) { |
|
|
|
// 单选三级工种模式 |
|
|
|
fullJobType += this.selectedDetailType.name |
|
|
|
result.selectedJobType = this.selectedDetailType |
|
|
|
selectedId = this.selectedDetailType.id |
|
|
|
} else { |
|
|
|
// 选择整个二级工种 |
|
|
|
result.selectedJobType = this.selectedSubType |
|
|
|
selectedId = this.selectedSubType.id |
|
|
|
} |
|
|
|
} else { |
|
|
|
// 选择整个一级工种 |
|
|
|
result.selectedJobType = this.selectedParentType |
|
|
|
selectedId = this.selectedParentType.id |
|
|
|
} |
|
|
|
|
|
|
|
result.fullJobType = fullJobType |
|
|
|
result.selectedId = selectedId // 单选时的ID |
|
|
|
result.selectedIds = selectedIds // 多选时的ID数组 |
|
|
|
|
|
|
|
this.$emit('confirm', result) |
|
|
|
this.close() |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
</script> |
|
|
|
|
|
|
|
<style scoped lang="scss"> |
|
|
|
.job-type-picker { |
|
|
|
height: 70vh; |
|
|
|
background: #fff; |
|
|
|
|
|
|
|
.header { |
|
|
|
display: flex; |
|
|
|
justify-content: space-between; |
|
|
|
align-items: center; |
|
|
|
padding: 30rpx; |
|
|
|
border-bottom: 1px solid #eee; |
|
|
|
|
|
|
|
.title { |
|
|
|
font-size: 32rpx; |
|
|
|
font-weight: bold; |
|
|
|
color: #333; |
|
|
|
} |
|
|
|
|
|
|
|
.close-btn { |
|
|
|
padding: 10rpx; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.content { |
|
|
|
display: flex; |
|
|
|
height: calc(70vh - 160rpx); |
|
|
|
|
|
|
|
.left-panel { |
|
|
|
width: 240rpx; |
|
|
|
border-right: 1px solid #eee; |
|
|
|
background: #f8f8f8; |
|
|
|
} |
|
|
|
|
|
|
|
.right-panel { |
|
|
|
flex: 1; |
|
|
|
} |
|
|
|
|
|
|
|
.scroll-view { |
|
|
|
height: 100%; |
|
|
|
} |
|
|
|
|
|
|
|
.job-type-item { |
|
|
|
padding: 30rpx 20rpx; |
|
|
|
font-size: 28rpx; |
|
|
|
color: #333; |
|
|
|
border-bottom: 1px solid #f0f0f0; |
|
|
|
|
|
|
|
&:last-child { |
|
|
|
border-bottom: none; |
|
|
|
} |
|
|
|
|
|
|
|
&.active { |
|
|
|
background: #fff; |
|
|
|
color: $uni-color; |
|
|
|
font-weight: bold; |
|
|
|
position: relative; |
|
|
|
|
|
|
|
&::after { |
|
|
|
content: ''; |
|
|
|
position: absolute; |
|
|
|
right: 0; |
|
|
|
top: 0; |
|
|
|
bottom: 0; |
|
|
|
width: 6rpx; |
|
|
|
background: $uni-color; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&.back-item { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
color: $uni-color; |
|
|
|
background: #f8f8f8; |
|
|
|
|
|
|
|
uv-icon { |
|
|
|
margin-right: 10rpx; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&.whole-type-item { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
color: #3796F8; |
|
|
|
background: rgba(#3796F8, 0.1); |
|
|
|
font-weight: bold; |
|
|
|
|
|
|
|
uv-icon { |
|
|
|
margin-right: 10rpx; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&.selected { |
|
|
|
background: rgba($uni-color, 0.1); |
|
|
|
color: $uni-color; |
|
|
|
font-weight: bold; |
|
|
|
position: relative; |
|
|
|
|
|
|
|
&::after { |
|
|
|
content: ''; |
|
|
|
position: absolute; |
|
|
|
right: 0; |
|
|
|
top: 0; |
|
|
|
bottom: 0; |
|
|
|
width: 6rpx; |
|
|
|
background: $uni-color; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.left-panel { |
|
|
|
.select-all-item { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
color: #3796F8; |
|
|
|
background: rgba(#3796F8, 0.1); |
|
|
|
font-weight: bold; |
|
|
|
padding: 30rpx 20rpx; |
|
|
|
font-size: 28rpx; |
|
|
|
border-bottom: 1px solid #f0f0f0; |
|
|
|
|
|
|
|
uv-icon { |
|
|
|
margin-right: 10rpx; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.confirm-btn { |
|
|
|
position: sticky; |
|
|
|
bottom: 0; |
|
|
|
background: #fff; |
|
|
|
padding: 20rpx; |
|
|
|
border-top: 1px solid #eee; |
|
|
|
|
|
|
|
.confirm-button { |
|
|
|
width: 100%; |
|
|
|
background: $uni-color; |
|
|
|
color: #fff; |
|
|
|
border: none; |
|
|
|
border-radius: 10rpx; |
|
|
|
padding: 20rpx; |
|
|
|
font-size: 28rpx; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
</style> |