| const menu = { | ||
| ROOT: { | ||
| key: 'SYSTEM_DEMO', | ||
| name: 'GPS', | ||
| }, | ||
| DEMO_BASIC: { | ||
| key: 'DEMO_BASIC', | ||
| name: '基础数据', | ||
| }, | ||
| }; | ||
| export default menu; |
+8
-0
@@ -0,1 +1,9 @@ | ||
| ## 2.3.4 | ||
| ### `umi` 应用 | ||
| #### ✨ Features | ||
| - 支持通过配置快速生成 ums 菜单结构 | ||
| ## 2.3.3 | ||
@@ -2,0 +10,0 @@ |
| import { defineConfig } from 'umi'; | ||
| import fs from 'fs'; | ||
| /** | ||
@@ -9,2 +9,11 @@ * 此为生产环境的配置文件 | ||
| export default defineConfig({ | ||
| // 设置要复制到输出目录的文件或文件夹。 | ||
| copy: fs.existsSync('menu.json') | ||
| ? [ | ||
| { | ||
| from: 'menu.json', | ||
| to: 'resources/json/menu.json', | ||
| }, | ||
| ] | ||
| : [], | ||
| // 默认是 ['umi'],可修改,比如做了 vendors 依赖提取之后,会需要在 umi.js 之前加载 vendors.js。 | ||
@@ -11,0 +20,0 @@ // https://umijs.org/zh-CN/config#chunks |
@@ -6,4 +6,6 @@ /** | ||
| */ | ||
| import MENU from '../menu.config'; | ||
| const routes = [ | ||
| { path: '/demo', component: '@/pages/demo', title: '示例' }, | ||
| { path: '/demo', component: '@/pages/demo', title: '示例', parent: MENU.DEMO_BASIC }, | ||
| // 在这里添加路由 | ||
@@ -21,2 +23,2 @@ | ||
| }, | ||
| ].filter(item => item); | ||
| ].filter(item => item); |
| /* | ||
| * @Author: yemu | ||
| * @Date: 2021-04-02 15:43:14 | ||
| * @LastEditTime: 2021-04-06 13:24:35 | ||
| * @LastEditTime: 2021-07-07 17:18:01 | ||
| * @LastEditors: yemu | ||
@@ -10,8 +10,14 @@ * @Description: 生成按钮权限码 | ||
| import yaml from 'js-yaml'; | ||
| import groupBy from 'lodash/groupBy'; | ||
| import routes from './config/routes'; | ||
| import { name } from './package'; | ||
| // 默认菜单配置路径 | ||
| const MENU_SETTING_PATH = './menu.config.js'; | ||
| (function permission2md() { | ||
| // 基本路径 | ||
| const BASE = 'CF'; | ||
| // 主功能基本路径 | ||
| const FUNC_MAIN = 'FUNC_MAIN'; | ||
| // 包名大写 | ||
@@ -28,31 +34,91 @@ const packageName = name.toUpperCase(); | ||
| try { | ||
| // 菜单配置 | ||
| let menuSetting = {}; | ||
| // 根菜单 | ||
| let rootMenu = {}; | ||
| // 判断根目录下是否存在菜单配置文件 | ||
| if (fs.existsSync(MENU_SETTING_PATH)) { | ||
| menuSetting = require(MENU_SETTING_PATH).default; | ||
| rootMenu = menuSetting.ROOT || {}; | ||
| } | ||
| // 菜单配置 | ||
| const menus = []; | ||
| // 遍历路由路径从头部注释中获取权限信息 | ||
| routes[0]?.routes.map(item => { | ||
| if (!item.title) { | ||
| return; | ||
| } | ||
| let filePath = item.component.replace('@', './src'); | ||
| if (fs.statSync(filePath).isDirectory()) { | ||
| filePath = `${filePath}/index.js`; | ||
| } | ||
| const content = fs.readFileSync(filePath, 'utf8').toString(); | ||
| const { permissions } = transformer(content) || {}; | ||
| if (Object.prototype.toString.call(permissions) === '[object Object]') { | ||
| text.push(`## ${item.title}(${item.path})`); | ||
| routes[0]?.routes | ||
| .filter(item => !!item.title) | ||
| .map(item => { | ||
| // 读取路由component指向的文件地址并替换别名 | ||
| let filePath = item.component.replace('@', './src'); | ||
| // 判断是否是文件夹,如果是文件夹,路径默认加上index.js | ||
| if (fs.statSync(filePath).isDirectory()) { | ||
| filePath = `${filePath}/index.js`; | ||
| } | ||
| // 读取该文件路径内的内容 | ||
| const content = fs.readFileSync(filePath, 'utf8').toString(); | ||
| // 解析文件头部注释信息 获取按钮权限配置 | ||
| const { permissions } = transformer(content) || {}; | ||
| // 页面路由 | ||
| const page = item.path.replace('/', '').toUpperCase(); | ||
| text.push('\r'); | ||
| Object.keys(permissions).map(f => { | ||
| text.push( | ||
| `- ${[BASE, packageName, page, f.toUpperCase()].join('_')} ${ | ||
| item.title | ||
| }-${permissions[f]}`, | ||
| ); | ||
| }); | ||
| text.push('\r'); | ||
| } | ||
| }); | ||
| // 记录功能权限 | ||
| const functions = []; | ||
| if (Object.prototype.toString.call(permissions) === '[object Object]') { | ||
| // 页面标题 + 路由路径 | ||
| text.push(`## ${item.title}(${item.path})`); | ||
| text.push('\r'); | ||
| Object.keys(permissions).map(f => { | ||
| // 权限码生成规则:CF_{ 工程包名 }_{ 页面路由 }_{ 操作类型 } | ||
| const permissionCode = [BASE, packageName, page, f.toUpperCase()].join('_'); | ||
| text.push(`- ${permissionCode} ${item.title}-${permissions[f]}`); | ||
| // 缓存功能权限 | ||
| functions.push({ | ||
| code: permissionCode, | ||
| name: permissions[f], | ||
| }); | ||
| }); | ||
| text.push('\r'); | ||
| } | ||
| if (item.parent) { | ||
| // 父级CODE | ||
| const parentCode = item.parent.key; | ||
| menus.push({ | ||
| // 菜单key,规则:{ 父级菜单CODE }_{ 页面路由大写 } | ||
| key: [parentCode, page].join('_'), | ||
| // 菜单名称 | ||
| name: item.title, | ||
| // 父级菜单code | ||
| parentCode, | ||
| // 主功能 - 页面 | ||
| mainFun: { | ||
| // 主功能CODE,唯一标识,规则:{ 父级菜单CODE }_{ 主功能基本路径 }_{ 页面路由大写 } | ||
| code: [parentCode, FUNC_MAIN, page].join('_'), | ||
| // 主功能标题 | ||
| name: item.title, | ||
| // 页面访问地址 | ||
| url: `/#${item.path}`, | ||
| }, | ||
| // 子功能 - 按钮权限 | ||
| functions, | ||
| }); | ||
| } | ||
| }); | ||
| // 写入文件 | ||
| if (menus.length > 0) { | ||
| // 将路由按父级菜单分组 | ||
| const groupMenus = groupBy(menus, 'parentCode'); | ||
| // 合并项目根节点 | ||
| const menuTree = { | ||
| ...rootMenu, | ||
| children: Object.keys(groupMenus).map(key => { | ||
| return { | ||
| ...menuSetting[key], | ||
| children: groupMenus[key], | ||
| }; | ||
| }), | ||
| }; | ||
| // 将菜单写入到根目录menu.json中 | ||
| const data = JSON.stringify(menuTree, null, 4); | ||
| fs.writeFileSync('menu.json', data); | ||
| console.log('✨ 菜单menu.json文件生成成功'); | ||
| } | ||
| fs.writeFileSync('PERMISSION_CODE.md', text.join('\n')); | ||
@@ -59,0 +125,0 @@ console.log('✨ 按钮权限码生成成功'); |
@@ -0,1 +1,7 @@ | ||
| /** | ||
| * permissions: | ||
| * add: 新增 | ||
| * edit: 编辑 | ||
| * delete: 删除 | ||
| */ | ||
| import React, { forwardRef, useState, useEffect } from 'react'; | ||
@@ -10,2 +16,3 @@ import { connect } from 'umi'; | ||
| import useDeleteRows from '@/hooks/useDeleteRows'; | ||
| import usePermission from '@/hooks/usePermission'; | ||
@@ -19,5 +26,7 @@ import { renderColumns } from '@/utils/renderColumn'; | ||
| function Demo({ dispatch, act, demo, form }, ref) { | ||
| function Demo({ dispatch, act, demo, form, route }, ref) { | ||
| const [selectedRowKeys, setSelectedRowKeys] = useState([]); | ||
| const { getFieldDecorator } = form; | ||
| // 按钮权限验证 | ||
| const { validate } = usePermission(route); | ||
@@ -62,2 +71,3 @@ // 列表分页查询 | ||
| }, | ||
| visible: validate('edit'), | ||
| }, | ||
@@ -72,2 +82,3 @@ { | ||
| }, | ||
| visible: validate('delete'), | ||
| }, | ||
@@ -165,12 +176,19 @@ ]; | ||
| <ButtonWrap> | ||
| <Button icon="plus" onClick={() => addFormModal.setVisible(true)}> | ||
| 新增 | ||
| </Button> | ||
| <Button | ||
| icon="delete" | ||
| disabled={selectedRowKeys.length == 0} | ||
| onClick={() => deleteRows.model(selectedRowKeys)} | ||
| > | ||
| 删除 | ||
| </Button> | ||
| {validate('add') && ( | ||
| <Button | ||
| icon="plus" | ||
| onClick={() => addFormModal.setVisible(true)} | ||
| > | ||
| 新增 | ||
| </Button> | ||
| )} | ||
| {validate('delete') && ( | ||
| <Button | ||
| icon="delete" | ||
| disabled={selectedRowKeys.length == 0} | ||
| onClick={() => deleteRows.model(selectedRowKeys)} | ||
| > | ||
| 删除 | ||
| </Button> | ||
| )} | ||
| </ButtonWrap> | ||
@@ -177,0 +195,0 @@ } |
+1
-1
| { | ||
| "name": "@vtx/cli", | ||
| "version": "2.3.3", | ||
| "version": "2.3.4", | ||
| "description": "前端项目脚手架工具", | ||
@@ -5,0 +5,0 @@ "bin": { |
+5
-13
@@ -7,15 +7,7 @@ # @vtx/cli | ||
| Install, create and start. | ||
| ```bash | ||
| # Install | ||
| $ npm install @vtx/cli -g | ||
| # Create app | ||
| $ vtx new myapp | ||
| # Start app | ||
| $ cd myapp | ||
| $ npm install | ||
| $ npm start | ||
| ```shell | ||
| npx @vtx/cli new my-app | ||
| cd my-app | ||
| yarn install | ||
| yarn start | ||
| ``` | ||
@@ -22,0 +14,0 @@ |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
705008
0.62%117
0.86%4094
2.66%32
-20%15
15.38%