Browse Source

feat: 完成验证码布局

windyeasy 1 month ago
parent
commit
040bdb21b1

+ 3 - 1
.eslintrc-auto-import.json

@@ -89,6 +89,8 @@
     "watch": true,
     "watchEffect": true,
     "watchPostEffect": true,
-    "watchSyncEffect": true
+    "watchSyncEffect": true,
+    "showToast": true,
+    "regular": true
   }
 }

+ 1 - 0
package.json

@@ -83,6 +83,7 @@
     "bin-wrapper": "npm:bin-wrapper-china"
   },
   "dependencies": {
+    "@climblee/uv-ui": "^1.1.20",
     "@dcloudio/uni-app": "3.0.0-alpha-4010520240507001",
     "@dcloudio/uni-app-plus": "3.0.0-alpha-4010520240507001",
     "@dcloudio/uni-components": "3.0.0-alpha-4010520240507001",

+ 1 - 0
pages.config.ts

@@ -14,6 +14,7 @@ export default defineUniPages({
       '^wd-(.*)': 'wot-design-uni/components/wd-$1/wd-$1.vue',
       '^(?!z-paging-refresh|z-paging-load-more)z-paging(.*)':
         'z-paging/components/z-paging$1/z-paging$1.vue',
+      '^uv-(.*)': '@climblee/uv-ui/components/uv-$1/uv-$1.vue',
     },
   },
   tabBar: {

File diff suppressed because it is too large
+ 169 - 149
pnpm-lock.yaml


+ 76 - 0
src/components/count-down.vue

@@ -0,0 +1,76 @@
+<template>
+  <view class="count-down" :style="{ color: color }" @click="sendVerificationCode">
+    {{ buttonText }}
+  </view>
+</template>
+<script lang="ts" setup>
+const emit = defineEmits(['update:modelValue'])
+interface IProps {
+  phone?: string
+  modelValue?: string | number
+  color?: string
+}
+
+const props = withDefaults(defineProps<IProps>(), {
+  phone: '',
+  modelValue: '',
+  color: '#333',
+})
+const isDisabled = ref(false)
+const countDown = ref(60)
+const buttonText = ref('发送验证码')
+
+const sendVerificationCode = () => {
+  if (!regular.phone.test(props.phone)) {
+    uni.showToast({
+      title: '请填写正确的手机号码',
+      icon: 'error',
+    })
+    return
+  }
+  if (isDisabled.value) return
+  isDisabled.value = true
+  countDown.value = 60
+  buttonText.value = `${countDown.value}秒后重新发送`
+  // sendValidate({ phone: props.phone })
+  //   .then((res) => {
+  //     emit('update:modelValue', res.id)
+  //     uni.showToast({
+  //       title: '发送成功',
+  //       icon: 'success',
+  //     })
+  //     const timer = setInterval(() => {
+  //       countDown.value--
+  //       buttonText.value = `${countDown.value}秒后重新发送`
+  //       if (countDown.value <= 0) {
+  //         clearInterval(timer)
+  //         isDisabled.value = false
+  //         buttonText.value = '发送验证码'
+  //       }
+  //     }, 1000)
+  //   })
+  //   .catch(() => {
+  //     uni.showToast({
+  //       title: '发送失败',
+  //       icon: 'error',
+  //     })
+  //     isDisabled.value = false
+  //     buttonText.value = '发送验证码'
+  //   })
+}
+</script>
+<style lang="scss" scoped>
+.count-down {
+  display: inline-block;
+  width: 120px;
+  height: 24px;
+  padding: 6px 0;
+  margin-left: 4px;
+  font-size: 14px;
+  line-height: 24px;
+  color: #000;
+  text-align: center;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+}
+</style>

+ 37 - 1
src/pages.json

@@ -10,7 +10,8 @@
     "autoscan": true,
     "custom": {
       "^wd-(.*)": "wot-design-uni/components/wd-$1/wd-$1.vue",
-      "^(?!z-paging-refresh|z-paging-load-more)z-paging(.*)": "z-paging/components/z-paging$1/z-paging$1.vue"
+      "^(?!z-paging-refresh|z-paging-load-more)z-paging(.*)": "z-paging/components/z-paging$1/z-paging$1.vue",
+      "^uv-(.*)": "@climblee/uv-ui/components/uv-$1/uv-$1.vue"
     }
   },
   "tabBar": {
@@ -53,6 +54,41 @@
         "navigationStyle": "custom",
         "navigationBarTitleText": "首页"
       }
+    },
+    {
+      "path": "pages/agreement/index",
+      "type": "page",
+      "layout": "default",
+      "style": {
+        "navigationBarTitleText": "用户协议",
+        "navigationStyle": "default"
+      }
+    },
+    {
+      "path": "pages/forget-password/index",
+      "type": "page",
+      "layout": "default",
+      "style": {
+        "navigationBarTitleText": "忘记密码",
+        "navigationStyle": "default"
+      }
+    },
+    {
+      "path": "pages/login/index",
+      "type": "page",
+      "layout": "default",
+      "style": {
+        "navigationStyle": "custom",
+        "navigationBarTitleText": "登录"
+      }
+    },
+    {
+      "path": "pages/register/index",
+      "type": "page",
+      "layout": "default",
+      "style": {
+        "navigationBarTitleText": "注册"
+      }
     }
   ],
   "subPackages": []

+ 1 - 1
src/pages/login/components/login-panel.vue

