Преглед на файлове

feature:增加注册须知,首页增加考试报名状态

liuzhenlin преди 2 седмици
родител
ревизия
b04f9254b5
променени са 2 файла, в които са добавени 349 реда и са изтрити 211 реда
  1. 239 208
      src/view/home/index.vue
  2. 110 3
      src/view/login/index.vue

+ 239 - 208
src/view/home/index.vue

@@ -67,7 +67,8 @@
     </div>
     <div class="swipe-con flex justify-between mt10">
       <van-swipe class="my-swipe" :autoplay="5000" :show-indicators="false" vertical height="30">
-        <van-swipe-item v-for="item in noticeList" :key="item.id" @click="onRouterPush('/notice/detail', { id: item.id })">
+        <van-swipe-item v-for="item in noticeList" :key="item.id"
+          @click="onRouterPush('/notice/detail', { id: item.id })">
           <div class="flex justify-between">
             <span>{{ `【${item.noticeType === '10' ? '公告' : '通知'}】${item.noticeTitle}` }}</span>
             <span class="time">{{ formatDate(new Date(item.noticeTime), 'YYYY-mm-dd') }}</span>
@@ -101,7 +102,12 @@
       </h4>
       <ul class="approval">
         <li v-for="item in trainingList" :key="item.id" @click="onRouterPush('/training/enroll', { state: item.id })">
-          <van-text-ellipsis :content="`${item.title}`" />
+          <div class="flex justify-between">
+            <van-text-ellipsis :content="`${item.title}`" />
+            <van-tag v-if="item.status === '40'">已结束</van-tag>
+            <van-tag v-if="item.status !== '40' && item.applyStatus === '10'" type="warning">未报名</van-tag>
+            <van-tag v-else-if="item.status !== '40' && item.applyStatus === '20'" type="primary">已报名</van-tag>
+          </div>
           <footer class="flex justify-between">
             <span>发布人:{{ item.createdName }}</span>
             <span>{{ formatDate(new Date(item.startTime), 'YYYY-mm-dd') }}</span>
@@ -113,239 +119,264 @@
 </template>
 
 <script name="home" lang="ts" setup>
-  import to from 'await-to-js'
-  import { formatDate } from '/@/utils/formatTime'
-  import { onMounted, reactive, ref } from 'vue'
-  import { useDictApi } from '/@/api/system/dict'
-  import { useProApi } from '/@/api/project'
-  import { useDeptApi } from '/@/api/system/dept'
-  import { useExecutionApi } from '/@/api/execution'
-  import { useNewsApi } from '/@/api/system/news'
-  import { useUserApi } from '/@/api/system/user'
-  import { useTrainingApi } from '/@/api/training'
-  import { useRouter } from 'vue-router'
-  import {useUserInfo} from '/@/stores/userInfo'
+import to from 'await-to-js'
+import { formatDate } from '/@/utils/formatTime'
+import { onMounted, reactive, ref } from 'vue'
+import { useDictApi } from '/@/api/system/dict'
+import { useProApi } from '/@/api/project'
+import { useDeptApi } from '/@/api/system/dept'
+import { useExecutionApi } from '/@/api/execution'
+import { useNewsApi } from '/@/api/system/news'
+import { useUserApi } from '/@/api/system/user'
+import { useTrainingApi } from '/@/api/training'
+import { useRouter } from 'vue-router'
+import { useUserInfo } from '/@/stores/userInfo'
 
-  import { useUserInfos } from '/@/hooks/useUserInfos'
+import { useUserInfos } from '/@/hooks/useUserInfos'
 
