|
|
- <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>
|