MyOvertime.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. <script setup lang="ts">
  2. import {
  3. Overtime_User_list,
  4. Overtime_Stat,
  5. Overtime_Add,
  6. Overtime_Del,
  7. Overtime_Edit
  8. } from '@/api/workAttendance/index'
  9. import { User_List } from '@/api/user/index'
  10. import { GlobalStore } from '@/stores/index'
  11. import Drawer from '@/components/Drawer/index.vue'
  12. import Dialog from '@/components/dialog/Dialog.vue'
  13. import { floatReg } from '@/views/salary/salary/relus'
  14. import { reactive, ref, nextTick, computed } from 'vue'
  15. import TableBase from '@/components/TableBase/index.vue'
  16. import { getFormatDuration, dayJs } from '@/utils/common'
  17. import { Edit, Delete, View, Plus } from '@element-plus/icons-vue'
  18. import { ElMessageBox, ElMessage } from 'element-plus'
  19. import { ColumnProps } from '@/components/TableBase/interface/index'
  20. import type { FormInstance, FormRules } from 'element-plus'
  21. import Upload from '@/components/Upload/index.vue'
  22. let uuid = ''
  23. let isNew = ref(true)
  24. const search = ref('')
  25. const TableStatRef = ref()
  26. const disabled = ref(false)
  27. const tableApproverRef = ref()
  28. const globalStore = GlobalStore()
  29. const formLabelWidth = ref('100px')
  30. const ruleFormRef = ref<FormInstance>()
  31. const dialog = ref<InstanceType<typeof Dialog> | null>(null)
  32. const drawerRef = ref<InstanceType<typeof Drawer> | null>(null)
  33. const TableRef = ref<InstanceType<typeof TableBase> | null>(null)
  34. const uploadRef = ref<InstanceType<typeof Upload> | null>(null)
  35. const initParam = { User_tokey: globalStore.GET_User_tokey }
  36. const columns: ColumnProps[] = [
  37. { prop: 'T_start_time', label: '开始时间', ellipsis: true },
  38. { prop: 'T_end_time', label: '结束时间', ellipsis: true },
  39. { prop: 'T_duration', label: '时长', width: '100px', name: 'T_duration' },
  40. { prop: 'T_State', label: '审核', width: '100px', name: 'T_State' },
  41. { prop: 'operation', label: '操作', width: 200, fixed: 'right' }
  42. ]
  43. const columns_Stat: ColumnProps[] = [
  44. { prop: 'T_duration', label: '时长', width: '100px', name: 'T_duration' },
  45. { prop: 'RemainingTime', label: '剩余时长', width: '100px', name: 'RemainingTime' },
  46. { prop: 'T_type_name', label: '事项' },
  47. { prop: 'T_approver_name', label: '处理人' },
  48. { prop: 'UpdateTime', label: '时间', ellipsis: true }
  49. ]
  50. const form = ref({
  51. T_id: '',
  52. T_text: '',
  53. T_duration: 0,
  54. T_end_time: '',
  55. T_approver: '',
  56. T_prove_img: '',
  57. T_start_time: ''
  58. })
  59. const validate_float = (rule: any, value: any, callback: any) => {
  60. if (value === '') {
  61. callback(new Error('请输入加班时长'))
  62. } else {
  63. if (floatReg.test(value) || /\d+/.test(value)) {
  64. callback()
  65. } else {
  66. callback(new Error('时间必须是数字或小数'))
  67. }
  68. }
  69. }
  70. const rules = reactive<FormRules>({
  71. T_type: [{ required: true, message: '请选择请假类型', trigger: 'blur' }],
  72. T_start_time: [{ required: true, message: '请选择开始时间', trigger: 'blur' }],
  73. T_end_time: [{ required: true, message: '请选择结束时间', trigger: 'blur' }],
  74. T_duration: [{ required: true, validator: validate_float, trigger: 'blur' }],
  75. T_approver: [{ required: true, message: '请选择审批人', trigger: 'blur' }]
  76. })
  77. const openDrawerOvertime = (str: string, row?: any) => {
  78. isNew.value = str === 'new' ? true : false
  79. if (!isNew.value) {
  80. nextTick(() => {
  81. form.value = { ...row }
  82. uuid = row.T_approver
  83. form.value.T_approver = row.T_approver_name
  84. form.value.T_id = row.Id
  85. form.value.T_duration = row.T_duration / 60
  86. })
  87. }
  88. drawerRef.value && drawerRef.value.openDrawer()
  89. }
  90. const OvertimeView = (row: any) => {
  91. disabled.value = true
  92. drawerRef.value && drawerRef.value.openDrawer()
  93. nextTick(() => {
  94. form.value = { ...row }
  95. form.value.T_approver = row.T_approver_name
  96. })
  97. }
  98. const OvertimeDelete = (row: any) => {
  99. ElMessageBox.confirm('您确定要删除加班申请吗?', '警告', {
  100. confirmButtonText: '确定',
  101. cancelButtonText: '取消',
  102. type: 'warning'
  103. })
  104. .then(async () => {
  105. const res: any = await Overtime_Del({ User_tokey: globalStore.GET_User_tokey, T_id: row.Id })
  106. if (res.Code === 200) {
  107. ElMessage.success('删除成功!')
  108. nextTick(() => {
  109. TableRef.value?.getTableList()
  110. })
  111. }
  112. })
  113. .catch(() => {
  114. ElMessage.warning('取消成功!')
  115. })
  116. }
  117. const AddOvertime = (formEl: FormInstance | undefined) => {
  118. if (!formEl) return
  119. formEl.validate(async valid => {
  120. if (valid) {
  121. let res: any = {}
  122. let time = duration.value * 60
  123. if (isNew.value) {
  124. res = await Overtime_Add({ ...form.value, T_approver: uuid, T_duration: time })
  125. } else {
  126. res = await Overtime_Edit({ ...form.value, T_approver: uuid, T_duration: time })
  127. }
  128. if (res.Code === 200) {
  129. ElMessage.success(`${isNew.value ? '申请' : '修改'}成功!`)
  130. nextTick(() => {
  131. drawerRef.value?.closeDrawer()
  132. TableRef.value?.getTableList()
  133. resetForm(ruleFormRef.value)
  134. isNew.value = true
  135. })
  136. }
  137. } else {
  138. return false
  139. }
  140. })
  141. }
  142. // Drawer
  143. type Fn = () => void
  144. const callbackDrawer = (done: Fn) => {
  145. disabled.value = false
  146. isNew.value = true
  147. nextTick(() => {
  148. resetForm(ruleFormRef.value)
  149. done()
  150. })
  151. }
  152. const resetForm = (formEl: FormInstance | undefined) => {
  153. if (!formEl) return
  154. uploadRef.value?.clearfileList()
  155. formEl.resetFields()
  156. }
  157. // dialog
  158. const Dialogcolumns: ColumnProps[] = [{ prop: 'T_name', label: '名字', name: 'T_name' }]
  159. const approverInitParam = {
  160. User_tokey: globalStore.GET_User_tokey,
  161. T_name: '',
  162. T_dept_leader: 1
  163. }
  164. const searchHandle = () => {
  165. approverInitParam.T_name = search.value
  166. tableApproverRef.value.searchTable()
  167. }
  168. const selectApprover = () => {
  169. dialog.value?.DialogOpen()
  170. }
  171. const getApproverInfo = (row: any) => {
  172. uuid = row.T_uuid
  173. form.value.T_approver = row.T_name
  174. dialog.value?.DialogClose()
  175. }
  176. const duration = computed(() => {
  177. const end_time = dayJs(form.value.T_end_time)
  178. if (!form.value.T_end_time) {
  179. return 0
  180. }
  181. let count: number = end_time.diff(form.value.T_start_time, 'hour', true)
  182. let num: number = Number(count.toFixed(2))
  183. return Math.round(num * 10) / 10
  184. })
  185. const onResize = () => {
  186. const height = document.documentElement.clientHeight
  187. return height / 2
  188. }
  189. </script>
  190. <template>
  191. <el-row :gutter="24" class="h-100">
  192. <el-col :span="12" class="padding-right-0 h-100">
  193. <TableBase
  194. ref="TableRef"
  195. :columns="columns"
  196. :requestApi="Overtime_User_list"
  197. :initParam="initParam"
  198. layout="total,sizes,prev, pager, next"
  199. >
  200. <template #table-header>
  201. <div class="table-header">
  202. <h4>我的加班</h4>
  203. <el-button type="primary" @click="openDrawerOvertime('new')">申请加班</el-button>
  204. </div>
  205. </template>
  206. <template #T_duration="{ row }"> {{ getFormatDuration(row.T_duration) }} </template>
  207. <template #T_State="{ row }">
  208. <el-tag v-if="row.T_State === 1" type="success">通过</el-tag>
  209. <el-tag v-else-if="row.T_State === 2" type="warning">未通过</el-tag>
  210. <el-tag v-else type="danger">待审核</el-tag>
  211. </template>
  212. <template #right="{ row }">
  213. <el-button
  214. :disabled="row.T_State === 1"
  215. link
  216. type="primary"
  217. size="small"
  218. :icon="Edit"
  219. @click="openDrawerOvertime('edit', row)"
  220. >编辑</el-button
  221. >
  222. <el-button
  223. :disabled="row.T_State === 1"
  224. link
  225. type="danger"
  226. size="small"
  227. :icon="Delete"
  228. @click="OvertimeDelete(row)"
  229. >删除</el-button
  230. >
  231. <el-button link type="success" size="small" :icon="View" @click="OvertimeView(row)">查看</el-button>
  232. </template>
  233. </TableBase></el-col
  234. >
  235. <el-col :span="12" class="h-100" style="overflow: hidden">
  236. <TableBase
  237. ref="TableStatRef"
  238. :columns="columns_Stat"
  239. :requestApi="Overtime_Stat"
  240. :initParam="initParam"
  241. layout="total,sizes,prev, pager, next"
  242. >
  243. <template #table-header="{ pageable }">
  244. <el-button text
  245. ><h4>
  246. <el-text class="mx-1" type="primary"
  247. >剩余总时长:{{ getFormatDuration(pageable.RemainingTime as number) }}</el-text
  248. >
  249. </h4></el-button
  250. ></template
  251. >
  252. <template #T_duration="{ row }">{{ getFormatDuration(row.T_duration) }} </template>
  253. <template #RemainingTime="{ row }">{{ getFormatDuration(row.RemainingTime) }} </template>
  254. </TableBase>
  255. </el-col>
  256. <Drawer ref="drawerRef" :handleClose="callbackDrawer">
  257. <template #header="{ params }">
  258. <h4 :id="params.titleId" :class="params.titleClass">{{ isNew ? '添加' : '编辑' }} - 申请</h4>
  259. </template>
  260. <el-form ref="ruleFormRef" :model="form" :rules="rules">
  261. <el-form-item label="开始时间:" :label-width="formLabelWidth" prop="T_start_time">
  262. <el-date-picker
  263. style="width: 100%"
  264. class="my-date-picker"
  265. v-model="form.T_start_time"
  266. type="datetime"
  267. :disabled="disabled"
  268. placeholder="选择开始时间"
  269. format="YYYY-MM-DD HH:mm"
  270. value-format="YYYY-MM-DD HH:mm:ss"
  271. />
  272. </el-form-item>
  273. <el-form-item label="结束时间:" :label-width="formLabelWidth" prop="T_end_time">
  274. <el-date-picker
  275. style="width: 100%"
  276. class="my-date-picker"
  277. v-model="form.T_end_time"
  278. type="datetime"
  279. :disabled="disabled"
  280. placeholder="选择结束时间"
  281. format="YYYY-MM-DD HH:mm"
  282. value-format="YYYY-MM-DD HH:mm:ss"
  283. />
  284. </el-form-item>
  285. <el-form-item label="加班时长:" :label-width="formLabelWidth" prop="T_duration">
  286. <el-input v-model="duration" autocomplete="off" placeholder="请假时长">
  287. <template #suffix> 小时 </template>
  288. </el-input>
  289. </el-form-item>
  290. <el-form-item label="取证:" :label-width="formLabelWidth" prop="T_prove_img">
  291. <Upload
  292. ref="uploadRef"
  293. :isImg="true"
  294. :limit="1"
  295. v-model="form.T_prove_img"
  296. :disabled="disabled"
  297. accept="image/*"
  298. >
  299. <el-icon><Plus /></el-icon>
  300. </Upload>
  301. </el-form-item>
  302. <el-form-item label="内容:" :label-width="formLabelWidth" prop="T_text">
  303. <el-input
  304. v-model="form.T_text"
  305. :disabled="disabled"
  306. autocomplete="off"
  307. type="textarea"
  308. :autosize="{ minRows: 4, maxRows: 6 }"
  309. placeholder="请输入内容"
  310. />
  311. </el-form-item>
  312. <el-form-item label="审批:" :label-width="formLabelWidth" prop="T_approver">
  313. <el-input
  314. :disabled="disabled"
  315. v-model="form.T_approver"
  316. autocomplete="off"
  317. placeholder="审批人"
  318. @focus="selectApprover"
  319. />
  320. </el-form-item>
  321. <el-form-item :label-width="formLabelWidth">
  322. <el-button v-if="isNew" color="#626aef" @click="AddOvertime(ruleFormRef)" :disabled="disabled"
  323. >添加</el-button
  324. >
  325. <el-button v-else color="#626aef" @click="AddOvertime(ruleFormRef)">修改</el-button>
  326. </el-form-item>
  327. </el-form>
  328. </Drawer>
  329. <Dialog ref="dialog" width="30%">
  330. <template #header>
  331. <h3>选择审批人</h3>
  332. </template>
  333. <TableBase
  334. ref="tableApproverRef"
  335. :columns="Dialogcolumns"
  336. :initParam="approverInitParam"
  337. :requestApi="User_List"
  338. layout="total, prev, pager, next"
  339. :onResize="onResize"
  340. >
  341. <template #table-header>
  342. <el-row :gutter="20">
  343. <el-col :span="20" class="d-flex">
  344. <span class="inline-flex">账户查询:</span>
  345. <el-input v-model="search" type="text" class="w-50 m-2" />
  346. <el-button type="primary" @click="searchHandle">搜索</el-button>
  347. </el-col>
  348. </el-row>
  349. </template>
  350. <template #T_name="{ row }">
  351. <el-button type="primary" link @click="getApproverInfo(row)">{{ row.T_name }}</el-button>
  352. </template>
  353. </TableBase>
  354. </Dialog>
  355. </el-row>
  356. </template>
  357. <style scoped lang="scss">
  358. .table-header {
  359. width: 100%;
  360. display: flex;
  361. justify-content: space-between;
  362. align-items: center;
  363. }
  364. .full-img {
  365. width: 100%;
  366. height: 100%;
  367. }
  368. .d-flex {
  369. display: flex;
  370. align-items: center;
  371. .inline-flex {
  372. white-space: nowrap;
  373. }
  374. }
  375. .mx-1 {
  376. letter-spacing: 1px;
  377. }
  378. </style>