提交 a8b75bda authored 作者: pengxiaohui's avatar pengxiaohui

init

上级
module.exports = {
domain: 'dev.ezijing.com',
url: 'https://live-broadcast2-admin.ezijing.com/api',
webpack: {
externals: {
CKEDITOR: 'window.CKEDITOR',
Base64: 'window.Base64',
md5: 'window.md5',
regeneratorRuntime: 'window.regeneratorRuntime',
wx: 'window.wx',
WeixinJSBridge: 'window.WeixinJSBridge'
},
devServer: {
proxy: {
/* 多个代理 */
// '/api': {
// target: $GLOBAL.webConf.url,
// selfHandleResponse: false,
// // selfHandleResponse: true, // 自定义 响应结构
// secure: false, // 如果是https接口,需要配置这个参数
// changeOrigin: true, // 如果接口跨域,需要进行这个参数配置
// followRedirects: true, // 由于重定向307,所以跟随重定向直接返回一个接口
// logLevel: 'info', // 日志打印级别
// headers: {
// 'Referer': $GLOBAL.webConf.url
// },
// pathRewrite: {
// '^/api': '/' // 需要rewrite重写的
// }
// }
}
}
},
ProvidePlugin: {},
others: {
loginUrl: 'https://login2.ezijing.com/auth/login/index'
// loginUrl: 'https://login.ezijing.com/auth/login/index'
}
}
module.exports = {
url: '/',
DesDir: './client-dist',
isUploadStatic: false,
webpack: {
externals: {
CKEDITOR: 'window.CKEDITOR',
Base64: 'window.Base64',
md5: 'window.md5',
regeneratorRuntime: 'window.regeneratorRuntime',
wx: 'window.wx',
WeixinJSBridge: 'window.WeixinJSBridge'
}
},
ProvidePlugin: {},
others: {
loginUrl: 'https://login.ezijing.com/auth/login/index'
}
}
module.exports = {
url: '/',
DesDir: './client-dist',
isUploadStatic: false,
webpack: {
externals: {
CKEDITOR: 'window.CKEDITOR',
Base64: 'window.Base64',
md5: 'window.md5',
regeneratorRuntime: 'window.regeneratorRuntime',
wx: 'window.wx',
WeixinJSBridge: 'window.WeixinJSBridge'
}
},
ProvidePlugin: {},
others: {
loginUrl: 'https://login2.ezijing.com/auth/login/index'
}
}
# 查到当前目录就可以了,不用再往下查找
root = true
# 对所有文件制定规范
[*]
charset = utf-8 # 字符编码
end_of_line = lf # 从左往右写
indent_size = 2 # tab键长度2个空格
indent_style = space
insert_final_newline = true # 保存自动加上一个空行
trim_trailing_whitespace = true # 每行最后空格去掉
{
"extends": "standard",
"plugins": ["html"],
"parser": "vue-eslint-parser",
"parserOptions": {
"parser": "babel-eslint",
"sourceType": "module"
},
"rules": {
"no-new": "off",
"no-debugger": "off",
"space-before-function-paren": "off",
"semi": "off", // 语句末尾分号检测
"eol-last": "off", // 文件末尾必须有空行(以换行符结束)
"prefer-promise-reject-errors": "off" // promise reject必须是error对象
},
"globals": {
"CKEDITOR": false,
"Base64": false,
"md5": false,
"$": false,
"window": false,
"webConf": false,
"wx": false,
"WeixinJSBridge": false,
"Aliplayer": false
}
}
.DS_Store
node_modules
npm-debug.log
upload_tmp
# code protect - prevent submit code below
/dist
/client-dist
.DS_Store
node_modules
npm-debug.log
# code protect - prevent submit code below
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.12.0</center>
</body>
</html>
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.12.0</center>
</body>
</html>
var semver = require('semver')
var requiredVersion = require('../package.json').engines.node
function checkNodeVersion (wanted, id) {
if (!semver.satisfies(process.version, wanted)) {
console.log('\x1b[91m%s\x1B[0m',
'You are using Node ' + process.version + ', but this version of ' + id +
' requires Node ' + wanted + '.\nPlease upgrade your Node version.'
)
process.exit(1)
}
}
checkNodeVersion(requiredVersion, '`node uploadAliyunCDN.js`')
const isDev = process.env.NODE_ENV
const RegStrs = require('./regExpStr.js')
let config = {
isDev: isDev,
ResDir: 'src',
DesDir: '../client-dist',
HtmlPath: 'src/index.html',
IcoPath: 'src/assets/favicon.ico',
JsPath: 'src/main.js',
isHttps: true,
isEnableToIphoneDebugger: false,
CDN_BASE: 'https://zws-imgs-pub.ezijing.com/',
CDN_DIR: 'static/build/learn-mba/',
isUploadStatic: false,
webpack: {}
}
config.RegStrs = RegStrs
let vueClientConfig = {}
config.domain = ''
if (config.isDev === 'development') {
config.url = 'http://' + config.domain + ':12002'
try {
vueClientConfig = require('../.config.dev.js')
} catch (error) {
vueClientConfig = {}
console.error('没有开发环境配置文件 -- `.config.dev.js`,正在使用默认配置')
}
} else if(config.isDev === 'test') {
config.url = '//api.ezijing.com'
try {
vueClientConfig = require('../.config.test.js')
} catch (error) {
vueClientConfig = {}
console.error('没有测试环境配置文件 -- `.config.test.js`,正在使用默认配置')
}
} else {
config.url = '//api.ezijing.com'
try {
vueClientConfig = require('../.config.pro.js')
} catch (error) {
vueClientConfig = {}
console.error('没有生产环境配置文件 -- `.config.pro.js`,正在使用默认配置')
}
}
for (let k in vueClientConfig) {
config[k] = vueClientConfig[k]
}
module.exports = config
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA9MjUExxOj6tfMUaU+t/k0+VokVkh1GVZACLPdxR2VcjjOkaI
qloY4TK4/uybncLhoqu9ggyiJFNmXVLxe2TxReGXhR8tAc0RTCuaFv0oHJ7HXI48
CZ/zc8sgjyd7XsuyRurKwpHWXfy9FMHE7r/9R+IUHAkIPmZ17qlwqphlePK8I1fn
DU/LOvglXPIlR55TUe6NKVoCPZXQEHHPZClH0qdnXFiUq5I1f6GMUoGCbV5DLECb
OAndCP/snqakw8oeLmoBGSig/FGrc/41l2DJxyIxm/CfaEhfnSN4hvOTAFXcro9c
gyy88H1BfT/bEhM7OO+RRaKUrV5CieeIOEmvGQIDAQABAoIBAGmkcsJ8qPsgPskJ
aSqMjjlU/Lgd+5eq1apVW6xMzHVhaY+w+TJsB+jI90Yt30tK3A5UiEkkIqYCyF7m
eQmEGwzJu5bcSZRJaHmzJ6FcSH9xlyC+0fJlcbA7riWaKIhU6O/qTO+D+Tw+42ud
5NwVR75KN9uRmlkz5xnFTraRZtm3MJmA7dwXK3hrN+dFJR2vLO3KBAtpgtpPdkK1
ObpJQ1Q7jsnEmODVRZ7n1CKZEDmXd8GBPA/jCVqgiEbVVCdkhHkyxyIMQenBReyy
tJIPf7CdL3O3PPsThhMa1P2CP/xehS4bcQSLw9wtNTJcvVPHTvffHKOKUfhUxkHu
0cpl+zECgYEA/jzySW/br7W+xS2e4VBHzY+UZJwxd/3mY3d/kasMV1zuipr6WOhQ
FVsd5uJXPRr+rHBypwyOIlP205V2K5oQEK0yT+tF+IBvKGdJv89wskCgrXcD3Kfb
dCFbt014pHw89A8jb8LBbGOPH6jhZhGkxP33CJdVPtncUc4m0hj4HHcCgYEA9nsc
KcCZOIYRlZmJ93DoukhjxaouGFDTOZoujaqasrfXUaWRnpZYekDZWa1NneOzLBEz
h1RwPcmeYLCVRmXtpRzLOKXfJY0gGSJr979I0AVkzj8A9NZcU/HxUP0GqpwBbzAp
EEShQVhjYppQ62KAwZ1tbsVWX2V1SBsa3McExO8CgYEA6kVy5aTDhOgugDeHnguB
/rN9hDBBjVZTQ/jLfolld+NUlDg21FJN6T/rD+Qli1MitfdwTupM1ukUGugw2gC/
KP7Py8D62wBObaav2KXoLPlMlkuDLYMnv501jHVA5CDvcd25Q7Ts01nyerP97zX2
5Oc5CZuZm67ZTDBwqU0E5AUCgYBIC2wL+DPRBb8WDy74mJQt/wLKwBeBG/7hk2OQ
HRHis0HIp7CMvj1WXqYpRDKvt+KjOtPo9pFoPgqBEJxRW3G/FU+BW1qCS2HadulA
HTVXOHxinJ/W8OFD2DBFD/Bm5fq1WUpnaugHhaJnK9wDMWOZND7MZfn9IFbLoMCV
T8bhGQKBgG7qsZhI9ldAqooZQ1xSua/2SBc8GI8d03g7y8kZkkx/XclbEz6X6wUu
U3PVL+neY8Qw3JxC1cHS++KIdHR2ZSoTpF00A4QvDJL0+eo1KgI88vRV8QaWLxPB
ahvXwmkKW2+jgvCAqFtepZx/KsKpQW+x3GOJyhl2tIT8sZwRmE6u
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIFhzCCBG+gAwIBAgIQCzEi4VmynSzbyBV1UEXGojANBgkqhkiG9w0BAQsFADBu
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS0wKwYDVQQDEyRFbmNyeXB0aW9uIEV2ZXJ5d2hlcmUg
RFYgVExTIENBIC0gRzEwHhcNMjAxMTA5MDAwMDAwWhcNMjExMTA5MjM1OTU5WjAa
MRgwFgYDVQQDEw9kZXYuZXppamluZy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQD0yNQTHE6Pq18xRpT63+TT5WiRWSHUZVkAIs93FHZVyOM6Roiq
WhjhMrj+7JudwuGiq72CDKIkU2ZdUvF7ZPFF4ZeFHy0BzRFMK5oW/SgcnsdcjjwJ
n/NzyyCPJ3tey7JG6srCkdZd/L0UwcTuv/1H4hQcCQg+ZnXuqXCqmGV48rwjV+cN
T8s6+CVc8iVHnlNR7o0pWgI9ldAQcc9kKUfSp2dcWJSrkjV/oYxSgYJtXkMsQJs4
Cd0I/+yepqTDyh4uagEZKKD8Uatz/jWXYMnHIjGb8J9oSF+dI3iG85MAVdyuj1yD
LLzwfUF9P9sSEzs475FFopStXkKJ54g4Sa8ZAgMBAAGjggJzMIICbzAfBgNVHSME
GDAWgBRVdE+yck/1YLpQ0dfmUVyaAYca1zAdBgNVHQ4EFgQUkRHkmubxZAvEWtCY
IBT9sw/3Yb8wGgYDVR0RBBMwEYIPZGV2LmV6aWppbmcuY29tMA4GA1UdDwEB/wQE
AwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwTAYDVR0gBEUwQzA3
BglghkgBhv1sAQIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu
Y29tL0NQUzAIBgZngQwBAgEwgYAGCCsGAQUFBwEBBHQwcjAkBggrBgEFBQcwAYYY
aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEoGCCsGAQUFBzAChj5odHRwOi8vY2Fj
ZXJ0cy5kaWdpY2VydC5jb20vRW5jcnlwdGlvbkV2ZXJ5d2hlcmVEVlRMU0NBLUcx
LmNydDAJBgNVHRMEAjAAMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHYA9lyUL9F3
MCIUVBgIMJRWjuNNExkzv98MLyALzE7xZOMAAAF1qpa6jQAABAMARzBFAiAwHOcp
Ua1H0WK4OZUHiQ1rndqnYxPHhP9XWunwpRMoagIhAOB2MPSW9M4qj6Yih7eQkydl
lgawpoBZzRzhisU+TN67AHYAXNxDkv7mq0VEsV6a1FbmEDf71fpH3KFzlLJe5vbH
DsoAAAF1qpa63gAABAMARzBFAiEA92ZeW0PgyWW3j+3wypLS0O/wI63C+x0WTvMZ
Vngp6AMCIBoThjaKif+XY11YbaV89ndqs1nDlzbEfBrFftoB9fchMA0GCSqGSIb3
DQEBCwUAA4IBAQA2geo9wQAd+vx+lwAafVRxCBQyBiS0qT413ewYpZYDnSkLX0l1
5kRdxDGWQhPzOio0ckj/jOtOlbbSsiovBBVTyYPB8WfkNjMd0psMNx2e6Wy/WKkQ
X3DqEOB4XGg0RwpebiAmz6lWxyFwIAbCrwCntkkaIF4LnIvczn6pvPFBtK2nXJJC
HL0Igbxo+xJLt3Hql7TcwkFDXz/LIB8AwhhkkhhwW45r3Eyjw8eOyzvflDPwSNH+
ByadQ+AH4H4vYYVo0ILNIPCdaokLQ+u4FttB9VQ+iGmpJ56Yg2muxWh8Qckca+vH
40RbC5aK1RSy2RIRpC5fwvq2JuV/CksP5G5Q
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEqjCCA5KgAwIBAgIQAnmsRYvBskWr+YBTzSybsTANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0xNzExMjcxMjQ2MTBaFw0yNzExMjcxMjQ2MTBaMG4xCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xLTArBgNVBAMTJEVuY3J5cHRpb24gRXZlcnl3aGVyZSBEViBUTFMgQ0EgLSBH
MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALPeP6wkab41dyQh6mKc
oHqt3jRIxW5MDvf9QyiOR7VfFwK656es0UFiIb74N9pRntzF1UgYzDGu3ppZVMdo
lbxhm6dWS9OK/lFehKNT0OYI9aqk6F+U7cA6jxSC+iDBPXwdF4rs3KRyp3aQn6pj
pp1yr7IB6Y4zv72Ee/PlZ/6rK6InC6WpK0nPVOYR7n9iDuPe1E4IxUMBH/T33+3h
yuH3dvfgiWUOUkjdpMbyxX+XNle5uEIiyBsi4IvbcTCh8ruifCIi5mDXkZrnMT8n
wfYCV6v6kDdXkbgGRLKsR4pucbJtbKqIkUGxuZI2t7pfewKRc5nWecvDBZf3+p1M
pA8CAwEAAaOCAU8wggFLMB0GA1UdDgQWBBRVdE+yck/1YLpQ0dfmUVyaAYca1zAf
BgNVHSMEGDAWgBQD3lA1VtFMu2bwo+IbG8OXsj3RVTAOBgNVHQ8BAf8EBAMCAYYw
HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8C
AQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp
Y2VydC5jb20wQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQu
Y29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDBMBgNVHSAERTBDMDcGCWCGSAGG
/WwBAjAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BT
MAgGBmeBDAECATANBgkqhkiG9w0BAQsFAAOCAQEAK3Gp6/aGq7aBZsxf/oQ+TD/B
SwW3AU4ETK+GQf2kFzYZkby5SFrHdPomunx2HBzViUchGoofGgg7gHW0W3MlQAXW
M0r5LUvStcr82QDWYNPaUy4taCQmyaJ+VB+6wxHstSigOlSNF2a6vg4rgexixeiV
4YSB03Yqp2t3TeZHM9ESfkus74nQyW7pRGezj+TC44xCagCQQOzzNmzEAP2SnCrJ
sNE2DpRVMnL8J6xBRdjmOsC3N6cQuKuRXbzByVBjCqAA8t1L0I+9wXJerLPyErjy
rMKWaBFLmfK/AHNF4ZihwPGOc7w6UHczBZXH5RFzJNnww+WnKuTPI0HfnVH8lg==
-----END CERTIFICATE-----
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
const fs = require('fs')
const path = require('path')
const request = require('request')
const _conf = require('./config')
fs.writeFileSync(path.join(__dirname, _conf.domain + '.key'), '', { encoding: 'utf8', mode: 0o755 })
fs.writeFileSync(path.join(__dirname, _conf.domain + '.pem'), '', { encoding: 'utf8', mode: 0o755 })
request('https://ssl.godzyx.com/' + _conf.domain + '/' + _conf.domain + '.key?get=allow').pipe(fs.createWriteStream(path.join(__dirname, _conf.domain + '.key')))
request('https://ssl.godzyx.com/' + _conf.domain + '/' + _conf.domain + '.pem?get=allow').pipe(fs.createWriteStream(path.join(__dirname, _conf.domain + '.pem')))
/* 由于正则表达式,不能进行跟 gulpfile 中 去注释 在一起 */
module.exports = {
regExp_static: /('|"|`)[\.|\/]*?static\/(.*?\.(png|jpe?g|gif|svg|ico)(\?.*)?)\1/g
}
const _conf = require('./config')
module.exports = function (source) {
if (_conf.isDev !== 'development') {
return source
.replace(_conf.RegStrs.regExp_static, '$1' + _conf.CDN_BASE + _conf.CDN_DIR + 'static/$2$1')
} else {
return source
}
}
const fs = require('fs')
const path = require('path')
const OSS = require('ali-oss')
const conf = require('./config')
const client = new OSS({
region: 'oss-cn-beijing',
accessKeyId: 'LTAIOTuuLTaWoGJj',
accessKeySecret: 'dE5tTGm2lh35eItct2krW2DeH2lf2I',
bucket: 'zws-imgs-pub'
})
const headers = {
'x-oss-traffic-limit': 8 * 1024 * 100 * 100
}
const DIR_PATH = path.join(__dirname, '../' + conf.DesDir)
const PREFIX_PATH = conf.CDN_DIR
const isUploadStatic = conf.isUploadStatic
let fileCount = 1
async function uploadFile (prefixPath, dirFileName) {
try {
const upFilePath = prefixPath.replace(new RegExp(DIR_PATH, 'gi'), '') + path.basename(dirFileName)
const result = await client.put(prefixPath + path.basename(dirFileName), dirFileName, {
headers,
timeout: 600000
})
if (result.res.status === 200) {
console.log('第' + fileCount++ + '个文件,已上传:' + conf.CDN_BASE + upFilePath)
return { status: 200 }
}
} catch (err) {
console.log('第' + fileCount++ + '个文件,上传失败:' + conf.CDN_BASE + upFilePath)
return { status: 500, err: err }
}
}
function uploadfiles (dirPath, callback) {
const files = fs.readdirSync(dirPath)
files.forEach(function (filename, i) {
const filedir = path.join(dirPath, filename)
const info = fs.statSync(filedir)
if (info.isDirectory()) {
if (!(isUploadStatic ? true : filename !== 'static')) { return }
const morePath = filedir.replace(new RegExp(DIR_PATH, 'gi'), '') + '/'
uploadfiles(filedir, function (filedir) {
uploadFile(path.join(PREFIX_PATH, morePath), filedir)
})
} else {
if (typeof callback === 'function') {
callback(filedir)
} else {
uploadFile(PREFIX_PATH, filedir)
}
}
})
return true
}
uploadfiles(DIR_PATH, null)
const path = require('path')
const webpack = require('webpack')
const WebpackMerge = require('webpack-merge')
const _conf = require('./config')
const $GLOBAL = {
isDev: _conf.isDev,
ResDir: _conf.ResDir,
'isEnableToIphoneDebugger': _conf.isEnableToIphoneDebugger,
templatePath: path.resolve(__dirname, '../' + _conf.HtmlPath),
icoPath: _conf.IcoPath,
EntryPath: path.resolve(__dirname, '../' + _conf.JsPath),
OutputPath: path.resolve(__dirname, '../' + _conf.DesDir),
jsName: 'resources/[name].[chunkhash:8].js',
cssName: 'resources/[name].[contenthash:12].css',
resName: 'resources/[name].[hash:8].[ext]',
EntryStaticPath: path.resolve(__dirname, '../' + 'static'),
OutputStaticPath: path.resolve(__dirname, '../' + _conf.DesDir + '/static'),
RegStrs: _conf.RegStrs,
webConf: {
'isDev': _conf.isDev,
'serverPort': process.env.SERVER_PORT || 8000,
'isEnableToIphoneDebugger': _conf.isEnableToIphoneDebugger,
'domain': _conf.domain,
'url': _conf.url,
'isHttps': _conf.isHttps,
'apiBaseURL': _conf.apiBaseURL || '/api',
'CDN_PATH': _conf.CDN_BASE + _conf.CDN_DIR,
'others': _conf.others || {}
},
externals: _conf.webpack.externals || {},
ProvidePlugin: _conf.webpack.ProvidePlugin || {},
BaseConfig: {}
}
$GLOBAL.BaseConfig = {
target: 'web',
entry: $GLOBAL.EntryPath,
output: {
filename: $GLOBAL.jsName,
path: $GLOBAL.OutputPath,
publicPath: $GLOBAL.isDev === 'development' ? '/' : $GLOBAL.webConf.CDN_PATH
},
resolve: {
alias: {
'@': path.resolve(__dirname, '../' + $GLOBAL.ResDir),
'@api': path.resolve(__dirname, '../' + $GLOBAL.ResDir + '/api'),
'@action': path.resolve(__dirname, '../' + $GLOBAL.ResDir + '/action'),
'@tool': path.resolve(__dirname, '../' + $GLOBAL.ResDir + '/tool')
},
extensions: ['.js', '.json', '.jsx', '.vue']
},
module: {
rules: [
{
test: /\.(vue|js|jsx)$/,
loader: 'eslint-loader',
exclude: /node_modules/,
enforce: 'pre'
},
{
test: /\.(vue|js|jsx)|((sa|sc|c)ss)$/,
loader: './build/stringReplaceLoader.js',
exclude: /node_modules/,
enforce: 'pre'
},
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /(\.jsx|\.js)$/,
exclude: /(node_modules)|(dist)/,
loader: 'babel-loader',
options: {
presets: [[
'@babel/preset-env',
{
"targets": {
"browsers": [
"last 2 versions",
"ie >= 11"
],
},
corejs: '3.6.5',
useBuiltIns: 'usage'
}
]],
plugins: [
'@babel/plugin-syntax-jsx',
'@babel/plugin-proposal-class-properties',
'@babel/plugin-syntax-dynamic-import',
[
'@babel/plugin-transform-runtime',
{
corejs: 3,
helpers: true,
regenerator: true,
useESModules: false
}
]
]
}
},
{
test: /\.(png|jpe?g|gif|svg|ico)(\?.*)?$/,
use: {
loader: 'url-loader',
options: {
esModule: false,
limit: 4096,
name: $GLOBAL.resName
}
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: $GLOBAL.resName
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: $GLOBAL.resName
}
}
]
},
externals: {
},
plugins: [
new webpack.DefinePlugin({
'webConf': JSON.stringify($GLOBAL.webConf)
}),
new webpack.ProvidePlugin($GLOBAL.ProvidePlugin)
]
}
$GLOBAL.BaseConfig = WebpackMerge($GLOBAL.BaseConfig, _conf.webpack)
module.exports = $GLOBAL
const fs = require('fs')
const path = require('path')
const webpack = require('webpack')
const WebpackMerge = require('webpack-merge')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const AutoPrefixer = require('autoprefixer')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const HtmlReplaceWebpackPlugin = require('html-replace-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const VconsoleWebpackPlugin = require('vconsole-webpack-plugin')
const $GLOBAL = require('./webpack.base.conf')
let config = null
if ($GLOBAL.isDev === 'development') {
config = WebpackMerge($GLOBAL.BaseConfig, {
mode: 'development',
devtool: '#cheap-module-eval-source-map',
output: {
filename: '[name].js'
},
devServer: {
port: $GLOBAL.webConf.serverPort,
disableHostCheck: false,
host: $GLOBAL.webConf.domain || 'localhost',
http2: false,
https: $GLOBAL.webConf.isHttps && {
key: fs.readFileSync(path.join(__dirname, $GLOBAL.webConf.domain + '.key')),
cert: fs.readFileSync(path.join(__dirname, $GLOBAL.webConf.domain + '.pem'))
},
overlay: {
errors: true
},
historyApiFallback: {
index: '/index.html'
},
proxy: {
'/api': {
target: $GLOBAL.webConf.url,
selfHandleResponse: false,
secure: false,
changeOrigin: true,
followRedirects: true,
logLevel: 'info',
headers: {
'Referer': $GLOBAL.webConf.url
},
pathRewrite: {
'^/api': '/'
}
},
'/loginApi': {
target: 'https://learn-api2.ezijing.com/api/',
// target: 'https://learn-api.ezijing.com/api/',
selfHandleResponse: false,
secure: false,
changeOrigin: true,
followRedirects: true,
logLevel: 'info',
headers: {
'Referer': $GLOBAL.webConf.url
},
pathRewrite: {
'^/loginApi': '/'
}
}
},
open: true,
hot: true
},
module: {
rules: [{
test: /\.(sa|sc|c)ss$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [
AutoPrefixer({
'overrideBrowserslist': [
'cover 99.5%',
'ie 6-8',
'since 2015',
'last 10 iOS versions'
]
})
]
}
},
{
loader: 'sass-loader',
options: {
implementation: require('dart-sass')
}
}
]
}]
},
plugins: [
new VueLoaderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
template: $GLOBAL.templatePath,
inject: true,
favicon: $GLOBAL.icoPath
}),
new VconsoleWebpackPlugin({
filter: [],
enable: $GLOBAL.isEnableToIphoneDebugger
})
]
})
} else {
config = WebpackMerge($GLOBAL.BaseConfig, {
mode: 'production',
entry: {
app: $GLOBAL.EntryPath,
vendor: ['vue', 'vue-router', 'vue-i18n']
},
module: {
rules: [{
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
}
},
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [
AutoPrefixer({
'overrideBrowserslist': [
'cover 99.5%',
'ie 6-8',
'since 2015',
'last 10 iOS versions'
]
})
]
}
},
{
loader: 'sass-loader',
options: {
implementation: require('dart-sass')
}
}
]
}]
},
plugins: [
new CleanWebpackPlugin(['**/*'], { root: $GLOBAL.OutputPath }),
new MiniCssExtractPlugin({
filename: '[name].[contenthash:12].css',
chunkFilename: $GLOBAL.cssName
}),
new VueLoaderPlugin(),
new HtmlWebpackPlugin({
template: $GLOBAL.templatePath,
inject: true,
favicon: $GLOBAL.icoPath,
minify: {
removeComments: true,
collapseWhitespace: true
}
}),
new HtmlReplaceWebpackPlugin([
{
pattern: $GLOBAL.RegStrs.regExp_static,
replacement: '$1' + $GLOBAL.webConf.CDN_PATH + 'static/$2$1'
}
]),
new CopyWebpackPlugin([
{
from: $GLOBAL.EntryStaticPath,
to: $GLOBAL.OutputStaticPath,
ignore: ['.*'],
transform: function (content) {
return content
}
}
]),
new VconsoleWebpackPlugin({
filter: [],
enable: $GLOBAL.isEnableToIphoneDebugger
})
],
optimization: {
runtimeChunk: {
name: 'manifest'
},
splitChunks: {
chunks: 'async',
minSize: 30000,
maxSize: 400000,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
name: false,
cacheGroups: {
vendor: {
name: 'vendor',
chunks: 'initial',
priority: -10,
reuseExistingChunk: false,
test: /node_modules\/(.*)\.js/
},
}
}
}
})
}
module.exports = config
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "@god/vue-client",
"version": "3.0.14",
"description": "适应于公司全系统的纯客户端开发模型",
"main": "index.js",
"scripts": {
"lint": "eslint --ext .js --ext .jsx --ext .vue src/",
"lint:fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/",
"dev": "cross-env NODE_ENV=development node build/getSSL.js && cross-env NODE_ENV=development SERVER_PORT=3003 webpack-dev-server --inline --progress --config build/webpack.client.conf.js",
"build:test": "npm run check:node && cross-env NODE_ENV=test webpack --progress --config build/webpack.client.conf.js && cross-env NODE_ENV=test node ./build/uploadAliyunCDN.js",
"build:pro": "npm run check:node && cross-env NODE_ENV=production webpack --progress --config build/webpack.client.conf.js && cross-env NODE_ENV=production node ./build/uploadAliyunCDN.js",
"check:node": "node build/checkNodeVersion.js"
},
"repository": {
"type": "git",
"url": ""
},
"keywords": [
"vue-client"
],
"author": "zhangyanxin",
"license": "ISC",
"eslintIgnore": [
"client-dist/",
"node_modules/",
"assets/font-icons/"
],
"devDependencies": {
"@babel/core": "^7.11.6",
"@babel/plugin-proposal-class-properties": "^7.10.4",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-syntax-jsx": "^7.10.4",
"@babel/plugin-transform-runtime": "^7.11.5",
"@babel/preset-env": "^7.11.5",
"@babel/runtime-corejs3": "^7.11.2",
"acorn": "^7.1.1",
"ali-oss": "^6.11.2",
"autoprefixer": "^9.8.6",
"babel-eslint": "^10.1.0",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-loader": "^8.1.0",
"clean-webpack-plugin": "^1.0.1",
"copy-webpack-plugin": "^5.1.2",
"css-loader": "^4.3.0",
"dart-sass": "^1.25.0",
"eslint": "^6.8.0",
"eslint-config-standard": "^14.1.1",
"eslint-loader": "^3.0.4",
"eslint-plugin-html": "^6.1.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"eslint-plugin-vue": "^6.2.2",
"file-loader": "^6.1.1",
"html-replace-webpack-plugin": "^2.5.6",
"html-webpack-plugin": "^4.5.0",
"mini-css-extract-plugin": "^0.9.0",
"postcss-loader": "^3.0.0",
"request": "^2.88.2",
"sass-loader": "^10.0.3",
"semver": "^1.1.4",
"style-loader": "^2.0.0",
"url-loader": "^4.1.1",
"vconsole-webpack-plugin": "^1.5.2",
"webpack": "^4.44.2",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0",
"webpack-merge": "^4.2.2"
},
"dependencies": {
"axios": "^0.21.1",
"core-js": "^3.8.3",
"cross-env": "^7.0.3",
"element-ui": "^2.15.0",
"js-cookie": "^2.2.1",
"lodash": "^4.17.20",
"vue": "^2.6.12",
"vue-i18n": "^8.22.4",
"vue-loader": "^15.9.6",
"vue-meta-info": "^0.1.7",
"vue-router": "^3.4.9",
"vue-template-compiler": "^2.6.12",
"vuex": "^3.6.0"
},
"engines": {
"node": ">=8.9"
}
}
import httpRequest from '@/utils/axios'
// 登出
export function logout() {
return httpRequest.get('/api/passport/logout')
}
// 获取用户信息
export function getUser() {
return httpRequest.get('/api/passport/account/get-user-info')
}
import httpRequest from '@/utils/axios'
/**
* 操作日志
*/
export function operateLog(params) {
const logMsg = `操作人:${params.user.nickname},操作:${params.type}`
const data = {
detail: logMsg
}
httpRequest.post('/api/live/admin/v2/system/log/write', data).then(res => {
}).catch(() => {})
}
/**
* 模糊搜索
*/
export function searchUserList(params) {
return httpRequest.get('/api/live/common/v1/sso-user/search', { params })
}
/**
* 创建腾讯用户
*/
export function createAccount(data) {
return httpRequest.post('/api/live/admin/v2/tencent/user', data)
}
/**
* 获取腾讯用户列表(分页)
*/
export function getAccountList(params) {
return httpRequest.get('/api/live/admin/v2/tencent/users', { params })
}
/**
* 获取腾讯用户列表(不分页)
*/
export function getAllAccountList() {
return httpRequest.get('/api/live/admin/v2/tencent/user/list')
}
/**
* 更新腾讯用户
*/
export function updateAccount(data) {
return httpRequest.put(`/api/live/admin/v2/tencent/user/${data.userid}/update`, data)
}
/**
* 删除腾讯用户
*/
export function deleteAccount(params) {
return httpRequest.delete(`/api/live/admin/v2/tencent/user/${params.userid}/delete`, params)
}
/**
* 创建会议
*/
export function createMeeting(data) {
return httpRequest.post('/api/live/admin/v2/tencent/meeting', data)
}
/**
* 创建会议
*/
export function updateMeeting(data) {
return httpRequest.put(`/api/live/admin/v2/tencent/meeting/${data.meeting_id}/update`, data)
}
/**
* 获取腾讯会议列表
*/
export function getMeetingList(params) {
return httpRequest.get('/api/live/admin/v2/tencent/meetings', { params })
}
/**
* 获取腾讯会议列表(不分页)
*/
export function getNonpagedMeetingList(params) {
return httpRequest.get('/api/live/admin/v2/tencent/meeting/list-by-day', { params })
}
/**
* 获取腾讯会议详情
*/
export function getMeetingDetails(params) {
return httpRequest.get(`/api/live/admin/v2/tencent/meeting/${params.meeting_id}/detail`, { params })
}
/**
* 通过会议code获取腾讯会议详情
*/
export function getMeetingDetailsByCode(params) {
return httpRequest.get(`/api/live/admin/v2/tencent/meeting/${params.meeting_code}/detail-code`, { params })
}
/**
* 取消(删除)会议
*/
export function cancelMeeting(params) {
return httpRequest.post(`/api/live/admin/v2/tencent/meeting/${params.meeting_id}/cancel`, params)
}
/**
* 终止会议
*/
export function stopMeeting(params) {
return httpRequest.post(`/api/live/admin/v2/tencent/meeting/${params.meeting_id}/dimiss`, params)
}
/**
* 获取回放地址
*/
export function getMeetingRecordAddr(params) {
return httpRequest.post(`/api/live/admin/v2/tencent/meeting/${params.meeting_id}/records/address`, params)
}
/**
* 导出参会人员
*/
export function exportParticipants(params) {
return httpRequest({
url: `/api/live/admin/v2/tencent/meeting/${params.meeting_id}/participants/export`,
method: 'get',
params,
responseType: 'blob'
})
}
import httpRequest from '@/utils/axios'
/**
* 操作日志
*/
export function operateLog(params) {
const logMsg = `操作人:${params.user.nickname},操作:${params.type}`
const data = {
detail: logMsg
}
httpRequest.post('/api/live/admin/v2/system/log/write', data).then(res => {
}).catch(() => {})
}
/**
* 模糊搜索
*/
export function searchUserList(params) {
return httpRequest.get('/api/live/common/v1/sso-user/search', { params })
}
/**
* 获取当前用户的角色
*/
export function getUserRoles() {
return httpRequest.get('/api/live/admin/v2/user/roles')
}
/**
* 创建角色
*/
export function createRole(data) {
return httpRequest.post('/api/live/admin/v2/role', data)
}
/**
* 更新角色
*/
export function updateRole(params) {
return httpRequest.get(`/api/live/admin/v2/role/${params.role_id}/update`, { params })
}
/**
* 获取角色详情
*/
export function getRoleDetails(params) {
return httpRequest.get(`/api/live/admin/v2/role/${params.role_id}/detail`, { params })
}
/**
* 删除
*/
export function deleteRole(params) {
return httpRequest.get(`/api/live/admin/v2/role/${params.role_id}/delete`, { params })
}
/**
* 获取角色列表
*/
export function getRoles(params) {
return httpRequest.get('/api/live/admin/v2/roles', { params })
}
/**
* 分配角色给用户
*/
export function roleToUser(data) {
return httpRequest.post('/api/live/admin/v2/assign/roles-to-user', data)
}
/**
* 获取角色下的用户列表
*/
export function getUserListUnderRole(params) {
return httpRequest.get(`/api/live/admin/v2/role/${params.role_id}/users`, { params })
}
/**
* 从角色中移除用户
*/
export function romoveUserUnderRole(data) {
return httpRequest.post('/api/live/admin/v2/assign/remove-user-form-role', data)
}
/**
* 获取权限列表
*/
export function getPermissions(params) {
return httpRequest.get('/api/live/admin/v2/permissions', { params })
}
/**
* 分配权限给角色
*/
export function permissionToRole(data) {
return httpRequest.post('/api/live/admin/v2/assign/permission-to-role', data)
}
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
name: 'App',
date() {
return {}
}
}
</script>
\ No newline at end of file
<template>
<el-breadcrumb class="app-breadcrumb" separator="/">
<transition-group name="breadcrumb">
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
<span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
</el-breadcrumb-item>
</transition-group>
</el-breadcrumb>
</template>
<script>
// import pathToRegexp from 'path-to-regexp'
export default {
data() {
return {
levelList: null
}
},
watch: {
$route() {
this.getBreadcrumb()
}
},
created() {
this.getBreadcrumb()
},
methods: {
getBreadcrumb() {
// only show routes with meta.title
const matched = this.$route.matched.filter(item => item.meta && item.meta.title)
this.levelList = matched
},
handleLink(item) {
const { redirect, path } = item
if (redirect) {
this.$router.push(redirect)
return
}
this.$router.push(path)
}
}
}
</script>
<style scoped>
.app-breadcrumb.el-breadcrumb {
display: inline-block;
font-size: 14px;
line-height: 50px;
margin-left: 8px;
}
.no-redirect {
color: #97a8be;
cursor: text;
}
</style>
<template>
<div style="padding: 0 15px;" @click="toggleClick">
<svg
:class="{'is-active':isActive}"
class="hamburger"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
width="64"
height="64"
>
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
</svg>
</div>
</template>
<script>
export default {
name: 'Hamburger',
props: {
isActive: {
type: Boolean,
default: false
}
},
methods: {
toggleClick () {
this.$emit('toggleClick')
}
}
}
</script>
<style scoped>
.hamburger {
display: inline-block;
vertical-align: middle;
width: 20px;
height: 20px;
cursor: pointer;
}
.hamburger.is-active {
transform: rotate(180deg);
}
</style>
<template>
<div>
<el-menu-item v-if="hasChild(navItem)" :index="navItem.path">
<i :class="navItem.icon"></i>
<span slot="title">{{navItem.title}}</span>
</el-menu-item>
<el-submenu v-else ref="subMenu" :index="navItem.path">
<template slot="title">
<i :class="navItem.icon"></i>
<span>{{navItem.title}}</span>
</template>
<menu-item
v-for="child in navItem.children"
:key="child.path"
:navItem="child"
class="nest-menu"
/>
</el-submenu>
</div>
</template>
<script>
export default {
name: 'MenuItem',
props: {
navItem: {
type: Object,
required: true
}
},
data() {
return {}
},
methods: {
hasChild (item) {
return !item.children || (item.children && item.children.length === 0)
}
}
}
</script>
<style scoped>
::v-deep.el-menu-item i{
display:inline-block;
width:24px;
}
</style>
\ No newline at end of file
<template>
<div>
<div :class="{ logo: true, 'logo-collapse': isCollapse }">
<img
v-if="!isCollapse"
src="http://zws-imgs-pub.oss-cn-beijing.aliyuncs.com/static/ezijing/logo/ezijing-logo.png"
/>
<img
v-if="isCollapse"
src="http://zws-imgs-pub.oss-cn-beijing.aliyuncs.com/static/ezijing/logo/favicon.svg"
/>
</div>
<el-scrollbar wrap-class="scrollbar-wrapper sidebar-container-wrap">
<el-menu
:default-active="defaultActive"
class="sidebar-menu"
background-color="#EFF0F0"
text-color="#484848"
active-text-color="#409EFF"
:collapse="isCollapse"
@select="handlleSelect"
>
<menu-item v-for="item in menu" :key="item.path" :navItem="item" />
</el-menu>
</el-scrollbar>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import MenuItem from './MenuItem'
export default {
data() {
return {
defaultActive: '/content-manage/ads',
menu: [
{
title: '内容管理',
icon: 'el-icon-document',
path: '/content-manage',
children: [
{
title: '广告列表',
icon: '',
path: '/content-manage/ads'
},
{
title: '文章列表',
icon: '',
path: '/content-manage/article'
},
{
title: '图文列表',
icon: '',
path: '/content-manage/image-text'
}
]
},
{
title: '设置',
icon: 'el-icon-setting',
path: '/settings',
children: [
{
title: '员工管理',
icon: '',
path: '/settings/staff'
},
{
title: '项目管理',
icon: '',
path: '/settings/project'
},
{
title: '类型管理',
icon: '',
path: '/settings/type'
},
{
title: '高级设置',
icon: '',
path: '/settings/role'
}
]
}
]
}
},
computed: {
...mapGetters(['sidebar']),
isCollapse() {
return !this.sidebar.opened
}
},
components: { MenuItem },
watch: {
$route: {
handler: function(nv) {
if (nv && nv.path) this.defaultActive = nv.path
else this.defaultActive = ''
},
immediate: true
}
},
methods: {
handlleSelect(path) {
this.$router.push(path)
}
}
}
</script>
<style scoped>
.logo {
height: 48px;
width: 166px;
background: #fff;
padding-top: 4px;
transition: width 0.295s ease-in-out;
padding-left:6px;
}
.logo-collapse {
width: 48px;
}
.logo img {
width: 140px;
height: 46px;
}
.logo-collapse img {
width: 46px;
height: 46px;
}
</style>
<style>
.sidebar-container-wrap {
overflow-x: hidden !important;
}
.sidebar-container .el-scrollbar {
height: 100%;
}
.sidebar-container .el-menu {
border: none;
/* width:166px; */
}
.sidebar-container .el-scrollbar__view {
height: 100%;
}
.sidebar-container .el-scrollbar__view ul {
height: 100%;
}
</style>
<template>
<div class="app-header">
<hamburger
id="hamburger-container"
:is-active="sidebar.opened"
class="hamburger-container"
@toggleClick="toggleSideBar"
/>
<breadcrumb />
<div class="right-menu">
<el-dropdown class="avatar-container" trigger="click">
<div class="avatar-wrapper">
<img :src="avatar" class="user-avatar" />
<i class="el-icon-caret-bottom" />
</div>
<el-dropdown-menu slot="dropdown" class="user-dropdown">
<el-dropdown-item>
<span>{{user.nickname || ''}}, 你好</span>
</el-dropdown-item>
<el-dropdown-item divided @click.native="logout">
<span style="display: block">退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import Hamburger from '@/components/Hamburger'
import Breadcrumb from '@/components/Breadcrumb'
import defaultAvatar from '@/assets/images/avatar.png'
export default {
data() {
return {
sidebarFold: false
}
},
computed: {
...mapGetters(['sidebar', 'user']),
avatar() {
return this.user.avatar || defaultAvatar
}
},
components: { Hamburger, Breadcrumb },
methods: {
toggleSideBar() {
this.$store.dispatch('app/toggleSideBar')
},
toMeeting() {
this.$router.push('/meeting-create')
},
async logout() {
await this.$store.dispatch('logout')
this.$router.push(`/${this.$route.fullPath}`)
}
}
}
</script>
<style lang="scss" scoped>
.app-header {
height: 52px;
overflow: hidden;
position: relative;
background: #fff;
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
.hamburger-container {
line-height: 52px;
height: 100%;
float: left;
cursor: pointer;
transition: background 0.3s;
-webkit-tap-highlight-color: transparent;
&:hover {
background: rgba(0, 0, 0, 0.025);
}
}
.breadcrumb-container {
float: left;
}
.right-menu {
float: right;
height: 100%;
line-height: 52px;
&:focus {
outline: none;
}
.right-menu-item {
display: inline-block;
padding: 0 8px;
height: 100%;
font-size: 18px;
color: #5a5e66;
vertical-align: text-bottom;
&.hover-effect {
cursor: pointer;
transition: background 0.3s;
&:hover {
background: rgba(0, 0, 0, 0.025);
}
}
}
.avatar-container {
margin-right: 30px;
.avatar-wrapper {
margin-top: 0;
position: relative;
.user-avatar {
cursor: pointer;
width: 40px;
height: 40px;
border-radius: 10px;
}
.el-icon-caret-bottom {
cursor: pointer;
position: absolute;
right: -20px;
top: 22px;
font-size: 12px;
}
}
}
}
}
</style>
\ No newline at end of file
<template>
<div :class="{ 'app-wrapper': true, 'sidebar-collapse': isCollapse }">
<Sidebar class="sidebar-container" />
<div class="main-container">
<div class="fixed-haeder">
<app-header />
</div>
<app-main />
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import Sidebar from './Sidebar'
import AppHeader from './header'
import AppMain from './main'
export default {
data() {
return {}
},
computed: {
...mapGetters(['sidebar']),
isCollapse() {
return !this.sidebar.opened
}
},
components: { Sidebar, AppHeader, AppMain }
}
</script>
<style scoped>
.app-wrapper {
position: relative;
height: 100%;
width: 100%;
}
.sidebar-container {
/* transition: width 0.28s; */
width: 166px;
height: 100%;
position: fixed;
font-size: 0px;
top: 0;
bottom: 0;
left: 0;
z-index: 1001;
overflow: hidden;
}
.sidebar-collapse .sidebar-container {
width: 54px;
}
.main-container {
min-height: 100%;
-webkit-transition: margin-left 0.28s;
transition: margin-left 0.28s;
margin-left: 166px;
position: relative;
}
.sidebar-collapse .main-container {
margin-left: 54px;
}
</style>
<template>
<section class="app-main">
<transition name="fade-transform" mode="out-in">
<router-view :key="key" />
</transition>
</section>
</template>
<script>
export default {
name: 'AppMain',
computed: {
key () {
return this.$route.path
}
}
}
</script>
<style scoped>
.app-main {
height: calc(100vh - 52px);
width: 100%;
position: relative;
overflow: hidden;
}
.fixed-header+.app-main {
padding-top: 50px;
}
</style>
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta content="origin" name="referrer" />
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<title>紫荆内容管理系统</title>
<meta
name="viewport"
id="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, shrink-to-fit=no, viewport-fit=cover"
/>
</head>
<body>
<div id="app"></div>
</body>
</html>
import Vue from 'vue'
import router from './router'
import store from './store'
import App from './app.vue'
import './style.scss'
import ElementUI from 'element-ui'
import BeforeEnter from './utils/beforeEnter'
const before = new BeforeEnter()
Vue.use(ElementUI)
/* 导航守卫 */
router.beforeEach((to, from, next) => {
before.update(to, from, next)
next()
})
new Vue({
store,
router,
render: h => h(App)
}).$mount('#app')
<template>
<div class="ads">
<div class="btn-bar">
<el-select v-model="filter.project" placeholder="项目" size="mini" clearable>
<el-option v-for="item in projectList" :label="item.project_name" :value="item.project_id" :key="item.project_id"></el-option>
</el-select>
<el-input v-model="filter.id" placeholder="ID" size="mini" style="width:220px;" clearable/>
<el-select v-model="filter.type" placeholder="类型" size="mini" clearable>
<el-option v-for="item in typeList" :label="item.name" :value="item.id" :key="item.id"></el-option>
</el-select>
<el-button type="primary" icon="el-icon-search" size="mini" @click="fetchList">搜索</el-button>
<el-button icon="el-icon-refresh-left" size="mini" @click="reset">重置</el-button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
filter: {
project: '',
id: '',
type: ''
},
projectList: [
{ project_id: '111', project_name: '官网' },
{ project_id: '222', project_name: 'kellet' }
],
typeList: [
{ id: '111', name: 'banner广告' },
{ id: '222', name: '侧边栏广告' },
{ id: '333', name: '正文区广告' }
]
}
},
methods: {
reset() {
Object.keys(this.filter).map(key => { this.filter[key] = '' })
this.fetchList()
},
fetchList() {
}
}
}
</script>
<style scoped>
.ads{
width:calc(100% - 20px);
height:calc(100% - 20px);
margin:10px;
background:#fff;
border-radius:5px;
}
.btn-bar{
padding:10px;
}
</style>
\ No newline at end of file
<template>
<div>文章</div>
</template>
<script>
export default {
data() {
return {}
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<div>图文列表</div>
</template>
<script>
export default {
data() {
return {}
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<div>项目管理</div>
</template>
<script>
export default {
data() {
return {}
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<div>高级设置</div>
</template>
<script>
export default {
data() {
return {}
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<div>员工管理</div>
</template>
<script>
export default {
data() {
return {}
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<div>类型管理</div>
</template>
<script>
export default {
data() {
return {}
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
import Vue from 'vue'
import Router from 'vue-router'
import routes from './routes'
Vue.use(Router)
const originalPush = Router.prototype.push
Router.prototype.push = function push(location, onResolve, onReject) {
if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
return originalPush.call(this, location).catch(err => err)
}
export default new Router({
routes,
mode: 'history', // 还有一个 hash 默认
fallback: true // 浏览器不支持 history时,自动改成 hash方式
})
import Layout from '@/components/Layout'
export default [
{
path: '/',
name: 'Layout',
component: Layout,
redirect: '/content-manage'
},
{
path: '/content-manage',
component: Layout,
redirect: '/content-manage/ads',
name: 'System',
meta: { title: '内容管理', icon: 'el-icon-setting' },
children: [
{
path: 'ads',
name: 'Ads',
component: () => import('@/pages/content-manage/ads/index'),
meta: { title: '广告列表', icon: '' }
},
{
path: 'article',
name: 'Article',
component: () => import('@/pages/content-manage/article/index'),
meta: { title: '文章列表', icon: '' }
},
{
path: 'image-text',
name: 'ImageText',
component: () => import('@/pages/content-manage/image-text/index'),
meta: { title: '图文列表', icon: '' }
}
]
},
{
path: '/settings',
component: Layout,
redirect: '/settings/staff',
name: 'System',
meta: { title: '设置', icon: 'el-icon-setting' },
children: [
{
path: 'staff',
name: 'Staff',
component: () => import('@/pages/settings/staff/index'),
meta: { title: '员工管理', icon: '' }
},
{
path: 'project',
name: 'Project',
component: () => import('@/pages/settings/project/index'),
meta: { title: '项目管理', icon: '' }
},
{
path: 'type',
name: 'Type',
component: () => import('@/pages/settings/type/index'),
meta: { title: '类型管理', icon: '' }
},
{
path: 'role',
name: 'Role',
component: () => import('@/pages/settings/role/index'),
meta: { title: '高级设置', icon: '' }
}
]
}
]
const getters = {
user: state => state.user.user,
roles: state => state.user.roles,
isSuperAdmin: state => state.user.isSuperAdmin,
sidebar: state => state.app.sidebar
}
export default getters
import Vue from 'vue'
import Vuex from 'vuex'
import app from './modules/app'
import user from './modules/user'
import getters from './getters'
Vue.use(Vuex)
const store = new Vuex.Store({
namespaced: true,
modules: {
app,
user
},
getters
})
export default store
import Cookies from 'js-cookie'
const state = {
sidebar: {
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
withoutAnimation: false
}
}
const mutations = {
TOGGLE_SIDEBAR: state => {
state.sidebar.opened = !state.sidebar.opened
state.sidebar.withoutAnimation = false
if (state.sidebar.opened) {
Cookies.set('sidebarStatus', 1)
} else {
Cookies.set('sidebarStatus', 0)
}
}
}
const actions = {
toggleSideBar({ commit }) {
commit('TOGGLE_SIDEBAR')
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
import { getUser, logout } from '@/api/account'
import { getUserRoles } from '@/api/system'
const user = {
state: {
user: {},
roles: [],
isLogin: false,
isSuperAdmin: false
},
mutations: {
setUser(state, user) {
state.user = user
},
setIsLogin(state, isLogin) {
state.isLogin = isLogin
},
setRoles(state, roles) {
state.roles = roles
},
setSuperAdmin(state, isSuperAdmin) {
state.isSuperAdmin = isSuperAdmin
}
},
actions: {
getUser({ commit }) {
getUser().then(response => {
commit('setUser', response)
})
},
setUserRoles({ commit }) {
getUserRoles().then(res => {
const roles = res.data.roles
let isSuperAdmin = false
if (roles && Array.isArray(roles)) {
roles.forEach(it => {
if (it.name === 'administrator') isSuperAdmin = true
})
commit('setRoles', roles)
commit('setSuperAdmin', isSuperAdmin)
}
})
},
// 退出登录
logout({ commit }) {
return logout().then(response => {
commit('setUser', {})
commit('setIsLogin', false)
return response
})
},
// 检测登录状态
async checkLogin({ commit }) {
// await getUserGrade()
// .then(response => {
// commit('setUserGrade', response.data.level)
// })
// .catch(() => {
// })
const isLogin = await getUser()
.then(response => {
commit('setUser', response.data)
return true
})
.catch(() => {
commit('setUser', {})
return false
})
commit('setIsLogin', isLogin)
return isLogin
}
}
}
export default user
// $--color-primary: #c01540;
/* 改变 icon 字体路径变量,必需 */
$--font-path: '~element-ui/lib/theme-chalk/fonts';
@import '~element-ui/packages/theme-chalk/src/index';
body,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
p,
blockquote,
dl,
dt,
dd,
ul,
ol,
li,
pre,
form,
fieldset,
legend,
button,
input,
textarea,
th,
td {
margin: 0;
padding: 0;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: 100%;
}
ul,
ol,
li {
list-style: none;
}
em,
i {
font-style: normal;
}
img {
border: none;
}
input,
img {
vertical-align: middle;
}
a {
color: inherit;
text-decoration: none;
}
input,
button,
select,
textarea {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-appearance: none;
border: 0;
border-radius: 0;
}
textarea:focus {
outline: 0;
}
html {
font-size: 100px;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
:root {
--main-color: #c01540;
}
body {
font-size: 14px;
line-height: 1.4;
color: #606266;
font-family: 'PingFang SC', 'PingFangSC-Regular', 'Source Han Sans CN', -apple-system, 'Microsoft YaHei', 'Helvetica', 'Arial', Verdana,
'Hiragino Sans GB', 'Wenquanyi Micro Hei', sans-serif;
background-color: #f9f9f9;
}
/* fade-transform */
.fade-transform-leave-active,
.fade-transform-enter-active {
transition: all .5s;
}
.fade-transform-enter {
opacity: 0;
transform: translateX(-30px);
}
.fade-transform-leave-to {
opacity: 0;
transform: translateX(30px);
}
/* element input,textarea font-family */
.el-input__inner, .el-textarea__inner{
font-family: 'PingFang SC', 'PingFangSC-Regular', 'Source Han Sans CN', -apple-system, 'Microsoft YaHei', 'Helvetica', 'Arial', Verdana,
'Hiragino Sans GB', 'Wenquanyi Micro Hei', sans-serif;
}
import axios from 'axios'
import qs from 'qs'
import { Message } from 'element-ui'
import { getNonce } from '@/utils/utils'
import router from '@/router'
const httpRequest = axios.create({
timeout: 60000,
withCredentials: true,
headers: { 'Content-Type': 'application/json', apikey: 'McS1WsnMwMhsfc7cJ7Y0' }
})
// 请求拦截
httpRequest.interceptors.request.use(
function(config) {
const defaultParams = {
timestamp: parseInt(Date.now() / 1000),
nonce: getNonce(9),
signature: 'UG7wBenexQhiuD2wpCwuxkU0jqcj006d'
}
let params = config.params || config.data
params = Object.assign({}, defaultParams, params)
if (['post', 'put', 'delete'].includes(config.method)) {
config.data = params
} else {
config.params = params
}
if (config.headers['Content-Type'] === 'application/x-www-form-urlencoded') {
config.data = qs.stringify(config.data)
}
return config
},
function(error) {
return Promise.reject(error)
}
)
// 响应拦截
httpRequest.interceptors.response.use(
function(response) {
const { data } = response
if (data.code === 1 && data.msg === '请先登录') {
// Message.error(data.msg || data.message)
window.location.href = `${webConf.others.loginUrl}?rd=${encodeURIComponent(window.location.href)}`
return Promise.reject(data)
}
return data
},
function(error) {
console.log(error)
if (error.response) {
const { status, message, code } = error.response.data
// 未登录
if (status === 403) {
window.location.href = `${webConf.others.loginUrl}?rd=${encodeURIComponent(window.location.href)}`
} else if (status === 400 && code === 401) {
router.push('/role')
} else {
console.log(message)
// Message.error(message || error.response.data)
}
return Promise.reject(error.response)
} else if (typeof error === 'string') {
Message.error(error)
}
return Promise.reject(error)
}
)
export default httpRequest
import store from '@/store'
export default class BeforeEnter {
constructor(opt) {
this.opt = opt || {}
}
async update(to, from, next) {
const isLogin = store.state.isLogin || (await store.dispatch('checkLogin'))
if (to.meta.requiredLogin && !isLogin) {
next(`/login?redirect_uri=${encodeURIComponent(window.location.href)}`)
return
}
store.dispatch('setUserRoles')
next()
}
}
/**
* 获取随机字符串
* @param {number} length
* @returns {String}
*/
export function getNonce(length) {
typeof length !== 'number' && (length = 16)
const chars = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'k', 'm', 'n', 'p', 'r', 's', 't', 'w', 'x', 'y', 'z', 2, 3, 4, 5, 6, 7, 8]
const charsLen = chars.length;
let str = ''
for (let i = 0; i < length; i++) {
const idx = parseInt(charsLen * Math.random())
let _char = chars[idx];
if (typeof _char === 'string' && idx % 2) {
_char = _char.toUpperCase()
}
str += _char
}
return str
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论