$ cnpm install @uyun/grid-layout-screen
portal 拖拽布局
import {
Screen, // 屏整体布局组件
GridLayout, // 拖拽部分
GridLayoutHeader, // 布局头部标题和按钮
Widget // widget渲染部分
} from "@uyun/grid-layout-screen";
页面整体布局部分,用于放置 GridLayout
i18n = {
loadingText: "加载中..."
};
参数 | 类型 | 说明 |
---|---|---|
loading | boolean |
是否显示加载效果 |
i18n | object |
多语言内容 |
children | JSX.Element |
子元素 |
拖拽部分主体部分
type MaterialType = {
title: string,
disabled?: boolean
// ...可携带其他任意属性
};
type Data = {
jsUrl: string, // js文件地址
cssUrl: string, // css文件地址
title: string // widget标题
};
type LayoutItem = {
i: string, // 布局元素的唯一标识
x: number, // 布局元素的位置信息
y: number,
w: number,
h: number,
minW?: number, // 最小宽度
minH?: number, // 最小高度
maxW?: number, // 最大宽度
maxH?: number, // 最小宽度
static?: boolean, // 是否是静态的元素,即不永远不变化位置
isDraggable?: ?boolean, // 是否可拖拽
isResizable?: ?boolean, // 是否可调整大小
data: Data // 拖拽元素对应的widget信息
};
i18n = {
materialsTitle: "部件列表",
materialsDesc: "选择所需部件,并拖至相应位置",
materialsEmpty: "没有可用部件"
};
参数 | 类型 | 说明 |
---|---|---|
i18n | object |
多语言内容 |
cols | number |
布局列数 |
rowHeight | number |
布局每一个单位的高度 |
margin | number[] |
布局元素间的 x 方向和 y 方向的距离 |
layout | LayoutItem[] |
布局数据 |
materials | MaterialType[] |
widget 列表 |
isEditable | boolean |
是否处于可编辑状态 |
onLayoutChange | (layout: LayoutItem[]) => void |
布局改变之后的回调,回调参数为新的布局数组 |
header | JSX.Element |
头部的屏标题和操作按钮 |
children | (layoutItem: LayoutItem) => JSX.Element |
布局中的每一项的渲染函数 |
布局头部样式
type ButtonItem = {
icon: JSX.Element, // 按钮图标
text: string, // 按钮文字
disabled: false, // 是否禁用
onClick: () => void // 点击回调
};
i18n = {
cancel: "取消",
ok: "保存"
};
参数 | 类型 | 说明 |
---|---|---|
i18n | object |
多语言内容 |
isEditable | boolean |
是否处于可编辑状态 |
title | string |
头部标题 |
buttons | ButtonItem[] |
头部的屏标题和操作按钮 |
onCancel | () => void |
取消按钮点击回调 |
onOk | () => void |
确定按钮点击回调 |
onTitleChange | (e: Event) => void |
标题输入改变事件 |
type Data = {
jsUrl: string, // js文件地址
cssUrl: string, // css文件地址
title: string // widget标题
};
i18n = {
deleteTips: "确定删除部件吗?",
loadingText: "加载中...",
loadError: "部件加载失败!",
renderError: "部件内部出错无法显示!"
};
参数 | 类型 | 说明 |
---|---|---|
i18n | object |
多语言内容 |
i | string |
部件的唯一 id,与 layout 中的 i 相同 |
isEditable | boolean |
是否处于可编辑状态 |
data | Data |
部件渲染相关的数据,与LayoutItem 中的 data 是一致的 |
onDelete | (i:string, data: Data) => void |
删除部件事件回调 |
onChange | (i:string, data: Data) => void |
widget 改变事件回调,如标题等 |
import React from "react";
import {
Screen,
GridLayout,
GridLayoutHeader,
Widget
} from "@uyun/grid-layout-screen";
import request from "@/utils/request";
import { Icon } from "@uyun/components";
import cloneDeep from "lodash/cloneDeep";
export default class extends React.Component {
state = {
title: "",
loading: true,
widgets: [],
layout: [],
isEditable: false,
data: {}
};
buttons = [
{
action: "edit",
icon: <Icon type="edit" />,
text: "编辑",
disabled: false,
onClick: () => {
this.setState({
isEditable: true,
data: {
layout: cloneDeep(this.state.layout),
title: this.state.title
}
});
}
},
{
action: "copy",
icon: <Icon type="copy" />,
text: "复制",
disabled: false
},
{
action: "add",
icon: <Icon type="plus" />,
text: "添加屏",
disabled: false
},
{
action: "authorize",
icon: <Icon type="user-switch" />,
text: "授权",
disabled: false
},
{
action: "delete",
icon: <Icon type="delete" />,
text: "删除",
disabled: false
},
{
action: "home",
icon: <Icon type="home" />,
text: "设为主屏",
disabled: false
}
];
componentDidMount() {
Promise.all([
request.get("/portal/frontapi/v1/widget/getOriginalWidget"),
request.get("/portal/frontapi/v1/screen/getScreenWidget?id=165")
]).then(([widgets, screen]) => {
this.setState({
title: screen.data.name,
layout: screen.data.widgets.map((item, index) => {
const { width, height, minHeight, ...layout } = item.layout;
return {
...layout,
i: `${item.id}-${index}`,
w: Math.round(width),
h: Math.round(height / 60),
minH: Math.round(minHeight / 60),
data: item
};
}),
widgets: widgets.data.map(item => {
if (item.config.repeat === 0) {
if (screen.data.widgets.find(it => it.name === item.name)) {
item.disabled = true;
}
}
if (!item.authorized) {
item.disabled = true;
}
return item;
}),
loading: false
});
});
}
onLayoutChange = items => {
this.setState({
layout: items
});
};
onDrop = widget => {
const { widgets } = this.state;
const index = widgets.findIndex(
item => item.insertWidgetId === widget.insertWidgetId
);
if (index === -1) return;
if (widget.config.repeat === 0) {
widgets[index].disabled = true;
}
console.log(index);
this.setState({
widgets
});
};
onWidgetChange = (i, data) => {
const { layout } = this.state;
const index = layout.findIndex(item => item.i === i);
if (index === -1) return;
layout[index].data = data;
this.setState({
layout
});
};
onWidgetDelete = (i, data) => {
const { layout, widgets } = this.state;
const index = layout.findIndex(item => item.i === i);
if (index === -1) return;
layout.splice(index, 1);
const idx = widgets.findIndex(({ name }) => data.name === name);
if (idx === -1) return;
const widget = widgets[idx];
if (widget.config.repeat === 0) {
widgets[idx].disabled = false;
}
console.log(idx);
this.setState({
layout,
widgets
});
};
screenHeaderChange = e => {
this.setState({
title: e.target.value
});
};
exitEdit = () => {
const { layout = [], title = "" } = this.state.data;
this.setState({
isEditable: false,
layout,
title
});
};
save = () => {
this.setState({
isEditable: false
});
};
render() {
return (
<Screen
loading={this.state.loading}
i18n={{
loadingText: "加载中..."
}}
>
<GridLayout
i18n={{
materialsTitle: "部件列表",
materialsDesc: "选择所需部件,并拖至相应位置"
}}
cols={6}
rowHeight={50}
margin={[15, 10]}
layout={this.state.layout}
materials={this.state.widgets}
isEditable={this.state.isEditable}
onDrop={this.onDrop}
onLayoutChange={this.onLayoutChange}
header={
<GridLayoutHeader
i18n={{
cancel: "取消",
ok: "保存"
}}
isEditable={this.state.isEditable}
buttons={this.buttons}
title={this.state.title}
onTitleChange={this.screenHeaderChange}
onCancel={this.exitEdit}
onOk={this.save}
/>
}
>
{item => {
return (
<Widget
{...item}
i18n={{
deleteTips: "确定删除部件吗?",
loadingText: "加载中...",
loadError: "部件加载失败!",
renderError: "部件内部出错无法显示!"
}}
isEditable={this.state.isEditable}
onChange={this.onWidgetChange}
onDelete={this.onWidgetDelete}
/>
);
}}
</GridLayout>
</Screen>
);
}
}
Copyright 2013 - present © cnpmjs.org