#经过下面的配置,以后所有的 npm install 都会经过淘宝的镜像地址下载
npm config set registry https://registry.npm.taobao.org
#查看npm配置信息
npm config list
lintOnSave: false,
{
"semi": false,
"singleQuote": true,
"htmlWhitespaceSensitivity": "ignore"
}
<template>
<div class="app-container">
积分等级列表
div>
template>
form.vue
<template>
<div class="app-container">
积分等级表单
div>
template>
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
//在整个路由中匹配,匹配到了跳转,没有匹配到有*跳转到404
/* Layout */
import Layout from '@/layout'
/**
* Note: sub-menu only appear when route children.length >= 1
* Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
*
* hidden: true if set true, item will not show in the sidebar(default is false)
* alwaysShow: true if set true, will always show the root menu
* if not set alwaysShow, when item has more than one children route,
* it will becomes nested mode, otherwise not show the root menu
* redirect: noRedirect if set noRedirect will no redirect in the breadcrumb
* name:'router-name' the name is used by (must set!!!)
* meta : {
roles: ['admin','editor'] control the page roles (you can set multiple roles)
title: 'title' the name show in sidebar and breadcrumb (recommend set)
icon: 'svg-name'/'el-icon-x' the icon show in the sidebar
breadcrumb: false if set false, the item will hidden in breadcrumb(default is true)
activeMenu: '/example/list' if set path, the sidebar will highlight the path you set
}
*/
/**
* constantRoutes
* a base page that does not have permission requirements
* all roles can be accessed
*/
export const constantRoutes = [
{
//路径是/login
path: '/login',
//登录页的路由
component: () => import('@/views/login/index'),
hidden: true,
},
//直接可以进入/404页
{
path: '/404',
component: () => import('@/views/404'),
hidden: true,
},
//只展示首页访问/跳转到/dashboard等于跳转到/src/views/dashboard/index
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [
{
path: 'dashboard',
name: 'Dashboard',
component: () => import('@/views/dashboard/index'),
meta: { title: '首页', icon: 'dashboard' },
},
],
},
{
//父路由 ,最终完整的路由为/core/integral-grade+子路由的path
path: '/core/integral-grade',
//布局组件,在大布局组件下的右侧为路由出口
component: Layout,
//访问/core/integral-grade后默认发跳转/core/integral-grade/list
redirect: '/core/integral-grade/list',
//名称都不能相同
name: 'coreIntegralGrade',
//显示节点名称和图标
meta: { title: '积分等级管理', icon: 'el-icon-s-marketing' },
//true任何时候都显示父节点和子节点,false如果只有一个子节点则只显示子节点不显示父节点
alwaysShow: true,
//三个子节点,只有两个子节点
children: [
{
path: 'list',
//为组件节点的定义名称,每个节点的name节点不能相同
name: 'coreIntegralGradeList',
//组件节点,引入模块 指向src/views/core/integral-grade/list
component: () => import('@/views/core/integral-grade/list'),
meta: { title: '积分等级列表' },
},
{
path: 'create',
name: 'coreIntegralGradeCreate',
component: () => import('@/views/core/integral-grade/form'),
meta: { title: '新增积分等级' },
},
{
//:id是一个占位符,表示这部分url是任何一个id
path: 'edit/:id',
name: 'coreIntegralGradeEdit',
component: () => import('@/views/core/integral-grade/form'),
meta: { title: '编辑积分等级' },
//隐藏子节点,希望通过新增积分等级的按钮进入该子节点
hidden: true,
},
],
},
{
path: '/example',
component: Layout,
redirect: '/example/table',
name: 'Example',
meta: { title: '例子', icon: 'el-icon-s-help' },
children: [
{
path: 'table',
name: 'Table',
component: () => import('@/views/table/index'),
meta: { title: 'Table', icon: 'table' },
},
{
path: 'tree',
name: 'Tree',
component: () => import('@/views/tree/index'),
meta: { title: 'Tree', icon: 'tree' },
},
],
},
{
path: '/form',
component: Layout,
children: [
{
path: 'index',
name: 'Form',
component: () => import('@/views/form/index'),
meta: { title: '表单', icon: 'el-icon-goods' },
},
],
},
]
/**
* asyncRoutes
* the routes that need to be dynamically loaded based on user roles
*/
export const asyncRoutes = [
{
path: '/nested',
component: Layout,
redirect: '/nested/menu1',
name: 'Nested',
meta: {
title: 'Nested',
icon: 'nested',
},
children: [
{
path: 'menu1',
component: () => import('@/views/nested/menu1/index'), // Parent router-view
name: 'Menu1',
meta: { title: 'Menu1' },
children: [
{
path: 'menu1-1',
component: () => import('@/views/nested/menu1/menu1-1'),
name: 'Menu1-1',
meta: { title: 'Menu1-1' },
},
{
path: 'menu1-2',
component: () => import('@/views/nested/menu1/menu1-2'),
name: 'Menu1-2',
meta: { title: 'Menu1-2' },
children: [
{
path: 'menu1-2-1',
component: () =>
import('@/views/nested/menu1/menu1-2/menu1-2-1'),
name: 'Menu1-2-1',
meta: { title: 'Menu1-2-1' },
},
{
path: 'menu1-2-2',
component: () =>
import('@/views/nested/menu1/menu1-2/menu1-2-2'),
name: 'Menu1-2-2',
meta: { title: 'Menu1-2-2' },
},
],
},
{
path: 'menu1-3',
component: () => import('@/views/nested/menu1/menu1-3'),
name: 'Menu1-3',
meta: { title: 'Menu1-3' },
},
],
},
{
path: 'menu2',
component: () => import('@/views/nested/menu2/index'),
meta: { title: 'menu2' },
},
],
},
{
path: 'external-link',
component: Layout,
children: [
{
path: 'https://panjiachen.github.io/vue-element-admin-site/#/',
meta: { title: 'External Link', icon: 'link' },
},
],
},
// 404 page must be placed at the end !!!
{ path: '*', redirect: '/404', hidden: true },
]
const createRouter = () =>
new Router({
// mode: 'history', // require service support
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes,
})
const router = createRouter()
// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher // reset router
}
export default router
server {
listen 80;
server_name localhost;
location ~ /core/ {
proxy_pass http://localhost:8110;
}
location ~ /sms/ {
proxy_pass http://localhost:8120;
}
location ~ /oss/ {
proxy_pass http://localhost:8130;
}
}
# just a flag
ENV = 'development'
# base api
#VUE_APP_BASE_API = '/dev-api'
#原来访问login: http://localhost:8528/dev-api/vue-admin-template/user/login
#更改后访问login:http://localhost/vue-admin-template/user/login
#登录不了,因为更改了
#登录登出为原来的登录登出的模拟(登录登出硬编码)
#其他为访问我们的nginx服务器(其他的)
#将地址更改为实际的nginx服务器端口80
#为真正的界面配置的
VUE_APP_BASE_API = 'http://localhost'
// for mock server
const responseFake = (url, type, respond) => {
return {
//连接mock服务器
//动态获取登录地址,此时硬编码写死
//原来是${process.env.VUE_APP_BASE_API}${url}
url: new RegExp(`/dev-api${url}`),
//request中仍然引的是VUE_APP_BASE_API
import request from '@/utils/request'
export function login(data) {
return request({
//原来的baseURL:ocess.env.VUE_APP_BASE_API-->VUE_APP_BASE_API = 'http://localhost'
//给模拟登录的路径配置的
baseURL: '/dev-api',
url: '/vue-admin-template/user/login',
method: 'post',
data,
})
}
export function getInfo(token) {
return request({
baseURL: '/dev-api',
url: '/vue-admin-template/user/info',
method: 'get',
params: { token },
})
}
export function logout() {
return request({
baseURL: '/dev-api',
url: '/vue-admin-template/user/logout',
method: 'post',
})
}
//引入axios的初始化模块
import request from '@/utils/request'
//导出默认模块
export default {
//定义模块成员
//成员方法:获取积分等级列表
list() {
//调用axios的初始化模块,发送远程ajax请求
return request({
//baseURL我们配置过为http://localhost
url: '/admin/core/integralGrade/list',
method: 'get',
})
},
}
<template>
<div class="app-container">
<!-- 表格 -->
<el-table :data="list" border stripe>
<el-table-column type="index" width="50" />
<el-table-column prop="borrowAmount" label="借款额度" />
<el-table-column prop="integralStart" label="积分区间开始" />
<el-table-column prop="integralEnd" label="积分区间结束" />
</el-table>
</div>
</template>
<script>
//引入api模块
import integralGradeApi from '@/api/core/integral-grade'
export default {
data() {
return {
list: [], //积分等级列表
}
},
created() {
this.fetchData()
},
methods: {
fetchData() {
integralGradeApi.list().then((response) => {
this.list = response.data.list
})
},
},
}
</script>
(response) => {
const res = response.data
// if the custom code is not 20000, it is judged as an error.
//mockserver 访问成功返回20000,自己的结果成功返回0
if (res.code !== 20000 && res.code != 0) {
Message({
message: res.message || 'Error',
type: 'error',
duration: 5 * 1000,
})
{
//父路由 ,最终完整的路由为/core/integral-grade+子路由的path
path: '/core/integral-grade',
//布局组件,在大布局组件下的右侧为路由出口
component: Layout,
//访问/core/integral-grade后默认发跳转/core/integral-grade/list
redirect: '/core/integral-grade/list',
//名称都不能相同
name: 'coreIntegralGrade',
//显示节点名称和图标
meta: { title: '积分等级管理', icon: 'el-icon-s-marketing' },
//true任何时候都显示父节点和子节点,false如果只有一个子节点则只显示子节点不显示父节点
alwaysShow: true,
//三个子节点,只有两个子节点
children: [
{
path: 'list',
//为组件节点的定义名称,每个节点的name节点不能相同
name: 'coreIntegralGradeList',
//组件节点,引入模块 指向src/views/core/integral-grade/list
component: () => import('@/views/core/integral-grade/list'),
meta: { title: '积分等级列表' },
},
{
path: 'create',
name: 'coreIntegralGradeCreate',
component: () => import('@/views/core/integral-grade/form'),
meta: { title: '新增积分等级' },
},
{
//:id是一个占位符,表示这部分url是任何一个id
path: 'edit/:id',
name: 'coreIntegralGradeEdit',
component: () => import('@/views/core/integral-grade/form'),
meta: { title: '编辑积分等级' },
//隐藏子节点,希望通过新增积分等级的按钮进入该子节点
hidden: true,
},
],
},
//引入axios的初始化模块
import request from '@/utils/request'
//导出默认模块
export default {
//定义模块成员
//成员方法:获取积分等级列表
list() {
//调用axios的初始化模块,发送远程ajax请求
return request({
//baseURL我们配置过为http://localhost
url: '/admin/core/integralGrade/list',
method: 'get',
})
},
removeById(id) {
return request({
url: '/admin/core/integralGrade/remove/' + id,
method: 'delete',
})
},
save(integralGrade) {
return request({
url: '/admin/core/integralGrade/save',
method: 'post',
//如果数据类型为json,需要data
data: integralGrade,
})
},
getById(id) {
return request({
url: '/admin/core/integralGrade/get/' + id,
method: 'get',
})
},
updateById(integralGrade) {
return request({
url: '/admin/core/integralGrade/update',
method: 'put',
data: integralGrade,
})
},
}
<template>
<div class="app-container">
<!-- 表格 -->
<el-table :data="list" border stripe>
<el-table-column type="index" width="50" />
<el-table-column prop="borrowAmount" label="借款额度" />
<el-table-column prop="integralStart" label="积分区间开始" />
<el-table-column prop="integralEnd" label="积分区间结束" />
<el-table-column label="操作" width="200" align="center">
<!-- 自定义模板内容 -->
<!-- slot-scope="scope"能够获得当前行的所有数据的id -->
<template slot-scope="scope">
<router-link
:to="'/core/integral-grade/edit/' + scope.row.id"
style="margin-right: 5px"
>
<el-button type="primary" size="mini" icon="el-icon-edit">
修改
</el-button>
</router-link>
<el-button
type="danger"
size="mini"
icon="el-icon-delete"
@click="removeById(scope.row.id)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
//引入api模块
import integralGradeApi from '@/api/core/integral-grade'
export default {
data() {
return {
list: [], //积分等级列表
}
},
created() {
this.fetchData()
},
methods: {
fetchData() {
integralGradeApi.list().then((response) => {
this.list = response.data.list
})
},
removeById(id) {
//debugger自动设置断点调试
this.$confirm('此操作将永久删除该记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
return integralGradeApi.removeById(id)
})
.then((response) => {
//调用message的模块
this.$message({
showClose: true,
message: response.message,
type: 'success',
})
//删除成功后重新获取list
this.fetchData()
})
.catch((error) => {
//因为response的模板里面也会有catch的模块,在例如url发生错误时但是又点击删除
//由于response模板先捕获删除,显示network error,又返回error对象
//此时进入这里的catch,那个error类型为'network error',故又会显示 已取消删除
//解决:加入判断error类型,如果error类型为前面的cancel则执行,如果为response里抛出的error则不执行
if (error == 'cancel') {
this.$message({
type: 'info',
message: '已取消删除',
})
}
})
},
},
}
</script>
<template>
<div class="app-container">
<!-- 输入表单 -->
<el-form label-width="120px">
<el-form-item label="借款额度">
<!-- 数字输入框 -->
<el-input-number v-model="integralGrade.borrowAmount" :min="0" />
</el-form-item>
<el-form-item label="积分区间开始">
<el-input-number v-model="integralGrade.integralStart" :min="0" />
</el-form-item>
<el-form-item label="积分区间结束">
<el-input-number v-model="integralGrade.integralEnd" :min="0" />
</el-form-item>
<el-form-item>
<el-button
:disabled="saveBtnDisabled"
type="primary"
@click="saveOrUpdate()"
>
保存
</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import integralGradeApi from '@/api/core/integral-grade'
export default {
data() {
return {
saveBtnDisabled: false, //是否禁用保存按钮,防止表单重复提交
integralGrade: {}, //积分等级对象
}
},
created() {
//当id存在时回显,id不存在时新增
//route对象是在发送response时自带对象route,能够获得前面url占位符id的值,没有则不调用
if (this.$route.params.id) {
this.fetchById(this.$route.params.id)
}
},
methods: {
fetchById(id) {
integralGradeApi.getById(id).then((response) => {
this.integralGrade = response.data.record
})
},
//保存或者更新
saveOrUpdate() {
//禁用保存按钮
this.saveBtnDisabled = true
if (!this.integralGrade.id) {
this.saveData()
this.$router.push('/core/integral-grade/list')
} else {
//调用更新
this.updateData()
}
//调用新增,调用完之后路由跳转
},
saveData() {
integralGradeApi.save(this.integralGrade).then((response) => {
this.$message({
type: 'success',
message: response.message,
})
})
},
// 根据id更新记录
updateData() {
// 数据的获取
integralGradeApi.updateById(this.integralGrade).then((response) => {
this.$message({
type: 'success',
message: response.message,
})
//重新加载list数据,跳转页面
this.$router.push('/core/integral-grade/list')
})
},
},
}
</script>
有唯一html文件(动态渲染,访问什么都是进入该html文件,包含一个div的id为app)
srb-admin\public\index.html
有唯一Vue对象(引入了路由并且动态渲染html中的id为app)
srb-admin\src\main.js
Vue对象渲染根组件
srb-admin\src\App.vue(定义了路由的出口)
通过路由渲染子组件(views视图–>侧边栏,导航栏,主内容栏)
srb-admin\src\router\index.js(路由)
srb-admin\src\layout\index.vue(要渲染的组件侧边栏,导航栏,主内容栏)
通过路由中定义的子节点来渲染主内容栏(获取积分数据)
srb-admin\src\layout\components\AppMain.vue(主内容栏定义了子路由的出口)
srb-admin\src\views\core\integral-grade\form.vue(路由子节点声明的模板渲染主内容栏)
难理解的问题
两个路由出口,第一次是路由整体渲染全部子节点的出口,第二次是子路由渲染子节点的出口。即父路由出口的位置和父路由+子路由渲染的出口的位置。
DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= webpackConfig.name %>title>
head>
<body>
<noscript>
<strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.strong>
noscript>
<div id="app">div>
body>
html>
import Vue from 'vue' //Vue
import 'normalize.css/normalize.css' // A modern alternative to CSS resets//基础CSS样式
import ElementUI from 'element-ui' //element-ui
import 'element-ui/lib/theme-chalk/index.css'
import locale from 'element-ui/lib/locale/lang/zh-CN' // lang i18n
import '@/styles/index.scss' // global css//全局css样式定义
import App from './App' //根组件
import store from './store' //前端信息存储工具
import router from './router' //路由模块
import '@/icons' // icon //扩展图标系统
import '@/permission' // permission control//角色控制权限系统
//mock为模拟接口(模拟接口服务器)
/**
* If you don't want to use mock-server
* you want to use MockJs for mock api
* you can execute: mockXHR()
*
* Currently MockJs will be used in the production environment,
* please remove it before going online ! ! !
*/
if (process.env.NODE_ENV === 'production') {
const { mockXHR } = require('../mock')
mockXHR()
}
//将elemeneUI挂载到Vue中
// set ElementUI lang to EN
Vue.use(ElementUI, { locale })
// 如果想要中文版 element-ui,按如下方式声明
// Vue.use(ElementUI)
Vue.config.productionTip = false
//创建Vue对象(核心Vue对象,指定渲染的节点,app,渲染public/index.html中的id为app的div)
new Vue({
el: '#app',
//挂载路由(将srb-admin\src\router\index.js的路由挂载到这)
router,
store,
//页面中展示的内容,组件(srb-admin\src\App.vue为根组件,最后所有组件都会嵌入)
render: (h) => h(App),
})
<template>
<div id="app">
<!--路由出口显式模板,模板都是由srb-admin\src\views下的文件来定义的-->
<router-view />
</div>
</template>
<script>
export default {
name: 'App',
}
</script>
{
//父路由 ,最终完整的路由为/core/integral-grade+子路由的path
path: '/core/integral-grade',
//布局组件,在大布局组件下的右侧为路由出口
component: Layout,
//访问/core/integral-grade后默认发跳转/core/integral-grade/list
redirect: '/core/integral-grade/list',
//名称都不能相同
name: 'coreIntegralGrade',
//显示节点名称和图标
meta: { title: '积分等级管理', icon: 'el-icon-s-marketing' },
//true任何时候都显示父节点和子节点,false如果只有一个子节点则只显示子节点不显示父节点
alwaysShow: true,
//三个子节点,只有两个子节点
children: [
{
path: 'list',
//为组件节点的定义名称,每个节点的name节点不能相同
name: 'coreIntegralGradeList',
//组件节点,引入模块 指向src/views/core/integral-grade/list
component: () => import('@/views/core/integral-grade/list'),
meta: { title: '积分等级列表' },
},
{
path: 'create',
name: 'coreIntegralGradeCreate',
component: () => import('@/views/core/integral-grade/form'),
meta: { title: '新增积分等级' },
},
{
//:id是一个占位符,表示这部分url是任何一个id
path: 'edit/:id',
name: 'coreIntegralGradeEdit',
component: () => import('@/views/core/integral-grade/form'),
meta: { title: '编辑积分等级' },
//隐藏子节点,希望通过新增积分等级的按钮进入该子节点
hidden: true,
},
],
},
{
path: '/example',
component: Layout,
redirect: '/example/table',
name: 'Example',
meta: { title: '例子', icon: 'el-icon-s-help' },
children: [
{
path: 'table',
name: 'Table',
component: () => import('@/views/table/index'),
meta: { title: 'Table', icon: 'table' },
},
{
path: 'tree',
name: 'Tree',
component: () => import('@/views/tree/index'),
meta: { title: 'Tree', icon: 'tree' },
},
],
},
{
path: '/form',
component: Layout,
children: [
{
path: 'index',
name: 'Form',
component: () => import('@/views/form/index'),
meta: { title: '表单', icon: 'el-icon-goods' },
},
],
},
]
<div
v-if="device === 'mobile' && sidebar.opened"
class="drawer-bg"
@click="handleClickOutside"
/>
<!--侧边栏-->
<sidebar class="sidebar-container" />
<div class="main-container">
<div :class="{ 'fixed-header': fixedHeader }">
<!--导航栏-->
<navbar />
</div>
<!--主内容区-->
<app-main />
</div>
</div>