OA/pages/leave_request/index.vue

1012 lines
24 KiB
Vue
Raw Normal View History

2023-11-05 00:11:08 +08:00
<template>
<view class="leave_request">
<view class="leave_box">
<view class="" v-for='(fieldValue, fieldKey) in dataobj' :key="fieldKey">
<!-- {{fieldKey}} -->
<!-- {{ fieldValue.title }} - {{ fieldValue.type }} -->
<view class="leava_type flex_a_c"
v-if="fieldValue.type=='select'&&fieldKey!='copy_uids'&&fieldKey!='check_admin_ids'&&fieldKey!='flow_id'&&fieldKey!='name'">
<view class="title">{{fieldValue.title}}</view>
<!-- {{fieldKey}} -->
<input type="text" v-model="meatelist[fieldKey]" placeholder="请选择" @click="leixin(fieldKey)">
</view>
<view class="leava_type flex_a_c" v-if="fieldKey=='name'&&typeId!=24">
<view class="title">{{fieldValue.title}}</view>
<input type="text" v-model="meatelist[fieldKey]" placeholder="请选择" @click="leixiner()">
</view>
<view class=""
v-if="fieldValue.type=='input'&&fieldKey!='end_time'&&fieldKey!='start_time'&&fieldKey!='duration'">
<view class="cont_cell">
<view class="title">{{fieldValue.title}}</view>
<input type="text" v-model="meatelist[fieldKey]" :placeholder="fieldValue.title">
</view>
</view>
<view class="" v-if=" fieldKey=='start_time'">
<view class="cont_cell">
<view class="title">{{ timeData[0].title }}</view>
<input type="text" v-model="timeData[0].time" placeholder="请选择时间" disabled
@click="selectTime(timeData[0])">
</view>
</view>
<view class="" v-if="fieldKey=='end_time'">
<view class="cont_cell">
<view class="title">{{ timeData[1].title }}</view>
<input type="text" v-model="timeData[1].time" placeholder="请选择时间" disabled
@click="selectTime(timeData[1])">
</view>
</view>
<view class="" v-if="fieldKey=='duration'">
<view class="cont_cell">
<view class="title">{{fieldValue.title}}</view>
<input type="text" v-model="manHour" disabled placeholder="请假工时">
</view>
</view>
<view class="" v-if="fieldValue.type=='textarea'">
<view class="cont_cell">
<view class="title">{{fieldValue.title}}</view>
<input type="text" v-model="meatelist[fieldKey]" :placeholder="fieldValue.title">
</view>
</view>
<view class="" v-if="fieldValue.type=='file'">
<block v-for="(item, i) in fileArray" :key="i">
<view class="file flex_a_c_j_sb">
<view class="l_file">
<view class="file_name">{{ item.name }}</view>
<view class="file_size">{{ item.filesize | formatBytes }}</view>
<view class="upload_people">上传人{{ item.admin_name }}</view>
</view>
<u-icon @click="delImg(i)" name="close-circle" color="#333333" size="28"></u-icon>
</view>
</block>
<!-- <view class="upload_box flex_a_c_j_sb" @click="seleckImage">
<view>
<view class="title">选择文件并上传</view>
<view class="text">
上传前请规范命名最大只能上传100M的文件<br />
超过请压缩成多个文件上传
</view>
</view>
<u-icon name="plus-circle" color="#333333" size="28"></u-icon>
</view> -->
</view>
<!-- <view class="" v-for="(itemValue, itemKey) in fieldValue.item" :key="itemKey">
{{ itemKey }}: {{ itemValue }}
</view> -->
</view>
</view>
<view class="cont_details">
<view class="examine">审批流程</view>
<view class="cont_cell">
<view class="title" >审核状态</view>
{{dataobj1.detail.check_status=='0'?'待审核':dataobj1.detail.check_status=='1'?'审核中':dataobj1.detail.check_status=='2'?'审核通过':dataobj1.detail.check_status=='3'?'审核不通过':'撤销审核'}}
</view>
<view class="cont_cell">
<view class="title">当前审核人</view>
<input type="text" v-model="dataobj1.detail.check_user" disabled placeholder="请假工时">
</view>
<view class="cont_cell">
<view class="title">抄送人</view>
<input type="text" v-model="dataobj1.detail.copy_user" disabled placeholder="请假工时">
</view>
<view class="examine">审批记录</view>
<block v-for="(item,i) in check_record" :key="i">
<view class="record" style="display: flex;">
<view class="circle"></view>
<text class="text">{{item.check_time_str}} {{item.name}} {{item.status_str}}
了此申请操作意见{{item.content}}</text>
</view>
</block>
</view>
<view class="flow_path">
<radio-group class="select_group" @change="deliveryWayChangetwo">
<label class="radio_select" style="margin-right:15rpx;display: flex; margin-bottom: 30rpx;">
<view style="margin-right:5rpx;">
<radio value="1" />
</view>
审核结束
</label>
<label class="radio_select" style="margin-right:15rpx;display: flex;">
<view style="margin-right:5rpx;">
<radio value="2" />
</view>
<view @click="branchShow = true" style="display: flex;">
<view class="title"> 下一位审批人</view>
<input type="text" v-model="check_admin_name" placeholder="请选择" disabled>
</view>
</label>
</radio-group>
<!-- <view class="cont_cell" @click="branchShow1 = true">
<view class="title">抄送人</view>
<input type="text" v-model="copy_names" placeholder="请选择" disabled>
</view> -->
<view class="cont_cell" style="padding-top: 20rpx;">
<view class="title" style="width: 200rpx;">审核意见</view>
<textarea v-model="mscontent" placeholder="请输入审核意见" />
</view>
</view>
<view class="bot_btn">
<view class="reset" @click="appflowcheck()">拒绝</view>
<view class="submit_btn" @click=" appflowcheck1()">通过</view>
</view>
<u-picker :show="branchShow" :defaultIndex='defaultIndex' ref="branchRef" :columns="branchColumns"
@confirm="branchConfirm" @change="columnCode" :closeOnClickOverlay="true" @close="branchShowclose"
keyName="name">
</u-picker>
</view>
</template>
<script>
import {
oaLeaveData
} from '@/static/server/server.js'
import {
oaUploads
} from '../../api/upload'
import {
Toast
} from '../../libs/uniApi'
import {
appfield,
getemployee,
userdepartment,
appapprove,
appapproveview,
appflow_check,
} from '@/api/oa.js'
export default {
data() {
return {
meatelist: {
},
defaultIndex: [0, 0, 0],
defaultIndex1: [0, 0, 0],
defaultIndex2: [0, 0, 0],
dataobj: {},
timestamp: '', // 当前时间
flowPath: '', // 审批流程
flow_id: '', // 审批流程id
check_admin_name: '', // 审核人
check_admin_ids: [],
copy_names: '', // 抄送人
copy_uids: '', // 抄送人id
manHour: '', // 请假工时
daysNum: '', // 请假天数
content: '', // 请假事由
flowPathShow: false,
flowPathSheet: [],
check: "",
mscontent: "",
timeData: [{
title: '开始时间:',
timeShow: false,
timeVal: '', // 时间戳
time: '', // 完整时间
timeDay: '', // 年月日
timeHour: '', // 时分秒
},
{
title: '结束时间:',
timeShow: false,
timeVal: '', // 时间戳
time: '', // 完整时间
timeDay: '', // 年月日
timeHour: '', // 时分秒
}
],
leavaTypeShow: false,
leavaTypeVal: '',
leavaTypeId: '',
leavaTypeId1: '',
leavaTypeId2: '',
columns: [],
// 部门选择 三级级联动
branchShow: false,
branchShow1: false,
branchShow2: false,
branchColumns: [],
branchColumns1: [],
branchColumns2: [],
isflowDate: true,
flowDate: [],
fileArray: [],
typeId: '',
flag1: false,
datatype: '',
dataobj1: {},
check_record: []
}
},
onLoad(option) {
this.typeId = option.type
if (option.type == 8) {
this.timeData[0].title = '借用日期:'
this.timeData[1].title = '拟归还日期:'
}
this.applist(option.type)
this.getDocumentList()
this.getDocumentList2()
},
onShow() {
// this.getFlow()
// 获取当前时间戳
this.timestamp = Date.parse(new Date());
},
watch: {
timeData: {
handler(newVal, oldVal) {
if (newVal[0].time.length > 0 && newVal[1].time.length > 0) {
const {
leaveDays,
leaveHours
} = this.calculateLeaveDaysAndHours(this.timeData[0].time, this.timeData[1]
.time)
this.manHour = leaveHours + '小时'
this.daysNum = leaveDays + '天'
}
},
deep: true
}
},
methods: {
async getDocumentList2() {
this.columns3 = []
const res = await userdepartment({
tree: 1
})
const deArr = res.data
this.columns3.push(deArr)
},
confirm(e) {
console.log(e)
this.flag1 = false
},
async applist(type) {
let res = await appapproveview({
id: type
})
console.log(res.data)
this.dataobj1 = res.data
this.check_record = res.data.check_record
this.applist1(res.data.detail.type)
// this.dataobj = res.data.field
// console.log(this.dataobj)
},
async applist1(type) {
let res = await appfield({
type: type
})
this.dataobj = res.data.field
this.meatelist.name = 'name' in this.dataobj1.detail ? this.dataobj1.detail.name : ''
this.timeData[0].time = 'start_time' in this.dataobj1.detail ? this.dataobj1.detail.start_time : ''
this.timeData[1].time = 'end_time' in this.dataobj1.detail ? this.dataobj1.detail.end_time : ''
this.meatelist.mobile = 'mobile' in this.dataobj1.detail ? this.dataobj1.detail.mobile : ''
this.meatelist.department_type = 'department_type' in this.dataobj1.detail ? this.dataobj1.detail
.department_type_title : ''
this.meatelist.detail_type = 'detail_type' in this.dataobj1.detail ? this.dataobj1.detail
.detail_type_title : ''
this.meatelist.other_type = 'other_type' in this.dataobj1.detail ? this.dataobj1.detail
.other_type_title : ''
this.meatelist.remark = 'remark' in this.dataobj1.detail ? this.dataobj1.detail.remark : ''
this.meatelist.remark1 = 'remark1' in this.dataobj1.detail ? this.dataobj1.detail.remark1 : ''
this.meatelist.address = 'address' in this.dataobj1.detail ? this.dataobj1.detail.address : ''
this.meatelist.detail_time = 'detail_time' in this.dataobj1.detail ? this.dataobj1.detail.detail_time :
''
this.meatelist.content = 'content' in this.dataobj1.detail ? this.dataobj1.detail.content : ''
// this.meatelist.remark1 = 'remark1' in this.dataobj1.detail ? this.dataobj1.detail.remark1 : ''
// this.meatelist.remark1 = 'remark1' in this.dataobj1.detail ? this.dataobj1.detail.remark1 : ''
if ('detail_type' in this.dataobj1.detail) {
const detailTypeOptions = Object.entries(this.dataobj.detail_type.item).map(([id, name]) => ({
id,
name
}));
this.columns = detailTypeOptions
for (let i in this.columns) {
if (this.columns[i].id == this.dataobj1.detail.detail_type) {
this.meatelist.detail_type = this.columns[i].name
}
}
}
},
//获取部门
async getDocumentList() {
const res = await userdepartment()
const deArr = res.data
let codelist = [
[], //顶级部门
[], //次级部门
[] // 负责人
]
codelist[0] = res.data.map((item) => { // 赋值
return {
id: item.id,
name: item.title
}
})
codelist[1] = res.data[0].children.map((item) => { // 赋值
return {
id: item.id,
name: item.title
}
})
let dat = await getemployee({
did: codelist[1][0].id
})
codelist[2] = dat.data.map((item) => {
return {
id: item.id,
name: item.name
}
})
this.$forceUpdate()
this.$nextTick(() => {
this.branchColumns = codelist
this.branchColumns1 = codelist
this.branchColumns2 = codelist
})
},
//监听人员加载数据
async columnCode(e) {
if (e.columnIndex == 1) {
let arr1 = []
let dat = await getemployee({
did: this.branchColumns[e.columnIndex][e.index].id
})
if (dat.data.length > 0) {
const newColumn = dat.data.map((item) => {
return {
id: item.id,
name: item.name
}
})
// 使用 Vue.set 或 this.$set 方法将新数组赋值给 columns3 数组对应位置
this.$set(this.branchColumns, 2, newColumn);
}
}
},
//监听人员加载数据
async columnCode1(e) {
if (e.columnIndex == 1) {
let arr1 = []
let dat = await getemployee({
did: this.branchColumns1[e.columnIndex][e.index].id
})
if (dat.data.length > 0) {
const newColumn = dat.data.map((item) => {
return {
id: item.id,
name: item.name
}
})
// 使用 Vue.set 或 this.$set 方法将新数组赋值给 columns3 数组对应位置
this.$set(this.branchColumns1, 2, newColumn);
}
}
},
async columnCode2(e) {
console.log(e)
if (e.columnIndex == 1) {
let arr1 = []
let dat = await getemployee({
did: this.branchColumns2[e.columnIndex][e.index].id
})
if (dat.data.length > 0) {
const newColumn = dat.data.map((item) => {
return {
id: item.id,
name: item.name
}
})
// 使用 Vue.set 或 this.$set 方法将新数组赋值给 columns3 数组对应位置
this.$set(this.branchColumns2, 2, newColumn);
}
}
},
//选择是否结束
deliveryWayChangetwo(e) {
console.log(e)
this.check = e.detail.value
},
//流程审批
async appflowcheck() {
let data = {
id: this.dataobj1.detail.id,
type: 1,
check_node: this.check,
content: this.mscontent,
check: 2,
check_admin_ids: this.check_admin_ids.toString()
}
let res = await appflow_check(data)
Toast(res.msg)
},
async appflowcheck1() {
let data = {
id: this.dataobj1.detail.id,
type: 1,
check_node: this.check,
check: 1,
content: this.mscontent,
check_admin_ids: this.check_admin_ids.toString()
}
let res = await appflow_check(data)
console.log(res)
Toast(res.msg)
},
leixin(e) {
// console.log(e)
// this.meatelist[e]==1
this.datatype = e
if (e == 'department_type') {
const detailTypeOptions = Object.entries(this.dataobj.department_type.item).map(([id, name]) => ({
id,
name
}));
this.columns = detailTypeOptions
}
if (e == 'detail_type') {
const detailTypeOptions = Object.entries(this.dataobj.detail_type.item).map(([id, name]) => ({
id,
name
}));
this.columns = detailTypeOptions
}
if (e == 'other_type') {
const detailTypeOptions = Object.entries(this.dataobj.other_type.item).map(([id, name]) => ({
id,
name
}));
this.columns = detailTypeOptions
}
// console.log(this.meatelist)
this.leavaTypeShow = true
},
leixiner() {
this.branchShow2 = true
},
branchShowclose() {
this.branchShow = false
},
branchShowclose1() {
this.branchShow1 = false
},
selectTime(item) {
item.timeShow = true
},
async branchHandler(e) {
const {
columnIndex,
value,
values, // values为当前变化列的数组内容
index,
// 微信小程序无法将picker实例传出来只能通过ref操作
picker = this.$refs.branchRef
} = e
// 当第一列值发生变化时,变化第二列(后一列)对应的选项
if (columnIndex === 0) {
// picker为选择器this实例变化第二列对应的选项
let res = await getEmployeeAPI({
did: value[0].id
})
if (res.length < 1) {
res[0] = {
name: '无'
}
}
picker.setColumnValues(1, res)
}
},
// 回调参数为包含columnIndex、value、values
branchConfirm(e) {
console.log('confirm', e, e.value[2].name)
this.check_admin_name = e.value[2].name
this.check_admin_ids.push(e.value[2].id)
this.branchShow = false
},
branchConfirm1(e) {
console.log('confirm', e, e.value[2].name)
this.copy_uids += e.value[2].id
this.copy_names += e.value[2].name + ','
this.branchShow1 = false
},
branchConfirm2(e) {
console.log('confirm', e, e.value[2].name)
this.meatelist.uid = e.value[2].id
this.meatelist.name = e.value[2].name
this.branchShow2 = false
},
/** 请假类型 */
leavaType(e) {
console.log(this.meatelist, this.datatype, e)
if (this.datatype == 'department_type') {
this.meatelist.department_type = e.name
this.leavaTypeId = e.id
} else if (this.datatype == 'detail_type') {
this.meatelist.detail_type = e.name
this.leavaTypeId1 = e.id
} else if (this.datatype == 'other_type') {
this.meatelist.other_type = e.name
this.leavaTypeId2 = e.id
}
console.log(this.leavaTypeId2)
// console.log(this.meatelist,this.datatype, e.name)
// this.meatelist.detail_type = e.name
// // this.leavaTypeVal = e.name
// this.meatelist.department_type = e.name
// this.meatelist.detail_type = e.name
// this.meatelist.other_type = e.name
this.leavaTypeShow = false
},
flowPathSelect(value) {
this.flowPath = value.name
this.flow_id = value.id
},
async getFlow() {
const flow = await getFlowAPI({
type: 1,
flow_cate: 1
})
this.flowPathSheet = flow
},
timeConfirm(e, i) {
this.timeData[i].time = uni.$u.timeFormat(e.value, 'yyyy-mm-dd hh:MM:ss')
this.timeData[i].timeDay = uni.$u.timeFormat(e.value, 'yyyy-mm-dd')
this.timeData[i].timeHour = uni.$u.timeFormat(e.value, 'hh:MM')
this.timeData[i].timeShow = false
},
async submiteBtn() {
console.log(this.leavaTypeId2)
let subData;
let subData1;
if (this.typeId == 6 || this.typeId == 7 || this.typeId == 8) {
let fileIds = [];
this.fileArray.map((item, i) => {
fileIds.push(item.id)
});
subData1 = {
detail_type: this.leavaTypeId,
content: this.meatelist.content,
check_admin_name: this.check_admin_name,
check_admin_ids: this.check_admin_ids,
flow_id: this.flow_id,
file_ids: fileIds.join(','),
copy_names: this.copy_names,
copy_uids: this.copy_uids,
type: this.typeId,
}
if (this.typeId == 8) {
subData1.start_time = this.timeData[0].timeDay + ' ' + this.timeData[0].timeHour,
subData1.end_time = this.timeData[1].timeDay + ' ' + this.timeData[1].timeHour,
subData1.department_type = this.leavaTypeId
subData1.detail_type = this.leavaTypeId1
subData1.other_type = this.leavaTypeId2
}
subData = {
...this.meatelist,
...subData1
}
} else {
let fileIds = [];
this.fileArray.map((item, i) => {
fileIds.push(item.id)
});
subData = {
detail_type: this.leavaTypeId,
start_time: this.timeData[0].timeDay + ' ' + this.timeData[0].timeHour,
end_time: this.timeData[1].timeDay + ' ' + this.timeData[1].timeHour,
duration: this.manHour,
content: this.meatelist.content,
check_admin_name: this.check_admin_name,
check_admin_ids: this.check_admin_ids,
flow_id: this.flow_id,
file_ids: fileIds.join(','),
copy_names: this.copy_names,
copy_uids: this.copy_uids,
type: this.typeId,
file: ''
}
}
console.log(subData)
try {
const res = await appapprove(subData)
Toast('提交成功')
} catch (e) {
Toast('提交失败')
}
},
reset() {
this.flowPath = ''
this.flowDate = []
this.leavaTypeVal = ''
this.leavaTypeId = ''
this.daysNum = ''
this.timeData[0].time = ''
this.timeData[0].time = ''
this.timeData[1].time = ''
this.timeData[1].time = ''
this.manHour = ''
this.content = ''
this.flow_id = ''
this.check_admin_name = ''
this.check_admin_ids = ''
this.copy_names = ''
this.copy_uids = ''
},
/**
* 计算两个时间戳之间相差的小时数
* */
calculateLeaveDaysAndHours(leaveStartTime, leaveEndTime, hoursPerDay = 8) {
const startDate = new Date(leaveStartTime);
const endDate = new Date(leaveEndTime);
// 计算请假天数
const leaveDays = Math.floor((endDate.getTime() - startDate.getTime()) / (24 * 60 * 60 * 1000)) + 1;
// 计算请假总小时数
const leaveHours = leaveDays * hoursPerDay;
// 返回结果
return {
leaveDays,
leaveHours,
};
}
},
filters: {
// 数字转MB
formatBytes(bytes, decimals = 2) {
if (bytes === 0) return '0 MB';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i];
}
},
onPullDownRefresh() {
uni.stopPullDownRefresh()
}
}
</script>
<style lang="scss">
.leave_request {
position: relative;
padding-bottom: 100px;
}
.leave_box,
.flow_path {
width: 100%;
padding: 0 28.07rpx;
background: #fff;
margin-bottom: 35.09rpx;
padding-bottom: 28.07rpx;
}
.bot_btn {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
height: 87.72rpx;
>view {
width: 50%;
text-align: center;
line-height: 87.72rpx;
}
.reset {
background-color: #fff;
}
.submit_btn {
color: #fff;
height: 87.72rpx;
background: $theme-oa-color;
}
}
.leava_type {
height: 100rpx;
border-bottom: 1px solid #999;
.title {
font-size: 31.58rpx;
}
}
.cont_cell {
display: flex;
align-items: center;
width: 100%;
min-height: 87.72rpx;
border-bottom: 1px solid #f7f7f7;
.title {
font-size: 31.58rpx;
}
}
.cont_details {
padding: 24.56rpx 24.56rpx;
font-size: 28.07rpx;
background-color: #fff;
}
// 审批
.examine {
margin-bottom: 17.54rpx;
}
.record {
position: relative;
margin-bottom: 14.04rpx;
.circle {
width: 31.58rpx;
height: 31.58rpx;
background-color: #fff;
border: 2px solid #34A853;
border-radius: 50%;
margin: 5px;
display: flex;
flex-direction: column;
align-items: center;
&::before {
content: "";
display: block;
position: absolute;
clear: both;
width: 1px;
height: 100%;
background-color: rgba(204, 204, 204, 0.5);
margin: 31.58rpx;
}
}
.text {
flex: 1;
margin-left: 7.02rpx;
}
}
.circle {
width: 31.58rpx;
height: 31.58rpx;
background-color: #fff;
border: 2px solid #34A853;
border-radius: 50%;
margin: 0 5px;
display: flex;
flex-direction: column;
align-items: center;
&::before {
content: "";
display: block;
position: absolute;
clear: both;
width: 1px;
height: 100%;
background-color: rgba(204, 204, 204, 0.5);
margin: 31.58rpx;
}
}
:last-child {
.circle {
&::before {
display: none;
}
}
}
// 审批流程
.audit_process {
.process_item {
position: relative;
height: 100%;
margin: 17.54rpx 0;
}
:last-child {
.circle {
&::before {
display: none;
}
}
}
.tag {
font-size: 21.05rpx;
color: #fff;
padding: 0 4px;
margin-left: 10.53rpx;
background-color: #3c9cff;
border-radius: 2px;
}
.verifier {
margin: 17.54rpx 0;
}
}
.circle {
width: 31.58rpx;
height: 31.58rpx;
background-color: #fff;
border: 2px solid #34A853;
border-radius: 50%;
margin: 0 5px;
display: flex;
flex-direction: column;
align-items: center;
&::before {
content: "";
display: block;
position: absolute;
clear: both;
width: 1px;
height: 100%;
background-color: rgba(204, 204, 204, 0.5);
margin: 31.58rpx;
}
}
// 附件
.upload_box {
padding: 17.54rpx;
background-color: #F7F7F7;
border-radius: 4px;
.title {
font-size: 28.07rpx;
}
.text {
margin-top: 7.02rpx;
font-size: 21.05rpx;
color: #999;
}
}
.file_name {
width: 526.32rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.file {
padding: 17.54rpx;
border-radius: 4px;
border: 1px solid #F2F2F2;
margin: 17.54rpx 0;
.file_size {
margin-top: 7.02rpx;
}
.file_size,
.upload_people {
font-size: 21.05rpx;
color: #999;
}
}
</style>