@@ -24,7 +24,7 @@ function toRegister() {
     </wd-tabs>
     <view class="control-panel my-2 flex items-center justify-between">
       <wd-checkbox v-model="isKeep" shape="square">记住密码</wd-checkbox>
-      <view class="text text-[#3c9cff]">记密码</view>
+      <view class="text text-[#3c9cff]">记密码</view>
     </view>
     <uv-button mt3 type="primary" text="登 录" w-full></uv-button>
     <view class="text-area mt-10 text-center">

+ 1 - 2
src/pages/login/components/panel-account.vue

@@ -48,9 +48,8 @@ defineExpose({
       </uv-form-item>
       <uv-form-item prop="password">
         <uv-input
-          placeholder="请输入码"
+          placeholder="请输入验证码"
           prefixIcon="lock"
-          type="password"
           size="large"
           prefixIconStyle="font-size: 22px;color: #909399"
         ></uv-input>

+ 18 - 16
src/pages/login/components/panel-phone.vue

@@ -1,13 +1,16 @@
 <script lang="ts" setup>
+import CountDown from '@/components/count-down.vue'
 const formRef = ref<any>()
 const account = reactive({
   name: '',
   password: '',
 })
 const accountRules = {
-  name: [{ required: true, type: 'string', message: '请输入账号', trigger: ['blur', 'change'] }],
+  name: [
+    { required: true, type: 'string', message: '请输入正确手机号', trigger: ['blur', 'change'] },
+  ],
   password: [
-    { required: true, type: 'string', message: '请输入密码', trigger: ['blur', 'change'] },
+    { required: true, type: 'string', message: '请输入验证码', trigger: ['blur', 'change'] },
   ],
 }
 
@@ -39,24 +42,23 @@ defineExpose({
       :rules="accountRules"
     >
       <uv-form-item prop="name">
-        <uv-input
-          placeholder="请输入正确的账号"
-          prefixIcon="account"
-          size="large"
-          prefixIconStyle="font-size: 22px;color: #909399"
-        ></uv-input>
+        <view class="user-account-front">+ 86</view>
+        <uv-input placeholder="11位手机号" size="large"></uv-input>
       </uv-form-item>
       <uv-form-item prop="password">
-        <uv-input
-          placeholder="请输入密码"
-          prefixIcon="lock"
-          type="password"
-          size="large"
-          prefixIconStyle="font-size: 22px;color: #909399"
-        ></uv-input>
+        <uv-input placeholder="输入验证码" size="large"></uv-input>
+        <count-down />
       </uv-form-item>
     </uv-form>
   </div>
 </template>
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+.user-account-front {
+  height: 24px;
+  padding: 6px 10px;
+  line-height: 24px;
+  border: 0.5px solid #ccc;
+  border-radius: 4px 0 0 4px;
+}
+</style>

+ 6 - 0
src/types/auto-import.d.ts

@@ -63,10 +63,12 @@ declare global {
   const reactive: typeof import('vue')['reactive']
   const readonly: typeof import('vue')['readonly']
   const ref: typeof import('vue')['ref']
+  const regular: typeof import('../utils/common/index')['regular']
   const resolveComponent: typeof import('vue')['resolveComponent']
   const shallowReactive: typeof import('vue')['shallowReactive']
   const shallowReadonly: typeof import('vue')['shallowReadonly']
   const shallowRef: typeof import('vue')['shallowRef']
+  const showToast: typeof import('../utils/common/index')['showToast']
   const toRaw: typeof import('vue')['toRaw']
   const toRef: typeof import('vue')['toRef']
   const toRefs: typeof import('vue')['toRefs']
@@ -155,10 +157,12 @@ declare module 'vue' {
     readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
     readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
     readonly ref: UnwrapRef<typeof import('vue')['ref']>
+    readonly regular: UnwrapRef<typeof import('../utils/common/index')['regular']>
     readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
     readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
     readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
     readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
+    readonly showToast: UnwrapRef<typeof import('../utils/common/index')['showToast']>
     readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']>
     readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
     readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
@@ -238,10 +242,12 @@ declare module '@vue/runtime-core' {
     readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
     readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
     readonly ref: UnwrapRef<typeof import('vue')['ref']>
+    readonly regular: UnwrapRef<typeof import('../utils/common/index')['regular']>
     readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
     readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
     readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
     readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
+    readonly showToast: UnwrapRef<typeof import('../utils/common/index')['showToast']>
     readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']>
     readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
     readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>

+ 5 - 1
src/types/uni-pages.d.ts

@@ -5,7 +5,11 @@
 
 interface NavigateToOptions {
   url: "/pages/profile/index" |
-       "/pages/index/index";
+       "/pages/index/index" |
+       "/pages/agreement/index" |
+       "/pages/forget-password/index" |
+       "/pages/login/index" |
+       "/pages/register/index";
 }
 interface RedirectToOptions extends NavigateToOptions {}
 

+ 7 - 0
src/utils/common/index.ts

@@ -18,3 +18,10 @@ export function showToast(title: string, options: UniApp.ShowToastOptions = {})
     })
   })
 }
+// 校验规则
+export const regular = {
+  phone: /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/,
+  // 身份证 id ,支持 15,18 位
+  idCard:
+    /(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)/,
+}

+ 1 - 1
vite.config.ts

@@ -79,7 +79,7 @@ export default ({ command, mode }) => {
       AutoImport({
         imports: ['vue', 'uni-app'],
         dts: 'src/types/auto-import.d.ts',
-        dirs: ['src/hooks'], // 自动导入 hooks
+        dirs: ['src/hooks', 'src/utils/common'], // 自动导入 hooks
         eslintrc: { enabled: true },
         vueTemplate: true, // default false
       }),

Some files were not shown because too many files changed in this diff