山东大学软件学院项目实训weblab-4

前言

项目地址
本项目是为开发一套容器化的开发、运行、测试环境,用以支持Web开发、程序设计等课程的实验教学。

任务

用pinia、router和localStorage实现本地的注册、登录、重置密码、登出等功能。

store.ts

import { defineStore } from "pinia";

export const useLoginStore = defineStore({
  id: "login",
  state: () => ({
    isLogin: Number(localStorage.getItem('isLogin') || '0'),
    userId: localStorage.getItem('userId') || '',
    userPassword: localStorage.getItem('userPassword') || '',
  }),
  getters: {
    getIsLogin(state) {
      return (state.isLogin == 1) ? true : false;
    },
    getUserId(state) {
      return state.userId;
    },
    getUserPassword(state) {
      return state.userPassword
    }

  },
  actions: {
    userLogin(id: string, pwd: string) {
      this.isLogin = 1;
      this.userId = id;
      this.userPassword = pwd;
      localStorage.setItem('isLogin', '1');
      localStorage.setItem('userId', id);
      localStorage.setItem('userPassword', pwd);
    },
    userLogout() {
      this.isLogin = 0;
      localStorage.setItem('isLogin', '0');
      // this.userId = '';
      // this.userPassword = '';
      // localStorage.setItem('userId', '');
      // localStorage.setItem('userPassword', '');
    },
    userRegister(id: string, pwd: string) {
      localStorage.setItem('userId', id);
      localStorage.setItem('userPassword', pwd);
      this.userId = id;
      this.userPassword = pwd;
    },
    updateUserPassword(newPass:string){
      this.userPassword=newPass;
      localStorage.setItem('userPassword',newPass);
    }
  },
});

注册

<!--注册界面-->
<template>
  <div class="login-wrap">
    <el-form
      ref="registerFormRef"
      class="login-container"
      :model="registerForm"
      :rules="registerRules"
      label-position="right"
      label-width="80px"
    >
      <h1 class="title">注册</h1>
      <el-form-item label="用户名称" prop="username">
        <el-input type="text" placeholder="请输入名称" v-model="registerForm.username"></el-input>
      </el-form-item>
      <el-form-item label="用户邮箱" prop="useremail">
        <el-input type="email" placeholder="请输入邮箱" v-model="registerForm.useremail" size="default"></el-input>
      </el-form-item>
      <el-form-item label="用户密码" prop="pass">
        <el-tooltip content="<span>长度为8~15位,必须同时包含大小写字母及数字</span>" raw-content>
          <el-input v-model="registerForm.pass" type="password" placeholder="请输入密码" show-password />
        </el-tooltip>
      </el-form-item>
      <el-form-item label="确认密码" prop="checkPass">
        <el-input
          v-model="registerForm.checkPass"
          type="password"
          placeholder="请再次输入密码"
          show-password
        />
      </el-form-item>
      <el-form-item label="验证码" prop="checkCode">
        <el-input v-model="registerForm.checkCode" placeholder="请输入验证码" />
      </el-form-item>
      <el-form-item label-width="100px">
        <CharacterVerification ref="ver"></CharacterVerification>
      </el-form-item>
      <el-form-item label-width="0px">
        <el-button type="primary" @click="registerUser()" style="width: 48%;">用户注册</el-button>
        <el-button style="width: 48%;" @click="gotoLogin()">返回登录</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script lang="ts">
import { useRouter } from "vue-router";
import { ref, defineComponent, reactive, unref } from 'vue';
import CharacterVerification from '../components/CharacterVerification.vue';
import { ElMessage } from "element-plus";
import { useLoginStore } from "@/stores/store";

