ylb
1、项目的目录结构
2、前端起步
2.1 App.vue:
<template><nav></nav><router-view/>
</template><style>
</style>
2.2 index
在views目录下创建IndexView.vue ,作为自定义首页面
初始化:
<template><div>Index</div>
</template><script>
export default {name: "Index"
}
</script><style scoped></style>
2.3 修改路由
修改路由,链接到首页面IndexView。在router/index.js 添加配置修改:(部分代码)
1、导入import
2、添加routes,首页的path为 path: ‘/’
import Index from "../views/Index";const routes = [{path: '/',name: 'Index',component: Index},
2.4 导入全局css
在main.js文件中导入import全部css
//导入全局css
import '@/assets/css/details.css'
import '@/assets/css/font-awesome.min.css'
import '@/assets/css/index.css'
import '@/assets/css/list.css'
import '@/assets/css/login.css'
import '@/assets/css/public-head.css'
import '@/assets/css/reset.css'
import '@/assets/css/swiper.css'
import '@/assets/css/user_center.css'
import '@/assets/css/user_pay.css'
3、公共组件
创建页头,页脚Header ,Footer公共组件
在views目录下创建common, 分别创建Footer.vue , Header.vue
3.1 页头Header
<template><!--头部--><div class="public-head"><div class="public-head-nav"><div class="public-head-left"><h1 class="public-head-logo"><a href="javascript:;"><img src="@/assets/image/logo.png" alt=""></a></h1><ul class="public-head-list"><li><a href="javascript:void(0)" @click="goLink('/')">主页</a></li><li class="public-head-hover"><a href="javascript:void(0);">我要投资</a><!--二级导航--><div class="two-title"><a href="javascript:void(0);" @click="goLink('/page/product/list',{ptype:1})">优选类产品</a><a href="javascript:void(0);" @click="goLink('/page/product/list',{ptype:2})">散标类产品</a></div></li><li><a href="javascript:void(0);" >借款人信息</a></li><li><a href="javascript:void(0);" >信息披露</a></li><li><a href="javascript:void(0);" >安全计划</a></li></ul></div><div class="public-head-right" v-if="logined"><a href="javascript:void(0);" @click="goLink('/page/user/realname',)">实名认证</a><a href="javascript:void(0);" @click="goLink('/page/user/usercenter',)">用户中心</a></div><div class="public-head-right" v-else><a href="javascript:void(0);" @click="goLink('/page/user/login',)">登录</a><a href="javascript:void(0);" @click="goLink('/page/user/register',)">注册</a></div></div></div><!--end-->
</template><script>
export default {// eslint-disable-next-line vue/multi-word-component-namesname: "Header",data(){return {logined:false}},mounted() {//判断是否登录了if(window.localStorage.getItem("userinfo")){this.logined = true;}},methods:{goLink(url,params){//使用router做页面跳转, vue中的对象this.$router.push({path: url,query: params})},}
}
</script><style scoped></style>
导入页头,在views/IndexView下,
1、template标签内:
2、script标签内
3.2 页脚Footer
<template><!--公共底部--><div class="public-bottom"><div><p>版权所有 ©2017 北京动力节点教育科技有限公司 京ICP备09027468号 | 京公网安备京公网安备11030808027468</p><p>一家只教授Java的培训机构<a href="javascript:;">Visit the HomePage</a></p></div></div></template><script>
export default {// eslint-disable-next-line vue/multi-word-component-namesname: "Footer"
}
</script><style scoped></style>
导入页头,在views/IndexView下,
1、template标签内:
2、script标签内
4、封装axios的强求函数
在api文件下,创建httpRequest.js
import axios from "axios";
import qs from 'qs';
import layx from "vue-layx";//设置默认值
axios.defaults.baseURL = "http://localhost:8000/api";
axios.defaults.timeout = 50000/**** @param url url请求的地址,去掉了baseURL以外的部分* @param params 是对象,json对象。表示请求的参数* @returns {AxiosPromise}*/
function doGet(url, params) {return axios({url: url,method: 'get',params: params});
}/*** 传递json数据,在请求报文中是json格式* @param url* @param params* @returns {AxiosPromise}*/
function doPostJson(url, params) {return axios({url: url,method: 'post',data: params})
}/*** 请求是 key=value参数格式* */
function doPost(url, params) {//qs 把json对象转为 a=1&b=2 , 也可以反向let requestData = qs.stringify(params);return axios.post(url, requestData);
}//创建拦截器
axios.interceptors.request.use(function (config) {//在需要用户登录后的操作,在请求的url中加入token//判断访问服务器的url地址, 需要提供身份信息,加入tokenlet storageToken = window.localStorage.getItem("token");let userinfo = window.localStorage.getItem("userinfo");if (storageToken && userinfo) {if (config.url == '/v1/user/realname' || config.url == '/v1/user/usercenter' ||config.url == '/v1/recharge/records' || config.url=='/v1/invest/product') {//在header中传递token 和一个userIdconfig.headers['Authorization'] = 'Bearer ' + storageToken;config.headers['uid'] = JSON.parse(userinfo).uid;}}return config;
}, function (err) {console.log("请求错误" + err);
})//创建应答拦截器,统一对错误处理, 后端返回 code > 1000 都是错误
axios.interceptors.response.use(function (resp) {if (resp && resp.data.code > 1000) {let code = resp.data.code;if (code == 3000) {//token无效,重新登录window.location.href = '/page/user/login';} else {layx.msg(resp.data.msg, {dialogIcon: 'warn', position: 'ct'});}}return resp;
}, function (err) {console.log("应答拦截器错误:" + err)//回到首页//window.location.href = '/';
})//导出,暴露这个函数。 其他模块才能使用
export {doGet, doPost, doPostJson}
更新IndexView:
5、路由route主要方法
5.1 跳转到其他页面
5.2 获取当前页面访问url
6、goLink方法
在首页IndexView.vue和页头Header.vue的script标签中都加入goLink方法:
methods:{goLink(url,params){//使用router做页面跳转, vue中的对象this.$router.push({path: url,query: params})}}
在Header的template标签中:
在IndexView的template标签中:
完整的IndexView.vue:
<template><div><Header></Header><!--banner--><div class="banner-content"><div class="swiper-container banner-lb"><div class="swiper-wrapper"><div class="swiper-slide"><a href="javascript:;" ><img src="@/assets/image/banner.jpg" alt=""></a></div><div class="swiper-slide"><a href="javascript:;" ><img src="@/assets/image/banner.jpg" alt=""></a></div></div></div><div class="banner-abs"><div class="banner-abs-box"><div class="banner-abs-title">动力金融网历史年化收益率</div><b>{{platInfo.historyAvgRate}}<i>%</i></b><p>平台用户数</p><span>{{platInfo.registerUsers}}<i>位</i></span><p class="banner-abs-border">累计成交金额</p><span>{{ platInfo.sumBidMoney }}<i>元</i></span></div></div></div><div class="banner-list"><ul><li><img src="@/assets/image/banner-tag1.png" alt=""><p><b>实力雄厚</b><span>亿级注册资本 ,千万技术投入</span></p></li><li><img src="@/assets/image/banner-tag2.png" alt=""><p><b>风控严苛</b><span>30道风控工序,60项信用审核</span></p></li><li><img src="@/assets/image/banner-tag3.png" alt=""><p><b>投资省心</b><span>资金安全风控,银行安全托管</span></p></li></ul></div><!--产品--><div class="content"><h2 class="public-title"><span>新手宝</span></h2><div class="new-user" v-for="product in xinShouBao" :key="product.id"><div class="new-user-sm"><span>{{product.bidMinLimit}}元起投</span><span>投资最高限额{{ product.bidMaxLimit }}元</span><span>当日即系</span></div><div class="new-user-number"><ul><li><p><b>{{product.rate}}</b>%</p><span>历史年化收益率</span></li><li><p><b>{{product.cycle}}</b>天</p><span>投资周期</span></li><li><p><b>{{ product.leftProductMoney }}</b>元</p><span>余利可投资金额</span></li></ul><a href="javascript:void(0)" @click="goLink('/page/product/detail',{productId: product.id})" class="new-user-btn">立即投资</a></div><span class="new-tag">新用户专享</span></div><h2 class="public-title"><span>优选产品</span> <a href="javascript:void(0)" @click="goLink('/page/product/list',{ptype:1})" class="public-title-more">查看更多产品>></a></h2><ul class="preferred-select clearfix"><li v-for="(product,index) in youXuan" :key="product.id"><h3 class="preferred-select-title"><span>{{product.productName}}</span><img src="@/assets/image/1-bg1.jpg" alt="" v-if="index == 0 "><img src="@/assets/image/1-bg2.jpg" alt="" v-else-if="index == 1 "><img src="@/assets/image/1-bg3.jpg" alt="" v-else></h3><div class="preferred-select-number"><p><b>{{product.rate}}</b>%</p><span>历史年化收益率</span></div><div class="preferred-select-date"><div><span>投资周期</span><p><b>{{product.cycle}}</b>个月</p></div><div><span>余利可投资金额</span><p><b>{{product.leftProductMoney}}</b>元</p></div></div><p class="preferred-select-txt">优选计划项目,投资回报周期1个月,起点低,适合短期资金周转、对流动性要求高的投资人。</p><a href="javascript:void(0)" @click="goLink('/page/product/detail',{productId: product.id})" class="preferred-select-btn">立即投资</a></li></ul><h2 class="public-title"><span>散标产品</span> <a href="javascript:void(0)" @click="goLink('/page/product/list',{ptype:2})" class="public-title-more">查看更多产品>></a></h2><ul class="preferred-select clearfix"><li v-for="product in sanBiao" :key="product.id"><h3 class="preferred-select-title1">{{product.productName}}<span>散标</span></h3><div class="preferred-select-number"><p><b>{{product.rate}}</b>%</p><span>历史年化收益率</span></div><div class="preferred-select-date"><div><span>投资周期</span><p><b>{{product.cycle}}</b>个月</p></div><div><span>余利可投资金额</span><p><b>{{ product.leftProductMoney }}</b>元</p></div></div><p class="preferred-select-txt">散标计划项目,投资回报周期1个月,起点低,适合短期资金周转、对流动性要求高的投资人。</p><a href="javascript:void(0)" @click="goLink('/page/product/detail',{productId: product.id})" class="preferred-select-btn">立即投资</a></li></ul></div><!--说明--><div class="information-box"><ul><li><img src="@/assets/image/2-icon1.png" alt=""><p>优质借款</p><span>严苛风控,多重审核</span></li><li><img src="@/assets/image/2-icon2.png" alt=""><p>次日计息</p><span>闪电成交,谁比我快</span></li><li><img src="@/assets/image/2-icon3.png" alt=""><p>全年无休</p><span>百万用户,一路同行</span></li><li><img src="@/assets/image/2-icon4.png" alt=""><p>知心托付</p><span>百万用户,一路同行</span></li><li><img src="@/assets/image/2-icon5.png" alt=""><p>技术保障</p><span>千万投入,专注研发</span></li></ul></div><!--页脚 --><Footer></Footer></div>
</template><script>
import Header from "@/components/common/Header"
import Footer from "@/components/common/Footer"
import {doGet} from "@/api/httpRequest";export default {name: "IndexView",components:{// eslint-disable-next-line vue/no-unused-componentsHeader,Footer},data(){return {platInfo:{historyAvgRate:0.00,sumBidMoney:0.00,registerUsers:0},xinShouBao: [{id: 0,productName: "",rate: 0.0,cycle: 0,releaseTime: 0,productType: 0,productNo: "",productMoney: 0,leftProductMoney: 0,bidMinLimit: 0,bidMaxLimit: 0,productStatus: 0,productFullTime: "",productDesc: ""}],youXuan: [{id: 0,productName: "",rate: 0.0,cycle: 0,releaseTime: 0,productType: 0,productNo: "",productMoney: 0,leftProductMoney: 0,bidMinLimit: 0,bidMaxLimit: 0,productStatus: 0,productFullTime: "",productDesc: ""}],sanBiao: [{id: 0,productName: "",rate: 0.0,cycle: 0,releaseTime: 0,productType: 0,productNo: "",productMoney: 0,leftProductMoney: 0,bidMinLimit: 0,bidMaxLimit: 0,productStatus: 0,productFullTime: "",productDesc: ""}],}},mounted() { //页面加载到浏览器,执行mounted//向服务器发起请求,获取数据,更新页面doGet('/v1/plat/info').then( resp=>{if(resp){this.platInfo = resp.data.data;}})//向服务器获取产品数据doGet('/v1/product/index').then(resp=>{if( resp ){this.xinShouBao = resp.data.data.xinShouBao;this.youXuan = resp.data.data.youXuan;this.sanBiao = resp.data.data.sanBiao;}})},methods:{goLink(url,params){//使用router做页面跳转, vue中的对象this.$router.push({path: url,query: params})}}
}
</script><style scoped></style>
7、路由懒加载
懒加载:一开始进入页面时不需要一次性把资源都加载完,需要时在加载对应的资源。
路由懒加载的主要作用是将 路由对应的组件打包成一个个的js代码块。只有在这个路由被访问到的时候,才会加载对应组件的代码块。
vue实现路由懒加载的三种方式:
- Vue异步组件
- ES6的import()
- webpack的require.ensure()
完整的index.js:
import { createRouter, createWebHistory } from 'vue-router'
import IndexView from "@/views/IndexView";const routes = [{path: '/',name: 'IndexView',component: IndexView},{path: '/about',name: 'about',// route level code-splitting// this generates a separate chunk (about.[hash].js) for this route// which is lazy-loaded when the route is visitedponent: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')},{path: '/page/product/list',name: 'ProductList',component: () => import('../views/ProductList.vue')},{path: '/page/product/detail',name: 'ProductDetail',component: () => import('../views/ProductDetail.vue')},{path: '/page/user/register',name: 'RegisterView',component: () => import('../views/RegisterView.vue')},{path: '/page/user/login',name: 'LoginView',component: () => import('../views/LoginView.vue')},{path: '/page/user/realname',name: 'RealNameView',component: () => import('../views/RealNameView.vue')},{path: '/page/user/usercenter',name: 'UserCenterView',component: () => import('../views/UserCenterView.vue')} ,{path: '/page/user/userpay',name: 'UserPayView',component: () => import('../views/UserPayView.vue')}
]const router = createRouter({history: createWebHistory(process.env.BASE_URL),routes
})export default router
8、分页和弹层
安装弹层插件 layer 使用文档
安装:
npm i vue-layx -S
配置:
import layx from "vue-layx"
在ProductList.vue中:
template标签:
在script标签中:
9、加载一次
一些页数跳转时,有些地方是一样的(比如:在产品列表中投资排行榜是不会随着页数变化而变化的),我们把它的请求方法放在mounted中:
完整的ProductList.vue:
<template><div><Header></Header><div class="content clearfix"><!--排行榜--><ul class="rank-list"><li v-for="(item,ind) in rank" :key="item.phone"><img src="@/assets/image/list-rank1.png" alt="" v-if="ind == 0 "><img src="@/assets/image/list-rank2.png" alt="" v-else-if="ind == 1 "><img src="@/assets/image/list-rank3.png" alt="" v-else><p class="rank-list-phone">{{ item.phone }}</p><span>{{ item.money }}元</span></li></ul><!--产品列表--><ul class="preferred-select clearfix"><li v-for="product in productList" :key="product.id"><h3 class="preferred-select-title"><span>{{ product.productName }}</span><img src="@/assets/image/1-bg1.jpg" alt=""></h3><div class="preferred-select-number"><p><b>{{ product.rate }}</b>%</p><span>历史年化收益率</span></div><div class="preferred-select-date"><div><span>投资周期</span><p><b>{{ product.cycle }}</b>个月</p></div><div><span>剩余可投资金额</span><p><b>{{ product.leftProductMoney }}</b>元</p></div></div><p class="preferred-select-txt">优选计划项目,投资回报周期{{ product.cycle }}个月,起点低,适合短期资金周转、对流动性要求高的投资人。</p><a href="javascript:void(0)" @click="goLink('/page/product/detail',{productId: product.id})" class="preferred-select-btn">立即投资</a></li></ul><!--分页--><div class="page_box"><ul class="pagination"><li ><a href="javascript:void(0)" @click="first">首页</a></li><li><a href="javascript:void(0)" @click="pre">上一页</a></li><li class="active"><span>{{page.pageNo}}</span></li><li><a href="javascript:void(0)" @click="next">下一页</a></li><li><a href="javascript:void(0)" @click="last">尾页</a></li><li class="totalPages"><span>共{{page.totalPage}}页</span></li></ul></div></div><Footer></Footer></div>
</template><script>
import Header from "@/components/common/Header";
import Footer from "@/components/common/Footer";
import {doGet} from "@/api/httpRequest";
import layx from "vue-layx";
//获取参数
let productType = 0 ;export default {name: "ProductList",components: {// eslint-disable-next-line vue/no-unused-componentsHeader,// eslint-disable-next-line vue/no-unused-componentsFooter},data() {return {rank: [{"phone": "","money": 0}],productList: [{id: 0,productName: "",rate: 0.0,cycle: 0,releaseTime: 0,productType: 0,productNo: "",productMoney: 0,leftProductMoney: 0,bidMinLimit: 0,bidMaxLimit: 0,productStatus: 0,productFullTime: "",productDesc: ""}],page:{pageNo: 1,pageSize: 0,totalPage: 0,totalRecord: 0}}},mounted() {productType = this.$route.query.ptype;this.initPage(productType,1,9);//获取服务器数据doGet('/v1/invest/rank').then(resp => {if (resp) {this.rank = resp.data.list;}})},methods: {goLink(url,params){//使用router做页面跳转, vue中的对象this.$router.push({path: url,query: params})},initPage(productType,pNo,pSize) {//获取产品列表数据doGet('/v1/product/list', {ptype: productType, pageNo: pNo, pageSize: pSize}).then(resp => {if (resp) {this.productList = resp.data.list;this.page = resp.data.page;}})},first(){if( this.page.pageNo == 1 ){layx.msg('已经是第一页数据.',{dialogIcon:'warn',position:'ct'});} else {this.initPage(productType,1,9)}},last(){if( this.page.pageNo == this.page.totalPage ){layx.msg('已经是最后一页数据.',{dialogIcon:'warn',position:'ct'});} else {this.initPage(productType,this.page.totalPage,9)}},pre(){if( this.page.pageNo <= 1 ){layx.msg('已经是第一页数据.',{dialogIcon:'warn',position:'ct'});} else {this.initPage(productType,this.page.pageNo - 1 , 9);}},next(){if( this.page.pageNo >= this.page.totalPage ){layx.msg('已经是最后一页数据.',{dialogIcon:'warn',position:'ct'});} else {this.initPage(productType,this.page.pageNo + 1, 9);}}}
}
</script><style scoped></style>
10、产品详情Vue
<template><div><Header></Header><div class="content clearfix"><div class="detail-left"><div class="detail-left-title">{{ product.productName }}({{ product.productNo }}期)</div><ul class="detail-left-number"><li><span>历史年化收益率</span><p><b>{{ product.rate }}</b>%</p><span>历史年化收益率</span></li><li><span>募集金额(元)</span><p><b>{{ product.productMoney }}</b>元</p><span v-if="product.leftProductMoney > 0 ">募集中 剩余募集金额{{ product.leftProductMoney }}元</span><span v-else>已满标</span></li><li><span>投资周期</span><p v-if="product.productType == 0 "><b>{{product.cycle}}</b>天</p><p v-else><b>{{product.cycle}}</b>个月</p></li></ul><div class="detail-left-way"><span>收益获取方式</span><span>收益返还:<i>到期还本付息</i></span></div><!--投资记录--><div class="datail-record"><h2 class="datail-record-title">投资记录</h2><div class="datail-record-list"><table align="center" width="880" border="0" cellspacing="0" cellpadding="0"><colgroup><col style="width: 72px" /><col style="width: 203px" /><col style="width: 251px" /><col style="width: 354px" /></colgroup><thead class="datail_thead"><tr><th>序号</th><th>投资人</th><th>投资金额(元)</th><th>投资时间</th></tr></thead><tbody><tr v-for="(bid,ind) in bidList" :key="bid.id"><td>{{ind+1}}</td><td class="datail-record-phone">{{ bid.phone }}</td><td>{{ bid.bidMoney }}</td><td>{{ bid.bidTime }}</td></tr></tbody></table></div></div></div><!--右侧--><div class="detail-right"><div class="detail-right-title">立即投资</div><div class="detail-right-mode"><h3 class="detail-right-mode-title">收益方式</h3><p class="detail-right-mode-p"><span>到期还本付息</span></p><h3 class="detail-right-mode-title">我的账户可用</h3><div class="detail-right-mode-rmb" v-if="logined==false"><p>资金(元):******</p><a href="javascript:void(0);" @click="goLink('/page/user/login',)">请登录</a></div><div class="detail-right-mode-rmb" v-else><p>资金(元):{{this.accountMoney}}</p></div><h3 class="detail-right-mode-title">利息收入(元){{income}}</h3><form action="" id="number_submit"><p>请在下方输入投资金额</p><input type="text" placeholder="请输入日投资金额,应为100元整倍数" v-model="investMoney" @blur="checkInvestMoney" class="number-money" ><div class="err">{{investMoneyErr}}</div><input type="button" value="立即投资" @click="investProduct" class="submit-btn"></form></div></div></div><Footer></Footer></div>
</template><script>
import Header from "@/components/common/Header";
import Footer from "@/components/common/Footer";
import {doGet, doPost} from "@/api/httpRequest";
import layx from "vue-layx";export default {name: "ProductDetail",components:{// eslint-disable-next-line vue/no-unused-componentsHeader,// eslint-disable-next-line vue/no-unused-componentsFooter},data(){return {product:{id: 0,productName: "",rate: 0.0,cycle: 0,releaseTime: 0,productType: 0,productNo: "",productMoney: 0,leftProductMoney: 0,bidMinLimit: 0,bidMaxLimit: 0,productStatus: 0,productFullTime: "",productDesc: ""},bidList:[{id: 0,phone: "",bidTime: "",bidMoney: 0.00}],logined:false,accountMoney:0.0,investMoney: 100,investMoneyErr:'',income:""}},mounted() {//判断是否登录if( window.localStorage.getItem("userinfo")){this.logined = true;}this.initPage();},methods:{goLink(url,params){//使用router做页面跳转, vue中的对象this.$router.push({path: url,query: params})},initPage(){//查询产品信息let productId = this.$route.query.productId;doGet('/v1/product/info',{productId:productId}).then(resp=>{if( resp ) {this.product = resp.data.data;this.bidList = resp.data.list;}})//查询资金doGet('/v1/user/usercenter').then(resp=>{if( resp && resp.data.code == 1000){this.accountMoney = resp.data.data.money;}})},checkInvestMoney(){if( isNaN(this.investMoney )){this.investMoneyErr = '请输入正确的金额';} else if( parseInt(this.investMoney) < 100){this.investMoneyErr = '投资最小是100元';} else if( parseFloat(this.investMoney) % 100 !=0 ){this.investMoneyErr = '投资金额是100的整数倍';} else {this.investMoneyErr = '';//计算利息 利息 = 本金 * 周期 * 利率//当前产品数据 利率是 年利率是 ,百分数 。//不同类型的产品 ,周期不同, 新手宝是 天, 其他是月(30)//日利率let dayRate = this.product.rate / 365 / 100;//利息let incomeMoney = 0.0;if( this.product.productType == 0 ) {incomeMoney = this.investMoney * this.product.cycle * dayRate;} else {incomeMoney = this.investMoney * (this.product.cycle * 30) * dayRate;}this.income = incomeMoney.toFixed(2);}},investProduct(){//登录, 实名认证过let userinfo = JSON.parse(window.localStorage.getItem("userinfo"));if( userinfo ) {//检查是否有实名认证if(userinfo.name != ''){//投资this.checkInvestMoney();if(this.investMoneyErr == ''){doPost('/v1/invest/product',{ productId: this.product.id, money:this.investMoney}).then(resp=>{if( resp && resp.data.code == 1000){//投资成功this.initPage();}})}} else {//进行实名认证layx.msg('投资前需要实名认证.',{dialogIcon:'warn',position:'ct'});}} else {//去登录layx.msg('请先登录.',{dialogIcon:'warn',position:'ct'});}}}
}
</script><style scoped>
.err {color: red;font-size: 18px;
}
</style>
11、页面倒计时
12、注册Vue
<template><div><Header></Header><div class="login-content"><div class="login-flex"><div class="login-left"><p>万民用户知心托付 <span>{{ historyAvgRate }}%</span>历史年化收益</p><p>千万级技术研发投入 亿级注册资本平台 </p></div><!----><div class="login-box"><h3 class="login-title">用户注册</h3><form action="" id="register_Submit"><div class="alert-input"><input type="text" class="form-border user-num" @blur="checkPhone" v-model="phone" name="mobile"placeholder="请输入11位手机号"><div class="err">{{ phoneErr }}</div><p class="prompt_num"></p><input type="password" placeholder="请输入6-20位英文和数字混合密码"class="form-border user-pass" autocomplete name="password" v-model="password"@blur="checkPassword"><div class="err">{{ passwordErr }}</div><p class="prompt_pass"></p><div class="form-yzm form-border"><input class="yzm-write" type="text" name="" placeholder="输入短信验证码" v-model="code" @blur="checkCode"><input class="yzm-send" type="button" v-bind:value="yzmText" @click="requestSmsCode" id="yzmBtn"></div><div class="err">{{ codeErr }}</div><p class="prompt_yan"></p></div><div class="alert-input-agree"><input type="checkbox" v-model="agree">我已阅读并同意<a href="javascript:;" target="_blank">《动力金融网注册服务协议》</a></div><div class="alert-input-btn"><input type="button" class="login-submit" @click="requestUserRegister" value="注册"></div></form><div class="login-skip">已有账号? <a href="javascript:void(0)" @click="goLink('/page/user/login')">登录</a></div></div></div></div><Footer></Footer></div>
</template><script>
import Header from "@/components/common/Header";
import Footer from "@/components/common/Footer";
import {doGet, doPost} from "@/api/httpRequest";
import layx from "vue-layx";
import md5 from 'js-md5';export default {name: "RegisterView",components: {// eslint-disable-next-line vue/no-unused-componentsHeader,// eslint-disable-next-line vue/no-unused-componentsFooter},data() {return {historyAvgRate: 0.0,phone: '13812345699',phoneErr: '',password: '111aaa',passwordErr: '',code: '',codeErr: '',yzmText: '获取验证码',isSend: false,agree: false}},mounted() {//向服务器发起请求,获取数据,更新页面doGet('/v1/plat/info').then(resp => {if (resp) {this.historyAvgRate = resp.data.data.historyAvgRate;}})},methods: {goLink(url,params){//使用router做页面跳转, vue中的对象this.$router.push({path: url,query: params})},checkPhone() {if (this.phone == '' || this.phone == undefined) {this.phoneErr = '请输入手机号';} else if (this.phone.length != 11) {this.phoneErr = '手机号长度不足11位';} else if (!/^1[1-9]\d{9}$/.test(this.phone)) {this.phoneErr = '手机号格式不正确'} else {this.phoneErr = '';//向服务器发起请求,验证手机号是否可以注册doGet('/v1/user/phone/exists', {phone: this.phone}).then(resp => {if (resp && resp.data.code == 1000) {//手机号可以注册console.log("手机号可以注册")} else {this.phoneErr = resp.data.msg;}})}},checkPassword() {if (this.password == '' || this.password == undefined) {this.passwordErr = '请输入密码';} else if (this.password.length < 6 || this.password.length > 20) {this.passwordErr = '密码长度是6-20位';} else if (!/^[0-9a-zA-Z]+$/.test(this.password)) {this.passwordErr = '密码只能使用数字和字母';} else if (!/^(([a-zA-Z]+[0-9]+)|([0-9]+[a-zA-Z]+))[a-zA-Z0-9]*/.test(this.password)) {this.passwordErr = '密码是数字和字母的混合';} else {this.passwordErr = '';}},checkCode() {if (this.code == '' || this.code == undefined) {this.codeErr = '必须输入验证码';} else if (this.code.length != 4) {this.codeErr = '验证码是4位的';} else {this.codeErr = '';}},requestSmsCode() {//isSend:true, 发送验证码, 倒计时正在执行中。 false可以重新发送验证码if (this.isSend == false) {this.checkPhone();if (this.phoneErr == '') {this.isSend = true;let btn = document.getElementById("yzmBtn");btn.style.color = 'red';//处理倒计时let second = 5; //倒计时时间,默认是60秒setInterval(() => {if (second <= 1) {btn.style.color = '#688EF9';this.yzmText = "获取验证码";this.isSend = false;} else {second = second - 1;this.yzmText = second + "秒后重新获取";}}, 1000)//发起请求,给手机号发送验证码doGet('/v1/sms/code/register', {phone: this.phone}).then(resp => {if (resp && (resp.data.code == 1000 || resp.data.code == 1006)) {layx.msg('短信已经发送了', {dialogIcon: 'success', position: 'ct'});}})}}},requestUserRegister() {this.checkPhone();this.checkPassword();this.checkCode();if (this.phoneErr == '' && this.passwordErr == '' && this.codeErr == '') {if (this.agree) {//数据正确,提交注册请求//前端密码的md5()let newPassword = md5(this.password);doPost('/v1/user/register', {phone: this.phone,pword: newPassword,scode: this.code}).then(resp => {if (resp && resp.data.code == 1000) {//跳转登录页面this.$router.push({path: "/page/user/login"})}})} else {layx.msg("请阅读注册协议",{dialogIcon:'warn',position:'ct'});}}}}
}
</script><style scoped>
.err {color: red;font-size: 18px;
}
</style>
13、登录页面Vue
<template><div><Header></Header><div class="login-content"><div class="login-flex"><div class="login-left"><h3>加入动力金融网</h3><p>坐享<span>{{platInfo.historyAvgRate}}%</span>历史年化收益</p><p>平台用户<span>{{platInfo.registerUsers}}</span>位 </p><p>累计成交金额<span>{{platInfo.sumBidMoney}}</span>元</p></div><!----><div class="login-box"><h3 class="login-title">欢迎登录</h3><form action="" id="login_Submit"><div class="alert-input"><!--<input class="form-border user-name" name="username" type="text" placeholder="您的姓名"><p class="prompt_name"></p>--><input type="text" class="form-border user-num" v-model="phone" @blur="checkPhone" name="mobile" placeholder="请输入11位手机号"><div class="err">{{phoneErr}}</div><p class="prompt_num"></p><input type="password" placeholder="请输入登录密码" class="form-border user-pass" v-model="password" @blur="checkPassword" autocomplete name="password"><div class="err">{{passwordErr}}</div><p class="prompt_pass"></p><div class="form-yzm form-border"><input class="yzm-write" type="text" v-model="code" @blur="checkCode" placeholder="输入短信验证码"><input class="yzm-send" type="button" value="获取验证码" id="yzmBtn" @click="requestSmsCode" ></div><div class="err">{{codeErr}}</div><p class="prompt_yan"></p></div><div class="alert-input-btn"><input type="button" @click="userLogin" class="login-submit" value="登录"></div></form></div></div></div><Footer></Footer></div>
</template><script>
import Footer from "@/components/common/Footer";
import Header from "@/components/common/Header";
import {doGet, doPost} from "@/api/httpRequest";
import layx from "vue-layx";
import md5 from 'js-md5';export default {name: "LoginView",components:{// eslint-disable-next-line vue/no-unused-componentsHeader,// eslint-disable-next-line vue/no-unused-componentsFooter},data(){return {platInfo:{historyAvgRate:0.00,sumBidMoney:0.00,registerUsers:0},phone: '13812345699',phoneErr: '',password: '111aaa',passwordErr: '',code: '',codeErr: '',}},mounted() {doGet('/v1/plat/info').then(resp=>{if(resp ){this.platInfo = resp.data.data;}})},methods:{checkPhone(){if (this.phone == '' || this.phone == undefined) {this.phoneErr = '请输入手机号';} else if (this.phone.length != 11) {this.phoneErr = '手机号长度不足11位';} else if (!/^1[1-9]\d{9}$/.test(this.phone)) {this.phoneErr = '手机号格式不正确'} else {this.phoneErr = '';}},checkPassword() {if (this.password == '' || this.password == undefined) {this.passwordErr = '请输入密码';} else if (this.password.length < 6 || this.password.length > 20) {this.passwordErr = '密码长度是6-20位';} else if (!/^[0-9a-zA-Z]+$/.test(this.password)) {this.passwordErr = '密码只能使用数字和字母';} else if (!/^(([a-zA-Z]+[0-9]+)|([0-9]+[a-zA-Z]+))[a-zA-Z0-9]*/.test(this.password)) {this.passwordErr = '密码是数字和字母的混合';} else {this.passwordErr = '';}},checkCode() {if (this.code == '' || this.code == undefined) {this.codeErr = '必须输入验证码';} else if (this.code.length != 4) {this.codeErr = '验证码是4位的';} else {this.codeErr = '';}},requestSmsCode(){this.checkPhone();if( this.phoneErr == '' ){//调用服务器发到短信的接口 /code/logindoGet('/v1/sms/code/login',{phone:this.phone}).then(resp=>{if( resp && resp.data.code == 1000 ){layx.msg('短信已经发送了', {dialogIcon: 'success', position: 'ct'});}})}},userLogin(){this.checkPhone();this.checkPassword();this.checkCode();if( this.phoneErr == '' && this.passwordErr == '' & this.codeErr==''){//发起登录请求let param = {phone:this.phone,pword:md5(this.password),scode:this.code}doPost('/v1/user/login',param).then(resp=>{if( resp && resp.data.code == 1000){//登录成功,存储数据到localStorage,存的是字符串window.localStorage.setItem("token",resp.data.accessToken);//把 json对象转为 stringwindow.localStorage.setItem("userinfo", JSON.stringify(resp.data.data));//登录之后,如果name没有值,需要进入到实名认证页面//如果name有值,进入到用户中心if(resp.data.data.name == ''){//实名认证this.$router.push({path:'/page/user/realname'})} else {//用户中心this.$router.push({path:'/page/user/usercenter'})}}})}}}
}
</script><style scoped>
.err {color: red;font-size: 18px;
}
</style>
14、实名认证Vue
<template><div><Header> </Header><div class="login-content"><div class="login-flex"><div class="login-left"></div><!----><div class="login-box"><h3 class="login-title">实名认证</h3><form action="" id="renZ_Submit"><div class="alert-input"><input type="text" class="form-border user-name" name="username" v-model="name" @blur="checkName" placeholder="请输入您的真实姓名"><div class="err">{{nameErr}}</div><p class="prompt_name"></p><input type="text" class="form-border user-sfz" name="sfz" v-model="idCard" @blur="checkIdCard" placeholder="请输入15位或18位身份证号"><div class="err">{{idCardErr}}</div><p class="prompt_sfz"></p><input type="text" class="form-border user-num" name="mobile" v-bind:value="phone" readonly placeholder="请输入11位手机号"><p class="prompt_num"></p><div class="form-yzm form-border"><input class="yzm-write" type="text" v-model="code" @blur="checkCode" placeholder="输入短信验证码"><input class="yzm-send" type="text" value="获取验证码" disabled="disabled" id="yzmBtn" readonly="readonly" ></div><div class="err">{{codeErr}}</div><p class="prompt_yan"></p></div><div class="alert-input-agree"><input type="checkbox" v-model="agree">我已阅读并同意<a href="javascript:;" target="_blank">《动力金融网注册服务协议》</a></div><div class="alert-input-btn"><input type="button" @click="requestRealname" class="login-submit" value="认证"></div></form><div class="login-skip">暂不认证? <a href="javascript:;" @click="goLink('/page/user/usercenter')">跳过</a></div></div></div></div><Footer></Footer></div>
</template><script>
import Header from "@/components/common/Header";
import Footer from "@/components/common/Footer";
import {doPostJson} from "@/api/httpRequest";
import layx from "vue-layx";export default {name: "RealNameView",components: {// eslint-disable-next-line vue/no-unused-componentsHeader,// eslint-disable-next-line vue/no-unused-componentsFooter},data(){return {name:'',nameErr:'',idCard:'350721197702134399',idCardErr:'',code:'1234',codeErr:'',phone:'',agree:false}},mounted() {//获取localStorage中的用户数据let userinfo = window.localStorage.getItem("userinfo");if( userinfo ){this.phone = JSON.parse(userinfo).phone;}},methods:{goLink(url,params){//使用router做页面跳转, vue中的对象this.$router.push({path: url,query: params})},checkName(){if( this.name == '' || this.name == null ){this.nameErr = '必须输入姓名';} else if( this.name.length < 2 ){this.nameErr = '姓名不正确';} else if( !/^[\u4e00-\u9fa5]{0,}$/.test(this.name)){this.nameErr ='姓名必须是中文';} else {this.nameErr = '';}},checkIdCard(){if( this.idCard == '' || this.idCard == null){this.idCardErr = '请输入身份证号';} else if(!/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(this.idCard)){this.idCardErr='身份证号格式不正确';} else {this.idCardErr = '';}},checkCode() {if (this.code == '' || this.code == undefined) {this.codeErr = '必须输入验证码';} else if (this.code.length != 4) {this.codeErr = '验证码是4位的';} else {this.codeErr = '';}},requestRealname(){if(this.agree == false ){layx.msg('请阅读注册协议.',{dialogIcon:'warn',position:'ct'});return;}this.checkName();this.checkIdCard();this.checkCode();if( this.codeErr == '' && this.nameErr == '' && this.idCardErr == ''){let param = {name:this.name,phone:this.phone,idCard:this.idCard,code:this.code}doPostJson('/v1/user/realname',param).then(resp=>{if(resp && resp.data.code == 1000){//跳转到用户中心this.$router.push({path:'/page/user/usercenter'})}})}}}}
</script><style scoped>
.err {color: red;font-size: 18px;
}
</style>
15、用户中心Vue
<template><div><Header></Header><div class="content clearfix"><!--个人信息--><div class="user-head"><div class="user-head-left fl"><div class="user-head-img"><img src="@/assets/image/user-head.png" alt=""></div><p>上传头像</p></div><div class="user-head-right fl"><ul class="user-head-name fl"><li><b>{{userBaseInfo.name}}</b></li><li>{{ userBaseInfo.phone }}</li><li>最近登录:{{userBaseInfo.loginTime}}</li></ul><div class="user-head-money fr"><p>可用余额:<span>¥{{ userBaseInfo.money }}元</span></p><a href="javascript:void(0)" @click="goLink('/page/user/userpay')"style="color: red" class="user-head-a1">充值</a><a href="details.html" style="color: red" class="user-head-a2">投资</a></div></div></div><!--记录--><div class="user-record-box clearfix"><div class="user-record user-record-1"><h3 class="user-record-title">最近投资</h3><table align="center" width="388" border="0" cellspacing="0" cellpadding="0"><thead class="datail_thead"><tr><th>序号</th><th>投资产品</th><th>投资金额</th><th>投资时间</th></tr></thead><tbody><tr><td>1</td><td>新手宝</td><td>1500.0</td><td>2021-08-19</td></tr><tr><td>2</td><td>新手宝</td><td>1500.0</td><td>2021-08-19</td></tr><tr><td>3</td><td>新手宝</td><td>1500.0</td><td>2021-08-19</td></tr><tr><td>4</td><td>新手宝</td><td>1500.0</td><td>2021-08-19</td></tr><tr><td>5</td><td>新手宝</td><td>1500.0</td><td>2021-08-19</td></tr><tr><td>6</td><td>新手宝</td><td>1500.0</td><td>2021-08-19</td></tr></tbody></table><!--无记录--><p class="user-record-no">还没有投资记录,请投资:<a href="user_center.html" target="_blank">投资</a></p></div><div class="user-record user-record-2"><h3 class="user-record-title">最近充值</h3><table align="center" width="388" border="0" cellspacing="0" cellpadding="0"><thead class="datail_thead"><tr><th>序号</th><th>充值结果</th><th>充值金额</th><th>充值时间</th></tr></thead><tbody><tr v-for="(item,index) in rechargeList" :key="item.id"><td>{{index+1}}</td><td>{{item.result}}</td><td>{{item.rechargeMoney}}</td><td>{{item.rechargeDate}}</td></tr></tbody></table><!--无记录--><p class="user-record-no">还没有充值记录,请充值:<a href="javascript:void(0)" @click="goLink('/page/user/userpay')">充值</a></p></div><div class="user-record user-record-3"><h3 class="user-record-title ">最近收益</h3><table align="center" width="388" border="0" cellspacing="0" cellpadding="0"><thead class="datail_thead"><tr><th>序号</th><th>项目名称</th><th>投资日期</th><th>收益金额</th></tr></thead><tbody><tr><td>1</td><td>新手宝</td><td>2021-08-19</td><td>0.46</td></tr><tr><td>2</td><td>新手宝</td><td>2021-08-19</td><td>0.46</td></tr><tr><td>3</td><td>新手宝</td><td>2021-08-19</td><td>0.46</td></tr><tr><td>4</td><td>新手宝</td><td>2021-08-19</td><td>0.46</td></tr><tr><td>5</td><td>新手宝</td><td>2021-08-19</td><td>0.46</td></tr><tr><td>6</td><td>新手宝</td><td>2021-08-19</td><td>0.46</td></tr></tbody></table><!--无记录--><p class="user-record-no">还没有收益记录</p></div></div></div><Footer></Footer></div>
</template><script>
import Header from "@/components/common/Header";
import Footer from "@/components/common/Footer";
import {doGet} from "@/api/httpRequest";export default {name: "UserCenterView",components: {// eslint-disable-next-line vue/no-unused-componentsHeader,// eslint-disable-next-line vue/no-unused-componentsFooter},data() {return {userBaseInfo: {loginTime: "",money: 0.0,phone: "",name: "",headerUrl: ""},rechargeList:[{id: 0,result: "",rechargeDate: "",rechargeMoney: 0}]}},mounted() {doGet('/v1/user/usercenter').then(resp => {if (resp && resp.data.code == 1000) {this.userBaseInfo = resp.data.data;}});doGet('/v1/recharge/records',{pageNo:1,pageSize: 6}).then(resp=>{if(resp && resp.data.code == 1000){this.rechargeList = resp.data.list;}})},methods:{goLink(url,params){//使用router做页面跳转, vue中的对象this.$router.push({path: url,query: params})}}}
</script><style scoped></style>
16、前端访问api传递token,拦截器
在api/httpRequest.js中添加:
//创建拦截器
axios.interceptors.request.use(function (config) {//在需要用户登录后的操作,在请求的url中加入token//判断访问服务器的url地址, 需要提供身份信息,加入tokenlet storageToken = window.localStorage.getItem("token");let userinfo = window.localStorage.getItem("userinfo");if (storageToken && userinfo) {if (config.url == '/v1/user/realname' || config.url == '/v1/user/usercenter' ||config.url == '/v1/recharge/records' || config.url=='/v1/invest/product') {//在header中传递token 和一个userIdconfig.headers['Authorization'] = 'Bearer ' + storageToken;config.headers['uid'] = JSON.parse(userinfo).uid;}}return config;
}, function (err) {console.log("请求错误" + err);
})//创建应答拦截器,统一对错误处理, 后端返回 code > 1000 都是错误
axios.interceptors.response.use(function (resp) {if (resp && resp.data.code > 1000) {let code = resp.data.code;if (code == 3000) {//token无效,重新登录window.location.href = '/page/user/login';} else {layx.msg(resp.data.msg, {dialogIcon: 'warn', position: 'ct'});}}return resp;
}, function (err) {console.log("应答拦截器错误:" + err)//回到首页//window.location.href = '/';
})
17、用户充值Vue
<template>
<div><Header></Header><!--充值--><div class="user-pay-box clearfix"><div class="user-pay-left fl"><p class="user-pay-title1">我的账户</p><div class="user-pay-list"><a href="javascript:;" class="user-pay-list-on">充值</a><a href="javascript:;" target="_blank">我的信息</a><a href="javascript:;" target="_blank">投资记录</a><a href="javascript:;" target="_blank">收益记录</a></div></div><div class="user-pay-right fl"><p class="user-pay-title2">第三方支付平台</p><div class="user-pay-form"><img src="@/assets/image/kq.png" alt=""><form action="http://localhost:9000/pay/kq/rece/recharge" target="_blank" id="money_submit"><p class="user-pay-form-ts">请输入金额</p><input type="text" placeholder="元" name="rechargeMoney" value="0.01" class="number-money" ><input type="hidden" name="uid" v-bind:value="userId"><input type="submit" value="支付" class="submit-btn"></form></div><div class="user-pay-sm"><h3>温馨提示</h3><p>1.为了您的使用安全,充值操作建议不要使用公共电脑。</p><p>2.银行卡充值限额,由各银行限制。</p><p>3.品台禁止用卡套现、虚拟交易、洗钱等行为,一经发现并确认,将终止该账户的使用。</p><p>4.如果充值中出现问题,请联系客服400-890-0000。</p></div></div></div><Footer></Footer>
</div>
</template><script>
import Header from "@/components/common/Header";
import Footer from "@/components/common/Footer";export default {name: "UserPayView",data(){return {userId:0}},mounted() {let userinfo = window.localStorage.getItem("userinfo");if( userinfo ){this.userId = JSON.parse(userinfo).uid;}},components:{// eslint-disable-next-line vue/no-unused-componentsHeader,// eslint-disable-next-line vue/no-unused-componentsFooter},methods:{}
}
</script><style scoped></style>
ylb
1、项目的目录结构
2、前端起步
2.1 App.vue:
<template><nav></nav><router-view/>
</template><style>
</style>
2.2 index
在views目录下创建IndexView.vue ,作为自定义首页面
初始化:
<template><div>Index</div>
</template><script>
export default {name: "Index"
}
</script><style scoped></style>
2.3 修改路由
修改路由,链接到首页面IndexView。在router/index.js 添加配置修改:(部分代码)
1、导入import
2、添加routes,首页的path为 path: ‘/’
import Index from "../views/Index";const routes = [{path: '/',name: 'Index',component: Index},
2.4 导入全局css
在main.js文件中导入import全部css
//导入全局css
import '@/assets/css/details.css'
import '@/assets/css/font-awesome.min.css'
import '@/assets/css/index.css'
import '@/assets/css/list.css'
import '@/assets/css/login.css'
import '@/assets/css/public-head.css'
import '@/assets/css/reset.css'
import '@/assets/css/swiper.css'
import '@/assets/css/user_center.css'
import '@/assets/css/user_pay.css'
3、公共组件
创建页头,页脚Header ,Footer公共组件
在views目录下创建common, 分别创建Footer.vue , Header.vue
3.1 页头Header
<template><!--头部--><div class="public-head"><div class="public-head-nav"><div class="public-head-left"><h1 class="public-head-logo"><a href="javascript:;"><img src="@/assets/image/logo.png" alt=""></a></h1><ul class="public-head-list"><li><a href="javascript:void(0)" @click="goLink('/')">主页</a></li><li class="public-head-hover"><a href="javascript:void(0);">我要投资</a><!--二级导航--><div class="two-title"><a href="javascript:void(0);" @click="goLink('/page/product/list',{ptype:1})">优选类产品</a><a href="javascript:void(0);" @click="goLink('/page/product/list',{ptype:2})">散标类产品</a></div></li><li><a href="javascript:void(0);" >借款人信息</a></li><li><a href="javascript:void(0);" >信息披露</a></li><li><a href="javascript:void(0);" >安全计划</a></li></ul></div><div class="public-head-right" v-if="logined"><a href="javascript:void(0);" @click="goLink('/page/user/realname',)">实名认证</a><a href="javascript:void(0);" @click="goLink('/page/user/usercenter',)">用户中心</a></div><div class="public-head-right" v-else><a href="javascript:void(0);" @click="goLink('/page/user/login',)">登录</a><a href="javascript:void(0);" @click="goLink('/page/user/register',)">注册</a></div></div></div><!--end-->
</template><script>
export default {// eslint-disable-next-line vue/multi-word-component-namesname: "Header",data(){return {logined:false}},mounted() {//判断是否登录了if(window.localStorage.getItem("userinfo")){this.logined = true;}},methods:{goLink(url,params){//使用router做页面跳转, vue中的对象this.$router.push({path: url,query: params})},}
}
</script><style scoped></style>
导入页头,在views/IndexView下,
1、template标签内:
2、script标签内
3.2 页脚Footer
<template><!--公共底部--><div class="public-bottom"><div><p>版权所有 ©2017 北京动力节点教育科技有限公司 京ICP备09027468号 | 京公网安备京公网安备11030808027468</p><p>一家只教授Java的培训机构<a href="javascript:;">Visit the HomePage</a></p></div></div></template><script>
export default {// eslint-disable-next-line vue/multi-word-component-namesname: "Footer"
}
</script><style scoped></style>
导入页头,在views/IndexView下,
1、template标签内:
2、script标签内
4、封装axios的强求函数
在api文件下,创建httpRequest.js
import axios from "axios";
import qs from 'qs';
import layx from "vue-layx";//设置默认值
axios.defaults.baseURL = "http://localhost:8000/api";
axios.defaults.timeout = 50000/**** @param url url请求的地址,去掉了baseURL以外的部分* @param params 是对象,json对象。表示请求的参数* @returns {AxiosPromise}*/
function doGet(url, params) {return axios({url: url,method: 'get',params: params});
}/*** 传递json数据,在请求报文中是json格式* @param url* @param params* @returns {AxiosPromise}*/
function doPostJson(url, params) {return axios({url: url,method: 'post',data: params})
}/*** 请求是 key=value参数格式* */
function doPost(url, params) {//qs 把json对象转为 a=1&b=2 , 也可以反向let requestData = qs.stringify(params);return axios.post(url, requestData);
}//创建拦截器
axios.interceptors.request.use(function (config) {//在需要用户登录后的操作,在请求的url中加入token//判断访问服务器的url地址, 需要提供身份信息,加入tokenlet storageToken = window.localStorage.getItem("token");let userinfo = window.localStorage.getItem("userinfo");if (storageToken && userinfo) {if (config.url == '/v1/user/realname' || config.url == '/v1/user/usercenter' ||config.url == '/v1/recharge/records' || config.url=='/v1/invest/product') {//在header中传递token 和一个userIdconfig.headers['Authorization'] = 'Bearer ' + storageToken;config.headers['uid'] = JSON.parse(userinfo).uid;}}return config;
}, function (err) {console.log("请求错误" + err);
})//创建应答拦截器,统一对错误处理, 后端返回 code > 1000 都是错误
axios.interceptors.response.use(function (resp) {if (resp && resp.data.code > 1000) {let code = resp.data.code;if (code == 3000) {//token无效,重新登录window.location.href = '/page/user/login';} else {layx.msg(resp.data.msg, {dialogIcon: 'warn', position: 'ct'});}}return resp;
}, function (err) {console.log("应答拦截器错误:" + err)//回到首页//window.location.href = '/';
})//导出,暴露这个函数。 其他模块才能使用
export {doGet, doPost, doPostJson}
更新IndexView:
5、路由route主要方法
5.1 跳转到其他页面
5.2 获取当前页面访问url
6、goLink方法
在首页IndexView.vue和页头Header.vue的script标签中都加入goLink方法:
methods:{goLink(url,params){//使用router做页面跳转, vue中的对象this.$router.push({path: url,query: params})}}
在Header的template标签中:
在IndexView的template标签中:
完整的IndexView.vue:
<template><div><Header></Header><!--banner--><div class="banner-content"><div class="swiper-container banner-lb"><div class="swiper-wrapper"><div class="swiper-slide"><a href="javascript:;" ><img src="@/assets/image/banner.jpg" alt=""></a></div><div class="swiper-slide"><a href="javascript:;" ><img src="@/assets/image/banner.jpg" alt=""></a></div></div></div><div class="banner-abs"><div class="banner-abs-box"><div class="banner-abs-title">动力金融网历史年化收益率</div><b>{{platInfo.historyAvgRate}}<i>%</i></b><p>平台用户数</p><span>{{platInfo.registerUsers}}<i>位</i></span><p class="banner-abs-border">累计成交金额</p><span>{{ platInfo.sumBidMoney }}<i>元</i></span></div></div></div><div class="banner-list"><ul><li><img src="@/assets/image/banner-tag1.png" alt=""><p><b>实力雄厚</b><span>亿级注册资本 ,千万技术投入</span></p></li><li><img src="@/assets/image/banner-tag2.png" alt=""><p><b>风控严苛</b><span>30道风控工序,60项信用审核</span></p></li><li><img src="@/assets/image/banner-tag3.png" alt=""><p><b>投资省心</b><span>资金安全风控,银行安全托管</span></p></li></ul></div><!--产品--><div class="content"><h2 class="public-title"><span>新手宝</span></h2><div class="new-user" v-for="product in xinShouBao" :key="product.id"><div class="new-user-sm"><span>{{product.bidMinLimit}}元起投</span><span>投资最高限额{{ product.bidMaxLimit }}元</span><span>当日即系</span></div><div class="new-user-number"><ul><li><p><b>{{product.rate}}</b>%</p><span>历史年化收益率</span></li><li><p><b>{{product.cycle}}</b>天</p><span>投资周期</span></li><li><p><b>{{ product.leftProductMoney }}</b>元</p><span>余利可投资金额</span></li></ul><a href="javascript:void(0)" @click="goLink('/page/product/detail',{productId: product.id})" class="new-user-btn">立即投资</a></div><span class="new-tag">新用户专享</span></div><h2 class="public-title"><span>优选产品</span> <a href="javascript:void(0)" @click="goLink('/page/product/list',{ptype:1})" class="public-title-more">查看更多产品>></a></h2><ul class="preferred-select clearfix"><li v-for="(product,index) in youXuan" :key="product.id"><h3 class="preferred-select-title"><span>{{product.productName}}</span><img src="@/assets/image/1-bg1.jpg" alt="" v-if="index == 0 "><img src="@/assets/image/1-bg2.jpg" alt="" v-else-if="index == 1 "><img src="@/assets/image/1-bg3.jpg" alt="" v-else></h3><div class="preferred-select-number"><p><b>{{product.rate}}</b>%</p><span>历史年化收益率</span></div><div class="preferred-select-date"><div><span>投资周期</span><p><b>{{product.cycle}}</b>个月</p></div><div><span>余利可投资金额</span><p><b>{{product.leftProductMoney}}</b>元</p></div></div><p class="preferred-select-txt">优选计划项目,投资回报周期1个月,起点低,适合短期资金周转、对流动性要求高的投资人。</p><a href="javascript:void(0)" @click="goLink('/page/product/detail',{productId: product.id})" class="preferred-select-btn">立即投资</a></li></ul><h2 class="public-title"><span>散标产品</span> <a href="javascript:void(0)" @click="goLink('/page/product/list',{ptype:2})" class="public-title-more">查看更多产品>></a></h2><ul class="preferred-select clearfix"><li v-for="product in sanBiao" :key="product.id"><h3 class="preferred-select-title1">{{product.productName}}<span>散标</span></h3><div class="preferred-select-number"><p><b>{{product.rate}}</b>%</p><span>历史年化收益率</span></div><div class="preferred-select-date"><div><span>投资周期</span><p><b>{{product.cycle}}</b>个月</p></div><div><span>余利可投资金额</span><p><b>{{ product.leftProductMoney }}</b>元</p></div></div><p class="preferred-select-txt">散标计划项目,投资回报周期1个月,起点低,适合短期资金周转、对流动性要求高的投资人。</p><a href="javascript:void(0)" @click="goLink('/page/product/detail',{productId: product.id})" class="preferred-select-btn">立即投资</a></li></ul></div><!--说明--><div class="information-box"><ul><li><img src="@/assets/image/2-icon1.png" alt=""><p>优质借款</p><span>严苛风控,多重审核</span></li><li><img src="@/assets/image/2-icon2.png" alt=""><p>次日计息</p><span>闪电成交,谁比我快</span></li><li><img src="@/assets/image/2-icon3.png" alt=""><p>全年无休</p><span>百万用户,一路同行</span></li><li><img src="@/assets/image/2-icon4.png" alt=""><p>知心托付</p><span>百万用户,一路同行</span></li><li><img src="@/assets/image/2-icon5.png" alt=""><p>技术保障</p><span>千万投入,专注研发</span></li></ul></div><!--页脚 --><Footer></Footer></div>
</template><script>
import Header from "@/components/common/Header"
import Footer from "@/components/common/Footer"
import {doGet} from "@/api/httpRequest";export default {name: "IndexView",components:{// eslint-disable-next-line vue/no-unused-componentsHeader,Footer},data(){return {platInfo:{historyAvgRate:0.00,sumBidMoney:0.00,registerUsers:0},xinShouBao: [{id: 0,productName: "",rate: 0.0,cycle: 0,releaseTime: 0,productType: 0,productNo: "",productMoney: 0,leftProductMoney: 0,bidMinLimit: 0,bidMaxLimit: 0,productStatus: 0,productFullTime: "",productDesc: ""}],youXuan: [{id: 0,productName: "",rate: 0.0,cycle: 0,releaseTime: 0,productType: 0,productNo: "",productMoney: 0,leftProductMoney: 0,bidMinLimit: 0,bidMaxLimit: 0,productStatus: 0,productFullTime: "",productDesc: ""}],sanBiao: [{id: 0,productName: "",rate: 0.0,cycle: 0,releaseTime: 0,productType: 0,productNo: "",productMoney: 0,leftProductMoney: 0,bidMinLimit: 0,bidMaxLimit: 0,productStatus: 0,productFullTime: "",productDesc: ""}],}},mounted() { //页面加载到浏览器,执行mounted//向服务器发起请求,获取数据,更新页面doGet('/v1/plat/info').then( resp=>{if(resp){this.platInfo = resp.data.data;}})//向服务器获取产品数据doGet('/v1/product/index').then(resp=>{if( resp ){this.xinShouBao = resp.data.data.xinShouBao;this.youXuan = resp.data.data.youXuan;this.sanBiao = resp.data.data.sanBiao;}})},methods:{goLink(url,params){//使用router做页面跳转, vue中的对象this.$router.push({path: url,query: params})}}
}
</script><style scoped></style>
7、路由懒加载
懒加载:一开始进入页面时不需要一次性把资源都加载完,需要时在加载对应的资源。
路由懒加载的主要作用是将 路由对应的组件打包成一个个的js代码块。只有在这个路由被访问到的时候,才会加载对应组件的代码块。
vue实现路由懒加载的三种方式:
- Vue异步组件
- ES6的import()
- webpack的require.ensure()
完整的index.js:
import { createRouter, createWebHistory } from 'vue-router'
import IndexView from "@/views/IndexView";const routes = [{path: '/',name: 'IndexView',component: IndexView},{path: '/about',name: 'about',// route level code-splitting// this generates a separate chunk (about.[hash].js) for this route// which is lazy-loaded when the route is visitedponent: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')},{path: '/page/product/list',name: 'ProductList',component: () => import('../views/ProductList.vue')},{path: '/page/product/detail',name: 'ProductDetail',component: () => import('../views/ProductDetail.vue')},{path: '/page/user/register',name: 'RegisterView',component: () => import('../views/RegisterView.vue')},{path: '/page/user/login',name: 'LoginView',component: () => import('../views/LoginView.vue')},{path: '/page/user/realname',name: 'RealNameView',component: () => import('../views/RealNameView.vue')},{path: '/page/user/usercenter',name: 'UserCenterView',component: () => import('../views/UserCenterView.vue')} ,{path: '/page/user/userpay',name: 'UserPayView',component: () => import('../views/UserPayView.vue')}
]const router = createRouter({history: createWebHistory(process.env.BASE_URL),routes
})export default router
8、分页和弹层
安装弹层插件 layer 使用文档
安装:
npm i vue-layx -S
配置:
import layx from "vue-layx"
在ProductList.vue中:
template标签:
在script标签中:
9、加载一次
一些页数跳转时,有些地方是一样的(比如:在产品列表中投资排行榜是不会随着页数变化而变化的),我们把它的请求方法放在mounted中:
完整的ProductList.vue:
<template><div><Header></Header><div class="content clearfix"><!--排行榜--><ul class="rank-list"><li v-for="(item,ind) in rank" :key="item.phone"><img src="@/assets/image/list-rank1.png" alt="" v-if="ind == 0 "><img src="@/assets/image/list-rank2.png" alt="" v-else-if="ind == 1 "><img src="@/assets/image/list-rank3.png" alt="" v-else><p class="rank-list-phone">{{ item.phone }}</p><span>{{ item.money }}元</span></li></ul><!--产品列表--><ul class="preferred-select clearfix"><li v-for="product in productList" :key="product.id"><h3 class="preferred-select-title"><span>{{ product.productName }}</span><img src="@/assets/image/1-bg1.jpg" alt=""></h3><div class="preferred-select-number"><p><b>{{ product.rate }}</b>%</p><span>历史年化收益率</span></div><div class="preferred-select-date"><div><span>投资周期</span><p><b>{{ product.cycle }}</b>个月</p></div><div><span>剩余可投资金额</span><p><b>{{ product.leftProductMoney }}</b>元</p></div></div><p class="preferred-select-txt">优选计划项目,投资回报周期{{ product.cycle }}个月,起点低,适合短期资金周转、对流动性要求高的投资人。</p><a href="javascript:void(0)" @click="goLink('/page/product/detail',{productId: product.id})" class="preferred-select-btn">立即投资</a></li></ul><!--分页--><div class="page_box"><ul class="pagination"><li ><a href="javascript:void(0)" @click="first">首页</a></li><li><a href="javascript:void(0)" @click="pre">上一页</a></li><li class="active"><span>{{page.pageNo}}</span></li><li><a href="javascript:void(0)" @click="next">下一页</a></li><li><a href="javascript:void(0)" @click="last">尾页</a></li><li class="totalPages"><span>共{{page.totalPage}}页</span></li></ul></div></div><Footer></Footer></div>
</template><script>
import Header from "@/components/common/Header";
import Footer from "@/components/common/Footer";
import {doGet} from "@/api/httpRequest";
import layx from "vue-layx";
//获取参数
let productType = 0 ;export default {name: "ProductList",components: {// eslint-disable-next-line vue/no-unused-componentsHeader,// eslint-disable-next-line vue/no-unused-componentsFooter},data() {return {rank: [{"phone": "","money": 0}],productList: [{id: 0,productName: "",rate: 0.0,cycle: 0,releaseTime: 0,productType: 0,productNo: "",productMoney: 0,leftProductMoney: 0,bidMinLimit: 0,bidMaxLimit: 0,productStatus: 0,productFullTime: "",productDesc: ""}],page:{pageNo: 1,pageSize: 0,totalPage: 0,totalRecord: 0}}},mounted() {productType = this.$route.query.ptype;this.initPage(productType,1,9);//获取服务器数据doGet('/v1/invest/rank').then(resp => {if (resp) {this.rank = resp.data.list;}})},methods: {goLink(url,params){//使用router做页面跳转, vue中的对象this.$router.push({path: url,query: params})},initPage(productType,pNo,pSize) {//获取产品列表数据doGet('/v1/product/list', {ptype: productType, pageNo: pNo, pageSize: pSize}).then(resp => {if (resp) {this.productList = resp.data.list;this.page = resp.data.page;}})},first(){if( this.page.pageNo == 1 ){layx.msg('已经是第一页数据.',{dialogIcon:'warn',position:'ct'});} else {this.initPage(productType,1,9)}},last(){if( this.page.pageNo == this.page.totalPage ){layx.msg('已经是最后一页数据.',{dialogIcon:'warn',position:'ct'});} else {this.initPage(productType,this.page.totalPage,9)}},pre(){if( this.page.pageNo <= 1 ){layx.msg('已经是第一页数据.',{dialogIcon:'warn',position:'ct'});} else {this.initPage(productType,this.page.pageNo - 1 , 9);}},next(){if( this.page.pageNo >= this.page.totalPage ){layx.msg('已经是最后一页数据.',{dialogIcon:'warn',position:'ct'});} else {this.initPage(productType,this.page.pageNo + 1, 9);}}}
}
</script><style scoped></style>
10、产品详情Vue
<template><div><Header></Header><div class="content clearfix"><div class="detail-left"><div class="detail-left-title">{{ product.productName }}({{ product.productNo }}期)</div><ul class="detail-left-number"><li><span>历史年化收益率</span><p><b>{{ product.rate }}</b>%</p><span>历史年化收益率</span></li><li><span>募集金额(元)</span><p><b>{{ product.productMoney }}</b>元</p><span v-if="product.leftProductMoney > 0 ">募集中 剩余募集金额{{ product.leftProductMoney }}元</span><span v-else>已满标</span></li><li><span>投资周期</span><p v-if="product.productType == 0 "><b>{{product.cycle}}</b>天</p><p v-else><b>{{product.cycle}}</b>个月</p></li></ul><div class="detail-left-way"><span>收益获取方式</span><span>收益返还:<i>到期还本付息</i></span></div><!--投资记录--><div class="datail-record"><h2 class="datail-record-title">投资记录</h2><div class="datail-record-list"><table align="center" width="880" border="0" cellspacing="0" cellpadding="0"><colgroup><col style="width: 72px" /><col style="width: 203px" /><col style="width: 251px" /><col style="width: 354px" /></colgroup><thead class="datail_thead"><tr><th>序号</th><th>投资人</th><th>投资金额(元)</th><th>投资时间</th></tr></thead><tbody><tr v-for="(bid,ind) in bidList" :key="bid.id"><td>{{ind+1}}</td><td class="datail-record-phone">{{ bid.phone }}</td><td>{{ bid.bidMoney }}</td><td>{{ bid.bidTime }}</td></tr></tbody></table></div></div></div><!--右侧--><div class="detail-right"><div class="detail-right-title">立即投资</div><div class="detail-right-mode"><h3 class="detail-right-mode-title">收益方式</h3><p class="detail-right-mode-p"><span>到期还本付息</span></p><h3 class="detail-right-mode-title">我的账户可用</h3><div class="detail-right-mode-rmb" v-if="logined==false"><p>资金(元):******</p><a href="javascript:void(0);" @click="goLink('/page/user/login',)">请登录</a></div><div class="detail-right-mode-rmb" v-else><p>资金(元):{{this.accountMoney}}</p></div><h3 class="detail-right-mode-title">利息收入(元){{income}}</h3><form action="" id="number_submit"><p>请在下方输入投资金额</p><input type="text" placeholder="请输入日投资金额,应为100元整倍数" v-model="investMoney" @blur="checkInvestMoney" class="number-money" ><div class="err">{{investMoneyErr}}</div><input type="button" value="立即投资" @click="investProduct" class="submit-btn"></form></div></div></div><Footer></Footer></div>
</template><script>
import Header from "@/components/common/Header";
import Footer from "@/components/common/Footer";
import {doGet, doPost} from "@/api/httpRequest";
import layx from "vue-layx";export default {name: "ProductDetail",components:{// eslint-disable-next-line vue/no-unused-componentsHeader,// eslint-disable-next-line vue/no-unused-componentsFooter},data(){return {product:{id: 0,productName: "",rate: 0.0,cycle: 0,releaseTime: 0,productType: 0,productNo: "",productMoney: 0,leftProductMoney: 0,bidMinLimit: 0,bidMaxLimit: 0,productStatus: 0,productFullTime: "",productDesc: ""},bidList:[{id: 0,phone: "",bidTime: "",bidMoney: 0.00}],logined:false,accountMoney:0.0,investMoney: 100,investMoneyErr:'',income:""}},mounted() {//判断是否登录if( window.localStorage.getItem("userinfo")){this.logined = true;}this.initPage();},methods:{goLink(url,params){//使用router做页面跳转, vue中的对象this.$router.push({path: url,query: params})},initPage(){//查询产品信息let productId = this.$route.query.productId;doGet('/v1/product/info',{productId:productId}).then(resp=>{if( resp ) {this.product = resp.data.data;this.bidList = resp.data.list;}})//查询资金doGet('/v1/user/usercenter').then(resp=>{if( resp && resp.data.code == 1000){this.accountMoney = resp.data.data.money;}})},checkInvestMoney(){if( isNaN(this.investMoney )){this.investMoneyErr = '请输入正确的金额';} else if( parseInt(this.investMoney) < 100){this.investMoneyErr = '投资最小是100元';} else if( parseFloat(this.investMoney) % 100 !=0 ){this.investMoneyErr = '投资金额是100的整数倍';} else {this.investMoneyErr = '';//计算利息 利息 = 本金 * 周期 * 利率//当前产品数据 利率是 年利率是 ,百分数 。//不同类型的产品 ,周期不同, 新手宝是 天, 其他是月(30)//日利率let dayRate = this.product.rate / 365 / 100;//利息let incomeMoney = 0.0;if( this.product.productType == 0 ) {incomeMoney = this.investMoney * this.product.cycle * dayRate;} else {incomeMoney = this.investMoney * (this.product.cycle * 30) * dayRate;}this.income = incomeMoney.toFixed(2);}},investProduct(){//登录, 实名认证过let userinfo = JSON.parse(window.localStorage.getItem("userinfo"));if( userinfo ) {//检查是否有实名认证if(userinfo.name != ''){//投资this.checkInvestMoney();if(this.investMoneyErr == ''){doPost('/v1/invest/product',{ productId: this.product.id, money:this.investMoney}).then(resp=>{if( resp && resp.data.code == 1000){//投资成功this.initPage();}})}} else {//进行实名认证layx.msg('投资前需要实名认证.',{dialogIcon:'warn',position:'ct'});}} else {//去登录layx.msg('请先登录.',{dialogIcon:'warn',position:'ct'});}}}
}
</script><style scoped>
.err {color: red;font-size: 18px;
}
</style>
11、页面倒计时
12、注册Vue
<template><div><Header></Header><div class="login-content"><div class="login-flex"><div class="login-left"><p>万民用户知心托付 <span>{{ historyAvgRate }}%</span>历史年化收益</p><p>千万级技术研发投入 亿级注册资本平台 </p></div><!----><div class="login-box"><h3 class="login-title">用户注册</h3><form action="" id="register_Submit"><div class="alert-input"><input type="text" class="form-border user-num" @blur="checkPhone" v-model="phone" name="mobile"placeholder="请输入11位手机号"><div class="err">{{ phoneErr }}</div><p class="prompt_num"></p><input type="password" placeholder="请输入6-20位英文和数字混合密码"class="form-border user-pass" autocomplete name="password" v-model="password"@blur="checkPassword"><div class="err">{{ passwordErr }}</div><p class="prompt_pass"></p><div class="form-yzm form-border"><input class="yzm-write" type="text" name="" placeholder="输入短信验证码" v-model="code" @blur="checkCode"><input class="yzm-send" type="button" v-bind:value="yzmText" @click="requestSmsCode" id="yzmBtn"></div><div class="err">{{ codeErr }}</div><p class="prompt_yan"></p></div><div class="alert-input-agree"><input type="checkbox" v-model="agree">我已阅读并同意<a href="javascript:;" target="_blank">《动力金融网注册服务协议》</a></div><div class="alert-input-btn"><input type="button" class="login-submit" @click="requestUserRegister" value="注册"></div></form><div class="login-skip">已有账号? <a href="javascript:void(0)" @click="goLink('/page/user/login')">登录</a></div></div></div></div><Footer></Footer></div>
</template><script>
import Header from "@/components/common/Header";
import Footer from "@/components/common/Footer";
import {doGet, doPost} from "@/api/httpRequest";
import layx from "vue-layx";
import md5 from 'js-md5';export default {name: "RegisterView",components: {// eslint-disable-next-line vue/no-unused-componentsHeader,// eslint-disable-next-line vue/no-unused-componentsFooter},data() {return {historyAvgRate: 0.0,phone: '13812345699',phoneErr: '',password: '111aaa',passwordErr: '',code: '',codeErr: '',yzmText: '获取验证码',isSend: false,agree: false}},mounted() {//向服务器发起请求,获取数据,更新页面doGet('/v1/plat/info').then(resp => {if (resp) {this.historyAvgRate = resp.data.data.historyAvgRate;}})},methods: {goLink(url,params){//使用router做页面跳转, vue中的对象this.$router.push({path: url,query: params})},checkPhone() {if (this.phone == '' || this.phone == undefined) {this.phoneErr = '请输入手机号';} else if (this.phone.length != 11) {this.phoneErr = '手机号长度不足11位';} else if (!/^1[1-9]\d{9}$/.test(this.phone)) {this.phoneErr = '手机号格式不正确'} else {this.phoneErr = '';//向服务器发起请求,验证手机号是否可以注册doGet('/v1/user/phone/exists', {phone: this.phone}).then(resp => {if (resp && resp.data.code == 1000) {//手机号可以注册console.log("手机号可以注册")} else {this.phoneErr = resp.data.msg;}})}},checkPassword() {if (this.password == '' || this.password == undefined) {this.passwordErr = '请输入密码';} else if (this.password.length < 6 || this.password.length > 20) {this.passwordErr = '密码长度是6-20位';} else if (!/^[0-9a-zA-Z]+$/.test(this.password)) {this.passwordErr = '密码只能使用数字和字母';} else if (!/^(([a-zA-Z]+[0-9]+)|([0-9]+[a-zA-Z]+))[a-zA-Z0-9]*/.test(this.password)) {this.passwordErr = '密码是数字和字母的混合';} else {this.passwordErr = '';}},checkCode() {if (this.code == '' || this.code == undefined) {this.codeErr = '必须输入验证码';} else if (this.code.length != 4) {this.codeErr = '验证码是4位的';} else {this.codeErr = '';}},requestSmsCode() {//isSend:true, 发送验证码, 倒计时正在执行中。 false可以重新发送验证码if (this.isSend == false) {this.checkPhone();if (this.phoneErr == '') {this.isSend = true;let btn = document.getElementById("yzmBtn");btn.style.color = 'red';//处理倒计时let second = 5; //倒计时时间,默认是60秒setInterval(() => {if (second <= 1) {btn.style.color = '#688EF9';this.yzmText = "获取验证码";this.isSend = false;} else {second = second - 1;this.yzmText = second + "秒后重新获取";}}, 1000)//发起请求,给手机号发送验证码doGet('/v1/sms/code/register', {phone: this.phone}).then(resp => {if (resp && (resp.data.code == 1000 || resp.data.code == 1006)) {layx.msg('短信已经发送了', {dialogIcon: 'success', position: 'ct'});}})}}},requestUserRegister() {this.checkPhone();this.checkPassword();this.checkCode();if (this.phoneErr == '' && this.passwordErr == '' && this.codeErr == '') {if (this.agree) {//数据正确,提交注册请求//前端密码的md5()let newPassword = md5(this.password);doPost('/v1/user/register', {phone: this.phone,pword: newPassword,scode: this.code}).then(resp => {if (resp && resp.data.code == 1000) {//跳转登录页面this.$router.push({path: "/page/user/login"})}})} else {layx.msg("请阅读注册协议",{dialogIcon:'warn',position:'ct'});}}}}
}
</script><style scoped>
.err {color: red;font-size: 18px;
}
</style>
13、登录页面Vue
<template><div><Header></Header><div class="login-content"><div class="login-flex"><div class="login-left"><h3>加入动力金融网</h3><p>坐享<span>{{platInfo.historyAvgRate}}%</span>历史年化收益</p><p>平台用户<span>{{platInfo.registerUsers}}</span>位 </p><p>累计成交金额<span>{{platInfo.sumBidMoney}}</span>元</p></div><!----><div class="login-box"><h3 class="login-title">欢迎登录</h3><form action="" id="login_Submit"><div class="alert-input"><!--<input class="form-border user-name" name="username" type="text" placeholder="您的姓名"><p class="prompt_name"></p>--><input type="text" class="form-border user-num" v-model="phone" @blur="checkPhone" name="mobile" placeholder="请输入11位手机号"><div class="err">{{phoneErr}}</div><p class="prompt_num"></p><input type="password" placeholder="请输入登录密码" class="form-border user-pass" v-model="password" @blur="checkPassword" autocomplete name="password"><div class="err">{{passwordErr}}</div><p class="prompt_pass"></p><div class="form-yzm form-border"><input class="yzm-write" type="text" v-model="code" @blur="checkCode" placeholder="输入短信验证码"><input class="yzm-send" type="button" value="获取验证码" id="yzmBtn" @click="requestSmsCode" ></div><div class="err">{{codeErr}}</div><p class="prompt_yan"></p></div><div class="alert-input-btn"><input type="button" @click="userLogin" class="login-submit" value="登录"></div></form></div></div></div><Footer></Footer></div>
</template><script>
import Footer from "@/components/common/Footer";
import Header from "@/components/common/Header";
import {doGet, doPost} from "@/api/httpRequest";
import layx from "vue-layx";
import md5 from 'js-md5';export default {name: "LoginView",components:{// eslint-disable-next-line vue/no-unused-componentsHeader,// eslint-disable-next-line vue/no-unused-componentsFooter},data(){return {platInfo:{historyAvgRate:0.00,sumBidMoney:0.00,registerUsers:0},phone: '13812345699',phoneErr: '',password: '111aaa',passwordErr: '',code: '',codeErr: '',}},mounted() {doGet('/v1/plat/info').then(resp=>{if(resp ){this.platInfo = resp.data.data;}})},methods:{checkPhone(){if (this.phone == '' || this.phone == undefined) {this.phoneErr = '请输入手机号';} else if (this.phone.length != 11) {this.phoneErr = '手机号长度不足11位';} else if (!/^1[1-9]\d{9}$/.test(this.phone)) {this.phoneErr = '手机号格式不正确'} else {this.phoneErr = '';}},checkPassword() {if (this.password == '' || this.password == undefined) {this.passwordErr = '请输入密码';} else if (this.password.length < 6 || this.password.length > 20) {this.passwordErr = '密码长度是6-20位';} else if (!/^[0-9a-zA-Z]+$/.test(this.password)) {this.passwordErr = '密码只能使用数字和字母';} else if (!/^(([a-zA-Z]+[0-9]+)|([0-9]+[a-zA-Z]+))[a-zA-Z0-9]*/.test(this.password)) {this.passwordErr = '密码是数字和字母的混合';} else {this.passwordErr = '';}},checkCode() {if (this.code == '' || this.code == undefined) {this.codeErr = '必须输入验证码';} else if (this.code.length != 4) {this.codeErr = '验证码是4位的';} else {this.codeErr = '';}},requestSmsCode(){this.checkPhone();if( this.phoneErr == '' ){//调用服务器发到短信的接口 /code/logindoGet('/v1/sms/code/login',{phone:this.phone}).then(resp=>{if( resp && resp.data.code == 1000 ){layx.msg('短信已经发送了', {dialogIcon: 'success', position: 'ct'});}})}},userLogin(){this.checkPhone();this.checkPassword();this.checkCode();if( this.phoneErr == '' && this.passwordErr == '' & this.codeErr==''){//发起登录请求let param = {phone:this.phone,pword:md5(this.password),scode:this.code}doPost('/v1/user/login',param).then(resp=>{if( resp && resp.data.code == 1000){//登录成功,存储数据到localStorage,存的是字符串window.localStorage.setItem("token",resp.data.accessToken);//把 json对象转为 stringwindow.localStorage.setItem("userinfo", JSON.stringify(resp.data.data));//登录之后,如果name没有值,需要进入到实名认证页面//如果name有值,进入到用户中心if(resp.data.data.name == ''){//实名认证this.$router.push({path:'/page/user/realname'})} else {//用户中心this.$router.push({path:'/page/user/usercenter'})}}})}}}
}
</script><style scoped>
.err {color: red;font-size: 18px;
}
</style>
14、实名认证Vue
<template><div><Header> </Header><div class="login-content"><div class="login-flex"><div class="login-left"></div><!----><div class="login-box"><h3 class="login-title">实名认证</h3><form action="" id="renZ_Submit"><div class="alert-input"><input type="text" class="form-border user-name" name="username" v-model="name" @blur="checkName" placeholder="请输入您的真实姓名"><div class="err">{{nameErr}}</div><p class="prompt_name"></p><input type="text" class="form-border user-sfz" name="sfz" v-model="idCard" @blur="checkIdCard" placeholder="请输入15位或18位身份证号"><div class="err">{{idCardErr}}</div><p class="prompt_sfz"></p><input type="text" class="form-border user-num" name="mobile" v-bind:value="phone" readonly placeholder="请输入11位手机号"><p class="prompt_num"></p><div class="form-yzm form-border"><input class="yzm-write" type="text" v-model="code" @blur="checkCode" placeholder="输入短信验证码"><input class="yzm-send" type="text" value="获取验证码" disabled="disabled" id="yzmBtn" readonly="readonly" ></div><div class="err">{{codeErr}}</div><p class="prompt_yan"></p></div><div class="alert-input-agree"><input type="checkbox" v-model="agree">我已阅读并同意<a href="javascript:;" target="_blank">《动力金融网注册服务协议》</a></div><div class="alert-input-btn"><input type="button" @click="requestRealname" class="login-submit" value="认证"></div></form><div class="login-skip">暂不认证? <a href="javascript:;" @click="goLink('/page/user/usercenter')">跳过</a></div></div></div></div><Footer></Footer></div>
</template><script>
import Header from "@/components/common/Header";
import Footer from "@/components/common/Footer";
import {doPostJson} from "@/api/httpRequest";
import layx from "vue-layx";export default {name: "RealNameView",components: {// eslint-disable-next-line vue/no-unused-componentsHeader,// eslint-disable-next-line vue/no-unused-componentsFooter},data(){return {name:'',nameErr:'',idCard:'350721197702134399',idCardErr:'',code:'1234',codeErr:'',phone:'',agree:false}},mounted() {//获取localStorage中的用户数据let userinfo = window.localStorage.getItem("userinfo");if( userinfo ){this.phone = JSON.parse(userinfo).phone;}},methods:{goLink(url,params){//使用router做页面跳转, vue中的对象this.$router.push({path: url,query: params})},checkName(){if( this.name == '' || this.name == null ){this.nameErr = '必须输入姓名';} else if( this.name.length < 2 ){this.nameErr = '姓名不正确';} else if( !/^[\u4e00-\u9fa5]{0,}$/.test(this.name)){this.nameErr ='姓名必须是中文';} else {this.nameErr = '';}},checkIdCard(){if( this.idCard == '' || this.idCard == null){this.idCardErr = '请输入身份证号';} else if(!/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(this.idCard)){this.idCardErr='身份证号格式不正确';} else {this.idCardErr = '';}},checkCode() {if (this.code == '' || this.code == undefined) {this.codeErr = '必须输入验证码';} else if (this.code.length != 4) {this.codeErr = '验证码是4位的';} else {this.codeErr = '';}},requestRealname(){if(this.agree == false ){layx.msg('请阅读注册协议.',{dialogIcon:'warn',position:'ct'});return;}this.checkName();this.checkIdCard();this.checkCode();if( this.codeErr == '' && this.nameErr == '' && this.idCardErr == ''){let param = {name:this.name,phone:this.phone,idCard:this.idCard,code:this.code}doPostJson('/v1/user/realname',param).then(resp=>{if(resp && resp.data.code == 1000){//跳转到用户中心this.$router.push({path:'/page/user/usercenter'})}})}}}}
</script><style scoped>
.err {color: red;font-size: 18px;
}
</style>
15、用户中心Vue
<template><div><Header></Header><div class="content clearfix"><!--个人信息--><div class="user-head"><div class="user-head-left fl"><div class="user-head-img"><img src="@/assets/image/user-head.png" alt=""></div><p>上传头像</p></div><div class="user-head-right fl"><ul class="user-head-name fl"><li><b>{{userBaseInfo.name}}</b></li><li>{{ userBaseInfo.phone }}</li><li>最近登录:{{userBaseInfo.loginTime}}</li></ul><div class="user-head-money fr"><p>可用余额:<span>¥{{ userBaseInfo.money }}元</span></p><a href="javascript:void(0)" @click="goLink('/page/user/userpay')"style="color: red" class="user-head-a1">充值</a><a href="details.html" style="color: red" class="user-head-a2">投资</a></div></div></div><!--记录--><div class="user-record-box clearfix"><div class="user-record user-record-1"><h3 class="user-record-title">最近投资</h3><table align="center" width="388" border="0" cellspacing="0" cellpadding="0"><thead class="datail_thead"><tr><th>序号</th><th>投资产品</th><th>投资金额</th><th>投资时间</th></tr></thead><tbody><tr><td>1</td><td>新手宝</td><td>1500.0</td><td>2021-08-19</td></tr><tr><td>2</td><td>新手宝</td><td>1500.0</td><td>2021-08-19</td></tr><tr><td>3</td><td>新手宝</td><td>1500.0</td><td>2021-08-19</td></tr><tr><td>4</td><td>新手宝</td><td>1500.0</td><td>2021-08-19</td></tr><tr><td>5</td><td>新手宝</td><td>1500.0</td><td>2021-08-19</td></tr><tr><td>6</td><td>新手宝</td><td>1500.0</td><td>2021-08-19</td></tr></tbody></table><!--无记录--><p class="user-record-no">还没有投资记录,请投资:<a href="user_center.html" target="_blank">投资</a></p></div><div class="user-record user-record-2"><h3 class="user-record-title">最近充值</h3><table align="center" width="388" border="0" cellspacing="0" cellpadding="0"><thead class="datail_thead"><tr><th>序号</th><th>充值结果</th><th>充值金额</th><th>充值时间</th></tr></thead><tbody><tr v-for="(item,index) in rechargeList" :key="item.id"><td>{{index+1}}</td><td>{{item.result}}</td><td>{{item.rechargeMoney}}</td><td>{{item.rechargeDate}}</td></tr></tbody></table><!--无记录--><p class="user-record-no">还没有充值记录,请充值:<a href="javascript:void(0)" @click="goLink('/page/user/userpay')">充值</a></p></div><div class="user-record user-record-3"><h3 class="user-record-title ">最近收益</h3><table align="center" width="388" border="0" cellspacing="0" cellpadding="0"><thead class="datail_thead"><tr><th>序号</th><th>项目名称</th><th>投资日期</th><th>收益金额</th></tr></thead><tbody><tr><td>1</td><td>新手宝</td><td>2021-08-19</td><td>0.46</td></tr><tr><td>2</td><td>新手宝</td><td>2021-08-19</td><td>0.46</td></tr><tr><td>3</td><td>新手宝</td><td>2021-08-19</td><td>0.46</td></tr><tr><td>4</td><td>新手宝</td><td>2021-08-19</td><td>0.46</td></tr><tr><td>5</td><td>新手宝</td><td>2021-08-19</td><td>0.46</td></tr><tr><td>6</td><td>新手宝</td><td>2021-08-19</td><td>0.46</td></tr></tbody></table><!--无记录--><p class="user-record-no">还没有收益记录</p></div></div></div><Footer></Footer></div>
</template><script>
import Header from "@/components/common/Header";
import Footer from "@/components/common/Footer";
import {doGet} from "@/api/httpRequest";export default {name: "UserCenterView",components: {// eslint-disable-next-line vue/no-unused-componentsHeader,// eslint-disable-next-line vue/no-unused-componentsFooter},data() {return {userBaseInfo: {loginTime: "",money: 0.0,phone: "",name: "",headerUrl: ""},rechargeList:[{id: 0,result: "",rechargeDate: "",rechargeMoney: 0}]}},mounted() {doGet('/v1/user/usercenter').then(resp => {if (resp && resp.data.code == 1000) {this.userBaseInfo = resp.data.data;}});doGet('/v1/recharge/records',{pageNo:1,pageSize: 6}).then(resp=>{if(resp && resp.data.code == 1000){this.rechargeList = resp.data.list;}})},methods:{goLink(url,params){//使用router做页面跳转, vue中的对象this.$router.push({path: url,query: params})}}}
</script><style scoped></style>
16、前端访问api传递token,拦截器
在api/httpRequest.js中添加:
//创建拦截器
axios.interceptors.request.use(function (config) {//在需要用户登录后的操作,在请求的url中加入token//判断访问服务器的url地址, 需要提供身份信息,加入tokenlet storageToken = window.localStorage.getItem("token");let userinfo = window.localStorage.getItem("userinfo");if (storageToken && userinfo) {if (config.url == '/v1/user/realname' || config.url == '/v1/user/usercenter' ||config.url == '/v1/recharge/records' || config.url=='/v1/invest/product') {//在header中传递token 和一个userIdconfig.headers['Authorization'] = 'Bearer ' + storageToken;config.headers['uid'] = JSON.parse(userinfo).uid;}}return config;
}, function (err) {console.log("请求错误" + err);
})//创建应答拦截器,统一对错误处理, 后端返回 code > 1000 都是错误
axios.interceptors.response.use(function (resp) {if (resp && resp.data.code > 1000) {let code = resp.data.code;if (code == 3000) {//token无效,重新登录window.location.href = '/page/user/login';} else {layx.msg(resp.data.msg, {dialogIcon: 'warn', position: 'ct'});}}return resp;
}, function (err) {console.log("应答拦截器错误:" + err)//回到首页//window.location.href = '/';
})
17、用户充值Vue
<template>
<div><Header></Header><!--充值--><div class="user-pay-box clearfix"><div class="user-pay-left fl"><p class="user-pay-title1">我的账户</p><div class="user-pay-list"><a href="javascript:;" class="user-pay-list-on">充值</a><a href="javascript:;" target="_blank">我的信息</a><a href="javascript:;" target="_blank">投资记录</a><a href="javascript:;" target="_blank">收益记录</a></div></div><div class="user-pay-right fl"><p class="user-pay-title2">第三方支付平台</p><div class="user-pay-form"><img src="@/assets/image/kq.png" alt=""><form action="http://localhost:9000/pay/kq/rece/recharge" target="_blank" id="money_submit"><p class="user-pay-form-ts">请输入金额</p><input type="text" placeholder="元" name="rechargeMoney" value="0.01" class="number-money" ><input type="hidden" name="uid" v-bind:value="userId"><input type="submit" value="支付" class="submit-btn"></form></div><div class="user-pay-sm"><h3>温馨提示</h3><p>1.为了您的使用安全,充值操作建议不要使用公共电脑。</p><p>2.银行卡充值限额,由各银行限制。</p><p>3.品台禁止用卡套现、虚拟交易、洗钱等行为,一经发现并确认,将终止该账户的使用。</p><p>4.如果充值中出现问题,请联系客服400-890-0000。</p></div></div></div><Footer></Footer>
</div>
</template><script>
import Header from "@/components/common/Header";
import Footer from "@/components/common/Footer";export default {name: "UserPayView",data(){return {userId:0}},mounted() {let userinfo = window.localStorage.getItem("userinfo");if( userinfo ){this.userId = JSON.parse(userinfo).uid;}},components:{// eslint-disable-next-line vue/no-unused-componentsHeader,// eslint-disable-next-line vue/no-unused-componentsFooter},methods:{}
}
</script><style scoped></style>
发布评论