Przeglądaj źródła

fix:退出登录去掉关闭页面改为跳转登录页、笼位申请用户展示nickname,饲养区域必填

liuzhenlin 5 dni temu
rodzic
commit
f20d1af17a

+ 7 - 6
src/view/animal/application/components/Application.vue

@@ -10,7 +10,7 @@
             <van-cell-group>
               <van-field v-model="state.form.projectName" label="课题名称" placeholder="请选择" readonly is-link required
                 @click="showProjectPicker = true" :rules="rules.projectGroupId" />
-              <van-field v-model="userInfos.userName" label="姓名" placeholder="姓名" readonly />
+              <van-field v-model="userInfos.nickName" label="姓名" placeholder="姓名" readonly />
               <van-field v-model="userInfos.deptName" label="部门" placeholder="部门" readonly />
               <van-field v-model="userInfos.phone" label="联系方式" placeholder="联系方式" readonly />
             </van-cell-group>
@@ -29,7 +29,7 @@
                 @click="showCategoryPicker = true" :rules="rules.categoryId" />
               <van-field v-model="state.form.variety" label="品种品系" placeholder="请输入品种品系" required
                 :rules="rules.variety" />
-              <van-field v-model="state.form.levelName" label="饲养区域" placeholder="请选择" readonly is-link
+              <van-field v-model="state.form.levelName" label="饲养区域" placeholder="请选择" readonly is-link required :rules="rules.levelName"
                 @click="showLevelPicker = true" />
               <van-field v-model="state.form.age" label="周龄" placeholder="请输入周龄" type="digit">
                 <template #button>