export default defineComponent({
  components: { CharacterVerification },
  setup() {
    const store=useLoginStore();
    const router = useRouter();
    //表单内容
    const registerForm = reactive({
      username: '',
      useremail: '',
      pass: '',
      checkPass: '',
      checkCode: ''
    })
    const registerFormRef = ref();
    const ver = ref();

    // 自定义验证规则
    const validatePass = (rule: any, value: any, callback: any) => {
      const reg = /^(?=.*\d)(?=.*[a-zA-Z])[\da-zA-Z]{8,15}$/;
      if (!reg.test(value)) {
        callback(new Error('长度为8~15位,必须同时包含大小写字母及数字'));
      }
      if (registerForm.checkPass != null && registerForm.checkPass !== '') {
        if (!registerFormRef.value) return
        registerFormRef.value.validateField('checkPass', () => null)
      }
      callback();

    }
    const validateCheckPass = (rule: any, value: any, callback: any) => {
      const reg = /^(?=.*\d)(?=.*[a-zA-Z])[\da-zA-Z]{8,15}$/;
      if (value !== registerForm.pass) {
        callback(new Error('输入密码不一致'));
      }
      if (!reg.test(value)) {
        callback(new Error('长度为8~15位,必须同时包含大小写字母及数字'));
      }
      callback();
    }

    //检查验证码是否正确
    const validateVerificationCode = (rule: any, value: any, callback: any) => {
      if (!ver.value.validate(value)) {
        callback(new Error('验证码错误'));
      } else {
        callback()
      }
    }
    // 定义校验规则
    const registerRules = reactive({
      username: [
        { required: true, message: '用户名称不能为空', trigger: 'blur' },
        { min: 2, max: 32, message: '名称长度只能在2~32之间', trigger: 'blur' }
      ],
      useremail: [
        { required: true, message: '邮箱不能为空', trigger: 'blur' },
        { type: 'email', message: '邮箱格式不正确', trigger: 'blur' }
      ],
      pass: [
        { required: true, message: '密码不能为空', trigger: 'blur' },
        { min: 8, max: 15, message: '密码位数只能在8~15之间', trigger: 'blur' },
        { validator: validatePass, trigger: 'blur' }
      ],
      checkPass: [
        { required: true, message: '密码不能为空', trigger: 'blur' },
        { min: 8, max: 15, message: '密码位数只能在8~15之间', trigger: 'blur' },
        { validator: validateCheckPass, trigger: 'blur' }
      ],
      checkCode: [
        { required: true, message: '验证码不能为空', trigger: 'blur' },
        { validator: validateVerificationCode, trigger: 'blur' }
      ]
    })


    const registerUser = async () => {
      const form = unref(registerFormRef);
      if (!form) return
      try {
        await form.validate();
        const { username, useremail, pass } = registerForm;
        console.log(username, useremail, pass);
        //todo: 发送注册请求

        store.userRegister(username,pass);

        ElMessage({
          showClose: true,
          message: '注册成功',
          type: 'success',
          center: true,
          grouping:true,
          onClose:()=>{router.push({ path: "/login" });}
        })
      } catch (error: any) {
        ElMessage({
          showClose: true,
          message: '输入格式不正确',
          type: 'error',
          center: true,
          grouping:true,
        })
      }
    }

    function gotoLogin() {
      router.push({ path: "/login" });
    }


    return {
      ver,
      registerFormRef,
      registerForm,
      registerRules,
      registerUser,
      gotoLogin,

    }
  }

})
</script>
<style>
.login-wrap {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  padding-top: 10%;
}

.login-container {
  border-radius: 10px;
  margin: 0px auto;
  width: 350px;
  padding: 30px 35px 15px 35px;
  background: #fff;
  border: 1px solid #eaeaea;
  text-align: left;
  box-shadow: 0 0 20px 2px rgba(0, 0, 0, 0.1);
}

.title {
  margin: 0px auto 40px auto;
  text-align: center;
  color: #505458;
}
</style>

登录

