punchin-detail.vue 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. <template>
  2. <main-layout :showHome="true" :showBack="true">
  3. <uni-calendar
  4. :start-date="punchInData.startDate"
  5. :end-date="punchInData.endDate"
  6. :selected="punchInData.calendarSelected"
  7. @monthSwitch="calendarMonthSwitchChange"/>
  8. <viwe class="info-box">
  9. <view class="left">打卡:{{punchInData.punchInNum}}次</view>
  10. <view class="right">全勤率:{{punchInData.punchInRate}}%</view>
  11. </viwe>
  12. <view class="log-box">
  13. <uni-section title="打卡记录" type="line">
  14. <uni-list>
  15. <uni-list-item v-for="record in punchInData.punchInRecords" :key="record.punchInDate">
  16. <template v-slot:body>
  17. {{record.punchInDate}}
  18. <span v-if="record.punchInStatus == 1 || record.punchInStatus == 3"> 完成打卡</span>
  19. <span v-else> 未完成打卡</span>
  20. <span v-if="record.settleCategory == 1">,打卡{{record.countTrack}}次</span>
  21. <span v-if="record.settleCategory == 2">,打卡时长{{record.timeTrack}}</span>
  22. </template>
  23. </uni-list-item>
  24. </uni-list>
  25. </uni-section>
  26. </view>
  27. <uni-fab ref="fabBtn" :content="fabContent" :pattern="fabPattern" horizontal="right" vertical="bottom" direction="vertical" @trigger="trigger"/>
  28. <!-- 删除确认框 -->
  29. <uni-popup ref="deleteDialog" type="dialog">
  30. <uni-popup-dialog mode="base" :before-close="true"
  31. title="删除提示" content="确认删除当前任务?"
  32. @confirm="deleteDialogConfirm" @close="deleteDialogClose"></uni-popup-dialog>
  33. </uni-popup>
  34. <!-- 归档确认框 -->
  35. <uni-popup ref="archiveDialog" type="dialog">
  36. <uni-popup-dialog mode="base" :before-close="true"
  37. title="归档提示" content="确认归档当前任务?"
  38. @confirm="archiveDialogConfirm" @close="archiveDialogClose"></uni-popup-dialog>
  39. </uni-popup>
  40. <!-- 撤销确认框 -->
  41. <uni-popup ref="revokeDialog" type="dialog">
  42. <uni-popup-dialog mode="base" :before-close="true"
  43. title="撤销提示" content="确认撤销打卡?"
  44. @confirm="revokeDialogConfirm" @close="revokeDialogClose"></uni-popup-dialog>
  45. </uni-popup>
  46. <!-- 补卡弹出框 -->
  47. <uni-popup ref="remakeInputDialog" type="dialog" :is-mask-click="false">
  48. <uni-popup-dialog
  49. mode="input"
  50. :before-close="true"
  51. title="补卡"
  52. @confirm="remakeFormConfirm"
  53. @close="remakeFormClose">
  54. <view style="width: 100%;">
  55. <uni-forms ref="remakeForm" :modelValue="remakeFormData" :rules="remakeFormRules" label-position="top" :label-width="150">
  56. <uni-forms-item name="punchInDate">
  57. <picker mode="date" :value="remakeFormData.punchInDate" @change="remakePunchInDateChange">
  58. <view class="pick-box">{{remakeFormData.punchInDate}}</view>
  59. </picker>
  60. </uni-forms-item>
  61. </uni-forms>
  62. </view>
  63. </uni-popup-dialog>
  64. </uni-popup>
  65. </main-layout>
  66. </template>
  67. <script setup>
  68. import { ref } from 'vue';
  69. import { onLoad, onPullDownRefresh } from '@dcloudio/uni-app';
  70. import router from '@/common/constants/router';
  71. import { punchInApi } from '@/service/apis.js';
  72. import dateUtils from '@/utils/date';
  73. // 组件
  74. const fabBtn = ref(null);
  75. /**
  76. * 删除弹出框
  77. */
  78. const deleteDialog = ref(null);
  79. /**
  80. * 归档弹出框
  81. */
  82. const archiveDialog = ref(null);
  83. /**
  84. * 补卡弹出框
  85. */
  86. const remakeInputDialog = ref(null);
  87. /**
  88. * 补卡表单
  89. */
  90. const remakeForm = ref(null);
  91. /**
  92. * 撤销弹出框
  93. */
  94. const revokeDialog = ref(null);
  95. // 属性
  96. /**
  97. * 任务ID
  98. */
  99. const punchInId = ref(null);
  100. /**
  101. * 悬浮菜单样式
  102. */
  103. const fabPattern = ref({
  104. icon: 'compose'
  105. });
  106. /**
  107. * 悬浮按钮菜单
  108. */
  109. const fabContent = [{
  110. text: '删除',
  111. active: false,
  112. iconPath: '/static/delete.svg',
  113. selectedIconPath: '/static/delete-active.svg',
  114. func: "delete"
  115. },
  116. {
  117. text: '归档',
  118. active: false,
  119. iconPath: '/static/archive.svg',
  120. selectedIconPath: '/static/archive-active.svg',
  121. func: "archive"
  122. },
  123. {
  124. text: '撤销',
  125. active: false,
  126. iconPath: '/static/revoke.svg',
  127. selectedIconPath: '/static/revoke_active.svg',
  128. func: "revoke"
  129. },
  130. {
  131. text: '补卡',
  132. active: false,
  133. iconPath: '/static/append.svg',
  134. selectedIconPath: '/static/append-active.svg',
  135. func: "remake"
  136. },
  137. {
  138. text: '编辑',
  139. active: false,
  140. iconPath: '/static/edit.svg',
  141. selectedIconPath: '/static/edit-active.svg',
  142. func: "edit"
  143. }
  144. ];
  145. /**
  146. * 补卡表单数据
  147. */
  148. const remakeFormData = ref({
  149. punchIndate: '2024-12-16'
  150. });
  151. /**
  152. * 补卡表单校验规则
  153. */
  154. const remakeFormRules = ref({
  155. punchInDate: {
  156. rules: [{
  157. required: true,
  158. errorMessage: '补卡日期不能为空'
  159. }]
  160. }
  161. });
  162. /**
  163. * 查询条件
  164. */
  165. const queryData = ref(null);
  166. /**
  167. * 打卡日历数据
  168. */
  169. const punchInData = ref({
  170. startDate: '2024-12-01',
  171. endDate: '2024-12-31',
  172. punchInNum: 0,
  173. punchInRate: 0,
  174. calendarSelected: [],
  175. punchInRecords: []
  176. });
  177. // 方法
  178. /**
  179. * 悬浮按钮点击事件
  180. */
  181. const trigger = (e) => {
  182. if (e.item.func == 'delete') {
  183. deleteDialog.value.open();
  184. }
  185. if (e.item.func == 'archive') {
  186. archiveDialog.value.open();
  187. }
  188. if (e.item.func == 'revoke') {
  189. revokeDialog.value.open();
  190. }
  191. if (e.item.func == 'remake') {
  192. // 初始化上一轮的数据
  193. remakeFormData.value = {
  194. punchInId: punchInId.value,
  195. punchInDate: dateUtils.getYesterday()
  196. };
  197. remakeInputDialog.value.open();
  198. }
  199. if (e.item.func == 'edit') {
  200. uni.navigateTo({
  201. url: router.PUNCHIN_EDIT_URL + "?id=" + punchInId.value
  202. });
  203. }
  204. fabBtn.value.close();
  205. }
  206. /**
  207. * 删除确认
  208. */
  209. const deleteDialogConfirm = async () => {
  210. punchInApi.deletePunchIn({id: punchInId.value})
  211. .then(ret => {
  212. deleteDialog.value.close();
  213. uni.showToast({
  214. title: '删除成功',
  215. icon: 'success'
  216. });
  217. setTimeout(() => {
  218. uni.navigateBack();
  219. }, 1000);
  220. })
  221. .catch(err => {
  222. uni.showToast({
  223. title: '删除失败',
  224. icon: 'error'
  225. });
  226. });
  227. }
  228. /**
  229. * 删除取消
  230. */
  231. const deleteDialogClose = () => {
  232. deleteDialog.value.close();
  233. }
  234. /**
  235. * 归档确认
  236. */
  237. const archiveDialogConfirm = async () => {
  238. punchInApi.archivePunchIn({id: punchInId.value})
  239. .then(ret => {
  240. archiveDialog.value.close();
  241. uni.showToast({
  242. title: '归档成功',
  243. icon: 'success'
  244. });
  245. setTimeout(() => {
  246. uni.navigateBack();
  247. }, 1000);
  248. })
  249. .catch(err => {
  250. uni.showToast({
  251. title: '归档失败',
  252. icon: 'error'
  253. });
  254. });
  255. }
  256. /**
  257. * 归档取消
  258. */
  259. const archiveDialogClose = () => {
  260. archiveDialog.value.close();
  261. }
  262. /**
  263. * 补卡时间选择监听
  264. */
  265. const remakePunchInDateChange = (e) => {
  266. remakeFormData.value.punchInDate = e.detail.value;
  267. }
  268. /**
  269. * 补卡表单提交
  270. */
  271. const remakeFormConfirm = async () => {
  272. remakeForm.value.validate(['punchInId']).then(data => {
  273. return punchInApi.remakePunchIn(data);
  274. }).then(e => {
  275. remakeInputDialog.value.close();
  276. uni.showToast({
  277. title: '补卡成功',
  278. icon: 'success'
  279. });
  280. loadData();
  281. }).catch(err => {
  282. uni.showToast({
  283. title: '补卡失败',
  284. icon: 'error'
  285. });
  286. })
  287. }
  288. /**
  289. * 补卡表单取消
  290. */
  291. const remakeFormClose = async () => {
  292. remakeInputDialog.value.close();
  293. }
  294. /**
  295. * 撤销确认
  296. */
  297. const revokeDialogConfirm = async () => {
  298. punchInApi.revokePunchIn({id: punchInId.value})
  299. .then(ret => {
  300. revokeDialog.value.close();
  301. uni.showToast({
  302. title: '撤销成功',
  303. icon: 'success'
  304. });
  305. loadData();
  306. })
  307. .catch(err => {
  308. uni.showToast({
  309. title: '撤销失败',
  310. icon: 'error'
  311. });
  312. });
  313. }
  314. /**
  315. * 撤销取消
  316. */
  317. const revokeDialogClose = () => {
  318. revokeDialog.value.close();
  319. }
  320. /**
  321. * 日历月份切换
  322. */
  323. const calendarMonthSwitchChange = (e) => {
  324. queryData.value = e;
  325. loadData();
  326. }
  327. /**
  328. * 加载数据
  329. */
  330. const loadData = () => {
  331. punchInApi.queryPunchInData({
  332. id: punchInId.value,
  333. year: queryData.value.year,
  334. month: queryData.value.month,
  335. }).then(data => {
  336. punchInData.value = data;
  337. }).catch(err => {
  338. uni.showToast({
  339. title: '加载失败',
  340. icon: 'error'
  341. });
  342. });
  343. }
  344. onLoad(async (e) => {
  345. if (e.id) {
  346. punchInId.value = e.id;
  347. // 初始化查询条件
  348. queryData.value = dateUtils.getTodayYearMonthObj();
  349. // 加载数据
  350. loadData();
  351. }
  352. });
  353. onPullDownRefresh(() => {
  354. loadData();
  355. uni.stopPullDownRefresh();
  356. });
  357. </script>
  358. <style lang="scss" scoped>
  359. .info-box, .log-box {
  360. margin-top: 24rpx;
  361. }
  362. .info-box {
  363. display: flex;
  364. background-color: #FFFFFF;
  365. padding: 20rpx 10rpx;
  366. .left, .right {
  367. flex: 1;
  368. display: flex;
  369. align-items: center;
  370. justify-content: center;
  371. }
  372. }
  373. .pick-box {
  374. display: flex;
  375. box-sizing: border-box;
  376. flex-direction: row;
  377. align-items: center;
  378. border: 1px solid #dcdfe6;
  379. border-radius: 4px;
  380. width: auto;
  381. position: relative;
  382. overflow: hidden;
  383. flex: 1;
  384. line-height: 1;
  385. font-size: 14px;
  386. height: 35px;
  387. padding-left: 10px;
  388. }
  389. </style>