Teemo
A scaffold for developing SPA admin console based on react with antd
Install / Use
/learn @watertao/TeemoREADME
= Teemo watertao 1059912278@qq.com :toc: left :toclevels: 3 :source-highlighter: coderay :sectnums: :icons: font
:sectnumlevels: 3
一个基于 react + antd pro 的前端开发脚手架。
== 贡献者
曾利(henry),吴涛(watertao)
== 预览
image::https://github.com/watertao/static-assets/blob/master/teemo/Xnip2019-04-27_18-33-12.jpg?raw=true[] image::https://github.com/watertao/static-assets/blob/master/teemo/Xnip2019-04-27_18-53-23.jpg?raw=true[]
== 快速开始
=== clone 项目
将 Teemo 项目 clone 到本地开发环境:
[source, bash]
clone --depth=1 https://github.com/watertao/teemo.git myapp
=== 安装依赖 通过 yarn 或 npm 安装依赖:
[source, bash]
cd myapp yarn install
=== 启动应用
[source, bash]
npm start
[NOTE]
确保 8000 端口未被占用。
== 项目配置
修改 src/defaultSettings.js 中的配置以满足自己的项目需求:
.defaultSettings.js [source, javascript]
module.exports = {
navTheme: 'dark', // <1> primaryColor: '#1890FF', layout: 'sidemenu', contentWidth: 'Fluid', fixedHeader: false, autoHideHeader: false, fixSiderbar: false,
menu: { disableLocal: false, },
pwa: true,
title: 'app.title', // <2> logoImg: 'MY-LOGO.svg', // <3>
request: { timeout: 5000, // <4> debounceDelay: 50, // <5> },
footer: { copyright: 'Copyright123 © 2019 watertao.github.com', // <6> },
};
<1> antd pro 自带的样式配置
<2> 系统的名称 locale,将会显示在登录页及左侧菜单顶部,locale 定义在 src/locales/ 下
<3> 系统的 logo,注意该值修改后需要重新启动应用
<4> fetch 请求默认超过该值会被认为超时
<5> 默认的 debounce 延迟
<6> copyright,显示在页面底部
== 模块
Teemo 将每个菜单视作一个模块,模块与模块之间相互独立。模块位于 src/pages 下, Teemo 将递归查找该目录下的所有子目录,但凡某个目录下包含
module.config.js,那么该目录被视作一个模块。
=== module.config.js
模块的配置文件:
.module.config.js [source, javascript]
module.exports = {
name: 'moduleName', // <1>
authority: { resources: [ // <2> 'GET /auth/roles', // <3> 'GET /auth/roles/{roleId}', 'GET /auth/roles/{roleId}', 'GET /auth/roles/{roleId}', ], events: [ // <4> { code: 'create-role', // <5> name: 'createRoleEventName', // <6> resources: [ // <7> 'POST /auth/roles', ], }, { code: 'modify-role', name: 'modifyRoleEventName', resources: [ 'PUT /auth/roles/{roleId}', 'GET /auth/roles/{roleId}', ], }, { code: 'delete-role', name: 'deleteRoleEventName', resources: [ 'DELETE /auth/roles/{roleId}', ], }, ], },
routes: [ // <8> { path: '/detail', // <9> component: 'components/Analysis', // <10> routes: [ { path: '/detail/more-detail', component: 'components/MoreDetail', } ] } ]
}
<1> 模块的名称 locale,对应模块目录下的国际化消息文件(如 module.locale.en-US.js)中的 key
<2> 进入该模块所需的关联资源
<3> 资源以 动词 + URI 的形式表达
<4> 定义该模块下的事件权限,比如按钮的权限
<5> 事件的编码,在一个模块中唯一
<6> 事件的名称 locale,对应模块目录下的国际化消息文件
<7> 事件关联的资源
<8> 模块内的路由配置
<9> 转成实际路由时会在前面补上菜单对应的路径前缀
<10> 路由对应的组件,相对目录模块的路径
=== 模块国际化消息
在模块目录下定义的名称看起来为 module.locale.xx-XX.js 的文件便是国际化消息文件,其中 xx-XX 便是语言缩写,常见的如 en-US 和
zh-CN 等。 +
.module.locale.en-US.js [source, javascript]
module.exports = {
'moduleName': 'Role Management',
'createRoleEventName': 'Create Role', 'modifyRoleEventName': 'Modify Role', 'deleteRoleEventName': 'Delete Role',
};
在组件中,我们可以通过以下方式使用消息:
[source, javascript]
import mm from '@/utils/message-util';
export function(props) { return mm('createRoleEventName'); }
模块内的国际化消息只能用于同一模块下的组件,倘若想要跨模块使用国际化消息,那么可以使用 antd pro 原生的解决方案,即在 src/locales 中定义, 并通过 formatMessage 函数去使用。
=== 入口组件
每个模块目录下必须定义一个入口组件 index.js,在进入某一个模块时, Teemo 会自动加载此组件
=== 创建模块
Teemo 提供了一个命令行工具用于快速创建模块骨架:
[source, bash]
umi module-gen
根据提示依次输入参数:
[cols="1,2", options="header"] |=== |参数 |描述
|模块路径 |比如 /demo/demo-a, 这会生成 src/pages/demo/demo-a 这个模块
|国际化定义 |en-US, zh-CN 中选择
|model 名 |比如 demoa
|service 名 |比如 demoa
|===
执行完毕后会在 src/pages/demo/demo-a 下生成以下文件:
├── index.js ├── models │ └── demoa.model.js ├── module.config.js ├── module.locale.en-US.js ├── module.locale.zh-CN.js ├── services │ └── demoa.service.js └── style.less
== 菜单
模块定义完成后,在菜单中该如何布局需要在 src/menu.config.js 中设置:
=== menu.config.js
.menu.config.js [source, javascript]
// restart server after change
module.exports = [ { code: 'test', type: 'group', icon: 'profile', children: [ { code: 'test-a', type: 'module' }, { code: 'test-b', type: 'module', }, { code: 'test-c', type: 'module', },
]
},
{ code: 'authority', type: 'group', icon: 'safety', // <1> children: [ { code: 'authority_resource-mgnt', type: 'module' }, // <2> { code: 'authority_role-mgnt', type: 'module' }, { code: 'authority_user-mgnt', type: 'module' }, ] },
];
<1> type 为 group 的节点是菜单组,code 需唯一 <2> type 为 module 的节点是模块(即可被点击进入的菜单),code 设置为 src/pages 下的目录结构以下划线组合,比如 src/pages/demo/demo-a , 则 code 为 demo_demo-a
== 权限
=== 受保护的资源
对于前后端分离的应用而言,权限真正控制的点是 REST 接口。但 Teemo 仍然象征性的在前端做了权限控制,控制当前用户对哪些菜单可见,哪些按钮可按等。
==== 菜单的权限控制
菜单分为菜单组(type=group)和模块 (type=module):
image::https://github.com/watertao/static-assets/blob/master/teemo/menu.jpg?raw=true[menu,350,*]
这种层级关系可以通过 <<menu_config_js, menu.config.js>> 配置。 + 模块的显示权限由该模块的关联接口(参考 <<module_config_js, module.config.js>>)决定,当前登录用户具备了所有关联接口的访问权限便能在菜单 中显示该模块。 + 菜单组的显示权限取决于该菜单组下是否包含可见的模块,若没有任何模块可显示,那么菜单组也将被隐藏。
==== 事件的权限控制
Teemo 为了让权限的粒度能够到按钮级别,所以定义了事件权限,参考 <<module_config_js, module.config.js>>。当前登录用户具备了某事件的所有 关联接口的访问权限,那么它就具备访问该事件的权限了。
=== 用户的权限
定义了模块和事件的关联接口之后,我们还需要根据当前用户的权限才能知道他是否具备访问这些模块或事件的权限。 用户完成登录或会话同步后,Teemo 会 在 src/models/global.model.js 中存储下用户的基本信息及权限信息,它的数据结构看起来如下:
[source, json]
{ "token":"dd2043f9-2116-42bb-b59a-b74eb12b4f54", // <1> "login_name":"demacia", // <2> "id":73, // <3> "name":"超级用户", // <4> "resources":[ // <5> { "verb":"GET", // <6> "name":"获取资源集合", // <7> "uri_pattern":"/auth/resources", // <8> "id":1 // <9> } ] }
<1> 会话令牌 <2> 登录名 <3> 用户的标识 <4> 用户名称 <5> 用户能否访问的 REST 接口集合 <6> 接口的动词 <7> 接口名称 <8> 接口的 URI 模式 <9> 接口的标识
以上结构是必须的,倘若后端所返回的数据结构与上面不符,那么需要转换成上面这种结构。如果使用 link:https://github.com/watertao/hygen-veigar-simple-auth[hygen-veigar-simple-auth] 生成的登录及会话同步接口,那么返回的数据结构默认就是这样的。
Related Skills
node-connect
344.4kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
99.2kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
344.4kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
344.4kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