<!--登录界面-->
<template>
  <div class="login-wrap">
    <el-form
      ref="loginFormRef"
      :model="loginForm"
      :rules="loginRules"
      class="login-container"
      label-position="right"
      label-width="80px"
    >
      <h1 class="title">登录</h1>
      <el-form-item label="用户账号" prop="userid">
        <el-input v-model="loginForm.userid" placeholder="请输入账号" />
      </el-form-item>
      <el-form-item label="用户密码" prop="pass">
        <el-input v-model="loginForm.pass" type="password" placeholder="请输入密码" show-password />
      </el-form-item>
      <el-form-item label="验证码" prop="checkCode">
        <el-input v-model="loginForm.checkCode" placeholder="请输入验证码" />
      </el-form-item>
      <el-form-item label-width="100px">
        <CharacterVerification ref="ver"></CharacterVerification>
      </el-form-item>
      <el-form-item label-width="0px">
        <el-button type="primary" @click="doLogin()" style="width: 100%;">用户登录</el-button>
      </el-form-item>
      <el-row :gutter="20" style="text-align: center;">
        <el-col :span="5">
          <div class="grid-content"></div>
        </el-col>
        <el-col :span="6">
          <el-link @click="gotoRegister()">用户注册</el-link>
        </el-col>
        <el-col :span="1">
          <div class="grid-content"></div>
        </el-col>
        <el-col :span="6">
          <el-link @click="gotoForget()">忘记密码</el-link>
        </el-col>
      </el-row>
    </el-form>
  </div>
</template>

<script lang="ts">
import { ref, defineComponent, reactive, unref } from 'vue'
import { useRouter } from "vue-router";
import CharacterVerification from '../components/CharacterVerification.vue';
import { ElMessage } from 'element-plus';
import { useLoginStore } from '@/stores/store';

export default defineComponent({
  components: { CharacterVerification },
  setup() {
    const store = useLoginStore();
    const router = useRouter();
    const loginFormRef = ref();
    const ver = ref();
    //表单内容
    const loginForm = reactive({
      userid: '',
      pass: '',
      checkCode: ''
    })

    //自定义表单验证
    const validatePass = (rule: any, value: any, callback: any) => {
      const reg = /^(?=.*\d)(?=.*[a-zA-Z])[\da-zA-Z]{8,15}$/;
      if (!reg.test(value)) {
        callback(new Error('长度为8~15位,必须同时包含大小写字母及数字'));
      }
      callback();
    }
    //检查验证码是否正确
    const validateVerificationCode = (rule: any, value: any, callback: any) => {
      if (!ver.value.validate(value)) {
        callback(new Error('验证码错误'));
      } else {
        callback()
      }
    }
    // 定义校验规则
    const loginRules = reactive({
      userid: [
        { required: true, message: '用户账号不能为空', trigger: 'blur' },
      ],
      pass: [
        { required: true, message: '密码不能为空', trigger: 'blur' },
        { min: 8, max: 15, message: '密码位数只能在8~15之间', trigger: 'blur' },
        { validator: validatePass, trigger: 'blur' }
      ],
      checkCode: [
        { required: true, message: '验证码不能为空', trigger: 'blur' },
        { validator: validateVerificationCode, trigger: 'blur' }
      ]
    })

    function gotoForget() {
      router.push({ path: '/forget_password' });
    }
    function gotoRegister() {
      router.push({ path: '/register' });
    }

    const doLogin = async () => {
      const form = unref(loginFormRef);
      if (!form) return
      try {
        await form.validate();
        const { userid, pass } = loginForm;
        console.log(userid, pass);
        //todo: 发送登录请求

        const l_id = store.getUserId;
        const l_pass = store.getUserPassword;
        //登录成功
        if (userid == l_id && pass == l_pass) {
          store.userLogin(userid, pass);
          router.push({ path: '/login_home' });
        }

      } catch (error: any) {
        ElMessage({
          showClose: true,
          message: '输入格式不正确',
          type: 'error',
          center: true,
          grouping:true,
        })
      }
    }


    return {
      ver,
      loginFormRef,
      loginForm,
      loginRules,
      gotoForget,
      gotoRegister,
      doLogin,
    }
  },

})
</script>

<style>
.login-wrap {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  padding-top: 10%;
}

.login-container {
  border-radius: 10px;
  margin: 0px auto;
  width: 350px;
  padding: 30px 35px 15px 35px;
  background: #fff;
  border: 1px solid #eaeaea;
  text-align: left;
  box-shadow: 0 0 20px 2px rgba(0, 0, 0, 0.1);
}

.title {
  margin: 0px auto 40px auto;
  text-align: center;
  color: #505458;
}
.grid-content {
  border-radius: 4px;
  min-height: 36px;
}
</style>




登出

