branch_cwy
cwy 3 months ago
parent 2737b1315a
commit b50b497f91

@ -1,30 +1,52 @@
// 导入Vue框架
import Vue from 'vue'
import 'normalize.css/normalize.css'// A modern alternative to CSS resets
// 导入normalize.css这是一种现代的CSS重置替代方案
import 'normalize.css/normalize.css'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import locale from 'element-ui/lib/locale/lang/zh-CN' // lang i18n
import VCharts from 'v-charts'
// 导入Element UI库
import ElementUI from 'element - ui'
// 导入Element UI的样式文件这里使用的是主题为chalk的样式
import 'element - ui/lib/theme - chalk/index.css'
// 导入Element UI的中文语言包用于国际化i18n
import locale from 'element - ui/lib/locale/lang/zh - CN'
import '@/styles/index.scss' // global css
// 导入V - Charts库用于图表绘制
import VCharts from 'v - charts'
// 导入项目中自定义的全局样式文件
import '@/styles/index.scss'
// 导入应用的根组件App
import App from './App'
// 导入路由配置文件
import router from './router'
// 导入Vuex的store配置文件
import store from './store'
import '@/icons' // icon
import '@/permission' // permission control
// 导入项目中的图标相关配置(可能是注册全局图标组件等操作)
import '@/icons'
// 导入权限控制相关的配置(可能是实现路由权限、组件权限等功能)
import '@/permission'
// 使用Element UI并传入中文语言包配置
Vue.use(ElementUI, { locale })
// 使用V - Charts库
Vue.use(VCharts)
// 设置在生产环境下不显示Vue的提示信息
Vue.config.productionTip = false
// 创建一个Vue实例
new Vue({
// 挂载点选择id为app的DOM元素
el: '#app',
// 使用导入的路由配置
router,
// 使用导入的store配置
store,
// 使用App组件作为模板
template: '<App/>',
// 注册App组件
components: { App }
})

