mirror of
https://gitee.com/baidu/amis.git
synced 2024-12-01 19:38:16 +08:00
first commit
This commit is contained in:
commit
f7f071ffbf
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
# Files
|
||||
.DS_Store
|
||||
.ruby-version
|
||||
test.sass
|
||||
npm-debug.log
|
||||
|
||||
# Folders
|
||||
.idea/
|
||||
.sass-cache
|
||||
_gh_pages
|
||||
_site
|
||||
node_modules
|
||||
/dist
|
||||
/lib
|
||||
/public
|
||||
/.vscode
|
||||
/output
|
||||
/toolkit/amis-renderer
|
||||
/toolkit/output
|
||||
/coverage
|
||||
/package-lock.json
|
17
.npmignore
Normal file
17
.npmignore
Normal file
@ -0,0 +1,17 @@
|
||||
/public
|
||||
/node_moduels
|
||||
/mock
|
||||
/build
|
||||
/.vscode
|
||||
server.conf
|
||||
build.js
|
||||
BCLOUD
|
||||
fis-conf.js
|
||||
/toolkit
|
||||
/output
|
||||
/build.sh
|
||||
/types
|
||||
/__tests__
|
||||
/__mocks__
|
||||
/coverage
|
||||
/publish.sh
|
1
BCLOUD
Normal file
1
BCLOUD
Normal file
@ -0,0 +1 @@
|
||||
BUILD_SUBMITTER -x -e FIS -m baidu/amis/renderer -c "cd baidu/amis/renderer && sh build.sh" -u ./
|
13
LICENSE
Normal file
13
LICENSE
Normal file
@ -0,0 +1,13 @@
|
||||
Copyright Baidu
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
56
README.md
Normal file
56
README.md
Normal file
@ -0,0 +1,56 @@
|
||||
# amis
|
||||
|
||||
一种页面渲染器,可以直接基于特定格式的 JSON 配置将页面渲染出来,结合业务方 API 可快速完成各类管理页面的开发。
|
||||
|
||||
目前用于百度内部 [AMIS](http://amis.baidu.com) 平台,已有 100+ 部门接入使用,创建 1.2w+ 页面,欢迎大家使用和提建议。
|
||||
|
||||
## 快速开始
|
||||
|
||||
```
|
||||
# 安装项目 npm 依赖。
|
||||
npm i
|
||||
|
||||
# 开始编译,把代码产出到刚开启的服务的 webroot 目录。
|
||||
npm run dev
|
||||
|
||||
# 开启 fis3 服务,请通过 http://127.0.0.1:8888/examples/pages/simple 访问。
|
||||
npm start
|
||||
```
|
||||
|
||||
## 测试
|
||||
|
||||
```bash
|
||||
# 安装依赖
|
||||
npm i
|
||||
|
||||
# 执行测试用率
|
||||
npm test
|
||||
|
||||
# 查看测试用率覆盖率
|
||||
npm run coverage
|
||||
```
|
||||
|
||||
## 使用文档
|
||||
|
||||
为了更好的阅读体验,建议本地运行此项目后,通过 [http://127.0.0.1:8888/v2/docs/getting-started](http://127.0.0.1:8888/v2/docs/getting-started) 阅读。
|
||||
|
||||
* [快速开始](/docs/getting_started.md)
|
||||
* [高级用法](/docs/advanced.md)
|
||||
* [渲染器手册](/docs/renderers.md)
|
||||
* [如何使用](/docs/sdk.md)
|
||||
* [自定义组件](/docs/dev.md)
|
||||
* [辅助样式](/docs/style.md)
|
||||
|
||||
## 如何贡献
|
||||
|
||||
请采用 typescript 编写,所有合理的改动、新的公用渲染器、用率或者文档的提交都会被接收。
|
||||
|
||||
## 维护者
|
||||
|
||||
* [2betop](https://github.com/2betop)
|
||||
* [RickCole21](https://github.com/RickCole21)
|
||||
* [catchonme](https://github.com/catchonme)
|
||||
|
||||
## 讨论
|
||||
|
||||
欢迎提 ISSUE 讨论。
|
6
__mocks__/styleMock.js
Normal file
6
__mocks__/styleMock.js
Normal file
@ -0,0 +1,6 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* 用于 jest 加载 css 的 mock
|
||||
*/
|
||||
module.exports = {};
|
34
__tests__/__snapshots__/factory.test.tsx.snap
Normal file
34
__tests__/__snapshots__/factory.test.tsx.snap
Normal file
@ -0,0 +1,34 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`factory unregistered Renderer 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="Alert Alert--danger"
|
||||
>
|
||||
<p>
|
||||
Error: 找不到对应的渲染器
|
||||
</p>
|
||||
<p>
|
||||
Path:
|
||||
my-renderer
|
||||
</p>
|
||||
<pre>
|
||||
<code>
|
||||
{
|
||||
"type": "my-renderer",
|
||||
"a": 23
|
||||
}
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`factory:registerRenderer 1`] = `
|
||||
<div>
|
||||
<div>
|
||||
This is Custom Renderer, a is
|
||||
23
|
||||
</div>
|
||||
</div>
|
||||
`;
|
25
__tests__/components/404.test.tsx
Normal file
25
__tests__/components/404.test.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import React = require('react');
|
||||
import NotFound from '../../src/components/404';
|
||||
import * as renderer from 'react-test-renderer';
|
||||
import {render, fireEvent, cleanup} from 'react-testing-library';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
test('Components:404 default View', () => {
|
||||
const component = renderer.create(
|
||||
<NotFound />
|
||||
);
|
||||
let tree = component.toJSON();
|
||||
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
||||
test('Components:404 Custom code & messages', () => {
|
||||
const component = renderer.create(
|
||||
<NotFound code={500} description="Internal Error" />
|
||||
);
|
||||
let tree = component.toJSON();
|
||||
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
38
__tests__/components/__snapshots__/404.test.tsx.snap
Normal file
38
__tests__/components/__snapshots__/404.test.tsx.snap
Normal file
@ -0,0 +1,38 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Components:404 Custom code & messages 1`] = `
|
||||
<div
|
||||
className="container w-xxl w-auto-xs"
|
||||
>
|
||||
<div
|
||||
className="text-center m-b-lg"
|
||||
>
|
||||
<h1
|
||||
className="text-shadow text-white"
|
||||
>
|
||||
500
|
||||
</h1>
|
||||
<div
|
||||
className="text-danger"
|
||||
>
|
||||
Internal Error
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Components:404 default View 1`] = `
|
||||
<div
|
||||
className="container w-xxl w-auto-xs"
|
||||
>
|
||||
<div
|
||||
className="text-center m-b-lg"
|
||||
>
|
||||
<h1
|
||||
className="text-shadow text-white"
|
||||
>
|
||||
404
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
46
__tests__/factory.test.tsx
Normal file
46
__tests__/factory.test.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
import {
|
||||
registerRenderer,
|
||||
unRegisterRenderer,
|
||||
RendererProps,
|
||||
render as amisRender
|
||||
} from '../src/factory';
|
||||
import React = require('react');
|
||||
import {render, fireEvent, cleanup} from 'react-testing-library';
|
||||
|
||||
test('factory unregistered Renderer', () => {
|
||||
const {
|
||||
container,
|
||||
} = render(amisRender({
|
||||
type: 'my-renderer',
|
||||
a: 23
|
||||
}));
|
||||
|
||||
expect(container).toMatchSnapshot(); // not found
|
||||
});
|
||||
|
||||
test('factory:registerRenderer', () => {
|
||||
interface MyProps extends RendererProps {
|
||||
a: number;
|
||||
};
|
||||
|
||||
class MyComponent extends React.Component<MyProps> {
|
||||
render() {
|
||||
return (<div>This is Custom Renderer, a is {this.props.a}</div>);
|
||||
}
|
||||
}
|
||||
|
||||
const renderer = registerRenderer({
|
||||
component: MyComponent,
|
||||
test: /\bmy-renderer$/
|
||||
});
|
||||
|
||||
const {
|
||||
container
|
||||
} = render(amisRender({
|
||||
type: 'my-renderer',
|
||||
a: 23
|
||||
}))
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
unRegisterRenderer(renderer);
|
||||
});
|
23
__tests__/helper.tsx
Normal file
23
__tests__/helper.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import { RenderOptions } from "../src/factory";
|
||||
|
||||
// jest.useFakeTimers 会修改 global 的 setTimeout 所以需要把原始的记录下来。
|
||||
const timerFn = setTimeout;
|
||||
export function wait(duration:number, fn?:Function) {
|
||||
return new Promise((resolve) => {
|
||||
timerFn(() => {
|
||||
fn && fn();
|
||||
resolve();
|
||||
}, duration);
|
||||
});
|
||||
}
|
||||
|
||||
export function makeEnv(env?:Partial<RenderOptions>):RenderOptions {
|
||||
return {
|
||||
session: 'test-case',
|
||||
isCancel: () => false,
|
||||
notify: (msg:string) => null,
|
||||
jumpTo: (to:string) => console.info('Now should jump to ' + to),
|
||||
alert: (msg) => console.info(`Alert: ${msg}`),
|
||||
...env
|
||||
}
|
||||
}
|
118
__tests__/renderers/Action.test.tsx
Normal file
118
__tests__/renderers/Action.test.tsx
Normal file
@ -0,0 +1,118 @@
|
||||
import React = require('react');
|
||||
import Action from '../../src/renderers/Action';
|
||||
import * as renderer from 'react-test-renderer';
|
||||
import {render, fireEvent, cleanup} from 'react-testing-library';
|
||||
import '../../src/themes/default';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
test('Renderers:Action MenuItem changes class when actived & disabled', () => {
|
||||
const component = renderer.create(
|
||||
<Action isMenuItem className="a" label="123" />
|
||||
);
|
||||
let tree = component.toJSON();
|
||||
|
||||
expect(tree).toMatchSnapshot();
|
||||
|
||||
component.update(
|
||||
<Action isMenuItem className="a" label="233" active />
|
||||
);
|
||||
|
||||
tree = component.toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
|
||||
component.update(
|
||||
<Action isMenuItem className="a" label="233" active disabled />
|
||||
);
|
||||
|
||||
tree = component.toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('Renderers:Action MenuItem display icon', () => {
|
||||
const component = renderer.create(
|
||||
<Action isMenuItem className="a" label="123" />
|
||||
);
|
||||
let tree = component.toJSON();
|
||||
|
||||
expect(tree).toMatchSnapshot();
|
||||
|
||||
component.update(
|
||||
<Action isMenuItem className="a" label="123" icon="fa fa-cloud" />
|
||||
);
|
||||
|
||||
tree = component.toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('Renderers:Action [actionType = "link"] show active class', () => {
|
||||
const isCurrentUrl = (link:string) => link === "b";
|
||||
const component = renderer.create(
|
||||
<Action actionType="link" link="a" className="a" label="123" isCurrentUrl={isCurrentUrl} />
|
||||
);
|
||||
let tree = component.toJSON();
|
||||
|
||||
expect(tree).toMatchSnapshot();
|
||||
|
||||
component.update(
|
||||
<Action actionType="link" link="b" className="a" label="123" isCurrentUrl={isCurrentUrl} />
|
||||
);
|
||||
|
||||
tree = component.toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('Renderers:Action custom activeClass', () => {
|
||||
const component = renderer.create(
|
||||
<Action className="a" label="123" activeClassName="custom-active" />
|
||||
);
|
||||
let tree = component.toJSON();
|
||||
|
||||
expect(tree).toMatchSnapshot();
|
||||
|
||||
component.update(
|
||||
<Action className="a" label="123" activeClassName="custom-active" active />
|
||||
);
|
||||
|
||||
tree = component.toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('Renderers:Action onAction called?', () => {
|
||||
const onAction = jest.fn();
|
||||
const {getByText} = render(
|
||||
<Action className="a" label="123" onAction={onAction}></Action>
|
||||
);
|
||||
|
||||
fireEvent.click(getByText(/123/));
|
||||
expect(onAction).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('Renderers:Action disabled onAction called?', () => {
|
||||
const onAction = jest.fn();
|
||||
const {getByText} = render(
|
||||
<Action disabled className="a" label="123" onAction={onAction}></Action>
|
||||
);
|
||||
|
||||
fireEvent.click(getByText(/123/));
|
||||
expect(onAction).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('Renderers:Action onClick cancel onAction?', () => {
|
||||
const onAction = jest.fn();
|
||||
const onClick = jest.fn(e => e.preventDefault());
|
||||
const {getByText} = render(
|
||||
<Action
|
||||
isMenuItem
|
||||
className="a"
|
||||
label="123"
|
||||
onClick={onClick}
|
||||
onAction={onAction}>
|
||||
</Action>
|
||||
);
|
||||
|
||||
fireEvent.click(getByText(/123/));
|
||||
|
||||
expect(onClick).toHaveBeenCalled();
|
||||
expect(onAction).not.toHaveBeenCalled();
|
||||
});
|
5
__tests__/renderers/CRUD.test.tsx
Normal file
5
__tests__/renderers/CRUD.test.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
|
||||
test('todo', () => {
|
||||
|
||||
});
|
750
__tests__/renderers/Form/__snapshots__/index.test.tsx.snap
Normal file
750
__tests__/renderers/Form/__snapshots__/index.test.tsx.snap
Normal file
@ -0,0 +1,750 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Renderer:Form 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="a-Panel a-Panel--default a-Panel--form"
|
||||
>
|
||||
<div
|
||||
class="a-Panel-heading"
|
||||
>
|
||||
<h3
|
||||
class="a-Panel-title"
|
||||
>
|
||||
<span
|
||||
class="a-TplField"
|
||||
>
|
||||
The form
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="a-Panel-body"
|
||||
>
|
||||
<form
|
||||
class="a-Form a-Form--normal"
|
||||
novalidate=""
|
||||
>
|
||||
<div
|
||||
class="a-Form-item a-Form-item--normal"
|
||||
>
|
||||
<label
|
||||
class="a-Form-label"
|
||||
>
|
||||
<span>
|
||||
Label
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="a-Form-control a-TextControl"
|
||||
>
|
||||
<div
|
||||
class="a-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
name="a"
|
||||
placeholder=""
|
||||
type="text"
|
||||
value="123"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="a-Panel-btnToolbar a-Panel-footer"
|
||||
>
|
||||
<button
|
||||
class="a-Button a-Button--default"
|
||||
type="submit"
|
||||
>
|
||||
<span>
|
||||
Submit
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Renderer:Form 2`] = `
|
||||
Object {
|
||||
"config": Object {
|
||||
"errorMessage": "保存失败",
|
||||
"method": "post",
|
||||
"onSuccess": [Function],
|
||||
"successMessage": "保存成功",
|
||||
},
|
||||
"data": Object {
|
||||
"a": "123",
|
||||
},
|
||||
"method": "post",
|
||||
"url": "/api/xxx",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Renderer:Form initApi 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="a-Panel a-Panel--default a-Panel--form"
|
||||
>
|
||||
<div
|
||||
class="a-Panel-heading"
|
||||
>
|
||||
<h3
|
||||
class="a-Panel-title"
|
||||
>
|
||||
<span
|
||||
class="a-TplField"
|
||||
>
|
||||
The form
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="a-Panel-body"
|
||||
>
|
||||
<form
|
||||
class="a-Form a-Form--normal"
|
||||
novalidate=""
|
||||
>
|
||||
<div
|
||||
class="a-Form-item a-Form-item--normal"
|
||||
>
|
||||
<label
|
||||
class="a-Form-label"
|
||||
>
|
||||
<span>
|
||||
A
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="a-Form-control a-TextControl"
|
||||
>
|
||||
<div
|
||||
class="a-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
name="a"
|
||||
placeholder=""
|
||||
type="text"
|
||||
value="1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="a-Form-item a-Form-item--normal"
|
||||
>
|
||||
<label
|
||||
class="a-Form-label"
|
||||
>
|
||||
<span>
|
||||
B
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="a-Form-control a-TextControl"
|
||||
>
|
||||
<div
|
||||
class="a-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
name="b"
|
||||
placeholder=""
|
||||
type="text"
|
||||
value="2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="a-Panel-btnToolbar a-Panel-footer"
|
||||
>
|
||||
<button
|
||||
class="a-Button a-Button--primary"
|
||||
type="submit"
|
||||
>
|
||||
<span>
|
||||
提交
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Renderer:Form sendOn:true 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="a-Panel a-Panel--default a-Panel--form"
|
||||
>
|
||||
<div
|
||||
class="a-Panel-heading"
|
||||
>
|
||||
<h3
|
||||
class="a-Panel-title"
|
||||
>
|
||||
<span
|
||||
class="a-TplField"
|
||||
>
|
||||
The form
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="a-Panel-body"
|
||||
>
|
||||
<form
|
||||
class="a-Form a-Form--normal"
|
||||
novalidate=""
|
||||
>
|
||||
<div
|
||||
class="a-Form-item a-Form-item--normal"
|
||||
>
|
||||
<label
|
||||
class="a-Form-label"
|
||||
>
|
||||
<span>
|
||||
A
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="a-Form-control a-TextControl"
|
||||
>
|
||||
<div
|
||||
class="a-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
name="a"
|
||||
placeholder=""
|
||||
type="text"
|
||||
value="1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="a-Form-item a-Form-item--normal"
|
||||
>
|
||||
<label
|
||||
class="a-Form-label"
|
||||
>
|
||||
<span>
|
||||
B
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="a-Form-control a-TextControl"
|
||||
>
|
||||
<div
|
||||
class="a-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
name="b"
|
||||
placeholder=""
|
||||
type="text"
|
||||
value="2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="a-Panel-btnToolbar a-Panel-footer"
|
||||
>
|
||||
<button
|
||||
class="a-Button a-Button--primary"
|
||||
type="submit"
|
||||
>
|
||||
<span>
|
||||
提交
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Renderer:Form:onValidate 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="a-Panel a-Panel--default a-Panel--form"
|
||||
>
|
||||
<div
|
||||
class="a-Panel-heading"
|
||||
>
|
||||
<h3
|
||||
class="a-Panel-title"
|
||||
>
|
||||
<span
|
||||
class="a-TplField"
|
||||
>
|
||||
The form
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="a-Panel-body"
|
||||
>
|
||||
<form
|
||||
class="a-Form a-Form--normal"
|
||||
novalidate=""
|
||||
>
|
||||
<div
|
||||
class="a-Form-item a-Form-item--normal is-error"
|
||||
>
|
||||
<label
|
||||
class="a-Form-label"
|
||||
>
|
||||
<span>
|
||||
A
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="a-Form-control is-error a-TextControl"
|
||||
>
|
||||
<div
|
||||
class="a-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
name="a"
|
||||
placeholder=""
|
||||
type="text"
|
||||
value="1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<ul
|
||||
class="a-Form-feedback"
|
||||
>
|
||||
<li>
|
||||
a is wrong
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div
|
||||
class="a-Form-item a-Form-item--normal is-error"
|
||||
>
|
||||
<label
|
||||
class="a-Form-label"
|
||||
>
|
||||
<span>
|
||||
B
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="a-Form-control is-error a-TextControl"
|
||||
>
|
||||
<div
|
||||
class="a-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
name="b"
|
||||
placeholder=""
|
||||
type="text"
|
||||
value="2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<ul
|
||||
class="a-Form-feedback"
|
||||
>
|
||||
<li>
|
||||
b is wrong
|
||||
</li>
|
||||
<li>
|
||||
b is wrong 2
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="a-Panel-btnToolbar a-Panel-footer"
|
||||
>
|
||||
<button
|
||||
class="a-Button a-Button--default"
|
||||
type="submit"
|
||||
>
|
||||
<span>
|
||||
Submit
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Renderer:Form:onValidate 2`] = `
|
||||
Object {
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Renderer:Form:onValidate 3`] = `
|
||||
<div>
|
||||
<div
|
||||
class="a-Panel a-Panel--default a-Panel--form"
|
||||
>
|
||||
<div
|
||||
class="a-Panel-heading"
|
||||
>
|
||||
<h3
|
||||
class="a-Panel-title"
|
||||
>
|
||||
<span
|
||||
class="a-TplField"
|
||||
>
|
||||
The form
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="a-Panel-body"
|
||||
>
|
||||
<form
|
||||
class="a-Form a-Form--normal"
|
||||
novalidate=""
|
||||
>
|
||||
<div
|
||||
class="a-Form-item a-Form-item--normal"
|
||||
>
|
||||
<label
|
||||
class="a-Form-label"
|
||||
>
|
||||
<span>
|
||||
A
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="a-Form-control a-TextControl"
|
||||
>
|
||||
<div
|
||||
class="a-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
name="a"
|
||||
placeholder=""
|
||||
type="text"
|
||||
value="1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="a-Form-item a-Form-item--normal"
|
||||
>
|
||||
<label
|
||||
class="a-Form-label"
|
||||
>
|
||||
<span>
|
||||
B
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="a-Form-control a-TextControl"
|
||||
>
|
||||
<div
|
||||
class="a-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
name="b"
|
||||
placeholder=""
|
||||
type="text"
|
||||
value="2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="a-Panel-btnToolbar a-Panel-footer"
|
||||
>
|
||||
<button
|
||||
class="a-Button a-Button--default"
|
||||
type="submit"
|
||||
>
|
||||
<span>
|
||||
Submit
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Renderer:Form:onValidate 4`] = `
|
||||
Object {
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Renderer:Form:remoteValidate 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="a-Panel a-Panel--default a-Panel--form"
|
||||
>
|
||||
<div
|
||||
class="a-Panel-heading"
|
||||
>
|
||||
<h3
|
||||
class="a-Panel-title"
|
||||
>
|
||||
<span
|
||||
class="a-TplField"
|
||||
>
|
||||
The form
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="a-Panel-body"
|
||||
>
|
||||
<form
|
||||
class="a-Form a-Form--normal"
|
||||
novalidate=""
|
||||
>
|
||||
<div
|
||||
class="a-Form-item a-Form-item--normal is-error"
|
||||
>
|
||||
<label
|
||||
class="a-Form-label"
|
||||
>
|
||||
<span>
|
||||
Label
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="a-Form-control is-error a-TextControl"
|
||||
>
|
||||
<div
|
||||
class="a-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
name="a"
|
||||
placeholder=""
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<ul
|
||||
class="a-Form-feedback"
|
||||
>
|
||||
<li>
|
||||
这个字段服务端验证失败
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="a-Panel-btnToolbar a-Panel-footer"
|
||||
>
|
||||
<button
|
||||
class="a-Button a-Button--default"
|
||||
type="submit"
|
||||
>
|
||||
<span>
|
||||
Submit
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Renderer:Form:valdiate 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="a-Panel a-Panel--default a-Panel--form"
|
||||
>
|
||||
<div
|
||||
class="a-Panel-heading"
|
||||
>
|
||||
<h3
|
||||
class="a-Panel-title"
|
||||
>
|
||||
<span
|
||||
class="a-TplField"
|
||||
>
|
||||
The form
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="a-Panel-body"
|
||||
>
|
||||
<form
|
||||
class="a-Form a-Form--normal"
|
||||
novalidate=""
|
||||
>
|
||||
<div
|
||||
class="a-Form-item a-Form-item--normal is-error is-required"
|
||||
>
|
||||
<label
|
||||
class="a-Form-label"
|
||||
>
|
||||
<span>
|
||||
Label
|
||||
<span
|
||||
class="a-Form-star"
|
||||
>
|
||||
*
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="a-Form-control is-error a-TextControl"
|
||||
>
|
||||
<div
|
||||
class="a-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
name="a"
|
||||
placeholder=""
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<ul
|
||||
class="a-Form-feedback"
|
||||
>
|
||||
<li>
|
||||
这是必填项
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="a-Panel-btnToolbar a-Panel-footer"
|
||||
>
|
||||
<button
|
||||
class="a-Button a-Button--default"
|
||||
type="submit"
|
||||
>
|
||||
<span>
|
||||
Submit
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Renderer:Form:valdiate 2`] = `
|
||||
<div>
|
||||
<div
|
||||
class="a-Panel a-Panel--default a-Panel--form"
|
||||
>
|
||||
<div
|
||||
class="a-Panel-heading"
|
||||
>
|
||||
<h3
|
||||
class="a-Panel-title"
|
||||
>
|
||||
<span
|
||||
class="a-TplField"
|
||||
>
|
||||
The form
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="a-Panel-body"
|
||||
>
|
||||
<form
|
||||
class="a-Form a-Form--normal"
|
||||
novalidate=""
|
||||
>
|
||||
<div
|
||||
class="a-Form-item a-Form-item--normal is-required"
|
||||
>
|
||||
<label
|
||||
class="a-Form-label"
|
||||
>
|
||||
<span>
|
||||
Label
|
||||
<span
|
||||
class="a-Form-star"
|
||||
>
|
||||
*
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="a-Form-control a-TextControl"
|
||||
>
|
||||
<div
|
||||
class="a-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
name="a"
|
||||
placeholder=""
|
||||
type="text"
|
||||
value="123"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="a-Panel-btnToolbar a-Panel-footer"
|
||||
>
|
||||
<button
|
||||
class="a-Button a-Button--default"
|
||||
type="submit"
|
||||
>
|
||||
<span>
|
||||
Submit
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Renderer:Form:valdiate 3`] = `
|
||||
Object {
|
||||
"a": "123",
|
||||
}
|
||||
`;
|
456
__tests__/renderers/Form/index.test.tsx
Normal file
456
__tests__/renderers/Form/index.test.tsx
Normal file
@ -0,0 +1,456 @@
|
||||
import React = require('react');
|
||||
import PageRenderer from '../../../src/renderers/Form';
|
||||
import * as renderer from 'react-test-renderer';
|
||||
import {render, fireEvent, cleanup, getByText} from 'react-testing-library';
|
||||
import '../../../src/themes/default';
|
||||
import {
|
||||
render as amisRender
|
||||
} from '../../../src/index';
|
||||
import { wait, makeEnv } from '../../helper';
|
||||
import { clearStoresCache } from '../../../src/factory';
|
||||
import {
|
||||
createMemoryHistory
|
||||
} from 'history';
|
||||
|
||||
// mock getComputedStyle
|
||||
Object.defineProperty(window, 'getComputedStyle', {
|
||||
value: () => ({
|
||||
getPropertyValue: (prop) => {
|
||||
return '';
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
clearStoresCache();
|
||||
});
|
||||
|
||||
|
||||
test('Renderer:Form', async () => {
|
||||
const resultPromise = Promise.resolve({
|
||||
data: {
|
||||
status: 0,
|
||||
msg: 'ok'
|
||||
}
|
||||
});
|
||||
const fetcher = jest.fn().mockImplementation(() => resultPromise);
|
||||
const {
|
||||
container,
|
||||
getByText
|
||||
} = render(amisRender({
|
||||
type: 'form',
|
||||
api: '/api/xxx',
|
||||
controls: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'a',
|
||||
label: 'Label',
|
||||
value: '123'
|
||||
}
|
||||
],
|
||||
title: 'The form',
|
||||
actions: [
|
||||
{
|
||||
type: 'submit',
|
||||
label: 'Submit'
|
||||
}
|
||||
]
|
||||
}, {}, makeEnv({
|
||||
fetcher
|
||||
})));
|
||||
expect(container).toMatchSnapshot();
|
||||
|
||||
fireEvent.click(getByText('Submit'));
|
||||
await resultPromise;
|
||||
await wait(100);
|
||||
|
||||
expect(fetcher).toHaveBeenCalled();
|
||||
expect(fetcher.mock.calls[0][0]).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
||||
test('Renderer:Form:valdiate', async () => {
|
||||
const notify = jest.fn();
|
||||
const onSubmit = jest.fn();
|
||||
const {
|
||||
container,
|
||||
getByText,
|
||||
} = render(amisRender({
|
||||
type: 'form',
|
||||
controls: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'a',
|
||||
required: true,
|
||||
label: 'Label'
|
||||
}
|
||||
],
|
||||
title: 'The form',
|
||||
actions: [
|
||||
{
|
||||
type: 'submit',
|
||||
label: 'Submit'
|
||||
}
|
||||
]
|
||||
}, {
|
||||
onSubmit
|
||||
}, makeEnv({
|
||||
notify
|
||||
})));
|
||||
|
||||
fireEvent.click(getByText('Submit'));
|
||||
expect(container).toMatchSnapshot();
|
||||
expect(onSubmit).not.toHaveBeenCalled();
|
||||
|
||||
await wait(100);
|
||||
expect(notify).toHaveBeenCalledWith('error', '表单验证失败,请仔细检查');
|
||||
|
||||
const input = container.querySelector('input[name=a]');
|
||||
expect(input).toBeTruthy();
|
||||
fireEvent.change(input, {
|
||||
target: {
|
||||
value: '123'
|
||||
}
|
||||
});
|
||||
await wait(300); // 有 250 秒左右的节流
|
||||
fireEvent.click(getByText('Submit'));
|
||||
expect(container).toMatchSnapshot();
|
||||
|
||||
await wait(100);
|
||||
expect(onSubmit).toHaveBeenCalled();
|
||||
expect(onSubmit.mock.calls[0][0]).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
||||
test('Renderer:Form:remoteValidate', async () => {
|
||||
const notify = jest.fn();
|
||||
const fetcher = jest.fn().mockImplementation(() => Promise.resolve({
|
||||
data: {
|
||||
status: 422,
|
||||
msg: '服务端验证失败',
|
||||
errors: {
|
||||
a: '这个字段服务端验证失败'
|
||||
}
|
||||
}
|
||||
}));
|
||||
const {
|
||||
container,
|
||||
getByText,
|
||||
} = render(amisRender({
|
||||
type: 'form',
|
||||
api: '/api/xxx',
|
||||
controls: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'a',
|
||||
label: 'Label'
|
||||
}
|
||||
],
|
||||
title: 'The form',
|
||||
actions: [
|
||||
{
|
||||
type: 'submit',
|
||||
label: 'Submit'
|
||||
}
|
||||
]
|
||||
}, {
|
||||
}, makeEnv({
|
||||
notify,
|
||||
fetcher
|
||||
})));
|
||||
|
||||
fireEvent.click(getByText('Submit'));
|
||||
await wait(100);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('Renderer:Form:onValidate', async () => {
|
||||
const notify = jest.fn();
|
||||
const onSubmit = jest.fn();
|
||||
const onValidate = jest.fn()
|
||||
.mockImplementationOnce(() => ({
|
||||
a: 'a is wrong',
|
||||
b: [
|
||||
'b is wrong',
|
||||
'b is wrong 2'
|
||||
]
|
||||
}))
|
||||
.mockImplementationOnce(() => ({
|
||||
a: '',
|
||||
b: ''
|
||||
}))
|
||||
const {
|
||||
container,
|
||||
getByText,
|
||||
} = render(amisRender({
|
||||
type: 'form',
|
||||
controls: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'a',
|
||||
label: 'A',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'b',
|
||||
label: 'B',
|
||||
value: 2
|
||||
}
|
||||
],
|
||||
title: 'The form',
|
||||
actions: [
|
||||
{
|
||||
type: 'submit',
|
||||
label: 'Submit'
|
||||
}
|
||||
]
|
||||
}, {
|
||||
onSubmit,
|
||||
onValidate
|
||||
}, makeEnv({
|
||||
notify
|
||||
})));
|
||||
|
||||
fireEvent.click(getByText('Submit'));
|
||||
await wait(100);
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
expect(onSubmit).not.toHaveBeenCalled();
|
||||
expect(onValidate).toHaveBeenCalled();
|
||||
expect(onValidate.mock.calls[0][0]).toMatchSnapshot();
|
||||
|
||||
await wait(100);
|
||||
expect(notify).toHaveBeenCalledWith('error', '表单验证失败,请仔细检查');
|
||||
|
||||
fireEvent.click(getByText('Submit'));
|
||||
await wait(100);
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
expect(onSubmit).toHaveBeenCalled();
|
||||
expect(onSubmit.mock.calls[0][0]).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('Renderer:Form initApi', async () => {
|
||||
const notify = jest.fn();
|
||||
let p0;
|
||||
const fetcher = jest.fn().mockImplementation(() => p0 = Promise.resolve({
|
||||
data: {
|
||||
status: 0,
|
||||
data: {
|
||||
a: 1,
|
||||
b: 2
|
||||
}
|
||||
}
|
||||
}));
|
||||
const {
|
||||
container,
|
||||
getByText,
|
||||
} = render(amisRender({
|
||||
type: 'form',
|
||||
initApi: '/api/xxx',
|
||||
controls: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'a',
|
||||
label: 'A'
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'b',
|
||||
label: 'B'
|
||||
}
|
||||
],
|
||||
title: 'The form'
|
||||
}, {
|
||||
}, makeEnv({
|
||||
notify,
|
||||
fetcher
|
||||
})));
|
||||
|
||||
// fetch 调用了,所有 initApi 接口调用了
|
||||
expect(fetcher).toHaveBeenCalled();
|
||||
await p0;
|
||||
|
||||
// 通过 snapshot 可断定 initApi 返回值已经作用到了表单项上。
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('Renderer:Form initFetch:false', async () => {
|
||||
const notify = jest.fn();
|
||||
const fetcher = jest.fn().mockImplementation(() => Promise.resolve({
|
||||
data: {
|
||||
status: 0,
|
||||
data: {
|
||||
a: 1,
|
||||
b: 2
|
||||
}
|
||||
}
|
||||
}));
|
||||
const {
|
||||
container,
|
||||
getByText,
|
||||
} = render(amisRender({
|
||||
type: 'form',
|
||||
initApi: '/api/xxx',
|
||||
initFetch: false,
|
||||
controls: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'a',
|
||||
label: 'A'
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'b',
|
||||
label: 'B'
|
||||
}
|
||||
],
|
||||
title: 'The form'
|
||||
}, {
|
||||
}, makeEnv({
|
||||
notify,
|
||||
fetcher
|
||||
})));
|
||||
|
||||
expect(fetcher).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('Renderer:Form initFetchOn:false', async () => {
|
||||
const notify = jest.fn();
|
||||
const fetcher = jest.fn().mockImplementation(() => Promise.resolve({
|
||||
data: {
|
||||
status: 0,
|
||||
data: {
|
||||
a: 1,
|
||||
b: 2
|
||||
}
|
||||
}
|
||||
}));
|
||||
const {
|
||||
container,
|
||||
getByText,
|
||||
} = render(amisRender({
|
||||
type: 'form',
|
||||
initApi: '/api/xxx',
|
||||
initFetchOn: 'this.goFetch',
|
||||
controls: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'a',
|
||||
label: 'A'
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'b',
|
||||
label: 'B'
|
||||
}
|
||||
],
|
||||
title: 'The form'
|
||||
}, {
|
||||
data: {
|
||||
goFetch: false
|
||||
}
|
||||
}, makeEnv({
|
||||
notify,
|
||||
fetcher
|
||||
})));
|
||||
|
||||
expect(fetcher).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('Renderer:Form sendOn:false', async () => {
|
||||
const notify = jest.fn();
|
||||
const fetcher = jest.fn().mockImplementation(() => Promise.resolve({
|
||||
data: {
|
||||
status: 0,
|
||||
data: {
|
||||
a: 1,
|
||||
b: 2
|
||||
}
|
||||
}
|
||||
}));
|
||||
const {
|
||||
container,
|
||||
getByText,
|
||||
} = render(amisRender({
|
||||
type: 'form',
|
||||
initApi: {
|
||||
method: 'get',
|
||||
url: '/api/xxx',
|
||||
sendOn: 'this.goFetch'
|
||||
},
|
||||
controls: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'a',
|
||||
label: 'A'
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'b',
|
||||
label: 'B'
|
||||
}
|
||||
],
|
||||
title: 'The form'
|
||||
}, {
|
||||
data: {
|
||||
goFetch: false
|
||||
}
|
||||
}, makeEnv({
|
||||
notify,
|
||||
fetcher
|
||||
})));
|
||||
|
||||
expect(fetcher).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('Renderer:Form sendOn:true', async () => {
|
||||
const notify = jest.fn();
|
||||
let p0;
|
||||
const fetcher = jest.fn().mockImplementation(() => p0 = Promise.resolve({
|
||||
data: {
|
||||
status: 0,
|
||||
data: {
|
||||
a: 1,
|
||||
b: 2
|
||||
}
|
||||
}
|
||||
}));
|
||||
const {
|
||||
container,
|
||||
getByText,
|
||||
} = render(amisRender({
|
||||
type: 'form',
|
||||
initApi: {
|
||||
method: 'get',
|
||||
url: '/api/xxx',
|
||||
sendOn: 'this.goFetch'
|
||||
},
|
||||
controls: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'a',
|
||||
label: 'A'
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'b',
|
||||
label: 'B'
|
||||
}
|
||||
],
|
||||
title: 'The form'
|
||||
}, {
|
||||
data: {
|
||||
goFetch: true
|
||||
}
|
||||
}, makeEnv({
|
||||
notify,
|
||||
fetcher
|
||||
})));
|
||||
|
||||
expect(fetcher).toHaveBeenCalled();
|
||||
await p0;
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
1127
__tests__/renderers/Page.test.tsx
Normal file
1127
__tests__/renderers/Page.test.tsx
Normal file
File diff suppressed because it is too large
Load Diff
1302
__tests__/renderers/Wizard.test.tsx
Normal file
1302
__tests__/renderers/Wizard.test.tsx
Normal file
File diff suppressed because it is too large
Load Diff
97
__tests__/renderers/__snapshots__/Action.test.tsx.snap
Normal file
97
__tests__/renderers/__snapshots__/Action.test.tsx.snap
Normal file
@ -0,0 +1,97 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Renderers:Action [actionType = "link"] show active class 1`] = `
|
||||
<button
|
||||
className="a-Button a-Button--default a"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
123
|
||||
</span>
|
||||
</button>
|
||||
`;
|
||||
|
||||
exports[`Renderers:Action [actionType = "link"] show active class 2`] = `
|
||||
<button
|
||||
className="a-Button a-Button--default a is-active"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
123
|
||||
</span>
|
||||
</button>
|
||||
`;
|
||||
|
||||
exports[`Renderers:Action MenuItem changes class when actived & disabled 1`] = `
|
||||
<a
|
||||
className="a"
|
||||
onClick={[Function]}
|
||||
>
|
||||
123
|
||||
</a>
|
||||
`;
|
||||
|
||||
exports[`Renderers:Action MenuItem changes class when actived & disabled 2`] = `
|
||||
<a
|
||||
className="a is-active"
|
||||
onClick={[Function]}
|
||||
>
|
||||
233
|
||||
</a>
|
||||
`;
|
||||
|
||||
exports[`Renderers:Action MenuItem changes class when actived & disabled 3`] = `
|
||||
<a
|
||||
className="a is-active is-disabled"
|
||||
onClick={[Function]}
|
||||
>
|
||||
233
|
||||
</a>
|
||||
`;
|
||||
|
||||
exports[`Renderers:Action MenuItem display icon 1`] = `
|
||||
<a
|
||||
className="a"
|
||||
onClick={[Function]}
|
||||
>
|
||||
123
|
||||
</a>
|
||||
`;
|
||||
|
||||
exports[`Renderers:Action MenuItem display icon 2`] = `
|
||||
<a
|
||||
className="a"
|
||||
onClick={[Function]}
|
||||
>
|
||||
123
|
||||
<i
|
||||
className="a-Button-icon fa fa-cloud"
|
||||
/>
|
||||
</a>
|
||||
`;
|
||||
|
||||
exports[`Renderers:Action custom activeClass 1`] = `
|
||||
<button
|
||||
className="a-Button a-Button--default a"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
123
|
||||
</span>
|
||||
</button>
|
||||
`;
|
||||
|
||||
exports[`Renderers:Action custom activeClass 2`] = `
|
||||
<button
|
||||
className="a-Button a-Button--default a custom-active"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
123
|
||||
</span>
|
||||
</button>
|
||||
`;
|
1956
__tests__/renderers/__snapshots__/Page.test.tsx.snap
Normal file
1956
__tests__/renderers/__snapshots__/Page.test.tsx.snap
Normal file
File diff suppressed because it is too large
Load Diff
2053
__tests__/renderers/__snapshots__/Wizard.test.tsx.snap
Normal file
2053
__tests__/renderers/__snapshots__/Wizard.test.tsx.snap
Normal file
File diff suppressed because it is too large
Load Diff
128
__tests__/stores/__snapshots__/index.test.ts.snap
Normal file
128
__tests__/stores/__snapshots__/index.test.ts.snap
Normal file
@ -0,0 +1,128 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`store:index 1`] = `
|
||||
Object {
|
||||
"storeType": "RendererStore",
|
||||
"stores": Object {},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`store:index 2`] = `
|
||||
Object {
|
||||
"storeType": "RendererStore",
|
||||
"stores": Object {
|
||||
"1": Object {
|
||||
"action": undefined,
|
||||
"busying": false,
|
||||
"checking": false,
|
||||
"data": Object {},
|
||||
"dialogData": undefined,
|
||||
"dialogOpen": false,
|
||||
"drawerData": undefined,
|
||||
"drawerOpen": false,
|
||||
"error": false,
|
||||
"fetching": false,
|
||||
"hasRemoteData": false,
|
||||
"id": "1",
|
||||
"initializing": false,
|
||||
"msg": "",
|
||||
"parentId": "",
|
||||
"path": "/xxx",
|
||||
"pristine": Object {},
|
||||
"saving": false,
|
||||
"schema": null,
|
||||
"schemaKey": "",
|
||||
"storeType": "ServiceStore",
|
||||
"updatedAt": 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`store:index 3`] = `
|
||||
Object {
|
||||
"storeType": "RendererStore",
|
||||
"stores": Object {
|
||||
"1": Object {
|
||||
"action": undefined,
|
||||
"busying": false,
|
||||
"checking": false,
|
||||
"data": Object {},
|
||||
"dialogData": undefined,
|
||||
"dialogOpen": false,
|
||||
"drawerData": undefined,
|
||||
"drawerOpen": false,
|
||||
"error": false,
|
||||
"fetching": false,
|
||||
"hasRemoteData": false,
|
||||
"id": "1",
|
||||
"initializing": false,
|
||||
"msg": "",
|
||||
"parentId": "",
|
||||
"path": "/xxx",
|
||||
"pristine": Object {},
|
||||
"saving": false,
|
||||
"schema": null,
|
||||
"schemaKey": "",
|
||||
"storeType": "ServiceStore",
|
||||
"updatedAt": 0,
|
||||
},
|
||||
"2": Object {
|
||||
"action": undefined,
|
||||
"busying": false,
|
||||
"checking": false,
|
||||
"data": Object {},
|
||||
"dialogData": undefined,
|
||||
"dialogOpen": false,
|
||||
"drawerData": undefined,
|
||||
"drawerOpen": false,
|
||||
"error": false,
|
||||
"fetching": false,
|
||||
"hasRemoteData": false,
|
||||
"id": "2",
|
||||
"initializing": false,
|
||||
"msg": "",
|
||||
"parentId": "1",
|
||||
"path": "/yyy",
|
||||
"pristine": Object {},
|
||||
"saving": false,
|
||||
"schema": null,
|
||||
"schemaKey": "",
|
||||
"storeType": "ServiceStore",
|
||||
"updatedAt": 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`store:index 4`] = `
|
||||
Object {
|
||||
"storeType": "RendererStore",
|
||||
"stores": Object {
|
||||
"1": Object {
|
||||
"action": undefined,
|
||||
"busying": false,
|
||||
"checking": false,
|
||||
"data": Object {},
|
||||
"dialogData": undefined,
|
||||
"dialogOpen": false,
|
||||
"drawerData": undefined,
|
||||
"drawerOpen": false,
|
||||
"error": false,
|
||||
"fetching": false,
|
||||
"hasRemoteData": false,
|
||||
"id": "1",
|
||||
"initializing": false,
|
||||
"msg": "",
|
||||
"parentId": "",
|
||||
"path": "/xxx",
|
||||
"pristine": Object {},
|
||||
"saving": false,
|
||||
"schema": null,
|
||||
"schemaKey": "",
|
||||
"storeType": "ServiceStore",
|
||||
"updatedAt": 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
`;
|
138
__tests__/stores/__snapshots__/service.test.ts.snap
Normal file
138
__tests__/stores/__snapshots__/service.test.ts.snap
Normal file
@ -0,0 +1,138 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`store:ServiceStore 1`] = `
|
||||
Object {
|
||||
"action": undefined,
|
||||
"busying": false,
|
||||
"checking": false,
|
||||
"data": Object {},
|
||||
"dialogData": undefined,
|
||||
"dialogOpen": false,
|
||||
"drawerData": undefined,
|
||||
"drawerOpen": false,
|
||||
"error": false,
|
||||
"fetching": false,
|
||||
"hasRemoteData": false,
|
||||
"id": "1",
|
||||
"initializing": false,
|
||||
"msg": "",
|
||||
"parentId": "",
|
||||
"path": "",
|
||||
"pristine": Object {},
|
||||
"saving": false,
|
||||
"schema": null,
|
||||
"schemaKey": "",
|
||||
"storeType": "ServiceStore",
|
||||
"updatedAt": 0,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`store:ServiceStore fetchInitData failed 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"action": undefined,
|
||||
"busying": false,
|
||||
"checking": false,
|
||||
"data": Object {},
|
||||
"dialogData": undefined,
|
||||
"dialogOpen": false,
|
||||
"drawerData": undefined,
|
||||
"drawerOpen": false,
|
||||
"error": false,
|
||||
"fetching": true,
|
||||
"hasRemoteData": false,
|
||||
"id": "1",
|
||||
"initializing": false,
|
||||
"msg": "",
|
||||
"parentId": "",
|
||||
"path": "",
|
||||
"pristine": Object {},
|
||||
"saving": false,
|
||||
"schema": null,
|
||||
"schemaKey": "",
|
||||
"storeType": "ServiceStore",
|
||||
"updatedAt": 0,
|
||||
},
|
||||
Object {
|
||||
"action": undefined,
|
||||
"busying": false,
|
||||
"checking": false,
|
||||
"data": Object {},
|
||||
"dialogData": undefined,
|
||||
"dialogOpen": false,
|
||||
"drawerData": undefined,
|
||||
"drawerOpen": false,
|
||||
"error": false,
|
||||
"fetching": false,
|
||||
"hasRemoteData": false,
|
||||
"id": "1",
|
||||
"initializing": false,
|
||||
"msg": "",
|
||||
"parentId": "",
|
||||
"path": "",
|
||||
"pristine": Object {},
|
||||
"saving": false,
|
||||
"schema": null,
|
||||
"schemaKey": "",
|
||||
"storeType": "ServiceStore",
|
||||
"updatedAt": 0,
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`store:ServiceStore fetchInitData success 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"action": undefined,
|
||||
"busying": false,
|
||||
"checking": false,
|
||||
"data": Object {},
|
||||
"dialogData": undefined,
|
||||
"dialogOpen": false,
|
||||
"drawerData": undefined,
|
||||
"drawerOpen": false,
|
||||
"error": false,
|
||||
"fetching": true,
|
||||
"hasRemoteData": false,
|
||||
"id": "1",
|
||||
"initializing": false,
|
||||
"msg": "",
|
||||
"parentId": "",
|
||||
"path": "",
|
||||
"pristine": Object {},
|
||||
"saving": false,
|
||||
"schema": null,
|
||||
"schemaKey": "",
|
||||
"storeType": "ServiceStore",
|
||||
},
|
||||
Object {
|
||||
"action": undefined,
|
||||
"busying": false,
|
||||
"checking": false,
|
||||
"data": Object {
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
},
|
||||
"dialogData": undefined,
|
||||
"dialogOpen": false,
|
||||
"drawerData": undefined,
|
||||
"drawerOpen": false,
|
||||
"error": false,
|
||||
"fetching": false,
|
||||
"hasRemoteData": true,
|
||||
"id": "1",
|
||||
"initializing": false,
|
||||
"msg": "undefined",
|
||||
"parentId": "",
|
||||
"path": "",
|
||||
"pristine": Object {
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
},
|
||||
"saving": false,
|
||||
"schema": null,
|
||||
"schemaKey": "",
|
||||
"storeType": "ServiceStore",
|
||||
},
|
||||
]
|
||||
`;
|
54
__tests__/stores/index.test.ts
Normal file
54
__tests__/stores/index.test.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import {
|
||||
RendererStore
|
||||
} from '../../src/store/index';
|
||||
import { getSnapshot, getEnv } from 'mobx-state-tree';
|
||||
import { ServiceStore } from '../../src/store/service';
|
||||
|
||||
test('store:index', () => {
|
||||
const store = RendererStore.create({});
|
||||
|
||||
expect(getSnapshot(store)).toMatchSnapshot();
|
||||
|
||||
const serviceStore = ServiceStore.create({
|
||||
path: '/xxx',
|
||||
storeType: ServiceStore.name,
|
||||
id: '1'
|
||||
});
|
||||
store.addStore(serviceStore);
|
||||
|
||||
expect(getSnapshot(store)).toMatchSnapshot();
|
||||
|
||||
const serviceStore2 = ServiceStore.create({
|
||||
path: '/yyy',
|
||||
storeType: ServiceStore.name,
|
||||
id: '2',
|
||||
parentId: '1'
|
||||
});
|
||||
|
||||
store.addStore(serviceStore2);
|
||||
|
||||
expect(getSnapshot(store)).toMatchSnapshot();
|
||||
|
||||
expect(serviceStore2.parentStore).toEqual(serviceStore);
|
||||
|
||||
store.removeStore(serviceStore2);
|
||||
expect(getSnapshot(store)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
||||
test('store:index env', () => {
|
||||
const fetcher = jest.fn();
|
||||
const notify = jest.fn();
|
||||
const isCancel = jest.fn(() => false);
|
||||
|
||||
|
||||
const store = RendererStore.create({}, {
|
||||
fetcher,
|
||||
notify,
|
||||
isCancel
|
||||
});
|
||||
|
||||
expect(store.fetcher).toBe(fetcher);
|
||||
expect(store.notify).toBe(notify);
|
||||
expect(store.isCancel).toBe(isCancel);
|
||||
});
|
73
__tests__/stores/service.test.ts
Normal file
73
__tests__/stores/service.test.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import { getSnapshot, getEnv, onSnapshot } from 'mobx-state-tree';
|
||||
import { ServiceStore } from '../../src/store/service';
|
||||
import { RendererStore } from '../../src/store';
|
||||
import omit = require('lodash/omit');
|
||||
|
||||
|
||||
test('store:ServiceStore', () => {
|
||||
const store = ServiceStore.create({
|
||||
id: '1',
|
||||
storeType: ServiceStore.name
|
||||
});
|
||||
|
||||
expect(getSnapshot(store)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
||||
test('store:ServiceStore fetchInitData success', async () => {
|
||||
const fetcher = jest.fn().mockImplementationOnce(() => Promise.resolve({
|
||||
ok: true,
|
||||
data: {
|
||||
a: 1,
|
||||
b: 2
|
||||
}
|
||||
}));
|
||||
const mainStore = RendererStore.create({}, {
|
||||
fetcher
|
||||
});
|
||||
const states:Array<any> = [];
|
||||
|
||||
|
||||
const store = ServiceStore.create({
|
||||
id: '1',
|
||||
storeType: ServiceStore.name
|
||||
});
|
||||
mainStore.addStore(store);
|
||||
|
||||
onSnapshot(store, (snapshot) => states.push(snapshot));
|
||||
|
||||
await store.fetchInitData('/api/xxx');
|
||||
|
||||
const ignoreUdatedAt = states.map(snapshot => omit(snapshot, ['updatedAt']));
|
||||
expect(ignoreUdatedAt).toMatchSnapshot();
|
||||
|
||||
expect(states.length).toBe(2);
|
||||
expect(states[1].updatedAt).not.toEqual(states[0].updatedAt);
|
||||
});
|
||||
|
||||
test('store:ServiceStore fetchInitData failed', async () => {
|
||||
const fetcher = jest.fn().mockImplementationOnce(() => Promise.reject('Network Error'));
|
||||
const notify = jest.fn();
|
||||
const isCancel = jest.fn(() => false);
|
||||
const mainStore = RendererStore.create({}, {
|
||||
fetcher,
|
||||
notify,
|
||||
isCancel
|
||||
});
|
||||
const states:Array<any> = [];
|
||||
|
||||
|
||||
const store = ServiceStore.create({
|
||||
id: '1',
|
||||
storeType: ServiceStore.name
|
||||
});
|
||||
mainStore.addStore(store);
|
||||
|
||||
onSnapshot(store, (snapshot) => states.push(snapshot));
|
||||
|
||||
await store.fetchInitData('/api/xxx');
|
||||
expect(states).toMatchSnapshot();
|
||||
expect(notify).toHaveBeenCalled();
|
||||
expect(notify).toHaveBeenLastCalledWith("error", "Network Error");
|
||||
expect(isCancel).toHaveBeenCalled();
|
||||
});
|
146
__tests__/utils/api.test.ts
Normal file
146
__tests__/utils/api.test.ts
Normal file
@ -0,0 +1,146 @@
|
||||
import {
|
||||
buildApi,
|
||||
isApiOutdated
|
||||
} from '../../src/utils/api';
|
||||
|
||||
test('api:buildApi', () => {
|
||||
expect(buildApi('/api/xxx')).toMatchObject({
|
||||
method: 'get',
|
||||
url: '/api/xxx'
|
||||
});
|
||||
|
||||
expect(buildApi('get:/api/xxx')).toMatchObject({
|
||||
method: 'get',
|
||||
url: '/api/xxx'
|
||||
});
|
||||
|
||||
expect(buildApi('delete:/api/xxx')).toMatchObject({
|
||||
method: 'delete',
|
||||
url: '/api/xxx'
|
||||
});
|
||||
|
||||
|
||||
expect(buildApi('/api/xxx?a=${a}&b=${b}', {
|
||||
a: 1,
|
||||
b: 2
|
||||
})).toMatchObject({
|
||||
method: 'get',
|
||||
url: '/api/xxx?a=1&b=2'
|
||||
});
|
||||
|
||||
expect(buildApi({
|
||||
method: 'get',
|
||||
url: '/api/xxx?a=${a}&b=${b}'
|
||||
}, {
|
||||
a: 1,
|
||||
b: 2
|
||||
})).toMatchObject({
|
||||
method: 'get',
|
||||
url: '/api/xxx?a=1&b=2'
|
||||
});
|
||||
|
||||
expect(buildApi('/api/xxx?a=${a}', {
|
||||
a: '&'
|
||||
})).toMatchObject({
|
||||
method: 'get',
|
||||
url: '/api/xxx?a=' + encodeURIComponent('&')
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
test('api:buildApi:dataMapping', () => {
|
||||
expect(buildApi({
|
||||
method: 'post',
|
||||
url: '/api/xxx',
|
||||
data: {
|
||||
a: 1,
|
||||
b: '${b}'
|
||||
}
|
||||
}, {
|
||||
b: 2
|
||||
})).toMatchObject({
|
||||
method: 'post',
|
||||
url: '/api/xxx',
|
||||
data: {
|
||||
a: 1,
|
||||
b: 2
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
expect(buildApi({
|
||||
method: 'post',
|
||||
url: '/api/xxx',
|
||||
headers: {
|
||||
a: 1,
|
||||
b: '${b}'
|
||||
}
|
||||
}, {
|
||||
b: 2
|
||||
})).toMatchObject({
|
||||
method: 'post',
|
||||
url: '/api/xxx',
|
||||
headers: {
|
||||
a: 1,
|
||||
b: 2
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('api:buildApi:autoAppend', () => {
|
||||
expect(buildApi({
|
||||
method: 'get',
|
||||
url: '/api/xxx',
|
||||
}, {
|
||||
a: 1,
|
||||
b: 2
|
||||
}, {
|
||||
autoAppend: true
|
||||
})).toMatchObject({
|
||||
method: 'get',
|
||||
url: '/api/xxx?a=1&b=2'
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
test('api:isApiOutdated', () => {
|
||||
expect(isApiOutdated('/api/xxx?a=${a}', '/api/xxx?a=${a}', {
|
||||
a: 1,
|
||||
b: 0
|
||||
}, {
|
||||
a: 1,
|
||||
b: 2,
|
||||
})).toBeFalsy();
|
||||
|
||||
expect(isApiOutdated('/api/xxx?a=${a}', '/api/xxx?a=${a}', {
|
||||
a: 1,
|
||||
b: 0
|
||||
}, {
|
||||
a: 2,
|
||||
b: 2,
|
||||
})).toBeTruthy();
|
||||
|
||||
|
||||
expect(isApiOutdated('/api/xxx', '/api/xxx', {
|
||||
a: 1,
|
||||
b: 0
|
||||
}, {
|
||||
a: 2,
|
||||
b: 2,
|
||||
})).toBeFalsy();
|
||||
|
||||
expect(isApiOutdated({
|
||||
method: 'get',
|
||||
url: '/api/xxx?a=${a}'
|
||||
}, {
|
||||
method: 'get',
|
||||
url: '/api/xxx?a=${a}',
|
||||
sendOn: 'this.b === 0'
|
||||
}, {
|
||||
a: 1,
|
||||
b: 0
|
||||
}, {
|
||||
a: 2,
|
||||
b: 2,
|
||||
})).toBeFalsy();
|
||||
});
|
22
__tests__/utils/tpl-builtin.test.ts
Normal file
22
__tests__/utils/tpl-builtin.test.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import {
|
||||
prettyBytes,
|
||||
escapeHtml,
|
||||
formatDuration
|
||||
} from '../../src/utils/tpl-builtin';
|
||||
|
||||
test('tpl-builtin:prettyBytes', () => {
|
||||
expect(prettyBytes(1024)).toEqual('1.02 kB');
|
||||
expect(prettyBytes(1024000)).toEqual('1.02 MB');
|
||||
});
|
||||
|
||||
|
||||
test('tpl-builtin:escapeHtml', () => {
|
||||
expect(escapeHtml('<div id="1">Hello&world</div>')).toEqual('<div id="1">Hello&world</div>');
|
||||
});
|
||||
|
||||
test('tpl-builtin:formatDuration', () => {
|
||||
expect(formatDuration(1)).toEqual('1秒');
|
||||
expect(formatDuration(61)).toEqual('1分1秒');
|
||||
expect(formatDuration(233233)).toEqual('3天17时47分13秒');
|
||||
|
||||
})
|
17
__tests__/utils/tpl.test.ts
Normal file
17
__tests__/utils/tpl.test.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import {
|
||||
filter
|
||||
} from '../../src/utils/tpl';
|
||||
|
||||
import '../../src/utils/tpl-builtin';
|
||||
import '../../src/utils/tpl-lodash';
|
||||
test('filter', () => {
|
||||
expect(filter('xxx_a=${a}&b=${b}', {
|
||||
a: 1,
|
||||
b: 2
|
||||
})).toEqual('xxx_a=1&b=2');
|
||||
|
||||
expect(filter('xxx_a=<%= data.a%>&b=<%= data.b%>', {
|
||||
a: 1,
|
||||
b: 2
|
||||
})).toEqual('xxx_a=1&b=2');
|
||||
})
|
429
__tests__/utils/validations.test.ts
Normal file
429
__tests__/utils/validations.test.ts
Normal file
@ -0,0 +1,429 @@
|
||||
import {
|
||||
validate,
|
||||
str2rules
|
||||
} from '../../src/utils/validations';
|
||||
|
||||
test('validation:isRequired valid', () => {
|
||||
expect(validate('somestring', {}, {
|
||||
isRequired: true
|
||||
}, {
|
||||
isRequired: 'This is required!'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:isRequired invalid', () => {
|
||||
expect(validate('', {}, {
|
||||
isRequired: true
|
||||
}, {
|
||||
isRequired: 'This is required!'
|
||||
})).toMatchObject(['This is required!']);
|
||||
});
|
||||
|
||||
test('validation:isEmail valid', () => {
|
||||
expect(validate('abc@gmail.com', {}, {
|
||||
isEmail: true
|
||||
}, {
|
||||
isEmail: 'Email 格式不正确'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:isEmail invalid', () => {
|
||||
expect(validate('somestring', {}, {
|
||||
isEmail: true
|
||||
}, {
|
||||
isEmail: 'Email 格式不正确'
|
||||
})).toMatchObject(['Email 格式不正确']);
|
||||
});
|
||||
|
||||
test('validation:isUrl valid', () => {
|
||||
expect(validate('http://www.baidu.com', {}, {
|
||||
isUrl: true
|
||||
}, {
|
||||
isUrl: 'Url 格式不正确'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:isUrl invalid', () => {
|
||||
expect(validate('somestring', {}, {
|
||||
isUrl: true
|
||||
}, {
|
||||
isUrl: 'Url 格式不正确'
|
||||
})).toMatchObject(['Url 格式不正确']);
|
||||
});
|
||||
|
||||
test('validation:isInt valid', () => {
|
||||
expect(validate(1, {}, {
|
||||
isInt: true
|
||||
}, {
|
||||
isInt: '请输入整形数字'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:isInt invalid', () => {
|
||||
expect(validate(1.1, {}, {
|
||||
isInt: true
|
||||
}, {
|
||||
isInt: '请输入整形数字'
|
||||
})).toMatchObject(['请输入整形数字']);
|
||||
});
|
||||
|
||||
test('validation:isAlpha valid', () => {
|
||||
expect(validate('a', {}, {
|
||||
isAlpha: true
|
||||
}, {
|
||||
isAlpha: '请输入字母'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:isAlpha invalid', () => {
|
||||
expect(validate('%', {}, {
|
||||
isAlpha: true
|
||||
}, {
|
||||
isAlpha: '请输入字母'
|
||||
})).toMatchObject(['请输入字母']);
|
||||
});
|
||||
|
||||
test('validation:isNumeric valid', () => {
|
||||
expect(validate(1.1, {}, {
|
||||
isNumeric: true
|
||||
}, {
|
||||
isNumeric: '请输入数字'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:isNumeric invalid', () => {
|
||||
expect(validate('a', {}, {
|
||||
isNumeric: true
|
||||
}, {
|
||||
isNumeric: '请输入数字'
|
||||
})).toMatchObject(['请输入数字']);
|
||||
});
|
||||
|
||||
test('validation:isAlphanumeric Alpha valid', () => {
|
||||
expect(validate('a', {}, {
|
||||
isAlphanumeric: true
|
||||
}, {
|
||||
isAlphanumeric: '请输入数字'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:isAlphanumeric numeric valid', () => {
|
||||
expect(validate(1, {}, {
|
||||
isAlphanumeric: true
|
||||
}, {
|
||||
isAlphanumeric: '请输入字母或者数字'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:isAlphanumeric invalid', () => {
|
||||
expect(validate('%', {}, {
|
||||
isAlphanumeric: true
|
||||
}, {
|
||||
isAlphanumeric: '请输入字母或者数字'
|
||||
})).toMatchObject(['请输入字母或者数字']);
|
||||
});
|
||||
|
||||
test('validation:isFloat valid', () => {
|
||||
expect(validate(1.1, {}, {
|
||||
isFloat: true
|
||||
}, {
|
||||
isFloat: '请输入浮点型数值'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:isFloat invalid', () => {
|
||||
expect(validate('a', {}, {
|
||||
isFloat: true
|
||||
}, {
|
||||
isFloat: '请输入浮点型数值'
|
||||
})).toMatchObject(['请输入浮点型数值']);
|
||||
});
|
||||
|
||||
test('validation:isWords valid', () => {
|
||||
expect(validate('baidu', {}, {
|
||||
isWords: true
|
||||
}, {
|
||||
isWords: '请输入字母'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:isWords invalid', () => {
|
||||
expect(validate('%', {}, {
|
||||
isWords: true
|
||||
}, {
|
||||
isWords: '请输入字母'
|
||||
})).toMatchObject(['请输入字母']);
|
||||
});
|
||||
|
||||
test('validation:isUrlPath valid', () => {
|
||||
expect(validate('baidu-fex_team', {}, {
|
||||
isUrlPath: true
|
||||
}, {
|
||||
isUrlPath: '只能输入字母、数字、`-` 和 `_`'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:isUrlPath invalid', () => {
|
||||
expect(validate('baidu&fex%team', {}, {
|
||||
isUrlPath: true
|
||||
}, {
|
||||
isUrlPath: '只能输入字母、数字、`-` 和 `_`'
|
||||
})).toMatchObject(['只能输入字母、数字、`-` 和 `_`']);
|
||||
});
|
||||
|
||||
test('validation:minLength valid', () => {
|
||||
expect(validate('abcdef', {}, {
|
||||
minLength: 5
|
||||
}, {
|
||||
minLength: '请至少输入 5 个字符。'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:minLength invalid', () => {
|
||||
expect(validate('abcd', {}, {
|
||||
minLength: 5
|
||||
}, {
|
||||
minLength: '至少输入 5 个字符。'
|
||||
})).toMatchObject(['至少输入 5 个字符。']);
|
||||
});
|
||||
|
||||
test('validation:maxLength valid', () => {
|
||||
expect(validate('abcde', {}, {
|
||||
maxLength: 5
|
||||
}, {
|
||||
maxLength: '请不要输入 5 个字符以上'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:maxLength invalid', () => {
|
||||
expect(validate('abcded', {}, {
|
||||
maxLength: 5
|
||||
}, {
|
||||
maxLength: '请不要输入 5 个字符以上'
|
||||
})).toMatchObject(['请不要输入 5 个字符以上']);
|
||||
});
|
||||
|
||||
test('validation:minimum valid', () => {
|
||||
expect(validate(6, {}, {
|
||||
minimum: 5
|
||||
}, {
|
||||
minimum: '当前输入值低于最小值 5,请检查'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:minimum invalid', () => {
|
||||
expect(validate(4, {}, {
|
||||
minimum: 5
|
||||
}, {
|
||||
minimum: '当前输入值低于最小值 5,请检查'
|
||||
})).toMatchObject(['当前输入值低于最小值 5,请检查']);
|
||||
});
|
||||
|
||||
test('validation:maximum valid', () => {
|
||||
expect(validate(5, {}, {
|
||||
maximum: 5
|
||||
}, {
|
||||
maximum: '当前输入值超出最大值 5,请检查'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:maximum invalid', () => {
|
||||
expect(validate(6, {}, {
|
||||
maximum: 5
|
||||
}, {
|
||||
maximum: '当前输入值超出最大值 5,请检查'
|
||||
})).toMatchObject(['当前输入值超出最大值 5,请检查']);
|
||||
});
|
||||
|
||||
test('validation:isJson valid', () => {
|
||||
expect(validate('{ "type": "select", "options": [ { "label": "A", "value": "a" } ] }', {}, {
|
||||
isJson: true
|
||||
}, {
|
||||
isJson: '请检查 Json 格式'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:isJson invalid', () => {
|
||||
expect(validate('string', {}, {
|
||||
isJson: true
|
||||
}, {
|
||||
isJson: '请检查 Json 格式'
|
||||
})).toMatchObject(['请检查 Json 格式']);
|
||||
});
|
||||
|
||||
test('validation:isLength valid', () => {
|
||||
expect(validate('abcde', {}, {
|
||||
isLength: 5
|
||||
}, {
|
||||
isLength: '请输入长度为 5 的内容'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:isLength invalid', () => {
|
||||
expect(validate('abc', {}, {
|
||||
isLength: 5
|
||||
}, {
|
||||
isLength: '请输入长度为 5 的内容'
|
||||
})).toMatchObject(['请输入长度为 5 的内容']);
|
||||
});
|
||||
|
||||
test('validation:notEmptyString valid', () => {
|
||||
expect(validate('abc', {}, {
|
||||
notEmptyString: true
|
||||
}, {
|
||||
notEmptyString: '请不要全输入空白字符'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:notEmptyString invalid', () => {
|
||||
expect(validate(' ', {}, {
|
||||
notEmptyString: true
|
||||
}, {
|
||||
notEmptyString: '请不要全输入空白字符'
|
||||
})).toMatchObject(['请不要全输入空白字符']);
|
||||
});
|
||||
|
||||
test('validation:equalsField valid', () => {
|
||||
expect(validate('a', {
|
||||
a: 'a'
|
||||
}, {
|
||||
equalsField: 'a'
|
||||
}, {
|
||||
equalsField: '输入的数据与 a 值不一致'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:equalsField invalid', () => {
|
||||
expect(validate('b', {
|
||||
a: 'a'
|
||||
}, {
|
||||
equalsField: 'a'
|
||||
}, {
|
||||
equalsField: '输入的数据与 a 值不一致'
|
||||
})).toMatchObject(['输入的数据与 a 值不一致']);
|
||||
});
|
||||
|
||||
test('validation:equals valid', () => {
|
||||
expect(validate('a', {}, {
|
||||
equals: 'a'
|
||||
}, {
|
||||
equals: '输入的数据与 a 不一致'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:equals invalid', () => {
|
||||
expect(validate('b', {}, {
|
||||
equals: 'a'
|
||||
}, {
|
||||
equals: '输入的数据与 a 不一致'
|
||||
})).toMatchObject(['输入的数据与 a 不一致']);
|
||||
});
|
||||
|
||||
test('validation:multipleRules invalid', () => {
|
||||
expect(validate('abc', {}, {
|
||||
isUrl: true,
|
||||
isInt: true
|
||||
})).toMatchObject(['Url 格式不正确', '请输入整形数字']);
|
||||
});
|
||||
|
||||
test('validation:matchRegexp valid', () => {
|
||||
expect(validate('abcd', {}, {
|
||||
matchRegexp: '/^abc/'
|
||||
}, {
|
||||
matchRegexp: '请输入abc开头的好么'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:matchRegexp invalid', () => {
|
||||
expect(validate('cba', {}, {
|
||||
matchRegexp: '/^abc/'
|
||||
}, {
|
||||
matchRegexp: '请输入abc开头的好么'
|
||||
})).toMatchObject(['请输入abc开头的好么']);
|
||||
});
|
||||
|
||||
test('validation:matchRegexp:noSlash valid', () => {
|
||||
expect(validate('abcd', {}, {
|
||||
matchRegexp: '^abc'
|
||||
}, {
|
||||
matchRegexp: '请输入abc开头的好么'
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:matchRegexp:noSlash invalid', () => {
|
||||
expect(validate('cba', {}, {
|
||||
matchRegexp: '^abc'
|
||||
}, {
|
||||
matchRegexp: '请输入abc开头的好么'
|
||||
})).toMatchObject(['请输入abc开头的好么']);
|
||||
});
|
||||
|
||||
test('validation:multipleMatchRegexp valid', () => {
|
||||
expect(validate('abcd123', {}, {
|
||||
matchRegexp1: '/^abc/',
|
||||
matchRegexp2: '/123$/',
|
||||
}, {
|
||||
matchRegexp1: '请输入abc开头的好么',
|
||||
matchRegexp2: '请输入123结尾的好么',
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:multipleMatchRegexp invalid', () => {
|
||||
expect(validate('cba', {}, {
|
||||
matchRegexp1: '/^abc/',
|
||||
matchRegexp2: '/123$/',
|
||||
}, {
|
||||
matchRegexp1: '请输入abc开头的好么',
|
||||
matchRegexp2: '请输入123结尾的好么',
|
||||
})).toMatchObject(['请输入abc开头的好么', '请输入123结尾的好么']);
|
||||
});
|
||||
|
||||
test('validation:multipleMatchRegexp:noSlash valid', () => {
|
||||
expect(validate('abcd123', {}, {
|
||||
matchRegexp1: '^abc',
|
||||
matchRegexp2: '123$',
|
||||
}, {
|
||||
matchRegexp1: '请输入abc开头的好么',
|
||||
matchRegexp2: '请输入123结尾的好么',
|
||||
})).toMatchObject([]);
|
||||
});
|
||||
|
||||
test('validation:multipleMatchRegexp:noSlash invalid', () => {
|
||||
expect(validate('cba', {}, {
|
||||
matchRegexp1: '^abc',
|
||||
matchRegexp2: '123$',
|
||||
}, {
|
||||
matchRegexp1: '请输入abc开头的好么',
|
||||
matchRegexp2: '请输入123结尾的好么',
|
||||
})).toMatchObject(['请输入abc开头的好么', '请输入123结尾的好么']);
|
||||
});
|
||||
|
||||
test('validation:str2rules', () => {
|
||||
expect(str2rules('matchRegexp:/^abc/'))
|
||||
.toMatchObject({
|
||||
matchRegexp: ['/^abc/']
|
||||
});
|
||||
});
|
||||
|
||||
test('validation:multiplestr2rules', () => {
|
||||
expect(str2rules('matchRegexp1:/^abc/,matchRegexp2:/123$/'))
|
||||
.toMatchObject({
|
||||
matchRegexp1: ['/^abc/'],
|
||||
matchRegexp2: ['/123$/']
|
||||
});
|
||||
});
|
||||
|
||||
test('validation:str2rules:noSlash', () => {
|
||||
expect(str2rules('matchRegexp:^abc'))
|
||||
.toMatchObject({
|
||||
matchRegexp: ['^abc']
|
||||
});
|
||||
});
|
||||
|
||||
test('validation:multiplestr2rules:noSlash', () => {
|
||||
expect(str2rules('matchRegexp1:^abc,matchRegexp2:123$'))
|
||||
.toMatchObject({
|
||||
matchRegexp1: ['^abc'],
|
||||
matchRegexp2: ['123$']
|
||||
});
|
||||
});
|
181
build/md-parser.js
Normal file
181
build/md-parser.js
Normal file
@ -0,0 +1,181 @@
|
||||
/* eslint-disable */
|
||||
|
||||
var marked = require("marked");
|
||||
var yaml = (yaml = require("js-yaml"));
|
||||
var rYml = /^\s*---([\s\S]*?)---\s/;
|
||||
var renderer = new marked.Renderer();
|
||||
marked.setOptions({
|
||||
renderer: renderer,
|
||||
gfm: true,
|
||||
tables: true,
|
||||
breaks: false,
|
||||
pedantic: false,
|
||||
sanitize: true,
|
||||
smartLists: true,
|
||||
smartypants: false
|
||||
});
|
||||
|
||||
// Synchronous highlighting with highlight.js
|
||||
marked.setOptions({
|
||||
highlight: function(code) {
|
||||
return require("highlight.js").highlightAuto(code).value;
|
||||
}
|
||||
});
|
||||
|
||||
// renderer.table = function(header, body) {
|
||||
// return '<table class="table table-striped">\n'
|
||||
// + '<thead>\n'
|
||||
// + header
|
||||
// + '</thead>\n'
|
||||
// + '<tbody>\n'
|
||||
// + body
|
||||
// + '</tbody>\n'
|
||||
// + '</table>\n';
|
||||
// };
|
||||
|
||||
renderer.link = function(href, title, text) {
|
||||
if (this.options.sanitize) {
|
||||
try {
|
||||
var prot = decodeURIComponent(unescape(href))
|
||||
.replace(/[^\w:]/g, "")
|
||||
.toLowerCase();
|
||||
} catch (e) {
|
||||
return "";
|
||||
}
|
||||
if (
|
||||
prot.indexOf("javascript:") === 0 ||
|
||||
prot.indexOf("vbscript:") === 0
|
||||
) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
if (href && href[0] === "#") {
|
||||
href = "#" +
|
||||
encodeURIComponent(
|
||||
href
|
||||
.substring(1)
|
||||
.toLowerCase()
|
||||
.replace(/[^\u4e00-\u9fa5_a-zA-Z0-9]+/g, "-")
|
||||
);
|
||||
}
|
||||
|
||||
var out = '<a href="' + href + '"';
|
||||
if (title) {
|
||||
out += ' title="' + title + '"';
|
||||
}
|
||||
out += ">" + text + "</a>";
|
||||
return out;
|
||||
};
|
||||
|
||||
module.exports = function(content, file) {
|
||||
var m = rYml.exec(content);
|
||||
var info = {};
|
||||
if (m && m[1]) {
|
||||
info = yaml.safeLoad(m[1]);
|
||||
content = content.substring(m[0].length);
|
||||
}
|
||||
|
||||
var toc = {
|
||||
label: "目录",
|
||||
type: "toc",
|
||||
children: [],
|
||||
level: 0
|
||||
};
|
||||
var stack = [toc];
|
||||
|
||||
renderer.heading = function(text, level) {
|
||||
var escapedText = encodeURIComponent(
|
||||
text.toLowerCase().replace(/[^\u4e00-\u9fa5_a-zA-Z0-9]+/g, "-")
|
||||
);
|
||||
|
||||
if (level < 5) {
|
||||
var menu = {
|
||||
label: text,
|
||||
fragment: escapedText,
|
||||
fullPath: "#" + escapedText,
|
||||
level: level
|
||||
};
|
||||
|
||||
while (stack.length && stack[0].level >= level) {
|
||||
stack.shift();
|
||||
}
|
||||
|
||||
stack[0].children = stack[0].children || [];
|
||||
stack[0].children.push(menu);
|
||||
|
||||
stack.unshift(menu);
|
||||
}
|
||||
|
||||
var anchor =
|
||||
'<a class="anchor" name="' +
|
||||
escapedText +
|
||||
'" href="#' +
|
||||
escapedText +
|
||||
'" aria-hidden="true"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>';
|
||||
|
||||
return "<h" + level + ">" + anchor + text + "</h" + level + ">";
|
||||
|
||||
// return '<h' + level + '><a name="' +
|
||||
// escapedText +
|
||||
// '" class="anchor" href="#' +
|
||||
// escapedText +
|
||||
// '"><span class="header-link"></span></a>' +
|
||||
// text + '</h' + level + '>';
|
||||
};
|
||||
|
||||
const placeholder = {};
|
||||
let index = 1;
|
||||
|
||||
content = content.replace(
|
||||
/```(schema|html)(?::(.*?))?\n([\s\S]*?)```/g,
|
||||
function(_, lang, attr, code) {
|
||||
const setting = {};
|
||||
attr && attr.split(/\s+/).forEach(function(item) {
|
||||
var parts = item.split("=");
|
||||
|
||||
if (parts[1] && /^('|").*\1/.test(parts[1])) {
|
||||
parts[1] = parts[1].substring(1, parts[1].length - 1);
|
||||
}
|
||||
|
||||
setting[parts[0]] = parts[1] ? decodeURIComponent(parts[1]) : "";
|
||||
|
||||
if (parts[0] === 'height') {
|
||||
setting.height = parseInt(setting.height, 10) + 200/*编辑器的高度*/;
|
||||
attr = attr.replace(item, `height="${setting.height}"`);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// placeholder[index] = `<iframe class="doc-iframe" width="100%" height="${setting.height || 200}px" frameBorder="0" src="/play?code=${encodeURIComponent(code)}&scope=${encodeURIComponent(setting.scope)}"></iframe>`;
|
||||
if (lang === "html") {
|
||||
placeholder[
|
||||
index
|
||||
] = `<div class="amis-doc"><div class="preview">${code}</div><pre><code class="lang-html">${
|
||||
require("highlight.js").highlightAuto(code).value
|
||||
}</code></pre></div>`;
|
||||
} else {
|
||||
placeholder[
|
||||
index
|
||||
] = `<div class="amis-preview" style="height: ${
|
||||
setting.height
|
||||
}px"><script type="text/schema" ${attr}>${code}</script></div>`;
|
||||
}
|
||||
|
||||
return `[[${index++}]]`;
|
||||
}
|
||||
);
|
||||
|
||||
content = marked(content).replace(/<p>\[\[(\d+)\]\]<\/p>/g, function(
|
||||
_,
|
||||
id
|
||||
) {
|
||||
return placeholder[id] || "";
|
||||
});
|
||||
|
||||
content = fis.compile.partial(content, file, "html");
|
||||
info.html = content;
|
||||
info.toc = toc;
|
||||
|
||||
return "module.exports = " + JSON.stringify(info, null, 2) + ";";
|
||||
};
|
289
docs/advanced.md
Normal file
289
docs/advanced.md
Normal file
@ -0,0 +1,289 @@
|
||||
---
|
||||
title: 高级用法
|
||||
shortname: advanced
|
||||
---
|
||||
|
||||
在开始阅读之前,希望你已经对阅读 [快速开始文档](/docs/getting-started) 。
|
||||
|
||||
## 数据作用域
|
||||
|
||||
|
||||
配置中很多地方都可以用变量如: [tpl](#/docs/renderers#tpl) 类型的渲染器、API 中的 Url、FormItem 中的 source 配置、visibleOn、disabledOn 以及 Form 中的 `redirect` 配置等等。
|
||||
|
||||
那么都有哪些数据可以用?这取决于在哪个容器,关于容器中的数据说明如下:
|
||||
|
||||
* `page` 等价于全局变量,因为顶级渲染器就是它,所以下面的所有组件都能用到这个里面的数据。
|
||||
|
||||
* `amisPage` 当前页面的数据信息,包含标题,id,key 之类的信息。
|
||||
* `amisUser` 当前用户信息,包含邮箱和用户名信息。
|
||||
* `params 中的数据` 如果地址栏中也携带了参数,也会merge到该层的数据中。
|
||||
* `initApi 返回的数据` 如果 page 设置了 `initApi` 那么初始化的时候会从 API 中拉取数据,拉取到的数据可以用于整个页面。
|
||||
|
||||
* `crud`
|
||||
|
||||
* 父级 容器中的数据可以直接使用,如 page 容器
|
||||
* `api` 返回的数据,crud 的 api 除了可以返回 `rows` 和 `count` 数据外,其他的数据会被 merge 到数据中,供容器使用。
|
||||
|
||||
* `form`
|
||||
|
||||
* 父级 容器中的数据可以直接使用,如 page 容器
|
||||
* `initApi` 返回的数据。
|
||||
* FormItem 的数据直接会存入到数据中,而且每次修改都会及时更新。通过 FormItem 设置的 `name` 值获取。
|
||||
|
||||
* `formItem` 表单项中,所在的表单中的数据都能用。
|
||||
* `wizard` 同 form
|
||||
* `dialog` dialog 由 button 触发弹出,携带的数据根据按钮所在的位置来决定。
|
||||
* form 中弹出则会把 form 中的数据复制份传给 dialog。
|
||||
* crud 中的批量操作按钮。把整个列表数据复制给 dialog。
|
||||
* crud 中的某一项中的按钮,则只会把对应的那一条数据拷贝给 dialog。
|
||||
* `servcie`
|
||||
* 父级 容器中的数据可以直接使用,如 page 容器
|
||||
* 如果配置了 `api`, `api` 返回的数据可以用。
|
||||
|
||||
取值过程,也跟 JS 作用域中取值一样,当前作用域中有,则直接返回当前作用域中,如果没有当前作用域没有,会一直往上找,直到找到了为止。如果存在同名变量,则返回就近作用域中数据。
|
||||
|
||||
需要注意的是,要取到值一定是在自己所在的作用域,或者上级作用域里面,同级的是取不到的,如果需要怎么办?可以往下看联动,比如:FormA 的数据发送给 formB, 另外一种方式,可以把接口拉取换到父级组件去操作,没有可拉取数据的组件,就一起包在一个 service 控件里面。
|
||||
|
||||
## 联动
|
||||
|
||||
### 简单的显隐联动
|
||||
|
||||
主要通过 `visibleOn`、`hiddenOn` 和 `disabledOn` 来配置。
|
||||
|
||||
```schema:height="300" scope="form"
|
||||
[
|
||||
{
|
||||
"type": "radios",
|
||||
"name": "foo",
|
||||
"inline": true,
|
||||
"label": " ",
|
||||
"options": [
|
||||
{
|
||||
"label": "类型1",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "类型2",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "类型3",
|
||||
"value": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"type": "text",
|
||||
"name": "text",
|
||||
"placeholder": "类型1 可见",
|
||||
"visibleOn": "data.foo == 1"
|
||||
},
|
||||
|
||||
{
|
||||
"type": "text",
|
||||
"name": "text2",
|
||||
"placeholder": "类型2 不可点",
|
||||
"disabledOn": "data.foo == 2"
|
||||
},
|
||||
|
||||
{
|
||||
"type": "button",
|
||||
"label": "类型三不能提交",
|
||||
"level": "primary",
|
||||
"disabledOn": "data.foo == 3"
|
||||
}
|
||||
|
||||
]
|
||||
```
|
||||
|
||||
### 选项联动
|
||||
|
||||
比如 select 中 options 可能根据某个值不同而不同。
|
||||
|
||||
```schema:height="300" scope="form"
|
||||
[
|
||||
{
|
||||
"label": "选项1",
|
||||
"type": "radios",
|
||||
"labelClassName": "text-muted",
|
||||
"name": "a",
|
||||
"inline": true,
|
||||
"options": [
|
||||
{
|
||||
"label": "选项1",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "选项2",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "选项3",
|
||||
"value": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "选项2",
|
||||
"type": "select",
|
||||
"labelClassName": "text-muted",
|
||||
"name": "b",
|
||||
"inline": true,
|
||||
"source": "/api/mock2/options/level2?a=${a}",
|
||||
"initFetchOn": "data.a"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
他们是怎么关联的呢?注意看 select 的 source 配置 `"/api/mock/getOptions?waitSeconds=1&type=$foo"` 这里用了变量 `$foo` 这个 foo 正好是第一个表单的 name 值。只要这个值发生变化,source 就会重新获取一次。
|
||||
|
||||
这里有个问题就是,数据一旦变化就会出发重新拉取,如果是输入框岂不是拉取得很频繁?没关系,也可以主动拉取如:
|
||||
|
||||
```schema:height="300" scope="body"
|
||||
{
|
||||
"type": "form",
|
||||
"name": "lidong",
|
||||
"controls": [
|
||||
{
|
||||
"type": "text",
|
||||
"name": "foo",
|
||||
"addOn": {
|
||||
"label": "搜索",
|
||||
"className": "btn-info",
|
||||
"type": "button",
|
||||
"actionType": "reload",
|
||||
"disabledOn": "!data.foo",
|
||||
"target": "lidong.select"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"type": "select",
|
||||
"name": "select",
|
||||
"label": "Select",
|
||||
"source": {
|
||||
"method": "get",
|
||||
"url": "/api/mock2/options/level2?waitSeconds=1",
|
||||
"data": {
|
||||
"a": "$foo"
|
||||
}
|
||||
},
|
||||
"desc": "这里只是演示刷新不会真正的过滤。"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
注意,source中的传参是通过 source 中的 data 关联的,不能写在 source 的 url 中,因为如果写了,就会自动监控值的变化而自动刷新,写在 data 里面关联则不会。如果对 source 中的配置规则不了解,请前往 [API 说明](/docs/renderers#api)
|
||||
|
||||
另外注意 button 的 target 值,正好是这个 form 的 name 值 `lidong` 的 formItem 的 name 值 `select`。当按钮的对象是一个 formItem 时,会出发 formItem 的数据重新拉取。
|
||||
|
||||
### 数据联动
|
||||
|
||||
Form 和 CRUD, CRUD 有个 filter 配置项,里面可以配置表单项,当他提交时 CRUD 自动就会携带接受到的表单数据然后重新获取数据。有个限制,就是 CRUD 和 filter 必须放在一起,不能分开,实际上完全可以分开,只要 Form 的 target 是 CRUD 的 name 值即可。
|
||||
|
||||
```schema:height="300"
|
||||
{
|
||||
"type": "page",
|
||||
"aside": {
|
||||
"type": "form",
|
||||
"target": "doc-crud",
|
||||
"wrapWithPanel": false,
|
||||
"className": "wrapper-xs",
|
||||
"controls": [
|
||||
{
|
||||
"type": "text",
|
||||
"name": "keywords",
|
||||
"placeholder": "请输入关键字",
|
||||
"clearable": true,
|
||||
"addOn": {
|
||||
"label": "搜索",
|
||||
"className": "btn-info",
|
||||
"type": "submit"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"body": {
|
||||
"name": "doc-crud",
|
||||
"type": "crud",
|
||||
"api": "/api/sample",
|
||||
"syncLocation": false,
|
||||
"title": null,
|
||||
"perPageField":"rn",
|
||||
"defaultParams":{
|
||||
"rn": 10
|
||||
},
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"label": "ID",
|
||||
"width": 20,
|
||||
"sortable": true
|
||||
},
|
||||
{
|
||||
"name": "engine",
|
||||
"label": "Rendering engine",
|
||||
"sortable": true,
|
||||
"toggled": false
|
||||
},
|
||||
{
|
||||
"name": "browser",
|
||||
"label": "Browser",
|
||||
"sortable": true
|
||||
},
|
||||
{
|
||||
"name": "platform",
|
||||
"label": "Platform(s)",
|
||||
"sortable": true
|
||||
},
|
||||
{
|
||||
"name": "version",
|
||||
"label": "Engine version"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Form 的 target 还可以是另外一个 Form,当 A Form 把自己的数据提交给 B Form 时,A 的数据会被合并到 B Form 中,同时,B Form 会再次初始化,如:拉取 initApi, 重新拉取 formItem 上的 source 等等。 比如用户管理中的[加入用户](/group/test/admin/users?perPage=12)操作就是用这种方式实现的。
|
||||
|
||||
```schema:height="300"
|
||||
{
|
||||
"type": "page",
|
||||
"aside": {
|
||||
"type": "form",
|
||||
"target": "doc-form",
|
||||
"wrapWithPanel": false,
|
||||
"className": "wrapper-xs",
|
||||
"controls": [
|
||||
{
|
||||
"type": "text",
|
||||
"name": "keywords",
|
||||
"clearable": true,
|
||||
"placeholder": "请输入关键字",
|
||||
"addOn": {
|
||||
"label": "提交",
|
||||
"className": "btn-info",
|
||||
"type": "submit"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"body": {
|
||||
"name": "doc-form",
|
||||
"type": "form",
|
||||
"api": "/api/sample",
|
||||
"submitText": null,
|
||||
"controls": [
|
||||
{
|
||||
"type": "static",
|
||||
"name": "keywords",
|
||||
"label": "你刚刚输入的是:"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
181
docs/dev.md
Normal file
181
docs/dev.md
Normal file
@ -0,0 +1,181 @@
|
||||
---
|
||||
title: 自定义组件
|
||||
shortname: dev
|
||||
---
|
||||
|
||||
AMis 平台中,支持了大部分的[通用组件](/docs/renderers),基本需求都能满足。针对比较定制的需求,则需要通过在群组内添加自定义组件来实现。
|
||||
|
||||
## 如何添加
|
||||
|
||||
1. 自定义组件是群级别的,先进入你想要添加的自定义组件的群组。
|
||||
2. 然后进入【组件管理】页面。(你需要拥有管理权限,一般管理员自带这个权限)
|
||||
3. 然后点击右上角添加【新建】
|
||||
|
||||
![图片](http://bos.nj.bpc.baidu.com/v1/agroup/e3619506735bbec17ea83da71944fc447d709de4)
|
||||
|
||||
* `组件名` 随意。
|
||||
* `组件代码` React Component 代码。
|
||||
|
||||
## 如何开发?
|
||||
|
||||
AMis 中自定义组件主要分两类。表单类和非表单类。
|
||||
|
||||
### FormItem
|
||||
|
||||
即表单类,它主要用来扩充表单项。先看个例子。
|
||||
|
||||
```jsx
|
||||
import * as React from 'react';
|
||||
import {FormItem} from 'amis';
|
||||
import * as cx from 'classnames';
|
||||
|
||||
@FormItem({
|
||||
type:'custom-checkbox'
|
||||
})
|
||||
export default class CustomCheckbox extends React.PureComponent{
|
||||
toggle = () => {
|
||||
const {
|
||||
value,
|
||||
onChange
|
||||
} = this.props;
|
||||
|
||||
onChange(!value);
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
value
|
||||
} = this.props;
|
||||
const checked = !!value;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<a
|
||||
className={cx('btn btn-default', {
|
||||
'btn-success': checked,
|
||||
})}
|
||||
onClick={this.toggle}
|
||||
>{checked ? '已勾选' : '请勾选'}</a>
|
||||
<div className="inline m-l-xs">{checked ? '已勾选' : '请勾选'}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
有了这个代码后,页面配置 form 的 controls 里面就可以通过这样的配置启动了。[在线 Demo](http://amis.baidu.com/group/demo/custom)。
|
||||
|
||||
```js
|
||||
{
|
||||
// 其他信息省略了。。
|
||||
type: 'form',
|
||||
controls: [
|
||||
{
|
||||
type: 'custom-checkbox',
|
||||
name: '变量名',
|
||||
label: '自定义组件。'
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
表单项开发主要关心两件事。
|
||||
|
||||
1. 呈现当前值。如以上例子,勾选了则显示`已勾选`,否则显示`请勾选`。
|
||||
2. 接收用户交互,修改表单项值。如以上例子,当用户点击按钮时,切换当前选中的值。
|
||||
|
||||
至于其他功能如:label/description 的展示、表单验证功能、表单布局(常规、左右或者内联)等等,只要是通过 FormItem 注册进去的都无需自己实现。
|
||||
|
||||
### Renderer
|
||||
|
||||
非表单类的组件自定义,主要通过 `Renderer` 实现。在开始阅读之前,请先阅读 [AMis 工作原理](/docs/sdk#工作原理)。
|
||||
|
||||
```jsx
|
||||
import * as React from 'react';
|
||||
import {
|
||||
Renderer
|
||||
} from 'amis';
|
||||
|
||||
@Renderer({
|
||||
test: /(^|\/)my\-renderer$/,
|
||||
})
|
||||
class CustomRenderer extends React.Component {
|
||||
render() {
|
||||
const {
|
||||
tip,
|
||||
body,
|
||||
render
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>这是自定义组件:{tip}</p>
|
||||
{body ? (
|
||||
<div className="container">
|
||||
{render('body', body, {
|
||||
// 这里的信息会作为 props 传递给子组件,一般情况下都不需要这个
|
||||
})}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
这里注册一个 React 组件,当节点的 path 信息是 `my-renderer` 结尾时,交给当前组件来完成渲染。
|
||||
|
||||
请注意 `this.props` 中的 `render` 方法,它用来实现容器功能,通过它可以让使用者动态的配置其他渲染模型。
|
||||
|
||||
|
||||
## 工具
|
||||
|
||||
目前主要提供以下工具。
|
||||
|
||||
### fetch
|
||||
|
||||
```jsx
|
||||
import {
|
||||
fetch
|
||||
} from 'amis/utils';
|
||||
```
|
||||
|
||||
用来做 ajax 请求。参数说明
|
||||
|
||||
* `api` 字符串或者 api 对象,如: {url: 'http://www.baidu.com', method: 'get'}, api 地址支持变量。
|
||||
* `data` 数据体
|
||||
|
||||
返回一个 Promise。
|
||||
|
||||
如:
|
||||
|
||||
```js
|
||||
import {
|
||||
fetch
|
||||
} from 'amis/utils';
|
||||
|
||||
fetch('http://www.baidu.com/api/xxx?a=${a}&b=${b}', {
|
||||
a: 'aa',
|
||||
b: 'bb'
|
||||
}).then(function(result) {
|
||||
console.log(result);
|
||||
});
|
||||
```
|
||||
|
||||
### filter
|
||||
|
||||
```jsx
|
||||
import {
|
||||
filter
|
||||
} from 'amis/utils';
|
||||
```
|
||||
|
||||
主要用来做字符替换,如:
|
||||
|
||||
```js
|
||||
import {
|
||||
filter
|
||||
} from 'amis/utils';
|
||||
|
||||
filter('blabla?a={a}', {a: 123}); // => 'blabla?a=123'
|
||||
```
|
409
docs/getting_started.md
Normal file
409
docs/getting_started.md
Normal file
@ -0,0 +1,409 @@
|
||||
---
|
||||
title: 快速开始
|
||||
---
|
||||
|
||||
为了简化前端开发,AMis Renderer 能够直接用配置就能将页面渲染出来。
|
||||
|
||||
先来看个简单的例子。
|
||||
|
||||
```schema:height="300"
|
||||
{
|
||||
"$schema": "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
"type": "page",
|
||||
"title": "这是标题部分",
|
||||
"subTitle": "这是子标题",
|
||||
"remark": "这是小提示信息",
|
||||
"aside": "这是侧边栏部分",
|
||||
"body": "这是内容区",
|
||||
"toolbar": "这是工具栏部分"
|
||||
}
|
||||
```
|
||||
|
||||
> PS: 可以通过编辑器实时修改预览
|
||||
|
||||
从上面的内容可以看出,一个简单页面框架已经基本出来了,这是 AMis 渲染器配置的入口。从 `page` 渲染器开始出发,通过在容器中放置不同的渲染器来配置不同性质的页面。
|
||||
|
||||
简单说明以上配置信息。
|
||||
|
||||
* `$schema` 这个字段可以忽略,他是指定当前 JSON 配置是符合指定路径 http://amis.baidu.com/v2/schemas/page.json 的 JSON SCHEMA 文件描述的。PS: 编辑器就是靠这个描述文件提示的,可以 hover 到字段上看效果。
|
||||
* `type` 指定渲染器类型,这里指定的类型为 `page`。 更多渲染器类型可以去[这里面查看](/v2/docs/renderers)。
|
||||
* `title` 从 title 开始就是对应的渲染模型上的属性了。这里用来指定标题内容。
|
||||
* `subTitle` 副标题.
|
||||
* `remark` 标题上面的提示信息
|
||||
* `aside` 边栏区域内容
|
||||
* `body` 内容区域的内容
|
||||
* `toolbar` 工具栏部分的内容
|
||||
|
||||
这里有三个配置都是容器类型的。`aside`、`body` 和 `toolbar`。什么是容器类型?容器类型表示,他能够把其他渲染类型放进来。以上的例子为了简单,直接放了个字符串。字符串类型内部是把他当成了 [tpl](/v2/docs/renderers#tpl) 渲染器来处理,在这里也可以通过对象的形式指定,如以下的例子的 body 区域是完全等价的。
|
||||
|
||||
```schema:height="100"
|
||||
{
|
||||
"$schema": "http://amis.baidu.com/v2/schemas/page.json",
|
||||
"type": "page",
|
||||
"body": {
|
||||
"type": "tpl",
|
||||
"tpl": "这是内容区"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
容器内可以直接放一个渲染器,也可以放多个,用数组包起来即可如:
|
||||
|
||||
```schema:height="130"
|
||||
{
|
||||
"$schema": "http://amis.baidu.com/v2/schemas/page.json",
|
||||
"type": "page",
|
||||
"body": [
|
||||
{
|
||||
"type": "tpl",
|
||||
"tpl": "<p>段落1</p>"
|
||||
},
|
||||
|
||||
{
|
||||
"type": "tpl",
|
||||
"tpl": "<p>段落2</p>"
|
||||
},
|
||||
|
||||
"<p>段落3</p>"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
再来看一个表单页面的列子
|
||||
|
||||
|
||||
```schema:height="440"
|
||||
{
|
||||
"$schema": "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
"type": "page",
|
||||
"body": {
|
||||
"api": "/api/mock2/form/saveForm",
|
||||
"type": "form",
|
||||
"title": "联系我们",
|
||||
"controls": [
|
||||
{
|
||||
"type": "text",
|
||||
"label": "姓名",
|
||||
"name": "name"
|
||||
},
|
||||
|
||||
{
|
||||
"type": "email",
|
||||
"label": "邮箱",
|
||||
"name": "email",
|
||||
"required": true
|
||||
},
|
||||
|
||||
{
|
||||
"type": "textarea",
|
||||
"label": "内容",
|
||||
"name": "content",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
{
|
||||
"label": "发送",
|
||||
"type": "submit",
|
||||
"primary": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
这个例子就是在 body 容器内,放置一个 `form` 类型的渲染,它就成了一个简单的表单提交页面了,controls 中可以决定放哪些表单项目,actions 中可以放置操作按钮。
|
||||
|
||||
如果 body 区域放置一个 `crud` 渲染器,它就是列表页面了,再来看个栗子:
|
||||
|
||||
```schema:height="600"
|
||||
{
|
||||
"$schema": "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
"type": "page",
|
||||
"title": "增删改查示例",
|
||||
"toolbar": [
|
||||
{
|
||||
"type": "button",
|
||||
"actionType": "dialog",
|
||||
"label": "新增",
|
||||
"icon": "fa fa-plus pull-left",
|
||||
"primary": true,
|
||||
"dialog": {
|
||||
"title": "新增",
|
||||
"body": {
|
||||
"type": "form",
|
||||
"name": "sample-edit-form",
|
||||
"api": "",
|
||||
"controls": [
|
||||
{
|
||||
"type": "alert",
|
||||
"level": "info",
|
||||
"body": "因为没有配置 api 接口,不能真正的提交哈!"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"name": "text",
|
||||
"label": "文本",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "image",
|
||||
"name": "image",
|
||||
"label": "图片",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "date",
|
||||
"name": "date",
|
||||
"label": "日期",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"name": "type",
|
||||
"label": "选项",
|
||||
"options": [
|
||||
{
|
||||
"label": "漂亮",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"label": "开心",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"label": "惊吓",
|
||||
"value": "3"
|
||||
},
|
||||
{
|
||||
"label": "漂亮",
|
||||
"value": "紧张"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"body": [
|
||||
{
|
||||
"type": "crud",
|
||||
"api": "/api/mock2/crud/list",
|
||||
"defaultParams": {
|
||||
"perPage": 5
|
||||
},
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"label": "ID",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"name": "text",
|
||||
"label": "文本",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"type": "image",
|
||||
"label": "图片",
|
||||
"multiple": false,
|
||||
"name": "image",
|
||||
"popOver": {
|
||||
"title": "查看大图",
|
||||
"body": "<div class=\"w-xxl\"><img class=\"w-full\" src=\"${image}\"/></div>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "date",
|
||||
"type": "date",
|
||||
"label": "日期"
|
||||
},
|
||||
{
|
||||
"name": "type",
|
||||
"label": "映射",
|
||||
"type": "mapping",
|
||||
"map": {
|
||||
"1": "<span class='label label-info'>漂亮</span>",
|
||||
"2": "<span class='label label-success'>开心</span>",
|
||||
"3": "<span class='label label-danger'>惊吓</span>",
|
||||
"4": "<span class='label label-warning'>紧张</span>",
|
||||
"*": "其他:${type}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "container",
|
||||
"label": "操作",
|
||||
"body": [
|
||||
{
|
||||
"type": "button",
|
||||
"icon": "fa fa-eye",
|
||||
"level": "link",
|
||||
"actionType": "dialog",
|
||||
"tooltip": "查看",
|
||||
"dialog": {
|
||||
"title": "查看",
|
||||
"body": {
|
||||
"type": "form",
|
||||
"controls": [
|
||||
{
|
||||
"type": "static",
|
||||
"name": "id",
|
||||
"label": "ID"
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"name": "text",
|
||||
"label": "文本"
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "static-image",
|
||||
"label": "图片",
|
||||
"name": "image",
|
||||
"popOver": {
|
||||
"title": "查看大图",
|
||||
"body": "<div class=\"w-xxl\"><img class=\"w-full\" src=\"${image}\"/></div>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"name": "date",
|
||||
"type": "static-date",
|
||||
"label": "日期"
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"name": "type",
|
||||
"label": "映射",
|
||||
"type": "static-mapping",
|
||||
"map": {
|
||||
"1": "<span class='label label-info'>漂亮</span>",
|
||||
"2": "<span class='label label-success'>开心</span>",
|
||||
"3": "<span class='label label-danger'>惊吓</span>",
|
||||
"4": "<span class='label label-warning'>紧张</span>",
|
||||
"*": "其他:${type}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"icon": "fa fa-pencil",
|
||||
"tooltip": "编辑",
|
||||
"level": "link",
|
||||
"actionType": "drawer",
|
||||
"drawer": {
|
||||
"position": "left",
|
||||
"size": "lg",
|
||||
"title": "编辑",
|
||||
"body": {
|
||||
"type": "form",
|
||||
"name": "sample-edit-form",
|
||||
"controls": [
|
||||
{
|
||||
"type": "alert",
|
||||
"level": "info",
|
||||
"body": "因为没有配置 api 接口,不能真正的提交哈!"
|
||||
},
|
||||
{
|
||||
"type": "hidden",
|
||||
"name": "id"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"name": "text",
|
||||
"label": "文本",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "image",
|
||||
"name": "image",
|
||||
"multiple": false,
|
||||
"label": "图片",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "date",
|
||||
"name": "date",
|
||||
"label": "日期",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"name": "type",
|
||||
"label": "选项",
|
||||
"options": [
|
||||
{
|
||||
"label": "漂亮",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"label": "开心",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"label": "惊吓",
|
||||
"value": "3"
|
||||
},
|
||||
{
|
||||
"label": "漂亮",
|
||||
"value": "紧张"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"level": "link",
|
||||
"icon": "fa fa-times text-danger",
|
||||
"actionType": "ajax",
|
||||
"tooltip": "删除",
|
||||
"confirmText": "您确认要删除?",
|
||||
"api": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
这个栗子最主要的渲染器就是 CRUD 渲染器了,他的作用是配置了个 API,把数据拉取过来后,根据配置 columns 信息完成列表展示,列类型可以是静态文本、图片、映射或者日期等等。 `columns` 通过 `name` 与行数据关联。除了展示外还可以放置操作按钮。
|
||||
|
||||
这里相对复杂一点配置就是按钮了,按钮主要是通过 `actionType`来决定用户点下的行为。可以配置成 弹框、发送 ajax、页面跳转、复制内容到剪切板、刷新目标组件等等。具体请参考:[Action 渲染器说明](/v2/docs/renderers#action)
|
||||
|
||||
更多用法请参考[渲染器手册](/v2/docs/renderers)和示例。
|
4541
docs/renderers.md
Normal file
4541
docs/renderers.md
Normal file
File diff suppressed because it is too large
Load Diff
404
docs/sdk.md
Normal file
404
docs/sdk.md
Normal file
@ -0,0 +1,404 @@
|
||||
---
|
||||
title: 如何使用
|
||||
---
|
||||
|
||||
|
||||
## 如何使用
|
||||
|
||||
```bash
|
||||
npm i amis
|
||||
```
|
||||
|
||||
安装完后可以在 React Component 这么使用。
|
||||
|
||||
```tsx
|
||||
import * as React from 'react';
|
||||
import {
|
||||
render as renderAmis
|
||||
} from 'amis';
|
||||
|
||||
class MyComponent extends React.Component<any, any> {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<p>通过 AMis 渲染页面</p>
|
||||
{renderAmis({
|
||||
// schema
|
||||
// 这里是 AMis 的 Json 配置。
|
||||
type: 'page',
|
||||
title: '简单页面',
|
||||
body: '内容'
|
||||
}, {
|
||||
// props
|
||||
}, {
|
||||
// env
|
||||
// 这些是 AMis 需要的一些接口实现
|
||||
// 可以参考本项目里面的 Demo 部分代码。
|
||||
|
||||
updateLocation: (location:string/*目标地址*/, replace:boolean/*是replace,还是push?*/) => {
|
||||
// 用来更新地址栏
|
||||
},
|
||||
|
||||
jumpTo: (location:string/*目标地址*/) => {
|
||||
// 页面跳转, actionType: link、url 都会进来。
|
||||
},
|
||||
|
||||
fetcher: ({
|
||||
url,
|
||||
method,
|
||||
data,
|
||||
config
|
||||
}:{
|
||||
url:string/*目标地址*/,
|
||||
method:'get' | 'post' | 'put' | 'delete'/*发送方式*/,
|
||||
data: object | void/*数据*/,
|
||||
config: object/*其他配置*/
|
||||
}) => {
|
||||
// 用来发送 Ajax 请求,建议使用 axios
|
||||
},
|
||||
notify: (type:'error'|'success'/**/, msg:string/*提示内容*/) => {
|
||||
// 用来提示用户
|
||||
},
|
||||
alert: (content:string/*提示信息*/) => {
|
||||
// 另外一种提示,可以直接用系统框
|
||||
},
|
||||
confirm: (content:string/*提示信息*/) => {
|
||||
// 确认框。
|
||||
}
|
||||
});}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 工作原理
|
||||
|
||||
AMis 的渲染过程就是将 `json` 转成对应的 React 组件。先通过 `json` 的 type 找到对应的 `Component` 然后,然后把其他属性作为 `props` 传递过去完成渲染。
|
||||
|
||||
拿一个表单页面来说,如果用React组件调用大概是这样。
|
||||
|
||||
```jsx
|
||||
<Page
|
||||
title="页面标题"
|
||||
subTitle="副标题"
|
||||
>
|
||||
<Form
|
||||
title="用户登录"
|
||||
controls={[
|
||||
{
|
||||
type: 'text',
|
||||
name: 'username',
|
||||
label: '用户名'
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</Page>
|
||||
```
|
||||
|
||||
把以上配置方式换成 AMis JSON, 则是:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "page",
|
||||
"title": "页面标题",
|
||||
"subTitle": "副标题",
|
||||
"body": {
|
||||
"type": "form",
|
||||
"title": "用户登录",
|
||||
"controls": [
|
||||
{
|
||||
"type": "text",
|
||||
"name": "username",
|
||||
"label": "用户名"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
那么,AMis 是如何将 JSON 转成组件的呢?直接根据节点的 type 去跟组件一一对应?似乎很可能会重名比如在表格里面展示的类型 `text` 跟表单里面的 `text`是完全不一样的,一个负责展示,一个却负责输入。所以说一个节点要被什么组件渲染,还需要携带上下文(context)信息。
|
||||
|
||||
如何去携带上下文(context)信息?AMis 中直接是用节点的路径(path)来作为上下文信息。从上面的例子来看,一共有三个节点,path 信息分别是。
|
||||
|
||||
* `page` 页面节点
|
||||
* `page/body/form` 表单节点
|
||||
* `page/body/form/controls/0/text` 文本框节点。
|
||||
|
||||
根据 path 的信息就能很容易注册组件跟节点对应了。
|
||||
|
||||
Page 组件的示例代码
|
||||
|
||||
```jsx
|
||||
@Renderer({
|
||||
test: /^page$/,
|
||||
// ... 其他信息隐藏了
|
||||
})
|
||||
export class PageRenderer extends React.Component {
|
||||
// ... 其他信息隐藏了
|
||||
render() {
|
||||
const {
|
||||
title,
|
||||
body,
|
||||
render // 用来渲染孩子节点,如果当前是叶子节点则可以忽略。
|
||||
} = this.props;
|
||||
return (
|
||||
<div className="page">
|
||||
<h1>{title}</h1>
|
||||
<div className="body-container">
|
||||
{render('body', body)/*渲染孩子节点*/}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Form 组件的示例代码
|
||||
|
||||
```jsx
|
||||
@Renderer({
|
||||
test: /(^|\/)form$/,
|
||||
// ... 其他信息隐藏了
|
||||
})
|
||||
export class FormRenderer extends React.Component {
|
||||
// ... 其他信息隐藏了
|
||||
render() {
|
||||
const {
|
||||
title,
|
||||
controls,
|
||||
render // 用来渲染孩子节点,如果当前是叶子节点则可以忽略。
|
||||
} = this.props;
|
||||
return (
|
||||
<form className="form">
|
||||
{controls.map((control, index) => (
|
||||
<div className="form-item" key={index}>
|
||||
{render(`${index}/control`, control)}
|
||||
</div>
|
||||
))}
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Text 组件的示例代码
|
||||
|
||||
```jsx
|
||||
@Renderer({
|
||||
test: /(^|\/)form(?:\/\d+)?\/control(?\/\d+)?\/text$/
|
||||
// ... 其他信息隐藏了
|
||||
})
|
||||
export class FormItemTextRenderer extends React.Component {
|
||||
// ... 其他信息隐藏了
|
||||
render() {
|
||||
const {
|
||||
label,
|
||||
name,
|
||||
onChange
|
||||
} = this.props;
|
||||
return (
|
||||
<div className="form-group">
|
||||
<label>{label}<label>
|
||||
<input type="text" onChange={(e) => onChange(e.currentTarget.value)} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
那么渲染过程就是根据节点 path 信息,跟组件池中的组件 `test` (检测) 信息做匹配,如果命中,则把当前节点转给对应组件渲染,节点中其他属性将作为目标组件的 props。需要注意的是,如果是容器组件,比如以上例子中的 `page` 组件,从 props 中拿到的 `body` 是一个子节点,由于节点类型是不固定,由使用者决定,所以不能直接完成渲染,所以交给属性中下发的 `render` 方法去完成渲染,`{render('body', body)}`,他的工作就是拿子节点的 path 信息去组件池里面找到对应的渲染器,然后交给对应组件去完成渲染。
|
||||
|
||||
## 自定义组件
|
||||
|
||||
如果 AMis 中组件不能满足你的需求,同时你又会 React 组件开发,那么就自己定制一个吧。
|
||||
|
||||
先来看个简单的例子
|
||||
|
||||
```jsx
|
||||
import * as React from 'react';
|
||||
import {
|
||||
Renderer
|
||||
} from 'amis';
|
||||
|
||||
@Renderer({
|
||||
test: /(^|\/)my\-renderer$/,
|
||||
})
|
||||
class CustomRenderer extends React.Component {
|
||||
render() {
|
||||
const {tip} = this.props;
|
||||
return (
|
||||
<div>这是自定义组件:{tip}</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
有了以上这段代码后,就可以这样使用了。
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "page",
|
||||
"title": "自定义组件示例",
|
||||
"body": {
|
||||
"type": "my-renderer",
|
||||
"tip": "简单示例"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
如果你看了[AMis工作原理](#工作原理)应该不难理解,这里注册一个 React 组件,当节点的 path 信息是 `my-renderer` 结尾时,交给当前组件来完成渲染。
|
||||
如果你只写叶子节点的渲染器,已经可以不用看了,如果你的渲染器中有容器需要可以放置其他节点,那么接着看以下这段代码。
|
||||
|
||||
```jsx
|
||||
import * as React from 'react';
|
||||
import {
|
||||
Renderer
|
||||
} from 'amis';
|
||||
|
||||
@Renderer({
|
||||
test: /(^|\/)my\-renderer2$/,
|
||||
})
|
||||
class CustomRenderer extends React.Component {
|
||||
render() {
|
||||
const {
|
||||
tip,
|
||||
body,
|
||||
render
|
||||
} = this.props;
|
||||
return (
|
||||
<div>
|
||||
<p>这是自定义组件:{tip}</p>
|
||||
{body ? (
|
||||
<div className="container">
|
||||
{render('body', body, {
|
||||
// 这里的信息会作为 props 传递给子组件,一般情况下都不需要这个
|
||||
})}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
有了以上这段代码后,就可以这样使用了。
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "page",
|
||||
"title": "自定义组件示例",
|
||||
"body": {
|
||||
"type": "my-renderer2",
|
||||
"tip": "简单示例",
|
||||
"body": {
|
||||
"type": "form",
|
||||
"controls": [
|
||||
{
|
||||
"type": "text",
|
||||
"label": "用户名",
|
||||
"name": "usename"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
跟第一个列子不同的地方是,这里多了个 `render` 方法,这个方法就是专门用来渲染子节点的。来看下参数说明:
|
||||
|
||||
* `region` 区域名称,你有可能有多个区域可以作为容器,请不要重复。
|
||||
* `node` 子节点。
|
||||
* `props` 可选,可以通过此对象跟子节点通信等。
|
||||
|
||||
以上是普通渲染器的注册方式,如果是表单项,为了更简单的扩充,请使用 `FormItem` 注解,而不是 `Renderer`。 原因是如果用 `FormItem` 是不用关心:label怎么摆,表单验证器怎么实现,如何适配表单的3中展现方式(水平、上下和内联模式),而只用关心:有了值后如何回显,响应用户交互设置新值。
|
||||
|
||||
```jsx
|
||||
import * as React from 'react';
|
||||
import {
|
||||
FormItem
|
||||
} from 'amis';
|
||||
|
||||
@FormItem({
|
||||
type: 'custom'
|
||||
})
|
||||
class MyFormItem extends React.Component {
|
||||
render() {
|
||||
const {
|
||||
value,
|
||||
onChange
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>这个是个自定义组件</p>
|
||||
<p>当前值:{value}</p>
|
||||
<a className="btn btn-default" onClick={() => onChange(Math.round(Math.random() * 10000))}>随机修改</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
有了以上这段代码后,就可以这样使用了。
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "page",
|
||||
"title": "自定义组件示例",
|
||||
"body": {
|
||||
"type": "form",
|
||||
"controls": [
|
||||
{
|
||||
"type": "text",
|
||||
"label": "用户名",
|
||||
"name": "usename"
|
||||
},
|
||||
|
||||
{
|
||||
"type": "custom",
|
||||
"label": "随机值",
|
||||
"name": "randon"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 注意: 使用 FormItem 默认是严格模式,即只有必要的属性变化才会重新渲染,有可能满足不了你的需求,如果忽略性能问题,可以传入 `strictMode`: `false` 来关闭。
|
||||
|
||||
以上的例子都是需要先注册组件,然后再使用的,如果你在自己项目中使用,还有更简单的用法,以下示例直接无需注册。
|
||||
|
||||
```jsx
|
||||
{
|
||||
"type": "page",
|
||||
"title": "自定义组件示例",
|
||||
"body": {
|
||||
"type": "form",
|
||||
"controls": [
|
||||
{
|
||||
"type": "text",
|
||||
"label": "用户名",
|
||||
"name": "usename"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "a",
|
||||
"children": ({
|
||||
value,
|
||||
onChange
|
||||
}) => (
|
||||
<div>
|
||||
<p>这个是个自定义组件</p>
|
||||
<p>当前值:{value}</p>
|
||||
<a className="btn btn-default" onClick={() => onChange(Math.round(Math.random() * 10000))}>随机修改</a>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
即:通过 `children` 传递一个React组件,这个示例是一个React Stateless Functional Component,也可以是传统的 React 组件。
|
||||
任何节点如果包含 `children` 这个属性,则都会把当前节点交给 `children` 来处理,跳过了从 AMis 渲染器池子中选择渲染器的过程。
|
291
docs/style.md
Normal file
291
docs/style.md
Normal file
@ -0,0 +1,291 @@
|
||||
---
|
||||
title: 样式表说明
|
||||
shortname: style
|
||||
---
|
||||
|
||||
AMis 中有大量的功能类 class 可以使用,即可以用在 schema 中,也可以用在自定义组件开发中,掌握这些 class, 几乎可以不用写样式。
|
||||
|
||||
AMis 中的样式基于 [BootStrap V3](http://getbootstrap.com/css/), 这里主要讲 Bootstrap 中没有涉及到的。
|
||||
|
||||
## 图标
|
||||
|
||||
AMis 集成了 [fontawesome](http://fontawesome.io/icons/),所以关于图标部分,请前往 [fontawesome](http://fontawesome.io/icons/) 查看。
|
||||
|
||||
## 布局
|
||||
|
||||
水平布局可以考虑用 Bootstrap 的 [Grids](http://getbootstrap.com/css/#grid) 或者用 `hobx` 加 `col`
|
||||
|
||||
```html
|
||||
<div class="hbox b-a">
|
||||
<div class="col wrapper-sm bg-success">Col A</div>
|
||||
<div class="col wrapper-sm bg-info">Col B</div>
|
||||
<div class="col wrapper-sm bg-danger">Col C</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## 宽高
|
||||
|
||||
```css
|
||||
.w-1x { width: 1em; }
|
||||
.w-2x { width: 2em; }
|
||||
.w-3x { width: 3em; }
|
||||
.w-xxs { width: 60px; }
|
||||
.w-xs { width: 90px; }
|
||||
.w-sm { width: 150px; }
|
||||
.w { width: 200px; }
|
||||
.w-md { width: 240px; }
|
||||
.w-lg { width: 280px; }
|
||||
.w-xl { width: 320px; }
|
||||
.w-xxl { width: 360px; }
|
||||
.w-full { width: 100%; }
|
||||
.w-auto { width: auto; }
|
||||
.h-auto { height: auto; }
|
||||
.h-full { height: 100% !important; max-height: none !important; }
|
||||
```
|
||||
|
||||
```html
|
||||
<div class="hbox b-a bg-primary">
|
||||
<div class="col wrapper-sm b-r w-1x">w-1x</div>
|
||||
<div class="col wrapper-sm b-r w-2x">w-2x</div>
|
||||
<div class="col wrapper-sm b-r w-3x">w-3x</div>
|
||||
<div class="col wrapper-sm b-r w-xxs">w-xxs</div>
|
||||
<div class="col wrapper-sm b-r w-xs">w-xs</div>
|
||||
<div class="col wrapper-sm b-r w-sm">w-sm</div>
|
||||
<div class="col wrapper-sm b-r w">w</div>
|
||||
<div class="col wrapper-sm lter">...</div>
|
||||
</div>
|
||||
<div class="hbox b-a bg-primary m-t">
|
||||
<div class="col wrapper-sm b-r w-md">w-md</div>
|
||||
<div class="col wrapper-sm b-r w-lg">w-lg</div>
|
||||
<div class="col wrapper-sm b-r w-xl">w-xl</div>
|
||||
<div class="col wrapper-sm lter">...</div>
|
||||
</div>
|
||||
<div class="hbox b-a bg-primary m-t">
|
||||
<div class="col wrapper-sm b-r w-xxl">w-xxl</div>
|
||||
<div class="col wrapper-sm lter">...</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## 外边距
|
||||
|
||||
```css
|
||||
.m-xxs { margin: 2px 4px }
|
||||
.m-xs { margin: 5px; }
|
||||
.m-sm { margin: 10px; }
|
||||
.m { margin: 15px; }
|
||||
.m-md { margin: 20px; }
|
||||
.m-lg { margin: 30px; }
|
||||
.m-xl { margin: 50px; }
|
||||
.m-n { margin: 0 !important }
|
||||
.m-l-none { margin-left: 0 !important }
|
||||
.m-l-xs { margin-left: 5px; }
|
||||
.m-l-sm { margin-left: 10px; }
|
||||
.m-l { margin-left: 15px }
|
||||
.m-l-md { margin-left: 20px; }
|
||||
.m-l-lg { margin-left: 30px; }
|
||||
.m-l-xl { margin-left: 40px; }
|
||||
.m-l-xxl { margin-left: 50px; }
|
||||
.m-l-n-xxs { margin-left: -1px }
|
||||
.m-l-n-xs { margin-left: -5px }
|
||||
.m-l-n-sm { margin-left: -10px }
|
||||
.m-l-n { margin-left: -15px }
|
||||
.m-l-n-md { margin-left: -20px }
|
||||
.m-l-n-lg { margin-left: -30px }
|
||||
.m-l-n-xl { margin-left: -40px }
|
||||
.m-l-n-xxl { margin-left: -50px }
|
||||
.m-t-none { margin-top: 0 !important }
|
||||
.m-t-xxs { margin-top: 1px; }
|
||||
.m-t-xs { margin-top: 5px; }
|
||||
.m-t-sm { margin-top: 10px; }
|
||||
.m-t { margin-top: 15px }
|
||||
.m-t-md { margin-top: 20px; }
|
||||
.m-t-lg { margin-top: 30px; }
|
||||
.m-t-xl { margin-top: 40px; }
|
||||
.m-t-xxl { margin-top: 50px; }
|
||||
.m-t-n-xxs { margin-top: -1px }
|
||||
.m-t-n-xs { margin-top: -5px }
|
||||
.m-t-n-sm { margin-top: -10px }
|
||||
.m-t-n { margin-top: -15px }
|
||||
.m-t-n-md { margin-top: -20px }
|
||||
.m-t-n-lg { margin-top: -30px }
|
||||
.m-t-n-xl { margin-top: -40px }
|
||||
.m-t-n-xxl { margin-top: -50px }
|
||||
.m-r-none { margin-right: 0 !important }
|
||||
.m-r-xxs { margin-right: 1px }
|
||||
.m-r-xs { margin-right: 5px }
|
||||
.m-r-sm { margin-right: 10px }
|
||||
.m-r { margin-right: 15px }
|
||||
.m-r-md { margin-right: 20px }
|
||||
.m-r-lg { margin-right: 30px }
|
||||
.m-r-xl { margin-right: 40px }
|
||||
.m-r-xxl { margin-right: 50px }
|
||||
.m-r-n-xxs { margin-right: -1px }
|
||||
.m-r-n-xs { margin-right: -5px }
|
||||
.m-r-n-sm { margin-right: -10px }
|
||||
.m-r-n { margin-right: -15px }
|
||||
.m-r-n-md { margin-right: -20px }
|
||||
.m-r-n-lg { margin-right: -30px }
|
||||
.m-r-n-xl { margin-right: -40px }
|
||||
.m-r-n-xxl { margin-right: -50px }
|
||||
.m-b-none { margin-bottom: 0 !important }
|
||||
.m-b-xxs { margin-bottom: 1px; }
|
||||
.m-b-xs { margin-bottom: 5px; }
|
||||
.m-b-sm { margin-bottom: 10px; }
|
||||
.m-b { margin-bottom: 15px; }
|
||||
.m-b-md { margin-bottom: 20px; }
|
||||
.m-b-lg { margin-bottom: 30px; }
|
||||
.m-b-xl { margin-bottom: 40px; }
|
||||
.m-b-xxl { margin-bottom: 50px; }
|
||||
.m-b-n-xxs { margin-bottom: -1px }
|
||||
.m-b-n-xs { margin-bottom: -5px }
|
||||
.m-b-n-sm { margin-bottom: -10px }
|
||||
.m-b-n { margin-bottom: -15px }
|
||||
.m-b-n-md { margin-bottom: -20px }
|
||||
.m-b-n-lg { margin-bottom: -30px }
|
||||
.m-b-n-xl { margin-bottom: -40px }
|
||||
.m-b-n-xxl { margin-bottom: -50px }
|
||||
```
|
||||
|
||||
## 内边距
|
||||
|
||||
```css
|
||||
.wrapper-xs { padding: 5px; }
|
||||
.wrapper-sm { padding: 10px; }
|
||||
.wrapper { padding: 15px; }
|
||||
.wrapper-md { padding: 20px; }
|
||||
.wrapper-lg { padding: 30px; }
|
||||
.wrapper-xl { padding: 50px; }
|
||||
.padder-xs { padding-left: 5px; padding-right: 5px }
|
||||
.padder-sm { padding-left: 10px; padding-right: 10px }
|
||||
.padder-lg { padding-left: 30px; padding-right: 30px }
|
||||
.padder-md { padding-left: 20px; padding-right: 20px }
|
||||
.padder { padding-left: 15px; padding-right: 15px }
|
||||
.padder-v-xs { padding-top: 5px; padding-bottom: 5px }
|
||||
.padder-v-sm { padding-top: 10px; padding-bottom: 10px }
|
||||
.padder-v-lg { padding-top: 30px; padding-bottom: 30px }
|
||||
.padder-v-md { padding-top: 20px; padding-bottom: 20px }
|
||||
.padder-v { padding-top: 15px; padding-bottom: 15px }
|
||||
.no-padder { padding: 0 !important; }
|
||||
.pull-in { margin-left: -15px; margin-right: -15px; }
|
||||
.pull-out { margin: -10px -15px; }
|
||||
```
|
||||
|
||||
## 边框
|
||||
|
||||
```css
|
||||
.b { border: 1px solid rgba(0, 0, 0, 0.05) }
|
||||
.b-a { border: 1px solid @border-color }
|
||||
.b-t { border-top: 1px solid @border-color }
|
||||
.b-r { border-right: 1px solid @border-color }
|
||||
.b-b { border-bottom: 1px solid @border-color }
|
||||
.b-l { border-left: 1px solid @border-color }
|
||||
.b-light { border-color: @brand-light }
|
||||
.b-dark { border-color: @brand-dark }
|
||||
.b-black { border-color: @brand-dark }
|
||||
.b-primary { border-color: @brand-primary }
|
||||
.b-success { border-color: @brand-success }
|
||||
.b-info { border-color: @brand-info }
|
||||
.b-warning { border-color: @brand-warning }
|
||||
.b-danger { border-color: @brand-danger }
|
||||
.b-white { border-color: #fff }
|
||||
.b-dashed { border-style: dashed !important; }
|
||||
.b-l-light { border-left-color: @brand-light }
|
||||
.b-l-dark { border-left-color: @brand-dark }
|
||||
.b-l-black { border-left-color: @brand-dark }
|
||||
.b-l-primary { border-left-color: @brand-primary }
|
||||
.b-l-success { border-left-color: @brand-success }
|
||||
.b-l-info { border-left-color: @brand-info }
|
||||
.b-l-warning { border-left-color: @brand-warning }
|
||||
.b-l-danger { border-left-color: @brand-danger }
|
||||
.b-l-white { border-left-color: #fff }
|
||||
.b-l-2x { border-left-width: 2px }
|
||||
.b-l-3x { border-left-width: 3px }
|
||||
.b-l-4x { border-left-width: 4px }
|
||||
.b-l-5x { border-left-width: 5px }
|
||||
.b-2x { border-width: 2px }
|
||||
.b-3x { border-width: 3px }
|
||||
.b-4x { border-width: 4px }
|
||||
.b-5x { border-width: 5px }
|
||||
```
|
||||
|
||||
## 圆角
|
||||
|
||||
```css
|
||||
.r { border-radius: @border-radius-base @border-radius-base @border-radius-base @border-radius-base; }
|
||||
.r-2x { border-radius: @border-radius-base * 2; }
|
||||
.r-3x { border-radius: @border-radius-base * 3; }
|
||||
.r-l { border-radius: @border-radius-base 0 0 @border-radius-base; }
|
||||
.r-r { border-radius: 0 @border-radius-base @border-radius-base 0; }
|
||||
.r-t { border-radius: @border-radius-base @border-radius-base 0 0; }
|
||||
.r-b { border-radius: 0 0 @border-radius-base @border-radius-base; }
|
||||
```
|
||||
|
||||
|
||||
## 字体相关
|
||||
|
||||
```css
|
||||
.font-normal { font-weight: normal; }
|
||||
.font-thin { font-weight: 300; }
|
||||
.font-bold { font-weight: 700; }
|
||||
.text-3x { font-size: 3em; }
|
||||
.text-2x { font-size: 2em; }
|
||||
.text-lg { font-size: @font-size-lg; }
|
||||
.text-md { font-size: @font-size-md; }
|
||||
.text-base { font-size: @font-size-base; }
|
||||
.text-sm { font-size: @font-size-sm; }
|
||||
.text-xs { font-size: @font-size-xs; }
|
||||
.text-xxs { text-indent: -9999px }
|
||||
.text-ellipsis { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.text-u-c { text-transform: uppercase; }
|
||||
.text-l-t { text-decoration: line-through; }
|
||||
.text-u-l { text-decoration: underline; }
|
||||
```
|
||||
|
||||
|
||||
## 定位
|
||||
|
||||
```css
|
||||
.pos-rlt { position: relative; }
|
||||
.pos-stc { position: static !important; }
|
||||
.pos-abt { position: absolute; }
|
||||
.pos-fix { position: fixed; }
|
||||
```
|
||||
|
||||
## 背景
|
||||
|
||||
```html
|
||||
<div class="hbox b-a bg-light">
|
||||
<div class="col wrapper-sm b-r bg-white">bg-white</div>
|
||||
<div class="col wrapper-sm b-r bg-dark">bg-dark</div>
|
||||
<div class="col wrapper-sm b-r bg-info">bg-info</div>
|
||||
<div class="col wrapper-sm b-r bg-success">bg-sucess</div>
|
||||
<div class="col wrapper-sm b-r bg-warning">bg-warning</div>
|
||||
<div class="col wrapper-sm b-r bg-danger">bg-danger</div>
|
||||
<div class="col wrapper-sm bg-primary">bg-primary</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
## 其他
|
||||
|
||||
```css
|
||||
.show { visibility: visible; }
|
||||
.line { *width: 100%; height: 2px; margin: 10px 0; font-size: 0; overflow: hidden; background-color: transparent; border-width: 0; border-top: 1px solid @border-color; }
|
||||
.line-xs { margin: 0 }
|
||||
.line-lg { margin-top: 15px; margin-bottom: 15px }
|
||||
.line-dashed { border-style: dashed; background: transparent; }
|
||||
.no-line { border-width: 0 }
|
||||
.no-border, .no-borders { border-color: transparent; border-width: 0 }
|
||||
.no-radius { border-radius: 0 }
|
||||
.block { display: block; }
|
||||
.block.hide { display: none; }
|
||||
.inline { display: inline-block !important; }
|
||||
.none { display: none; }
|
||||
.pull-none { float: none; }
|
||||
.rounded { border-radius: 500px; }
|
||||
.clear { display: block; overflow: hidden; }
|
||||
.no-bg { background-color: transparent; color: inherit; }
|
||||
.no-select { -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }
|
||||
```
|
||||
|
||||
|
777
examples/components/App.jsx
Normal file
777
examples/components/App.jsx
Normal file
@ -0,0 +1,777 @@
|
||||
import * as React from 'react';
|
||||
import NotFound from '../../src/components/404';
|
||||
import Layout from '../../src/components/Layout';
|
||||
import AsideNav from '../../src/components/AsideNav';
|
||||
import {AlertComponent, ToastComponent} from '../../src/components/index';
|
||||
import {
|
||||
mapTree
|
||||
} from '../../src/utils/helper';
|
||||
import { Router, Route, IndexRoute, browserHistory, Link, Redirect } from 'react-router';
|
||||
import * as cx from 'classnames';
|
||||
import makeSchemaRenderer from './SchemaRender';
|
||||
import makeMarkdownRenderer from './MdRenderer';
|
||||
|
||||
import SimplePageSchema from './Page/Simple';
|
||||
import ErrorPageSchema from './Page/Error';
|
||||
import FormPageSchema from './Page/Form';
|
||||
import ModeFormSchema from './Form/Mode';
|
||||
import FieldSetFormSchema from './Form/FieldSet';
|
||||
import TabsFormSchema from './Form/Tabs';
|
||||
import RemoteFormSchema from './Form/Remote';
|
||||
import ReactionFormSchema from './Form/Reaction';
|
||||
import ValidationFormSchema from './Form/Validation';
|
||||
import FullFormSchema from './Form/Full';
|
||||
import StaticFormSchema from './Form/Static';
|
||||
import HintFormSchema from './Form/Hint';
|
||||
import FieldSetInTabsFormSchema from './Form/FieldSetInTabs';
|
||||
import ComboFormSchema from './Form/Combo';
|
||||
import SubFormSchema from './Form/SubForm';
|
||||
import RichTextSchema from './Form/RichText';
|
||||
import EditorSchema from './Form/Editor';
|
||||
import TestFormSchema from './Form/Test';
|
||||
import TableFormSchema from './Form/Table';
|
||||
import PickerFormSchema from './Form/Picker';
|
||||
import FormulaFormSchema from './Form/Formula';
|
||||
import CustomFormSchema from './Form/Custom';
|
||||
import FormLayoutTestSchema from './Form/layoutTest';
|
||||
|
||||
import TableCrudSchema from './CRUD/Table';
|
||||
import ItemActionsSchema from './CRUD/ItemActions';
|
||||
import GridCrudSchema from './CRUD/Grid';
|
||||
import ListCrudSchema from './CRUD/List';
|
||||
import LoadMoreSchema from './CRUD/LoadMore';
|
||||
import TestCrudSchema from './CRUD/test';
|
||||
import FixedCrudSchema from './CRUD/Fix';
|
||||
import AsideCrudSchema from './CRUD/Aside';
|
||||
import FieldsCrudSchema from './CRUD/Fields';
|
||||
import JumpNextCrudSchema from './CRUD/JumpNext';
|
||||
import KeyboardsCrudSchema from './CRUD/Keyboards';
|
||||
import FootableCrudSchema from './CRUD/Footable';
|
||||
import NestedCrudSchema from './CRUD/Nested';
|
||||
import MergeCellSchema from './CRUD/MergeCell';
|
||||
import SdkTest from './Sdk/Test';
|
||||
import JSONSchemaForm from './Form/Schem';
|
||||
import SimpleDialogSchema from './Dialog/Simple';
|
||||
import DrwaerSchema from './Dialog/Drawer';
|
||||
|
||||
import PageLinkPageSchema from './Linkage/Page';
|
||||
import FormLinkPageSchema from './Linkage/Form';
|
||||
import Form2LinkPageSchema from './Linkage/Form2';
|
||||
import CRUDLinkPageSchema from './Linkage/CRUD';
|
||||
import OptionsPageSchema from './Linkage/Options';
|
||||
import OptionsLocalPageSchema from './Linkage/OptionsLocal';
|
||||
import WizardSchema from './Wizard';
|
||||
import ChartSchema from './Chart';
|
||||
import HorizontalSchema from './Horizontal';
|
||||
import VideoSchema from './Video';
|
||||
import TasksSchema from './Tasks';
|
||||
import ServicesDataSchema from './Services/Data';
|
||||
import ServicesSchemaSchema from './Services/Schema';
|
||||
import ServicesFormSchema from './Services/Form';
|
||||
import IFrameSchema from './IFrame';
|
||||
|
||||
import NormalTabSchema from './Tabs/Normal';
|
||||
import FormTabSchema from './Tabs/Form';
|
||||
import Tab1Schema from './Tabs/Tab1';
|
||||
import Tab2Schema from './Tabs/Tab2';
|
||||
import Tab3Schema from './Tabs/Tab3';
|
||||
import TestComponent from './Test';
|
||||
import Select from '../../src/components/Select';
|
||||
import Button from '../../src/components/Button';
|
||||
|
||||
let PathPrefix = '/examples';
|
||||
|
||||
const navigations = [
|
||||
{
|
||||
label: '示例',
|
||||
children: [
|
||||
{
|
||||
label: '页面',
|
||||
icon: 'glyphicon glyphicon-th',
|
||||
badge: 3,
|
||||
badgeClassName: 'bg-info',
|
||||
children: [
|
||||
{
|
||||
label: '简单页面',
|
||||
path: 'pages/simple',
|
||||
component: makeSchemaRenderer(SimplePageSchema)
|
||||
},
|
||||
{
|
||||
label: '初始化出错',
|
||||
path: 'pages/error',
|
||||
component: makeSchemaRenderer(ErrorPageSchema)
|
||||
},
|
||||
{
|
||||
label: '表单页面',
|
||||
path: 'pages/form',
|
||||
component: makeSchemaRenderer(FormPageSchema)
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: '表单',
|
||||
icon: 'fa fa-list-alt',
|
||||
children: [
|
||||
{
|
||||
label: '表单展示模式',
|
||||
path: 'form/mode',
|
||||
component: makeSchemaRenderer(ModeFormSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: '所有类型汇总',
|
||||
path: 'form/full',
|
||||
component: makeSchemaRenderer(FullFormSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: '静态展示',
|
||||
path: 'form/static',
|
||||
component: makeSchemaRenderer(StaticFormSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: '输入提示',
|
||||
path: 'form/hint',
|
||||
component: makeSchemaRenderer(HintFormSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: 'FieldSet',
|
||||
path: 'form/fieldset',
|
||||
component: makeSchemaRenderer(FieldSetFormSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Tabs',
|
||||
path: 'form/tabs',
|
||||
component: makeSchemaRenderer(TabsFormSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: 'FieldSet Tabs 组合',
|
||||
path: 'form/fields-tabs',
|
||||
component: makeSchemaRenderer(FieldSetInTabsFormSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: '动态数据',
|
||||
path: 'form/remote',
|
||||
component: makeSchemaRenderer(RemoteFormSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: '显隐状态联动',
|
||||
path: 'form/reaction',
|
||||
component: makeSchemaRenderer(ReactionFormSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: '表单验证',
|
||||
path: 'form/validation',
|
||||
component: makeSchemaRenderer(ValidationFormSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: '组合类型',
|
||||
path: 'form/combo',
|
||||
component: makeSchemaRenderer(ComboFormSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: '多功能选择器',
|
||||
path: 'form/picker',
|
||||
component: makeSchemaRenderer(PickerFormSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: '子表单',
|
||||
path: 'form/sub-form',
|
||||
component: makeSchemaRenderer(SubFormSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: 'JSon Schema表单',
|
||||
path: 'form/json-schema',
|
||||
component: JSONSchemaForm
|
||||
},
|
||||
|
||||
{
|
||||
label: '富文本',
|
||||
path: 'form/rich-text',
|
||||
component: makeSchemaRenderer(RichTextSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: '代码编辑器',
|
||||
path: 'form/ide',
|
||||
component: makeSchemaRenderer(EditorSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: '自定义组件',
|
||||
path: 'form/custom',
|
||||
component: makeSchemaRenderer(CustomFormSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: '表格编辑',
|
||||
path: 'form/table',
|
||||
component: makeSchemaRenderer(TableFormSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: '公式示例',
|
||||
path: 'form/formula',
|
||||
component: makeSchemaRenderer(FormulaFormSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: '布局测试',
|
||||
path: 'form/layout-test',
|
||||
component: makeSchemaRenderer(FormLayoutTestSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: '测试',
|
||||
path: 'form/test',
|
||||
component: makeSchemaRenderer(TestFormSchema)
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: '增删改查',
|
||||
icon: 'fa fa-table',
|
||||
children: [
|
||||
{
|
||||
label: '表格模式',
|
||||
path: 'crud/table',
|
||||
component: makeSchemaRenderer(TableCrudSchema)
|
||||
},
|
||||
{
|
||||
label: '卡片模式',
|
||||
path: 'crud/grid',
|
||||
component: makeSchemaRenderer(GridCrudSchema)
|
||||
},
|
||||
{
|
||||
label: '列表模式',
|
||||
path: 'crud/list',
|
||||
component: makeSchemaRenderer(ListCrudSchema)
|
||||
},
|
||||
{
|
||||
label: '加载更多模式',
|
||||
path: 'crud/load-more',
|
||||
component: makeSchemaRenderer(LoadMoreSchema)
|
||||
},
|
||||
{
|
||||
label: '操作交互显示',
|
||||
path: 'crud/item-actions',
|
||||
component: makeSchemaRenderer(ItemActionsSchema)
|
||||
},
|
||||
{
|
||||
label: '列类型汇总',
|
||||
path: 'crud/columns',
|
||||
component: makeSchemaRenderer(FieldsCrudSchema)
|
||||
},
|
||||
{
|
||||
label: '可折叠',
|
||||
path: 'crud/footable',
|
||||
component: makeSchemaRenderer(FootableCrudSchema)
|
||||
},
|
||||
{
|
||||
label: '嵌套',
|
||||
path: 'crud/nested',
|
||||
component: makeSchemaRenderer(NestedCrudSchema)
|
||||
},
|
||||
{
|
||||
label: '合并单元格',
|
||||
path: 'crud/merge-cell',
|
||||
component: makeSchemaRenderer(MergeCellSchema)
|
||||
},
|
||||
{
|
||||
label: '带边栏',
|
||||
path: 'crud/aside',
|
||||
component: makeSchemaRenderer(AsideCrudSchema)
|
||||
},
|
||||
{
|
||||
label: '固定表头/列',
|
||||
path: 'crud/fixed',
|
||||
component: makeSchemaRenderer(FixedCrudSchema)
|
||||
},
|
||||
{
|
||||
label: '键盘操作编辑',
|
||||
path: 'crud/keyboards',
|
||||
component: makeSchemaRenderer(KeyboardsCrudSchema)
|
||||
},
|
||||
{
|
||||
label: '操作并下一个',
|
||||
path: 'crud/jump-next',
|
||||
component: makeSchemaRenderer(JumpNextCrudSchema)
|
||||
},
|
||||
{
|
||||
label: '测试',
|
||||
path: 'crud/test',
|
||||
component: makeSchemaRenderer(TestCrudSchema)
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: '弹框',
|
||||
icon: 'fa fa-bomb',
|
||||
children: [
|
||||
{
|
||||
label: '对话框',
|
||||
path: 'dialog/simple',
|
||||
component: makeSchemaRenderer(SimpleDialogSchema)
|
||||
},
|
||||
{
|
||||
label: '侧边弹出',
|
||||
path: 'dialog/drawer',
|
||||
component: makeSchemaRenderer(DrwaerSchema)
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: '选项卡',
|
||||
icon: 'fa fa-clone',
|
||||
children: [
|
||||
{
|
||||
label: '常规选项卡',
|
||||
path: 'tabs/normal',
|
||||
component: makeSchemaRenderer(NormalTabSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: '表单中选项卡分组',
|
||||
path: 'tabs/form',
|
||||
component: makeSchemaRenderer(FormTabSchema)
|
||||
},
|
||||
{
|
||||
label: '选项卡页面1',
|
||||
path: 'tabs/tab1',
|
||||
component: makeSchemaRenderer(Tab1Schema)
|
||||
},
|
||||
{
|
||||
label: '选项卡页面2',
|
||||
path: 'tabs/tab2',
|
||||
component: makeSchemaRenderer(Tab2Schema)
|
||||
},
|
||||
{
|
||||
label: '选项卡页面3',
|
||||
path: 'tabs/tab3',
|
||||
component: makeSchemaRenderer(Tab3Schema)
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: '联动',
|
||||
icon: 'fa fa-bolt',
|
||||
children: [
|
||||
{
|
||||
label: '地址栏变化自动更新',
|
||||
path: 'linkpage/page',
|
||||
component: makeSchemaRenderer(PageLinkPageSchema)
|
||||
},
|
||||
{
|
||||
label: '选项联动',
|
||||
path: 'linkpage/options-local',
|
||||
component: makeSchemaRenderer(OptionsLocalPageSchema)
|
||||
},
|
||||
{
|
||||
label: '选项远程联动',
|
||||
path: 'linkpage/options',
|
||||
component: makeSchemaRenderer(OptionsPageSchema)
|
||||
},
|
||||
{
|
||||
label: '表单和表单联动',
|
||||
path: 'linkpage/form',
|
||||
component: makeSchemaRenderer(FormLinkPageSchema)
|
||||
},
|
||||
{
|
||||
label: '表单自动更新',
|
||||
path: 'linkpage/form2',
|
||||
component: makeSchemaRenderer(Form2LinkPageSchema)
|
||||
},
|
||||
{
|
||||
label: '表单和列表联动',
|
||||
path: 'linkpage/crud',
|
||||
component: makeSchemaRenderer(CRUDLinkPageSchema)
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: '动态加载',
|
||||
icon: 'fa fa-magic',
|
||||
children: [
|
||||
{
|
||||
label: '动态加载数据',
|
||||
path: 'services/data',
|
||||
component: makeSchemaRenderer(ServicesDataSchema)
|
||||
},
|
||||
{
|
||||
label: '动态加载页面',
|
||||
path: 'services/schema',
|
||||
component: makeSchemaRenderer(ServicesSchemaSchema)
|
||||
},
|
||||
{
|
||||
label: '动态加载部分表单',
|
||||
path: 'services/form',
|
||||
component: makeSchemaRenderer(ServicesFormSchema)
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: '向导',
|
||||
icon: 'fa fa-desktop',
|
||||
path: 'wizard',
|
||||
component: makeSchemaRenderer(WizardSchema)
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
label: '排版',
|
||||
icon: 'fa fa-columns',
|
||||
path: 'horizontal',
|
||||
component: makeSchemaRenderer(HorizontalSchema)
|
||||
},
|
||||
|
||||
{
|
||||
label: '图表',
|
||||
icon: 'fa fa-bar-chart',
|
||||
path: 'chart',
|
||||
component: makeSchemaRenderer(ChartSchema)
|
||||
},
|
||||
{
|
||||
label: '视频',
|
||||
icon: 'fa fa-video-camera',
|
||||
path: 'video',
|
||||
component: makeSchemaRenderer(VideoSchema)
|
||||
},
|
||||
{
|
||||
label: '异步任务',
|
||||
icon: 'fa fa-tasks',
|
||||
path: 'task',
|
||||
component: makeSchemaRenderer(TasksSchema)
|
||||
},
|
||||
{
|
||||
label: 'IFrame',
|
||||
icon: 'fa fa-cloud',
|
||||
path: 'iframe',
|
||||
component: makeSchemaRenderer(IFrameSchema)
|
||||
},
|
||||
{
|
||||
label: 'SDK',
|
||||
icon: 'fa fa-rocket',
|
||||
path: 'sdk',
|
||||
component: SdkTest
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Test',
|
||||
icon: 'fa fa-code',
|
||||
path: 'test',
|
||||
component: TestComponent
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
prefix: ({classnames: cx}) => (<li className={cx('AsideNav-divider')}></li>),
|
||||
label: '文档',
|
||||
children: [
|
||||
{
|
||||
label: '快速开始',
|
||||
icon: 'fa fa-flash',
|
||||
path: '/v2/docs/getting-started',
|
||||
getComponent: (location, cb) => require(['../../docs/getting_started.md'], (doc) => {
|
||||
cb(null, makeMarkdownRenderer(doc));
|
||||
})
|
||||
},
|
||||
|
||||
{
|
||||
label: '高级用法',
|
||||
icon: 'fa fa-rocket',
|
||||
path: '/v2/docs/advanced',
|
||||
getComponent: (location, cb) => require(['../../docs/advanced.md'], (doc) => {
|
||||
cb(null, makeMarkdownRenderer(doc));
|
||||
})
|
||||
},
|
||||
|
||||
{
|
||||
label: '渲染器手册',
|
||||
icon: 'fa fa-diamond',
|
||||
path: '/v2/docs/renderers',
|
||||
getComponent: (location, cb) => require(['../../docs/renderers.md'], (doc) => {
|
||||
cb(null, makeMarkdownRenderer(doc));
|
||||
})
|
||||
},
|
||||
|
||||
{
|
||||
label: '开源渲染器',
|
||||
path: '/v2/docs/sdk',
|
||||
icon: 'fa fa-cubes',
|
||||
getComponent: (location, cb) => require(['../../docs/sdk.md'], (doc) => {
|
||||
cb(null, makeMarkdownRenderer(doc));
|
||||
})
|
||||
},
|
||||
|
||||
{
|
||||
label: '自定义组件',
|
||||
path: '/v2/docs/dev',
|
||||
icon: 'fa fa-code',
|
||||
getComponent: (location, cb) => require(['../../docs/dev.md'], (doc) => {
|
||||
cb(null, makeMarkdownRenderer(doc));
|
||||
})
|
||||
},
|
||||
|
||||
{
|
||||
label: '样式说明',
|
||||
path: '/v2/docs/style',
|
||||
icon: 'fa fa-laptop',
|
||||
getComponent: (location, cb) => require(['../../docs/style.md'], (doc) => {
|
||||
cb(null, makeMarkdownRenderer(doc));
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
function isActive(link, location) {
|
||||
return !!(link && link === location.pathname);
|
||||
}
|
||||
|
||||
const themes = [
|
||||
{
|
||||
label: '默认主题',
|
||||
ns: 'a-',
|
||||
value: 'default'
|
||||
},
|
||||
|
||||
{
|
||||
label: '百度云舍',
|
||||
ns: 'cxd-',
|
||||
value: 'cxd'
|
||||
}
|
||||
];
|
||||
|
||||
export class App extends React.PureComponent {
|
||||
|
||||
state = {
|
||||
asideFolded: localStorage.getItem('asideFolded') === 'true',
|
||||
offScreen: false,
|
||||
headerVisible: true,
|
||||
themeIndex: 0,
|
||||
themes: themes,
|
||||
theme: themes[localStorage.getItem('themeIndex') || 0]
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.toggleAside = this.toggleAside.bind(this);
|
||||
this.setAsideFolded = this.setAsideFolded.bind(this);
|
||||
this.setHeaderVisible = this.setHeaderVisible.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.state.theme.value !== "default") {
|
||||
document.querySelectorAll('link[title]').forEach(item => {
|
||||
item.disabled = true
|
||||
});
|
||||
document.querySelector(`link[title=${this.state.theme.value}]`).disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(preProps, preState) {
|
||||
if (preState.theme.value !== this.state.theme.value) {
|
||||
document.querySelector(`link[title=${preState.theme.value}]`).disabled = true;
|
||||
document.querySelector(`link[title=${this.state.theme.value}]`).disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
toggleAside() {
|
||||
this.setAsideFolded(!this.state.asideFolded);
|
||||
}
|
||||
|
||||
setAsideFolded(folded = false) {
|
||||
localStorage.setItem('asideFolded', JSON.stringify(folded));
|
||||
this.setState({
|
||||
asideFolded: folded
|
||||
});
|
||||
}
|
||||
|
||||
setHeaderVisible(visible = false) {
|
||||
this.setState({
|
||||
headerVisible: visible
|
||||
});
|
||||
}
|
||||
|
||||
renderAside() {
|
||||
const location = this.props.location;
|
||||
|
||||
if (location.pathname === '/edit') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const theme = this.state.theme;
|
||||
|
||||
return (
|
||||
<AsideNav
|
||||
theme={theme.value}
|
||||
navigations={navigations}
|
||||
renderLink={({link, active, toggleExpand, classnames: cx}) => {
|
||||
let children = [];
|
||||
|
||||
if (link.children) {
|
||||
children.push(
|
||||
<span
|
||||
key="expand-toggle"
|
||||
className={cx('AsideNav-itemArrow')}
|
||||
></span>
|
||||
);
|
||||
}
|
||||
|
||||
link.badge && children.push(
|
||||
<b key="badge" className={cx(`AsideNav-itemBadge`, link.badgeClassName || 'bg-info')}>{link.badge}</b>
|
||||
);
|
||||
|
||||
link.icon && children.push(
|
||||
<i key="icon" className={cx(`AsideNav-itemIcon`, link.icon)} />
|
||||
);
|
||||
|
||||
children.push(
|
||||
<span className={cx(`AsideNav-itemLabel`)} key="label">{link.label}</span>
|
||||
);
|
||||
|
||||
return link.path ? (<Link to={link.path[0] === '/' ? link.path : `${PathPrefix}/${link.path}`}>{children}</Link>) : (<a onClick={link.children ? () => toggleExpand(link) : null}>{children}</a>);
|
||||
}}
|
||||
isActive={link => isActive(link.path && link.path[0] === '/' ? link.path : `${PathPrefix}/${link.path}`, location)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderHeader() {
|
||||
const location = this.props.location;
|
||||
const theme = this.state.theme;
|
||||
|
||||
if (location.pathname === '/edit') {
|
||||
return (
|
||||
<div id="headerBar" className="box-shadow bg-dark">
|
||||
<div className={`${theme.ns}Layout-brand`}>AMis 可视化编辑器</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={`${theme.ns}Layout-brandBar`}>
|
||||
<button
|
||||
onClick={() => this.setState({offScreen: !this.state.offScreen})}
|
||||
className="pull-right visible-xs"
|
||||
>
|
||||
<i className="glyphicon glyphicon-align-justify"></i>
|
||||
</button>
|
||||
<div className={`${theme.ns}Layout-brand`}>
|
||||
<i className="fa fa-paw"></i>
|
||||
<span className="hidden-folded m-l-sm">AMis Renderer</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`${theme.ns}Layout-headerBar`}>
|
||||
<div className="nav navbar-nav hidden-xs">
|
||||
<Button
|
||||
theme={this.state.theme.value}
|
||||
level="link"
|
||||
className="no-shadow navbar-btn"
|
||||
onClick={this.toggleAside}
|
||||
tooltip="展开或收起侧边栏"
|
||||
placement="bottom"
|
||||
iconOnly
|
||||
>
|
||||
<i className={this.state.asideFolded ? 'fa fa-indent' : 'fa fa-dedent'} />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="hidden-xs p-t-sm pull-right">
|
||||
主题:{(
|
||||
<Select
|
||||
theme={this.state.theme.value}
|
||||
value={this.state.theme}
|
||||
options={this.state.themes}
|
||||
onChange={(theme) => {
|
||||
this.setState({theme});
|
||||
localStorage.setItem('themeIndex', this.state.themes.indexOf(theme));
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
// const pathname = this.props.location.pathname;
|
||||
const theme = this.state.theme;
|
||||
return (
|
||||
<Layout
|
||||
theme={theme.value}
|
||||
offScreen={this.state.offScreen}
|
||||
header={this.state.headerVisible ? this.renderHeader() : null}
|
||||
folded={this.state.asideFolded}
|
||||
aside={this.renderAside()}
|
||||
>
|
||||
<ToastComponent theme={theme.value} />
|
||||
<AlertComponent theme={theme.value} />
|
||||
{React.cloneElement(this.props.children, {
|
||||
...this.props.children.props,
|
||||
setAsideFolded: this.setAsideFolded,
|
||||
setHeaderVisible: this.setHeaderVisible,
|
||||
theme: theme.value,
|
||||
classPrefix: theme.ns
|
||||
})}
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function navigations2route(pathPrefix = '/examples') {
|
||||
let routes = [];
|
||||
|
||||
navigations.forEach(root => {
|
||||
root.children && mapTree(root.children, item => {
|
||||
if (item.path && item.component) {
|
||||
routes.push(
|
||||
<Route key={routes.length + 1} path={item.path[0] === '/' ? item.path : `${pathPrefix}/${item.path}`} component={item.component} />
|
||||
)
|
||||
} else if (item.path && item.getComponent) {
|
||||
routes.push(
|
||||
<Route key={routes.length + 1} path={item.path[0] === '/' ? item.path : `${pathPrefix}/${item.path}`} getComponent={item.getComponent} />
|
||||
)
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return routes;
|
||||
}
|
||||
|
||||
export default function entry({pathPrefix}) {
|
||||
PathPrefix = pathPrefix || '/examples';
|
||||
|
||||
return (
|
||||
<Router history={ browserHistory }>
|
||||
<Route component={App}>
|
||||
<Redirect from={`${PathPrefix}/`} to={`${PathPrefix}/pages/simple`} />
|
||||
{navigations2route(PathPrefix)}
|
||||
<Route path="*" component={NotFound} />
|
||||
</Route>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
|
332
examples/components/CRUD/Aside.jsx
Normal file
332
examples/components/CRUD/Aside.jsx
Normal file
@ -0,0 +1,332 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "带边栏联动",
|
||||
aside: {
|
||||
type: 'form',
|
||||
wrapWithPanel: false,
|
||||
target: 'window', // 直接修改location,当然也可以直接指向某个组件。
|
||||
controls: [
|
||||
{
|
||||
type: 'tree',
|
||||
name: 'cat',
|
||||
inputClassName: 'no-border',
|
||||
submitOnChange: true,
|
||||
options: [
|
||||
{
|
||||
label: '分类1',
|
||||
value: 'cat1'
|
||||
},
|
||||
|
||||
{
|
||||
label: '分类2',
|
||||
value: 'cat2'
|
||||
},
|
||||
|
||||
{
|
||||
label: '分类3',
|
||||
value: 'cat3'
|
||||
},
|
||||
|
||||
{
|
||||
label: '分类4',
|
||||
value: 'cat4'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
toolbar: [
|
||||
{
|
||||
type: "button",
|
||||
actionType: "dialog",
|
||||
label: "新增",
|
||||
primary: true,
|
||||
dialog: {
|
||||
title: "新增",
|
||||
body: {
|
||||
type: "form",
|
||||
name: "sample-edit-form",
|
||||
api: "post:/api/sample",
|
||||
controls: [
|
||||
{
|
||||
type: "text",
|
||||
name: "engine",
|
||||
label: "Engine",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "grade",
|
||||
label: "CSS grade"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
body: {
|
||||
type: "crud",
|
||||
draggable: true,
|
||||
api: "/api/sample",
|
||||
filter: {
|
||||
title: "条件搜索",
|
||||
submitText: "",
|
||||
controls: [
|
||||
{
|
||||
type: "text",
|
||||
name: "keywords",
|
||||
placeholder: "通过关键字搜索",
|
||||
addOn: {
|
||||
label: "搜索",
|
||||
type: "submit"
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "plain",
|
||||
text: "这里的表单项可以配置多个"
|
||||
}
|
||||
]
|
||||
},
|
||||
bulkActions: [
|
||||
{
|
||||
label: "批量删除",
|
||||
actionType: "ajax",
|
||||
api: "delete:/api/sample/$ids",
|
||||
confirmText: "确定要批量删除?"
|
||||
},
|
||||
{
|
||||
label: "批量修改",
|
||||
actionType: "dialog",
|
||||
dialog: {
|
||||
title: "批量编辑",
|
||||
name: "sample-bulk-edit",
|
||||
body: {
|
||||
type: "form",
|
||||
api: "/api/sample/bulkUpdate2",
|
||||
controls: [
|
||||
{
|
||||
type: 'hidden',
|
||||
name: 'ids'
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "engine",
|
||||
label: "Engine"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
quickSaveApi: "/api/sample/bulkUpdate",
|
||||
quickSaveItemApi: "/api/sample/$id",
|
||||
columns: [
|
||||
{
|
||||
name: "id",
|
||||
label: "ID",
|
||||
width: 20,
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "engine",
|
||||
label: "Rendering engine",
|
||||
sortable: true,
|
||||
searchable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "version",
|
||||
label: "Engine version",
|
||||
quickEdit: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "grade",
|
||||
label: "CSS grade",
|
||||
quickEdit: {
|
||||
mode: "inline",
|
||||
type: "select",
|
||||
options: ["A", "B", "C", "D", "X"],
|
||||
saveImmediately: true
|
||||
},
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
type: "operation",
|
||||
label: "操作",
|
||||
width: 130,
|
||||
buttons: [
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-eye",
|
||||
actionType: "dialog",
|
||||
dialog: {
|
||||
title: "查看",
|
||||
body: {
|
||||
type: "form",
|
||||
controls: [
|
||||
{
|
||||
type: "static",
|
||||
name: "engine",
|
||||
label: "Engine"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "browser",
|
||||
label: "Browser"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "platform",
|
||||
label: "Platform(s)"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "grade",
|
||||
label: "CSS grade"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "html",
|
||||
html:
|
||||
"<p>添加其他 <span>Html 片段</span> 需要支持变量替换(todo).</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-pencil",
|
||||
actionType: "dialog",
|
||||
dialog: {
|
||||
title: "编辑",
|
||||
body: {
|
||||
type: "form",
|
||||
name: "sample-edit-form",
|
||||
api: "/api/sample/$id",
|
||||
controls: [
|
||||
{
|
||||
type: "text",
|
||||
name: "engine",
|
||||
label: "Engine",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "grade",
|
||||
label: "CSS grade"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-times text-danger",
|
||||
actionType: "ajax",
|
||||
confirmText: "您确认要删除?",
|
||||
api: "delete:/api/sample/$id"
|
||||
}
|
||||
],
|
||||
toggled: true
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
80
examples/components/CRUD/Fields.jsx
Normal file
80
examples/components/CRUD/Fields.jsx
Normal file
@ -0,0 +1,80 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "增删改查列类型汇总",
|
||||
body: {
|
||||
type: "crud",
|
||||
api: "/api/mock2/crud/list",
|
||||
columns: [
|
||||
{
|
||||
name: "id",
|
||||
label: "ID",
|
||||
type: "text"
|
||||
},
|
||||
{
|
||||
name: "text",
|
||||
label: "文本",
|
||||
type: "text"
|
||||
},
|
||||
{
|
||||
type: 'image',
|
||||
label: '图片',
|
||||
name: 'image',
|
||||
popOver: {
|
||||
title: '查看大图',
|
||||
body: '<div class="w-xxl"><img class="w-full" src="${image}"/></div>'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'date',
|
||||
type: 'date',
|
||||
label: '日期'
|
||||
},
|
||||
{
|
||||
name: "progress",
|
||||
label: "进度",
|
||||
type: "progress"
|
||||
},
|
||||
{
|
||||
name: "boolean",
|
||||
label: "状态",
|
||||
type: "status"
|
||||
},
|
||||
{
|
||||
name: "boolean",
|
||||
label: "开关",
|
||||
type: "switch",
|
||||
// readOnly: false // 可以开启修改模式
|
||||
},
|
||||
{
|
||||
name: "type",
|
||||
label: "映射",
|
||||
type: "mapping",
|
||||
map: {
|
||||
"*": "其他:${type}",
|
||||
"1": "<span class='label label-info'>漂亮</span>",
|
||||
"2": "<span class='label label-success'>开心</span>",
|
||||
"3": "<span class='label label-danger'>惊吓</span>",
|
||||
"4": "<span class='label label-warning'>紧张</span>"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: 'list',
|
||||
type: 'list',
|
||||
label: 'List',
|
||||
placeholder: '-',
|
||||
size: "sm",
|
||||
listItem: {
|
||||
title: '${title}',
|
||||
subTitle: '${description}'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: 'json',
|
||||
type: 'json',
|
||||
label: 'Json'
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
301
examples/components/CRUD/Fix.jsx
Normal file
301
examples/components/CRUD/Fix.jsx
Normal file
@ -0,0 +1,301 @@
|
||||
const table = {
|
||||
type: "table",
|
||||
data: [
|
||||
{
|
||||
engine: "Other browsers",
|
||||
browser: "All others",
|
||||
platform: "-",
|
||||
version: "-",
|
||||
grade: "U",
|
||||
progress: 50,
|
||||
status: true,
|
||||
image:
|
||||
"http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg",
|
||||
weight: 56,
|
||||
others: null,
|
||||
createdAt: "2017-11-17T08:47:50.000Z",
|
||||
updatedAt: "2017-11-17T08:47:50.000Z"
|
||||
},
|
||||
{
|
||||
engine: "Misc",
|
||||
browser: "PSP browser",
|
||||
platform: "PSP",
|
||||
version: "-",
|
||||
grade: "C",
|
||||
progress: 50,
|
||||
status: true,
|
||||
image:
|
||||
"http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg",
|
||||
weight: 55,
|
||||
others: null,
|
||||
createdAt: "2017-11-17T08:47:50.000Z",
|
||||
updatedAt: "2017-11-17T08:47:50.000Z"
|
||||
},
|
||||
{
|
||||
engine: "Misc",
|
||||
browser: "PSP browser",
|
||||
platform: "PSP",
|
||||
version: "-",
|
||||
grade: "C",
|
||||
progress: 50,
|
||||
status: true,
|
||||
image:
|
||||
"http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg",
|
||||
weight: 55,
|
||||
others: null,
|
||||
createdAt: "2017-11-17T08:47:50.000Z",
|
||||
updatedAt: "2017-11-17T08:47:50.000Z"
|
||||
},
|
||||
{
|
||||
engine: "Other browsers",
|
||||
browser: "All others",
|
||||
platform: "-",
|
||||
version: "-",
|
||||
grade: "U",
|
||||
progress: 50,
|
||||
status: true,
|
||||
image:
|
||||
"http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg",
|
||||
weight: 56,
|
||||
others: null,
|
||||
createdAt: "2017-11-17T08:47:50.000Z",
|
||||
updatedAt: "2017-11-17T08:47:50.000Z"
|
||||
},
|
||||
{
|
||||
engine: "Misc",
|
||||
browser: "PSP browser",
|
||||
platform: "PSP",
|
||||
version: "-",
|
||||
grade: "C",
|
||||
progress: 50,
|
||||
status: true,
|
||||
image:
|
||||
"http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg",
|
||||
weight: 55,
|
||||
others: null,
|
||||
createdAt: "2017-11-17T08:47:50.000Z",
|
||||
updatedAt: "2017-11-17T08:47:50.000Z"
|
||||
},
|
||||
{
|
||||
engine: "Misc",
|
||||
browser: "PSP browser",
|
||||
platform: "PSP",
|
||||
version: "-",
|
||||
grade: "C",
|
||||
progress: 50,
|
||||
status: true,
|
||||
image:
|
||||
"http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg",
|
||||
weight: 55,
|
||||
others: null,
|
||||
createdAt: "2017-11-17T08:47:50.000Z",
|
||||
updatedAt: "2017-11-17T08:47:50.000Z"
|
||||
},
|
||||
{
|
||||
engine: "Other browsers",
|
||||
browser: "All others",
|
||||
platform: "-",
|
||||
version: "-",
|
||||
grade: "U",
|
||||
progress: 50,
|
||||
status: true,
|
||||
image:
|
||||
"http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg",
|
||||
weight: 56,
|
||||
others: null,
|
||||
createdAt: "2017-11-17T08:47:50.000Z",
|
||||
updatedAt: "2017-11-17T08:47:50.000Z"
|
||||
},
|
||||
{
|
||||
engine: "Misc",
|
||||
browser: "PSP browser",
|
||||
platform: "PSP",
|
||||
version: "-",
|
||||
grade: "C",
|
||||
progress: 50,
|
||||
status: true,
|
||||
image:
|
||||
"http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg",
|
||||
weight: 55,
|
||||
others: null,
|
||||
createdAt: "2017-11-17T08:47:50.000Z",
|
||||
updatedAt: "2017-11-17T08:47:50.000Z"
|
||||
},
|
||||
{
|
||||
engine: "Misc",
|
||||
browser: "PSP browser",
|
||||
platform: "PSP",
|
||||
version: "-",
|
||||
grade: "C",
|
||||
progress: 50,
|
||||
status: true,
|
||||
image:
|
||||
"http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg",
|
||||
weight: 55,
|
||||
others: null,
|
||||
createdAt: "2017-11-17T08:47:50.000Z",
|
||||
updatedAt: "2017-11-17T08:47:50.000Z"
|
||||
},
|
||||
{
|
||||
engine: "Other browsers",
|
||||
browser: "All others",
|
||||
platform: "-",
|
||||
version: "-",
|
||||
grade: "U",
|
||||
progress: 50,
|
||||
status: true,
|
||||
image:
|
||||
"http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg",
|
||||
weight: 56,
|
||||
others: null,
|
||||
createdAt: "2017-11-17T08:47:50.000Z",
|
||||
updatedAt: "2017-11-17T08:47:50.000Z"
|
||||
}
|
||||
].map((item, key) => ({
|
||||
...item,
|
||||
id: key + 1
|
||||
})),
|
||||
columns: [
|
||||
{
|
||||
name: "id",
|
||||
label: "ID",
|
||||
width: 20,
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true,
|
||||
fixed: 'left'
|
||||
},
|
||||
{
|
||||
name: "engine",
|
||||
label: "Rendering engine",
|
||||
sortable: true,
|
||||
searchable: true,
|
||||
type: "text",
|
||||
toggled: true,
|
||||
fixed: 'left'
|
||||
},
|
||||
{
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "version",
|
||||
label: "Engine version",
|
||||
quickEdit: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "grade",
|
||||
label: "CSS grade",
|
||||
quickEdit: {
|
||||
mode: "inline",
|
||||
type: "select",
|
||||
options: ["A", "B", "C", "D", "X"],
|
||||
saveImmediately: true
|
||||
},
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "version",
|
||||
label: "Engine version",
|
||||
quickEdit: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "version",
|
||||
label: "Engine version",
|
||||
quickEdit: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true,
|
||||
fixed: 'right'
|
||||
},
|
||||
{
|
||||
name: "version",
|
||||
label: "Engine version",
|
||||
quickEdit: true,
|
||||
type: "text",
|
||||
toggled: true,
|
||||
fixed: 'right'
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "固顶和列固定示例",
|
||||
remark: "bla bla bla",
|
||||
body: [
|
||||
table,
|
||||
'<div>分割</div>',
|
||||
'<div>分割</div>',
|
||||
'<div>分割</div>',
|
||||
'<div>分割</div>',
|
||||
'<div>分割</div>',
|
||||
'<div>分割</div>',
|
||||
'<div>分割</div>',
|
||||
'<div>分割</div>',
|
||||
'<div>分割</div>',
|
||||
'<div>分割</div>',
|
||||
'<div>分割</div>',
|
||||
'<div>分割</div>',
|
||||
'<div>分割</div>',
|
||||
'<div>分割</div>',
|
||||
'<div>分割</div>',
|
||||
table
|
||||
]
|
||||
};
|
197
examples/components/CRUD/Footable.jsx
Normal file
197
examples/components/CRUD/Footable.jsx
Normal file
@ -0,0 +1,197 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "开启单条底部展示功能",
|
||||
body: {
|
||||
type: "crud",
|
||||
draggable: true,
|
||||
api: "/api/sample",
|
||||
footable: {
|
||||
expand: 'first'
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
name: "id",
|
||||
label: "ID",
|
||||
width: 20,
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "engine",
|
||||
label: "Rendering engine",
|
||||
sortable: true,
|
||||
searchable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "version",
|
||||
label: "Engine version",
|
||||
quickEdit: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "grade",
|
||||
label: "CSS grade",
|
||||
breakpoint: '*',
|
||||
quickEdit: {
|
||||
mode: "inline",
|
||||
type: "select",
|
||||
options: ["A", "B", "C", "D", "X"],
|
||||
inputClassName: 'w-xs',
|
||||
saveImmediately: true
|
||||
},
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
type: "operation",
|
||||
label: "操作",
|
||||
width: 100,
|
||||
breakpoint: '*',
|
||||
buttons: [
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-eye",
|
||||
actionType: "dialog",
|
||||
dialog: {
|
||||
title: "查看",
|
||||
body: {
|
||||
type: "form",
|
||||
controls: [
|
||||
{
|
||||
type: "static",
|
||||
name: "engine",
|
||||
label: "Engine"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "browser",
|
||||
label: "Browser"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "platform",
|
||||
label: "Platform(s)"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "grade",
|
||||
label: "CSS grade"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "html",
|
||||
html:
|
||||
"<p>添加其他 <span>Html 片段</span> 需要支持变量替换(todo).</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-pencil",
|
||||
actionType: "drawer",
|
||||
drawer: {
|
||||
position: 'left',
|
||||
size: 'lg',
|
||||
title: "编辑",
|
||||
body: {
|
||||
type: "form",
|
||||
name: "sample-edit-form",
|
||||
api: "/api/sample/$id",
|
||||
controls: [
|
||||
{
|
||||
type: "text",
|
||||
name: "engine",
|
||||
label: "Engine",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
name: "grade",
|
||||
label: "CSS grade",
|
||||
options: ["A", "B", "C", "D", "X"],
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-times text-danger",
|
||||
actionType: "ajax",
|
||||
confirmText: "您确认要删除?",
|
||||
api: "delete:/api/sample/$id"
|
||||
}
|
||||
],
|
||||
toggled: true
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
221
examples/components/CRUD/Grid.jsx
Normal file
221
examples/components/CRUD/Grid.jsx
Normal file
@ -0,0 +1,221 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "增删改查示例",
|
||||
remark: "bla bla bla",
|
||||
body: {
|
||||
type: "crud",
|
||||
api: "/api/sample",
|
||||
// api: "/api/mock2/crud/table?waitSeconds=100000",
|
||||
mode: "cards",
|
||||
defaultParams: {
|
||||
perPage: 12,
|
||||
},
|
||||
// fixAlignment: true,
|
||||
masonryLayout: true,
|
||||
filter: {
|
||||
title: "条件搜索",
|
||||
submitText: "",
|
||||
controls: [
|
||||
{
|
||||
type: "text",
|
||||
name: "keywords",
|
||||
placeholder: "通过关键字搜索",
|
||||
addOn: {
|
||||
label: "搜索",
|
||||
type: "submit"
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "plain",
|
||||
text: "这只是个示例, 目前搜索对查询结果无效."
|
||||
}
|
||||
]
|
||||
},
|
||||
bulkActions: [
|
||||
{
|
||||
label: "批量删除",
|
||||
actionType: "ajax",
|
||||
api: "delete:/api/sample/${ids|raw}",
|
||||
confirmText: "确定要批量删除?"
|
||||
},
|
||||
{
|
||||
label: "批量修改",
|
||||
actionType: "dialog",
|
||||
dialog: {
|
||||
title: "批量编辑",
|
||||
name: "sample-bulk-edit",
|
||||
body: {
|
||||
type: "form",
|
||||
api: "/api/sample/bulkUpdate2",
|
||||
controls: [
|
||||
{
|
||||
type: "hidden",
|
||||
name: "ids"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "engine",
|
||||
label: "Engine"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
quickSaveApi: "/api/sample/bulkUpdate",
|
||||
quickSaveItemApi: "/api/sample/$id",
|
||||
draggable: true,
|
||||
card: {
|
||||
header: {
|
||||
title: "$engine",
|
||||
subTitle: "$platform",
|
||||
subTitlePlaceholder: "暂无说明",
|
||||
avatar:
|
||||
'<%= data.avatar || "http://bos.nj.bpc.baidu.com/showx/146bc2ce1b30f3824838f4208ad2663c" %>',
|
||||
avatarClassName: "pull-left thumb b-3x m-r"
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
type: "button",
|
||||
label: "查看",
|
||||
actionType: "dialog",
|
||||
dialog: {
|
||||
title: "查看",
|
||||
body: {
|
||||
type: "form",
|
||||
controls: [
|
||||
{
|
||||
type: "static",
|
||||
name: "engine",
|
||||
label: "Engine"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "browser",
|
||||
label: "Browser"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "platform",
|
||||
label: "Platform(s)"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "grade",
|
||||
label: "CSS grade"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "html",
|
||||
html:
|
||||
"<p>添加其他 <span>Html 片段</span> 需要支持变量替换(todo).</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
label: "编辑",
|
||||
actionType: "dialog",
|
||||
dialog: {
|
||||
title: "编辑",
|
||||
body: {
|
||||
type: "form",
|
||||
name: "sample-edit-form",
|
||||
api: "/api/sample/$id",
|
||||
controls: [
|
||||
{
|
||||
type: "text",
|
||||
name: "engine",
|
||||
label: "Engine",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "grade",
|
||||
label: "CSS grade"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
label: "删除",
|
||||
actionType: "ajax",
|
||||
confirmText: "您确认要删除?",
|
||||
api: "delete:/api/sample/$id"
|
||||
}
|
||||
],
|
||||
body: [
|
||||
{
|
||||
name: "engine",
|
||||
label: "engine",
|
||||
sortable: true,
|
||||
quickEdit: true
|
||||
},
|
||||
{
|
||||
name: "browser",
|
||||
label: "Browser"
|
||||
},
|
||||
{
|
||||
name: "platform",
|
||||
label: "Platform"
|
||||
},
|
||||
{
|
||||
name: "version",
|
||||
label: "version"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
223
examples/components/CRUD/ItemActions.jsx
Normal file
223
examples/components/CRUD/ItemActions.jsx
Normal file
@ -0,0 +1,223 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "增删改查示例",
|
||||
remark: "bla bla bla",
|
||||
body: {
|
||||
type: "crud",
|
||||
api: "/api/sample",
|
||||
headerToolbar: ['bulkActions', {
|
||||
type: 'columns-toggler',
|
||||
className: 'pull-right',
|
||||
align: 'right'
|
||||
}, {
|
||||
type: 'drag-toggler',
|
||||
className: 'pull-right'
|
||||
}, {
|
||||
type: 'pagination',
|
||||
className: 'pull-right'
|
||||
}],
|
||||
itemActions: [
|
||||
{
|
||||
type: "button",
|
||||
label: "查看",
|
||||
actionType: "dialog",
|
||||
dialog: {
|
||||
title: "查看",
|
||||
body: {
|
||||
type: "form",
|
||||
controls: [
|
||||
{
|
||||
type: "static",
|
||||
name: "engine",
|
||||
label: "Engine"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "browser",
|
||||
label: "Browser"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "platform",
|
||||
label: "Platform(s)"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "grade",
|
||||
label: "CSS grade"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "html",
|
||||
html:
|
||||
"<p>添加其他 <span>Html 片段</span> 需要支持变量替换(todo).</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
label: "编辑",
|
||||
actionType: "drawer",
|
||||
drawer: {
|
||||
position: 'left',
|
||||
size: 'lg',
|
||||
title: "编辑",
|
||||
body: {
|
||||
type: "form",
|
||||
name: "sample-edit-form",
|
||||
api: "/api/sample/$id",
|
||||
controls: [
|
||||
{
|
||||
type: "text",
|
||||
name: "engine",
|
||||
label: "Engine",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
name: "grade",
|
||||
label: "CSS grade",
|
||||
options: ["A", "B", "C", "D", "X"],
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
label: "删除",
|
||||
actionType: "ajax",
|
||||
confirmText: "您确认要删除?",
|
||||
api: "delete:/api/sample/$id"
|
||||
}
|
||||
],
|
||||
bulkActions: [
|
||||
{
|
||||
label: "批量删除",
|
||||
actionType: "ajax",
|
||||
api: "delete:/api/sample/${ids|raw}",
|
||||
confirmText: "确定要批量删除?",
|
||||
type: "button"
|
||||
},
|
||||
{
|
||||
label: "批量修改",
|
||||
actionType: "dialog",
|
||||
dialog: {
|
||||
title: "批量编辑",
|
||||
name: "sample-bulk-edit",
|
||||
body: {
|
||||
type: "form",
|
||||
api: "/api/sample/bulkUpdate2",
|
||||
controls: [
|
||||
{
|
||||
type: 'hidden',
|
||||
name: 'ids'
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "engine",
|
||||
label: "Engine"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
type: "button"
|
||||
}
|
||||
],
|
||||
columns: [
|
||||
{
|
||||
name: "id",
|
||||
label: "ID",
|
||||
width: 20,
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true,
|
||||
remark: 'Bla bla Bla'
|
||||
},
|
||||
{
|
||||
name: "engine",
|
||||
label: "Rendering engine",
|
||||
sortable: true,
|
||||
searchable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: false
|
||||
},
|
||||
{
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "version",
|
||||
label: "Engine version",
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "grade",
|
||||
label: "CSS grade",
|
||||
type: "text",
|
||||
toggled: true
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
131
examples/components/CRUD/JumpNext.jsx
Normal file
131
examples/components/CRUD/JumpNext.jsx
Normal file
@ -0,0 +1,131 @@
|
||||
export default {
|
||||
"$schema": "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
"title": "操作并下一个",
|
||||
"remark": "当存在下一条时,支持直接打开下一条操作。",
|
||||
"body": {
|
||||
"type": "crud",
|
||||
"title": "",
|
||||
"api": "/api/sample/list",
|
||||
"columnsTogglable": false,
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"label": "ID",
|
||||
"width": 20,
|
||||
"type": "text",
|
||||
"toggled": true
|
||||
},
|
||||
{
|
||||
"name": "engine",
|
||||
"label": "Rendering engine",
|
||||
"type": "text",
|
||||
"toggled": true
|
||||
},
|
||||
{
|
||||
"name": "browser",
|
||||
"label": "Browser",
|
||||
"type": "text",
|
||||
"toggled": true
|
||||
},
|
||||
{
|
||||
"type": "operation",
|
||||
"label": "操作",
|
||||
"width": 130,
|
||||
"buttons": [
|
||||
{
|
||||
"type": "button",
|
||||
"icon": "fa fa-pencil",
|
||||
"actionType": "dialog",
|
||||
"nextCondition": "true",
|
||||
"_nextCondition": "可以设置条件比如: data.grade == \"B\"",
|
||||
"dialog": {
|
||||
"title": "编辑",
|
||||
"actions": [
|
||||
{
|
||||
"type": "button",
|
||||
"actionType": "prev",
|
||||
"level": "info",
|
||||
"visibleOn": "data.hasPrev",
|
||||
"label": "上一个"
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"actionType": "cancel",
|
||||
"label": "关闭"
|
||||
},
|
||||
{
|
||||
"type": "submit",
|
||||
"actionType": "next",
|
||||
"visibleOn": "data.hasNext",
|
||||
"label": "保存并下一个",
|
||||
"level": "primary"
|
||||
},
|
||||
{
|
||||
"type": "submit",
|
||||
"visibleOn": "!data.hasNext",
|
||||
"label": "保存",
|
||||
"level": "primary"
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"actionType": "next",
|
||||
"level": "info",
|
||||
"visibleOn": "data.hasNext",
|
||||
"label": "下一个"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"type": "form",
|
||||
"name": "sample-edit-form",
|
||||
"api": "/api/sample/$id",
|
||||
"controls": [
|
||||
{
|
||||
"type": "text",
|
||||
"name": "engine",
|
||||
"label": "Engine",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"name": "browser",
|
||||
"label": "Browser",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"name": "platform",
|
||||
"label": "Platform(s)",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"name": "version",
|
||||
"label": "Engine version"
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"name": "grade",
|
||||
"label": "CSS grade"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"toggled": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
76
examples/components/CRUD/Keyboards.jsx
Normal file
76
examples/components/CRUD/Keyboards.jsx
Normal file
@ -0,0 +1,76 @@
|
||||
export default {
|
||||
"$schema": "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
"title": "Table 全键盘操作示例",
|
||||
"remark": "bla bla bla",
|
||||
"body": [
|
||||
{
|
||||
"type": "plain",
|
||||
"className": "text-danger",
|
||||
"text": "请通过上下左右键切换单元格,按 `Space` 键进入编辑模式,按 `Enter` 提交编辑,并最后点左上角的全部保存完成操作。"
|
||||
},
|
||||
{
|
||||
"type": "crud",
|
||||
"className": "m-t",
|
||||
"api": "/api/sample",
|
||||
"quickSaveApi": "/api/sample/bulkUpdate",
|
||||
"quickSaveItemApi": "/api/sample/$id",
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"label": "ID",
|
||||
"width": 20,
|
||||
"sortable": true,
|
||||
"type": "text",
|
||||
"toggled": true
|
||||
},
|
||||
{
|
||||
"name": "engine",
|
||||
"label": "Rendering engine",
|
||||
"sortable": true,
|
||||
"quickEdit": true,
|
||||
"type": "text",
|
||||
"toggled": true
|
||||
},
|
||||
{
|
||||
"name": "browser",
|
||||
"label": "Browser",
|
||||
"sortable": true,
|
||||
"quickEdit": true,
|
||||
"type": "text",
|
||||
"toggled": true
|
||||
},
|
||||
{
|
||||
"name": "platform",
|
||||
"label": "Platform(s)",
|
||||
"sortable": true,
|
||||
"quickEdit": true,
|
||||
"type": "text",
|
||||
"toggled": true
|
||||
},
|
||||
{
|
||||
"name": "version",
|
||||
"label": "Engine version",
|
||||
"quickEdit": true,
|
||||
"type": "text",
|
||||
"toggled": true
|
||||
},
|
||||
{
|
||||
"name": "grade",
|
||||
"label": "CSS grade",
|
||||
"quickEdit": {
|
||||
"type": "select",
|
||||
"options": [
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"X"
|
||||
]
|
||||
},
|
||||
"type": "text",
|
||||
"toggled": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
214
examples/components/CRUD/List.jsx
Normal file
214
examples/components/CRUD/List.jsx
Normal file
@ -0,0 +1,214 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "增删改查示例",
|
||||
remark: "bla bla bla",
|
||||
body: {
|
||||
type: "crud",
|
||||
api: "/api/sample",
|
||||
mode: "list",
|
||||
draggable: true,
|
||||
saveOrderApi: {
|
||||
url: "/api/sample/saveOrder"
|
||||
},
|
||||
orderField: "weight",
|
||||
filter: {
|
||||
title: "条件搜索",
|
||||
submitText: "",
|
||||
controls: [
|
||||
{
|
||||
type: "text",
|
||||
name: "keywords",
|
||||
placeholder: "通过关键字搜索",
|
||||
addOn: {
|
||||
label: "搜索",
|
||||
type: "submit"
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "plain",
|
||||
text: "这只是个示例, 目前搜索对查询结果无效."
|
||||
}
|
||||
]
|
||||
},
|
||||
bulkActions: [
|
||||
{
|
||||
label: "批量删除",
|
||||
actionType: "ajax",
|
||||
api: "delete:/api/sample/${ids|raw}",
|
||||
confirmText: "确定要批量删除?",
|
||||
type: "button",
|
||||
level: "danger"
|
||||
},
|
||||
{
|
||||
label: "批量修改",
|
||||
actionType: "dialog",
|
||||
level: "info",
|
||||
type: "button",
|
||||
dialog: {
|
||||
title: "批量编辑",
|
||||
body: {
|
||||
type: 'form',
|
||||
api: "/api/sample/bulkUpdate2",
|
||||
controls: [
|
||||
{type: 'hidden', name: 'ids'},
|
||||
{
|
||||
type: "text",
|
||||
name: "engine",
|
||||
label: "Engine"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
quickSaveApi: "/api/sample/bulkUpdate",
|
||||
quickSaveItemApi: "/api/sample/$id",
|
||||
listItem: {
|
||||
actions: [
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-eye",
|
||||
actionType: "dialog",
|
||||
dialog: {
|
||||
title: "查看",
|
||||
body: {
|
||||
type: "form",
|
||||
controls: [
|
||||
{
|
||||
type: "static",
|
||||
name: "engine",
|
||||
label: "Engine"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "browser",
|
||||
label: "Browser"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "platform",
|
||||
label: "Platform(s)"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "grade",
|
||||
label: "CSS grade"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "html",
|
||||
html:
|
||||
"<p>添加其他 <span>Html 片段</span> 需要支持变量替换(todo).</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-pencil",
|
||||
actionType: "dialog",
|
||||
dialog: {
|
||||
title: "编辑",
|
||||
body: {
|
||||
type: "form",
|
||||
name: "sample-edit-form",
|
||||
api: "/api/sample/$id",
|
||||
controls: [
|
||||
{
|
||||
type: "text",
|
||||
name: "engine",
|
||||
label: "Engine",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "grade",
|
||||
label: "CSS grade"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-times text-danger",
|
||||
actionType: "ajax",
|
||||
confirmText: "您确认要删除?",
|
||||
api: "delete:/api/sample/$id"
|
||||
}
|
||||
],
|
||||
body: [
|
||||
{
|
||||
name: "engine",
|
||||
label: "Rendering engine",
|
||||
sortable: true,
|
||||
quickEdit: true
|
||||
},
|
||||
[
|
||||
{
|
||||
name: "browser",
|
||||
label: "Browser"
|
||||
|
||||
},
|
||||
{
|
||||
name: "platform",
|
||||
label: "Platform(s)"
|
||||
}
|
||||
],
|
||||
{
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
223
examples/components/CRUD/LoadMore.jsx
Normal file
223
examples/components/CRUD/LoadMore.jsx
Normal file
@ -0,0 +1,223 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "增删改查示例",
|
||||
remark: "bla bla bla",
|
||||
body: {
|
||||
type: "crud",
|
||||
api: "/api/sample",
|
||||
mode: "list",
|
||||
draggable: true,
|
||||
saveOrderApi: {
|
||||
url: "/api/sample/saveOrder"
|
||||
},
|
||||
orderField: "weight",
|
||||
filter: {
|
||||
title: "条件搜索",
|
||||
submitText: "",
|
||||
controls: [
|
||||
{
|
||||
type: "text",
|
||||
name: "keywords",
|
||||
placeholder: "通过关键字搜索",
|
||||
addOn: {
|
||||
label: "搜索",
|
||||
type: "submit"
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "plain",
|
||||
text: "这只是个示例, 目前搜索对查询结果无效."
|
||||
}
|
||||
]
|
||||
},
|
||||
bulkActions: [
|
||||
{
|
||||
label: "批量删除",
|
||||
actionType: "ajax",
|
||||
api: "delete:/api/sample/${ids|raw}",
|
||||
confirmText: "确定要批量删除?",
|
||||
type: "button",
|
||||
level: "danger"
|
||||
},
|
||||
{
|
||||
label: "批量修改",
|
||||
actionType: "dialog",
|
||||
level: "info",
|
||||
type: "button",
|
||||
dialog: {
|
||||
title: "批量编辑",
|
||||
body: {
|
||||
type: 'form',
|
||||
api: "/api/sample/bulkUpdate2",
|
||||
controls: [
|
||||
{type: 'hidden', name: 'ids'},
|
||||
{
|
||||
type: "text",
|
||||
name: "engine",
|
||||
label: "Engine"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
quickSaveApi: "/api/sample/bulkUpdate",
|
||||
quickSaveItemApi: "/api/sample/$id",
|
||||
headerToolbar: [
|
||||
"bulkActions"
|
||||
],
|
||||
footerToolbar: [
|
||||
"load-more"
|
||||
],
|
||||
listItem: {
|
||||
actions: [
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-eye",
|
||||
actionType: "dialog",
|
||||
dialog: {
|
||||
title: "查看",
|
||||
body: {
|
||||
type: "form",
|
||||
controls: [
|
||||
{
|
||||
type: "static",
|
||||
name: "engine",
|
||||
label: "Engine"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "browser",
|
||||
label: "Browser"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "platform",
|
||||
label: "Platform(s)"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "grade",
|
||||
label: "CSS grade"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "html",
|
||||
html:
|
||||
"<p>添加其他 <span>Html 片段</span> 需要支持变量替换(todo).</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-pencil",
|
||||
actionType: "dialog",
|
||||
dialog: {
|
||||
title: "编辑",
|
||||
body: {
|
||||
type: "form",
|
||||
name: "sample-edit-form",
|
||||
api: "/api/sample/$id",
|
||||
controls: [
|
||||
{
|
||||
type: "text",
|
||||
name: "engine",
|
||||
label: "Engine",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "grade",
|
||||
label: "CSS grade"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-times text-danger",
|
||||
actionType: "ajax",
|
||||
confirmText: "您确认要删除?",
|
||||
api: "delete:/api/sample/$id"
|
||||
}
|
||||
],
|
||||
body: [
|
||||
{
|
||||
name: "engine",
|
||||
label: "Rendering engine",
|
||||
sortable: true,
|
||||
quickEdit: true,
|
||||
labelClassName: "w-sm pull-left text-muted"
|
||||
},
|
||||
[
|
||||
{
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
labelClassName: "w-sm pull-left text-muted"
|
||||
},
|
||||
{
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
labelClassName: "w-sm pull-left text-muted"
|
||||
}
|
||||
],
|
||||
{
|
||||
name: "version",
|
||||
label: "Engine version",
|
||||
labelClassName: "w-sm pull-left text-muted"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
104
examples/components/CRUD/MergeCell.jsx
Normal file
104
examples/components/CRUD/MergeCell.jsx
Normal file
@ -0,0 +1,104 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "支持自动合并单元格,从左到右,可配置从左侧起多少列内启动自动合并单元格,当前配置 3",
|
||||
body: {
|
||||
type: "table",
|
||||
data: {
|
||||
items: [
|
||||
{
|
||||
"engine": "Trident",
|
||||
"browser": "Internet Explorer 4.2",
|
||||
"platform": "Win 95+",
|
||||
"version": "4",
|
||||
"grade": "A"
|
||||
},
|
||||
{
|
||||
"engine": "Trident",
|
||||
"browser": "Internet Explorer 4.2",
|
||||
"platform": "Win 95+",
|
||||
"version": "4",
|
||||
"grade": "B"
|
||||
},
|
||||
{
|
||||
"engine": "Trident",
|
||||
"browser": "AOL browser (AOL desktop)",
|
||||
"platform": "Win 95+",
|
||||
"version": "4",
|
||||
"grade": "C"
|
||||
},
|
||||
{
|
||||
"engine": "Trident",
|
||||
"browser": "AOL browser (AOL desktop)",
|
||||
"platform": "Win 98",
|
||||
"version": "3",
|
||||
"grade": "A"
|
||||
},
|
||||
{
|
||||
"engine": "Trident",
|
||||
"browser": "AOL browser (AOL desktop)",
|
||||
"platform": "Win 98",
|
||||
"version": "4",
|
||||
"grade": "A"
|
||||
},
|
||||
{
|
||||
"engine": "Gecko",
|
||||
"browser": "Firefox 1.0",
|
||||
"platform": "Win 98+ / OSX.2+",
|
||||
"version": "4",
|
||||
"grade": "A"
|
||||
},
|
||||
{
|
||||
"engine": "Gecko",
|
||||
"browser": "Firefox 1.0",
|
||||
"platform": "Win 98+ / OSX.2+",
|
||||
"version": "5",
|
||||
"grade": "A"
|
||||
},
|
||||
{
|
||||
"engine": "Gecko",
|
||||
"browser": "Firefox 2.0",
|
||||
"platform": "Win 98+ / OSX.2+",
|
||||
"version": "5",
|
||||
"grade": "B"
|
||||
},
|
||||
{
|
||||
"engine": "Gecko",
|
||||
"browser": "Firefox 2.0",
|
||||
"platform": "Win 98+ / OSX.2+",
|
||||
"version": "5",
|
||||
"grade": "C"
|
||||
},
|
||||
{
|
||||
"engine": "Gecko",
|
||||
"browser": "Firefox 2.0",
|
||||
"platform": "Win 98+ / OSX.2+",
|
||||
"version": "5",
|
||||
"grade": "D"
|
||||
}
|
||||
]
|
||||
},
|
||||
combineNum: 3, // 配置自动合并单元格的列数。
|
||||
columns: [
|
||||
{
|
||||
name: "engine",
|
||||
label: "Rendering engine"
|
||||
},
|
||||
{
|
||||
name: "browser",
|
||||
label: "Browser"
|
||||
},
|
||||
{
|
||||
name: "platform",
|
||||
label: "Platform(s)"
|
||||
},
|
||||
{
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
name: "grade",
|
||||
label: "CSS grade",
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
190
examples/components/CRUD/Nested.jsx
Normal file
190
examples/components/CRUD/Nested.jsx
Normal file
@ -0,0 +1,190 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "支持多层嵌套,列数据中有 children 字段即可。(建议不超过10层)",
|
||||
body: {
|
||||
type: "crud",
|
||||
api: "/api/mock2/crud/table2",
|
||||
columns: [
|
||||
{
|
||||
name: "id",
|
||||
label: "ID",
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "engine",
|
||||
label: "Rendering engine",
|
||||
sortable: true,
|
||||
searchable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "version",
|
||||
label: "Engine version",
|
||||
quickEdit: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "grade",
|
||||
label: "CSS grade",
|
||||
quickEdit: {
|
||||
mode: "inline",
|
||||
type: "select",
|
||||
options: ["A", "B", "C", "D", "X"],
|
||||
inputClassName: 'w-xs',
|
||||
saveImmediately: true
|
||||
},
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
type: "operation",
|
||||
label: "操作",
|
||||
width: 100,
|
||||
buttons: [
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-eye",
|
||||
actionType: "dialog",
|
||||
dialog: {
|
||||
title: "查看",
|
||||
body: {
|
||||
type: "form",
|
||||
controls: [
|
||||
{
|
||||
type: "static",
|
||||
name: "engine",
|
||||
label: "Engine"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "browser",
|
||||
label: "Browser"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "platform",
|
||||
label: "Platform(s)"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "grade",
|
||||
label: "CSS grade"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "html",
|
||||
html:
|
||||
"<p>添加其他 <span>Html 片段</span> 需要支持变量替换(todo).</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-pencil",
|
||||
actionType: "drawer",
|
||||
drawer: {
|
||||
position: 'left',
|
||||
size: 'lg',
|
||||
title: "编辑",
|
||||
body: {
|
||||
type: "form",
|
||||
name: "sample-edit-form",
|
||||
api: "/api/sample/$id",
|
||||
controls: [
|
||||
{
|
||||
type: "text",
|
||||
name: "engine",
|
||||
label: "Engine",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
name: "grade",
|
||||
label: "CSS grade",
|
||||
options: ["A", "B", "C", "D", "X"],
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-times text-danger",
|
||||
actionType: "ajax",
|
||||
confirmText: "您确认要删除?",
|
||||
api: "delete:/api/sample/$id"
|
||||
}
|
||||
],
|
||||
toggled: true
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
342
examples/components/CRUD/Table.jsx
Normal file
342
examples/components/CRUD/Table.jsx
Normal file
@ -0,0 +1,342 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "增删改查示例",
|
||||
remark: "bla bla bla",
|
||||
toolbar: [
|
||||
{
|
||||
type: "button",
|
||||
actionType: "dialog",
|
||||
label: "新增",
|
||||
icon: 'fa fa-plus pull-left',
|
||||
primary: true,
|
||||
dialog: {
|
||||
title: "新增",
|
||||
body: {
|
||||
type: "form",
|
||||
name: "sample-edit-form",
|
||||
api: "post:/api/sample",
|
||||
controls: [
|
||||
{
|
||||
type: "text",
|
||||
name: "engine",
|
||||
label: "Engine",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "grade",
|
||||
label: "CSS grade"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
body: {
|
||||
type: "crud",
|
||||
draggable: true,
|
||||
api: "/api/sample?waitSeconds=1",
|
||||
keepItemSelectionOnPageChange: true,
|
||||
labelTpl: '${id} ${engine}',
|
||||
filter: {
|
||||
title: "条件搜索",
|
||||
submitText: "",
|
||||
controls: [
|
||||
{
|
||||
type: "text",
|
||||
name: "keywords",
|
||||
placeholder: "通过关键字搜索",
|
||||
addOn: {
|
||||
label: "搜索",
|
||||
type: "submit"
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "plain",
|
||||
text: "这里的表单项可以配置多个"
|
||||
}
|
||||
]
|
||||
},
|
||||
bulkActions: [
|
||||
{
|
||||
label: "批量删除",
|
||||
actionType: "ajax",
|
||||
api: "delete:/api/sample/${ids|raw}",
|
||||
confirmText: "确定要批量删除?"
|
||||
},
|
||||
{
|
||||
label: "批量修改",
|
||||
actionType: "dialog",
|
||||
dialog: {
|
||||
title: "批量编辑",
|
||||
name: "sample-bulk-edit",
|
||||
body: {
|
||||
type: "form",
|
||||
api: "/api/sample/bulkUpdate2",
|
||||
controls: [
|
||||
{
|
||||
type: 'hidden',
|
||||
name: 'ids'
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "engine",
|
||||
label: "Engine"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
quickSaveApi: "/api/sample/bulkUpdate",
|
||||
quickSaveItemApi: "/api/sample/$id",
|
||||
filterTogglable: true,
|
||||
headerToolbar: ['filter-toggler', 'bulkActions', {
|
||||
type: 'tpl',
|
||||
tpl: '定制内容示例:当前有 ${count} 条数据。',
|
||||
className: 'v-middle'
|
||||
}, {
|
||||
type: 'columns-toggler',
|
||||
align: 'right'
|
||||
}, {
|
||||
type: 'drag-toggler',
|
||||
align: 'right'
|
||||
}, {
|
||||
type: 'pagination',
|
||||
align: 'right'
|
||||
}],
|
||||
footerToolbar: ['statistics', 'switch-per-page', 'pagination'],
|
||||
columns: [
|
||||
{
|
||||
name: "id",
|
||||
label: "ID",
|
||||
width: 20,
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true,
|
||||
remark: 'Bla bla Bla'
|
||||
},
|
||||
{
|
||||
name: "engine",
|
||||
label: "Rendering engine",
|
||||
sortable: true,
|
||||
searchable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: false
|
||||
},
|
||||
{
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
sortable: true,
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
name: "version",
|
||||
label: "Engine version",
|
||||
quickEdit: true,
|
||||
type: "text",
|
||||
toggled: true,
|
||||
filterable:{
|
||||
options:[
|
||||
{
|
||||
label:'4',
|
||||
value:'4'
|
||||
},
|
||||
{
|
||||
label:'5',
|
||||
value:'5'
|
||||
},
|
||||
{
|
||||
label:'6',
|
||||
value:'6'
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "grade",
|
||||
label: "CSS grade",
|
||||
quickEdit: {
|
||||
mode: "inline",
|
||||
type: "select",
|
||||
inputClassName: 'w-xs',
|
||||
options: ["A", "B", "C", "D", "X"],
|
||||
saveImmediately: true
|
||||
},
|
||||
type: "text",
|
||||
toggled: true
|
||||
},
|
||||
{
|
||||
type: "operation",
|
||||
label: "操作",
|
||||
width: 100,
|
||||
buttons: [
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-eye",
|
||||
actionType: "dialog",
|
||||
tooltip: "查看",
|
||||
dialog: {
|
||||
title: "查看",
|
||||
body: {
|
||||
type: "form",
|
||||
controls: [
|
||||
{
|
||||
type: "static",
|
||||
name: "engine",
|
||||
label: "Engine"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "browser",
|
||||
label: "Browser"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "platform",
|
||||
label: "Platform(s)"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "grade",
|
||||
label: "CSS grade"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "html",
|
||||
html:
|
||||
"<p>添加其他 <span>Html 片段</span> 需要支持变量替换(todo).</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-pencil",
|
||||
tooltip: "编辑",
|
||||
actionType: "drawer",
|
||||
drawer: {
|
||||
position: 'left',
|
||||
size: 'lg',
|
||||
title: "编辑",
|
||||
body: {
|
||||
type: "form",
|
||||
name: "sample-edit-form",
|
||||
api: "/api/sample/$id",
|
||||
controls: [
|
||||
{
|
||||
type: "text",
|
||||
name: "engine",
|
||||
label: "Engine",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
name: "grade",
|
||||
label: "CSS grade",
|
||||
options: ["A", "B", "C", "D", "X"],
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-times text-danger",
|
||||
actionType: "ajax",
|
||||
tooltip: "删除",
|
||||
confirmText: "您确认要删除?",
|
||||
api: "delete:/api/sample/$id"
|
||||
}
|
||||
],
|
||||
toggled: true
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
92
examples/components/CRUD/test.jsx
Normal file
92
examples/components/CRUD/test.jsx
Normal file
@ -0,0 +1,92 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "Test 信息:${page}",
|
||||
body: {
|
||||
"type": "crud",
|
||||
"api": "/api/sample",
|
||||
"syncLocation": false,
|
||||
"title": null,
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"label": "ID",
|
||||
"width": 20
|
||||
},
|
||||
{
|
||||
"name": "engine",
|
||||
"label": "Rendering engine",
|
||||
"sortable": true
|
||||
},
|
||||
{
|
||||
"name": "grade",
|
||||
"type": "map",
|
||||
"label": "Rendering engine",
|
||||
"map": {
|
||||
"A": "<span class='label label-info'>A</span>",
|
||||
"B": "<span class='label label-success'>B</span>",
|
||||
"C": "<span class='label label-primary'>C</span>",
|
||||
"X": "<span class='label label-danger'>X</span>",
|
||||
"*": "Unkown"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "operation",
|
||||
"label": "操作",
|
||||
"width": 200,
|
||||
"buttons": [
|
||||
{
|
||||
"type": "button-group",
|
||||
"buttons": [
|
||||
{
|
||||
"type": "button",
|
||||
"label": "查看",
|
||||
"actionType": "dialog",
|
||||
"dialog": {
|
||||
"disabled": true,
|
||||
"body": {
|
||||
"type": "form",
|
||||
"controls": [
|
||||
{
|
||||
"name": "engine",
|
||||
"label": "Rendering engine",
|
||||
"type": "static"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"type": "button",
|
||||
"label": "编辑",
|
||||
"actionType": "dialog",
|
||||
"dialog": {
|
||||
"body": {
|
||||
"api": "/api/sample/$id",
|
||||
"type": "form",
|
||||
"controls": [
|
||||
{
|
||||
"name": "engine",
|
||||
"label": "Rendering engine",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"type": "button",
|
||||
"label": "删除",
|
||||
"level": "danger",
|
||||
"actionType": "ajax",
|
||||
"confirmText": "确定?",
|
||||
"api": "delete:/api/sample/$id"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
197
examples/components/Chart.jsx
Normal file
197
examples/components/Chart.jsx
Normal file
@ -0,0 +1,197 @@
|
||||
export default {
|
||||
"$schema": "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
"title": "图表示例",
|
||||
"body": [
|
||||
{
|
||||
"type": "grid",
|
||||
"columns": [
|
||||
{
|
||||
"type": "panel",
|
||||
"title": "本地配置示例 支持交互",
|
||||
"name": "chart-local",
|
||||
"body": [
|
||||
{
|
||||
"type": "chart",
|
||||
"config": {
|
||||
"title": {
|
||||
"text": "极坐标双数值轴"
|
||||
},
|
||||
"legend": {
|
||||
"data": [
|
||||
"line"
|
||||
]
|
||||
},
|
||||
"polar": {
|
||||
"center": [
|
||||
"50%",
|
||||
"54%"
|
||||
]
|
||||
},
|
||||
"tooltip": {
|
||||
"trigger": "axis",
|
||||
"axisPointer": {
|
||||
"type": "cross"
|
||||
}
|
||||
},
|
||||
"angleAxis": {
|
||||
"type": "value",
|
||||
"startAngle": 0
|
||||
},
|
||||
"radiusAxis": {
|
||||
"min": 0
|
||||
},
|
||||
"series": [
|
||||
{
|
||||
"coordinateSystem": "polar",
|
||||
"name": "line",
|
||||
"type": "line",
|
||||
"showSymbol": false,
|
||||
"data": [
|
||||
[
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
0.03487823687206265,
|
||||
1
|
||||
],
|
||||
[
|
||||
0.06958655048003272,
|
||||
2
|
||||
],
|
||||
[
|
||||
0.10395584540887964,
|
||||
3
|
||||
],
|
||||
[
|
||||
0.13781867790849958,
|
||||
4
|
||||
],
|
||||
[
|
||||
0.17101007166283433,
|
||||
5
|
||||
],
|
||||
[
|
||||
0.2033683215379001,
|
||||
6
|
||||
],
|
||||
[
|
||||
0.2347357813929454,
|
||||
7
|
||||
],
|
||||
[
|
||||
0.26495963211660245,
|
||||
8
|
||||
],
|
||||
[
|
||||
0.2938926261462365,
|
||||
9
|
||||
],
|
||||
[
|
||||
0.3213938048432697,
|
||||
10
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"animationDuration": 2000
|
||||
},
|
||||
clickAction: {
|
||||
actionType: 'dialog',
|
||||
dialog: {
|
||||
title: '详情',
|
||||
body: [
|
||||
{
|
||||
type: 'tpl',
|
||||
tpl: '<span>当前选中值 ${value|json}<span>'
|
||||
},
|
||||
|
||||
{
|
||||
"type": "chart",
|
||||
"api": "/api/mock2/chart/chart1"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"title": "远程图表示例(返回值带function)",
|
||||
"name": "chart-remote",
|
||||
"body": [
|
||||
{
|
||||
"type": "chart",
|
||||
"api": "/api/mock2/chart/chart1"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"title": "Form+chart组合",
|
||||
"body": [
|
||||
{
|
||||
"type": "form",
|
||||
"title": "过滤条件",
|
||||
"target": "chart1,chart2",
|
||||
"submitOnInit":true,
|
||||
"className": "m-b",
|
||||
"wrapWithPanel": false,
|
||||
"mode": "inline",
|
||||
"controls": [
|
||||
{
|
||||
"type": "date",
|
||||
"label": "开始日期",
|
||||
"name": "starttime",
|
||||
"value": "-8days",
|
||||
"maxDate": "${endtime}"
|
||||
},
|
||||
|
||||
{
|
||||
"type": "date",
|
||||
"label": "结束日期",
|
||||
"name": "endtime",
|
||||
"value": "-1days",
|
||||
"minDate": "${starttime}"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"label": "条件",
|
||||
"name": "name",
|
||||
"addOn": {
|
||||
"type": "submit",
|
||||
"label": "搜索",
|
||||
"level": "primary"
|
||||
}
|
||||
}
|
||||
],
|
||||
"actions": []
|
||||
},
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
{
|
||||
"type": "grid",
|
||||
"className": "m-t-lg",
|
||||
"columns": [
|
||||
{
|
||||
"type": "chart",
|
||||
"name": "chart1",
|
||||
"initFetch": false,
|
||||
"api": "/api/mock2/chart/chart?name=$name&starttime=${starttime}&endtime=${endtime}"
|
||||
},
|
||||
{
|
||||
"type": "chart",
|
||||
"name": "chart2",
|
||||
"initFetch": false,
|
||||
"api": "/api/mock2/chart/chart2?name=$name"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
401
examples/components/Dialog/Drawer.jsx
Normal file
401
examples/components/Dialog/Drawer.jsx
Normal file
@ -0,0 +1,401 @@
|
||||
export default {
|
||||
type: 'page',
|
||||
title: 'Drawer',
|
||||
body: [
|
||||
{
|
||||
type: 'button-toolbar',
|
||||
className: "block",
|
||||
buttons: [
|
||||
{
|
||||
type: 'button',
|
||||
label: '左侧弹出-极小框',
|
||||
actionType: 'drawer',
|
||||
drawer: {
|
||||
position: 'left',
|
||||
size: 'xs',
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '左侧弹出-小框',
|
||||
actionType: 'drawer',
|
||||
drawer: {
|
||||
position: 'left',
|
||||
size: 'sm',
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '左侧弹出-中框',
|
||||
actionType: 'drawer',
|
||||
drawer: {
|
||||
position: 'left',
|
||||
size: 'md',
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '左侧弹出-大框',
|
||||
actionType: 'drawer',
|
||||
drawer: {
|
||||
position: 'left',
|
||||
size: 'lg',
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '左侧弹出-超大',
|
||||
actionType: 'drawer',
|
||||
level: 'danger',
|
||||
drawer: {
|
||||
position: 'left',
|
||||
size: 'xl',
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button-toolbar',
|
||||
className: 'block m-t',
|
||||
buttons: [
|
||||
{
|
||||
type: 'button',
|
||||
label: '右侧弹出-极小框',
|
||||
level: 'success',
|
||||
actionType: 'drawer',
|
||||
drawer: {
|
||||
position: 'right',
|
||||
size: 'xs',
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '右侧弹出-小框',
|
||||
level: 'success',
|
||||
actionType: 'drawer',
|
||||
drawer: {
|
||||
position: 'right',
|
||||
size: 'sm',
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '右侧弹出-中框',
|
||||
level: 'success',
|
||||
actionType: 'drawer',
|
||||
drawer: {
|
||||
position: 'right',
|
||||
size: 'md',
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '右侧弹出-大框',
|
||||
level: 'success',
|
||||
actionType: 'drawer',
|
||||
drawer: {
|
||||
position: 'right',
|
||||
size: 'lg',
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '右侧弹出-超大',
|
||||
level: 'danger',
|
||||
actionType: 'drawer',
|
||||
drawer: {
|
||||
size: 'xl',
|
||||
position: 'right',
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button-toolbar',
|
||||
className: 'block m-t',
|
||||
buttons: [
|
||||
{
|
||||
type: 'button',
|
||||
label: '顶部弹出-极小框',
|
||||
actionType: 'drawer',
|
||||
level: 'info',
|
||||
drawer: {
|
||||
position: 'top',
|
||||
size: 'xs',
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '顶部弹出-小框',
|
||||
level: 'info',
|
||||
actionType: 'drawer',
|
||||
drawer: {
|
||||
position: 'top',
|
||||
size: 'sm',
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '顶部弹出-中框',
|
||||
actionType: 'drawer',
|
||||
level: 'info',
|
||||
drawer: {
|
||||
position: 'top',
|
||||
size: 'md',
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '顶部弹出-大框',
|
||||
actionType: 'drawer',
|
||||
level: 'info',
|
||||
drawer: {
|
||||
position: 'top',
|
||||
size: 'lg',
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '顶部弹出 - 超大',
|
||||
level: 'danger',
|
||||
actionType: 'drawer',
|
||||
drawer: {
|
||||
position: 'top',
|
||||
size: 'xl',
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button-toolbar',
|
||||
className: 'block m-t',
|
||||
buttons: [
|
||||
{
|
||||
type: 'button',
|
||||
label: '底部弹出-极小框',
|
||||
actionType: 'drawer',
|
||||
level: 'primary',
|
||||
drawer: {
|
||||
position: 'bottom',
|
||||
size: 'xs',
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '底部弹出-小框',
|
||||
level: 'primary',
|
||||
actionType: 'drawer',
|
||||
drawer: {
|
||||
position: 'bottom',
|
||||
size: 'sm',
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '底部弹出-中框',
|
||||
actionType: 'drawer',
|
||||
level: 'primary',
|
||||
drawer: {
|
||||
position: 'bottom',
|
||||
size: 'md',
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '底部弹出-大框',
|
||||
actionType: 'drawer',
|
||||
level: 'primary',
|
||||
drawer: {
|
||||
position: 'bottom',
|
||||
size: 'lg',
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '底部弹出-超大',
|
||||
level: 'danger',
|
||||
actionType: 'drawer',
|
||||
drawer: {
|
||||
position: 'bottom',
|
||||
size: 'xl',
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button-toolbar',
|
||||
className: 'block m-t',
|
||||
buttons: [
|
||||
{
|
||||
type: 'button',
|
||||
label: '多级弹框',
|
||||
actionType: 'drawer',
|
||||
level: 'danger',
|
||||
drawer: {
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框',
|
||||
closeOnEsc: true,
|
||||
actions: [
|
||||
{
|
||||
type: 'button',
|
||||
actionType: 'confirm',
|
||||
label: '确认',
|
||||
primary: true
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
actionType: 'drawer',
|
||||
label: '再弹一个',
|
||||
drawer: {
|
||||
position: 'left',
|
||||
title: '弹框中的弹框',
|
||||
closeOnEsc: true,
|
||||
body: '如果你想,可以无限弹下去',
|
||||
actions: [
|
||||
{
|
||||
type: 'button',
|
||||
actionType: 'drawer',
|
||||
label: '来吧',
|
||||
level: 'info',
|
||||
drawer: {
|
||||
position: 'right',
|
||||
title: '弹框中的弹框',
|
||||
closeOnEsc: true,
|
||||
body: '如果你想,可以无限弹下去',
|
||||
actions: [
|
||||
{
|
||||
type: 'button',
|
||||
actionType: 'confirm',
|
||||
label: '可以了',
|
||||
primary: true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '交叉测试',
|
||||
actionType: 'drawer',
|
||||
className: 'm-l-xs',
|
||||
level: 'danger',
|
||||
drawer: {
|
||||
title: '提示',
|
||||
closeOnEsc: true,
|
||||
body: '这是个简单的弹框',
|
||||
actions: [
|
||||
{
|
||||
type: 'button',
|
||||
actionType: 'confirm',
|
||||
label: '确认',
|
||||
primary: true
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
actionType: 'dialog',
|
||||
closeOnEsc: true,
|
||||
label: '再弹一个',
|
||||
dialog: {
|
||||
position: 'left',
|
||||
title: '弹框中的弹框',
|
||||
closeOnEsc: true,
|
||||
body: '如果你想,可以无限弹下去',
|
||||
actions: [
|
||||
{
|
||||
type: 'button',
|
||||
actionType: 'drawer',
|
||||
label: '来吧',
|
||||
level: 'info',
|
||||
drawer: {
|
||||
position: 'right',
|
||||
title: '弹框中的弹框',
|
||||
body: '如果你想,可以无限弹下去',
|
||||
closeOnEsc: true,
|
||||
actions: [
|
||||
{
|
||||
type: 'button',
|
||||
actionType: 'confirm',
|
||||
label: '可以了',
|
||||
primary: true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
}
|
266
examples/components/Dialog/Simple.jsx
Normal file
266
examples/components/Dialog/Simple.jsx
Normal file
@ -0,0 +1,266 @@
|
||||
export default {
|
||||
type: 'page',
|
||||
title: 'Dialog',
|
||||
body: [
|
||||
{
|
||||
type: 'button-toolbar',
|
||||
className: 'm-b',
|
||||
buttons: [
|
||||
{
|
||||
type: 'button',
|
||||
label: '打开弹框',
|
||||
actionType: 'dialog',
|
||||
dialog: {
|
||||
title: '提示',
|
||||
closeOnEsc: true,
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '多级弹框',
|
||||
actionType: 'dialog',
|
||||
dialog: {
|
||||
title: '提示',
|
||||
closeOnEsc: true,
|
||||
body: '这是个简单的弹框',
|
||||
actions: [
|
||||
{
|
||||
type: 'button',
|
||||
actionType: 'confirm',
|
||||
label: '确认',
|
||||
primary: true
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
actionType: 'dialog',
|
||||
label: '再弹一个',
|
||||
dialog: {
|
||||
title: '弹框中的弹框',
|
||||
closeOnEsc: true,
|
||||
body: '如果你想,可以无限弹下去',
|
||||
actions: [
|
||||
{
|
||||
type: 'button',
|
||||
actionType: 'dialog',
|
||||
label: '来吧',
|
||||
level: 'info',
|
||||
dialog: {
|
||||
title: '弹框中的弹框',
|
||||
closeOnEsc: true,
|
||||
body: '如果你想,可以无限弹下去',
|
||||
actions: [
|
||||
{
|
||||
type: 'button',
|
||||
actionType: 'confirm',
|
||||
label: '不弹了',
|
||||
primary: true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '弹个表单',
|
||||
actionType: 'dialog',
|
||||
dialog: {
|
||||
title: '在弹框中的表单',
|
||||
closeOnEsc: true,
|
||||
actions: [
|
||||
{
|
||||
label: '取消',
|
||||
actionType: 'close',
|
||||
type: 'button'
|
||||
},
|
||||
|
||||
{
|
||||
label: '确认',
|
||||
actionType: 'confirm',
|
||||
type: 'button',
|
||||
level: 'primary'
|
||||
},
|
||||
|
||||
{
|
||||
label: '提交不关闭',
|
||||
actionType: 'submit',
|
||||
close: false,
|
||||
type: 'button',
|
||||
api: '/api/mock2/form/saveForm?waitSeconds=2',
|
||||
level: 'primary'
|
||||
},
|
||||
|
||||
{
|
||||
label: '保存不关闭',
|
||||
actionType: 'ajax',
|
||||
type: 'button',
|
||||
api: '/api/mock2/form/saveForm?waitSeconds=4',
|
||||
level: 'info'
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: 'Feedback',
|
||||
close: true,
|
||||
actionType: 'ajax',
|
||||
api: '/api/mock2/form/initData?waitSeconds=2',
|
||||
tooltip: '点击我后会发送一个请求,请求回来后,弹出一个框。',
|
||||
feedback: {
|
||||
title: '操作成功',
|
||||
body: 'xxx 已操作成功'
|
||||
}
|
||||
}
|
||||
],
|
||||
body: {
|
||||
type: "form",
|
||||
api: "/api/mock2/form/saveForm?waitSeconds=2",
|
||||
title: "常规模式",
|
||||
mode: "normal",
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email",
|
||||
required: true,
|
||||
placeholder: "请输入邮箱",
|
||||
label: "邮箱"
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password",
|
||||
label: "密码",
|
||||
required: true,
|
||||
placeholder: "请输入密码"
|
||||
},
|
||||
{
|
||||
type: "checkbox",
|
||||
name: "rememberMe",
|
||||
label: "记住登录"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '再弹个表单',
|
||||
actionType: 'dialog',
|
||||
dialog: {
|
||||
title: '在弹框中的表单',
|
||||
actions: [
|
||||
{
|
||||
label: '取消',
|
||||
actionType: 'close',
|
||||
type: 'button'
|
||||
},
|
||||
|
||||
{
|
||||
label: '确认',
|
||||
actionType: 'confirm',
|
||||
type: 'button',
|
||||
level: 'primary',
|
||||
disabledOn: '!data.rememberMe'
|
||||
}
|
||||
],
|
||||
body: {
|
||||
type: "form",
|
||||
api: "/api/mock2/form/saveForm?waitSeconds=2",
|
||||
title: "常规模式",
|
||||
mode: "normal",
|
||||
controls: [
|
||||
{
|
||||
type: "checkbox",
|
||||
name: "rememberMe",
|
||||
label: "勾上我才可以确认"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: 'Feedback',
|
||||
actionType: 'ajax',
|
||||
api: '/api/mock2/form/initData?waitSeconds=2',
|
||||
tooltip: '点击我后会发送一个请求,请求回来后,弹出一个框。',
|
||||
feedback: {
|
||||
title: '操作成功',
|
||||
closeOnEsc: true,
|
||||
body: 'xxx 已操作成功'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: 'Feedback2',
|
||||
actionType: 'ajax',
|
||||
api: '/api/mock2/form/initData?waitSeconds=2',
|
||||
tooltip: '可以根据条件弹出,比如这个栗子,看当前时间戳是否可以整除3',
|
||||
feedback: {
|
||||
visibleOn: '!(this.date % 3)',
|
||||
title: '操作成功',
|
||||
body: '当前时间戳: <code>${date}</code>'
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: "button-toolbar",
|
||||
className: 'm-l-none',
|
||||
buttons: [
|
||||
{
|
||||
type: 'button',
|
||||
label: 'sm 弹框',
|
||||
actionType: 'dialog',
|
||||
dialog: {
|
||||
size: "sm",
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '标准 弹框',
|
||||
actionType: 'dialog',
|
||||
dialog: {
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: 'lg 弹框',
|
||||
actionType: 'dialog',
|
||||
dialog: {
|
||||
size: "lg",
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: 'xl 弹框',
|
||||
actionType: 'dialog',
|
||||
dialog: {
|
||||
size: "xl",
|
||||
title: '提示',
|
||||
body: '这是个简单的弹框'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
}
|
51
examples/components/Editor.jsx
Normal file
51
examples/components/Editor.jsx
Normal file
@ -0,0 +1,51 @@
|
||||
import * as React from 'react';
|
||||
import Editor from '../../src/editor/Editor';
|
||||
import Switch from '../../src/components/Switch';
|
||||
import Button from '../../src/components/Button';
|
||||
import schema from './Form/Test';
|
||||
import { Portal } from 'react-overlays';
|
||||
|
||||
export default class AMisSchemaEditor extends React.Component {
|
||||
|
||||
state = {
|
||||
preview: localStorage.getItem('editting_preview') ? true : false,
|
||||
schema: localStorage.getItem('editting_schema') ? JSON.parse(localStorage.getItem('editting_schema')) : schema
|
||||
};
|
||||
|
||||
handleChange = (value) => {
|
||||
localStorage.setItem('editting_schema', JSON.stringify(value));
|
||||
|
||||
this.setState({
|
||||
schema: value
|
||||
});
|
||||
}
|
||||
handlePreviewChange = (preview) => {
|
||||
localStorage.setItem('editting_preview', preview ? 'true' : '');
|
||||
|
||||
this.setState({
|
||||
preview: !!preview
|
||||
});
|
||||
}
|
||||
clearCache = () => {
|
||||
localStorage.removeItem('editting_schema');
|
||||
this.setState({
|
||||
schema: schema
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="h-full">
|
||||
<Portal container={() => document.querySelector('#headerBar')}>
|
||||
<div className="inline m-l" >
|
||||
预览 <Switch value={this.state.preview} onChange={this.handlePreviewChange} className="v-middle" inline />
|
||||
<Button size="sm" className="m-l" onClick={this.clearCache}>清除缓存</Button>
|
||||
</div>
|
||||
</Portal>
|
||||
|
||||
|
||||
<Editor preview={this.state.preview} value={this.state.schema} onChange={this.handleChange} className="fix-settings" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
339
examples/components/Form/Combo.jsx
Normal file
339
examples/components/Form/Combo.jsx
Normal file
@ -0,0 +1,339 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "Combo 示例",
|
||||
body: [
|
||||
{
|
||||
type: "form",
|
||||
api: "/api/mock2/saveForm?waitSeconds=2",
|
||||
title: "",
|
||||
mode: "horizontal",
|
||||
// debug: true,
|
||||
controls: [
|
||||
{
|
||||
type: 'text',
|
||||
label: '文本',
|
||||
name: 'a'
|
||||
},
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
{
|
||||
type: "combo",
|
||||
name: "combo1",
|
||||
label: "组合多条多行",
|
||||
multiple: true,
|
||||
multiLine: true,
|
||||
value: [{}],
|
||||
controls: [
|
||||
{
|
||||
name: "a",
|
||||
label: "文本",
|
||||
type: "text",
|
||||
placeholder: "文本",
|
||||
value: '',
|
||||
size: 'full'
|
||||
},
|
||||
{
|
||||
name: "b",
|
||||
label: "选项",
|
||||
type: "select",
|
||||
options: ["a", "b", "c"],
|
||||
size: 'full'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: "button",
|
||||
label: "独立排序",
|
||||
level: "dark",
|
||||
className: "m-t-n-xs",
|
||||
size: "sm",
|
||||
actionType: "dialog",
|
||||
visibleOn: "data.combo1.length > 1",
|
||||
dialog: {
|
||||
title: "对 Combo 进行 拖拽排序",
|
||||
body: {
|
||||
type: "form",
|
||||
controls: [
|
||||
{
|
||||
type: "combo",
|
||||
name: "combo1",
|
||||
label: false,
|
||||
multiple: true,
|
||||
draggable: true,
|
||||
addable: false,
|
||||
removable: false,
|
||||
value: [{}],
|
||||
controls: [
|
||||
{
|
||||
name: "a",
|
||||
type: "static",
|
||||
tpl: "${a} - ${b}"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
type: "submit",
|
||||
mergeData: true,
|
||||
label: "确认",
|
||||
level: "primary"
|
||||
},
|
||||
|
||||
{
|
||||
type: "button",
|
||||
actionType: "close",
|
||||
label: "取消"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: "combo",
|
||||
name: "combo2",
|
||||
label: "组合多条单行",
|
||||
multiple: true,
|
||||
value: [{}],
|
||||
controls: [
|
||||
{
|
||||
name: "a",
|
||||
type: "text",
|
||||
placeholder: "文本",
|
||||
value: ''
|
||||
},
|
||||
{
|
||||
name: "b",
|
||||
type: "select",
|
||||
options: ["a", "b", "c"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
{
|
||||
type: "combo",
|
||||
name: "combo3",
|
||||
label: "组合单条多行",
|
||||
multiLine: true,
|
||||
controls: [
|
||||
{
|
||||
name: "a",
|
||||
label: "文本",
|
||||
type: "text",
|
||||
placeholder: "文本",
|
||||
value: '',
|
||||
size: 'full'
|
||||
},
|
||||
{
|
||||
name: "b",
|
||||
label: "选项",
|
||||
type: "select",
|
||||
options: ["a", "b", "c"]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: "combo",
|
||||
name: "combo4",
|
||||
label: "组合单条单行",
|
||||
controls: [
|
||||
{
|
||||
name: "a",
|
||||
type: "text",
|
||||
placeholder: "文本",
|
||||
value: '',
|
||||
size: 'full'
|
||||
},
|
||||
{
|
||||
name: "b",
|
||||
type: "select",
|
||||
options: ["a", "b", "c"]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
{
|
||||
type: "combo",
|
||||
name: "combo11",
|
||||
label: "组合多条多行内联",
|
||||
multiple: true,
|
||||
multiLine: true,
|
||||
inline: true,
|
||||
value: [{}],
|
||||
controls: [
|
||||
{
|
||||
name: "a",
|
||||
label: "文本",
|
||||
type: "text",
|
||||
placeholder: "文本",
|
||||
value: ''
|
||||
},
|
||||
{
|
||||
name: "b",
|
||||
label: "选项",
|
||||
type: "select",
|
||||
options: ["a", "b", "c"]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: "combo",
|
||||
name: "combo22",
|
||||
label: "组合多条单行内联",
|
||||
multiple: true,
|
||||
inline: true,
|
||||
value: [{}],
|
||||
controls: [
|
||||
{
|
||||
name: "a",
|
||||
type: "text",
|
||||
placeholder: "文本",
|
||||
value: ''
|
||||
},
|
||||
{
|
||||
name: "b",
|
||||
type: "select",
|
||||
options: ["a", "b", "c"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
{
|
||||
type: "combo",
|
||||
name: "combo33",
|
||||
label: "组合单条多行内联",
|
||||
multiLine: true,
|
||||
inline: true,
|
||||
controls: [
|
||||
{
|
||||
name: "a",
|
||||
label: "文本",
|
||||
type: "text",
|
||||
placeholder: "文本",
|
||||
value: ''
|
||||
},
|
||||
{
|
||||
name: "b",
|
||||
label: "选项",
|
||||
type: "select",
|
||||
options: ["a", "b", "c"]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: "combo",
|
||||
name: "combo44",
|
||||
label: "组合单条单行内联",
|
||||
inline: true,
|
||||
controls: [
|
||||
{
|
||||
name: "a",
|
||||
type: "text",
|
||||
placeholder: "文本",
|
||||
value: ''
|
||||
},
|
||||
{
|
||||
name: "b",
|
||||
type: "select",
|
||||
options: ["a", "b", "c"]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
||||
{
|
||||
type: "combo",
|
||||
name: "combo666",
|
||||
label: "组合多条唯一",
|
||||
multiple: true,
|
||||
value: [{}],
|
||||
controls: [
|
||||
{
|
||||
name: "a",
|
||||
type: "text",
|
||||
placeholder: "文本",
|
||||
value: '',
|
||||
unique: true
|
||||
},
|
||||
{
|
||||
name: "b",
|
||||
type: "select",
|
||||
options: ["a", "b", "c"],
|
||||
unique: true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
||||
{
|
||||
type: "combo",
|
||||
name: "combo777",
|
||||
label: "可拖拽排序",
|
||||
multiple: true,
|
||||
value: [{a: '1', b: "a"}, {a: '2', b: "b"}],
|
||||
draggable: true,
|
||||
controls: [
|
||||
{
|
||||
name: "a",
|
||||
type: "text",
|
||||
placeholder: "文本",
|
||||
unique: true
|
||||
},
|
||||
{
|
||||
name: "b",
|
||||
type: "select",
|
||||
options: ["a", "b", "c"],
|
||||
unique: true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
||||
{
|
||||
type: "combo",
|
||||
name: "combo888",
|
||||
label: "可打平只存储值",
|
||||
multiple: true,
|
||||
flat: true,
|
||||
value: ["red", "pink"],
|
||||
draggable: true,
|
||||
controls: [
|
||||
{
|
||||
name: "a",
|
||||
type: "color",
|
||||
placeholder: "选取颜色"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "combo888",
|
||||
label: "当前值",
|
||||
tpl: "<pre>${combo888|json}</pre>"
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
95
examples/components/Form/Custom.jsx
Normal file
95
examples/components/Form/Custom.jsx
Normal file
@ -0,0 +1,95 @@
|
||||
import * as React from 'react';
|
||||
import {
|
||||
FormItem,
|
||||
Renderer
|
||||
} from '../../../src/index';
|
||||
|
||||
@FormItem({
|
||||
type: 'custom'
|
||||
})
|
||||
class MyFormItem extends React.Component {
|
||||
render() {
|
||||
const {
|
||||
value,
|
||||
onChange
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>这个是个自定义组件。通过注册渲染器的方式实现。</p>
|
||||
|
||||
<p>当前值:{value}</p>
|
||||
|
||||
<a className="btn btn-default" onClick={() => onChange(Math.round(Math.random() * 10000))}>随机修改</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Renderer({
|
||||
test: /(^|\/)my\-renderer$/,
|
||||
})
|
||||
class CustomRenderer extends React.Component {
|
||||
render() {
|
||||
const {tip} = this.props;
|
||||
return (
|
||||
<div>{tip || '非 FormItem 类型的渲染器注册, 这种不能修改 form'}</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "自定义组件示例",
|
||||
body: [
|
||||
{
|
||||
type: "form",
|
||||
mode: "horizontal",
|
||||
api: "/api/mock2/form/saveForm?waitSeconds=2",
|
||||
actions: [
|
||||
{
|
||||
type: "submit",
|
||||
label: "提交",
|
||||
primary: true
|
||||
}
|
||||
],
|
||||
controls: [
|
||||
{
|
||||
name: 'a',
|
||||
children: ({value, onChange}) => (
|
||||
<div>
|
||||
<p>这个是个自定义组件。最简单直接的方式,不用注册直接使用。</p>
|
||||
|
||||
<p>当前值:{value}</p>
|
||||
|
||||
<a className="btn btn-default" onClick={() => onChange(Math.round(Math.random() * 10000))}>随机修改</a>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
||||
{
|
||||
name: 'b',
|
||||
type: 'custom',
|
||||
label: '自定义FormItem'
|
||||
},
|
||||
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
||||
{
|
||||
type: 'my-renderer'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'my-renderer',
|
||||
tip: '他能放 controls 里面,也能放外面。'
|
||||
}
|
||||
]
|
||||
};
|
35
examples/components/Form/Editor.jsx
Normal file
35
examples/components/Form/Editor.jsx
Normal file
@ -0,0 +1,35 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "Editor",
|
||||
body: [
|
||||
{
|
||||
type: "form",
|
||||
api: "/api/mock2/saveForm?waitSeconds=2",
|
||||
title: "",
|
||||
controls: [
|
||||
{
|
||||
name: "javascript",
|
||||
type: "javascript-editor",
|
||||
label: "Javascript",
|
||||
value: "console.log(1, 2, 3);"
|
||||
},
|
||||
|
||||
{
|
||||
name: "html",
|
||||
type: "html-editor",
|
||||
label: "Html",
|
||||
value: "<html><head><title>Hello</title></head><body><p>world</p></body></html>"
|
||||
},
|
||||
|
||||
{
|
||||
name: "css",
|
||||
type: "css-editor",
|
||||
label: "CSS",
|
||||
value: "body {color: red;}"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
147
examples/components/Form/FieldSet.jsx
Normal file
147
examples/components/Form/FieldSet.jsx
Normal file
@ -0,0 +1,147 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "FieldSet 示例",
|
||||
body: [
|
||||
{
|
||||
type: "form",
|
||||
mode: "horizontal",
|
||||
api: "/api/mock2/saveForm?waitSeconds=2",
|
||||
actions: [
|
||||
{
|
||||
type: "submit",
|
||||
label: "提交",
|
||||
primary: true
|
||||
}
|
||||
],
|
||||
collapsable: true,
|
||||
title: 'fieldSet 可以对表单元素做个分组',
|
||||
controls: [
|
||||
{
|
||||
type: 'fieldSet',
|
||||
title: '基本信息',
|
||||
controls: [
|
||||
{
|
||||
type: 'group',
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email",
|
||||
placeholder: "请输入邮箱地址",
|
||||
label: "邮箱"
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password",
|
||||
label: false,
|
||||
placeholder: "Password"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email",
|
||||
placeholder: "请输入邮箱地址",
|
||||
label: "邮箱"
|
||||
},
|
||||
{
|
||||
type: "checkbox",
|
||||
name: "rememberMe",
|
||||
label: false,
|
||||
option: "Remember me"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
title: '其他信息',
|
||||
type: 'fieldSet',
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email",
|
||||
placeholder: "请输入邮箱地址",
|
||||
label: "邮箱"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "checkbox",
|
||||
name: "rememberMe",
|
||||
option: "记住我"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "FieldSet 样式集",
|
||||
type: "form",
|
||||
controls: [
|
||||
{
|
||||
title: "超级小",
|
||||
type: 'fieldSet',
|
||||
className: "fieldset-xs",
|
||||
controls: [
|
||||
{
|
||||
type: "plain",
|
||||
text: "文本 ..."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "小尺寸",
|
||||
type: 'fieldSet',
|
||||
className: "fieldset-sm",
|
||||
controls: [
|
||||
{
|
||||
type: "plain",
|
||||
text: "文本 ..."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "正常尺寸",
|
||||
type: 'fieldSet',
|
||||
className: "fieldset",
|
||||
controls: [
|
||||
{
|
||||
type: "plain",
|
||||
text: "文本 ..."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "中大尺寸",
|
||||
type: 'fieldSet',
|
||||
className: "fieldset-md",
|
||||
controls: [
|
||||
{
|
||||
type: "plain",
|
||||
text: "文本 ..."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "超大尺寸",
|
||||
type: 'fieldSet',
|
||||
className: "fieldset-lg",
|
||||
controls: [
|
||||
{
|
||||
type: "plain",
|
||||
text: "文本 ..."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
101
examples/components/Form/FieldSetInTabs.jsx
Normal file
101
examples/components/Form/FieldSetInTabs.jsx
Normal file
@ -0,0 +1,101 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "FieldSet In Tabs",
|
||||
remark: "",
|
||||
body: {
|
||||
type: "form",
|
||||
collapsable: true,
|
||||
tabs: [
|
||||
{
|
||||
title: "Tab A",
|
||||
fieldSet: [
|
||||
{
|
||||
title: "Group A",
|
||||
tabs: [
|
||||
{
|
||||
title: "SubTab A",
|
||||
controls: [
|
||||
{
|
||||
name: "a",
|
||||
type: "text",
|
||||
label: "Text"
|
||||
},
|
||||
{
|
||||
name: "a",
|
||||
type: "text",
|
||||
label: "Text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "SubTab B",
|
||||
controls: [
|
||||
{
|
||||
name: "a",
|
||||
type: "text",
|
||||
label: "Text"
|
||||
},
|
||||
{
|
||||
name: "a",
|
||||
type: "text",
|
||||
label: "Text"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Group B",
|
||||
controls: [
|
||||
{
|
||||
name: "a",
|
||||
type: "text",
|
||||
label: "Text"
|
||||
},
|
||||
{
|
||||
name: "a",
|
||||
type: "text",
|
||||
label: "Text"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Tab B",
|
||||
fieldSet: [
|
||||
{
|
||||
title: "Group A",
|
||||
controls: [
|
||||
{
|
||||
name: "a",
|
||||
type: "text",
|
||||
label: "Text"
|
||||
},
|
||||
{
|
||||
name: "a",
|
||||
type: "text",
|
||||
label: "Text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Group B",
|
||||
controls: [
|
||||
{
|
||||
name: "a",
|
||||
type: "text",
|
||||
label: "Text"
|
||||
},
|
||||
{
|
||||
name: "a",
|
||||
type: "text",
|
||||
label: "Text"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
127
examples/components/Form/Formula.jsx
Normal file
127
examples/components/Form/Formula.jsx
Normal file
@ -0,0 +1,127 @@
|
||||
export default {
|
||||
"$schema": "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
"title": "公式示例",
|
||||
"body": [
|
||||
"<p>通过公式,可以动态的设置目标值。</p>",
|
||||
{
|
||||
"type": "form",
|
||||
title: "自动应用",
|
||||
"api": "/api/mock2/form/saveForm",
|
||||
"controls": [
|
||||
{
|
||||
"type": "number",
|
||||
"name": "a",
|
||||
"label": "A"
|
||||
},
|
||||
|
||||
{
|
||||
"type": "number",
|
||||
"name": "b",
|
||||
"label": "B"
|
||||
},
|
||||
|
||||
{
|
||||
"type": "number",
|
||||
"name": "sum",
|
||||
"label": "和",
|
||||
"disabled": true,
|
||||
description: '自动计算 A + B'
|
||||
},
|
||||
|
||||
{
|
||||
"type": "formula",
|
||||
"name": "sum",
|
||||
"value": 0,
|
||||
"formula": "a + b"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"type": "form",
|
||||
title: "手动应用",
|
||||
"api": "/api/mock2/form/saveForm",
|
||||
"controls": [
|
||||
{
|
||||
"type": "number",
|
||||
"name": "a",
|
||||
"label": "A"
|
||||
},
|
||||
|
||||
{
|
||||
"type": "number",
|
||||
"name": "b",
|
||||
"label": "B"
|
||||
},
|
||||
|
||||
{
|
||||
type: "group",
|
||||
controls: [
|
||||
{
|
||||
"type": "number",
|
||||
"name": "sum",
|
||||
"label": "和",
|
||||
"disabled": true,
|
||||
"columnClassName": "col-sm-11",
|
||||
},
|
||||
|
||||
{
|
||||
"type": "button",
|
||||
"label": "计算",
|
||||
"columnClassName": "col-sm-1 v-bottom",
|
||||
"target": "theFormula"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"type": "formula",
|
||||
"name": "sum",
|
||||
"id": "theFormula",
|
||||
"value": 0,
|
||||
"formula": "a + b",
|
||||
"initSet": false,
|
||||
"autoSet": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "form",
|
||||
title: "条件应用",
|
||||
"api": "/api/mock2/form/saveForm",
|
||||
"controls": [
|
||||
{
|
||||
"type": "radios",
|
||||
"name": "radios",
|
||||
"inline": true,
|
||||
"label": "radios",
|
||||
"options": [
|
||||
{
|
||||
"label": 'a',
|
||||
"value": 'a'
|
||||
},
|
||||
{
|
||||
"label": 'b',
|
||||
"value": 'b'
|
||||
},
|
||||
],
|
||||
"description": 'radios 变化会自动清空 B'
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"name": "b",
|
||||
"label": "B"
|
||||
},
|
||||
|
||||
{
|
||||
"type": "formula",
|
||||
"name": "b",
|
||||
"value": 'some string',
|
||||
"formula": "''",
|
||||
"condition": '${radios}',
|
||||
"initSet": false,
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
1168
examples/components/Form/Full.jsx
Normal file
1168
examples/components/Form/Full.jsx
Normal file
File diff suppressed because it is too large
Load Diff
96
examples/components/Form/Hint.jsx
Normal file
96
examples/components/Form/Hint.jsx
Normal file
@ -0,0 +1,96 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "其他类型演示",
|
||||
body: [
|
||||
{
|
||||
type: "form",
|
||||
api: "/api/mock2/saveForm?waitSeconds=2",
|
||||
title: "Hint demo",
|
||||
mode: "horizontal",
|
||||
horizontal: {
|
||||
leftFixed: true
|
||||
},
|
||||
controls: [
|
||||
{
|
||||
name: "button",
|
||||
type: "button",
|
||||
label: "ID",
|
||||
value: "",
|
||||
size: 'xs',
|
||||
hint: '比如输入 a-xxxx-xxx'
|
||||
},
|
||||
|
||||
{
|
||||
"type": "input-group",
|
||||
"size": "md",
|
||||
"label": "Icon 组合",
|
||||
"controls": [
|
||||
{
|
||||
"type": "icon",
|
||||
"addOnclassName": "no-bg",
|
||||
className: "text-sm",
|
||||
"icon": "search",
|
||||
"vendor": "iconfont"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"placeholder": "搜索作业ID/名称",
|
||||
"inputClassName": "b-l-none p-l-none",
|
||||
"name": "jobName"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
name: "a",
|
||||
type: "text",
|
||||
label: "ID",
|
||||
value: "",
|
||||
size: 'xs',
|
||||
hint: '比如输入 a-xxxx-xxx'
|
||||
},
|
||||
|
||||
{
|
||||
name: "b",
|
||||
type: "text",
|
||||
label: "ID",
|
||||
value: "",
|
||||
size: 'sm',
|
||||
hint: '比如输入 a-xxxx-xxx'
|
||||
},
|
||||
|
||||
{
|
||||
name: "c",
|
||||
type: "text",
|
||||
label: "ID",
|
||||
value: "",
|
||||
size: 'md',
|
||||
hint: '比如输入 a-xxxx-xxx'
|
||||
},
|
||||
|
||||
{
|
||||
name: "d",
|
||||
type: "text",
|
||||
label: "ID",
|
||||
value: "",
|
||||
size: 'lg',
|
||||
hint: '比如输入 a-xxxx-xxx'
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
name: "tag",
|
||||
type: "tag",
|
||||
label: "Tag",
|
||||
size: 'md',
|
||||
clearable: true,
|
||||
placeholder: "多个标签以逗号分隔",
|
||||
options: [
|
||||
"周小度",
|
||||
"杜小度"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
561
examples/components/Form/Mode.jsx
Normal file
561
examples/components/Form/Mode.jsx
Normal file
@ -0,0 +1,561 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "表单各种展示模式汇总",
|
||||
remark: "展示各种模式的 Form",
|
||||
body: [
|
||||
{
|
||||
type: "grid",
|
||||
columns: [
|
||||
{
|
||||
type: "form",
|
||||
api: "/api/mock2/form/saveForm?waitSeconds=2",
|
||||
title: "常规模式",
|
||||
mode: "normal",
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email",
|
||||
required: true,
|
||||
placeholder: "请输入邮箱",
|
||||
label: "邮箱",
|
||||
size: 'full'
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password",
|
||||
label: "密码",
|
||||
required: true,
|
||||
placeholder: "请输入密码",
|
||||
size: 'full'
|
||||
},
|
||||
{
|
||||
type: "checkbox",
|
||||
name: "rememberMe",
|
||||
label: "记住登录"
|
||||
},
|
||||
{
|
||||
type: "submit",
|
||||
btnClassName: "btn-default",
|
||||
label: "登录"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "form",
|
||||
api: "/api/mock2/form/saveForm?waitSeconds=2",
|
||||
title: "常规模式 input md 尺寸",
|
||||
mode: "normal",
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email",
|
||||
required: true,
|
||||
placeholder: "请输入邮箱",
|
||||
label: "邮箱",
|
||||
size: 'md',
|
||||
remark: 'xxxx',
|
||||
hint: 'bla bla bla'
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password",
|
||||
label: "密码",
|
||||
required: true,
|
||||
placeholder: "请输入密码",
|
||||
size: 'md'
|
||||
},
|
||||
{
|
||||
type: "checkbox",
|
||||
name: "rememberMe",
|
||||
label: "记住登录"
|
||||
},
|
||||
{
|
||||
type: "submit",
|
||||
btnClassName: "btn-default",
|
||||
label: "登录"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: "grid",
|
||||
columns: [
|
||||
{
|
||||
type: "form",
|
||||
api: "/api/mock2/form/saveForm?waitSeconds=2",
|
||||
title: "水平模式,左右摆放 左右比率分配 ",
|
||||
mode: "horizontal",
|
||||
autoFocus: false,
|
||||
horizontal: {
|
||||
left: 'col-sm-2',
|
||||
right: 'col-sm-10',
|
||||
offset: 'col-sm-offset-2'
|
||||
},
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email",
|
||||
placeholder: "请输入邮箱地址",
|
||||
label: "邮箱",
|
||||
required: true,
|
||||
desc: "表单描述文字",
|
||||
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password",
|
||||
label: "密码",
|
||||
placeholder: "输入密码",
|
||||
|
||||
},
|
||||
{
|
||||
type: "checkbox",
|
||||
name: "rememberMe",
|
||||
label: "记住登录"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "form",
|
||||
api: "/api/mock2/form/saveForm?waitSeconds=2",
|
||||
title: "水平模式,左右摆放 左侧固定宽度 input md 尺寸",
|
||||
mode: "horizontal",
|
||||
autoFocus: false,
|
||||
horizontal: {
|
||||
leftFixed: 'xs'
|
||||
},
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email",
|
||||
placeholder: "请输入邮箱地址",
|
||||
label: "邮箱",
|
||||
required: true,
|
||||
desc: "表单描述文字",
|
||||
size: 'md',
|
||||
remark: 'xxxx',
|
||||
hint: 'bla bla bla'
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password",
|
||||
label: "密码",
|
||||
placeholder: "输入密码",
|
||||
size: 'md'
|
||||
},
|
||||
{
|
||||
type: "checkbox",
|
||||
name: "rememberMe",
|
||||
label: "记住登录"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "form",
|
||||
api: "/api/mock2/form/saveForm?waitSeconds=2",
|
||||
title: "内联模式",
|
||||
mode: "inline",
|
||||
autoFocus: false,
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email",
|
||||
placeholder: "Enter Email",
|
||||
label: "邮箱",
|
||||
size: 'auto'
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password",
|
||||
placeholder: "密码",
|
||||
size: 'auto',
|
||||
remark: 'Bla bla bla'
|
||||
},
|
||||
{
|
||||
type: "checkbox",
|
||||
name: "rememberMe",
|
||||
label: "记住登录",
|
||||
size: 'auto'
|
||||
},
|
||||
{
|
||||
type: "submit",
|
||||
label: "登录"
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
label: "导出",
|
||||
url: "http://www.baidu.com/",
|
||||
level: "success"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "form",
|
||||
api: "/api/mock2/form/saveForm?waitSeconds=2",
|
||||
title: "常规模式下用数组包起来还能控制一行显示多个",
|
||||
mode: "normal",
|
||||
autoFocus: false,
|
||||
controls: [
|
||||
{
|
||||
type: "text",
|
||||
name: "name",
|
||||
placeholder: "请输入...",
|
||||
label: "名字",
|
||||
size: 'full'
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email",
|
||||
placeholder: "输入邮箱",
|
||||
label: "邮箱",
|
||||
size: 'full'
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password",
|
||||
label: "密码",
|
||||
placeholder: "请输入密码",
|
||||
size: 'full'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email2",
|
||||
mode: 'inline',
|
||||
placeholder: "请输入邮箱地址",
|
||||
label: "邮箱",
|
||||
size: 'full'
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password2",
|
||||
label: "密码",
|
||||
mode: 'inline',
|
||||
placeholder: "请输入密码",
|
||||
size: 'full'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email3",
|
||||
mode: 'inline',
|
||||
placeholder: "请输入邮箱地址",
|
||||
label: "邮箱",
|
||||
size: 'full'
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password3",
|
||||
label: "密码",
|
||||
placeholder: "请输入密码",
|
||||
size: 'full'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email4",
|
||||
placeholder: "请输入邮箱地址",
|
||||
label: "邮箱",
|
||||
size: 'full'
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password4",
|
||||
label: "密码",
|
||||
placeholder: "请输入密码",
|
||||
mode: 'inline',
|
||||
size: 'full'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "checkbox",
|
||||
name: "rememberMe",
|
||||
label: "记住我"
|
||||
},
|
||||
{
|
||||
type: "submit",
|
||||
btnClassName: "btn-default",
|
||||
label: "提交"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "form",
|
||||
api: "/api/mock2/form/saveForm?waitSeconds=2",
|
||||
title: "水平模式用数组包起来也能控制一行显示多个",
|
||||
mode: "horizontal",
|
||||
autoFocus: false,
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email",
|
||||
placeholder: "请输入邮箱地址",
|
||||
label: "邮箱",
|
||||
size: 'full'
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email2",
|
||||
placeholder: "请输入邮箱地址",
|
||||
label: "邮箱",
|
||||
size: 'full'
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password2",
|
||||
label: "密码",
|
||||
placeholder: "请输入密码",
|
||||
size: 'full'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email3",
|
||||
placeholder: "请输入邮箱地址",
|
||||
label: "邮箱",
|
||||
size: 'full'
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password3",
|
||||
label: "密码",
|
||||
placeholder: "请输入密码",
|
||||
size: 'full'
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password3",
|
||||
label: "密码",
|
||||
placeholder: "请输入密码",
|
||||
size: 'full'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email4",
|
||||
placeholder: "请输入邮箱地址",
|
||||
label: "邮箱",
|
||||
size: 'full',
|
||||
columnClassName: 'col-sm-6',
|
||||
horizontal: {
|
||||
left: 'col-sm-4',
|
||||
right: 'col-sm-8'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password4",
|
||||
label: "密码",
|
||||
placeholder: "请输入密码",
|
||||
mode: 'inline',
|
||||
size: 'full'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
label: "邮箱",
|
||||
gap: 'xs',
|
||||
controls: [
|
||||
{
|
||||
label: false,
|
||||
type: "email",
|
||||
name: "email5",
|
||||
placeholder: "请输入邮箱地址",
|
||||
size: 'full'
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password5",
|
||||
label: "密码",
|
||||
placeholder: "请输入密码",
|
||||
mode: 'inline',
|
||||
size: 'full'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
label: "邮箱",
|
||||
description: 'bla bla',
|
||||
gap: 'xs',
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email6",
|
||||
placeholder: "请输入邮箱地址",
|
||||
mode: 'inline'
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password6",
|
||||
// label: "密码",
|
||||
placeholder: "请输入密码",
|
||||
labelClassName: "w-auto p-r-none",
|
||||
mode: 'inline'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
label: "邮箱",
|
||||
description: 'bla bla',
|
||||
direction: "vertical",
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email9",
|
||||
mode: 'normal',
|
||||
placeholder: "请输入邮箱地址",
|
||||
inline: true,
|
||||
description: 'Bla blamfejkf fdjk',
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password9",
|
||||
mode: 'normal',
|
||||
placeholder: "请输入密码",
|
||||
labelClassName: "w-auto p-r-none",
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "checkbox",
|
||||
name: "rememberMe",
|
||||
label: "记住我"
|
||||
},
|
||||
{
|
||||
type: "submit",
|
||||
btnClassName: "btn-default",
|
||||
label: "Submit"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "form",
|
||||
api: "/api/mock2/form/saveForm?waitSeconds=2",
|
||||
title: "Inline form 用数组包起来还能控制一行显示多个",
|
||||
mode: "inline",
|
||||
submitText: null,
|
||||
autoFocus: false,
|
||||
controls: [
|
||||
[
|
||||
{
|
||||
type: "email",
|
||||
name: "email",
|
||||
placeholder: "Enter Email",
|
||||
label: "邮箱",
|
||||
size: 'full'
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password",
|
||||
placeholder: "Password",
|
||||
size: 'full'
|
||||
}
|
||||
],
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
[
|
||||
{
|
||||
type: "email",
|
||||
name: "email",
|
||||
placeholder: "Enter Email",
|
||||
label: "邮箱",
|
||||
size: 'full'
|
||||
},
|
||||
{
|
||||
type: "checkbox",
|
||||
name: "rememberMe",
|
||||
label: "记住我",
|
||||
size: 'full'
|
||||
},
|
||||
{
|
||||
type: 'button-toolbar',
|
||||
buttons: [
|
||||
{
|
||||
type: "submit",
|
||||
label: "登录"
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
label: "导出",
|
||||
url: "http://www.baidu.com/",
|
||||
level: "success"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
1301
examples/components/Form/Picker.jsx
Normal file
1301
examples/components/Form/Picker.jsx
Normal file
File diff suppressed because it is too large
Load Diff
93
examples/components/Form/Reaction.jsx
Normal file
93
examples/components/Form/Reaction.jsx
Normal file
@ -0,0 +1,93 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "显隐切换示例",
|
||||
body: [
|
||||
{
|
||||
name: "hiddenOn",
|
||||
type: "form",
|
||||
mode: "horizontal",
|
||||
api: "/api/mock2/saveForm?waitSeconds=2",
|
||||
title: "Hide On 和 disabledOn 示例",
|
||||
controls: [
|
||||
{
|
||||
type: "radios",
|
||||
name: "type",
|
||||
label: "类型选择",
|
||||
inline: true,
|
||||
value: "1",
|
||||
options: [
|
||||
{
|
||||
label: "类型 1",
|
||||
value: "1"
|
||||
},
|
||||
{
|
||||
label: "类型 2",
|
||||
value: "2"
|
||||
},
|
||||
{
|
||||
label: "类型 3",
|
||||
value: "3"
|
||||
}
|
||||
],
|
||||
description: '<span class="text-danger">请切换类型来看效果</span>'
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
label: "所有可见",
|
||||
name: "text1"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
label: "类型2 可见",
|
||||
hiddenOn: "data.type != 2",
|
||||
name: "text2"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
label: "类型3 不可点",
|
||||
disabledOn: "data.type == 3",
|
||||
name: "text3"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
required: true,
|
||||
label: "必填字段",
|
||||
name: "test4"
|
||||
},
|
||||
{
|
||||
type: "button-toolbar",
|
||||
buttons: [
|
||||
{
|
||||
type: "submit",
|
||||
disabledOn: "data.type == 1",
|
||||
label: "类型1不可点"
|
||||
},
|
||||
{
|
||||
type: "reset",
|
||||
label: "类型3出现且不可点",
|
||||
visibleOn: "data.type == 3",
|
||||
disabledOn: "data.type == 3",
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
label: "Baidu",
|
||||
href: "http://www.baidu.com?a=1&b=$test4"
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
actionType: "ajax",
|
||||
label: "No Submit",
|
||||
action: "/api/mock2/saveForm?waitSeconds=5"
|
||||
},
|
||||
{
|
||||
type: "submit",
|
||||
actionType: "ajax",
|
||||
label: "Submit",
|
||||
action: "/api/mock2/saveForm?waitSeconds=5"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
90
examples/components/Form/Remote.jsx
Normal file
90
examples/components/Form/Remote.jsx
Normal file
@ -0,0 +1,90 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "动态拉取选项",
|
||||
name: "page-form-remote",
|
||||
body: [
|
||||
{
|
||||
type: "form",
|
||||
title: "动态表单元素示例",
|
||||
name: "demo-form",
|
||||
api: "/api/mock2/form/saveForm?waitSeconds=2",
|
||||
mode: "horizontal",
|
||||
actions: [
|
||||
{
|
||||
type: "submit",
|
||||
label: "提交"
|
||||
}
|
||||
],
|
||||
controls: [
|
||||
{
|
||||
name: "select",
|
||||
type: "select",
|
||||
label: "动态选项",
|
||||
source: "/api/mock2/form/getOptions?waitSeconds=1",
|
||||
description: '通过接口一口气拉取选项',
|
||||
clearable: true,
|
||||
searchable: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
name: "select2",
|
||||
type: "select",
|
||||
label: "选项自动补全",
|
||||
autoComplete: "/api/mock2/options/autoComplete?term=$term",
|
||||
placeholder: "请输入",
|
||||
description: '通过接口自动补全'
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "text",
|
||||
label: "文本提示",
|
||||
source: "/api/mock2/form/getOptions?waitSeconds=1",
|
||||
placeholder: '请选择'
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
name: "text2",
|
||||
type: "text",
|
||||
label: "文本自动补全",
|
||||
clearable: true,
|
||||
autoComplete: "/api/mock2/options/autoComplete2?term=$term",
|
||||
description: '通过接口自动补全'
|
||||
},
|
||||
{
|
||||
name: "chained",
|
||||
type: "chained-select",
|
||||
label: "级联选项",
|
||||
source:
|
||||
"/api/mock2/options/chainedOptions?waitSeconds=1&parentId=$parentId&level=$level&maxLevel=4&waiSeconds=1",
|
||||
desc: "无限级别, 只要 api 返回数据就能继续往下选择. 当没有下级时请返回 null.",
|
||||
value: "a,b"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
name: "tree",
|
||||
type: "tree",
|
||||
label: "动态树",
|
||||
source: "/api/mock2/options/tree?waitSeconds=1"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
name: "matrix",
|
||||
type: "matrix",
|
||||
label: "动态矩阵开关",
|
||||
source: "/api/mock2/options/matrix?waitSeconds=1"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
21
examples/components/Form/RichText.jsx
Normal file
21
examples/components/Form/RichText.jsx
Normal file
@ -0,0 +1,21 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "富文本编辑器",
|
||||
body: [
|
||||
{
|
||||
type: "form",
|
||||
api: "/api/mock2/saveForm?waitSeconds=2",
|
||||
title: "Form elements",
|
||||
controls: [
|
||||
{
|
||||
name: "html",
|
||||
type: "rich-text",
|
||||
label: "富文本",
|
||||
value: "<p>Just do <code>IT</code></p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
156
examples/components/Form/Schem.jsx
Normal file
156
examples/components/Form/Schem.jsx
Normal file
@ -0,0 +1,156 @@
|
||||
import * as React from 'react';
|
||||
import TitleBar from '../../../src/components/TitleBar';
|
||||
import {render} from '../../../src/index';
|
||||
|
||||
const Schema = {
|
||||
"title": "Person",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"firstName": {
|
||||
"title": "First Name",
|
||||
"type": "string"
|
||||
},
|
||||
"lastName": {
|
||||
"type": "string"
|
||||
},
|
||||
"age": {
|
||||
"description": "Age in years",
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"tag": {
|
||||
"type": "array",
|
||||
"description": "Tags",
|
||||
"default": ["IT"],
|
||||
"items": {
|
||||
"type": "text"
|
||||
}
|
||||
},
|
||||
|
||||
"clients": {
|
||||
"type": "array",
|
||||
"description": "Tags",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"firstName": {
|
||||
"title": "First Name",
|
||||
"type": "string"
|
||||
},
|
||||
"lastName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["firstName", "lastName"]
|
||||
};
|
||||
|
||||
function property2control(property, key, schema) {
|
||||
const requiredList= schema.required || [];
|
||||
const rest = {};
|
||||
const validations = {};
|
||||
let type = 'text';
|
||||
|
||||
|
||||
|
||||
if (property.type === 'integer') {
|
||||
type = 'number';
|
||||
|
||||
typeof property.minimum === 'number' && (rest.min = property.minimum);
|
||||
// property.max
|
||||
} else if (property.type === 'array') {
|
||||
type = 'combo';
|
||||
const items = property.items;
|
||||
|
||||
if (items.type === 'object') {
|
||||
rest.controls = makeControls(items.properties, items);
|
||||
rest.multiLine = true;
|
||||
} else {
|
||||
type = 'array';
|
||||
rest.inline = true;
|
||||
rest.items = property2control(items, 'item', property);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof property.minimum === 'number') {
|
||||
validations.minimum = property.minimum;
|
||||
}
|
||||
|
||||
return {
|
||||
name: key,
|
||||
type,
|
||||
required: !!~requiredList.indexOf(key),
|
||||
label: property.title || property.description,
|
||||
desc: property.title && property.description,
|
||||
value: property.default,
|
||||
validations,
|
||||
...rest
|
||||
};
|
||||
}
|
||||
|
||||
function makeControls(properties, schema) {
|
||||
const keys = Object.keys(properties);
|
||||
return keys.map(key => property2control(properties[key], key, schema));
|
||||
}
|
||||
|
||||
function JSONSchme2AMisSchema(schema) {
|
||||
if (schema.type !== 'object') {
|
||||
throw new Error('JSONSchme2AMisSchema 只支持 object 转换');
|
||||
}
|
||||
|
||||
return {
|
||||
title: schema.title,
|
||||
type: 'form',
|
||||
mode: "horizontal",
|
||||
controls: makeControls(schema.properties, schema)
|
||||
}
|
||||
}
|
||||
|
||||
const amisFormSchema = JSONSchme2AMisSchema(Schema);
|
||||
|
||||
export default class JSONSchemaForm extends React.Component {
|
||||
state = {
|
||||
data: {}
|
||||
};
|
||||
|
||||
renderForm() {
|
||||
return render({
|
||||
type: 'page',
|
||||
title: '',
|
||||
body: {
|
||||
...amisFormSchema,
|
||||
onChange: values => this.setState({
|
||||
data: {
|
||||
...values
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<TitleBar title="JSON Schema Form" />
|
||||
<div className="wrapper">
|
||||
<div>
|
||||
<h3>Schema</h3>
|
||||
<pre><code>{JSON.stringify(Schema, null, 2)}</code></pre>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>Form</h3>
|
||||
{this.renderForm()}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>Data</h3>
|
||||
<pre><code>{JSON.stringify(this.state.data, null, 2)}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
130
examples/components/Form/Static.jsx
Normal file
130
examples/components/Form/Static.jsx
Normal file
@ -0,0 +1,130 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "所有 Form 元素列举",
|
||||
data: {
|
||||
id: 1,
|
||||
image: "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3893101144,2877209892&fm=23&gp=0.jpg"
|
||||
},
|
||||
body: [
|
||||
{
|
||||
type: "form",
|
||||
api: "/api/mock2/saveForm?waitSeconds=2",
|
||||
title: "表单项静态展示",
|
||||
mode: "horizontal",
|
||||
controls: [
|
||||
{
|
||||
type: "static",
|
||||
label: "文本",
|
||||
value: "文本"
|
||||
},
|
||||
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
||||
{
|
||||
type: "static-tpl",
|
||||
label: "模板",
|
||||
tpl: "自己拼接 HTML 取变量 \\${id}: ${id}"
|
||||
},
|
||||
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
||||
{
|
||||
type: "static-date",
|
||||
label: "日期",
|
||||
value: Math.round(Date.now()/1000)
|
||||
},
|
||||
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
||||
{
|
||||
type: "static-datetime",
|
||||
label: "日期时间",
|
||||
value: Math.round(Date.now()/1000)
|
||||
},
|
||||
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
||||
{
|
||||
type: "static-mapping",
|
||||
label: "映射",
|
||||
value: Math.floor(Math.random() * 5),
|
||||
map: {
|
||||
'*': "<span class='label label-default'>-</span>",
|
||||
'0': "<span class='label label-info'>一</span>",
|
||||
'1': "<span class='label label-success'>二</span>",
|
||||
'2': "<span class='label label-danger'>三</span>",
|
||||
'3': "<span class='label label-warning'>四</span>",
|
||||
'4': "<span class='label label-primary'>五</span>",
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
||||
{
|
||||
type: "static-progress",
|
||||
label: "进度",
|
||||
value: 66.66
|
||||
},
|
||||
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
||||
{
|
||||
type: "static-image",
|
||||
label: "图片",
|
||||
name: "image",
|
||||
popOver: {
|
||||
title: "查看大图",
|
||||
body: '<div class="w-xxl"><img class="w-full" src="${image}"/></div>'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
||||
{
|
||||
type: 'static-json',
|
||||
label: 'JSON',
|
||||
value: {a: 1, b: 2, c: {d: 3}}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
||||
{
|
||||
type: "static",
|
||||
label: "可复制",
|
||||
value: "文本",
|
||||
copyable: {
|
||||
content: "内容,支持变量 ${id}"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
||||
{
|
||||
type: "static",
|
||||
name: "text",
|
||||
label: "可快速编辑",
|
||||
value: "文本",
|
||||
quickEdit: true
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
60
examples/components/Form/SubForm.jsx
Normal file
60
examples/components/Form/SubForm.jsx
Normal file
@ -0,0 +1,60 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "SubForm 示例",
|
||||
body: [
|
||||
{
|
||||
type: "form",
|
||||
api: "/api/mock2/saveForm?waitSeconds=2",
|
||||
title: "Form elements",
|
||||
mode: "horizontal",
|
||||
// debug: true,
|
||||
controls: [
|
||||
{
|
||||
type: "form",
|
||||
label: "子表单单条",
|
||||
name: "subForm1",
|
||||
btnLabel: "点击设置",
|
||||
form: {
|
||||
title: "子表单",
|
||||
controls: [
|
||||
{
|
||||
name: "a",
|
||||
type: "text",
|
||||
label: "Foo"
|
||||
},
|
||||
{
|
||||
name: "b",
|
||||
type: "switch",
|
||||
label: "Boo"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
type: "form",
|
||||
label: "子表单多条",
|
||||
name: "subForm2",
|
||||
labelField: 'a',
|
||||
btnLabel: "点击设置",
|
||||
multiple: true,
|
||||
form: {
|
||||
title: "子表单",
|
||||
controls: [
|
||||
{
|
||||
name: "a",
|
||||
type: "text",
|
||||
label: "Foo"
|
||||
},
|
||||
{
|
||||
name: "b",
|
||||
type: "switch",
|
||||
label: "Boo"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
146
examples/components/Form/Table.jsx
Normal file
146
examples/components/Form/Table.jsx
Normal file
@ -0,0 +1,146 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "表格编辑",
|
||||
body: {
|
||||
type: "form",
|
||||
mode: "horizontal",
|
||||
api: "/api/mock2/form/saveForm?waitSeconds=2",
|
||||
actions: [
|
||||
{
|
||||
type: "submit",
|
||||
label: "提交",
|
||||
primary: true
|
||||
}
|
||||
],
|
||||
controls: [
|
||||
{
|
||||
type: 'combo',
|
||||
name: 'colors',
|
||||
label: 'Combo',
|
||||
multiple: true,
|
||||
draggable: true,
|
||||
multiLine: true,
|
||||
value: [
|
||||
{
|
||||
color: 'green',
|
||||
name: '颜色'
|
||||
}
|
||||
],
|
||||
controls: [
|
||||
{
|
||||
type: 'color',
|
||||
name: 'color'
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'name',
|
||||
placeholder: '说明文字'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
label: "当前值",
|
||||
tpl: "<pre>${colors|json}</pre>"
|
||||
},
|
||||
{
|
||||
type: 'table',
|
||||
name: 'colors',
|
||||
label: 'Table',
|
||||
draggable: true,
|
||||
columns: [
|
||||
{
|
||||
label: 'Color',
|
||||
name: 'color',
|
||||
quickEdit: {
|
||||
type: 'color',
|
||||
saveImmediately: true
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '说明文字',
|
||||
name: 'name',
|
||||
quickEdit: {
|
||||
type: 'text',
|
||||
mode: 'inline',
|
||||
saveImmediately: true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'button',
|
||||
label: 'Table2新增一行',
|
||||
target: 'table2',
|
||||
actionType: 'add'
|
||||
},
|
||||
{
|
||||
"type": "table",
|
||||
"name": "table2",
|
||||
"label": "Table2",
|
||||
"editable": true,
|
||||
"addable": true,
|
||||
"removable": true,
|
||||
"draggable": true,
|
||||
"columns": [
|
||||
{
|
||||
"name": "a",
|
||||
"label": "A"
|
||||
},
|
||||
{
|
||||
"name": "b",
|
||||
"label": "B",
|
||||
"quickEdit": {
|
||||
"type": "select",
|
||||
"options": [
|
||||
{
|
||||
"label": "A",
|
||||
"value": "a"
|
||||
},
|
||||
{
|
||||
"label": "B",
|
||||
"value": "b"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"type": "table",
|
||||
"name": "table3",
|
||||
"label": "Table3(指定第2列只有update时能编辑)",
|
||||
"editable": true,
|
||||
"addable": true,
|
||||
"removable": true,
|
||||
"draggable": true,
|
||||
"columns": [
|
||||
{
|
||||
"name": "a",
|
||||
"label": "A",
|
||||
"quickEdit": true
|
||||
},
|
||||
{
|
||||
"name": "b",
|
||||
"label": "B",
|
||||
"quickEdit": false,
|
||||
"quickEditOnUpdate": {
|
||||
"type": "select",
|
||||
"options": [
|
||||
{
|
||||
"label": "A",
|
||||
"value": "a"
|
||||
},
|
||||
{
|
||||
"label": "B",
|
||||
"value": "b"
|
||||
}
|
||||
]
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
169
examples/components/Form/Tabs.jsx
Normal file
169
examples/components/Form/Tabs.jsx
Normal file
@ -0,0 +1,169 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "Tabs 示例",
|
||||
body: [
|
||||
{
|
||||
type: "form",
|
||||
mode: "horizontal",
|
||||
api: "/api/mock2/form/saveForm?waitSeconds=2",
|
||||
title: "",
|
||||
actions: [
|
||||
{
|
||||
type: "button",
|
||||
actionType: "dialog",
|
||||
label: "弹框中的 Tabs",
|
||||
level: "info",
|
||||
dialog: {
|
||||
title: "",
|
||||
// size: "md",
|
||||
body: {
|
||||
type: "form",
|
||||
mode: "horizontal",
|
||||
horizontal: {
|
||||
leftFixed: 'xs'
|
||||
},
|
||||
api: "/api/mock2/form/saveForm?waitSeconds=2",
|
||||
actions: [
|
||||
{
|
||||
type: "submit",
|
||||
label: "提交",
|
||||
primary: true
|
||||
}
|
||||
],
|
||||
controls: [{
|
||||
type: 'tabs',
|
||||
tabs: [
|
||||
{
|
||||
title: "基本信息",
|
||||
controls: [
|
||||
[
|
||||
{
|
||||
type: "email",
|
||||
name: "email1",
|
||||
placeholder: "请输入邮箱地址",
|
||||
label: "邮箱"
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password",
|
||||
placeholder: "密码",
|
||||
label: false
|
||||
}
|
||||
],
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
[
|
||||
{
|
||||
type: "email",
|
||||
name: "email2",
|
||||
placeholder: "请输入邮箱地址",
|
||||
label: "邮箱"
|
||||
},
|
||||
{
|
||||
type: "checkbox",
|
||||
name: "rememberMe",
|
||||
label: false,
|
||||
option: "记住我"
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "其他信息",
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email3",
|
||||
placeholder: "请输入邮箱地址",
|
||||
label: "邮箱"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "checkbox",
|
||||
name: "rememberMe2",
|
||||
option: "记住我"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "submit",
|
||||
label: "提交",
|
||||
primary: true
|
||||
}
|
||||
],
|
||||
controls: [
|
||||
{
|
||||
type: 'tabs',
|
||||
|
||||
tabs: [
|
||||
{
|
||||
title: "基本信息",
|
||||
hash: 'tab1',
|
||||
controls: [
|
||||
[
|
||||
{
|
||||
type: "email",
|
||||
name: "email",
|
||||
placeholder: "请输入邮箱地址",
|
||||
label: "邮箱"
|
||||
},
|
||||
{
|
||||
type: "password",
|
||||
name: "password",
|
||||
placeholder: "密码",
|
||||
label: false
|
||||
}
|
||||
],
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
[
|
||||
{
|
||||
type: "email",
|
||||
name: "email2",
|
||||
placeholder: "请输入邮箱地址",
|
||||
label: "邮箱"
|
||||
},
|
||||
{
|
||||
type: "checkbox",
|
||||
name: "rememberMe",
|
||||
label: false,
|
||||
option: "记住我"
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "其他信息",
|
||||
hash: 'tab2',
|
||||
controls: [
|
||||
{
|
||||
type: "email",
|
||||
name: "email3",
|
||||
placeholder: "请输入邮箱地址",
|
||||
label: "邮箱"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "checkbox",
|
||||
name: "rememberMe4",
|
||||
label: "记住我"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
126
examples/components/Form/Test.jsx
Normal file
126
examples/components/Form/Test.jsx
Normal file
@ -0,0 +1,126 @@
|
||||
export default {
|
||||
"type": "page",
|
||||
"body": {
|
||||
"type": "form",
|
||||
"title": "详情",
|
||||
"name": "scene_detail",
|
||||
"mode": "horizontal",
|
||||
"submitText": "",
|
||||
"submitOnChange": false,
|
||||
"actions": [{
|
||||
"type": "button",
|
||||
"label": "修改",
|
||||
"actionType": "drawer",
|
||||
"drawer": {
|
||||
"type": "form",
|
||||
"position": "left",
|
||||
"title": "修改内容",
|
||||
"controls": [{
|
||||
"type": "text",
|
||||
"label": "标题",
|
||||
"name": "name",
|
||||
"required": true
|
||||
}, {
|
||||
"label": "描述",
|
||||
"type": "text",
|
||||
"name": "typeDesc",
|
||||
"required": true
|
||||
}, {
|
||||
"label": "内容",
|
||||
"type": "textarea",
|
||||
"name": "contents",
|
||||
"required": true
|
||||
}]
|
||||
}
|
||||
}],
|
||||
"controls": [
|
||||
{
|
||||
type: "tree",
|
||||
name: "tree",
|
||||
label: "树",
|
||||
options: [
|
||||
{
|
||||
label: "Folder A",
|
||||
value: 1,
|
||||
children: [
|
||||
{
|
||||
label: "file A",
|
||||
value: 2
|
||||
},
|
||||
{
|
||||
label: "file B",
|
||||
value: 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: "file C",
|
||||
value: 4
|
||||
},
|
||||
{
|
||||
label: "file D",
|
||||
value: 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "tree",
|
||||
name: "trees",
|
||||
label: "树多选",
|
||||
multiple: true,
|
||||
options: [
|
||||
{
|
||||
label: "Folder A",
|
||||
value: 1,
|
||||
children: [
|
||||
{
|
||||
label: "file A",
|
||||
value: 2
|
||||
},
|
||||
{
|
||||
label: "file B",
|
||||
value: 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: "file C",
|
||||
value: 4
|
||||
},
|
||||
{
|
||||
label: "file D",
|
||||
value: 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
|
||||
{
|
||||
name: "select",
|
||||
type: "tree-select",
|
||||
label: "动态选项",
|
||||
source: "/api/mock2/form/getTreeOptions?waitSeconds=1",
|
||||
description: '通过接口一口气拉取选项',
|
||||
clearable: true,
|
||||
searchable: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
name: "select2",
|
||||
type: "tree-select",
|
||||
label: "选项自动补全",
|
||||
autoComplete: "/api/mock2/tree/autoComplete?term=$term",
|
||||
placeholder: "请输入",
|
||||
description: '通过接口自动补全',
|
||||
multiple: true
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
109
examples/components/Form/Validation.jsx
Normal file
109
examples/components/Form/Validation.jsx
Normal file
@ -0,0 +1,109 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "表单验证示例",
|
||||
toolbar: "<a target='_blank' href='/docs/renderers#formitem'>文档</a>",
|
||||
body: [
|
||||
{
|
||||
type: "form",
|
||||
autoFocus: false,
|
||||
title: "表单",
|
||||
actions: [
|
||||
{
|
||||
type: "submit",
|
||||
label: "提交"
|
||||
}
|
||||
],
|
||||
api: "/api/mock2/form/saveFormFailed?waitSeconds=2",
|
||||
mode: "horizontal",
|
||||
controls: [
|
||||
{
|
||||
type: "text",
|
||||
name: "test",
|
||||
label: "必填",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
name: "test1",
|
||||
type: "email",
|
||||
label: "Email"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
name: "url",
|
||||
type: "url",
|
||||
label: "Url"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
name: "num",
|
||||
type: "text",
|
||||
label: "数字",
|
||||
validations: "isNumeric"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
name: "alpha",
|
||||
type: "text",
|
||||
label: "字母或数字",
|
||||
validations: "isAlphanumeric"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
name: "int",
|
||||
type: "text",
|
||||
label: "整形",
|
||||
validations: "isInt"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
name: "minLength",
|
||||
type: "text",
|
||||
label: "长度限制",
|
||||
validations: "minLength:2,maxLength:10"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
name: "min",
|
||||
type: "text",
|
||||
label: "数值限制",
|
||||
validations: "maximum:10,minimum:2"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
name: "reg",
|
||||
type: "text",
|
||||
label: "正则",
|
||||
validations: "matchRegexp:/^abc/",
|
||||
validationErrors: {
|
||||
matchRegexp: "请输入abc开头的好么?"
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
name: "test2",
|
||||
type: "text",
|
||||
label: "服务端验证"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
2141
examples/components/Form/layoutTest.jsx
Normal file
2141
examples/components/Form/layoutTest.jsx
Normal file
File diff suppressed because it is too large
Load Diff
137
examples/components/Horizontal.jsx
Normal file
137
examples/components/Horizontal.jsx
Normal file
@ -0,0 +1,137 @@
|
||||
export default {
|
||||
"$schema": "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
"title": "HBox & Grid",
|
||||
"type": "page",
|
||||
"body": [
|
||||
{
|
||||
"type": "plain",
|
||||
"tpl": "Grid 请参考 bootstrap 的 grid 布局",
|
||||
"inline": false,
|
||||
"className": "h3 m-b-xs"
|
||||
},
|
||||
{
|
||||
"type": "grid",
|
||||
"columns": [
|
||||
{
|
||||
"type": "tpl",
|
||||
"tpl": "sm-2",
|
||||
"sm": 2,
|
||||
"className": "bg-info",
|
||||
"inline": false
|
||||
},
|
||||
{
|
||||
"type": "tpl",
|
||||
"tpl": "sm-4",
|
||||
"sm": 4,
|
||||
"className": "bg-success",
|
||||
"inline": false
|
||||
},
|
||||
{
|
||||
"type": "tpl",
|
||||
"tpl": "sm-6",
|
||||
"sm": 6,
|
||||
"className": "bg-primary",
|
||||
"inline": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "plain",
|
||||
"tpl": "Hbox",
|
||||
"inline": false,
|
||||
"className": "h3 m-t m-b-xs"
|
||||
},
|
||||
{
|
||||
"type": "hbox",
|
||||
"columns": [
|
||||
{
|
||||
"type": "tpl",
|
||||
"tpl": "平均分配",
|
||||
"className": "bg-info",
|
||||
"inline": false
|
||||
},
|
||||
{
|
||||
"type": "tpl",
|
||||
"tpl": "平均分配",
|
||||
"className": "bg-success",
|
||||
"inline": false
|
||||
},
|
||||
{
|
||||
"type": "tpl",
|
||||
"tpl": "平均分配",
|
||||
"className": "bg-primary",
|
||||
"inline": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "plain",
|
||||
"tpl": "Hbox 部分定宽",
|
||||
"inline": false,
|
||||
"className": "h3 m-t m-b-xs"
|
||||
},
|
||||
{
|
||||
"type": "hbox",
|
||||
"columns": [
|
||||
{
|
||||
"type": "tpl",
|
||||
"tpl": "w-xs",
|
||||
"className": "bg-info",
|
||||
"inline": false,
|
||||
"columnClassName": "w-xs"
|
||||
},
|
||||
{
|
||||
"type": "tpl",
|
||||
"tpl": "w-sm",
|
||||
"className": "bg-info lter",
|
||||
"inline": false,
|
||||
"columnClassName": "w-sm"
|
||||
},
|
||||
{
|
||||
"type": "tpl",
|
||||
"tpl": "w",
|
||||
"className": "bg-info dk",
|
||||
"inline": false,
|
||||
"columnClassName": "w"
|
||||
},
|
||||
{
|
||||
"type": "tpl",
|
||||
"tpl": "平均分配",
|
||||
"className": "bg-success",
|
||||
"inline": false
|
||||
},
|
||||
{
|
||||
"type": "tpl",
|
||||
"tpl": "平均分配",
|
||||
"className": "bg-primary",
|
||||
"inline": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "plain",
|
||||
"tpl": "示例",
|
||||
"inline": false,
|
||||
"className": "h3 m-t m-b-xs"
|
||||
},
|
||||
{
|
||||
"type": "grid",
|
||||
"columns": [
|
||||
{
|
||||
"type": "panel",
|
||||
"title": "面板1",
|
||||
"className": "Panel--danger",
|
||||
"body": "内容",
|
||||
"sm": 4
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"title": "面板2",
|
||||
"className": "Panel--primary",
|
||||
"body": "内容",
|
||||
"sm": 8
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
31
examples/components/IFrame.jsx
Normal file
31
examples/components/IFrame.jsx
Normal file
@ -0,0 +1,31 @@
|
||||
export default {
|
||||
"$schema": "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
"title": "IFrame 可以用来嵌入其他网站",
|
||||
"body": [
|
||||
{
|
||||
type: 'form',
|
||||
mode: 'inline',
|
||||
target: 'window',
|
||||
title: '',
|
||||
controls: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'keywords',
|
||||
addOn: {
|
||||
type: 'submit',
|
||||
label: '搜索',
|
||||
level: 'info',
|
||||
icon: 'fa fa-search pull-left'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'iframe',
|
||||
className: 'b-a',
|
||||
src: "https://www.baidu.com/s?wd=${keywords|url_encode}",
|
||||
height: 500
|
||||
}
|
||||
]
|
||||
}
|
174
examples/components/Linkage/CRUD.jsx
Normal file
174
examples/components/Linkage/CRUD.jsx
Normal file
@ -0,0 +1,174 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
title: "表单与列表之间的联动",
|
||||
body: [
|
||||
{
|
||||
title: "",
|
||||
type: 'form',
|
||||
mode: 'inline',
|
||||
target: 'list',
|
||||
wrapWithPanel: false,
|
||||
className: 'm-b',
|
||||
controls: [
|
||||
{
|
||||
type: "text",
|
||||
name: "keywords",
|
||||
placeholder: "通过关键字搜索",
|
||||
clearable: true,
|
||||
addOn: {
|
||||
type: 'submit',
|
||||
icon: 'fa fa-search',
|
||||
level: 'primary'
|
||||
}
|
||||
},
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "crud",
|
||||
name: 'list',
|
||||
api: "/api/sample",
|
||||
mode: "list",
|
||||
listItem: {
|
||||
actions: [
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-eye",
|
||||
actionType: "dialog",
|
||||
dialog: {
|
||||
title: "查看",
|
||||
body: {
|
||||
type: "form",
|
||||
controls: [
|
||||
{
|
||||
type: "static",
|
||||
name: "engine",
|
||||
label: "Engine"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "browser",
|
||||
label: "Browser"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "platform",
|
||||
label: "Platform(s)"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "static",
|
||||
name: "grade",
|
||||
label: "CSS grade"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-pencil",
|
||||
actionType: "dialog",
|
||||
dialog: {
|
||||
title: "编辑",
|
||||
body: {
|
||||
type: "form",
|
||||
name: "sample-edit-form",
|
||||
api: "/api/sample/$id",
|
||||
controls: [
|
||||
{
|
||||
type: "text",
|
||||
name: "engine",
|
||||
label: "Engine",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "grade",
|
||||
label: "CSS grade"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
icon: "fa fa-times text-danger",
|
||||
actionType: "ajax",
|
||||
confirmText: "您确认要删除?",
|
||||
api: "delete:/api/sample/$id"
|
||||
}
|
||||
],
|
||||
body: [
|
||||
{
|
||||
name: "engine",
|
||||
label: "Rendering engine",
|
||||
labelClassName: "w-sm"
|
||||
},
|
||||
[
|
||||
{
|
||||
name: "browser",
|
||||
label: "Browser",
|
||||
labelClassName: "w-sm"
|
||||
},
|
||||
{
|
||||
name: "platform",
|
||||
label: "Platform(s)",
|
||||
labelClassName: "w-sm"
|
||||
}
|
||||
],
|
||||
{
|
||||
name: "version",
|
||||
label: "Engine version",
|
||||
labelClassName: "w-sm"
|
||||
}
|
||||
]
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
67
examples/components/Linkage/Form.jsx
Normal file
67
examples/components/Linkage/Form.jsx
Normal file
@ -0,0 +1,67 @@
|
||||
export default {
|
||||
type: 'page',
|
||||
title: '表单与表单之间的联动',
|
||||
aside: {
|
||||
type: 'form',
|
||||
target: 'detailForm',
|
||||
className: 'wrapper-sm', // 来点间隔
|
||||
wrapWithPanel: false, // 不要用 panel 包裹了。
|
||||
controls: [
|
||||
{
|
||||
type: 'text',
|
||||
placeholder: '关键字',
|
||||
name: 'keywords',
|
||||
addOn: {
|
||||
type: 'submit',
|
||||
label: '搜索',
|
||||
primary: true
|
||||
}
|
||||
},
|
||||
|
||||
'<span class="text-danger">请在此输入内容后点击搜索</sapn>'
|
||||
]
|
||||
},
|
||||
body: {
|
||||
name: 'detailForm',
|
||||
type: 'form',
|
||||
mode: 'horizontal',
|
||||
title: '',
|
||||
initApi: '/api/mock2/form/initData?keywords=${keywords}',
|
||||
actions: [],
|
||||
controls: [
|
||||
'Form 模型除了用来提交数据外,还比较适合用来做详情数据的展示',
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
||||
{
|
||||
label: '名称',
|
||||
type: 'static',
|
||||
labelClassName: 'text-muted',
|
||||
name: 'name'
|
||||
},
|
||||
|
||||
{
|
||||
label: '作者',
|
||||
type: 'static',
|
||||
labelClassName: 'text-muted',
|
||||
name: 'author'
|
||||
},
|
||||
|
||||
{
|
||||
label: '输入信息',
|
||||
type: 'static',
|
||||
labelClassName: 'text-muted',
|
||||
name: 'info'
|
||||
},
|
||||
|
||||
{
|
||||
label: '请求时间',
|
||||
type: 'static-datetime',
|
||||
labelClassName: 'text-muted',
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
name: 'date'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
306
examples/components/Linkage/Form2.jsx
Normal file
306
examples/components/Linkage/Form2.jsx
Normal file
@ -0,0 +1,306 @@
|
||||
export default {
|
||||
type: 'page',
|
||||
title: '表单初始数据自动重新拉取',
|
||||
body: [
|
||||
{
|
||||
type: 'form',
|
||||
mode: 'horizontal',
|
||||
title: '监听表单内部的修改',
|
||||
initApi: '/api/mock2/form/initData?tpl=${tpl}',
|
||||
actions: [],
|
||||
controls: [
|
||||
'<span class="text-danger">当 <code>initApi</code> 中有变量,且变量的值发生了变化了,则该表单就会重新初始数据。</span>',
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
||||
{
|
||||
label: '数据模板',
|
||||
type: 'select',
|
||||
labelClassName: 'text-muted',
|
||||
name: 'tpl',
|
||||
value: 'tpl1',
|
||||
inline: true,
|
||||
options: [
|
||||
{
|
||||
label: '模板1',
|
||||
value: 'tpl1'
|
||||
},
|
||||
|
||||
{
|
||||
label: '模板2',
|
||||
value: 'tpl2'
|
||||
},
|
||||
|
||||
{
|
||||
label: '模板3',
|
||||
value: 'tpl3'
|
||||
}
|
||||
],
|
||||
description: '<span class="text-danger">请修改这里看效果</span>'
|
||||
},
|
||||
|
||||
{
|
||||
label: '名称',
|
||||
type: 'static',
|
||||
labelClassName: 'text-muted',
|
||||
name: 'name'
|
||||
},
|
||||
|
||||
{
|
||||
label: '作者',
|
||||
type: 'static',
|
||||
labelClassName: 'text-muted',
|
||||
name: 'author'
|
||||
},
|
||||
|
||||
{
|
||||
label: '请求时间',
|
||||
type: 'static-datetime',
|
||||
labelClassName: 'text-muted',
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
name: 'date'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
type: 'grid',
|
||||
columns: [
|
||||
{
|
||||
type: 'form',
|
||||
mode: 'horizontal',
|
||||
title: '自动填充',
|
||||
actions: [],
|
||||
controls: [
|
||||
{
|
||||
label: '数据模板',
|
||||
type: 'select',
|
||||
labelClassName: 'text-muted',
|
||||
name: 'tpl',
|
||||
value: 'tpl1',
|
||||
inline: true,
|
||||
options: [
|
||||
{
|
||||
label: '模板1',
|
||||
value: 'tpl1'
|
||||
},
|
||||
|
||||
{
|
||||
label: '模板2',
|
||||
value: 'tpl2'
|
||||
},
|
||||
|
||||
{
|
||||
label: '模板3',
|
||||
value: 'tpl3'
|
||||
}
|
||||
],
|
||||
description: '<span class="text-danger">请修改这里看效果</span>'
|
||||
},
|
||||
|
||||
'<div class="text-danger m-b">如果 <code>initApi</code> 已经暂用,用 <code>service</code>一样可以拉取值填充,同样以下 api 值发生变化时会自动填充。</div>',
|
||||
|
||||
{
|
||||
type: 'service',
|
||||
api: '/api/mock2/form/initData?tpl=${tpl}',
|
||||
body: {
|
||||
controls: [
|
||||
{
|
||||
label: '名称',
|
||||
type: 'text',
|
||||
labelClassName: 'text-muted',
|
||||
name: 'name'
|
||||
},
|
||||
|
||||
{
|
||||
label: '作者',
|
||||
type: 'text',
|
||||
labelClassName: 'text-muted',
|
||||
name: 'author'
|
||||
},
|
||||
|
||||
{
|
||||
label: '请求时间',
|
||||
type: 'datetime',
|
||||
labelClassName: 'text-muted',
|
||||
inputFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
name: 'date'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'form',
|
||||
mode: 'horizontal',
|
||||
title: '手动填充',
|
||||
actions: [],
|
||||
controls: [
|
||||
{
|
||||
type: 'group',
|
||||
label: '数据模板',
|
||||
labelClassName: 'text-muted',
|
||||
controls: [
|
||||
{
|
||||
type: 'select',
|
||||
name: 'tpl',
|
||||
value: 'tpl1',
|
||||
mode: 'inline',
|
||||
options: [
|
||||
{
|
||||
label: '模板1',
|
||||
value: 'tpl1'
|
||||
},
|
||||
|
||||
{
|
||||
label: '模板2',
|
||||
value: 'tpl2'
|
||||
},
|
||||
|
||||
{
|
||||
label: '模板3',
|
||||
value: 'tpl3'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
mode: 'inline',
|
||||
type: 'button',
|
||||
label: '获取',
|
||||
level: 'dark',
|
||||
actionType: 'reload',
|
||||
target: 'theService'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
'<div class="text-danger m-b">如果不想自动填充,自动填充,则把参数放在 data 里面,就不会监控变化自动拉取了,同时把 <code>servcie</code> 的初始拉取关掉,然后来个刷新目标组件的按钮。</div>',
|
||||
|
||||
{
|
||||
type: 'service',
|
||||
name: 'theService',
|
||||
api: {
|
||||
method: 'get',
|
||||
url: '/api/mock2/form/initData',
|
||||
data: {
|
||||
tpl: '${tpl}'
|
||||
}
|
||||
},
|
||||
body: {
|
||||
controls: [
|
||||
{
|
||||
label: '名称',
|
||||
type: 'text',
|
||||
labelClassName: 'text-muted',
|
||||
name: 'name'
|
||||
},
|
||||
|
||||
{
|
||||
label: '作者',
|
||||
type: 'text',
|
||||
labelClassName: 'text-muted',
|
||||
name: 'author'
|
||||
},
|
||||
|
||||
{
|
||||
label: '请求时间',
|
||||
type: 'datetime',
|
||||
labelClassName: 'text-muted',
|
||||
inputFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
name: 'date'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
||||
{
|
||||
type: 'form',
|
||||
title: '条件表单',
|
||||
target: 'detailForm',
|
||||
submitOnInit: true,
|
||||
mode: 'inline',
|
||||
controls: [
|
||||
{
|
||||
label: '数据模板',
|
||||
type: 'select',
|
||||
labelClassName: 'text-muted',
|
||||
name: 'tpl',
|
||||
value: 'tpl1',
|
||||
options: [
|
||||
{
|
||||
label: '模板1',
|
||||
value: 'tpl1'
|
||||
},
|
||||
|
||||
{
|
||||
label: '模板2',
|
||||
value: 'tpl2'
|
||||
},
|
||||
|
||||
{
|
||||
label: '模板3',
|
||||
value: 'tpl3'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'submit',
|
||||
label: '提交',
|
||||
primary: true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'detailForm',
|
||||
type: 'form',
|
||||
mode: 'horizontal',
|
||||
title: '响应表单',
|
||||
initApi: '/api/mock2/form/initData?tpl=${tpl}',
|
||||
initFetchOn: 'data.tpl',
|
||||
actions: [],
|
||||
controls: [
|
||||
'<span class="text-danger">当 <code>initApi</code> 中有变量,且变量的值发生了变化了,则该表单就会重新初始数据。</span>',
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
||||
{
|
||||
label: '名称',
|
||||
type: 'static',
|
||||
labelClassName: 'text-muted',
|
||||
name: 'name'
|
||||
},
|
||||
|
||||
{
|
||||
label: '作者',
|
||||
type: 'static',
|
||||
labelClassName: 'text-muted',
|
||||
name: 'author'
|
||||
},
|
||||
|
||||
{
|
||||
label: '请求时间',
|
||||
type: 'static-datetime',
|
||||
labelClassName: 'text-muted',
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
name: 'date'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
60
examples/components/Linkage/Options.jsx
Normal file
60
examples/components/Linkage/Options.jsx
Normal file
@ -0,0 +1,60 @@
|
||||
export default {
|
||||
type: 'page',
|
||||
title: '表单选线之间的远程联动',
|
||||
body: {
|
||||
type: 'form',
|
||||
mode: 'horizontal',
|
||||
title: '',
|
||||
actions: [],
|
||||
controls: [
|
||||
'<p class="text-danger">表单选项可以设置 source 通过 API 远程拉取,同时如果 source 中有变量的话,变量值发生变化就会重新拉取,达到联动效果。</p>',
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
||||
{
|
||||
label: '选项1',
|
||||
type: 'select',
|
||||
labelClassName: 'text-muted',
|
||||
name: 'a',
|
||||
inline: true,
|
||||
options: [
|
||||
{
|
||||
label: '选项1',
|
||||
value: 1
|
||||
},
|
||||
|
||||
{
|
||||
label: '选项2',
|
||||
value: 2
|
||||
},
|
||||
|
||||
{
|
||||
label: '选项3',
|
||||
value: 3
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: '选项2',
|
||||
type: 'select',
|
||||
labelClassName: 'text-muted',
|
||||
name: 'b',
|
||||
inline: true,
|
||||
source: '/api/mock2/options/level2?a=${a}',
|
||||
initFetchOn: 'data.a'
|
||||
},
|
||||
|
||||
{
|
||||
label: '选项3',
|
||||
type: 'select',
|
||||
labelClassName: 'text-muted',
|
||||
name: 'c',
|
||||
inline: true,
|
||||
visibleOn: 'data.b',
|
||||
source: '/api/mock2/options/level3?b=${b}'
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
68
examples/components/Linkage/OptionsLocal.jsx
Normal file
68
examples/components/Linkage/OptionsLocal.jsx
Normal file
@ -0,0 +1,68 @@
|
||||
export default {
|
||||
type: 'page',
|
||||
title: '表单选线的联动',
|
||||
body: {
|
||||
type: 'form',
|
||||
mode: 'horizontal',
|
||||
title: '',
|
||||
actions: [],
|
||||
controls: [
|
||||
'<p class="text-danger">表单选项内也能联动,通过配置 visibleOn、hiddenOn或者disabledOn</p>',
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
||||
{
|
||||
label: '选项1',
|
||||
type: 'list',
|
||||
multiple: false,
|
||||
labelClassName: 'text-muted',
|
||||
name: 'a',
|
||||
inline: true,
|
||||
options: [
|
||||
{
|
||||
label: '选项1',
|
||||
value: 1
|
||||
},
|
||||
|
||||
{
|
||||
label: '选项2',
|
||||
value: 2
|
||||
},
|
||||
|
||||
{
|
||||
label: '选项3',
|
||||
value: 3
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: '选项2',
|
||||
type: 'radios',
|
||||
labelClassName: 'text-muted',
|
||||
name: 'b',
|
||||
inline: true,
|
||||
options: [
|
||||
{
|
||||
label: '选项1',
|
||||
value: 1,
|
||||
disabledOn: 'data.a == 1'
|
||||
},
|
||||
|
||||
{
|
||||
label: '选项2',
|
||||
value: 2,
|
||||
hiddenOn: 'data.a == 2'
|
||||
},
|
||||
|
||||
{
|
||||
label: '选项3',
|
||||
value: 3,
|
||||
visibleOn: 'data.a == 3'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
49
examples/components/Linkage/Page.jsx
Normal file
49
examples/components/Linkage/Page.jsx
Normal file
@ -0,0 +1,49 @@
|
||||
export default {
|
||||
$schema: "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
type: 'page',
|
||||
title: "地址栏变化自动更新",
|
||||
initApi: '/api/mock2/form/initData?id=${id}',
|
||||
aside: {
|
||||
type: 'wrapper',
|
||||
size: 'xs',
|
||||
className: '',
|
||||
body: {
|
||||
type: 'nav',
|
||||
stacked: true,
|
||||
links: [
|
||||
{
|
||||
label: '页面1',
|
||||
to: '?id=1'
|
||||
},
|
||||
|
||||
{
|
||||
label: '页面2',
|
||||
children: [
|
||||
{
|
||||
label: '页面2-1',
|
||||
to: '?id=2-1',
|
||||
},
|
||||
{
|
||||
label: '页面2-2',
|
||||
to: '?id=2-2',
|
||||
},
|
||||
{
|
||||
label: '页面2-3(disabled)',
|
||||
disabled: true,
|
||||
to: '?id=2-3',
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: '页面3',
|
||||
to: '?id=3'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
body: [
|
||||
'<p><span class="text-danger">注意 page 渲染器的 `initApi` 中有变量跟地址栏中变量关联,只要值发生了变化,就会重新拉取一次 initApi。</sapn></p>',
|
||||
"<p>这些数据是通过 initApi 拉取到的数据。 `\\$infoId`: <span class=\"text-danger\">${infoId|default:空}</span></p>"
|
||||
]
|
||||
};
|
190
examples/components/MdRenderer.jsx
Normal file
190
examples/components/MdRenderer.jsx
Normal file
@ -0,0 +1,190 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
import * as React from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import {render} from '../../src/index';
|
||||
import * as axios from 'axios';
|
||||
import TitleBar from '../../src/components/TitleBar';
|
||||
import LazyComponent from '../../src/components/LazyComponent';
|
||||
import Overlay from '../../src/components/Overlay';
|
||||
import PopOver from '../../src/components/PopOver';
|
||||
import NestedLinks from '../../src/components/AsideNav';
|
||||
import {Portal} from 'react-overlays';
|
||||
|
||||
class CodePreview extends React.Component {
|
||||
state = {
|
||||
PlayGround: null
|
||||
};
|
||||
componentDidMount() {
|
||||
require(['./Play'], (component) => this.setState({
|
||||
PlayGround: component.default
|
||||
}))
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
container,
|
||||
height,
|
||||
setAsideFolded,
|
||||
setHeaderVisible,
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
const PlayGround = this.state.PlayGround;
|
||||
// 不要放在 .markdown-body 下面,因为样式会干扰,复写又麻烦,所以通过 Overlay 渲染到同级
|
||||
|
||||
return (
|
||||
<div>
|
||||
<span style={{display: 'block', height: height}} ref="span"></span>
|
||||
{PlayGround ? <Overlay
|
||||
container={container}
|
||||
target={() => this.refs.span}
|
||||
placement="bottom"
|
||||
show
|
||||
>
|
||||
<PopOver offset={{x: 0, y: -height}} style={{height}} className="doc-shcema-preview-popover">
|
||||
<div className="doc-schema-preview">
|
||||
<PlayGround {...rest} vertical />
|
||||
</div>
|
||||
</PopOver>
|
||||
</Overlay> : null }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function isActive(link, location) {
|
||||
return !!(link.fullPath && link.fullPath === location.hash);
|
||||
}
|
||||
|
||||
export default function(doc) {
|
||||
return class extends React.Component {
|
||||
static displayName = 'MarkdownRenderer';
|
||||
ref = null;
|
||||
doms = [];
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.divRef = this.divRef.bind(this);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.renderSchema();
|
||||
|
||||
if (location.hash && location.hash.length > 1) {
|
||||
// 禁用自动跳转
|
||||
if (window.history && 'scrollRestoration' in window.history) {
|
||||
window.history.scrollRestoration = 'manual';
|
||||
}
|
||||
|
||||
const dom = document.querySelector(`[name="${location.hash.substring(1)}"]`);
|
||||
dom && dom.scrollIntoView();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.renderSchema();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.doms.forEach(dom => ReactDOM.unmountComponentAtNode(dom));
|
||||
}
|
||||
|
||||
handleClick(e) {
|
||||
const href = e.target.getAttribute('href');
|
||||
if (href && href[0] !== '#' && !/^http/.test(href)) {
|
||||
e.preventDefault();
|
||||
this.props.push(href);
|
||||
}
|
||||
}
|
||||
|
||||
divRef(ref) {
|
||||
this.ref = ref;
|
||||
|
||||
if (ref) {
|
||||
ref.innerHTML = doc.html;
|
||||
}
|
||||
}
|
||||
|
||||
renderSchema() {
|
||||
const scripts = document.querySelectorAll('script[type="text/schema"]');
|
||||
if (!scripts && !scripts.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0, len = scripts.length; i < len; i++) {
|
||||
let script = scripts[i];
|
||||
let props = {};
|
||||
[].slice.apply(script.attributes).forEach(item => {
|
||||
props[item.name] = item.value
|
||||
});
|
||||
|
||||
let dom = document.createElement('div');
|
||||
let height = props.height ? parseInt(props.height, 10) : 200;
|
||||
dom.setAttribute("class", "doc-play-ground")
|
||||
dom.setAttribute("style", `height: ${height}px;`);
|
||||
script.parentNode.replaceChild(dom, script);
|
||||
|
||||
this.doms.push(dom);
|
||||
ReactDOM.unstable_renderSubtreeIntoContainer(this, (
|
||||
<LazyComponent
|
||||
{...this.props}
|
||||
container={() => ReactDOM.findDOMNode(this)}
|
||||
height={height}
|
||||
component={CodePreview}
|
||||
code={script.innerText}
|
||||
scope={props.scope}
|
||||
unMountOnHidden
|
||||
placeholder="加载中,请稍后。。。"
|
||||
/>
|
||||
), dom);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {location} = this.props;
|
||||
|
||||
return (
|
||||
<div className="pos-rlt">
|
||||
<TitleBar title={doc.title} />
|
||||
<div className="markdown-body" ref={this.divRef}>Doc</div>
|
||||
{doc.toc && doc.toc.children && doc.toc.children.length ? (
|
||||
<Portal
|
||||
container={() => document.querySelector('#asideInner')}
|
||||
>
|
||||
<NestedLinks
|
||||
navigations={[doc.toc]}
|
||||
renderLink={({link, active, toggleExpand, depth, classnames: cx}) => {
|
||||
let children = [];
|
||||
|
||||
if (link.children) {
|
||||
children.push(
|
||||
<span
|
||||
key="expand-toggle"
|
||||
className={cx(`AsideNav-itemArrow`)}
|
||||
></span>
|
||||
);
|
||||
}
|
||||
|
||||
link.badge && children.push(
|
||||
<b key="badge" className={cx('AsideNav-itemBadge', link.badgeClassName || 'bg-info')}>{link.badge}</b>
|
||||
);
|
||||
|
||||
depth === 1 && children.push(
|
||||
<i key="icon" className={cx("AsideNav-itemIcon fa fa-flag")} />
|
||||
);
|
||||
|
||||
children.push(
|
||||
<span key="label" className={cx("AsideNav-itemLabel")}>{link.label}</span>
|
||||
);
|
||||
|
||||
return link.fragment ? (<a href={`#${link.fragment}`}>{children}</a>) : (<a onClick={link.children ? () => toggleExpand(link) : null}>{children}</a>);
|
||||
}}
|
||||
isActive={link => isActive(link, location)}
|
||||
/>
|
||||
</Portal>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
27
examples/components/Page/Error.jsx
Normal file
27
examples/components/Page/Error.jsx
Normal file
@ -0,0 +1,27 @@
|
||||
export default {
|
||||
type: 'page',
|
||||
title: '标题',
|
||||
remark: '提示 Tip',
|
||||
body: [
|
||||
`
|
||||
<p>\`initApi\` 拉取失败时,页面内容区会显示对应的错误信息。</p>
|
||||
|
||||
<p>其他提示示例</p>
|
||||
`,
|
||||
|
||||
{
|
||||
type: 'alert',
|
||||
level: 'success',
|
||||
body: `温馨提示:对页面功能的提示说明,绿色为正向类的消息提示`
|
||||
},
|
||||
|
||||
{
|
||||
type: 'alert',
|
||||
level: 'warning',
|
||||
body: `您的私有网络已达到配额,如需更多私有网络,可以通过<a>工单</a>申请`
|
||||
}
|
||||
],
|
||||
aside: '边栏',
|
||||
toolbar: '工具栏',
|
||||
initApi: '/api/mock2/page/initDataError'
|
||||
}
|
23
examples/components/Page/Form.jsx
Normal file
23
examples/components/Page/Form.jsx
Normal file
@ -0,0 +1,23 @@
|
||||
export default {
|
||||
type: 'page',
|
||||
title: '表单页面',
|
||||
body: {
|
||||
type: 'form',
|
||||
mode: 'horizontal',
|
||||
title: '',
|
||||
api: '/api/mock2/form/saveForm',
|
||||
controls: [
|
||||
{
|
||||
label: 'Name',
|
||||
type: 'text',
|
||||
name: 'name'
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Email',
|
||||
type: 'email',
|
||||
name: 'email'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
9
examples/components/Page/Simple.jsx
Normal file
9
examples/components/Page/Simple.jsx
Normal file
@ -0,0 +1,9 @@
|
||||
export default {
|
||||
type: 'page',
|
||||
title: '标题',
|
||||
remark: '提示 Tip',
|
||||
body: "内容部分. 可以使用 \\${var} 获取变量。如: `\\$date`: ${date}",
|
||||
aside: '边栏部分',
|
||||
toolbar: '工具栏',
|
||||
initApi: '/api/mock2/page/initData'
|
||||
}
|
290
examples/components/Play.jsx
Normal file
290
examples/components/Play.jsx
Normal file
@ -0,0 +1,290 @@
|
||||
import * as React from 'react';
|
||||
import {
|
||||
toast
|
||||
} from '../../src/components/Toast';
|
||||
import {render} from '../../src/index';
|
||||
import * as axios from 'axios';
|
||||
import Frame from 'react-frame-component';
|
||||
import * as stripJsonComments from 'strip-json-comments';
|
||||
import CodeEditor from '../../src/components/Editor';
|
||||
|
||||
const DEFAULT_CONTENT = `{
|
||||
"$schema": "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
"type": "page",
|
||||
"title": "Title",
|
||||
"body": "Body",
|
||||
"aside": "Aside",
|
||||
"toolbar": "Toolbar"
|
||||
}`;
|
||||
|
||||
const scopes = {
|
||||
'none': ``,
|
||||
|
||||
'body': `{
|
||||
"type": "page",
|
||||
"body": SCHEMA_PLACEHOLDER
|
||||
}`,
|
||||
|
||||
'form': `{
|
||||
"type": "page",
|
||||
"body": {
|
||||
"title": "",
|
||||
"type": "form",
|
||||
"autoFocus": false,
|
||||
"api": "/api/mock/saveForm?waitSeconds=1",
|
||||
"mode": "horizontal",
|
||||
"controls": SCHEMA_PLACEHOLDER,
|
||||
"submitText": null,
|
||||
"actions": []
|
||||
}
|
||||
}`,
|
||||
|
||||
'form-item': `{
|
||||
"type": "page",
|
||||
"body": {
|
||||
"title": "",
|
||||
"type": "form",
|
||||
"mode": "horizontal",
|
||||
"autoFocus": false,
|
||||
"controls": [
|
||||
SCHEMA_PLACEHOLDER
|
||||
],
|
||||
"submitText": null,
|
||||
"actions": []
|
||||
}
|
||||
}`
|
||||
|
||||
};
|
||||
|
||||
export default class PlayGround extends React.Component {
|
||||
|
||||
state = null;
|
||||
startX = 0;
|
||||
oldContents = '';
|
||||
frameTemplate;
|
||||
|
||||
static defaultProps = {
|
||||
useIFrame: false,
|
||||
vertical: false
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const schema = this.buildSchema(props.code || DEFAULT_CONTENT, props);
|
||||
this.state = {
|
||||
asideWidth: props.asideWidth || Math.max(300, window.innerWidth * 0.3),
|
||||
schema: schema,
|
||||
schemaCode: JSON.stringify(schema, null, 2)
|
||||
};
|
||||
|
||||
this.handleMouseDown = this.handleMouseDown.bind(this);
|
||||
this.handleMouseMove = this.handleMouseMove.bind(this);
|
||||
this.handleMouseUp = this.handleMouseUp.bind(this);
|
||||
this.removeWindowEvents = this.removeWindowEvents.bind(this);
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.schemaProps = {
|
||||
style: {
|
||||
height: '100%'
|
||||
}
|
||||
};
|
||||
this.env = {
|
||||
updateLocation: () => {
|
||||
},
|
||||
fetcher: config => {
|
||||
config = {
|
||||
dataType: 'json',
|
||||
...config
|
||||
};
|
||||
|
||||
if (config.dataType === 'json' && config.data) {
|
||||
config.data = JSON.stringify(config.data)
|
||||
config.headers = config.headers || {};
|
||||
config.headers['Content-Type'] = 'application/json';
|
||||
}
|
||||
|
||||
return axios[config.method](config.url, config.data, config);
|
||||
},
|
||||
notify: (type, msg) => toast[type] ? toast[type](msg, type === 'error' ? '系统错误' : '系统消息') : console.warn('[Notify]', type, msg)
|
||||
}
|
||||
|
||||
const links = [].slice.call(document.head.querySelectorAll('link,style')).map(item => item.outerHTML);
|
||||
this.frameTemplate = `<!DOCTYPE html><html><head>${links.join('')}</head><body><div></div></body></html>`;
|
||||
this.handleEditorMount = this.handleEditorMount.bind(this);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextprops) {
|
||||
const props = this.props;
|
||||
|
||||
if (props.code !== nextprops.code) {
|
||||
const schema = this.buildSchema(nextprops.code || DEFAULT_CONTENT, nextprops);
|
||||
this.setState({
|
||||
schema: schema,
|
||||
schemaCode: JSON.stringify(schema, null, 2)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.setAsideFolded && this.props.setAsideFolded(true);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.setAsideFolded && this.props.setAsideFolded(false);
|
||||
}
|
||||
|
||||
buildSchema(schemaContent, props = this.props) {
|
||||
const query = props.location.query;
|
||||
|
||||
try {
|
||||
const scope = query.scope || props.scope;
|
||||
|
||||
if (scope && scopes[scope]) {
|
||||
schemaContent = scopes[scope].replace('SCHEMA_PLACEHOLDER', schemaContent);
|
||||
}
|
||||
|
||||
schemaContent = stripJsonComments(schemaContent).replace(/('|")raw:/g, '$1'); // 去掉注释
|
||||
|
||||
return JSON.parse(schemaContent);
|
||||
} catch (e) {
|
||||
console.error(this.formatMessage(e.message, schemaContent));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
formatMessage(message, input) {
|
||||
if (/position\s?(\d+)$/.test(message)) {
|
||||
const lines = input.substring(0, parseInt(RegExp.$1, 10)).split(/\n|\r\n|\r/);
|
||||
message = `Json 语法错误,请检测。出错位置:${lines.length},列:${lines[lines.length -1].length}。`;
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
renderPreview() {
|
||||
const schema = this.state.schema;
|
||||
|
||||
if (!this.props.useIFrame) {
|
||||
return render(schema, this.schemaProps, this.env);
|
||||
}
|
||||
|
||||
return (
|
||||
<Frame
|
||||
width="100%"
|
||||
height="100%"
|
||||
frameBorder={0}
|
||||
initialContent={this.frameTemplate}
|
||||
>
|
||||
{render(schema, this.schemaProps, this.env)}
|
||||
</Frame>
|
||||
);
|
||||
}
|
||||
|
||||
handleEditorMount(editor, monaco) {
|
||||
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
|
||||
enableSchemaRequest: true,
|
||||
validate: true
|
||||
});
|
||||
}
|
||||
|
||||
handleChange(value) {
|
||||
this.setState({
|
||||
schemaCode: value
|
||||
});
|
||||
|
||||
try {
|
||||
const schema = JSON.parse(value);
|
||||
|
||||
this.setState({
|
||||
schema
|
||||
});
|
||||
} catch (e) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
|
||||
handleMouseDown(e) {
|
||||
this.startX = e.clientX;
|
||||
this.startWidth = this.state.asideWidth;
|
||||
|
||||
// this.startPosition.y = e.clientY;
|
||||
|
||||
window.addEventListener('mouseup', this.handleMouseUp);
|
||||
window.addEventListener('mousemove', this.handleMouseMove);
|
||||
return false;
|
||||
}
|
||||
|
||||
handleMouseMove(e) {
|
||||
const diff = this.startX - e.clientX;
|
||||
e.preventDefault();
|
||||
|
||||
this.setState({
|
||||
asideWidth: Math.min(800, Math.max(200, this.startWidth + diff))
|
||||
});
|
||||
}
|
||||
|
||||
handleMouseUp() {
|
||||
this.removeWindowEvents();
|
||||
}
|
||||
|
||||
removeWindowEvents() {
|
||||
window.removeEventListener('mouseup', this.handleMouseUp);
|
||||
window.removeEventListener('mousemove', this.handleMouseMove);
|
||||
}
|
||||
|
||||
renderEditor() {
|
||||
return (
|
||||
<CodeEditor
|
||||
value={this.state.schemaCode}
|
||||
onChange={this.handleChange}
|
||||
language="json"
|
||||
editorDidMount={this.handleEditorMount}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
vertical
|
||||
} = this.props;
|
||||
if (vertical) {
|
||||
return (
|
||||
<div className="vbox">
|
||||
<div className="row-row">
|
||||
<div className="cell pos-rlt">
|
||||
<div className="scroll-y h-full pos-abt w-full">
|
||||
{this.renderPreview()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row-row" style={{height: 200}}>
|
||||
<div className="cell">
|
||||
{this.renderEditor()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
position: "absolute",
|
||||
top: 50,
|
||||
bottom: 0
|
||||
}}>
|
||||
<div className="hbox">
|
||||
<div className="col pos-rlt">
|
||||
<div className="scroll-y h-full pos-abt w-full">
|
||||
{this.renderPreview()}
|
||||
</div>
|
||||
</div>
|
||||
<div className="col bg-light lter b-l bg-auto pos-rlt" style={{width: this.state.asideWidth}}>
|
||||
<div className="resizer" onMouseDown={this.handleMouseDown}></div>
|
||||
{this.renderEditor()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
171
examples/components/SchemaRender.jsx
Normal file
171
examples/components/SchemaRender.jsx
Normal file
@ -0,0 +1,171 @@
|
||||
import * as React from 'react';
|
||||
import {render} from '../../src/index';
|
||||
import * as axios from 'axios';
|
||||
import {toast} from '../../src/components/Toast';
|
||||
import {alert, confirm} from '../../src/components/Alert';
|
||||
import Button from '../../src/components/Button'
|
||||
import LazyComponent from '../../src/components/LazyComponent'
|
||||
import {default as DrawerContainer} from '../../src/components/Drawer'
|
||||
import { Portal } from 'react-overlays';
|
||||
function loadEditor() {
|
||||
return new Promise((resolve) => require(['../../src/components/Editor'], (component) => resolve(component.default)));
|
||||
}
|
||||
export default function(schema) {
|
||||
if (!schema['$schema']) {
|
||||
schema = {
|
||||
'$schema': 'http://amis.baidu.com/v2/schemas/page.json',
|
||||
...schema
|
||||
};
|
||||
}
|
||||
|
||||
return class extends React.Component {
|
||||
static displayName = 'SchemaRenderer';
|
||||
state = {open: false};
|
||||
toggleCode = () => this.setState({
|
||||
open: !this.state.open
|
||||
});
|
||||
close = () => this.setState({
|
||||
open: false
|
||||
});
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const {router} = props;
|
||||
const normalizeLink = (to) => {
|
||||
to = to || '';
|
||||
const location = router.getCurrentLocation();
|
||||
|
||||
if (to && to[0] === '#') {
|
||||
to = location.pathname + location.search + to;
|
||||
} else if (to && to[0] === '?') {
|
||||
to = location.pathname + to;
|
||||
}
|
||||
|
||||
const idx = to.indexOf('?');
|
||||
const idx2 = to.indexOf('#');
|
||||
let pathname = ~idx ? to.substring(0, idx) : ~idx2 ? to.substring(0, idx2) : to;
|
||||
let search = ~idx ? to.substring(idx, ~idx2 ? idx2 : undefined) : '';
|
||||
let hash = ~idx2 ? to.substring(idx2) : '';
|
||||
|
||||
if (!pathname) {
|
||||
pathname = location.pathname;
|
||||
} else if (pathname[0] != '/' && !/^https?:\/\//.test(pathname)) {
|
||||
// todo 把相对路径转成绝对路径。
|
||||
}
|
||||
|
||||
return pathname + search + hash;
|
||||
}
|
||||
this.env = {
|
||||
updateLocation: (location, replace) => {
|
||||
router[replace ? 'replace' : 'push'](normalizeLink(location));
|
||||
},
|
||||
isCurrentUrl: (to) => {
|
||||
const link = normalizeLink(to);
|
||||
return router.isActive(link);
|
||||
},
|
||||
jumpTo: (to) => {
|
||||
to = normalizeLink(to);
|
||||
|
||||
if (/^https?:\/\//.test(to)) {
|
||||
window.location.replace(to);
|
||||
} else {
|
||||
router.push(to);
|
||||
}
|
||||
},
|
||||
fetcher: ({
|
||||
url,
|
||||
method,
|
||||
data,
|
||||
config
|
||||
}) => {
|
||||
if (data && data instanceof FormData) {
|
||||
// config.headers = config.headers || {};
|
||||
// config.headers['Content-Type'] = 'multipart/form-data';
|
||||
} else if (data
|
||||
&& typeof data !== 'string'
|
||||
&& !(data instanceof Blob)
|
||||
&& !(data instanceof ArrayBuffer)
|
||||
) {
|
||||
data = JSON.stringify(data);
|
||||
config = config || {};
|
||||
config.headers = config.headers || {};
|
||||
config.headers['Content-Type'] = 'application/json';
|
||||
}
|
||||
|
||||
if (method !== 'post' && method !== 'put' && method !== 'patch') {
|
||||
if (data) {
|
||||
if (method === 'delete') {
|
||||
config.data = data;
|
||||
} else {
|
||||
config.params = data;
|
||||
}
|
||||
}
|
||||
|
||||
return axios[method](url, config);
|
||||
}
|
||||
|
||||
return axios[method](url, data, config);
|
||||
},
|
||||
notify: (type, msg) => toast[type] ? toast[type](msg, type === 'error' ? '系统错误' : '系统消息') : console.warn('[Notify]', type, msg),
|
||||
alert,
|
||||
confirm,
|
||||
copy: (content) => console.log('Copy', content)
|
||||
};
|
||||
|
||||
this.handleEditorMount = this.handleEditorMount.bind(this);
|
||||
}
|
||||
|
||||
handleEditorMount(editor, monaco) {
|
||||
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
|
||||
enableSchemaRequest: true,
|
||||
validate: true
|
||||
});
|
||||
}
|
||||
|
||||
renderCode() {
|
||||
return (
|
||||
<LazyComponent
|
||||
getComponent={loadEditor}
|
||||
editorDidMount={this.handleEditorMount}
|
||||
language="json"
|
||||
value={schema}
|
||||
placeholder="加载中,请稍后。。。"
|
||||
disabled
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderSchema() {
|
||||
const {
|
||||
router,
|
||||
location,
|
||||
theme
|
||||
} = this.props;
|
||||
|
||||
return render(schema, {
|
||||
location,
|
||||
theme
|
||||
}, this.env);
|
||||
}
|
||||
|
||||
render() {
|
||||
const ns = this.props.classPrefix;
|
||||
return (
|
||||
<div className="schema-wrapper">
|
||||
<DrawerContainer
|
||||
classPrefix={ns}
|
||||
size="lg"
|
||||
onHide={this.close}
|
||||
show={this.state.open}
|
||||
position="left"
|
||||
>
|
||||
{this.state.open ? this.renderCode() : null}
|
||||
</DrawerContainer>
|
||||
{this.renderSchema()}
|
||||
<Portal container={() => document.querySelector('.navbar-nav')}>
|
||||
<Button classPrefix={ns} onClick={this.toggleCode} active={this.state.open} iconOnly tooltip="查看源码" level="link" placement="bottom" className="view-code"><i className="fa fa-code" /></Button>
|
||||
</Portal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
90
examples/components/Sdk/Test.jsx
Normal file
90
examples/components/Sdk/Test.jsx
Normal file
@ -0,0 +1,90 @@
|
||||
import * as React from 'react';
|
||||
import TitleBar from '../../../src/components/TitleBar';
|
||||
import {render} from '../../../src/index';
|
||||
|
||||
|
||||
export default class SdkTest extends React.Component {
|
||||
state = {
|
||||
data: {
|
||||
name: 'Amis Renderer',
|
||||
id: 1,
|
||||
email: 'xxx@xxx.com'
|
||||
}
|
||||
};
|
||||
|
||||
renderForm() {
|
||||
return render({
|
||||
title: '',
|
||||
type: 'form',
|
||||
controls: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'name',
|
||||
label: 'Name'
|
||||
},
|
||||
|
||||
{
|
||||
type: 'text',
|
||||
name: 'id',
|
||||
label: 'Id'
|
||||
},
|
||||
|
||||
{
|
||||
type: 'email',
|
||||
name: 'email',
|
||||
label: 'Email'
|
||||
},
|
||||
|
||||
{
|
||||
type: 'static',
|
||||
label: '最后更新时间',
|
||||
name: 'lastModified'
|
||||
}
|
||||
]
|
||||
}, {
|
||||
data: this.state.data,
|
||||
onFailed: (reason, errors) => {
|
||||
console.log('Submit Failed', errors, '\n', reason);
|
||||
},
|
||||
onSubmit: (values) => {
|
||||
console.log('Submit', values);
|
||||
},
|
||||
onChange: (values, diff) => {
|
||||
this.setState({
|
||||
data: {
|
||||
...values,
|
||||
lastModified: new Date()
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Diff', diff);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
handleClick = () => {
|
||||
this.setState({
|
||||
data: {
|
||||
name: 'Amis Renderer',
|
||||
id: Math.round(Math.random() * 1000),
|
||||
email: 'xxx@xxx.com'
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<TitleBar title="API 调用 集成在你的 React 应用中" />
|
||||
<div className="wrapper">
|
||||
{this.renderForm()}
|
||||
|
||||
<button onClick={this.handleClick}>随机修改</button>
|
||||
|
||||
<h3>当前值</h3>
|
||||
<pre><code>{JSON.stringify(this.state.data, null, 2)}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
118
examples/components/Services/Data.jsx
Normal file
118
examples/components/Services/Data.jsx
Normal file
@ -0,0 +1,118 @@
|
||||
export default {
|
||||
type: 'page',
|
||||
title: '动态加载数据',
|
||||
body: [
|
||||
'<span class="text-danger">除了用 Page、CRUD、Form 或者 Wizard 能拉取数据外,还可以通过 Service 专门拉取数据,然后丢给其他类型的渲染器渲染。</span>',
|
||||
|
||||
{
|
||||
type: 'form',
|
||||
title: '条件输入',
|
||||
className: 'm-t',
|
||||
wrapWithPanel: false,
|
||||
target: 'service1',
|
||||
mode: 'inline',
|
||||
controls: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'keywords',
|
||||
placeholder: '关键字',
|
||||
addOn: {
|
||||
type: 'button',
|
||||
icon: 'fa fa-search',
|
||||
actionType: 'submit',
|
||||
level: 'primary'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'service1',
|
||||
type: 'service',
|
||||
className: 'm-t',
|
||||
api: '/api/mock2/service/data?keywords=${keywords}',
|
||||
body: [
|
||||
'当前关键字是 ${keywords},当前时间是: ${date|date:YYYY-MM-DD HH\\:mm}',
|
||||
|
||||
|
||||
{
|
||||
type: 'table',
|
||||
className: 'm-t',
|
||||
source: '${table1}',
|
||||
columns: [
|
||||
{
|
||||
name: "id",
|
||||
label: "ID",
|
||||
type: "text"
|
||||
},
|
||||
{
|
||||
name: "text",
|
||||
label: "文本",
|
||||
type: "text"
|
||||
},
|
||||
{
|
||||
type: 'image',
|
||||
label: '图片',
|
||||
name: 'image',
|
||||
popOver: {
|
||||
title: '查看大图',
|
||||
body: '<div class="w-xxl"><img class="w-full" src="${image}"/></div>'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'date',
|
||||
type: 'date',
|
||||
label: '日期'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'table',
|
||||
source: '${table2}',
|
||||
columns: [
|
||||
{
|
||||
name: "progress",
|
||||
label: "进度",
|
||||
type: "progress"
|
||||
},
|
||||
{
|
||||
name: "boolean",
|
||||
label: "状态",
|
||||
type: "status"
|
||||
},
|
||||
{
|
||||
name: "boolean",
|
||||
label: "开关",
|
||||
type: "switch",
|
||||
// readOnly: false // 可以开启修改模式
|
||||
},
|
||||
{
|
||||
name: "type",
|
||||
label: "映射",
|
||||
type: "mapping",
|
||||
map: {
|
||||
"*": "其他:${type}",
|
||||
"1": "<span class='label label-info'>漂亮</span>",
|
||||
"2": "<span class='label label-success'>开心</span>",
|
||||
"3": "<span class='label label-danger'>惊吓</span>",
|
||||
"4": "<span class='label label-warning'>紧张</span>"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: 'list',
|
||||
type: 'list',
|
||||
label: 'List',
|
||||
placeholder: '-',
|
||||
listItem: {
|
||||
title: '${title}',
|
||||
subTitle: '${description}'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
68
examples/components/Services/Form.jsx
Normal file
68
examples/components/Services/Form.jsx
Normal file
@ -0,0 +1,68 @@
|
||||
export default {
|
||||
type: 'page',
|
||||
title: '动态加载表单中的部分',
|
||||
body: [
|
||||
'<span class="text-danger">同样通过 <code>service</code>的<code>schemaApi</code> 来加载部分内容,当然也可以全部由它来加载</span>',
|
||||
|
||||
{
|
||||
type: 'form',
|
||||
panelClassName: 'Panel--info m-t',
|
||||
target: 'service1',
|
||||
mode: 'horizontal',
|
||||
api: '/api/mock2/form/saveForm?waitSeconds=1',
|
||||
fieldSet: [
|
||||
{
|
||||
title: '基本信息',
|
||||
controls: [
|
||||
{
|
||||
type: 'text',
|
||||
label: '字段一',
|
||||
name: 'filed1',
|
||||
},
|
||||
|
||||
{
|
||||
type: 'text',
|
||||
label: '字段二',
|
||||
name: 'filed2'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
title: '其他信息',
|
||||
controls: [
|
||||
{
|
||||
name: 'tpl',
|
||||
type: 'select',
|
||||
label: '模板',
|
||||
inline: true,
|
||||
required: true,
|
||||
value: 'tpl1',
|
||||
options: [
|
||||
{
|
||||
label: '模板1',
|
||||
value: 'tpl1'
|
||||
},
|
||||
{
|
||||
label: '模板2',
|
||||
value: 'tpl2'
|
||||
},
|
||||
{
|
||||
label: '模板3',
|
||||
value: 'tpl3'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'service',
|
||||
className: 'm-t',
|
||||
initFetchSchemaOn: 'data.tpl',
|
||||
schemaApi: '/api/mock2/service/form?tpl=$tpl',
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
50
examples/components/Services/Schema.jsx
Normal file
50
examples/components/Services/Schema.jsx
Normal file
@ -0,0 +1,50 @@
|
||||
export default {
|
||||
type: 'page',
|
||||
title: '动态加载页面',
|
||||
body: [
|
||||
'<span class="text-danger">可以通过 <code>service</code>的<code>schemaApi</code> 动态控制内容。</span>',
|
||||
|
||||
{
|
||||
type: 'form',
|
||||
title: '条件输入',
|
||||
panelClassName: 'panel-info m-t',
|
||||
target: 'service1',
|
||||
mode: 'inline',
|
||||
submitOnInit: true,
|
||||
controls: [
|
||||
{
|
||||
label: '加载页面类型',
|
||||
required: true,
|
||||
type: 'button-group',
|
||||
submitOnChange: true,
|
||||
value: 'crud',
|
||||
name: 'type',
|
||||
options: [
|
||||
{
|
||||
label: 'Crud',
|
||||
value: 'crud'
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Form',
|
||||
value: 'form'
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Tabs',
|
||||
value: 'tabs'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'service1',
|
||||
type: 'service',
|
||||
className: 'm-t',
|
||||
initFetchSchema: false,
|
||||
schemaApi: '/api/mock2/service/schema?type=$type',
|
||||
}
|
||||
]
|
||||
}
|
47
examples/components/Tabs/Form.jsx
Normal file
47
examples/components/Tabs/Form.jsx
Normal file
@ -0,0 +1,47 @@
|
||||
export default {
|
||||
type: 'page',
|
||||
title: '表单中选项卡分组',
|
||||
subTitle: '',
|
||||
body: [
|
||||
'<p>多个 controls 可以通过 tabs 来分组展示,表单将作为一个整体提交。</p>',
|
||||
{
|
||||
type: 'form',
|
||||
title: '',
|
||||
tabs: [
|
||||
{
|
||||
title: '选项卡1',
|
||||
hash: 'tab1',
|
||||
controls: [
|
||||
{
|
||||
type: 'text',
|
||||
label: '文本1',
|
||||
name: 'a'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '选项卡2',
|
||||
hash: 'tab2',
|
||||
controls: [
|
||||
{
|
||||
type: 'text',
|
||||
label: '文本2',
|
||||
name: 'b'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
title: '选项卡3',
|
||||
hash: 'tab3',
|
||||
controls: [
|
||||
{
|
||||
type: 'text',
|
||||
label: '文本3',
|
||||
name: 'c'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}]
|
||||
}
|
165
examples/components/Tabs/Normal.jsx
Normal file
165
examples/components/Tabs/Normal.jsx
Normal file
@ -0,0 +1,165 @@
|
||||
export default {
|
||||
type: 'page',
|
||||
title: '选项卡示例',
|
||||
subTitle: '所有选项卡都在当前页面中,包括默认、line、card以及radio模式',
|
||||
body: [
|
||||
{
|
||||
type: 'tabs',
|
||||
tabs: [
|
||||
{
|
||||
title: '选项卡1',
|
||||
hash: 'tab1',
|
||||
body: '选项卡内容1'
|
||||
},
|
||||
|
||||
{
|
||||
title: '选项卡2',
|
||||
hash: 'tab2',
|
||||
body: {
|
||||
type: 'form',
|
||||
panelClassName: 'panel-primary',
|
||||
controls: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'a',
|
||||
label: '文本'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
title: '选项卡3',
|
||||
body: {
|
||||
type: "crud",
|
||||
api: "/api/sample",
|
||||
filter: {
|
||||
title: "条件搜索",
|
||||
submitText: "",
|
||||
controls: [
|
||||
{
|
||||
type: "text",
|
||||
name: "keywords",
|
||||
placeholder: "通过关键字搜索",
|
||||
clearable: true,
|
||||
addOn: {
|
||||
label: "搜索",
|
||||
type: "submit"
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "plain",
|
||||
text: "这里的表单项可以配置多个"
|
||||
}
|
||||
]
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
name: "id",
|
||||
label: "ID",
|
||||
width: 20
|
||||
},
|
||||
{
|
||||
name: "engine",
|
||||
label: "Rendering engine"
|
||||
},
|
||||
{
|
||||
name: "browser",
|
||||
label: "Browser"
|
||||
},
|
||||
{
|
||||
name: "platform",
|
||||
label: "Platform(s)"
|
||||
},
|
||||
{
|
||||
name: "version",
|
||||
label: "Engine version"
|
||||
},
|
||||
{
|
||||
name: "grade",
|
||||
label: "CSS grade"
|
||||
},
|
||||
{
|
||||
type: "operation",
|
||||
label: "操作",
|
||||
width: 100,
|
||||
buttons: [
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
{
|
||||
type: 'tabs',
|
||||
mode: 'line',
|
||||
tabs: [
|
||||
{
|
||||
title: '选项卡1',
|
||||
body: '选项卡内容1'
|
||||
},
|
||||
|
||||
{
|
||||
title: '选项卡2',
|
||||
body: '选项卡内容2'
|
||||
},
|
||||
|
||||
{
|
||||
title: '选项卡3',
|
||||
body: '选项卡内容3'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
{
|
||||
type: 'tabs',
|
||||
mode: 'card',
|
||||
tabs: [
|
||||
{
|
||||
title: '选项卡1',
|
||||
body: '选项卡内容1'
|
||||
},
|
||||
|
||||
{
|
||||
title: '选项卡2',
|
||||
body: '选项卡内容2'
|
||||
},
|
||||
|
||||
{
|
||||
title: '选项卡3',
|
||||
body: '选项卡内容3'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
{
|
||||
type: 'tabs',
|
||||
mode: 'radio',
|
||||
tabs: [
|
||||
{
|
||||
title: '选项卡1',
|
||||
body: '选项卡内容1'
|
||||
},
|
||||
|
||||
{
|
||||
title: '选项卡2',
|
||||
body: '选项卡内容2'
|
||||
},
|
||||
|
||||
{
|
||||
title: '选项卡3',
|
||||
body: '选项卡内容3'
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
}
|
35
examples/components/Tabs/Tab1.jsx
Normal file
35
examples/components/Tabs/Tab1.jsx
Normal file
@ -0,0 +1,35 @@
|
||||
export default {
|
||||
type: 'page',
|
||||
title: '选项卡1页面',
|
||||
body: [
|
||||
'<p>也可以多个页面,利用导航<code>nav</code>渲染期模拟 tabs 的效果。这样可以让 url 更加友好,而不是只能用 hash。</p>',
|
||||
|
||||
{
|
||||
type: 'nav',
|
||||
links: [
|
||||
{
|
||||
label: '选项卡1',
|
||||
icon: 'fa fa-cloud',
|
||||
to: '/examples/tabs/tab1'
|
||||
},
|
||||
|
||||
{
|
||||
label: '选项卡2',
|
||||
to: '/examples/tabs/tab2'
|
||||
},
|
||||
|
||||
{
|
||||
label: '选项卡3',
|
||||
icon: 'fa fa-youtube',
|
||||
to: '/examples/tabs/tab3'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'wrapper',
|
||||
className: 'wrapper bg-white b-l b-b b-r',
|
||||
body: '选项卡1的内容'
|
||||
}
|
||||
]
|
||||
}
|
35
examples/components/Tabs/Tab2.jsx
Normal file
35
examples/components/Tabs/Tab2.jsx
Normal file
@ -0,0 +1,35 @@
|
||||
export default {
|
||||
type: 'page',
|
||||
title: '选项卡2页面',
|
||||
body: [
|
||||
'<p>也可以多个页面,利用导航<code>nav</code>渲染期模拟 tabs 的效果。</p>',
|
||||
|
||||
{
|
||||
type: 'nav',
|
||||
links: [
|
||||
{
|
||||
label: '选项卡1',
|
||||
icon: 'fa fa-cloud',
|
||||
to: '/examples/tabs/tab1'
|
||||
},
|
||||
|
||||
{
|
||||
label: '选项卡2',
|
||||
to: '/examples/tabs/tab2'
|
||||
},
|
||||
|
||||
{
|
||||
label: '选项卡3',
|
||||
icon: 'fa fa-youtube',
|
||||
to: '/examples/tabs/tab3'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'wrapper',
|
||||
className: 'wrapper bg-white b-l b-b b-r',
|
||||
body: '选项卡2的内容'
|
||||
}
|
||||
]
|
||||
}
|
121
examples/components/Tabs/Tab3.jsx
Normal file
121
examples/components/Tabs/Tab3.jsx
Normal file
@ -0,0 +1,121 @@
|
||||
export default {
|
||||
type: 'page',
|
||||
title: '选项卡3页面',
|
||||
body: [
|
||||
'<p>也可以多个页面,利用导航<code>nav</code>渲染期模拟 tabs 的效果。</p>',
|
||||
|
||||
{
|
||||
type: 'nav',
|
||||
links: [
|
||||
{
|
||||
label: '选项卡1',
|
||||
icon: 'fa fa-cloud',
|
||||
to: '/examples/tabs/tab1'
|
||||
},
|
||||
|
||||
{
|
||||
label: '选项卡2',
|
||||
to: '/examples/tabs/tab2'
|
||||
},
|
||||
|
||||
{
|
||||
label: '选项卡3',
|
||||
icon: 'fa fa-youtube',
|
||||
to: '/examples/tabs/tab3'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'wrapper',
|
||||
className: 'wrapper bg-white b-l b-b b-r',
|
||||
body: {
|
||||
"type": "chart",
|
||||
"config": {
|
||||
"title": {
|
||||
"text": "极坐标双数值轴"
|
||||
},
|
||||
"legend": {
|
||||
"data": [
|
||||
"line"
|
||||
]
|
||||
},
|
||||
"polar": {
|
||||
"center": [
|
||||
"50%",
|
||||
"54%"
|
||||
]
|
||||
},
|
||||
"tooltip": {
|
||||
"trigger": "axis",
|
||||
"axisPointer": {
|
||||
"type": "cross"
|
||||
}
|
||||
},
|
||||
"angleAxis": {
|
||||
"type": "value",
|
||||
"startAngle": 0
|
||||
},
|
||||
"radiusAxis": {
|
||||
"min": 0
|
||||
},
|
||||
"series": [
|
||||
{
|
||||
"coordinateSystem": "polar",
|
||||
"name": "line",
|
||||
"type": "line",
|
||||
"showSymbol": false,
|
||||
"data": [
|
||||
[
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
0.03487823687206265,
|
||||
1
|
||||
],
|
||||
[
|
||||
0.06958655048003272,
|
||||
2
|
||||
],
|
||||
[
|
||||
0.10395584540887964,
|
||||
3
|
||||
],
|
||||
[
|
||||
0.13781867790849958,
|
||||
4
|
||||
],
|
||||
[
|
||||
0.17101007166283433,
|
||||
5
|
||||
],
|
||||
[
|
||||
0.2033683215379001,
|
||||
6
|
||||
],
|
||||
[
|
||||
0.2347357813929454,
|
||||
7
|
||||
],
|
||||
[
|
||||
0.26495963211660245,
|
||||
8
|
||||
],
|
||||
[
|
||||
0.2938926261462365,
|
||||
9
|
||||
],
|
||||
[
|
||||
0.3213938048432697,
|
||||
10
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"animationDuration": 2000
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
36
examples/components/Tasks.jsx
Normal file
36
examples/components/Tasks.jsx
Normal file
@ -0,0 +1,36 @@
|
||||
export default {
|
||||
"$schema": "http://amis.baidu.com/v2/schemas/page.json#",
|
||||
"title": "异步任务",
|
||||
"body": [
|
||||
'<p class="text-danger"></p>',
|
||||
{
|
||||
"type": "tasks",
|
||||
"name": "tasks",
|
||||
"items": [
|
||||
{
|
||||
"label": "hive 任务",
|
||||
"key": "hive",
|
||||
"status": 4,
|
||||
"remark": "查看详情<a target=\"_blank\" href=\"http://www.baidu.com\">日志</a>。"
|
||||
},
|
||||
{
|
||||
"label": "小流量",
|
||||
"key": "partial",
|
||||
"status": 4
|
||||
},
|
||||
{
|
||||
"label": "全量",
|
||||
"key": "full",
|
||||
"status": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"type": "tasks",
|
||||
"name": "tasks",
|
||||
"className": "b-a bg-white table-responsive m-t",
|
||||
"checkApi": "/api/mock2/task"
|
||||
}
|
||||
]
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user