ソースを参照

【feat】【v3】

1.增加用户中心✌️、待办任务页、任务列表页、关于我们、免责声明
2.完善工具js
3.完善常量js
ChenYL 9 ヶ月 前
コミット
37f0fdf83d

+ 27 - 30
src/apis/punchInApi.js

@@ -1,53 +1,48 @@
 import request from "@/utils/request";
 
 /**
- * 查询打卡任务列表
+ * 查询待办的打卡任务
  */
-export function queryPunchIns() {
+export function queryToDoList() {
   return request({
-    url: "/punchIn/queryPunchIns"
+    url: "/punchIn/queryToDoList"
   });
 }
 
 /**
- * 新增打卡任务
- * @param {Object} data
+ * 查询打卡任务列表
  */
-export function addPunchIn(data) {
+export function queryTaskList() {
   return request({
-    url: "/punchIn/savePunchIn",
-    method: "post",
-    data,
-	loading: true,
-	loadingText: "正在保存打卡任务,请稍后..."
+    url: "/punchIn/queryTaskList"
   });
 }
 
 /**
- * 更新打卡任务
+ * 保存打卡任务
  * @param {Object} data
  */
-export function updatePunchIn(data) {
+export function saveTask(data) {
   return request({
-    url: "/punchIn/updatePunchIn",
+    url: "/punchIn/saveTask",
     method: "post",
     data,
-	loading: true,
-	loadingText: "正在更新打卡任务,请稍后..."
+	  loading: true,
+	  loadingText: "正在保存打卡任务,请稍后..."
   });
 }
 
 /**
  * 删除打卡任务
- * @param {Object} data
+ * @param {Object} params
  */
-export function deletePunchIn(data) {
+export function deleteTask(params) {
   return request({
-    url: "/punchIn/deletePunchIn",
-    method: "post",
-	data,
-	loading: true,
-	loadingText: "正在删除打卡任务,请稍后..."
+    url: "/punchIn/deleteTask",
+    method: "DELETE",
+	  params,
+	  loading: true,
+	  loadingText: "正在删除打卡任务,请稍后..."
   });
 }
 
@@ -74,8 +69,8 @@ export function queryPunchInById(data) {
     url: "/punchIn/queryPunchInById",
     method: "post",
     data,
-	loading: true,
-	loadingText: "正在查询打卡任务,请稍后..."
+	  loading: true,
+	  loadingText: "正在查询打卡任务,请稍后..."
   });
 }
 
@@ -83,11 +78,13 @@ export function queryPunchInById(data) {
  * 归档打卡任务
  * @param {Object} data
  */
-export function archivePunchIn(data) {
+export function archiveTask(params) {
   return request({
-    url: "/punchIn/archivePunchIn",
+    url: "/punchIn/archiveTask",
     method: "post",
-    data
+    params,
+    loading: true,
+	  loadingText: "正在归档打卡任务,请稍后..."
   });
 }
 
@@ -107,11 +104,11 @@ export function remakePunchIn(data) {
  * 撤销打卡
  * @param {Object} data
  */
-export function revokePunchIn(data) {
+export function revokePunchIn(params) {
   return request({
     url: "/punchIn/revokePunchIn",
     method: "post",
-    data
+    params
   });
 }
 

+ 2 - 2
src/common/dict.js

@@ -1,7 +1,7 @@
 /**
  * 字典常量
  */
-const dictConst = {
+const dict = {
     /**
      * 刮刮乐来源
      */
@@ -38,4 +38,4 @@ const dictConst = {
     PUNCH_IN_RULE: "PUNCH_IN_RULE"	
 };
 
-export default dictConst;
+export default dict;

+ 26 - 0
src/common/enums.js

@@ -0,0 +1,26 @@
+//  打卡方式常量(单次-SINGLE、计数-COUNT、计时-TIMING)
+export const PUNCH_IN_METHOD = {
+  SINGLE: 'SINGLE',
+  COUNT: 'COUNT',
+  TIMING: 'TIMING'
+};
+
+// 打卡结果(完成-DONE、未完成-UNDONE)
+export const PUNCH_IN_RESULT = {
+  DONE: 'DONE',
+  UNDONE: 'UNDONE'
+};
+
+/**
+ * 比较规则(大于等于-GTE、小于等于-LTE)
+ */
+export const COMPARE_RULE = {
+  GTE: 'GTE',
+  LTE: 'LTE'
+};
+
+// 通用启用状态(启用-ENABLED、禁用-DISABLED)
+export const COMMON_ENABLED_STATUS = {
+  ENABLED: 'ENABLED',
+  DISABLED: 'DISABLED'
+}

+ 10 - 0
src/common/router.js

@@ -13,6 +13,16 @@ const router = {
 	 */
 	TASK_TODO_PAGE: '/pages/taskTodo',
 
+	/**
+     * 关于我们
+     */
+    ABOUT_US_PAGE: '/pages/userCenter/aboutUs',
+
+    /**
+     * 免责声明
+     */
+    DISCLAIMER_PAGE: '/pages/userCenter/disclaimer',
+
 	/**
 	 * 主页
 	 */

+ 27 - 11
src/pages.json

@@ -9,7 +9,8 @@
 		{
 			"path": "pages/taskTodo",
 			"style": {
-				"navigationBarTitleText": "待办"
+				"navigationBarTitleText": "待办",
+				"enablePullDownRefresh": true
 			}
 		},
 		{
@@ -21,13 +22,22 @@
 		{
 			"path": "pages/rewardMarket",
 			"style": {
-				"navigationBarTitleText": "商城"
+				"navigationBarTitleText": "商城",
+				"enablePullDownRefresh": true
 			}
 		},
 		{
 			"path": "pages/statData",
 			"style": {
-				"navigationBarTitleText": "data"
+				"navigationBarTitleText": "数据",
+				"enablePullDownRefresh": true
+			}
+		},
+		{
+			"path": "pages/taskList",
+			"style": {
+				"navigationBarTitleText": "任务",
+				"enablePullDownRefresh": true
 			}
 		},
 		{
@@ -37,9 +47,15 @@
 			}
 		},
 		{
-			"path": "pages/taskList",
+			"path": "pages/userCenter/aboutUs",
 			"style": {
-				"navigationBarTitleText": "任务"
+				"navigationBarTitleText": "关于我们"
+			}
+		}
+		{
+			"path": "pages/userCenter/disclaimer",
+			"style": {
+				"navigationBarTitleText": "免责声明"
 			}
 		}
 	],
@@ -55,6 +71,12 @@
 				"selectedIconPath": "static/todo_active.png",
 				"text": "待办"
 			},
+			{
+				"pagePath": "pages/taskList",
+				"iconPath": "static/task.png",
+				"selectedIconPath": "static/task_active.png",
+				"text": "任务"
+			},
 			{
 				"pagePath": "pages/rewardMarket",
 				"iconPath": "static/market.png",
@@ -67,12 +89,6 @@
 				"selectedIconPath": "static/data_active.png",
 				"text": "数据"
 			},
-			{
-				"pagePath": "pages/taskList",
-				"iconPath": "static/task.png",
-				"selectedIconPath": "static/task_active.png",
-				"text": "任务"
-			},
 			{
 				"pagePath": "pages/userCenter",
 				"iconPath": "static/user.png",

+ 464 - 2
src/pages/taskList.vue

@@ -1,8 +1,470 @@
 <template>
-  <div class="task">task</div>
+  <!-- 打卡任务 -->
+  <view class="task-container">
+    <view class="task-header">
+      <view class="task-title" v-if="tasks.length && tasks.length > 0">任务({{ tasks.length }}个)
+      </view>
+      <view class="task-title" v-else>任务</view>
+      <view class="task-add-btn" @click="goPunchInEditPage">
+        <uni-icons type="plusempty" size="30" color="#406CE7"></uni-icons>
+      </view>
+    </view>
+    <view class="task-item" v-for="task in tasks" :key="task.id">
+      <view class="main-box" @click="goPunchInDetailPage(task.id)">
+        <view class="item-header">
+          <span class="item-title">{{ task.taskName }}</span>
+          <span class="item-reward">x{{ task.points }}</span>
+          <view class="item-tag" v-if="task.fullAttendanceFlag">全勤奖励</view>
+          <view class="item-tag" v-if="task.weekendDoubleFlag">周末双倍</view>
+        </view>
+        <view class="item-desc">
+          描述:{{ task.description }}
+        </view>
+        <view class="item-detail-list">
+          <view class="item-detail" v-for="punchInRecord in task.piTaskHistorySimpleVOS"
+            :key="punchInRecord.punchInDate">
+            <view class="detail-text">
+              <uni-dateformat :date="punchInRecord.punchInDate" format="M/d"></uni-dateformat>
+            </view>
+            <view class="detail-box" style="background-color: #E5E5E5;"
+              v-if="punchInRecord.punchInResult == 'NOT_NEED'"></view>
+            <view class="detail-box" style="background-color: #A5D63F;" v-if="punchInRecord.punchInResult == 'DONE'">
+            </view>
+            <view class="detail-box" style="background-color: #D43030;" v-if="punchInRecord.punchInResult == 'UNDONE'">
+            </view>
+            <view class="detail-box" v-if="punchInRecord.punchInResult == 'FUTURE'">
+            </view>
+          </view>
+        </view>
+        <view class="btn-group">
+          <view class="btn-item" @click="deleteDialogOpen(task.id)">删除</view>
+          <view class="btn-item" @click="archiveDialogOpen(task.id)">归档</view>
+          <view class="btn-item" @click="revokeDialogOpen(task.id)">撤销</view>
+          <view class="btn-item">编辑</view>
+        </view>
+      </view>
+    </view>
+
+    <uni-load-more status="no-more" v-if="!tasks || tasks.length == 0" />
+
+    <!-- 删除确认框 -->
+    <uni-popup ref="deleteDialog" type="dialog">
+      <uni-popup-dialog mode="base" :before-close="true" title="删除提示" content="确认删除当前任务?" @confirm="deleteDialogConfirm"
+        @close="deleteDialogClose"></uni-popup-dialog>
+    </uni-popup>
+
+    <!-- 归档确认框 -->
+    <uni-popup ref="archiveDialog" type="dialog">
+      <uni-popup-dialog mode="base" :before-close="true" title="归档提示" content="确认归档当前任务?"
+        @confirm="archiveDialogConfirm" @close="archiveDialogClose"></uni-popup-dialog>
+    </uni-popup>
+
+    <!-- 撤销确认框 -->
+    <uni-popup ref="revokeDialog" type="dialog">
+      <uni-popup-dialog mode="base" :before-close="true" title="撤销提示" content="确认撤销打卡?" @confirm="revokeDialogConfirm"
+        @close="revokeDialogClose"></uni-popup-dialog>
+    </uni-popup>
+  </view>
 </template>
 
 <script setup>
+import { ref } from 'vue';
+import { onPullDownRefresh, onShow } from "@dcloudio/uni-app";
+import { punchInApi } from '@/apis/apis.js';
+import router from '@/common/router.js';
+
+// 组件
+/**
+ * 删除弹出框
+ */
+const deleteDialog = ref(null);
+
+/**
+ * 归档弹出框
+ */
+const archiveDialog = ref(null);
+
+/**
+ * 撤销弹出框
+ */
+const revokeDialog = ref(null);
+
+// 属性
+/**
+ * 当前操作的的任务ID
+ */
+const currentTaskId = ref(null);
+
+/**
+ * 打卡任务
+ */
+const tasks = ref([]);
+
+// 方法
+
+/**
+ * 跳转打卡编辑页面
+ */
+const goPunchInEditPage = () => {
+  uni.navigateTo({
+    url: router.PUNCHIN_EDIT_URL
+  });
+};
+
+/**
+ * 跳转打卡详情页面
+ */
+const goPunchInDetailPage = (id) => {
+  uni.navigateTo({
+    url: router.PUNCHIN_DETAIL_URL + "?id=" + id
+  });
+};
+
+/**
+ * 加载数据
+ */
+const loadData = async () => {
+  // 获取打卡
+  let res = await punchInApi.queryTaskList();
+  tasks.value = res;
+};
+
+/**
+ * 打开删除对话框
+ */
+const deleteDialogOpen = (id) => {
+  currentTaskId.value = id;
+  deleteDialog.value.open();
+}
+
+/**
+ * 打开归档对话框
+ */
+const archiveDialogOpen = (id) => {
+  currentTaskId.value = id;
+  archiveDialog.value.open();
+}
+
+/**
+ * 打开撤销对话框
+ */
+const revokeDialogOpen = (id) => {
+  currentTaskId.value = id;
+  revokeDialog.value.open();
+}
+
+/**
+ * 删除确认
+ */
+const deleteDialogConfirm = async () => {
+  punchInApi.deleteTask({ id: currentTaskId.value })
+    .then(ret => {
+      uni.showToast({
+        title: '删除成功',
+        icon: 'success'
+      });
+    })
+    .catch(err => {
+      uni.showToast({
+        title: '删除失败',
+        icon: 'error'
+      });
+    }).finally(() => {
+      currentTaskId.value = null;
+      deleteDialog.value.close();
+      loadData();
+    })
+    ;
+}
+
+/**
+ * 删除取消
+ */
+const deleteDialogClose = () => {
+  currentTaskId.value = null;
+  deleteDialog.value.close();
+}
+
+/**
+ * 归档确认
+ */
+const archiveDialogConfirm = async () => {
+  punchInApi.archiveTask({ id: currentTaskId.value })
+    .then(ret => {
+      uni.showToast({
+        title: '归档成功',
+        icon: 'success'
+      });
+    })
+    .catch(err => {
+      uni.showToast({
+        title: '归档失败',
+        icon: 'error'
+      });
+    })
+    .finally(() => {
+      currentTaskId.value = null;
+      archiveDialog.value.close();
+      loadData();
+    });
+}
+
+/**
+ * 归档取消
+ */
+const archiveDialogClose = () => {
+  currentTaskId.value = null;
+  archiveDialog.value.close();
+}
+
+/**
+ * 撤销确认
+ */
+const revokeDialogConfirm = async () => {
+  punchInApi.revokePunchIn({ id: currentTaskId.value })
+    .then(ret => {
+      uni.showToast({
+        title: '撤销成功',
+        icon: 'success'
+      });
+    })
+    .catch(err => {
+      currentTaskId.value = null;
+      uni.showToast({
+        title: '撤销失败',
+        icon: 'error'
+      });
+    })
+    .finally(() => {
+      currentTaskId.value = null;
+      revokeDialog.value.close();
+      loadData();
+    });
+}
+
+/**
+ * 撤销取消
+ */
+const revokeDialogClose = () => {
+  currentTaskId.value = null;
+  revokeDialog.value.close();
+}
+
+// 生命周期
+onShow(() => {
+  loadData();
+});
+
+onPullDownRefresh(() => {
+  loadData();
+  uni.stopPullDownRefresh();
+});
 </script>
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+.task-container {
+  padding: 0rpx 24rpx;
+
+  .task-header {
+    position: relative;
+    height: 80rpx;
+    display: flex;
+    justify-content: center;
+    /* 水平居中 */
+    align-items: center;
+    /* 垂直居中 */
+
+    .task-title {
+      position: absolute;
+      left: 0rpx;
+      font-size: 30rpx;
+      font-weight: 400;
+      line-height: 43.44rpx;
+      color: rgba(0, 0, 0, 1);
+    }
+
+    .task-add-btn {
+      display: inline-flex;
+      justify-content: center;
+      align-items: center;
+      position: absolute;
+      right: 0rpx;
+      width: 60rpx;
+      height: 60rpx;
+      border-radius: 10rpx;
+      border: 3px solid rgba(64, 108, 231, 1);
+    }
+  }
+
+  .task-item {
+    margin-top: 16rpx;
+    width: 100%;
+    // height: 239rpx;
+    border-radius: 24rpx;
+    background: #FFFFFF;
+    border: 0.5px solid #E4E4E4;
+    box-shadow: 0px 1px 6px #D8D8D8;
+
+    display: flex;
+
+    .main-box {
+      flex-grow: 1;
+      padding: 16rpx 16rpx 16rpx 24rpx;
+
+      .item-header {
+        // position: relative;
+        display: flex;
+        align-items: center;
+
+        .item-title {
+          font-size: 30rpx;
+          font-weight: 400;
+          letter-spacing: 0rpx;
+          line-height: 43.44rpx;
+          color: #000000;
+        }
+
+        .item-reward {
+          margin-left: 8rpx;
+          font-size: 24rpx;
+          font-weight: 400;
+          letter-spacing: 0rpx;
+          line-height: 34.75rpx;
+          color: #000000;
+        }
+
+        .item-tag:first-child {
+          margin-left: 24rpx;
+        }
+
+        .item-tag {
+          margin-left: 16rpx;
+          width: 94rpx;
+          height: 38rpx;
+          opacity: 1;
+          border-radius: 24rpx;
+          background: #FFFFFF;
+          border: 1px solid #406CE7;
+
+          display: inline-flex;
+          justify-content: center;
+          align-items: center;
+
+          font-size: 18rpx;
+          font-weight: 400;
+          letter-spacing: 0rpx;
+          // line-height: 26.06rpx;
+          color: #406CE7;
+
+        }
+
+        .item-btn {
+          display: inline-flex;
+          position: absolute;
+          right: 0rpx;
+          width: 123rpx;
+          height: 42rpx;
+          border-radius: 30rpx;
+          border: 1rpx solid #2A82E4;
+          justify-content: center;
+          align-items: center;
+
+          font-size: 20rpx;
+          font-weight: 400;
+          line-height: 28.96px;
+          color: rgba(64, 108, 231, 1);
+        }
+      }
+
+      .item-desc {
+        margin-top: 16rpx;
+        font-size: 24rpx;
+        font-weight: 400;
+        letter-spacing: 0rpx;
+        line-height: 34.75rpx;
+        color: #000000;
+      }
+
+      .item-detail-list {
+        margin-top: 16rpx;
+        display: grid;
+        grid-template-columns: repeat(7, 1fr);
+
+        .item-detail {
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+          align-items: center;
+
+          .detail-text {
+            font-size: 20rpx;
+            font-weight: 400;
+            letter-spacing: 0rpx;
+            line-height: 28.96rpx;
+            color: rgba(0, 0, 0, 1);
+          }
+
+          .detail-box {
+            // display: block;
+            width: 42rpx;
+            height: 42rpx;
+            margin-top: 5rpx;
+            border: 5rpx solid #000000;
+          }
+        }
+      }
+    }
+
+    .func-box {
+      flex-shrink: 0;
+      width: 160rpx;
+      border-radius: 0rpx 24rpx 24rpx 0rpx;
+
+
+      font-size: 36rpx;
+      font-weight: 400;
+      letter-spacing: 0rpx;
+      line-height: 52.13rpx;
+      color: #FFFFFF;
+
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      flex-direction: column;
+    }
+
+    .func-box-finish {
+      background: #F2607A;
+    }
+
+    .func-box-unfinish {
+      background: #406CE7;
+    }
+
+    .btn-group {
+      margin-top: 16rpx;
+      display: flex;
+      border-top: 1px solid #C7C7C7;
+
+      .btn-item {
+        flex-grow: 1;
+
+        display: inline-flex;
+        justify-content: center;
+        align-items: center;
+
+        padding: 0rpx 16rpx;
+        font-size: 28rpx;
+        font-weight: 400;
+        letter-spacing: 0prx;
+        line-height: 40.54rpx;
+        color: #6A6A6A;
+      }
+
+      .btn-item:not(:last-child) {
+        border-right: 1px solid #C7C7C7;
+      }
+    }
+  }
+}
+</style>

+ 379 - 2
src/pages/taskTodo.vue

@@ -1,8 +1,385 @@
 <template>
-  <div class="todo">todo</div>
+
+  <!-- 打卡任务 -->
+  <view class="task-container">
+    <view class="task-header">
+      <view class="task-title" v-if="tasks.length && tasks.length > 0">任务({{ tasks.length }}个)
+      </view>
+      <view class="task-title" v-else>任务</view>
+      <view class="task-add-btn" @click="goPunchInEditPage">
+        <uni-icons type="plusempty" size="30" color="#406CE7"></uni-icons>
+      </view>
+    </view>
+    <view class="task-item" v-for="task in tasks" :key="task.id">
+      <view class="main-box" @click="goPunchInDetailPage(task.id)">
+        <view class="item-header">
+          <span class="item-title">{{ task.taskName }}</span>
+          <span class="item-reward">x{{ task.points }}</span>
+          <view class="item-tag" v-if="task.fullAttendanceFlag">全勤奖励</view>
+          <view class="item-tag" v-if="task.holidayFlag">节假日双倍</view>
+        </view>
+        <view class="item-desc"
+          v-if="task.punchInMethod == PUNCH_IN_METHOD.COUNT || task.punchInMethod == PUNCH_IN_METHOD.TIMING">
+          <span v-if="task.punchInMethod == PUNCH_IN_METHOD.COUNT">规则:打卡次数</span>
+          <span v-if="task.punchInMethod == PUNCH_IN_METHOD.TIMING">规则:计时时间</span>
+          <dict-item :dictCode="dict.PUNCH_IN_RULE" :itemCode="task.rule"></dict-item>
+          <span v-if="task.compareRule == COMPARE_RULE.GTE">大于等于</span>
+          <span v-if="task.compareRule == COMPARE_RULE.LTE">小于等于等于</span>
+          <span v-if="task.punchInMethod == PUNCH_IN_METHOD.COUNT">{{ holidayFlag ? task.holidayCountTrack :
+            task.countTrack }}次</span>
+          <span v-if="task.punchInMethod == PUNCH_IN_METHOD.TIMING">{{ holidayFlag ? task.holidayTimeTrack :
+            task.timeTrack.slice(0, 5) }}</span>
+        </view>
+        <view class="item-desc">
+          描述:{{ task.description }}
+        </view>
+      </view>
+      <view
+        :class="task.punchInResult == PUNCH_IN_RESULT.DONE ? 'func-box func-box-finish' : 'func-box func-box-unfinish'"
+        v-if="task.punchInMethod == PUNCH_IN_METHOD.SINGLE" @click="doPunchIn(task.id)">
+        <span v-if="task.punchInResult == PUNCH_IN_RESULT.UNDONE">打卡</span>
+        <span v-else>已完成</span>
+      </view>
+      <view
+        :class="task.punchInResult == PUNCH_IN_RESULT.DONE ? 'func-box func-box-finish' : 'func-box func-box-unfinish'"
+        v-if="task.punchInMethod == PUNCH_IN_METHOD.COUNT" @click="doPunchIn(task.id)">
+        <span>{{ task.currentCountTrack }}</span>
+        <span>计数</span>
+      </view>
+      <view
+        :class="task.punchInResult == PUNCH_IN_RESULT.DONE ? 'func-box func-box-finish' : 'func-box func-box-unfinish'"
+        v-if="task.punchInMethod == PUNCH_IN_METHOD.TIMING" @click="doPunchInForTimeTrack(task.id, task.timeTrack)">
+        <span>
+          {{ task.currentTimeTrack.slice(0, 5) }}
+        </span>
+        <span>计时</span>
+      </view>
+    </view>
+
+    <uni-load-more status="no-more" v-if="!tasks || tasks.length == 0" />
+  </view>
+
+  <!-- 计时弹出框 -->
+  <uni-popup ref="timeTrackInputDialog" type="dialog" :is-mask-click="false">
+    <uni-popup-dialog mode="input" :before-close="true" title="计时记录" confirmText="保存" @confirm="timeTrackFormConfirm"
+      @close="timeTrackFormClose">
+      <view class="pick-box" @click="timeTrackClick">
+        <picker mode="time" :value="timeTrackFormData.timeTrack" @change="timeTrackChange">
+          <view class="pick-box-time">{{ timeTrackFormData.timeTrack }}</view>
+        </picker>
+      </view>
+      <view style="display: none;">
+        <uni-forms ref="timeTrackForm" :modelValue="timeTrackFormData" :rules="timeTrackFormRules">
+          <uni-forms-item name="timeTrack">
+            <uni-easyinput v-model="timeTrackFormData.timeTrack" />
+          </uni-forms-item>
+        </uni-forms>
+      </view>
+    </uni-popup-dialog>
+  </uni-popup>
 </template>
 
 <script setup>
+import { ref } from 'vue';
+import { onPullDownRefresh, onShow } from "@dcloudio/uni-app";
+import { punchInApi } from '@/apis/apis.js';
+import router from '@/common/router.js';
+import dict from '@/common/dict.js';
+import { PUNCH_IN_METHOD, PUNCH_IN_RESULT, COMPARE_RULE } from '@/common/enums.js';
+
+// 组件
+
+/**
+ * 计时弹出框
+ */
+const timeTrackInputDialog = ref(null);
+
+/**
+ * 计时表单
+ */
+const timeTrackForm = ref(null);
+
+
+// 属性
+/**
+ * 打卡任务
+ */
+const tasks = ref([]);
+
+/**
+ * 计时表单数据
+ */
+const timeTrackFormData = ref({
+  timeTrack: '00:00'
+});
+
+/**
+ * 计时表单规则
+ */
+const timeTrackFormRules = ref({
+  timeTrack: {
+    rules: [{
+      required: true,
+      errorMessage: "请输入时间"
+    }]
+  }
+});
+
+
+// 方法
+/**
+ * 计时时间选择监听
+ */
+const timeTrackChange = (e) => {
+  timeTrackFormData.value.timeTrack = e.detail.value;
+}
+
+/**
+ * 打卡(计时)
+ */
+const doPunchInForTimeTrack = (id, timeTrack) => {
+  // 重置上一轮的表单数据
+  timeTrackFormData.value = {
+    id,
+    timeTrack: timeTrack ? timeTrack.slice(0, 5) : '00:00'
+  };
+  timeTrackInputDialog.value.open();
+}
+
+/**
+ * 计时表单提交
+ */
+const timeTrackFormConfirm = async () => {
+  timeTrackForm.value.validate(['id']).then(data => {
+    return punchInApi.doPunchIn(data);
+  }).then(e => {
+    timeTrackInputDialog.value.close();
+    loadData();
+  });
+}
+
+
+/**
+ * 打卡
+ */
+const doPunchIn = async (id) => {
+  await punchInApi.doPunchIn({
+    id
+  });
+  loadData();
+}
+
+/**
+ * 跳转打卡编辑页面
+ */
+const goPunchInEditPage = () => {
+  uni.navigateTo({
+    url: router.PUNCHIN_EDIT_URL
+  });
+};
+
+/**
+ * 跳转打卡详情页面
+ */
+const goPunchInDetailPage = (id) => {
+  uni.navigateTo({
+    url: router.PUNCHIN_DETAIL_URL + "?id=" + id
+  });
+};
+
+/**
+ * 获取待办任务
+ */
+const loadData = async () => {
+  let res = await punchInApi.queryToDoList();
+  tasks.value = res;
+};
+
+onShow(() => {
+  loadData();
+});
+
+onPullDownRefresh(() => {
+  loadData();
+  uni.stopPullDownRefresh();
+});
 </script>
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+.task-container {
+  padding: 0rpx 24rpx;
+
+  .task-header {
+    position: relative;
+    height: 80rpx;
+    display: flex;
+    justify-content: center;
+    /* 水平居中 */
+    align-items: center;
+    /* 垂直居中 */
+
+    .task-title {
+      position: absolute;
+      left: 0rpx;
+      font-size: 30rpx;
+      font-weight: 400;
+      line-height: 43.44rpx;
+      color: rgba(0, 0, 0, 1);
+    }
+
+    .task-add-btn {
+      display: inline-flex;
+      justify-content: center;
+      align-items: center;
+      position: absolute;
+      right: 0rpx;
+      width: 60rpx;
+      height: 60rpx;
+      border-radius: 10rpx;
+      border: 3px solid rgba(64, 108, 231, 1);
+    }
+  }
+
+  .task-item {
+    margin-top: 16rpx;
+    width: 100%;
+    // height: 239rpx;
+    border-radius: 24rpx;
+    background: #FFFFFF;
+    border: 0.5px solid #E4E4E4;
+    box-shadow: 0px 1px 6px #D8D8D8;
+
+    display: flex;
+
+    .main-box {
+      flex-grow: 1;
+      padding: 16rpx 16rpx 16rpx 24rpx;
+
+      .item-header {
+        // position: relative;
+        display: flex;
+        align-items: center;
+
+        .item-title {
+          font-size: 30rpx;
+          font-weight: 400;
+          letter-spacing: 0rpx;
+          line-height: 43.44rpx;
+          color: #000000;
+        }
+
+        .item-reward {
+          margin-left: 8rpx;
+          font-size: 24rpx;
+          font-weight: 400;
+          letter-spacing: 0rpx;
+          line-height: 34.75rpx;
+          color: #000000;
+        }
+
+        .item-tag:first-child {
+          margin-left: 24rpx;
+        }
+
+        .item-tag {
+          margin-left: 16rpx;
+          width: 94rpx;
+          height: 38rpx;
+          opacity: 1;
+          border-radius: 24rpx;
+          background: #FFFFFF;
+          border: 1px solid #406CE7;
+
+          display: inline-flex;
+          justify-content: center;
+          align-items: center;
+
+          font-size: 18rpx;
+          font-weight: 400;
+          letter-spacing: 0rpx;
+          // line-height: 26.06rpx;
+          color: #406CE7;
+
+        }
+
+        .item-btn {
+          display: inline-flex;
+          position: absolute;
+          right: 0rpx;
+          width: 123rpx;
+          height: 42rpx;
+          border-radius: 30rpx;
+          border: 1rpx solid #2A82E4;
+          justify-content: center;
+          align-items: center;
+
+          font-size: 20rpx;
+          font-weight: 400;
+          line-height: 28.96px;
+          color: rgba(64, 108, 231, 1);
+        }
+      }
+
+      .item-desc {
+        margin-top: 16rpx;
+        font-size: 24rpx;
+        font-weight: 400;
+        letter-spacing: 0rpx;
+        line-height: 34.75rpx;
+        color: #000000;
+      }
+    }
+
+    .func-box {
+      flex-shrink: 0;
+      width: 160rpx;
+      border-radius: 0rpx 24rpx 24rpx 0rpx;
+
+
+      font-size: 36rpx;
+      font-weight: 400;
+      letter-spacing: 0rpx;
+      line-height: 52.13rpx;
+      color: #FFFFFF;
+
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      flex-direction: column;
+    }
+
+    .func-box-finish {
+      background: #F2607A;
+    }
+
+    .func-box-unfinish {
+      background: #406CE7;
+    }
+  }
+}
+
+.pick-box {
+  width: 100%;
+  height: 100rpx;
+  border-radius: 8px;
+  background: #ffffff;
+  // 阴影
+  border: 0.5px solid #e4e4e4;
+
+  picker {
+    width: 100%;
+    height: 100%;
+
+    .pick-box-time {
+      width: 100%;
+      height: 100rpx;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      color: #000000;
+      border-radius: 24rpx;
+      text-align: center;
+    }
+  }
+}
+</style>

+ 120 - 4
src/pages/userCenter.vue

@@ -22,14 +22,72 @@
       </uni-list>
     </view>
 
+    <view class="mt24 stat-board" v-if="loginStatus">
+      <view class="stat-board-box">
+        <view class="stat-item">
+          <view class="stat-title">积分</view>
+        </view>
+        <view class="stat-item">
+          <view class="stat-item-label">待使用</view>
+          <view class="stat-item-value">{{ userInfo.unusedPoints }}</view>
+        </view>
+        <view class="stat-item">
+          <view class="stat-item-label">已使用</view>
+          <view class="stat-item-value">{{ userInfo.usedPoints }}</view>
+        </view>
+        <view class="stat-item">
+          <view class="stat-item-label">总积分</view>
+          <view class="stat-item-value">{{ userInfo.totalPoints }}</view>
+        </view>
+      </view>
+      <view class="stat-board-box stat-mt16">
+        <view class="stat-item">
+          <view class="stat-title">彩票</view>
+        </view>
+        <view class="stat-item">
+          <view class="stat-item-label">购买</view>
+          <view class="stat-item-value">{{ userInfo.totalConsumeAmount }}元</view>
+        </view>
+        <view class="stat-item">
+          <view class="stat-item-label">中奖</view>
+          <view class="stat-item-value">{{ userInfo.totalWinAmount }}元</view>
+        </view>
+        <view class="stat-item">
+          <view class="stat-item-label"></view>
+          <view class="stat-item-value"></view>
+        </view>
+      </view>
+    </view>
+
     <view class="mt24" v-if="loginStatus">
       <uni-list :border="true">
-        <uni-list-item title="订单记录" :showArrow="true" :showExtraIcon="true"
-          :extraIcon="{ color: '#000000', size: 22, type: 'list' }" link="navigateTo" :to="router.ORDER_LIST_PAGE">
+        <uni-list-item title="积分结算记录" :showArrow="true" :showExtraIcon="true"
+          :extraIcon="{ color: '#000000', size: 22, type: 'info' }" link="navigateTo" :to="router.ABOUT_US_PAGE">
+        </uni-list-item>
+        <uni-list-item title="积分兑换记录" :showArrow="true" :showExtraIcon="true" clickable
+          :extraIcon="{ color: '#000000', size: 22, type: 'minus' }" link="navigateTo" :to="router.DISCLAIMER_PAGE">
+        </uni-list-item>
+        <uni-list-item title="彩票消费与中奖记录" :showArrow="true" :showExtraIcon="true"
+          :extraIcon="{ color: '#000000', size: 22, type: 'info' }" link="navigateTo" :to="router.ABOUT_US_PAGE">
+        </uni-list-item>
+        <uni-list-item title="账户转账记录" :showArrow="true" :showExtraIcon="true" clickable
+          :extraIcon="{ color: '#000000', size: 22, type: 'minus' }" link="navigateTo" :to="router.DISCLAIMER_PAGE">
         </uni-list-item>
       </uni-list>
     </view>
 
+    <view class="mt24" v-if="loginStatus">
+      <uni-list :border="true">
+        <uni-list-item title="积分账户" :showArrow="true" :showExtraIcon="true"
+          :extraIcon="{ color: '#000000', size: 22, type: 'info' }" link="navigateTo" :to="router.ABOUT_US_PAGE">
+        </uni-list-item>
+        <uni-list-item title="兑换列表" :showArrow="true" :showExtraIcon="true" clickable
+          :extraIcon="{ color: '#000000', size: 22, type: 'minus' }" link="navigateTo" :to="router.DISCLAIMER_PAGE">
+        </uni-list-item>
+      </uni-list>
+    </view>
+
+
     <view class="mt24">
       <uni-list :border="true">
         <uni-list-item title="关于我们" :showArrow="true" :showExtraIcon="true"
@@ -154,7 +212,7 @@ const logout = () => {
       uni.removeStorageSync(cacheKey.NICKNAME);
       // 跳转到主页
       uni.reLaunch({
-        url: router.SUBSCRIPTION_SOURCE_MARKET_PAGE,
+        url: router.TASK_TODO_PAGE
       });
     }
   });
@@ -215,7 +273,7 @@ onShow(() => {
 }
 
 .mt24 {
-  margin-top: 24rpx;
+  margin-top: 16rpx;
 }
 
 .placehold {
@@ -267,4 +325,62 @@ onShow(() => {
     text-align: center;
   }
 }
+
+.stat-board {
+  background-color: #ffffff;
+  padding: 16rpx 64rpx 16rpx 24rpx;
+
+  .stat-mt16 {
+    margin-top: 16rpx;
+  }
+
+  .stat-board-box {
+    display: flex;
+
+    .stat-item {
+      flex: 1;
+      display: inline-block;
+
+      .stat-title {
+        width: 100%;
+        height: 100%;
+        font-size: 32rpx;
+        font-weight: 400;
+        letter-spacing: 0rpx;
+        line-height: 46.34rpx;
+        color: #000000;
+        text-align: center;
+
+        display: flex;
+        /* 启用flex布局 */
+        justify-content: center;
+        /* 水平居中 */
+        align-items: center;
+        /* 垂直居中 */
+      }
+
+      .stat-item-label {
+        font-size: 24rpx;
+        font-weight: 400;
+        letter-spacing: 0rpx;
+        line-height: 34.75rpx;
+        color: #000000;
+        text-align: center;
+        vertical-align: middle;
+      }
+
+      .stat-item-value {
+        font-size: 32rpx;
+        font-weight: 400;
+        letter-spacing: 0rpx;
+        line-height: 46.34rpx;
+        color: #000000;
+        text-align: center;
+        vertical-align: middle;
+      }
+    }
+  }
+
+
+}
 </style>

+ 67 - 0
src/pages/userCenter/aboutUs.vue

@@ -0,0 +1,67 @@
+<template>
+  <view class="box">
+    <view class="main-content">设计:小石</view>
+    <view class="main-content">前端:小石</view>
+    <view class="main-content">后端:小石</view>
+    <view class="second-content">我是后端工程师,出于个人爱好,设计并开发了本小程序,不足之处还望包涵,如有任何建议或意见,欢迎提出。</view>
+    <view class="main-content">
+      联系方式:<button class="concat-btn" open-type="contact">》》》点击联系客服《《《</button>
+    </view>
+
+  </view>
+</template>
+
+<script setup>
+</script>
+
+<style lang="scss" scoped>
+.box {
+  padding: 16rpx 24rpx;
+
+  .main-content,
+  .second-content {
+    margin-bottom: 16rpx;
+  }
+
+  .main-content {
+    font-size: 30rpx;
+    font-weight: 400;
+    letter-spacing: 0rpx;
+    line-height: 43.44rpx;
+    color: #000000;
+    text-align: left;
+    vertical-align: top;
+  }
+
+  .second-content {
+    font-size: 24rpx;
+    font-weight: 400;
+    letter-spacing: 0rpx;
+    line-height: 34.75rpx;
+    color: #6a6a6a;
+    text-align: left;
+    vertical-align: top;
+  }
+
+  .concat-btn {
+    display: inline-block;
+    color: #4a90e2;
+
+    font-size: 30rpx;
+    font-weight: 400;
+    letter-spacing: 0rpx;
+    line-height: 43.44rpx;
+    text-align: left;
+    vertical-align: top;
+    padding: 0;
+    margin: 0;
+    border: none;
+    outline: none;
+    background: none;
+  }
+
+  button::after {
+    border: none;
+  }
+}
+</style>

+ 72 - 0
src/pages/userCenter/disclaimer.vue

@@ -0,0 +1,72 @@
+<template>
+  <view class="box">
+    <view class="term">
+      <view class="title">1.信息收集与使用</view>
+      <view class="content">刮刮打卡小程序不要求用户授权任何权限,不会后台收集用户的任何信息,程序使用过程中产生的数据归开发者所有。</view>
+    </view>
+
+    <view class="term">
+      <view class="title">2.使用限制</view>
+      <view class="content">刮刮打卡小程序请勿用于非法活动,由此产生的后果,开发者概不负责。小程序用户默认同意此限制。</view>
+    </view>
+
+    <view class="term">
+      <view class="title">3.联系方式</view>
+      <view><button class="concat-btn" open-type="contact">》》》点击联系客服《《《</button></view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+</script>
+
+<style lang="scss" scoped>
+.box {
+  padding: 16rpx 24rpx;
+}
+
+.term {
+  margin-bottom: 24rpx;
+
+  .title {
+    font-size: 30rpx;
+    font-weight: 400;
+    letter-spacing: 0rpx;
+    line-height: 43.44rpx;
+    color: #000000;
+    text-align: left;
+    vertical-align: top;
+  }
+
+  .content {
+    font-size: 24rpx;
+    font-weight: 400;
+    letter-spacing: 0rpx;
+    line-height: 34.75rpx;
+    color: #6a6a6a;
+    text-align: left;
+    vertical-align: top;
+  }
+
+  .concat-btn {
+    display: inline-block;
+    color: #4a90e2;
+
+    font-size: 30rpx;
+    font-weight: 400;
+    letter-spacing: 0rpx;
+    line-height: 43.44rpx;
+    text-align: left;
+    vertical-align: top;
+    padding: 0;
+    margin: 0;
+    border: none;
+    outline: none;
+    background: none;
+  }
+
+  button::after {
+    border: none;
+  }
+}
+</style>

+ 10 - 1
src/utils/request.js

@@ -5,6 +5,7 @@ export default function request(config = {}) {
 
 	let {
 		url,
+		params,
 		data = {},
 		method = "GET",
 		header = {},
@@ -14,6 +15,13 @@ export default function request(config = {}) {
 
 	// 拼接url
 	url = process.env.BASE_API_URL + url;
+	
+	// 拼接查询字符串
+	if (params) {
+		let queryString = Object.keys(params).map(key => `${key}=${encodeURIComponent(params[key])}`).join('&');
+		url = `${url}?${queryString}`;
+	}
+	
 
 	// 添加token
 	let token = uni.getStorageSync(cacheKey.TOKEN);
@@ -47,7 +55,7 @@ export default function request(config = {}) {
 						success: function (res) {
 							if (res.confirm) {
 								uni.navigateTo({
-									url: router.LOGIN_URL
+									url: router.LOGIN_PAGE
 								});
 							}
 						}
@@ -58,6 +66,7 @@ export default function request(config = {}) {
 				if (res.data.code === '0') {
 					resolve(res.data.data);
 				} else if (res.data.code === '999') {
+					console.log("9999 lalall ");
 					uni.showModal({
 						title: "错误提示",
 						content: res.data.msg,