Browse Source

出差申请

sunlupeng 1 năm trước cách đây
mục cha
commit
227ba9549e

+ 96 - 0
api/oa/business.js

@@ -0,0 +1,96 @@
+import request from '@/utils/request'
+
+
+// 创建流程
+export function create(data) {
+  return request({
+    url: '/bpm/oa-business/commit',
+    method: 'post',
+    data: data
+  })
+}
+//驳回或撤回后再次提交通用用事项审批流程信息
+export function reCommit(data) {
+  return request({
+    url: '/bpm/oa-business/reCommit',
+    method: 'post',
+    data: data
+  })
+}
+// 暂存数据保存
+export function save(data) {
+  return request({
+    url: '/bpm/oa-business/staging',
+    method: 'post',
+    data: data
+  })
+}
+// 暂存数据删除
+export function deleteById(id) {
+  return request({
+    url: '/bpm/oa-business/delete?id=' + id,
+    method: 'delete'
+  })
+}
+
+// 关闭审批流程信息
+export function closeById(id) {
+  return request({
+    url: '/bpm/oa-business/close?id=' + id,
+    method: 'delete'
+  })
+}
+
+// 获得详情
+export function getDetail(id) {
+  return request({
+    url: '/bpm/oa-business/get?id=' + id,
+    method: 'get'
+  })
+}
+
+// 获得列表
+export function getListData(query) {
+  return request({
+    url: '/bpm/oa-business/page',
+    method: 'get',
+    params: query
+  })
+}
+// 导出列表
+export function exportList(query) {
+  return request({
+    url: '/bpm/oa-business/export-excel',
+    method: 'get',
+    params: query,
+    responseType: 'blob'
+  })
+}
+
+//审批同意通用事项审批流程信息
+export function agree(data) {
+  return request({
+    url: '/bpm/oa-business/agree',
+    method: 'post',
+    data: data
+  })
+}
+
+//驳回通用事项审批流程信息
+export function disagree(data) {
+  return request({
+    url: '/bpm/oa-business/disagree',
+    method: 'post',
+    data: data
+  })
+}
+
+//撤回通用事项审批流程信息
+export function revocation(data) {
+  return request({
+    url: '/bpm/oa-business/revocation',
+    method: 'post',
+    data: data
+  })
+}
+

+ 1 - 1
api/oa/leave.js

