提交 eac053f5 authored 作者: 王鹏飞's avatar 王鹏飞

init

上级
module.exports = {
isHttps: false,
domain: 'localhost',
url: 'http://172.16.3.11:8011/',
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: {
baseUrl: 'http://172.16.3.11:8011',
loginUrl: 'https://login2.ezijing.com/xlearn/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: {
baseUrl: 'https://learn-api.ezijing.com',
loginUrl: 'https://login.ezijing.com/xlearn/login/index',
xtrainingUrl: 'https://xtraining.ezijing.com'
}
}
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: {
baseUrl: 'https://learn-api2.ezijing.com',
loginUrl: 'https://login2.ezijing.com/xlearn/login/index',
xtrainingUrl: 'https://x-training2.ezijing.com'
}
}
# 查到当前目录就可以了,不用再往下查找
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"
},
"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-----
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')))
<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>
/* 由于正则表达式,不能进行跟 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': '/'
}
}
},
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.15",
"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": "npm run check:node && cross-env NODE_ENV=development node build/getSSL.js && cross-env NODE_ENV=development SERVER_PORT=3001 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",
"@vue/composition-api": "^1.0.0-rc.5",
"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.6.5",
"cross-env": "^7.0.3",
"echarts": "^5.0.2",
"vue": "^2.6.12",
"vue-echarts": "^6.0.0-rc.3",
"vue-loader": "^15.9.6",
"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 login(data) {
return httpRequest.post('/api/passport/rest/login', data)
}
// 绑定微信
export function bindWechat(data) {
return httpRequest.post('/api/passport/rest/wechat/bind-unionid', data)
}
// 修改密码
export function updatePassword(data) {
return httpRequest.post('/api/usercenter/user/change-pwd-by-cookie', data)
}
// 重置密码
export function resetPassword(data) {
return httpRequest.post('/api/usercenter/user/update-pwd', data)
}
// 发送验证码
export function sendCode(data) {
return httpRequest.post('/api/usercenter/user/send-code', data)
}
// 登出
export function logout() {
return httpRequest.get('/api/zy/user/logout')
}
// 获取用户信息
export function getUser() {
return httpRequest.get('/api/zy/user/getinfo')
}
import httpRequest from '@/utils/axios'
// 年度各项目 销售额
export function getYearIncome(params) {
return httpRequest.get('/v1/big_screen_marketing/year_plan_completion', { params })
}
// 年度各项目 报名数量
export function getYearApply(params) {
return httpRequest.get('/v1/big_screen_marketing/year_project_apply', { params })
}
// 当月的各项目 缴费额/计划完成率/总销售额/总成单量
export function getMonthIncome(params) {
return httpRequest.get('/v1/big_screen_marketing/now_month_project_income', { params })
}
// 各项目每月 销售额/完成率
export function getx(params) {
return httpRequest.get('/v1/big_screen_marketing/every_month_project_income', { params })
}
// 各项目 实时缴费数据
export function getNowIncome(params) {
return httpRequest.get('/v1/big_screen_marketing/real_time_pay', { params })
}
// 各项目 留资数/留资成本/总报名费/报名后转化率
export function getProjectCost(params) {
return httpRequest.get('/v1/big_screen_marketing/project_app_cost', { params })
}
// 所有项目各渠道缴费额
export function getChannelPayMoney(params) {
return httpRequest.get('/v1/big_screen_marketing/channel_pay_money', { params })
}
// 周 实际缴费额/预测缴费额
export function getPayMoneyByWeek(params) {
return httpRequest.get('/v1/big_screen_marketing/project_pay_week', { params })
}
<template>
<div id="app">
<router-view />
</div>
</template>
<style>
* {
margin: 0;
padding: 0;
}
body {
background: linear-gradient(180deg, #1e0c0d, #1a0200);
}
#app {
max-width: 375px;
margin: 0 auto;
}
table {
table-layout: fixed;
border-collapse: separate;
}
</style>
<template>
<div class="card">
<div class="card-hd" v-if="title">{{ title }}</div>
<div class="card-bd">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
props: {
title: String
}
}
</script>
<style lang="scss">
.card {
border: 3px solid;
border-image: linear-gradient(56deg, #162b85, #20b4e2, #000f4a, #172987) 10 10;
background: linear-gradient(0deg, #1d357a 0%, rgba(23, 41, 136, 0) 100%);
border-radius: 20px;
}
</style>
<template>
<!-- 月收入 -->
<v-chart class="chart" :option="option" />
</template>
<script>
import * as api from '@/api/index'
export default {
name: 'MonthlyIncome',
data() {
return {
response: { sell_data: [] }
}
},
computed: {
option() {
// const data = this.response.sell_data.map(item => {
// return { value: item.pay_money, name: item.project_name }
// })
const option = {
grid: {
// 直角坐标系内绘图网格
left: '80', // grid 组件离容器左侧的距离,
// left的值可以是80这样具体像素值,
// 也可以是'80%'这样相对于容器高度的百分比
top: '80',
right: '0',
bottom: '0',
containLabel: true // gid区域是否包含坐标轴的刻度标签。为true的时候,
// left/right/top/bottom/width/height决定的是包括了坐标轴标签在内的
// 所有内容所形成的矩形的位置.常用于【防止标签溢出】的场景
},
xAxis: {
// 直角坐标系grid中的x轴,
// 一般情况下单个grid组件最多只能放上下两个x轴,
// 多于两个x轴需要通过配置offset属性防止同个位置多个x轴的重叠。
type: 'value', // 坐标轴类型,分别有:
// 'value'-数值轴;'category'-类目轴;
// 'time'-时间轴;'log'-对数轴
splitLine: { show: false }, // 坐标轴在 grid 区域中的分隔线
axisLabel: { show: false }, // 坐标轴刻度标签
axisTick: { show: false }, // 坐标轴刻度
axisLine: { show: false } // 坐标轴轴线
},
yAxis: {
type: 'category',
axisTick: { show: false },
axisLine: { show: false },
axisLabel: {
color: 'black',
fontSize: 36
},
data: ['sofia', 'kelley'] // 类目数据,在类目轴(type: 'category')中有效。
// 如果没有设置 type,但是设置了axis.data,则认为type 是 'category'。
},
series: [
// 系列列表。每个系列通过 type 决定自己的图表类型
{
name: '%', // 系列名称
type: 'bar', // 柱状、条形图
barWidth: 19, // 柱条的宽度,默认自适应
data: [20, 120], // 系列中数据内容数组
label: {
// 图形上的文本标签
show: true,
position: 'right', // 标签的位置
offset: [0, -40], // 标签文字的偏移,此处表示向上偏移40
formatter: '{c}{a}', // 标签内容格式器 {a}-系列名,{b}-数据名,{c}-数据值
color: 'black', // 标签字体颜色
fontSize: 36 // 标签字号
},
itemStyle: {
// 图形样式
normal: {
// normal 图形在默认状态下的样式;
// emphasis图形在高亮状态下的样式
barBorderRadius: 10 // 柱条圆角半径,单位px.
// 此处统一设置4个角的圆角大小;
// 也可以分开设置[10,10,10,10]顺时针左上、右上、右下、左下
// color: new Echarts.graphic.LinearGradient(0, 0, 1, 0, [
// {
// offset: 0,
// color: '#22B6ED'
// },
// {
// offset: 1,
// color: '#3FE279'
// }
// ])
}
},
zlevel: 1 // 柱状图所有图形的 zlevel 值,
// zlevel 大的 Canvas 会放在 zlevel 小的 Canvas 的上面
},
{
name: '进度条背景',
type: 'bar',
barGap: '-100%', // 不同系列的柱间距离,为百分比。
// 在同一坐标系上,此属性会被多个 'bar' 系列共享。
// 此属性应设置于此坐标系中最后一个 'bar' 系列上才会生效,
// 并且是对此坐标系中所有 'bar' 系列生效。
barWidth: 19,
data: [100, 100, 100],
color: '#151B87', // 柱条颜色
itemStyle: {
normal: {
barBorderRadius: 10
}
}
}
]
}
return option
}
},
methods: {
getData() {
api.getMonthIncome().then(response => {
this.response = response
})
}
},
beforeMount() {
this.getData()
}
}
</script>
<style scoped>
.chart {
height: 200px;
}
</style>
<template>
<div class="inner">
<dl>
<dt>总销售额</dt>
<dd>¥{{ response.all_pay_money / 10000 }}<span class="unit">万元</span></dd>
</dl>
<dl>
<dt>总成单量</dt>
<dd>{{ response.all_pay_count }}<span class="unit"></span></dd>
</dl>
</div>
</template>
<script>
import * as api from '@/api/index'
export default {
name: 'MonthDashboard',
data() {
return {
response: {}
}
},
methods: {
getData() {
api.getMonthIncome().then(response => {
this.response = response
})
}
},
beforeMount() {
this.getData()
}
}
</script>
<style lang="scss" scoped>
.inner {
display: flex;
align-items: center;
justify-content: space-between;
background: linear-gradient(0deg, #142e53 0%, #142e53 100%);
height: 140px;
dl {
flex: 1;
text-align: center;
font-size: 24px;
dt {
font-size: 18px;
color: #fff;
}
dd {
font-size: 30px;
color: #3ce4e3;
}
.unit {
font-size: 18px;
}
}
}
</style>
<template>
<!-- 月收入 -->
<v-chart class="chart" :option="option" />
</template>
<script>
import * as api from '@/api/index'
export default {
name: 'MonthlyIncome',
data() {
return {
response: { sell_data: [] }
}
},
computed: {
option() {
// const data = this.response.sell_data.map(item => {
// return { value: item.pay_money, name: item.project_name }
// })
const option = {
toolbox: {},
angleAxis: {
max: 2,
startAngle: 30,
splitLine: {
show: false
},
show: false
},
radiusAxis: {
type: 'category',
data: ['sofia', 'kelley'],
z: 10
},
polar: {},
series: [
{
type: 'bar',
data: [920870],
coordinateSystem: 'polar',
name: 'sofia'
},
{
type: 'bar',
data: [499600],
coordinateSystem: 'polar',
name: 'kelley',
roundCap: true
}
]
}
return option
}
},
methods: {
getData() {
api.getMonthIncome().then(response => {
this.response = response
})
}
},
beforeMount() {
this.getData()
}
}
</script>
<style scoped>
.chart {
height: 200px;
}
.card {
border: 3px solid;
border-image: linear-gradient(56deg, #162b85, #20b4e2, #000f4a, #172987) 10 10;
background: linear-gradient(0deg, #1d357a 0%, rgba(23, 41, 136, 0) 100%);
border-radius: 20px;
}
</style>
<template>
<div class="inner">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<th>时间</th>
<th>姓名</th>
<th>类型</th>
<th>项目</th>
<th>金额(元)</th>
</tr>
<tr v-for="(item, index) in response" :key="index">
<td>{{ item.pay_time }}</td>
<td>{{ item.user_name }}</td>
<td>{{ item.pay_type }}</td>
<td>{{ item.project_name }}</td>
<td>{{ item.pay_money }}</td>
</tr>
</table>
</div>
</template>
<script>
import * as api from '@/api/index'
export default {
name: 'MonthlyIncome',
data() {
return {
response: []
}
},
methods: {
getData() {
api.getNowIncome().then(response => {
this.response = response
})
}
},
beforeMount() {
this.getData()
}
}
</script>
<style scoped>
td,
th {
text-align: center;
}
td {
padding: 12px 0;
white-space: nowrap;
border: 1px solid rgba(255, 255, 255, 0.3);
}
th {
background-color: rgba(102, 251, 249, 0.3);
}
</style>
<template>
<div class="inner">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<th>时间</th>
<th>姓名</th>
<th>类型</th>
<th>项目</th>
<th>金额(元)</th>
</tr>
<tr v-for="(item, index) in response" :key="index">
<td>{{ item.pay_time }}</td>
<td>{{ item.user_name }}</td>
<td>{{ item.pay_type }}</td>
<td>{{ item.project_name }}</td>
<td>{{ item.pay_money }}</td>
</tr>
</table>
</div>
</template>
<script>
import * as api from '@/api/index'
export default {
name: 'MonthlyIncome',
data() {
return {
response: []
}
},
methods: {
getData() {
api.getNowIncome().then(response => {
this.response = response
})
}
},
beforeMount() {
this.getData()
}
}
</script>
<style scoped>
td,
th {
text-align: center;
}
td {
padding: 12px 0;
white-space: nowrap;
border: 1px solid rgba(255, 255, 255, 0.3);
}
th {
background-color: rgba(102, 251, 249, 0.3);
}
</style>
<template>
<!-- 月收入 -->
<v-chart class="chart" :option="option" />
</template>
<script>
import * as api from '@/api/index'
export default {
name: 'PaymentStructure',
data() {
return {
response: { sell_data: [] }
}
},
computed: {
option() {
return {
radar: [
{
indicator: [
{ text: '品牌', max: 100 },
{ text: '内容', max: 100 },
{ text: '可用性', max: 100 },
{ text: '功能', max: 100 }
]
}
],
series: [
{
type: 'radar',
tooltip: {
trigger: 'item'
},
areaStyle: {},
data: [
{
value: [60, 73, 85, 40],
name: '某软件'
}
]
}
]
}
}
},
methods: {
getData() {
api.getChannelPayMoney().then(response => {
this.response = response
})
}
},
beforeMount() {
this.getData()
}
}
</script>
<style scoped>
.chart {
height: 200px;
}
</style>
<template>
<div class="inner">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<th>项目</th>
<th>留资总数</th>
<th>单条留资成本</th>
<th>已交报名费</th>
<th>报名后均转率</th>
</tr>
<tr v-for="(item, index) in response" :key="index">
<td>{{ item.project_name }}</td>
<td>{{ item.app_count }}</td>
<td>{{ item.app_cost }}</td>
<td>{{ item.pay_count }}</td>
<td>{{ item.conversion_rate }}</td>
</tr>
</table>
</div>
</template>
<script>
import * as api from '@/api/index'
export default {
name: 'MonthlyIncome',
data() {
return {
response: []
}
},
methods: {
getData() {
api.getProjectCost().then(response => {
this.response = response
})
}
},
beforeMount() {
this.getData()
}
}
</script>
<style scoped>
td,
th {
text-align: center;
}
td {
padding: 12px 0;
white-space: nowrap;
border: 1px solid rgba(255, 255, 255, 0.3);
}
th {
background-color: rgba(102, 251, 249, 0.3);
}
</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 ECharts from 'vue-echarts'
import 'echarts'
// register globally (or you can do it locally)
Vue.component('v-chart', ECharts)
// import BeforeEnter from './utils/beforeEnter'
// const before = new BeforeEnter()
// /* 导航守卫 */
// router.beforeEach((to, from, next) => {
// before.update(to, from, next)
// next()
// })
Vue.prototype.msgCenter = new Vue()
new Vue({
store,
router,
render: h => h(App)
}).$mount('#app')
<template>
<div>
<month-dashboard></month-dashboard>
<card title="各项目月度营收">
<month-income></month-income>
</card>
<card title="各项目月度达成率">
<month-complete-rate></month-complete-rate>
</card>
<card title="营收实时滚动信息">
<now-income></now-income>
</card>
<project-cost></project-cost>
<card title="缴费结构">
<payment-structure></payment-structure>
</card>
</div>
</template>
<script>
import Card from '@/components/card'
// 月概览
import MonthDashboard from '@/components/monthDashboard'
// 月收入
import MonthIncome from '@/components/monthIncome'
// 各项目月度达成率
import MonthCompleteRate from '@/components/monthCompleteRate'
// 营收实时滚动信息
import NowIncome from '@/components/nowIncome'
import ProjectCost from '@/components/projectCost'
// 缴费结构
import PaymentStructure from '@/components/PaymentStructure'
export default {
name: 'Index',
components: { Card, MonthDashboard, MonthIncome, MonthCompleteRate, NowIncome, ProjectCost, PaymentStructure },
data() {
return {}
}
}
</script>
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方式
})
export default [
{ path: '*', redirect: '/' },
{ path: '/', component: () => import('@/pages/home/index.vue') }
]
import Vue from 'vue'
import Vuex from 'vuex'
import { getUser, logout } from '@/api/account'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
user: {},
isLogin: false,
isIos: /iphone|ipad|ipod/i.test(navigator.userAgent),
isAndroid: /android/i.test(navigator.userAgent),
isWeapp: /miniProgram/.test(navigator.userAgent)
},
mutations: {
setUser(state, user) {
state.user = user
},
setIsWeapp(state, isWeapp) {
state.isWeapp = isWeapp
},
setIsLogin(state, isLogin) {
state.isLogin = isLogin
}
},
actions: {
getUser({ commit }) {
getUser().then(response => {
commit('setUser', response)
})
},
// 退出登录
logout({ commit }) {
return logout().then(response => {
commit('setUser', {})
commit('setIsLogin', false)
return response
})
},
// 检测登录状态
async checkLogin({ commit }) {
const isLogin = await getUser()
.then(response => {
commit('setUser', response)
return true
})
.catch(() => {
commit('setUser', {})
return false
})
commit('setIsLogin', isLogin)
return isLogin
}
}
})
export default store
$--color-primary: #c01540;
/* 改变 icon 字体路径变量,必需 */
$--font-path: '~element-ui/lib/theme-chalk/fonts';
@import '~element-ui/packages/theme-chalk/src/index';
/* 引入三方 自定义图标库,方法 vue -> 第三方 自建图标库 中有 */
@import '~@/assets/font-icons/iconfont.css';
[class^='el-icon-self-'],
[class*='el-icon-self-'] {
font-family: 'selfAllIcon' !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
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: #222;
font-family: 'PingFang SC', 'Source Han Sans CN', -apple-system, 'Microsoft YaHei', 'Helvetica', 'Arial', Verdana,
'Hiragino Sans GB', 'Wenquanyi Micro Hei', sans-serif;
background-color: #f9f9f9;
}
.empty {
padding: 120px;
text-align: center;
font-size: 18px;
color: #999;
}
.el-tabs__item {
font-size: 18px;
}
import axios from 'axios'
import router from '@/router'
const httpRequest = axios.create({
baseURL: webConf.others.baseUrl,
timeout: 60000,
withCredentials: true,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
tenant: 'x1'
}
})
// 请求拦截
httpRequest.interceptors.request.use(
function(config) {
return config
},
function(error) {
return Promise.reject(error)
}
)
// 响应拦截
httpRequest.interceptors.response.use(
function(response) {
const { data } = response
if (data.code !== 200) {
console.error(data.msg || data.message)
return Promise.reject(data)
}
return data.data
},
function(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.error(message || error.response.data)
}
return Promise.reject(error.response)
} else {
console.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 { user_id: userId, student_id: studentId } = to.query
if (userId && studentId) {
store.commit('setGuestUser', { user_id: userId, student_id: studentId })
}
// 创建游客用户
// await store.dispatch('createGuestUser')
// 登录白名单
const whiteList = ['/role']
if (whiteList.includes(to.path)) {
next()
return
}
const isLogin = store.state.isLogin || (await store.dispatch('checkLogin'))
if (to.meta.requiredLogin && !isLogin) {
next(`/login?redirect_uri=${encodeURIComponent(window.location.href)}`)
return
}
next()
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论