Xiao_123 1 년 전
부모
커밋
7eda933887

+ 6 - 1
src/api/common/index.js

@@ -13,4 +13,9 @@ export const smsLogin = (params) => {
 // 退出登录
 export const logout = () => {
   return http.post('/menduner/system/auth/logout')
-}
+}
+
+// 重置密码
+export const resetPassword = (params) => {
+  return http.put('/menduner/system/mde-user/reset-password', params)
+} 

+ 141 - 0
src/components/VerificationCode/index.vue

@@ -0,0 +1,141 @@
+<template>
+  <div>
+    <v-form @submit.prevent ref="phoneForm">
+      <v-text-field v-model="loginData.phone" placeholder="请输入手机号" color="#00897B" variant="outlined" density="compact" :rules="phoneRules" validate-on="input">
+        <template v-slot:prepend-inner>
+          <span class="d-flex">
+            <v-icon icon="mdi-cellphone" size="20"></v-icon>
+            <span class="d-flex" id="menu-activator">
+              <span class="phone-number">{{ currentArea }}</span>
+              <v-icon size="20">mdi-chevron-down</v-icon>
+            </span>
+            <v-menu activator="#menu-activator">
+              <v-list>
+                <v-list-item v-for="(item, index) in items" :key="index" :value="index" @click="handleChangeCurrentArea(item)">
+                  <v-list-item-title>{{ item.label }}</v-list-item-title>
+                </v-list-item>
+              </v-list>
+            </v-menu>
+          </span>
+        </template>
+      </v-text-field>
+      <v-text-field v-model="loginData.code" placeholder="请输入验证码" color="#00897B" variant="outlined" density="compact" prepend-inner-icon="mdi-security" :rules="[v=> !!v || '请填写验证码']">
+        <template #append-inner>
+          <span v-if="showCode" class="login-code" @click="handleCode">获取验证码</span>
+          <span v-else class="disable">重新获取{{ count }}s</span>
+        </template>
+      </v-text-field>
+    </v-form>
+    <v-snackbar v-model="tips.show" :color="tips.color" :timeout="1500" location="top">{{ tips.text }}</v-snackbar>
+  </div>
+</template>
+
+<script setup>
+defineOptions({ name: 'verification-code' })
+import { ref, reactive, defineExpose } from 'vue'
+import { setCodeTime } from '@/utils/code'
+import { sendSmsCode } from '@/api/common/index'
+
+const phoneRules = ref([
+  value => {
+    if (value) return true
+    return '请输入手机号'
+  },
+  value => {
+    if (value?.length <= 11 && /^1[3456789]\d{9}$/.test(value)) return true
+    return '请输入正确的手机号码'
+  }
+])
+
+const tips = reactive({
+  show: false,
+  color: '',
+  text: ''
+})
+
+// 手机号区域
+const currentArea = ref('0086')
+const items = [
+  { label: '中国大陆-0086', value: '0086' }
+]
+const handleChangeCurrentArea = (e) => {
+  currentArea.value = e.value
+}
+
+// 获取验证码
+const showCode = ref(true)
+const count = ref(0)
+const timer = ref(null)
+const handleCode = () => {
+  if (!loginData.phone) {
+    tips.text = '请输入手机号码'
+    tips.color = 'warning'
+    tips.show = true
+    return
+  }
+  count.value = 60
+  setTime()
+  getSmsCode()
+}
+const getSmsCode = async () => {
+  const query = {
+    phone: loginData.phone,
+    scene: 30
+  }
+  try {
+    await sendSmsCode(query)
+  } catch (error) {
+    console.log(error, 'error')
+  }
+}
+const setTime = () => {
+  showCode.value = false
+  timer.value = setInterval(() => {
+    let number = count.value
+    if (number > 0 && number <= 60) {
+      count.value--
+      setCodeTime(number - 1)
+    } else {
+      showCode.value = true
+      clearInterval(timer.value)
+      timer.value = null
+    }
+  }, 1000)
+}
+const autoTimer = () => {
+  count.value = 0
+  if(!count.value) return
+  setTime()
+}
+autoTimer()
+
+const loginData = reactive({
+  phone: '13229740091',
+  code: ''
+})
+
+const phoneForm = ref()
+
+defineExpose({
+  loginData, 
+  phoneForm
+})
+</script>
+
+<style lang="scss" scoped>
+.login-code {
+  width: 62px;
+  color: var(--default-color); 
+  font-size: 12px; 
+  cursor: pointer;
+}
+.disable {
+  width: 72px;
+  color: grey;
+  font-size: 12px;
+}
+.phone-number {
+  width: 34px;
+  font-size: 12px;
+}
+</style>

