Commit f5376f2b authored by wangwei's avatar wangwei

前端框架编写

parent 9e3de4e5
......@@ -11,7 +11,9 @@ const ExtractTextPlugin = require('extract-text-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const env = require('../config/prod.env')
const env = process.env.NODE_ENV === 'testing'
? require('../config/test.env')
: require('../config/prod.env')
const webpackConfig = merge(baseWebpackConfig, {
module: {
......@@ -46,7 +48,7 @@ const webpackConfig = merge(baseWebpackConfig, {
filename: utils.assetsPath('css/[name].[contenthash].css'),
// Setting the following option to `false` will not extract CSS from codesplit chunks.
// Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
// It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
// It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
// increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
allChunks: true,
}),
......@@ -62,7 +64,7 @@ const webpackConfig = merge(baseWebpackConfig, {
// see https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: config.build.index,
template: 'index.html',
template: process.env.NODE_ENV === 'testing' ? 'index.html' : 'index_prod.html',
inject: true,
minify: {
removeComments: true,
......
......@@ -3,5 +3,7 @@ const merge = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"'
NODE_ENV: '"development"',
API_URL: '"/"',
INVITE_URL:'"http://wechat.test.singsingenglish.com"',
})
......@@ -6,12 +6,17 @@ const path = require('path')
module.exports = {
dev: {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {},
//本地代理设置
proxyTable: {
'/api': {
target: 'http://local.base-api.sing.com', // 接口的域名
changeOrigin: true, // 如果接口跨域,需要进行这个参数配置
}
},
// Various Dev Server settings
host: 'localhost', // can be overwritten by process.env.HOST
port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
......@@ -20,7 +25,7 @@ module.exports = {
notifyOnErrors: true,
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
/**
* Source Maps
*/
......@@ -32,7 +37,6 @@ module.exports = {
// set this to false - it *may* help
// https://vue-loader.vuejs.org/en/options.html#cachebusting
cacheBusting: true,
cssSourceMap: true
},
......
......@@ -5234,6 +5234,11 @@
"integrity": "sha512-aUnNwqMOXw3yvErjMPSQu6qIIzUmT1e5KcU1OZxRDU1g/am6mzBvcrmLAYwzmB59BHPrh5/tKaiF4OPhqRWESQ==",
"dev": true
},
"js-md5": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.7.3.tgz",
"integrity": "sha512-ZC41vPSTLKGwIRjqDh8DfXoCrdQIyBgspJVPXHBGu4nZlAEvG3nf+jO9avM9RmLiGakg7vz974ms99nEV0tmTQ=="
},
"js-tokens": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
......
This diff is collapsed.
<template>
<div class="head-index">
<img src="../../assets/logo.png"/>
<!--<span> - 后台管理系统</span>-->
{{$store.state.userName}}
<div class="fl-r">
<el-button round size="mini">退出登录</el-button>
<el-button icon="el-icon-setting" circle size="mini"></el-button>
</div>
</div>
</template>
......@@ -15,16 +18,6 @@
@import "../../util/public";
.head-index{
height: 100%;
img{
height: 50px;
vertical-align: middle;
}
span{
color: @secondary-font-color;
margin-top: 4px;
font-size: 14px;
display: inline-block;
vertical-align: middle;
}
line-height: 40px;
}
</style>
<template>
<el-container>
<el-header height="60px">
<head-index/>
</el-header>
<el-aside width="60px">
<left-menu></left-menu>
</el-aside>
<el-container>
<el-aside width="60px">
<left-menu></left-menu>
</el-aside>
<el-header height="40px">
<head-index/>
</el-header>
<el-main>
<tab/>
<div class="router-block">
<el-collapse-transition>
<transition name="el-fade-in-linear">
<keep-alive>
<router-view class="child-view"/>
</keep-alive>
</el-collapse-transition>
</transition>
</div>
</el-main>
</el-container>
......@@ -60,6 +60,7 @@
}
.el-header{
border-bottom: 1px solid @light-line;
background: @light-line;
}
.child-view {
position: absolute;
......@@ -76,9 +77,14 @@
padding: 0;
overflow: hidden;
position: relative;
.tab{
position: relative;
z-index: 1;
}
.router-block{
position: absolute;
top: 49px;
top: 40px;
z-index: 0;
left: 0;
bottom: 0;
right: 0;
......
<template>
<div class="left-menu">
<img class="logo" :src="iconUrl"/>
<div class="menu-block">
<div class="menu-content" v-for="data in menuList" @click="toPath(data)">
<i :class="'iconfont '+data.icon"></i>
......@@ -10,10 +11,12 @@
</template>
<script>
import iconUrl from '../../assets/logos.png'
export default {
name: "leftMenu",
data(){
return {
iconUrl:iconUrl,
menuList:this.$store.state.menuList
}
},
......@@ -47,8 +50,12 @@
font-size: 12px;
text-align: center;
color: @main-font-color;
.logo{
margin-top: 20px;
width: 80%;
}
.menu-block {
padding-top: 100px;
padding-top: 20px;
.menu-content {
padding: 15px 0;
cursor: pointer;
......
......@@ -35,9 +35,9 @@
<style scoped lang="less">
@import "../../util/public";
.tab{
padding: 2px 5px;
background-color: @light-line;
padding: 0 5px;
position: relative;
box-shadow: 1px 0 5px @bg-b;
.clear-both;
.li-parent{
float: left;
......
<template>
<div>
<div class="login" :style="{backgroundImage:'url('+ bgUrl + ')'}">
<div class="wrap-main">
<h1 class="title">唱唱启蒙——后台管理系统</h1>
<el-form :model="login" :rules="loginRules" ref="loginForm">
<el-form-item prop="username">
<el-input v-model="login.username" placeholder="用户名"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input type="password" v-model="login.password" placeholder="密码"></el-input>
</el-form-item>
<el-form-item>
<el-button class="btn" size="medium" type="primary" @click="submitForm">登陆</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import { loginApi } from "../../service/api";
import md5 from 'js-md5';
import bgUrl from '../../assets/skyBackground.png'
export default {
name: "index"
name: "index",
data(){
return{
bgUrl:bgUrl,
login:{
username:'',
password:''
},
loginRules:{
username:[
{ required: true, message: '请输入您的用户名', trigger: 'blur' }
],
password:[
{ required: true, message: '请输入您的密码', trigger: 'blur' }
]
}
}
},
methods:{
// 提交
submitForm(){
this.$refs["loginForm"].validate((valid) => {
if (valid) {
let json = {
username:this.login.username,
password:md5(this.login.password)
};
loginApi(json).then(res=>{
if(res.code === 0){
this.$store.dispatch('setToken',res.data.token);
this.$store.dispatch('setUserName',res.data.user_name);
this.$router.push({name:'index'})
}else{
this.$message.error(res.msg);
}
})
}
})
}
}
}
</script>
<style scoped>
<style scoped lang="less">
@import "../../util/public";
.login{
height: 100%;
background-size: 100%;
background-repeat: no-repeat;
}
.wrap-main{
width: 300px;
height: 180px;
padding:50px 20px;
border-radius: 5px;
box-shadow: 0 0 10px @gray-line;
position: fixed;
line-height: 50px;
background-color: rgba(255,255,255,0.3);
top: 50%;
left: 50%;
margin-left: -200px;
margin-top: -200px;
.btn{
display: block;
width: 100%;
}
.title{
position: absolute;
top: -100px;
width: 100%;
text-align: center;
left: 0;
color: @black-line;
font-size: 26px;
text-shadow: 4px 4px rgba(255,255,255,0.3);
}
}
</style>
<template>
<div>
教材管理
</div>
<el-container>
<el-aside width="200px">
<resources-list />
</el-aside>
<el-main>
</el-main>
</el-container>
</template>
<script>
import ajax from '../../service'
export default {
import resourcesList from './resourcesList'
export default {
name: "index",
mounted(){
ajax.ajaxSend({
url:'http://wechat.test.singsingenglish.com/api/adm/textbook?page=1&per_page=20',
success:data=>{
console.log(this)
},
error:data=>{
console.log(this)
}
})
}
components: {resourcesList},
}
</script>
<style scoped>
<style scoped lang="less">
@import "../../util/public";
.el-container{
height: 100%;
}
</style>
<template>
<div class="resource-list">
<div class="title">
素材库
</div>
<div class="content">
<div class="img-block">
<img :src="defaultImgUrl"/>
添加图片
</div>
<div class="img-block">
<img :src="defaultTxtUrl"/>
添加文字
</div>
<div class="img-block">
<img :src="defaultMusicUrl"/>
添加音频
</div>
<div class="img-block">
<img :src="defaultVideoUrl"/>
添加视频
</div>
<div class="img-block">
<img :src="defaultTxtUrl"/>
添加绘本
</div>
</div>
</div>
</template>
<script>
import defaultImgUrl from '../../assets/defaultImg.png'
import defaultTxtUrl from '../../assets/defaultTxt.png'
import defaultMusicUrl from '../../assets/defaultMusic.png'
import defaultVideoUrl from '../../assets/defaultVideo.png'
import defaultBookUrl from '../../assets/defaultBook.png'
export default {
name: "resourcesList",
data(){
return{
defaultImgUrl:defaultImgUrl,
defaultTxtUrl:defaultTxtUrl,
defaultMusicUrl:defaultMusicUrl,
defaultVideoUrl:defaultVideoUrl,
defaultBookUrl:defaultBookUrl
}
}
}
</script>
<style scoped lang="less">
@import "../../util/public";
.resource-list{
height: 100%;
background: @light-line;
position: relative;
.title{
text-align: center;
background: white;
height: 30px;
line-height: 30px;
border-bottom: 1px solid @secondary-font-color;
}
.content{
position: absolute;
top: 31px;
bottom: 0;
left: 0;
right: 0;
overflow: auto;
.img-block{
margin: 10px;
background: white;
text-align: center;
padding: 10px;
img{
width: 60%;
margin: auto;
display: block;
}
}
}
}
</style>
......@@ -25,6 +25,8 @@
import 'tinymce/plugins/colorpicker'
import 'tinymce/plugins/preview'
import 'tinymce/plugins/media'
import {getAdminListApi} from "../../service/api";
export default {
name: 'tinymce',
data () {
......@@ -45,6 +47,9 @@
},
activated(){
this.show = true
getAdminListApi().then(res=>{
console.log(res)
})
},
deactivated(){
this.show = false
......
import Vue from 'vue'
import store from "@/store"
import Router from 'vue-router'
import Cookie from '../util/cookie'
import index from '@/components/framework'
import main from '@/components/main'
import login from '@/components/login'
import resources from '@/components/resources'
Vue.use(Router)
export default new Router({
const router =new Router({
routes: [
{
path:'/login',
name:'login',
component:login,
meta:{
skip_auth:true,
}
},
{
path: '/',
name: 'index',
......@@ -25,4 +37,25 @@ export default new Router({
]
}
]
})
});
router.beforeEach((to,from,next)=> {
//在已登录状态下不允许退回登录页面去
if (to.name === 'login' && store.state.token) {
next(false);
return;
}
//获取cookie里的token
if(Cookie.get('cc_token')){
store.dispatch('setToken',Cookie.get('cc_token'))
}
// 登录拦截
if (to.matched.some(record => record.meta.skip_auth !== true) && !store.state.token) {
next({
path: '/login'
})
} else {
next()
}
});
export default router;
import Vue from 'vue';
import {post,fetch,patch,put} from './index'
const _baseUrl=process.env.API_URL;
Vue.prototype.$post=post;
Vue.prototype.$fetch=fetch;
Vue.prototype.$patch=patch;
Vue.prototype.$put=put;
const loginURL = `${_baseUrl}api/admin/login`;
const getAdminListUrl = `${_baseUrl}api/admin/user/list`;
//登录
export const loginApi = function(json) {
return Vue.prototype.$post(loginURL,{"username":json.username,"passwd":json.password})
};
//查询用户列表
export const getAdminListApi = function () {
return Vue.prototype.$fetch(getAdminListUrl)
};
import axios from 'axios'
import { Message } from "element-ui";
export default {
"ajaxSend":function (ajaxObj) {
if(!ajaxObj.data){
ajaxObj.data={};//给data设置默认值
import axios from 'axios';
import md5 from 'js-md5';
import { MessageBox } from 'element-ui';
import Cookie from '../util/cookie'
// 默认超时设置
axios.defaults.timeout = 5000;
// 相对路径设置
axios.defaults.baseURL ='';
//http request 拦截器
axios.interceptors.request.use(
config => {
// 获取token
const token = Cookie.get('cc_token');
// 设置参数格式
config.headers = {
'Content-Type':'application/json',
};
// 添加token到headers
if(token){
config.headers.token = token
}
axios({
url:ajaxObj.url,
method:'post',
data:ajaxObj.data,
transformRequest: function(obj) {
}
}).then(res=>{
ajaxObj.success(res)
console.log(this)
}).catch(error=>{
ajaxObj.error(error);
Message.error({
// 饿了么的消息弹窗组件,类似toast
showClose: true,
message: error.response.data.message,
type: "error.data.error.message"
});
console.log(error.response.data.message)
console.log(this)
});
// 鉴权参数设置
if(config.method === 'get' && config.url !== '/api/admin/login'){
config.params = config.params || {}
let json = JSON.parse(JSON.stringify(config.params));
json.sing = "singsingenglish21000";
config.params.param_token = md5(JSON.stringify(json));
}else if(config.url !== '/api/admin/login'){
config.data = config.data || {};
let json = JSON.parse(JSON.stringify(config.data));
json = JSON.parse(json);
json.sing = "singsingenglish21000";
config.data.param_token = md5(JSON.stringify(json));
}
return config;
},
err => {
return Promise.reject(err);
}
);
//http response 拦截器
axios.interceptors.response.use(
response => {
if(response.data.errCode ===2){
// 登录验证
router.push({
path:"/login",
querry:{redirect:router.currentRoute.fullPath}//从哪个页面跳转
})
}
return response;
},
error => {
return Promise.reject(error)
}
);
/**
* 封装get方法
* @param url
* @param params
* @returns {Promise}
*/
export function fetch(url,params={}){
return new Promise((resolve,reject) => {
axios.get(url,{
params:params
})
.then(response => {
resolve(response.data);
})
.catch(err => {
reject(err);
let message = '请求失败!请检查网络';
if(err.response)message=err.response.data.message;
MessageBox({
title:'错误!',
message:message,
type:'error',
})
})
})
}
/**
* 封装post请求
* @param url
* @param data
* @returns {Promise}
*/
export function post(url,data = {}){
return new Promise((resolve,reject) => {
axios.post(url,data)
.then(response => {
resolve(response.data);
},err => {
reject(err);
let message = '请求失败!请检查网络';
if(err.response)message=err.response.data.message;
MessageBox({
title:'错误!',
message:message,
type:'error',
})
})
})
}
/**
* 封装patch请求
* @param url
* @param data
* @returns {Promise}
*/
export function patch(url,data = {}){
return new Promise((resolve,reject) => {
axios.patch(url,data)
.then(response => {
resolve(response.data);
},err => {
reject(err);
let message = '请求失败!请检查网络';
if(err.response)message=err.response.data.message;
MessageBox({
title:'错误!',
message:message,
type:'error',
})
})
})
}
/**
* 封装put请求
* @param url
* @param data
* @returns {Promise}
*/
export function put(url,data = {}){
return new Promise((resolve,reject) => {
axios.put(url,data)
.then(response => {
resolve(response.data);
},err => {
reject(err);
let message = '请求失败!请检查网络';
if(err.response)message=err.response.data.message;
MessageBox({
title:'错误!',
message:message,
type:'error',
})
})
})
}
export default{
//设置token
setToken({commit},token){
commit('setToken',token);
},
//设置用户名
setUserName({commit},name){
commit('setUserName',name);
},
}
import Vue from 'vue'
import vuex from 'vuex'
import menu from '../util/menuList'
import mutations from './mutations'
import actions from './actions'
Vue.use(vuex);
export default new vuex.Store({
state:{
show:false,
userName:'',
token:'',
menuList:menu,
menuType:false,
nowTab:'first',
......@@ -17,5 +21,7 @@ export default new vuex.Store({
routerPath:'/index'
}
],
}
},
mutations,
actions
})
import Cookie from "@/util/cookie";
const mutations={
//设置token
setToken(state,token){
state.token=token;
Cookie.set('cc_token',token);
},
//设置用户名
setUserName(state,userName){
state.userName=userName;
Cookie.set('cc_user_name',userName);
},
};
export default mutations;
export default{
set:function(name,value,days){
var d=new Date;
d.setTime(d.getTime()+24*60*60*1000*days);
window.document.cookie=name+"="+value+";path=/;expires="+d.toGMTString();
},
get:function(name){
var v=window.document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)');
return v?v[2]:null;
},
delete:function(name){
this.set(name,'',-1);
}
}
\ No newline at end of file
//颜色参数
@bg-b: #2f2f3c;
@black-line:#191919;
@gray-line:#666;
......@@ -7,8 +8,19 @@
@gold-color-light:#FFD04B;
@gold-color: #a18430;
//公共类
.fl-r{
float: right;
}
html{
font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
font-family: "Helvetica Neue",
Helvetica,
"PingFang SC",
"Hiragino Sans GB",
"Microsoft YaHei",
"微软雅黑",
Arial,
sans-serif;
}
.clear-both{
&:after{
......@@ -17,3 +29,17 @@ html{
clear: both;
}
}
//滚动条样式
::-webkit-scrollbar-track-piece { //滚动条凹槽的颜色,还可以设置边框属性
border-radius: 10px;
}
::-webkit-scrollbar {//滚动条的宽度
width:5px;
height:5px;
}
::-webkit-scrollbar-thumb {//滚动条的设置
background-color:@secondary-font-color;
border-radius: 10px;
height: 10px;
min-height:10px;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment