gz_att_web_wechat/src/pages/temporary-outing/index.vue

791 lines
28 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

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.

<template>
<!-- 轮休申请 -->
<view class="container">
<view class="tabs">
<text class="tab" :class="{ active: activeTab === 'form' }" @tap="switchTab('form')">
外出申请
</text>
<text
class="tab"
:class="{ active: activeTab === 'records' }"
@tap="switchTab('records')"
>
外出记录
</text>
</view>
<view v-if="activeTab === 'form'" class="form-container">
<view>
<text v-if="isFormDisabled" style="color: #3370ff; margin-bottom: 10px">
请确认填写信息是否准确,保存后不可修改;若修改可联系相关工作人员在统计报表核对时修改
</text>
</view>
<view class="form-item">
<text class="label required">申请人</text>
<input
type="text"
v-model="formData.userName"
placeholder="请输入申请人姓名"
disabled
/>
<text v-if="errors.userName" class="error-message">{{ errors.userName }}</text>
</view>
<!-- <view class="form-item">
<text class="label required">职务</text>
<input type="text" placeholder="请输入职务" disabled />
</view>
<view class="form-item">
<text class="label required">所属部门</text>
<input type="text" placeholder="请输入所属部门" disabled />
</view> -->
<view class="form-item">
<text class="label required">外出开始时间</text>
<picker
mode="date"
:value="formData.leaveStartDate"
@change="onStartDateChange"
:disabled="isFormDisabled"
>
<view class="picker-value">{{ formData.leaveStartDate }}</view>
</picker>
<text v-if="errors.leaveStartDate" class="error-message">
{{ errors.leaveStartDate }}
</text>
</view>
<view class="form-item">
<text class="label required">外出开始时间上下午</text>
<!-- 上下午选择 -->
<picker
mode="selector"
:range="['请选择','上午', '下午']"
:value="formData.leaveStartInterval"
@change="onStartAmPmChange"
:disabled="isFormDisabled"
>
<view class="picker-value">{{ ['请选择','上午', '下午'][formData.leaveStartInterval ] }}</view>
</picker>
</view>
<view class="form-item">
<text class="label required">外出结束时间</text>
<picker
mode="date"
:value="formData.leaveEndDate"
@change="onEndDateChange"
:disabled="isFormDisabled"
>
<view class="picker-value">{{ formData.leaveEndDate }}</view>
</picker>
<text v-if="errors.leaveEndDate" class="error-message">
{{ errors.leaveEndDate }}
</text>
</view>
<view class="form-item">
<text class="label required">外出结束时间上下午</text>
<!-- 上下午选择 -->
<picker
mode="selector"
:range="['请选择','上午', '下午']"
:value="formData.leaveEndInterval"
@change="onEndAmPmChange"
:disabled="isFormDisabled"
>
<view class="picker-value">{{ ['请选择','上午', '下午'][formData.leaveEndInterval] }}</view>
</picker>
</view>
<view class="form-item">
<text class="label required">外出时长(天)</text>
<input type="number" v-model="formData.leaveDuration" disabled />
</view>
<view class="form-item">
<text class="label">地点</text>
<input
type="text"
v-model="formData.location"
placeholder="请输入"
:disabled="isFormDisabled"
/>
</view>
<view class="form-item">
<text class="label required" style="width: 300px">是否请示领导同意</text>
<radio-group @change="onAgreerovalChange">
<label class="radio">
<radio
value="1"
:disabled="isFormDisabled"
checked
:checked="formData.isAgree === '1'"
/>
</label>
<label class="radio">
<radio
value="0"
:disabled="isFormDisabled"
:checked="formData.isAgree === '0'"
/>
</label>
</radio-group>
</view>
<view class="form-item">
<text class="label required" style="width: 300px">是否培训</text>
<radio-group @change="onTrainChange">
<label class="radio">
<radio
value="1"
:disabled="isFormDisabled"
checked
:checked="formData.isTrain === '1'"
/>
</label>
<label class="radio">
<radio
value="0"
:disabled="isFormDisabled"
:checked="formData.isTrain === '0'"
/>
</label>
</radio-group>
</view>
<view class="form-item" style="margin-bottom: 20rpx">
<text
class="label required"
style="display: block; margin-bottom: 10rpx; width: 300px"
>
代理主持工作人员
</text>
<view class="selected-values" style="margin-bottom: 10rpx">
{{ hostUserNames }}
</view>
<view
v-if="!isFormDisabled"
class="toggle-button"
@tap="toggleCheckboxGroups"
style="
background-color: #f0f0f0;
width: 55px;
line-height: 35px;
text-align: center;
padding: 10rpx 20rpx;
border-radius: 10rpx;
display: inline-block;
margin-bottom: 10rpx;
"
>
{{ isCheckboxGroupVisibles ? '收起' : '展开' }}
</view>
<view
class="checkbox-group-container"
v-if="!isFormDisabled && isCheckboxGroupVisibles"
>
<checkbox-group
@change="onHostUserChange"
v-if="isCheckboxGroupVisibles"
style="display: flex; flex-wrap: wrap"
>
<view
class="search-container"
style="display: flex; margin-bottom: 10rpx; width: 100%"
>
<input
v-model="searchQuerys"
placeholder="搜索人名"
style="
flex: 1;
padding: 10rpx;
border: 1px solid #ccc;
border-radius: 4px;
height: 30px;
"
/>
<button
@tap="searchPersons"
style="
line-height: 22px;
font-size: 13px;
margin-left: 10rpx;
padding: 10px 20px;
background-color: #007aff;
color: white;
border: none;
border-radius: 4px;
text-align: center;
"
>
搜索
</button>
</view>
<label
v-for="(option, index) in displayedPersonOptionss"
:key="index"
style="width: 33.33%; padding: 10rpx; box-sizing: border-box"
>
<checkbox
:value="option.userId"
:checked="option.checked"
style="transform: scale(0.7)"
/>
<text style="font-size: 28rpx">{{ option.username }}</text>
</label>
</checkbox-group>
</view>
</view>
<view class="form-item">
<text class="label required">外出事由</text>
<textarea
v-model="formData.leaveReason"
placeholder="请输入外出事由"
:disabled="isFormDisabled"
/>
<text v-if="errors.leaveReason" class="error-message">
{{ errors.leaveReason }}
</text>
</view>
<view class="form-item">
<text class="label">备注</text>
<textarea v-model="formData.remark" :disabled="isFormDisabled" />
</view>
<view class="button-group">
<button
class="submit-btn"
@tap="onSubmit"
:disabled="isFormDisabled && !isDataUploaded"
>
{{ isDataUploaded ? '确认提交' : '保存' }}
</button>
<button class="cancel-btn" @tap="onCancel">取消</button>
</view>
</view>
<RecordList v-if="activeTab === 'records'" @onEditData="onEditData" />
</view>
</template>
<script>
import {
addHoliday,
getDays,
getPersonSelect,
editHolidayApi,
getLeaveReporting,
} from '@/api/temporary-outing/index.js'
import RecordList from './recordList.vue'
export default {
components: {
RecordList,
},
data() {
return {
isFormDisabled: false,
isDataUploaded: false,
showConfirmDialog: false,
searchQuerys: '',
activeTab: 'form',
formData: {
userName: '',
leaveType: '临时外出',
leaveStartDate: '',
leaveStartInterval:'',
leaveEndDate: '',
leaveEndInterval:'',
leaveDuration: '',
location: '',
isAgree: '1',
isTrain: '1',
representative: '',
hostUserId: '',
hostUserName: '',
leaveReason: '',
remark: '',
type: '临时外出',
},
userInfo: {
token: '',
userId: '',
name: '',
phone: '',
},
today: new Date().toISOString().substr(0, 10), // 格式化为YYYY-MM-DD
errors: {},
hostUserOptions: [], // 人员选项列表
filteredPersonOptionss: [],
hostUserId: [], // 选中的ID列表
hostUserNames: '', // 显示的选中名字
isCheckboxGroupVisibles: false,
isEdit: false, // 判断是否为编辑状态
daysNumber: "", //时间之间的差
}
},
mounted() {
// 在组件挂载后读取存储的数据
this.userInfo.token = uni.getStorageSync('token') || ''
this.userInfo.userId = uni.getStorageSync('userId') || ''
this.userInfo.name = uni.getStorageSync('username') || ''
this.userInfo.phone = uni.getStorageSync('phone') || ''
this.formData.userName = uni.getStorageSync('username') || ''
},
created() {
this.gethostUserSelect()
},
computed: {
displayedPersonOptionss() {
return this.filteredPersonOptionss.map((person) => ({
...person,
checked: this.hostUserId.includes(person.userId),
}))
},
},
methods: {
toggleCheckboxGroups() {
this.isCheckboxGroupVisibles = !this.isCheckboxGroupVisibles
},
switchTab(tab) {
this.activeTab = tab
},
onStartDateChange(e) {
const startDate = e.detail.value
this.formData.leaveStartDate = startDate
this.validateAndCalculateDuration(startDate, this.formData.leaveEndDate)
},
onStartAmPmChange(e) {
if(e.detail.value ==0){
return;
}
console.log("开始",e.detail.value)
this.formData.leaveStartInterval = e.detail.value;
this.handleDateChanges()
},
onEndDateChange(e) {
const endDate = e.detail.value
this.formData.leaveEndDate = endDate
this.validateAndCalculateDuration(this.formData.leaveStartDate, endDate)
},
onEndAmPmChange(e) {
if(e.detail.value ==0){
return;
}
console.log("结束",e.detail.value)
this.formData.leaveEndInterval = e.detail.value;
this.handleDateChanges()
},
validateAndCalculateDuration(startDate, endDate) {
// 清除之前的错误信息
this.errors.leaveStartDate = ''
this.errors.leaveEndDate = ''
// 转换日期为Date对象
const start = new Date(startDate)
const end = new Date(endDate)
const today = new Date(this.today)
// 验证开始日期不能早于今天
if (start < today) {
this.errors.leaveStartDate = '开始日期不能早于今天'
this.formData.leaveStartDate = ''
return
}
// 验证结束日期不能早于开始日期
if (end < start) {
this.errors.leaveEndDate = '结束日期不能早于开始日期'
this.formData.leaveEndDate = ''
return
}
let dateData = {
startTime: startDate,
endTime: endDate,
}
if (startDate != null && startDate !== '' && endDate != null && endDate !== '') {
getDays(dateData).then((response) => {
if (response.status === 200) {
console.log(response)
// this.formData.leaveDuration = response.data
this.daysNumber = response.data
this.handleDateChanges()
} else {
this.formData.leaveDuration = ''
}
})
}
},
handleDateChanges() {
if (this.formData.leaveStartDate && this.formData.leaveEndDate && this.formData.leaveStartInterval && this.formData.leaveEndInterval ) {
// 比较开始日期和结束日期
const startDate = new Date(this.formData.leaveStartDate);
const endDate = new Date(this.formData.leaveEndDate);
if (startDate > endDate ||
(startDate.getTime() === endDate.getTime() &&
this.formData.leaveStartInterval > this.formData.leaveEndInterval)) {
this.errors.leaveStartDate = '开始时间应该早于结束时间'
this.formData.leaveStartDate = ''
this.formData.leaveEndDate = ''
this.formData.leaveStartInterval = ''
this.formData.leaveEndInterval = ''
return
// 这里可以添加更多的用户提示或者处理逻辑
return;
}
if (startDate.getTime() === endDate.getTime()) { // 同一天
if (this.formData.leaveStartInterval == 1 && this.formData.leaveEndInterval == 2) {
this.formData.leaveDuration = 1; // 上午到下午算作1天
} else {
this.formData.leaveDuration = 0.5; // 其他情况,上/下午到同一天的上/下午,算作半天
}
} else { // 不同天
let totalDays = this.daysNumber;
if (this.formData.leaveStartInterval == 1) totalDays -= 0.5; // 开始当天只算半天
if (this.formData.leaveEndInterval == 1) totalDays -= 0.5; // 结束当天只算半天
this.formData.leaveDuration = totalDays;
}
}
},
onApprovalChange(e) {
this.formData.isApproved = e.detail.value
},
onAgreerovalChange(e){
this.formData.isAgree = e.detail.value
},
onTrainChange(e){
this.formData.isTrain = e.detail.value
},
onRepresentativeChange(e) {
this.formData.representative = e.detail.value
},
validateForm() {
this.errors = {}
if (!this.formData.userName.trim()) {
this.errors.userName = '请输入姓名'
}
if (!this.formData.leaveStartDate) {
this.errors.leaveStartDate = '请选择休假开始时间'
}
if (!this.formData.leaveEndDate) {
this.errors.leaveEndDate = '请选择休假结束时间'
}
if (!this.formData.leaveDuration) {
this.errors.leaveDuration = '请输入休假时长'
}
if (!this.formData.hostUserId) {
this.errors.hostUserId = '请选择代理主持工作人员'
}
// if (!this.formData.leaveReason.trim()) {
// this.errors.leaveReason = '请输入休假事由'
// }
return Object.keys(this.errors).length === 0
},
gethostUserSelect() {
// 假设getPersonSelect是一个API调用函数返回Promise
getPersonSelect().then((response) => {
this.hostUserOptions = response.data
this.filteredPersonOptionss = [...this.hostUserOptions] // 初始化过滤后的选项
console.log('this.hostUserOptions', this.hostUserOptions)
})
},
searchPersons() {
if (this.searchQuerys.trim() === '') {
this.filteredPersonOptionss = [...this.hostUserOptions]
} else {
this.filteredPersonOptionss = this.hostUserOptions.filter((person) =>
person.username.toLowerCase().includes(this.searchQuerys.toLowerCase()),
)
}
// 确保已选中的选项始终显示在过滤结果中
const selectedPersons = this.hostUserOptions.filter((person) =>
this.hostUserId.includes(person.userId),
)
this.filteredPersonOptionss = [
...new Set([...selectedPersons, ...this.filteredPersonOptionss]),
]
},
onHostUserChange(e) {
// 合并新选中的ID和之前已选中的ID
this.hostUserId = [...new Set([...this.hostUserId, ...e.detail.value])]
// 移除取消选中的ID
this.hostUserId = this.hostUserId.filter((id) => e.detail.value.includes(id))
this.formData.hostUserId = this.hostUserId.join(',')
this.updateSelectedNamess()
},
updateSelectedNamess() {
this.hostUserNames = this.hostUserOptions
.filter((person) => this.hostUserId.includes(person.userId))
.map((person) => person.username)
.join(', ')
this.formData.hostUserName = this.hostUserNames
},
onSubmit() {
// 实现表单提交逻辑
if (this.validateForm()) {
if (!this.isDataUploaded) {
this.isFormDisabled = true
console.log('禁用表单元素')
// 在这里可以添加一些视觉反馈,比如改变按钮文字
this.isDataUploaded = true
} else {
console.log('提交表单参数:', this.formData)
// 判断当前是新增还是修改
const SUBMIT_API = this.isEdit ? editHolidayApi : addHoliday
SUBMIT_API(this.formData).then((response) => {
if (response.status == 200) {
uni.showToast({
title: this.isEdit ? '修改成功' : '新增成功',
icon: 'success',
})
this.isEdit = false
// 成功后返回上一级
setTimeout(() => {
uni.navigateBack({
delta: 1, // 返回上一级
})
}, 1500) // 可以根据需要调整这个延迟时间,以便用户可以看到成功的提示信息
} else {
uni.showToast({
title: response.msg,
icon: 'none',
time:'5000'
})
}
// 重置表单状态
this.isFormDisabled = false
this.isDataUploaded = false
})
}
} else {
uni.showToast({
title: '请填写所有必填项',
icon: 'none',
})
}
},
onCancel() {
if (this.isDataUploaded) {
// 如果按钮显示"确认提交",取消禁用并重置状态
this.isFormDisabled = false
this.isDataUploaded = false
// 可能需要重置其他状态,比如:
// this.resetForm(); // 假设你有一个重置表单的方法
} else {
// 否则,返回上一级
uni.navigateBack()
}
},
// 自定义事件子组件修改触发
async onEditData(uuid) {
const res = await getLeaveReporting({ uuid })
if (res.code === 200) {
this.isEdit = true
const {
hostUserId,
hostUserName,
isAgree,
isTrain,
leaveDuration,
leaveEndDate,
leaveStartDate,
leaveStartInterval,
leaveEndInterval,
leaveType,
location,
remark,
type,
userName,
uuid,
leaveReason,
} = res.data
this.hostUserNames = hostUserName
this.hostUserId = hostUserId.split(',')
// this.formData
Object.assign(this.formData, {
hostUserId,
hostUserName,
isAgree,
isTrain,
leaveDuration,
leaveEndDate,
leaveStartDate,
leaveStartInterval,
leaveEndInterval,
leaveType,
location,
remark,
type,
userName,
uuid,
leaveReason,
})
this.activeTab = 'form'
}
},
},
}
</script>
<style>
.container {
padding: 20rpx;
}
.header {
display: flex;
align-items: center;
padding: 20rpx 0;
}
.back-icon {
margin-right: 20rpx;
}
.title {
font-size: 36rpx;
font-weight: bold;
}
.tabs {
display: flex;
border-bottom: 1rpx solid #eee;
background: #fff;
}
.tab {
flex: 1;
text-align: center;
padding: 20rpx 0;
font-size: 32rpx;
color: #333;
position: relative;
}
.tab.active {
color: #007aff;
}
.tab.active::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 120rpx;
height: 4rpx;
background: #007aff;
}
.form-container {
background: #fff;
padding: 20rpx;
border-radius: 12rpx;
}
.form-item {
margin-bottom: 30rpx;
}
.label {
display: block;
margin-bottom: 10rpx;
font-size: 28rpx;
}
.required::after {
content: '*';
color: #ff4d4f;
margin-left: 4rpx;
}
.checkbox-group-container {
max-height: 300px;
overflow-y: auto;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
}
.checkbox-group-container::-webkit-scrollbar {
width: 5px;
}
.checkbox-group-container::-webkit-scrollbar-track {
background: #f1f1f1;
}
.checkbox-group-container::-webkit-scrollbar-thumb {
background: #888;
border-radius: 5px;
}
.checkbox-group-container::-webkit-scrollbar-thumb:hover {
background: #555;
}
input,
.picker-value {
width: 95%;
height: 80rpx;
line-height: 80rpx;
padding: 0 20rpx;
border: 2rpx solid #e5e5e5;
border-radius: 8rpx;
}
textarea {
width: 95%;
height: 160rpx;
padding: 20rpx;
border: 2rpx solid #e5e5e5;
border-radius: 8rpx;
}
.radio {
margin-right: 30rpx;
}
.button-group {
margin-top: 40rpx;
padding: 20rpx;
}
.submit-btn {
background: #4080ff;
color: #fff;
margin-bottom: 20rpx;
}
.cancel-btn {
background: #f5f5f5;
}
.error-message {
color: #ff4d4f;
font-size: 24rpx;
margin-top: 8rpx;
}
</style>