1.DEMO安装
1.1.前端安装
下载最新的Node
下载GIT并且安装,安装好后用管理员模式执行git-bash.exe
VSCODE导入项目:
1.2.后端安装
需要本机支持Maven,没有需要安装配置好。然后开始下载脚手架:
STS载入项目:
1.3.数据库安装
导入一个示例SQL脚步:
配置数据库参数:
1.4.DEMO运行效果
http://localhost:8000,使用admin,1登陆
2.DEMO学习
2.1.前端学习-概览
2.1.1.主要文件
a.config->router.config.js:菜单配置
path:浏览器访问路径
name:菜单中文名称
icon:菜单图标
在官网如下:
routes:子菜单
component:页面对应的js文件,以src/pages/为基准,作为相对路径的起点目录
hideInMenu: true, 不显示改菜单
hideChildrenInMenu: true, 子菜单不显示
首页,一般要写成./System/index.js, 可以简写:./System/index,也可以再简写:./System
b.src->pages->System->index.js:首页
Card是官方库的内容,可以在官网查找说明如下:
访问地址 : https://3x.ant.design/docs/react/introduce-cn
c.dist 打包后的文件
输入命令后打包才生成dist目录
d.public 静态资源
e.src->defaultSettings.js
项目设置*
f.src->domain.js
请求域名*
g.src->pages
pages 业务组件*
h.src->pages->System
System 系统管理
i.src->pages->System->Account
个人设置
j.src->pages->System->Const
常量数据
k.src->pages->System->Role
角色管理
l.src->pages->System->User
用户管理
2.1.2.常用语法
import
根据代码所需导入库、组件、函数等
config/router.config.js:
import {Button} from 'antdlib';
类似于java:
import java.util.List;
创建组件class
固定写法
export default class Example extends React.PureComponent {}
类似于java:
public class Controller{}
render
class中需要定义render方法,通过返回一个根节点,用来渲染html中的一块区域
render(){
return <div />
}
return后面必须返回一个根节点
componentDidMount
页面载入时触发componentDidMount一次
componentDidMount() {
}
类似于html body onload
<html>
<body onload="">
</body>
</html>
数组、对象的解析
从数组、对象中取值
const [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
const params = { a: 'aaa', b: 'bbb' };
const { a, b } = params;
a // "aaa"
b // "bbb"
...params // a: 'aaa', b: 'bbb'
参数默认值
如果没有传参数,可以设置一个默认值
handleSearch = ( params={} )=> {
ajax({
...params
})
}
无参和有参函数都能调用上面这个函数定义:
- handleSearch()
- handleSearch({a:'aaa',b:'bbb'})
箭头函数
省略了 function 和 return 关键字:
const f = v => v;
// 等同于
const f = function (v) {
return v;
};
如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分:
const f = () => 5;
// 等同于
const f = function () { return 5 };
const sum = (num1, num2) => num1 + num2;
// 等同于
const sum = function(num1, num2) {
return num1 + num2;
};
局部变量
设置值
this.setState({
key:value
})
取值:
const { key } = this.state;
或
this.state.key
2.1.3.布局
a.栅格布局
b.区块间隔
c.左右偏移
2.2.前端学习-组件
2.2.1.基础组件
a.单选框
- - 用于在多个备选项中选中单个状态。
- - 和 Select 的区别是,Radio 所有选项默认可见,方便用户在比较中选择,因此选项不宜过多。
import React from 'react';
import {SmartRadio} from 'antdlib';
export default class Example extends React.PureComponent {
constructor(props){
super(props);
this.state = {
options: [{
text: 'A',
value: 'A',
},{
text: 'B',
value: 'B',
}],
value: 'A',
}
}
handleRadio=(value) => {
console.log(value);
}
render() {
const { options,value } = this.state;
return (
<div>
<SmartRadio options={options} value={value} onChange={this.handleRadio} />
</div>
);
}
}
b.多选框
- - 在一组可选项中进行多项选择时;
- - checkbox 一般用于状态标记
import React from 'react';
import { SmartCheckbox } from 'antdlib';
export default class Example extends React.Component {
state = {
options: [
{ label: 'Apple', value: 'Apple' },
{ label: 'Pear', value: 'Pear' },
{ label: 'Orange', value: 'Orange' },
],
value: ['Apple','Pear'],
}
handleCheckbox=(checkedList) => {
this.setState({
checkedList
});
}
render () {
const { options,value } = this.state;
return (
<SmartCheckbox options={options} checkedList={value} onChange={this.handleCheckbox} />
);
}
}
c.下拉框
import React from 'react';
import {SmartSelect} from 'antdlib';
export default class Example extends React.Component {
state = {
options: [{value:'A',text:'A'},{value:'B',text:'B'},{value:'C',text:'C'}],
value: 'A,B',
}
handleSelect = (value) => {
console.log('select:',value);
}
render () {
const { options,value } = this.state;
return (
<SmartSelect options={options} value={value} onChange={this.handleSelect} />
);
}
}
d.时间段选择
import { message, SmartDatepicker , getTimeDistance } from 'antdlib';
import moment from 'moment';
import React from 'react';
import dateStyle from '@/pages/Style/SmartDatepicker/index.less';
export default class Example extends React.PureComponent {
state = {
rangePickerValue: getTimeDistance('today'),
}
handleRangePickerChange = rangePickerValue => {
this.setState({
rangePickerValue,
});
message.success(moment(rangePickerValue[0]).format('YYYY-MM-DD')}+'~'+moment(rangePickerValue[1]).format('YYYY-MM-DD')});
};
render () {
const { rangePickerValue } = this.state;
return (
<SmartDatepicker value={rangePickerValue} onChange={this.handleRangePickerChange} className={dateStyle} />
);
}
}
e.开关
import { message, SmartSwitch } from 'antdlib';
import React from 'react';
export default class Example extends React.PureComponent {
state = {
checkedChildren : '开',
unCheckedChildren: '关',
switch: undefined,
}
handleSwitch = (value) => {
this.setState({
switch: value
});
}
render () {
const { checkedChildren,unCheckedChildren } = this.state;
return (
<SmartSwitch checkedChildren={checkedChildren} unCheckedChildren={unCheckedChildren} onChange={this.handleSwitch} />
);
}
}
f.级联选择
import { message, SmartCascader } from 'antdlib';
import React from 'react';
export default class Example extends React.PureComponent {
state = {
cascaderOptions : [
{
value: 'zhejiang',
label: '浙江',
children: [
{
value: 'hangzhou',
label: '杭州',
children: [
{
value: 'xihu',
label: '西湖',
},
],
},
],
},
{
value: 'jiangsu',
label: '江苏',
children: [
{
value: 'nanjing',
label: '南京',
children: [
{
value: 'zhonghuamen',
label: '中华门',
},
],
},
],
},
],
value: ['jiangsu','nanjing','zhonghuamen']
}
handleCascader = (value) => {
this.setState({
cascaderOption: value
},()=>{
message.success(JSON.stringify(value));
});
}
render () {
const { cascaderOptions,value } = this.state;
return (
<SmartCascader options={cascaderOptions} value={value} onChange={this.handleCascader} />
);
}
}
g.分页卡片
import { Avatar, Card, Col, Icon, Row, SmartSection } from 'antdlib';
import React from 'react';
const { Meta } = Card;
export default class Example extends React.PureComponent {
render () {
return (
<div>
<Row gutter={16}>
<Col span={12}>
<SmartSection title="典型卡片">
<Card title="Default size card" extra={<a href="#">More</a>} style={{ width: 300 }}>
<p>Card content</p>
<p>Card content</p>
<p>Card content</p>
</Card>
<br />
<Card size="small" title="Small size card" extra={<a href="#">More</a>} style={{ width: 300 }}>
<p>Card content</p>
<p>Card content</p>
<p>Card content</p>
</Card>
<br />
<Card style={{ width: 300 }}>
<p>Card content</p>
<p>Card content</p>
<p>Card content</p>
</Card>
</SmartSection>
</Col>
<Col span={12}>
<SmartSection title="无边框">
<div style={{ background: '#ECECEC', padding: '30px' }}>
<Card title="Card title" bordered={false} style={{ width: 300 }}>
<p>Card content</p>
<p>Card content</p>
<p>Card content</p>
</Card>
</div>
</SmartSection>
<br />
<SmartSection title="丰富信息">
<Card
style={{ width: 300 }}
cover={
<img
alt="example"
src="https://gw.alipayobjects.com/zos/rmsportal/JiqGstEfoWAOHiTxclqi.png"
/>
}
actions={[
<Icon type="setting" key="setting" />,
<Icon type="edit" key="edit" />,
<Icon type="ellipsis" key="ellipsis" />,
]}
>
<Meta
avatar={<Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />}
title="Card title"
description="This is the description"
/>
</Card>
</SmartSection>
</Col>
</Row>
<br />
<Row>
<SmartSection title="栅格">
<div style={{ background: '#ECECEC', padding: '30px' }}>
<Row gutter={16}>
<Col span={8}>
<Card title="Card title" bordered={false}>
Card content
</Card>
</Col>
<Col span={8}>
<Card title="Card title" bordered={false}>
Card content
</Card>
</Col>
<Col span={8}>
<Card title="Card title" bordered={false}>
Card content
</Card>
</Col>
</Row>
</div>
</SmartSection>
</Row>
</div>
);
}
}
h.可编辑表格
import { Button, Card, Form, Tabs,SmartEditableTable,ajax } from 'antdlib';
import { connect } from 'dva';
import React from 'react';
@connect(({content, loading}) => ({
content,
loading: loading.models.content,
}))
export default class Example extends React.Component {
componentDidMount(){
this.searchRoleKV();
this.handleSearch();
}
handleSearch = (params={})=> {
ajax({
url:'user.selectByPrimaryKey',
listKey:'user',
showAll:true,
...params
});
}
searchRoleKV = ()=> {
ajax({
url: 'kv/role.selectByPrimaryKey',
key: 'id', // key名称
value: 'name', // value名称
retKey: 'roleKV', // 表名称
});
}
getColumns = () => {
const { roleKV } = this.props.content;
return [
{
title: '账户',
dataIndex: 'account',
editable: true,
inputType: 'text',
width: 100,
required: true,
},
{
title: '名称',
dataIndex: 'name',
editable: true,
inputType: 'text',
width: 200,
required: true,
},
{
title: '角色',
dataIndex: 'roleid',
editable: true,
inputType: 'select',
options: roleKV && roleKV.tv,
render: (val)=> val && roleKV && roleKV.kv[val],
width: 300,
required: true,
},
]
}
save = (record, addOrUpdate) => {
if(addOrUpdate === 'add'){
ajax({
url: 'user.insertSelective',
acountRef:record.account,
...record
},
() => {
this.handleSearch();
});
}else{
ajax({
url: 'user.updateByPrimaryKeySelective',
acountRef:record.account,
...record
},
() => {
this.handleSearch();
});
}
}
onRef=(ref)=>{
this.ref= ref;
}
add = (e) => {
this.ref.handleAdd({});
}
render () {
const {
content: {user={}},
loading,
} = this.props;
const EditableFormTable = Form.create()(SmartEditableTable);
return (
<Card bordered={false}>
<Button type="primary" style={{marginBottom:'12px'}} onClick={this.add}>新增</Button>
<EditableFormTable
loading={loading}
onRef={this.onRef}
outcolumns={this.getColumns()}
data={user||{}}
save={this.save}
handleChange={this.handleSearch}/>
</Card>
);
}
}
i.树结构
import React from 'react';
import {Tree,message} from 'antdlib';
export default class Example extends React.Component {
onSelect = (value) => {
message.success(value);
}
render () {
const treeData = [
{
title: '江苏',
key: '320000',
children: [
{
title: '常州',
key: '320400',
children: [
{ title: '钟楼', key: '320404' },
{ title: '天宁', key: '320401' },
],
},
{
title: '南京',
key: '320100',
children: [
{ title: '鼓楼', key: '320101' },
{ title: '建邺', key: '320102' },
],
},
],
},
{
title: '上海',
key: '310000',
children: [
{ title: '黄埔', key: '310101' },
{ title: '长宁', key: '310104' },
],
},
];
return (
<div>
<Tree
defaultExpandAll
onSelect={this.onSelect}
treeData={treeData}
/>
</div>
);
}
}
2.2.2.业务组件
a.表单
import { Col, Row, SmartForm,Button,ajax,Card } from 'antdlib';
import React from 'react';
import { domain } from '@/domain';
import moment from 'moment';
import { connect } from 'dva';
@connect(({ content, loading }) => ({
content,
loading: loading.models.content,
}))
export default class Example extends React.Component {
state = {
confirmDirty: false,
formLayout: 'horizontal', // vertical, horizontal, inline
cols: 2,
submitName: '查询',
}
componentDidMount() {
this.searchRole();
this.handleSearch();
}
getFields = () => {
return [
{
type: 'input',
label: '输入项',
field: 'input',
required: true,
message: '请输入',
placeholder: '输入项',
// initialValue: 1,
},
];
};
handleSubmit = e => {
e.preventDefault();
this.formComp.validateFieldsAndScroll((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
}
});
};
refForm = ref => {
this.formComp = ref.getForm();
};
// 查询表单数据
handleSearch = (params={})=> {
// ajax
ajax({
url:'user.selectByPrimaryKey',
listKey:'user',
showAll:true,
...params
});
};
// 查询基础数据 ,固定写法 url: kv/namespace.sqlid
// key 表示数据库id字段
// value 表示数据库值字段
// retKey 要给返回的内容起个名字,取值的时候用这个作变量名
// 返回的内容为{ tv: [{text:'text',value:'value'}], kv: {id:'name'}}
searchRole = ()=> {
// ajax
ajax({
url: 'kv/role.selectByPrimaryKey',
key: 'id',
value: 'name',
retKey: 'roleKV',
});
};
render() {
const {formLayout,cols,submitName} = this.state;
return (
<Card>
<Row>
<Col>
<SmartForm
onRef={this.refForm}
onSubmit={this.handleSubmit}
cols={cols}
formLayout={formLayout}
fields={this.getFields()}
submitName={submitName}
>
<Row span={24} gutter={16}>
<Col span={2} offset={16}>
<Button type="primary" htmlType="submit">提交</Button>
</Col>
<Col span={2}>
<Button onClick={()=>{this.formComp.getForm().resetFields();}}>重置</Button>
</Col>
</Row>
</SmartForm>
</Col>
</Row>
</Card>
);
}
}
b.表格
import { Row, Button, Card, Dropdown, Icon, Menu, Popconfirm, SmartTable,SmartCheckbox,ajax } from 'antdlib';
import { connect } from 'dva';
import React, { Fragment, PureComponent } from 'react';
@connect(({ content, loading }) => ({
content,
loading: loading.models.content,
}))
export default class Example extends PureComponent {
state = {
selectedRowKeys: [],
selectedRows: [],
record: null,
}
componentDidMount() {
this.searchRole();
this.handleSearch();
}
getColumns = () => {
// 在此获取key value配置进行翻译
const { roleKV } = this.props.content;
return [
{
title: '数值',
dataIndex: 'id',
needTotal:true,
sorter:true,
render: (val)=> val+'元',
},
{
title: '普通值',
dataIndex: 'account',
},
{
title: '数据格式化',
dataIndex: 'name',
align: 'right',
render: val => <span style={{fontWeight:'900'}}>{val + ' 先生'}</span>,
},
{
title: '状态',
dataIndex: 'state',
render: (val,record) => {
return val === 1 ? '正常': '停用';
}
},
{
title: 'id字段显示为名称',
dataIndex: 'roleid',
filters: roleKV && roleKV.tv,
render: (val,record) => val && roleKV && roleKV.kv[val]
},
{title:'操作',align:'center',dataIndex:'',
render: (text, record, index) => (
<Fragment>
<a style={{marginRight:'8px'}} onClick={() => this.setState({visible:true,record})}>修改</a>
<Popconfirm title="确认删除吗?" onConfirm={()=>this.handleDelete(record)}>
{index > 0 && <a style={{marginRight:'8px'}} href="">删除</a>}
</Popconfirm>
</Fragment>
),
},
];
};
// 查询表格数据
handleSearch = (params={})=> {
ajax({
url:'user.selectByPrimaryKey',
listKey:'user',
showAll:true,
...params
});
}
// 查询基础数据
searchRole = ()=> {
ajax({
url: 'kv/role.selectByPrimaryKey',
key: 'id', // key名称
value: 'name', // value名称
retKey: 'roleKV', // 表名称
});
}
handleDelete = record => {
if (!record) return;
// ajax
};
handleUpdate = record => {
if (!record) return;
// ajax
};
// 下拉菜单按钮操作处理
handleMenuClick = e => {
if (!selectedRows) return;
const { selectedRows } = this.state;
switch (e.key) {
case 'remove':
break;
default:
break;
}
};
// 批量操作
handleDeleteBatch = () => {
if (!selectedRows) return;
const { selectedRows } = this.state;
// ajax
};
// 勾选行时触发
onSelectChange = (selectedRowKeys, selectedRows) => {
console.log('selectedRowKeys changed: ', selectedRowKeys);
console.log('selectedRows changed: ', selectedRows);
this.setState({ selectedRowKeys, selectedRows });
};
render() {
const {
content: { user },
content,
loading,
} = this.props;
const { selectedRows, selectedRowKeys } = this.state;
// 设置选中行选项
const rowSelection = {
selectedRowKeys, // 选中行的key字段
selectedRows, // 选中的行记录
onChange: this.onSelectChange, //选中时触发
getCheckboxProps: record => ({
name: record.account, // 根据哪个字段来判断是否能被选中
disabled: record.account === 'admin', // 当条件为true时,记录无法被选中
}),
} || {} ;
// 下拉菜单按钮
const menu = (
<Menu onClick={this.handleMenuClick} selectedKeys={[]}>
<Menu.Item key="remove">删除</Menu.Item>
<Menu.Item key="approval">批量审批</Menu.Item>
</Menu>
);
// 行展开内容渲染
const renderExpand = record => {
return (
<p>
渲染详情:可自由组织数据 {JSON.stringify(record)}
</p>
);
};
return (
<Card bordered={false} >
<div style={{marginBottom: '16px'}}>
<Button style={{marginRight:'8px'}} icon="plus" type="primary" onClick={() => {}}>
新建
</Button>
{selectedRows.length > 0 && (
<span>
<Button style={{marginRight:'8px'}}>批量操作</Button>
<Dropdown overlay={menu}>
<Button style={{marginRight:'8px'}}>
更多操作 <Icon type="down" />
</Button>
</Dropdown>
</span>
)}
</div>
<SmartTable
bordered
rowSelection={rowSelection}
expandedRowRender={renderExpand}
loading={loading}
data={user||[]}
columns={this.getColumns()}
// scroll={{ x: 800 }} x表示水平方向的宽度
handleChange={(params)=>this.handleSearch(params)}
/>
</Card>
);
}
}
2.3.前端学习-交互
2.3.1.数据绑定
import { connect } from 'dva';
import React from 'react';
@connect(({content, loading}) => ({
content,
loading: loading.models.content,
}))
export default class Example extends React.PureComponent {
render() {
const { content:{result} } = this.props;
return (
<div>
{result}
</div>
);
}
}
2.3.2.请求响应
import { message, SmartForm,ajax } from 'antdlib';
import { connect } from 'dva';
import React from 'react';
@connect(({content, loading}) => ({
content,
loading: loading.models.content,
}))
export default class Example extends React.PureComponent {
constructor(props){
super(props);
this.state = {
confirmDirty: false,
formLayout: 'horizontal', // horizontal, inline
cols: 3,
submitName: '提交',
fields : [
{
type: 'input',
label: '输入项',
field: 'input',
required: true,
message: '请输入',
placeholder: '输入项',
},
]
}
}
handleSubmit = e => {
e.preventDefault();
this.formComp.getForm().validateFieldsAndScroll((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
ajax(
{
url:'level.selectByPrimaryKey'
},
()=>{
message.success('提交form表单数据:'+JSON.stringify(values));
}
);
}
});
};
refForm = ref => {
this.formComp = ref;
}
render() {
const {loading} = this.props;
const {formLayout,cols,submitName,fields} = this.state;
return (
<div>
<SmartForm
loading={loading}
onRef={this.refForm}
onSubmit={this.handleSubmit}
cols={cols}
formLayout={formLayout}
fields={fields}
submitName={submitName && submitName}
>
</SmartForm>
</div>
);
}
}