@@ -225,6 +225,7 @@ const rules = {
   projectGroupId: [{ required: true, message: '课题名称不能为空' }],
   categoryId: [{ required: true, message: '动物类别不能为空' }],
   variety: [{ required: true, message: '品种品系不能为空' }],
+  levelName: [{ required: true, message: '饲养区域不能为空' }],
   number: [{ required: true, message: '笼位数量不能为空' }],
   startDate: [{ required: true, message: '开始使用时间不能为空' }],
   buyFrom: [{ required: true, message: '采购渠道不能为空' }],
@@ -460,7 +461,7 @@ const onComeTimeConfirm = (date: Date) => {
 const onSubmit = async () => {
   // 设置提交状态为加载中
   submitting.value = true
-  
+
   try {
     await expertDialogFormRef.value?.validate()
   } catch (error: any) {
@@ -573,12 +574,12 @@ const onSubmit = async () => {
     submitting.value = false // 重置提交状态
     return
   }
-  
+
   showToast({
     type: 'success',
     message: '操作成功',
   })
-  
+
   // 接口成功后继续保持加载状态2秒,提供更好的用户体验
   setTimeout(() => {
     closeDialog()
@@ -694,4 +695,4 @@ defineExpose({
   top: 16px;
   right: 16px;
 }
-</style>
+</style>

+ 331 - 375
src/view/user/index.vue

@@ -2,21 +2,11 @@
   <div class="app-container">
     <header>
       <!-- <img :src="userInfos.avatar" alt="" /> -->
-      <van-image
-        class="mr10"
-        width="100px"
-        height="100px"
-        round
-        :src="userInfos.avatar"
-      />
+      <van-image class="mr10" width="100px" height="100px" round :src="userInfos.avatar" />
       <div class="content">
         <p class="bold">
           <van-text-ellipsis :content="`${userInfos.nickName}(信用分:${userInfos.creditScore})`" />
-          <van-icon
-            name="setting"
-            size="20"
-            @click="onRouterPush('/user/edit')"
-          />
+          <van-icon name="setting" size="20" @click="onRouterPush('/user/edit')" />
         </p>
         <p class="flex justify-between">
           <van-text-ellipsis :content="userInfos.pgName" />
@@ -58,25 +48,12 @@
           </li>
         </ul>
       </div>
-      <div
-        class="card"
-        @click="showOperatingGuidelines"
-      >
+      <div class="card" @click="showOperatingGuidelines">
         <h4>平台入室操作指引</h4>
       </div>
       <div class="card">
-        <van-cell
-          v-auth="'instr_open'"
-          title="打开设备"
-          is-link
-          @click="openInst"
-        />
-        <van-cell
-          v-auth="'instr_close'"
-          title="关闭设备"
-          is-link
-          @click="closeInst"
-        />
+        <van-cell v-auth="'instr_open'" title="打开设备" is-link @click="openInst" />
+        <van-cell v-auth="'instr_close'" title="关闭设备" is-link @click="closeInst" />
       </div>
     </div>
     <footer>
@@ -85,50 +62,27 @@
           <button class="w100 ">订阅</button>
         </component>
       </wx-open-subscribe> -->
-      <van-button
-        class="w100 mt10"
-        color="#1cb4fd"
-        plain
-        @click="onRouterPush('/user/password')"
-      >
+      <van-button class="w100 mt10" color="#1cb4fd" plain @click="onRouterPush('/user/password')">
         修改密码
       </van-button>
-      <van-button
-        class="w100 mt10"
-        @click="signOut"
-        type="primary"
-      >
+      <van-button class="w100 mt10" @click="signOut" type="primary">
         切换账号
       </van-button>
     </footer>
 
-    <van-popup
-      position="bottom"
-      v-model:show="showPopup"
-      :style="{ padding: '20px' }"
-    >
+    <van-popup position="bottom" v-model:show="showPopup" :style="{ padding: '20px' }">
       <div class="operation-guide">
         <div class="guide-header">
           <h3>操作指引</h3>
-          <van-icon
-            name="cross"
-            @click="showPopup = false"
-          />
+          <van-icon name="cross" @click="showPopup = false" />
         </div>
 
         <div class="steps-container">
-          <div
-            v-for="(item, index) in handleStepList"
-            :key="item.step"
-            class="step-item"
-            :class="{ 'last-step': index === handleStepList.length - 1 }"
-          >
+          <div v-for="(item, index) in handleStepList" :key="item.step" class="step-item"
+            :class="{ 'last-step': index === handleStepList.length - 1 }">
             <div class="step-number-wrapper">
               <div class="step-number">{{ item.step }}</div>
-              <div
-                v-if="index < handleStepList.length - 1"
-                class="step-line"
-              ></div>
+              <div v-if="index < handleStepList.length - 1" class="step-line"></div>
             </div>
 
             <div class="step-content">
@@ -157,387 +111,389 @@
 </template>
 
 <script lang="ts" setup>
-  import { ref, onMounted } from 'vue'
-  import { storeToRefs } from 'pinia'
-  import to from 'await-to-js'
-  import { showConfirmDialog, showToast } from 'vant'
-  import { useRouter } from 'vue-router'
-
-  import { useUserInfo } from '/@/stores/userInfo'
-  import { Local, Session } from '/@/utils/storage'
-  import { useBillApi } from '/@/api/instr/finance/bill'
-  import { useLoginApi } from '/@/api/login'
-
-  import { scanCodeWxUrl, InstSwitchType } from '/@/constants/pageConstants'
-
-  import wx from 'weixin-js-sdk'
-
-  const billApi = useBillApi()
-  const loginApi = useLoginApi()
-
-  const router = useRouter()
-  const storesUseUserInfo = useUserInfo()
-  const { userInfos, openId } = storeToRefs(storesUseUserInfo)
-
-  const showPopup = ref<boolean>(false)
-  const billInfo = ref<{
-    totalFlowCount: number
-    currentMonthFee: number
-    totalFee: number
-  }>({
-    totalFlowCount: 0,
-    currentMonthFee: 0,
-    totalFee: 0,
-  })
-
-  const handleStepList = ref([
-    {
-      title: '第一步:入室培训和考试',
-      desc: '请先完成入室培训,掌握必要的安全操作知识和实验室规章制度,并通过考试',
-      btn: '培训报名',
-      step: 1,
-    },
-    {
-      title: '第二步:提交入室申请',
-      desc: '完成入室培训考核合格后,在入室管理里面提交入室申请,等待平台管理员审核',
-      btn: '前往提交',
-      step: 2,
-    },
-    // {
-    //   title: '第三步:上传入室资料',
-    //   desc: '整理相关凭证并将入室资料上传到系统中',
-    //   step: 3,
-    // },
-    {
-      title: '第三步:等待审核和房间分配',
-      desc: '由平台管理老师进行审核并分配细胞房或分配分子储物柜,收到审核通过的通知后,即可在申请的时段进入细胞房或分子室进行实验',
-      step: 3,
-    },
-  ])
-
-  const onRouterPush = (val: string) => {
-    router.push(val)
-  }
-  const signOut = () => {
-    showConfirmDialog({
-      message: '确认切换账号?',
-    }).then(async () => {
-      // 如果有 openId,先解绑微信
-      if (openId.value) {
-        await to(loginApi.WeChatUnBindOpenId({ openId: openId.value }))
-      }
-      
-      // 调用退出登录接口
-      const [err]: ToResponse = await to(loginApi.signOut())
-      if (err) return
-      
-      // 清理所有本地缓存
-      Local.clear()
-      Session.clear()
-      // 重置用户信息
-      storesUseUserInfo.resetUserInfo()
-      // 关闭窗口
-      wx.closeWindow()
-    })
-  }
-  const handleSubscribe = (errMsg: any, subscribeDetails: any) => {
-    console.log(errMsg, subscribeDetails)
-  }
-
-  const showOperatingGuidelines = () => {
-    showPopup.value = true
-  }
-
-  const handleStepAction = (item: any) => {
-    // Implementation of handleStepAction
-  }
-
-  const checkPermi = (perms: string[]) => {
-    const list = userInfos.value?.authBtnList || []
-    return perms.some((p) => list.includes(p))
-  }
-
-  const openInst = () => {
-    const url = scanCodeWxUrl('START_RUN', InstSwitchType.OPEN)
-    window.location.href = url
-  }
-
-  const closeInst = () => {
-    const url = scanCodeWxUrl('END_RUN', InstSwitchType.CLOSE)
-    window.location.href = url
-  }
-
-  // 获取个人账单信息
-  const getBillInfo = async () => {
-    const [err, res]: ToResponse = await to(billApi.getMyOrderTotal())
+import { ref, onMounted } from 'vue'
+import { storeToRefs } from 'pinia'
+import to from 'await-to-js'
+import { showConfirmDialog, showToast } from 'vant'
+import { useRouter } from 'vue-router'
+
+import { useUserInfo } from '/@/stores/userInfo'
+import { Local, Session } from '/@/utils/storage'
+import { useBillApi } from '/@/api/instr/finance/bill'
+import { useLoginApi } from '/@/api/login'
+
+import { scanCodeWxUrl, InstSwitchType } from '/@/constants/pageConstants'
+
+import wx from 'weixin-js-sdk'
+
+const billApi = useBillApi()
+const loginApi = useLoginApi()
+
+const router = useRouter()
+const storesUseUserInfo = useUserInfo()
+const { userInfos, openId } = storeToRefs(storesUseUserInfo)
+
+const showPopup = ref<boolean>(false)
+const billInfo = ref<{
+  totalFlowCount: number
+  currentMonthFee: number
+  totalFee: number
+}>({
+  totalFlowCount: 0,
+  currentMonthFee: 0,
+  totalFee: 0,
+})
+
+const handleStepList = ref([
+  {
+    title: '第一步:入室培训和考试',
+    desc: '请先完成入室培训,掌握必要的安全操作知识和实验室规章制度,并通过考试',
+    btn: '培训报名',
+    step: 1,
+  },
+  {
+    title: '第二步:提交入室申请',
+    desc: '完成入室培训考核合格后,在入室管理里面提交入室申请,等待平台管理员审核',
+    btn: '前往提交',
+    step: 2,
+  },
+  // {
+  //   title: '第三步:上传入室资料',
+  //   desc: '整理相关凭证并将入室资料上传到系统中',
+  //   step: 3,
+  // },
+  {
+    title: '第三步:等待审核和房间分配',
+    desc: '由平台管理老师进行审核并分配细胞房或分配分子储物柜,收到审核通过的通知后,即可在申请的时段进入细胞房或分子室进行实验',
+    step: 3,
+  },
+])
+
+const onRouterPush = (val: string) => {
+  router.push(val)
+}
+const signOut = () => {
+  showConfirmDialog({
+    message: '确认切换账号?',
+  }).then(async () => {
+    // 如果有 openId,先解绑微信
+    // if (openId.value) {
+    //   await to(loginApi.WeChatUnBindOpenId({ openId: openId.value }))
+    // }
+
+    // 调用退出登录接口
+    const [err]: ToResponse = await to(loginApi.signOut())
     if (err) return
-    billInfo.value = res?.data
-  }
 
-  onMounted(() => {
-    getBillInfo()
+    // 清理所有本地缓存
+    Local.clear()
+    Session.clear()
+    // 重置用户信息
+    storesUseUserInfo.resetUserInfo()
+    // 关闭窗口
+    // wx.closeWindow()
+    // 跳转登录重新走授权
+    router.replace('/login')
   })
+}
+const handleSubscribe = (errMsg: any, subscribeDetails: any) => {
+  console.log(errMsg, subscribeDetails)
+}
+
+const showOperatingGuidelines = () => {
+  showPopup.value = true
+}
+
+const handleStepAction = (item: any) => {
+  // Implementation of handleStepAction
+}
+
+const checkPermi = (perms: string[]) => {
+  const list = userInfos.value?.authBtnList || []
+  return perms.some((p) => list.includes(p))
+}
+
+const openInst = () => {
+  const url = scanCodeWxUrl('START_RUN', InstSwitchType.OPEN)
+  window.location.href = url
+}
+
+const closeInst = () => {
+  const url = scanCodeWxUrl('END_RUN', InstSwitchType.CLOSE)
+  window.location.href = url
+}
+
+// 获取个人账单信息
+const getBillInfo = async () => {
+  const [err, res]: ToResponse = await to(billApi.getMyOrderTotal())
+  if (err) return
+  billInfo.value = res?.data
+}
+
+onMounted(() => {
+  getBillInfo()
+})
 </script>
 
 <style lang="scss" scoped>
-  .app-container {
+.app-container {
+  display: flex;
+  flex-direction: column;
+
+  header {
+    background-color: #1c9bfd;
+    color: #fff;
+    padding: 10px;
+    border-radius: 8px;
+    margin-top: 10px;
     display: flex;
-    flex-direction: column;
 
-    header {
-      background-color: #1c9bfd;
-      color: #fff;
-      padding: 10px;
-      border-radius: 8px;
-      margin-top: 10px;
+    .content {
+      flex: 1;
       display: flex;
+      flex-direction: column;
+      justify-content: space-around;
+      overflow: hidden;
 
-      .content {
-        flex: 1;
+      .bold {
         display: flex;
-        flex-direction: column;
-        justify-content: space-around;
-        overflow: hidden;
+        align-items: center;
+        font-weight: bold;
+        // flex-wrap: nowrap;
+        white-space: nowrap;
 
-        .bold {
-          display: flex;
-          align-items: center;
-          font-weight: bold;
-          // flex-wrap: nowrap;
-          white-space: nowrap;
-
-          .van-text-ellipsis {
-            flex: 1;
-          }
+        .van-text-ellipsis {
+          flex: 1;
         }
       }
     }
+  }
 
-    .main {
-      flex: 1;
-      overflow-y: auto;
+  .main {
+    flex: 1;
+    overflow-y: auto;
 
-      > ul {
-        display: flex;
-        height: 60px;
-        margin-top: 10px;
+    >ul {
+      display: flex;
+      height: 60px;
+      margin-top: 10px;
 
-        li {
-          flex: 1;
-          background: #fff;
-          color: #333;
-          display: flex;
-          align-items: center;
-          justify-content: center;
-          border-radius: 4px;
+      li {
+        flex: 1;
+        background: #fff;
+        color: #333;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        border-radius: 4px;
 
-          & + li {
-            margin-left: 10px;
-          }
+        &+li {
+          margin-left: 10px;
         }
+      }
 
-        &.links {
-          li {
-            color: #fff;
-            background: #5eb7fc;
+      &.links {
+        li {
+          color: #fff;
+          background: #5eb7fc;
 
-            &:nth-child(2) {
-              background: #fd9c5e;
-            }
+          &:nth-child(2) {
+            background: #fd9c5e;
+          }
 
-            &:nth-child(3) {
-              background: #53e3a7;
-            }
+          &:nth-child(3) {
+            background: #53e3a7;
+          }
 
-            &:nth-child(4) {
-              background: #888ac3;
-            }
+          &:nth-child(4) {
+            background: #888ac3;
           }
         }
       }
+    }
 
-      .card {
-        margin-top: 10px;
-        border-radius: 4px;
-        background-color: #fff;
-        padding: 10px;
+    .card {
+      margin-top: 10px;
+      border-radius: 4px;
+      background-color: #fff;
+      padding: 10px;
+
+      h4 {
+        height: 18px;
+        line-height: 18px;
 
-        h4 {
+        &::before {
+          display: inline-block;
+          content: '';
+          width: 3px;
           height: 18px;
-          line-height: 18px;
-
-          &::before {
-            display: inline-block;
-            content: '';
-            width: 3px;
-            height: 18px;
-            background-color: #1c9bfd;
-            margin-right: 4px;
-            vertical-align: middle;
-          }
+          background-color: #1c9bfd;
+          margin-right: 4px;
+          vertical-align: middle;
         }
+      }
+
+      .nav {
+        display: flex;
+        margin: 10px 0;
+        flex-wrap: wrap;
+        justify-content: space-between;
 
-        .nav {
+        li {
+          flex: 0 0 25%;
           display: flex;
-          margin: 10px 0;
-          flex-wrap: wrap;
-          justify-content: space-between;
-
-          li {
-            flex: 0 0 25%;
-            display: flex;
-            flex-direction: column;
-            align-items: center;
-            justify-content: center;
-
-            span {
-              font-size: 20px;
-            }
-
-            p {
-              margin-top: 4px;
-            }
-
-            &:nth-child(n + 5) {
-              margin-top: 10px;
-            }
+          flex-direction: column;
+          align-items: center;
+          justify-content: center;
+
+          span {
+            font-size: 20px;
+          }
+
+          p {
+            margin-top: 4px;
+          }
+
+          &:nth-child(n + 5) {
+            margin-top: 10px;
           }
         }
       }
     }
-
-    footer {
-      flex: 0 0 44px;
-      margin-bottom: 20px;
-    }
   }
 
-  :deep(.van-popup--bottom) {
-    padding: 20px !important;
+  footer {
+    flex: 0 0 44px;
+    margin-bottom: 20px;
   }
+}
 
-  .operation-guide {
-    max-height: 70vh;
-    overflow-y: auto;
+:deep(.van-popup--bottom) {
+  padding: 20px !important;
+}
 
-    .guide-header {
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      margin-bottom: 20px;
-      padding-bottom: 15px;
-      border-bottom: 1px solid #eee;
+.operation-guide {
+  max-height: 70vh;
+  overflow-y: auto;
 
-      h3 {
-        margin: 0;
-        font-size: 18px;
-        font-weight: 600;
-        color: #333;
-      }
+  .guide-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 20px;
+    padding-bottom: 15px;
+    border-bottom: 1px solid #eee;
+
+    h3 {
+      margin: 0;
+      font-size: 18px;
+      font-weight: 600;
+      color: #333;
+    }
 
-      .van-icon {
-        font-size: 18px;
-        color: #999;
-        cursor: pointer;
+    .van-icon {
+      font-size: 18px;
+      color: #999;
+      cursor: pointer;
 
-        &:hover {
-          color: #666;
-        }
+      &:hover {
+        color: #666;
       }
     }
+  }
 
-    .steps-container {
-      .step-item {
-        display: flex;
-        margin-bottom: 20px;
+  .steps-container {
+    .step-item {
+      display: flex;
+      margin-bottom: 20px;
 
-        &.last-step {
-          margin-bottom: 0;
-        }
+      &.last-step {
+        margin-bottom: 0;
+      }
 
-        .step-number-wrapper {
-          position: relative;
-          margin-right: 15px;
+      .step-number-wrapper {
+        position: relative;
+        margin-right: 15px;
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+
+        .step-number {
+          width: 32px;
+          height: 32px;
+          background: linear-gradient(135deg, #1c9bfd, #5eb7fc);
+          color: white;
+          border-radius: 50%;
           display: flex;
-          flex-direction: column;
           align-items: center;
+          justify-content: center;
+          font-weight: 600;
+          font-size: 14px;
+          box-shadow: 0 2px 8px rgba(28, 155, 253, 0.3);
+        }
 
-          .step-number {
-            width: 32px;
-            height: 32px;
-            background: linear-gradient(135deg, #1c9bfd, #5eb7fc);
-            color: white;
-            border-radius: 50%;
-            display: flex;
-            align-items: center;
-            justify-content: center;
-            font-weight: 600;
-            font-size: 14px;
-            box-shadow: 0 2px 8px rgba(28, 155, 253, 0.3);
-          }
+        .step-line {
+          width: 2px;
+          height: 40px;
+          background: linear-gradient(to bottom, #1c9bfd, #e0e0e0);
+          margin-top: 8px;
+        }
+      }
 
-          .step-line {
-            width: 2px;
-            height: 40px;
-            background: linear-gradient(to bottom, #1c9bfd, #e0e0e0);
-            margin-top: 8px;
-          }
+      .step-content {
+        flex: 1;
+        padding-top: 2px;
+
+        .step-title {
+          margin: 0 0 8px 0;
+          font-size: 16px;
+          font-weight: 600;
+          color: #333;
+          line-height: 1.4;
         }
 
-        .step-content {
-          flex: 1;
-          padding-top: 2px;
-
-          .step-title {
-            margin: 0 0 8px 0;
-            font-size: 16px;
-            font-weight: 600;
-            color: #333;
-            line-height: 1.4;
-          }
+        .step-desc {
+          margin: 0 0 12px 0;
+          font-size: 14px;
+          color: #666;
+          line-height: 1.5;
+        }
 
-          .step-desc {
-            margin: 0 0 12px 0;
-            font-size: 14px;
-            color: #666;
-            line-height: 1.5;
-          }
+        .step-btn {
+          border-radius: 20px;
+          padding: 8px 16px;
+          font-size: 12px;
+          background: linear-gradient(135deg, #1c9bfd, #5eb7fc);
+          border: none;
+          box-shadow: 0 2px 8px rgba(28, 155, 253, 0.3);
 
-          .step-btn {
-            border-radius: 20px;
-            padding: 8px 16px;
-            font-size: 12px;
-            background: linear-gradient(135deg, #1c9bfd, #5eb7fc);
-            border: none;
-            box-shadow: 0 2px 8px rgba(28, 155, 253, 0.3);
-
-            &:active {
-              transform: translateY(1px);
-            }
+          &:active {
+            transform: translateY(1px);
           }
         }
       }
     }
+  }
 
-    .guide-footer {
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      margin-top: 20px;
-      padding: 15px;
-      background: #f8f9fa;
-      border-radius: 8px;
-
-      .van-icon {
-        margin-right: 6px;
-        color: #1c9bfd;
-        font-size: 16px;
-      }
+  .guide-footer {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-top: 20px;
+    padding: 15px;
+    background: #f8f9fa;
+    border-radius: 8px;
+
+    .van-icon {
+      margin-right: 6px;
+      color: #1c9bfd;
+      font-size: 16px;
+    }
 
-      span {
-        font-size: 13px;
-        color: #666;
-      }
+    span {
+      font-size: 13px;
+      color: #666;
     }
   }
+}
 </style>