taskList.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. <template>
  2. <!-- 打卡任务 -->
  3. <view class="task-container">
  4. <view class="task-header">
  5. <view class="task-title" v-if="tasks.length && tasks.length > 0">任务({{ tasks.length }}个)
  6. </view>
  7. <view class="task-title" v-else>任务</view>
  8. <view class="task-add-btn" @click="goTaskEditPage()">
  9. <uni-icons type="plusempty" size="30" color="#406CE7"></uni-icons>
  10. </view>
  11. </view>
  12. <view class="task-item" v-for="task in tasks" :key="task.id">
  13. <view class="main-box" @click="goPunchInDetailPage(task.id)">
  14. <view class="item-header">
  15. <span class="item-title">{{ task.taskName }}</span>
  16. <span class="item-reward">x{{ task.points }}</span>
  17. <view class="item-tag" v-if="task.fullAttendanceFlag">全勤奖励</view>
  18. <view class="item-tag" v-if="task.weekendDoubleFlag">周末双倍</view>
  19. </view>
  20. <view class="item-desc">
  21. 描述:{{ task.description }}
  22. </view>
  23. <view class="item-detail-list">
  24. <view class="item-detail" v-for="punchInRecord in task.piTaskHistorySimpleVOS"
  25. :key="punchInRecord.punchInDate">
  26. <view class="detail-text">
  27. <uni-dateformat :date="punchInRecord.punchInDate" format="M/d"></uni-dateformat>
  28. </view>
  29. <view class="detail-box" style="background-color: #E5E5E5;"
  30. v-if="punchInRecord.punchInResult == 'NOT_NEED'"></view>
  31. <view class="detail-box" style="background-color: #A5D63F;" v-if="punchInRecord.punchInResult == 'DONE'">
  32. </view>
  33. <view class="detail-box" style="background-color: #D43030;" v-if="punchInRecord.punchInResult == 'UNDONE'">
  34. </view>
  35. <view class="detail-box" v-if="punchInRecord.punchInResult == 'FUTURE'">
  36. </view>
  37. </view>
  38. </view>
  39. </view>
  40. <view class="btn-group">
  41. <view class="btn-item" @click="deleteDialogOpen(task.id)">删除</view>
  42. <view class="btn-item" @click="archiveDialogOpen(task.id)">归档</view>
  43. <view class="btn-item" @click="revokeDialogOpen(task.id)">撤销</view>
  44. <view class="btn-item" @click="goTaskEditPage(task.id)">编辑</view>
  45. </view>
  46. </view>
  47. <uni-load-more status="no-more" v-if="!tasks || tasks.length == 0" />
  48. <!-- 删除确认框 -->
  49. <uni-popup ref="deleteDialog" type="dialog">
  50. <uni-popup-dialog mode="base" :before-close="true" title="删除提示" content="确认删除当前任务?" @confirm="deleteDialogConfirm"
  51. @close="deleteDialogClose"></uni-popup-dialog>
  52. </uni-popup>
  53. <!-- 归档确认框 -->
  54. <uni-popup ref="archiveDialog" type="dialog">
  55. <uni-popup-dialog mode="base" :before-close="true" title="归档提示" content="确认归档当前任务?"
  56. @confirm="archiveDialogConfirm" @close="archiveDialogClose"></uni-popup-dialog>
  57. </uni-popup>
  58. <!-- 撤销确认框 -->
  59. <uni-popup ref="revokeDialog" type="dialog">
  60. <uni-popup-dialog mode="base" :before-close="true" title="撤销提示" content="确认撤销打卡?" @confirm="revokeDialogConfirm"
  61. @close="revokeDialogClose"></uni-popup-dialog>
  62. </uni-popup>
  63. </view>
  64. </template>
  65. <script setup>
  66. import { ref } from 'vue';
  67. import { onPullDownRefresh, onShow } from "@dcloudio/uni-app";
  68. import { punchInApi } from '@/apis/apis.js';
  69. import router from '@/common/router.js';
  70. // 组件
  71. /**
  72. * 删除弹出框
  73. */
  74. const deleteDialog = ref(null);
  75. /**
  76. * 归档弹出框
  77. */
  78. const archiveDialog = ref(null);
  79. /**
  80. * 撤销弹出框
  81. */
  82. const revokeDialog = ref(null);
  83. // 属性
  84. /**
  85. * 当前操作的的任务ID
  86. */
  87. const currentTaskId = ref(null);
  88. /**
  89. * 打卡任务
  90. */
  91. const tasks = ref([]);
  92. // 方法
  93. /**
  94. * 跳转打卡编辑页面
  95. */
  96. const goPunchInEditPage = () => {
  97. uni.navigateTo({
  98. url: router.PUNCHIN_EDIT_URL
  99. });
  100. };
  101. /**
  102. * 跳转打卡任务编辑页
  103. */
  104. const goTaskEditPage = (id) => {
  105. uni.navigateTo({
  106. url: id ? router.TASK_EDIT_PAGE + "?id=" + id : router.TASK_EDIT_PAGE
  107. });
  108. };
  109. /**
  110. * 加载数据
  111. */
  112. const loadData = async () => {
  113. // 获取打卡
  114. let res = await punchInApi.queryTaskList();
  115. tasks.value = res;
  116. };
  117. /**
  118. * 打开删除对话框
  119. */
  120. const deleteDialogOpen = (id) => {
  121. currentTaskId.value = id;
  122. deleteDialog.value.open();
  123. }
  124. /**
  125. * 打开归档对话框
  126. */
  127. const archiveDialogOpen = (id) => {
  128. currentTaskId.value = id;
  129. archiveDialog.value.open();
  130. }
  131. /**
  132. * 打开撤销对话框
  133. */
  134. const revokeDialogOpen = (id) => {
  135. currentTaskId.value = id;
  136. revokeDialog.value.open();
  137. }
  138. /**
  139. * 删除确认
  140. */
  141. const deleteDialogConfirm = async () => {
  142. punchInApi.deleteTask({ id: currentTaskId.value })
  143. .then(ret => {
  144. uni.showToast({
  145. title: '删除成功',
  146. icon: 'success'
  147. });
  148. })
  149. .catch(err => {
  150. uni.showToast({
  151. title: '删除失败',
  152. icon: 'error'
  153. });
  154. }).finally(() => {
  155. currentTaskId.value = null;
  156. deleteDialog.value.close();
  157. loadData();
  158. })
  159. ;
  160. }
  161. /**
  162. * 删除取消
  163. */
  164. const deleteDialogClose = () => {
  165. currentTaskId.value = null;
  166. deleteDialog.value.close();
  167. }
  168. /**
  169. * 归档确认
  170. */
  171. const archiveDialogConfirm = async () => {
  172. punchInApi.archiveTask({ id: currentTaskId.value })
  173. .then(ret => {
  174. uni.showToast({
  175. title: '归档成功',
  176. icon: 'success'
  177. });
  178. })
  179. .catch(err => {
  180. uni.showToast({
  181. title: '归档失败',
  182. icon: 'error'
  183. });
  184. })
  185. .finally(() => {
  186. currentTaskId.value = null;
  187. archiveDialog.value.close();
  188. loadData();
  189. });
  190. }
  191. /**
  192. * 归档取消
  193. */
  194. const archiveDialogClose = () => {
  195. currentTaskId.value = null;
  196. archiveDialog.value.close();
  197. }
  198. /**
  199. * 撤销确认
  200. */
  201. const revokeDialogConfirm = async () => {
  202. punchInApi.revokePunchIn({ id: currentTaskId.value })
  203. .then(ret => {
  204. uni.showToast({
  205. title: '撤销成功',
  206. icon: 'success'
  207. });
  208. })
  209. .catch(err => {
  210. currentTaskId.value = null;
  211. uni.showToast({
  212. title: '撤销失败',
  213. icon: 'error'
  214. });
  215. })
  216. .finally(() => {
  217. currentTaskId.value = null;
  218. revokeDialog.value.close();
  219. loadData();
  220. });
  221. }
  222. /**
  223. * 撤销取消
  224. */
  225. const revokeDialogClose = () => {
  226. currentTaskId.value = null;
  227. revokeDialog.value.close();
  228. }
  229. // 生命周期
  230. onShow(() => {
  231. loadData();
  232. });
  233. onPullDownRefresh(() => {
  234. loadData();
  235. uni.stopPullDownRefresh();
  236. });
  237. </script>
  238. <style lang="scss" scoped>
  239. .task-container {
  240. padding: 0rpx 24rpx;
  241. .task-header {
  242. position: relative;
  243. height: 80rpx;
  244. display: flex;
  245. justify-content: center;
  246. /* 水平居中 */
  247. align-items: center;
  248. /* 垂直居中 */
  249. .task-title {
  250. position: absolute;
  251. left: 0rpx;
  252. font-size: 30rpx;
  253. font-weight: 400;
  254. line-height: 43.44rpx;
  255. color: rgba(0, 0, 0, 1);
  256. }
  257. .task-add-btn {
  258. display: inline-flex;
  259. justify-content: center;
  260. align-items: center;
  261. position: absolute;
  262. right: 0rpx;
  263. width: 60rpx;
  264. height: 60rpx;
  265. border-radius: 10rpx;
  266. border: 3px solid rgba(64, 108, 231, 1);
  267. }
  268. }
  269. .task-item {
  270. margin-top: 16rpx;
  271. width: 100%;
  272. // height: 239rpx;
  273. border-radius: 24rpx;
  274. background: #FFFFFF;
  275. border: 0.5px solid #E4E4E4;
  276. box-shadow: 0px 1px 6px #D8D8D8;
  277. .main-box {
  278. padding: 16rpx 16rpx 16rpx 24rpx;
  279. .item-header {
  280. // position: relative;
  281. display: flex;
  282. align-items: center;
  283. .item-title {
  284. font-size: 30rpx;
  285. font-weight: 400;
  286. letter-spacing: 0rpx;
  287. line-height: 43.44rpx;
  288. color: #000000;
  289. }
  290. .item-reward {
  291. margin-left: 8rpx;
  292. font-size: 24rpx;
  293. font-weight: 400;
  294. letter-spacing: 0rpx;
  295. line-height: 34.75rpx;
  296. color: #000000;
  297. }
  298. .item-tag:first-child {
  299. margin-left: 24rpx;
  300. }
  301. .item-tag {
  302. margin-left: 16rpx;
  303. width: 94rpx;
  304. height: 38rpx;
  305. opacity: 1;
  306. border-radius: 24rpx;
  307. background: #FFFFFF;
  308. border: 1px solid #406CE7;
  309. display: inline-flex;
  310. justify-content: center;
  311. align-items: center;
  312. font-size: 18rpx;
  313. font-weight: 400;
  314. letter-spacing: 0rpx;
  315. // line-height: 26.06rpx;
  316. color: #406CE7;
  317. }
  318. .item-btn {
  319. display: inline-flex;
  320. position: absolute;
  321. right: 0rpx;
  322. width: 123rpx;
  323. height: 42rpx;
  324. border-radius: 30rpx;
  325. border: 1rpx solid #2A82E4;
  326. justify-content: center;
  327. align-items: center;
  328. font-size: 20rpx;
  329. font-weight: 400;
  330. line-height: 28.96px;
  331. color: rgba(64, 108, 231, 1);
  332. }
  333. }
  334. .item-desc {
  335. margin-top: 16rpx;
  336. font-size: 24rpx;
  337. font-weight: 400;
  338. letter-spacing: 0rpx;
  339. line-height: 34.75rpx;
  340. color: #000000;
  341. }
  342. .item-detail-list {
  343. margin-top: 16rpx;
  344. display: grid;
  345. grid-template-columns: repeat(7, 1fr);
  346. .item-detail {
  347. display: flex;
  348. flex-direction: column;
  349. justify-content: center;
  350. align-items: center;
  351. .detail-text {
  352. font-size: 20rpx;
  353. font-weight: 400;
  354. letter-spacing: 0rpx;
  355. line-height: 28.96rpx;
  356. color: rgba(0, 0, 0, 1);
  357. }
  358. .detail-box {
  359. // display: block;
  360. width: 42rpx;
  361. height: 42rpx;
  362. margin-top: 5rpx;
  363. border: 5rpx solid #000000;
  364. }
  365. }
  366. }
  367. }
  368. .btn-group {
  369. margin-top: 16rpx;
  370. display: flex;
  371. border-top: 1px solid #C7C7C7;
  372. .btn-item {
  373. flex-grow: 1;
  374. display: inline-flex;
  375. justify-content: center;
  376. align-items: center;
  377. padding: 0rpx 16rpx;
  378. font-size: 28rpx;
  379. font-weight: 400;
  380. letter-spacing: 0prx;
  381. line-height: 40.54rpx;
  382. color: #6A6A6A;
  383. }
  384. .btn-item:not(:last-child) {
  385. border-right: 1px solid #C7C7C7;
  386. }
  387. }
  388. }
  389. }
  390. </style>