function goto_codingview() {
      ElMessageBox.confirm(
        '是否确认退出?',
        '退出提示',
        {
          confirmButtonText: '确认',
          cancelButtonText: '取消',
        }
      )
        .then(() => {
          //点击确认
          store.userLogout();
          router.push({ path: '/' });
        })
        .catch(() => {
          //点击取消
          router.push({ path: '/login_home' });
        })
    }

忘记密码

<template>
  <div class="email-wrap" v-if="showEmail == 1">
    <el-form ref="emailRef" :model="emailForm" :rules="emailRules" class="login-container">
      <el-steps :active="0" finish-status="success" simple style="margin-top: 20px">
        <el-step title="Step 1" />
        <el-step title="Step 2" />
        <el-step title="Step 3" />
      </el-steps>
      <el-form-item label></el-form-item>
      <el-form-item label="用户邮箱" prop="email">
        <el-input type="email" placeholder="请输入邮箱" v-model="emailForm.email" />
      </el-form-item>
      <el-button style="margin-top: 12px" @click="getCheckCode">获取邮箱验证码</el-button>
    </el-form>
  </div>
  <div class="email-check-wrap" v-else-if="showEmail == 2">
    <el-form
      ref="emailCheckFormRef"
      :model="emailCheckForm"
      :rules="emailCheckRules"
      class="email-container"
    >
      <el-steps :active="1" finish-status="success" simple style="margin-top: 20px">
        <el-step title="Step 1" />
        <el-step title="Step 2" />
        <el-step title="Step 3" />
      </el-steps>
      <el-form-item label></el-form-item>
      <el-form-item label="邮箱验证码" prop="checkCode">
        <el-input v-model="emailCheckForm.checkCode" placeholder="请输入验证码" />
      </el-form-item>
      <el-button style="margin-top: 12px" @click="next">下一步</el-button>
    </el-form>
  </div>
  <div class="password-wrap" v-else>
    <el-form ref="resetFormRef" :model="resetForm" :rules="resetRules" class="password-container">
      <el-steps :active="2" finish-status="success" simple style="margin-top: 20px">
        <el-step title="Step 1" />
        <el-step title="Step 2" />
        <el-step title="Step 3" />
      </el-steps>
      <el-form-item label></el-form-item>
      <el-form-item label="新的密码" prop="newPass">
        <el-input v-model="resetForm.newPass" placeholder="请输入新密码" type="password" show-password />
      </el-form-item>
      <el-form-item label="确认密码" prop="checkPass">
        <el-input v-model="resetForm.checkPass" placeholder="请输入新密码" type="password" show-password />
      </el-form-item>
      <el-button style="margin-top: 12px" @click="goHome()">确认</el-button>
    </el-form>
  </div>
</template>

