timeTable.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. <template>
  2. <el-form
  3. ref="form"
  4. :model="form"
  5. :rules="rules"
  6. label-width="140px"
  7. class="el-form-box"
  8. :disabled="title == '详情'"
  9. >
  10. <ele-pro-table
  11. :columns="columns"
  12. :datasource="form.list"
  13. ref="table"
  14. height="300px"
  15. full-height="calc(100vh - 116px)"
  16. :needPage="false"
  17. >
  18. <template v-slot:toolbar v-if="title != '详情'">
  19. <el-button
  20. size="small"
  21. type="primary"
  22. icon="el-icon-plus"
  23. class="ele-btn-icon"
  24. @click="handAdd()"
  25. style="margin-bottom: 5px"
  26. >
  27. 新增
  28. </el-button>
  29. <!-- <el-popconfirm
  30. class="ele-action"
  31. title="确定要删除选中的信息吗?"
  32. @confirm="remove()"
  33. >
  34. <template v-slot:reference>
  35. <el-button
  36. type="danger"
  37. :underline="false"
  38. icon="el-icon-delete"
  39. :disabled="selection?.length === 0"
  40. >
  41. 删除
  42. </el-button>
  43. </template>
  44. </el-popconfirm> -->
  45. </template>
  46. <template v-slot:dutyName="{ row, $index }">
  47. <el-form-item
  48. label-width="0"
  49. :prop="'list.' + $index + '.dutyName'"
  50. :rules="[
  51. {
  52. required: true,
  53. message: '出勤名称不能为空',
  54. trigger: 'blur'
  55. }
  56. ]"
  57. >
  58. <DictSelection
  59. dictName="班次出勤名称"
  60. clearable
  61. v-model="row.dutyName"
  62. filterable
  63. valueName="dictValue"
  64. allow-create
  65. default-first-option
  66. :isOne="$index === 0"
  67. >
  68. </DictSelection>
  69. </el-form-item>
  70. </template>
  71. <template v-slot:timeType="{ row, $index }">
  72. <el-form-item
  73. label-width="0"
  74. :prop="'list.' + $index + '.timeType'"
  75. :rules="[
  76. {
  77. required: true,
  78. message: '请选择时间类型',
  79. trigger: 'blur'
  80. }
  81. ]"
  82. >
  83. <el-select
  84. v-model="row.timeType"
  85. clearable
  86. style="width: 100%"
  87. @change="setFormtime"
  88. >
  89. <el-option :value="'1'" label="工作时间"></el-option>
  90. <el-option :value="'2'" label="休息时间"></el-option>
  91. </el-select>
  92. </el-form-item>
  93. </template>
  94. <template v-slot:startTime="{ row, $index }">
  95. <el-form-item
  96. label-width="0"
  97. :prop="'list.' + $index + '.startTime'"
  98. :rules="[
  99. {
  100. required: true,
  101. message: '请选择开始时间',
  102. trigger: 'blur'
  103. }
  104. ]"
  105. >
  106. <el-time-picker
  107. style="width: 100%"
  108. placeholder="开始时间"
  109. v-model="row.startTime"
  110. format="HH:mm"
  111. value-format="HH:mm"
  112. @change="changeTime(row, $index, 'startTime')"
  113. :disabled="!!form.list[$index - 1]?.endTime"
  114. >
  115. </el-time-picker>
  116. <!-- <el-time-select
  117. placeholder="开始时间"
  118. v-model="row.startTime"
  119. @change="changeTime(row, $index, 'startTime')"
  120. :disabled="!!form.list[$index - 1]?.endTime"
  121. :picker-options="{
  122. ...defTime,
  123. ...(form.list[$index - 1]
  124. ? {
  125. minTime: form.list[$index - 1].endTime
  126. }
  127. : {})
  128. }"
  129. >
  130. </el-time-select> -->
  131. </el-form-item>
  132. </template>
  133. <template v-slot:endTime="{ row, $index }">
  134. <el-form-item
  135. label-width="0"
  136. :prop="'list.' + $index + '.endTime'"
  137. :rules="[
  138. {
  139. required: true,
  140. message: '请选择结束时间',
  141. trigger: 'blur'
  142. }
  143. ]"
  144. >
  145. <el-time-picker
  146. style="width: 100%"
  147. placeholder="结束时间"
  148. v-model="row.endTime"
  149. format="HH:mm"
  150. value-format="HH:mm"
  151. :disabled="!row.startTime"
  152. @change="changeTime(row, $index, 'endTime')"
  153. :picker-options="{
  154. selectableRange: row.startTime + ':00-23:59:59'
  155. }"
  156. >
  157. </el-time-picker>
  158. <!-- <el-time-select
  159. placeholder="结束时间"
  160. v-model="row.endTime"
  161. @change="changeTime(row, $index, 'endTime')"
  162. :picker-options="{
  163. ...defTime,
  164. ...{
  165. minTime: row.startTime
  166. }
  167. }"
  168. >
  169. </el-time-select> -->
  170. </el-form-item>
  171. </template>
  172. <template v-slot:columnRequired="{ column }">
  173. <span class="is-required">{{ column.label }}</span>
  174. </template>
  175. <template v-slot:note="{ row }">
  176. <el-input clearable v-model="row.note" placeholder="请输入" />
  177. </template>
  178. <template v-slot:action="{ row, $index }">
  179. <el-popconfirm
  180. class="ele-action"
  181. title="确定要删除此信息吗?"
  182. @confirm="remove($index)"
  183. >
  184. <template v-slot:reference>
  185. <el-link type="danger" :underline="false" icon="el-icon-delete">
  186. 删除
  187. </el-link>
  188. </template>
  189. </el-popconfirm>
  190. </template>
  191. </ele-pro-table>
  192. </el-form>
  193. </template>
  194. <script>
  195. const defForm = {
  196. list: [] //表格数据
  197. };
  198. export default {
  199. data() {
  200. return {
  201. columns: [
  202. {
  203. width: 60,
  204. type: 'index',
  205. columnKey: 'index',
  206. label: '序号',
  207. align: 'center',
  208. fixed: 'left'
  209. },
  210. {
  211. width: 45,
  212. type: 'selection',
  213. columnKey: 'selection',
  214. align: 'center'
  215. },
  216. {
  217. prop: 'dutyName',
  218. slot: 'dutyName',
  219. headerSlot: 'columnRequired',
  220. label: '出勤名称',
  221. align: 'center',
  222. showOverflowTooltip: true,
  223. minWidth: 180
  224. },
  225. {
  226. slot: 'timeType',
  227. prop: 'timeType',
  228. headerSlot: 'columnRequired',
  229. label: '时间类型',
  230. align: 'center',
  231. showOverflowTooltip: true,
  232. minWidth: 110
  233. },
  234. {
  235. prop: 'startTime',
  236. label: '开始时间',
  237. align: 'center',
  238. headerSlot: 'columnRequired',
  239. slot: 'startTime',
  240. showOverflowTooltip: true,
  241. minWidth: 170
  242. },
  243. {
  244. prop: 'endTime',
  245. minWidth: 170,
  246. headerSlot: 'columnRequired',
  247. slot: 'endTime',
  248. label: '结束时间',
  249. align: 'center'
  250. },
  251. {
  252. width: 160,
  253. prop: 'totalDuration',
  254. label: '总时长(分钟)',
  255. align: 'center'
  256. },
  257. {
  258. prop: 'note',
  259. slot: 'note',
  260. label: '备注',
  261. align: 'center',
  262. showOverflowTooltip: true,
  263. minWidth: 200
  264. },
  265. {
  266. columnKey: 'action',
  267. label: '操作',
  268. width: 150,
  269. align: 'center',
  270. resizable: false,
  271. slot: 'action',
  272. showOverflowTooltip: true,
  273. fixed: 'right'
  274. }
  275. ],
  276. selection: [],
  277. form: { ...defForm },
  278. rules: {},
  279. title: '新增'
  280. };
  281. },
  282. mounted() {},
  283. created() {},
  284. methods: {
  285. //初始化
  286. async init(row = {}, type) {
  287. this.title = type == 'add' ? '新增' : type == 'edit' ? '修改' : '详情';
  288. this.form.list = row.list;
  289. this.form.list.forEach((item, index) => {
  290. item.key = index;
  291. });
  292. },
  293. handAdd() {
  294. if (
  295. this.form.list?.length &&
  296. !this.form.list[this.form.list?.length - 1].endTime
  297. ) {
  298. this.$message.error('请先填写前一条数据的结束时间');
  299. return;
  300. }
  301. this.form.list.push({
  302. startTime: this.form.list[this.form.list?.length - 1]?.endTime || '',
  303. endTime: '',
  304. note: '',
  305. totalDuration: '',
  306. dutyName: '',
  307. timeType: '1',
  308. key: this.form.list?.length || 0
  309. });
  310. },
  311. changeTime(row, index, type) {
  312. // return
  313. if (type == 'startTime') {
  314. this.$set(this.form.list[index], 'endTime', '');
  315. row.startTime =
  316. row.startTime.split(':')[0] +
  317. ':' +
  318. row.startTime.split(':')[1] +
  319. ':00';
  320. }
  321. this.removeFormtime(index);
  322. if (row.startTime && row.endTime) {
  323. let startTime = new Date(row.startTime).getTime();
  324. if (!startTime) {
  325. startTime = new Date('2025-01-01 ' + row.startTime).getTime();
  326. }
  327. let endTime = new Date('2025-01-01 ' + row.endTime).getTime();
  328. let val = (endTime - startTime) / 60000;
  329. this.$set(this.form.list[index], 'totalDuration', val);
  330. } else {
  331. this.$set(this.form.list[index], 'totalDuration', 0);
  332. }
  333. this.setFormtime();
  334. },
  335. removeFormtime(i) {
  336. this.form.list.splice(i + 1, this.form.list.length - i);
  337. },
  338. setFormtime() {
  339. if (this.form.list?.length) {
  340. let attendanceStartTime = this.form.list[0].startTime;
  341. let attendanceEndTime =
  342. this.form.list[this.form.list.length - 1].endTime;
  343. let totalWorkingMinutes = 0;
  344. let restDurationMinutes = 0;
  345. this.form.list.forEach((v, index) => {
  346. v.key = index;
  347. if (v.timeType == '1') {
  348. totalWorkingMinutes += v.totalDuration;
  349. } else {
  350. restDurationMinutes += v.totalDuration;
  351. }
  352. });
  353. this.$emit('setFormtime', {
  354. attendanceStartTime,
  355. attendanceEndTime,
  356. totalWorkingMinutes,
  357. restDurationMinutes
  358. });
  359. }
  360. },
  361. remove(index) {
  362. if (index != 0) {
  363. this.removeFormtime(index);
  364. }
  365. this.form.list.splice(index, 1);
  366. this.setFormtime();
  367. this.selection = [];
  368. },
  369. getTableValue() {
  370. return new Promise((resolve) => {
  371. this.$refs.form.validate((valid) => {
  372. if (!valid) {
  373. resolve([]);
  374. } else {
  375. resolve(this.form.list);
  376. }
  377. });
  378. });
  379. }
  380. }
  381. };
  382. </script>
  383. <style scoped lang="scss"></style>