+ 5 - 3
src/layout/index.vue

@@ -1,14 +1,16 @@
 <template>
   <div class="parent">
     <Headers></Headers>
-    <router-view></router-view>
-    <Footers class="footer"></Footers>
+    <div class="pa-3" style="background-color: #f0f2f5;">
+      <router-view></router-view>
+    </div>
+    <!-- <Footers class="footer"></Footers> -->
   </div>
 </template>
 
 <script setup>
 import Headers from './personal/navBar.vue'
-import Footers from './personal/footer.vue'
+// import Footers from './personal/footer.vue'
 defineOptions({ name: 'layout-index' })
 </script>
 

+ 26 - 1
src/router/modules/personal.js

@@ -1,4 +1,29 @@
 // 个人路由信息
 
-const personal = []
+import Layout from '@/layout'
+const personal = [
+  {
+    path: '/personalAccount',
+    component: Layout,
+    name: 'personalAccount',
+    children: [
+      {
+        path: '/personalAccount',
+        component: () => import('@/views/Home/personal/account/index'),
+        meta: {
+          title: '账号与安全中心'
+        },
+        children: [
+          {
+            path:'/personalAccount/editPassword',
+            component: () => import('@/views/Home/personal/account/dynamic/editPassword'),
+            meta:{
+              title:'修改密码'
+            }
+          }
+        ]
+      }
+    ]
+  },
+]
 export default personal

+ 0 - 9
src/router/modules/remaining.js

@@ -71,15 +71,6 @@ const remainingRouter = [
       title: '注册企业'
     }
   },
-  {
-    path: '/personalAccount',
-    component: () => import('@/views/Home/personal/account/index'),
-    name: 'personalAccount',
-    meta: {
-      hidden: true,
-      title: '注册企业'
-    }
-  },
   ...items
 ]
 

+ 10 - 0
src/utils/request.js

@@ -90,6 +90,16 @@ const http = {
       }
     })
   },