<script lang="ts">
import { ref, defineComponent, reactive, unref } from 'vue'
import { Edit, UploadFilled, Picture } from '@element-plus/icons-vue'
import { useRouter } from "vue-router";
import { ElMessage } from 'element-plus';
import { useLoginStore } from '@/stores/store';
export default defineComponent({
  setup() {
    const store = useLoginStore();
    const router = useRouter();
    const showEmail = ref(1);

    const emailRef = ref();
    const emailForm = reactive({
      email: '',
    })

    const emailRules = reactive({
      email: [
        { required: true, message: '邮箱不能为空', trigger: 'blur' },
        { type: 'email', message: '邮箱格式不正确', trigger: 'blur' }
      ],
    })

    const emailCheckFormRef = ref();
    const emailCheckForm = reactive({
      checkCode: '',
    })
    const resetFormRef = ref();
    const resetForm = reactive({
      newPass: '',
      checkPass: '',
    })

    const validateCheckCode = (rule: any, value: any, callback: any) => {

      //发送获取验证码请求
      const checkCode = '123';
      if (value != checkCode) {
        callback(new Error('验证码错误'));
      }
      callback();
    }
    const validateNewPass = (rule: any, value: any, callback: any) => {
      const reg = /^(?=.*\d)(?=.*[a-zA-Z])[\da-zA-Z]{8,15}$/;
      if (!reg.test(value)) {
        callback(new Error('长度为8~15位,必须同时包含大小写字母及数字'));
      }
      if (resetForm.checkPass != null && resetForm.checkPass !== '') {
        if (!resetFormRef.value) return
        resetFormRef.value.validateField('checkPass', () => null)
      }
      callback();

    }
    const validateCheckPass = (rule: any, value: any, callback: any) => {
      const reg = /^(?=.*\d)(?=.*[a-zA-Z])[\da-zA-Z]{8,15}$/;
      if (value !== resetForm.newPass) {
        callback(new Error('输入密码不一致'));
      }
      if (!reg.test(value)) {
        callback(new Error('长度为8~15位,必须同时包含大小写字母及数字'));
      }
      callback();
    }

    const emailCheckRules = reactive({
      checkCode: [
        { required: true, message: '请输入验证码', trigger: 'blur' },
        { validator: validateCheckCode, trigger: 'blur' },
      ],
    })
    const resetRules = reactive({
      newPass: [
        { required: true, message: '密码不能为空', trigger: 'blur' },
        { min: 8, max: 15, message: '密码位数只能在8~15之间', trigger: 'blur' },
        { validator: validateNewPass, trigger: 'blur' }
      ],
      checkPass: [
        { required: true, message: '密码不能为空', trigger: 'blur' },
        { min: 8, max: 15, message: '密码位数只能在8~15之间', trigger: 'blur' },
        { validator: validateCheckPass, trigger: 'blur' }
      ],
    })

    const getCheckCode = async () => {
      //发送邮箱验证码
      const form = unref(emailRef);
      if (!form) return
      try {
        await form.validate();
        showEmail.value = 2;
      } catch (error: any) {
        ElMessage({
          showClose: true,
          message: '输入格式不正确',
          type: 'error',
          center: true,
          grouping: true,
        })
      }
    }

    const next = async () => {
      const form = unref(emailCheckFormRef);
      if (!form) return
      try {
        await form.validate();
        showEmail.value = 3;
      } catch (error) {
        ElMessage({
          showClose: true,
          message: '验证码不正确',
          type: 'error',
          center: true,
          grouping: true
        })
      }
    };
    const goHome = async () => {
      const form = unref(resetFormRef);
      if (!form) return
      try {
        await form.validate();

        //todo 发送修改密码请求
        store.updateUserPassword(resetForm.newPass);

        ElMessage({
          showClose: true,
          message: '修改密码成功',
          type: 'success',
          center: true,
          grouping: true,
          onClose: () => { router.push({ path: '/login' }) }
        })
      } catch (error) {
        ElMessage({
          showClose: true,
          message: '密码格式错误',
          type: 'error',
          center: true,
          grouping: true
        })
      }

    }
    return {
      showEmail,
      emailRef,
      emailForm,
      emailRules,
      emailCheckFormRef,
      emailCheckForm,
      emailCheckRules,
      resetForm,
      resetRules,
      resetFormRef,
      getCheckCode,
      next,
      goHome,

    }
  },
})

</script>

<style>
.email-wrap {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  padding-top: 10%;
}
.email-check-wrap {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  padding-top: 10%;
}
.email-container {
  border-radius: 10px;
  margin: 0px auto;
  width: 400px;
  padding: 30px 35px 15px 35px;
  background: #fff;
  border: 1px solid #eaeaea;
  text-align: left;
  box-shadow: 0 0 20px 2px rgba(0, 0, 0, 0.1);
}
.password-wrap {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  padding-top: 10%;
}

.password-container {
  border-radius: 10px;
  margin: 0px auto;
  width: 400px;
  padding: 30px 35px 15px 35px;
  background: #fff;
  border: 1px solid #eaeaea;
  text-align: left;
  box-shadow: 0 0 20px 2px rgba(0, 0, 0, 0.1);
}
</style>

重置密码

<template>
  <div class="login-wrap">
    <el-form
      ref="uptFormRef"
      class="login-container"
      :model="uptForm"
      :rules="uptRules"
      label-position="right"
      label-width="80px"
    >
      <el-form-item label></el-form-item>
      <el-form-item label="旧的密码" prop="oldPass">
        <el-input v-model="uptForm.oldPass" placeholder="请输入旧密码" type="password" show-password />
      </el-form-item>
      <el-form-item label="新的密码" prop="newPass">
        <el-input v-model="uptForm.newPass" placeholder="请输入新密码" type="password" show-password />
      </el-form-item>
      <el-form-item label="确认密码" prop="checkPass">
        <el-input v-model="uptForm.checkPass" placeholder="请输入新密码" type="password" show-password />
      </el-form-item>
      <el-button style="margin-top: 12px" @click="next">确认</el-button>
    </el-form>
  </div>