@@ -27,7 +27,7 @@ export function save(data) {
 // 暂存数据删除
 export function deleteById(id) {
   return request({
-    url: 'bpm/oa-leave/delete?id=' + id,
+    url: '/bpm/oa-leave/delete?id=' + id,
     method: 'delete'
   })
 }

+ 5 - 0
pages.json

@@ -101,6 +101,11 @@
     "style": {
       "navigationBarTitleText": "请假申请"
     }
+  },{
+    "path": "pages/oa/business/index",
+    "style": {
+      "navigationBarTitleText": "出差申请"
+    }
   },{
 			"path": "pages/popleSelect/choose",
 			"style": {

+ 97 - 0
pages/oa/business/dataList.vue

@@ -0,0 +1,97 @@
+<template>
+	<view class='my-unit' @click="childClick">
+		<view class="unit-head">
+			<text style="font-weight: bold;font-size: 26upx;">{{ info.oaType }}</text>
+			<text style="color: gray;font-size: 20upx;">{{ parseTime(info.time) }}</text>
+		</view>
+		<view class="unit-body">
+			<text class="uni-ellipsis-1">出差人:{{ info.title }}</text>
+			<text class="uni-ellipsis-1">出差目的地:{{ info.remarks }}</text>
+		</view>
+		<view class="unit-foot">
+			<text>{{ info.status }}</text>
+			<text style="color: orange;">{{ info.nickname }}</text>
+		</view>
+	</view>
+
+</template>
+
+<script>
+export default {
+	props: {
+		info: {
+			type: Object
+		},
+		initIndex: {
+			type: Number
+		}
+	},
+	data() {
+		return {}
+	},
+	methods: {
+		childClick(){
+			this.$emit('faClick', this.info)
+		}
+	},
+	computed: {
+
+	},
+	created() {
+
+	},
+}
+</script>
+<style lang='scss'>
+.my-unit {
+	margin: 20upx 10upx;
+	background-color: #ffffff;
+	font-size: 28upx;
+	transform: all 1s;
+	border-radius: 10upx;
+	box-shadow: rgba(0, 0, 0, 0.08) 0px 0px 3;
+
+	.unit-head {
+		font-size: 26upx;
+		padding: 20upx 20upx 10upx 20upx;
+		display: flex;
+		flex-wrap: wrap;
+		justify-content: space-between;
+		align-items: center;
+	}
+
+	.unit-body {
+		padding: 0 20upx;
+		color: gray;
+		display: flex;
+		flex-direction: column;
+		font-size: 22upx;
+		line-height: 30upx;
+	}
+
+	.unit-foot {
+		font-size: 24upx;
+		height: 66upx;
+		padding: 0 20upx;
+		// border-top: 2upx solid #f5f5f5;
+		border-bottom: none;
+		line-height: 66upx;
+		display: flex;
+		flex-wrap: wrap;
+		justify-content: space-between;
+		align-items: center;
+		font-weight: bold;
+	}
+}
+.uni-ellipsis-1 {
+		/* #ifndef APP-NVUE */
+		overflow: hidden;
+		white-space: nowrap;
+		text-overflow: ellipsis;
+		/* #endif */
+		/* #ifdef APP-NVUE */
+		lines: 1;
+		text-overflow:ellipsis;
+		/* #endif */
+	}
+</style>

+ 357 - 0
pages/oa/business/detail.vue

@@ -0,0 +1,357 @@
+<template>
+	<view class="container">
+		<uni-forms ref="form" :model="form" labelWidth="120px" :label-position="alignment">
+			<uni-forms-item label="出差人">
+				<uni-easyinput v-model="form.employeeName" disabled />
+			</uni-forms-item>
+			<uni-forms-item label="部门">
+				<uni-easyinput v-model="form.deptName" disabled />
+			</uni-forms-item>
+			<uni-forms-item label="职位">
+				<uni-easyinput v-model="form.position" disabled />
+			</uni-forms-item>
+			<uni-forms-item label="手机号">
+				<uni-easyinput v-model="form.employeePhone" disabled />
+			</uni-forms-item>
+			<uni-forms-item label="出差地点">
+				<uni-easyinput v-model="form.destination" disabled />
+			</uni-forms-item>
+			<uni-forms-item label="出差开始日期">
+				<uni-easyinput v-model="form.startDate" disabled />
+			</uni-forms-item>
+			<uni-forms-item label="出差结束日期">
+				<uni-easyinput v-model="form.endDate" disabled />
+			</uni-forms-item>
+			<uni-forms-item label="请假天数">
+				<uni-easyinput v-model="form.day" disabled />
+			</uni-forms-item>
+			<uni-forms-item label="预估费用(元)">
+				<uni-easyinput v-model="form.estimatedCost" disabled />
+			</uni-forms-item>
+			<uni-forms-item label="出差事由">
+				<uni-easyinput autoHeight type="textarea" v-model="form.reason" disabled />
+			</uni-forms-item>
+			<uni-forms-item label="附件">
+				<view class="upload-wrap">
+					<view class="mgb-16 file-wrap" v-for="(item, index) in form.fileList" :key="index">
+					  <view class="btn-click file-line" @click="handlePreview(item)">
+					    <view class="file-info">
+					      <image :src="icons.file" mode="aspectFill" class="file-icon" />
+					      <text class="file-name">{{ item.name || title[type] }}</text>
+					    </view>
+					  </view>
+					</view>
+				</view>
+			</uni-forms-item>
+			<uni-forms-item label="备注">
+				<uni-easyinput autoHeight type="textarea" v-model="form.remarks" disabled />
+			</uni-forms-item>
+			<uni-forms-item label="审批意见" required v-if="(form.auditStatus==2 || form.auditStatus==1) && name=='0'">
+				<uni-easyinput autoHeight maxlength="200" type="textarea" v-model="reason" placeholder="请输入审批建议" />
+			</uni-forms-item>
+			<uni-forms-item label="流程动态">
+				<uni-steps active-icon="medal" :options="tasks" active-color="#007AFF" :active="tasks.length" direction="column" />
+			</uni-forms-item>
+		</uni-forms>
+		<view class="button-group" v-if="name=='0'">
+			<button type="primary" size="mini" @click="handleAudit(true)">同意</button>
+			<button size="mini" @click="handleAudit(false)">驳回</button>
+		</view>
+		<view class="button-group" v-if="name=='2'">
+			<button type="warning" size="mini" @click="handleRevocation('form')">撤回</button>
+		</view>
+	</view>
+</template>
+
+<script>
+	import { getDetail,revocation,agree,disagree } from "@/api/oa/business.js"
+	export default {
+		props: {
+		    id: {
+		      type: [String, Number],
+		      default: undefined
+		    },
+		    name: {
+		      type: String,
+		      default: undefined
+		    },
+		  },
+		data() {
+			return {
+				reason:'',
+				active: -1,
+				tasks: [],
+				alignment:'top',
+				fileList: [],
+				icons: {
+				  file: '/static/icon_file.png',
+				},
+				// 表单数据
+				form: {},
+			}
+		},
+		watch: {
+		    id: {
+		      immediate: true,
+		      handler(val) {
+		        this.getDetail(val);
+		      }
+		    }
+		  },
+		methods: {
+			  /** 获得详情信息 */
+			    getDetail(val) {
+			      getDetail(val).then(response => {
+					let gender = response.data.gender==1?'男':'女';
+			        this.form = response.data;
+					this.form.gender = gender;
+			        let auditRecordList = response.data.auditRecordList;
+					let tasks = [];
+					auditRecordList.forEach(v => {
+						tasks.push({
+							title:'任务:' + v.assigneeUser.nickname + v.name,
+							desc:this.parseTime(v.endTime),
+						})
+					})
+					this.tasks = tasks;
+			      });
+			    },
+			// 预览
+			handlePreview(val) {
+			  console.log('PreviewFile', val);
+			  const fileType = this.getFileType(val.name);
+			  if (fileType === 'image') {
+			   uni.previewImage({
+			     current: 0,
+			     urls: [val.url],
+			   });
+			  }
+			  else if (fileType === 'office') {
+				  return uni.downloadFile({
+				    url: val.url, 
+				    success: function (res) {
+				      let filePath = res.filePath || res.tempFilePath;
+				      uni.openDocument({
+				        filePath: filePath,
+				        showMenu: true,
+				        success: function (res) {
+				          console.log('打开文档成功');
+				        }
+				      });
+				    }
+				  });
+			  }
+			  else{
+				  uni.showModal({
+				    title: '该类型文件无法预览',
+				    content: val.name,
+				    showCancel: false,
+				  });
+			  }
+			  
+			},
+			handleRevocation(){
+			      console.log(this.form.taskId);
+				  let that = this
+				  uni.showModal({
+				          title: '提示',
+				          content: '是否确认撤回?',
+				          success: function (res) {
+				            if (res.confirm) {
+				              console.log('用户点击确定');
+				              revocation({id:that.form.taskId}).then(response => {
+				               uni.showToast({
+				               	title: "撤回成功!"
+				               })
+				              })
+				            } else if (res.cancel) {
+				              console.log('用户点击取消');
+				            }
+				          }
+				        });
+			    },
+			    handleAudit(pass) {
+			      if (!this.reason) {
+					uni.showModal({
+						title: "提示",
+						content: "请填写审批意见",
+						showCancel: false,
+						confirmText: "确定"
+					})
+			        return;
+			      } else {
+			        const data = {
+			          id: this.form.taskId,
+			          reason: this.reason,
+			        }
+			        if (pass) {
+			          agree(data).then(response => {
+						  uni.showToast({
+						  	title: "审批通过成功!"
+						  })
+						  this.$emit('popupClose');
+			          });
+			        } else {
+			          disagree(data).then(response => {
+						  uni.showToast({
+						  	title: "驳回成功!"
+						  })
+						  this.$emit('popupClose');
+			          });
+			        }
+			      }
+			    },
+			
+			
+		}
+	}
+</script>
+
+<style lang="scss">
+	.container {
+		padding: 15px;
+		background-color: #fff;
+	}
+
+	.segmented-control {
+		margin-bottom: 15px;
+	}
+
+	.button-group {
+		margin-top: 15px;
+		display: flex;
+	}
+
+	.form-item {
+		display: flex;
+		align-items: center;
+		flex: 1;
+	}
+
+	.button {
+		display: flex;
+		align-items: center;
+		height: 35px;
+		line-height: 35px;
+		margin-left: 10px;
+	}
+</style>
+<style lang="scss" scoped>
+	.user-avatar {
+	  width: 22px;
+	  height: 22px;
+	  line-height: 19px;
+	  font-size: 12px;
+	  background: #46c26f;
+	  border: 1px solid transparent;
+	  border-radius: 5px;
+	  color: #fff;
+	  display: inline-block;
+	  overflow: hidden;
+	  text-align: center;
+	  line-height: 22px;
+	  margin-bottom: 2px;
+	}
+	.popup-body{
+		z-index: 99;
+		height: 450px;
+		overflow-x: auto;
+		// margin-bottom: 60px;
+	}
+	.popup-close{
+		cursor: pointer;
+		height: 40px;
+		line-height: 40px;
+		padding-left: 10px;
+		border-bottom: 1px solid #eaecef;
+	}
+	.popup-content{
+		margin: 20px;
+	}
+.btn-click {
+  transition: all 0.3s;
+  opacity: 1;
+}
+
+.btn-click:active {
+  opacity: 0.5;
+}
+
+.mgb-16 {
+  margin-bottom: 16rpx;
+
+  &:last-child {
+    margin-bottom: 0;
+  }
+}
+
+.upload-wrap {
+  width: 100%;
+  border-radius: 16rpx;
+  background: white;
+  // padding: 32rpx;
+
+  .upload-btn {
+    width: 100%;
+    height: 176rpx;
+    border: 2rpx dashed #AAAAAA;
+    background: #FAFAFA;
+    border-radius: 16rpx;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    flex-direction: column;
+
+    .upload-icon {
+      width: 48rpx;
+      height: 48rpx;
+      margin-bottom: 8rpx;
+    }
+
+    .upload-text {
+      font-size: 26rpx;
+      color: #9E9E9E;
+      line-height: 40rpx;
+    }
+  }
+
+  .file-wrap {
+    .file-line {
+      width: 100%;
+      background: #F5F5F5;
+      border-radius: 8rpx;
+      padding: 16rpx;
+      font-size: 26rpx;
+      color: #1A1A1A;
+      line-height: 40rpx;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+
+      .file-info {
+        width: 90%;
+        display: flex;
+        align-items: center;
+
+        .file-name {
+          max-width: 80%;
+          padding-left: 16rpx;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          white-space: nowrap;
+        }
+      }
+
+      .file-icon {
+        width: 40rpx;
+        height: 40rpx;
+        flex-shrink: 0;
+      }
+
+      .file-empty {
+        color: #999999;
+      }
+    }
+  }
+}
+</style>

+ 735 - 0
pages/oa/business/edit.vue

@@ -0,0 +1,735 @@
+<template>
+	<view class="container">
+		<uni-forms ref="form" :rules="rules" :model="form" labelWidth="120px" :label-position="alignment">
+			<uni-forms-item label="出差人" required name="employeeName">
+				<uni-easyinput v-model="form.employeeName" placeholder="点击选择" :clearable="false"
+					@click.native="gotochooseUser('single')" />
+			</uni-forms-item>
+			<uni-forms-item label="部门">
+				<uni-easyinput v-model="form.deptName" disabled />
+			</uni-forms-item>
+			<uni-forms-item label="职位">
+				<uni-easyinput v-model="form.position" disabled />
+			</uni-forms-item>
+			<uni-forms-item label="手机号">
+				<uni-easyinput v-model="form.employeePhone" disabled />
+			</uni-forms-item>
+			<uni-forms-item label="出差地点" required name="destination">
+				<uni-easyinput maxlength="20" v-model="form.destination" placeholder="请输入出差地点" />
+			</uni-forms-item>
+			<uni-forms-item label="出差开始日期" required name="startDate">
+				<uni-datetime-picker type="date" v-model="form.startDate" @change="upDayStart"/>
+			</uni-forms-item>
+			<uni-forms-item label="出差结束日期" required name="endDate">
+				<uni-datetime-picker type="date" v-model="form.endDate" @change="upDayEnd"/>
+			</uni-forms-item>
+			<uni-forms-item label="请假天数" required name="day">
+				<uni-easyinput v-model="form.day" placeholder="请输入" />
+			</uni-forms-item>
+			<uni-forms-item label="预估费用(元)" required name="estimatedCost">
+				<uni-easyinput v-model="form.estimatedCost" placeholder="请输入" />
+			</uni-forms-item>
+			<uni-forms-item label="出差事由" required name="reason">
+				<uni-easyinput maxlength="200" type="textarea" v-model="form.reason" placeholder="出差的主要目的或需要完成的任务" />
+			</uni-forms-item>
+			<uni-forms-item label="附件">
+				<view class="upload-wrap">
+					<button type="primary" size="mini" @click="handleUploadClick">点击上传</button>
+					<xe-upload ref="XeUpload" :options="uploadOptions" @callback="handleUploadCallback"></xe-upload>
+					<view class="mgb-16 file-wrap" v-for="(item, index) in fileList" :key="index">
+						<view class="btn-click file-line" @click="handlePreview(item)">
+							<view class="file-info">
+								<image :src="icons.file" mode="aspectFill" class="file-icon" />
+								<text class="file-name">{{ item.name || title[type] }}</text>
+							</view>
+							<image :src="icons.close" mode="aspectFill" class="file-icon"
+								@click.stop="handleDeleteFile(index)" />
+						</view>
+					</view>
+				</view>
+
+			</uni-forms-item>
+			<uni-forms-item label="备注">
+				<uni-easyinput maxlength="200" type="textarea" v-model="form.remarks" placeholder="请输入备注" />
+			</uni-forms-item>
+			<uni-forms-item label="审批人" required name="peopleList">
+				<uni-easyinput v-model="form.peopleList" style="display: none;" />
+				<view style="display: flex;justify-content: flex-start;align-items: center;">
+					<uni-icons type="folder-add" size="40" @click="gotochooseUser('multiple')"></uni-icons>
+					<view style="display: flex;justify-content: flex-start;align-items: center;"
+						v-for="(tag, index) in nikeNamelist" :key="index">
+						<uni-icons type="right" size="20"></uni-icons>
+						<view style="display: flex;flex-direction: column;justify-content: center;align-items: center;"
+							@click="handleClose(index)">
+							<span class="user-avatar">{{ tag.substring(0, 1) || 'U' }}</span>
+							<text style="font-size: 12px;">{{ tag }}</text>
+						</view>
+
+					</view>
+				</view>
+			</uni-forms-item>
+			<uni-forms-item label="流程动态" v-if="tasks.length > 0">
+				<uni-steps active-icon="medal" :options="tasks" active-color="#007AFF" :active="tasks.length"
+					direction="column" />
+			</uni-forms-item>
+		</uni-forms>
+		<view class="button-group" v-if="name == '0'">
+			<button type="default" size="mini" @click="onReCommit('form')">提交</button>
+			<button type="primary" size="mini" @click="onClose()">关闭</button>
+		</view>
+		<view class="button-group" v-else>
+			<button type="primary" size="mini" @click="submit('form')">提交</button>
+			<button type="default" size="mini" @click="onSave()">暂存</button>
+			<button type="warn" size="mini" @click="onDelete()" v-if="form.auditStatus == 0">删除</button>
+		</view>
+
+		<view>
+			<!-- 普通弹窗 -->
+			<uni-popup ref="popup" background-color="#fff" border-radius="10px 10px 0 0">
+				<view class="popup-body">
+					<view class="popup-close">
+						<uni-icons type="closeempty" size="20" @click="popupClose"></uni-icons>
+					</view>
+					<view class="popup-content">
+						<pople-Select :type="popleSelectType" @submit="submitPeople" ref="popleSelect"></pople-Select>
+					</view>
+				</view>
+
+			</uni-popup>
+		</view>
+	</view>
+</template>
+
+<script>
+import {
+	getDetail,
+	create,
+	save,
+	deleteById,
+	closeById,
+	reCommit
+} from "@/api/oa/business.js"
+import { getDicts, getOpenDicts, listSimplePosts, listSimpleDepts } from "@/api/system/dict.js";
+import {
+	uploadFile,
+	getEmployeeInfo
+} from "@/api/system/user"
+import popleSelect from '../../popleSelect/choose.vue'
+export default {
+	components: {
+		popleSelect
+	},
+	props: {
+		id: {
+			type: [String, Number],
+			default: undefined
+		},
+		name: {
+			type: String,
+			default: undefined
+		},
+	},
+	data() {
+		return {
+			popleSelectType: 'single',
+			deptOptions: [],
+			postOptions: [],
+			employeeTypeListOpen: [],
+			userSexList: [],
+			tasks: [],
+			alignment: 'top',
+			uploadOptions: {},
+			fileList: [],
+			icons: {
+				close: '/static/icon_close.png',
+				file: '/static/icon_file.png',
+			},
+			nikeNamelist: [],
+			// 表单数据
+			form: {
+				employeeName: undefined,
+				employeeId: undefined,
+				deptName: undefined,
+				position: undefined,
+				employeePhone: undefined,
+				destination: undefined,
+				startDate: undefined,
+				endDate: undefined,
+				day: undefined,
+				estimatedCost: undefined,
+				reason: undefined,
+				fileIdList: undefined,
+				remarks: undefined,
+				peopleList: '',
+			},
+			// 校验规则
+			rules: {
+				employeeName: {
+					rules: [{
+						required: true,
+						errorMessage: '请选择'
+					},]
+				},
+				destination: {
+					rules: [{
+						required: true,
+						errorMessage: '请输入'
+					}]
+				},
+				startDate: {
+					rules: [{
+						required: true,
+						errorMessage: '请选择'
+					},]
+				},
+				endDate: {
+					rules: [{
+						required: true,
+						errorMessage: '请选择'
+					},]
+				},
+				day: {
+					rules: [{
+						required: true,
+						errorMessage: '请输入'
+					}, {
+						validateFunction: function (rule, value, data, callback) {
+							// ^(([1-9]{1}\d*)|(0{1}))(\.\d{0,2})?$就表示了小数点后可以保留0位、1位、或2位小数。
+							let reg = /^(([1-9]{1}\d*)|(0{1}))(\.\d{0,1})?$/ //保留0位、1位
+							if (!reg.test(value)) {
+								callback("请输入正确天数")
+							}
+							return true
+						}
+					}]
+				},
+				estimatedCost: {
+					rules: [
+						{
+							required: true,
+							errorMessage: '请输入'
+						},
+						{
+							validateFunction: function (rule, value, data, callback) {
+								// ^(([1-9]{1}\d*)|(0{1}))(\.\d{0,2})?$就表示了小数点后可以保留0位、1位、或2位小数。
+								let reg = /^(([1-9]{1}\d*)|(0{1}))(\.\d{0,2})?$/ //保留0位、1位
+								if (!reg.test(value)) {
+									callback("请输入正确金额")
+								}
+								return true
+							}
+						}
+					]
+				},
+				reason: {
+					rules: [{
+						required: true,
+						errorMessage: '请输入'
+					},]
+				},
+				peopleList: {
+					rules: [{
+						required: true,
+						errorMessage: '请选择审批人'
+					},]
+				},
+			},
+		}
+	},
+	watch: {
+		id: {
+			immediate: true,
+			handler(val) {
+				this.getInfoDataList();
+				if (val) {
+					this.getDetail(val);
+				}
+			}
+		}
+	},
+	methods: {
+		upDayStart(e) {
+			this.form.startDate = e;
+			if (this.form.startDate && this.form.endDate) {
+				let Days = this.calLeaveDays();
+				this.form.day = Days;
+				console.log(this.form.day);
+				if (Days <= 0) {
+					this.form.startDate = "";
+					this.form.endDate = "";
+					this.form.day = "";
+					this.$modal.showToast('起始日期小于结束日期,请重新选择!')
+					return;
+				}
+			}
+
+		},
+		upDayEnd(e) {
+			this.form.endDate = e;
+			if (this.form.startDate && this.form.endDate) {
+				let Days = this.calLeaveDays();
+				this.form.day = Days;
+				console.log(this.form.day);
+				if (Days <= 0) {
+					this.form.startDate = "";
+					this.form.endDate = "";
+					this.form.day = "";
+					this.$modal.showToast('起始日期小于结束日期,请重新选择!')
+					return;
+				}
+			}
+
+		},
+		calLeaveDays() {
+			var start_date = new Date();
+			var end_date = new Date();
+			start_date = new Date(this.form.startDate + " 00:00:00");
+			end_date = new Date(this.form.endDate + " 24:00:00");
+			console.log(start_date);
+			console.log(end_date);
+			//转成毫秒数,两个日期相减
+			var days = end_date.getTime() - start_date.getTime();
+			//转换成天数
+			var day = days / (1000 * 60 * 60 * 24);
+			console.log("day = ", day);
+			return day;
+		},
+		/** 查询部门列表 */
+		getInfoDataList() {
+			listSimpleDepts().then(response => {
+				response.data.forEach(v => {
+					this.deptOptions.push({
+						text: v.name,
+						value: v.id,
+					})
+				})
+			});
+			getDicts('system_user_sex').then(response => {
+				response.data.forEach(v => {
+					this.userSexList.push({
+						text: v.label,
+						value: v.value,
+					})
+				})
+			});
+			getOpenDicts('tenant_employee_type').then(response => {
+				response.data.forEach(v => {
+					this.employeeTypeListOpen.push({
+						text: v.label,
+						value: v.value,
+					})
+				})
+			});
+			listSimplePosts().then(response => {
+				response.data.forEach(v => {
+					this.postOptions.push({
+						text: v.name,
+						value: v.id,
+					})
+				})
+			});
+		},
+		/** 获得详情信息 */
+		getDetail(val) {
+			getDetail(val).then(response => {
+				this.form = response.data;
+				console.log(this.form);
+				this.fileList = response.data.fileList ? response.data.fileList : [];
+				let auditUserList = response.data.auditUserList;
+				if (auditUserList) {
+					let peopleList = [];
+					let nikeNamelist = [];
+					auditUserList.map(item => {
+						peopleList.push(item.id);
+						nikeNamelist.push(item.nickname)
+					});
+					this.$set(this.form, 'peopleList', peopleList.join(','));
+					this.nikeNamelist = nikeNamelist;
+				} else {
+					this.$set(this.form, 'peopleList', '');
+					this.nikeNamelist = [];
+				}
+				let auditRecordList = response.data.auditRecordList;
+				if (auditRecordList) {
+					let tasks = [];
+					auditRecordList.forEach(v => {
+						tasks.push({
+							title: '任务:' + v.assigneeUser.nickname + v.name,
+							desc: this.parseTime(v.endTime),
+						})
+					})
+					this.tasks = tasks;
+				}
+			});
+		},
+		// 关闭标签
+		handleClose(index) {
+			this.nikeNamelist.splice(index, 1);
+			let peopleList = this.form.peopleList.split(',');
+			peopleList.splice(index, 1);
+			this.form.peopleList = peopleList.join(',');
+		},
+		getEmployee() {
+			getEmployeeInfo(this.form.employeeId).then(response => {
+				let employeeInfo = response.data;
+				this.form.deptName = employeeInfo.deptName;
+				this.form.position = employeeInfo.position;
+				this.form.employeePhone = employeeInfo.phone;
+				this.form.oldContractStartDate = employeeInfo.oldContractStartDate;
+				this.form.oldContractEndDate = employeeInfo.oldContractEndDate;
+			});
+		},
+		submitPeople(userList, nikeNamelist, userIdList) {
+			console.log(userList);
+			console.log(userIdList);
+			if (this.popleSelectType == 'multiple') {
+				this.nikeNamelist = nikeNamelist;
+				this.form.peopleList = userIdList.join(',');
+				this.$refs.popup.close();
+			} else {
+				this.form.employeeName = nikeNamelist.join();
+				this.form.employeeId = userIdList.join();
+				this.getEmployee();
+				this.$refs.popup.close();
+			}
+
+		},
+		popupClose() {
+			this.$refs.popup.close();
+		},
+		gotochooseUser(type) {
+			this.popleSelectType = type;
+			this.$refs.popup.open('bottom');
+			setTimeout(() => {
+				this.$refs.popleSelect.getInfoData();
+			})
+		},
+		handleUploadClick() {
+			this.$refs.XeUpload.upload('file');
+		},
+		handleUploadCallback(e) {
+			console.log('UploadCallback', e);
+			let data = {
+				filePath: e.data[0].tempFilePath
+			}
+			uploadFile(data).then(response => {
+				const tmpFiles = ([response.data] || []).map(({
+					id,
+					url,
+					name,
+					type
+				}) => {
+					return {
+						id,
+						url,
+						name,
+						type,
+					};
+				});
+				this.fileList.push(...tmpFiles);
+			})
+		},
+		// 预览
+		handlePreview(val) {
+			console.log('PreviewFile', val);
+			const fileType = this.getFileType(val.name);
+			if (fileType === 'image') {
+				uni.previewImage({
+					current: 0,
+					urls: [val.url],
+				});
+			} else if (fileType === 'office') {
+				return uni.downloadFile({
+					url: val.url,
+					success: function (res) {
+						let filePath = res.filePath || res.tempFilePath;
+						uni.openDocument({
+							filePath: filePath,
+							showMenu: true,
+							success: function (res) {
+								console.log('打开文档成功');
+							}
+						});
+					}
+				});
+			} else {
+				uni.showModal({
+					title: '该类型文件无法预览',
+					content: val.name,
+					showCancel: false,
+				});
+			}
+
+		},
+		handleDeleteFile(index) {
+			this.fileList.splice(index, 1);
+		},
+		submit(ref) {
+			this.$refs[ref].validate().then(res => {
+				this.form.startUserSelectAssignees = this.form.peopleList.split(',');
+				this.form.auditPass = true;
+				let fileIds = [];
+				this.fileList.forEach(v => {
+					fileIds.push(v.id)
+				})
+				this.form.fileIdList = fileIds;
+				create(this.form).then(response => {
+					uni.showToast({
+						title: `提交成功`
+					})
+					if (this.id) {
+						this.$emit('popupClose');
+					} else {
+						setTimeout(() => {
+							this.$router.go(0)
+						}, 500)
+					}
+
+				}).catch(() => {
+
+				});
+			}).catch(err => {
+				console.log('err', err);
+			})
+		},
+		//暂存
+		onSave() {
+			if (this.form.peopleList) {
+				this.form.startUserSelectAssignees = this.form.peopleList.split(',');
+			}
+			this.form.auditPass = false;
+			let fileIds = [];
+			this.fileList.forEach(v => {
+				fileIds.push(v.id)
+			})
+			this.form.fileIdList = fileIds;
+			save(this.form).then(response => {
+				uni.showToast({
+					title: `暂存成功`
+				})
+				if (this.id) {
+					this.$emit('popupClose');
+				} else {
+					setTimeout(() => {
+						this.$router.go(0)
+					}, 500)
+				}
+			}).catch(() => {
+
+			});
+		},
+		//驳回或撤回后再次提交
+		onReCommit(ref) {
+			this.$refs[ref].validate().then(res => {
+				this.form.startUserSelectAssignees = this.form.peopleList.split(',');
+				this.form.auditPass = true;
+				reCommit(this.form).then(response => {
+					uni.showToast({
+						title: `提交成功`
+					})
+					this.$emit('popupClose');
+				}).catch(() => {
+
+				});
+			}).catch(err => {
+				console.log('err', err);
+			})
+		},
+		//暂存删除
+		async onDelete() {
+			let that = this;
+			uni.showModal({
+				title: '提示',
+				content: '是否确认删除?',
+				success: function (res) {
+					if (res.confirm) {
+						console.log('用户点击确定');
+						deleteById(that.id).then(response => {
+							uni.showToast({
+								title: "删除成功!"
+							})
+							that.$emit('popupClose');
+						})
+					} else if (res.cancel) {
+						console.log('用户点击取消');
+					}
+				}
+			});
+		},
+		//暂存关闭
+		async onClose() {
+			let that = this;
+			uni.showModal({
+				title: '提示',
+				content: '是否确认关闭?',
+				success: function (res) {
+					if (res.confirm) {
+						console.log('用户点击确定');
+						closeById(that.id).then(response => {
+							uni.showToast({
+								title: "流程已关闭!"
+							})
+							that.$emit('popupClose');
+						})
+					} else if (res.cancel) {
+						console.log('用户点击取消');
+					}
+				}
+			});
+		},
+	}
+}
+</script>
+
+<style lang="scss">
+.container {
+	padding: 15px;
+	background-color: #fff;
+}
+
+.segmented-control {
+	margin-bottom: 15px;
+}
+
+.button-group {
+	margin-top: 15px;
+	display: flex;
+}
+
+.form-item {
+	display: flex;
+	align-items: center;
+	flex: 1;
+}
+
+.button {
+	display: flex;
+	align-items: center;
+	height: 35px;
+	line-height: 35px;
+	margin-left: 10px;
+}
+</style>
+<style lang="scss" scoped>
+.user-avatar {
+	width: 22px;
+	height: 22px;
+	line-height: 19px;
+	font-size: 12px;
+	background: #46c26f;
+	border: 1px solid transparent;
+	border-radius: 5px;
+	color: #fff;
+	display: inline-block;
+	overflow: hidden;
+	text-align: center;
+	line-height: 22px;
+	margin-bottom: 2px;
+}
+
+.popup-body {
+	z-index: 99;
+	margin-bottom: 30px;
+}
+
+.popup-close {
+	cursor: pointer;
+	height: 40px;
+	line-height: 40px;
+	padding-left: 10px;
+	border-bottom: 1px solid #eaecef;
+}
+
+.popup-content {
+	height: 450px;
+	overflow-x: auto;
+	margin: 20px;
+}
+
+.btn-click {
+	transition: all 0.3s;
+	opacity: 1;
+}
+
+.btn-click:active {
+	opacity: 0.5;
+}
+
+.mgb-16 {
+	margin-bottom: 16rpx;
+
+	&:last-child {
+		margin-bottom: 0;
+	}
+}
+
+.upload-wrap {
+	width: 100%;
+	border-radius: 16rpx;
+	background: white;
+	// padding: 32rpx;
+
+	.upload-btn {
+		width: 100%;
+		height: 176rpx;
+		border: 2rpx dashed #AAAAAA;
+		background: #FAFAFA;
+		border-radius: 16rpx;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		flex-direction: column;
+
+		.upload-icon {
+			width: 48rpx;
+			height: 48rpx;
+			margin-bottom: 8rpx;
+		}
+
+		.upload-text {
+			font-size: 26rpx;
+			color: #9E9E9E;
+			line-height: 40rpx;
+		}
+	}
+
+	.file-wrap {
+		.file-line {
+			width: 100%;
+			background: #F5F5F5;
+			border-radius: 8rpx;
+			padding: 16rpx;
+			font-size: 26rpx;
+			color: #1A1A1A;
+			line-height: 40rpx;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+
+			.file-info {
+				width: 90%;
+				display: flex;
+				align-items: center;
+
+				.file-name {
+					max-width: 80%;
+					padding-left: 16rpx;
+					overflow: hidden;
+					text-overflow: ellipsis;
+					white-space: nowrap;
+				}
+			}
+
+			.file-icon {
+				width: 40rpx;
+				height: 40rpx;
+				flex-shrink: 0;
+			}
+
+			.file-empty {
+				color: #999999;
+			}
+		}
+	}
+}
+</style>

+ 185 - 0
pages/oa/business/index.vue

@@ -0,0 +1,185 @@
+<template>
+	<view class='purchase-list'>
+		<my-tabs @change="tapChange" :initIndex="initIndex"></my-tabs>
+		<scroll-view class="purchase-body" scroll-y="true" @scrolltolower="scrolltolower" @scroll="scroll">
+			<view v-if="initIndex === 0">
+				<!-- <form-Create></form-Create> -->
+				<form-Edit @popupClose="popupClose"></form-Edit>
+			</view>
+			<view v-if="initIndex === 1">
+				<view class="searchBox">
+					<uni-search-bar placeholder="请输入搜索内容" @confirm="search" @blur="blur" @cancel="cancel" @clear="clear">
+					</uni-search-bar>
+				</view>
+				<data-List v-for="(item,index) in listData" :key="index" :info="item" @faClick="handdle"></data-List>
+				<uni-fab :pattern="pattern" :horizontal="horizontal" :vertical="vertical"
+									:direction="direction" @fabClick="fabClick" />
+				<!-- 普通弹窗 -->
+				<uni-popup ref="popup" background-color="#fff" border-radius="10px 10px 0 0">
+					<view class="popup-body">
+						<view class="popup-close">
+							<uni-icons type="closeempty" size="20" @click="popupClose"></uni-icons>
+						</view>
+						<view class="popup-content">
+							<form-Edit :id="id" v-if="status=='暂存'" @popupClose="popupClose"></form-Edit>
+							<form-Detail :id="id" v-else @popupClose="popupClose"></form-Detail>
+						</view>
+					</view>
+					
+				</uni-popup>
+			</view>
+		</scroll-view>
+	</view>
+</template>
+<script>
+	import { getListData } from "@/api/oa/business"
+	import myTabs from '../myTabs.vue'
+	import dataList from './dataList.vue'
+	import formDetail from './detail.vue'
+	import formEdit from './edit.vue'
+	import myPull from '@/static/js/myPull.js'
+	export default {
+		components:{myTabs,dataList,formEdit,formDetail},
+		data() {
+			return {
+				id:'',
+				status:'',
+				initIndex: 0,
+				searchStr:'',
+				pageNo: 1,
+				pageSize: 10,
+				horizontal: 'right',
+				vertical: 'bottom',
+				direction: 'horizontal',
+				pattern: {
+					color: '#7A7E83',
+					backgroundColor: '#fff',
+					selectedColor: '#007AFF',
+					buttonColor: '#007AFF',
+					iconColor: '#fff'
+				},
+			}
+		},
+		onLoad(){
+			this.refresh();
+		},
+		methods: {
+			fabClick() {
+				this.initIndex = 0;
+							
+			},
+			search(res) {
+				this.searchStr = res.value;
+				this.page = 1;
+				this.getList(this.page,this.__pulldone)
+			},
+			clear(res) {
+				this.searchStr = '';
+				this.page = 1;
+				this.getList(this.page,this.__pulldone)
+			},
+			blur(res) {
+				this.searchStr = res.value;
+				this.page = 1;
+				this.getList(this.page,this.__pulldone)
+			},
+			cancel(res) {
+				this.searchStr = '';
+				this.page = 1;
+				this.getList(this.page,this.__pulldone)
+			},
+			popupClose(){
+				this.$refs.popup.close();
+				this.page = 1;
+				this.getList(this.page,this.__pulldone)
+			},
+			handdle(row) {
+				this.$refs.popup.open('bottom');
+			    this.id = row.id;
+				this.status = row.status;
+			},
+			fabClick() {
+				this.initIndex = 0;
+			},
+			/**
+			 * @name 获取列表
+			 */
+			getList(page,done){
+				if(this.initIndex==1){
+					getListData({pageNo:page,pageSize: this.pageSize,str:this.searchStr}).then(response => {
+						let dataList = response.data.list;
+						let list = []
+						dataList.forEach(v => {
+							list.push({
+								id:v.id,
+								oaType:v.applyEmployeeName+'提交的出差申请',
+								time:v.createTime,
+								title:v.employeeName,
+								remarks:v.destination,
+								status: v.auditStatusDesc,
+								nickname:v.currentAuditEmployeeName
+							})
+						})
+						done(list);
+					});
+				}
+			},
+			
+			/**
+			 * @name 触底加载
+			 */
+			scrolltolower(event){
+				this.getList(this.page,this.__pulldone)
+			},
+			
+			scroll(e){
+				// 重新设置pulldown
+				this.setPullDown(e.detail.scrollTop<10)
+			},
+			/**
+			 * @name 改变tab
+			 * @param val 索引
+			 */
+			tapChange(val){
+				this.initIndex=val;
+				this.page = 1;
+				this.getList(this.page,this.__pulldone)
+			}
+		},
+		mixins:[myPull({})],
+		
+	}
+</script>
+<style lang='scss' scoped>
+	.searchBox{
+		background-color: #fff;
+		position: -webkit-sticky; /* Safari */
+		position: sticky;
+		top: 0; /* 设置元素距离顶部的位置 */
+		width: 100%;
+	}
+	.popup-body{
+		z-index: 99;
+	}
+	.popup-close{
+		cursor: pointer;
+		height: 40px;
+		line-height: 40px;
+		padding-left: 10px;
+		border-bottom: 1px solid #eaecef;
+	}
+	.popup-content{
+		height: 450px;
+		overflow-x: auto;
+	}
+	.purchase-list {
+		background-color: #f5f5f5;
+		height: 100%;
+		overflow: hidden;
+		
+		.purchase-body{
+			height: calc(100% - 88upx);
+			overflow: auto
+		}
+	}
+</style>

+ 2 - 2
pages/oa/universal/detail.vue

@@ -13,10 +13,10 @@
 			<uni-forms-item label="手机号">
 				<uni-easyinput v-model="userInfo.mobile" disabled />
 			</uni-forms-item>
-			<uni-forms-item label="事项标题" required name="title">
+			<uni-forms-item label="事项标题">
 				<uni-easyinput maxlength="20" v-model="form.title" disabled />
 			</uni-forms-item>
-			<uni-forms-item label="详细描述" required name="description">
+			<uni-forms-item label="详细描述">
 				<uni-easyinput autoHeight maxlength="200" type="textarea" v-model="form.description" disabled />
 			</uni-forms-item>
 			<uni-forms-item label="附件">