-  const { userInfos } = useUserInfos()
-  const newsApi = useNewsApi()
-  const dictApi = useDictApi()
-  const proApi = useProApi()
-  const deptApi = useDeptApi()
-  const executionApi = useExecutionApi()
-  const trainingApi = useTrainingApi()
-  const approvalList = ref<any[]>([])
-  const noticeList = ref<any[]>([])
-  const trainingList = ref<any[]>([])
-  const userTypeList = ref(<RowDicDataType[]>[])
-  const userSexList = ref(<RowDicDataType[]>[])
-  const userCertList = ref(<RowDicDataType[]>[])
-  const deptData = ref(<any[]>[])
-  const pjtList = ref(<any[]>[])
-  const pjtTypeList = ref(<any[]>[])
-  const router = useRouter()
-  const state = reactive({
-    form: {
-      keyWord: ''
-    }
-  })
-  const getDicts = () => {
-    Promise.all([
-      dictApi.getDictDataByType('sys_user_type'),
-      dictApi.getDictDataByType('sys_com_sex'),
-      dictApi.getDictDataByType('sys_user_certificate'),
-      deptApi.getDeptTree(),
-      proApi.getProjectGroupListForApp({ noPage: true }),
-      dictApi.getDictDataByType('sci_pjt_level'),
-    ]).then(([type, sex, cert, dept, pjt, pjtType]) => {
-      userTypeList.value = type.data.values || []
-      userSexList.value = sex.data.values || []
-      userCertList.value = cert.data.values || []
-      deptData.value = dept.data || []
-      pjtList.value = pjt.data.list || []
-      pjtTypeList.value = pjtType.data.values || []
-    })
-  }
-  const getApprovalList = async () => {
-    // todo 平台id参数需要删除
-    const [err, res]: ToResponse = await to(executionApi.getOwApproveList({ platformId: 1000103, pageNum: 1, pageSize: 3 }))
-    if (err) return
-    approvalList.value = res?.data?.list || []
+const { userInfos } = useUserInfos()
+const newsApi = useNewsApi()
+const dictApi = useDictApi()
+const proApi = useProApi()
+const deptApi = useDeptApi()
+const executionApi = useExecutionApi()
+const trainingApi = useTrainingApi()
+const approvalList = ref<any[]>([])
+const noticeList = ref<any[]>([])
+const trainingList = ref<any[]>([])
+const userTypeList = ref(<RowDicDataType[]>[])
+const userSexList = ref(<RowDicDataType[]>[])
+const userCertList = ref(<RowDicDataType[]>[])
+const deptData = ref(<any[]>[])
+const pjtList = ref(<any[]>[])
+const pjtTypeList = ref(<any[]>[])
+const router = useRouter()
+const state = reactive({
+  form: {
+    keyWord: ''
   }
-  const getNotice = async () => {
-    const [err, res]: ToResponse = await to(newsApi.getNoticeList())
-    if (err) return
-    noticeList.value = res?.data?.list || []
-  }
-  const getTrainingList = async () => {
-    const [err, res]: ToResponse = await to(trainingApi.getList({ pageNum: 1, pageSize: 3 }))
-    if (err) return
-    trainingList.value = res?.data?.list || []
-  }
-  const onSearch = () => {}
-  const onRouterPush = (val: string, params?: any) => {
-    router.push({
-      path: val,
-      query: { ...params }
-    })
-  }
-  onMounted(() => {
-    getDicts()
-    getApprovalList()
-    getNotice()
-    getTrainingList()
-    useUserApi().updateUserWxInfo({
-      wechatOpenId: localStorage.getItem('openId'),
-      wechatUnionId: localStorage.getItem('unionId')
-    })
+})
+const getDicts = () => {
+  Promise.all([
+    dictApi.getDictDataByType('sys_user_type'),
+    dictApi.getDictDataByType('sys_com_sex'),
+    dictApi.getDictDataByType('sys_user_certificate'),
+    deptApi.getDeptTree(),
+    proApi.getProjectGroupListForApp({ noPage: true }),
+    dictApi.getDictDataByType('sci_pjt_level'),
+  ]).then(([type, sex, cert, dept, pjt, pjtType]) => {
+    userTypeList.value = type.data.values || []
+    userSexList.value = sex.data.values || []
+    userCertList.value = cert.data.values || []
+    deptData.value = dept.data || []
+    pjtList.value = pjt.data.list || []
+    pjtTypeList.value = pjtType.data.values || []
+  })
+}
+const getApprovalList = async () => {
+  // todo 平台id参数需要删除
+  const [err, res]: ToResponse = await to(executionApi.getOwApproveList({ platformId: 1000103, pageNum: 1, pageSize: 3 }))
+  if (err) return
+  approvalList.value = res?.data?.list || []
+}
+const getNotice = async () => {
+  const [err, res]: ToResponse = await to(newsApi.getNoticeList())
+  if (err) return
+  noticeList.value = res?.data?.list || []
+}
+const getTrainingList = async () => {
+  const [err, res]: ToResponse = await to(trainingApi.getListForUser({ pageNum: 1, pageSize: 3, isAll: "10" }))
+  if (err) return
+  trainingList.value = res?.data?.list || []
+}
+const onSearch = () => { }
+const onRouterPush = (val: string, params?: any) => {
+  router.push({
+    path: val,
+    query: { ...params }
+  })
+}
+onMounted(() => {
+  getDicts()
+  getApprovalList()
+  getNotice()
+  getTrainingList()
+  useUserApi().updateUserWxInfo({
+    wechatOpenId: localStorage.getItem('openId'),
+    wechatUnionId: localStorage.getItem('unionId')
   })
+})
 </script>
 
 <style lang="scss" scoped>
-  .app-container {
-    header {
-      padding: 12px;
-      border-radius: 8px;
-      background-color: #1c9bfd;
-      margin-top: 10px;
-      .search {
-        display: flex;
-        border-radius: 4px;
-        overflow: hidden;
-        height: 28px;
-        input {
-          flex: 1;
-          outline: none;
-          border: none;
-          padding: 0 10px;
-          line-height: 28px;
-        }
-        button {
-          border: none;
-          border-left: 1px solid #d7d7d7;
-          background-color: #fff;
-          color: #3c78e5;
-          padding: 0 20px;
-          font-weight: bold;
-        }
+.app-container {
+  header {
+    padding: 12px;
+    border-radius: 8px;
+    background-color: #1c9bfd;
+    margin-top: 10px;
+
+    .search {
+      display: flex;
+      border-radius: 4px;
+      overflow: hidden;
+      height: 28px;
+
+      input {
+        flex: 1;
+        outline: none;
+        border: none;
+        padding: 0 10px;
+        line-height: 28px;
       }
-      ul {
-        display: flex;
-        justify-content: space-between;
-        margin-top: 10px;
-        li {
-          color: #fff;
-          height: 14px;
-          line-height: 14px;
-          &::before {
-            display: inline-block;
-            content: '';
-            height: 14px;
-            width: 14px;
-            border-radius: 9px;
-            background-color: #ffff;
-            vertical-align: top;
-            margin-right: 2px;
-          }
-        }
+
+      button {
+        border: none;
+        border-left: 1px solid #d7d7d7;
+        background-color: #fff;
+        color: #3c78e5;
+        padding: 0 20px;
+        font-weight: bold;
       }
     }
-    .card {
-      min-height: 60px;
+
+    ul {
+      display: flex;
+      justify-content: space-between;
       margin-top: 10px;
-      border-radius: 4px;
-      background-color: #fff;
-      padding: 10px;
-      box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
-      h4 {
-        height: 18px;
-        line-height: 18px;
-        display: flex;
-        span {
-          font-weight: normal;
-          margin-left: auto;
-        }
+
+      li {
+        color: #fff;
+        height: 14px;
+        line-height: 14px;
+
         &::before {
           display: inline-block;
           content: '';
-          width: 3px;
-          height: 18px;
-          background-color: #1c9bfd;
-          margin-right: 4px;
-          vertical-align: middle;
+          height: 14px;
+          width: 14px;
+          border-radius: 9px;
+          background-color: #ffff;
+          vertical-align: top;
+          margin-right: 2px;
         }
       }
-      .time {
-        color: #f69a4d;
+    }
+  }
+
+  .card {
+    min-height: 60px;
+    margin-top: 10px;
+    border-radius: 4px;
+    background-color: #fff;
+    padding: 10px;
+    box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
+
+    h4 {
+      height: 18px;
+      line-height: 18px;
+      display: flex;
+
+      span {
+        font-weight: normal;
+        margin-left: auto;
+      }
+
+      &::before {
+        display: inline-block;
+        content: '';
+        width: 3px;
+        height: 18px;
+        background-color: #1c9bfd;
+        margin-right: 4px;
+        vertical-align: middle;
       }
-      .nav {
+    }
+
+    .time {
+      color: #f69a4d;
+    }
+
+    .nav {
+      display: flex;
+      margin: 10px 0;
+      flex-wrap: wrap;
+      font-weight: normal;
+
+      li {
+        flex: 0 0 25%;
         display: flex;
-        margin: 10px 0;
-        flex-wrap: wrap;
-        font-weight: normal;
-        li {
-          flex: 0 0 25%;
-          display: flex;
-          flex-direction: column;
-          align-items: center;
-          justify-content: center;
-          &:nth-child(n + 5) {
-            margin-top: 10px;
-          }
-          img {
-            height: 48px;
-            width: 48px;
-            margin-bottom: 4px;
-          }
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+
+        &:nth-child(n + 5) {
+          margin-top: 10px;
+        }
+
+        img {
+          height: 48px;
+          width: 48px;
+          margin-bottom: 4px;
         }
       }
-      .approval {
-        li {
-          padding: 10px;
-          background-color: #f9f9f9;
-          margin-top: 8px;
-          border-bottom: 1px solid #ecf5fa;
-          .van-text-ellipsis {
-            font-weight: bold;
-            font-size: 16px;
-          }
-          footer {
-            color: #969799;
-          }
-          a {
-            color: #3c78e3;
-          }
+    }
+
+    .approval {
+      li {
+        padding: 10px;
+        background-color: #f9f9f9;
+        margin-top: 8px;
+        border-bottom: 1px solid #ecf5fa;
+
+        .van-text-ellipsis {
+          font-weight: bold;
+          font-size: 16px;
+        }
+
+        footer {
+          color: #969799;
+        }
+
+        a {
+          color: #3c78e3;
         }
       }
     }
-    .swipe-con {
-      display: flex;
-      .my-swipe {
-        flex: 1;
-        height: 30px !important;
-        line-height: 30px !important;
-        :deep(.flex) {
+  }
+
+  .swipe-con {
+    display: flex;
+
+    .my-swipe {
+      flex: 1;
+      height: 30px !important;
+      line-height: 30px !important;
+
+      :deep(.flex) {
+        height: 30px;
+        overflow: hidden;
+
+        span {
+          display: inline-block;
           height: 30px;
+          line-height: 30px;
+        }
+
+        span:first-child {
+          flex: 1;
+          white-space: nowrap;
           overflow: hidden;
-          span {
-            display: inline-block;
-            height: 30px;
-            line-height: 30px;
-          }
-          span:first-child {
-            flex: 1;
-            white-space: nowrap;
-            overflow: hidden;
-            text-overflow: ellipsis;
-          }
+          text-overflow: ellipsis;
         }
       }
-      > a {
-        flex: 0 0 28px;
-        margin-left: 4px;
-        color: #3c78e3;
-      }
+    }
+
+    >a {
+      flex: 0 0 28px;
+      margin-left: 4px;
+      color: #3c78e3;
     }
   }
+}
 </style>

+ 110 - 3
src/view/login/index.vue

@@ -34,12 +34,39 @@
         <van-button size="mini" round class="mt10 w50">找回密码</van-button>
       </van-row> -->
       <van-button type="primary" round class="mt10" @click="onSignIn" :loading="state.loading.signIn">登录</van-button>
-      <van-button round class="mt10" @click="onRegister">注册</van-button>
+      <van-button round class="mt10" @click="openNoticeDialog">注册</van-button>
       <!-- <van-button round class="mt10" @click="blueTooth">蓝牙</van-button> -->
     </header>
     <footer>
       <img width="124" src="../../assets/img/slogan.png" />
     </footer>
+    <van-dialog
+      v-model:show="noticeDialogVisible"
+      title="注册须知"
+      :show-confirm-button="false"
+      :show-cancel-button="false"
+      class="notice-dialog"
+    >
+      <div class="notice-content">
+        <div class="notice-list">
+          <div class="notice-item" v-for="(item, index) in noticeContent" :key="index">
+            <p class="notice-item-title">{{ index + 1 }}. {{ item.title }}</p>
+            <p class="notice-item-content">{{ item.content }}</p>
+          </div>
+        </div>
+        <van-checkbox v-model="noticeChecked" icon-size="18px" class="agreement-checkbox">
+          我已阅读并同意注册须知
+        </van-checkbox>
+        <div class="notice-buttons">
+          <van-button block plain hairline class="notice-btn" @click="noticeDialogVisible = false">
+            关闭
+          </van-button>
+          <van-button block type="primary" class="notice-btn" :disabled="!noticeChecked" @click="handleAgreeNotice">
+            确认并注册
+          </van-button>
+        </div>
+      </div>
+    </van-dialog>
   </div>
 </template>
 
@@ -52,7 +79,7 @@ import crypto from 'sm-crypto'
 import { useRouter, useRoute } from 'vue-router'
 import { storeToRefs } from 'pinia'
 import { useUserInfo } from '/@/stores/userInfo'
-import { showDialog } from 'vant'
+import { showDialog, showToast } from 'vant'
 import { HttpStatus } from '/@/constants/pageConstants'
 
 const router = useRouter()
@@ -62,6 +89,30 @@ const loginApi = useLoginApi()
 const storesUseUserInfo = useUserInfo()
 const { userInfos, openId, unionId } = storeToRefs(storesUseUserInfo)
 const showPassword = ref(false)
+const noticeDialogVisible = ref(false)
+const noticeChecked = ref(false)
+const noticeContent = ref([
+  {
+    title: '校内课题组负责人',
+    content:
+      '点击统一身份登录,会自动建立同名课题组,完善课题组信息。(组织机构选择默认的远程组织机构,完善邮箱电话等信息,客户端密码暂与信息门户密码一致)提示注册成功后即可登录。',
+  },
+  {
+    title: '校内普通用户',
+    content:
+      '点击统一身份登录,完善个人信息,选择对应老师的课题组(如搜索不到请联系导师先注册课题组),注册之后等待课题组负责人审核激活。',
+  },
+  {
+    title: '校外用户加入已有课题组',
+    content:
+      '设置账户密码后点击下一步,完善个人信息后选择需要加入的对应课题组,提交后等待课题组负责人审核激活。',
+  },
+  {
+    title: '校外用户注册新课题组',
+    content:
+      '设置账号密码后点击下一步,点击新建课题组,完善基本信息(单位名称填写公司名称或学校名称,组织机构选择企业或其他高校,注册课题组的同时该课题组的负责人信息会一并注册,无需重复注册个人用户),注册成功后联系管理员激活。',
+  },
+])
 const state = reactive({
   captchaImage: '',
   loading: {
@@ -113,7 +164,16 @@ const openIdLogin = async () => {
   Local.set('token', res?.data.token)
   router.push('/home')
 }
-const onRegister = () => {
+const openNoticeDialog = () => {
+  noticeChecked.value = false
+  noticeDialogVisible.value = true
+}
+const handleAgreeNotice = () => {
+  if (!noticeChecked.value) {
+    showToast({ message: '请先阅读并勾选注册须知', position: 'top' })
+    return
+  }
+  noticeDialogVisible.value = false
   router.push('/register')
 }
 const blueTooth = async () => {
@@ -237,4 +297,51 @@ onMounted(async () => {
     margin-left: 16px;
   }
 }
+.notice-dialog {
+  :deep(.van-dialog__header) {
+    font-size: 18px;
+    font-weight: 600;
+  }
+
+  .notice-content {
+    max-height: 90vh;
+    overflow-y: auto;
+    padding: 20px;
+  }
+  .notice-title {
+    text-align: center;
+    color: #333;
+    margin-bottom: 16px;
+    font-size: 14px;
+    font-weight: 600;
+  }
+  .notice-list {
+    margin-bottom: 14px;
+  }
+  .notice-item {
+    margin-bottom: 12px;
+  }
+  .notice-item-title {
+    font-weight: 600;
+    color: #333;
+    margin-bottom: 4px;
+    font-size: 14px;
+  }
+  .notice-item-content {
+    color: #666;
+    line-height: 1.5;
+    font-size: 14px;
+  }
+  .agreement-checkbox {
+    margin: 16px 0;
+    color: #666;
+  }
+  .notice-buttons {
+    display: flex;
+    gap: 12px;
+    .notice-btn {
+      flex: 1;
+    }
+  }
+}
 </style>