</template>

<script lang="ts">
import { ref, defineComponent, reactive, unref } from 'vue'
import { useRouter } from "vue-router";
import { ElMessage } from "element-plus";
import { useLoginStore } from "@/stores/store";
export default defineComponent({
  setup() {
    const router = useRouter();
    const store = useLoginStore();
    //表单内容
    const uptForm = reactive({
      oldPass: '',
      newPass: '',
      checkPass: '',
    })
    const uptFormRef = ref();

    const validateOldPass = (rule: any, value: any, callback: any) => {

      //发送获取密码请求
      const storedPass = store.getUserPassword;
      if (value != storedPass) {
        callback(new Error('输入密码错误'));
      }

      callback();

    }
    const validateNewPass = (rule: any, value: any, callback: any) => {
      const reg = /^(?=.*\d)(?=.*[a-zA-Z])[\da-zA-Z]{8,15}$/;
      if (!reg.test(value)) {
        callback(new Error('长度为8~15位,必须同时包含大小写字母及数字'));
      }
      if (uptForm.checkPass != null && uptForm.checkPass !== '') {
        if (!uptFormRef.value) return
        uptFormRef.value.validateField('checkPass', () => null)
      }
      callback();

    }
    const validateCheckPass = (rule: any, value: any, callback: any) => {
      const reg = /^(?=.*\d)(?=.*[a-zA-Z])[\da-zA-Z]{8,15}$/;
      if (value !== uptForm.newPass) {
        callback(new Error('输入密码不一致'));
      }
      if (!reg.test(value)) {
        callback(new Error('长度为8~15位,必须同时包含大小写字母及数字'));
      }
      callback();
    }
    // 定义校验规则
    const uptRules = reactive({
      oldPass: [
        { required: true, message: '密码不能为空', trigger: 'blur' },
        { min: 8, max: 15, message: '密码位数只能在8~15之间', trigger: 'blur' },
        { validator: validateOldPass, trigger: 'blur' }
      ],
      newPass: [
        { required: true, message: '密码不能为空', trigger: 'blur' },
        { min: 8, max: 15, message: '密码位数只能在8~15之间', trigger: 'blur' },
        { validator: validateNewPass, trigger: 'blur' }
      ],
      checkPass: [
        { required: true, message: '密码不能为空', trigger: 'blur' },
        { min: 8, max: 15, message: '密码位数只能在8~15之间', trigger: 'blur' },
        { validator: validateCheckPass, trigger: 'blur' }
      ],
    })
    const next = async () => {
      const form = unref(uptFormRef);
      if (!form) return
      try {
        await form.validate();

        //todo: 发送修改请求
        store.updateUserPassword(uptForm.newPass);

        ElMessage({
          showClose: true,
          message: '修改密码成功',
          type: 'success',
          center: true,
          grouping:true,
          onClose: () => { router.push({ path: "/login_home" }); }
        });
      } catch (error: any) {
        ElMessage({
          showClose: true,
          message: '输入格式不正确',
          type: 'error',
          center: true,
          grouping:true,
        })
      }
    }
    return {
      uptForm,
      uptFormRef,
      uptRules,
      next,
    }
  }
})
</script>

<style>
.login-wrap {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  padding-top: 10%;
}

.login-container {
  border-radius: 10px;
  margin: 0px auto;
  width: 350px;
  padding: 30px 35px 15px 35px;
  background: #fff;
  border: 1px solid #eaeaea;
  text-align: left;
  box-shadow: 0 0 20px 2px rgba(0, 0, 0, 0.1);
}

.title {
  margin: 0px auto 40px auto;
  text-align: center;
  color: #505458;
}
.grid-content {
  border-radius: 4px;
  min-height: 36px;
}
</style>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值