@ -1,46 +1,79 @@
// 导入路由配置文件,这里的路由配置可能定义了应用中的各个页面路径和对应的组件等信息
import router from './router'
// 导入Vuex的store配置文件store通常用于管理应用中的状态数据
import store from './store'
import NProgress from 'nprogress' // Progress 进度条
import 'nprogress/nprogress.css'// Progress 进度条样式
import { Message } from 'element-ui'
import { getToken } from '@/utils/auth' // 验权
// 导入NProgress库用于在页面跳转时显示进度条
import NProgress from 'nprogress'
// 导入NProgress的样式文件这样才能正确显示进度条样式
import 'nprogress/nprogress.css'
// 从element - ui中导入Message组件用于显示提示信息
import { Message } from 'element - ui'
// 从 @/utils/auth文件中导入getToken函数该函数可能用于获取用户的登录令牌token用于验证用户是否已登录
import { getToken } from '@/utils/auth'
const whiteList = ['/login'] // 不重定向白名单
// 定义一个数组,其中包含不需要进行重定向的路径(白名单),这里只有'/login'路径在白名单中
const whiteList = ['/login']
// 注册一个全局的路由前置守卫beforeEach在每次路由跳转前都会执行这个函数
router.beforeEach((to, from, next) => {
// 启动NProgress进度条表示路由跳转开始
NProgress.start()
// 判断用户是否有登录令牌token
if (getToken()) {
// 如果用户已登录且要访问的路径是'/login'(登录页)
if (to.path === '/login') {
// 则重定向到应用的首页('/'
next({ path: '/' })
NProgress.done() // if current page is dashboard will not trigger afterEach hook, so manually handle it
// 手动结束NProgress进度条因为如果当前页是首页不会触发afterEach钩子函数
NProgress.done()
} else {
// 如果用户已登录且要访问的不是登录页
// 检查store中是否已经获取到用户角色信息如果没有获取到说明可能是首次登录或者角色信息丢失
if (store.getters.roles.length === 0) {
store.dispatch('GetInfo').then(res => { // 拉取用户信息
let menus=res.data.menus;
let username=res.data.username;
store.dispatch('GenerateRoutes', { menus,username }).then(() => { // 生成可访问的路由表
router.addRoutes(store.getters.addRouters); // 动态添加可访问路由表
next({ ...to, replace: true })
// 从store中分发dispatch一个名为'GetInfo'的action这个action可能用于从后端获取用户信息
store.dispatch('GetInfo').then(res => {
// 获取从后端返回的用户信息中的菜单menus数据和用户名username数据
let menus = res.data.menus;
let username = res.data.username;
// 根据获取到的菜单数据和用户名在store中分发dispatch一个名为'GenerateRoutes'的action来生成用户可访问的路由表
store.dispatch('GenerateRoutes', { menus, username }).then(() => {
// 将生成的可访问路由表动态添加到路由实例中
router.addRoutes(store.getters.addRoutes);
// 使用传入的to对象要访问的路由进行跳转并设置replace为true表示替换当前历史记录而不是添加新记录
next({...to, replace: true })
})
}).catch((err) => {
// 如果在获取用户信息过程中出错
// 先从store中分发dispatch一个名为'FedLogOut'的action这个action可能用于执行用户登出操作
store.dispatch('FedLogOut').then(() => {
// 显示错误提示信息,提示用户验证失败,需要重新登录
Message.error(err || 'Verification failed, please login again')
// 重定向到应用的首页('/'
next({ path: '/' })
})
})
} else {
// 如果store中已经有用户角色信息直接放行允许用户访问目标路由
next()
}
}
} else {
if (whiteList.indexOf(to.path) !== -1) {
// 如果用户没有登录令牌token
// 检查要访问的路径是否在白名单中
if (whiteList.indexOf(to.path)!== -1) {
// 如果在白名单中,直接放行,允许用户访问目标路由
next()
} else {
// 如果不在白名单中,重定向到登录页('/login'
next('/login')
// 手动结束NProgress进度条
NProgress.done()
}
}
})
// 注册一个全局的路由后置守卫afterEach在每次路由跳转完成后都会执行这个函数
router.afterEach(() => {
NProgress.done() // 结束Progress
// 结束NProgress进度条表示路由跳转结束
NProgress.done()
})

@ -1,42 +1,69 @@
// date.js
// 这个函数用于将一个日期对象按照指定的格式进行格式化
export function formatDate(date, fmt) {
// 如果格式化字符串中包含'y+'(表示年份)
if (/(y+)/.test(fmt)) {
// 使用正则表达式匹配到的'y+'替换为对应的年份值
// 获取当前日期的年份,将其转换为字符串
// 根据'y+'的长度,从年份字符串的末尾截取相应长度的字符进行替换
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
}
// 创建一个对象,包含了从日期对象中获取各种时间单位的方法
let o = {
'M+': date.getMonth() + 1,
'd+': date.getDate(),
'h+': date.getHours(),
'm+': date.getMinutes(),
's+': date.getSeconds()
'M+': date.getMonth() + 1, // 获取月份月份是从0开始的所以要加1
'd+': date.getDate(), // 获取日期
'h+': date.getHours(), // 获取小时
'm+': date.getMinutes(), // 获取分钟
's+': date.getSeconds() // 获取秒
};
// 遍历对象o中的每个属性时间单位
for (let k in o) {
// 使用正则表达式检查格式化字符串中是否包含当前时间单位的格式
if (new RegExp(`(${k})`).test(fmt)) {
// 将当前时间单位的值转换为字符串
let str = o[k] + '';
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str));
// 如果当前时间单位在格式化字符串中的格式长度为1则直接替换
// 如果长度大于1则调用padLeftZero函数进行补零操作后再替换
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1)? str : padLeftZero(str));
}
}
// 返回格式化后的字符串
return fmt;
}
function padLeftZero(str) {
return ('00' + str).substr(str.length);
}
// 这个函数用于将字符串格式的日期转换为日期对象
// 如果没有传入分隔符参数,则默认使用'-'作为分隔符
export function str2Date(dateStr, separator) {
if (!separator) {
separator = "-";
}
// 根据分隔符将日期字符串拆分成数组
let dateArr = dateStr.split(separator);
// 解析年份
let year = parseInt(dateArr[0]);
// 解析月份
let month;
//处理月份为04这样的情况
// 如果月份字符串以'0'开头(例如'04'),则去掉'0'后再解析为整数
if (dateArr[1].indexOf("0") == 0) {
month = parseInt(dateArr[1].substring(1));
} else {
month = parseInt(dateArr[1]);
}
// 解析日期
let day = parseInt(dateArr[2]);
// 使用解析后的年、月、日创建一个新的日期对象
// 注意月份在日期对象中是从0开始计数的所以要减1
let date = new Date(year, month - 1, day);
// 返回日期对象
return date;
}
// 这个函数用于在字符串左边补零
// 例如,如果传入'5',则返回'05'
function padLeftZero(str) {
// 在字符串前面加上'00',然后根据原字符串的长度从右边截取
return ('00' + str).substr(str.length);
}

@ -1,10 +1,17 @@
<template>
<!-- 整体的应用容器用于包裹页面内的各个功能模块通过设置外边距来控制在页面中的位置 -->
<div class="app-container">
<!-- 用于展示一些地址相关链接信息的布局容器 -->
<div class="address-layout">
<!-- el-row 组件用于创建行布局通过 :gutter 属性设置列之间的间隔为 20px -->
<el-row :gutter="20">
<!-- el-col 组件用于定义列这里设置占 6 列的宽度在使用了 12 列布局系统的情况下 -->
<el-col :span="6">
<!-- 带有外边框样式的容器 -->
<div class="out-border">
<!-- 标题部分用于显示该区域的标题 -->
<div class="layout-title">学习教程</div>
<!-- 主要内容部分展示具体的链接文本链接指向外部网站点击会在新标签页打开 -->
<div class="color-main address-content">
<a href="https://www.macrozheng.com" target="_blank">mall学习教程</a>
</div>
@ -28,12 +35,17 @@
</el-col>
</el-row>
</div>
<!-- 用于展示一些统计总数相关信息的布局容器 -->
<div class="total-layout">
<el-row :gutter="20">
<el-col :span="6">
<!-- 用于包裹单个统计项的框架容器 -->
<div class="total-frame">
<!-- 通过绑定属性显示对应的图标图标样式通过类名控制 -->
<img :src="img_home_order" class="total-icon">
<!-- 统计项的标题部分 -->
<div class="total-title">今日订单总数</div>
<!-- 显示具体统计数值的部分 -->
<div class="total-value">200</div>
</div>
</el-col>
@ -51,30 +63,40 @@
<div class="total-value">5000.00</div>
</div>
</el-col>
<!-- 以下是被注释掉的一个统计项可能原本用于展示近 7 天销售总额相关信息 -->
<!--<el-col :span="6">-->
<!--<div class="total-frame">-->
<!--<svg-icon icon-class="total-week" class="total-icon">-->
<!--</svg-icon>-->
<!--<div class="total-title">近7天销售总额</div>-->
<!--<div class="total-value">50000.00</div>-->
<!--</div>-->
<!--<div class="total-frame">-->
<!--<svg-icon icon-class="total-week" class="total-icon">-->
<!--</svg-icon>-->
<!--<div class="total-title">近7天销售总额</div>-->
<!--<div class="total-value">50000.00</div>-->
<!--</div>-->
<!--</el-col>-->
</el-row>
</div>
<!-- 用于展示一些特定信息如二维码提示文字等的卡片式布局容器 -->
<el-card class="mine-layout">
<!-- 将图片在水平方向上居中显示图片展示的是一个二维码设置了宽度和高度 -->
<div style="text-align: center">
<img width="150px" height="150px" src="http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg">
</div>
<!-- 提示文字告知用户 mall 全套学习教程正在连载中 -->
<div style="text-align: center">mall全套学习教程连载中</div>
<!-- 另一行提示文字引导用户关注公众号以第一时间获取相关内容 -->
<div style="text-align: center;margin-top: 5px"><span class="color-main">关注公号</span>第一时间获取</div>
</el-card>
<!-- 用于展示待处理事务相关信息的布局容器 -->
<div class="un-handle-layout">
<!-- 标题部分用于标识这是待处理事务区域 -->
<div class="layout-title">待处理事务</div>
<!-- 内容部分包含多个行和列来展示不同类型的待处理事务信息 -->
<div class="un-handle-content">
<el-row :gutter="20">
<el-col :span="8">
<div class="un-handle-item">
<!-- 显示事务类型的文字设置了字体粗细 -->
<span class="font-medium">待付款订单</span>
<!-- 显示对应事务数量的文字通过浮动使其靠右显示并设置了危险红色的颜色样式 -->
<span style="float: right" class="color-danger">(10)</span>
</div>
</el-col>
@ -133,6 +155,7 @@
</el-row>
</div>
</div>
<!-- 用于展示商品和用户总览信息的布局容器 -->
<div class="overview-layout">
<el-row :gutter="20">
<el-col :span="12">
@ -140,12 +163,14 @@
<div class="layout-title">商品总览</div>
<div style="padding: 40px">
<el-row>
<!-- 展示商品相关统计数值的列设置了危险红色的颜色样式 -->
<el-col :span="6" class="color-danger overview-item-value">100</el-col>
<el-col :span="6" class="color-danger overview-item-value">400</el-col>
<el-col :span="6" class="color-danger overview-item-value">50</el-col>
<el-col :span="6" class="color-danger overview-item-value">500</el-col>
</el-row>
<el-row class="font-medium">
<!-- 展示对应统计数值含义的标题列 -->
<el-col :span="6" class="overview-item-title">已下架</el-col>
<el-col :span="6" class="overview-item-title">已上架</el-col>
<el-col :span="6" class="overview-item-title">库存紧张</el-col>
@ -175,12 +200,14 @@
</el-col>
</el-row>
</div>
<!-- 用于展示订单统计相关信息的布局容器 -->
<div class="statistics-layout">
<div class="layout-title">订单统计</div>
<el-row>
<el-col :span="4">
<div style="padding: 20px">
<div>
<!-- 显示本月订单总数相关信息包括描述文字具体数值以及同比上月的增长情况 -->
<div style="color: #909399;font-size: 14px">本月订单总数</div>
<div style="color: #606266;font-size: 24px;padding: 10px 0">10000</div>
<div>
@ -189,6 +216,7 @@
</div>
</div>
<div style="margin-top: 20px;">
<!-- 显示本周订单总数相关信息同样包括描述文字数值和同比上周的变化情况 -->
<div style="color: #909399;font-size: 14px">本周订单总数</div>
<div style="color: #606266;font-size: 24px;padding: 10px 0">1000</div>
<div>
@ -197,6 +225,7 @@
</div>
</div>
<div style="margin-top: 20px;">
<!-- 显示本月销售总额相关信息 -->
<div style="color: #909399;font-size: 14px">本月销售总额</div>
<div style="color: #606266;font-size: 24px;padding: 10px 0">100000</div>
<div>
@ -205,6 +234,7 @@
</div>
</div>
<div style="margin-top: 20px;">
<!-- 显示本周销售总额相关信息 -->
<div style="color: #909399;font-size: 14px">本周销售总额</div>
<div style="color: #606266;font-size: 24px;padding: 10px 0">50000</div>
<div>
@ -216,6 +246,7 @@
</el-col>
<el-col :span="20">
<div style="padding: 10px;border-left:1px solid #DCDFE6">
<!-- el-date-picker 组件用于选择日期范围以下是对其各种属性的设置说明 -->
<el-date-picker
style="float: right;z-index: 1"
size="small"
@ -230,6 +261,7 @@
:picker-options="pickerOptions">
</el-date-picker>
<div>
<!-- ve-line 组件可能用于展示图表比如折线图等通过绑定多个属性来设置图表的数据是否显示图例加载状态等 -->
<ve-line
:data="chartData"
:legend-visible="false"
@ -243,7 +275,6 @@
</div>
</div>
</template>
<script>
import {str2Date} from '@/utils/date';
import img_home_order from '@/assets/images/home_order.png';

@ -1,18 +1,28 @@
<template>
<!-- el-menu 组件用于创建一个菜单这里设置了类名为 "navbar"模式为水平方向horizontal通常用于页面顶部的导航栏布局 -->
<el-menu class="navbar" mode="horizontal">
<!-- Hamburger 组件用于实现类似汉堡包样式的图标按钮点击可切换侧边栏状态通过绑定 :toggleClick 事件来触发切换侧边栏的方法:isActive 根据侧边栏的打开状态来显示相应的样式 -->
<hamburger class="hamburger-container" :toggleClick="toggleSideBar" :isActive="sidebar.opened"></hamburger>
<!-- 引入 Breadcrumb 组件可能用于展示页面的面包屑导航显示当前页面在整个网站结构中的层级路径但此处没有传入具体属性 -->
<breadcrumb></breadcrumb>
<!-- el-dropdown 组件用于创建一个下拉菜单触发方式设置为点击click这里用于展示用户相关操作的下拉菜单比如首页退出等功能 -->
<el-dropdown class="avatar-container" trigger="click">
<!-- 内部的 div 作为一个容器包裹用户头像和下拉箭头图标 -->
<div class="avatar-wrapper">
<!-- 通过绑定 :src 属性展示用户头像图片图片的源地址由变量 "avatar" 决定 -->
<img class="user-avatar" :src="avatar">
<!-- 使用一个向下的图标el-icon-caret-bottom作为下拉菜单的指示箭头 -->
<i class="el-icon-caret-bottom"></i>
</div>
<!-- el-dropdown-menu 组件用于定义下拉菜单的具体内容通过 slot="dropdown" 指定它在 el-dropdown 组件中的插槽位置 -->
<el-dropdown-menu class="user-dropdown" slot="dropdown">
<!-- router-link 组件用于创建路由链接点击可跳转到对应的路由路径这里是首页路径为 "/"样式设置为行内块元素 -->
<router-link class="inlineBlock" to="/">
<el-dropdown-item>
首页
</el-dropdown-item>
</router-link>
<!-- 另一个 el-dropdown-item 用于展示 "退出" 操作添加了分割线样式divided通过点击内部的 span 元素触发 logout 方法来执行退出登录操作 -->
<el-dropdown-item divided>
<span @click="logout" style="display:block;">退出</span>
</el-dropdown-item>
@ -20,27 +30,37 @@
</el-dropdown>
</el-menu>
</template>
<script>
// vuex mapGetters Vuex store getter
import { mapGetters } from 'vuex'
// Breadcrumb
import Breadcrumb from '@/components/Breadcrumb'
// Hamburger
import Hamburger from '@/components/Hamburger'
export default {
// 使 Breadcrumb Hamburger 便使
components: {
Breadcrumb,
Hamburger
},
computed: {
// 使 mapGetters Vuex store 'sidebar' 'avatar' getter
// this.sidebar this.avatar 访 store
...mapGetters([
'sidebar',
'avatar'
])
},
methods: {
// toggleSideBar Vuex store ToggleSideBar action
// action Vuex
toggleSideBar() {
this.$store.dispatch('ToggleSideBar')
},
// logout 退
// this.$store.dispatch Vuex store LogOut action LogOut action
// Promise .then location.reload() vue-router bug
logout() {
this.$store.dispatch('LogOut').then(() => {
location.reload() // vue-router bug
@ -49,46 +69,75 @@ export default {
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
/* 为类名为 "navbar" 的元素设置样式,以下是具体的样式属性说明 */
.navbar {
/* 设置元素的高度为 50px */
height: 50px;
/* 设置行高为 50px使得内部文本在垂直方向上居中对齐 */
line-height: 50px;
border-radius: 0px !important;
/* 覆盖默认的边框圆角设置,将其设置为 0px使其呈现直角样式 */
border-radius: 0px!important;
/* 为类名为 "hamburger-container" 的子元素设置样式,它属于 "navbar" 元素内部的元素 */
.hamburger-container {
/* 设置行高为 58px用于垂直方向上的布局调整 */
line-height: 58px;
/* 设置高度与父元素navbar保持一致为 50px */
height: 50px;
/* 将元素向左浮动,使其在水平方向上靠左排列 */
float: left;
/* 设置左右内边距为 10px用于控制内部元素与边界的间距 */
padding: 0 10px;
}
/* 为类名为 "screenfull" 的元素设置样式,它在 "navbar" 元素内部(从样式结构看应该是与全屏相关的功能元素,但代码中未体现其完整使用场景) */
.screenfull {
/* 设置元素的定位为绝对定位,以便可以精确控制其在父元素中的位置 */
position: absolute;
/* 设置元素距离父元素右侧 90px 的位置 */
right: 90px;
/* 设置元素距离父元素顶部 16px 的位置 */
top: 16px;
/* 设置元素的颜色为红色,可能用于特定的提示等功能 */
color: red;
}
/* 为类名为 "avatar-container" 的元素设置样式,它同样是 "navbar" 元素内部用于包裹用户头像及下拉菜单相关内容的容器 */
.avatar-container {
/* 设置高度与父元素navbar一致为 50px */
height: 50px;
/* 将元素设置为行内块级元素,使其可以在水平方向上与其他元素并排显示,同时又能设置宽度、高度等块级元素的属性 */
display: inline-block;
/* 将元素定位在父元素navbar的右侧距离右侧 35px 的位置 */
position: absolute;
right: 35px;
/* 为类名为 "avatar-wrapper" 的子元素设置样式,它是 "avatar-container" 内部进一步包裹头像和图标的容器 */
.avatar-wrapper {
/* 设置鼠标指针样式为手型,提示用户此处可点击操作(一般用于有交互功能的元素) */
cursor: pointer;
/* 设置元素距离顶部 5px 的外边距,用于垂直方向上的位置微调 */
margin-top: 5px;
/* 设置元素为相对定位,以便内部的绝对定位元素可以基于它来进行定位 */
position: relative;
/* 为类名为 "user-avatar" 的子元素(即用户头像图片元素)设置样式 */
.user-avatar {
/* 设置图片的宽度为 40px */
width: 40px;
/* 设置图片的高度为 40px */
height: 40px;
/* 设置图片的边框圆角为 10px使其呈现圆角矩形的外观 */
border-radius: 10px;
}
/* 为类名为 "el-icon-caret-bottom" 的子元素(即下拉箭头图标元素)设置样式 */
.el-icon-caret-bottom {
/* 设置元素为绝对定位以便精确控制其在父元素avatar-wrapper中的位置 */
position: absolute;
/* 设置元素距离父元素右侧 -20px 的位置(负数表示向左偏移) */
right: -20px;
/* 设置元素距离父元素顶部 25px 的位置,用于垂直方向上的定位 */
top: 25px;
/* 设置图标的字体大小为 12px调整图标大小 */
font-size: 12px;
}
}
}
}
</style>

@ -1,26 +1,36 @@
<template>
<!-- 最外层的 div 作为整个登录页面内容的容器 -->
<div>
<!-- 使用 el-card 组件创建一个卡片式的布局容器用于包裹登录表单相关内容并设置了特定的类名 -->
<el-card class="login-form-layout">
<!-- el-form 组件用于创建表单以下是对其属性的设置说明 -->
<el-form autoComplete="on"
:model="loginForm"
:rules="loginRules"
ref="loginForm"
label-position="left">
<!-- div 元素用于将 SVG 图标在水平方向上居中显示 -->
<div style="text-align: center">
<!-- svg-icon 组件用于展示 SVG 图标这里展示的图标类名为 "login-mall"并设置了宽度高度和颜色 -->
<svg-icon icon-class="login-mall" style="width: 56px;height: 56px;color: #409EFF"></svg-icon>
</div>
<!-- h2 标题元素展示登录页面的标题 "mall-admin-web"并设置了类名用于样式控制 -->
<h2 class="login-title color-main">mall-admin-web</h2>
<!-- el-form-item 组件表示表单中的一个项目这里对应 "用户名" 输入项通过 prop 属性关联验证规则 -->
<el-form-item prop="username">
<!-- el-input 组件用于创建输入框以下是对其属性和插槽的详细说明 -->
<el-input name="username"
type="text"
v-model="loginForm.username"
autoComplete="on"
placeholder="请输入用户名">
<span slot="prefix">
<svg-icon icon-class="user" class="color-main"></svg-icon>
</span>
<!-- 使用插槽 "prefix" 在输入框前面添加一个 SVG 图标图标类名为 "user"并设置了类名用于样式控制 -->
<span slot="prefix">
<svg-icon icon-class="user" class="color-main"></svg-icon>
</span>
</el-input>
</el-form-item>
<!-- 另一个 el-form-item 组件对应 "密码" 输入项同样通过 prop 属性关联验证规则 -->
<el-form-item prop="password">
<el-input name="password"
:type="pwdType"
@ -28,15 +38,19 @@
v-model="loginForm.password"
autoComplete="on"
placeholder="请输入密码">
<span slot="prefix">
<svg-icon icon-class="password" class="color-main"></svg-icon>
</span>
<!-- 同样使用插槽 "prefix" 在输入框前面添加表示密码的 SVG 图标图标类名为 "password"并设置类名用于样式控制 -->
<span slot="prefix">
<svg-icon icon-class="password" class="color-main"></svg-icon>
</span>
<!-- 使用插槽 "suffix" 在输入框后面添加一个可点击的 SVG 图标点击这个图标可以切换密码的显示隐藏状态图标类名为 "eye"并设置类名用于样式控制 -->
<span slot="suffix" @click="showPwd">
<svg-icon icon-class="eye" class="color-main"></svg-icon>
</span>
<svg-icon icon-class="eye" class="color-main"></svg-icon>
</span>
</el-input>
</el-form-item>
<!-- 又是一个 el-form-item 组件用于放置登录和获取体验账号的按钮并设置了底部外边距和文本居中样式 -->
<el-form-item style="margin-bottom: 60px;text-align: center">
<!-- el-button 组件用于创建按钮以下是按钮的相关属性设置说明 -->
<el-button style="width: 45%" type="primary" :loading="loading" @click.native.prevent="handleLogin">
登录
</el-button>
@ -46,139 +60,202 @@
</el-form-item>
</el-form>
</el-card>
<!-- img 标签用于展示一张背景图片图片的源地址通过绑定的变量 login_center_bg 来动态设置并设置了类名用于样式控制 -->
<img :src="login_center_bg" class="login-center-layout">
<!-- el-dialog 组件用于创建一个对话框以下是对其属性的详细说明 -->
<el-dialog
title="公众号二维码"
:visible.sync="dialogVisible"
:show-close="false"
:center="true"
width="30%">
<!-- div 元素用于在对话框内放置相关内容并将文本居中显示 -->
<div style="text-align: center">
<!-- span 元素用于展示提示文字通过设置不同的类名来控制文字的样式如字体大小颜色等提示用户关注公众号获取体验账号的操作流程 -->
<span class="font-title-large"><span class="color-main font-extra-large">关注公众号</span>回复<span class="color-main font-extra-large">体验</span>获取体验账号</span>
<br>
<!-- 再次使用 img 标签在对话框内展示公众号的二维码图片设置了图片的宽度高度以及顶部外边距 -->
<img src="http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg" width="160" height="160" style="margin-top: 10px">
</div>
<!-- 使用插槽 "footer" 在对话框底部定义按钮区域这里只有一个确定按钮 -->
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="dialogConfirm"></el-button>
<el-button type="primary" @click="dialogConfirm"></el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import {isvalidUsername} from '@/utils/validate';
import {setSupport,getSupport,setCookie,getCookie} from '@/utils/support';
import login_center_bg from '@/assets/images/login_center_bg.png'
// @/utils/validate isvalidUsername
import {isvalidUsername} from '@/utils/validate';
// @/utils/support Cookie
import {setSupport, getSupport, setCookie, getCookie} from '@/utils/support';
//
import login_center_bg from '@/assets/images/login_center_bg.png'
export default {
name: 'login',
data() {
const validateUsername = (rule, value, callback) => {
if (!isvalidUsername(value)) {
callback(new Error('请输入正确的用户名'))
} else {
callback()
}
};
const validatePass = (rule, value, callback) => {
if (value.length < 3) {
callback(new Error('密码不能小于3位'))
} else {
callback()
}
};
return {
loginForm: {
username: '',
password: '',
},
loginRules: {
username: [{required: true, trigger: 'blur', validator: validateUsername}],
password: [{required: true, trigger: 'blur', validator: validatePass}]
},
loading: false,
pwdType: 'password',
login_center_bg,
dialogVisible:false,
supportDialogVisible:false
export default {
name: 'login',
data() {
// validateUsername
const validateUsername = (rule, value, callback) => {
// isvalidUsername
if (!isvalidUsername(value)) {
// callback Error
callback(new Error('请输入正确的用户名'))
} else {
//
callback()
}
},
created() {
this.loginForm.username = getCookie("username");
this.loginForm.password = getCookie("password");
if(this.loginForm.username === undefined||this.loginForm.username==null||this.loginForm.username===''){
this.loginForm.username = 'admin';
};
// validatePass
const validatePass = (rule, value, callback) => {
// 3
if (value.length < 3) {
// callback Error 3
callback(new Error('密码不能小于3位'))
} else {
//
callback()
}
if(this.loginForm.password === undefined||this.loginForm.password==null){
this.loginForm.password = '';
};
return {
// loginForm
loginForm: {
username: '',
password: '',
},
// loginRules
loginRules: {
// blur validateUsername
username: [{required: true, trigger: 'blur', validator: validateUsername}],
// validatePass
password: [{required: true, trigger: 'blur', validator: validatePass}]
},
// loading false
loading: false,
// pwdType 'password'
pwdType: 'password',
//
login_center_bg,
// dialogVisible false
dialogVisible: false,
// supportDialogVisible 使 false
supportDialogVisible: false
}
},
created() {
// Cookie loginForm.username
this.loginForm.username = getCookie("username");
// Cookie loginForm.password
this.loginForm.password = getCookie("password");
// undefinednull
if (this.loginForm.username === undefined || this.loginForm.username == null || this.loginForm.username === '') {
// 'admin'
this.loginForm.username = 'admin';
}
// undefined null
if (this.loginForm.password === undefined || this.loginForm.password == null) {
//
this.loginForm.password = '';
}
},
methods: {
showPwd() {
// pwdType 'password'
if (this.pwdType === 'password') {
//
this.pwdType = ''
} else {
// 'password'
this.pwdType = 'password'
}
},
methods: {
showPwd() {
if (this.pwdType === 'password') {
this.pwdType = ''
handleLogin() {
// loginForm
this.$refs.loginForm.validate(valid => {
if (valid) {
// let isSupport = getSupport();
// if (isSupport === undefined || isSupport == null) {
// this.dialogVisible = true;
// return;
// }
// loading true
this.loading = true;
// $store.dispatch 'Login' action loginForm
this.$store.dispatch('Login', this.loginForm).then(() => {
// loading false
this.loading = false;
// Cookie 15 15
setCookie("username", this.loginForm.username, 15);
// Cookie 15
setCookie("password", this.loginForm.password, 15);
// $router.push '/'
this.$router.push({path: '/'})
}).catch(() => {
// loading false
this.loading = false
})
} else {
this.pwdType = 'password'
// false
console.log('参数验证不合法!');
return false
}
},
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
// let isSupport = getSupport();
// if(isSupport===undefined||isSupport==null){
// this.dialogVisible =true;
// return;
// }
this.loading = true;
this.$store.dispatch('Login', this.loginForm).then(() => {
this.loading = false;
setCookie("username",this.loginForm.username,15);
setCookie("password",this.loginForm.password,15);
this.$router.push({path: '/'})
}).catch(() => {
this.loading = false
})
} else {
console.log('参数验证不合法!');
return false
}
})
},
handleTry(){
this.dialogVisible =true
},
dialogConfirm(){
this.dialogVisible =false;
setSupport(true);
},
dialogCancel(){
this.dialogVisible = false;
setSupport(false);
}
})
},
handleTry() {
// dialogVisible true
this.dialogVisible = true
},
dialogConfirm() {
// dialogVisible false
this.dialogVisible = false;
// setSupport true setSupport
setSupport(true);
},
dialogCancel() {
// dialogVisible false
this.dialogVisible = false;
// setSupport false setSupport
setSupport(false);
}
}
}
</script>
<style scoped>
.login-form-layout {
position: absolute;
left: 0;
right: 0;
width: 360px;
margin: 140px auto;
border-top: 10px solid #409EFF;
}
/* 为类名为 "login-form-layout" 的元素设置样式,以下是具体样式属性的说明 */
.login-form-layout {
/* 将元素定位设置为绝对定位,使其可以相对于最近的已定位祖先元素进行定位 */
position: absolute;
/* 使其在水平方向上相对于父元素左对齐 */
left: 0;
/* 使其在水平方向上相对于父元素右对齐 */
right: 0;
/* 设置元素的宽度为 360px */
width: 360px;
/* 设置元素在垂直方向上居中,通过上下外边距 auto 实现 */
margin: 140px auto;
/* 设置元素的上边框样式,宽度为 10px颜色为 #409EFF */
border-top: 10px solid #409EFF;
}
.login-title {
text-align: center;
}
/* 为类名为 "login-title" 的元素设置样式,这里只是简单地将文本在元素内居中显示 */
.login-title {
text-align: center;
}
.login-center-layout {
background: #409EFF;
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
margin-top: 200px;
}
/* 为类名为 "login-center-layout" 的元素设置样式,以下是具体样式属性的说明 */
.login-center-layout {
/* 设置元素的背景颜色为 #409EFF */
background: #409EFF;
/* 设置元素的宽度自动适应内容,不会超出父元素宽度 */
width: auto;
/* 设置元素的高度自动适应内容,不会超出父元素高度 */
height: auto;
/* 设置元素的最大宽度为 100%,即不会超过父元素的宽度 */
max-width: 100%;
/* 设置元素的最大高度为 100%,即不会超过父元素的高度 */
max-height: 100%;
/* 设置元素的顶部外边距为 200px */
margin-top: 200px;
}
</style>

Loading…
Cancel
Save