Files
ks-app-employment-service/packageRc/pages/demand/components/trainService.vue
2025-11-03 17:48:14 +08:00

765 lines
20 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!--
* @Date: 2024-10-08 14:29:36
* @LastEditors: shirlwang
* @LastEditTime: 2025-11-03 16:07:22
-->
<template>
<view class="container">
<scroll-view scroll-y="true" :style="{height: edit?'calc(90vh - 150px)':'calc(100vh - 144px)'}">
<view class="inner">
<view class="part-title" style="display: flex;justify-content: space-between;">培训需求信息
<view v-if="!edit&&formData.id&&formData.currentStatus!=3" class="btn"
style="font-weight: normal;display: flex;" @click="edit=true">编辑<view class="icon-right"></view></view>
</view>
<view class="inner-part">
<view class="self-form">
<view class="form-item">
<view class="form-label">姓名 <text class="required">*</text></view>
<view v-if="name" style="width: 100%;"
class="disabledLine">
{{ formData.personName || '请选择' }}
</view>
<view v-else style="width: 100%;" @click="openPersonChooser"
:class="{disabledLine: !edit||!canChoosePerson, noValue: !formData.personName}">
{{ formData.personName || '请选择' }}
</view>
<view class="icon-right"></view>
</view>
<view class="form-item">
<view class="form-label">培训意愿工种 <text class="required">*</text></view>
<picker
mode="multiSelector"
:range="workTypeColumns"
range-key="workTypeName"
:value="workTypeIndexes"
@change="onWorkTypePickerChange"
@columnchange="onWorkTypeColumnChange"
v-if="workTypeColumns[0] && workTypeColumns[0].length"
>
<view class="picker-view">
<view class="picker-view-text">{{ formData.qwpxgzName || '请选择工种' }}</view>
<view class="icon-right"></view>
</view>
</picker>
<view v-else class="picker-view">
<view class="picker-view-text">工种数据加载中...</view>
</view>
</view>
<view class="form-item">
<view class="form-label">期望培训时间 <text class="required">*</text></view>
<picker mode="date" :value="formData.qwpxsj" start="1900-01-01" end="2100-12-31" @change="onDateChange">
<view class="date-picker-wrapper" :class="{ noValue: !formData.qwpxsj }">
<view v-if="formData.qwpxsj" class="date-value">{{ formData.qwpxsj }}</view>
<view v-else>请选择</view>
<view class="icon-right"></view>
</view>
</picker>
</view>
<view class="form-item">
<view class="form-label">需求说明 <text class="required">*</text></view>
<textarea :disabled="!edit" v-model="formData.jobDescription" placeholder="请输入" :class="['form-textarea', { 'form-textarea-disabled': !edit }]"></textarea>
</view>
</view>
</view>
</view>
<!-- 办理完成后 需求说明 -->
<req-comp :form="{
actualSolveDate: formData.actualSolveDate,
actualSolvePeople: formData.actualSolvePeople,
solveDesc: formData.solveDesc,
fileUrl: formData.fileUrl
}" />
</scroll-view>
<view class="button-area" v-if="edit">
<view class="btn" @click="cancelPage">取消</view>
<view class="btn reset" @click="getDetail(formData.id)">重置</view>
<view class="btn save" @click="saveInfo">保存</view>
</view>
</view>
</template>
<script>
import { getPersonBase } from "@/packageRc/api/personinfo/index";
import { addPersonDemand, updatePersonDemand, getPersonDemand } from "@/packageRc/api/needs/personDemand";
import { listJobType } from "@/packageRc/api/jobType/index";
import uniDateformat from '@/uni_modules/uni-dateformat/components/uni-dateformat/uni-dateformat.vue';
export default {
components: {
// ChoosePerson
},
props: {
needId: {
type: String,
default: ''
},
name: {
type: String,
default: ''
}
},
data() {
return {
edit: true,
personBase: {},
formData: {
userId:"",
personName:"",
demandType: "3",
personName: '',
personId: "",
userId: "",
demandTitle: '',
qwpxsj: '',
qwpxgz: '',
qwpxgzName: '',
jobDescription: ''
},
rules: {
personName: [{
required: true,
message: '请填写姓名',
trigger: ['blur', 'change'],
}, ],
qwpxgz: [{
required: true,
message: '请选择培训意愿工种',
trigger: ['blur', 'change'],
validator: (rule, value) => {
// 允许数组且有值,或字符串有值
return (Array.isArray(value) && value.length > 0) || (!!value);
}
}, ],
qwpxsj: [{
required: true,
message: '请选择期望培训时间',
trigger: ['blur', 'change'],
}, ],
},
dict: {},
show: {},
currentCityArr: [],
originalDept: [],
currentCity: '请选择',
bysj: '',
loading: false,
jobTypeList: [],
route: {},
canChoosePerson: false,
workTypeTreeList: [],
searchKeyword: '',
workTypeList: [],
workTypeColumns: [[], [], []],
workTypeIndexes: [0, 0, 0],
}
},
onReady() {
this.$refs.uForm.setRules(this.rules)
},
created() {
this.setName();
this.loading = true;
this.workTypeRemoteMethod('');
},
methods: {
setName() {
// 直接设置人员信息
this.formData.personName = this.name;
this.formData.personId = this.needId;
this.formData.userId = this.needId;
// 设置需求标题
if (this.formData.personName) {
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0');
const day = String(today.getDate()).padStart(2, '0');
const formattedDate = `${year}-${month}-${day}`;
this.formData.demandTitle = `${this.formData.personName}_于${formattedDate}_提出培训需求`;
}
},
cancelPage() {
if (this.formData.id) {
this.edit = false;
this.getDetail(this.formData.id)
} else {
uni.navigateBack()
}
},
openPersonChooser() {
if (this.edit && this.canChoosePerson) {
this.$refs.personChooser.open();
}
},
personNameConfirm(event) {
this.formData.personName = event.name
this.formData.personId = event.id
this.formData.userId = event.userId
this.formNameChange();
this.$forceUpdate();
},
// 使用picker组件的日期选择
onDateChange(e) {
this.formData.qwpxsj = e.detail.value;
},
changeFile(e) {
// 清空当前的 fileUrl 数组
this.formData.fileUrl = [];
// 如果 e 有长度(即用户选择了文件)
if (e.length) {
// 遍历每个文件对象并获取其 url
for (let data of e) {
const url = data.data ? data.data.url : data.url;
this.formData.fileUrl.push(url);
}
}
this.formData.fileUrl = this.$arrayToString(this.formData.fileUrl)
},
addOne() {
this.formData = {}
this.getPersonInfo()
if(this.name){
this.formData.personName = this.name
this.formData.userId = this.needId
}
this.edit = true
},
workTypeRemoteMethod(key) {
listJobType({
workTypeName: key,
pageNum: 1,
pageSize: 50
}).then(
(res) => {
console.log('工种数据加载成功:', res.rows);
this.jobTypeList = res.rows;
// 处理树形数据为级联选择器格式
this.processWorkTypeTree(res.rows);
}
).catch(error => {
console.error('获取工种列表失败:', error);
this.workTypeList = [];
this.workTypeColumns = [[], [], []];
});
},
jobTypeConfirm(type, event) {
this.show[type] = false
this.formData[type] = event.value[0].id
this.formData.qwpxgzName = event.value[0].workTypeName
this.$forceUpdate();
},
getDetail(id) {
getPersonDemand(id).then(res => {
this.formData = res.data;
// 设置工种索引(需要等工种数据加载完成后)
if (this.formData.qwpxgz && this.workTypeColumns[0].length) {
this.setWorkTypeIndexes(this.formData.qwpxgz);
}
this.edit = false;
}).catch(error => {
console.error('Error fetching training detail:', error);
});
},
goBack() {
uni.navigateBack();
},
cancelPicker(type) {
this.$set(this.show, type, false)
this.$forceUpdate()
},
getDictLabel(value, list) {
if (list) {
let arr = list.filter(ele => ele.dictValue == value)
if (arr.length) {
return arr[0].dictLabel
} else {
return '请选择'
}
}
},
pickerConfirm(type, event) {
this.show[type] = false
this.formData[type] = event.value[0].dictValue
this.$forceUpdate();
},
showPicker(type) {
if (this.edit) {
this.show[type] = true
this.$forceUpdate()
}
},
getPersonInfo() {
this.loading = true;
this.$store.dispatch("GetInfo").then((res) => {
if (res.data.roles.indexOf('qunzhong') == -1) {
this.canChoosePerson = true;
this.setName() // 确保非群众角色也能获取姓名
} else {
this.canChoosePerson = false;
getPersonBase(res.data.user.userId).then(resp => {
this.formData.personId = resp.data.id
this.formData.userId = resp.data.userId
this.formData.personName = resp.data.name
this.formNameChange();
this.$forceUpdate();
})
}
})
},
setName() {
this.formData.personName = this.name;
this.formData.personId = this.needId;
this.formData.userId = this.needId;
let date = new Date();
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const dayNew = `${year}-${month}-${day}`;
this.formData.demandTitle = `${this.formData.personName}_于${dayNew}_提出培训需求`;
},
async saveInfo() {
try {
this.setName();
console.log("执行保存,表单数据:", this.formData);
console.log("personName:", this.formData.personName);
console.log("personId:", this.formData.personId);
console.log("userId:", this.formData.userId);
// 手动检查培训意愿工种是否已选择
if (!this.formData.qwpxgz || (typeof this.formData.qwpxgz === 'string' && this.formData.qwpxgz.trim() === '')) {
uni.showToast({
title: '请选择培训意愿工种!',
icon: 'none'
});
return;
}
// 手动检查期望培训时间是否已选择
if (!this.formData.qwpxsj || (typeof this.formData.qwpxsj === 'string' && this.formData.qwpxsj.trim() === '')) {
uni.showToast({
title: '请选择期望培训时间!',
icon: 'none'
});
return;
}
// 表单字段已通过手动检查,无需额外验证
uni.showLoading({
title: '加载中...'
});
let response;
let successMessage;
this.formData.demandType = 3;
if (this.formData.id) {
response = await updatePersonDemand(this.formData);
successMessage = '修改成功';
} else {
response = await addPersonDemand(this.formData);
successMessage = '保存成功';
}
// 检查响应码是否为200
if (response.code === 200) {
uni.showToast({
title: successMessage,
icon: 'success'
});
// 如果是编辑模式,关闭编辑状态;否则返回上一页
if (this.formData.id) {
this.edit = false;
} else {
setTimeout(() => {
uni.navigateBack();
}, 1000);
}
} else {
// 响应码不为200时显示服务器返回的错误信息或默认错误信息
uni.showToast({
title: response.msg || '操作失败,请重试!',
icon: 'none'
});
}
} catch (error) {
console.error('保存失败:', error);
// 检查错误是否为字符串类型或有特定消息
if(typeof error === 'string' || (error && error.message && error.message.includes('请检查'))){
uni.showToast({
title: '请填写完整信息!',
icon: 'none'
});
} else {
uni.showToast({
title: '系统错误,请联系管理员!',
icon: 'none'
});
}
} finally {
// 确保加载页总是会被隐藏
uni.hideLoading();
}
},
// getWorkTypeTree() {
// listJobType({
// workTypeName: '',
// pageNum: 1,
// pageSize: 9999
// }).then(res => {
// console.log("11111",this.workTypeTreeList)
// this.workTypeTreeList = Array.isArray(res.rows) ? res.rows : [];
// });
// },
// 处理树形数据为级联选择器格式
processWorkTypeTree(treeData) {
if (!treeData || !Array.isArray(treeData)) {
this.workTypeColumns = [[], [], []];
return;
}
// 第一级
const level1 = treeData.filter(item => item.level === "1");
// 第二级
const level2 = treeData.filter(item => item.level === "2");
// 第三级
const level3 = treeData.filter(item => item.level === "3");
// 构建级联数据
const columns = [];
columns[0] = level1;
// 根据第一级选择,过滤第二级
if (level1.length > 0) {
const firstLevelId = level1[0].id;
columns[1] = level2.filter(item => item.parentId === firstLevelId);
} else {
columns[1] = [];
}
// 根据第二级选择,过滤第三级
if (columns[1].length > 0) {
const secondLevelId = columns[1][0].id;
columns[2] = level3.filter(item => item.parentId === secondLevelId);
} else {
columns[2] = [];
}
this.workTypeColumns = columns;
console.log('级联数据构建完成:', this.workTypeColumns);
},
// 级联选择器列变化事件
onWorkTypeColumnChange(e) {
const { column, value } = e.detail;
const newIndexes = [...this.workTypeIndexes];
newIndexes[column] = value;
// 重置后续列的数据
if (column === 0) {
// 第一列变化,重置第二、三列
const selectedLevel1 = this.workTypeColumns[0][value];
if (selectedLevel1) {
const level2 = this.jobTypeList.filter(item =>
item.level === "2" && item.parentId === selectedLevel1.id
);
this.workTypeColumns[1] = level2;
this.workTypeColumns[2] = [];
newIndexes[1] = 0;
newIndexes[2] = 0;
}
} else if (column === 1) {
// 第二列变化,重置第三列
const selectedLevel2 = this.workTypeColumns[1][value];
if (selectedLevel2) {
const level3 = this.jobTypeList.filter(item =>
item.level === "3" && item.parentId === selectedLevel2.id
);
this.workTypeColumns[2] = level3;
newIndexes[2] = 0;
}
}
this.workTypeIndexes = newIndexes;
},
// 级联选择器确认事件
onWorkTypePickerChange(e) {
const indexes = e.detail.value;
const selectedLevel1 = this.workTypeColumns[0][indexes[0]];
const selectedLevel2 = this.workTypeColumns[1][indexes[1]];
const selectedLevel3 = this.workTypeColumns[2][indexes[2]];
// 直接赋值确保响应式更新
if (selectedLevel3) {
// 选择第三级
this.formData.qwpxgz = selectedLevel3.id;
this.formData.qwpxgzName = `${selectedLevel1.workTypeName}/${selectedLevel2.workTypeName}/${selectedLevel3.workTypeName}`;
} else if (selectedLevel2) {
// 选择第二级
this.formData.qwpxgz = selectedLevel2.id;
this.formData.qwpxgzName = `${selectedLevel1.workTypeName}/${selectedLevel2.workTypeName}`;
} else if (selectedLevel1) {
// 选择第一级
this.formData.qwpxgz = selectedLevel1.id;
this.formData.qwpxgzName = selectedLevel1.workTypeName;
}
this.workTypeIndexes = indexes;
// 强制重新渲染组件
this.$forceUpdate();
},
// 根据工种ID设置索引
setWorkTypeIndexes(workTypeId) {
// 在工种列表中查找对应的工种
const targetWorkType = this.jobTypeList.find(item => item.id == workTypeId);
if (!targetWorkType) return;
// 根据level确定是哪一级
if (targetWorkType.level === "1") {
const index = this.workTypeColumns[0].findIndex(item => item.id == workTypeId);
if (index !== -1) {
this.workTypeIndexes = [index, 0, 0];
}
} else if (targetWorkType.level === "2") {
// 需要先找到父级
const parent = this.jobTypeList.find(item => item.id == targetWorkType.parentId);
if (parent) {
const parentIndex = this.workTypeColumns[0].findIndex(item => item.id == parent.id);
const childIndex = this.workTypeColumns[1].findIndex(item => item.id == workTypeId);
if (parentIndex !== -1 && childIndex !== -1) {
this.workTypeIndexes = [parentIndex, childIndex, 0];
}
}
} else if (targetWorkType.level === "3") {
// 需要找到祖父级和父级
const parent = this.jobTypeList.find(item => item.id == targetWorkType.parentId);
const grandparent = this.jobTypeList.find(item => item.id == parent.parentId);
if (parent && grandparent) {
const grandparentIndex = this.workTypeColumns[0].findIndex(item => item.id == grandparent.id);
const parentIndex = this.workTypeColumns[1].findIndex(item => item.id == parent.id);
const childIndex = this.workTypeColumns[2].findIndex(item => item.id == workTypeId);
if (grandparentIndex !== -1 && parentIndex !== -1 && childIndex !== -1) {
this.workTypeIndexes = [grandparentIndex, parentIndex, childIndex];
}
}
}
},
}
}
</script>
<style lang="scss">
.inner {
background: #fff;
width: calc(100% - 64rpx);
margin: 0 auto;
box-sizing: border-box;
border-radius: 16rpx;
padding: 32rpx;
margin-bottom: 24rpx;
}
.inner-part {
width: 100%;
}
/* 为表单元素添加一些间距 */
.self-form {
width: 100%;
}
/* 表单项目样式 */
.form-item {
display: flex;
align-items: flex-start;
margin-bottom: 24rpx;
background-color: #fff;
border-radius: 8rpx;
padding: 24rpx 0;
}
.form-label {
width: 200rpx;
font-size: 28rpx;
color: #333;
flex-shrink: 0;
line-height: 48rpx;
}
.required {
color: #f56c6c;
margin-left: 4rpx;
}
.form-input {
flex: 1;
border: none;
outline: none;
font-size: 28rpx;
color: #333;
background: none;
height: 48rpx;
line-height: 48rpx;
}
.form-input-disabled {
color: #909399;
background-color: #f5f7fa;
}
.form-textarea {
flex: 1;
border: none;
outline: none;
font-size: 28rpx;
color: #333;
background: none;
min-height: 120rpx;
line-height: 40rpx;
}
.form-textarea-disabled {
color: #909399;
background-color: #f5f7fa;
}
.icon-right {
width: 40rpx;
height: 40rpx;
display: flex;
align-items: center;
justify-content: center;
color: #A6A6A6;
margin-left: 16rpx;
}
/* 单选框样式 */
.radio-group {
flex: 1;
display: flex;
align-items: center;
}
.radio-item {
display: flex;
align-items: center;
margin-right: 32rpx;
cursor: pointer;
}
.radio-item.radio-disabled {
cursor: not-allowed;
}
.radio {
width: 28rpx;
height: 28rpx;
border-radius: 50%;
border: 2rpx solid #dcdfe6;
margin-right: 12rpx;
position: relative;
}
.radio.radio-checked {
border-color: #409eff;
background-color: #409eff;
}
.radio.radio-checked::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 12rpx;
height: 12rpx;
border-radius: 50%;
background-color: #fff;
}
/* 调整按钮区域样式 */
.button-area {
margin-top: 24rpx;
}
.picker-cover {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 99;
}
.button-area {
padding: 24rpx 32rpx 68rpx;
width: 100%;
background: #fff;
display: flex;
box-sizing: border-box;
margin-top: 40rpx;
border-radius: 16px 16px 0px 0px;
.btn {
line-height: 72rpx;
width: 176rpx;
margin-right: 16rpx;
font-size: 28rpx;
border: 1px solid #B8C5D4;
color: #282828;
text-align: center;
border-radius: 8rpx;
}
.reset {
background: #DCE2E9;
}
.save {
background: linear-gradient(103deg, #1D64CF 0%, #1590D4 99%);
color: #fff;
border: 0;
flex-grow: 1;
}
}
.noValue {
color: rgb(192, 196, 204);
}
.disabledLine {
background: rgb(245, 247, 250);
cursor: not-allowed;
}
.bordered {
border: 1rpx solid #dadbde;
padding: 9px;
border-radius: 4px;
}
.picker-view {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
}
.picker-view-text {
color: #333333;
flex: 1;
text-align: left; font-size: 28rpx;
flex: 1;
}
</style>