Skip to content

Commit

Permalink
修改权限加载形式,cli命令,新增遗漏目录
Browse files Browse the repository at this point in the history
  • Loading branch information
vannvan committed Sep 7, 2020
1 parent 576cf8e commit 39dc11f
Show file tree
Hide file tree
Showing 13 changed files with 203 additions and 78 deletions.
91 changes: 91 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,94 @@ yarn lint
```

### Customize configuration

### 开发规范

- 接口管理:
按照不同的功能模块采取对应的名称文件进行存放,index 已采取自动引入, 页面使用时导入具体的接口即可。
示例:

```js
import { post } from './http'
export default {
getUserList: (p) => post('/api/userList', p), //获取用户列表
}
//组件内
const { getUserList } = require('@/api').User
getUserList().then((res) => {
//TODO
})
```

- 静态资源:
图片资源较多的情况下,建议采用的图片模块划分形式
a. 采取不同功能模块命名进行划分,
b. icon、background、功能大图进行划分
此脚手架已将 scss 相关配置初始化,为避免项目样式杂乱,项目严禁同时使用多个 css 扩展语言
其他因项目有特殊需求的不同配置形式可根据具体情况进行调整和变更。

- 页面及组件:
所有页面均需在 pages 下进行开发,每个功能模块拥有一个文件夹,具体层级可根据模块的大小进行规划,建议不超过三级,特属于某个模块内的子组件存放在当前模块内部即可,通用性组件存放在 components 文件夹下

- 路由管理:
路由已采用全局自动化加载进行配置,特殊页面仍可采取手动配置进行引入,自动加载路由会排除功能模块下的子组件文件,故某模块下不作为页面使用的组件均需放在其对应的 components 文件夹下,router/index.js 对路由及权限关系管理有基础示例

- store 管理:
store 已采取自动化加载进行配置,须根据不同功能的模块进行划分命名,避免因 store 过多造成的混乱,具体可参照初始化文件下的使用方式

- utils:
utils 是用于抽离可作为全局或可重复使用的方法的封装,遵循一个函数只有一个功能的思想,方法的指定需考虑一定的扩展性和健壮性,必须写函数的注释说明。

- 代码格式化:
项目采用 vue 脚手架默认的 eslint 规范,严禁关闭全局的 eslint 验证,编辑器建议安装 prettier 进行代码美化
- 组件开发: [vue 开发风格指南](https://cn.vuejs.org/v2/style-guide/)
建议按照以下书写顺序进行组件开发,没有使用到的可以忽略

```js
export default {
name: '',

mixins: [],

components: {},

props: {},

data() {
return {
menuList: [], // 必要的注释说明
}
},

computed: {
formattedValue() {
// ...
},
//空行
styles() {
// ...
},
},

watch: {},

created() {},

mounted() {},

destroyed() {},

methods: {
//方法功能说明
onInput() {
// ...
},
//空行
onChange() {
// ...
},
},
}
```

### 注意事项
64 changes: 45 additions & 19 deletions cli/zip.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,70 @@

process.stdin.setEncoding('utf8');
const compressing = require('compressing');
var pjson = require('../package.json');
const inquirer = require('inquirer');
const chalk = require('chalk');
const symbols = require('log-symbols');
const fs = require('fs');
const promptList = [{
type: 'list',
name: 'type',
message: '部署环境:',
choices: ['test', 'pre', 'prod']
}]

const prefixName = pjson.packPrefix || 'wwvue-cli_'; //默认压缩包前缀
const prefixName = ''; //默认压缩包前缀
const time = formatDateToString(new Date());

inquirer.prompt(promptList).then((answers) => {
let { type } = answers
let packName = prefixName + type + '_' + time
toPack(packName)
// writeApiConfig(area,type)
})

// 执行打包
const toPack = async function(packName) {
// await writeApiConfig()
await writePackVersionToIndex(packName)
await toZip(packName)
}

// 052910 格式
function formatDateToString(date) {
var year = date.getFullYear();
var month = date.getMonth() + 1;
var day = date.getDate();
var hour = date.getHours();
let fm = month < 10 ? '0' + month : month;
let fd = day < 10 ? '0' + day : day;
let fh = hour < 10 ? '0' + hour : hour;
return fm + fd + fh
return fm.toString() + fd + fh
}


//执行压缩
function toZip(name) {
compressing.zip.compressDir('dist', `${name}.zip`)
.then(() => {
console.log(`${name}.zip` + '已保存至项目目录!');
console.log(symbols.success, chalk.green(`${name}.zip` + '已保存至项目目录!'));
process.exit()
})
.catch(err => {
console.error(err);
});
}
//给index追加打包时间注释
function writePackVersionToIndex(packName) {
var time = new Date().toLocaleString()
var append = `\n <!--packTime: ${time} packName: ${packName} --> \n`;
fs.appendFile('dist/index.html', append, 'utf8', function(err) {
if (err) {
console.log(err);
}
console.log(symbols.success, chalk.green('打包信息已追加至index.html'));
});
}

const time = formatDateToString(new Date());

process.stdout.write(`请输入压缩文件名:`)
process.stdin.resume()
process.stdin.on('data', (chunk) => {
chunk = chunk.toString().trim(); //输入的文件名
var name = chunk || prefixName + time;
toZip(name)
});



process.stdin.on('end', () => {
process.stdout.write('结束');
process.on('SIGINT', function() {
console.log('Exit now!');
process.exit();
});
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"version": "0.1.0",
"private": true,
"scripts": {
"ccc": "node cli/create-custom-components",
"pack": "node cli/zip",
"serve": "vue-cli-service serve --open",
"build": "vue-cli-service build --mode production && node cli/write",
"lint": "vue-cli-service lint",
Expand Down
2 changes: 1 addition & 1 deletion src/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ requireModule.keys().forEach(fileName => {
})


export default { ...APILIST }
module.exports = APILIST
38 changes: 28 additions & 10 deletions src/assets/menu.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,48 @@
export default {
'superAdmin': [
{ name: '首页', path: "/index", icon: '', id: 1, pid: 0 },
{ name: 'HelloWorld', path: "/HelloWorld", icon: '', id: 2, pid: 0 },
{ name: '首页', path: "/home", icon: 'ios-analytics', id: 1, pid: 0 },
{
name: '广告',
name: '广告管理',
path: '/ad',
icon: '',
icon: 'ios-analytics',
id: 3,
pid: 0,
children: [
{ name: '广告List', path: '/ad/index', icon: '', id: 31, pid: 3 },
{ name: "广告详情", path: '/ad/detail', icon: '', id: 32, pid: 3 }
{ name: '广告列表', path: '/ad/list', icon: 'ios-analytics', id: 31, pid: 3 },
{ name: "广告详情", path: '/ad/details', icon: 'ios-analytics', id: 32, pid: 3 }
]
},
{
name: '订单管理',
path: '/order',
icon: 'ios-analytics',
id: 4,
pid: 0,
children: [
{ name: '订单列表', path: '/order/list', icon: 'ios-analytics', id: 41, pid: 4 },
]
},
{
name: 'example',
path: '/example',
icon: 'md-cloud',
id: 5,
pid: 0,
children: [

]
}
],
'admin': [
{ name: '首页', path: "/index", icon: '', id: 1, pid: 0 },
{ name: 'HelloWorld', path: "/HelloWorld", icon: '', id: 2, pid: 0 },
{ name: '首页', path: "/index", icon: 'ios-analytics', id: 1, pid: 0 },
{
name: '广告',
path: '/ad',
icon: '',
icon: 'ios-analytics',
id: 3,
pid: 0,
children: [
{ name: '广告List', path: '/ad/index', icon: '', id: 31, pid: 3 },
{ name: '广告List', path: '/ad/index', icon: 'ios-analytics', id: 31, pid: 3 },
]
}
]
Expand Down
12 changes: 12 additions & 0 deletions src/layout/Layout.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<template>
<div>
<router-view></router-view>
</div>
</template>

<script>
export default {};
</script>

<style>
</style>
7 changes: 0 additions & 7 deletions src/packages/Lala/index.js

This file was deleted.

13 changes: 0 additions & 13 deletions src/packages/Lala/src/Lala.vue

This file was deleted.

2 changes: 1 addition & 1 deletion src/pages/HelloWorld.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</template>

<script>
const { User } = require("@/api").default;
const { User } = require("@/api").User;
import { mapState } from "vuex";
export default {
name: "HelloWorld",
Expand Down
File renamed without changes.
22 changes: 9 additions & 13 deletions src/router/auto-register-route.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
// 懒加载
const requireAllVueComponents = require.context('../pages', true, /\.vue$/, 'lazy');
// 非懒加载
// const requireAllVueComponents = require.context('../components/autoRouter', true, /\.vue$/);

const routerList = [];

const EXCLUDE_PAGE = ['Login'] //需要排除的一些特例页面,例如登录页面,空缺页

requireAllVueComponents.keys().forEach((allVueComponentItem) => {
const completeName = allVueComponentItem.match(/\w+\.vue$/, '')[0];
const isComponents = /components/.test(allVueComponentItem)
if (!/^[A-Z]+/.test(completeName.replace(/(^\.|\.vue)/g, ''))) {
console.error('组件: ' + completeName, '命名不符合规范,请采用大驼峰形式命名');
}
const isExclude = EXCLUDE_PAGE.every(el => new RegExp(el).test(completeName))
// 文件名尾部有数值的情况下 自动注入路由
if (completeName.match(/\w\.vue$/g) && !isComponents) {
if (completeName.match(/\w\.vue$/g) && !isComponents && !isExclude) {
const routerMap = {};
routerMap.path = allVueComponentItem.replace(/(^\.|\.vue)/g, '')
routerMap.name = allVueComponentItem.replace(/(\.\/|\/|\.vue)/g, '')
// const componentName = allVueComponentItem.replace(/\.\//, '../components/autoRouter/').replace(/\.vue$/, '');
// 一、懒加载的实现

routerMap.path = allVueComponentItem.replace(/(^\.|\.vue)/g, '').toLowerCase()
routerMap.name = allVueComponentItem.replace(/(\.\/|\/|\.vue)/g, '').toLowerCase()
routerMap.component = () => requireAllVueComponents(allVueComponentItem)

// 二、非懒加载--同步的实现
// routerMap.component = requireAllVueComponents(allVueComponentItem).default || requireAllVueComponents(allVueComponentItem)

routerList.push(routerMap)
}
})
Expand Down
16 changes: 9 additions & 7 deletions src/router/index.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
import Vue from 'vue'
import Router from 'vue-router'
import routes from './routers'
import routerList from './auto-register-route'
import { uniqueElementsBy, flatData, generateRoleRouters } from '@/utils'
import { flatData, generateRoleRouters } from '@/utils'
import authMenu from '@/assets/menu.js'


const CURRENT_AUTH = 'admin' //当前角色

const permissionSwitch = true //权限开关,用于某些场景开发环境需要所有路由可访问的情况
const permissionSwitch = false //权限开关,用于某些场景开发环境需要所有路由可访问的情况


const routesCombination = uniqueElementsBy([...routes, ...routerList], (a, b) => b.path == a.path) //去重
const flatAuthMenu = flatData(authMenu[CURRENT_AUTH])


Vue.use(Router)

const router = new Router({
base: '/',
routes: permissionSwitch ?
generateRoleRouters(flatAuthMenu, routesCombination) : routesCombination,
generateRoleRouters(flatAuthMenu, flatData(routes)) : routes,
mode: 'history'
})

Expand All @@ -38,4 +34,10 @@ router.afterEach(() => {
window.scrollTo(0, 0)
})

//用于解决菜单重复点击控制台报错的坑
const originalPush = Router.prototype.push
Router.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}

export default router
Loading

0 comments on commit 39dc11f

Please sign in to comment.