1、vue.config.js
require('events').EventEmitter.defaultMaxListeners = 0
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin')
const productionGzipExtensions = ['js', 'css']
let { SERVEIP } = require('./src/service/appConfig')
module.exports = {
// 基本路径
publicPath: process.env.NODE_ENV === 'production' ? '/res' : '/',
devServer: {
open: true,
port: 8099,
proxy: {
'/dev': {
target: SERVEIP,
changeOrigin: true,
pathRewrite: {
'^/dev': ''
}
}
},
overlay: {
warnings: true,
errors: true
}
},
runtimeCompiler: true,
productionSourceMap: false,
lintOnSave: process.env.NODE_ENV === 'development',
chainWebpack: config => {
config.entry('index').add('babel-polyfill')
},
configureWebpack: {
plugins: process.env.NODE_ENV === 'production' ? [
new CompressionWebpackPlugin({
algorithm: 'gzip',
test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
threshold: 10240,
minRatio: 0.8,
deleteOriginalAssets: true
}),
new LodashModuleReplacementPlugin()
] : []
}
}
2、package.json
{
"name": "himes",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"start": "node index.js",
"server": "nodemon index.js --ignore client",
"lint": "vue-cli-service lint"
},
"dependencies": {
"@babel/polyfill": "^7.8.7",
"@types/lodash": "^4.14.149",
"@types/qs": "^6.9.1",
"axios": "^0.19.0",
"babel-polyfill": "^6.26.0",
"core-js": "^2.6.5",
"dhtmlx-gantt": "^7.0.13",
"echarts": "^5.1.1",
"hikui": "^1.0.15",
"nprogress": "^0.2.0",
"qs": "^6.9.1",
"vue": "^2.6.10",
"vue-class-component": "^7.0.2",
"vue-grid-layout": "^2.3.7",
"vue-i18n": "^8.15.3",
"vue-property-decorator": "^8.1.0",
"vue-router": "^3.0.3",
"vuedraggable": "^2.23.2",
"vuex": "^3.0.1",
"vuex-class": "^0.3.2",
"vuex-module-decorators": "^0.11.0"
},
"devDependencies": {
"@types/echarts": "^4.9.7",
"@vue/babel-helper-vue-jsx-merge-props": "^1.0.0",
"@vue/babel-preset-jsx": "^1.1.2",
"@vue/cli-plugin-babel": "^3.9.0",
"@vue/cli-plugin-eslint": "^3.9.0",
"@vue/cli-plugin-typescript": "^3.9.0",
"@vue/cli-service": "^3.9.0",
"@vue/eslint-config-standard": "^4.0.0",
"@vue/eslint-config-typescript": "^4.0.0",
"babel-eslint": "^10.0.1",
"babel-plugin-transform-remove-console": "^6.9.4",
"compression-webpack-plugin": "^3.1.0",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.0.0",
"less": "^3.0.4",
"less-loader": "^5.0.0",
"lodash-webpack-plugin": "^0.11.6",
"typescript": "^3.4.3",
"vue-template-compiler": "^2.6.10"
}
}
3、tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"experimentalDecorators": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env"
],
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}
4、babel.config.js
const plugins = []
if (['production', 'prod'].includes(process.env.NODE_ENV)) {
plugins.push('transform-remove-console') //打包去除console
}
module.exports = {
presets: [
[
'@vue/app',
{
'useBuiltIns': 'entry',
polyfills: [
'es6.promise',
'es6.symbol'
],
jsx: {
injectH: false
}
}
],
['@vue/babel-preset-jsx']
],
plugins: plugins
}
5、.eslintrc.js
module.exports = {
root: true,
env: {
node: true
},
'extends': [
'plugin:vue/essential',
'@vue/standard',
'@vue/typescript'
],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-multiple-empty-lines': [1, { 'max': 2 }],
'no-mixed-spaces-and-tabs': ['error', 'smart-tabs'],
'semi': ['error', 'never'],
'indent': ['off'],
'arrow-parens': 0,
'generator-star-spacing': 0,
'spaced-comment': ['off'],
'eqeqeq': 0,
'camelcase': ['off']
},
parserOptions: {
parser: '@typescript-eslint/parser',
'ecmaFeatures': {
'jsx': false
}
}
}
6、router.ts
import Vue from 'vue'
import Router from 'vue-router'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import store from '@/store/index'
// @ts-ignore
import { Message } from 'hikui'
NProgress.configure({ showSpinner: false })
Vue.use(Router)
const VueRouterPush = Router.prototype.push
Router.prototype.push = function push (to: any) {
// @ts-ignore
return VueRouterPush.call(this, to).catch((err: any) => err)
}
// 设置路由
let routers: any = []
const files = require.context('../views/', true, /router.js/)
files.keys().forEach(key => {
if (files(key).router) {
routers = routers.concat(files(key).router)
}
})
let newWindowRouter = routers.filter((items: any) => {
return items.meta.target && items.meta.target == '_blank'
})
let currentRouter = routers.filter((items: any) => {
return !items.meta.target || (items.meta.target && items.meta.target != '_blank')
})
const routerConf: any = new Router({
base: process.env.BASE_URL,
routes: [
{
path: '/',
redirect: '/index',
component: () => import('../views/index/index.vue'),
children: currentRouter
},
{
path: '*',
redirect: '/error'
},
{
path: '/',
component: () => import('../App.vue'),
children: newWindowRouter
}
]
})
let permissionData: any[] = []
let getPermission = (routes: any) => {
routes.forEach((route: any) => {
if (!route.children || route.children.length === 0) {
permissionData.push(route)
} else {
getPermission(route.children)
}
})
}
routerConf.beforeEach(async (to: any, from: any, next: any) => {
NProgress.start()
// next()
let username = store.getters.username
// if (process.env.NODE_ENV === 'development') {
// store.commit('SETUSERNAME', Vue.prototype.devUserCode.userCode)
// } else {
if (username == '') {
let resUser = await store.dispatch('getUserName')
if (resUser.success) {
store.commit('SETUSERNAME', resUser.content.userName)
} else {
Message.warning('获取用户信息失败!')
}
}
let data = store.getters.menuTree
const hasMenu = data && data.length > 0
if (!hasMenu) {
permissionData = []
if (to.name != 'index') {
try {
let res = await store.dispatch('System/getTreeMenu')
if (res.success) {
res.content.menuList.forEach((i:any) => {
i.children = i.list
})
store.commit('SETMENUTREE', res.content.menuList)
getPermission(res.content.menuList)
} else {
store.commit('SETMENUTREE', [])
Message.error(res.message || '获取导航失败!')
}
} catch (e) {
store.commit('SETMENUTREE', [])
Message.error(JSON.stringify(e))
}
} else {
store.dispatch('System/getTreeMenu').then((res: any) => {
if (res.success) {
res.content.menuList.forEach((i:any) => {
i.children = i.list
})
store.commit('SETMENUTREE', res.content.menuList)
next()
getPermission(res.content.menuList)
} else {
store.commit('SETMENUTREE', [])
}
}).catch((e) => {
store.commit('SETMENUTREE', [])
Message.error(JSON.stringify(e))
})
}
} else {
}
let hasPer: any[] = []
for (let i = 0; i < permissionData.length; i++) {
if (('/' + to.path) == permissionData[i].url) {
hasPer = [permissionData[i]]
break
}
}
if (process.env.NODE_ENV != 'development') {
if (to.path != '/' && to.path != '/refresh') {
store.commit('SAVEROUTEDATA', {
title: hasPer.length > 0 ? hasPer[0].name : to.meta.title,
path: to.path,
componentName: to.meta.componentName
})
next()
} else {
next()
}
} else {
if (to.path != '/' && to.path != '/refresh') {
store.commit('SAVEROUTEDATA', {
title: hasPer.length > 0 ? hasPer[0].name : to.meta.title,
path: to.path,
componentName: to.meta.componentName
})
}
next()
}
NProgress.done()
})
routerConf.afterEach(() => {
NProgress.done()
})
export default routerConf
7、request.ts
import { as } from './axios'
import qs from 'qs'
// @ts-ignore
import { Message, Loading } from 'hikui'
import Vue from 'vue'
const noError = ['selectUserInfo', 'listCommonResources', 'isOuterResourceOpen']
const server = (config: any) => {
const cfg = Object.assign({ method: 'post' }, config)
delete (cfg.data)
if (cfg.method && cfg.method.toLowerCase() === 'get') {
// get
for (let key in config.data) {
if (config.data[key] == null || config.data[key] == undefined) {
config.data[key] = ''
}
}
cfg.params = config.data
} else if (cfg.method.toLowerCase() === 'post' && cfg.headers && cfg.headers['Content-Type'] == 'application/x-www-form-urlencoded') {
// form
cfg.data = qs.stringify(config.data)
} else {
cfg.data = config.data
}
let loadingIc = Loading.service({
lock: true,
background: 'rgba(0, 0, 0, 0.3)'
})
return new Promise((resolve, reject) => {
as(cfg).then((res: any) => {
loadingIc.close()
if (res.request.responseType == 'blob') {
resolve(res)
}
const data = res.data
if (data.code == Vue.prototype.errorCode && res.request.responseType !== 'blob') {
if (!noError.some((item) => config.url.split('/')[config.url.split('/').length - 1] == item)) {
Message.error(data.message)
}
}
resolve(data)
}).catch((err: any) => {
loadingIc.close()
resolve([])
return Message.error('token失效,请退出重新登录', err)
})
})
}
export default server
8、i18n
import Vue from 'vue'
import VueI18n from 'vue-i18n'
//@ts-ignore
import enLocale from 'hikui/dist/locale/lang/en'
//@ts-ignore
import zhLocale from 'hikui/dist/locale/lang/zh-CN'
//@ts-ignore
import Locale from 'hikui/dist/locale'
import store from '@/store'
Vue.use(VueI18n)
const messages: any = {
en: {
...enLocale
},
zh: {
...zhLocale
}
}
let language = window.localStorage.getItem('language') ? <string>window.localStorage.getItem('language') : 'zh'
store.commit('SETLANGUAGE', language)
function setLanguage (localResources: any) {
if (!localResources) {
return
}
for (let key in localResources) {
messages.zh[key] = localResources[key]
messages.en[key] = localResources[key]
}
}
const i18n = new VueI18n({
locale: language || 'zh',
messages,
silentTranslationWarn: true
})
// store.dispatch('System/getResources').then((res: any) => {
// if (res.code === Vue.prototype.successCode) {
// setLanguage(res.data)
// i18n.mergeLocaleMessage(language, messages[language])
// }
// })
Locale.i18n((key: any, value: any) => i18n.t(key, value))
//重新封装国际化翻译,增加默认显示
Vue.prototype.$l = (key: string, language?: string) => {
if (i18n.tc(key) === key && language) {
return language
}
return i18n.tc(key)
}
export default i18n