+  put(url, params) {
+    return service.put(url, params, {
+      transformRequest: [(params) => {
+        return JSON.stringify(params)
+      }],
+      headers: {
+        'Content-Type': 'application/json'
+      }
+    })
+  },
   formData (url, params) {
     return service.post(url, params, {
       timeout: 600000,

+ 78 - 0
src/views/Home/personal/account/dynamic/editPassword.vue

@@ -0,0 +1,78 @@
+<template>
+  <div>
+    <h3>修改密码</h3>
+    <v-divider class="mb-4"></v-divider>
+    <div style="width: 300px;">
+      <PhonePage ref="phoneRef"></PhonePage>
+      <v-form ref="passwordRef">
+        <v-text-field
+          v-model="query.password"
+          placeholder="请输入密码" 
+          variant="outlined" 
+          density="compact"
+          color="#00897B"
+          prepend-inner-icon="mdi-lock-outline" 
+          :append-inner-icon="passwordType ? 'mdi-eye-outline' : 'mdi-eye-off-outline'"
+          :type="passwordType ? 'text' : 'password'"
+          :rules="[v=> !!v || '请填写密码']"
+          @click:append-inner="passwordType = !passwordType"
+        ></v-text-field>
+        <v-text-field
+          v-model="query.checkPassword"
+          placeholder="请再次输入密码" 
+          variant="outlined" 
+          density="compact"
+          color="#00897B"
+          prepend-inner-icon="mdi-lock-outline" 
+          :append-inner-icon="show ? 'mdi-eye-outline' : 'mdi-eye-off-outline'"
+          :type="show ? 'text' : 'password'"
+          :rules="[v=> !!v || '请再次输入密码', passwordCheck]"
+          @click:append-inner="show = !show"
+        ></v-text-field>
+      </v-form>
+      <v-btn color="primary" rounded @click="handleSubmit" :loading="loading">提 交</v-btn>
+    </div>
+  </div>
+</template>
+
+<script setup name="editPassword">
+import PhonePage from '@/components/VerificationCode'
+import { resetPassword } from '@/api/common/index'
+
+import { ref, reactive, computed } from 'vue'
+const phoneRef = ref()
+const passwordRef = ref()
+const passwordType = ref(false)
+const show = ref(false)
+const loading = ref(false)
+const query = reactive({
+  password: '',
+  checkPassword: ''
+})
+const passwordCheck = computed(() => {
+  return query.checkPassword === query.password || '两次密码输入不一致'
+})
+
+const handleSubmit = async () => {
+  const { valid: phoneValid } = await phoneRef.value.phoneForm.validate()
+  const { valid: passValid} = await passwordRef.value.validate()
+  if (!phoneValid || !passValid) return
+  loading.value = true
+  try {
+    await resetPassword({ password: query.password, ...phoneRef.value.loginData })
+  } catch (error) {
+    console.log(error, 'error')
+  } finally {
+    loading.value = false
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+h3 {
+  font-size: 20px;
+  text-align: left;
+  font-weight: 600;
+  padding-bottom: 25px;
+}
+</style>

+ 42 - 20
src/views/Home/personal/account/index.vue

@@ -1,45 +1,67 @@
 <!-- 账号与安全中心 -->
 <template>
-  <div class="d-flex pt-16">
-    <v-card>
+  <div class="d-flex" style="height: 700px;">
+    <v-card class="left">
       <h3>账号与安全中心</h3>
       
-      <v-list dense density="compact">
+      <v-list>
         <v-list-item
           v-for="item in items"
           :key="item.value"
-          @click="listClick(item.value)"
+          :to="item.path"
+          color="primary"
         >
-          <v-list-item-content>
-            <v-list-item-title>{{ item.title }}</v-list-item-title>
-          </v-list-item-content>
+          <v-list-item-title class="list-item">{{ item.title }}</v-list-item-title>
         </v-list-item>
       </v-list>
-      
-      <v-list :items="items" @click="listClick"></v-list>
     </v-card>
-    <v-card>
-      <span>123</span>
+
+    <v-card class="right ml-1" style="padding: 30px 60px">
+      <router-view></router-view>
     </v-card>
   </div>
 </template>
-<script setup>
-import { ref } from 'vue';
 
+<script setup>
 defineOptions({ name:'personal-account-index'})
-const items = ref([
+const items = [
   { title: '首页', value: 1, },
   { title: '账号管理', value: 2, },
   { title: '权限管理', value: 3, },
-  { title: '修改密码', value: 4, },
+  { title: '修改密码', path: '/personalAccount/editPassword', },
   { title: '身份验证', value: 5, },
   { title: '个人信息管理', value: 6, },
   { title: '登录设备管理', value: 7, },
-])
-const listClick = (val) => {
-  console.log('val', val)
-}
+]
 </script>
-<style lang="scss" scoped>
 
+<style lang="scss" scoped>
+.left {
+  width: 220px;
+}
+.right {
+  flex: 1;
+}
+::v-deep .v-list-item {
+  padding: 0 !important;
+}
+.list-item {
+  height: 62px;
+  width: 100%;
+  line-height: 62px;
+  font-weight: 500;
+  // color: #666;
+  font-size: 16px;
+  cursor: pointer;
+  margin: 0;
+  padding-left: 40px;
+  text-align: left;
+  transition: all .3s;
+}
+h3 {
+  font-size: 20px;
+  padding: 30px 0 30px 40px;
+  text-align: left;
+  font-weight: 600;
+}
 </style>

+ 1 - 1
src/views/login/index.vue

@@ -51,7 +51,7 @@
 <script setup>
 import { ref, reactive } from 'vue'
 import passwordFrom from './components/passwordPage.vue'
-import phoneFrom from './components/phonePage.vue'
+import phoneFrom from '@/components/VerificationCode'
 import qrCode from './components/qrCode.vue'
 import { userLocaleStore } from '@/store/user'
 import { useRouter } from 'vue-router'